跳转到内容

功耗优化

功耗优化

本节介绍优化电子纸显示项目功耗的详细技术。虽然深度睡眠提供了最大的节能效果,但几项额外的优化可以进一步将电池续航从数月延长到一年以上。完成本节后,你将能够:

  • 测量和分析 ESP32 + 电子纸系统的功耗预算
  • 对每个功耗域实施硬件和软件优化
  • 计算不同配置下的预期电池续航
  • 在功能和功耗之间做出权衡决策

开始本节前,请确保:

  • 理解深度睡眠配置(参见 02-08
  • 了解电池管理基础(参见 02-09
  • 可使用具有 µA 分辨率的万用表
ESP32 功耗分解
┌─────────────────────────────────────────────────────┐
│ 总功耗 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ │
│ │ WiFi 发送│ │ WiFi 接收│ │ CPU + 外设 │ │
│ │ ~200-260 │ │ ~100-130 │ │ ~20-50 mA │ │
│ │ mA │ │ mA │ │ │ │
│ └──────────┘ └──────────┘ └───────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ │
│ │ 电子纸 │ │ 电子纸 │ │ 深度睡眠 │ │
│ │ 刷新 │ │ 空闲 │ │ ~5-50 µA │ │
│ │ ~20-30mA │ │ ~0 µA │ │ │ │
│ └──────────┘ └──────────┘ └───────────────────┘ │
└─────────────────────────────────────────────────────┘

各状态的系统电流消耗

状态电流持续时间每周期能耗
WiFi 连接120 mA3 秒0.100 mAh
MQTT 数据交换80 mA1 秒0.022 mAh
显示刷新25 mA3 秒0.021 mAh
深度睡眠0.01 mA(10 µA)3593 秒0.010 mAh
每周期合计3600 秒0.153 mAh

显示刷新消耗的能量比 WiFi 连接还少! 优化 WiFi 连接时间对电池续航影响最大。

刷新间隔周期数/年能耗/年所需电池(1年目标)
每 30 分钟17,5202,680 mAh~3,000 mAh
每 1 小时8,7601,340 mAh~1,500 mAh
每 2 小时4,380670 mAh~800 mAh
每 6 小时1,460223 mAh~300 mAh
每 12 小时730112 mAh~150 mAh
每天一次36556 mAh~100 mAh

WiFi 连接是最大的能量消耗者。积极优化:

优化前(标准连接):

// ~5-8 秒,120 mA 平均
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}

优化后(快速连接):

// 减少连接尝试——不需要完美 RSSI
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
WiFi.setAutoReconnect(false);
WiFi.setSleep(WIFI_PS_MIN_MODEM); // 空闲时调制解调器睡眠
WiFi.begin(ssid, password);
// 5 秒后超时——稍后重试比耗尽电池更好
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 10) {
delay(500);
attempts++;
}
if (WiFi.status() != WL_CONNECTED) {
// 跳过此周期——使用缓存数据
Serial.println("WiFi 超时,跳过此周期");
goToSleep();
return;
}

优化要点:设置严格连接超时,跳过而非无限重试。

进入深度睡眠前,明确禁用所有外设:

void prepareForSleep() {
// 禁用 WiFi 硬件
client.disconnect();
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
// 关闭显示屏电源
display.powerOff(); // GxEPD2 方法
// 将所有 GPIO 设置为安全状态
pinMode(EPD_CS, INPUT_PULLDOWN);
pinMode(EPD_DC, INPUT_PULLDOWN);
pinMode(EPD_RST, INPUT_PULLDOWN);
// 如果不用于电池监测,禁用 ADC
// adc_power_off();
// 关闭蓝牙
btStop();
}
void goToSleep() {
prepareForSleep();
esp_sleep_enable_timer_wakeup(SLEEP_INTERVAL_US);
esp_deep_sleep_start();
}

优化显示更新序列:

void updateDisplayOptimized() {
unsigned long start = millis();
// 快速初始化——尽可能跳过完整上电序列
display.init(4000000, true, 10); // 更高 SPI 速度
// 如果可用,使用局部刷新(主要时间节省)
// 某些显示屏支持仅更新屏幕的一部分
// 最小化绘图操作
display.fillScreen(GxEPD_WHITE);
// 仅绘制最小内容
display.setFont(&FreeMonoBold12pt7b);
display.setCursor(5, 20);
display.print(temperature);
// 单次 display() 调用——不是多次
display.display();
unsigned long elapsed = millis() - start;
Serial.print("显示更新时间:");
Serial.print(elapsed);
Serial.println("ms");
}
GPIO 状态电流泄漏建议
高电平输出~0 µA✅ 用于 CS 取消选中
低电平输出~0 µA✅ 控制引脚安全
输入下拉~1 µA✅ 未使用引脚
输入浮空~10-50 µA❌ 避免——不可预测
// 休眠的安全 GPIO 配置
void configureGpioForSleep() {
const int pins[] = {5, 17, 16, 4, 23, 18}; // 所有使用的引脚
for (int pin : pins) {
gpio_set_direction((gpio_num_t)pin, GPIO_MODE_INPUT);
gpio_set_pull_mode((gpio_num_t)pin, GPIO_PULLDOWN_ONLY);
}
}

更高的 SPI 速度减少活动时间:

// 标准速度
display.init(115200); // ~115kHz SPI — 3-5 秒刷新
// 优化速度
display.init(4000000); // ~4MHz SPI — 1-2 秒刷新
// 最大安全速度(取决于接线质量)
display.init(8000000); // ~8MHz SPI — ~1 秒刷新(需要短线)

注意:非常高的 SPI 速度可能在长线缆下导致通信错误。在每个速度下测试稳定性。

电池性能在低温下降级。相应调整调度:

void configureSleepInterval() {
// 从传感器读取温度
float temp = readTemperature();
unsigned long sleepUs;
if (temp < 0) {
// 非常冷——电池降级,减少更新频率
sleepUs = 6 * 3600 * 1000000ULL; // 每 6 小时
} else if (temp < 10) {
// 冷——中度降级
sleepUs = 3 * 3600 * 1000000ULL; // 每 3 小时
} else {
// 正常温度
sleepUs = 1 * 3600 * 1000000ULL; // 每 1 小时
}
esp_sleep_enable_timer_wakeup(sleepUs);
}
void setup() {
// 1. 快速启动——无不必要的延迟
Serial.begin(115200);
// 2. 快速 WiFi 连接
WiFi.mode(WIFI_STA);
WiFi.setSleep(WIFI_PS_MIN_MODEM);
// 3. 带严格超时的连接
WiFi.begin(ssid, password);
unsigned long timeout = millis() + 5000;
while (WiFi.status() != WL_CONNECTED && millis() < timeout) {
delay(100); // 短延迟——不是 500ms
}
if (WiFi.status() == WL_CONNECTED) {
// 4. 快速 MQTT 交换
fetchAndDisplayData(); // 总共 ~2 秒
}
// 5. 干净关机
prepareForSleep();
// 6. 进入深度睡眠
esp_sleep_enable_timer_wakeup(SLEEP_INTERVAL_US);
esp_deep_sleep_start();
}
Terminal window
# 用万用表测量(串联连接)
# 1. 将万用表设置为 DC mA 档
# 2. 断开 USB 电源
# 3. 将万用表连接在电池和 ESP32 之间
# 4. 记录各阶段的值
# 睡眠模式下 µA 测量:
# 1. 切换到 µA 档
# 2. 确保 ESP32 已进入深度睡眠(等待 5 秒)
# 3. 记录稳定读数
典型结果(所有优化启用后):
活动阶段: ~120 mA 持续 ~5 (0.167 mAh)
睡眠阶段: ~10 µA 持续 3595 秒(0.010 mAh)
每周期总计: 0.177 mAh
每日: 4.25 mAh
电池续航: ~282 天(1200 mAh 电池)
  • 活动阶段时间低于 10 秒
  • 深度睡眠电流低于 50 µA
  • WiFi 在睡眠前正确断开
  • 即使快速启动,显示屏也能成功更新
  • 电池续航估算与实际测量相差在 20% 以内

问题 1:睡眠电流过高(>100 µA)

Section titled “问题 1:睡眠电流过高(>100 µA)”

症状

  • 电池消耗比预期快
  • 万用表显示睡眠时 >100 µA

检查清单

  • 任何外部外设在睡眠期间是否仍通电?
  • WiFi 是否完全禁用?(WiFi.mode(WIFI_OFF)
  • 所有 GPIO 是否处于安全状态?(无浮空输入)
  • 电压调节器是否已断电?
  • 电子纸显示屏电源是否关闭?(display.powerOff()

症状

  • 活动阶段 >15 秒
  • WiFi 连接时间 >5 秒

解决方案

  • 减少连接超时
  • 如果 WiFi 较慢,使用缓存数据
  • 提高显示刷新的 SPI 速度
  • 使用快速启动技术
技术节能工作量优先级
深度睡眠定时器~99.9%⭐⭐⭐
WiFi 超时(最长 5 秒)~50% WiFi 能耗⭐⭐⭐
睡眠前断开 WiFi~10 µA 节能⭐⭐⭐
GPIO 安全状态~10-50 µA⭐⭐
提高 SPI 速度~50% 显示时间⭐⭐
禁用蓝牙~20 mA(如果启用)⭐⭐⭐
降低 CPU 频率~10 mA 活动
  1. WiFi 连接主导活动功耗——首先优化连接时间
  2. 总活动时间应少于 5 秒以达到最佳电池续航
  3. 深度睡眠电流应低于 20 µA,配置正确
  4. 每微安都很重要——睡眠中 10 µA 的差异可以改变电池续航数周
  5. 启用所有优化后:1200 mAh 电池每小时更新可实现约 1 年电池续航