做便携式设备,尤其是带段码屏、带传感器的电池供电设备,电源管理永远是落在代码之前要解决的事。这次项目用一颗 PCA9422 搭配 PIC18F86J16,把整机从电池输入、多路降压、顺序上电到动态调压、故障保护和电量显示全部收到一个框架里。这套方案跑了一段时间,稳定性、功耗和开发效率都比较满意,我把完整的设计思路、硬件细节、固件实现和踩坑记录整理成文,给正在做类似便携设备的朋友一个可以直接参考的样本。
先说结论:PCA9422 是一颗非常适合低功耗小系统的多路电源管理芯片,PIC18F86J16 则把监控、控制、显示都集成了,两颗芯片组合后 BOM 大幅简化,开发重点从“搭电源”变成了“管电源”。下面按我的实际推进顺序展开。
1. 为什么选用 PCA9422 加 PIC18F86J16 这套组合
1.1 PCA9422 在多节锂电便携系统里解决什么问题
PCA9422 属于多路降压 PMIC,输入范围覆盖单节锂电池的完整电压区间,2.4V 到 5.5V 都能工作。它内部集成了多路降压转换器和 LDO,每路输出电压和限流都可以通过 I2C 寄存器独立配置。最方便的一点是各路 Buck 都支持动态电压调节,也就是 DVS,运行过程中随时可以通过 I2C 把输出电压往上提或者往下降,这正好满足低功耗设备“重负载时拉高电压、轻负载时调低电压省电”的需求。
对比传统做法,如果每一路 3.3V、2.8V、1.8V 都放一颗独立 LDO,电路简单是简单,但效率在电池高压段非常吃亏。以 3.3V 输出为例,电池 4.2V 时 LDO 效率只有 78%,电池 3.6V 时约 91%,而 Buck 转换器在同样输入范围内基本稳定在 90% 以上。如果设备要长时间挂在电池上工作,效率差异会直接变成续航差距。PCA9422 的静态功耗也控制得比较低,待机状态下整颗 PMIC 自身耗电只有微安到几十微安级别,对睡眠电流要求严苛的场景很关键。
另外,PCA9422 自带故障检测和输出状态指示引脚。各路输出电压异常、输入欠压、芯片过温都会触发中断或状态位,MCU 不需要自己去猜电源是否正常,直接读状态、看中断引脚就能拿到结论。这一点在后面做异常保护时帮了大忙。
1.2 PIC18F86J16 承担电源管理里的什么角色
PIC18F86J16 是一颗 8 位增强型 MCU,主频可跑到 64MHz,片内集成 12 位 ADC、多路定时器、MSSP 模块(用于 I2C/SPI),更重要的是还集成了段码 LCD 驱动控制器。在整套电源管理方案里,MCU 不是“被供电的对象”,而是核心管理节点。
具体分工可以列得很清楚:
- 通过 I2C 总线初始化 PCA9422,配置各路输出电压、限流、工作模式。
- 使用片内 12 位 ADC 采样电池电压、充电电流信号、板温和关键负载电流。
- 根据当前系统负载,动态调整 PCA9422 输出电压,实现性能和功耗的平衡。
- 读取 PMIC 故障标志,响应中断,执行安全断电和故障记录。
- 把电池电量、充电状态、电压值等内容直接驱动到段码 LCD 上显示。
这里最省事的是 LCD 驱动部分。段码 LCD 需要特定的偏压和 COM/SEG 扫描时序,传统方案要外挂一颗驱动芯片,而 PIC18F86J16 直接把这块做进 MCU,软件写显存、配置 LCDCON 寄存器就能点亮屏幕。整个电源板的主控、显示、监控都在一颗芯片里,调试和固件升级都简单很多。
1.3 为什么没继续用“LDO 堆叠”方案
很多人会问,做这种小系统,直接 LDO 堆上去不就好了?我最早也是这么干的,直到有一次做温湿度记录仪,发现电池电量从满电到低压,LDO 方案整个生命周期里的平均效率比 Buck 方案低了差不多 15%,待机电流也压不下来。后来换成集成 PMIC,同样的功能,PCB 面积小了一圈,电源部分的 BOM 元件数量大约是原来的三分之一。
用表格对比更直观:
| 方案 | 电源元件数量 | 整机待机电流 | 上电时序实现 | 动态调压 | 故障保护 |
|---|---|---|---|---|---|
| 分立 LDO 方案 | 15~20 | 偏高,低压差 LDO 静态电流大 | 需要额外加延时电路 | 不支持 | 需外接电压监测器 |
| 多路 DC-DC 控制器方案 | 25~35 | 中等 | 需设计反馈补偿与使能逻辑 | 部分支持 | 需外加比较器电路 |
| PCA9422 + MCU 方案 | 8~10 | 低 | 用 PMIC 使能和 MCU GPIO 组合实现 | 原生支持 | PMIC 中断引脚加 MCU 中断 |
分立方案最大的痛点不是效率,而是上电时序和故障保护全靠硬件电路凑,每次改需求都要重新改 RC 延时、改比较器阈值,维护成本很高。PMIC 加 MCU 之后,上电顺序变成软件逻辑,想先开后开哪一路,改代码比改 PCB 容易得多。这也是我最终选这套组合最核心的原因。
2. 电源树与整体架构设计
2.1 先把负载需求拆成电源轨
开始画板之前,我习惯先把所有负载按电压和电流列成一张表。这次设计的模拟项目是一个便携式环境监测仪,包含段码 LCD、温湿度传感器、无线模块、MCU 和背光 LED,各路电源需求如下:
| 电源轨 | 电压 | 最大电流 | 主要负载 | 备注 |
|---|---|---|---|---|
| VDD_MCU | 3.3V | 50mA | PIC18F86J16 及逻辑电路 | 常开 |
| VDD_LCD | 3.0V | 5mA | 段码液晶偏压 | 常开 |
| VDD_SENSOR | 2.8V | 30mA | 温湿度传感器及其他传感 | 按需开关 |
| VDD_WIRELESS | 3.3V | 80mA 峰值 | 无线模块射频发射 | 无线发射时才打开 |
| VDD_ANA | 1.8V | 20mA | 模拟前端与电平转换 | 按需开关 |
把这些需求加起来,整机最大负载大约 185mA,平均负载在 65mA 左右。如果全部用 LDO,在电池 4.2V 时,3.3V 轨的损耗是 0.9V×80mA,大概 72mW,这部分能量全部变成热量。而用 Buck 之后,损耗降到约 20mW 之内,差距非常明显。
2.2 PCA9422 的电源轨分配
PCA9422 内部有多路 Buck 和 LDO,我按负载特性做了如下分配:BUCK1 负责 VDD_MCU 和 VDD_WIRELESS 共用的 3.3V 主轨,因为它需要支持射频信号的瞬态大电流,对动态响应要求最高,交给带 DVS 的主 Buck 最合适;BUCK2 负责 VDD_ANA 的 1.8V 轨,专门给模拟前端用,纹波要求严格一些;LDO 负责 VDD_LCD 的 3.0V 轨,因为 LCD 电流很小,使用 LDO 不会浪费太多能量,还能顺便滤掉 Buck 产生的开关纹波,保证显示不闪;VDD_SENSOR 这一路我用 MCU 的 GPIO 控制一个负载开关,从 BUCK1 引出来后做二次开关。
这样安排有一个额外好处:无线模块发射时,BUCK1 会短暂拉高输出,而传感器和 LCD 不挂在同一路上,瞬态波动不会影响到模拟采样和显示。实际测试中无线发射瞬间,BUCK1 电压跌落幅度小于 50mV,而 LCD 和传感器供电纹波基本没有变化。
2.3 上电时序设计与实现
上电时序是完整电源管理里不能跳过的环节。传感器和模拟器件在欠压状态下可能出现锁存,有些 I2C 芯片在电压爬升到一半时会被意外初始化进入错误状态,因此必须先保证主控稳定,再逐步打开外设。
这套系统我设计了四步上电顺序:第一步,电池接入并经过输入保护后,PCA9422 的 BUCK1 先启动,MCU 开始运行;第二步,MCU 完成自身初始化后,通过 GPIO 打开 VDD_SENSOR,此时传感器才开始上电;第三步,LCD 驱动模块初始化完成,打开 LCD 供电和背光;第四步,无线模块只在需要通信时临时打开,每次通信完成立刻断电。
虽然 PCA9422 支持配置内部的电源序列,但这个项目里我选择了更直观的“GPIO 控制使能”方式,原因是后续如果要调整外设顺序,只需要改固件延时和使能逻辑,不用重新配置 PMIC 寄存器。
2.4 异常保护的四层防线
完整电源管理不是“能输出稳定电压”就完了,真正的价值在于故障状态下系统知道怎么自我保护。我在这里拉了四层防线:
第一层是 PCA9422 自身的输出监控,每一路都有电压阈值检测,输出过压或欠压时立即置位状态寄存器并拉低故障引脚;第二层是 MCU 的 12 位 ADC,周期性采样电池电压、充电电流、板温,发现趋势性异常可以先告警,不用等 PMIC 硬性保护动作;第三层是电池保护电路,处理过流和过放,这层主要在硬件上做,MCU 的固件不参与;第四层是软件看门狗,如果主程序跑飞或主循环卡死,看门狗复位后 MCU 重新初始化 PMIC,避免系统以错误配置长期运行。
这四层各管一段:PMIC 管输出侧,MCU 管策略侧,电池保护管安全侧,看门狗管软件侧。四层叠加之后,不管是电池老化、负载短路还是固件异常,都不会让板子处于无法恢复的状态。
3. 硬件设计实操要点
3.1 引脚连接和 I2C 地址确认
PCA9422 和 PIC18F86J16 之间的连接很简单,核心就是 I2C 两根线加几个控制脚。SCL、SDA 接 MCU 的 MSSP 模块引脚,各加一颗上拉电阻;PMIC 的故障指示引脚接 MCU 的外部中断输入;ADDR 引脚的电平决定芯片的 I2C 从机地址,我这边按数据手册接法拉高,地址 7 位值是 0x25 附近,具体以你手上型号和 ADDR 接法为准。
提示:I2C 上拉电阻不能照抄通用电路的 10kΩ。总线速率 400kHz 时,我习惯用 4.7kΩ;如果打算跑 1MHz,要降到 2.2kΩ 左右。电阻太大边沿变缓,长时间运行偶发 NACK;电阻太小又增加总线静态功耗,睡眠模式下漏电明显。选型时同时考虑上升时间和待机电流两个约束。
另外重要的一点是电平匹配。PCA9422 的逻辑电平是 1.8V 到 3.3V,PIC18F86J16 的 I/O 供电我统一放在 3.3V,这样 I2C 和中断线不需要额外的电平转换,连接最简单。如果你的主控用 5V 供电,那 I2C 线上必须加电平转换或者用开漏额外上拉到 3.3V,不能直接连。
3.2 电感电容选型与计算
Buck 转换器的电感值直接影响纹波和动态响应。经验公式是:
L = (Vin_max - Vout) × Vout / (Vin_max × fsw × ΔIL)
其中 ΔIL 通常取负载电流的 20% 到 40%。以 BUCK1 为例,输入最高 4.2V(锂电满电),输出 3.3V,开关频率约 2MHz,负载最大 130mA,按负载的 30% 计算纹波电流约 40mA:
L = (4.2 - 3.3) × 3.3 / (4.2 × 2,000,000 × 0.04) ≈ 9.8µH
实测后我用的是 10µH、饱和电流 500mA 的电感,输出纹波大约 35mVpp,动态负载响应在可接受范围内。如果电感选小了,纹波会明显变大;选太大则动态响应变慢,无线模块突然拉 80mA 时电压跌落会更严重。
输出电容我全部选了 X5R/X7R 陶瓷电容,容量和耐压按降额规则选,3.3V 输出用 10µF/16V,1.8V 用 10µF/10V,3.0V LDO 输出用 2.2µF 就够了。这里特别提醒一下,陶瓷电容上的直流偏压会造成容量衰减,同容量的 0402 和 0603 在同电压下衰减不同,最好选 0603 或 0805,留足降额余量。
3.3 PCB 布局布线的三条硬性规矩
开关电源布局不好,再好的芯片也会出问题。这次画电源区域时,我给自己定了几条规矩。
第一,最小开关回路要紧凑。输入电容、Buck 输出电感、输出电容和 IC 的功率引脚之间的回路必须围成尽可能小的环路,避免高频电流穿过大面积地平面。理论上这个环路面积越小,辐射越低,电压尖峰也越小。实际画板时,我把输入电容放在 PMIC 电源输入引脚和 GND 引脚的正对面,输出电感贴着开关节点放,反馈采样线远离开关节点。
第二,反馈采样要走到负载端。PCA9422 的电压反馈不能直接从芯片输出脚取,而是要从负载端单独引一根细线回到反馈引脚。如果直接从输出电容上采样,负载线上的压降会导致实际负载电压偏低,尤其在无线模块瞬时拉电时,问题更明显。
第三,功率地和模拟地单点汇接。我在地平面上做了分区,功率地集中在 PMIC 附近,模拟地集中在 ADC 采样和传感器区域,两地在电池负极处通过一个 0Ω 电阻单点连接。这样射频发射的大电流不会在模拟地上产生电压偏置,ADC 读数稳定很多。PMIC 底部散热焊盘要打满过孔阵列到内层地平面,不然连续充电或满载运行时会触发过热保护。
3.4 电池电压采样与电量显示设计
电池电压采样我用的是两个高阻值电阻分压后直接进 MCU 的 ADC。电池最高 4.35V,ADC 参考电压选 3.3V,分压比需要保证最坏情况下 ADC 输入不超过 3.3V。我选 R1=100kΩ、R2=75kΩ,分压比 75/175≈0.4286,4.35V 时输入约 1.86V,余量充足。分压电阻后面并联一颗 100nF 电容滤除高频噪声。
注意:分压电阻不能省大阻值。两个电阻都是 100kΩ 级别,采样支路静态电流在微安级,不影响待机功耗。如果为了省事用 10kΩ 级别,电池一天会额外多耗接近 0.3mAh,长期下来不可忽视。
电量显示我用的是查表法,而不是线性映射。锂电池放电曲线不是一条直线,4.2V 到 3.8V 容量下降缓慢,3.7V 以后掉电速度加快。我先把电压和剩余电量区间做成一张分段表,ADC 读到的电压转换后查表,直接映射到 LCD 上的 10 格电量图标。实测下来,这种方式虽然做不到库仑计那么精确,但作为 UI 展示完全够用,也避免用户看到电量在一小时内从 50% 跳到 10% 的尴尬。
4. 固件实现与核心逻辑
4.1 I2C 底层驱动与总线初始化
电源管理的软件核心是 I2C 通信,PIC18F86J16 的 MSSP 模块配置成主模式即可。初始化代码我写成了模块化函数:
void I2C_Init(void) { SSP1CON1 = 0x28; // I2C 主模式,使能串口 SSP1CON2 = 0x00; SSP1ADD = 9; // 64MHz 主频下约 400kHz,实际按公式修正 SSP1STAT = 0x00; } unsigned char I2C_WriteReg(unsigned char addr, unsigned char reg, unsigned char val) { unsigned char ret = 1; IdleI2C(); StartI2C(); if (WriteI2C(addr << 1) == 0) { // 写地址 if (WriteI2C(reg) == 0) { // 写寄存器地址 if (WriteI2C(val) == 0) { // 写数据 ret = 0; } } } StopI2C(); return ret; }很多人在 I2C 通信上踩坑是因为 Host 已经发送完成,但 PMIC 还在处理上一条命令,紧接着发第二条就出现 NACK。解决方法是每次写寄存器后加一个短延时,或者读状态寄存器确认设备空闲。我在驱动里统一加了 1ms 的延时,代价是配置速度慢一点,但换来的是稳定,尤其是在初始化阶段连续写好几个寄存器时特别管用。
4.2 PMIC 初始化序列与回读验证
固件上电后执行的第一个动作,就是用 I2C 把 PCA9422 各路输出电压和限流配置好。我写了一个初始化函数,按顺序配置 BUCK1 为 3.3V、BUCK2 为 1.8V、LDO 为 3.0V,然后打开输出使能:
#define PCA9422_ADDR 0x25 // 按 ADDR 引脚实际配置 #define REG_BUCK1_VOUT 0x03 #define REG_BUCK2_VOUT 0x04 #define REG_LDO_VOUT 0x06 #define REG_ENABLE 0x00 void PMIC_Init(void) { I2C_Init(); I2C_WriteReg(PCA9422_ADDR, REG_BUCK1_VOUT, 0x0A); // 示例值,以手册为准 I2C_WriteReg(PCA9422_ADDR, REG_BUCK2_VOUT, 0x05); I2C_WriteReg(PCA9422_ADDR, REG_LDO_VOUT, 0x08); I2C_WriteReg(PCA9422_ADDR, REG_ENABLE, 0x07); // 使能全部输出 PMIC_VerifyConfig(); }初始化之后我坚持要做回读验证,不是写完就完了。回读的目的是确认写入的寄存器值和实际生效值一致,防止 I2C 总线上的毛刺导致某一位写错,或者芯片因内部时序问题拒绝接收。这个验证在调试阶段能节省大量时间,正式产品里也等于给电源配置加了一道保险。
之前遇到过一个问题,初始化函数看起来都在执行,但 BUCK1 输出始终是默认电压,怎么改都不生效。后来排查发现是 I2C 写入顺序错了,芯片手册要求输出电压寄存器必须先解锁或处于特定状态才能修改。这提醒我:任何 PMIC 寄存器的操作顺序都必须以你手头型号的数据手册为准,不要想当然地认为所有寄存器都能随时写。
4.3 动态调压与低功耗切换逻辑
PCA9422 支持 DVS 之后,软件上的功耗优化玩法多了很多。正常运行时无线模块需要 3.3V 才能保证发射功率,但进入待机状态后,MCU 和外设实际上只需要维持逻辑状态,这时把 BUCK1 电压降到 2.4V,漏电会大幅下降。低压待机加长睡眠时间,整机电流能做得很低。
实现方法很简单:
void PMIC_SetBuck1Voltage(unsigned char pattern) { I2C_WriteReg(PCA9422_ADDR, REG_BUCK1_VOUT, pattern); } void System_EnterSleep(void) { PMIC_SetBuck1Voltage(0x02); // 降为低电压档 GPIO_LCD_Off(); GPIO_SENSOR_Off(); GPIO_WIRELESS_Off(); // 关闭未用的模拟模块 ADCON0 = 0; // 进入 SLEEP 前确认 I2C 总线空闲 Sleep(); }这里有几点细节需要注意。降电压之前,必须先断开重负载,否则在电压切换瞬间负载电流过大,可能导致输出电压塌陷。我先把无线模块和传感器断电,再降电压,最后 MCU 进入 Sleep,顺序都不能反。唤醒流程则相反,MCU 先醒来,把 BUCK1 电压恢复到 3.3V,等电压稳定后再打开外设供电。
I2C 上拉电阻在睡眠时也会成为漏电源。PMIC 和 MCU 都供电,I2C 线上拉到 3.3V,会持续流过微小电流。我实测中这个漏电在几微安到十几微安之间,对于目标睡眠电流 50µA 的系统来说就是很大占比了。解决办法是 I2C 上拉不要直接接常开电源,而是接到一个由 GPIO 控制的电源轨上,睡眠时把这个轨关掉,或者干脆把 I2C 引脚配置为输入并禁用内部上拉,通过 PMIC 的使能逻辑彻底切断。
4.4 电源状态监控与中断处理
整个系统里,PCA9422 的故障引脚接到 PIC18F86J16 的外部中断 RB0 上,中断优先级设为最高。PMIC 一旦触发故障,MCU 无论在主循环还是睡眠中,都能第一时间进入中断处理。
void __interrupt(high_priority) HighISR(void) { if (INT0IF) { INT0IF = 0; PMIC_FaultHandler(); } } void PMIC_FaultHandler(void) { unsigned char status = PMIC_ReadStatus(); SaveFaultRecord(status); PMIC_DisableAllOutputs(); // 保存关键数据到 EEPROM // 进入安全关机状态 }中断里只做最快、最必要的事:读状态、保存、关输出。其余详细的日志记录和历史故障分析放到主循环里处理。把故障处理放中断而不是主循环,是因为无线模块开启时主循环可能正忙,轮询状态寄存器会有几十毫秒甚至上百毫秒的延迟,而中断响应可以在微秒级完成。对于过压、过温这类故障,晚一步关可能就烧器件了。
4.5 充电管理逻辑与状态联动
完整电源管理里,充电和放电同样重要。PCA9422 负责放电侧的多路降压,充电侧的电池充电我用了独立的充电控制方案,两者共用电池,但管理逻辑都汇总到 MCU。
充电管理我关注几个状态:预充电、恒流充电、恒压充电、充满停止、充电异常。MCU 通过 ADC 检测充电电流采样信号,判断当前处于哪个阶段。充满后不仅充电芯片自动停止充电,MCU 也会在 UI 上把“充电中”图标切到“已充满”。这里有个容易忽略的点,就是充电状态下系统仍然可以运行,充电电流和系统负载电流叠加之后,充电管理芯片上的热量会明显增加。实际测试中,一边充电一边开启无线模块,电池区域温度升高明显,因此我在固件里加了一个策略:充电过程中如果检测到板温超过 45°C,降低无线模块发射功率,温度继续升高则暂停充电。这个策略对延长电池寿命和保证安全都很重要。
5. 实测数据与常见问题排查
5.1 各路电源轨实测指标
整板调试完成后做了连续 8 小时运行测试,数据记录如下:
| 电源轨 | 设定值 | 实测值 | 纹波(峰峰值) | 负载条件 |
|---|---|---|---|---|
| VDD_MCU | 3.3V | 3.307V | 32mV | MCU 全速运行 |
| VDD_LCD | 3.0V | 3.012V | 18mV | LCD 正常工作 |
| VDD_SENSOR | 2.8V | 2.821V | 25mV | 传感器采集 |
| VDD_WIRELESS | 3.3V | 3.291V | 48mV(瞬时) | 无线发射瞬间 |
| VDD_ANA | 1.8V | 1.793V | 12mV | 模拟前端工作 |
VDD_WIRELESS 的 48mV 瞬时跌落发生在无线模块从睡眠切换到发射的瞬间,时间很短,回落也很快。无线模块对电压瞬态的要求通常是跌落不超过 5%,实测 48mV 对应约 1.5%,完全在范围内。如果后续要更严格的指标,可以适当增大 BUCK1 的输出电容,或者把无线模块的使能提前 10ms,避免与 MCU 的高负载操作重叠。
5.2 整机功耗与续航估算
整机功耗测试结果大概分成四档:运行态(LDC 亮、传感器轮询、无线关闭)平均电流约 40mA;无线传输态瞬时电流约 100mA,持续 50ms 后回到空闲;轻负载待机态(LCD 亮、无线关闭、传感器 10 秒一次唤醒)约 6mA;深度睡眠态约 35µA。用 1200mAh 电池估算,如果按每天 10% 时间运行、90% 时间睡眠的使用模型,理论续航在两周左右。如果把 I2C 上拉漏电问题和 PMIC 低压待机都做好,睡眠态还能再往下压。
这个数据是在没有额外优化的情况下测出来的。想要更长续航,可以在不使用时直接关闭整颗 PMIC 的部分输出,用 MCU 的保持引脚再加一颗 MOSFET 实现“总电源开关”,把静态电流压到接近零。
5.3 常见问题速查表
调试过程中踩过一些坑,也帮朋友排查过类似问题,整理成一张速查表:
| 问题现象 | 根本原因 | 解决办法 |
|---|---|---|
| I2C 读不到 PMIC 寄存器 | 上拉电阻过大导致上升沿过缓,偶发 NACK | 把 10kΩ 上拉换成 4.7kΩ,降低总线速率到 100kHz 先验证 |
| 上电后 MCU 不启动 | 复位脚被 PMIC 故障引脚拉低 | 故障引脚用开漏输出,MCU 复位配置为上电复位,不要互相锁死 |
| Buck 输出电压和配置值不一致 | 寄存器写入顺序不对,输出电压要先解锁 | 按数据手册规定的写序列操作,先写解锁位再写电压值 |
| 无线发射瞬间系统复位 | BUCK1 电压跌落超过 MCU 欠压复位阈值 | 增大输出电容、降低输出电感饱和余量、提前降负载 |
| 充电时 PMIC 温度快速升高 | 系统负载和充电电流叠加,散热焊盘没接地 | 检查 PMIC 底部过孔阵列,充电时降低无线发射功率 |
| 睡眠电流偏高 | I2C 上拉电阻和分压电阻持续漏电 | 上拉电阻接 GPIO 控制轨,分压电阻提高到 100kΩ 级别 |
| 段码 LCD 显示内容不稳定 | LDO 输出被数字噪声干扰,公共端波形抖动 | LCD 供电从 LDO 直出,加 1µF 陶瓷电容,布线避开 PWM 走线 |
5.4 两个值得单独说的避坑细节
排障过程中有两个细节,我觉得比那些“标准答案”更能节省时间。
第一个是 I2C 总线上最好加示波器抓波形,不要只依赖逻辑分析仪。之前碰到 I2C 偶发通信失败,逻辑分析仪看时序完全正常,但用示波器一看才发现 SDA 下降沿有振铃,回弹到高电平后又被拉低,造成虚假的起始位。原因是 I2C 走线太靠近 Buck 电感,高频开关噪声耦合进来。解决办法是调整走线,让 I2C 完全避开电感投影区域,同时在 SDA、SCL 各加一颗 22Ω 串联电阻抑制振铃。
第二个是 PMIC 的故障引脚不能直接当 MCU 的复位信号用。刚开始我给 PMIC 故障引脚直接接了 MCU 的 MCLR 复位脚,想着出故障就复位,结果在低功耗调试时,PMIC 每次正常完成上电时序都会把故障引脚短暂拉低,导致 MCU 不断复位,根本无法进入主循环。后来改成接普通 IO 加中断,用软件区分到底是“启动过程中的正常状态翻转”还是“真正需要响应的异常故障”,问题才解决。硬件保护能简单就简单,但逻辑判断一定要交给软件。
最后分享一个印象深刻的细节
做完这套设计,我最大的体会是:电源管理永远不要把所有判断放在主循环里轮询。刚开始我也觉得轮询足够,反正主循环很快,结果一开启无线模块,发射瞬间 MCU 忙着处理数据包,状态采集和判断全被挤到后面,一次过温保护就延迟了好几毫秒。改成中断驱动之后,故障响应速度明显提升,整个系统的可靠性完全不一样。先花时间把 PCA9422 的故障中断链路调通,再去折腾低功耗优化,你会在后续调试中省掉大量时间。