☰
PMIC+MCU双芯片架构:锂电池充电管理与低功耗电源设计实战
2026/10/24 1:01:56 网站建设 项目流程

如果你做过带锂电池的便携设备,一定被电源管理恶心过:充电保护要自己搭,过放检测要自己写,功耗一高电池就崩。我之前为一块低功耗传感器板做电源方案,一开始图省事用了 LDO 加独立充电模块的老套路,结果待机电流怎么压都压不到理想值,充放电过程基本是个黑盒,出了问题连根因都摸不着。最后狠狠心把方案推倒,换成了 PCA9422 加 PIC18F4620 的双芯片架构,把充电路径、系统供电、电量监测和异常保护统一交给 PMIC 和主控配合管理,才算真正把电源理顺。

这套组合负责的是小型电池设备里最难缠的三件事:充电管理、路径切换、电量监控。主控只需要通过 I2C 下发配置,剩下功率层面的脏活累活全部由 PMIC 承担。如果你正在做可穿戴设备、传感器节点、追踪器、手持终端这类产品,这篇文章里的选型逻辑、硬件接线、驱动实现和排障记录都可以直接参考,每一步都是实际验证过的东西,不是纸上谈兵。

1. 双芯片选型逻辑:为什么非要 PMIC 加 MCU 的组合

1.1 分立方案的三个死穴

LDO 加独立充电模块是很多人起步时喜欢用的做法。LDO 负责把电池电压稳下来给系统供电,充电模块负责给电池充电,看起来分工明确,实际用起来全是麻烦。

第一个死穴是效率。电池电压从满电 4.2V 一路降到 3.3V,LDO 把多余的压差以热量形式消耗掉,电池后半段电量基本是浪费的,系统跑着跑着就突然关机,剩余电量根本用不干净。第二个死穴是路径管理。插入 USB 之后充电模块给电池充电,系统负载同时又从电池取电,充电模块不会自动把系统切到 USB 侧,结果是电池一边充一边放,寿命和状态都变得难以预测。第三个死穴是保护。过流、过温、欠压这些保护全靠自己搭分立电路,搭多了成本上去,搭少了关键时刻不会动作,出了问题板子烧掉都不知道是谁的责任。

正是这些痛点让我彻底转向 PMIC 思路。把电源相关的功率部分交给专用芯片,主控只做策略和调度,系统的电源行为才真正变得可控。

1.2 PCA9422 的核心价值

PCA9422 这类小封装 PMIC,把电池管理需要的那一大堆功能合到了一起。充电管理、功率路径切换、系统输出电压、充放电保护、状态监测都在一颗芯片里完成,外部只需要很少的被动元件,不占板子面积。

最实用的接口是 I2C,充电电压、充电电流、输入限流这些参数全部可以用软件配置,而不是靠焊电阻去设定。对批量产品来说,改版只需要改代码,连 PCB 都不用动,这是非常大的灵活性。它还会把电池电压采样值、充电状态、故障标志通过寄存器反馈出来,主控拿到这些数据就能实时知道系统处于什么状态,该做什么决策。

这颗 PMIC 的任务是离电池最近的那一层。它不负责业务逻辑,负责功率变换、充电管理、保护,并且通过中断把异常第一时间汇报给主控。换句话说,它把电源从单纯的硬件变成了可以参与软件策略的一部分。

1.3 PIC18F4620 在系统里的角色

PIC18F4620 是一颗很成熟的 8 位单片机,64KB Flash、4KB RAM 的空间放这套电源管理代码外加应用逻辑非常够用。它内置的 MSSP 模块可以直接做 I2C 主模式,硬件时序比软件模拟稳定得多,CPU 占用也更低。自带的 13 路 10 位 ADC 可以完成电池电压冗余采集和温度采样,多个外部中断引脚则支持睡眠状态下被 PMIC 的中断信号唤醒,这是低功耗设备必需的能力。

在这套系统里,MCU 要做的是三件事。上电初始化时把 PCA9422 的寄存器配置写好,运行过程中根据读取到的电池状态执行充电、放电、待机、故障处理的状态机切换,再通过串口或无线模块把电源状态上报出去。

可以说 PMIC 管功率,MCU 管策略。两者配合,正好把一套小型电池系统的电源管理完整做下来。

1.4 适合这套方案的产品形态

不是所有项目都需要 PMIC 加 MCU 的架构。我用一张表说明判断依据:

产品类型典型需求是否适合
纽扣电池供电的小玩具单节干电池,无需充电管理不需要
锂电池供电的传感器节点需要充电、低功耗、状态上报非常适合
智能手环、耳机盒类充电管理加电量监测,体积受限非常适合
自带主控的电池产品已有 MCU,只差充电和路径管理非常适合

判断标准很简单:只要有锂电池、有充电需求、有需要上报的状态,这套架构就值得考虑。它省掉的是一堆离散保护电路和调试时间,换来的是原理图更简洁、BOM 更短、行为可配置。

2. 硬件搭建:电源树、I2C 和中断引脚的连接细节

2.1 电源树的整体结构

先看整体供电路径。USB 输入接到 PCA9422 的输入侧,电池接在电池端,PCA9422 的系统输出端作为整个设备的主供电轨,PIC18F4620 和后级负载都从这条轨取电。

我实际用的连接关系整理成表,方便对照自己的板子:

PCA9422 引脚功能作用连接去向
VBUS 输入USB 或适配器电源输入5V 输入,对地放 0.1uF 陶瓷电容
BAT锂电池正极单节锂离子电池,靠近引脚放 10uF 电容
SCL / SDAI2C 总线接 PIC18F4620 的 RC3/RC4,各接 4.7k 上拉
INT中断输出,低电平有效接 PIC18F4620 的 RB0/INT0
EN芯片使能接普通 GPIO,由系统控制
GND地系统地平面,单点连接功率地

PIC18F4620 的 MSSP 模块对应引脚就是 RC3(SCL)和 RC4(SDA),这两个引脚在 I2C 模式下保持开漏特性,配合外部上拉电阻工作。RB0/INT0 配置为外部中断,低电平触发,这样 PMIC 有异常时可以立刻把睡着的 MCU 叫醒。EN 引脚单独用 GPIO 控制,调试阶段可以在软件里直接关断整个 PMIC 做故障注入测试。

2.2 系统输出与后级稳压

PCA9422 的系统输出一般可以作为主电源轨,但不同配置下输出设置可能不一样。我当时的做法是让 PMIC 输出一个稳定的系统电压,然后加了一级低压差稳压器给 MCU 供电,这样即使 PMIC 在路径切换瞬间出现电压波动,MCU 也不会复位。

有人为了省电会跳过一级 LDO,直接让 MCU 吃系统轨,但我实测在 USB 插入的瞬间系统轨容易有跌落,稳妥起见还是加了一级。如果你的后级有无线模块,建议在模块电源脚附近放独立的滤波电容,无线发射时瞬时电流可能到几百毫安,这个瞬态处理不好会让电池电压读数出现假跳变,影响电量判断。

2.3 布局布线和测试点

布局方面有几个经验。第一,PCA9422 和电池之间的走线越短越好,充电电流回路的铜皮尽量加宽,别用细线走,否则充电时线上压降会直接影响满充电压判断。第二,芯片电源引脚附近的去耦电容要紧贴引脚放,我习惯是 10uF 和 0.1uF 成组,别只放一个。第三,SCL/SDA 上拉电阻放在靠近主控侧,上拉到和 PMIC 同一供电域,避免跨域漏电,这个在调试阶段坑过我一次,后面排障部分详细说。

测试点一定不要省。电池电压测试点、系统输出测试点、I2C 信号测试点都留出来,调试时可以随时挂示波器看波形,不用去捅芯片引脚。我第一版就吃了没留测试点的亏,量信号只能用镊子颤颤巍巍搭在芯片引脚上,既危险又容易短路。

3. PIC18F4620 侧 I2C 驱动:先把 PMIC 的通信打通

3.1 MSSP 模块初始化与时钟计算

PIC18F4620 的 MSSP 模块配置成 I2C 主模式很简单,关键是把 SSPCON1 的 SSPM 位设为 1000,再用 SSPADD 寄存器决定总线时钟。频率公式是 SCL = FOSC / (4 × (SSPADD + 1))。

我当时系统主频用 16MHz,目标总线速度 100kHz,反推出来 SSPADD = 16MHz / (4 × 100kHz) - 1 = 39。初始化代码写成这样:

void pmic_i2c_init(void) { // RC3/RC4 设为输入模式,I2C 总线靠外部上拉释放 TRISCbits.TRISC3 = 1; TRISCbits.TRISC4 = 1; // MSSP 模块使能,配置为 I2C Master 模式 SSPCON1 = 0b00101000; // SSPEN=1, SSPM=1000 SSPCON2 = 0x00; // 清空控制位 SSPSTAT = 0x00; // 标准 100kHz 模式,不使用 SMBus 特性 SSPADD = 39; // FOSC/(4*100kHz)-1 }

TRIS 置 1 加外部上拉是最省事的做法,总线释放时由外部 4.7k 电阻拉高,主从机都靠这个机制维持通信。如果引脚支持内部弱上拉也可以试,但我建议外部独立上拉,阻值可控,信号边沿也更干净。

3.2 寄存器写和读的时序

I2C 驱动里最常用的两个函数是写寄存器和读寄存器。写寄存器流程是启动条件、器件地址加写位、寄存器地址、数据字节、停止条件,每个字节传输完之后检查 ACK。读寄存器要多一个重复起始条件:先写器件地址和寄存器地址,再用重复起始切换为读模式,主机收到数据后发 NACK 结束。

完整代码如下:

// 写一个寄存器字节 unsigned char pmic_write_reg(unsigned char reg, unsigned char val) { I2C_Start(); if (pmic_tx_byte(0x90) == 0) return 1; // 器件地址 0x48 加写位,NACK 则失败 if (pmic_tx_byte(reg) == 0) return 1; if (pmic_tx_byte(val) == 0) return 1; I2C_Stop(); return 0; } // 读一个寄存器字节 unsigned char pmic_read_reg(unsigned char reg) { unsigned char val; I2C_Start(); pmic_tx_byte(0x90); pmic_tx_byte(reg); I2C_Start(); // 重复起始 pmic_tx_byte(0x91); // 器件地址加读位 val = pmic_rx_byte(1); // 主机收 1 字节,最后给 NACK I2C_Stop(); return val; }

底层发送和接收函数里,一定要对 ACKSTAT、总线冲突位做判断,超时后重试几次而不是傻等。I2C 总线上出问题很常见,一次通信失败不能直接判定硬件坏了,加个重试计数再用状态机处理,比一次失败就 panic 靠谱得多。

3.3 器件地址的一个关键提醒

PCA9422 的器件地址并不是固定的,通常和 ADDR 引脚的电平设置有关。我上面写的 0x90/0x91 是把 7 位地址 0x48 左移一位得到的,实际地址要以数据手册和你的 ADDR 接法为准。

建议在代码里用宏定义地址,把读取 ADDR 引脚电平的逻辑写进去,避免硬编码。不同 PCB 上 ADDR 接法不同,代码也要跟着改,做成宏之后只需要改一处。首次调板最值得做的是一段 I2C 扫描程序:遍历常见地址,向每个地址发一个写操作,能收到 ACK 的地址就是 PMIC 当前所在位置。把这个程序烧进去跑一遍,比对着示波器猜快非常多。

3.4 时钟选择与抗干扰

总线速度建议先从 100kHz 起步。400kHz 能跑,但对 PCB 布局和上拉阻值更敏感,信号质量差的时候偶发 NACK 会让人排查到崩溃。如果后面确实需要更高频率,再把上拉电阻换成 2.2k,同时检查波形上升沿是否陡峭。

抗干扰方面,I2C 线尽量短,不要绕远路。板上其他容易产生毛刺的信号线,比如 PWM 输出、无线模块的控制线,和 I2C 线保持距离,避免串扰导致伪启动或伪停止条件。这个问题在双层板上特别容易出现,布线阶段多花十分钟,调试阶段省十小时。

4. 电源策略配置:充电曲线、路径切换与系统状态机

4.1 上电默认值不一定能用

这是很容易踩的坑:PMIC 的寄存器配置在每次上电复位后会回到出厂默认值,并不具备掉电保存能力。如果板子一上电就直接让系统跑起来,PMIC 很可能停留在默认状态,充电参数不是你要的,系统输出也未必打开。所以 PIC18F4620 上电初始化阶段最重要的事,就是把关键寄存器全部重新写一遍,再读回来做校验。

我把这个过程叫配置下发,放在系统上电后的前 100ms 内完成。实际代码里是一个数组加循环,把寄存器地址和数值成对写进去,之后再逐条读回来比对。如果校验不过,说明 I2C 链路或 PMIC 本身有问题,直接进入故障状态,比稀里糊涂跑下去好得多。

4.2 关键充电参数的配置顺序

充电相关的参数决定了电池能不能安全、完整地充满。我常用的配置顺序是:先设充电电压上限,再设充电电流,然后设输入限流,最后使能充电功能。顺序本身很重要,如果先使能充电再写参数,PMIC 会先用默认参数开始充电,等软件再把参数写进去才切换过来,这个过程存在风险。

具体配置项整理成表,参考的是单节锂离子电池的常规方案:

配置项典型值说明
充电电压上限4.2V常规三元锂电池,具体看电池规格书
恒流充电电流500mA配合电池容量和散热设计
预充电流50mA 左右电池过放时先小电流恢复
终止充电电流50-100mA设太低会导致久久不判充满
输入限流900mA保护 USB 输入不被拉垮
系统输出按后端需求以数据手册配置范围为准

每个参数写入后立刻读回确认。寄存器写入失败不代表板子坏了,可能只是总线时序的瞬时抖动,重试一次就过去,但不读回校验,错误配置会影响整个充电过程,这种问题最难查。

4.3 系统状态机的设计与实现

电源管理不能只靠一堆 if 判断,功能一多逻辑准乱。我把它实现成一个小型状态机,用枚举定义:

typedef enum { PMIC_STATE_INIT, // 上电配置阶段 PMIC_STATE_STANDBY, // 待机 PMIC_STATE_CHARGING, // 充电中 PMIC_STATE_CHARGED, // 已充满 PMIC_STATE_RUNNING, // 正常放电运行 PMIC_STATE_FAULT // 故障 } pmic_state_t;

状态切换由事件驱动。主循环里检查事件标志,比如 VBUS 插入、VBUS 拔出、充电完成、外部中断触发、电压阈值越限,然后调用对应的事件处理函数,在函数里判断当前状态、决定是否迁移到新状态。每个状态迁移时打印一条串口日志,调试时随时能看出系统在哪一步发生了什么。

这个状态机第一版代码里我就做了,后面调低功耗和充电逻辑时帮了大忙。电源问题最怕毫无征兆,状态日志能直接告诉你是配置问题、路径问题还是保护触发,排查时间至少砍半。

5. 电量与健康监测:ADC 与中断怎么配合

5.1 从 PMIC 读回的量化数据

PCA9422 内部带有 ADC,电池电压、充电电流、片上温度这些量会以数字形式放在寄存器里,PIC18F4620 通过 I2C 读取后换算成真实物理量。关键是把数据手册给出的换算关系写成代码里的宏,比如电压寄存器每个 LSB 对应多少毫伏,电流寄存器每个 LSB 对应多少毫安。直接使用寄存器原始值会导致后续所有阈值判断都出错,这个换算步骤不能省。

我当时的做法是做一个统一的读取函数,把 PMIC 的原始采样值转换成工程值,再用这些工程值去做状态判断。这样策略代码里写的都是 3.6V、350mA 这样直观的数字,可读性高,后面换电池模型时改阈值也方便。

5.2 主控 ADC 作为冗余备份

只依赖 PMIC 内部 ADC 有一个风险:如果 I2C 通信异常,主控就拿不到任何电池状态了。所以我额外用 PIC18F4620 自身的 ADC 采集电池电压,通过两个精密电阻组成的分压网络接入。正常情况下两套数据互相印证,异常情况下即使 I2C 彻底断开,MCU 也能凭分压值做一次紧急低压保护。

分压电阻用 1% 精度,阻值选大一些,尽量减少对电池的消耗。ADC 参考电压我接了外部基准,比内部参考更稳,电压判断的重复精度提高不少。如果只是做粗略保护,内部参考也够用,但要做精准的电量百分比估算,外部基准值得加。

5.3 用中断代替轮询

电源管理里最不建议的就是满节奏轮询。低功耗设备大部分时间在睡眠,如果每隔几百毫秒醒一次读 PMIC 状态,总线功耗和 MCU 唤醒功耗都会上去。正确做法是利用 PCA9422 的中断输出:充电完成、故障、输入接入这些事件发生时 INT 引脚拉低,PIC18F4620 的外部中断把 MCU 从睡眠唤醒,主循环再通过 I2C 读取具体状态。

中断服务程序里只做一件事,置标志位然后退出。真正处理逻辑放在主循环,因为在中断里直接做 I2C 通信非常容易卡死,还会拉长中断响应时间,影响系统稳定性。这个习惯我踩过教训后才彻底改过来,强烈建议从一开始就按这个规范写。

6. 实测排障:五个坑的完整排查记录

6.1 首版板子 I2C 完全没有 ACK

第一版板子回来,烧上 I2C 扫描程序,扫了一圈没有任何地址回应,总线上一片死寂。我的排查链路是这样的:先看示波器上 SCL 和 SDA 的静态电平,发现都拉高了,说明上拉没问题;再查器件供电,PMIC 供电正常;然后检查 I2C 引脚连接,结果发现我把 RC4 接到了板上一个调试 LED 的复用网络,数据线被 LED 驱动电路干扰,等效于地址对不上。重新改板把 LED 移到其他引脚后,扫描程序立刻找到了器件地址。

这次教训让我意识到,I2C 引脚在原理图阶段就要检查复用冲突。特别是带 LED、按键、调试接口的板子,这些引脚很容易在布线后期被挪用,最终受害者往往是 I2C 这种对时序敏感的接口。

6.2 插入 USB 瞬间系统复位

插上 USB 给电池充电时,系统偶尔会复位,空板带电池时尤其明显。排查发现输入浪涌电流瞬间把系统电压拉低,MCU 掉电复位。对策分两步:一是把 PMIC 的输入限流配置调低一点,让充电启动时对输入侧的冲击更平缓;二是在 USB 输入端增加 TVS 和大容量储能电容,吸收插拔时的瞬态能量。这样处理后,插拔动作对系统轨的扰动明显减小,复位问题消失。

这个坑提醒我,电源管理方案测试时一定要覆盖热插拔场景,很多问题只有在带载动态切换时才会暴露。只做静态功能测试,永远不知道真实使用场景下会出现什么。

6.3 充电充到 80% 就不走

有一版电池实测充到接近 80% 电量时充电就停了,看起来像是充满,实际上电池电压离 4.2V 还差很远。查下来是终止充电电流阈值被我设置得太高,电池内阻稍微大一点,恒流阶段结束后电压还达不到满电,终止判断就提前触发了。把终止电流调低、加了一个满充检测的迟滞窗口之后,电池可以正常充到满电。

这里也想提醒一下,老化和低温下电池内阻会变大,满充判断不能只看电压,要结合充电电流衰减曲线一起看。电池是化学器件,不是理想电压源,它的表现会随温度和使用时间变化。

6.4 待机电流 2mA 压不下去

低功耗模式调试时发现整机待机电流一直在 2mA 左右,怎么都降不下。逐路断开负载排查,最后定位到 I2C 上拉电阻被放在了跨电源域的路径上:上拉电源来自系统轨,而 PMIC 的 I2C 引脚参考的是另一个电域,形成一条稳定的漏电路径。把上拉电阻改到和 PMIC 同一个电源域之后,待机电流立刻降了一个数量级。

另外一个常见漏电来源是悬空的 GPIO。所有不用的引脚要么设输入加内部弱上拉,要么设输出固定电平,绝对不能放着不管。这类问题用电流钳逐路排查很有效,就是费时间,最好在原理图评审阶段就堵住。

6.5 配置下发之后又被覆盖

最后这个坑比较隐蔽:代码里明明把充电参数写进去了,跑一段时间后发现配置又变回默认值。排查后发现是器件在某次上电复位后重新走了默认配置流程,而我的下发代码只在初始化阶段执行过一次,后续复位后不会再执行。解决办法是把配置下发逻辑放进一个统一的电源初始化函数里,无论冷启动还是复位后都会被执行,并且下发后强制读回校验,确保关键配置始终落在预期值上。

这个坑的根因是 PMIC 配置不具备非易失特性,任何复位都会丢失。所以在架构设计上,配置下发必须和系统初始化绑定,而不是和应用启动绑定,这个区别很多人会忽略。

整个方案做下来,我的体会是电源管理难不在某个单点,而在整个系统要把功率流向和策略逻辑彻底理顺。PCA9422 承担了充电、路径、保护这些脏活累活,PIC18F4620 做好配置和决策,两者配合起来,小型电池设备的电源才算真正可控。这里分享一个小技巧:把 PCA9422 的寄存器映射整理成一张表格,标注每个字段的默认值、实际值、写入时机,开发时打印出来贴在工位上,调试效率提升非常明显。如果你正准备做类似的可穿戴或其他电池产品,这个组合值得纳入方案评估,尤其是需要定制充电行为和精细电量管理的项目。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询