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 错误状态转换图
下面这张图,我建议你多看几遍。它把整个错误状态机的逻辑讲得清清楚楚。
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值,它们会告诉你很多故事。