2. CAN协议基础:CAN数据帧结构

好,咱们今天聊聊CAN数据帧的结构。说实话,这是整个CAN协议里最核心的内容。你想想看,一辆车上几十个ECU,它们之间怎么交流?就是靠这个数据帧。我在调试台架时,经常要对着逻辑分析仪一帧一帧地看数据,所以对这个结构特别熟悉。

一个标准的CAN数据帧,总共由7个场组成。我习惯把它们分成三部分来看:开头、中间和结尾。开头是SOF和仲裁场,中间是控制场和数据场,结尾是CRC场、ACK场和EOF。咱们一个一个说。

2.1 SOF(帧起始)

SOF就是一个显性位(逻辑0)。它告诉总线上所有节点:“我要开始说话了”。

为什么只有一个位?因为CAN总线是“线与”机制。显性位会覆盖隐性位。所以只要有一个节点拉低总线,其他节点就知道有数据来了。嗯,这里要注意:SOF必须是严格的显性位,不能有任何偏差。我在项目中遇到过,有个节点的晶振精度不够,SOF位置偏了,结果整个网络都乱套了。

关键点:SOF是同步的起点。所有节点都靠这个边沿来重新同步自己的时钟。

2.2 仲裁场

仲裁场包含两部分:11位标识符(标准帧)和RTR位。如果是扩展帧,那就是29位标识符。

这里有个很有意思的机制:总线仲裁。说白了,就是多个节点同时发数据时,谁优先级高谁先发。标识符越小,优先级越高。为什么?因为显性位(0)会覆盖隐性位(1)。

我举个例子:

节点A:ID = 0x7FF(二进制:111 1111 1111)
节点B:ID = 0x001(二进制:000 0000 0001)

同时发送时,从最高位开始比较。
节点A发1(隐性),节点B发0(显性)。
总线被拉低为0,节点A检测到总线与自己发送的不一致,立刻退出。
节点B继续发送,赢得仲裁。

RTR位呢?它区分数据帧和远程帧。数据帧的RTR是显性,远程帧是隐性。我在做诊断工具时,经常用远程帧来请求某个节点的数据,挺方便的。

个人经验:设计网络时,尽量把高优先级(小ID)分配给关键功能,比如刹车、转向。娱乐系统的ID可以大一些,反正优先级低点也没事。

2.3 控制场

控制场有6位:IDE位、保留位r0、DLC(数据长度码)4位。

IDE位用来区分标准帧和扩展帧。标准帧的IDE是显性,扩展帧是隐性。保留位r0目前固定为显性,留给以后用。

DLC表示数据场的字节数,范围是0到8。注意,DLC可以设置成0到8,但实际数据场长度必须匹配。我曾经见过一个新手,DLC设成8但只发了3个字节,结果接收方读到一堆垃圾数据。

DLC值 数据长度(字节)
00
11
22
33
44
55
66
77
88

2.4 数据场

数据场就是实际要传输的数据,最多8个字节。为什么是8个?因为CAN最初是为汽车设计的,8个字节足够传递大部分控制信号了。比如发动机转速、车速、水温这些,每个信号2个字节,8个字节能装4个信号。

数据场的排列方式,我建议遵循Motorola格式(大端序)或者Intel格式(小端序)。这个在项目初期就要定好,不然不同ECU之间会解析错。我踩过这个坑:有一次两个团队用了不同的字节序,结果车速显示成了负数,排查了好久才发现是字节序的问题。

注意:数据场的内容完全由用户定义。CAN协议只负责传输,不关心里面是什么。所以发送方和接收方必须约定好数据格式,包括信号起始位、长度、缩放因子、偏移量等。

2.5 CRC场

CRC场包含15位CRC序列和1位CRC界定符(隐性)。

CRC的计算范围是从SOF到数据场结束。算法是CRC-15,多项式是x¹⁵ + x¹⁴ + x¹⁰ + x⁸ + x⁷ + x⁴ + x³ + 1。嗯,这个多项式不用背,芯片会自动算。但你要知道它的作用:检测传输错误。

我在做EMC测试时,遇到过总线受到干扰导致CRC错误的情况。CAN控制器会自动重发,但如果错误太多,节点会进入总线关闭状态。所以CRC不仅是检错,还关系到网络的可靠性。

2.6 ACK场

ACK场有2位:ACK槽和ACK界定符。

发送节点在ACK槽发送隐性位。接收节点如果正确收到数据,就在ACK槽发送显性位。这样发送节点就知道数据被至少一个节点收到了。

这里有个细节:ACK是“线与”的。只要有一个节点应答成功,总线就是显性。发送节点只关心有没有应答,不关心有几个节点应答。

重要:如果总线上只有一个节点,它自己发自己收,ACK会失败。因为发送节点自己不会应答自己。所以单节点网络需要特殊处理,比如开启自应答模式。

2.7 EOF(帧结束)

EOF是7个隐性位。它告诉总线:“这帧数据结束了”。

为什么是7个?因为CAN协议规定,连续6个相同位就表示错误。所以EOF用7个隐性位,既表示结束,又不会触发错误检测。设计得挺巧妙的,对吧?

EOF之后,总线会进入3位的ITM(帧间空间)。然后就可以开始下一帧了。

总结一下

一个完整的CAN数据帧,从SOF开始,到EOF结束,总共47到111位不等(取决于数据场长度)。我习惯用这个口诀来记:

SOF开始一个0
仲裁场里比高低
控制场里说长度
数据场里装内容
CRC场里查错误
ACK场里求应答
EOF结束七个1

嗯,这个口诀虽然不太押韵,但挺实用的。你在看逻辑分析仪波形时,可以对照着这个口诀来解析每一帧数据。

下一章咱们聊聊CAN的位时序和同步机制,那个更烧脑,但理解了之后,你对CAN的掌握就更深一层了。