前阵子在整理一套小型储能备电单元的电池管理时,要处理两节串联电芯的均衡问题,方案里用到了 MP2642GR-Z 均衡器和 dsPIC30F3014 数字信号控制器。一开始我也觉得,两节电池串联而已,电压差小的时候不管它也出不了大事。但真正跑了一段浮充和充放电循环之后才发现,失衡对可用容量和电芯寿命的影响比想象中大得多。这篇记录就是把这套 2S 均衡方案的硬件分工、均衡策略、固件实现和实测数据完整梳理一遍,给正在做储能或备电系统电池管理的朋友做个参考。
1. 两节串联电池为何也要专门的均衡方案:备电系统长期浮充的失衡代价
1.1 什么场景下失衡会真正伤害系统
先说清楚一个问题:均衡不是"电芯之间电压不一致了"才需要做的事,而是从系统上电第一天起就该默认开启的维护性工作。储能和备用电源系统和消费电子不一样,电池大部分时间是挂在固定电压上待命的,尤其是备电场景,电池长期处于满电保持或浮充状态。
这里有个容易被忽略的机制:同一批出厂的电芯,容量、内阻、自放电率不可能完全一致。自放电率差异在长期浮充里会被放大——自放电大的电芯每次补电都要多充一点,自放电小的电芯则一直处于偏高电压。一年下来,两节电芯的荷电状态可能已经差了百分之十几。平时看不出来,一旦真正停电切换到电池供电,容量低的电芯最先触底,系统为了保护电池被迫提前切断,整包可用容量直接塌掉。
另外,串联电芯还面临一个"木桶效应"的硬约束。充电时,电压高的电芯先到上限,充电电流必须停,否则过压;放电时,电压低的电芯先到下限,放电电流必须停,否则过放。两头都受限制,中段容量再大也用不出来。对一套设计寿命五到十年的储能备电单元来说,这种慢性损耗完全不能接受。
1.2 被动均衡与主动均衡的取舍
均衡方案大致分两类。被动均衡是给每节电芯并一个泄放电阻,电压高的电芯多余的能量以热量形式放掉,电路很简单,但缺点也很明显:能量浪费、发热集中在小电阻上、均衡电流做不大、而且只在充电阶段有效。主动均衡则是把高电压电芯的能量搬到低电压电芯去,属于能量复用,效率高得多。
MP2642GR-Z 在项目里承担的就是主动均衡的功率通路。按这类电荷转移式均衡器的常见用法,它内部是一个以电感为储能元件的双向变换电路,在控制信号作用下把电荷从上侧电芯搬到下侧电芯,或者反向搬运。相比被动均衡,它的优势在于均衡电流可以做得更大、不依赖充电状态、发热低,非常适合备电系统这种需要长期维护性均衡的场景。
| 对比项 | 被动均衡 | 主动均衡(本项目所用类型) |
|---|---|---|
| 能量去向 | 以热量形式消耗 | 转移到低电压电芯,循环复用 |
| 发热情况 | 均衡电流越大发热越明显 | 主要损耗在电感和开关管,温升低很多 |
| 均衡电流 | 受泄放电阻功率限制,一般较小 | 可以做到几百毫安甚至更高 |
| 控制复杂度 | 只需要开关泄放回路 | 需要控制方向,由 MCU 统一接管 |
| 适用场景 | 小容量、成本敏感 | 长期维护、频繁充放电的储能与备电 |
1.3 均衡目标:顶均衡还是底均衡
均衡不是无脑把两节电压拉到完全一致就行。我在这套系统里把均衡目标拆成了两部分:
充电末端做顶均衡。备电系统绝大多数时间处于满电保持,均衡的重点是防止高电压电芯提前到达上限,给它留出空间。这个阶段必须让均衡电流和充电电流配合好,否则一边充一边搬,永远追不上。
放电末端做底均衡。真正停电转电池供电时,目标是让两节电芯尽可能同时到达放电下限,最大化可利用容量。底均衡的问题在于放电时电芯端电压受内阻压降影响严重,很难准确判断荷电状态,所以我的做法是负载断开后的静置窗口做短时均衡,放电过程中只监控不动作。
还有一个锂电池特有的坑:磷酸铁锂的放电平台非常平,电压差个二三十毫伏,荷电状态可能差出不少;但到了曲线两端,电压对荷电状态又极其敏感。这意味着单纯靠电压判据做均衡,在平台区容易误判,在端点区又容易过激。后面第三部分讲算法的时候会专门说怎么处理。
2. 硬件分工:MP2642GR-Z 搬运电荷,dsPIC30F3014 负责采样与决策
2.1 MP2642GR-Z 在这个项目里的职责边界
把系统拆开看,MP2642GR-Z 和 dsPIC30F3014 的分工非常清楚:前者是执行机构,负责物理上的电荷搬运;后者是决策机构,负责测量、判断、保护和对外通信。
MP2642GR-Z 在模块里被配置成一个双向的电荷转移通路。它需要的外围元件不多,核心就是一个合适规格的电感,以及输入输出侧的滤波电容。真正需要注意的是它的工作状态必须由外部控制信号来约束——想让电荷从电芯 1 流向电芯 2,或者反向流动,需要按固定时序给出控制电平。也就是说,它本身不是一个"自己会思考"的均衡器,而是一个"听话的功率级"。
这意味着整个系统的均衡质量,很大程度上取决于上面那颗 dsPIC30F3014 的采样和决策逻辑。硬件再强,策略错了也白搭。
2.2 dsPIC30F3014 在系统里的采样与监控角色
选 dsPIC30F3014 而不是普通单片机,主要看中它作为 16 位数字信号控制器的几个特性:内置多通道 10 位 ADC,采样速度足够;自带定时器和 PWM,方便产生均衡控制时序;有 UART 和 I2C 可以做上位机通信;程序 Flash 和 EEPROM 足够放下均衡状态机和标定数据。对一套两节串联的均衡管理任务,这个资源量算是绰绰有余,成本也压得住。
它的核心任务有三件:周期采集两节电芯电压和模块温度;根据均衡策略决定启停和方向;监测异常并联动保护。这三件事都依赖 ADC 采样的准确性,所以硬件上最花心思的反而不是均衡功率部分,而是电压采集链路。
2.3 电压采样拓扑、供电与地线处理
两串电池的电压采集有个常见的坑。下侧电芯(电芯 1)的一端是系统地,它的电压可以直接测量;但上侧电芯(电芯 2)跨在中间节点和正极之间,没有一端接地,不能直接往 ADC 引脚上怼。
我的做法是分别测量正极对地电压和中间节点对地电压,然后做差。正极最高约 8.4V,需要先用电阻分压缩到 ADC 量程内,再由软件算出差值。这里要提醒一下:分压电阻的精度会直接折算进电芯 2 的测量误差,我用了 0.1% 精度的电阻,并且在校准流程里逐通道补偿增益和偏移,否则两节电芯的实际测量精度会差很多。
ADC 输入端还加了一级 RC 滤波,典型参数是几百欧姆串联电阻加 100nF 电容,兼顾高频噪声抑制和采样电容的充电时间。这个时间常数不能取得太大,不然 ADC 采样时电荷还没充完,读数会偏低。更重要的是,均衡器的开关节点、电感和采样线必须拉开距离,采样线要在电芯端子处做真正的开尔文连接,不能从 PCB 走线上随便拉一根。
供电方面,dsPIC30F3014 的电源直接由电池组通过线性稳压器得到,输入范围要覆盖到最高 8.4V,输出 3.3V,输入输出侧都加了足够的去耦电容。地线处理上,功率地和模拟地做了单点连接,避免均衡电流在地线上产生压降干扰参考地。最开始我没注意这一点,后面导致了不少诡异的采样跳动,这个在第五部分会详细说。
3. 均衡算法与状态机设计:迟滞阈值、测量窗口和场景解耦
3.1 先测量再动作:采样窗口与控制时序
均衡算法最核心的原则就一条:不要在均衡器工作的时候测量电芯电压。原因很简单,均衡电流会在电芯内阻和连接阻抗上产生压降,实测端电压不代表真实电动势,这时候算出来的电压差是"带扰动的数据",拿它做反馈很容易把方向搞错。
所以我把整个控制过程设计成"测量窗口—动作窗口"交替进行。先关闭均衡器,等待几十毫秒让 RC 滤波器和采样链路稳定下来,然后连续采样取平均,得到两节电芯的静置电压;再根据电压差决定接下来一个动作窗口内均衡器该不该开、该朝哪个方向开;动作窗口结束时,回到测量窗口重新判断。
这样做的代价是均衡不是连续的,而是间歇式小步前进。但收益非常大:每一次动作都基于干净的静置电压,不会因为反馈数据污染而出现方向反复横跳。实际跑下来,收敛速度和连续均衡相比慢不了多少。
3.2 迟滞阈值与方向判定
电压判据用了迟滞设计。启动阈值设在 30mV,停止阈值设在 10mV,方向按电压差的正负决定。这个区间差保证了系统不会在阈值附近反复启停,同时也留出了测量噪声的容错空间。
伪代码可以写成这样:
#define BAL_START_MV 30 #define BAL_STOP_MV 10 #define BAL_WINDOW_MS 5000 #define SENSE_SETTLE_MS 80 static int8_t bal_dir = 0; // 0: off, 1: C1->C2, -1: C2->C1 void balancer_periodic(void) { int16_t v1, v2, delta; disable_balancer(); delay_ms(SENSE_SETTLE_MS); v1 = get_cell1_mv(); v2 = get_cell2_mv(); delta = v1 - v2; if (bal_dir != 0) { // 已经在均衡:只有压差收敛到停止阈值才停 if ((int32_t)abs(delta) < BAL_STOP_MV) { disable_balancer(); bal_dir = 0; } else { enable_balancer(bal_dir); } } else { // 空闲状态:压差超过启动阈值才开启 if (delta > BAL_START_MV) { bal_dir = 1; // 电芯1偏高,向电芯2搬 enable_balancer(bal_dir); } else if (delta < -BAL_START_MV) { bal_dir = -1; // 电芯2偏高,向电芯1搬 enable_balancer(bal_dir); } } delay_ms(BAL_WINDOW_MS); }注意一个细节:已经在均衡的时候,只要压差还没回到停止阈值,就保持原方向继续搬,不要因为一次测量毛刺就换方向。这个"保持方向优先"的逻辑看着简单,实际上把很多控制振荡问题消弭于无形。
3.3 充电、放电、待机三种场景下的差异化策略
同一个均衡器,在不同系统状态下应该有不同的行为。我把它做成了状态机,而不是一个无脑周期任务。
| 系统状态 | 触发条件 | 均衡动作 |
|---|---|---|
| 待机(STANDBY) | 系统空闲,压差小于 30mV | 均衡关闭,周期采样监控 |
| 满电维护(TOPOFF) | 充电进入恒压段,任一电芯接近上限 | 开启均衡,配合充电电流防止过压 |
| 静置刷新(REFRESH) | 待机超过 4 小时且压差大于 15mV | 短时动作窗口均衡,完成后回待机 |
| 放电监控(DISCHARGE) | 负载接通或系统处于放电状态 | 关闭均衡,仅监控低电芯 |
| 故障(FAULT) | 过压、欠压、过温、采样异常 | 关闭均衡,置位故障标志并上报 |
这里的关键是充放电解耦。充电阶段做均衡,目标是给高电压电芯"减负",因为充电电流本身在给所有电芯加压,均衡电流是逆着充的,效率不高但能防止过充电;待机阶段做均衡,才是真正把高电芯的能量搬到低电芯,属于净转移。放电阶段我干脆禁止均衡,原因是负载电流叠加均衡电流会让单体电压测量完全失真,强行动作反而可能把低电芯进一步压低。
还有一个被很多人忽略的点:均衡电流相对于电芯容量其实很小。对 20Ah 的电芯,即使 500mA 均衡电流,搬运 1% 电量也要二十多分钟。所以均衡是"慢功夫",不要期望短时间内把一百多毫伏压差拉平。设置静置刷新周期时,要按能量转移速率来估算维持时间,而不是拍脑袋定个时间。
4. 固件实现笔记:ADC 采样滤波、通道标定与故障保护
4.1 ADC 采样滤波:10 位分辨率如何跑出稳定读数
dsPIC30F3014 的 ADC 是 10 位的,参考电压 3.3V 时每个 LSB 大约 3.2mV。这点分辨率直接拿去判断 30mV 的均衡阈值有点勉强,但通过软件手段完全可以把它用到位。
我在固件里做了两层滤波。第一层是过采样:每个电压通道连续采样 16 次后做平均,等效把随机噪声压低,让均值分辨率好于单个 LSB。第二层是中值滤波:取最近 5 个均值结果,丢掉最大和最小,剩下求平均。中值滤波对偶发的尖峰毛刺特别有效,那些来自继电器动作或均衡开关串扰的瞬时跳变,会被直接剔除掉。
uint16_t read_cell_voltage_mv(uint8_t ch) { uint32_t sum = 0; uint16_t i; for (i = 0; i < 16; i++) { adc_start_conversion(ch); while (!adc_conversion_done()); sum += adc_read_mv(ch); } return (uint16_t)(sum / 16); }实测下来,单次读数的峰峰值跳动能从 15mV 压到 3mV 以内,已经远小于均衡启动阈值 30mV。注意过采样并不能真正提高 ADC 自身的积分非线性,所以后面还必须做逐通道标定。
4.2 每路电压通道的标定与补偿
10 位 ADC 加上外部电阻分压,如果不标定,两节电芯的测量误差很容易超过 20mV——这个误差本身就比均衡启动阈值小不了多少,会导致系统在错误的时机启动或停止。
我的标定流程是两点标定。用精密电压源分别给每个采样通道加两个已知电压,比如 2.5V 和 4.0V,记录 ADC 原始读数,算出该通道的增益和偏移,写入非易失存储。运行时所有软件阈值全部基于标定后的电压值判断。这样还有一个附带好处:即使换一批电芯,不同模块之间的均衡行为也基本一致,量产时不用逐台调参。
还有一点容易漏:电芯 2 的测量是由两个通道做差得来的,分压电阻比例的误差会被放大。标定时要特别注意正极通道和中间节点通道在同一个温度环境下标定,并且程序里用同一个 ADC 转换序列顺序采样,减小温漂和时序带来的额外误差。
4.3 异常检测与联动保护
均衡功能再重要,也不能凌驾于安全保护之上。固件里有一组独立的硬保护逻辑,和均衡状态机并行运行。每节电芯设置过压和欠压阈值,超过立即报警并切断负载或充电通路;模块温度由 NTC 采样,超过阈值停止均衡,防止电感或开关器件过热。
针对两串架构还有两个专门的检测:压差异常和断线检测。如果在静置状态下压差超过 400mV,大概率不是正常的电池失衡,而是采样线接触不良或者电芯已经严重劣化,这时候绝不能启动均衡,应该上报异常。断线检测则靠周期性读取采样通道的绝对值,如果读到接近 0V 或满量程的异常值,说明采样链路可能有开路或短路,需要进入故障状态。
均衡器本身也会上报故障状态,比如过流或内部保护触发。固件一旦收到,立即关闭并使能信号,等待一段时间后尝试恢复,连续失败三次就锁定故障,必须人工介入。这套"快速断开、慢速重试"的策略,是我在各种电源管理项目里验证过比较稳的做法。
5. 实测收敛数据与三个隐蔽的坑:地弹、采样毛刺和接触电阻
5.1 收敛曲线:从 128mV 到 8mV
样机用两节磷酸铁锂电芯串联,其中一节是做过循环老化的旧电芯,初始静置压差 128mV,标称容量 20Ah。均衡电流设定在 400mA 左右,按第三节的状态机运行。实测数据如下:
| 时间点 | 电芯1电压 (mV) | 电芯2电压 (mV) | 压差 (mV) |
|---|---|---|---|
| 0 min | 3612 | 3484 | 128 |
| 10 min | 3595 | 3501 | 94 |
| 20 min | 3579 | 3518 | 61 |
| 30 min | 3566 | 3533 | 33 |
| 40 min | 3554 | 3539 | 15 |
| 50 min | 3548 | 3540 | 8 |
整个收敛过程大约 50 分钟,最终停在 8mV,进入了迟滞停止区间。注意表里的电压都是在均衡器关闭并稳定后测的,不是动作过程中的瞬时值。我也专门对比了均衡前后的可用容量,同样条件下放完电的容量比均衡前多了约 6%,对两串小系统来说这个收益相当可观。
5.2 坑一:均衡器开关噪声污染 ADC 采样
第一次联调时发现一个怪现象:均衡器一开,ADC 读数就跳,跳幅最大能到 20mV 以上,而且看起来毫无规律。排查到最后确认是均衡器开关节点的高频分量通过地平面和采样线串进了 ADC 输入端。
解决办法是三管齐下:采样严格放在均衡器关闭的窗口内;ADC 前端 RC 滤波参数调大了一点;PCB 上把采样走线从功率回路旁边挪走,并且采样点直接引到电芯端子,避免采集到功率电流在铜箔上的压降。这个坑说明,采样链路的抗干扰设计不是靠软件滤波单方面解决的,硬件布局和软件时序必须一起考虑。
5.3 坑二:接触电阻让均衡方向反复横跳
另一个让我折腾了两天的问题是均衡方向"一会儿向左一会儿向右"。每个测量窗口算出的压差正负不断变化,均衡器在两种方向之间来回切换,电压却一点都没收敛。
后来用万用表直接量电芯端子才找到根子:均衡器电流路径上的连接器接触电阻偏大,加上采样点接在了接触电阻内侧,均衡电流流经接触电阻时产生了压降,这个压降直接叠加进了采样值。均衡器开启时,系统以为电芯 1 电压高,启动向电芯 2 搬移,结果搬移电流在连接器上产生的压降又把测量结果翻转,系统又以为电芯 2 电压高,马上切换方向。
修这个问题的关键动作是:采样必须用独立的开尔文线从电芯端子引出,不经过功率连接器;同时严格控制均衡动作窗口内的方向切换逻辑,已经启动的方向不允许因为单次测量结果而反向,只有停下来重新测量后才能换方向。接触电阻本身也需要在装配工艺上控制,连接器压接质量差的模块,均衡效果完全不可预期。
5.4 坑三:地弹带来的单片机复位
还有一个隐蔽问题出现在大电流均衡启动瞬间。均衡器启动时电流突变,电池组内阻和线路电感上会产生一个反向压降,导致 MCU 电源轨瞬间跌落,触发了欠压复位。现象是均衡刚开始几秒钟,系统就重启,数据清零,然后又重启,反复循环。
解决思路分两步:硬件上加大 MCU 供电的 bulk 电容,并且在 LDO 输出侧增加合适的退耦电容,让电源轨扛过瞬态跌落;软件上使能欠压复位检测,同时在均衡启动时使用"软启动"时序——先以短脉冲方式预热,再进完整动作窗口,避免电流突变。经过这样处理,即使电池接近低压状态也不会再复位。
最后分享一下我的个人习惯:量产和调试时,我会把每块板的累计均衡时间记录到非易失存储里。这个数据平时没人看,但非常有价值——同一批电芯、同样的使用环境,某块板的均衡时间突然变长,通常意味着某节电芯的自放电在加速。从运维角度看,这比等电压差报警更早发现问题。做储能备电这类长期运行的产品,细节上的提前量,往往就是寿命和可靠性上的差距。