TOP > カテゴリ > ロボット・電子工作・マイコン >

リアルタイムクロック(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(); 
  }  
}

このスケッチはこちらのサイトのコードを参考にしています。特に初心者向けにコメントをフンダンに付けました。

システムの流れ

1setup()で時刻などの情報をRTCに書き込みます。
2RTCの機能を使用して1Hz毎(1秒に1回)にクロック出力(CLKOUT)で外部割込みを発生させます。この割り込みでシリアルモニターに現在時刻を表示させます。

スケッチの流れとしては、割り込みが発生すると、myInterrupt()が実行されて「state」のフラグを逆にします。次にloop()で「state」が「HIGH」の場合にRTCから時刻を取得してシリアルモニターへ出力しています。
3上記の流れとは別に、RTCのアラーム機能で12時21分になったら、LEDを点灯するようにしています。このLEDを消灯にするにはブレッドボードに設置したボタンを押下します。

最後に

今回は「時計・カレンダー」「アラーム機能」「クロック出力」をご紹介しましたが「タイマー機能」には触れていません。

というのは「アラーム機能」と「タイマー機能」は2ピン[INT]の扱いで被っているんです。AF/TFフラグの状態を確認すればわかるみたいですが、ややこしくなるので却下しました。

詳しく知りたい方は、公式のデータシートをご参照ください。

参考リンク

リアルタイムクロック
リアルタイムクロック(RTC)との接続
RTC(リアルタイムクロック)と接続して読み書きを行って見ます





関連記事



公開日:2017年05月25日 最終更新日:2017年08月20日
記事NO:02395