ESP32[26] RTC
ESP32にはRTCが内蔵されています。内臓RTCはDeep Sleep する前に起きる時間をマイクロ秒で指定します。
esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us);
time_in_us
の型は uint64_t
(64ビット符号なし整数)なので、理論上の最大値は:
2^64 - 1 = 18,446,744,073,709,551,615(マイクロ秒)
ですが、実際にESP32のハードウェアが対応できる最大値はもっと小さいです。
これは、RTCタイマーの精度と上限に依存します。
実際の最大値(目安)
多くのESP32系では、スリープの最大時間は約71分(~4,294,967,295μs ≒ 約4295秒)が限界です。
この値は32ビットのRTCタイマーを使っていることに由来します。
結論(実用上の最大値):
ESP32の場合、esp_sleep_enable_timer_wakeup() に指定できる実用上の最大値は:
time_in_us <= 4294967295 // 約71分
なので、これ以上の間寝かしておくには工夫が必要です。そんな場合は、
基本アイデア
- NVSに残りスリープ時間を保存
- 起動するたびにその時間を読み出し、再スリープ
- 時間が来たら通常処理を行う
#include <esp_sleep.h>
#define MAX_SLEEP_SEC 180 // 1回にスリープできる最大時間(例:3分 = 180秒)
#define TOTAL_SLEEP_SEC 10800 // 最初のスリープ時間(例:3時間 = 10800秒)
RTC_DATA_ATTR int total_sleep_sec = TOTAL_SLEEP_SEC; // トータルスリープ時間を保持(スリープ状態でもデータ保持)
void setup() {
Serial.begin(115200);
delay(1000);
// スリープから復帰後の処理
Serial.println("=== ESP32 起動 ===");
// RTCメモリから最初のスリープ時間を読み込む
int initial_sleep = total_sleep_sec;
// 残りスリープ時間を計算(最初のスリープ時間からMAX_SLEEP_SEC秒までスリープ)
int sleep_now = (initial_sleep > MAX_SLEEP_SEC) ? MAX_SLEEP_SEC : initial_sleep;
total_sleep_sec -= sleep_now; // 残りスリープ時間を更新
// 残りスリープ時間がある場合、次にスリープする
if (total_sleep_sec > 0) {
Serial.printf("次に %d 秒スリープします。残り %d 秒。\n", sleep_now, total_sleep_sec);
esp_sleep_enable_timer_wakeup((uint64_t)sleep_now * 1000000ULL);
Serial.flush(); // 出力完了を待つ
esp_deep_sleep_start(); // ここでディープスリープに入る
} else {
// 残りのスリープ時間がない場合は、スリープなしで起動
Serial.println("スリープ時間終了");
}
}
void loop() {
// 3分間のスリープ設定(MAX_SLEEP_SEC)
int sleep_now = MAX_SLEEP_SEC;
// スリープ時間を RTCメモリに保存(最初に設定したスリープ時間を保存)
total_sleep_sec = TOTAL_SLEEP_SEC;
// スリープ設定
esp_sleep_enable_timer_wakeup((uint64_t)sleep_now * 1000000ULL);
Serial.printf("最初のスリープ時間: %d秒\n", sleep_now);
Serial.flush();
// 最初のディープスリープに入る
esp_deep_sleep_start();
// ここには戻らない(スリープ後に再起動され、setup() が呼ばれる)
}
目的の時間まで何回も起きるので、IOが初期化されます。なので、すぐに、設定しなおしてまた寝る。確かにESP32の内臓RTCは使い方が簡単ですが、このように長期に寝る場合は、外付けのRTCをつけて、RTCに時間になったらESP32のIOをたたいて起こしてやる必要があるかもしれません。まさか、最大71分しか寝られないとは思いませんでした。3日はまりました。