ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于MP2642GR-Z与PIC18F85J10的两串电芯被动均衡BMS设计实战

基于MP2642GR-Z与PIC18F85J10的两串电芯被动均衡BMS设计实战

1. 从两个串联电芯的电压差说起:为什么被动均衡在储能场景里依然是主流选择

储能系统和备用电源系统里,两串电芯的架构非常常见——小到便携式储能电源,大到通信基站的后备电池组,很多设计都会采用两节锂离子或磷酸铁锂电芯串联来获得更高的母线电压。但只要是串联,就一定会遇到一个绕不开的问题:两颗电芯的荷电状态会随着循环逐渐拉开差距。

这个差距的来源很多。制造工艺上,两颗电芯的容量、内阻、自放电率不可能完全一致;使用过程中,温度分布不均匀会让靠近发热源的那颗电芯老化更快;甚至同一批次电芯在配组时如果分容不够精细,出厂时就埋下了不一致的种子。结果就是,充电时容量小的那颗先到截止电压,放电时它又先到欠压保护点。BMS如果只盯着整串电压做保护,容量大的那颗永远吃不饱,容量小的那颗永远被过度使用,整组可用容量会以肉眼可见的速度衰减。

解决这个问题的思路分两大流派:被动均衡和主动均衡。主动均衡用变压器、电感或者电容做能量搬运,效率高、发热小,但电路复杂、成本高、EMI难搞。被动均衡说白了就是给电压高的那颗电芯并联一个电阻放电,把多出来的能量以热的形式消耗掉。听起来很"笨",但在两串电芯的小型储能和备用电源场景里,被动均衡的性价比几乎是无敌的——元件少、控制简单、可靠性高,而且两串架构下能量浪费本来就有限。

我这次做的方案,就是用MP2642GR-Z这颗模拟前端芯片配合PIC18F85J10单片机,搭一套两串电芯的被动均衡系统。MP2642GR-Z负责高精度的电压采集和均衡开关驱动,PIC18F85J10负责逻辑判断、均衡策略执行和对外通信。整套方案的成本控制得很好,精度和安全性也完全能满足中小型储能系统的要求。下面我把整个设计过程拆开来讲,包括芯片选型的理由、硬件连接的细节、均衡算法的实现,以及调试过程中踩过的那些坑。

2. MP2642GR-Z 与 PIC18F85J10 的分工逻辑:为什么不是一颗芯片全包

2.1 MP2642GR-Z 在均衡回路里到底管什么

MP2642GR-Z是一颗专为多串电池管理设计的模拟前端,支持2到4串电芯的电压采集。它的核心价值在于高精度的电芯电压测量和内置的均衡MOSFET驱动能力。对于两串应用来说,它刚好覆盖需求,不会浪费通道。

这颗芯片的电压采集精度在同类产品里属于中上水平,典型条件下每节电芯的测量误差可以控制在毫伏级别。这个精度对被动均衡来说至关重要——如果电压采集本身就有几十毫伏的误差,那均衡开启和关闭的阈值判断就完全失去了意义,可能出现"该均衡的没均衡,不该均衡的乱放电"的情况。

MP2642GR-Z内部集成了均衡开关管,外部只需要接均衡电阻就能构成完整的放电回路。均衡电阻的选型直接决定了均衡电流的大小,而均衡电流又直接影响均衡速度和发热量。这个后面会详细算。

另外,这颗芯片通过I2C接口与主控通信,寄存器里包含了每节电芯的电压值、均衡状态、故障标志等信息。主控只需要周期性读取这些寄存器,就能掌握整组电池的状态。

2.2 PIC18F85J10 为什么适合做这个主控

PIC18F85J10是Microchip旗下PIC18系列的一款8位单片机,资源对于两串BMS来说绰绰有余。它有几个特点特别适合这个场景:

  • 宽工作电压范围:可以直接从电池组取电经过LDO降压后供电,不需要额外的复杂电源架构。
  • 丰富的GPIO和通信外设:I2C接口用来跟MP2642GR-Z通信,UART可以对外输出数据或者接显示屏,还有足够的IO做状态指示和按键输入。
  • 低功耗模式:备用电源系统很多时候处于待机状态,单片机需要能进入休眠,定期唤醒做一次电压采集和均衡判断,这对延长电池寿命很重要。
  • 开发工具成熟:MPLAB X IDE加上XC8编译器,开发效率很高,调试也方便。

有人可能会问,为什么不用一颗集成了MCU和AFE的SoC?原因很简单:灵活性和成本。SoC方案虽然集成度高,但一旦某个功能不满足需求,整个方案就要推倒重来。分离方案里,AFE和MCU各自可以独立选型替换,而且PIC18F85J10的供货一直比较稳定,不会因为某颗专用芯片缺货就卡住整条产品线。

2.3 两颗芯片之间的通信协议设计

MP2642GR-Z的I2C地址可以通过外部引脚配置,这样在同一块板子上挂多颗AFE时不会冲突。通信速率方面,标准模式100kHz就够用了,因为电压采集不需要很高的刷新率,每秒读几次完全能满足均衡判断的需求。

我在实际代码里把I2C读写封装成了两个底层函数,上层只关心"读第N节电芯电压"和"设置第N节电芯均衡开关"这两个操作。这样即使以后换用其他型号的AFE,只需要改底层驱动,均衡策略层不用动。

通信的可靠性需要特别注意。I2C总线在电池这种有较强电磁干扰的环境里,偶尔出现NACK或者数据错位是正常的。我的做法是每次读取都做两次校验:先读一次电压寄存器,延时几毫秒再读一次,两次结果如果差异超过预设阈值就判定为通信异常,放弃本次均衡判断,等下一个周期再试。这个简单的策略在实际运行中避免了很多误动作。

3. 硬件设计里那些容易翻车的细节:从均衡电阻选型到PCB布局

3.1 均衡电阻的功率计算与散热处理

均衡电阻的选型是整个被动均衡设计里最核心的计算。假设我们选定的均衡电流目标是100mA,电芯满电电压按4.2V算,那么均衡电阻的阻值就是:

R = V / I = 4.2V / 0.1A = 42Ω

实际选型时取标准值43Ω或者39Ω都可以。接下来算功率:

P = V² / R = 4.2² / 43 ≈ 0.41W

这个功率已经不小了,0603或者0805封装的电阻根本扛不住。我选的是2512封装的贴片电阻,额定功率1W,留了一倍以上的余量。即便如此,在持续均衡的时候电阻表面温度也能到七八十度,所以PCB布局时一定要把均衡电阻放在板子边缘或者通风好的位置,远离温度敏感元件。

注意:均衡电阻的功率计算要按电芯最高电压来算,不能按标称电压。磷酸铁锂满电3.65V,三元锂满电4.2V,算出来的功率差别很大。

如果空间允许,用两个电阻并联或者串联来分担功率也是好办法。比如用两个82Ω的2512电阻并联,等效阻值41Ω,每个电阻只承担一半的功率,温升会明显降低。

3.2 均衡开关的驱动与保护

MP2642GR-Z内部集成了均衡开关管,但外部电路还是需要一些保护措施。我在每个均衡回路上串了一个小阻值的限流电阻(10Ω左右),作用是限制开关瞬间的电流尖峰。虽然均衡电阻本身已经限制了稳态电流,但PCB走线电感和电阻的寄生电容在开关瞬间可能产生振铃,串一个小电阻能有效抑制。

另外,均衡开关的驱动电压来自芯片内部,不需要外部再加驱动电路。但要确保芯片的供电电压稳定,否则开关管的导通电阻会变大,实际均衡电流会偏离设计值。

3.3 电压采集走线的开尔文连接

电压采集精度直接决定均衡效果,而走线方式对精度的影响经常被忽视。MP2642GR-Z的电压采集引脚必须采用开尔文连接——也就是从电芯正负极的焊盘上单独引一对线到芯片的采集引脚,这对线不承载任何负载电流。

如果图省事直接从均衡电阻的焊盘上引线,那么均衡电流在走线电阻上产生的压降就会叠加到采集电压上,导致测量值偏低。100mA的均衡电流在10mΩ的走线电阻上就能产生1mV的误差,看起来不大,但均衡阈值往往只设几十毫伏,这个误差已经足够影响判断了。

PCB布局时,采集走线要尽量短、尽量粗,并且远离均衡电阻和功率走线。如果板子空间紧张,至少保证采集走线在均衡电阻的"上游",不要穿过均衡电流的路径。

3.4 电源架构与LDO选型

PIC18F85J10和MP2642GR-Z都需要稳定的供电。两串电池组的电压范围大概在6V到8.4V之间(三元锂)或者5V到7.3V之间(磷酸铁锂),所以需要一个LDO降到3.3V或者5V。

LDO的选型要注意两点:静态电流和压差。备用电源系统长期待机,LDO的静态电流直接决定了待机功耗。我选的是静态电流在微安级别的LDO,配合单片机的休眠模式,整机待机电流可以控制在几十微安。

压差方面,电池组最低电压可能到5V左右,如果LDO输出3.3V,压差有1.7V,完全够用。但如果输出5V,压差就只有0V了,LDO会失去调节能力。所以建议LDO输出3.3V,给单片机和外设供电,需要5V的外设再单独加升压或者直接用电池电压。

4. 均衡策略的代码实现:从电压读取到均衡开关的完整逻辑

4.1 电压采集的滤波与校准

MP2642GR-Z读回来的原始电压值会有噪声,直接用来判断均衡会频繁误触发。我在固件里做了滑动平均滤波:每节电芯维护一个长度为8的环形缓冲区,每次采集到新值就替换最旧的值,然后取平均值作为当前电压。

滤波之后还要做校准。每颗芯片的电压采集都有个体差异,批量生产时如果每块板子都单独校准成本太高。我的做法是在代码里留一个校准系数数组,出厂时用高精度万用表测一次实际电压,跟芯片读数对比,把比例系数写进EEPROM。这样即使芯片有±1%的初始误差,校准后也能压到±0.1%以内。

// 电压采集与滤波的简化逻辑 #define FILTER_SIZE 8 typedef struct { uint16_t buffer[FILTER_SIZE]; uint8_t index; uint32_t sum; } VoltageFilter; uint16_t getFilteredVoltage(VoltageFilter *f, uint16_t newSample) { f->sum -= f->buffer[f->index]; f->buffer[f->index] = newSample; f->sum += newSample; f->index = (f->index + 1) % FILTER_SIZE; return (uint16_t)(f->sum / FILTER_SIZE); }

4.2 均衡开启与关闭的阈值设计

均衡阈值的设定需要一点"迟滞"思维。如果只设一个阈值,比如电压差超过30mV就开启均衡,低于30mV就关闭,那么当电压差在30mV附近波动时,均衡开关会频繁切换,既影响寿命又产生噪声。

我的做法是设双阈值:电压差超过50mV时开启均衡,低于20mV时关闭均衡。中间这30mV的区间是"死区",电压差落在这个区间时保持当前状态不变。这样均衡动作会变得很"沉稳",不会来回抖动。

另外,均衡只在充电后期或者静置状态进行。充电时电芯电压在上升,这时候均衡判断容易受充电电流影响;放电时电压在下降,均衡放电会加速容量小的那颗电芯的衰减。所以我的策略是:检测到充电电流小于某个阈值(比如50mA)且持续一段时间后,才允许开启均衡。

4.3 均衡超时保护与温度监控

被动均衡的本质是放电,如果因为某种原因均衡开关一直开着,电芯会被过度放电。所以必须加超时保护:单次均衡连续开启时间超过预设值(比如30分钟),强制关闭均衡,等待下一个周期再判断。

温度监控也很重要。均衡电阻发热会拉高局部温度,如果板子上有NTC测温电阻,可以在温度超过60度时降低均衡占空比或者暂停均衡。没有NTC的话,至少要在软件里限制均衡的最大持续时间,避免热量累积。

// 均衡控制状态机的简化逻辑 typedef enum { BAL_IDLE, BAL_ACTIVE, BAL_COOLDOWN } BalState; void balanceTask(void) { static BalState state = BAL_IDLE; static uint32_t balanceStartTime = 0; uint16_t v1 = getCellVoltage(1); uint16_t v2 = getCellVoltage(2); uint16_t diff = (v1 > v2) ? (v1 - v2) : (v2 - v1); switch(state) { case BAL_IDLE: if (diff > 50 && isChargingDone()) { enableBalance(v1 > v2 ? 1 : 2); balanceStartTime = getTick(); state = BAL_ACTIVE; } break; case BAL_ACTIVE: if (diff < 20 || (getTick() - balanceStartTime > 1800000)) { disableAllBalance(); state = BAL_COOLDOWN; } break; case BAL_COOLDOWN: if (getTick() - balanceStartTime > 300000) { state = BAL_IDLE; } break; } }

4.4 与上位机的通信协议设计

PIC18F85J10的UART可以对外输出电池状态,方便接显示屏或者上位机监控。我定义了一个简单的帧格式:帧头(0xAA 0x55)+ 命令字 + 数据长度 + 数据 + 校验和。校验和用简单的累加取反,够用且计算量小。

数据内容包括:两节电芯电压、电压差、均衡状态、总电压、温度(如果有)、故障标志。上位机可以实时显示这些数据,也可以下发命令强制开启或关闭均衡,方便调试。

通信协议的设计原则是简单可靠。8位单片机的处理能力有限,复杂的协议解析会占用太多CPU时间。帧头用两个字节是为了降低误同步的概率,校验和虽然简单但能挡住大部分传输错误。

5. 调试过程中遇到的三个典型问题与排查过程

5.1 均衡开启后电压读数反而变大

这个问题困扰了我很久。现象是:开启第一节电芯的均衡后,第一节的电压读数不但没有下降,反而比第二节高了。按理说均衡在放电,电压应该降低才对。

排查过程是这样的:先确认硬件连接没问题,用万用表直接测电芯电压,发现实际电压确实在下降,但芯片读回来的值偏高。然后检查PCB布局,发现电压采集走线正好从均衡电阻下方穿过,均衡电流产生的磁场在采集走线上感应出了电压。虽然这个感应电压很小,但采集走线的阻抗和芯片输入端的滤波电容构成了一个微小的RC网络,导致读数偏移。

解决办法:重新布线,把电压采集走线移到板子另一层,并且用地平面隔离。改板之后问题消失。这个坑告诉我,均衡电流路径和电压采集路径必须物理隔离,不能有任何交叉或者平行走线。

5.2 I2C通信在均衡开启时偶发失败

另一个问题是:均衡没开的时候I2C通信很稳定,一旦开启均衡,偶尔会出现读取失败。用示波器抓波形发现,均衡开启瞬间I2C的SCL线上有明显的毛刺。

原因分析:均衡开关切换时,较大的di/dt在电源和地线上产生了尖峰,通过共用的电源引脚耦合到了I2C接口。MP2642GR-Z的I2C引脚和均衡驱动引脚共用同一组电源,去耦电容如果不够靠近芯片,这个耦合就很难避免。

改进措施:在MP2642GR-Z的电源引脚旁边加了一个1μF的陶瓷电容和一个10Ω的磁珠,构成LC滤波。同时在I2C的SCL和SDA线上各串了一个33Ω的电阻,限制瞬态电流。改完之后通信稳定性大幅提升,均衡开启时也不再出现读取失败。

5.3 长期运行后均衡效果变差

系统连续运行了几个月后,发现两节电芯的电压差虽然被控制在阈值以内,但整组电池的可用容量在下降。拆下来单独测两节电芯,发现它们的实际容量差异比初始时大了不少。

这个问题的根源不在均衡电路本身,而在均衡策略的局限性。被动均衡只能把电压高的电芯放电到跟低的那颗一致,但它不能提升低电压电芯的容量。如果两颗电芯的容量本身就在分化,被动均衡只能"掩盖"问题,不能"解决"问题。长期来看,容量差异会越来越大,直到均衡电流完全跟不上自放电和老化带来的差异。

应对策略:在软件里增加了容量趋势监测。记录每次充满电后两节电芯的电压差,如果这个差值在多次循环中持续增大,就通过UART上报"电芯一致性预警",提示维护人员检查或更换电芯。这个功能不能阻止老化,但能提前发现问题,避免整组电池突然失效。

6. 被动均衡方案的边界与适用场景:什么时候该换主动均衡

6.1 两串架构下被动均衡的性价比拐点

被动均衡最大的缺点是能量浪费。均衡电流100mA,两节电芯电压差50mV,那么均衡功率就是5mW左右,听起来不大。但如果电压差到了200mV,均衡功率就是20mW,持续几个小时就是几十焦耳的能量白白变成热。对于小容量电池(比如两节18650,总容量5Ah左右),这个浪费比例还可以接受;但对于大容量电池(比如两节100Ah的磷酸铁锂),被动均衡的电流就显得杯水车薪了。

我的经验是:均衡电流应该至少达到电池容量的0.5%到1%。比如5Ah的电池,均衡电流50mA到100mA就够了;但100Ah的电池,均衡电流至少要500mA到1A,这时候被动均衡的电阻功率就要到4W以上,散热和空间都成了大问题。到了这个量级,主动均衡的优势就体现出来了。

6.2 什么情况下必须上主动均衡

有几个明确的信号说明被动均衡已经不够用了:

  • 电池容量超过20Ah:均衡电流需求超过200mA,被动均衡的发热和空间成本开始超过主动均衡。
  • 充放电循环频繁:每天一次以上的深度循环,被动均衡的能量浪费累积起来很可观。
  • 对发热敏感的场景:比如密封的备用电源机箱,被动均衡的热量散不出去,会加速周边元件老化。
  • 电芯一致性差:如果配组时电芯差异就比较大,被动均衡需要频繁工作,效率太低。

主动均衡虽然电路复杂,但能量转移效率可以做到80%以上,均衡电流也能轻松做到1A以上。对于大容量或者高循环次数的场景,主动均衡的长期收益是明显的。

6.3 这套方案还能怎么扩展

MP2642GR-Z支持最多4串电芯,所以这套方案可以很容易地从两串扩展到三串或者四串。硬件上只需要增加均衡电阻和采集走线,软件上把电压采集和均衡控制的循环从2扩展到4就行。PIC18F85J10的GPIO和I2C带宽完全够用。

如果要加保护功能,可以在固件里增加过压、欠压、过温的判断逻辑,通过GPIO控制外部保护MOSFET。MP2642GR-Z本身也有故障标志寄存器,读取这些标志可以快速定位问题。

对外通信方面,UART可以接蓝牙模块或者WiFi模块,把电池数据传到手机或者云端。PIC18F85J10的UART波特率可以设到115200,传输这些数据绰绰有余。

我在实际使用中发现,这套方案最舒服的地方是调试直观。I2C总线上挂个逻辑分析仪,就能看到所有电压寄存器的原始值;UART输出接个串口助手,均衡状态一目了然。相比那些高度集成的SoC方案,分离方案的每一个环节都是可见、可控的,出了问题也容易定位。对于中小型储能和备用电源项目来说,这种"透明感"比省几颗元件重要得多。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进