去年年中我调试一台备用电源设备的电池管理板时,被一个现象折磨得不轻:两节同一批次的新电池,串联跑了不到三个月,充电时第一节已经到4.22V触发保护,第二节才3.95V;放电时反过来,第一节先掉到2.9V触发低压告警,整台设备被迫提前停机。后来我把两节电池单独充满再测容量,差了整整18%。储能和备用电源这种长时间浮充、偶发深度放电的使用方式,对电池一致性的惩罚比普通消费电子狠得多,被动均衡电路根本压不住这种偏差。我的解决方案是从头搭一套基于MP2642GR-Z与STM32F429ZI的主动均衡电路,专门针对两个串联电池单元的电压差做能量搬运,而不是把多余能量烧成热。这篇文章就是这套方案的完整复盘,包括拓扑选择、硬件参数计算、固件状态机设计以及调试时踩过的三个大坑,适合正在做BMS、储能PCS或者备用电源系统的朋友参考。
1. 两节电池不均衡,为什么会成为储能系统的阿喀琉斯之踵
1.1 串联不均衡的三个典型后果
串联电池组有个铁律:整组可用容量不是各节容量的平均值,而是最弱那一节的容量。我实测过一组两串电池,一节标称50Ah、实际容量还有48Ah,另一节实际只有39Ah,串联以后放电到整组低压保护时,整组放出的电量只有38Ah左右,接近短板那节的水平。这看起来只是“浪费了一部分容量”,但在储能和备电场景里,后果远不止浪费这么简单。
第一个后果是充电过压。充电时容量小的那一节先充满,电压先顶到保护阈值,BMS只能停止整组充电,容量大的那节实际上还没充满就被迫中止。长期这样跑,大容量那节的平均充电电压偏低,它的可用容量会进一步衰退,形成“强的变弱、弱的更弱”的恶性循环。
第二个后果是放电过放。放电时容量小的那节先到放电截止电压,整组切断负载,但容量大的那节还剩下不少能量没有放出来。在备电系统里,这意味着本来应该支撑4小时的备电时间,可能提前到3小时就结束,而且每次都深度放掉短板电池,铅酸和锂电都很忌讳这种反复深放。
第三个后果容易被忽略:浮充状态下,电压偏高的那节电池长期承担偏高的浮充电流,正极腐蚀和电解液分解的速度会加快。备用电源系统可能一整年都处于浮充状态,这种慢刀子割肉式的损害,比几次过充过放更致命。所以对储能和备电系统来说,均衡不是锦上添花,而是维持整组寿命的必需品。
1.2 电阻耗散的局限与主动均衡的必要性
传统BMS上最常见的被动均衡,本质上就是给每节电池并联一个放电电阻,检测到某节电压偏高时把多余的能量以热量形式放掉。它的优点是电路简单、成本极低、控制逻辑不复杂,缺点也很直白:均衡电流通常只有几十到一百毫安,对于容量几十安时的储能电池,花十几个小时也不一定能把几十毫伏的压差拉平;而且能量全变成热,效率是零,还要担心PCB局部过热。
更重要的是被动均衡只能“放掉高的”,不能“补上低的”。如果系统里有一节电池容量天生偏小,被动均衡能做的只是每次充电时把它的电压多放一点,让它不至于过充,但放电末端它依然最早掉到截止电压,整组可用容量依然受它限制。想让短板电池的容量“找回来”,唯一办法是从其它电池搬能量给它,这就是主动均衡存在的意义。
主动均衡的效率核心是“能量转移而非能量消耗”。一块效率85%的均衡电路,搬过去100焦耳能量,只有约15焦耳变成热量,跟被动均衡100%发热相比完全是两个量级。在储能和备电这样对能量利用率敏感的场合,这个差异值得多花几块钱成本。
1.3 为什么偏偏是“双向升降压”
主动均衡的实现方式有好几种,常见的有电容飞渡、电感转移和变压器隔离。电容飞渡适合小电流、对成本敏感的场景,但均衡速度慢,而且相邻电池压差很小时效率会掉得厉害;电感转移结构简单,但通常只适合相邻电池之间做能量搬运;变压器隔离可以做到任意电池对均衡,性能最好,代价是电路复杂、磁性元件体积大、设计周期长。
我最终选择基于MP2642GR-Z做双向Buck-Boost,实际上想清楚了一件事:两个串联电池单元之间做能量搬运,电压范围都在3.0V到4.2V之间,谁高谁低不确定,而且工作过程中可能会交错变化。如果只用降压或只用升压,方向一反转就抓瞎。双向升降压天然就支持源侧和目标侧的互换,第一节电压高于第二节时能量正向流动,第二节高于第一节时能量反向流动,不需要额外加复杂的极性切换电路。
另一个现实原因是MP2642GR-Z内部把Buck、Boost、Buck-Boost三种模式切换逻辑做进去了,占空比极限状态下的模式衔接由硬件自动处理。如果用普通控制器自己搭四开关桥,最难搞的就是模式切换瞬间的环路稳定性,处理不好会在模式边界来回振荡。这颗芯片把最麻烦的模拟部分接走了,留给我的主要是给STM32F429ZI写采样、判断和调度逻辑,这是我选它而不是自己用分立元件拼拓扑的最直接理由。
2. MP2642GR-Z加STM32F429ZI的硬件拼图
2.1 能量流动拓扑:一个Buck-Boost就是一个搬运工
整套系统的核心拓扑可以这样理解:两节串联电池B1和B2,B1的负极就是B2的正极,这个公共点作为功率级的参考地。MP2642GR-Z控制四个开关管组成同步整流桥,中间接一个功率电感,B1两端接到半桥A侧,B2两端接到半桥B侧。当B1电压比B2高时,控制器让能量从A侧流向B侧,等效于给B2充电,同时B1被轻微放电;当B2电压比B1高时,能量反向流动。
关键点在于这四个开关管构成的桥本身是对称的,能量从A到B和从B到A都走同一条物理路径,只是占空比控制时序不同。MP2642GR-Z的PWM逻辑负责产生四路驱动信号,STM32F429ZI通过一个方向控制信号告诉芯片当前应该以哪一侧为源,以及目标均衡电流是多少。这里要强调一下:方向切换不是简单地把驱动信号颠倒过来,还要切换电压/电流反馈采样网络,否则环路会工作在错误的反馈极性上。我在第一版设计时忽略了这一点,结果方向切换瞬间芯片直接满占空比输出,差点把功率管烧了。
这套结构相比传统“两个独立的Buck和Boost背靠背”的方案,少了一套功率电感,少了一半开关管,效率和成本都更友好。对于两串电池的均衡,它是一个很干净的解法。
2.2 电感、采样电阻和控制环路的选型计算
功率级选型里最容易拍脑袋的就是电感。均衡系统追求的不是功率,而是长时间稳定运行,所以我把目标均衡电流设定为0.5A,这个电流下2Ah的单节电池大概4小时才能完成一次明显的SOC搬移,速度够用且发热可控。电感值的选择要同时兼顾纹波电流和体积,我们实际用了10uH,DCR在30毫欧以内,饱和电流1.5A以上。
可以用一个简单的Buck模式纹波公式来验证这个取值是否合理。假设能量从4.0V的电池搬到3.5V的电池,开关频率500kHz,平均电流0.5A。纹波电流ΔI的计算公式为:
ΔI = V_out × (V_in - V_out) / (f × L × V_in)
代入数值:4.0V输入、3.5V输出、500kHz、10uH,算出来ΔI约87mA,占平均电流的17%左右,属于比较健康的纹波比例。如果换成22uH电感,纹波还能降到40mA以下,但电感的体积和DCR都会上去,对0.5A级别的应用没必要。
采样电阻也要仔细选。均衡电流只有0.5A,如果用10毫欧采样电阻,压降只有5mV,非常容易被噪声淹没;用20毫欧又会在0.5A时多耗10mV电压,对低电池侧的充电电压有微小影响。我的做法是采样电阻放在功率电感和电池之间的低侧回路,用开尔文四线接法连到MP2642GR-Z的电流检测引脚,避免功率电流在PCB铜箔上的压降被误判成采样信号。输出电容方面,在A、B两个端口各放了一组22uF陶瓷电容和47uF电解电容并联,用于吸收开关纹波和均衡电流切换时的瞬态能量。
2.3 STM32F429ZI在功率链路里扮演的角色
有人会问,MP2642GR-Z自己就能完成电压电流环路控制,为什么还要加一颗STM32F429ZI?因为芯片管的是“怎么把能量搬得稳”,不管“该不该搬、往哪搬、搬多少”。这两个问题正好是系统层面的决策,需要实时采样两节电池电压、计算压差、判断均衡方向、给芯片下发目标值、记录运行日志。
STM32F429ZI的资源在这个项目里是明显冗余的,但冗余反而是好事。我用它的三个ADC通道分别采B1电压、B2电压和均衡电流,用软件滤波后做均衡判决;用DAC输出一个0到2.5V的参考电压,通过一个电阻叠加到MP2642GR-Z的反馈引脚上,实现目标电压的软件微调,这比直接改硬件分压电阻灵活太多。DAC配合硬件环路后,0.5A均衡电流的设定值可以直接在固件里调整,不需要动烙铁。
另外STM32F429ZI的高级定时器还能输出互补PWM带死区,如果后续不想用MP2642GR-Z内部的驱动逻辑、想自己搭H桥驱动,这套PWM资源可以直接顶上。虽然本次没有这么用,但留了这个后路,板子的可玩性高很多。整个硬件分工可以概括为一句话:功率控制交给MP2642GR-Z,系统大脑交给STM32F429ZI,两边通过几条模拟信号线对话。
3. 固件里真正要处理的事:采样、判决和闭环
3.1 ADC采样与滤波:均衡判决的基础
均衡系统做决策只依赖一个量:两节电池的电压差。如果电压采样都不准,后面所有逻辑都是空中楼阁。我在这块踩过不少坑,最后总结出一个相对可靠的采样方案。
硬件上,电池电压先用精密电阻分压到3.3V以内,分压比选的1:2,4.2V降到2.8V左右,留出余量;分压输出经过一个100欧电阻和100nF电容组成的RC低通滤波器,再进ADC引脚。软件上,我做了两层滤波:第一层是连续取9次采样的中位值,把偶发的开关毛刺直接剔除;第二层是对中位值再做16点滑动平均,把热噪声和纹波压到最低。
ADC配置有个容易被忽略的细节:采样时间如果太短,内部采样电容没充满,读出来的值会系统性偏低。我在STM32F429ZI上把采样周期拉到最长的480个周期,配合ADC时钟分频,单次采样转换时间约5微秒,三个通道轮询一遍也就十几微秒,完全够用。经过这套处理,静态电压测量误差可以控制在正负5mV以内,这为后面的均衡判决提供了可靠基础。
下面是我用的ADC初始化片段,基于HAL库写,实际引脚按你的板子调整:
static void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig = {0}; hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = ENABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.NbrOfConversion = 3; hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV; HAL_ADC_Init(&hadc1); sConfig.Channel = ADC_CHANNEL_0; // B1电压 sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; HAL_ADC_ConfigChannel(&hadc1, &sConfig); sConfig.Channel = ADC_CHANNEL_1; // B2电压 sConfig.Rank = 2; HAL_ADC_ConfigChannel(&hadc1, &sConfig); sConfig.Channel = ADC_CHANNEL_2; // 均衡电流 sConfig.Rank = 3; HAL_ADC_ConfigChannel(&hadc1, &sConfig); }3.2 均衡状态机:怎么定义“正在均衡”和“均衡结束”
均衡控制的核心不是PID,而是一个逻辑清晰的状态机。我的设计分了四个状态:空闲、正向均衡、反向均衡、保护。正向均衡表示能量从B1流向B2,反向表示从B2流向B1。
状态切换的关键是滞环,否则会出现在压差临界点来回抖动的“临界振荡”。我设置开启均衡的阈值是30mV,关闭均衡的阈值是10mV,方向判定要连续3次采样都指向同一个方向才确认。举个例子:初始压差120mV,B1高于B2,系统进入正向均衡;当压差被拉到8mV时,系统进入空闲状态;如果静置后压差回升到35mV,则会再次切入对应方向。用30mV和10mV而不是单个阈值的原因很简单:电池电压本身有动态回弹,如果用单一20mV阈值,会在20mV附近反复进进出出,均衡电流频繁通断反而降低效率。
均衡结束不能只靠电压差一个条件。电池极化会导致电压暂时“虚假接近”,实际SOC差异还很大,这时候停止均衡,静置半小时后压差又会反弹。我在状态机里加了一个确认逻辑:压差小于10mV并稳定保持5分钟才判定完成,同时设了最长均衡时间限制(默认2小时),防止某节电池内阻异常导致永远拉不平。
下面是简化版的状态机主循环代码:
typedef enum { BAL_IDLE, BAL_FWD, BAL_REV, BAL_FAULT } bal_state_t; bal_state_t bal_state = BAL_IDLE; void bal_state_machine(void) { float v1 = get_battery_voltage(0); float v2 = get_battery_voltage(1); float diff = v1 - v2; switch (bal_state) { case BAL_IDLE: if (diff > 0.030f) { bal_state = BAL_FWD; set_balance_direction(1); } else if (diff < -0.030f) { bal_state = BAL_REV; set_balance_direction(0); } break; case BAL_FWD: if (diff < 0.010f) { bal_state = BAL_IDLE; set_balance_enable(0); } break; case BAL_REV: if (diff > -0.010f) { bal_state = BAL_IDLE; set_balance_enable(0); } break; default: bal_state = BAL_FAULT; break; } }3.3 电流环路的实现:用DAC参与电压反馈
MP2642GR-Z内部有完整的电压反馈环路,正常使用时通过分压电阻把输出电压设定在目标值。但在均衡场景里,我们需要的是“以0.5A电流从高电池搬能量到低电池”,更像一个限流源,而不是精确稳压源。我的做法是给DAC输出加一个电阻,注入到采样电阻分压网络的中点,用软件动态修改芯片的反馈点电压,从而间接控制输出电流。
具体原理不复杂。DAC输出通过一个100k电阻接到反馈分压网络,DAC电压升高相当于给反馈节点注入电流,芯片会认为输出电压偏高,主动往下调,于是低电池侧的实际充电电压降低,电流被限制住。通过标定DAC值和实测电流的关系,我做了一张简单的映射表,固件里设定目标电流时直接查表输出DAC值。
DAC的值不需要很精确,因为电池电压和均衡电流的关系是缓变的。我在实测中发现,DAC输出变化50mV,均衡电流大约变化200mA左右,线性度尚可。真正要注意的是DAC的电源噪声,如果直接用STM32F429ZI的VDDA供电,开关噪声会耦合进反馈节点。我给DAC参考电压单独加了一颗低噪声基准源,并在DAC输出端加了10k串阻和100nF电容滤波,稳定后再进反馈网络。这一步看起来小,实际对均衡电流的稳定性影响非常大。
4. 实测数据与调试踩坑记录
4.1 一组从0.12V到0.018V的实验数据
我在实验平台上用两节全新磷酸铁锂电池做了一轮完整测试,目标是把初始压差拉平。测试条件:均衡电流设定0.5A,环境温度25摄氏度,电池静置30分钟后开始记录。
测试数据整理成表格如下:
| 时间点 | B1电压 | B2电压 | 压差 | 状态 |
|---|---|---|---|---|
| 0分钟 | 3.986V | 3.868V | 118mV | 开始正向均衡 |
| 10分钟 | 3.964V | 3.902V | 62mV | 均衡中 |
| 25分钟 | 3.934V | 3.921V | 13mV | 接近完成 |
| 40分钟 | 3.921V | 3.910V | 11mV | 压差小于阈值,进入确认 |
| 47分钟 | 3.918V | 3.909V | 9mV | 判定完成,停止均衡 |
| 77分钟 | 3.922V | 3.915V | 7mV | 静置后回弹很小 |
从数据能看到,最开始的20分钟压差收敛很快,因为电池极化电阻和SOC差都在起作用;最后10mV以内的收敛变慢,是因为电压曲线在这个区间比较平缓,0.5A电流搬移0.07Ah能量只产生几毫伏的电压变化。这套平台的效率我也测了,正向降压模式下实测约88%,反向升压模式约84%,主要损耗在外置MOS导通电阻和电感DCR上,整体表现可以接受。
4.2 踩坑一:环路补偿参数选错导致的振荡
第一版样机上电后,我很快发现一个诡异现象:均衡电流设定0.5A时,输出端电压以约2kHz的频率来回摆动,幅度50mV左右,同时电感发出嘶嘶的啸叫。用示波器看MP2642GR-Z的开关节点波形,发现不是在正常开关,而是占空比大幅跳动。这个问题直接指向环路补偿环节。
排查过程中我先怀疑电容容量不够,把输出电容从22uF加到220uF,啸叫有所缓解但没有消失。后来仔细对照芯片应用笔记,发现是补偿网络的零点和输出电容ESR零点没有配合好。我把补偿电阻从10k改成4.7k,补偿电容从10nF改成47nF,重新上电后振荡消失,电感啸叫也彻底没有了。
这个教训很重要:同步升降压控制器的环路稳定性不是随便抄一个阻容值就行的,它和输出电容特性、负载电流、工作模式都强相关。调试这类电路,示波器一定要接在输出电压和开关节点上,先确认环路稳定,再谈均衡逻辑。
4.3 踩坑二:ADC采样噪声让均衡方向来回跳
第二个坑出现在软件联调阶段。均衡方向判断在压差60mV左右时开始出现抖动,均衡电流一会儿正一会儿负,效率骤降。我在ADC原始值前面加打印,发现分压采样值在开关动作时跳变超过20mV,光靠滑动平均根本压不住。
问题的根源是功率级开关动作时,地线电位发生瞬态跳变,ADC采样正好落在开关沿附近,采到了被污染的值。我做了两处修改:一是ADC采样触发改成和PWM开关频率同步,避开死区边沿;二是软件滤波从单纯的滑动平均改成“中位值+滑动平均”两级结构,先用9点中位值剔除异常尖峰,再做16点平均。改完以后采样噪声从20mV降到了3mV以内,方向判定的抖动彻底消失。
这里有个经验:BMS系统的ADC采样不要用连续自由采样,最好用定时器触发,并把采样窗口放在PWM周期的固定相点,尤其是PWM关断稳定期。这样做可以稳定避开大部分开关噪声,比事后滤波有效得多。
4.4 踩坑三:功率地单点连接的教训
第三个坑是PCB布局问题。第一版板子为了走线方便,采样电阻的地线直接就近连到了功率MOS的源极地,结果均衡电流0.5A时,电池电压采样值比万用表实测值高了35mV。这个误差对均衡判决来说很致命,因为它直接导致压差阈值判断完全失真。
后来我把布局改成功放区和采样区分开走线:功率回路的地采用星型汇集到输入电容的负极,所有的电压采样线则从电池端子单独走一对开尔文线,经过100欧限流电阻后回到ADC,采样地上不流过任何功率电流。改完以后,0.5A均衡电流下的采样误差降到了5mV以内,这个问题才算彻底解决。做这类板子,永远要记住一句话:采样线和功率线不能共用回流路径。
5. 从“两串”到“多串”:这套方案怎么进化
5.1 相邻均衡和任意电池对均衡
文章标题虽然只写了两节串联电池的均衡,但实际储能系统的电池簇通常是十几节到几十节串联。两串是最小模块,也是我最推荐的起步方式,因为可以在最小代价下把功率级、采样、状态机全部验证成熟。
从两串扩展到多串,常见路线有两条。第一条是相邻电池均衡,即每两节相邻电池之间配一个均衡模块,第一节对第二节、第二节对第三节,这样N节电池需要N-1个功率级。这套方案电路简单、控制独立,缺点是成本随电池数量线性增加,而且只能搬运相邻电量。第二条是集中式均衡,整个系统只保留一个MP2642GR-Z功率级,前面加一组MOS或继电器开关矩阵,可以选通任意两个电池单元做能量搬运。这种方式功率级利用率高,但开关矩阵的控制逻辑复杂得多,开关动作时的瞬态也要格外小心。
我个人的建议是:如果电池节数不超过8串,用相邻均衡方案性价比最高,电路简单、故障定位容易,每节电池都有独立的均衡通路;如果超过8串,集中式均衡在成本上更占优势,但必须处理好开关矩阵互锁和采样时序。
5.2 与系统级BMS的协同
一个独立的均衡模块解决的是“电池内部不一致”的问题,但它不是孤岛,必须和BMS主控配合。我在扩展设计中让STM32F429ZI通过CAN总线把实时电压、均衡方向、均衡电流和故障状态上报给上位机,同时接收上位机下发的均衡开启/关闭命令。
这套协同逻辑里有几个关键点。浮充阶段,均衡模块应该以小电流工作,因为此时电池静止、极化小,电压能比较真实地反映SOC差异,适合慢速补齐;放电末期,电池电压动态变化快,均衡模块如果还按静态压差判断,很容易误动作,所以最好在放电电流大于某阈值时暂停均衡。这些策略在固件里实现起来不难,难的是想明白什么时候该均衡、什么时候该让路。
5.3 一个值得做的后续优化
整套方案跑通之后,我觉得最值得继续投入的方向是给均衡电流加真正的闭环控制。目前的做法是用DAC配合硬件环路间接限制电流,精度和动态响应都还过得去,但遇到大容量电池或低温环境时,0.5A的固定电流未必是最优的。可以增加一节温度传感器,根据电池温度和压差动态调整目标电流,低温时减小电流防止析锂,高温时减小电流防止热失控。
另外一个可以做的优化是故障记录:把每次均衡的起始压差、结束压差、运行时间和累计转移能量存到Flash里。长期积累这些数据以后,可以判断哪节电池的衰退速度异常,提前安排维护。电池管理系统最大的价值往往不是单次均衡做得多好,而是能通过历史数据把慢性的异常提前发现。如果让我从头再设计一次,我会把功率级的采样电阻和ADC参考地做成完全隔离,调试阶段能省掉一半噪声相关的返工时间,这个教训我现在还记得很清楚。