13.picoでRTCサンプル動作 Arduino


13.picoでRTCサンプル動作 Arduino

picoの内蔵時計(RTC)のサンプルスケッチ2つを動作させます。
picoにはバッテリバックアップがないので、電源を切ると時間が失われます。よって起動時にRTCを更新する必要があります。

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

RP2040_RTC
https://www.arduino.cc/reference/en/libraries/rp2040_rtc/
の、RP2040_RTC Library
https://github.com/khoih-prog/RP2040_RTC
を使用します。

Arduino-IDE > スケッチ > ライブラリをインクルード > ライブラリを管理... > "pico RTC"で検索
RP2040_RCT by Khoi Hoang Ver1.1.0 をインストール > Install all は no protocol でエラーになったので > Install 'RP2040_RTC' only > 閉じる

RP2040_RTCライブラリ

Raspberry Pi Pico C/C++ SDK https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf の、
p195 4.1.21.3. Function Documentation と
p260 4.2.17.3. Function Documentation より

Typedef

typedef void(* rtc_callback_t )(void);
typedef struct{
int16_t year; // 年(0..4095)
int8_t month; // 月(1..12) 1:1月
int8_t day; // 日(1..28,29,30,31)
int8_t dotw; // 曜日(0..6) 0:日曜日
int8_t hour; // 時(0..23)
int8_t min; // 分(0..59)
int8_t sec; // 秒(0..59)
} datetime_t;

rtc_disable_alarm

void rtc_disable_alarm(void);
アクティブならRTCアラームを無効にします

rtc_enable_alarm

void rtc_enable_alarm(void);
非アクティブならRTCアラームを有効にします

rtc_get_datetime

bool rtc_get_datetime(datetime_t *t);
RTCから現在時刻を取得
t:現在のRTC時刻を受け取るdatetime_t構造体へのポインタ
戻り値:true=日時が有効, false=RTCが実行されていない

rtc_init

void rtc_init(void);
RTCシステムを初期化

rtc_running

bool rtc_running(void);
RTCは実行していますか?

rtc_set_alarm

void rtc_set_alarm(datetime_t *t, rtc_callback_t user_callback);
RTCがユーザー提供のコールバックを呼び出す将来時間を設定
t:アラームを発生させる未来の時刻を格納した datetime_t構造体へのポインタを指定。-1に設定された値は、マッチングされない。
user_callback:アラームが発生したときに呼び出す rtc_callback_t へのポインタ。

rtc_set_datetime

bool rtc_set_datetime(datetime_t *t);
RTCを指定時間に設定
t:datetime_t構造体へのポインタには、設定する時間が含まれています
戻り値:true=設定されている場合, false=渡された日時が無効

datetime_to_str

void datetime_to_str(char *buf, uint buf_size, const datetime_t *t);
datetime_t構造体を文字列に変換。使い勝手が悪い
buf:生成された文字列を受け入れる文字バッファ
buf_size:渡されたバッファのサイズ
t:変換される日時

スケッチ1

Arduino-IDE > ファイル > スケッチ例 > (カスタムライブラリのスケッチ例) RP2040_RTC > Time > RP2040_RTC_Time.ino

スケッチには夏時間のライブラリがありましたが、
khoih-prog/Timezone_Generic
https://github.com/khoih-prog/Timezone_Generic
Timezone(夏時間)を削除し、UTC時刻のみの表示に変更しました。スケッチ内で時刻を設定し、10秒ごとに時刻を表示します。なぜか、1番最初の時刻がでたらめです。

スケッチ

"RP2040_RTC_Time.ino"

// RP2040_RTC_Time.ino
// RP2040で内蔵RTCを使用する ESP8266-WiFi、ESP8266-ATモジュール/シールドなど
// https://github.com/khoih-prog/RP2040_RTC
// バッテリーバックアップがないので、電源断で時刻は失われます。よって、起動ごとにNTP時刻を取得必要
// typedef struct{
//  int16_t year;   // 0..4095
//  int8_t  month;  // 1..12, 1 is January
//  int8_t  day;    // 1..28,29,30,31 depending on month
//  int8_t  dotw;   // 0..6, 0 is Sunday
//  int8_t  hour;   // 0..23
//  int8_t  min;    // 0..59
//  int8_t  sec;    // 0..59
//  } datetime_t;
#include "defines.h"  // 添付 定義
datetime_t currTime = {2022, 1, 21, 5, 5, 0, 0}; // 2022年1月21日金曜日5:00:00

void printDateTime(time_t t, const char *tz) { // 時刻表示関数(タイムゾーン付)
  char buf[32];                                // 表示用時刻保存
  sprintf(buf, "%d/%.2d/%.2d(%s) %.2d:%.2d:%.2d %s", year(t), month(t), day(t),
          dayShortStr(weekday(t)), hour(t), minute(t), second(t), tz); // 時刻文字列作成
  Serial.println(buf);                         // 時刻表示
}

void setup() {
  Serial.begin(115200);                // システムモニタ初期設定
  while (!Serial && millis() < 5000);  // モニタを開いてなく起動5秒以内なら待つ
  delay(200);                          // 0.2秒待つ
  Serial.print(F("\nRP2040_RTC_Time.ino開始\nボード名= ")); // 表示
  Serial.println(BOARD_NAME);          // "RASPBERRY_PI_PICO"と表示
  Serial.println(RP2040_RTC_VERSION);  // "RP2040_RTC v1.1.0"と表示
  rtc_init();                          // RTCシステムを初期化
  rtc_set_datetime(&currTime);         // RTCを指定時間に設定
}

void loop() {
  static unsigned long displayRTCTime_timeout = 0;  // 10秒後のmS
  // static変数は 最初に呼出された時にのみ作成と初期化
#define DISPLAY_RTC_INTERVAL     10000L             // 10秒ごと表示 デフォルト60
  if ((millis() > displayRTCTime_timeout) || (displayRTCTime_timeout == 0)) {
    // timeout時間後 or timeout=0(ループ最初の開始時刻)なら
    rtc_get_datetime(&currTime);        // RTCから現在時刻を取得
    DateTime now = DateTime(currTime);  // DateTimeライブラリ
    time_t utc = now.get_time_t();      // time_t型式に変換?
    printDateTime(utc, "UTC");          // time_t形式で時刻表示関数へ ここのみ
    displayRTCTime_timeout = millis() + DISPLAY_RTC_INTERVAL; // 次の10秒後の時間設定
  }
}
defines.h

// defines.h
// 内蔵RTCを使用するRP2040用 ESP8266-WiFi,ESP8266-ATモジュール/シールドなど
// https://github.com/khoih-prog/RP2040_RTC
#ifndef defines_h         // 定義がされてなければ
  #define defines_h       // 定義する
  #include <RP2040_RTC.h> // RP2040_RTCを使用
#endif                    // defines_h
* フラッシュメモリ(1Mbyte)を、スケッチが4%使用。RAM(262kbyte)を、グローバル変数が2%使用、ローカル変数で254kbyte使用可能。(1000byte=1kで計算)

スケッチ2

Arduino-IDE > ファイル > スケッチ例 > (カスタムライブラリのスケッチ例) RP2040_RTC > Alarm > RP2040_RTC_Alarm.ino

夏時間は削除しました。スケッチ内で時刻を設定します。10秒(DISPLAY_RTC_INTERVAL)ごとに時刻表示し、各分の05秒時(ALARM_AT_SECONDS)にアラーム処理(ここでは時刻表示)します。一番最初の時刻表示が合っていません。

スケッチ

"RP2040_RTC_Alarm.ino" ("defines.h"は同じ)

// RP2040_RTC_Alarm.ino
// 内蔵RTCを使用するRP2040ベースのボード用
// ESP8266-WiFi,ESP8266-ATモジュール/シールドなど
// https://github.com/khoih-prog/RP2040_RTC
// バッテリーバックアップがないので、電源断で時刻は失われます。起動時にNTP時刻を取得必要
// typedef struct{
//  int16_t year;  // 0..4095
//  int8_t  month; // 1..12, 1 is January
//  int8_t  day;   // 1..28,29,30,31 depending on month
//  int8_t  dotw;  // 0..6, 0 is Sunday
//  int8_t  hour;  // 0..23
//  int8_t  min;   // 0..59
//  int8_t  sec;   // 0..59
// } datetime_t;

#include "defines.h"                  // 添付 定義
datetime_t currTime = {2022, 1, 21, 5, 5, 0, 0};// 2022/1/21 Fri 05:00:00 時計時刻
datetime_t alarmT;                    // アラーム時刻
volatile bool alarmTriggered = false; // アラームでない
#define ALARM_AT_SECONDS          5   // 5秒時にアラーム
#define ALARM_REPEAT_FOREVER    true  // 繰返しアラーム,false:1回アラーム
bool setAlarmDone = false;            // アラーム内容未設定

void rtcCallback() {     // アラーム時動作関数
  alarmTriggered = true; // アラームになった
}

void set_RTC_Alarm(datetime_t *alarmTime) { // アラーム時間と動作関数の設定
  rtc_set_alarm(alarmTime, rtcCallback);// RTCが設定のコールバックを呼出す将来時間を設定
}

void printDateTime(time_t t, const char *tz) {  // 時刻表示関数(タイムゾーン付)
  char buf[32];                                 // 時刻表示文字用
  sprintf(buf, "%d/%.2d/%.2d(%s) %.2d:%.2d:%.2d %s", year(t), month(t), day(t),
          dayShortStr(weekday(t)), hour(t), minute(t), second(t), tz); // 時刻文字列作成
  Serial.println(buf);                          // 時刻表示
}

void setup() {
  Serial.begin(115200);                // システムモニタ初期設定
  while (!Serial && millis() < 5000);  // モニタを開いてなく起動5秒以内なら待つ
  delay(200);                          // 0.2秒待つ
  Serial.print(F("\nRP2040_RTC_Alarm.ino開始\nボード名= "));   // 表示
  Serial.println(BOARD_NAME);          // "RASPBERRY_PI_PICO"と表示
  Serial.println(RP2040_RTC_VERSION);  // "RP2040_RTC v1.1.0"と表示
  rtc_init();                          // RTCシステムを初期化
  rtc_set_datetime(&currTime);         // RTCを指定時間に設定
}

void displayTime() {                  // 表示設定関数
  rtc_get_datetime(&currTime);        // RTCから現在時刻を取得
  DateTime now = DateTime(currTime);  // DateTimeライブラリ
  time_t utc = now.get_time_t();      // time_t型式に変換?
  printDateTime(utc, "UTC");          // time_t形式で時刻表示関数へ ここのみ
}

void loop() {
  static unsigned long displayRTCTime_timeout = 0; // 10秒後のmS
  // static変数は 最初に呼出された時にのみ作成と初期化
#define DISPLAY_RTC_INTERVAL     10000L            // 10秒ごと表示 デフォルト60
  if ((millis() > displayRTCTime_timeout) || (displayRTCTime_timeout == 0)) {
    // timeout時間後 or timeout=0(ループ最初の開始時刻)なら
    displayTime();                                 // 表示設定関数へ(開始時と10秒ごと)
    displayRTCTime_timeout = millis() + DISPLAY_RTC_INTERVAL; //次の10秒後の時間設定
  }
  if (!setAlarmDone) {          // アラーム内容未設定なら
#if ALARM_REPEAT_FOREVER        // 繰返しアラームの設定なら
    rtc_get_datetime(&alarmT);  //RTCから現在時刻を取得
    alarmT.min = alarmT.hour = alarmT.day = -1;    // アラームマッチング外
    alarmT.dotw = alarmT.month = alarmT.year = -1; // アラームマッチング外
    alarmT.sec = ALARM_AT_SECONDS;                 // アラーム秒代入
    set_RTC_Alarm(&alarmT);                        // アラーム設定関数へ
    Serial.print("繰返しアラーム設定秒= ");           // 表示
    Serial.println(ALARM_AT_SECONDS);              // アラーム秒表示
#else                                   // 1回アラームの設定なら
    rtc_get_datetime(&alarmT);          // RTCから現在時刻を取得
    if (ALARM_AT_SECONDS > alarmT.sec)  // 設定値が現在以降なら
      alarmT.sec = ALARM_AT_SECONDS;    // アラームを設定値に設定
    else {
      alarmT.sec = ALARM_AT_SECONDS;    // アラームを設定値に設定するが
      alarmT.min += 1;                  // 1加算 次の分
    }
    set_RTC_Alarm(&alarmT);             // アラーム設定関数へ
    Serial.print("1回アラームを設定秒= "); // 表示
    Serial.println(ALARM_AT_SECONDS);   // アラーム秒数表示
#endif
    setAlarmDone = true;                // アラーム内容設定済
  }
  if (alarmTriggered) {         // アラームになったら
    alarmTriggered = false;     // アラームトリガー解除
    Serial.println("Alarm ↓"); // 表示
    displayTime();              // 表示設定関数へ(アラーム時刻)
  }
}
* フラッシュメモリ(1Mbyte)を、スケッチが4%使用。RAM(262kbyte)を、グローバル変数が2%使用、ローカル変数で254kbyte使用可能。(1000byte=1kで計算)