做低功耗电池设备时,最容易被低估的就是电源部分。很多朋友一开始都是直接找几颗LDO、一个充电板拼起来,结果发现系统要么效率太低发热严重,要么睡眠电流根本压不下去。前段时间我帮一个朋友梳理一台便携式传感器节点的供电方案,最终采用了“PCA9422 + PIC18LF45K80”这套组合:PMIC负责多路电源输出、锂电池充电和低功耗切换,MCU通过I2C动态调节各路电压,实现完整的电源状态管理。这篇文章就把整个方案从选型、硬件连接、固件配置到调试排障,完整拆开讲一遍,适合正在做电池供电设备、无线传感器或便携仪表的开发者参考。
1. 系统整体设计与选型逻辑
1.1 先从一颗锂电池和MCU的供电需求说起
先明确一下应用场景:单节锂电池供电,系统里有一块PIC18LF45K80作为主控,另外还有无线模块和几个传感器。PIC18LF45K80这颗8位MCU是低电压版本,工作电压可以低到1.8V,正常IO和内部模拟外设跑3.3V的时候最省心。但它不是整套系统唯一的用电对象,传感器可能需要3.3V模拟电源,无线模块可能需要1.8V逻辑电源,有些器件还要独立供电才能保证低功耗隔离。
这时候真正的问题不是“怎么给MCU通电”,而是“怎么让一坨电压需求各异的负载共享同一颗电池,还能在睡眠时把每一路都管住”。如果用LDO直接降压,3.7V电池到3.3V负载看似只掉了0.4V,但系统里工作电流可能是几十毫安,压差乘以电流就是热损耗。电池电压降到3.2V附近时LDO接近压差极限,输出不稳。再叠加充电管理,电路复杂度会上升得非常快。
1.2 为什么选择PCA9422而不是堆积LDO
PCA9422是一颗面向低功耗MCU平台的多功能PMIC,它和传统LDO方案的本质区别在于:它把高效率降压、多路LDO、锂电池充电、I2C可编程输出、中断反馈整合在一颗芯片里。BUCK负责压差较大的电压转换,LDO负责低噪声小电流的电源轨,充电部分由PMIC统一控制,MCU通过I2C寄存器就能在运行中和睡眠前调整各输出电压。
之前我自己也试过用独立DCDC加独立充电芯片加几颗LDO,虽然在实验室里能工作,但带来几个很实际的问题:多颗芯片的静态电流叠加很高,睡眠时很难整体降下来;多芯片的上电时序需要自己用复位电路或MCU的GPIO去控制;还有一个更隐蔽的问题,就是每个芯片都有独立的使能脚、旁路电容和接地策略,PCB布局稍不小心就会引入环路噪声。PCA9422把这些都集中到一起,PCB面积小,电源树清晰,低功耗切换可以通过寄存器一次性完成。
1.3 整套系统供电架构
我给这套系统设计的电源树是这样:锂电池通过VBAT进入PCA9422,USB的5V通过VBUS进入同一颗PMIC,PMIC内部完成电池充电和输入源切换。BUCK输出1.8V给无线模块和低电压传感器,LDO1输出3.3V给PIC18LF45K80以及普通IO外设,LDO2输出3.3V给模拟采集前端,必要时让LDO2和LDO1分开配置。PIC18LF45K80的MSSP模块作为I2C主机,SCL和SDA接PCA9422的I2C接口,PCA9422的INT中断输出接到MCU的一个普通IO口,用来上报充电完成、输入源切换和低电量事件。
这套架构的好处在于:MCU的VDD由LDO1供给,电压相对平稳而且纹波低,适合跑ADC采样;BUCK承担大电流转换,效率高;不同外设可以独立断电。实际做下来这套系统最容易被忽略的是INT中断线,如果只通过I2C轮询PMIC状态,MCU要么必须频繁唤醒,要么会漏掉充电异常这类瞬时事件,所以中断反馈必须接,而且要接在能唤醒睡眠的引脚上。
2. 硬件侧的接法与参数计算
2.1 输入侧:VBUS、VBAT、输入电容与保护
输入侧看起来简单,却最影响稳定性。VBUS建议先经过一个ESD保护管再进PCA9422的VBUS引脚,毕竟USB热拔插的瞬间脉冲对PMIC内部比较脆弱。VBAT侧要加一颗尽量靠近引脚的10μF陶瓷电容,用来吸收负载突变时电池内阻造成的电压跌落;如果电池离板子比较远,这一颗电容不能省。
不少人在输入侧忽略了一个细节:充电电流路径和系统负载路径不要共享同一段长走线。充电时电流较大,如果PCB走线过细,线上压降会让PMIC误判电池电压,导致充电提前终止。我一般把电池正极触点直接铺宽铜进入VBAT,然后从VBAT引脚附近分叉到充电功率管和系统电源路径,而不是把整个电池电流都串进检测电阻。
PCA9422的充电参数我采用了比较保守的设置:充电电压4.2V,充电电流300mA到500mA之间。不要一上来就设1A,很多便携设备的结构件散热条件很差,PMIC自发热会在充电后半段触发温度降额,反而拖慢充电。如果设备支持快充,也应该在固件里根据温度传感器反馈动态调整充电电流。
2.2 降压转换器的电感与输出电容选择
PCA9422的BUCK是一颗同步降压转换器,电感的选择直接决定了纹波和效率。开关频率在典型配置下大概在1MHz量级,所以电感不需要很大,但饱和电流必须留足。电感的纹波电流可以按负载电流的30%到40%估算,峰值电流等于负载电流加上一半纹波电流。我给1.8V那路留了最大800mA负载,纹波率选0.35,峰值电流大概是800mA乘1.175,接近950mA,所以选了一颗额定饱和电流2A的电感,留了足够裕量。
电感阻值也很关键。小封装的功率电感虽然省面积,但DCR可能到几百毫欧,在800mA下损耗不可忽略。我实测过同样1μH的电感,一个是DCR 80mΩ,另一个是DCR 280mΩ,BUCK满载效率差了两个百分点。低功耗设备跑大电流的时间短,但效率和热表现依然不能放水。
输出电容方面,BUCK输出端至少放一颗22μF的X5R陶瓷电容。有些资料说10μF也能工作,但动态负载响应会变得敏感。这里要特别注意陶瓷电容的直流偏压特性,尺寸小的22μF在1.8V下实际容量可能只剩标称的70%,有条件建议上0805封装。另外电容的ESR不能太低,否则会与BUCK的环路产生次谐波振荡,如果发现输出有小幅度高频自激,可以在输出电容上串联一颗0.1Ω电阻再判断。
2.3 LDO输出配置与去耦
PCA9422内部的LDO做小电流供电是很合适的。比如给PIC18LF45K80供电的LDO1,负载电流一般在10mA以内,LDO自己的纹波抑制能力足以保证MCU的ADC参考电压稳定。LDO输出端每路配一颗1μF或2.2μF的陶瓷电容就够了,不需要像BUCK那样追求大容量,因为LDO本质上是线性调整而不是开关储能。
一个容易踩的坑是LDO输出电容的ESR不能太低。某些LDO在纯陶瓷电容下会不稳定,虽然PCA9422这颗PMIC内建了补偿,但我在第一版设计时还是加了0.5Ω串联电阻,排查之后发现完全可以去掉。这里的建议是严格参考PMIC数据手册里推荐的LDO输出电容范围,不要为了省事把BUCK输出电容的设计思路套到LDO上。
LDO的输入来自电池还是来自BUCK,取决于你想要的噪声特性。如果要求模拟传感器电源纹波极低,我倾向于让LDO直接从VBAT取电,利用压差换取抑制能力;但这会降低效率,电池电压3.7V到LDO输出3.3V的热损耗在20mA下只有8mW,完全可以接受。
2.4 I2C上拉、INT和PCB布局
PCA9422的I2C接口是标准开漏,MCU侧必须接上拉电阻。上拉电阻我习惯用4.7kΩ,如果I2C线长超过5cm,可以考虑换成2.2kΩ。上拉电阻接的电源要选择与MCU IO电平匹配的电压轨,建议接在LDO1输出的3.3V上,避免系统进入睡眠后该电源轨被关断导致I2C拉死。
还有一个非常关键的布局原则:PMIC的功率地、MCU的数字地、模拟传感器地不能直接乱连通。我在第二版板子上的做法是设置单点地,把PMIC输入输出电容的接地脚、MCU的地引脚、I2C上拉电阻的地脚在PCB底层汇合到一个星地点。电源走线尽量短粗,BUCK的SW节点是高频开关节点,不要与I2C布线走平行长线,否则容易串扰到SDA上导致通信误码。实测发现,I2C通信失败有时候不是电气问题,而是SW节点的振铃从PCB寄生耦合进了SDA。
3. 固件侧:让PIC18LF45K80驾驭PCA9422
3.1 用MSSP外设配置I2C主机
PIC18LF45K80的MSSP外设可以配置成I2C主机模式。我自己不会手写全部寄存器初始化,直接用MCC图形化配置工具生成,把MSSP选成I2C主机模式,波特率设为100kHz,启动代码就自动生成了。PCA9422的寄存器访问频率在配置阶段和状态读取阶段都不高,100kHz足够,没必要上400kHz快速模式,低频还能减少串扰问题。
如果你想手写初始化,核心就是设置波特率寄存器、使能I2C主机模式、使能SDA和SCL引脚的数字输入。PIC18LF45K80的MSSP模块在这颗片子上有几个引脚复用选项,务必核对数据手册里MSSP模块的引脚映射,确认和PCA9422接线对应。生成代码之后先做写寄存器测试,不要直接配置电源输出,先把通信打通再说。
3.2 寄存器读写基础函数
I2C驱动的核心操作性函数其实只有两个:写寄存器、读寄存器。PCA9422支持标准的I2C写操作和读操作,写寄存器时序是起始位、器件地址加写位、寄存器地址、数据字节、终止位;读寄存器则是起始位、器件地址加写位、寄存器地址、重启位、器件地址加读位、读取数据、终止位。
下面是一段用MCC生成的驱动基础上封装出的寄存器读写函数,寄存器地址和器件地址需要按你手里的数据手册填入:
#define PCA9422_I2C_ADDR 0x11 // 实际地址以手册为准 uint8_t pca9422_read_reg(uint8_t reg) { uint8_t val = 0; I2C_Start(); I2C_Write((PCA9422_I2C_ADDR << 1) | 0); I2C_Write(reg); I2C_Restart(); I2C_Write((PCA9422_I2C_ADDR << 1) | 1); val = I2C_Read(1); I2C_Stop(); return val; } void pca9422_write_reg(uint8_t reg, uint8_t val) { I2C_Start(); I2C_Write((PCA9422_I2C_ADDR << 1) | 0); I2C_Write(reg); I2C_Write(val); I2C_Stop(); }我这里特意把器件地址写成了0x11,但不同板级配置可能不同,一定要用示波器或逻辑分析仪抓一次总线波形,确认手册里的7位地址被左移后拼上方向位是否正确。很多初学者在这处翻车,以为I2C读写不成功是时序问题,结果只是器件地址配置与芯片的ADDR引脚状态不一致。
3.3 上电初始化流程与典型配置序列
PCA9422上电后,内部寄存器通常是默认状态,但不一定满足你的实际电源需求。PC18LF45K80复位后的第一件电源相关事情,就是通过I2C把PMIC调整到目标配置。我推荐的配置顺序是先配输入源和充电,再配输出电压,最后开启各路输出,这样能避免负载在上电瞬间看到未完成的中间态电压。
初始化序列大致如下:先读取PMIC器件ID寄存器,确认通信正常;然后写充电控制寄存器,设置充电电压和充电电流;接着设置BUCK输出电压选择位和LDO1、LDO2的输出选择位;给必要的位写使能控制,让各路输出按预设电压启动;最后清一次中断标志,读取状态寄存器,确认没有上电异常。
典型配置代码可以看下面这段,具体寄存器和位定义必须对照数据手册修改:
void pca9422_init(void) { // 确认通信,读设备ID uint8_t id = pca9422_read_reg(0x00); if (id != EXPECTED_ID) { // 处理通信异常,通常是接线或地址问题 return; } // 配置充电电压4.2V、充电电流300mA pca9422_write_reg(0x10, 0x4E); // 配置BUCK输出1.8V pca9422_write_reg(0x20, 0x18); // 配置LDO1输出3.3V pca9422_write_reg(0x21, 0x33); // 配置LDO2输出3.3V pca9422_write_reg(0x22, 0x32); // 使能各路输出 pca9422_write_reg(0x30, 0x07); // 清除中断 pca9422_write_reg(0x40, 0xFF); }这里把寄存器地址用0x10、0x20这类作示意说明,因为它们在不同版本的PMIC里定义可能完全不同。真正写代码时,我会把所有寄存器地址和掩码定义成宏,放在一个头文件里,不要散落在C文件中。之后每次读数据手册确认一次,比调了很久才发现是寄存器掩码写错要省事得多。
3.4 动态电压调节与低功耗睡眠联动
PIC18LF45K80本身就是低功耗MCU,睡眠电流能跑到很低,但整机功耗是由电源路径决定的。PMIC在这个方案里最大的价值是MCU可以在睡眠前通过I2C调低BUCK电压、关闭用不到的LDO,唤醒后再调回来。这个做法实际效果非常明显。我实测过,如果睡眠时所有LDO都保持开启,系统电流接近1.2mA;把LDO2关掉、BUCK输出调到最低,整机睡眠电流降到2μA以下,差了差不多三个数量级。
睡眠流程可以这样设计:MCU收到休眠指令后先保存现场,然后把BUCK输出电压通过I2C降到目标值,把不用的LDO关断,最后执行SLEEP指令。唤醒后第一时间在中断服务程序里把BUCK调回正常运行电压,再执行主循环。需要注意动态调压过程中一定不要关闭MCU自己所在的那路LDO,否则会把自己锁死,这个问题只能靠看门狗复位救回来。
3.5 充电状态读取与故障处理
PCA9422的充电状态和中断信息都需要MCU通过I2C读取。PIC18LF45K80的IO中断引脚接PMIC的INT输出,PMIC在充电完成、VBUS插入、输入源切换、低电量等事件触发时拉低INT。MCU收到中断后应该进入中断服务程序读取状态寄存器,判断是哪类事件,然后决定点亮充电指示灯还是调整任务调度。
这里有个工程经验:充电状态读取要加简单的防抖。INT引脚只有在PMIC发现真正的事件时才会被拉低,但某些瞬态事件如VBUS刚插入时的抖动会在短时间内多次触发中断。我在中断服务程序里做了一个软件延时状态机,第一次读取状态后不立即清中断,等待3ms再读一次,两次读取值一致时才执行后续处理。这个办法非常土但是非常有效,避免了充电过程中MCU被重复唤醒。
4. 调试、功耗实测与常见问题排查
4.1 上电前检查与假负载调试
全套接好之后,不要直接把电池和USB同时插上,我的习惯是先用稳压电源代替电池,限制电流100mA,逐步确认各路输出是否正常。PMIC上电后如果BUCK没有输出,不要急着怀疑芯片损坏,先测EN引脚和输入电压。ENA引脚如果悬空,很多PMIC默认是不工作的。第二件事是检查I2C地址,逻辑分析仪挂在SDA和SCL上,抓一次MCU发出的起始条件,确认地址字节完全符合预期。
调试电源还有一个技巧:带一个假负载。直接用MCU当负载会增加排查变量,我一般先用一个电阻把BUCK输出加载到100mA左右,或者用一个LED灯珠串电阻,观察PMIC带载时输出电压是否稳稳落在设定值。如果空载正常、带载跌压,多半是电感饱和电流不够或者输入侧电容不足。
4.2 常见问题速查表
我把这套系统调试中可能遇到的问题整理成一张排查表,避免被同一类问题绊倒两次:
| 现象 | 可能原因 | 排查思路 |
|---|---|---|
| 上电后BUCK无输出 | EN未使能、输入电压过低 | 先测VBAT和VBUS电压,再测EN引脚电平 |
| I2C写寄存器没反应 | 器件地址错误、上拉电阻缺失 | 逻辑分析仪抓总线,核对地址帧和ACK位 |
| BUCK输出纹波偏大 | 电感不合适、输出电容偏小 | 换低DCR电感、加大输出电容并排除直流偏压问题 |
| 整机睡眠电流高 | 未关闭LDO、BUCK未降档 | 检查PMIC寄存器,确认各路输出使能状态 |
| LDO输出电压偏高 | 寄存器位设置错误 | 重新阅读数据手册的LDO输出编码表 |
| 充电电流异常 | 电池检测电阻布局不合理 | 检查电池路径走线,改用星形接地 |
| 无线模块工作时MCU复位 | 电源瞬态跌落 | 加大BUCK输出电容,检查输入路径阻抗 |
4.3 功耗实测方法与优化思路
功耗测试建议用高精度万用表或者专门的功耗分析仪,测量方式是把电源表串联在电池正极和PCA9422的VBAT之间。测睡眠电流时有一个特别容易踩的坑:刚进入睡眠的瞬间系统电流不会立刻掉下来,可能还会因为电容放电保持几百微安,所以要等10秒以上再读取稳态值。第一次测到2.1μA时我以为自己在做梦,后来确认是真实数据,原因就是LDO2被关闭、BUCK降到了低电压状态,整条电源链路的静态电流被压到了极低的水平。
运行状态下的功耗优化可以从时钟入手。PIC18LF45K80在不需要全速运行时,可以把内部振荡器频率降低,或者切换到低功耗内部振荡器。PMIC的BUCK在轻载时会自动进入省电模式,这些因素叠加下来,一个周期性的无线节点能做到平均功耗几十微安的水平。想进一步压低,可以把MCU的运行任务集中化,几十毫秒完成采集传输后立即进入睡眠,比长时间停留在低速运行更省电。
5. 我踩过坑之后的一些体会
如果让我把这次“PCA9422 + PIC18LF45K80”完整电源管理的经验浓缩成几句话,第一句是数据手册里的典型应用图值得反复看,很多布局和参数都是直接决定成败的;第二句是电感和电容的位置比参数更关键,一颗走线过长的22μF电容还不如一颗紧贴引脚的4.7μF电容效果好;第三句是I2C和中断这条控制通路重要程度不亚于功率通路,前者的稳定性决定了整套电源策略能不能落到实地。这套方案我后续还会继续用,下一步打算把电池内阻监测和温度补偿都加进去,让充电和放电策略更智能一点。如果你也在玩低功耗单片机加PMIC的架构,希望在充电配置和睡眠调压两个环节多留一点测试时间,那两块是最花精力也最值得打磨的地方。