1. 项目缘起与整体设计思路
嵌入式设备做多了,你会发现一个规律:功能越复杂的产品,电源管理越不能凑合。我手头这个项目是一个工业数据采集终端,主控用的是 PIC18F87K22,外设包括 4G 模组、SD 卡、温湿度传感器、LCD 段码屏,还有一路 RS485。整机要求 24 小时在线,支持锂电池备份,市电断电后至少撑 30 分钟,还要能上报电池电量、充电状态、故障告警。
一开始我图省事,用了一颗普通的 LDO 加一堆分立元件搭充电电路,结果问题一个接一个:充电电流不可控、电池电量测不准、休眠功耗压不下去、上电时序混乱导致 4G 模组偶尔起不来。后来痛定思痛,换成了 PCA9422 这颗电源管理芯片,配合 PIC18F87K22 的片上外设做了一套完整的电源管理方案,才算把这块硬骨头啃下来。
PCA9422 是 NXP 的一款高度集成的电源管理 IC,内部集成了线性充电器、多路可配置稳压输出、电量计、看门狗、I2C 通信接口,还带一个可编程的复位输出。它最大的好处是把充电、供电、监测、复位这几件事全包了,主控只需要通过 I2C 读写寄存器就能掌控全局。PIC18F87K22 这边则负责策略层:什么时候进休眠、什么时候唤醒 4G、电池低于多少切低功耗模式、充满后怎么处理。
这套方案适合谁参考?我觉得有三类人:一是做工业手持终端、便携仪表的嵌入式工程师;二是正在选型电源管理方案、被分立方案折磨过的硬件同学;三是想学习 I2C 器件驱动和低功耗状态机设计的学生或爱好者。哪怕你用的不是这两颗芯片,思路也是通用的——把电源管理从“硬件堆料”变成“软件可编程”,这是整个项目最核心的转变。
整体设计上,我把它分成四层:硬件供电层(PCA9422 负责)、通信驱动层(I2C 读写寄存器)、策略控制层(PIC18F87K22 的状态机)、应用接口层(对外提供电量、状态、控制命令)。下面逐层拆开讲。
2. PCA9422 核心功能与寄存器级细节解析
2.1 为什么选 PCA9422 而不是分立方案
先说选型逻辑。分立方案不是不能用,而是可控性差、一致性差、调试成本高。举个例子,充电电流用电阻设定,一旦板子做出来发现电流偏大,只能换电阻;电池电量用 ADC 分压测量,负载一跳变读数就飘;上电时序靠 RC 延时,批次之间误差能到几十毫秒。这些问题在小批量时看不出来,一上量就集中爆发。
PCA9422 把这些全部数字化了。充电电流、充电电压、输出电压、看门狗超时、复位阈值,统统通过 I2C 寄存器配置。更关键的是它内置了7 位 ADC 电量计,可以直接读电池电压和充电电流,不用主控再搭分压电路。还有一个我特别看重的功能:可编程复位输出,能在电压跌落时主动拉低主控复位脚,避免 PIC18F87K22 在欠压状态下跑飞。
注意:PCA9422 的 I2C 地址是固定的,具体地址需要查对应型号的数据手册确认,不同后缀版本可能不同,选型时务必核对。
2.2 关键寄存器分组与作用
PCA9422 的寄存器大致分五组,我按使用频率排一下:
| 寄存器组 | 主要作用 | 使用频率 |
|---|---|---|
| 充电控制组 | 设定充电电流、充电终止电压、充电使能 | 高 |
| 输出调节组 | 配置各路 LDO/BUCK 输出电压 | 中 |
| 电量计组 | 读电池电压、充电电流、温度 | 高 |
| 看门狗组 | 设定超时时间、喂狗、复位使能 | 中 |
| 中断状态组 | 读取充电完成、过温、欠压等事件 | 高 |
充电控制组里,充电电流是分档设置的,不是连续可调。比如某几档对应 100mA、200mA、500mA、1000mA,具体档位看手册。我一般根据电池容量来选:充电电流取电池容量的 0.5C 左右,比如 2000mAh 的电池,充电流设 1000mA 比较合适,既不太慢也不伤电池。
输出调节组要注意,PCA9422 的各路输出有默认值,但默认值不一定适合你的系统。我遇到过默认输出 3.3V 但 4G 模组需要 3.8V 峰值电流的情况,必须改寄存器。改的时候要先关输出再改电压再开输出,直接改可能导致输出抖动。
2.3 电量计的读数换算
电量计读出来的是原始 ADC 值,需要换算。以电池电压为例,假设 7 位 ADC,参考电压内部固定,满量程对应某个最大电压。换算公式大致是:
电池电压 = (ADC原始值 / 127) * 满量程电压实际使用时不能只读一次,我一般连续读 8 次取平均,再去查电池放电曲线。因为锂电池电压和剩余电量不是线性的,3.7V 到 3.5V 可能只掉 10% 电量,但 3.5V 到 3.3V 可能掉 30%。所以我在固件里建了一张电压-电量对照表,分段线性插值,比单纯看电压准得多。
实操心得:电量计读数在充电时和放电时差异明显,因为充电时电池内阻压降方向相反。我的做法是充电时用充电电流做补偿,放电时用负载电流做补偿,补偿系数靠实测标定。
3. PIC18F87K22 侧的驱动与状态机设计
3.1 I2C 驱动层怎么写才稳
PIC18F87K22 有硬件 MSSP 模块,支持 I2C 主模式。我一开始用软件模拟 I2C,后来发现硬件 I2C 在 400kHz 下稳定性好太多,尤其是总线上挂了 PCA9422 和一颗 EEPROM 的时候。配置步骤大致是:
- 设置 SSPCON1 寄存器,选择 I2C 主模式,时钟 = Fosc/(4*(SSPADD+1))。
- 设置 SSPADD 得到目标波特率,比如 16MHz 晶振下要 400kHz,SSPADD 约等于 9。
- 配置 SSPSTAT 的 SMP 和 CKE 位,400kHz 时 SMP 要置 1。
- 使能 MSSP 模块。
读写 PCA9422 的时序是标准的:启动、发地址+写、发寄存器地址、重启、发地址+读、读数据、NACK、停止。我封装了两个函数PCA9422_WriteReg和PCA9422_ReadReg,上层全部调这两个。
注意:PIC18F87K22 的 I2C 在总线被拉低时会一直等,如果 PCA9422 没焊好或者地址错,程序会卡死。我加了超时计数,超过一定次数就报错返回,避免死等。
3.2 电源状态机的四个状态
整个电源管理我用一个状态机实现,四个状态:
- STATE_INIT:上电初始化,配置 PCA9422 各路输出、充电参数、看门狗。
- STATE_RUN:正常运行,周期性读电量、喂狗、监测中断。
- STATE_LOWPOWER:低功耗模式,关 4G、关 LCD 背光、降低主频。
- STATE_CHARGING:检测到充电器插入,进入充电管理,监测充电完成。
状态切换条件我列一下:
| 当前状态 | 切换条件 | 目标状态 |
|---|---|---|
| INIT | 配置完成 | RUN |
| RUN | 电池低于 20% 且无充电器 | LOWPOWER |
| RUN | 检测到充电器插入 | CHARGING |
| LOWPOWER | 电池回升或充电器插入 | RUN |
| CHARGING | 充电完成且电池高于 90% | RUN |
这个状态机跑在主循环里,每个状态执行自己的任务,不阻塞。我试过用中断驱动,但 I2C 读写在中断里容易和主循环冲突,后来改成主循环轮询 + 定时器打时间戳,反而更稳。
3.3 看门狗与复位策略
PCA9422 的看门狗和 PIC18F87K22 自带的 WDT 是两套独立机制。我的策略是:PCA9422 看门狗负责“硬复位”,PIC 内部 WDT 负责“软恢复”。正常情况下喂 PCA9422 的狗,如果主控死机超过设定时间(我设的 2 秒),PCA9422 直接拉复位脚,整机重启。PIC 内部 WDT 设更长(比如 4 秒),作为第二道防线。
喂狗时机很关键。我放在主循环末尾,确保所有任务都跑完一遍才喂。如果某个任务卡住,狗就喂不上,触发复位。这个设计帮我抓到过一次 4G 模组初始化死等的问题。
实操心得:调试阶段可以先关看门狗,用 LED 指示状态;量产前再打开,并且一定要做“故意不喂狗”测试,确认复位电路真的能工作。
4. 完整实操流程与关键参数计算
4.1 硬件连接与上电时序
PCA9422 和 PIC18F87K22 的连接不复杂,但有几个点容易错:
- I2C 上拉电阻:我用的 4.7k,接 3.3V。如果总线长或者挂的设备多,可以降到 2.2k,但功耗会增加。
- 复位输出:PCA9422 的 nRST 接到 PIC 的 MCLR,中间不要加电容,否则复位沿变缓。
- 充电输入:VBUS 进来先过 TVS 和滤波电容,再进 PCA9422 的充电输入脚。
- 电池连接:电池正极接 BAT 脚,负极接地,中间走线要粗,至少 20mil。
上电时序我实测下来是这样的:VBUS 上电后,PCA9422 先启动内部参考,约 5ms 后各路输出建立,再 10ms 后 nRST 释放,PIC 开始跑。所以 PIC 的初始化代码里不需要额外延时等电源,但如果你发现 PIC 跑起来后 I2C 读不到 PCA9422,可以在初始化前加 20ms 延时试试。
4.2 充电参数计算实例
假设我用一节 2000mAh 的单节锂电池,充电终止电压 4.2V,充电电流设 0.5C = 1000mA。PCA9422 的充电电流档位如果最接近的是 1000mA,就直接选这档。如果只有 800mA 和 1200mA 两档,我选 800mA,宁小勿大,充电慢一点但安全。
充电终止电压必须匹配电池规格。4.2V 是标准锂电,如果是 4.35V 的高压电池,寄存器要改,否则充不满。这个参数绝对不能拍脑袋,错了要么充不满要么过充。
充电完成判断:PCA9422 会在充电电流降到设定值的 10% 左右时置充电完成标志。我读这个标志后,再等 10 分钟确认电压稳定,才切到 RUN 状态。
4.3 低功耗模式实测数据
低功耗模式我做了几轮优化,数据如下:
| 优化项 | 优化前电流 | 优化后电流 |
|---|---|---|
| 4G 模组常开 | 85mA | — |
| 4G 模组关闭 | — | 12mA |
| LCD 背光关闭 | — | 8mA |
| 主频降到 4MHz | — | 5mA |
| PCA9422 输出关一路 | — | 3.5mA |
最终整机低功耗电流约 3.5mA,2000mAh 电池理论上能撑 500 多小时,远超 30 分钟要求。这里的关键是PCA9422 可以单独关掉某一路输出,我把传感器那路关了,需要时再开。
注意:关输出再开,有些传感器需要重新初始化,所以我在状态机里加了“传感器重新初始化”步骤,不能直接读数据。
5. 常见问题与排查技巧实录
5.1 I2C 通信失败排查
这是最常见的问题。我的排查顺序是:
- 量电压:PCA9422 的 VDD 是否正常,I2C 上拉电压是否有。
- 量波形:用示波器看 SCL 和 SDA,有没有起始条件,ACK 位是否被拉低。
- 查地址:确认 I2C 地址对不对,读手册核对。
- 查时序:400kHz 下上升沿是否太慢,上拉电阻是否太大。
- 查冲突:总线上其他设备是否在抢总线。
我遇到过 SDA 被 EEPROM 拉死的情况,后来在初始化时先发 9 个时钟脉冲解锁总线,问题解决。
5.2 电量读数跳变
电量读数跳变一般是两个原因:ADC 采样时机不对或者负载突变。我的解决方法是:
- 在 4G 发射间隙读电量,避开大电流时刻。
- 连续读 8 次,去掉最大最小值,剩下取平均。
- 加一阶滤波:
新值 = 0.7*旧值 + 0.3*当前值。
这样处理后,电量显示基本稳定,不会出现 80% 突然跳到 60% 的情况。
5.3 充电异常与过温保护
PCA9422 有内置过温保护,但前提是芯片散热要做好。我第一版 PCB 把 PCA9422 放在角落,充电时烫得厉害,后来加了散热焊盘和过孔,温度降了 15 度。如果充电电流大,建议在芯片底下铺铜并打多个过孔到地平面。
充电异常还有一种情况:电池电压过低时,充电电流上不去。这是正常的,PCA9422 会先小电流预充,等电压上来再切大电流。如果一直上不去,检查电池是否损坏。
5.4 常见问题速查表
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| I2C 读不到 | 地址错/上拉缺失/总线死锁 | 核对地址、加上拉、发时钟解锁 |
| 电量跳变 | 采样时机差/无滤波 | 避开大电流、加滤波 |
| 充电慢 | 电流档位低/电池老化 | 调档位、换电池 |
| 复位频繁 | 看门狗超时短/喂狗不及时 | 加长超时、优化任务 |
| 低功耗不达标 | 外设未关/输出未关 | 逐路关输出、测电流 |
最后分享一个小技巧:调试电源管理时,用一颗可调电源代替电池,可以模拟不同电压下的行为,比反复充放电快得多。但要注意可调电源的电流限制要设好,别把芯片烧了。
这套方案我前后调了大概三周,踩过的坑基本都写在上面的。PCA9422 这颗芯片功能很全,但寄存器多,刚开始看手册会有点晕,建议先跑通 I2C 读写,再一个一个功能加,别想着一口气全配好。PIC18F87K22 这边,状态机设计要清晰,每个状态的进入和退出条件写明白,后面加功能才不会乱。