为什么 Deep Sleep 是物联网节点的核心

物联网节点(如传感器、追踪器)通常需要长时间待机,仅在特定时刻采集数据并发送。若让 ESP32 保持 Active 模式,电流高达 80~240mA,电池很快耗尽。而 Deep Sleep 模式下,CPU 和大多数外设关闭,仅保留 RTC 和部分 ULP 协处理器,电流可降至 10μA 左右,功耗降低数千倍。

ESP32 电源模式概览

  • Active:全速运行,电流 80~240mA(取决于 WiFi/蓝牙活动)
  • Modem Sleep:CPU 运行,WiFi/蓝牙关闭,电流约 3~8mA
  • Light Sleep:CPU 暂停,可被外设唤醒,电流约 0.8mA
  • Deep Sleep:CPU 和大部分 RAM 关闭,仅 RTC 和 ULP 工作,电流约 10μA
  • Hibernation:RTC 也关闭,仅保留唤醒引脚,电流约 2.5μA

对于周期性上报的节点,Deep Sleep 是最佳平衡点:既能保留 RTC 计时,又能通过 GPIO 或定时器唤醒。

Deep Sleep 的工作原理

进入 Deep Sleep 时,ESP32 会:

  1. 保存 RTC 内存(可保留少量数据,如状态变量)
  2. 关闭主系统时钟和大部分电源域
  3. 仅保留 RTC 定时器、ULP 协处理器(可选)和唤醒源检测电路

唤醒后,系统从复位向量重新启动,esp_sleep_get_wakeup_cause() 可判断唤醒原因。

定时唤醒:RTC Timer 配置

RTC 定时器基于内部 150kHz 振荡器,支持微秒级精度,最长可定时约 4 小时(若需更长,可多次循环或使用外部 RTC)。

配置步骤

  1. 初始化 NVS(非易失存储)——部分驱动需要
  2. 配置唤醒源:esp_sleep_enable_timer_wakeup(time_in_us)
  3. 可选:配置 GPIO 唤醒(如按键)
  4. 调用 esp_deep_sleep_start() 进入睡眠

完整代码示例:每 30 秒唤醒一次并打印唤醒原因

#include <stdio.h>
#include "esp_sleep.h"
#include "esp_log.h"
#include "nvs_flash.h"

#define WAKEUP_PERIOD_US  (30 * 1000000)  // 30 秒

static const char *TAG = "deep_sleep_demo";

void app_main(void) {
    // 初始化 NVS(部分外设需要)
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        nvs_flash_erase();
        nvs_flash_init();
    }

    // 获取唤醒原因
    esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
    switch (cause) {
        case ESP_SLEEP_WAKEUP_TIMER:
            ESP_LOGI(TAG, "唤醒原因:定时器");
            break;
        case ESP_SLEEP_WAKEUP_EXT0:
            ESP_LOGI(TAG, "唤醒原因:GPIO 外部触发");
            break;
        default:
            ESP_LOGI(TAG, "唤醒原因:上电/复位");
    }

    // 模拟传感器读取和上报(此处仅打印)
    ESP_LOGI(TAG, "采集数据并上报...");

    // 配置定时唤醒
    ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(WAKEUP_PERIOD_US));

    // 可选:配置 GPIO 唤醒(例如 GPIO0 低电平触发)
    // esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0);

    // 进入 Deep Sleep
    ESP_LOGI(TAG, "进入 Deep Sleep,%d 秒后唤醒\n", WAKEUP_PERIOD_US / 1000000);
    esp_deep_sleep_start();
}

代码说明

  • esp_sleep_enable_timer_wakeup() 参数为微秒,可用 us 常量或计算得出
  • 唤醒后程序从头执行,因此需在 app_main 中判断唤醒源
  • 打印日志使用 ESP_LOGI,但注意串口输出会增加功耗,实际产品中建议关闭日志

降低功耗的额外技巧

  • 关闭未用的外设:进入 Deep Sleep 前,调用 esp_wifi_stop()esp_bluedroid_disable() 等关闭 WiFi/蓝牙
  • 设置 GPIO 为低功耗状态:将未使用的 GPIO 配置为下拉或悬空,避免漏电流
  • 使用 ULP 协处理器:在 Deep Sleep 期间,ULP 可执行简单传感器读取,仅在需要时唤醒主 CPU
  • 优化唤醒周期:根据业务需求调整定时周期,避免频繁唤醒
  • 测量实际功耗:使用功耗分析仪(如 Nordic PPK)验证,注意不同开发板(如官方 DevKit 的 USB 转串口芯片会额外耗电)

注意事项

  • RTC 内存:Deep Sleep 期间,普通 RAM 数据丢失,若需保留数据,使用 RTC_DATA_ATTR 修饰变量
  • 定时器精度:RTC 振荡器受温度影响,长时间定时可能漂移,若需高精度可外接 32.768kHz 晶振
  • 唤醒后初始化:每次唤醒后,外设(如 ADC、I2C)需重新初始化
  • 电源电压:Deep Sleep 电流与供电电压相关,3.3V 时约 10μA,2.5V 时可降至 5μA 以下
  • 开发板差异:部分开发板(如 NodeMCU)带有电源 LED 和稳压器,会增加静态电流,量产时需设计最小系统

总结

ESP32 的 Deep Sleep 模式为物联网节点提供了极低功耗的解决方案。通过合理配置定时唤醒和外部触发,开发者可以轻松实现电池供电的长期运行。本文的示例代码可直接用于项目原型,但实际产品还需结合 ULP、电源管理和硬件设计进一步优化。掌握这些技术,你就能设计出续航以年计的智能传感器节点。