1. 两节串联为什么会失衡容量差、自放电差与“木桶效应”在储能和备用电源系统里两节串联电池之间的压差一旦被拉开整个模组的可用容量和循环寿命都会往下塌。与其用被动均衡把多余的能量在电阻上烧成热量不如用主动均衡芯片直接把电荷从高电压单元搬到低电压单元。这篇就聊聊我最近用 MP2642GR-Z 搭配 STM32F411RE 做的一块两节串联电池均衡板从硬件接线、I2C 通信到均衡策略和实测数据把能复现的细节全部摊开。适合正在做小容量储能、UPS 备用电池或者两串锂电模组的工程师参考尤其是第一次接触主动均衡芯片的开发者。1.1 失衡的三个来源与量化代价先说清楚问题本身。任何两节电池都不可能是完全一致的出厂容量有偏差、内阻有偏差、自放电率有偏差使用一段时间后这些偏差还会被放大。再加上电池在模组里的位置不同散热条件不同温度差异会进一步加剧自放电和容量衰减的差异。在串联拓扑里充电电流和放电电流完全一样于是容量小的那节总是先充满、先放空时间一长两节电池的 SOC荷电状态差距就越拉越大。这个差距的代价可以用“木桶效应”一句话概括整串电池的可用容量等于最弱的一节而不是平均值。举个例子两节 50Ah 磷酸铁锂串联标称电压 6.4V假设两节之间 SOC 相差 8%那就是 4Ah 的电荷量差。充电时电压高的那节先顶到充电截止电压充电停止电压低的还没充满放电时电压低的先到放电截止电压放电停止电压高的还剩不少。一来一回整串电池每次循环少用 4Ah相当于白白丢了 8% 的容量。在备用电源场景里这种容量损失平时看不见等到市电掉电测试时才发现备用时间缩水那时候再处理就晚了。1.2 被动均衡和主动均衡的本质差别传统的被动均衡思路很简单在电压高的电芯上并联一个放电电阻把多余的能量以热量形式放掉。成本低、控制简单但有两个硬伤。一是均衡电流做不大受限于电阻功耗和散热一般只有 50~100mA碰上几十安时的大电芯均衡一次要几十个小时二是能量浪费严重放掉的都是电池里实实在在存储的电能最后变成封装内部的热量对散热设计非常不友好。主动均衡的思路是把电荷从高电压电芯“搬运”到低电压电芯而不是烧掉。实现方式通常是电感或电容式的能量转移效率能做到 80%~90%。同样处理 4Ah 的不平衡1A 均衡电流大约 4 小时完成被动均衡按 0.1A 算要 40 小时而且被动方案要把 4Ah × 3.2V ≈ 12.8Wh 的能量全部变成热量散掉主动方案按 85% 效率算实际发热只有不到 2Wh。这就是我在这个项目里最终选择 MP2642GR-Z 这类主动均衡芯片的根本原因。提示均衡的目标不是把每节电池电压做到完全相等而是把 SOC 差控制在一个可接受范围。电压相等不等于 SOC 相等不同电芯的 OCV-SOC 曲线有细微差异判断时脑子里要时刻有这个前提。2. MP2642GR-Z 接入电池组拓扑、接线与电感选型2.1 这颗芯片替你完成了什么MP2642GR-Z 是专为两串电池设计的双向主动均衡控制器内部集成功率开关和控制环路外部只需要一颗功率电感。它的核心工作模式是持续检测两个电芯的电压当检测到电压差超过内部阈值时自动把电荷从高电压电芯泵到低电压电芯。泵浦方向由芯片内部逻辑决定不需要 MCU 判断极性这点非常省事。MCU 在中间扮演的角色是“策略决策者”芯片只关心怎么搬电荷但什么时候搬、搬到什么程度、系统当前是否适合均衡这些判断需要交给 STM32F411RE。MCU 通过 I2C 读写芯片的寄存器配置使能位、查询两个电芯的电压遥测、读取故障状态再根据整机工况决定均衡是否运行。需要说明的是具体管脚命名和寄存器地址请以 MP2642GR-Z 官方数据手册为准下面给出的接线逻辑按这类主动均衡芯片的通用框架描述整体拓扑是可靠的。2.2 接线关系与采样走线的关键两节电池的串联关系很直观电芯1的正极是整个模组的 BAT电芯1的负极与电芯2的正极在中间相连电芯2的负极是整个模组的 BAT-。芯片需要感知三个节点顶层电芯电压、底层电芯电压、以及串联中点。连接节点接向位置说明VBAT 顶层采样电芯1正极顶层电芯电压采样与芯片供电中点采样电芯1负极 / 电芯2正极串联中点必须单独引线GND 底层采样电芯2负极底层参考地SW 开关节点外置功率电感两端电感型能量搬运路径SCL / SDAF411RE 的 I2C 引脚需要上拉到 3.3V可加串阻抑制振铃ENF411RE 的 GPIO高电平使能均衡控制器INTF411RE 的外部中断引脚故障或状态变化通知这里必须强调采样线的走法。芯片做均衡方向判断依赖的是电压比较所以 VBAT、中点、GND 这三条采样线必须采用独立的 Kelvin 接法直接从电芯端子上拉细线到芯片采样脚绝不能在采样路径上共用负载电流的铜皮。原因很简单均衡电流或者负载电流在铜皮上会产生毫伏级压降总线阻越宽越容易被忽略但这几分压降足够让电压比较器做出错误判断。实测中采样线不处理干净的板子电压读数的抖动可以达到 20mV 以上比均衡停止阈值还大加上之后整个状态机就没法稳定工作。2.3 电感和电容的选型电感是这套方案里最容易选错的元件。它直接影响均衡电流峰值、系统效率和开关噪声。我整理了一份自己的选型参考参数推荐范围选型理由电感量2.2~10 µH太小则电流峰值过大容易触发过流保护太大则响应慢、体积大饱和电流≥ 1.5 × 峰值均衡电流防止电感饱和后电感量骤降电流瞬间激增DCR尽量 50 mΩ直接影响能量搬运效率类型屏蔽式绕线功率电感叠层电感抗饱和能力弱屏蔽型对周边走线干扰小我最终用的是 4.7µH、饱和电流 4.5A 的屏蔽绕线电感DCR 大概 20mΩ。这个参数的逻辑是芯片的峰值均衡电流能做到 2A 级别按 1.5 倍余量就需要至少 3A 饱和电流再预留一点温度降额4.5A 比较稳妥。PCB 布局上四条硬性要求第一SW 开关节点和电感之间的走线要短要粗开关节点面积控制在最小避免形成天线辐射第二去耦电容紧贴 VBAT 和 GND 引脚100nF 陶瓷电容配合 10µF 的电解电容组合第三I2C 两根信号线不要贴着电感或者 SW 节点走必要时两侧包地处理第四电池采样线采用星型接地先汇到芯片的采样地再统一回流到电池负极不要和功率地混在一起。这几条如果第一条没做好后面实测时示波器上看到的开关振铃会教你重新做人。3. STM32F411RE 上位控制I2C 通信与寄存器操作3.1 为什么选 F411RE 这颗 MCU均衡芯片本身是个能量搬运执行器它并不了解整机状态现在是在充电还是放电温度合不合适要均衡多久这些策略问题需要一个 MCU 来做。选 STM32F411RE 有几点实际考量第一这颗芯片在 100MHz 下运行 Cortex-M4F 内核512KB Flash、128KB SRAM跑均衡状态机绰绰有余剩余空间还能做日志缓存和曲线记录。第二硬件 I2C 支持 400kHz 快速模式和均衡芯片通信完全够用不用软件模拟 I2C。第三GPIO 数量足够覆盖均衡使能、中断输入、状态指示灯、与主机通信这几件事不需要为了 IO 扩展再挂一颗芯片。第四Cortex-M4 的 FPU 和 DSP 指令虽然在这个项目里不是刚需但以后要加数字滤波或者 SOC 估算算法时不用换平台。对比过更小的 G0 系列和老的 F103 系列G0 便宜但 SRAM 太小日志不够存F103 频率和外设都够但同配置下价格和供货灵活性不如 F4 系列。最终 F411RE 是成本、性能、开发速度三者平衡下来的选择。3.2 I2C 通信骨架与代码通信层面要处理的寄存器不多基本就三类控制寄存器、状态/故障寄存器、两节电芯的电压遥测寄存器。以下代码展示了用 HAL 库读写均衡芯片的基础函数#define BAL_I2C hi2c1 #define BAL_ADDR 0x25 /* 7位地址以数据手册为准 */ #define BAL_REG_CTRL 0x00 #define BAL_REG_STAT 0x01 #define BAL_REG_VCELL1_H 0x02 #define BAL_REG_VCELL1_L 0x03 #define BAL_REG_VCELL2_H 0x04 #define BAL_REG_VCELL2_L 0x05 #define BAL_CTRL_EN (1U 0) static HAL_StatusTypeDef bal_write_reg(uint8_t reg, uint8_t val) { return HAL_I2C_Mem_Write(hi2c1, (uint16_t)(BAL_ADDR 1), reg, I2C_MEMADD_SIZE_8BIT, val, 1, 50); } static HAL_StatusTypeDef bal_read_regs(uint8_t reg, uint8_t *buf, uint8_t len) { HAL_StatusTypeDef st; for (uint8_t retry 0; retry 3; retry) { st HAL_I2C_Mem_Read(hi2c1, (uint16_t)(BAL_ADDR 1), reg, I2C_MEMADD_SIZE_8BIT, buf, len, 100); if (st HAL_OK) return HAL_OK; HAL_Delay(1); } return st; }为什么用HAL_I2C_Mem_Read而不是先写地址再读因为一条Mem_Read调用就在内部处理了起始条件、从机地址、寄存器指针、重复起始和数据读取的完整时序代码简洁且不容易出错。我加了重试机制原因是在均衡芯片检测到故障并进入锁存状态时它可能短暂不响应 ACK或者在忙状态时直接 NACK。实测重试 3 次、间隔 1ms 后总线基本都能恢复不用做复杂的总线恢复流程。上拉电阻也值得单独说。400kHz 下如果总线上只有这一颗从机总电容不大4.7kΩ 上拉就能得到干净波形如果总线上还挂了 EEPROM 或者温度传感器直接把上拉降到 2.2kΩ。我在 SCL 和 SDA 上各串了一个 100Ω 电阻抑制振铃配合示波器实测边沿过冲明显改善。注意上拉必须接到芯片 IO 供电的 3.3V 侧绝对不要图省事接到板子的 5V 电源这个坑我后面实测部分会细说。3.3 电压读取与数据可信度校验电芯电压遥测寄存器通常是 16 位数据分高字节和低字节存储。读取后需要合并并做合理性校验static uint16_t bal_read_cell_mv(uint8_t reg_h, uint8_t reg_l) { uint8_t buf[2]; if (bal_read_regs(reg_h, buf, 2) ! HAL_OK) return 0xFFFF; uint16_t raw ((uint16_t)buf[0] 8) | buf[1]; /* 数据有效性判断0.5V~5V 之外的值一律视为异常 */ if (raw 500 || raw 5000) return 0xFFFF; return raw; }这个校验非常关键。I2C 在电气噪声大的环境里偶尔会读到错误数据如果直接用错误电压去做均衡判据状态机会做出完全错误的行为。把异常值挡在外面宁可判为故障也不冒险均衡是电池系统设计的基本原则。均衡期间芯片自身的 ADC 采样也可能被开关噪声影响所以严格来说电压遥测最好在芯片停止开关动作之后再读取这一点在下一节的测量窗口里展开。4. 均衡策略与状态机什么时候均衡、均衡多久、停在哪4.1 判据设计阈值、迟滞与系统工况均衡策略的第一条原则是不能只看瞬时电压差就启动均衡。我采用的判据是启动阈值 30mV、停止阈值 10mV并且要求电压差持续 10 秒以上才触发。这个迟滞设计是为了避免状态机在阈值附近反复横跳。如果不加迟滞噪声稍微波动一下就可能让均衡在启动和停止之间来回切换电感上的电流反复建立又关断效率损失远大于收益。第二条原则是均衡必须和工作状态绑定。我只允许在系统待机、浮充、且负载电流小于 0.05C 的情况下启动均衡。原因很直接大电流充放电时串联回路的负载电流会在电芯内阻与线路阻抗上产生极化电压这个极化电压叠加到端电压上会让电压差读数严重失真误判概率极高。而且均衡电流与负载电流叠加电池发热更明显对寿命没有好处。备用电源系统的特点是大部分时间处于浮充或待机状态均衡窗口非常充裕不需要去挑战大电流工况。第三条原则是温度限制。当电池温度低于 5°C 或高于 45°C 时强制禁止均衡。低温下锂电负极析锂风险升高高温下均衡产生的附加热量可能推高电芯温度这两类场景都不适合做能量搬运。如果系统里有 NTC软件直接读取温度再做判断没有 NTC 的话可以参考芯片自身的过温保护但保守的做法还是建议外接温度传感器。4.2 状态机实现整个均衡控制核心是一个简单的状态机任务以 10ms 周期调度typedef enum { BAL_IDLE, BAL_CONDITION_CHECK, BAL_ACTIVE, BAL_HOLD, BAL_FAULT } bal_state_t; #define START_DELTA_MV 30 #define STOP_DELTA_MV 10 #define ACTIVE_WINDOW_MS 200 #define HOLD_WINDOW_MS 20 static bal_state_t g_bal_state BAL_IDLE; static uint16_t g_window_cnt 0; void bal_task_10ms(void) { switch (g_bal_state) { case BAL_IDLE: if (system_is_idle() battery_temp_ok()) g_bal_state BAL_CONDITION_CHECK; break; case BAL_CONDITION_CHECK: read_cell_voltages(v1_mv, v2_mv); if (abs((int32_t)v1_mv - (int32_t)v2_mv) START_DELTA_MV) g_bal_state BAL_ACTIVE; else g_bal_state BAL_IDLE; break; case BAL_ACTIVE: bal_write_reg(BAL_REG_CTRL, BAL_CTRL_EN); /* 使能均衡 */ g_window_cnt; if (g_window_cnt (ACTIVE_WINDOW_MS / 10)) { bal_write_reg(BAL_REG_CTRL, 0); /* 进入保持前先停均衡 */ g_window_cnt 0; g_bal_state BAL_HOLD; } break; case BAL_HOLD: g_window_cnt; if (g_window_cnt (HOLD_WINDOW_MS / 10)) { g_window_cnt 0; read_cell_voltages(v1_mv, v2_mv); if (abs((int32_t)v1_mv - (int32_t)v2_mv) STOP_DELTA_MV) g_bal_state BAL_IDLE; else g_bal_state BAL_ACTIVE; } break; case BAL_FAULT: bal_write_reg(BAL_REG_CTRL, 0); /* 上报主机等待人工确认后复位 */ break; } }注意 BAL_ACTIVE 这个分支它运行 200ms 后强制停止均衡进入 20ms 的 HOLD 窗口。这个设计不是多余的。电感型变换器在停止开关后残留的电压尖峰和振铃需要几个毫秒才能平息HOLD 窗口就是给这些开关噪声一个“落地”的时间。在 HOLD 窗口里读电压相当于在系统相对安静的时刻采样才能拿到可信的数据。4.3 测量避让为什么不能边均衡边采样这是整套方案里最容易被低估的细节。均衡芯片工作的时候SW 节点在几十纳秒内完成一次电压跳变产生的高频能量会通过空间耦合和地弹进入采样回路。如果 MCU 的 ADC 引脚走线离电池采样线比较近读到的电压可能跳变十几甚至二十毫伏。我最初没有加 HOLD 窗口时观察到一个现象均衡启动后读到的电压差反而比实际更大状态机不断延长均衡时间而芯片自身的电压比较器却认为已经差不多了两边对不上整个闭环逻辑就乱了。另一个叠加因素是 MCU 的 ADC 参考电压。板上的 3.3V 参考电源在均衡电流变化的瞬间会有轻微的下垂虽然幅值不大但会让 ADC 的量化结果整体偏移进一步放大误差。HOLD 窗口同时解决这两个问题停掉均衡让 3.3V 稳定回来再让 ADC 连续采样 16 次取平均这样读到的电压波动可以压到 1mV 以内状态机工作就稳定了。5. 实测验证与踩坑记录5.1 81mV 偏差的收敛过程样机做好后我做的第一项验证是人为制造一个不平衡状态然后观察均衡效果。方法很简单两块 50Ah 磷酸铁锂先把其中一块单独多充 5% SOC串成两节模组后实测压差约 81mV随后让系统进入待机均衡模式每 5 分钟记录一次压差和均衡电流。时间 (min)压差 ΔV (mV)实测均衡电流 (A)0811.1515521.0530290.9260140.619060.3012040.18从数据能看出的规律很典型压差越大均衡电流越高随着电荷逐步搬过去电感两端电压差变小功率自然下降这符合电感型能量转移的物理特征。整个收敛过程大约是 110 分钟把压差从 81mV 拉到 4mV比我预期的快因为中间压差大的阶段电流一直维持在高位。同时记录的温度数据也印证了主动均衡的效率优势均衡期间芯片表面最高 42°C电感 39°C环境 25°C。同样的场景如果使用被动均衡以 0.1A 的均衡电流处理 4Ah 的不平衡按照 12.8Wh 发热量计算电阻器表面温度轻松超过 90°C而且需要 40 小时才能完成两者完全不在一个量级。5.2 三个踩得很深的坑第一个坑是电感饱和。初期为了压低成本用了 4.7µH、饱和电流只有 1.6A 的叠层电感结果在大压差启动瞬间芯片直接报过流故障还伴随尖锐的啸叫。原因是启动瞬间峰值电流超出饱和电流电感量骤降到空气电感水平电流失去限制之后瞬间激增。处理方式是换成 4.7µH、饱和电流 4.5A 的屏蔽绕线功率电感啸叫消失过流故障也不再出现。第二个坑是 I2C 上拉拉错电压。第一次整板焊完调试发现硬件 I2C 收不到 ACK或者偶尔收到错乱的数据。用示波器量 SCL 和 SDA 波形发现高电平被拉到了 5V。问题出在上拉电阻接到了板子的 5V 电源轨而均衡芯片的 SCL/SDA 引脚最高只能承受 3.6V5V 上拉等于把引脚强制拉到超范围电压芯片内部的输入保护逻辑就开始捣乱。改成 3.3V 上拉后通信立刻恢复正常。这个教训总结成一句话上拉电源必须与芯片 IO 逻辑电平一致不能想当然接到系统电源。第三个坑是采样线与功率回路共用。最初原理图设计时芯片的 VBAT 和 GND 采样脚直接就近连在电池接线端子的同一块铜皮上均衡电流经过这块铜皮时产生了 2~3mV 的压降而且压降方向随均衡电流方向变化导致电压读数来回抖动。改成从电芯端子上单独拉细线走到芯片采样脚之后读数稳定在 1mV 以内。这个问题的本质是采样电流路径和功率电流路径没有分开属于典型的 Kelvin 接法缺失。5.3 批量阶段还需要注意的两个点除了上面三个坑产线验证阶段还会遇到两个容易被忽略的问题。一是芯片的故障锁存处理芯片检测到过温、过流等异常后会进入锁存状态单纯靠软件写控制寄存器无法恢复必须通过 EN 引脚下电再上电才能复位。所以软件流程里要有读 FAULT 寄存器的步骤而不是只会在主循环里盲发使能命令。二是虚焊导致的偶发 NACK回流焊温度曲线不合适时芯片引脚可能出现虚焊I2C 通信表现为偶发超时或 NACK这种问题在产线上非常难定位。我的处理是在出厂测试固件里加了一段连续读寄存器 100 次的压力循环任何一次失败就判定不良品至少能把虚焊板子拦在产线上。这块板子的方案我后来又复制到了一个四串小型备用电源模块里做法是用两片同样的均衡芯片分别处理两组两串电池F411RE 用两路 I2C 分别控制逻辑结构完全相同。实际跑下来最明显的感觉是主动均衡方案的调试成本确实比被动均衡高不少但一旦把状态机、测量避让、故障处理这三块理顺后续几乎不需要干预电池一致性维持得比预期好得多。如果你正在做类似的两串储能模块我的建议是第一版样机就按“接线到位、软件留测量窗口、I2C 加重试”这三个底线来设计能省掉后面一大半的排错时间。