2. CAN报文帧结构:标准帧与扩展帧、数据帧、远程帧、错误帧、过载帧、帧间隔

好,咱们今天来啃一块硬骨头——CAN报文的帧结构。说实话,我刚入行那会儿,看到这些帧类型也是一头雾水。什么标准帧、扩展帧,数据帧、远程帧……感觉像在看天书。但后来在项目里被坑过几次,才真正搞明白这些东西有多重要。

你想想看,CAN总线上跑的就是这些帧。不理解它们,你连报文都读不懂。咱们一个一个来拆解。

2.1 标准帧 vs 扩展帧

先说最基础的区别——ID长度。标准帧的ID是11位,扩展帧是29位。为什么要有两种?说白了,早期CAN总线节点少,11位ID够用。后来车上的ECU越来越多,11位不够分了,就搞了个29位的扩展帧。

关键区别:

  • 标准帧:11位标识符,最多2032个不同ID
  • 扩展帧:29位标识符,最多5.3亿个不同ID
  • IDE位(Identifier Extension)决定是标准还是扩展

我在项目中遇到过一件事:有个同事把标准帧和扩展帧混着用,结果接收节点死活收不到数据。查了半天,原来是接收滤波器配置只认标准帧,而发送端发的是扩展帧。嗯,这种坑踩过一次就记住了。

2.2 数据帧

数据帧,这是咱们用得最多的。它负责把数据从发送节点传到接收节点。结构上分7个段:

段名称 说明 我的一点经验
帧起始 1位显性位,同步用 别小看这一位,总线空闲时全靠它
仲裁段 ID + RTR位 ID越小优先级越高,这是CAN的精华
控制段 IDE + DLC DLC告诉你有几个字节数据
数据段 0-8字节数据 最多8字节,别想塞更多
CRC段 15位校验 + 1位界定符 校验出错?节点会自动重发
ACK段 2位:应答间隙 + 界定符 接收节点拉低应答位,告诉发送方"我收到了"
帧结束 7位隐性位 表示帧结束了

小技巧:抓包时看到DLC=0的数据帧别慌,那是合法的。有些节点就用空数据帧来当心跳包用。

2.3 远程帧

远程帧,说白了就是"请求帧"。一个节点发远程帧,意思是"谁有某某ID的数据?发给我"。它没有数据段,DLC表示它期望接收的数据长度。

我记得有一次调试一个电机控制器,发现它老是发远程帧请求某个传感器的数据。但传感器节点没响应。查了半天,原来是传感器节点的接收滤波器没配好,压根没认出这个远程帧。后来我把滤波器改了一下,问题就解决了。

注意:远程帧的RTR位是隐性(1),而数据帧的RTR位是显性(0)。抓包时看到RTR=1,那就是远程帧。

2.4 错误帧

错误帧,这是CAN总线的"警察"。一旦有节点检测到错误,就会发错误帧通知大家。错误帧由两部分组成:

  • 错误标志:6个连续相同位(显性或隐性)
  • 错误界定符:8个隐性位

错误类型有几种:位错误、填充错误、CRC错误、格式错误、应答错误。我见过最典型的是位错误——某个节点发送显性位,但总线上读到的是隐性位,说明总线被其他节点抢占了或者短路了。

我曾经在实验室里用示波器抓过错误帧。那波形看着就乱,一堆显性位挤在一起。后来发现是终端电阻没接好,信号反射导致位错误。嗯,这种问题排查起来确实费劲。

2.5 过载帧

过载帧,相当于"我忙,等会儿再说"。当接收节点来不及处理数据时,就发过载帧让发送方等一等。它的结构和错误帧很像:

  • 过载标志:6个显性位
  • 过载界定符:8个隐性位

为什么会有过载?你想想看,如果总线上数据量太大,接收节点的缓冲区满了,它就得发过载帧。我在一个多节点项目中就遇到过这种情况——某个节点处理速度慢,总线上数据一多它就发过载帧,搞得整个网络效率下降。后来给它换了个性能更强的MCU才解决。

2.6 帧间隔

帧间隔,就是两帧之间的"休息时间"。CAN总线规定,每发完一帧,必须等3个隐性位才能发下一帧。这3个位叫"间歇场"。之后总线进入"总线空闲"状态,直到有节点开始发下一帧。

为什么要这样?说白了,给节点一点时间处理刚收到的数据,也防止总线冲突。我见过有人为了追求高吞吐量,把帧间隔缩短,结果总线乱成一锅粥。嗯,别这么干,规矩就是规矩。

总结一下:

  • 数据帧:传数据用的,最常见
  • 远程帧:请求数据用的,没有数据段
  • 错误帧:出错了,大家注意
  • 过载帧:我忙不过来,等会儿
  • 帧间隔:两帧之间的休息时间

好了,帧结构这块就讲这么多。你把这些搞清楚了,抓包解析的时候就能一眼看出报文类型。下一章咱们聊聊CAN的位时序和同步,那个更烧脑,但搞懂了就能自己算波特率了。