4. CAN错误处理机制:错误类型与错误状态

大家好,我是你们的讲师。今天我们来聊聊CAN总线里一个特别重要、也特别容易被忽视的话题——错误处理机制。

说实话,我刚入行那会儿,总觉得CAN通信挺稳定的,错误处理嘛,知道有这回事就行了。直到有一次,我在一个车载项目中,总线莫名其妙就“罢工”了,所有节点都发不出数据。排查了整整两天,最后发现是一个节点的CAN收发器坏了,不停地发错误帧,把整个总线给“拖死”了。从那以后,我再也不敢小看CAN的错误处理机制了。

CAN协议之所以能在工业、汽车领域这么“皮实”,靠的就是这套完善的错误检测和恢复机制。说白了,它自己就能发现错误、报告错误,还能自动恢复,不需要你额外写什么复杂的校验代码。

4.1 五种错误类型:CAN的“火眼金睛”

CAN协议定义了五种错误类型。任何一个CAN节点,只要发现其中一种,就会立刻出手干预。我们来一个一个看。

错误类型 检测时机 通俗理解
位错误 发送节点发送时 我发的是1,但总线上读回来是0,说明出问题了
填充错误 接收节点接收时 连续5个相同位之后,没看到填充的相反位
CRC错误 接收节点接收时 我算出来的CRC和发送方的不一样
形式错误 接收节点接收时 帧格式不对,比如固定位域出现了非法电平
应答错误 发送节点发送后 我发完了,但没收到ACK应答

4.1.1 位错误

这个最好理解。发送节点在往总线上放数据的时候,它会同时“监听”总线上的电平。如果它发送的是显性位(逻辑0),但读回来是隐性位(逻辑1),那就说明总线被别的节点干扰了,或者物理层出了问题。我个人的习惯是,调试CAN通信时,如果发现位错误频繁出现,第一反应就是去查终端电阻和线束。

4.1.2 填充错误

CAN协议为了保证时钟同步,规定连续发送5个相同位之后,必须插入一个相反的位。接收节点如果发现连续6个相同位,就知道出错了。嗯,这里要注意,这个规则在CRC界定符和ACK槽这些固定位段是不适用的,别搞混了。

4.1.3 CRC错误

CRC(循环冗余校验)是数据完整性的最后一道防线。发送节点会计算一个15位的CRC值,放在帧里。接收节点收到数据后,用同样的算法再算一遍。对不上?那就是CRC错误。我在项目中遇到过,有时候CRC错误率突然升高,往往是因为总线波特率设置得不太准,或者时钟漂移导致的。

4.1.4 形式错误

CAN帧里有些位段的值是固定的,比如CRC界定符必须是隐性位,ACK界定符也必须是隐性位。如果接收节点在这些地方读到了显性位,那就是形式错误。说白了,就是帧的“格式”不对。

4.1.5 应答错误

发送节点在发送完整个帧之后,会在ACK槽等待接收节点拉低总线(显性位)来确认。如果它没等到,就认为应答错误。为什么会这样?可能是总线上根本没有其他节点,或者接收节点因为某种原因没来得及响应。

核心要点: 这五种错误类型覆盖了CAN通信的物理层、数据链路层和协议层。任何一个节点检测到错误,都会立即发送错误帧来通知其他节点。

4.2 错误状态机:从“好人”到“黑名单”

光能检测错误还不够,还得有办法管理那些“总犯错”的节点。CAN协议定义了一个三状态错误模型:主动错误、被动错误和总线关闭。

每个节点内部都有两个计数器:发送错误计数器(TEC)和接收错误计数器(REC)。这两个计数器就是节点行为的“记分牌”。

我的经验: 调试时,我经常通过读取节点的TEC和REC值来判断它当前处于什么状态。如果REC一直在涨,说明总线噪声大或者终端匹配有问题。如果TEC在涨,那多半是这个节点自己发数据有问题。

4.2.1 主动错误状态

这是节点的“正常”状态。TEC和REC都小于127。处于这个状态的节点,检测到错误后,会发送主动错误标志——也就是连续6个显性位。这个标志很“强势”,会覆盖总线上其他节点的数据,强制中断当前通信。

4.2.2 被动错误状态

当TEC或REC超过127时,节点就进入被动错误状态。这时候,节点虽然还能收发数据,但已经“怂”了。它检测到错误后,只能发送被动错误标志——连续6个隐性位。这个标志不会干扰其他节点,说白了就是“我错了,但我不影响你们”。

我曾经在一个项目中,有个节点的CAN收发器接触不良,导致它频繁进入被动错误状态。它自己发不出数据,但也不影响总线,排查起来特别隐蔽。

4.2.3 总线关闭状态

这是最严重的状态。当TEC超过255时,节点会认为自己“不配”再参与通信了,于是主动断开与总线的连接。它不再发送任何数据,也不再接收任何数据。相当于被“踢出群聊”了。

要退出总线关闭状态,节点需要检测到128次连续的11个隐性位(总线空闲序列)。嗯,这里要注意,有些硬件支持自动恢复,有些则需要软件手动复位。

避坑指南: 我曾经遇到过,一个节点频繁进入总线关闭状态,然后自动恢复,再关闭,再恢复……导致总线通信时断时续。后来发现是它的CAN控制器配置有问题,导致发送错误帧的频率过高。所以,不要完全依赖硬件自动恢复,软件层面最好也做监控和限制。

4.3 错误状态转换图

下面这张图,我建议你多看几遍。它把整个错误状态机的逻辑讲得清清楚楚。

CAN错误状态转换图 CAN 错误状态转换图 主动错误 TEC < 127, REC < 127 被动错误 TEC > 127 或 REC > 127 总线关闭 TEC > 255 错误次数增加 错误计数归零 TEC > 255 128次总线空闲序列后自动恢复 说明: 1. 主动错误节点发送“主动错误标志”(6个显性位) 2. 被动错误节点发送“被动错误标志”(6个隐性位) 3. 总线关闭节点不参与任何通信,需等待恢复

4.4 错误计数器的增减规则

这两个计数器怎么加、怎么减,是有严格规则的。我整理了一个表格,方便你对照。

事件 TEC变化 REC变化
发送节点检测到位错误 +8 不变
发送节点检测到ACK错误 +8 不变
接收节点检测到CRC错误 不变 +1
接收节点检测到填充错误 不变 +1
节点成功发送一帧 -1 不变
节点成功接收一帧 不变 -1(若REC > 0)
节点从被动错误恢复为主动错误 置为0 置为0

一个小技巧: 你看,发送错误的“代价”比接收错误高得多(一次+8 vs +1)。这是协议设计者的意图——宁可错杀一个发送有问题的节点,也不能让它污染总线。所以,如果你的节点TEC涨得很快,先检查它自己的发送逻辑。

4.5 错误帧的结构

当节点检测到错误时,它会发送一个错误帧。错误帧由两部分组成:

  • 错误标志: 主动错误是6个显性位,被动错误是6个隐性位。
  • 错误界定符: 8个隐性位,用于结束错误帧。

有意思的是,主动错误标志的6个显性位,会破坏当前帧的填充规则,导致其他节点也检测到填充错误,进而发送自己的错误标志。这样一来,总线上就会出现6到12个连续的显性位。嗯,这就是所谓的“错误叠加”现象。

4.6 总结一下

CAN的错误处理机制,说白了就是一套“自我诊断、自我隔离”的系统。它通过五种错误类型覆盖了通信的方方面面,又通过三状态错误模型来管理节点的“健康度”。

我个人觉得,理解这套机制,是深入掌握CAN协议的关键一步。你想想看,一个网络协议能自己发现错误、自己报告错误、还能把“捣乱”的节点踢出去,这设计得多巧妙。

好了,这一章的内容就到这里。记住,下次调试CAN总线时,别忘了看看节点的TEC和REC值,它们会告诉你很多故事。