资讯详情

用MCU管理PMIC:PCA9422与PIC18F86K90的电源管理设计与动态调压实践

📅 2026/10/24 1:28:53 | 华诺云谱 👁 阅读
用MCU管理PMIC:PCA9422与PIC18F86K90的电源管理设计与动态调压实践
做多路供电设备的时候我一开始也是老老实实三片 DC-DC 加两片 LDO 分开布局。原理图看着简单调起来真不简单上电顺序、负载瞬态纹波、休眠功耗哪一项都够折腾。后来我把电源部分整体换成 PCA9422 这颗 PMIC再让 PIC18F86K90 通过 I2C 去配置它、监测它、切换它的工作模式整套电源才算真正管起来。这篇就把这套组合的硬件接线、固件状态机、动态调压过程以及我实际踩过的几个坑完整写出来。对正在做多轨供电、低功耗便携设备或者好奇怎么用 MCU 管理 PMIC 的工程师来说这应该是一份能直接上手的参考。1. 为什么选 PCA9422 PIC18F86K90 这个组合1.1 PCA9422 的电源骨架PCA9422 是一颗集成度比较高的电源管理芯片内部集成了 3 路 DCDC 降压转换器和 2 路 LDO可以同时输出多路电压基本覆盖一个典型嵌入式系统的电源需求。DCDC 适合给 CPU 核心、DDR、外设这种电流需求比较大的负载因为开关电源的转换效率高在大电流下发热少LDO 则适合给模拟前端、PLL、低速接口这类更在意输出噪声的电路LDO 输出纹波小对负载瞬态的响应也相对温和。这颗芯片最吸引我的地方是所有输出电压都由内部寄存器控制不是靠外部电阻分压决定。这就意味着固件可以在系统运行过程中直接修改某一路输出电压实现真正的动态调压DVFS。比如 CPU 降频时把核心电压从 1.0V 降到 0.9V动态功耗和漏电流都能明显降下来频率拉高之前再把电压补回去保证时序裕量。除此之外PCA9422 内部还集成了限流保护、过温保护、输入欠压检测等常见电源保护逻辑并且有一个中断输出引脚。只要芯片内部检测到异常就会主动通知 MCUMCU 不需要一直轮询寄存器处理故障的实时性会好很多。这里要说明一点具体的输入电压范围、输出电压范围和寄存器地址映射每个封装批次都会有详细手册说明我后面提到的数值都是基于常见配置真正做项目时一定要以你手里那本数据手册为准。1.2 PIC18F86K90 在系统里到底管什么PIC18F86K90 在这里并不是系统的主处理器而是一个电源管理协处理器说白了就是整个系统的“电源管家”。它有多个 MSSP 模块可以用硬件 I2C 和 PMIC 通信有 12 位 ADC可以检测输入电压、电池电压、温度还有外部中断引脚用来快速响应 PMIC 的告警。更关键的是这颗 MCU 有很丰富的低功耗休眠模式系统待机时它自己可以睡得非常深同时保留 RTC 或者外部唤醒源有事件发生再快速醒来。这一点在做电池供电设备时特别值钱。另外PIC18F86K90 本身还带一个片上 LCD 驱动控制器。如果设备上需要显示当前电压、工作模式、故障代码这些信息不需要再额外接一颗显示驱动芯片MCU 直接驱动 LCD 屏就行。这样整个电源管理子系统的成本很低PCB 面积也被压得很小。我更愿意把 PIC18F86K90 的角色理解成“决策者”PCA9422 负责执行电压转换和保护动作但什么时候调压、什么时候关电源轨、什么故障对应什么处理策略这些决策都由 PIC 来做。这个分工是完整的、闭环的比单纯把 PMIC 当稳压器用要高明得多。1.3 分离器件方案和 PMIC 方案的实际差异很多人会觉得“三路 DCDC 两路 LDO”分开画也没什么问题我一开始也是这么想。可真放在一个要量产的系统里差别就出来了。我整理了一张对比表基本说明了为什么我最终转向集成 PMIC 方案。对比项分离器件方案多颗 DCDC/LDO集成 PMIC 方案PCA9422上电时序控制需要 MCU 用多个 GPIO 依次控制使能脚软件控制时序逻辑繁琐芯片内部可编程时序MCU 写入配置即可上电自动执行输出电压调整靠外部电阻分压改电压必须换电阻或者加 DAC通过 I2C 改寄存器运行中可动态调压静态功耗每颗芯片都有自身静态电流数量多时待机功耗明显偏高单芯片集成低功耗模式统一管理待机电流容易压得低保护功能每路需要额外设计过流/过温保护电路芯片内部集成状态可读异常可中断PCB 面积与 BOM器件数量多布局分散电感电容一大堆单芯片加少量外围面积和采购成本优势明显先说结论分离方案并不是不能用它成本更低选型灵活适合电源轨很少、不需要频繁调压的设备。但如果你想做“完整电源管理”也就是运行中动态调压、待机自动关断部分电源轨、故障主动上报、软关机不掉数据分离方案会非常痛苦。PMIC 方案的优势不仅在于集成度高更在于“所有状态都能被固件读到所有输出都能被固件改”这才是真正意义上的可管理电源。当然集成 PMIC 也有门槛最大的门槛就是寄存器配置。刚开始接触时会觉得寄存器数量多不知道从哪里下手。我的经验是不要被手册吓到先只关注 ID 寄存器、电压配置寄存器、使能寄存器、中断状态寄存器这几个关键块跑通第一条 I2C 通路后面都是查表填值的事情。2. 硬件连接与电源拓扑设计2.1 电源分配架构我做的是一个便携式采集设备外部输入 5V系统主控需要多路电源轨。PCA9422 的输出分配如下DCDC1 输出 0.9V 给系统主控核心DCDC2 输出 1.8V 给逻辑和内存接口DCDC3 输出 3.3V 给外部传感器和外设接口LDO1 输出 2.8V 给模拟采集前端LDO2 输出 1.2V 给对噪声敏感的锁相环和部分模拟电路。另外还需要一路备用电源域用来在系统深度睡眠时给 RTC 和唤醒逻辑供电这正好可以接 PCA9422 的保留输出域。这样的分配思路是大电流、电压变化频繁的负载走 DCDC因为开关电源效率高小电流、对噪声敏感的负载走 LDO因为干净。启动顺序方面先建立核心电源轨再建立外围电源轨最后启动模拟电源轨。如果系统有明确的上电先级需求可以直接利用 PMIC 内部的时序控制来配置不需要额外加迟延芯片。PCB 布局上有一点要特别注意DCDC 的电感要靠近芯片引脚走线尽量短粗输出电容放在电感后面。我习惯每一路输出放一个 10uF 陶瓷电容加一个 22uF 陶瓷电容把高频和低频纹波都压一压。电感值通常在 2.2uH 到 4.7uH 之间具体要看负载电流和开关频率按手册推荐值选最稳妥不要自己拍脑袋改。2.2 I2C 控制链路与上拉设计PCA9422 通过 I2C 接口和 PIC18F86K90 通信我使用 MSSP1 模块。SCL 和 SDA 分别接 MCU 的对应引脚再通过两根 2.2kΩ 电阻上拉到 3.3V 电源。上拉电阻的大小很讲究太小会增大灌电流功耗高太大会导致信号上升沿慢通信不稳。在 400kHz 快模式下我一般选 2.2kΩ如果板子上连接线比较长可以降到 1.8kΩ 到 1.5kΩ。I2C 速率建议先从 100kHz 起步。硬件 I2C 通信最怕总线上地址冲突所以要确认总线上没有其他器件使用相同地址。PCA9422 的从机地址会受到 ADDR 引脚电平的影响不同参考设计里的地址可能不一样。我踩过这个坑后面专门讲。代码里要把地址做成宏同时在上电初始化时读回芯片 ID 做确认宁可在初始化时多花 10 毫秒校验也不要等到配置写无效了才发现地址不对。还有个细节I2C 总线上如果同时挂了其他器件比如 EEPROM要注意它们之间的地址会不会撞车。建议画原理图时就把所有 I2C 设备的地址列一张表逐位比对。2.3 使能、中断和电压采样的引脚分配PIC18F86K90 的引脚资源很充足分配起来不紧张。我的分配大致是这样PIC18F86K90 引脚功能说明MSSP1_SCL连接 PCA9422 SCLI2C 时钟线带上拉MSSP1_SDA连接 PCA9422 SDAI2C 数据线带上拉外部中断引脚连接 PCA9422 INTB低电平有效故障触发中断AN0输入电压采样电阻分压后接 ADCAN1电池电压采样分压加滤波电容AN2NTC 温度采样用于系统温度监测GPIO 握手脚连接主控复位/状态脚软关机前通知主控保存数据使能引脚这里多说一句PCA9422 有硬件使能脚但也有通过 I2C 寄存器关断输出的方式。我建议把硬件使能脚接固定上拉始终允许芯片工作具体每一路电源轨的开启和关断都交给 I2C 寄存器。原因是寄存器关断的时序更平滑可以在关断前先通知主控做善后工作直接拔硬件使能太粗暴容易引起系统突然掉电。电压采样电路要处理好分压电阻。输入电压如果是 12V 或者更高分压电阻选高一点阻值比如 100kΩ 对 10kΩ避免采样电路自身消耗过多电流。ADC 引脚上并一个 100nF 到 1uF 的滤波电容采样值会更稳定。3. 固件侧的电源管理状态机3.1 I2C 初始化与芯片 ID 校验PIC18F86K90 的 MSSP1 模块配置成 I2C 主模式7 位地址速率先设成 100kHz。初始化完成后第一件事不是写各种配置寄存器而是读芯片 ID。只有 ID 读回来是正确的才说明硬件链路没问题后面写的所有寄存器才有意义。/* 寄存器地址这里用逻辑命名实际数值以 PCA9422 数据手册为准 */ #define PMIC_I2C_ADDR 0x30 #define PMIC_ID_REG 0x00 void mssp1_init_i2c(void) { /* Fosc 16MHz 时SSP1ADD 39得到 100kHz */ SSP1ADD 39; SSP1STAT 0x80; SSP1CON1 0x28; } uint8_t pmic_read_id(void) { uint8_t id 0; i2c_read_byte(PMIC_I2C_ADDR, PMIC_ID_REG, id); return id; }这段代码里 i2c_read_byte 是封装好的底层函数不同编译器可能写法不同但逻辑都差不多。我特别建议把“读 ID”做成一个独立函数调试时可以直接调用。如果你在板上发现 ID 一直读不到先看波形用示波器抓 SCL 和 SDA确认 START 条件有没有发出去、从机有没有回 ACK。如果从机回了 ACK 但数据是 0xFF多半是地址不对如果一直 NACK要检查上拉电阻、电源和 ADDR 引脚。3.2 输出通道配置的写入流程硬件通路确认没问题之后就可以开始配置各路输出了。我习惯把配置表设计成结构体数组每一行代表一个通道的完整配置包括通道号、输出电压、限流值、是否使能。这样后期要适配不同硬件版本只需要改表不需要改逻辑。typedef struct { uint8_t channel; uint8_t vout; uint8_t ilim; uint8_t enable; } pmic_ch_cfg_t; const pmic_ch_cfg_t sys_power_cfg[] { { PMIC_DCDC1, VOUT_0V90, ILIM_1500MA, EF_ENABLE }, { PMIC_DCDC2, VOUT_1V80, ILIM_1200MA, EF_ENABLE }, { PMIC_DCDC3, VOUT_3V30, ILIM_1000MA, EF_ENABLE }, { PMIC_LDO1, VOUT_2V80, ILIM_300MA, EF_ENABLE }, { PMIC_LDO2, VOUT_1V20, ILIM_200MA, EF_ENABLE }, }; void pmic_apply_configuration(void) { uint8_t i 0; for (i 0; i sizeof(sys_power_cfg) / sizeof(sys_power_cfg[0]); i) { i2c_write_byte(PMIC_I2C_ADDR, sys_power_cfg[i].channel, sys_power_cfg[i].vout); i2c_write_byte(PMIC_I2C_ADDR, sys_power_cfg[i].channel 1, /* 假设限流寄存器紧随其后 */ sys_power_cfg[i].ilim); i2c_write_byte(PMIC_I2C_ADDR, sys_power_cfg[i].channel 2, /* 假设使能寄存器紧随其后 */ sys_power_cfg[i].enable); } }注释里我用“假设”就是为了提醒具体寄存器偏移要看手册不要照抄。写配置的时候建议暂时关掉全局中断因为 PIC 的硬件 I2C 模块在字节传输过程中被中断打断容易出现未完成的事务。如果一定要开中断至少 I2C 中断优先级要设成最高并且主循环里别出现耗时太长的临界区。配置写入完成后PMIC 的输出电压会快速跳变到目标值不需要额外等待。但如果你发现写入后输出电压没有变化查两件事一是有没有写错寄存器地址二是这个芯片是否要求写入后额外置位一个 commit 位才生效。后者在带影子寄存器的 PMIC 中很常见具体看手册的“寄存器更新模式”章节。3.3 运行/待机/软关机状态切换逻辑电源管理最核心的其实是状态机。我维护了三个主状态运行态、待机态、软关机态。运行态下所有电源轨正常输出PIC 定时轮询状态寄存器和 ADC 采样值待机态下关闭大电流外设轨保留核心和唤醒电路软关机态则把所有主电源轨关掉只保留备用电源域给 RTC 和唤醒逻辑。状态输出电压状态PIC 状态唤醒源RUN全部输出正常正常运行ADC 轮询按键、通信事件STANDBY关闭 DCDC3、LDO2保留核心轨进入低功耗休眠定时唤醒、外部中断SOFT_OFF关闭全部主输出只保留备用域深度睡眠按键、RTC 定时状态切换的流程必须严谨。以软关机为例PIC 先通过握手引脚通知主控保存数据收到主控应答后再写 PMIC 关机寄存器最后 PIC 自己进入深度睡眠。绝对不能跳过“通知主控”这一步直接切电源否则主控可能正在写 Flash突然断电轻则丢数据重则文件系统损坏。状态切换之后还要读回 PMIC 状态寄存器确认目标状态已经达到了。如果超时没达到要记录故障状态并回滚到上一个有效状态而不是卡在中间状态。待机态的逻辑有点意思。我把 DCDC3 和 LDO2 关掉之后系统功耗能降一大截但保留的 DCDC1 仍需要持续给主控核心供电否则主控没法在外部事件到来时快速唤醒。PIC 自己进入休眠之前把唤醒源配置好比如按键边缘中断、定时器溢出、主控握手引脚跳变。这样整个系统在典型待机场景下板级功耗可以压到几十微安级别。4. 动态调压与故障处理4.1 在线电压调整的实现动态调压是这套组合里最有意思的功能。系统运行时PIC 根据主控的工作频率请求通过 I2C 实时修改 DCDC1 的输出电压。调压的原则是“升频先升压降频后降压”主控频率准备提高前先把电压写高等电压稳定后再提高频率频率降下来之后再把电压降回去。这个顺序如果反了主控在电压不足的情况下高频运行轻则跑飞重则造成逻辑误翻转非常危险。uint8_t pmic_set_dcdc1_voltage(uint8_t vout_code) { uint8_t status 0; status i2c_write_byte(PMIC_I2C_ADDR, PMIC_DCDC1_VOUT, vout_code); return status; }实际调压时我会先用示波器探头夹在输出电容两端看着输出电压曲线改寄存器。步进幅度如果比较大比如从 0.9V 直接调到 1.2V建议分两次写中间隔 1 到 2 毫秒让 DCDC 环路有时间稳定避免输出出现过冲或者跌落。过冲 100mV 对某些主控来说已经是极限了一定不要图快。DVFS 除了能省电还可以做温度控制。当 NTC 温度偏高时PIC 主动请求主控降频同时把电压降下来整机功耗和发热都能明显缓解。这在便携设备上非常实用相当于用电源管理做了热管理的第一道防线。4.2 中断与故障联动PCA9422 的 INTB 引脚是低电平有效我把它接到 PIC 的外部中断引脚。芯片检测到输入欠压、过温、输出过流等异常时会主动把 INTB 拉低。PIC 在中断里不要做完整的 I2C 读操作正确做法是只置一个故障标志位然后立刻退出中断回到主循环后再去读中断状态寄存器。这样做是为了避免 I2C 通信过程本身被其它中断打断导致读到的状态不完整。volatile uint8_t pmic_int_flag 0; void __interrupt() high_isr(void) { if (INT0IF) { pmic_int_flag 1; INT0IF 0; } }主循环里发现 pmic_int_flag 被置位就调用故障处理函数读中断状态寄存器确认具体故障类型然后按策略处理。不同故障对应不同动作。输入欠压时先通知主控保存数据然后执行软关机过温时先降频降负载看温度能不能回落过流时关掉故障电源轨保留其它关键轨同时记录故障码到非易失存储。故障码很重要设备返修时可以通过读取故障码快速定位问题。刚开始做故障处理时容易贪多想在 ISR 里把状态一次读清楚。我的建议是千万不要这样做。中断里只置标志主循环里慢慢处理哪怕处理延迟几十毫秒对整个电源管理子系统来说也完全可以接受。稳定可靠比实时响应更重要。4.3 状态监测与安全关断链路PIC 的 12 位 ADC 会定期采样输入电压、电池电压和 NTC 温度。采样周期我放在主循环里每 100 毫秒采一组换算成真实电压和温度后和阈值比较。输入电压如果缓慢下降说明外部电源可能即将断开PIC 可以在低压保护触发之前就主动发起安全关断给系统多留一部分保存时间。安全关断链路是这样的PIC 检测到输入电压低于阈值后先通过握手引脚通知主控进入保存模式主控保存完成后会给出应答信号PIC 收到应答后写 PMIC 关机寄存器把全部主输出关闭确认 PMIC 进入关闭状态后PIC 自己再进入深度睡眠。这个链路里任何一步超时都要有故障兜底我设了 500 毫秒超时超时后不管主控有没有应答都强制进行后续动作保证系统不会无限期停在半死状态。状态监测的另一个用处是记录电源历史。PIC 把每次异常事件的类型、时间戳、当前电压值写到 EEPROM长年累月之后可以画出电源健康状况曲线对分析现场问题非常有帮助。这也许不算产品必需功能但做过现场维护的人都知道这套数据有多省心。5. 实测结果与踩坑记录5.1 关键电性能实测数据硬件和固件都调通之后我专门对电源部分做了一轮比较完整的实测。测试条件是输入 5V输出端并接 10uF 陶瓷电容示波器探头使用 20MHz 带宽限制测量点尽量靠近负载端。一组典型数据如下输出通道目标电压负载电流实测纹波DCDC10.9V1.2A12mVppDCDC21.8V0.9A15mVppDCDC33.3V0.6A18mVppLDO12.8V180mA8mVppLDO21.2V120mA8mVpp待机功耗方面整板在 STANDBY 状态下实测工作电流约 28 微安SOFT_OFF 状态下约 15 微安这个数据让我比较满意。DVFS 从 0.9V 升到 1.1V输出电压稳定时间大约 200 微秒。整套方案在常温下连续运行了 72 小时没有出现电源轨跌落或者看门狗误复位。这里要说明一下这些数据只是我手里这块样板在特定测试条件下的结果不同批次芯片、不同 PCB 布局、不同负载特性都会带来差异。想拿到稳定数据关键还是按照数据手册的推荐布局和外围参数来设计。5.2 值得记录的三个坑和排查链路第一个坑是 I2C 地址读不通。上电后我按参考设计写的 0x54 地址去读 ID结果一直在等 ACK波形显示主机发完从机地址后收到的是 NACK。排查时我先用示波器确认 SCL/SDA 电平正常然后用总线扫描程序把所有 7 位地址都扫了一遍才发现实际地址因为 ADDR 引脚接法不同变成了 0x30。解决办法很简单地址宏改成实际值同时保留读 ID 校验逻辑以后换板子也能自动发现地址不对的问题。第二个坑是上电瞬间输出电压不是配置值。示波器抓 DCDC1 的上电波形发现电压先爬到 1.1V再降到配置的 0.9V中间还维持了大约 100 毫秒平台。这是因为 PMIC 在 PIC 初始化完成之前用的是默认启动电压。如果负载不允许短暂过压要么在硬件上把默认配置引脚设置成正确电压要么增加一个负载开关等配置完成后再接通负载。我这套系统的主控能容忍短时过压所以只做了软件快速配置。第三个坑是 DCDC 开关噪声串进 I2C。现象是系统在大电流负载瞬态时偶尔读到错误的寄存器值不是每次都复现很难抓。后来用逻辑分析仪记录完整帧发现错误帧大多出现在 SCL 信号上有毛刺把时钟沿多打了一下导致收发的字节错位。解决措施有三条SCL/SDA 走线远离电感总线对地加 100pF 滤波电容PMIC 的功率地和模拟地单点连接。改完之后跑了很久都没有再复现。5.3 给后来者的三条实操建议第一条先跑通 I2C 回环再画板。拿到 PCA9422 的测试板后先用杜邦线把它接到 PIC 最小系统上写一个最简单的读 ID 程序确认能稳定读回 ID 再开始画正式 PCB。这套预研工作不需要花很多时间但能帮你省掉后面大半的调试时间。第二条寄存器配置一定要表驱动。实际项目里硬件版本会迭代某一路电压从 0.9V 改成 0.8V或者某个通道限流值变了如果配置散落在主循环里改一个参数要找半天做成配置表之后只改一行数据就够了。代码可维护性差距很大。第三条状态机一定要有超时和故障回滚。电源模块最怕卡在中间状态说关没关彻底说开没开完整。给每个状态切换都加超时判断超时就回滚到上一个已知状态并记录错误码。这样系统就算真的出了异常你也能从错误码里快速找到方向而不是对着示波器猜。实际做这套方案下来我最大的体会是电源管理的复杂度不在硬件而在状态。硬件把 PMIC 接好之后剩下的工作几乎全是“如何在正确的时刻做正确的寄存器操作”。PCA9422 和 PIC18F86K90 的组合让我可以随时调压、随时读状态、随时切换工作模式这在分离方案里是不敢想的。最后再分享一个小技巧如果你刚拿到板子先把 I2C 地址封装好写一个最简单的读 ID 函数能在十分钟内确认通信没问题再谈后面的动态调压和故障处理这一定是最快的路径。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑