
做便携设备这几年我越来越认同一件事电源管理不是选一颗充电芯片、配一个LDO、再用IO口去拉开关的拼图游戏。初期功能少的时候确实能跑一旦设备要兼顾待机功耗、电池电量监测、充电保护、唤醒协同、多个电源域独立通断分立方案立刻就散架了。我最近把一台手持采集设备的电源部分整体推倒重做最终方案就是 PCA9422 STM32F373RC 的完整电源管理系统。PCA9422管整机电源拓扑、充放电管理和按键唤醒STM32F373RC当主控用片上自带的16位高精度ADC做电池电压和电流采样把充电流程、电量估算、低功耗状态机统一到一套代码里。这篇文章把硬件接线、固件架构、充电流程、实测踩坑全部记录下来给正在折腾电池设备电源管理的同行做个参照。这篇内容适合两类人。一类是做便携仪表、手持巡检设备、IoT节点想告别多芯片拼凑方案的硬件工程师可以照着这套思路重新梳理电源树另一类是平时主要写应用层、对PMIC驱动不太熟悉的软件工程师也能从这里知道寄存器驱动怎么组织、充电状态机为什么要按这个顺序写。1. 为什么电源管理值得单独做成一个子系统很多项目一开始是把电源芯片挂在主板角落MCU顺便开个I2C读一下寄存器能充上电、能开机就满足了。但随着整机功能堆上来问题会接二连三出现屏幕背光、传感器、无线模组待机电流差异巨大靠一颗LDO硬扛电池电量靠查表估算温度一变误差就离谱充电没做完就会提前充满或者过充过放没有任何记录。这些问题凑到一起其实是在提醒你该把电源管理当作一个独立子系统来设计了而不是几颗芯片的简单叠加。1.1 分立方案为什么越来越忙不过来先说一个我在早期项目里的真实体验。当时用的是独立充电IC加独立LDO加电压检测电路听起来也没什么大问题。但设备加进了远程上报功能之后待机功耗要求从毫安级降到微安级麻烦就来了。充电芯片和LDO各自有不同的使能逻辑开关时序要MCU用GPIO去拼电池电压检测用的电阻分压网络本身又一直在耗电低功耗模式下还得想办法把分压网络切断。到最后GPIO不够用飞线加逻辑功耗却始终降不下去。更麻烦的是故障保护。分立方案里过压、欠压、过温、过流这些保护分散在各颗IC里有些甚至根本没有保护。出问题的时候很难判断是电池问题、充电芯片问题、还是负载问题只能一块一块板子量波形。换成一颗可编程PMIC加一颗适合做模拟采集的MCU之后这些状态全部统一到寄存器里读一次状态字就知道当前处于什么模式、异常出在哪里排查效率完全不是一个量级。1.2 PCA9422 和 STM32F373RC 到底怎么分工PCA9422 这颗PMIC我把它定位成电源链路的总管。它内部集成了电池充放电通道和可编程输出轨充电电路负责预充、恒流、恒压输出轨通过I2C配置电压还自带了按键检测、唤醒检测、温度监测相关的引脚。也就是说外部电源拓扑的事情PCB上几颗电阻电容加这颗芯片就全部覆盖了不需要再单独拉一路LDO也不需要为了进入低功耗去手动切分压网络。STM32F373RC 在这套方案里的角色不是普通主控它带的16位高精度SDADC才是选它的直接原因。电源管理需要长时间、稳定地采集电池电压和回路电流普通12位ADC在3.7V的电池电压上一个LSB就有将近1mV级的量化误差配合电流采样电阻去算电量偏差会被放大到无法接受。而F373RC的16位SDADC配合外部增益配置可以直接把毫欧级采样电阻上的微弱压差读得明明白白省掉一颗外部高精度ADC整套系统的元器件数量和成本反而更友好。1.3 F373RC 的低功耗模式与实时时钟配合除了高精度采样F373RC的几个低功耗模式也正好契合电源管理需求。正常运行时CPU全速跑业务逻辑和状态机进入待机后切到低功耗睡眠模式把SDADC和I2C关掉只留实时时钟和唤醒源相关的部分如果需要长时间深度休眠可以直接停在较低功耗的停止模式等PCA9422的按键中断或外部事件把它叫醒。这样CPU几乎不额外消耗电池整机静态电流的贡献者只剩PMIC自身的静态功耗和不可避免的漏电流。就这个项目来说调整完睡眠配置之后整机休眠电流能压到比较理想的范围后面实测章节会专门写。2. 硬件规划电源树、I2C链路与高精度采样通道硬件设计是这套方案里最值得认真画图的部分。电源树画错了固件怎么写都救不回来I2C链路和采样通道的细节没处理好软件上的调节能力也会被硬件噪声吃掉。我按当时的实际做法把关键规划拆成三块来说。2.1 电源树怎么画从VBUS到四个输出域拿到一个新的便携设备项目我习惯先把负载按电源域分类再决定每个域由谁供电。这个手持采集设备里负载大致分四类核心控制域MCU、复位电路、启动配置需要稳定干净的电压典型1.8V或3.3V模拟采样域运放、比较器、参考电压对纹波敏感要和数字负载分开供电最好用单独的LDO输出轨外设域屏幕背光、通信模组、按键灯电流瞬时变化大允许一定纹波电池管理域充电路径、电池温度检测、采样电阻直接由电池或VBUS路径管理。把这四类列出来之后供电关系就清楚了。VBUS进来先到PCA9422的输入端电池也挂在PCA9422的电池引脚上。PCA9422的某个可编程输出轨负责给主控核心域供电另一个输出轨负责给外设域供电模拟域则从核心域后面再加一级低噪声滤波避免数字部分干扰模拟采样。电池电压本身不直接引到外设供电而是统一经过PMIC输出轨分配这样每个域都可以独立关断进入低功耗。这里有一个容易忽视的点电池欠压保护值一定要设置正确。PCA9422的输出轨虽然在电池电压范围内都能工作但它里面有些逻辑要依赖一个最低工作电压。如果电池已经放到很低还在开机PMIC和MCU都会出现不稳定复位。我在这个项目里把浅放电截止电压配置在电池规格允许的范围内同时预留了预充电模式让严重亏电的电池先小电流充电一段再进入正常充电流程避免刚接上充电器时被误判为损坏。2.2 I2C控制通路和唤醒链路要一起规划PMIC和MCU之间的信息通路主要是I2C。这个通路看起来简单但有几个硬件细节会让后面省很多事。首先是上拉电阻总线工作在100kHz到400kHz我用了2.2kΩ的上拉电阻因为总线上的设备不多电容不大2.2k能保证沿足够快也不至于让低电平拉不下去。其次是地址选择。PCA9422一般给出一两个地址配置引脚硬件上接高或接低就能选地址。设计阶段就把这个引脚固定好给PMIC一个唯一地址不要在软件里做扫描猜地址的动作。真遇到读不到设备的情况第一步先去量I2C引脚波形而不是反复改软件。唤醒链路单独说。便携设备绝大多数时间在休眠按键唤醒是最常用的唤醒源。PCA9422的按键引脚直接接到设备外壳的物理按键按键事件发生后PMIC会改变某个中断/状态引脚的电平这个电平再连到MCU的唤醒引脚。我的做法是按键引脚不经过任何缓冲直接进MCUMCU在低功耗模式下把这个引脚配置为外部中断同时让PMIC的对应中断引脚也作为第二路备份防止某一边配置丢失导致整机没有反应。2.3 16位SDADC用在采样点的接法与滤波F373RC自带高精度SDADC这是它在电源管理场景里最值钱的部分。高精度ADC有一些使用纪律起初很容易忽略。首先是输入范围SDADC支持差分输入采样端我接的是高边电流采样电阻的两端这样直接把微小压差差分读进来共模噪声被大大抑制。电流采样电阻我选了10毫欧的合金电阻最大采样电流2A时压差也才20mV这个压差在SDADC的增益放大后信号幅度比较合适。其次是布线。采样电阻两端必须走开尔文接法单独拉两根细线回ADC输入端不要在采样电阻的焊盘上就近并线否则负载电流在铜箔上产生的压降全被算进采样信号里了。另外SDADC的采样速率不需要太高电源管理关心的本来就是秒级的趋势我配置成每秒20到50次采样数字滤波加滑动平均之后噪声基本能被压平。电池电压采样也走SDADC但不是直接测电池正极到地的电位。为了切掉分压网络在休眠时的漏电我引入了一个受控的采样开关MCU在需要测量时才打开分压网络测完立即关闭。这样测量时刻的功耗非常短暂平均到一天里几乎可以忽略而休眠期间电池电压不会被分压电阻持续拉低。3. 固件实现寄存器驱动、充电状态机与低功耗唤醒硬件定下来接下来就是把PMIC用起来。PCA9422的很多能力是靠寄存器配置出来的固件如果只是一次性写几个寄存器然后就不管那和分立方案差别不大。我的建议是把PMIC驱动做成一个独立模块上层状态机通过接口调用底层处理寄存器细节和通信容错这样后面扩展新设备或换PMIC时不用重写业务逻辑。3.1 PMIC寄存器读写封装先读ID再回读校验PMIC驱动模块的第一步不是配置功能而是通信自检。每次上电后先读芯片ID寄存器确认MCU和PMIC在I2C总线上真的握手成功了再继续后续操作。这一步看起来多余却能省去后面好几个小时的排查时间。系统初始化时电源时序可能还没完全稳定这时候贸然写配置寄存器写入可能失败或者写入一半被复位打断芯片处于不可预期状态。通信封装我建议统一成三个函数寄存器读、寄存器写、写后回读。尤其是回读PMIC的寄存器有些是带状态自动清除位的有些是需要确认写入成功的。我在这套固件里凡是涉及关键输出的配置寄存器写完立刻回读比对不一致就重试三次三次都不一致就进入故障分支通过状态指示灯给出明确故障码。这样做的好处是现场出问题时不用猜是I2C偶发错误还是数据写错日志里会有明确记录。代码结构上不需要复杂设计一个纯C模块就够int pmic_write_reg(uint8_t reg, uint8_t val) { uint8_t buf[2] {reg, val}; int status i2c_transmit(PMIC_ADDR, buf, 2); if (status ! OK) return -1; uint8_t check pmic_read_reg(reg); return (check val) ? 0 : -2; }3.2 三段式充电流程与终止条件判断锂电池充电的基本流程是预充、恒流、恒压、终止。PCA9422的硬件已经能把这段流程跑起来但MCU要做的不是当甩手掌柜而是监视每个阶段的状态决定什么时候结束充电、什么时候要报异常。预充阶段针对的是电池电压过低的场景。电池电压低于规格书建议的阈值时如果直接上大电流充电电池内部会有析锂风险所以PMIC会用很小的电流先把电池电压拉到安全区间再切恒流。MCU这段时间要做的只是确认预充电流正常并且给预充超时保护计时避免一颗损坏的电池永远卡在预充状态。进入恒流阶段后电流是充电主阶段MCU重点监视电池温度和充电电压。我用NTC电阻挂在电池上NTC分压信号送到F373RC的普通ADC通道。温度超过设定范围就通知PMIC暂停充电或降低电流这一条既是保护电池也是保护整机安全。恒压阶段电流会逐渐下降当电流降到恒流设定值的十分之一左右就认为充电已经接近终止再充下去意义不大反而增加电池老化。这里有个经验终止电流到底设多少不能照搬数据手册默认值。要结合电池容量和充电电流来定。容量小、充电电流小的电池终止电流也要同步调低否则电池实际只充到九成多就停了。我一般取恒流值的8%到12%然后通过实测充电截止后的电压反馈来微调。3.3 电量估算OCV基准加库仑修正完整电源管理不能没有电量显示。这个项目没有独立电量计芯片我利用F373RC的高精度采样能力做了OCV基准加电流积分的简化版算法。核心思路是这样的电池在静置一段时间后开路电压和剩余电量有相对稳定的对应关系。设备每次从深度睡眠唤醒时先静置一小会采样电池电压查询放电曲线得到基础电量百分比。运行期间再用充电或放电电流做库仑积分累计的安时数拿来修正基础值。这样既不会在剧烈负载波动时频繁跳动也不会因为长时间积分漂移导致电量显示失真。高精度ADC在这一块帮了大忙。库仑积分要准确电流采样的精度必须够如果电流采样分辨率太粗积分误差会越积越大。F373RC的SDADC配合校准过的10毫欧采样电阻在常见负载范围内电流读数的稳定性非常好实测下来电量估算的偏差能控制在可接受范围。重点提醒一句采样电阻的精确阻值要上电校准一次逻辑上可以用外接精密源灌已知电流然后读取ADC值反推比直接采用标称值靠谱得多。3.4 低功耗状态机与唤醒源分配完整电源管理最考验代码结构的就是状态机。我把整机状态分为正常运行、待机、深度睡眠、充电中、故障保护五个大状态再按设备实际业务细分。状态切换的触发源有按键、RTC定时器、充电器插入拔出事件、电池电压告警。深度睡眠状态下的处理顺序是先把非必要外设域的PMIC输出轨关掉只保留核心域然后关闭SDADC采样让MCU进入低功耗停止模式最后把唤醒源配置好。这里有个细节MCU进入停止模式前要把I2C总线释放掉否则总线上还挂着一个处于活跃状态的I2C从机PMIC或者其它设备以为总线被占用唤醒后重新初始化时容易出通信卡死。唤醒之后不是直接回到正常运行而是先快速采样电池电压和温度看当前电池状态是否安全。电池电压低于关机门限就立刻执行关机流程而不是强行开机带负载避免电池被深度放电损坏。这套状态机的逻辑其实不复杂但是把硬件和软件边界理清楚之后整机的电源行为才真正统一起来。4. 实测排查上电时序、I2C稳定性与功耗偏高的根因再好的设计方案也要过实测这一关。这个系统在实验室调试阶段遇到的问题不算多但每个都很有代表性按当时排查的顺序记录下来。4.1 上电时序怎么看示波器抓三路波形第一次上电我没有直接跑业务代码而是用一个最小固件先验证电源链路。示波器四个通道分别接VBUS、PMIC输出轨、MCU电源引脚和复位引脚抓上电全过程。正常情况下应该是VBUS先建立PMIC内部完成初始化后输出轨稳定上升MCU看到电源稳定后跑起来。如果输出轨电压上升过程中有台阶或者跌落通常是负载太重、去耦电容不够或者PMIC某个输出轨的配置在初始化时被反复使能。实际操作中我建议把示波器的时间轴拉长到几百毫秒不要只看前几个毫秒。PMIC的配置写入和电压切换需要时间MCU启动也需要时间在几百毫秒尺度上能看出顺序关系是否合理。我遇到过MCU复位期间外设域已经被PMIC开启的情况外设芯片在MCU还没接管时就进入未知状态上电好几次才能正常启动一次。解决办法是在PMIC配置时先让外设域输出轨保持失能状态等MCU初始化完成后再由软件打开。4.2 I2C偶发失败从电平、速率到回读校验的完整排查系统跑稳定之后出现了一个很让人头疼的问题I2C通信偶发失败不是每次复现但是一旦出现充电状态就卡住不更新。一开始怀疑是上拉电阻不够加大到1kΩ还是偶尔失败。又怀疑是速率问题把I2C从400kHz降到100kHz失败频率明显下降但偶尔还是会出现。后来用示波器抓波形才发现问题出在PMIC和MCU之间的电平域。MCU的I2C引脚供电来自核心输出轨而PCA9422的I2C部分参考电平是它自己的源电压两者在电源切换瞬间会出现短暂的不一致。当MCU执行写入时刚好碰上PMIC输出轨电压在切换总线状态就乱了。最终的做法是三管齐下把I2C速率固定到100kHz以确保时序裕量所有关键寄存器写操作完成后强制回读校验PMIC输出轨电压切换期间不上层业务不发起I2C通信。从那之后这个偶发失败就再没出现过。这个坑给我们的教训是PMIC在正常工作时也会动态调压固件不能假设I2C总线在任何时刻都绝对可用通信层必须带重试和状态确认。4.3 整机休眠电流偏高逐路断开定位漏电点低功耗性能是便携设备的核心指标之一。这个系统刚实现深度睡眠功能时实测整机电流比预估值高了将近十倍明显不符合设计预期。第一步先确认MCU确实进入了低功耗模式用调试器看PC指针已经停在WFI指令处说明CPU这边没问题。接下来我用逐路断开法排查。PCB上每一路负载供电都预留了0欧跳线或磁珠连接点我按电源域一路一路断开每一路断开后重新测整机电流。测到外设域时电流数值下降非常明显。进一步定位发现是一颗外设芯片的某个状态引脚被悬空芯片在输入浮动下反复尝试启动产生了不小的电流。把该引脚通过电阻固定到确定电平之后问题解决。这件事给硬件设计提了一个醒低功耗设备里所有输入引脚都不能悬空包括那些看似无关的状态脚。PCB设计阶段最好列一张悬空引脚检查表把所有芯片的没用到引脚统一处理要么拉高、要么拉低、要么接个电阻做默认状态。这类问题软件完全无能为力只能在硬件上堵住。5. 给打算自己搭电源管理方案的几个提醒这篇文章详细写了PCA9422和STM32F373RC结合做完整电源管理的整体方案最后提几个我自己在项目里反复踩过、总结出来的经验希望能帮你少走弯路。5.1 PCB布局上的几个习惯电源管理部分的PCB布局我建议把PMIC、采样电阻、MCU的模拟采样引脚布置在同一侧并保持较短的信号路径。采样电阻到ADC的差分走线要平行并且尽量短中间不要穿过数字信号线。PMIC的去耦电容要放在芯片电源引脚同面、紧贴引脚的位置不要通过过孔连接过孔带来的寄生电感在高频开关时会放大纹波。PMIC底层要保留完整的地平面采样信号最好在这个地平面上单独走一个小区域其它数字信号绕开走实测对SDADC的噪声改善很明显。5.2 把PMIC控制设计成通用电源驱动层软件上最值得投入的地方是把PMIC配置抽象出一个电源驱动层。应用代码不要直接对着PCA9422的寄存器操作而是通过类似power_set_rail_enable、power_get_charge_status、power_enter_sleep这样的接口来调用。这一层的好处是业务逻辑和硬件解耦调试时可以通过打印接口层调用来快速定位问题换PMIC或者换板卡时只要重写这层实现上层状态机基本不用动。对于经常做不同硬件方案的项目团队这样做能省下大量重复开发时间。5.3 充分验证故障保护路径最后再强调一下验证环节。电源管理代码很容易出现正常流程没问题异常流程一塌糊涂的情况。调试完成后我建议刻意做一轮破坏性测试把电池放到过放状态再充电、充电过程中突然拔掉充电器、负载短路后恢复、NTC断线后继续充电。这些异常路径比正常流程更能暴露固件的漏洞。每个保护分支都要有对应的现象、日志和复位行为否则系统只是一坨看起来能跑的代码而已。我自己在这个项目里最大的感受是电源管理做得好不好不在于用了多少高级功能而在于每个环节的设计边界是否清楚。芯片选型合理、电源树清晰、固件状态机可读、异常路径有兜底这套系统就算真正立住了。后续如果想继续扩展可以往PMIC实时健康上报、更细粒度的电量学习算法、老化电池参数自适应这些方向做基础已经打好了。