我前阵子做的一个便携式带屏设备,最头疼的不是功能逻辑怎么写,而是“电”本身。锂电池充放电管理、系统多路供电、待机功耗压到能扛住一周,再加上充电安全保护,这些问题堆在一起,靠几个7805和稳压管根本扛不住。后来我把整条电源链路重新捋了一遍,主控换成 STM32F100ZE,电源部分交给 PCA9422 这颗专门做电池管理的 PMIC,才算是把“能跑”变成了“能真正交付”。这篇文章就把这套组合的完整实现过程、寄存器初始化、状态机设计、实测数据,以及我踩过的三个坑,一次性讲清楚。
1. 选型逻辑链:为什么是 PCA9422 + STM32F100ZE
很多人一听到电源管理,第一反应是用一颗专门的电源管理芯片,或者直接用带DCDC和LDO的PMIC,主控随便挂一颗低功耗单片机就行。这个思路本身没错,但实际做过设备的人都知道,PMIC 和主控之间的配合远比“上电就能用”复杂。我之所以选 PCA9422 和 STM32F100ZE 这套组合,核心逻辑有三层:功能覆盖、成本匹配、以及软件可控性。
1.1 电源管理在便携设备里到底管什么
便携设备看着简单,拆开一看全是供电问题。一颗锂电池供电,系统里往往需要好几个电压轨:核心逻辑 3.3V、传感器或接口 1.8V、射频或蜂鸣器可能还要单独的 3.0V,特殊场景下甚至要临时升出 5V 来驱动外部模块。这还没算充电链路,USB 插入时得按涓流、恒流、恒压三个阶段给电池充电,充电过程还得监测电池温度。
如果用分立方案搞,充电管理至少要一个充电IC,降压要一个DCDC,再配一个LDO,保护电路还得自己用分立运放搭。这样搞出来的板子面积大、器件多、调试麻烦,而且很多保护功能根本做不全。PCA9422 这类集成PMIC 的优势就在这里体现出来了:它把线性充电、升压输出、两路LDO、电池电压监测、温度监测、过压欠压保护全部集中在一颗小封装里,而且所有配置都通过 I2C 控制,软件可以随时把某个输出轨关掉,这对低功耗设计来说是决定性的。
1.2 F100ZE 的定位:够用且能省的地方都要省
选 STM32F100ZE 而不是 STM32F103ZE,预算是一个原因,但更关键的是匹配。电源管理这个场景对算力要求很低,I2C 通信频率 100kHz 到 400kHz 足以胜任,Cortex-M3 的内核即便跑在 24MHz 也非常富裕。F100 系列本身就定位在“高性价比 Value line”,主频 72MHz,外设资源也很全面。ZE 后缀代表 144 脚封装,512KB Flash、64KB RAM,这在跑个小状态机加电池算法时绰绰有余。
有人会质疑,既然要低功耗,为什么不选 M0+ 或者专门的低功耗 MCU?我的判断是,便携设备往往还要兼顾显示按键、通信、日志存储这些功能,M0+ 做复杂状态切换会吃力,而 STM32F100 在 Stop 模式下也能把电流压到微安级。只要把无关外设时钟全部关闭,让 PCA9422 在空载时也进入低功耗模式,整机待机做到几十微安并不难。成本上,F100ZE 比同容量的 F103ZE 便宜一截,在“功能刚好够+待机够低+省预算”这三个维度上,它的得分是比专用低功耗芯片更综合的。
1.3 整套系统的拓扑关系
这块板子的电源拓扑不复杂,但角色划分非常清晰。电池是唯一能量来源,PCA9422 负责所有电能转换和充放电管理,输出四路电源轨给系统;STM32F100ZE 是唯一的控制大脑,通过 I2C 总线读取 PCA9422 的状态寄存器、写入配置寄存器、响应中断。主控自己本身也挂在 PCA9422 的一路输出上,这样即使电池电压波动,MCU 供电也是稳定的。
整个链路的可信度完全取决于两件事:PCA9422 的寄存器配置是否正确,以及 MCU 的电源状态机是否把每一个异常路径都覆盖到了。前者是硬件层面的数据库,后者是软件层面的控制逻辑,缺一不可。这就是我为什么坚持在项目里自己写 PMIC 驱动,而不是简单套一个厂商示例代码的原因——示例代码只会演示正常流程,真正交付时你面对的全是异常路径。
2. 电源树与硬件设计:每一颗外围都值得较真
硬件设计阶段是最容易“想当然”的环节。很多人拿到 PMIC,照着参考设计把电路画完就扔给 PCB 工程师了,结果样机回来不是纹波大就是充电不稳。其实 PMIC 外围器件数量确实不多,但每一颗电容、每一个电阻的位置和参数都有讲究。
2.1 四路输出怎么分配
我这块板的电源树是这么规划的:PCA9422 的 SYS 输出接到电池正极端,因为 PMIC 内部有路径管理,USB 插入时系统优先用外部输入供电,同时给电池充电,拔掉 USB 后自动切换到电池供电。系统主供电轨从 SYS 出来经过一个 DCDC 降压到 3.3V,专门给 MCU、显示和数字逻辑。LDO1 输出 1.8V 给传感器和 SD 卡,LDO2 输出 3.0V 给无线模块的 IO 电平参考。Boost 输出则是在需要 5V 时才打开,比如驱动一个小型加热片或者给外部 USB 设备短暂供电。
| 输出轨 | 电压 | 峰值电流 | 用途 |
|---|---|---|---|
| SYS | 电池电压范围 | 系统总电流 | 路径管理、系统主输入 |
| DCDC | 3.3V | 500mA | MCU、显示屏、数字逻辑 |
| LDO1 | 1.8V | 150mA | 传感器、存储卡 |
| LDO2 | 3.0V | 150mA | 无线模块IO参考 |
| Boost | 5.0V | 200mA | 临时外设供电 |
分配的原则很简单:大电流、纹波敏感的数字电路走 DCDC;模拟前端和低噪声敏感部分走 LDO;不常用的高压需求单独用 Boost 并在软件里做到“用时才开”。这套分配在实测中表现不错,数字电路纹波峰值大概 20mV,模拟部分干净得多。
2.2 PCA9422 外围器件的选型细节
数据手册里的参考设计不会告诉你每颗电容的价值,得自己根据负载动态来定。SYS 入口的输入电容我放了 22µF 陶瓷电容加一颗 0.1µF 高频去耦,这个组合能扛住系统瞬时大电流。DCDC 输出的电感选了饱和电流至少是最大负载 1.5 倍的型号,同时注意电感 DCR 不能太大,否则重载效率掉得厉害。
电池 NTC 这根线容易被忽略。PCA9422 支持电池温度监测,NTC 采样分压电阻直接决定了充电温度窗口。我用的是 10kΩ NTC,上拉电阻取 10kΩ,在 0 到 45 度区间内电压范围刚好落进芯片的比较窗口。如果你把上拉电阻换大,温度阈值会漂,极端情况下充电会在室温直接被判停。这个参数最好根据你实际电池的热敏电阻规格反算一遍。
中断脚 INT 必须接到 STM32F100ZE 的一个 EXTI 引脚上,这样电池电压进入警告区、充电完成、输入插拔这些事情都能以硬件中断的方式通知 MCU。如果只靠 I2C 轮询,反应速度既慢又浪费 MCU 时间。
2.3 与 STM32F100ZE 的电气连接
PCA9422 和 F100ZE 之间的 I2C 总线,SCL 和 SDA 都需要上拉电阻,我选用 4.7kΩ 上拉到 3.3V。因为 F100ZE 的 IO 电平就是 3.3V,PMIC 的 I2C 电平也支持 3.3V,所以直接连没有风险。注意上拉电阻别太小,否则总线高电平被拉偏,也别太大,否则频率跑高时上升沿跟不上。
这里有个经验:I2C 总线上如果还有其他设备,最好把 PMIC 放在靠近 MCU 的一侧,走线短而直。我曾经因为把 PMIC 挂在总线末端、中间又穿过一个连接器,结果负载切换瞬间总线出现毛刺,把通信时序打乱了。这个问题到后面调试阶段才暴露,浪费了不少时间。PCA9422 的多个使能脚和电源按键引脚,我各串了一个 1kΩ 电阻到 GPIO,防止上电瞬间 IO 处于不确定状态时误触发。
3. 底层驱动与初始化:把 PMIC 的寄存器“讲”清楚
硬件是骨架,软件才是让 PMIC 动起来的关键。PCA9422 的所有行为都挂在寄存器上,上电默认状态、充电电流、输出电压、保护阈值全部靠 I2C 写进去。这块驱动写好了,后面的状态机就是水到渠成的事。
3.1 I2C 驱动封装:寄存器读写要稳、要快
F100ZE 的硬件 I2C 在低速标准模式下很稳,我就直接用硬件外设,时钟配置成 100kHz。这里不建议为了“看起来快”去跑 400kHz,PMIC 的 I2C 接口本身可能支持,但线长了、板子有干扰时容易出问题。驱动封装成两组函数就够了:
uint8_t pmic_read_reg(uint8_t reg); void pmic_write_reg(uint8_t reg, uint8_t val); void pmic_update_bits(uint8_t reg, uint8_t mask, uint8_t val);关键在于pmic_update_bits,配置寄存器往往一个字节里同时管着好几个功能,直接写整个字节容易把别的位搞乱。比如控制 Boost 使能的那一位和 Boost 电压选择位在同一寄存器里,用读-改-写的方式才能保证不出错。
I2C 通信必须带超时和重试。PMIC 在极端负载切换时可能暂时拉低总线,MCU 如果一直死等,整个系统就卡死了。我在每个读写的 while 等待里都加了超时计数,超过一定次数就释放总线、延时、重新初始化 I2C 外设。
3.2 上电初始化序列:每一步都得有先后顺序
初始化顺序不能乱,这是我从第一次样机调试就记住的教训。PCA9422 上电后默认状态是“系统输出跟随输入源”,也就是说如果有电池,SYS 就有电,但 DCDC、LDO、Boost 默认都是关闭的。如果 MCU 一上来就去读各种状态寄存器,数据可能全是对的,但一写不存在的配置就会触发错误。
我按以下顺序走:
- 读取设备 ID 寄存器,确认 I2C 通信建立,这个步骤能过滤掉一大批硬件连接问题。
- 把看门狗和所有中断源清零,避免上电瞬间的毛刺产生误中断。
- 配置 DCDC 输出电压为 3.3V,启动 DCDC,等待输出稳定标志置位。
- 配置 LDO1、LDO2 输出电压并启动。
- 配置充电参数:涓流电流、恒流电流、截止电压、充电温度窗口。
- 设置电池电压监测阈值,开启低压告警中断。
- 最后才把系统级的全局中断使能打开。
初始化函数执行完,PCA9422 才真正进入可工作状态。这里每一步之后最好加一个回读校验,我用的是读同一个寄存器比对,不一致就重写一次,两次不一致就上报错误。虽然 PMIC 正常情况不会这么脆弱,但在样机阶段这个校验帮我抓到了两处虚焊问题。
3.3 关键寄存器配置表与两种工作模式
我把核心配置整理成一张表,每个配置项都标注了作用,方便对着手册核对。这张表在评审和排查时特别有用,不用每次都在 100 多个寄存器里翻。
| 配置项 | 寄存器作用 | 我设的值 | 说明 |
|---|---|---|---|
| 充电恒流 | 充电电流上限 | 300mA | 根据电池容量 1000mAh 取 0.3C |
| 充电截止电压 | 恒压阶段电压 | 4.2V | 常规锂电池满电电压 |
| DCDC 输出电压 | 主电源轨 | 3.3V | 给 MCU 与数字部分 |
| LDO1 输出电压 | 传感器供电 | 1.8V | 低噪声模拟轨 |
| 电池低压告警 | 阈值 | 3.6V | 提前提醒用户充电 |
| 系统关机电压 | 强制关断 | 3.0V | 防止过放 |
| Boost 输出 | 临时 5V | 5.0V | 默认关闭,用时开启 |
轮询和中断这两种模式我都用过。样机调试阶段用轮询,每 500ms 读一次状态,方便通过调试器盯着变化;到正式版本必须切到中断驱动,MCU 平时停在 Stop 模式,只有 PMIC 的 INT 脚拉低才唤醒。两者的核心逻辑一模一样,只是“什么时候去读寄存器”的策略不同。
4. 电源状态机与低功耗:设备的四种角色切换
PMIC 配置完之后,真正的灵魂在于 MCU 里跑的电源状态机。同一块板子,在充电、满电待机、唤醒工作、深度关机这四种状态下,应该像完全不同的一套系统。电源状态机要回答的问题就是:我现在处于哪个状态,什么时候切到哪个状态,每个状态里哪些外设该断电。
4.1 设备级状态机的设计与迁移条件
我的状态机分五态:上电初始化态(BOOT)、正常工作态(ACTIVE)、轻度休眠态(SLEEP)、充电等待态(CHARGING)、深度关机态(SHUTDOWN)。每个状态对应 PMIC 不同的输出轨组合和 MCU 自身的工作模式。
迁移条件完全由事件驱动:电池电压过低进入低压告警,屏幕亮度下调并提示用户;电压继续跌到关机阈值,MCU 记录关键数据后主动通知 PMIC 关断所有输出,进入深度关机态;VBUS 插入则无论当前什么状态,都有最高优先级——先切换到充电态,再判断要不要唤醒系统。
状态机里我特别看重“每个状态进入时做一次电源轨重配置”这个动作。比如从 ACTIVE 进 SLEEP,MCU 先把外设时钟关了,再把 LDO2 关掉,然后才执行 WFI 指令。如果顺序反了,可能出现外设还在工作、供电却断了的情况,轻则数据错误,重则损坏器件。
4.2 电池电量监测:别只看电压
电量监测这块,我没有上专用的电量计芯片,因为 F100ZE 自带 12 位 ADC,加上 PCA9422 内部的电池电压监测功能,已经能满足精度需求。做法是:每 10 秒唤醒一次 ADC,采样电池电压做均值滤波,再把结果喂给一阶低通滤波,最后映射到电量百分比。
只测电压有个天然问题,空载电压和带载电压能差 0.3V 甚至更多,如果系统正在跑无线通信,按电压查表会得出“电池快没电了”的错误结论。我的处理方式是把 ADC 采样安排在系统休眠的稳定期,并且每次采样前先让 DCDC 停止大动态负载 10ms 再读取,这样拿到的电压接近开路电压,查表才有意义。
我还加了一个迟滞窗口,电压 3.7V 才从“低电量”状态恢复成“正常”,避免在 3.65V 附近反复抖动。这个细节如果不做,屏幕的低电量弹窗会像呼吸灯一样来回跳。
4.3 低功耗实测和优化顺序
整机待机电流是逐项抠出来的。第一次实测待机是 700µA 左右,这在一颗 1000mAh 电池下理论上能待 60 天,看着还行,但拆解后发现大头全在无关外设上:GPIO 悬空、ADC 没有关闭、LDO2 还在给一个不工作的传感器供电。
把 F100ZE 切进 Stop 模式前,我严格按照这个顺序处理:关闭所有复用时钟、把所有未用 GPIO 配成 analog 模式、关闭 ADC 和定时器、切断 I2C 外设时钟、把 LDO2 关掉,最后才进入 Stop。这一套操作下来,整机待机电流从 700µA 降到了 80µA 左右,电池能用一年。Stop 模式的唤醒源我留了两个:一个是 RTC 闹钟,负责周期性地起来采电压做记录;另一个就是 PCA9422 的 INT 中断,负责响应充电插入和低压告警。
5. 实测数据与三个差点让我推翻方案的坑
软件写完、样机到手,真正的麻烦才开始。电源管理这种模块,平时不出问题,一出问题就是系统级的。下面这几个问题,有的查了整整两天,有的差点让我怀疑芯片选型,记录一下完整的排查链路。
5.1 功耗与充放电实测
电池容量 1000mAh,充满电后跑实测工作循环,结果稳定在这个水平:
| 工作状态 | 电流功耗 | 场景说明 |
|---|---|---|
| 深度关机 | 15µA | PMIC 全输出关断,MCU 停振 |
| 待机(Stop) | 80µA | RTC 运行,等待唤醒 |
| 轻度工作 | 25mA | 屏幕刷新、传感器采样 |
| 满载运行 | 180mA | 无线通信发射 |
| 充电(输入侧) | 420mA | 300mA 充电电流加系统功耗 |
实测下来的续航表现:日常使用大概 12 个小时,纯待机能超过一年。这个结果已经能覆盖目标产品的使用场景了。充电曲线我也抓了,从 3.0V 开始充,CC 阶段电流恒定 300mA,电压爬到 4.2V 后切 CV,电流慢慢降到 30mA 判定充满,全程约 3 小时 40 分钟,跟理论值吻合。
5.2 坑一:I2C 偶发卡死,总线 SDA 被拉低
现象很恶心,系统运行一阵子后突然读不到 PMIC 寄存器,逻辑分析仪抓到的波形是 SDA 一直为低,MCU 侧报忙。这个坑查了差不多一天,一开始怀疑上拉电阻不够强,换成 2.2kΩ 没解决;又怀疑是 PMIC 从机状态机被打乱,但无法稳定复现。
我用示波器同时抓 SCL/SDA 和 SYS 电压,终于发现规律:每次总线卡死都发生在无线模块发射的瞬间,SYS 电压有一串毛刺,会顺着地平面和电源平面耦合到 I2C 线上。这是典型的噪声干扰时序问题。解决措施有两层:硬件上把 I2C 走线改成包地处理,并且在线路里预留了 100pF 对地电容衰减毛刺;软件上把 I2C 时钟降到 100kHz 且给每次通信加了超时和总线恢复流程——检测到总线忙超过 2ms 就用 GPIO 手动拉 9 个时钟脉冲复位从机。这个组合拳打完后,再也没复现过。
5.3 坑二:插上 USB 充电,系统直接复位重启
这个问题一出来,我第一反应是 DCDC 输入崩溃。看波形果然,VBUS 插入瞬间,输入电压有一个很大的跌落,SYS 电压跟着塌到 MCU 的复位阈值以下,然后整个系统重启。根因是 PC 的 USB 口输出能力有限,而 PCA9422 内部路径管理在 VBUS 刚插入时瞬间把输入拉到大电流,输入侧又没有足够的储能电容。
排查确认后,我在 VBUS 输入路径上加了一个缓启动设计,并且调整了寄存器里的输入电流限制,让充电电流缓慢爬升而不是瞬间达到 300mA。又输入侧并了一颗 10µF 电容吸收浪涌。现在热插拔 USB 的时候系统纹丝不动,充电状态指示正常切换。
5.4 坑三:电池深度放电后插充电器不工作
这是最阴间的一个问题。电池电压放到 2.8V 以下,插上充电器,整机没有任何反应,LED 不亮,PMIC 像一个死芯片。一开始我以为是充电器坏了,后来发现 PCA9422 内部有电池深度放电保护,电池电压太低时其内部某些功能会自我锁死,必须满足特定条件才能唤醒。
解决办法有两个路径。一是通过 PMIC 的强制复位引脚,在检测到 VBUS 插入后主动触发一次软复位,让 PMIC 重新进入初始化状态;二是在系统关机时不要把电池彻底放空,低压告警触发后尽早让用户充电。我两个都做了,软件上把关机电压阈值提到 3.0V,硬件上把复位引脚引到了 MCU 的一个 GPIO,确保任何时候插入充电器,MCU 都能拉着 PMIC 做一次强制重启。
5.5 硬件设计上的其他提醒
PCB 布局上,PMIC 周边的地回路要特别注意。DCDC 开关节点、电感、输出电容这块必须是一个紧致的小环路,环路面积大了,EMI 和纹波双双超标。我第一版 PCB 就是滤波电容距离芯片太远,结果带载纹波多了 40mV。电池连接器到 PMIC 的走线也尽量加宽,至少 1mm,电池瞬间大电流时这条线的压降会影响系统电压判断。
6. 写在最后:这套电源方案还能怎么延伸
这套 PCA9422 加 STM32F100ZE 的组合,我用下来的感受是:PMIC 管硬件层面的电能转换,MCU 管策略层面的电源调度,两者搭好,整机电源管理就成功了一大半。后续如果想缩成本和面积,主控可以换成同系列的 F100RB,PMIC 周边不动,驱动代码几乎零修改;如果产品还要加蓝牙或者传感数据记录,F100ZE 的 512KB Flash 也完全够用。
个人最深的体会是,电源管理不是“把 PMIC 调通”就完事,而是要像对待一个独立子系统一样对待它。状态切换的时序、异常恢复的路径、噪声干扰的隔离,这些在调试阶段不一定能暴露,但到了量产和现场使用阶段,每一个都是致命的。多花一点时间在状态机和异常处理上,比反复调充电参数划算得多。另外调试工具一定要备齐,逻辑分析仪和示波器配合着看,很多 PMIC 的诡异问题其实就是时序或纹波那一瞬间的事。