跳转到内容

深度睡眠功耗优化

深度睡眠功耗优化

本节介绍 ESP32 深度睡眠模式的配置与优化,以实现电池供电 IoT 按钮应用的超低功耗。学习完本节后,您将能够:

  • 了解 ESP32 的电源模式及其电流消耗
  • 配置按键按下唤醒的深度睡眠
  • 测量和优化睡眠电流
  • 解释按钮应用的睡眠/唤醒循环

开始本节前,请确保:

ESP32 提供多种电源模式,其电流消耗差异显著:

模式电流(ESP32-C3)描述用途
活跃(WiFi 开启)~60-80 mACPU 运行中,WiFi 已连接正常运行
活跃(WiFi 关闭)~15-25 mACPU 运行中,无射频本地处理
Modem 睡眠~3-5 mACPU 运行中,WiFi 空闲短暂暂停
轻度睡眠~0.5-1 mACPU 暂停,可快速唤醒短时空闲
深度睡眠~5-10 µACPU 关闭,仅 RTC 外设运行长时间空闲
休眠模式~2.5 µARTC 内存关闭,仅 RTC 定时器最大节能

对于 IoT 按钮,深度睡眠是关键模式——设备几乎整个生命周期都处于此状态,仅在按钮按下时短暂唤醒发送消息。

在深度睡眠模式下:

  • CPU 断电
  • 大部分 RAM 内容丢失(RTC 慢速内存保留数据)
  • WiFi/BT 断电
  • RTC 外设保持活动(GPIO、定时器、ULP 协处理器)
  • 唤醒源保持监视(GPIO、定时器、触摸传感器)
┌─────────────────────────────────────────────────────────┐
│ 深度睡眠状态 │
│ │
│ ┌──────────────────┐ ┌──────────────────────────┐ │
│ │ CPU(关闭) │ │ WiFi/BT(关闭) │ │
│ └──────────────────┘ └──────────────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────────────┐ │
│ │ RTC 内存 │ │ RTC 外设 │ │
│ │(保留数据) │ │(GPIO 唤醒、定时器) │ │
│ └──────────────────┘ └──────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 主内存(SRAM)——内容丢失 │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
唤醒源配置方式按钮适用性
EXT0RTC GPIO → 电平变化✅ GPIO 2 → LOW 唤醒(按键按下)
EXT1多个 RTC GPIO → 模式匹配⚠️ 适用于多个按键
定时器RTC 定时器 → 时间到达✅ 定时唤醒进行状态检查
触摸电容触摸传感器❌ 按键不需要
ULP超低功耗协处理器❌ 简单按键场景过于复杂

步骤 1:配置带 GPIO 唤醒的深度睡眠

Section titled “步骤 1:配置带 GPIO 唤醒的深度睡眠”
#include <esp_sleep.h>
// 引脚定义
const int BUTTON_PIN = 2; // GPIO 2 用于按键(唤醒源)
const int LED_PIN = D10; // 内置 LED(XIAO 上为 GPIO 10)
void setup() {
Serial.begin(115200);
delay(100); // 让串口初始化
// 检查唤醒原因
esp_sleep_wakeup_cause_t wake_reason = esp_sleep_get_wakeup_cause();
switch (wake_reason) {
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("按键按下唤醒");
break;
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("定时器唤醒(按键模式不应出现)");
break;
default:
Serial.println("首次上电或未知唤醒源");
break;
}
// 短暂 LED 指示
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
delay(200);
digitalWrite(LED_PIN, LOW);
// 执行按键操作
performButtonAction();
// 重新进入睡眠
Serial.println("进入深度睡眠...");
Serial.flush();
delay(100); // 让串口输出完成
// 配置唤醒源
esp_sleep_enable_ext0_wakeup((gpio_num_t)BUTTON_PIN, 0); // LOW = 按下
// 进入深度睡眠
esp_deep_sleep_start();
}
void loop() {
// 永远不会执行到这里
}
void performButtonAction() {
// 连接 WiFi 并发送 MQTT 消息
// 此函数将在 04-07 和 04-08 节中详细介绍
Serial.println("按键操作已执行");
}

并非所有 GPIO 都能从深度睡眠中唤醒 ESP32。XIAO ESP32-C3 上兼容的 RTC GPIO:

GPIORTC 唤醒兼容推荐用途
GPIO 0BOOT 按键(不推荐)
GPIO 1按键
GPIO 2按键(推荐)
GPIO 3按键
GPIO 4状态 LED
GPIO 5状态 LED

验证深度睡眠电流:

void setup() {
// ... 正常设置 ...
// 睡眠前测量和报告
Serial.println("--- 功耗报告 ---");
Serial.print("活跃电流:~60-80 mA(WiFi 开启)\n");
Serial.print("深度睡眠目标电流:< 10 µA\n");
Serial.println("--------------------");
delay(50);
esp_deep_sleep_start();
}

测量方法

  1. 将万用表设置为 µA 档位
  2. 断开电源
  3. 将万用表串联在电池正极和 XIAO VIN 之间
  4. 按下按键唤醒;观察活跃期间的电流
  5. 等待深度睡眠;读取万用表上的 µA 值
预期测量序列:
时间 0s: 唤醒 → 60-80 mA(WiFi 连接 + MQTT 发布)
时间 3-5s:操作完成 → 准备睡眠
时间 5s+: 深度睡眠 → ~5 µA
void maximizePowerSaving() {
// 睡眠前断开 WiFi(如果下次唤醒不需要)
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}

最重要的优化是最大限度地减少在活跃模式下的时间:

// 快速路径——最大限度地减少活跃模式下的延迟
void optimizedButtonAction() {
unsigned long startTime = millis();
connectWiFi(); // ~1-3 秒
publishMQTT(); // ~500ms
delay(10); // 让 MQTT 刷新
WiFi.disconnect(true);
Serial.print("活跃时间:");
Serial.print(millis() - startTime);
Serial.println(" ms");
// 立即深度睡眠——无不必要的延迟
}

为获得最小睡眠电流,配置按键引脚以避免悬空:

  • 内部上拉在大多数情况下已足够
  • 对于极低漏电,可添加一个 10kΩ 外部上拉电阻

XIAO 板载稳压器的静态电流约为 2-3 µA。该值已包含在总睡眠电流测量中,无法消除。

  • 深度睡眠电流 < 10 µA
  • 按键按下可靠唤醒设备
  • 活跃时间已最小化(每次按下 < 5 秒)
  • 操作后设备返回深度睡眠
  • 无按键按下时无自发唤醒

症状:睡眠电流 > 50 µA

可能原因

  • GPIO 悬空(未配置为 INPUT_PULLUP 或 OUTPUT)
  • 串口监视器启用(某些开发板保持 USB 激活)
  • 外部组件消耗电流
  • 电容漏电

解决方案

// 检查所有 GPIO 在睡眠前是否正确配置
gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_NUM_4, 0); // 设为 LOW 以最小化漏电
gpio_set_direction(GPIO_NUM_5, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_NUM_5, 0);

症状:设备处于深度睡眠状态,按键按下无反应

可能原因

  • 唤醒源使用的 GPIO 编号错误
  • 按键连接到了非 RTC GPIO
  • 电平配置相反(在 HIGH 而非 LOW 上唤醒)

解决方案:确认 GPIO 在 RTC 唤醒范围内,并使用以下代码测试:

// 临时使用定时器唤醒测试
esp_sleep_enable_timer_wakeup(10 * 1000000); // 每 10 秒唤醒一次
  • 最小化活跃时间——连接 WiFi、发布 MQTT、立即睡眠
  • 在进入深度睡眠前断开 WiFi
  • 使用 RTC GPIO 引脚作为唤醒源
  • 睡眠前添加串口刷新以确保输出完整
  • 除非必要,不要在 setup() 中使用 delay()
  • 避免不配置 GPIO 引脚
  1. 深度睡眠将电流降至约 5 µA——实现 100+ 天电池寿命的关键
  2. GPIO EXT0 唤醒允许按键按下立即唤醒 ESP32
  3. 最小化活跃时间是最关键的优化
  4. 定期电流测量验证功耗优化是否有效
  5. 进入深度睡眠前应禁用所有外设