第1章:CAN总线数据链路层:报文帧格式、ID仲裁机制、位填充与CRC校验

大家好,我是老张。今天咱们聊聊CAN总线数据链路层。说实话,很多工程师做CAN通信诊断,一上来就抓波形、看电压,却忽略了数据链路层本身。我个人觉得,这层才是理解通信丢失的关键。

数据链路层,说白了就是CAN协议的核心。它规定了报文怎么打包、怎么发出去、怎么保证不出错。你想想看,如果这层出了问题,物理层再完美也没用。

1.1 报文帧格式:五种帧类型

CAN总线有五种帧类型。我刚开始学的时候,总觉得记不住。后来在项目里吃过亏,才真正搞明白。

帧类型 用途 我遇到过的坑
数据帧 发送节点把数据传给其他节点 最常见,但ID设错了谁也收不到
远程帧 请求其他节点发送数据 有些ECU不支持远程帧,会直接忽略
错误帧 检测到总线错误时主动发出 我曾经被错误帧刷屏,总线直接瘫痪
过载帧 接收节点忙不过来时请求延迟 少见,但老旧的ECU偶尔会触发
帧间隔 帧与帧之间的分隔 间隔时间不对,会导致同步丢失

数据帧是最常用的。它由七个段组成:帧起始、仲裁段、控制段、数据段、CRC段、ACK段、帧结束。嗯,这里要注意,数据段最多8个字节。为什么是8个?因为CAN总线设计时考虑的是实时控制,8个字节够用了。你想想看,一个发动机转速信号,两个字节就搞定了。

重点记忆:数据帧的仲裁段包含ID和RTR位。RTR位用来区分数据帧(显性0)和远程帧(隐性1)。这个位在仲裁时很关键。

1.2 ID仲裁机制:谁优先级高谁先发

CAN总线的仲裁机制,是我觉得最巧妙的设计。多个节点同时发数据怎么办?不会冲突吗?答案是:不会。CAN用"线与"机制,显性位(0)会覆盖隐性位(1)。

仲裁的过程是这样的:所有节点同时发送ID位。谁先发了一个隐性位(1),但总线上是显性位(0),谁就输了,自动退出发送。赢的那个继续发完。

我举个例子。假设节点A的ID是0x100,节点B的ID是0x200。二进制分别是:

节点A: 001 0000 0000
节点B: 010 0000 0000

从最高位开始比。第一位都是0,没问题。第二位,节点A是0,节点B是1。节点B发了1,但总线上是0(节点A发的),所以节点B输了,退出。节点A继续发送。

为什么会这样?因为ID值越小,优先级越高。0x100比0x200小,所以0x100赢。

我的经验:设计CAN网络时,一定要把关键信号的ID设小一点。比如刹车信号,ID设成0x001,比空调信号0x100优先级高。这样紧急情况下,刹车信号总能抢到总线。

我曾经在一个项目里,把两个ECU的ID设反了。结果空调信号老是抢在刹车信号前面发出去。嗯,那场面,想想都后怕。

1.3 位填充:保证同步的"小聪明"

位填充,说白了就是防止总线"睡着"。CAN总线靠电平跳变来同步时钟。如果连续出现5个相同的位,接收节点可能就失去同步了。

规则很简单:发送节点每发送5个相同位,就自动插入一个相反位。接收节点收到后,自动把这个填充位去掉。

举个例子:

原始数据: 11111 00000 11111
填充后:   11111 0 00000 1 11111 0

注意看,每5个1后面插一个0,每5个0后面插一个1。这样总线上就不会出现连续6个相同位了。

避坑指南:我曾经遇到过一个ECU,它的位填充逻辑有bug。连续发送了6个相同位,没有插入填充位。结果其他节点全部失去同步,总线直接报错。排查了三天,最后用示波器抓波形才发现问题。

位填充会影响实际传输速率。你想想看,本来要发100个位,可能因为填充变成了110个位。所以CAN总线的实际带宽,要比理论值低一些。设计时一定要留余量。

1.4 CRC校验:最后的防线

CRC校验,是数据链路层的最后一道防线。它用来检测传输过程中有没有发生位错误。

CAN用的CRC是15位的。发送节点根据数据段和部分控制段,计算出一个15位的CRC值,放在CRC段里。接收节点收到后,用同样的算法重新计算,然后比对。

如果比对不一致,接收节点会发错误帧,要求发送节点重发。

CRC的算法是固定的,但计算过程有点复杂。我一般直接用工具算,不手算。但你要知道它的原理:

生成多项式: x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
二进制:     1100010110011001

嗯,这个多项式是CAN协议规定的,不能改。所有符合CAN2.0的节点都用这个。

关键点:CRC只能检测错误,不能纠正错误。检测到错误后,靠重传机制来恢复。如果重传也失败,那通信就丢失了。

我在项目里见过一种情况:总线上的干扰特别大,CRC错误率很高。ECU不停地重传,重传又失败,最后直接进入Bus Off状态。通信彻底丢失。这种情况,光靠数据链路层解决不了,得从物理层找原因。

1.5 总结:排查通信丢失的思路

好了,咱们把数据链路层的几个关键点串起来。排查通信丢失时,你可以按这个思路来:

  1. 先看ID仲裁:是不是有更高优先级的节点在抢总线?用CAN分析仪抓一下,看看哪些ID在发。
  2. 再看位填充:有没有节点发送了连续6个相同位?这个用示波器看波形最直观。
  3. 最后看CRC:错误帧多不多?如果CRC错误率超过1%,物理层大概率有问题。

我个人习惯,排查时先看错误帧数量。如果错误帧很多,直接查物理层。如果错误帧很少但通信还是丢,那就查ID仲裁和位填充。

下一章,咱们聊CAN物理层。到时候我会讲讲终端电阻、共模电压这些实战中经常踩的坑。嗯,今天就到这里,有问题随时找我。