3. BMS通信协议详解:BMS数据报文结构
各位同学,咱们今天聊点实在的。BMS和PCS能不能好好配合,全看通信协议写得怎么样。我见过太多项目,硬件都调通了,结果卡在协议解析上,一查就是好几天。说白了,协议就是BMS和PCS之间的“共同语言”,语言不通,啥都白搭。
这一节,我带你拆解BMS报文的核心结构。电压、电流、温度、SOC,这些数据怎么打包发送?告警和保护报文长什么样?心跳机制又是怎么维持的?咱们一个一个来。
核心要点:BMS报文结构遵循“帧头+数据域+校验+帧尾”的通用格式。数据域中,每个参数都有固定的字节位置和精度定义。搞懂这个,你就能读懂任何BMS协议。
3.1 数据报文结构:电压、电流、温度、SOC
先看最基础的数据报文。BMS需要定期上报电池的实时状态,包括总电压、总电流、最高/最低单体电压、平均温度、SOC等。这些数据怎么组织?
我个人习惯用Modbus RTU协议,因为它简单可靠。但不管用哪种协议,报文结构都大同小异。下面是一个典型的BMS数据报文示例:
帧头: 0xAA 0x55
数据长度: 0x1E (30字节)
设备地址: 0x01
功能码: 0x03 (读取寄存器)
数据域:
- 总电压: 0x0B 0xB8 (3000, 表示300.0V, 精度0.1V)
- 总电流: 0x00 0x64 (100, 表示10.0A, 精度0.1A)
- 最高单体电压: 0x0E 0x10 (3600, 表示3.600V, 精度0.001V)
- 最低单体电压: 0x0D 0xF0 (3568, 表示3.568V, 精度0.001V)
- 平均温度: 0x00 0x1E (30, 表示30.0°C, 精度0.1°C)
- SOC: 0x00 0x3C (60, 表示60.0%, 精度0.1%)
- 预留字节: 0x00 * 18
CRC校验: 0xXX 0xXX
帧尾: 0x0D 0x0A
你注意看,每个参数都有明确的精度定义。总电压精度0.1V,单体电压精度0.001V,温度精度0.1°C。为什么这么设计?因为电池管理对精度要求很高。我曾经遇到一个项目,单体电压精度用了0.01V,结果SOC估算偏差很大,后来改成0.001V才解决问题。
这里有个表格,把常见参数的数据格式列出来:
| 参数名称 | 字节数 | 数据类型 | 精度 | 取值范围 |
|---|---|---|---|---|
| 总电压 | 2 | uint16 | 0.1V | 0~6553.5V |
| 总电流 | 2 | int16 | 0.1A | -3276.8~3276.7A |
| 最高单体电压 | 2 | uint16 | 0.001V | 0~65.535V |
| 最低单体电压 | 2 | uint16 | 0.001V | 0~65.535V |
| 平均温度 | 2 | int16 | 0.1°C | -3276.8~3276.7°C |
| SOC | 2 | uint16 | 0.1% | 0~100.0% |
经验之谈:电流用int16是因为有充放电方向。正数表示充电,负数表示放电。我见过有人用uint16,结果放电电流解析出来是65535A,直接触发过流保护。嗯,这种低级错误咱们别犯。
3.2 BMS告警与保护报文
数据报文是常规上报,告警报文则是紧急情况。BMS检测到异常时,会主动发送告警报文,通知PCS执行保护动作。
告警报文的结构和数据报文类似,但数据域的内容不同。它通常包含告警类型、告警级别、告警参数等。下面是一个例子:
帧头: 0xAA 0x55
数据长度: 0x0A (10字节)
设备地址: 0x01
功能码: 0x04 (告警上报)
数据域:
- 告警类型: 0x01 (单体过压)
- 告警级别: 0x02 (严重)
- 告警参数: 0x0E 0x10 (告警时的电压值, 3.600V)
- 告警时间戳: 0x00 0x00 0x00 0x01 (系统运行时间, 单位秒)
CRC校验: 0xXX 0xXX
帧尾: 0x0D 0x0A
告警类型通常用一个字节表示,常见的告警类型包括:
- 0x01:单体过压
- 0x02:单体欠压
- 0x03:过温
- 0x04:低温
- 0x05:过流
- 0x06:短路
- 0x07:绝缘故障
- 0x08:通信故障
告警级别一般分三级:
- 0x01:提示(仅记录,不动作)
- 0x02:严重(需要降功率或停止充放电)
- 0x03:致命(立即切断接触器)
注意:告警报文的优先级高于数据报文。BMS在发送告警时,可以中断正在发送的数据报文。我曾经调试一个项目,BMS一直发数据报文,结果过温告警发不出去,PCS没收到指令,电池直接热失控了。后来我们在协议里加了优先级机制,告警报文插队发送。
保护报文和告警报文类似,但保护报文是BMS主动执行保护动作后发送的确认报文。比如BMS检测到过压,先发告警,然后执行保护动作(断开接触器),再发保护报文确认。PCS收到保护报文后,需要停止充放电并等待BMS的恢复指令。
3.3 BMS心跳与同步机制
心跳机制,说白了就是BMS和PCS互相确认“我还活着”。没有心跳,你根本不知道对方是不是已经掉线了。
心跳报文通常很简单,就是一个固定格式的短报文。BMS每隔一定时间(比如1秒)发送一次心跳,PCS收到后回复确认。如果PCS连续几次没收到心跳,就认为BMS故障,需要执行安全动作。
下面是一个心跳报文的例子:
BMS发送:
帧头: 0xAA 0x55
数据长度: 0x02
设备地址: 0x01
功能码: 0x10 (心跳)
数据域: 0x00 0x01 (心跳计数, 每次加1)
CRC校验: 0xXX 0xXX
帧尾: 0x0D 0x0A
PCS回复:
帧头: 0xAA 0x55
数据长度: 0x02
设备地址: 0x01
功能码: 0x10 (心跳回复)
数据域: 0x00 0x01 (回复相同的心跳计数)
CRC校验: 0xXX 0xXX
帧尾: 0x0D 0x0A
心跳计数很重要。它用来检测报文是否丢失。如果BMS发送了计数5,但PCS回复的是计数3,说明中间有报文丢失了。这时候需要重新同步。
同步机制,我建议用“三次握手”的方式。BMS启动后,先发送同步请求,PCS回复同步确认,BMS再发送同步完成。这样双方就建立了可靠的通信链路。
同步流程如下:
- BMS发送同步请求(包含设备ID、协议版本号)
- PCS回复同步确认(包含PCS设备ID、支持的协议版本)
- BMS发送同步完成(确认版本一致,开始正常通信)
如果版本不一致怎么办?我建议BMS和PCS都支持向下兼容。比如BMS支持协议版本1.0和2.0,PCS只支持1.0,那就用1.0通信。如果完全不兼容,BMS需要上报“协议不匹配”告警。
避坑指南:我曾经遇到一个项目,BMS和PCS的心跳周期不一致。BMS设了1秒,PCS设了2秒。结果BMS发两次心跳,PCS才回一次,BMS以为PCS掉线了,直接切断了接触器。后来我们统一了心跳周期,并且在协议里明确写了“心跳周期可配置,但双方必须一致”。
好了,这一节的内容就这些。报文结构、告警保护、心跳同步,这三个点搞清楚了,BMS和PCS的通信对接就成功了一半。剩下的就是调试和测试了。