Arduino UNO R4 MINIMAでRTCを使ってみる
Arduino UNO R4 MINIMAを買ってから久しいですが、今一つ使い道に困っていて、とりあえずRTCを試してみることにしました。
Arduino UNO R4 MINIMAにはRTCが搭載されています。これにより、単独で時計機能を維持できます。しかしながら、MINIMAにはWi-Fiがありませんので、最初の時刻設定をどうするかが問題です。それについては、サンプルプログラムに解決方法がありました。
要は、ビルドした時の時間を取得して、その後はUSBケーブルを外して単独運転するという方法ができることが分かりました。それでは、デジタル時計を作ってみます。
#include <Wire.h>
#include<Adafruit_GFX.h>
#include<Adafruit_SSD1306.h>
#include <RTC.h>
Adafruit_SSD1306 display(-1);
DayOfWeek convertDayOfWeek(String s)
{
if (s == String("Mon"))
{
return DayOfWeek::MONDAY;
}
if (s == String("Tue"))
{
return DayOfWeek::TUESDAY;
}
if (s == String("Wed"))
{
return DayOfWeek::WEDNESDAY;
}
if (s == String("Thu"))
{
return DayOfWeek::THURSDAY;
}
if (s == String("Fri"))
{
return DayOfWeek::FRIDAY;
}
if (s == String("Sat"))
{
return DayOfWeek::SATURDAY;
}
if (s == String("Sun"))
{
return DayOfWeek::SUNDAY;
}
}
Month convertMonth(String s)
{
if (s == String("Jan"))
{
return Month::JANUARY;
}
if (s == String("Feb"))
{
return Month::FEBRUARY;
}
if (s == String("Mar"))
{
return Month::MARCH;
}
if (s == String("Apr"))
{
return Month::APRIL;
}
if (s == String("May"))
{
return Month::MAY;
}
if (s == String("Jun"))
{
return Month::JUNE;
}
if (s == String("Jul"))
{
return Month::JULY;
}
if (s == String("Aug"))
{
return Month::AUGUST;
}
if (s == String("Sep"))
{
return Month::SEPTEMBER;
}
if (s == String("Oct"))
{
return Month::OCTOBER;
}
if (s == String("Nov"))
{
return Month::NOVEMBER;
}
if (s == String("Dec"))
{
return Month::DECEMBER;
}
}
RTCTime currentRTCTime()
{
// Get a compilation timestamp of the format: Wed May 10 08:54:31 2023
// __TIMESTAMP__ is a GNU C extension macro
// We can't use the standard macros __DATE__ and __TIME__ because they don't provide the day of the week
String timeStamp = __TIMESTAMP__;
// Extract the day of the week
int pos1 = timeStamp.indexOf(" ");
DayOfWeek dayOfWeek = convertDayOfWeek(timeStamp.substring(0, pos1));
// Extract the month
++pos1;
int pos2 = timeStamp.indexOf(" ", pos1);
Month month = convertMonth(timeStamp.substring(pos1, pos2));
// Extract the day
pos1 = ++pos2;
pos2 = timeStamp.indexOf(" ", pos1);
int day = timeStamp.substring(pos1, pos2).toInt();
// Extract the hour
pos1 = ++pos2;
pos2 = timeStamp.indexOf(":", pos1);
int hour = timeStamp.substring(pos1, pos2).toInt();
// Extract the minute
pos1 = ++pos2;
pos2 = timeStamp.indexOf(":", pos1);
int minute = timeStamp.substring(pos1, pos2).toInt();
// Extract the second
pos1 = ++pos2;
pos2 = timeStamp.indexOf(" ", pos1);
int second = timeStamp.substring(pos1, pos2).toInt();
// Extract the year
pos1 = ++pos2;
pos2 = timeStamp.indexOf(" ", pos1);
int year = timeStamp.substring(pos1, pos2).toInt();
return RTCTime(day, month, year, hour, minute, second, dayOfWeek, SaveLight::SAVING_TIME_INACTIVE);
}
void setup() {
Serial.begin(115200) ;
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
RTC.begin();
RTCTime timeToSet = currentRTCTime();
RTC.setTime(timeToSet);
delay(1000);
}
void loop() {
// put your main code here, to run repeatedly:
char buff[256] ;
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
delay(100);
RTCTime currentTime;
RTC.getTime(currentTime);
// 現在の時刻を取得
int hours = currentTime.getHour() ;
int minutes = currentTime.getMinutes() ;
int seconds = currentTime.getSeconds() ;
int years = currentTime.getYear() ;
int months = Month2int(currentTime.getMonth()) ;
int days = currentTime.getDayOfMonth() ;
display.setCursor(0, 0);
sprintf(buff, "%02d:%02d:%02d", hours, minutes, seconds);
display.print(buff);
display.setCursor(0, 16);
sprintf(buff, "%04d/%02d/%02d", years, months, days);
display.print(buff);
display.display();
delay(250); // 0.25秒ごとに更新
}
時間の取得部分は、サンプルを使わさせて頂いています。表示はSSD1306を使うOLEDディスプレイです。
まずは、USBケーブルを接続して、プログラムをArduino UNO R4 MINIMAにロードします。
バッテリーからArduino UNO R4 MINIMAへ電力を供給します。5VINとGNDにジャンパーケーブルで接続します。
そして、USBケーブルを外して、パソコンからの電力を遮断します。これで、Arduino UNO R4 MINIMA単独で時計が動作します。
13時間ほど動作させました。テスト開始時、電波時計との時間差は25秒でしたが、8分以上ずれています。なんと1時間あたり40秒前後もずれてしまっています。ちょっと精度が悪すぎですが、やり方が悪いのでしょうか。
どちらかというと、タイマーなどで使う方が良いのかもしれません。何か分かったら追記します。