第2章:CAN协议详解:CAN数据帧、CAN远程帧、CAN错误帧、CAN过载帧、帧间隔

大家好,我是老张。今天咱们来啃一块硬骨头——CAN协议的五种帧结构。说实话,我刚入行那会儿,光看协议文档看得头大,什么SOF、CRC、ACK,一堆缩写。后来在项目里亲手抓了几次波形,才真正搞明白。

嗯,咱们不搞那些虚的。直接上干货。CAN总线上一共就五种帧:数据帧、远程帧、错误帧、过载帧、帧间隔。你想想看,一辆车上几百个ECU,全靠这五种帧在一条双绞线上沟通,是不是挺神奇的?

2.1 数据帧——最常用的"快递员"

数据帧,说白了就是用来发数据的。我习惯把它想象成一个快递包裹:有收件地址(ID),有货物(数据),还有签收确认(ACK)。

数据帧分两种格式:标准帧(11位ID)扩展帧(29位ID)。我在做车身控制项目时,大部分节点用标准帧就够了,但遇到多路况诊断系统,29位ID才够用。

数据帧结构(标准帧):

SOF + 11位ID + RTR + IDE + r0 + DLC + 数据段(0-8字节) + CRC + ACK + EOF

咱们拆开来看:

  • SOF(帧起始):一个显性位。告诉总线上所有节点:"我要开始说话了!"
  • ID(标识符):11位。注意,ID越小优先级越高。我曾经遇到过一个bug,两个节点同时发数据,优先级低的那个总是发不出去,查了半天发现ID设反了。
  • RTR(远程帧标志):数据帧里这一位是显性(0)。
  • DLC(数据长度码):4位,表示数据段有多少字节。范围0-8。注意,DLC可以写0,表示不携带数据。
  • 数据段:0-8字节。这就是真正的"货物"。
  • CRC(循环冗余校验):15位CRC + 1位CRC界定符。用来检查数据有没有传错。
  • ACK(应答):2位。发送节点发隐性位,接收节点如果正确收到,就拉成显性。这就是"签收确认"。
  • EOF(帧结束):7个隐性位。

我的经验:调试时,如果发现某个节点总是收不到数据,先查ACK。用示波器抓一下,看接收节点有没有把ACK位拉低。没有?那说明接收节点根本没收到,或者收到了但校验失败。

2.2 远程帧——"帮我带个话"

远程帧,说白了就是请求数据。一个节点发远程帧,另一个节点收到后,就会发对应的数据帧。

远程帧和数据帧长得几乎一样,唯一的区别是RTR位:远程帧的RTR是隐性(1)。而且远程帧没有数据段,DLC写的是请求的数据长度。

我记得有一次做发动机和变速箱的联调,发动机需要变速箱的当前档位信息。发动机发一个远程帧,ID是变速箱的地址,DLC=1。变速箱收到后,立刻回一个数据帧,里面就是档位值。

注意:远程帧的DLC必须和期望的数据帧的DLC一致。我曾经见过一个新手,远程帧DLC写2,但数据帧DLC是1,结果接收节点直接报错。嗯,这种坑踩过一次就记住了。

2.3 错误帧——"出错了,大家注意!"

错误帧,是CAN总线上的"警报器"。任何节点检测到错误,都会立刻发错误帧,通知所有节点:刚才那帧数据有问题,别用了。

错误帧分两部分:

  • 错误标志:6个连续相同位(显性或隐性)。主动错误节点发6个显性位,被动错误节点发6个隐性位。
  • 错误界定符:8个隐性位。

为什么会这样?因为CAN协议规定,连续6个相同位就是违规(位填充规则)。所以错误标志一出来,所有节点都知道出事了。

我遇到过最头疼的问题,就是总线一直报错。用CAN分析仪一看,错误帧满天飞。最后发现是一个节点的晶振不准,导致位时序偏差,老是发错数据。换了个晶振,世界清净了。

错误类型有5种:

  1. 位错误:发送节点发现总线上的位和自己发的不一样。
  2. 填充错误:连续6个相同位,违反位填充规则。
  3. CRC错误:接收节点算出来的CRC和收到的CRC不一致。
  4. 形式错误:固定格式的位(如CRC界定符、ACK界定符)不是隐性。
  5. ACK错误:发送节点没收到ACK应答。

2.4 过载帧——"慢点,我处理不过来了"

过载帧,相当于"流量控制"。当一个节点太忙,来不及处理数据时,就发过载帧,让其他节点等一等。

过载帧的结构和错误帧很像:

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

说实话,过载帧在实际项目中用得不多。我做了这么多年,也就见过两三次。大部分情况下,CAN总线的速率足够快,节点处理能力也够。但如果你在做高负载系统,比如ADAS(高级驾驶辅助系统),就要小心了。

避坑指南:我曾经在一个项目中,发现某个节点频繁发过载帧。查了半天,原来是它的接收缓冲区太小,数据一多就溢出。解决办法很简单:加大缓冲区,或者降低发送频率。

2.5 帧间隔——"喘口气,歇一歇"

帧间隔,就是两帧之间的空闲时间。CAN协议规定,每发完一帧,必须等3个隐性位才能发下一帧。

帧间隔分两部分:

  • 间歇场:3个隐性位。
  • 总线空闲:任意长度的隐性位,直到有节点开始发SOF。

你想想看,如果没有帧间隔,总线上的数据帧一个接一个,接收节点根本来不及处理。这3个隐性位,就是给节点一个"喘息"的机会。

嗯,这里要注意:被动错误节点在帧间隔之后,还要多等8个隐性位(挂起传输场)才能发数据。这是为了防止错误节点频繁干扰总线。

2.6 实战总结:五种帧的关系

咱们用一张表来总结一下:

帧类型 作用 关键特征 常见问题
数据帧 发送数据 RTR=0,有数据段 ACK无应答、CRC错误
远程帧 请求数据 RTR=1,无数据段 DLC不匹配
错误帧 通知错误 6个连续相同位 位时序问题、晶振偏差
过载帧 流量控制 6个显性位 接收缓冲区溢出
帧间隔 帧间隔离 3个隐性位 被动错误节点需额外等待

最后说一句:搞懂这五种帧,CAN协议你就掌握了80%。剩下的20%是位时序、同步、滤波器这些细节。别急,咱们后面慢慢聊。

下一章,我会带大家深入位时序与同步,这可是CAN总线稳定运行的"心脏"。到时候我会分享一个我当年调试位时序的惨痛经历,保证让你印象深刻。