4. ESP32功耗模式详解
ESP32 的省电能力并不是靠“关掉 CPU”这一招实现的,而是由一组层层递进的电源与时钟管理机制组成。理解 Active、Modem-sleep、Light-sleep、Deep-sleep、Hibernation 这五种模式的关键,是搞清楚三件事:哪些电源域还活着、哪些时钟还在跑、唤醒后程序从哪里继续。这三者决定了功耗数量级,也决定了它适合什么场景。
一、五种模式的工作原理
Active(运行模式)是芯片的默认状态。此时 CPU、Wi-Fi/蓝牙射频、外设时钟全部开启,程序全速执行。功耗取决于 CPU 主频、是否开启射频、外设负载,典型值在 80 mA 到 240 mA 之间。任何“省电”讨论的起点,都是先让系统尽快离开 Active。
Modem-sleep(调制解调器睡眠)针对的是“必须保持 Wi-Fi 连接”的场景。CPU 仍然运行,但 Wi-Fi/蓝牙基带会在每个 DTIM 周期之间自动关闭射频,只在信标到达前醒来接收。它不需要用户显式调用 API,只要连接了 AP 并开启省电模式即可生效。功耗通常降到 3–20 mA,是智能插座、联网传感器这类“常在线但低吞吐”设备的基础档位。
Light-sleep(浅睡眠)会暂停 CPU 与数字外设时钟,但保留 RTC 域和 RAM 供电。它的最大价值是上下文不丢失:唤醒后程序从暂停处继续执行,无需重新初始化。GPIO、触摸、UART 等都可以作为唤醒源,唤醒延迟在毫秒级。代价是功耗仍在 0.8–2 mA 量级,因为 RAM 需要持续刷新。
Deep-sleep(深睡眠)关闭 CPU、主时钟和大部分电源域,只保留 RTC 控制器、RTC 内存和少量唤醒逻辑。唤醒后芯片执行复位流程,程序从 setup() 重新开始。它支持 RTC 定时器、EXT0/EXT1 外部 IO、触摸和 ULP 协处理器唤醒,功耗可降到 10–150 µA。这是电池设备最常用的主力模式。
Hibernation(休眠)是 ESP32 系列中功耗最低的状态,连 RTC 核心与 RTC 内存都断电,仅保留极少数 RTC IO 和定时器逻辑。功耗可低至 2–5 µA,但 RAM 内容全部丢失,唤醒等同于完全冷启动。它适合“几个月才上报一次”的极端低功耗节点。
二、模式切换与配置流程
实际项目中,模式不是孤立使用的,而是按任务节奏动态切换。典型流程是:上电初始化 → 采集/联网 → 进入低功耗模式 → 被定时器或外部事件唤醒 → 再次采集。下面是一段 Deep-sleep 定时唤醒的配置示例:
#include <esp_sleep.h>
#define WAKE_INTERVAL_US (60ULL * 1000000ULL) // 60 秒
void setup() {
Serial.begin(115200);
// 1. 配置 RTC 定时器作为唤醒源
esp_sleep_enable_timer_wakeup(WAKE_INTERVAL_US);
// 2. 可选:配置外部按键唤醒(EXT0)
// esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0);
// 3. 判断本次是冷启动还是定时唤醒
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
if (cause == ESP_SLEEP_WAKEUP_TIMER) {
Serial.println("定时唤醒,执行周期采集");
} else {
Serial.println("上电冷启动,执行初始化");
}
// 4. 采集并上报数据
read_sensor_and_upload();
// 5. 进入 Deep-sleep
Serial.flush();
esp_deep_sleep_start();
}
void loop() {
// Deep-sleep 模式下不会执行到这里
}
如果使用 Light-sleep,则改为调用 esp_light_sleep_start(),它会在函数返回后继续执行后续代码,因此需要把它放在循环中,并配合 esp_sleep_enable_timer_wakeup() 或 GPIO 唤醒源使用。
三、五种模式对比清单
| 模式 | CPU / 时钟 | RAM 保持 | 典型功耗 | 唤醒后行为 | 适用场景 |
|---|---|---|---|---|---|
| Active | 全开 | 是 | 80–240 mA | 持续运行 | 计算、通信、控制 |
| Modem-sleep | CPU 运行 | 是 | 3–20 mA | 射频自动唤醒 | 保持 Wi-Fi 连接 |
| Light-sleep | CPU 暂停 | 是 | 0.8–2 mA | 从暂停处继续 | 快速响应外部事件 |
| Deep-sleep | 关闭 | RTC RAM 可选 | 10–150 µA | 复位重启 | 周期采集、电池节点 |
| Hibernation | 全部关闭 | 否 | 2–5 µA | 完全冷启动 | 超长待机、极低频上报 |
四、案例:温湿度节点的模式选择
假设一个电池供电的温湿度节点,要求每 5 分钟采集一次并通过 Wi-Fi 上报,使用 2000 mAh 电池。若全程 Active,平均电流约 100 mA,续航不到一天;若采用 Deep-sleep 定时唤醒,每次唤醒工作约 2 秒、平均 80 mA,其余时间 20 µA,则平均电流约为:
平均电流 ≈ (80 mA × 2 s + 0.02 mA × 298 s) / 300 s
≈ (160 + 5.96) / 300
≈ 0.55 mA
理论续航 ≈ 2000 mAh / 0.55 mA ≈ 3600 小时 ≈ 150 天
如果采集间隔拉长到 30 分钟,平均电流可进一步降到 0.1 mA 以下,续航进入一年以上。这说明占空比才是电池寿命的第一决定因素,模式选择只是把“睡眠期间的底电流”压到最低。
五、常见误区与复盘
- 误区一:以为 Light-sleep 和 Deep-sleep 只是功耗不同。两者唤醒后的程序状态完全不同,Light-sleep 继续执行,Deep-sleep 从 setup() 重启,代码结构必须相应调整。
- 误区二:忽略外设漏电。开发板上 USB 转串口芯片、LDO 静态电流、上拉电阻都可能带来几百微安漏电,把 Deep-sleep 的 10 µA 优势完全吃掉。测功耗时要断开调试器,单独给核心板供电。
- 误区三:忘记关闭未用外设。进入睡眠前应关闭 ADC、LED、传感器电源,把未用 GPIO 设为合适电平,避免悬空输入造成额外功耗。
- 误区四:唤醒源配置冲突。EXT0 与 EXT1 不能同时使用,RTC IO 与普通 IO 的编号也要区分清楚,否则会出现无法唤醒或误唤醒。
复盘时建议用电流表或功耗分析仪记录完整的一次“唤醒—工作—睡眠”波形,确认工作电流、睡眠底电流和占空比三个数字,再反推电池寿命。只有把模式原理、唤醒路径和实际漏电一起考虑,ESP32 的低功耗设计才真正可控。