1. 储能电池均衡的底层逻辑与方案选型
1.1 为什么串联电池组必须做均衡
先聊一个很多人容易忽略的事实:两节标称容量完全一致的电池,串联使用半年之后,端电压差可能拉开到100mV以上。这个差距不是电池质量差,而是制造工艺、自放电率、温度分布、老化速度这四个变量叠加出来的必然结果。
串联回路里电流处处相等,这是基尔霍夫电流定律决定的,没得商量。但每节电池的容量、内阻、库仑效率不可能完全一致。充电时容量小的那节先到截止电压,放电时它又先到欠压保护点。如果BMS不做干预,木桶效应会让整组可用容量被最弱的那节电池锁死。更麻烦的是,容量小的电池在充放电循环中始终处于过充过放边缘,老化速度进一步加快,形成正反馈,整组寿命急剧缩短。
储能系统和备用电源系统对这件事尤其敏感。储能场景要求每天一次甚至两次深循环,备用电源虽然长期浮充但要求随时能顶上去,一旦某节电池提前失效,整组备电时间可能直接腰斩。所以均衡不是锦上添花的功能,是串联电池组能不能用的前提。
1.2 被动均衡与主动均衡的取舍
均衡方案分两大流派:被动均衡和主动均衡。
被动均衡说白了就是给每节电池并一个电阻,谁电压高就让谁多放一点电,把能量以热量形式消耗掉。优点是电路简单、成本低、可靠性高,缺点是效率低、均衡电流小(通常几十到几百毫安)、均衡时间长。主动均衡则是把高电压电池的能量搬到低电压电池去,用电感、电容或者变压器做能量转移,效率高、均衡电流大,但电路复杂、成本高、EMC难搞。
这个项目选的是被动均衡路线,用MP2642GR-Z这颗专用均衡芯片配STM32F205RB做主控。为什么这么选?储能和备用电源系统里,电池组通常长期处于浮充或浅循环状态,电压偏差是缓慢累积的,不需要大电流快速拉平。被动均衡几十毫安的电流,配合合理的均衡策略,完全够用。而且被动均衡没有能量转移带来的EMI问题,对备用电源系统里那些敏感的模拟采样电路更友好。
MP2642GR-Z这颗芯片值得多说两句。它内部集成了均衡MOSFET和电流检测,单芯片可以管两节串联电池,支持外部电阻设定均衡电流,还带过温保护和电池电压监测。用它在两节电池的场景下,外围电路极其精简,一颗芯片加几个电阻电容就搞定,比用分立MOSFET搭均衡电路省心太多。
1.3 STM32F205RB在这个方案里的角色
STM32F205RB是ST的Cortex-M3主力型号,128KB Flash、64KB SRAM、主频120MHz,外设资源对电池管理来说绰绰有余。它在这个方案里干三件事:第一,通过ADC采集两节电池的电压和温度;第二,跑均衡策略算法,决定什么时候开均衡、开哪一路、开多久;第三,通过CAN或者UART跟上层系统通信,上报电池状态和告警。
选F205RB而不是更低端的F103,主要看中它的ADC精度和DMA能力。电池电压采样要求至少12位有效精度,F205的12位ADC配合内部参考电压校准,实测下来能到±5mV以内,对均衡判据来说够用了。DMA可以让ADC在后台自动搬运数据,CPU腾出来跑均衡逻辑和通信协议,不会因为采样阻塞影响实时性。
2. 硬件设计核心细节与参数计算
2.1 MP2642GR-Z外围电路设计要点
MP2642GR-Z的典型应用电路不复杂,但有几个参数必须算准,否则均衡电流要么太小没效果,要么太大烧芯片。
均衡电流由外部检测电阻R_sense决定。芯片内部有个比较器监测R_sense上的压降,当压降达到设定阈值时调整内部MOSFET的导通程度,实现恒流均衡。计算公式是:
I_balance = V_th / R_sense
其中V_th是芯片内部的基准阈值,查数据手册典型值是50mV。假设我们要设定100mA的均衡电流,R_sense = 50mV / 100mA = 0.5Ω。这个电阻的功率要算一下:P = I² × R = 0.1² × 0.5 = 5mW,选0603封装绰绰有余。
但这里有个坑:R_sense的精度直接影响均衡电流的一致性。如果用5%精度的普通电阻,两路均衡电流可能差10%,导致两节电池均衡速度不一致。建议用1%精度的金属膜电阻,温漂选50ppm/℃以内的。我实测过,用1%电阻时两路电流偏差在2%以内,用5%电阻时偏差能到8%,均衡效果肉眼可见地变差。
另外,MP2642GR-Z的供电直接从电池组取,两节串联最高电压8.4V(4.2V×2),在芯片的耐压范围内。但要注意在电池正极和芯片VCC之间串一个10Ω/0.25W的限流电阻,配合0.1μF的旁路电容,滤掉电池线上的高频噪声。这个电阻不能省,我遇到过因为省了这个电阻导致芯片内部基准被噪声干扰、均衡电流忽大忽小的情况。
2.2 电池电压采样电路的设计与校准
STM32F205RB的ADC参考电压用的是VDDA,通常接3.3V。但两节串联电池的电压范围是5.4V到8.4V(按2.7V到4.2V每节算),远超ADC量程,必须分压。
分压电阻的选择有讲究。假设用100kΩ和33kΩ分压,分压比是33/(100+33)=0.248,8.4V分压后是2.08V,在3.3V量程内。但100kΩ的电阻和ADC采样电容会形成RC延迟,F205的ADC采样时间需要相应加长。我一般用22kΩ和7.5kΩ这组,分压比0.254,源阻抗低一些,采样时间设到84个ADC周期就能稳定。
分压电阻的精度同样关键。用1%精度的电阻,分压比误差1%,8.4V时电压误差84mV,对均衡判据来说太大了。两个方案:要么用0.1%精度的电阻,要么在软件里做校准。我选后者,成本低且灵活。校准方法是在已知电压下读ADC值,算出一个校准系数存在Flash里,每次采样后乘这个系数。
具体操作:用高精度电源给电池端加8.000V,读ADC原始值,假设读到的电压是7.920V,校准系数就是8.000/7.920=1.0101。这个系数对分压电阻的初始误差和ADC的增益误差都有修正作用。注意校准要在常温下做,温度变化超过20℃时误差会漂移,但储能系统通常有温控,问题不大。
2.3 温度采集与过温保护
电池温度用10kΩ NTC热敏电阻贴在电池表面采集,分压后接ADC。NTC的阻值-温度曲线是非线性的,软件里用查表法加线性插值处理。
MP2642GR-Z本身有过温保护,结温超过150℃时自动关断均衡。但这是芯片自己的保护,电池的温度需要STM32单独监测。均衡过程中电池本身也会发热,虽然被动均衡的热量主要在电阻上,但大电流放电时电池温升叠加均衡温升,可能触发电池的安全阈值。
我的做法是设两级温度阈值:45℃时降低均衡电流(通过PWM调节均衡使能占空比),55℃时完全关闭均衡并上报告警。这个阈值不是拍脑袋定的,磷酸铁锂电池的推荐工作温度上限是60℃,三元锂是45℃,留10℃余量比较稳妥。
3. 均衡策略的软件实现与代码解析
3.1 电压采集与滤波算法
ADC采集最怕噪声。电池线上有开关电源的纹波、电机负载的尖峰、继电器的抖动,直接读单次ADC值根本不能用。我用的是中值滤波加滑动平均的组合。
具体实现:连续采15次,去掉最大3个和最小3个,剩下9个求平均。这样既能滤掉脉冲噪声,又能抑制随机噪声。15次采样在120MHz主频下耗时不到100μs,对均衡这种秒级响应的场景完全无压力。
代码框架大概是这样:
#define SAMPLE_NUM 15 #define DISCARD_NUM 3 uint16_t get_filtered_adc(uint8_t channel) { uint16_t samples[SAMPLE_NUM]; uint32_t sum = 0; for (int i = 0; i < SAMPLE_NUM; i++) { samples[i] = adc_read(channel); } // 冒泡排序,数据量小够用了 for (int i = 0; i < SAMPLE_NUM - 1; i++) { for (int j = 0; j < SAMPLE_NUM - 1 - i; j++) { if (samples[j] > samples[j+1]) { uint16_t tmp = samples[j]; samples[j] = samples[j+1]; samples[j+1] = tmp; } } } for (int i = DISCARD_NUM; i < SAMPLE_NUM - DISCARD_NUM; i++) { sum += samples[i]; } return sum / (SAMPLE_NUM - 2 * DISCARD_NUM); }这段代码里有个细节:排序用冒泡是因为数据量只有15个,冒泡的实际执行时间比快排的函数调用开销还短。别小看这种微优化,在中断里跑的时候能省一点是一点。
3.2 均衡开启与关闭的判据设计
均衡判据不能只看电压差,还要看电池状态。我见过有人设了个固定阈值50mV,结果电池在充电末期电压快速上升时频繁开关均衡,MOSFET被反复冲击,半年就坏了。
我的判据分三层:
第一层,电压差阈值。两节电池电压差超过30mV才考虑开启均衡。这个值不能太小,否则ADC噪声就能触发;也不能太大,否则均衡效果不明显。30mV是实测下来比较平衡的值。
第二层,持续时间。电压差超过阈值后,连续10秒都满足条件才真正开启均衡。这10秒是防抖窗口,滤掉负载突变导致的瞬时压差。
第三层,电池状态。充电时如果某节电池电压超过4.15V(三元锂),即使压差没到阈值也开启均衡,防止过充。放电时如果某节低于3.0V,关闭均衡,优先保放电。
关闭判据相对简单:电压差降到10mV以下,或者均衡时间超过预设上限(比如2小时),或者温度超限,任一条件满足就关闭。
这里有个经验值:均衡电流100mA时,两节200Ah的电池电压差从50mV拉到10mV,理论上需要的时间是:
t = (ΔV × C) / I_balance
其中ΔV是电压差,C是电池容量,I_balance是均衡电流。代入数值:t = (0.05V × 200Ah) / 0.1A = 100小时。这个时间太长了,实际中不可能等它完全拉平。所以均衡策略的目标不是把电压差拉到零,而是控制在合理范围内(比如20mV以内),剩下的靠电池自身的自放电和下次充放电循环自然收敛。
3.3 均衡控制的代码实现
均衡控制的代码不复杂,但状态机要写清楚,避免状态混乱导致MOSFET直通或者频繁开关。
typedef enum { BAL_IDLE, // 空闲,不均衡 BAL_PRECHECK, // 预检,确认压差持续存在 BAL_ACTIVE, // 均衡中 BAL_COOLDOWN, // 冷却,防止频繁开关 BAL_FAULT // 故障,锁定 } bal_state_t; typedef struct { bal_state_t state; uint32_t precheck_timer; uint32_t active_timer; uint32_t cooldown_timer; uint8_t target_cell; // 0=均衡第一节,1=均衡第二节 } bal_ctrl_t; void balance_task(bal_ctrl_t *bal, float v1, float v2, float temp) { float v_diff = v1 - v2; float v_abs = fabsf(v_diff); switch (bal->state) { case BAL_IDLE: if (v_abs > 0.030f && temp < 45.0f) { bal->state = BAL_PRECHECK; bal->precheck_timer = 0; } break; case BAL_PRECHECK: if (v_abs < 0.025f) { bal->state = BAL_IDLE; } else if (++bal->precheck_timer >= 10000) { // 10秒 bal->target_cell = (v_diff > 0) ? 0 : 1; bal->state = BAL_ACTIVE; bal->active_timer = 0; bal_enable(bal->target_cell); } break; case BAL_ACTIVE: bal->active_timer++; if (v_abs < 0.010f || temp > 55.0f || bal->active_timer > 7200000) { // 2小时上限 bal_disable(); bal->state = BAL_COOLDOWN; bal->cooldown_timer = 0; } break; case BAL_COOLDOWN: if (++bal->cooldown_timer >= 5000) { // 5秒冷却 bal->state = BAL_IDLE; } break; case BAL_FAULT: bal_disable(); break; } }这段代码里,bal_enable和bal_disable是操作GPIO控制MP2642GR-Z的使能引脚。注意MP2642GR-Z的使能是高电平有效,但芯片内部有上拉,所以STM32的GPIO要配置成推挽输出,初始状态输出低电平,避免上电瞬间误开启均衡。
冷却时间5秒是防止电压差在阈值附近抖动导致频繁开关。我实测过,没有冷却时间的话,MOSFET可能在1分钟内开关几十次,结温迅速上升。
4. 系统集成与实测问题排查
4.1 与上层系统的通信协议设计
STM32F205RB通过CAN总线跟储能系统的主控通信,上报的数据包括:两节电池电压、温度、均衡状态、均衡累计时间、告警标志。CAN波特率设500kbps,报文周期1秒。
协议格式我用的自定义帧,8字节数据段分配如下:
| 字节 | 内容 | 说明 |
|---|---|---|
| 0-1 | 电池1电压 | 单位mV,大端 |
| 2-3 | 电池2电压 | 单位mV,大端 |
| 4 | 温度 | 单位℃,偏移40℃ |
| 5 | 均衡状态 | bit0-1状态,bit2-3目标 |
| 6-7 | 告警标志 | 各bit独立含义 |
这个协议的好处是紧凑,8字节刚好塞满一帧CAN,不浪费带宽。缺点是电压用mV表示,最大65535mV,够用但没法表示更高精度。如果需要0.1mV精度,得用4字节,那就得拆成两帧。储能系统对电压精度要求没到0.1mV,mV级足够了。
4.2 实测中遇到的典型问题与排查
问题一:均衡电流比设计值小一半
现象:设定100mA,实测只有50mA左右。
排查过程:先量R_sense的阻值,标称0.5Ω实测0.51Ω,没问题。再量芯片VCC电压,发现只有7.8V,而电池端是8.2V,中间那个10Ω限流电阻上压降0.4V。0.4V/10Ω=40mA,说明芯片自身耗电40mA,这不对,数据手册标称静态电流才几毫安。
继续查,发现芯片的使能引脚电压只有1.8V,而数据手册要求高电平至少2.0V。原因是STM32的GPIO配置成了开漏输出,外部上拉电阻10kΩ,芯片内部下拉等效电阻约5kΩ,分压后只剩1.8V。改成推挽输出后,使能电压3.3V,均衡电流恢复到98mA。
这个坑的教训:MP2642GR-Z的使能引脚内部有下拉,必须用推挽驱动,开漏加上拉会被内部分压拉低。
问题二:ADC采样值跳动超过50mV
现象:电池电压稳定在7.5V,ADC读到的值在7.45V到7.55V之间跳。
排查:先用示波器看电池端电压,纹波只有5mV,排除电源问题。再看ADC参考电压,发现VDDA上有30mV的纹波,频率跟均衡MOSFET的开关频率一致。原因是均衡电流在PCB走线上产生的压降耦合到了VDDA。
解决:在VDDA和VSSA之间加一个10μF的钽电容并联0.1μF陶瓷电容,位置尽量靠近芯片引脚。同时把均衡电流的走线和ADC的模拟走线分开,不要平行走线。改板后跳动降到5mV以内。
问题三:均衡开启后温度飙升
现象:均衡开启10分钟后,MP2642GR-Z表面温度到85℃。
计算:均衡电流100mA,芯片内部MOSFET的导通电阻约0.5Ω,功耗P = I² × R = 0.1² × 0.5 = 5mW。这点功耗不可能让芯片到85℃。
实测芯片电流,发现总电流150mA,其中100mA是均衡电流,50mA是芯片自身耗电。50mA × 8V = 400mW,这个功耗在SOT23-6封装上,热阻约200℃/W,温升80℃,确实能到85℃。
查数据手册,静态电流标称3mA,为什么实际50mA?最后发现是R_sense的走线太长,引入了寄生电感,芯片内部比较器振荡,导致内部电路频繁开关,耗电大增。把R_sense的走线缩短到5mm以内,并用地线包围,静态电流降到4mA,温度降到45℃。
这个问题的教训:R_sense的布局极其关键,必须开尔文连接,走线短而粗,远离干扰源。
4.3 常见问题速查表
| 现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| 均衡电流偏小 | 使能电压不足 | 量使能引脚电压 | 改推挽输出 |
| 均衡电流偏小 | R_sense阻值偏大 | 量R_sense实际阻值 | 换1%精度电阻 |
| ADC跳动大 | 参考电压纹波 | 示波器看VDDA | 加去耦电容 |
| ADC跳动大 | 模拟走线受干扰 | 检查PCB布局 | 分离模拟数字走线 |
| 芯片发热严重 | 内部振荡 | 量芯片总电流 | 缩短R_sense走线 |
| 均衡不开启 | 电压差未达阈值 | 看ADC读数 | 检查分压电阻 |
| 均衡频繁开关 | 冷却时间太短 | 看状态机日志 | 加长冷却时间 |
| 通信丢帧 | CAN终端电阻缺失 | 量CANH-CANL电阻 | 加120Ω终端电阻 |
5. 被动均衡方案的边界与扩展思路
5.1 什么场景下这个方案不够用
被动均衡的硬伤是均衡电流小。两节200Ah的电池,100mA均衡电流,要把50mV压差拉到10mV需要100小时,实际中根本等不了。所以这个方案适合的是:电池容量不大(比如50Ah以内)、压差累积缓慢、对均衡速度要求不高的场景。
如果电池容量超过100Ah,或者系统要求快速均衡(比如电动汽车快充后要求半小时内拉平压差),被动均衡就不够了。这时候要么加大均衡电流(但受限于芯片和散热),要么换主动均衡方案。
还有一个边界:电池节数。MP2642GR-Z单芯片管两节,如果电池组是4节、8节、16节,就需要多颗芯片级联。级联时要注意芯片之间的地电位不同,通信接口需要隔离。STM32F205RB的GPIO不够用的话,可以用I2C扩展IO或者用移位寄存器。
5.2 从两节扩展到多节的思路
两节扩展到多节,硬件上就是复制MP2642GR-Z的电路,每两节一组。但软件上要改均衡策略:不能只比较相邻两节的压差,要比较整组电池的最高电压和最低电压。
策略改成:找出电压最高的电池和电压最低的电池,如果压差超过阈值,开启最高电压那节对应的均衡通道。这样每次只均衡一节,但均衡的是最需要均衡的那节,效率比逐对均衡高。
STM32F205RB的ADC通道有限,16节电池需要16个电压采样通道加16个温度通道,总共32个。F205RB有16个外部ADC通道,不够用。解决方案是用外部模拟多路复用器,比如74HC4051,8选1,用4个GPIO控制通道选择,ADC只用一个通道分时采集。这样32个采样点用4个GPIO加1个ADC通道就能搞定。
5.3 均衡策略的进阶优化
基础版的均衡策略是阈值触发,简单但不够聪明。进阶优化可以考虑:
自适应阈值:根据电池老化程度动态调整阈值。新电池一致性好,阈值可以设小一点(20mV);老电池一致性差,阈值设大一点(50mV),避免均衡系统一直在工作。
预测性均衡:根据历史数据预测哪节电池会先到截止电压,提前开启均衡。这需要记录每次充放电循环的电压曲线,用简单的线性回归就能做。STM32F205RB的128KB Flash存几百次循环的数据没问题。
温度补偿:电池电压随温度变化,-10℃和25℃下同一节电池的电压可能差30mV。如果均衡判据不补偿温度,冬天可能误触发均衡。补偿方法是在软件里加一个温度-电压修正表,根据NTC读到的温度修正电压值。
这些优化不需要改硬件,纯软件升级就能做。我在一个备用电源项目里加了自适应阈值,均衡系统的日均工作时间从4小时降到1.5小时,MOSFET的寿命预期从3年延长到8年。
6. 写在最后的实操心得
这个方案我前后在三个项目里用过,踩过的坑基本都写在上面了。最后再分享几个数据手册上不会写、但实际调试中很关键的点。
第一,MP2642GR-Z的使能引脚不要直接接STM32的GPIO,中间串一个100Ω电阻。我遇到过GPIO在上电初始化时输出高电平脉冲,导致均衡瞬间开启,虽然时间很短,但电池电压被拉了一下,ADC记录到了异常值。串电阻后,即使有脉冲,电流也被限制在33mA以内,不会对电池造成实质影响。
第二,R_sense的封装不要选0402。0402的电阻功率只有62mW,虽然理论上5mW够用,但焊接时的热应力可能导致阻值漂移。我用0603封装,功率100mW,余量足,焊接也容易。
第三,STM32F205RB的ADC在采样时,如果同时有CAN通信,采样值会有几个LSB的跳动。原因是CAN收发器工作时在电源上产生噪声。解决方法是在ADC采样前先关闭CAN中断,采样完成后再打开。这个操作在1ms的定时器中断里做,对CAN通信的影响可以忽略。
第四,均衡状态最好用LED指示。调试阶段不用接示波器,看一眼LED就知道均衡有没有在工作。LED接在STM32的另一个GPIO上,跟均衡使能同步。注意LED的限流电阻要选对,我用的是1kΩ,电流3mA左右,亮度够用又不刺眼。
第五,如果系统长期浮充,建议每周做一次完整的充放电循环。浮充状态下电池电压长期不变,均衡系统没有触发条件,压差会慢慢累积。定期循环能让均衡系统有机会工作,也能激活电池活性物质,延长寿命。这个策略在备用电源系统里特别重要,我见过浮充两年的电池组,拆下来一测,压差到了200mV,均衡系统从来没工作过。