Skip to content

ESP32睡眠

ESP32睡眠后,有多种唤醒方式。ESP32 几种睡眠模式对比。

Modem-Sleep Light-Sleep Deep-Sleep Hibernation
WiFi 不活动 不活动 不活动 不活动
Bluetooth 不活动 不活动 不活动 不活动
Radio 不活动 不活动 不活动 不活动
外设 不活动 不活动 不活动 不活动
ESP32 Core 活动 暂停 不活动 不活动
ULP协处理器 活动 活动 活动 不活动
RTC 活动 活动 活动 活动

以时间唤醒为例。因为ESP32 是32位MCU,所以它的最大睡眠时间是32位的整数,即0xFFFF FFFF 或 4294967295 毫秒,约71分钟。

Modem-Sleep

在Modem-Sleep模式下,CPU 供电,ESP32 根据 WiFi 通信的使用情况在主动模式和调制解调器睡眠模式之间切换。切换是自动完成的,CPU 频率也会自动更改,具体取决于 CPU 负载和外围设备的使用。

由于ESP32会自动进入modem-sleep模式,因此没有Arduino功能可以进入该模式。

Light-Sleep

light-sleep 模式下 ESP32 Core暂停。这意味着大部分 RAM 和 CPU 都遵循睡眠模式。在这种模式下,内部触发器不会切换状态,因为这种切换会消耗功率。

在轻度睡眠模式下,WiFi 基带被禁用,但 WiFi 连接本身保持活动状态。

ESP32 Light-Sleep 程序代码

我们可以通过以下函数进入轻度睡眠模式:

esp_light_sleep_start(void)

以下 Arduino 代码显示了如何进入浅睡眠模式

#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  5        /* Time ESP32 will go to sleep (in seconds) */

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup(){
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  }
}

void loop(){
  print_wakeup_reason(); //Print the wakeup reason for ESP32

  delay(5000);

  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); // ESP32 wakes up every 5 seconds

  Serial.println("Going to light-sleep now");
  Serial.flush(); 
  esp_light_sleep_start();
}

Deep-Sleep模式

在浅睡眠模式下,ESP32 Core 暂停并遵循睡眠模式,而在深度睡眠电源模式下,ESP32 Core 完全不活动。只有 ULP 协处理器和 RTC 保持活动状态。

在深度睡眠模式下,WiFi 连接不活跃,但 WiFi 配置数据存储在实时时钟的内存中。因此,ESP32 从深度睡眠模式唤醒后重新建立 WiFi 连接非常快。

ESP32 深度睡眠程序代码

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  5        /* Time ESP32 will go to sleep (in seconds) */

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup(){
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  }

  print_wakeup_reason(); //Print the wakeup reason for ESP32

  delay(5000);

  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); // ESP32 wakes up every 5 seconds

  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); // all RTC Peripherals are powered

  Serial.println("Going to deep-sleep now");
  Serial.flush(); 
  esp_deep_sleep_start();
}

void loop(){
}

深度睡眠电源模式从函数esp_deep_sleep_start开始。

每次微控制器从深度睡眠模式唤醒时,ESP32 都会启动 setup 函数,所以我们在 setup 函数中定义了我们所有的代码,不使用循环函数。

对于深度睡眠模式,我们可以定义所有 RTC 外设是活动还是断电。在睡眠配置文件中,我们定义 RTC IO、传感器和 ULP 协处理器等 RTC 模块保持活动状态。

Hibernation模式

休眠电源模式是电流消耗最低的电源模式。空白的 ESP32 微控制器仅消耗 5μA。内部 8 MHz 振荡器和 ULP 协处理器被禁用,RTC 恢复存储器断电。慢速时钟上只有一个 RTC 定时器和某些 RTC GPIO 处于活动状态。RTC 定时器或 RTC GPIO 可以将芯片从休眠模式唤醒。

ESP32 休眠程序代码

要进入休眠电源模式,我们使用与深度睡眠模式相同的 Arduino 脚本,但我们选择停用所有 RTC 外设。因此我们只将睡眠配置文件更改为:

esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);

增加睡眠时间以降低功耗

我们从上一章中获得了两个重要的见解,这有助于我们进一步降低整个 ESP32 项目的功耗。

  1. 建立WiFi连接并通过WiFi发送数据具有非常高的功耗
  2. 在深度睡眠或休眠模式下,ESP32 的功耗显着降低。

因此,如果精确规划各个阶段(唤醒、通过 WiFi 发送数据、睡眠),则可以降低功耗。

下表列出两种开发板在各种状态下的电流,供参考。

Reference [mA] Light-Sleep [mA] Deep-Sleep [mA] Hibernation [mA]
ESP32 – DevKitC 51 10 9 9
FireBeetle ESP32 39 1.94 0.011 0.008

loading-ag-1204

以气象站为例,可以清楚地描述各个阶段:

ESP32 连接到 DHT22 温度和湿度传感器。如果我们每 10 秒传输一次温度和湿度,功耗将不必要地高,因为传输的测量值大多相同。

可以通过每 10 分钟而不是每 10 秒传输读数来降低功耗。有了这个,我们延长了绵羊时间。为了减少 WiFi 连接的数量,每次从睡眠模式唤醒时,可以将当前传感器值与上次发送的值进行比较,只有在温度或湿度发生变化时才通过 WiFi 发送新数据。

要在睡眠模式下存储变量,它们必须加载到 RTC 内存中,在 ESP32 上只有 8kB。您只需在变量前添加RTC_DATA_ATT 即可

RTC_DATA_ATT int temperature;
RTC_DATA_ATT int humidity;