4. CAN协议基础:从物理层到BMS实战
各位同学好,我是老张。在储能系统里摸爬滚打了十几年,今天咱们聊聊CAN总线。说实话,CAN协议在BMS里就像人的神经系统——电池数据、控制指令全得靠它跑。我见过太多项目因为CAN通信出问题,现场调试到凌晨三点。所以这一章,咱们把CAN的底裤都扒清楚。
4.1 CAN总线物理层特性
先说说物理层。CAN总线用两根线:CAN_H和CAN_L。它靠差分信号传输,说白了就是两根线的电压差来决定是0还是1。
关键参数:
- 显性电平(逻辑0):CAN_H ≈ 3.5V,CAN_L ≈ 1.5V,压差2V
- 隐性电平(逻辑1):CAN_H ≈ 2.5V,CAN_L ≈ 2.5V,压差0V
- 总线终端电阻:120Ω(两端各一个)
- 最大通信距离:40m @ 1Mbps,1000m @ 50kbps
为什么用差分信号?抗干扰啊!我在储能电站现场遇到过,逆变器一启动,单端信号全乱套。但CAN总线稳如老狗,因为干扰同时作用在两根线上,压差不变。嗯,这里要注意:终端电阻必须加,不加的话信号反射能把波形打成狗啃的。
避坑指南:我曾经在调试一个40尺集装箱的BMS时,发现CAN通信偶尔丢包。查了两天,最后发现是终端电阻焊在了PCB上,但线缆太长导致阻抗不匹配。后来改成在接线端子处加120Ω电阻,问题解决。
4.2 CAN 2.0A与CAN 2.0B帧格式
CAN协议有两个版本:2.0A和2.0B。区别在哪?说白了就是ID长度不同。
| 特性 | CAN 2.0A(标准帧) | CAN 2.0B(扩展帧) |
|---|---|---|
| ID长度 | 11位 | 29位 |
| 最大节点数 | 2048个 | 5.36亿个 |
| 帧头开销 | 47位 | 67位 |
| 兼容性 | 基础 | 兼容2.0A |
数据帧结构是这样的:
标准帧(CAN 2.0A):
SOF + 11位ID + RTR + IDE + r0 + 4位DLC + 0-8字节数据 + 15位CRC + ACK + EOF
扩展帧(CAN 2.0B):
SOF + 11位ID + SRR + IDE + 18位扩展ID + RTR + r1 + r0 + 4位DLC + 0-8字节数据 + 15位CRC + ACK + EOF
我个人习惯在BMS里用CAN 2.0B。为什么?因为储能系统动辄上百个电池模组,11位ID根本不够分。你想想看,每个模组要上报电压、温度、SOC,还要下发均衡指令,29位ID才能把设备类型、模组编号、数据类型都编码进去。
4.3 CAN报文ID与仲裁机制
仲裁机制是CAN总线的精髓。多个节点同时发送时,ID小的优先。怎么做到的?靠线与逻辑——显性电平(0)会覆盖隐性电平(1)。
举个例子:
节点A发送ID:0x123(二进制:0001 0010 0011)
节点B发送ID:0x456(二进制:0100 0101 0110)
仲裁过程:
第1位:A发0,B发0 → 继续
第2位:A发0,B发1 → A的0覆盖B的1,B退出
结果:A获胜,继续发送数据
实战经验:我在设计BMS通信协议时,会把紧急报文(比如过压报警)的ID设得很小,比如0x001。普通数据(比如温度巡检)用大ID,比如0x300。这样紧急情况永远优先。记住:ID越小,优先级越高。
为什么会这样设计?因为CAN总线没有主从关系,所有节点平等。靠仲裁机制解决冲突,不需要额外的握手协议。这在储能系统里太重要了——电池保护动作必须毫秒级响应,等主机轮询黄花菜都凉了。
4.4 CAN在BMS中的应用
BMS里CAN总线主要干三件事:
- 电池数据上报:每个模组定时发送电压、温度、SOC
- 控制指令下发:均衡开启/关闭、继电器控制
- 故障报警:过压、欠压、过温、绝缘故障
我参与的一个50MW储能项目,用了三级CAN网络:
- 一级:电池模组内部CAN(250kbps,短距离)
- 二级:电池簇CAN(500kbps,簇内通信)
- 三级:系统级CAN(1Mbps,BMS到PCS、EMS)
这里有个坑:不同速率的总线之间必须加网关。我曾经见过有人直接把不同速率的CAN节点挂同一根线上,结果整个网络瘫痪。嗯,CAN控制器会检测到错误帧然后不断重发,形成总线风暴。
典型BMS报文定义示例:
// 电池电压报文
ID: 0x100 + 模组编号 (0-15)
数据: 8字节,每2字节一个电芯电压,单位mV
示例:0x100 发送 0x0BB8 0x0BC0 0x0BA8 0x0BB2
→ 电芯1: 3000mV, 电芯2: 3008mV, 电芯3: 2984mV, 电芯4: 2994mV
// 故障报警报文
ID: 0x001 (最高优先级)
数据: 第1字节故障类型,第2字节故障模组
示例:0x001 发送 0x01 0x03
→ 模组3发生过压故障
避坑指南:我曾经在项目里遇到一个诡异问题——BMS偶尔会误报绝缘故障。查了三天,最后发现是CAN总线上的某个节点在发送报文时,数据域的第7位刚好和绝缘检测仪器的报文ID冲突,导致数据被错误解析。从那以后,我要求所有BMS报文的数据域第一位必须固定为0xAA作为帧头校验。
最后说一句:CAN总线虽然可靠,但不是万能的。在强电磁干扰环境(比如大功率逆变器旁边),建议用CAN FD或者光纤转换。我见过一个光伏电站,CAN总线被逆变器的IGBT开关干扰得完全没法用,最后全部换成光纤环网才搞定。
个人建议:刚开始做BMS通信设计时,先画好ID分配表。把紧急报警、控制指令、周期数据、诊断数据分区间管理。我习惯用0x000-0x0FF给报警,0x100-0x2FF给控制,0x300-0x7FF给数据。这样即使以后扩展,也不会乱。
公众号:蓝海资料掘金营,微信deep3321