第三章:CAN远程帧与错误帧

大家好,我是你们的讲师。今天我们来聊聊CAN总线里两个比较特殊的话题——远程帧和错误帧。说实话,很多工程师做了好几年CAN开发,对数据帧和遥控帧门儿清,但一提到远程帧和错误帧,就开始含糊了。我当年刚入行时也是这样,总觉得远程帧没啥用,错误帧嘛,出了错自然就有了。直到我在一个BMS项目中,被远程帧和错误帧折腾得够呛……嗯,今天就把这些坑和经验,一次性讲清楚。

3.1 远程帧:它到底有什么用?

先问大家一个问题:CAN总线上,数据是怎么传输的?

通常是一个节点主动发送数据,其他节点接收。但有时候,某个节点需要“请求”另一个节点发送数据。这时候,远程帧就派上用场了。

远程帧的作用,说白了就是:一个节点向另一个节点请求数据。它本身不携带数据,只携带一个标识符(ID),告诉目标节点:“嘿,把你那个ID对应的数据发给我!”

举个例子。在BMS中,电池管理单元(BMU)可能需要从电流传感器那里获取实时电流值。BMU可以发送一个远程帧,ID设置为电流传感器的数据ID。电流传感器收到后,就会发送一个对应的数据帧回来。

核心要点:远程帧是“请求”,数据帧是“响应”。远程帧没有数据场,数据帧有数据场。

3.2 远程帧的结构

远程帧的结构,其实和数据帧非常像。我习惯把它们放在一起对比着看,这样更容易理解。

字段 数据帧 远程帧
帧起始 1位显性 1位显性
仲裁场 ID + RTR位(显性) ID + RTR位(隐性)
控制场 IDE + r0 + DLC IDE + r0 + DLC
数据场 0-8字节数据
CRC场 CRC序列 + CRC界定符 CRC序列 + CRC界定符
ACK场 ACK槽 + ACK界定符 ACK槽 + ACK界定符
帧结束 7位隐性 7位隐性

你发现关键区别了吗?对,就是RTR位(Remote Transmission Request)。

  • 数据帧的RTR位是显性(0)
  • 远程帧的RTR位是隐性(1)

就这么一位之差,决定了这个帧是“送数据”还是“要数据”。

我的小技巧:在调试时,如果你看到总线上有ID相同但RTR位不同的帧,别慌。一个可能是数据帧,另一个可能是远程帧。我曾经在分析CAN报文时,就因为没注意RTR位,把远程帧当成了数据帧,结果解析出来的数据全是0,折腾了半天才发现问题。

3.3 远程帧的避坑指南

远程帧虽然好用,但用不好就是坑。我总结了几点:

  • 不要滥用远程帧。 远程帧的优先级比同ID的数据帧低(因为RTR位是隐性)。如果你频繁发送远程帧,可能会影响总线上其他高优先级报文的传输。
  • 注意DLC的设置。 远程帧的DLC(数据长度码)必须与对应数据帧的DLC一致。比如你请求一个4字节的数据,远程帧的DLC就要设为4。否则,目标节点可能不知道要发多少数据。
  • 避免远程帧风暴。 如果一个节点没有及时响应远程帧,发送节点可能会不断重发。这会导致总线负载飙升。我在一个项目中就遇到过这种情况,一个传感器偶尔死机,BMU就疯狂发远程帧,结果总线直接被堵死。后来我加了一个超时重试机制,才解决了问题。

警告:在BMS中,远程帧通常用于请求关键数据(如电压、电流、温度)。但请记住,远程帧本身不携带数据,所以它不能用于传输紧急信息。紧急信息请使用数据帧,并设置高优先级ID。

3.4 错误帧:CAN总线的“自我修复”机制

接下来聊聊错误帧。CAN总线之所以可靠,很大程度上归功于它的错误检测和处理机制。当任何一个节点检测到总线错误时,它就会发送一个错误帧,通知其他节点:“出问题了,大家注意!”

错误帧的结构很简单,就两个部分:

  • 错误标志(Error Flag): 6个连续的显性位(主动错误)或6个连续的隐性位(被动错误)。
  • 错误界定符(Error Delimiter): 8个连续的隐性位。

你可能会问:“为什么是6个显性位?” 嗯,这是因为CAN总线规定,任何节点在检测到错误后,都要发送6个显性位来“覆盖”正在传输的报文。这样一来,其他节点也会检测到位填充错误或格式错误,从而同步进入错误处理状态。

3.5 错误帧的两种类型:主动错误 vs 被动错误

CAN节点有三种状态:主动错误、被动错误、总线关闭。错误帧的类型,就取决于节点当前的状态。

节点状态 错误计数 错误帧类型 行为
主动错误 发送错误计数 < 127
接收错误计数 < 127
主动错误帧 发送6个显性位,积极破坏错误报文
被动错误 发送错误计数 > 127
或接收错误计数 > 127
被动错误帧 发送6个隐性位,不破坏总线
总线关闭 发送错误计数 > 255 完全脱离总线,不参与任何通信

主动错误帧:节点很“强势”,一旦发现错误,立刻发送6个显性位,强制中断当前报文。其他节点收到后,也会检测到错误,纷纷发送错误帧。最终,整个总线上的节点都会同步进入错误处理流程。

被动错误帧:节点变得“弱势”了。它虽然也检测到了错误,但只能发送6个隐性位。为什么?因为被动错误节点不能主动破坏总线,否则可能会干扰其他正常节点的通信。说白了,就是“我可能有问题,但我不能连累大家”。

关键区别:主动错误帧会“破坏”总线(发送显性位),被动错误帧不会(发送隐性位)。主动错误节点是“积极纠错”,被动错误节点是“消极避让”。

3.6 总线关闭状态:最严重的惩罚

如果一个节点的发送错误计数超过了255,它就会进入总线关闭状态。这意味着什么呢?

这个节点将完全脱离总线,不再发送任何报文,也不再接收任何报文。它就像一个被开除的球员,只能在场边看着别人比赛。

为什么会这样?因为CAN协议认为,如果一个节点频繁出错,它可能已经“坏掉了”。让它继续留在总线上,只会干扰其他节点。所以,干脆把它踢出去。

总线关闭的节点如何恢复?有两种方式:

  • 硬件复位: 重新上电或复位芯片,错误计数清零,节点重新进入主动错误状态。
  • 软件恢复: 节点在检测到128次11个连续的隐性位(即总线空闲)后,可以自动恢复。但这个过程比较慢,通常需要几十毫秒甚至更长时间。

我的经验:在BMS中,总线关闭是一个非常严重的问题。一旦某个节点(比如电池管理单元)进入总线关闭状态,整个BMS系统可能就无法正常工作。我曾经在一个项目中,因为CAN收发器的共模电压问题,导致一个节点频繁进入总线关闭状态。后来我增加了共模扼流圈,并优化了PCB布局,才彻底解决。

3.7 错误帧的实战分析

在实际调试中,如何判断总线上出现了错误帧?

用CAN分析仪抓一下波形就知道了。正常的数据帧或远程帧,波形是规整的。但错误帧出现时,你会看到一段异常的显性电平(6个位时间),然后跟着8个隐性位。这就是典型的错误帧波形。

我建议你在调试时,重点关注以下几点:

  • 错误帧的频率: 如果错误帧频繁出现,说明总线通信质量很差。可能是终端电阻没接好、线缆过长、或节点间地电位差过大。
  • 错误帧的来源: 通过分析错误帧前后的报文,可以判断是哪个节点触发了错误。通常,发送错误计数高的节点就是“罪魁祸首”。
  • 错误类型: 位错误、填充错误、CRC错误、格式错误、ACK错误。不同的错误类型,对应不同的故障原因。比如ACK错误,通常是因为总线上没有其他节点响应。

注意:不要忽视偶尔出现的错误帧。一次两次可能没问题,但如果错误帧持续出现,总线最终可能会被某个节点“拖垮”。我见过一个项目,因为一个节点的晶振偏差太大,导致位定时错误,总线上错误帧不断。最后整个系统通信瘫痪,所有节点都进入了总线关闭状态。

3.8 本章小结

好了,我们来快速回顾一下今天的内容:

  • 远程帧:用于请求数据,没有数据场,RTR位为隐性。不要滥用,注意DLC匹配。
  • 错误帧:用于错误通知,由错误标志和错误界定符组成。
  • 主动错误帧:发送6个显性位,积极破坏错误报文。
  • 被动错误帧:发送6个隐性位,不破坏总线。
  • 总线关闭:发送错误计数超过255,节点完全脱离总线。

说实话,远程帧和错误帧在平时开发中可能不常用到,但一旦遇到问题,它们就是排查故障的关键。我个人建议,大家在设计BMS通信协议时,一定要考虑错误处理机制。比如,给每个节点设置合理的错误计数阈值,以及总线关闭后的恢复策略。别等到系统崩溃了,才想起来补课。

下一章,我们会深入讲解CAN的位定时与同步。这可是CAN通信的“心脏”,搞懂了它,你就能理解为什么CAN总线能跑得又快又稳。我们下次见!