4. CAN错误帧与错误处理:位错误、填充错误、CRC错误、格式错误、应答错误、错误状态机(主动/被动/总线关闭)
大家好,我是老周。今天我们来聊聊CAN总线里一个特别“硬核”的话题——错误处理。
说实话,很多工程师做CAN开发,能收发报文就觉得万事大吉了。但一旦上了车,跑起来,各种稀奇古怪的问题就来了。报文丢了、总线挂了、节点莫名其妙“失联”了……
这些问题的根源,十有八九都出在错误处理机制上。CAN协议之所以能在工业、汽车领域“横行霸道”这么多年,靠的就是这套极其健壮的错误检测与恢复机制。今天,我就把这套机制掰开了、揉碎了,讲给你听。
4.1 错误检测的五种“武器”
CAN协议定义了五种错误检测方式。它们就像五个哨兵,时刻盯着总线上的每一个比特。任何一个哨兵发现问题,就会立刻触发错误帧。
| 错误类型 | 检测层级 | 检测原理 | 个人经验 |
|---|---|---|---|
| 位错误 | 发送器 | 发送器监控总线电平,若与自己发送的不一致,则报错 | 最常见,硬件驱动能力不足或总线阻抗不匹配时频发 |
| 填充错误 | 接收器 | 检测到连续6个相同电平的位,违反位填充规则 | 干扰导致同步丢失时容易出现 |
| CRC错误 | 接收器 | 接收方计算的CRC校验和与发送方的不一致 | 数据完整性被破坏,硬件或线缆问题居多 |
| 格式错误 | 接收器 | 检测到固定格式位(如CRC界定符、ACK界定符)为显性 | 协议栈实现bug或节点时序偏差 |
| 应答错误 | 发送器 | 发送器在ACK槽未检测到显性位 | 总线上没有其他节点接收,或接收节点全部故障 |
4.1.1 位错误
这个我太熟了。发送器在发送每个比特的同时,会去读总线上的电平。如果读回来的和自己发出去的不一样,那就说明出问题了。比如你发了个显性位(0),但总线电平却是隐性的(1),那肯定是别的节点在跟你“抢”总线,或者你的驱动器根本没把总线拉下去。
4.1.2 填充错误
CAN协议规定,连续发送5个相同电平后,必须插入一个相反电平的位。这叫“位填充”。接收器如果检测到连续6个相同电平,就知道填充规则被破坏了。
为什么会这样?说白了,是为了保证总线有足够的跳变沿,方便所有节点同步时钟。如果长时间没有跳变,节点的时钟漂移就会累积,最终导致采样错误。
4.1.3 CRC错误
CRC(循环冗余校验)是数据完整性的最后一道防线。发送器会为数据场计算一个15位的CRC校验和,放在CRC场里。接收器收到后,用同样的算法重新算一遍。如果对不上,那就是CRC错误。
嗯,这里要注意:CRC错误只由接收器报告。发送器不会知道自己发的CRC错了。
4.1.4 格式错误
CAN帧里有些位是固定格式的,比如CRC界定符、ACK界定符、EOF(帧结束)等。这些位必须是隐性电平(1)。如果接收器在这些位置检测到显性电平(0),就会报格式错误。
我个人习惯把格式错误看作是“协议层面的语法错误”。出现这种错误,多半是节点时序有问题,或者协议栈实现有bug。
4.1.5 应答错误
这个最好理解。发送器在ACK槽发送一个隐性位,然后等待总线上至少有一个接收节点把它拉成显性。如果没人拉,那就是应答错误。
说白了,就是你的报文发出去了,但没人听。我遇到过一种情况:某个节点因为软件bug,把自己设置成了只听模式(Listen-Only),结果它只收不发,导致所有发给它的报文都得不到ACK,发送器一直报应答错误。
4.2 错误帧的结构
任何一个节点检测到错误,就会立刻发送错误帧。错误帧由两部分组成:错误标志和错误界定符。
- 错误标志: 主动错误节点发送6个连续的显性位,被动错误节点发送6个连续的隐性位。
- 错误界定符: 8个连续的隐性位,用于恢复总线空闲状态。
这里有个关键点:主动错误标志的6个显性位,会破坏当前正在传输的帧的位填充规则。其他节点收到这6个显性位后,也会检测到填充错误,进而发送自己的错误标志。这样一来,错误标志就会被“叠加”,总线上可能出现6到12个显性位。
4.3 错误状态机:从“好人”到“黑户”
CAN节点不是一报错就“死”的。它有一套非常精妙的状态机,根据错误严重程度,逐步限制自己的行为。这套状态机有三个状态:主动错误、被动错误和总线关闭。
4.3.1 主动错误状态
这是节点的“正常”状态。在这个状态下,节点检测到错误后,会发送主动错误标志(6个显性位)。这个标志足够强势,可以打断任何正在进行的通信。
说白了,主动错误节点是个“暴脾气”,发现问题就立刻拉总线,让所有人都知道。
4.3.2 被动错误状态
当节点的发送错误计数器(TEC)超过127时,它会进入被动错误状态。在这个状态下,节点检测到错误后,只能发送被动错误标志(6个隐性位)。
你想想看,6个隐性位能干什么?它不会影响总线电平,其他节点根本感觉不到。所以,被动错误节点虽然知道自己错了,但它没有能力去打断别人。它只能默默等待当前帧结束,然后重试。
4.3.3 总线关闭状态
这是最严重的状态。当TEC超过255时,节点会进入总线关闭状态。在这个状态下,节点完全与总线断开,既不发送也不接收任何报文。
我曾经在一个项目中,遇到一个ECU(电子控制单元)频繁进入总线关闭状态。查到最后,发现是它的CAN收发器电源纹波太大,导致发送数据时经常出错。TEC一路飙升,直到超过255,节点就“自闭”了。
要恢复,只能等硬件复位,或者等待协议规定的128个总线空闲信号出现。嗯,说白了,就是让节点“冷静”一段时间。
4.4 错误处理的实际影响
这套错误处理机制,保证了CAN总线在恶劣环境下的可靠性。但如果你不了解它,它也会给你带来很多麻烦。
- 总线利用率下降: 频繁的错误帧和重传,会占用大量总线带宽。
- 节点“失联”: 总线关闭的节点,就像人间蒸发一样,你发什么它都不回。
- 故障扩散: 一个节点的错误,可能导致其他节点也检测到错误,形成“雪崩效应”。
好了,关于CAN的错误帧与错误处理,我就讲到这里。这套机制是CAN协议的“灵魂”所在。理解了它,你才算真正入门了CAN总线开发。下次遇到总线问题,别慌,先看看错误计数器,再分析错误类型,问题往往就能迎刃而解。