错误帧结构:主动错误标志、被动错误标志、错误分隔符
错误帧的结构其实不复杂,但很多新手一看到那堆“标志位”“分隔符”就懵了。我刚开始学CAN的时候也是这个感觉。说白了,错误帧就是节点发现自己或别人出错时,立刻往总线上发的一串特殊电平。它只有两个成员:错误标志和错误分隔符。根据节点的错误状态不同,错误标志又分为主动和被动两种。记忆起来很简单——主动的时候“强势”,被动的时候“怂”。
主动错误标志
如果一个节点处于主动错误状态,它检测到错误时,会发出连续6个显性位。这6个显性位会覆盖总线上其他节点的任何电平,相当于强行喊停。
- 宽度:6位
- 总线电平:全部显性(逻辑0)
- 效果:强制破坏当前帧,让所有节点都看到总线异常
- 发送者:处于主动错误状态的节点
你想想看,为什么是6位?CAN规范就是这么定的。6个连续显性位在任何正常帧里都不会出现(正常帧最多5个连续显性位+填充位),所以其他节点一看到6个显性位,就知道出错了。我在项目中遇到过一例:一个ECU因为供电不稳,偶尔进入总线关闭状态,但恢复后主动错误标志发得太猛,直接把整个CAN网络打瘫痪——幸亏有示波器抓到了这6个显性位波形,不然真不知道是哪个节点在搞鬼。
被动错误标志
如果节点处于被动错误状态,它检测到错误时,就会发出连续6个隐性位。注意,隐性位不强制拉低总线,所以其他节点如果还在发显性位,被动错误标志就根本“盖不住”它们。说白了,被动节点已经没资格强势打断总线了。
- 宽度:6位
- 总线电平:全部隐性(逻辑1)
- 效果:只有总线同时没有被其他节点驱动显性时,其他节点才能识别到这个错误
- 发送者:处于被动错误状态的节点
这里有个极易踩坑的地方:被动错误标志本身是隐性的,但如果另一个主动节点也在发显性位,被动标志就会被覆盖掉。所以被动节点发完6个隐性位后,必须立刻释放总线,它自己的错误计数器会继续增加。我曾经调试过一个设备,总是丢帧但抓不到错误帧,后来发现是因为那个节点已经进入被动错误状态,它发的隐性错误标志被其他主动节点的高优先级帧直接覆盖了,导致我们以为没出错。解决方案是强制让这个节点离线一段时间,先复位错误计数器。
错误分隔符
错误标志发完之后,必须跟8个隐性位作为分隔符。这8个位的作用就是给所有节点一个缓冲时间,让总线恢复成隐性空闲状态,然后才能继续传下一帧。错误帧的结束没有结束帧段——分隔符就是它的结尾。
| 字段 | 位数 | 电平 | 功能 |
|---|---|---|---|
| 主动错误标志 | 6 | 显性 | 强制打断当前帧 |
| 被动错误标志 | 6 | 隐性 | 柔和提示错误(可能被覆盖) |
| 错误分隔符 | 8 | 隐性 | 收尾,让总线恢复空闲 |
关键记忆点:错误标志只有6位,分隔符固定8位隐性。无论主动还是被动,错误帧总长度都是14位。错误标志和分隔符之间没有填充位。
你可能注意到,我反复说“6个”“8个”。是的,CAN协议里这些数字都是固定的,你不需要死记硬背,但调试的时候用示波器数电平个数是最直接的诊断方法。我建议你把示波器的光标放在错误帧上,数一数显性位的连续个数——如果出现6个以上,基本就是错误标志。
对比一览:主动 vs 被动
| 特性 | 主动错误标志 | 被动错误标志 |
|---|---|---|
| 发送条件 | 节点处于主动错误状态 | 节点处于被动错误状态 |
| 电平 | 6 bit 显性 | 6 bit 隐性 |
| 对总线的影响 | 强干涉,其他节点必定检测到 | 不强制,可能被覆盖 |
| 错误计数器变化 | 发送节点 REC+8 或 TEC+8 | 发送节点 TEC+8,但接收节点不增加 |
重要警告:不要以为被动错误标志“弱”就没用。被动节点如果持续发隐性错误标志,会使自身 TEC 不断增长,直到达到255进入总线关闭状态。我曾经见过一个设计,被动错误标志发完后,软件没有及时复位计数器,结果节点直接离线,整个系统通信中断——就是因为忽略了这6个隐性位带来的计数器累加效应。
下面这张图把主动、被动以及错误分隔符的时序关系画在一起。你可以把它当作调试时的速查图。
这张图里,你一眼就能看出三个关键块的位置。主动和被动的主要区别就在前6位的电平上,后面的分隔符完全一样。调试中只要抓住前6位的显隐性,就能判断出错的节点当前处于什么错误状态。记住我前面讲的那个被覆盖的例子——如果你的示波器看到一段错误帧,前6位全是隐性,说明发这个错误帧的节点已经“虚了”,得赶紧查它的错误计数值。
小贴士:如果你用逻辑分析仪抓CAN总线,可以在触发设置里选“错误帧触发”。大部分分析仪会把错误帧单独标出来,你再看二进制数据就能很容易分出前6位和后8位。我一般会同时抓CAN_H和CAN_L差分信号,避免单端噪声误判。
最后强调一句:错误帧的结构虽然简单,但你只要记住“6+8”这个公式,再加一个“主动显性、被动隐性”的口诀,就足够应付大多数调试场景了。别小看这14个位——很多通信疑难杂症,最后都归因到错误标志引发的连锁反应上。嗯,希望你下次在示波器上看到这6个连续显性位时,能自信地说:“哦,主动错误标志,这里有个节点在发脾气。”