ESP8266两次深度睡眠间隔时长测量方法咨询
获取ESP8266深度睡眠间隔时长的可行方案
好问题!我之前用ESP8266做低功耗数据采集项目时,刚好遇到过一模一样的需求——既要支持定时唤醒,又要支持中断提前唤醒,还得准确记录每次睡眠的时长。给你分享几个靠谱的实现思路:
方案一:利用RTC内存+内置RTC计数器(推荐)
ESP8266的RTC模块在深度睡眠时会持续运行,而且有一块专门的RTC内存区域(断电/深度睡眠不会丢失数据),刚好用来存储睡眠前的计时点。
具体步骤:
定义一个存放在RTC内存的全局变量,用来记录进入睡眠前的RTC计数器值:
// 用RTC_DATA_ATTR标记,变量会存在RTC内存,深度睡眠不丢失 RTC_DATA_ATTR uint32_t sleep_start_rtc = 0;在进入深度睡眠前,读取当前RTC计数器值并保存:
void enterDeepSleep() { // 获取当前RTC计时值(单位:RTC时钟tick,ESP8266的RTC时钟是150kHz) sleep_start_rtc = system_get_rtc_time(); // 设置唤醒规则:定时20秒 + 允许外部中断唤醒 // WAKE_RF_DEFAULT表示唤醒后恢复WiFi功能 ESP.deepSleep(20e6, WAKE_RF_DEFAULT); }每次唤醒后,计算睡眠时长:
void setup() { Serial.begin(115200); delay(100); // 给串口初始化留时间 uint32_t current_rtc = system_get_rtc_time(); if (sleep_start_rtc != 0) { // 排除第一次上电的情况 uint32_t sleep_ticks; // 处理RTC计数器溢出(32位无符号数约8小时溢出一次) if (current_rtc >= sleep_start_rtc) { sleep_ticks = current_rtc - sleep_start_rtc; } else { sleep_ticks = (0xFFFFFFFF - sleep_start_rtc) + current_rtc + 1; } // 转换成秒:150kHz时钟,每秒150000个tick float sleep_duration = sleep_ticks / 150000.0; Serial.print("本次深度睡眠时长:"); Serial.print(sleep_duration); Serial.println(" 秒"); } else { Serial.println("首次上电,无睡眠时长记录"); } // 这里写你的数据采集、WiFi传输代码... // 完成任务后进入深度睡眠 enterDeepSleep(); } void loop() { // 深度睡眠后不会执行到这里,无需编写内容 }
为什么推荐这个方案?
- 完全不需要额外硬件,利用ESP8266内置资源即可实现
- RTC内存读写无Flash损耗(不像EEPROM是模拟在Flash上的)
- 不管是定时唤醒还是中断唤醒,都能精准计算睡眠时长
方案二:结合唤醒原因+预设时长(适合简单场景)
如果你的中断唤醒场景不多,也可以通过判断唤醒原因来估算时长:
- 用
esp_sleep_get_wakeup_cause()函数获取唤醒源:ESP_SLEEP_WAKEUP_TIMER:定时唤醒,时长就是你设置的ESP.deepSleep()参数ESP_SLEEP_WAKEUP_EXT0/ESP_SLEEP_WAKEUP_EXT1:外部中断唤醒,这时候需要额外记录进入睡眠的时间(还是得用方案一的RTC计数器思路)
这个方案本质上是方案一的简化版,只在定时唤醒时直接用预设值,中断唤醒时再计算实际时长。
关于EEPROM的补充说明
你提到可以用EEPROM,但我不推荐:
- ESP8266的EEPROM是模拟在Flash上的,频繁写入会缩短Flash寿命(Flash有擦写次数限制)
- 读写EEPROM需要额外的初始化和操作代码,比RTC内存麻烦得多
- 如果一定要用,逻辑和方案一类似:进入睡眠前把RTC计数器值写入EEPROM,唤醒后读取并计算差值,但要注意处理EEPROM的擦写和溢出问题
内容的提问来源于stack exchange,提问作者EnriqM




