《ESP32 物联网全栈实战-09》低功耗设计
·
第 9 篇:低功耗设计——18650 电池如何续航 3 个月
插座类设备插着电能活,但温湿度传感器、门磁、人体感应这些设备只能靠电池。ESP32 吃电大户,怎么让它省着吃?这篇教你把功耗从 80mA 压到 μA 级。
1. ESP32 各模式功耗实测
| 模式 | 功耗(ESP32-C3) | CPU | WiFi | BLE | 唤醒后状态 |
|---|---|---|---|---|---|
| Active (WiFi TX) | ~80mA | 全速 | 发射 | 关 | - |
| Active (接收) | ~50mA | 全速 | 接收 | 关 | - |
| Modem Sleep | ~3mA | 运行 | 间歇唤醒 | 关 | 保持 |
| Light Sleep | ~0.8mA | 停 | 关 | 关 | RAM 保持 |
| Deep Sleep | ~5μA | 停 | 关 | 关 | 仅 RTC 保持 |
从 80mA → 5μA,差了 16000 倍。 关键在于:大部分时间让 ESP32 沉睡,需要时才醒来。
2. Deep Sleep 工作模式
时间线(周期 60 秒):
0s 1s 2s 5s 60s 61s
│ 醒来 │ WiFi连接 │ 读传感器+发MQTT │ 沉睡 │ 醒来 │
│ │ │ │ │ │
├──────┼──────────┼─────────────────┼───────┼───────┤
│80mA │ 80mA │ 80mA │ 5μA │ 80mA │
平均功耗 ≈ (80mA × 5s + 5μA × 55s) / 60s ≈ 6.7mA
2000mAh 电池续航 ≈ 2000 / 6.7 ≈ 298 小时 ≈ 12 天
3. 优化——从 12 天到 90 天
上面的方案只能撑 12 天,离 3 个月差得远。优化措施:
优化 1:减少 WiFi 连接时间
WiFi 连接是最大的耗电环节(5 秒中占了 4 秒)。ESP32 支持保存 PHY 校准数据:
// 首次连 WiFi 后保存 PHY 校准数据到 NVS
// 后续唤醒直接用,省去扫描信道的 2-3 秒
esp_wifi_set_storage(WIFI_STORAGE_FLASH);
优化后:WiFi 连接从 4s → 1.5s。
优化 2:增大上报间隔
60 秒 → 300 秒(5 分钟):
平均功耗 ≈ (80mA × 2.5s + 5μA × 297.5s) / 300s ≈ 0.67mA
续航 ≈ 2000 / 0.67 ≈ 2985 小时 ≈ 124 天 ≈ 4 个月 ✅
优化 3:用 ESP-NOW 替代 WiFi
如果不需要连互联网,只是把数据传到室内的网关(树莓派/另一块 ESP32),用 ESP-NOW 替代 WiFi:
- ESP-NOW 连接:<100ms(WiFi 要 1-4s)
- 无需 DHCP、DNS、TCP 握手
4. Deep Sleep 完整代码
#include "esp_sleep.h"
#include "esp_wifi.h"
#include "driver/rtc_io.h"
#define SLEEP_SECONDS 300 // 5 分钟醒来一次
RTC_DATA_ATTR static int boot_count = 0; // 睡醒次数(RTC 内存保持)
void app_main(void) {
boot_count++;
ESP_LOGI("WAKE", "第 %d 次醒来", boot_count);
// 1. 初始化 NVS(必须在 WiFi 之前)
nvs_flash_init();
// 2. 连接 WiFi
wifi_init_sta_fast(); // 快速连接模式
// 3. 连 MQTT → 读传感器 → 上报
mqtt_app_start();
float temp, humi;
sht30_read(&temp, &humi);
char payload[64];
snprintf(payload, sizeof(payload),
"{\"t\":%.1f,\"h\":%.1f,\"boot\":%d}", temp, humi, boot_count);
esp_mqtt_client_publish(mqtt_client, "sensor/bedroom", payload, 0, 1, 0);
// 4. 等待 MQTT 发送完毕(QoS 1 需要等 ACK)
vTaskDelay(pdMS_TO_TICKS(2000));
// 5. 断电前清理
esp_mqtt_client_stop(mqtt_client);
esp_mqtt_client_destroy(mqtt_client);
esp_wifi_stop();
esp_wifi_deinit();
// 6. 设置定时唤醒 + 进入 Deep Sleep
ESP_LOGI("SLEEP", "进入深度睡眠,%d 秒后醒来", SLEEP_SECONDS);
esp_sleep_enable_timer_wakeup(SLEEP_SECONDS * 1000000ULL);
esp_deep_sleep_start();
// ← 这行之后,CPU 完全断电,醒来时从 app_main 重新开始
}
5. GPIO 唤醒——需要立即响应时
温湿度可以定时上报,但门磁不行——门一开必须立刻通知。
// 用 GPIO 唤醒 Deep Sleep
// GPIO_NUM_4 接门磁传感器(磁铁靠近=高电平,移开=低电平)
esp_sleep_enable_ext0_wakeup(GPIO_NUM_4, 0); // 低电平唤醒
// 醒来后检查是哪种唤醒源
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
if (cause == ESP_SLEEP_WAKEUP_EXT0) {
ESP_LOGI("WAKE", "门磁触发!有人在开门");
// 立即连 WiFi 发告警
}
功耗:外部 GPIO 唤醒几乎不增加功耗(RTC GPIO 在 Deep Sleep 时仍在监听)。
6. 低功耗设计 Checklist
| 检查项 | 方法 |
|---|---|
| 用 Deep Sleep 而非 Light Sleep | esp_deep_sleep_start() |
| WiFi 连上就发,发完就断 | 不要保持长连接 |
| 保存 PHY 校准数据 | esp_wifi_set_storage(WIFI_STORAGE_FLASH) |
| 关闭不用的外设 | I2C/SPI 在读写完后 driver_uninstall |
| 降低 CPU 频率 | esp_pm_configure 最低到 40MHz |
| 外设供电用 GPIO 控制 | SHT30 的 VCC 接 GPIO → 不读时完全断电 |
| 减少 LED 闪烁 | 每 LED 灯耗电 2-5mA |
传感器独立供电的技巧:
// SHT30 的 VCC 不接 3.3V,接 GPIO5
gpio_set_direction(GPIO_NUM_5, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_NUM_5, 1); // 给传感器上电
vTaskDelay(pdMS_TO_TICKS(100)); // 等传感器稳定
sht30_read(&t, &h); // 读取
gpio_set_level(GPIO_NUM_5, 0); // 传感器完全断电 → 省 0.5mA
下一篇:微信小程序入门——用 WebSocket 连接 MQTT,手机上看温湿度
更多推荐


所有评论(0)