ESP32 五种电源模式
IoT 设备往往依赖电池供电,低功耗设计直接决定设备寿命。ESP32 提供五种由高功耗到超低功耗的工作模式,理解每种模式的特性是优化电池寿命的基础。
| 电源模式 | 典型电流 | Wi-Fi | CPU | 唤醒延迟 |
|---|---|---|---|---|
| Active(活跃) | 240mA(峰值)/ 80mA(平均) | 发送/接收 | 满速运行 | N/A |
| Modem-sleep | 3~20mA | 定时休眠(DTIM 间隔) | 正常运行 | 毫秒级 |
| Light-sleep | 0.8mA | 暂停,可保持连接 | 暂停 | 约 3ms |
| Deep-sleep | 10~150μA | 关闭 | 关闭(仅 RTC 运行) | 约 300ms(含启动) |
| Hibernation | 2.5μA | 关闭 | 关闭,RTC 外设也关 | 约 300ms + 完整启动 |
一块常见的 18650 锂电池容量约 2500mAh。在纯 Active 模式下(80mA),只能用约 31 小时。而用深度睡眠(每 10 分钟唤醒一次,每次活跃 3 秒),平均电流约 30μA,理论寿命超过 9 年(当然实际还受自放电影响)。
深度睡眠(Deep Sleep)详解
深度睡眠是 IoT 设备最重要的省电手段。进入深度睡眠后,主 CPU、大部分 RAM 和外设全部断电,只有 RTC 时钟域(RTC 定时器、RTC 内存、RTC GPIO)保持供电。
唤醒源类型
深度睡眠完整示例
#include "esp_sleep.h"
#include "esp_log.h"
#include "driver/rtc_io.h"
static const char *TAG = "SLEEP";
/* RTC_DATA_ATTR:变量存储在 RTC SRAM,深度睡眠后保留 */
static RTC_DATA_ATTR int boot_count = 0;
static RTC_DATA_ATTR float last_temperature = 0.0f;
#define SLEEP_DURATION_S 600 // 10 分钟
#define WAKEUP_PIN GPIO_NUM_33
void app_main(void)
{
boot_count++;
ESP_LOGI(TAG, "第 %d 次启动", boot_count);
/* 判断唤醒原因 */
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
switch (cause) {
case ESP_SLEEP_WAKEUP_TIMER:
ESP_LOGI(TAG, "定时器唤醒,上次温度: %.1f°C", last_temperature);
break;
case ESP_SLEEP_WAKEUP_EXT0:
ESP_LOGI(TAG, "GPIO 唤醒(按键)");
break;
default:
ESP_LOGI(TAG, "上电启动");
break;
}
/* ── 执行业务逻辑(读传感器、上报数据)── */
last_temperature = 25.6f; // 模拟读取传感器
ESP_LOGI(TAG, "数据已处理,准备进入深度睡眠");
/* ── 配置唤醒源 ── */
/* 1. 定时器唤醒 */
esp_sleep_enable_timer_wakeup((uint64_t)SLEEP_DURATION_S * 1000000ULL);
/* 2. GPIO 唤醒(GPIO33 低电平触发,需使用 RTC GPIO)*/
rtc_gpio_pullup_en(WAKEUP_PIN); // 上拉,按键接地
esp_sleep_enable_ext0_wakeup(WAKEUP_PIN, 0); // 0 = 低电平唤醒
/* 进入深度睡眠 */
ESP_LOGI(TAG, "进入深度睡眠 %d 秒...", SLEEP_DURATION_S);
esp_deep_sleep_start(); // 不返回!
}
Light Sleep(浅睡眠)
Light Sleep 比 Deep Sleep 功耗稍高(约 0.8mA),但唤醒后无需完整启动流程(仅约 3ms),程序从调用 esp_light_sleep_start() 的下一行继续执行,RAM 和状态完全保留。适合需要频繁唤醒的场景(如每秒唤醒一次)。
void light_sleep_demo(void)
{
while (1) {
ESP_LOGI(TAG, "开始 5 秒浅睡眠");
esp_sleep_enable_timer_wakeup(5000000); // 5秒
esp_light_sleep_start(); // ← 此处暂停 5 秒
/* 唤醒后从这里继续,变量状态保留 */
ESP_LOGI(TAG, "唤醒!继续执行...");
/* 处理数据... */
}
}
ULP(超低功耗)协处理器
ULP(Ultra Low Power Coprocessor)是 ESP32 内置的独立处理器,在深度睡眠中以极低功耗(100μA 以下)独立运行,可以读取 ADC、I2C 传感器,在满足条件时唤醒主 CPU。
#include "esp32/ulp.h"
#include "driver/rtc_io.h"
#include "ulp_main.h" // 由 ULP 汇编程序生成
/* ULP 读取 ADC 并在超阈值时唤醒主 CPU */
/* ULP 程序用汇编或 C(ESP32-S2/S3 支持 C)编写 */
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
void start_ulp_program(void)
{
/* 加载 ULP 程序到 RTC 内存 */
ulp_load_binary(0, ulp_main_bin_start,
(ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));
/* 设置 ULP 唤醒间隔(每 100ms 运行一次) */
ulp_set_wakeup_period(0, 100000); // 100000 μs = 100ms
/* 启动 ULP */
ulp_run(&ulp_main - RTC_SLOW_MEM);
/* 允许 ULP 唤醒主 CPU */
esp_sleep_enable_ulp_wakeup();
esp_deep_sleep_start();
}
ESP32 原版 ULP 只能用汇编编写,学习曲线陡峭。ESP32-S2 和 S3 引入了 ULP-RISC-V 核,支持用 C 语言编写 ULP 程序,大大降低了开发门槛。新项目建议优先考虑 ESP32-S3。
电流实测与分析
1. GPIO 有外接上拉/下拉电阻:睡眠时 GPIO 浮空,电阻持续漏电。解决:睡眠前将相关 GPIO 配置为 RTC GPIO 并设置保持(hold)状态。
2. 外部传感器/模块仍在供电:用 MOSFET 或 Load Switch 在睡眠前切断外设供电。
3. I2C 总线上拉电阻:ESP32 I2C 引脚低电平时,上拉电阻到 3.3V 持续产生漏电流。睡眠前释放 I2C 总线并切断电源。