4. CAN错误处理:错误类型、错误计数器、错误状态机与总线关闭
说实话,很多工程师做CAN节点,功能调通了就以为万事大吉。结果一上现场,总线动不动就掉线,节点莫名其妙就“死”了。我早年吃过这个亏——一个电机驱动节点,在实验室跑得好好的,到客户产线上每隔两小时就离线一次。查了三天,最后发现是错误处理机制没配好,节点把自己关总线外面了。
这一章,咱们就把CAN错误处理这块硬骨头啃下来。你搞懂了错误类型、计数器、状态机,才算真正入了CAN的门。
4.1 错误类型:CAN总线上的“五宗罪”
CAN协议定义了五种错误。任何节点检测到其中一种,就会立刻发送错误帧。我习惯把这五种错误分成两类:格式错误和内容错误。
| 错误类型 | 检测位置 | 触发条件 | 分类 |
|---|---|---|---|
| 位错误(Bit Error) | 发送节点 | 发送位与总线电平不一致(仲裁场和应答间隙除外) | 内容错误 |
| 填充错误(Stuff Error) | 所有节点 | 连续6个相同电平位出现 | 格式错误 |
| CRC错误(CRC Error) | 接收节点 | 计算CRC与接收CRC不匹配 | 内容错误 |
| 格式错误(Form Error) | 所有节点 | 固定格式位(CRC界定符、ACK界定符、EOF)电平错误 | 格式错误 |
| 应答错误(ACK Error) | 发送节点 | 发送节点在ACK槽未检测到显性位 | 内容错误 |
4.2 错误计数器:两个“记分牌”
每个CAN节点内部有两个硬件计数器:发送错误计数器(TEC)和接收错误计数器(REC)。它们不是软件变量,是CAN控制器硬件自动维护的。你读寄存器就能拿到值。
计数的规则,我总结成一句话:谁犯错谁加分,别人犯错你减分。具体规则如下:
- 发送节点检测到位错误、ACK错误、格式错误 → TEC加8
- 发送节点检测到填充错误、CRC错误 → TEC加8(但如果是发送节点自己填充或CRC算错,也是加8)
- 接收节点检测到错误 → REC加1
- 节点主动发送错误标志 → TEC加8
- 节点作为接收者,成功收到一帧无错误报文 → REC减1(前提是REC > 0)
- 节点作为发送者,成功发送一帧无错误报文 → TEC减1(前提是TEC > 0)
你想想看,这个机制其实很巧妙。发送节点犯错扣分重,接收节点犯错扣分轻。因为发送节点对总线的影响更大。我曾经在调试一个多主站系统时,发现某个节点的TEC一直在128附近徘徊,但REC几乎为0。这说明它一直在尝试发送,但总线上有其他节点在干扰它的报文。
4.3 错误状态机:三个“等级”
CAN控制器根据TEC和REC的值,把节点划分为三种状态。这就是CAN错误状态机。我习惯把它画成一个三级台阶:
三种状态的行为差异,我用一个表格给你说清楚:
| 状态 | 错误标志 | 对总线的影响 | 恢复条件 |
|---|---|---|---|
| 错误主动 | 主动错误标志(6个显性位) | 会破坏其他节点的报文,强制终止当前通信 | TEC和REC都降到127以下 |
| 错误被动 | 被动错误标志(6个隐性位) | 不干扰总线,但发送的报文可能被其他节点忽略 | TEC和REC都降到127以下 |
| 总线关闭 | 无 | 完全离线,不参与任何总线活动 | 检测到128个连续总线空闲位(11个隐性位) |
4.4 总线关闭:最严重的惩罚
总线关闭是CAN节点能遇到的最严重状态。TEC达到256(注意,不是255,是超过255)时触发。一旦进入这个状态,节点就像被踢出群聊一样,完全无法参与总线通信。
恢复机制很有意思:节点必须检测到128次连续11个隐性位(即总线空闲状态)。这128次不需要连续出现,但每次检测到11个隐性位算一次,累计128次后自动恢复。恢复后,TEC和REC都清零,节点回到错误主动状态。
我建议你在设计节点时,一定要考虑总线关闭后的处理策略:
- 自动恢复:默认行为,节点自己恢复。适合大多数场景。
- 软件干预恢复:通过复位CAN控制器或写寄存器手动恢复。适合需要记录故障日志的场景。
- 硬件复位恢复:通过外部看门狗或复位引脚强制恢复。适合无人值守的系统。
4.5 实战:如何读取错误计数器
以STM32的bxCAN为例,读取TEC和REC很简单:
// 读取发送错误计数器
uint8_t tec = CAN->ESR & CAN_ESR_TEC_MASK;
// 读取接收错误计数器
uint8_t rec = (CAN->ESR >> 16) & CAN_ESR_REC_MASK;
// 读取错误状态
uint8_t state = (CAN->ESR >> 4) & 0x03;
// 0: 错误主动
// 1: 错误被动
// 2: 总线关闭
我一般在主循环里每100ms读一次这两个计数器,通过串口打印出来。调试时特别有用——你能直观看到节点在“犯错”和“恢复”之间来回摆动。
嗯,CAN错误处理这块,说白了就是一套“犯错→记分→惩罚→恢复”的闭环机制。你理解了计数器的加减规则,看懂了状态机的跳转条件,就能在节点出问题时快速定位。别等到现场总线崩了才去翻手册——调试阶段就把错误计数器打印出来,养成习惯。