Arduino UNO R4でRTCを使う

Arduino

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の初期化に成功したかどうかを論理値で返します。

意味
trueRTCの初期化に成功した
falseRTCの初期化に失敗した

今回の例では返却値を無視していますが、成功・失敗によって何らかのメッセージを表示するようにしても良いでしょう。

時刻の設定
  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)
引数
名前意味
dayint『日』を整数で指定。
monthuint8_t『月』を整数で指定。1月=0、2月=1、… 12月=11です。
紛らわしいので、Month型(enum)の定数が用意されています(後述)。
yearint『西暦年』を整数で指定。
hourint『時』を整数で指定。
minuteint『分』を整数で指定。
secondint『秒』を整数で指定。
dayofweekuint8_t『曜日』を指定。値は整数で、日曜=0、月曜=1、火曜=2、…、土曜=6です。
判りにくいので、DayOfWeek型(enum)の定数が用意されています(後述)
savingtimeuint8_t夏時間のフラグ

month(月)については、以下の定数が用意されています。(Month型)

名前意味
Month::JANUARY01月
Month::FEBRUARY12月
Month::MARCH23月
Month::APRIL34月
Month::MAY45月
Month::JUNE56月
Month::JULY67月
Month::AUGUST78月
Month::SEPTEMBER89月
Month::OCTOBER910月
Month::NOVEMBER1011月
Month::DECEMBER1112月

dayofweekについては、以下の定数が用意されています。(DayOfWeek型)

名前意味
DayOfWeek::SUNDAY0日曜
DayOfWeek::MONDAY1月曜
DayOfWeek::TUESDAY2火曜
DayOfWeek::WEDNESDAY3水曜
DayOfWeek::THURSDAY4木曜
DayOfWeek::FRIDAY5金曜
DayOfWeek::SATURDAY6土曜
書式
bool RTC.setTime(RTCTime& time)
引数
名前意味
timeRTCTime&設定したい時刻を表すRTCTime型のインスタンス
返却値

時刻の設定をした結果が論理値で返されます。

意味
true時刻の設定に成功した
false時刻の設定に失敗した

この例では、本記事投稿時刻(2024年9月13日 18時00分00秒 金曜日)を設定しています。

これ以降、自動的に時刻が刻まれていきます。

時刻の取得
  // 時刻の取得
  RTCTime currentTime;
  RTC.getTime(currentTime);

時刻を取得するには、RTC.getTime()関数を使用します。

書式
bool RTC.getTime(RTCTime& time)
引数
名前意味
timeRTCTime&形式としては引数だが、結果を受け取るための変数を渡す
返却値

取得に成功したかどうかを真偽値で返します。

意味
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)
引数
名前意味
funcrtc_cbk_t定期的に実行したい関数へのポインタ。要は関数名を書くだけです。
pPeriod実行間隔を表す値を指定します。実行間隔は \(\frac{1}{2^{p-1}}\)秒となります。

実行間隔pについては、以下のように定数が設定されています。

名前意味
ONCE_EVERY_2_SEC02秒に1回実行する
ONCE_EVERY_1_SEC11秒に1回実行する
N2_TIMES_EVERY_SEC21秒に2回実行する
N4_TIMES_EVERY_SEC31秒に4回実行する
N8_TIMES_EVERY_SEC41秒に8回実行する
N16_TIMES_EVERY_SEC51秒に16回実行する
N32_TIMES_EVERY_SEC61秒に32回実行する
N64_TIMES_EVERY_SEC71秒に64回実行する
N128_TIMES_EVERY_SEC81秒に128回実行する
N256_TIMES_EVERY_SEC91秒に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をインクルードするだけでよい

コメント

タイトルとURLをコピーしました