“节能不是让设备少做事,而是让它只在需要的时候才全力工作。”手机一天一充,你可能已经习惯了。但一个阅读器如果也一天一充,那它和手机有什么区别?续航是电子书阅读器最核心的体验指标之一——Kindle 号称可以续航数周,CrossPoint Reader 靠着一块 1000~2000mAh 的小电池,也要尽可能撑得久。 这一章我们来拆解 CrossPoint Reader 的电源管理策略:怎么在”干活”和”省电”之间找到最佳平衡。
13.1 为什么电源管理重要
先算一笔账。ESP32-C3 全速运行时的功耗约 150mA,假设电池容量为 1500mAh:13.2 CPU 动态调频
ESP32-C3 的 CPU 主频可以在运行时动态调整。CrossPoint Reader 利用这一点实现了自动降频:降频时机
回忆第 7 章介绍的主循环:为什么 WiFi 开着不能降频
代码的第一行就检查了 WiFi 状态:WiFi 开着时,强制enabled = false,不允许降频。
原因在于 WiFi 协议栈对时序有严格要求。WiFi 通信需要在精确的时间窗口内完成数据包的收发、加密解密、信道切换等操作。如果 CPU 降到 10MHz,这些操作可能来不及完成,导致 WiFi 连接不稳定甚至断开。
类比:降频就像把机场跑道从”高速运转”切换到”低速维护”模式。如果跑道上没有飞机(没有 WiFi 通信),低速模式没问题。但如果有飞机在起降(WiFi 正在工作),就必须保持高速运转,否则会出事故。
13.3 电池电量检测
用户需要知道”还剩多少电”。CrossPoint Reader 的 X3 和 X4 两个硬件版本用了完全不同的方案来检测电量:两种方案对比
| 方案 | X4:ADC 直读电压 | X3:I2C 电量计 (BQ27220) |
|---|---|---|
| 原理 | 用 ADC 读电池引脚的模拟电压,再根据电压-电量曲线换算百分比 | 芯片内部持续追踪充放电电流,通过库仑计算精确计算剩余容量 |
| 精度 | 较低(电压和电量不是线性关系,中间段特别平坦) | 高(直接追踪进出的电荷量) |
| 成本 | 几乎为零(GPIO 引脚自带 ADC) | 需要额外芯片(BQ27220 约几元) |
| 难点 | 需要校准电压曲线,受温度影响大 | 初始化配置比较复杂 |
类比:ADC 方案就像通过看油箱浮标来估算剩余油量——便宜但不精确,尤其是油量在中间水位时浮标几乎不动。I2C 电量计方案就像用流量计记录每一滴进出的油——精确但需要额外硬件。
13.4 深度睡眠:真正的省电杀招
降频可以把功耗从 ~150mA 降到 ~15mA,但对于一个可能几小时不被使用的设备来说,这还不够。CrossPoint Reader 的终极省电手段是深度睡眠(Deep Sleep)——直接关掉 CPU。进入深度睡眠的完整流程
- 保存状态:睡眠前把当前的阅读进度、设置等信息写到 SD 卡。因为深度睡眠后 RAM 会清零,所有运行时数据都会丢失。
- 渲染睡眠画面:在墨水屏上画一个”已关机”的画面。还记得第 5 章讲的墨水屏双稳态特性吗?断电后画面会一直保持,所以用户看到的是一个静态的关机画面,而不是黑屏。
- MCU 关机:CPU 完全停止运行。
硬件层面的深度睡眠
gpio_hold_en 确保在深度睡眠期间 GPIO13 的电平保持不变——否则 CPU 停止后引脚可能会浮空,MOSFET 状态不确定。
第三,设置唤醒源并进入睡眠。 esp_deep_sleep_start() 之后,CPU 完全停止运行。只有 RTC(Real-Time Clock)模块还在工作,它消耗的电流只有微安级别。当用户按下电源键时,RTC 检测到 GPIO 电平变化,重新启动 CPU——注意,这不是”恢复”,而是从头开始执行 setup() 函数,就像第一次开机一样。
深度睡眠 vs 普通 delay
setup() 执行,之前的变量、任务状态全部丢失,需要从 SD 卡重新加载。
13.5 开机流程与防误触
既然唤醒后从setup() 开始,固件需要区分”第一次开机”和”从睡眠中唤醒”:
为什么需要验证长按
想象设备放在口袋里。口袋里的钥匙或其他物品可能会意外碰到电源键。如果碰一下就开机,设备会白白消耗电量——更糟糕的是,可能会频繁地开机、超时、再睡眠,反复折腾。verifyPowerButtonWakeup 的逻辑是:被唤醒后,先不急着启动,而是持续检测电源键是否仍然被按住。只有当按住时间超过设定阈值(比如 1 秒),才真正完成开机流程。如果用户只是短按了一下就松开了——对不起,回去继续睡。
USB 供电的特殊情况
当用户插入 USB 充电线时,设备会被通电启动(冷启动)。但用户插充电线可能只是想充电,并不想使用设备。所以AfterUSBPower 分支的处理是:直接进入深度睡眠。设备在睡眠状态下也能充电,不需要开机。
13.6 PowerLock:RAII 防降频
第 7 章介绍过 RAII 锁模式。电源管理中也有一把类似的锁——HalPowerManager::Lock:
PowerLock 在构造时通知电源管理器”现在不能降频”,在析构时解除限制。这样只要刷屏操作还没完成,CPU 就不会被降频——渲染结束后锁自动释放,CPU 又可以回到省电模式。
RenderLock 内部其实嵌套了 PowerLock,所以每次获取渲染锁时都自动保证了 CPU 全速,不需要手动操心。
13.7 功耗预算估算
有了以上所有优化手段,我们可以算一笔完整的功耗账:本章要点
- 电源管理的核心思路:按需供电。CPU 在空闲时降频(160MHz -> 10MHz),在不用时彻底关机(深度睡眠),只在需要干活时才全速运行。
- 动态调频:3 秒无操作自动降到 10MHz,功耗降低约 10 倍。WiFi 开着时不能降频,因为协议栈依赖高频时钟。
- 电池检测的两种方案:ADC 读电压(便宜但不精确)和 I2C 电量计(精确但要额外芯片)。CrossPoint Reader 在 X3 和 X4 上分别采用了这两种方案。
- 深度睡眠:CPU 完全停止,通过 MOSFET 物理切断外设供电,功耗低至微安级别。代价是醒来后从
setup()重新开始,需要从存储中恢复状态。 - 防误触机制:唤醒后验证电源键长按时长,短按直接回去睡。USB 供电导致的冷启动也直接进入睡眠。
- PowerLock(RAII):防止在 SPI 通信(刷屏)期间 CPU 被降频,确保时序正确。
下一章预告:第 14 章我们将看看固件发布后的生命——用户怎么通过 WiFi 在线升级固件?如果新固件有 bug 导致崩溃怎么办?双分区安全网和崩溃捕获机制是怎么确保设备”不变砖”的。