基于PCA9422与PIC18F86J16的便携设备电源管理方案实践

发布时间:2026/10/10 8:10:43
基于PCA9422与PIC18F86J16的便携设备电源管理方案实践
做一个需要电池供电的便携式采集设备时我一度被板子上的电源部分弄得焦头烂额USB 充电管理、两路 LDO、一路 DC-DC再叠上电池保护和电量检测原理图上三分之一都是电源。后来我把整个电源链路改成了以PCA9422为核心、用PIC18F86J16做策略控制的方案调试面一下子小了很多。PCA9422 这类集成式 PMIC 把充电、电源路径、多路降压输出和 I2C 动态调压收进一颗芯片PIC18F86J16 则用 I2C、ADC、中断和低功耗休眠把这套电源链路管起来两个芯片配合才能真正落地“完整电源管理”。这篇文章把我从选型、硬件连接、软件状态机到实测踩坑的整个过程捋一遍。适合正在做手持仪表、可穿戴设备或任何电池供电产品的软硬件工程师参考关键选择和参数取舍的原因我也会一并讲清楚而不是只丢给你一份电路图。1. 先把电源需求拆干净再谈选型1.1 便携设备对电源的要求往往没有表面那么简单很多工程师看到“要 3.3V 和 1.8V”就直接画 LDO 了。但在电池设备里问题远不是电压值这么简单而是电源轨背后的一堆交叉逻辑USB 插入时系统不能掉电、电池快没电时要逐级关闭外设、充电过程不能因为 MCU 死机而失控、待机时整机电流要压到微安级。这些东西分开看每一项都不难合在一起就成了最烦的电源设计方案。我在这类项目开始时都会先从需求清单倒推选型核心条目大概是下面这样需求说明由谁承担输入切换与路径管理插 USB 时由 USB 供电电池同时充电系统不掉电PCA9422 硬件路径锂电充电全流程预充、CC、CV、截止、补充、温度保护PCA9422 充电前端MCU 观察状态多路输出轨数字核心、模拟部分、传感器偏置分开供电PCA9422 双 Buck 外部负载开关动态调压按运行状态切换电压档位降低功耗PCA9422 I2C 调压MCU 决策电压与温度监测电池电压、NTC、充电状态实时上报PIC18F86J16 的 ADC 和 I2C低功耗状态切换睡眠态把整机电流压到微安级MCU Sleep PMIC 中断唤醒过温/过流/欠压保护异常时快速断电不依赖软件运行PCA9422 硬件保护为主MCU 软件复核请注意最后一条保护逻辑放进 PMIC 硬件里是底线。MCU 里写再周全的保护策略一旦代码跑飞、芯片复位保护就失去了意义。硬件保护是安全底裤MCU 策略只是外套。1.2 让 PMIC 管功率MCU 管脑子一开始我也想过全部用软件做MCU 的 GPIO 控制几颗 LDO 的使能脚用 ADC 采样电压自己维护充电曲线。看起来省了一颗 PMIC实际做下去会发现两个问题一是线性充电方案在压差大的时候发热明显CC/CV 切换靠软件也容易过冲二是所有保护都挂在固件上任何异常死机都可能导致过充或过放。后来换成 PCA9422 后功率部分全交给硬件充电电流、截止电流、路径切换、输出级保护都由 PMIC 内部机制完成MCU 只是读状态、做策略。这样即使 MCU 正在被调试器复位、代码还没跑起来电池充电也不会失控系统仍能保持安全的供电状态。电源管理单元的定位就是“功率执行层”PIC18F86J16 的定位则是“策略控制层”。两者分工明确调试时也容易定位问题电压不对先查 PMIC 配置行为不对先查 MCU 状态机不用再像以前那样满板子追信号。1.3 8 位 MCU 为什么够用以及为什么是这颗电源管理这类任务有个特点事件频率低但分支逻辑多。充电过程的变化发生在分钟量级USB 插拔和按键唤醒是秒级甚至更长真正需要 MCU 处理的高频计算很少。这种情况下 32 位主控的优势发挥不出来反而把待机功耗和调试复杂度抬上去了。PIC18F86J16 满足我对“电源协处理器”的几乎全部要求I2C 主机接口连接 PMICADC 通道监测电池电压和 NTC可配置中断输入用于唤醒多个 IO 控制外部负载开关。工作电压范围也能覆盖常见的 3.3V/1.8V 数字系统直接由 PCA9422 的输出轨供电。这就像给电源子系统配了一个专职管家主控只管业务逻辑不用每隔几毫秒就去关心充电电流有没有到位。2. 硬件连接从拓扑到 PCB 的每一个关键点2.1 先定电源轨再连线我习惯先把电源轨拓扑画出来再决定每一路怎么接。PCA9422 执行路径管理和降压转换PIC18F86J16 作为负载挂在输出轨上同时用 GPIO 控制外设供电的通断。我这次原型的电源轨分配如下电源轨负载对象电压设置备注VBUSUSB 输入5V输入端加 TVS 和滤波BAT单节锂电池2.9~4.2VNTC 放在电池附近SYS系统主总线跟随 PMIC 路径给后级轨提供源头Buck1MCU 及数字接口逻辑1.8V纹波要求相对高Buck2传感器、显示偏置部分2.8V可独立关断分轨的原则是把数字负载和模拟负载分开。数字电路的高频开关噪声容易通过电源轨串到模拟部分导致 ADC 读数跳动或传感器信号被污染。Buck1 给纯数字部分Buck2 给模拟和传感器部分两者之间用磁珠或负载开关隔离实测效果比单轨并联好得多。连接顺序上PIC18F86J16 的 VDD 接 Buck1同时通过二极管或负载开关接 SYS 作为备用路径。这样如果 Buck1 因为瞬态过载跌落了MCU 也不会立刻彻底断电给软件留下做掉电保存的时间。2.2 I2C、中断与引脚映射的接法PCA9422 的 I2C 从机地址有固定值和可选位上电后 MCU 通过标准 I2C 读寄存器。SDA、SCL 各接一颗上拉电阻到 SYS注意上拉电压要和 MCU 的 IO 电平匹配。我用的 4.7kΩ 电阻400kHz 快速模式下总线容抗不大实测波形边沿干净。如果总线较长可以考虑降到 2.2kΩ。IRQ 引脚是开漏输出必须加上拉。我把它接到了 PIC18F86J16 的一个可唤醒中断输入上同时把 PMIC 的几个关键事件都开放到这根线上充电完成、USB 插入/拔出、电池进入低电压区间、供电路径切换。MCU 在中断服务程序里做的第一件事就是通过 I2C 读出状态寄存器并清除标志否则中断源会一直挂着造成持续唤醒。PIC18F86J16 如果有可配置的引脚映射功能布局会轻松很多。我当时把 SCL 和 SDA 映射到了靠近 PMIC 的两个空余引脚上避免跨过板子拉长走线。如果你的型号不支持这种映射就按原引脚布线功能上没有区别只是走线要绕一点。2.3 PCB 布局里的硬教训PCB 布局是这类型电源方案最容易翻车的地方。第一是输入和输出电容必须贴在对应引脚旁边不是“原理图上有就行”。PCA9422 的开关节点电流变化很快电容离引脚超过 5mm寄生电感就会让纹波明显变差。我实测同样一颗 PMIC电容贴脚和电容拉线放置纹波差了一倍多。第二是降压电感下方的铜皮处理。电感正下方不要铺大块地铜否则涡流会让电感温度上升还可能在特定负载下产生噪音。我把电感区域做了禁布区只在周围留出回流路径。第三是反馈采样走线。Buck 输出电压的反馈走线要从输出电容后端单独拉不要经过功率路径或靠近电感否则采样到的是被污染的信号轻则输出电压偏重则环路不稳定。NTC 的位置也要注意别放在电感和 PMIC 附近充电时 PMIC 发热会让 NTC 提前触发过温保护我就吃过这个亏。3. 软件状态机电源管理的灵魂在策略3.1 上电初始化让 PMIC 和 MCU 先握上手硬件焊接完成只是第一步。软件侧的第一个任务不是立刻配置所有电源轨而是先确认 PMIC 在线、状态可读。我会在 MCU 上电后先关闭不必要的外设避免在 PMIC 还没稳定时就去拉高 I2C 总线或者让负载开关提前动作。初始化流程大致是这样void pm_power_init(void) { // 1. 等待 PMIC 稳定轮询器件 ID for (uint8_t i 0; i 10; i) { uint8_t id pmic_read_reg(PMIC_REG_DEV_ID); if (id PMIC_EXPECT_ID) { break; } delay_ms(20); } // 2. 读取电源输入来源判断是 USB 还是纯电池 uint8_t status pmic_read_reg(PMIC_REG_STATUS); // 3. 按运行模式设置 Buck 电压 pmic_write_reg(PMIC_REG_BUCK1_VSEL, 0x1B); // 1.8V 档位 pmic_write_reg(PMIC_REG_BUCK2_VSEL, 0x23); // 2.8V 档位 // 4. 清中断开放需要的事件 uint8_t irq_src pmic_read_reg(PMIC_REG_INT_STATUS); pmic_write_reg(PMIC_REG_INT_MASK, PMIC_IRQ_USB_BIT | PMIC_IRQ_CHG_DONE_BIT | PMIC_IRQ_LOW_BATT_BIT); }这里的寄存器地址和档位数值只是一种映射关系具体以你手里的数据手册为准。关键是流程先确认通信正常再读取来源再写输出最后统一清中断。顺序反了的话可能出现 MCU 以为 PMIC 正常实际上 PMIC 正在异常状态里反复重试的情况。3.2 锂电充电状态机的实际编写锂电池充电的标准流程是预充 → 恒流 → 恒压 → 截止 → 补充。PCA9422 硬件负责执行这些阶段但 MCU 需要读取状态、判断是否在正常范围内还要结合温度做策略上的干预。我用一个简单的枚举类型来维护充电状态typedef enum { CHG_NO_POWER, // 无输入电源 CHG_TRICKLE, // 预充 CHG_CC, // 恒流 CHG_CV, // 恒压 CHG_DONE, // 充电完成 CHG_RECHARGE, // 补充充电 CHG_FAULT // 温度或电压异常 } charge_state_t;每次 I2C 读取到新状态后根据电池电压和充电状态寄存器做状态迁移。比如电池电压低于 2.9V 时进入预充充电电流不能按正常值设置电压升到 3.0V 以上进入恒流电压到达 4.2V 附近PMIC 自动转恒压电流开始下降电流衰减到设定值的十分之一左右进入完成状态之后电压回落到补充阈值重新开始充电。温度控制要放在软件里再做一道保险NTC 读数超过 0~45℃ 范围时不管 PMIC 还在不在充MCU 都先关闭充电或降低电流。硬件保护管极端情况软件保护管数据合理性两者叠加才能真正安全。3.3 动态调压用 I2C 改变输出而不是改硬件动态调压是这套方案里最值钱的功能之一。以前要改电压得换电阻分压、换稳压芯片现在 MCU 跑一段代码就能改变 Buck 输出档位。比如系统在活跃状态时 Buck1 保持 1.8V让 MCU 全速运行进入轻度睡眠时可以降到 1.2V让数字逻辑的功耗进一步下降深度睡眠时甚至可以把 Buck2 直接关断。void set_active_power_profile(void) { pmic_write_reg(PMIC_REG_BUCK1_VSEL, VOLT_1V8); pmic_write_reg(PMIC_REG_BUCK2_VSEL, VOLT_2V8); pmic_enable_buck2(); } void set_lowpower_profile(void) { pmic_disable_buck2(); // 先关外部重负载 pmic_write_reg(PMIC_REG_BUCK1_VSEL, VOLT_1V2); pmic_write_reg(PMIC_REG_BUCK2_VSEL, VOLT_0V9); // 保留待机档 }调压的顺序很有讲究先关掉大电流负载再降电压最后再开启负载。直接带载降压会导致输出端电容放电过快MCU 和传感器可能在切换瞬间掉电复位。如果电压档位跨度大尽量分成两步走而不是一步从 3.3V 跳到 1.2V。3.4 深度睡眠与唤醒链路把待机功耗压下去低功耗设计的核心不只是 MCU 进入 Sleep而是整个供电链路都进入低功耗状态。我会在睡眠前把 I2C 外设停掉、ADC 通道关闭、未使用 IO 设为输出低或者高阻再通过 I2C 让 PMIC 把输出电压降到低功耗档位然后 MCU 执行 SLEEP 指令。唤醒链路要保证 PMIC 的 IRQ 能够拉活 MCU。我在中断配置里把 IRQ 脚设为下降沿唤醒PMIC 任一事件都会把 IRQ 拉低MCU 醒来后第一件事是读状态寄存器并清除中断标志然后再恢复 I2C 和 ADC延迟几十毫秒等电源轨稳定后继续业务。这里最容易犯的错是 IRQ 上没有上拉电阻或者上拉电压来自被主动关断的电源轨。IRQ 开漏引脚如果没有上拉电平永远悬空PMIC 拉低时 MCU 能收到信号释放后又无法回到高电平中断状态会一直粘住。4. 调试时踩过的几个坑4.1 第一次上电 I2C 读 NACK复位后又正常现象很经典开发板上电后 MCU 去读 PCA9422 的器件 ID返回 NACK手动按一下复位再读就正常。一开始怀疑是焊接问题补焊后依旧如此。后来定位到是上电时序PMIC 输出轨起来需要时间MCU 跑得比 PMIC 快得多I2C 模块已经开始工作PMIC 还没就绪。解决方法是初始化时增加 50~100ms 的起步延时并且轮询器件 ID最多重试 10 次。这个经验直接写进了所有项目的上电流程成本很低收益很大。4.2 一开机就进中断IRQ 风暴调试时发现 MCU 几乎一直停在中断里业务逻辑根本没机会跑。看 IRQ 引脚波形低电平持续不断。查 PMIC 状态寄存器时发现充电完成标志位一直置位但这个标志位属于“状态寄存器”读取本身不会清除必须写清除命令。这就是 IRQ 处理设计的问题。正确做法是中断服务程序里一次性读出所有中断源确认后清晰对应标志位而不是只读一个寄存器就返回。我后来把“读状态—清标志—再检查一次是否还有未处理中断”写成了固定套路IRQ 风暴基本绝迹。4.3 “一使劲就关机”电池电压反转的误判设备接上电机或无线模块时负载电流瞬间冲到几百毫安电池内阻加上线阻Vbat 在采样点瞬间掉了几百毫伏。MCU 检测到电压低于关机阈值直接触发关机电池实际还有电。这种问题在电池供电设备里非常典型。解决分两层硬件上在电池电压采样点加 10kΩ 和 1μF 左右的低通滤波软件上用滑动平均和窗口判断连续多次低于阈值才执行关机动作。同时关机阈值要加迟滞比如 3.2V 触发3.4V 才能恢复避免在边界反复开关机。4.4 睡眠后醒不过来中断源被自己屏蔽了有一版固件在进入睡眠后怎么都唤不醒示波器看 IRQ 引脚确实有低电平脉冲MCU 却没有任何反应。查到最后是中段掩码寄存器里把 USB 插拔事件屏蔽了而测试时用的是 USB 供电唤醒硬件拉了电压PMIC 也发了事件但软件没开放这个中断源。这提醒我每次进入睡眠之前要把唤醒依赖的事件源逐项核对一遍当前是电池供电还是 USB 供电期望的唤醒方式是充电完成、按键还是 USB 插入不同场景开不同的中断掩码而不是一刀切全部屏蔽。建议把这些配置封装成一组函数根据电源来源选择掩码。4.5 动态调压时把系统调崩了我最早在调压代码里直接写 3.3V 档位切换到 1.2V 档位寄存器写下去的一瞬间外部传感器先掉电接着 MCU 掉电复位。原因就是前面提到的那条带载跳变电压输出电容放电时间不够。改成两步降档后问题消失先关掉 Buck2 和外部负载开关再把 Buck1 从 3.3V 调到 1.8V确认稳定后再进一步调低。升压时反过来先写高档位等输出电压稳定、IRQ 的电源正常事件确认后再打开外部负载。看 PMIC 的状态寄存器判断输出就绪比固定延时更可靠。5. 实测数据与参数取舍5.1 充电参数的取舍充电电流我最终设置在 500mA。原因很简单用的是 1500mAh 左右的电池0.5C 充电对寿命和温升都比较友好。PCB 在 25℃ 环境下跑满充PMIC 表面温度大约只比环境高 8℃ 左右NTC 读数也稳定。如果为了缩短充电时间强行上 1000mA热设计、电池寿命、供电输入端的压降都要重新评估小体积产品里通常划不来。截止电流取设定电流的十分之一也就是 50mA 左右。这样既能保证电池基本充满又不会让尾巴拖太长。补充充电阈值用默认值实测电池充满静置一晚后电压回落到 4.1V 附近能触发一次很短的补充充电对容量恢复效果明显。5.2 各电源轨的实测情况电源轨标称电压实测输出纹波最大瞬态跌落Buck11.8V1.803V低于 30mV约 90mVBuck22.8V2.796V低于 40mV约 120mVSYS 总线3.3V 档3.29V低于 50mV约 150mV瞬态跌落是在加一个 160mA 阶跃负载时测的。这个参数对 MCU 供电很敏感PIC18F86J16 的工作电压下限通常留有裕量90mV 的跌落完全能承受。如果你把 MCU 换成对电压更敏感的射频器件就需要在主电源输出侧再补大电容或者调高 Buck 的相位余量。5.3 整机功耗拆解整机功耗是这套方案的重点验收项。实测分三种状态状态电流说明活跃运行约 58mA 3.3VMCU 全速 传感器工作轻度待机约 410μABuck 降压档 保持 RTC深度睡眠约 12μAPMIC 保持 MCU Sleep关闭 Buck212μA 的深度睡眠电流包含了 PMIC 自身的维持功耗、MCU 的睡眠电流以及电源采样通路上的漏电流。如果想把待机功耗压到 5μA 以下还需要额外切断采样分压电阻的供电或者选择带更高集成度的低功耗 PMIC。对多数便携设备来说12μA 已经足够支撑长待机了。5.4 下一次改版我会做的调整这次试制板给了我两个明确改进方向。第一是把 NTC 从 PMIC 附近移到电池组负极位置直接测量电池温度避免充电温升造成的误保护。第二是给 Buck2 增加一路负载开关把传感器和显示屏的供电完全隔离在深度睡眠时不仅关 Buck2连输出端的电容漏电也一并切断预计能把待机电流再降 2μA 左右。6. 再进一步什么叫“完整”的电源管理6.1 从电压估算到精确电量计目前的方案通过电池电压查表估算电量胜在零成本但精度有限。电池在使用中的电压会随负载波动同一电压在不同温度下对应的剩余电量能差 15% 以上。如果你的产品需要更精确的剩余电量百分比可以考虑在电池回路里串联库仑计芯片或选择内部带计量的 PMIC。MCU 侧只需要把原有状态机里“电压估算 SOC”的模块替换成“读取库仑计 SOC”结构不需要大改。6.2 电源时序与负载开关有些传感器和显示屏要求上电顺序比如先供模拟电源再解复位最后使能接口。PCA9422 的输出轨只是基础外部负载开关可以提供更灵活的上电顺序控制。每个负载开关由 PIC18F86J16 的 GPIO 控制软件状态机里把启动和关断顺序做成配置表支持不同外设组合的时序管理。6.3 固件升级与异常工况的电源预算电源管理还要考虑运行时的极端工况。固件升级时无线模块或 USB 接口会拉高电流电池接近底电时升级容易中途断电变砖。我的做法是在进入升级模式前先判断电池电压和充电状态如果剩余电量不足以支持整段升级就强制插 USB 供电才开始。这套逻辑往里加代码只有一小段但能实实在在避免很多售后问题。我个人的体会是电源管理这套东西芯片选型反而不是最难的最难的是把“什么时候该做什么”定义清楚。PCA9422 把功率执行做到位PIC18F86J16 把策略和状态机管起来剩下的就是无数次上电、睡眠、唤醒、充电、放电的交叉测试。每次打样我都会先做一块 PMIC 最小系统把寄存器和中断读通再画主力载板这个习惯帮我省下的调试时间远比多花的那点板子面积值钱。