Arduino

RTCを使って日付・時間を表示する

今回は日付や時間をArudinoで使いたいと思います。ただ、Arudino UNOには日付や時間を取得するRTC(Real Time Clock)が搭載されていませんので、別途用意する必要があります。

RTCを使うと現在の時刻を7セグに表示する時計のようなものが作成できるようになります。また時刻を持つことによってサーバなどと同期することも可能となります。

RTCは様々な用途で使われている電子部品ですので、どういったものかをご紹介したいと思います。

RTCとは

RTCとはReal Time Clockの略称で、時刻をもつICのことです。RTCはボタン電池を内蔵しており、Arudinoに電源供給がなくなっても時刻を刻み続けることができます。

DS3231

今回使用するRTCは下図のDS3231になります。データーシートを見ると2.3V~5.5Vの電源供給であればいいので、Arudinoの5Vで事足ります。

端子は32K、SQW、SCL、SDA、VCC、GNDとなっています。SCLとSDAがあるとおり、I2C通信方式でデータ送受信を行います。それぞれの端子の機能について以下の表にまとめておきました。

32K        32kHzの信号を出力
SQWアラーム信号を出力
SCLシリアル通信をするときにマスターとスレーブ間の同期をとるための信号用
SDAシリアル通信時のデータを送受信用
VCC電源供給
GNDグランド

注意点として、Vccの電圧 > ボタン電池の電圧の場合、Vccからボタン電池へ充電がされてしまうみたいです。そのため、本来であれば、充電式のボタン電池(LIR2032)を使うべきですが、私は充電式でないボタン電池が手元にありますのでそれを使います。ただし、そのまま使うと普通のボタン電池へ充電をしようとするため、危険です。

充電式でないボタン電池をするには下図の場所をカッターやマイナスドライバーでパターンカットすればいいです。

RTClib

RTCをArudinoで使うためにAdafruit社が提供しているRTClibを使用します。簡単にですが、使い方について説明します。

初めにRTClibを使うためにライブラリをインクルードします。

#include <RTClib.h>

実際に使うためにはインスタンスを生成します。

RTC_DS3231 rtc

RTCを使うためにライブラリの初期化をします。戻り値がbooleanですので失敗した場合は異常終了するなどできます。

rtc.begin()

コンパイル時に基準となる現在の日付・時間を設定します。

if(!rtc.lostPower()){
    rtc.adjust(DateTime(F(__DATE__),F(__TIME__)));
  }

不要な端子を無効化します。

rtc.disable32K();

実際に日付・時刻を取得するには以下のような関数を使います。

DateTime date = rtc.now();
date.year();
date.month();
date.day();
date.hour();
date.minute();

RTCを使って日付・時間を取得する

RTCの使い方を知るためにまずは、RTCを使って日付と時刻をシリアル通信で取得し、確認する回路を作成しました。

作成した回路

作成した回路は以下の図となります。

使用した装置及び部品は下表をご覧ください。

Arduino小型コンピュータ搭載のマイコン
ブレッドボード抵抗・ジャンパー線などを使って回路を作る基板
ジャンパー線電気を中継する線
RTC(DS3231)時刻をもつIC

プログラムコード

プログラムコードは以下となります。

#include <RTClib.h>

RTC_DS3231 rtc;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  //RTCの初期設定(RTCがない場合は異常終了)
  if(!rtc.begin()){
    Serial.println("Couldn't find RTC!");
    Serial.flush();
    abort();
  }

  //コンパイル時に日付を設定する
  if(rtc.lostPower()){
    rtc.adjust(DateTime(F(__DATE__),F(__TIME__)));
  }

  //32Kピンは使わない
  rtc.disable32K();
}

void loop() {
  // put your main code here, to run repeatedly:
  DateTime date = rtc.now();
  Serial.print(date.year(),DEC);
  Serial.print("/");
  Serial.print(date.month(),DEC);
  Serial.print("/");
  Serial.print(date.day(),DEC);
  Serial.print("  ");
  Serial.print(date.hour(),DEC);
  Serial.print(":");
  Serial.print(date.minute(),DEC);
  Serial.print(":");
  Serial.println(date.second(),DEC);
  delay(500);
  
}

実行結果

実行結果は以下の画像をご覧ください。

RTCで取得した日付・時間を7セグに表示する

RTCを使って取得した日付・時間を7セグに表示したいと思います。7セグは4桁までしか表示できないので、スイッチのオン/オフで時間と日付の切り替えをする回路を作成しました。

作成した回路

作成した回路は以下の図をご覧ください。

使用した装置及び部品は下表をご覧ください。

Arduino 小型コンピュータ搭載のマイコン
ブレッドボード 抵抗・ジャンパー線などを使って回路を作る基板
ジャンパー線 電気を中継する線
RTC(DS3231) 時刻をもつIC
抵抗1kΩ電圧を下げる端子
抵抗220Ω×8電圧を下げる端子
タクトスイッチボタンのON/OFF
7セグLED0~9の数字を表示できるディスプレイ
16×8マトリクスLEDドライバモジュールLEDを点灯制御するドライバモジュール

プログラムコード

プログラムコードは以下となります。

#include <RTClib.h>
#include <Wire.h>

const int SWITCH_PIN = 8;//スイッチのピン
const int HT16K33_ADDR = 0x70;//HTK16K33のアドレス
const int DIG = 5;//表示する桁数
const char seg[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};
RTC_DS3231 rtc;//RTCのインスタンス

int value; //スイッチの今回の値
int old_value = 0;//スイッチの前回の値
int states = -1;//スイッチの状態
int disp[5];//セグに表示する値

void setup() {
  // put your setup code here, to run once:
  /* RTCの初期設定 */
  //RTCライブラリの初期化
  if(!rtc.begin()){
    abort();
  }
  //コンパイル時に日付等設定
  if(!rtc.lostPower()){
    rtc.adjust(DateTime(F(__DATE__),F(__TIME__)));
  }

  //32Kの無効化
  rtc.disable32K();

  /* LEDモジュールの初期設定 */
  Wire.begin();
  Wire.beginTransmission(HT16K33_ADDR);
  Wire.write(0x21);
  Wire.write(0x01);
  Wire.endTransmission();
  delay(10);
  Wire.beginTransmission(HT16K33_ADDR);
  Wire.write(0x81);
  Wire.write(0x01);
  Wire.endTransmission();
  delay(10);  

  /* スイッチ */
  pinMode(SWITCH_PIN,INPUT);


}

void loop() {
  // put your main code here, to run repeatedly:

  value = digitalRead(SWITCH_PIN);

  if(old_value==LOW && value==HIGH)
  {
    states = states * -1;
    delay(50);
  }
  else
  {
    //処理なし
  }
  old_value = value;
  
  if(states > 0)
  {
    setDisplayDate(disp);
  }
  else
  {
    setDisplayTime(disp);  
  }
  
   for(int i = 0;i < DIG;i++)
  {
    Wire.beginTransmission(HT16K33_ADDR);
    Wire.write(i*2);
    Wire.write(seg[disp[i]]);
    Wire.endTransmission();
    delay(10);
  }
}

void setDisplayTime(int disp[]){
  DateTime date = rtc.now();//日時を取得
  int h = date.hour();//  現在の時を取得
  int m = date.minute();//現在の分を取得

  if(h < 10)
  {
    disp[0] = 0;
    disp[1] = h;
  }
  else
  {
    disp[0] = h/10;
    disp[1] = h%10;
  }

  if(m < 10)
  {
    disp[2] = 0;
    disp[3] = m;
  }
  else
  {
    disp[2] = m/10;
    disp[3] = m%10;
  }

  disp[4] = 2;
}

void setDisplayDate(int disp[]){
  DateTime date = rtc.now();//日時を取得

  int m = date.month();//  現在の月を取得
  int d = date.day();//現在の日を取得

  if(m < 10)
  {
    disp[0] = 0;
    disp[1] = m;
  }
  else
  {
    disp[0] = m/10;
    disp[1] = m%10;
  }

  if(d < 10)
  {
    disp[2] = 0;
    disp[3] = d;
  }
  else
  {
    disp[2] = d/10;
    disp[3] = d%10;
  }

  disp[4] = 10;
}

実行結果

実行結果は以下の通りです。

まとめ

今回、RTCを使って日付・時間を7セグに表示する回路を作成しました。RTCはシステム電源とは別にボタン電池で日付・時間をバックアップできるため、時刻を刻み続けることができます。

日付・時間はIoT機器では多く使われる情報のため、RTCの使い方をしっかりと理解しておきたいものです。