第三章 CAN总线详解:CAN2.0与CANFD区别、报文帧结构、位填充、仲裁机制、错误处理
各位同学,今天我们来啃一块硬骨头——CAN总线。说实话,做三电系统这些年,CAN总线是我打交道最多的通信协议。从最早的CAN2.0到后来的CANFD,我踩过的坑,今天一次性给你们讲透。
3.1 CAN2.0 vs CANFD:到底差在哪?
先问大家一个问题:为什么要有CANFD?CAN2.0跑得好好的,干嘛要升级?
我2018年做某款纯电车型时,就遇到了瓶颈。电池管理系统(BMS)和整车控制器(VCU)之间,需要传输大量电池单体电压、温度数据。CAN2.0一帧最多8字节,一个电池包288个电芯,光传完一轮电压数据就要几十帧。总线负载率直接飙到70%以上,丢帧、延迟全来了。
CANFD就是来解决这个痛点的。咱们直接看对比:
| 特性 | CAN2.0 | CANFD |
|---|---|---|
| 数据场最大长度 | 8字节 | 64字节 |
| 最大波特率(数据段) | 1Mbps | 8Mbps(实际常用2-5Mbps) |
| 帧格式 | 标准帧/扩展帧 | 兼容CAN2.0 + 新增FDF标志 |
| CRC校验 | 15位CRC | 17位或21位CRC(根据数据长度) |
| 位填充 | 从SOF到CRC段 | 控制段和数据段采用不同填充规则 |
核心区别一句话:CANFD在数据段用更高速率传输更多数据,同时保持仲裁段与CAN2.0兼容。
3.2 报文帧结构:一帧数据长什么样?
咱们以标准数据帧为例,拆开看看里面都有啥。我习惯把一帧CAN报文想象成一封快递:
- SOF(起始帧):1个显性位,相当于快递单上的"开始"标记
- 仲裁场:11位ID + RTR位。ID决定了这帧报文的优先级,数值越小优先级越高
- 控制场:IDE位 + r0 + DLC(4位数据长度码)
- 数据场:0-8字节(CAN2.0)或0-64字节(CANFD)
- CRC场:15位CRC + 1位CRC分隔符
- ACK场:2位,接收节点应答
- EOF:7个隐性位,帧结束
这里有个细节我提醒大家注意——CANFD的帧结构在控制场多了一个FDF位和BRS位。FDF位为1表示这是CANFD帧,BRS位控制数据段是否切换到高速率。
避坑指南:我曾经在项目中遇到一个诡异问题——CANFD节点和CAN2.0节点混接,结果CAN2.0节点看到FDF位为1,直接报错。后来发现是CAN2.0控制器不认识这个位,把它当成了错误。解决方案:混接时确保CANFD节点发送兼容帧(FDF=0)。
3.3 位填充:为什么要有这玩意儿?
位填充,说白了就是防止总线"睡着"。CAN总线用隐性位(1)和显性位(0)表示数据,如果连续出现5个相同电平,接收节点的时钟同步就可能出问题。
规则很简单:发送节点在连续发送5个相同位后,自动插入一个相反电平的位。接收节点收到后,自动把这个填充位去掉。
举个例子:你要发送的数据是 11111 00000,经过位填充后变成 11111 0 00000 1。注意,填充位不参与数据解析。
个人经验:CANFD在位填充上做了优化。数据段采用更宽松的填充规则,允许连续12个相同位。为什么?因为数据段速率高,时钟同步更可靠。我测试过,5Mbps下用CAN2.0的填充规则,CPU负载会飙升30%以上。
3.4 仲裁机制:谁先说话?
CAN总线的仲裁机制,是我觉得最巧妙的设计。多个节点同时发送时,不会冲突,而是通过"线与"逻辑自动决定谁先发。
原理是这样的:
- 所有节点同时发送仲裁场(ID + RTR)
- 显性位(0)会覆盖隐性位(1)
- 发送隐性位的节点,如果检测到总线上是显性位,就知道自己输了,立即停止发送
- 发送显性位的节点继续,直到赢得仲裁
所以,ID数值越小,优先级越高。0x000比0x7FF优先级高得多。
关键点:仲裁机制只发生在仲裁场。一旦某个节点赢得仲裁,后续的数据场、CRC场就不会再有仲裁了。这也是为什么CANFD能在数据段提高速率——仲裁段必须用1Mbps以下,但数据段可以飙到8Mbps。
我记得有一次调试,发现电机控制器总是抢不到总线。查了半天,发现它的ID是0x500,而BMS的ID是0x100。每次BMS发报文,电机控制器就得等。后来我们把电机控制器的ID改成了0x200,问题解决。嗯,这就是仲裁机制的现实影响。
3.5 错误处理:CAN总线怎么保证可靠性?
CAN总线的错误处理机制,可以说是汽车级通信的基石。它包含5种错误类型和2个错误计数器。
5种错误类型:
- 位错误:发送节点监控总线,发现发送的电平和实际电平不一致
- 填充错误:接收节点发现连续6个相同位(违反填充规则)
- CRC错误:接收节点计算的CRC与发送的不一致
- 形式错误:固定格式的位(如CRC分隔符、ACK分隔符)出现错误电平
- ACK错误:发送节点没有收到接收节点的应答
错误计数器机制:
每个节点有两个计数器:TEC(发送错误计数)和REC(接收错误计数)。
- 成功发送一次,TEC减1
- 发送出错,TEC加8
- 接收出错,REC加1
- 当TEC或REC超过127,节点进入"被动错误"状态
- 当TEC超过255,节点进入"总线关闭"状态,彻底断开
我曾经踩过的坑:某次路试,车辆突然失去通信。查日志发现,一个网关节点的TEC飙到了256,触发了总线关闭。原因是什么?这个网关的CAN收发器电源纹波太大,导致发送的显性位电压不够,其他节点收不到,于是不断重发。TEC一路飙升到256。后来我们在收发器电源上加了个LC滤波,再没出过问题。
3.6 实际项目中的CAN设计要点
最后,我给大家总结几条实战经验:
- 总线负载率不要超过50%。我见过太多项目,设计时算负载率30%,实际跑起来各种诊断报文、网络管理报文一加,直接飙到70%。留足余量。
- CANFD的BRS位要谨慎使用。如果总线上有CAN2.0节点,CANFD节点发送时BRS必须为0,否则CAN2.0节点会报形式错误。
- 终端电阻必须加。120欧姆,两端各一个。没有终端电阻,信号反射会让你怀疑人生。
- CAN_H和CAN_L要双绞。绞距越小,抗共模干扰能力越强。我见过用平行线代替双绞线的,EMC测试直接挂掉。
- 错误处理要分级。不要一检测到错误就复位。先尝试重发,重发3次失败再上报故障。
一个小技巧:调试CAN总线时,用示波器看CAN_H和CAN_L的差分信号。正常波形应该是方波,边沿陡峭。如果看到波形圆润、有振铃,说明终端电阻匹配有问题,或者线束过长。
好了,CAN总线的内容就讲到这里。下一章我们聊LIN总线,那个更简单,但坑也不少。各位回去可以拿CAN分析仪抓抓自己车上的报文,看看实际跑起来是什么样子。实践出真知嘛。