Arduino(2) RTCで時刻表示
はじめに
前回液晶に文字が表示できたので、次はRTCを接続して時刻を表示して時計を作成します。
使用するのはZS-042という物で、RTCとしてDS3231SNモジュールが乗ってます。
接続
ZS-042
内容 | 詳細 |
---|---|
32K | 不使用 |
SQW | 不使用 |
SCL | I2C通信用 |
SDA | I2C通信用 |
VCC | 電源 |
GND | 電源 |
前回の液晶の配線はそのままで、今回使用するZS-042の配線を赤色で記載 | |
ライブラリのインストール
DS3232RTCというライブラリがあるので、こちらを使用します。デバイスはDS3231なんですが、DS3232ライブラリで問題無しと思う。以下のURLからDS3232RTC-master.zipをダウンロードして下さい。
使い方が良く分からないので、こういう場合はサンプルで動作確認。
次にシリアルモニタを表示させる。
サンプルを動作させると、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から読み取って表示しているだけで、時刻合わせ機能が無いので、次はその辺を記載する予定。
Discussion