4、CAN报文分析:标准帧与扩展帧区别、数据帧、远程帧、错误帧、过载帧、帧间隔、位填充机制

各位同学,咱们今天聊点硬核的——CAN报文。

说实话,搞UDS诊断,你天天都在跟CAN报文打交道。报文看不懂,诊断就无从谈起。我刚开始做车载项目那会儿,拿着逻辑分析仪抓了一堆波形,愣是分不清哪个是标准帧哪个是扩展帧。后来被老工程师点了一下,才恍然大悟。

今天我就把CAN报文的这些门道,掰开了揉碎了讲给你听。

4.1 标准帧 vs 扩展帧:到底差在哪?

CAN总线最早用的是标准帧,11位ID。后来发现11位不够用了,就搞了个扩展帧,29位ID。

你想想看,一辆车上几十个ECU,每个ECU又有几十个诊断服务,11位ID哪够分?

标准帧和扩展帧的区别,说白了就两点:

  • ID长度不同:标准帧11位,扩展帧29位
  • 帧格式不同:扩展帧多了IDE位和扩展ID段

我个人的习惯是:诊断通信尽量用扩展帧。为什么呢?因为UDS诊断的ID分配往往需要更多的地址空间。你想想,一个诊断请求、一个诊断响应,再加上功能寻址、物理寻址,11位ID真的捉襟见肘。

关键区别表:

特性 标准帧 扩展帧
ID位数 11位 29位
IDE位 0(显性) 1(隐性)
最大ID值 0x7FF 0x1FFFFFFF
数据场长度 0-8字节 0-8字节

嗯,这里要注意:IDE位是区分标准帧和扩展帧的关键。你在解析报文时,先看IDE位,就能知道后面该怎么读。

4.2 数据帧:最常用的报文类型

数据帧,就是用来传数据的。UDS诊断的请求和响应,全是通过数据帧来传递的。

数据帧的结构是这样的:

帧起始(SOF) + 仲裁场(11/29位ID + RTR + IDE) + 控制场(4位DLC) + 数据场(0-8字节) + CRC场 + ACK场 + 帧结束(EOF)

我在项目中遇到过一个问题:有个同事写代码,DLC(数据长度码)总是设成8,哪怕只传2个字节的数据。结果呢?总线负载率飙升,诊断响应也变慢了。

所以我的建议是:DLC一定要跟实际数据长度匹配。传多少字节,DLC就设多少。别浪费总线带宽。

4.3 远程帧:问而不答?

远程帧,说白了就是「请求数据」的帧。它没有数据场,只有ID和RTR位。

RTR位是啥?就是远程发送请求位。数据帧的RTR=0,远程帧的RTR=1。

远程帧的应用场景不多,但在某些诊断协议里,会用远程帧来查询ECU的状态。我个人不太推荐在UDS诊断里用远程帧,因为UDS本身就有完善的请求-响应机制,没必要再用远程帧来添乱。

小技巧: 如果你在总线上看到RTR=1的帧,别慌。它只是在问「你有没有数据要发给我?」而已。

4.4 错误帧:总线上的「警报」

错误帧,是CAN节点发现自己出错时主动发出的。它由错误标志和错误界定符组成。

错误帧有两种:

  • 主动错误帧:6个显性位 + 8个隐性位
  • 被动错误帧:6个隐性位 + 8个隐性位

我曾经调试过一个项目,总线老是莫名其妙地出现错误帧。查了半天,发现是一个ECU的CAN收发器坏了,一直在发错误标志。嗯,那次之后我就养成了习惯:先检查硬件,再怀疑软件。

避坑指南: 错误帧出现频繁时,别急着改代码。先看看总线终端电阻对不对,CANH/CANL有没有短路,节点供电稳不稳。我曾经因为一个虚焊的终端电阻,折腾了整整两天。

4.5 过载帧:总线太忙了

过载帧,是节点告诉总线「我忙不过来了,慢点发」。它跟错误帧有点像,但含义完全不同。

过载帧由过载标志(6个显性位)和过载界定符(8个隐性位)组成。

说实话,过载帧在现在的CAN总线里已经很少见了。因为现在的CAN控制器处理速度都很快,很少会出现处理不过来的情况。但如果你在总线上看到过载帧,那就要注意了——可能是某个节点的CPU负载太高了。

4.6 帧间隔:总线的「呼吸」

帧间隔,就是两帧之间的空闲时间。它由3个隐性位组成。

为什么要有帧间隔?

说白了,就是给总线一点喘息的时间。让每个节点都能检测到总线空闲,然后公平地竞争总线使用权。

我刚开始做CAN开发时,总觉得帧间隔是浪费带宽。后来才明白,没有帧间隔,总线仲裁就会乱套。你想想看,如果两帧之间没有间隔,节点怎么知道上一帧结束了?

4.7 位填充机制:保证同步的「小聪明」

位填充,是CAN总线的一个巧妙设计。

规则很简单:连续发送5个相同位后,自动插入一个相反位

比如你连续发了5个1,那第6位就自动变成0。接收端看到这个0,就知道这是填充位,不是数据。

为什么要这么做?

因为CAN节点是靠电平跳变来同步时钟的。如果连续太多相同的位,没有跳变,节点就会失去同步。位填充保证了总线上最多5个位就会出现一次跳变。

举个例子:

你要发送的数据:11111 00000 111

位填充后的数据:111110 000001 111

注意看,填充位我用粗体标出来了。接收端收到后,会自动去掉这些填充位,还原原始数据。

嗯,这里有个坑:位填充只发生在SOF到CRC场之间。ACK场和EOF是不做位填充的。我见过有人写代码时把ACK场也做了位填充,结果总线直接报错。

小结

今天咱们把CAN报文的几种类型都过了一遍。标准帧和扩展帧的区别要记牢,数据帧是诊断的主力,远程帧少用,错误帧和过载帧要能识别,帧间隔别忽略,位填充机制要理解。

下一章,咱们会讲CAN的位时序和同步机制。到时候你会发现,今天讲的这些内容,都是理解位时序的基础。

好了,今天就到这儿。有问题随时问我。