
1. 从两个串联电芯说起为什么被动均衡在储能场景里依然能打储能系统和备用电源系统里串联电芯的电压不均衡是个绕不开的老问题。你拿两节标称3.2V的磷酸铁锂电芯串起来用理论上总压6.4V但实际跑上几十个充放电循环之后你会发现其中一节可能已经冲到3.65V了另一节还趴在3.1V附近。这时候如果继续按总压充电高压那节就过充了如果按总压放电低压那节又提前触底。整个电池组的可用容量被最弱的那节电芯死死卡住这就是木桶效应在电池管理里的经典体现。解决这个问题的思路分两大流派被动均衡和主动均衡。主动均衡用变压器、电感或者电容把高电压电芯的能量搬到低电压电芯去效率高、发热小但电路复杂、成本高、体积大。被动均衡则是给电压偏高的那节电芯并联一个电阻让它通过电阻放电把多出来的能量以热量的形式消耗掉。听起来很笨但在两串电芯的储能和备用电源场景里被动均衡反而是最务实的选择——电路简单、可靠性高、成本可控而且两串系统的能量本就不大耗散掉的那点功率完全可以接受。我这次做的方案核心器件选了两颗MP2642GR-Z和MK64FX512VDC12。前者是一颗带均衡功能的电池管理前端芯片后者是一颗基于ARM Cortex-M4内核的微控制器。两颗芯片配合起来构成一个完整的双串电芯均衡控制系统。MP2642GR-Z负责实时采集每节电芯的电压、控制均衡MOS管的通断MK64FX512VDC12则负责读取前端数据、执行均衡策略、管理充放电状态、对外通信。这套方案适合谁参考如果你正在做小型的储能模组、UPS备用电源、便携式储能电源或者任何需要两串锂电管理的嵌入式项目这篇文章里的设计思路、参数计算和踩坑经验都能直接拿去用。即便你用的是别的MCU或者别的前端芯片均衡策略和电路设计的底层逻辑是相通的。提示被动均衡的本质是削峰不是填谷。它只能把高电压电芯的多余电量放掉不能给低电压电芯补电。所以均衡的前提是——低压那节电芯本身没有故障只是自放电率或者初始容量略有差异。2. MP2642GR-Z 的均衡引脚到底怎么接从数据手册到实际电路2.1 芯片均衡功能的内部结构MP2642GR-Z这颗芯片的均衡功能说白了就是内部集成了一个或者多个可控的放电开关。每个开关对应一节电芯开关闭合时电芯正负极之间就并联上一个外部电阻电芯通过这个电阻放电。芯片内部通常还会有一个均衡定时器或者PWM控制逻辑用来限制均衡电流的占空比防止电阻过热。具体到MP2642GR-Z它的均衡引脚通常标注为CB1、CB2之类的名字是开漏输出结构。这意味着你不能直接把电阻接到引脚和地之间就完事——开漏输出需要外部上拉或者配合外部MOS管才能形成完整的放电路径。我见过不少新手在这里翻车以为均衡引脚输出高电平就能驱动电阻放电结果电阻两端根本没有压差电芯电压纹丝不动。正确的接法是均衡引脚控制一个P沟道MOS管或者N沟道MOS管取决于芯片内部结构MOS管的源漏极串联均衡电阻再并联到电芯两端。当均衡引脚输出有效电平时MOS管导通电芯通过电阻放电。电阻的选型直接决定了均衡电流的大小。2.2 均衡电阻的取值计算均衡电流的计算公式很简单I V_cell / R_balance。假设单节电芯电压为3.4V你希望均衡电流控制在50mA左右那么R_balance 3.4V / 0.05A 68Ω。标准阻值选68Ω或者75Ω都可以。但这里有个功率问题不能忽略。电阻上的功耗P I² × R 0.05² × 68 0.17W。看起来不大但如果你选的是0402或者0603封装的电阻额定功率通常只有0.063W到0.1W长期跑下来电阻会发烫甚至烧毁。所以均衡电阻至少要选0805封装0.125W或者1206封装0.25W留足余量。我实际用的是1206封装的68Ω电阻实测表面温度在环境温度25℃时大约45℃到50℃手摸上去有点烫但不会烫伤。如果你把均衡电流提到100mA电阻功耗就变成0.68W了这时候必须用2512封装甚至加散热片而且PCB铜箔面积要足够大通过铺铜帮助散热。均衡电流电阻值3.4V电阻功耗推荐封装实测温升30mA113Ω0.10W0805约15℃50mA68Ω0.17W1206约25℃80mA42Ω0.27W1206/2512约40℃100mA34Ω0.34W2512约55℃2.3 均衡MOS管的选型要点MOS管的选择主要看三个参数导通电阻Rds(on)、栅极阈值电压Vgs(th)、漏源击穿电压Vds。两串电芯的总压最高也就8.4V左右所以Vds选20V或者30V的管子绰绰有余。关键是Rds(on)要小否则MOS管本身也会发热。我选的是某款SOT-23封装的N沟道MOSRds(on)在4.5V栅压下大约30mΩ均衡电流50mA时管子上的压降只有1.5mV功耗可以忽略不计。栅极阈值电压要特别注意。MP2642GR-Z的均衡引脚输出电压可能是3.3V逻辑电平如果你选的MOS管Vgs(th)标称2.5V但最大可能到3V那在3.3V驱动下可能处于半导通状态Rds(on)急剧增大管子会严重发热。稳妥的做法是选Vgs(th)最大不超过2V的管子或者用逻辑电平MOS。注意均衡MOS管的栅极最好串联一个100Ω到1kΩ的电阻用来抑制栅极振荡。虽然均衡开关频率不高但在PCB走线较长时寄生电感仍然可能引起振铃。3. MK64FX512VDC12 如何读取电芯电压ADC配置与滤波处理3.1 前端芯片的数据输出接口MP2642GR-Z采集到的电芯电压数据需要通过某种接口传给MK64FX512VDC12。常见的接口有I²C和SPI两种。I²C的好处是引脚少、接线简单缺点是速率相对较低而且在多设备总线上容易发生地址冲突。SPI速率高、全双工但需要四根线CS、SCK、MOSI、MISO。我用的这颗前端芯片支持I²C接口所以MK64FX512VDC12这边就配置I²C主机模式。MK64FX512VDC12的I²C模块支持标准模式100kbps、快速模式400kbps和快速模式1Mbps。对于电芯电压采集这种低频任务400kbps完全够用而且抗干扰能力比1Mbps更好。I²C的时钟频率由总线时钟分频得到。假设MK64FX512VDC12的总线时钟是60MHz要得到400kbps的SCL频率分频系数 60MHz / (2 × 400kHz) 75。实际配置时要注意分频寄存器通常只支持2的幂次分频或者特定范围的分频值需要根据参考手册的公式精确计算。3.2 ADC采样与数字滤波前端芯片输出的电压数据已经是数字量了但MK64FX512VDC12内部可能还需要对某些模拟信号比如总压、温度进行ADC采样。MK64FX512VDC12的ADC是16位逐次逼近型参考电压可以选内部1.2V或者外部VREFH。电芯电压经过电阻分压后送入ADC引脚。分压电阻的选取要兼顾功耗和精度。假设电芯最高电压4.2VADC参考电压3.3V分压比至少要是4.2/3.3 1.27。实际取分压电阻为上臂10kΩ、下臂33kΩ分压比 33/(1033) 0.7674.2V分压后是3.22V刚好在ADC量程内。分压电阻上的电流 4.2V / 43kΩ ≈ 0.1mA对电芯容量的影响可以忽略。ADC采样值转换成实际电压的公式V_actual (ADC_value / 65535) × V_ref / 分压比。这里65535是16位ADC的最大值。如果V_ref 3.3V分压比 0.767那么V_actual ADC_value × 3.3 / (65535 × 0.767) ADC_value × 6.57e-5。数字滤波方面我用了滑动平均滤波加中值滤波的组合。滑动平均窗口取8个采样点先去掉一个最大值和一个最小值剩下的6个点求平均。这样既能抑制随机噪声又能消除偶发的脉冲干扰。实测下来电芯电压的采样波动从±15mV降到了±3mV以内。#define FILTER_WINDOW 8 typedef struct { uint16_t buf[FILTER_WINDOW]; uint8_t index; uint8_t count; } filter_t; uint16_t filter_process(filter_t *f, uint16_t new_val) { f-buf[f-index] new_val; f-index (f-index 1) % FILTER_WINDOW; if (f-count FILTER_WINDOW) f-count; // 找最大值和最小值 uint16_t max 0, min 0xFFFF; uint32_t sum 0; for (uint8_t i 0; i f-count; i) { if (f-buf[i] max) max f-buf[i]; if (f-buf[i] min) min f-buf[i]; sum f-buf[i]; } // 去掉最大最小后求平均 if (f-count 3) { sum sum - max - min; return sum / (f-count - 2); } return sum / f-count; }3.3 电压采集的时序控制MK64FX512VDC12读取前端芯片数据时要注意时序配合。前端芯片完成一轮电压转换需要一定时间通常几十毫秒到几百毫秒取决于配置的采样速率。如果MCU在转换完成前就去读数据读到的可能是上一次的旧值或者无效值。我的做法是利用前端芯片的中断引脚。当转换完成时前端芯片拉低中断引脚MK64FX512VDC12的外部中断被触发在中断服务函数里置一个标志位。主循环检测到标志位后再通过I²C读取数据。这样既不会浪费CPU时间去轮询也不会读到无效数据。中断服务函数要尽量简短只做标志位置位和清除中断标志的操作。I²C读取这种耗时操作放在主循环里做避免在中断里长时间占用CPU导致其他中断响应延迟。4. 均衡策略的代码实现从阈值判断到状态机4.1 均衡启动和停止的阈值设定均衡什么时候启动、什么时候停止这个阈值设定直接关系到均衡效果和系统安全。设得太窄均衡频繁启停MOS管和电阻反复承受热冲击设得太宽均衡效果差电芯压差始终降不下来。我的经验值是压差超过30mV时启动均衡压差降到10mV以内时停止均衡。这个30mV和10mV的差值形成了20mV的迟滞带有效避免了均衡在阈值附近反复振荡。为什么选30mV因为磷酸铁锂电芯在充放电平台期的电压变化非常平缓3.2V到3.3V之间可能对应着20%到80%的SOC变化。如果阈值设得太小比如10mV均衡会频繁触发但实际对容量提升的帮助微乎其微。30mV是一个经过实测验证的平衡点既能有效改善电芯一致性又不会造成过多的能量浪费。停止阈值设10mV而不是0mV是因为ADC采样本身有噪声电芯电压也有微小波动。如果要求压差降到0才停止均衡可能永远停不下来。4.2 均衡状态机的设计均衡控制用一个简单的状态机来实现包含四个状态空闲态、检测态、均衡态、故障态。空闲态下系统正常采集电压但不启动均衡。每隔1秒进入一次检测态判断是否满足均衡启动条件。如果压差超过30mV且系统不在充电状态充电时均衡效果差因为充电电流会掩盖均衡电流则进入均衡态。均衡态下打开高压电芯对应的均衡MOS管同时持续监测压差。如果压差降到10mV以内或者均衡时间超过预设上限比如30分钟则关闭均衡MOS管回到空闲态。故障态在检测到异常时进入比如电芯电压超过4.3V过压、低于2.0V欠压、温度超过60℃等。故障态下立即关闭所有均衡MOS管并通过通信接口上报故障码。typedef enum { BAL_IDLE, BAL_CHECK, BAL_ACTIVE, BAL_FAULT } bal_state_t; typedef struct { bal_state_t state; uint32_t balance_start_time; uint32_t balance_duration; uint16_t cell_voltage[2]; uint16_t voltage_diff; uint8_t balance_channel; // 0: 均衡电芯1, 1: 均衡电芯2, 0xFF: 不均衡 } bal_ctrl_t; void balance_state_machine(bal_ctrl_t *bal) { bal-voltage_diff (bal-cell_voltage[0] bal-cell_voltage[1]) ? (bal-cell_voltage[0] - bal-cell_voltage[1]) : (bal-cell_voltage[1] - bal-cell_voltage[0]); switch (bal-state) { case BAL_IDLE: if (bal-voltage_diff 30) { bal-state BAL_CHECK; } break; case BAL_CHECK: if (bal-voltage_diff 30 !is_charging()) { bal-balance_channel (bal-cell_voltage[0] bal-cell_voltage[1]) ? 0 : 1; bal-balance_start_time get_tick(); bal-state BAL_ACTIVE; } else { bal-state BAL_IDLE; } break; case BAL_ACTIVE: bal-balance_duration get_tick() - bal-balance_start_time; if (bal-voltage_diff 10 || bal-balance_duration 1800000) { bal-balance_channel 0xFF; bal-state BAL_IDLE; } break; case BAL_FAULT: bal-balance_channel 0xFF; break; } }4.3 充电和放电状态下的均衡差异充电时均衡和放电时均衡效果完全不一样。充电时充电电流从电芯正极流入均衡电流从电芯正极流出两者方向相反。如果充电电流是1A均衡电流只有50mA那均衡对电芯电压的影响几乎被充电电流淹没了。你看到高压电芯的电压在上升但分不清是充电导致的还是均衡没起作用。所以我的策略是充电过程中不启动均衡只在充电结束后或者放电过程中启动均衡。充电结束后电芯电压会有一个弛豫过程从充电时的极化电压慢慢回落到开路电压。等弛豫完成通常静置30分钟以上再根据开路电压判断是否需要均衡。放电过程中均衡效果最好因为放电电流和均衡电流方向一致两者叠加后高压电芯的放电电流更大电压下降更快压差收敛速度明显加快。实测数据显示放电过程中均衡压差从30mV降到10mV只需要约15分钟而静置状态下均衡同样压差需要约40分钟。提示如果你的系统不允许放电时均衡比如备用电源长期浮充那就只能在充电结束后静置一段时间再均衡。这时候均衡时间要设长一些因为静置状态下均衡电流全部用于消耗电芯能量压差收敛速度慢。5. 实测中遇到的三个坑和排查过程5.1 均衡电阻发烫但压差纹丝不动第一次调试时我发现均衡电阻明显发烫手摸上去烫得厉害但电芯压差就是降不下来。用万用表量均衡电阻两端电压只有0.3V左右而电芯电压是3.4V。这说明均衡MOS管没有完全导通大部分压降落在了MOS管上。排查过程先量MOS管栅极电压发现只有1.8V。MP2642GR-Z的均衡引脚输出高电平应该是3.3V才对为什么只有1.8V查数据手册发现均衡引脚是开漏输出需要外部上拉到3.3V。我忘了接上拉电阻栅极电压是被MOS管内部寄生电容和漏电流浮起来的根本达不到完全导通的阈值。解决方案在均衡引脚和3.3V之间接一个10kΩ上拉电阻。接上之后栅极电压升到3.3VMOS管完全导通均衡电阻两端电压升到3.35V压差开始正常收敛。这个坑的教训是开漏输出必须接上拉电阻这是数字电路的基本常识但在实际画板子时很容易忽略。尤其是当芯片内部有多个开漏引脚时漏掉一个上拉电阻就可能导致整个功能失效。5.2 I²C通信偶尔丢数据系统跑起来之后发现电芯电压数据偶尔会跳变比如从3.42V突然跳到3.15V下一轮又跳回来。一开始以为是ADC噪声加了滤波之后还是有。后来用逻辑分析仪抓I²C波形发现偶尔会出现SCL被拉低但SDA没有正确响应的现象导致读到的数据错位。排查过程检查I²C总线的上拉电阻发现用的是10kΩ。MK64FX512VDC12的I²C总线电容加上PCB走线电容总电容大约200pF。10kΩ上拉电阻在400kbps速率下上升时间 2.2 × R × C 2.2 × 10000 × 200e-12 4.4μs。而400kbps的位周期是2.5μs上升时间已经超过了位周期导致信号还没完全拉高就被下一个时钟沿打断了。解决方案把上拉电阻从10kΩ换成2.2kΩ。上升时间降到约1μs满足400kbps的时序要求。换完之后I²C通信稳定数据跳变消失。上拉电阻上升时间200pF400kbps是否可用100kbps是否可用10kΩ4.4μs否勉强4.7kΩ2.1μs临界是2.2kΩ1.0μs是是1kΩ0.44μs是是上拉电阻也不是越小越好。电阻太小总线低电平时灌电流增大可能超过芯片引脚的驱动能力。2.2kΩ在3.3V系统下低电平灌电流 3.3V / 2.2kΩ 1.5mA大多数MCU的I²C引脚都能承受。如果降到1kΩ灌电流3.3mA有些芯片就吃不消了。5.3 均衡MOS管关断时的电压尖峰用示波器观察均衡MOS管漏极电压时发现关断瞬间有一个幅度约2V的电压尖峰持续时间约100ns。虽然2V的尖峰不会直接击穿MOS管Vds额定20V但长期反复冲击会加速器件老化。排查过程均衡回路的走线比较长大约5cm走线电感约50nH。均衡电流50mAMOS管关断时间约100ns产生的感应电动势 L × di/dt 50e-9 × 0.05 / 100e-9 25mV。等等这个计算值只有25mV和实测的2V尖峰差了两个数量级。重新分析问题不在均衡回路本身而在MOS管栅极。栅极走线也有电感关断时栅极电流突变在栅极电感上产生压降导致MOS管关断过程变得复杂。另外均衡电阻是绕线电阻吗如果是绕线电阻它本身就有几微亨的电感和走线电感一起构成LC谐振回路关断时产生高频振荡。解决方案在均衡电阻两端并联一个100nF的陶瓷电容吸收关断瞬间的高频能量。同时在MOS管漏极和源极之间加一个TVS二极管钳位电压12V把尖峰限制在安全范围内。改完之后尖峰降到0.5V以下效果立竿见影。注意均衡电阻最好选厚膜电阻不要选绕线电阻。厚膜电阻的寄生电感在nH级别绕线电阻可能到μH级别后者在高频关断时会产生更大的尖峰。6. 均衡策略的进阶优化温度补偿与自适应阈值6.1 温度对电芯电压的影响磷酸铁锂电芯的开路电压和温度有一定关系。在0℃时电芯内阻增大放电时电压下降更快在45℃时电芯活性增强同样SOC下电压略高。如果你在冬天和夏天用同一个压差阈值去判断均衡效果会有差异。我的做法是在电芯附近贴一颗NTC热敏电阻MK64FX512VDC12的ADC采集NTC分压电压换算成温度。然后根据温度对压差阈值做微调温度低于10℃时阈值放宽到40mV因为低温下电压波动大太窄的阈值容易误触发温度高于40℃时阈值收紧到25mV高温下电芯一致性变好可以更精细地均衡。NTC的阻值-温度关系不是线性的通常用Steinhart-Hart方程或者查表法换算。MK64FX512VDC12的Flash空间足够大我直接存了一张256点的温度-阻值对照表查表加线性插值精度可以做到±0.5℃。6.2 自适应均衡电流固定均衡电流有个问题电芯压差大的时候50mA均衡电流要很久才能把压差降下来电芯压差小的时候50mA又显得太猛容易过冲。我的优化方案是用PWM控制均衡MOS管的占空比实现自适应均衡电流。压差大于50mV时占空比100%均衡电流50mA压差在20mV到50mV之间时占空比50%均衡电流25mA压差小于20mV时占空比25%均衡电流12.5mA。这样压差大时收敛快压差小时收敛平稳不会出现均衡过头导致低压电芯反而变成高压电芯的情况。PWM频率选1kHz这个频率远高于电芯电压的变化速率不会对电压采集造成干扰。同时1kHz的开关频率下MOS管的开关损耗可以忽略不计。void balance_pwm_update(uint16_t voltage_diff) { uint8_t duty; if (voltage_diff 50) { duty 100; } else if (voltage_diff 20) { duty 50; } else { duty 25; } set_pwm_duty(BALANCE_PWM_CH, duty); }6.3 均衡次数的统计与健康度评估MK64FX512VDC12内部有512KB的Flash我划出一小块区域用来存储均衡统计数据每个电芯的累计均衡时间、均衡次数、平均均衡电流。这些数据可以用来评估电芯的健康状态。如果某个电芯的累计均衡时间明显长于另一个说明这个电芯的自放电率偏高或者容量衰减更快。当累计均衡时间超过某个阈值时系统可以通过通信接口上报电芯一致性变差建议检查的预警信息。这个功能在备用电源系统里特别有用因为备用电源平时没人盯着等到真正需要放电时才发现电芯不行了那就晚了。Flash写入要注意寿命问题。MK64FX512VDC12的Flash擦写次数典型值是10万次如果每次均衡结束都写一次Flash一天均衡10次一年就是3650次十年才3.65万次完全在寿命范围内。但为了保险起见我还是加了一个RAM缓存每10次均衡才把累计数据写入Flash一次减少擦写次数。7. 系统联调与长期运行观察7.1 联调步骤与验证方法系统联调我分了四步走。第一步不接电芯用直流电源模拟两节电芯的电压验证MK64FX512VDC12能否正确读取电压值。这一步主要检查I²C通信和ADC采样是否正常。第二步接上电芯但不启动均衡观察电压采集的稳定性和精度。第三步手动触发均衡用示波器和万用表监测均衡电流和电芯电压变化。第四步让系统自动运行记录24小时的电压曲线和均衡状态。验证均衡效果的方法很简单故意把两节电芯的初始电压差拉到100mV以上一节充到3.6V另一节放到3.2V然后让系统自动均衡。记录压差从100mV降到10mV所需的时间。我的实测数据是放电状态下约45分钟静置状态下约2小时。这个速度对于储能和备用电源应用来说完全够用毕竟这些系统通常有充足的时间来做均衡。7.2 长期运行中的注意事项系统连续跑了三个月之后我总结了几个长期运行才暴露出来的问题。第一个是均衡电阻的阻值漂移。厚膜电阻在长期高温下阻值会慢慢变大导致均衡电流逐渐减小。我用的1206封装电阻在50℃环境温度下跑了三个月阻值从68Ω变成了70.5Ω漂移了约3.7%。虽然影响不大但如果你的系统环境温度更高建议选低温漂电阻比如±100ppm/℃的薄膜电阻或者定期校准均衡电流。第二个是MOS管栅极氧化层的长期可靠性。均衡MOS管每天开关几十次三个月就是几千次。虽然远低于MOS管的开关寿命通常百万次以上但栅极氧化层在反复的电场应力下仍有可能出现缓慢退化。我的做法是在栅极串联一个稳压二极管比如5.1V的防止栅极电压意外超过额定值。第三个是连接器的接触电阻。电芯和PCB之间的连接器经过多次插拔和温度循环后接触电阻可能从几毫欧增加到几十毫欧。这个电阻在均衡回路里会分走一部分压降导致实际均衡电流减小。定期检查连接器接触电阻或者直接用焊接代替连接器可以避免这个问题。7.3 这套方案的成本和适用边界最后说说成本和适用边界。MP2642GR-Z加MK64FX512VDC12两颗芯片加上外围的MOS管、电阻、电容整个均衡控制部分的BOM成本大概在十几块钱人民币的量级。相比主动均衡方案动辄几十上百的成本这个方案在成本敏感的应用里很有优势。适用边界也很明确两串电芯、均衡电流不超过100mA、环境温度-20℃到60℃、对均衡速度要求不极端的场景。如果你的系统是四串、八串甚至更多串MP2642GR-Z可能就不够用了需要选支持更多串数的前端芯片。如果你需要快速均衡比如几分钟内把压差从100mV降到10mV被动均衡的功率耗散会让你在散热设计上非常头疼这时候就该考虑主动均衡了。但话说回来在两串储能和备用电源这个细分场景里被动均衡加MP2642GR-Z加MK64FX512VDC12的组合是我试过的性价比最高、最省心的方案。电路不复杂代码量也不大调试过程中踩过的坑我都写在上面的章节里了你照着做基本能一次跑通。