🙆

Arduino RTCで時刻表示

5 min read

初めに

前回液晶に文字が表示できたので、次はRTCを接続して時刻を表示して時計を作成します。
使用するのはZS-042という物で、RTCとしてDS3231SNモジュールが乗ってます。

接続

ZS-042

内容 詳細
32K 不使用
SQW 不使用
SCL I2C通信用
SDA I2C通信用
VCC 電源
GND 電源

前回の液晶の配線はそのままで、今回使用するZS-042の配線を赤色で記載

ライブラリのインストール

DS3232RTCというライブラリがあるので、こちらを使用します。デバイスはDS3231なんですが、DS3232ライブラリで問題無しと思う。以下のURLからDS3232RTC-master.zipをダウンロードして下さい。

https://github.com/JChristensen/DS3232RTC
ArduinoIDEにて、メニューよりライブラリをインストールして下さい。

使い方が良く分からないので、こういう場合はサンプルで動作確認。

次にシリアルモニタを表示させる。

サンプルを動作させると、1秒毎にシリアルモニタに時刻が表示される。どうやら「hour()」や「second()」といった関数で時間や秒が取得出来るらしいので、年月日時分秒を取得してLCDに表示する実装を書いた。

実装

前回のLCD実装に追記しています。説明は下の方

#include <stdio.h>

//LCD
#include <Wire.h>
//RTC
#include <DS3232RTC.h>

byte lcdAddress = 0x50;
char str[] = {"0000/00/00      00:00:00"};

//-----------------------------------------------
//  時刻の表示
//-----------------------------------------------
void rtc2lcd()
{
  char buffer[] = {"0000"};
  int value;

  //年を取得して文字列に代入
  value = year();
  itoa(value, buffer, 10);
  strncpy(str, buffer, 4);

  //月を取得して文字列に代入
  buffer[0] = '0';
  value = month();
  itoa(value, &buffer[1], 10);
  if(value > 9)
  {
    strncpy(&str[5], &buffer[1], 2);
  }else{
    strncpy(&str[5], buffer, 2);
  }
  
  //日を取得して文字列に代入
  value = day();
  itoa(value, &buffer[1], 10);
  if(value > 9)
  {
    strncpy(&str[8], &buffer[1], 2);
  }else{
    strncpy(&str[8], buffer, 2);
  }

  //時を取得して文字列に代入
  value = hour();
  itoa(value, &buffer[1], 10);
  if(value > 9)
  {
    strncpy(&str[16], &buffer[1], 2);
  }else{
    strncpy(&str[16], buffer, 2);
  }

  //分を取得して文字列に代入
  value = minute();
  itoa(value, &buffer[1], 10);
  if(value > 9)
  {
    strncpy(&str[19], &buffer[1], 2);
  }else{
    strncpy(&str[19], buffer, 2);
  }
  
  //秒を取得して文字列に代入
  value = second();
  itoa(value, &buffer[1], 10);
  if(value > 9)
  {
    strncpy(&str[22], &buffer[1], 2);
  }else{
    strncpy(&str[22], buffer, 2);
  }
  lcdWrite(str);                      //LCDに反映
}
//-----------------------------------------------
//  ACM1602NI初期化
//-----------------------------------------------
void lcdInit()
{
  i2cCmdWrite(0x01);    //Clear Display
  delay(5);
  i2cCmdWrite(0x38);    //Function Set
  delay(5);
  i2cCmdWrite(0x0c);    //Display ON/OFF Control
  delay(5);
  i2cCmdWrite(0x06);    //Entry Mode Set
  delay(5);  
}
//-----------------------------------------------
//  文字列の書き出し
//-----------------------------------------------
void lcdWrite(char* str)
{
  int i;

  i2cCmdWrite(0x80);    //1行目の先頭にカーソルを移動
  delay(5);
  for(i = 0;i < 16;i++)
  {
    if(*str == '\0')break;
    i2cDataWrite(*str++);
    delay(5);
  }
  i2cCmdWrite(0xc0);    //2行目の先頭にカーソルを移動
  delay(5);
  for(i = 0;i < 16;i++)
  {
    if(*str == '\0')break;
    i2cDataWrite(*str++);
    delay(5);
  }
}
//-----------------------------------------------
//  I2CにてACM1602NIにコマンドを送信
//-----------------------------------------------
int i2cCmdWrite(byte cmd){
  Wire.beginTransmission(lcdAddress);
  Wire.write(0x00);
  Wire.write(cmd);
  return Wire.endTransmission();
}

//-----------------------------------------------
//  I2CにてACM1602NIに表示文字を送信
//-----------------------------------------------
int i2cDataWrite(byte data){
  Wire.beginTransmission(lcdAddress);
  Wire.write(0x80);
  Wire.write(data);
  return Wire.endTransmission();
}

//-----------------------------------------------
//  Main
//-----------------------------------------------
void setup() {
  // put your setup code here, to run once:
  //LCD
  Wire.begin();
  lcdInit();
  
  //RTC
  setSyncProvider(RTC.get);
  if(timeStatus() != timeSet)
        Serial.println("Unable to sync with the RTC");
    else
        Serial.println("RTC has set the system time");
}

void loop() {
  // put your main code here, to run repeatedly:
  rtc2lcd();
  delay(1000);
}

説明

rtc2lcd関数

rtcから取得した時刻情報を文字列に変換して、前回作成したlcdWrite関数に渡して表示する。欲しい時刻情報は以下の関数にて取得出来る。それぞれ戻り値が数値となっている。

欲しい情報 関数名
year()
month()
day()
hour()
minute()
second()

年情報の取得処理を見ると、

 //年を取得して文字列に代入
  value = year();
  itoa(value, buffer, 10);
  strncpy(str, buffer, 4);

となっていて、value変数に年の数値を取得し、itoa関数で数値を文字列に変換して、strncpyでstr文字列変数に代入している流れ。itoa関数はstrncpy関数を使用しているので、冒頭でstdio.hをインクルードしている。年情報は4桁みたいなので、bufferも4byte分確保してある。

次に年以外の取得処理。たとえば月の場合には、

//月を取得して文字列に代入
  buffer[0] = '0';
  value = month();
  itoa(value, &buffer[1], 10);
  if(value > 9)
  {
    strncpy(&str[5], &buffer[1], 2);
  }else{
    strncpy(&str[5], buffer, 2);
  }

buffer変数内には年情報が入ってしまってるので、一旦先頭だけ0としている。これは1月~9月の場合にゼロパディング(0埋め)を行いたいため。月情報は先頭から2byte目から代入して、10月移行の場合には、2byte目と3byte目の2byte分をstr変数に代入して、1月~9月の場合には、0を記載した先頭から2byteをstr変数に代入する事で、ゼロパディングしています。
後で先頭に0文字を足して処理しても良かったけど、どのみち桁数みて2byte切り出すのは一緒なので、こういった処理としました。

日情報以降は月と同じなので、割愛。
loop関数内でrtc2lcd関数を読み出して表示を行い続けています。

残件

現状ではRTCから読み取って表示しているだけで、時刻合わせ機能が無いので、次はその辺を記載する予定。