第三章 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总线的仲裁机制,是我觉得最巧妙的设计。多个节点同时发送时,不会冲突,而是通过"线与"逻辑自动决定谁先发。

原理是这样的:

  1. 所有节点同时发送仲裁场(ID + RTR)
  2. 显性位(0)会覆盖隐性位(1)
  3. 发送隐性位的节点,如果检测到总线上是显性位,就知道自己输了,立即停止发送
  4. 发送显性位的节点继续,直到赢得仲裁

所以,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设计要点

最后,我给大家总结几条实战经验:

  1. 总线负载率不要超过50%。我见过太多项目,设计时算负载率30%,实际跑起来各种诊断报文、网络管理报文一加,直接飙到70%。留足余量。
  2. CANFD的BRS位要谨慎使用。如果总线上有CAN2.0节点,CANFD节点发送时BRS必须为0,否则CAN2.0节点会报形式错误。
  3. 终端电阻必须加。120欧姆,两端各一个。没有终端电阻,信号反射会让你怀疑人生。
  4. CAN_H和CAN_L要双绞。绞距越小,抗共模干扰能力越强。我见过用平行线代替双绞线的,EMC测试直接挂掉。
  5. 错误处理要分级。不要一检测到错误就复位。先尝试重发,重发3次失败再上报故障。

一个小技巧:调试CAN总线时,用示波器看CAN_H和CAN_L的差分信号。正常波形应该是方波,边沿陡峭。如果看到波形圆润、有振铃,说明终端电阻匹配有问题,或者线束过长。

好了,CAN总线的内容就讲到这里。下一章我们聊LIN总线,那个更简单,但坑也不少。各位回去可以拿CAN分析仪抓抓自己车上的报文,看看实际跑起来是什么样子。实践出真知嘛。