1. 项目缘起与整体设计思路
1.1 为什么要在嵌入式项目里认真做电源管理
很多做嵌入式开发的朋友,尤其是从单片机裸机一路走过来的,对电源管理这件事往往不太上心。板子能跑起来、外设能工作、程序不跑飞,就觉得万事大吉了。但真正做过量产项目的人都知道,一个产品的续航、发热、稳定性,甚至用户口碑,很大程度上取决于电源管理做得好不好。
我这次要聊的项目,核心就是用PCA9422这颗电源管理芯片,配合PIC32MX460F512L这颗经典的单片机,搭一套完整的电源管理方案。PCA9422 是带 I2C 接口的可编程电源管理芯片,内部集成了多个 LDO 和 DC-DC 转换器,还能做电池充电管理、电量计、系统复位控制等。PIC32MX460F512L 则是 Microchip 家基于 MIPS 内核的 32 位单片机,主频能跑到 80MHz,带 USB、CAN、以太网等丰富外设,在很多工业控制和消费电子里都能见到它的身影。
把这两颗芯片组合在一起,目标很明确:让整个系统能根据工作状态动态调节各路电源的输出电压和开关状态,同时监控电池电量、温度、充放电状态,在异常时能安全地切断或复位。这套方案适合谁呢?如果你正在做便携式设备、手持终端、工业数据采集器,或者任何需要电池供电且对功耗敏感的产品,那这套组合拳值得你花时间研究。
1.2 方案选型的背后逻辑
为什么选 PCA9422 而不是其他电源管理芯片?这里有几个很实际的考量。
第一,集成度高。PCA9422 内部集成了 4 路可编程 LDO 和 2 路 DC-DC 转换器,其中 DC-DC 支持高达 2A 的输出电流。对于 PIC32MX460F512L 这种需要 3.3V 核心电压、外设可能还需要 1.8V 或 2.5V 的场合,一颗芯片就能覆盖大部分供电需求,省掉了外围一堆分立器件。
第二,I2C 可编程。这意味着单片机可以在运行时动态调整输出电压。比如系统在满负荷跑的时候,把核心电压稍微调高保证稳定性;进入低功耗模式后,把不用的外设电源直接关掉,或者把电压降到维持数据保持的最低水平。这种灵活性是固定输出电源芯片给不了的。
第三,充电管理内置。PCA9422 支持锂离子和锂聚合物电池的线性充电,充电电流、终止电压、涓流充电阈值都可以通过寄存器配置。对于便携设备来说,这省掉了一颗专门的充电 IC。
第四,与 PIC32 的生态匹配。Microchip 自家的电源管理芯片和单片机在参考设计、应用笔记、代码库方面有很好的配套。虽然 PCA9422 不是 Microchip 原厂产品(它是 NXP 的),但 I2C 接口是通用的,PIC32 的 I2C 外设驱动起来很顺手。
从系统架构上看,整个电源树是这样的:电池或者外部电源输入先经过 PCA9422 的充电管理和输入路径管理,然后由 DC-DC 和 LDO 分别产生 3.3V 主电源、1.8V 外设电源、以及可能需要的 2.5V 模拟电源。PIC32MX460F512L 通过 I2C 总线与 PCA9422 通信,读取状态寄存器、写入配置寄存器,实现闭环控制。
1.3 系统框图的文字描述
虽然没有办法在这里画图,但我可以用文字把整个系统的连接关系说清楚。
电源输入部分:外部 5V 适配器或者 USB 供电接入 PCA9422 的 VIN 引脚,同时电池接在 BAT 引脚上。PCA9422 内部会自动判断输入源优先级,当外部电源存在时,系统由外部电源供电并同时给电池充电;外部电源拔掉后,自动切换到电池供电,切换过程不会导致系统掉电。
电源输出部分:PCA9422 的 Buck1 输出设为 3.3V,给 PIC32MX460F512L 的 VDD 和大部分数字外设供电;Buck2 输出设为 1.8V,给核心电压或者外部存储器供电;LDO1 输出 3.3V,给模拟部分或者对噪声敏感的电路供电;LDO2 可以配置为 2.5V,给传感器或者射频模块供电。每一路输出都可以通过 I2C 单独使能或关闭。
控制接口部分:PIC32MX460F512L 的 I2C2 模块(假设用 I2C2)的 SDA 和 SCL 引脚分别接到 PCA9422 的 SDA 和 SCL,加上 4.7k 的上拉电阻到 3.3V。PCA9422 的 INT 引脚接到 PIC32 的外部中断引脚,当有充电完成、电量低、温度异常等事件时,通过中断通知单片机。
监控部分:PCA9422 内部有 ADC,可以采集电池电压、电池电流、芯片温度等。PIC32 定期通过 I2C 读取这些数据,做电量计算和健康状态判断。
2. 核心细节解析与实操要点
2.1 PCA9422 的寄存器映射与关键配置项
PCA9422 的寄存器空间不算大,但每一个都有明确的用途。我把它分成几组来说。
充电控制寄存器组:包括充电电流设置、充电终止电压设置、涓流充电阈值、充电使能等。充电电流的设置是通过一个 6 位的寄存器值来决定的,步进大概是 25mA 左右,最大能到 1A 多。终止电压一般是 4.2V,但也可以配置成 4.35V 或者 4.1V,取决于电池规格。这里有个坑:如果你用的电池规格书上写的是 4.2V 终止电压,但你把寄存器配成了 4.35V,电池会过充,轻则鼓包,重则出安全问题。所以这一步一定要对着电池规格书来。
DC-DC 和 LDO 输出配置寄存器组:每一路输出都有独立的电压设置寄存器和使能位。Buck1 的输出电压范围大概是 0.6V 到 3.3V,步进 25mV 或者 50mV,具体看数据手册。Buck2 类似。LDO 的输出范围通常是 0.8V 到 3.3V。配置的时候要注意,输出电压不能超过输入电压减去压差,否则输出会不稳。
状态寄存器组:包括充电状态(正在充电、充电完成、故障)、输入源状态(外部电源存在、电池供电)、温度状态(正常、过温警告、过温关断)、电量计相关寄存器。这些寄存器是只读的,PIC32 通过读取它们来判断系统当前处于什么状态。
中断寄存器组:包括中断使能寄存器和中断标志寄存器。你可以选择哪些事件触发 INT 引脚。比如充电完成、电量低于阈值、过温、输入源切换等。配置好中断后,PIC32 就不需要一直轮询状态寄存器,只在中断发生时去处理,节省 CPU 资源和功耗。
系统控制寄存器组:包括软件复位、看门狗配置、I2C 地址设置等。PCA9422 的 I2C 地址可以通过硬件引脚配置,一般是 0x6B 或者 0x6A,具体看 ADDR 引脚接法。
2.2 PIC32MX460F512L 的 I2C 外设配置要点
PIC32MX460F512L 有两个 I2C 模块,I2C1 和 I2C2。我一般用 I2C2 来接电源管理芯片,因为 I2C1 有时候会跟其他外设冲突。配置 I2C 的时候,有几个关键参数要算清楚。
时钟频率:PCA9422 支持标准模式 100kHz 和快速模式 400kHz。我一般用 400kHz,速度快,而且 PIC32 的 I2C 外设完全支持。计算 I2C 波特率的时候,公式是:I2C 时钟频率 = PBCLK / (2 * (I2CxBRG + 1))。假设 PBCLK 是 80MHz,想要 400kHz,那么 I2CxBRG = 80MHz / (2 * 400kHz) - 1 = 100 - 1 = 99。所以 I2C2BRG 寄存器写 99。
上拉电阻:I2C 总线必须加上拉电阻,一般用 4.7k 到 3.3V。如果总线电容比较大(比如走线很长,或者挂了很多设备),上拉电阻要适当减小,比如 2.2k。但也不能太小,否则灌电流太大,可能超过引脚的最大拉电流能力。PCA9422 的 SDA 和 SCL 引脚是开漏输出,所以上拉电阻是必须的。
中断处理:I2C 通信可以用中断方式,也可以用轮询方式。对于电源管理这种实时性要求不是特别高的场合,轮询方式其实更简单可靠。但如果你系统里 I2C 总线很忙,或者有很多任务要处理,那就用中断方式。PIC32 的 I2C 中断标志位有多个,包括启动位中断、停止位中断、接收中断、发送中断等,处理的时候要仔细判断是哪个事件。
超时处理:I2C 总线有个经典问题,就是某个设备把 SDA 拉低不放,导致总线死锁。PIC32 的 I2C 外设有总线超时功能,可以配置一个超时计数器,当 SCL 被拉低超过一定时间后自动复位 I2C 模块。这个功能在实际产品里非常有用,强烈建议开启。
2.3 电源树设计与电压域划分
电源树的设计不是随便把电压分一分就完事了,要考虑几个因素。
电压精度要求:PIC32MX460F512L 的核心电压和 I/O 电压要求是 3.3V ± 10%,所以 3.0V 到 3.6V 都在范围内。但如果你外挂了精度要求高的模拟传感器,比如 16 位 ADC 或者高精度运放,那模拟电源的噪声和精度就要特别关注。这时候用 LDO 比用 DC-DC 更合适,因为 LDO 的输出纹波小得多。
电流需求:PIC32MX460F512L 在 80MHz 全速运行的时候,电流大概在 100mA 到 150mA 左右,加上外设比如 USB、以太网 PHY、SD 卡等,总电流可能到 300mA 甚至更高。所以 Buck1 的 2A 输出能力绰绰有余。但要注意,DC-DC 的效率在轻载和重载下差别很大,如果系统大部分时间处于轻载状态,要考虑 DC-DC 的轻载效率,或者切换到 PFM 模式。
上电时序:有些芯片对电源上电顺序有要求,比如核心电压要先于 I/O 电压建立,否则可能出现闩锁或者漏电流。PIC32MX460F512L 对上电顺序没有特别严格的要求,但如果你外挂了 FPGA 或者某些传感器,就要查一下它们的数据手册。PCA9422 支持通过寄存器配置每一路输出的上电顺序和延迟时间,这个功能在复杂系统里很有用。
电压域隔离:数字电源和模拟电源最好分开,用磁珠或者 0 欧电阻连接。PCA9422 的多路输出正好可以实现这一点。比如 Buck1 给数字部分供电,LDO1 给模拟部分供电,两路电源在 PCB 上分开走线,最后在一点汇合。
2.4 电池电量计的实现方式
PCA9422 内部有库仑计或者电压法电量计,具体看型号。如果是电压法,那就是通过测量电池电压来估算剩余电量。这种方法简单,但精度不高,因为电池电压和剩余电量的关系不是线性的,而且受温度、负载、老化影响很大。
更准的做法是库仑计,也就是对充放电电流进行积分,得到累计电量。PCA9422 如果支持库仑计,那它内部会有一个采样电阻或者利用内部 MOSFET 的导通电阻来测电流。PIC32 只需要定期读取累计电量寄存器,然后根据电池总容量换算出百分比。
我在实际项目里的做法是:用库仑计做主要估算,同时用电压法做校准。比如电池充满后,把库仑计清零;电池放到截止电压时,记录此时的库仑计值,作为满放点。这样长期运行下来,电量计的精度能保持在 5% 以内。
还有一个细节:电池的内阻会随着老化和温度变化,导致同样的剩余电量下,端电压不同。所以电量计要做好温度补偿和老化补偿。PCA9422 如果有温度传感器,可以读取电池温度,然后在软件里做补偿曲线。
3. 实操过程与核心环节实现
3.1 硬件连接与 PCB 布局要点
先说一下硬件连接。PCA9422 的封装一般是 QFN,引脚比较密,手工焊接有点难度,建议用热风枪或者回流焊。PCB 布局的时候,有几个地方要特别注意。
输入电容和输出电容:PCA9422 的 VIN 引脚旁边要放一个 10uF 的陶瓷电容,尽量靠近引脚。每一路 DC-DC 输出的电感和输出电容也要靠近芯片,走线要短而粗。LDO 的输出电容一般是 1uF 到 4.7uF,看数据手册推荐值。这些电容的作用是滤波和稳定环路,放远了效果大打折扣。
接地:PCA9422 的 GND 引脚和 PIC32 的 GND 要在底层铺铜连接,尽量减小地阻抗。模拟地和数字地可以分开铺,最后在电源输入点单点连接。如果板子上有射频部分,那射频地要单独处理,这个就不展开说了。
I2C 走线:SDA 和 SCL 走线要尽量短,远离高频信号线,比如时钟线、PWM 线。如果实在避不开,就在中间加地线隔离。上拉电阻放在靠近 PIC32 的一端还是靠近 PCA9422 的一端?一般放在靠近主控的一端,这样总线电容对上升沿的影响小一些。
散热:PCA9422 在充电电流比较大的时候会发热,尤其是线性充电模式,压差乘以电流就是功耗。比如 5V 输入给 3.7V 电池充电,充电电流 500mA,那功耗就是 (5 - 3.7) * 0.5 = 0.65W。QFN 封装的热阻大概在 50°C/W 左右,那温升就是 32.5°C。如果环境温度 40°C,芯片温度就到 72.5°C 了,虽然没超结温,但已经很烫了。所以 PCB 上要在芯片底部铺散热焊盘,多打过孔到地平面。
3.2 软件初始化流程与代码示例
软件这边,我一般把电源管理分成三个层次:底层 I2C 读写、中间层寄存器配置、上层状态机。
底层 I2C 读写就是封装两个函数,一个写寄存器,一个读寄存器。PIC32 的 I2C 外设用起来不算复杂,但要注意时序。下面是一个写寄存器的示例:
// 假设 I2C2 已经初始化,从机地址是 0x6B #define PCA9422_ADDR 0x6B void PCA9422_WriteReg(uint8_t reg, uint8_t value) { I2C2CONbits.SEN = 1; // 发送启动位 while (I2C2CONbits.SEN); // 等待启动位完成 I2C2TRN = PCA9422_ADDR << 1; // 发送从机地址 + 写位 while (I2C2STATbits.TRSTAT); // 等待发送完成 I2C2TRN = reg; // 发送寄存器地址 while (I2C2STATbits.TRSTAT); I2C2TRN = value; // 发送数据 while (I2C2STATbits.TRSTAT); I2C2CONbits.PEN = 1; // 发送停止位 while (I2C2CONbits.PEN); }读寄存器稍微复杂一点,需要先写寄存器地址,然后重启,再读数据:
uint8_t PCA9422_ReadReg(uint8_t reg) { uint8_t value; I2C2CONbits.SEN = 1; while (I2C2CONbits.SEN); I2C2TRN = PCA9422_ADDR << 1; // 写 while (I2C2STATbits.TRSTAT); I2C2TRN = reg; while (I2C2STATbits.TRSTAT); I2C2CONbits.RSEN = 1; // 重启 while (I2C2CONbits.RSEN); I2C2TRN = (PCA9422_ADDR << 1) | 1; // 读 while (I2C2STATbits.TRSTAT); I2C2CONbits.RCEN = 1; // 使能接收 while (!I2C2STATbits.RBF); // 等待接收完成 value = I2C2RCV; I2C2CONbits.ACKDT = 1; // 发送 NACK I2C2CONbits.ACKEN = 1; while (I2C2CONbits.ACKEN); I2C2CONbits.PEN = 1; while (I2C2CONbits.PEN); return value; }中间层就是根据数据手册,把每个寄存器的配置封装成函数。比如设置充电电流:
void PCA9422_SetChargeCurrent(uint16_t mA) { // 假设步进是 25mA,寄存器值 = mA / 25 uint8_t reg_val = mA / 25; if (reg_val > 63) reg_val = 63; // 限制最大值 PCA9422_WriteReg(CHARGE_CURRENT_REG, reg_val); }上层状态机就是根据系统状态决定电源配置。比如系统进入低功耗模式时,关闭 Buck2 和 LDO2,把 Buck1 电压降到 2.5V,关闭不必要的时钟。唤醒后恢复配置。
3.3 动态电压调节的实现与参数计算
动态电压调节是这套方案的核心价值之一。PIC32MX460F512L 支持多种低功耗模式,包括空闲模式、睡眠模式、深度睡眠模式。不同模式下,核心电压可以不同。
比如在深度睡眠模式下,PIC32 只需要维持看门狗和实时时钟工作,核心电压可以降到 1.8V 甚至更低。但要注意,PIC32 的深度睡眠模式对电压有最低要求,不能低于数据手册规定的下限。查一下 PIC32MX460F512L 的数据手册,深度睡眠模式下 VDD 最低是 1.8V,所以 Buck1 可以设到 1.8V。
计算功耗节省:假设系统在 3.3V 下运行电流是 100mA,功耗是 330mW。降到 1.8V 后,由于 CMOS 电路的动态功耗与电压平方成正比,电流会降到大约 100 * (1.8/3.3)^2 ≈ 30mA,功耗是 54mW。节省了 276mW,效果非常明显。
但电压切换不能太频繁,因为 DC-DC 的输出电压变化需要时间,而且频繁切换会影响电源稳定性。我一般设置一个滞回区间,比如系统负载低于 20% 持续 1 秒后,才降电压;负载高于 50% 持续 100ms 后,才升电压。
3.4 充电管理与温度监控的联动
充电管理不是简单地设置一个电流就完事了。锂电池充电分三个阶段:涓流充电、恒流充电、恒压充电。PCA9422 内部会自动处理这三个阶段,但阈值需要配置。
涓流充电阈值一般是 3.0V,也就是说电池电压低于 3.0V 时,用很小的电流(比如 50mA)充电,保护电池。恒流充电阶段,电流可以设大一点,比如 500mA,但要注意电池规格书上的最大充电电流。恒压阶段,电压固定在 4.2V,电流逐渐减小,当电流小于终止电流(比如 50mA)时,充电完成。
温度监控很重要。锂电池在 0°C 以下充电会析锂,有安全风险;在 45°C 以上充电会加速老化。所以 PCA9422 如果支持 JEITA 标准,那就配置好温度区间:0-10°C 时降低充电电流,10-45°C 正常充电,45°C 以上停止充电。PIC32 通过 I2C 读取温度寄存器,如果发现温度异常,可以主动关闭充电,并通过 INT 引脚通知系统。
我在实际项目里还加了一个软件保护:如果连续多次检测到过温,就把充电电流永久降低一档,并且记录到 EEPROM 里,下次上电也生效。这样即使温度传感器坏了,也不会一直过温充电。
4. 常见问题与排查技巧实录
4.1 I2C 通信失败的那些坑
I2C 通信失败是最常见的问题,没有之一。我总结了几种典型情况和排查方法。
第一种:完全没反应,读回来的都是 0xFF 或者 0x00。这种情况先查硬件:SDA 和 SCL 有没有接反?上拉电阻有没有焊?电源有没有到 PCA9422 的 VIN 和 VDD?用示波器看 SCL 和 SDA 有没有波形。如果波形都没有,那就是 PIC32 的 I2C 没配置对,检查 I2CxCON 寄存器的 ON 位有没有置 1,I2CxBRG 有没有设对。
第二种:能读到数据,但偶尔出错。这种一般是时序问题或者干扰。先降低 I2C 速率试试,从 400kHz 降到 100kHz。如果降速后正常了,那就是总线电容太大或者上拉电阻太大。减小上拉电阻到 2.2k 试试。另外检查一下 I2C 走线旁边有没有高频信号线,如果有,加地线隔离。
第三种:总线死锁,SCL 或 SDA 一直被拉低。这种情况通常是某个从机在通信过程中复位了,导致它一直拉着总线不放。解决办法是 PIC32 主动发送 9 个时钟脉冲,让从机把数据移完,然后发送停止位。如果还不行,就复位 I2C 模块。PIC32 的 I2C 模块有 I2CxCONbits.I2CEN 位,清零再置 1 就能复位。
注意:PCA9422 的 I2C 地址是 7 位的,发送的时候要左移一位,最低位是读写位。很多人在这里搞错,把地址直接写进去,结果通信失败。
4.2 电源输出不稳或纹波过大
DC-DC 输出纹波大,一般是这几个原因。
电感选型不对:DC-DC 的电感值要根据开关频率和输出电流来选。PCA9422 的开关频率一般是 2MHz 左右,电感值在 1uH 到 2.2uH 之间。电感值太小,纹波电流大;电感值太大,响应慢。另外电感的饱和电流要大于最大输出电流的 1.5 倍,否则大负载时电感饱和,输出会掉。
输出电容不够:输出电容的作用是滤除纹波和稳定环路。一般推荐 10uF 到 22uF 的陶瓷电容,ESR 要低。如果电容太小,纹波会很大;如果电容太大,环路可能不稳定。最好按照数据手册的推荐值来。
布局问题:DC-DC 的输入环路和输出环路面积要尽量小,否则会辐射噪声,也会影响效率。电感要靠近芯片的 SW 引脚,输出电容要靠近电感和地。
LDO 输出不稳:LDO 的输出电容有 ESR 要求,有些 LDO 要求 ESR 在特定范围内才稳定。如果用了 ESR 太低的陶瓷电容,LDO 可能会振荡。解决办法是在输出电容上串联一个小电阻,或者换用 ESR 合适的钽电容。
4.3 充电异常与电池保护
充电异常一般表现为:充不满、充电时间过长、充电时发热严重。
充不满:先查充电终止电压设置对不对。如果设成了 4.1V,那电池只能充到 4.1V,当然充不满。另外查一下充电终止电流,如果设得太小,充电时间会很长;如果设得太大,电池可能没充满就停了。
充电时间过长:可能是充电电流设得太小,或者输入电源的电流能力不够。PCA9422 的输入电流是有限制的,如果外部电源只能提供 500mA,而你设了 1A 的充电电流,那实际充电电流会被限制在 500mA 减去系统消耗的电流。另外,如果电池电压很低,涓流充电阶段会很长,这是正常的。
充电发热严重:线性充电的功耗等于 (VIN - VBAT) * ICHG。如果 VIN 是 5V,VBAT 是 3.7V,ICHG 是 1A,那功耗就是 1.3W,发热肯定严重。解决办法是降低充电电流,或者改用开关充电。PCA9422 如果是线性充电,那在大电流充电时发热是不可避免的,只能靠 PCB 散热。
提示:锂电池的保护板是最后一道防线,但不要依赖它。软件上要做好过压、过流、过温保护,硬件上也要有独立的保护电路。
4.4 低功耗模式下的电流消耗异常
系统进入低功耗模式后,如果实测电流比预期大很多,一般是这几个地方漏电。
GPIO 状态不对:未使用的 GPIO 如果悬空,输入缓冲器可能会振荡,导致额外功耗。解决办法是把未使用的 GPIO 配置为输出低电平,或者使能内部上拉/下拉。PIC32 的 GPIO 可以配置为数字输入、数字输出、模拟输入等,低功耗模式下要把不用的引脚设成模拟输入或者输出低。
外设时钟没关:PIC32 的外设时钟可以通过 PMD 寄存器单独关闭。进入低功耗前,把不用的外设时钟都关掉,比如 UART、SPI、定时器等。
电源芯片的静态电流:PCA9422 本身也有静态电流,一般在几十微安到几百微安。如果系统要求极低功耗,要查一下 PCA9422 在关断模式下的电流。有些电源芯片在关断模式下还有漏电流,这个要注意。
电池电量计的分流电阻:如果用了外部分流电阻做电量计,分流电阻上会有压降和功耗。选分流电阻的时候,阻值要小,比如 10mΩ,这样 1A 电流下功耗只有 10mW。
4.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| I2C 完全无响应 | 电源未上、地址错误、上拉缺失 | 示波器看波形、万用表测电压 | 检查电源、确认地址、加上拉 |
| I2C 偶发错误 | 速率过高、干扰、总线电容大 | 降速测试、观察波形 | 降速、减小上拉、加地线隔离 |
| DC-DC 纹波大 | 电感或电容选型不当 | 示波器测纹波 | 换电感、加输出电容 |
| 充电发热严重 | 线性充电功耗大 | 测芯片温度 | 降低充电电流、改善散热 |
| 低功耗电流大 | GPIO 悬空、外设时钟未关 | 逐个排查 | 配置 GPIO、关闭时钟 |
| 电池充不满 | 终止电压设置错误 | 读寄存器 | 按电池规格设置 |
| 系统频繁复位 | 电源不稳、看门狗误触发 | 测电源波形 | 加电容、调整看门狗 |
5. 项目扩展与个人经验分享
5.1 这套方案还能怎么扩展
PCA9422 加 PIC32MX460F512L 的组合,基础功能做完之后,还有不少可以深挖的地方。
加入 USB 充电识别:PCA9422 支持 USB BC1.2 充电识别,可以识别 SDP、DCP、CDP 等不同充电端口,然后自动调整输入电流限制。这个功能对于用 USB 充电的设备很实用,能避免因为输入电流过大导致电脑 USB 口保护。
加入电量计学习功能:如果电池是可拆卸的,可以做一个电量计学习流程。充满电后放电到截止电压,记录库仑计数据,然后更新电池容量参数。这样电量计会越来越准。
加入电源故障记录:PCA9422 的状态寄存器可以记录最后一次复位的原因,比如是上电复位、看门狗复位还是软件复位。PIC32 可以在启动时读取这些信息,存到 EEPROM 里,方便售后分析。
加入动态功耗管理:根据系统负载动态调整 PIC32 的主频和核心电压。PIC32MX460F512L 支持通过 OSCCON 寄存器切换时钟源和分频比。负载低的时候降频降压,负载高的时候升频升压。这个和 PCA9422 的动态电压调节配合起来,节能效果更好。
5.2 我在实际项目中踩过的坑
第一个坑:I2C 上拉电阻接到了 5V。PCA9422 的 I2C 引脚是 3.3V 电平,如果上拉到 5V,长期运行会损坏芯片。我一开始没注意,因为板子上有 5V 和 3.3V 两路电源,随手就接到了 5V。后来发现通信偶尔出错,查了好久才找到原因。所以上拉电阻一定要接到和 I2C 引脚电压相同的电源上。
第二个坑:充电电流设置超过了输入电源能力。我用了一个 500mA 的 USB 口供电,但充电电流设了 800mA。结果系统一充电,USB 口就保护了,系统反复重启。后来把充电电流降到 400mA,同时配置了输入电流限制,问题解决。所以充电电流和输入电流限制要匹配,不能只看电池规格。
第三个坑:低功耗模式下忘了关 I2C 上拉。I2C 的上拉电阻在总线空闲时会有持续电流。如果上拉是 4.7k 到 3.3V,那电流就是 0.7mA。虽然不大,但对于微安级低功耗的系统来说,这就是致命的。解决办法是在低功耗模式下,把 I2C 引脚配置为普通 GPIO 输出低,或者用 MOS 管切断上拉电阻的电源。
第四个坑:PCB 布局时 DC-DC 电感离模拟部分太近。DC-DC 的开关噪声通过空间辐射耦合到了模拟传感器上,导致 ADC 读数跳动。后来把电感移远,并且在模拟部分加了屏蔽罩,问题才解决。所以布局的时候,DC-DC 部分要远离模拟和射频部分。
5.3 给新手的几点建议
如果你刚开始接触电源管理,我建议先从简单的开始。不要一上来就搞动态电压调节和复杂的电量计。先把基本的电源输出调通,确保每一路电压都正确,纹波在可接受范围内。然后再加 I2C 通信,能读写寄存器。最后再加充电管理和低功耗功能。
调试的时候,万用表和示波器是必备的。万用表看静态电压和电流,示波器看纹波和时序。I2C 通信可以用逻辑分析仪抓包,比示波器更方便。如果没有逻辑分析仪,也可以用 PIC32 的 UART 打印调试信息,把 I2C 读写的每一步都打出来。
还有一点很重要:仔细读数据手册。PCA9422 和 PIC32MX460F512L 的数据手册加起来有上千页,但关键的信息都在里面。比如寄存器的默认值、时序要求、电气特性等。很多问题其实数据手册里都写了,只是没注意到。我习惯把关键页打印出来,放在手边随时翻。
最后,电源管理是一个需要耐心和细心的活。一个电阻、一个电容选错了,可能就会导致系统不稳定。多测、多试、多记录,慢慢就有经验了。