リアルタイムクロック(RTC-8564NB)の使い方 [Arduino]
今回のリアルタイムクロック(RTC)の「RTC-8564NB」はArduinoなどのマイコンボードにあるSDA/SCLピンをお互いに接続して「I2C通信」を行い利用します。
このRTCは「時計・カレンダー」以外に「アラーム機能」(日時指定の割り込み)、「タイマー機能」(カウントダウンによる割り込み)、「クロック出力」(一定周期による割り込み)があります。
実行例
[アラーム]
アラーム時刻(12時21分)になると、LEDが点灯します。
[シリアルモニター]
現在時刻とアラーム時刻を表示します。
使用部品・材料
総額で約800円です。(Arduino本体の値段を除く)
| 部品/材料 | 値段 | 備考 |
|---|---|---|
| ブレッドボード | ¥270 | 秋月電子の通販コード(P-00315) |
| リアルタイムクロック(RTC) モジュール | ¥500 | 秋月電子の通販コード(I-00233) |
| 5mm赤色LED OSDR5113A | ¥20 | 秋月電子の通販コード(I-11655) |
| タクトスイッチ | ¥10 | 秋月電子の通販コード(P-03647) |
| カーボン抵抗器 | 数円 | 10kΩ(1個)、1kΩ(2個)、220Ω(1個)を使用。 |
配線図
[RTC-8564NB] ※公式より引用。
[SDA/SCLについて]
Arduino UNOの場合はSDA/SCLはデジタルピン側のAREFの横にあります。「SDA=A4 SCL=A5」でも代用可能です。
[外部割り込みについて]
Arduino UNOの場合はデジタルの2ピン(int.0)または3ピン(int.1)を使用します。それ以外のピンでは動作しないのでご注意ください。
スケッチ(プログラム)
シリアルモニターに現在時刻とアラーム時刻を表示します。
アラーム時刻になるとLEDが点灯。LEDを消灯するにはボタンを押します。
#include <Wire.h>
// 外部割り込みの状態
volatile int state = LOW;
// RTCのレジスタテーブル(16byte)
int RegTbl[16];
// デバイスアドレス(スレーブ)
// ※Arduinoの仕様では8bitのアドレスを右に1bitシフトした「7bit」を使用する
// ※[8bit]Write : 0xA2 = 10100010 Read : 0xA3 = 10100011
byte DEVICE_ADDRESS= 0x51;
// 2進化10進数(BCD)を10進数に変換
byte BCDtoDec(byte value){
return ((value >> 4) * 10) + (value & 0x0F) ;
}
// 外部割り込みが発生した時に動作します。
void myInterrupt() {
state = !state;
}
void setup() {
Serial.begin(9600);
// タイマー割り込みの解除用
pinMode(8,INPUT);
// 2ピンの状態がLOWからHIGHに変化した場合に外部割り込みを発生させる
attachInterrupt(digitalPinToInterrupt(2), myInterrupt, RISING);
// マスタとしてI2Cバスに接続する
Wire.begin();
// I2Cスレーブに対して送信処理を開始する
Wire.beginTransmission(DEVICE_ADDRESS);
// レジスタのアドレスを指定する(0-15の内、先頭から)
Wire.write(0x00);
// ---------------------------------
// コントロールレジスタ
// ---------------------------------
// [00]Control1
Wire.write(0x00);
// [01]Control2
// 0x02:アラーム割り込み時に3ピン[INT]をLOWにする
Wire.write(0x02);
// ---------------------------------
// 時計・カレンダーレジスタ
// ---------------------------------
// アドレスの[02-05]及び[08-11]は2進化10進数(BCD)で指定します。
// [02]Seconds(15秒)
Wire.write(0x15);
// [03]Minutes(20分)
Wire.write(0x20);
// [04]Hours(12時)
Wire.write(0x12);
// [05]Days(25日)
Wire.write(0x25);
// [06]Weekdays(月)
// 0:日 1:月 2:火 3:水 4:木 5:金 6:土
Wire.write(0x01);
// [07]Month/Century(21世紀の12月)
// ・Month(01-12) BCD形式
// ・Century(先頭bit 0:20世紀[19xx年代],1(0x80):21世紀[20xx年代])
Wire.write(0x12 | 0x80);
// [08]Years(2017年)
Wire.write(0x17);
// ---------------------------------
// アラームレジスタ
// ---------------------------------
// 先頭bitに1がある場合(0x80)はアラーム対象外となる
// 例)次のコードは「25日(月)12時21分」にアラームが設定されていますが、
// 「25日」と「(月)」には0x80がありますので、実際のアラームは「12時21分」で毎日となります。
// [09]Minutes alarm(21分)
Wire.write(0x21);
// [0A]Hours Alarm(12時)
Wire.write(0x12);
// [0B]Days Alarm(25日)
Wire.write(0x25 | 0x80);
// [0C]Weekdays Alarm(月)
// 0:日 1:月 2:火 3:水 4:木 5:金 6:土
Wire.write(0x01 | 0x80);
// ---------------------------------
// クロック出力レジスタ
// ---------------------------------
// [0D]CLKOUT Frequency
// ・クロック出力機能を有効にする。
// ※有効:0x80 無効 :0x00
// ・クロック周波数は1Hz(1秒間に1回)とする
// ※0x00:32768Hz, 0x01:1024Hz, 0x02:32Hz, 0x03:1Hz
//
// 次の設定だと2ピン[CLKOUT]から1秒に1回、クロック出力される
Wire.write(0x80 | 0x03);
// I2Cスレーブへの送信完了
Wire.endTransmission();
Serial.println("RTCの初期化完了。");
}
void loop(){
int i;
// 外部割込みが発生した場合
if(state == HIGH){
// レジスタのアドレスを先頭にする
Wire.beginTransmission(DEVICE_ADDRESS);
Wire.write(0x00);
Wire.endTransmission();
// I2Cスレーブに16byteのレジスタデータを要求する
Wire.requestFrom(DEVICE_ADDRESS,16);
// 16byteのデータを取得する
for (i=0; i<16; i++){
while (Wire.available() == 0 ){}
RegTbl[i] = Wire.read();
}
// 現在日時
Serial.print("現在:");
Serial.print(String(BCDtoDec(RegTbl[8])+ 2000) + "年");
Serial.print(String(BCDtoDec(RegTbl[7] & 0x1F)) + "月");
Serial.print(String(BCDtoDec(RegTbl[5] & 0x3F)) + "日");
switch(RegTbl[6] & 0x07){
case 0 : Serial.print("(日)");break;
case 1 : Serial.print("(月)");break;
case 2 : Serial.print("(火)");break;
case 3 : Serial.print("(水)");break;
case 4 : Serial.print("(木)");break;
case 5 : Serial.print("(金)");break;
case 6 : Serial.print("(土)");break;
}
Serial.print(" ");
Serial.print(String(BCDtoDec(RegTbl[4] & 0x3F)) + "時");
Serial.print(String(BCDtoDec(RegTbl[3] & 0x7F)) + "分");
Serial.print(String(BCDtoDec(RegTbl[2] & 0x7F)) + "秒");
// アラーム日時
Serial.print(" アラーム:");
if((RegTbl[11] & 0x80) == 0){
Serial.print(String(BCDtoDec(RegTbl[11] & 0x3F)) + "日");
}
if((RegTbl[12] & 0x80) == 0){
switch(RegTbl[12] & 0x07){
case 0 : Serial.print("(日) ");break;
case 1 : Serial.print("(月) ");break;
case 2 : Serial.print("(火) ");break;
case 3 : Serial.print("(水) ");break;
case 4 : Serial.print("(木) ");break;
case 5 : Serial.print("(金) ");break;
case 6 : Serial.print("(土) ");break;
}
}
if((RegTbl[10] & 0x80) == 0){
Serial.print(String(BCDtoDec(RegTbl[10] & 0x3F)) + "時");
}
if((RegTbl[9] & 0x80) == 0){
Serial.print(String(BCDtoDec(RegTbl[9] & 0x7F)) + "分");
}
Serial.println("");
state = !state;
}
// ボタン押下時にアラーム割り込みイベントをクリアする(LEDを消灯する)
if(digitalRead(8) == HIGH){
// レジスタのアドレスをControl2にする
Wire.beginTransmission(DEVICE_ADDRESS);
Wire.write(0x01);
// アラーム割り込みが発生した際に
// Control2の4bit目のAFフラグが「1」になるので「0」にする
// それにより、3ピン[INT]がHIGHになりLEDが消灯します。
Wire.write(0x02);
Wire.endTransmission();
}
}
このスケッチはこちらのサイトのコードを参考にしています。特に初心者向けにコメントをフンダンに付けました。
システムの流れ
| 1 | setup()で時刻などの情報をRTCに書き込みます。 |
|---|---|
| 2 | RTCの機能を使用して1Hz毎(1秒に1回)にクロック出力(CLKOUT)で外部割込みを発生させます。この割り込みでシリアルモニターに現在時刻を表示させます。 スケッチの流れとしては、割り込みが発生すると、myInterrupt()が実行されて「state」のフラグを逆にします。次にloop()で「state」が「HIGH」の場合にRTCから時刻を取得してシリアルモニターへ出力しています。 |
| 3 | 上記の流れとは別に、RTCのアラーム機能で12時21分になったら、LEDを点灯するようにしています。このLEDを消灯にするにはブレッドボードに設置したボタンを押下します。 |
最後に
今回は「時計・カレンダー」「アラーム機能」「クロック出力」をご紹介しましたが「タイマー機能」には触れていません。
というのは「アラーム機能」と「タイマー機能」は2ピン[INT]の扱いで被っているんです。AF/TFフラグの状態を確認すればわかるみたいですが、ややこしくなるので却下しました。
詳しく知りたい方は、公式のデータシートをご参照ください。
参考リンク
リアルタイムクロック
リアルタイムクロック(RTC)との接続
RTC(リアルタイムクロック)と接続して読み書きを行って見ます
掲示板
ArduinoやRaspberry Piなどの電子工作の掲示板を作成しました。質問やわからない事は電子工作 (Arduino・ラズパイ等)でユーザー同士で情報を共有して下さい。
関連記事
プチモンテ ※この記事を書いた人
![]() | |
![]() | 💻 ITスキル・経験 サーバー構築からWebアプリケーション開発。IoTをはじめとする電子工作、ロボット、人工知能やスマホ/OSアプリまで分野問わず経験。 画像処理/音声処理/アニメーション、3Dゲーム、会計ソフト、PDF作成/編集、逆アセンブラ、EXE/DLLファイルの書き換えなどのアプリを公開。詳しくは自己紹介へ |
| 🎵 音楽制作 BGMは楽器(音源)さえあれば、何でも制作可能。歌モノは主にロック、バラード、ポップスを制作。歌詞は抒情詩、抒情的な楽曲が多い。楽曲制作は🔰2023年12月中旬 ~ | |









