Arduino UNO R4のRTC
概要
RTC(=Real Time Clock)とは、プログラムとは別に時刻や年月日などを自動的に刻む機能です。Arduino UNO R3以前では外付けのパーツが必要でスタが、Arduino UNO R4ではマイクロコントローラにRTCの機能が統合され、単体で利用可能です。今回はR4でRTCを使って観ます。
専用ライブラリ
マイクロコントローラのレジスタを直接操作すればいろいろ細かいことができるのでしょうがさすがにハードルが高いです。幸い主要機能を簡単に利用できるライブラリが公開されていますので、まずはこれを利用してみます。
例1:時刻の設定&取得
まずは一番基本となる、時刻の設定と取得を行うサンプルです。
#include "RTC.h"
void setup() {
Serial.begin(9600);
delay(1000);
// RTCの開始と時刻の設定
RTC.begin();
RTCTime startTime(13, Month::SEPTEMBER, 2024, 18, 0, 0, DayOfWeek::FRIDAY, SaveLight::SAVING_TIME_ACTIVE);
RTC.setTime(startTime);
}
void loop() {
// 時刻の取得
RTCTime currentTime;
RTC.getTime(currentTime);
char buffer[20];
sprintf(buffer,"%04d/%02d/%02d %02d:%02d:%02d",
currentTime.getYear(), ((int)currentTime.getMonth())+1, currentTime.getDayOfMonth(),
currentTime.getHour(), currentTime.getMinutes(), currentTime.getSeconds());
Serial.println(buffer);
delay(1000);
}
プログラムの解説
ライブラリのインクルード
#include "RTC.h"
R4の開発環境が整っていれば、”RTC.h”をインクルードするだけでRTC関係の関数を利用できるようになります。
シリアルインターフェイスの初期化
Serial.begin(9600);
delay(1000);
この部分はRTCとは直接関係ありません。結果をシリアルモニタ等で確認するためにシリアルインターフェイスを初期化しています。
RTCの利用開始
// RTCの開始と時刻の設定
RTC.begin();
RTCの利用を開始するには、RTC.begin()関数を使用します。
書式
bool RTC.begin()
引数
なし
返却値
RTCの初期化に成功したかどうかを論理値で返します。
値 | 意味 |
---|---|
true | RTCの初期化に成功した |
false | RTCの初期化に失敗した |
今回の例では返却値を無視していますが、成功・失敗によって何らかのメッセージを表示するようにしても良いでしょう。
時刻の設定
RTCTime startTime(13, Month::SEPTEMBER, 2024, 18, 0, 0, DayOfWeek::FRIDAY, SaveLight::SAVING_TIME_ACTIVE);
RTC.setTime(startTime);
RTCに時刻を設定するには、RTCTimeクラスのインスタンスとRTC.setTime()関数を使用します。
書式
RTCTime(int day, uint8_t month, int year, int hour, int minute, int second, uint8_t dayofweek, uint8_t savingtime)
引数
名前 | 型 | 意味 |
---|---|---|
day | int | 『日』を整数で指定。 |
month | uint8_t | 『月』を整数で指定。1月=0、2月=1、… 12月=11です。 紛らわしいので、Month型(enum)の定数が用意されています(後述)。 |
year | int | 『西暦年』を整数で指定。 |
hour | int | 『時』を整数で指定。 |
minute | int | 『分』を整数で指定。 |
second | int | 『秒』を整数で指定。 |
dayofweek | uint8_t | 『曜日』を指定。値は整数で、日曜=0、月曜=1、火曜=2、…、土曜=6です。 判りにくいので、DayOfWeek型(enum)の定数が用意されています(後述) |
savingtime | uint8_t | 夏時間のフラグ |
month(月)については、以下の定数が用意されています。(Month型)
名前 | 値 | 意味 |
---|---|---|
Month::JANUARY | 0 | 1月 |
Month::FEBRUARY | 1 | 2月 |
Month::MARCH | 2 | 3月 |
Month::APRIL | 3 | 4月 |
Month::MAY | 4 | 5月 |
Month::JUNE | 5 | 6月 |
Month::JULY | 6 | 7月 |
Month::AUGUST | 7 | 8月 |
Month::SEPTEMBER | 8 | 9月 |
Month::OCTOBER | 9 | 10月 |
Month::NOVEMBER | 10 | 11月 |
Month::DECEMBER | 11 | 12月 |
dayofweekについては、以下の定数が用意されています。(DayOfWeek型)
名前 | 値 | 意味 |
---|---|---|
DayOfWeek::SUNDAY | 0 | 日曜 |
DayOfWeek::MONDAY | 1 | 月曜 |
DayOfWeek::TUESDAY | 2 | 火曜 |
DayOfWeek::WEDNESDAY | 3 | 水曜 |
DayOfWeek::THURSDAY | 4 | 木曜 |
DayOfWeek::FRIDAY | 5 | 金曜 |
DayOfWeek::SATURDAY | 6 | 土曜 |
書式
bool RTC.setTime(RTCTime& time)
引数
名前 | 型 | 意味 |
---|---|---|
time | RTCTime& | 設定したい時刻を表すRTCTime型のインスタンス |
返却値
時刻の設定をした結果が論理値で返されます。
値 | 意味 |
---|---|
true | 時刻の設定に成功した |
false | 時刻の設定に失敗した |
この例では、本記事投稿時刻(2024年9月13日 18時00分00秒 金曜日)を設定しています。
これ以降、自動的に時刻が刻まれていきます。
時刻の取得
// 時刻の取得
RTCTime currentTime;
RTC.getTime(currentTime);
時刻を取得するには、RTC.getTime()関数を使用します。
書式
bool RTC.getTime(RTCTime& time)
引数
名前 | 型 | 意味 |
---|---|---|
time | RTCTime& | 形式としては引数だが、結果を受け取るための変数を渡す |
返却値
取得に成功したかどうかを真偽値で返します。
値 | 意味 |
---|---|
true | 取得に成功 |
false | 取得に失敗 |
時刻は返却値ではなく、引数で指定した変数に格納されます。
あらかじめ現在時刻を取得するための変数 currentTime を用意した上で RTC.getTime()関数を呼び出しています。結果は currentTime に格納されます。
年・月・日・時・分・秒に分解
char buffer[20];
sprintf(buffer,"%04d/%02d/%02d %02d:%02d:%02d",
currentTime.getYear(), ((int)currentTime.getMonth())+1, currentTime.getDayOfMonth(),
currentTime.getHour(), currentTime.getMinutes(), currentTime.getSeconds());
Serial.println(buffer);
RTCTime型のデータから年・月・日・時・分・秒をそれぞれ取得するには、以下の関数を使用します。
取得する値 | 関数名 |
---|---|
年 | RTCTime.getYear() |
月 | RTCTime.getMonth() |
日 | RTCTime.getDayOfMonth() |
時 | RTCTime.getHour() |
分 | RTCTime.getMinute() |
秒 | RTCTime.getSeconds() |
このうち RTCTime.getMonth()関数だけは注意が必要です。他の5つの関数は年・日・時・分・秒そのものが数値として返されるのですが、RTCTime.getMonth()関数は返却値がMonth型で、かつ値が1月ならば0、2月ならば1…と1つずれています。よって
((int)currentTime.getMonth())+1
のように、(int)で整数型にキャストして1を加算しています。
この例ではsprintf()関数をつかって『YYYY/MM/DD hh:mm:ss』の形式の文字列に変換し、Serial.println()関数でシリアル出力しています。
実行結果
実行すると、プログラムを起動した時刻を2024年9月13日18時0分0秒として1秒ごとに『現在時刻』を表示していきます。
例2:RTCを利用して定期実行する
次に、RTCを利用して定期的に割り込みをかける方法を試してみましょう。
#include "RTC.h"
bool flag = false;
void callbackFunc(){
flag = !flag;
}
void setup() {
Serial.begin(9600);
delay(1000);
// RTCの開始と時刻の設定
RTC.begin();
RTCTime startTime(13, Month::SEPTEMBER, 2024, 18, 0, 0, DayOfWeek::FRIDAY, SaveLight::SAVING_TIME_ACTIVE);
RTC.setTime(startTime);
// 定期実行の設定
RTC.setPeriodicCallback(callbackFunc, Period::ONCE_EVERY_1_SEC);
}
void loop() {
if(flag){
Serial.println("true");
}else{
Serial.println("false");
}
delay(1000);
}
プログラム解説
例1と共通する部分は省略します。
コールバック関数の定義
bool flag = false;
void callbackFunc(){
flag = !flag;
}
定期実行する内容はコールバック関数として定義します。この例では callbackFunc() というそのまんまな名前ですが、自由な名前を付けることができます。
コールバック関数内で複雑な(≒時間のかかる)処理をすると動作がおかしくなることがあるようなので、この例ではグローバル変数flagを用意して、callbackFunc()を呼び出す毎にtrueとfalseを切り替えるだけの処理にしてあります。
定期実行の設定
// 定期実行の設定
RTC.setPeriodicCallback(callbackFunc, Period::ONCE_EVERY_1_SEC);
RTCでの定期実行を設定するには、RTC.setPeriodicCallback()関数を使用します。
書式
bool RTC.setPeriodicCallback(rtc_cbk_t func, Period p)
引数
名前 | 型 | 意味 |
---|---|---|
func | rtc_cbk_t | 定期的に実行したい関数へのポインタ。要は関数名を書くだけです。 |
p | Period | 実行間隔を表す値を指定します。実行間隔は \(\frac{1}{2^{p-1}}\)秒となります。 |
実行間隔pについては、以下のように定数が設定されています。
名前 | 値 | 意味 |
---|---|---|
ONCE_EVERY_2_SEC | 0 | 2秒に1回実行する |
ONCE_EVERY_1_SEC | 1 | 1秒に1回実行する |
N2_TIMES_EVERY_SEC | 2 | 1秒に2回実行する |
N4_TIMES_EVERY_SEC | 3 | 1秒に4回実行する |
N8_TIMES_EVERY_SEC | 4 | 1秒に8回実行する |
N16_TIMES_EVERY_SEC | 5 | 1秒に16回実行する |
N32_TIMES_EVERY_SEC | 6 | 1秒に32回実行する |
N64_TIMES_EVERY_SEC | 7 | 1秒に64回実行する |
N128_TIMES_EVERY_SEC | 8 | 1秒に128回実行する |
N256_TIMES_EVERY_SEC | 9 | 1秒に256回実行する |
返却値
設定が成功したかどうかを真偽値で返します。
値 | 意味 |
---|---|
true | 設定に成功した |
false | 設定に失敗した |
ここでは、1秒に1回、先ほど定義した callbackFunc() を呼び出すように設定しています。
loop()
void loop() {
if(flag){
Serial.println("true");
}else{
Serial.println("false");
}
delay(1000);
}
loop()関数内では、1秒に1回グローバル変数flagの値を確認して”true”または”false”と表示しています。loop()関数内ではflagの値は変化させていませんが、これとは独立してRTCによる割り込み処理でcallbackFunc()が実行されるため、一定間隔でflagの値が変化しています。
実行結果
このプログラムではRTCによる割り込み実行もloop()内での処理も1秒間隔となっていますので、”true”と”false”が交互に表示されます。誤差があるのでまれに同じものが2回続くことがあるかも知れません。
まとめ
- Arduino UNO R4では、単体でRTCが利用可能
- RTCを使用するには、RTC.hをインクルードするだけでよい
コメント