首页 / 资讯中心 / 文章详情

CAN总线错误帧全解析:从结构原理到现场排查的完整指南

CAN总线错误帧全解析:从结构原理到现场排查的完整指南 ★ FEATURED ARTICLE
1. 为什么要专门花一整篇聊错误帧做CAN总线的人十有八九都经历过这种场景明明按规范把波特率、采样点、终端电阻都配好了示波器挂在CAN_H和CAN_L上波形看着也像那么回事可上位机就是疯狂报错数据一帧都收不到。或者更气人的是系统跑着跑着突然丢一堆报文过一会儿自己又好了。刚开始你会怀疑时序怀疑晶振怀疑收发器芯片折腾一圈下来最后用CAN分析仪抓包一看满屏都是错误帧。很多入门资料讲CAN协议都习惯把重点放在数据帧、远程帧、位定时这些正常工作的内容上错误帧往往两三句话带过好像它是件很边缘的事。但实际做项目你会发现错误帧恰恰是诊断总线问题最锋利的刀。它本身虽是一个坏东西但坏东西只要会读就是最有价值的信息源。那这一篇我们就把错误帧彻底剥开它长什么样什么时候会被发送是怎么参与CAN总线的一整套错误检测机制的以及拿到一只错误帧之后你该如何一步步反推问题根源。先说结论错误帧不是通信故障时某个节点随机乱发的一堆垃圾电平它有着严格的时间窗口、严格的位结构、严格的触发条件。能看懂错误帧怎么产生就意味着你能提前预判很多总线上看起来很奇怪的现象。2. 错误帧的结构拆解它到底长什么样2.1 错误帧不是一帧而是两段用CAN分析仪抓过错误帧的朋友应该都有印象错误帧的波形和正常帧差异明显——正常帧的帧起始是显性位然后是ID、控制段、数据段、CRC段、ACK槽最后是7个隐性位的帧结束。而错误帧出来的时候波形是主动错误标志 隐性错误界定符这样一个组合。主动错误标志6个连续的显性位 隐性错误界定符8个连续的隐性位两个部分加起来错误帧一共占14个位时间。这里有个容易混淆的点很多人把错误帧理解成一个单独的完整报文这是不对的。准确的描述应该是——错误帧只会叠加在另一帧报文之上。它是寄生的。正常节点正在发送或接收某一帧报文的过程中某节点检测到了错误立刻在当前位的时间窗口内强行拉低总线发出6个显性位把正在传输的这帧报文打断。所以你在总线上看到的错误帧永远是伴随着一帧被中断的报文一起出现的。没有哪帧报文的正常传输会单独凭空冒出一个错误帧。2.2 错误帧的帧内结构细节把这14个位拆细一点看第一段叫错误标志是错误帧的核心。主动错误标志是6个连续的显性位。这6个位非常有讲究——它们正好违反了两个正常协议规则第一个规则是位填充规则。CAN总线规定同一电平连续出现5次之后第6位必须反相也就是必须插入一个填充位。而错误帧的6个连续显性位直接违反了这一规则让所有正在收听总线上的节点都能立刻察觉这不是合法电平序列。第二个规则是帧结束规则。正常的数据帧或远程帧帧结束是7个连续的隐性位。错误帧的6个显性位直接踩进这个区域也会被认定为违规。这两个规则上的故意违规是CAN协议的错误帧设计里最有意思的地方——错误帧不是小心翼翼地去通知出错了而是用最大力量去破坏现场确保所有节点都能看到这个异常。为什么因为CAN是广播总线任何一帧报文都要保证所有节点在同一时刻看到相同的位流。如果某个节点悄悄把错误吞掉其他节点可能就会基于不完整的数据继续往下判断这是协议完全不允许的。第二段叫错误界定符是8个连续的隐性位。它的作用是给总线一个缓冲期让所有节点在错误标志结束后有时间恢复到正常状态然后再继续传输。界定符之后总线会回到空闲状态然后之前被中断的帧会重新开始传输。这里还有个细节补充错误帧也分主动和被动两种。主动错误标志6个显性位是主动错误状态的节点发的。所谓主动错误状态就是该节点错误计数还没超限它拥有主动报错的权利。被动错误标志6个隐性位是处于被动错误状态的节点发的。被动状态的节点检测到错误时无权去拉低总线只能发出6个隐性位。由于隐性位在总线仲裁里是让步的所以被动错误帧在总线上基本是隐形的——其他节点如果正常工作是注意不到这些隐性位的。这一段的结论是看到满屏错误帧时你要数一数错误标志是显性还是隐性的。主动错误标志说明总线上有节点处于正常状态但检测到了错误被动错误标志则说明某个节点已经快坏了它快把自己闭麦了。2.3 ACK错误的特殊形态这里顺带说一下ACK错误因为它太容易和错误帧混为一谈。ACK槽位于帧的CRC段之后包含一个ACK间隙位和一个ACK界定符。发送节点在发送完ACK间隙位后把这个位释放为隐性然后等待总线上至少有一个节点拉一个显性位来回应。如果有节点正确收到了这帧报文它会在ACK间隙位期间发一个显性位发送节点接收到显性位就认为有人收到我了。如果发送节点在ACK间隙位读到的是隐性位它就知道这帧没人接收于是立刻在ACK界定符处发出主动错误帧。这就是ACK错误的来源。ACK错误的错误帧标志也是6个显性位同样会插入在正常帧的尾部。所以你在抓包工具里看到ACK错误或者错误帧有时候并不是数据本身坏了而可能只是某个接收节点没来得及同步。这个后面在排查部分再展开。3. CAN协议里的五类错误检测机制错误帧是结果这些才是原因错误帧只是症状真正触发它的是CAN协议定义的五种错误检测机制。这些机制各管一摊分别从不同角度保证总线数据的可信度。理解它们各自的触发场景你拿到一条错误帧记录时才能猜出问题大概出在哪个环节。3.1 位错误最基础的我说的不等于我听到的CAN的收发器在发送每一个位的同时也在采样总线上实际的电平。如果发送出去的位电平是显性但采样回来读到的是隐性或者反过来发送隐性却读到显性就会触发位错误ACK错误其实也是一种位错误但被单独归类了。这里要特别注意一个例外在仲裁期间当一个节点发送隐性位、另一个节点发送显性位时隐性被显性覆盖是合法的这个不算位错误。只有赢得仲裁的节点在完整发送报文的过程中如果发现自己的位被覆盖才会报位错误。所以如果你的抓包工具显示的错误类型是位错误而且集中在某几个ID的帧上多半是这几个节点自身电路有问题或者总线上存在位冲突。比如两个节点配置了相同的ID并同一时刻发送仲裁机制虽然能分胜负但如果节点软件里没有正确处理仲裁失败的重发机制也会导致一系列连锁错误。3.2 填充错误违反连续5个同电平后必须反相规则CAN协议里有位填充机制为了避免长时间的直流电平规则是发送节点在连续发送5个相同电平之后必须在第6个位插入一个反相位。接收节点在接收到5个连续相同电平后会期待第6位是反相位。如果第6位还是同相就触发填充错误。填充错误的典型触发场景往往是软件里手动拼报文时算错了位序或者某个节点的位时序配置异常导致发送出来的位流不完整。还有一种常见情况总线上有强干扰导致某个位被翻转破坏了原本合法的填充序列。从排查角度看填充错误是比较硬的错误它基本意味着总线物理层出现了不可忽略的异常很少是软件配置的小问题。3.3 CRC错误帧内容在传输中被破坏的体检报告每个CAN帧的结尾都带一个15位的CRC校验值。发送节点根据帧内所有位包括填充位之前的位流计算出CRC接收节点收到同样数据后会重新计算一次如果两个值不一致就触发CRC错误。CRC错误是五种错误里最信息量充分的一种因为它能说明这一帧数据在物理传输过程中确实有内容被改动了。不是时序问题不是同步问题是数据位实实在在被干扰了。我在项目中遇到CRC错误第一反应是去查电磁干扰来源。常见的嫌疑对象包括电机驱动的大电流线缆离CAN线太近、继电器动作瞬间的浪涌、地线没有做星形接地导致地电位跳动、总线没有采用双绞线或者双绞的绞距过差。CRC错误如果只是零星出现还可以归结为偶发干扰如果是持续大量出现那基本可以断定布线或者接地有系统性缺陷。3.4 格式错误固定位域长度不对CAN帧里有几个固定格式的位域比如CRC界定符必须是隐性位、ACK界定符必须是隐性位、帧结束必须是7个隐性位等。如果接收节点在这些固定位上读到显性电平就会触发格式错误。格式错误出现得相对少但一旦出现要优先怀疑某个节点的位时序或收发器芯片出了问题。因为固定位域的逻辑非常简单——本该隐性的地方出现了显性这不是干扰造成的偶发翻转而是发送方真的把位流搞错了或者采样点设置导致接收节点在位的边缘处读到了不确定电平。特别提醒一种场景如果总线上某个节点的采样点设置得太靠后接近位的尾部当一个长时间隐性位流结束、下一个显性位到来时接收节点可能会因为采样点刚好落在电平跳变沿附近偶尔读到错误的电平从而触发格式错误。这个问题很隐蔽因为示波器上看波形是好的只有跑起来才会随机报格式错误。3.5 应答错误前面已经提到这里说透应答错误是指发送节点在ACK间隙位未收到显性应答。它本质上也是一种位错误但协议单独归类方便定位问题方向。应答错误最常见的原因是发送节点和接收节点之间没有建立同步。比如新接入总线的节点波特率偏差过大导致它采样到的位流全是乱的自然不会有正确的应答。另一种常见情况是接收节点软件里屏蔽了该报文ID或者在滤波器配置中把这个ID滤掉了——节点根本没打算接收自然不会应答。这句话说完你可能觉得荒谬滤波器过滤掉了还会导致应答错误吗答案是如果总线上只有发送节点和这一个接收节点而接收节点把该ID过滤掉那确实是应答错误。因为CAN的应答机制是至少一个节点正确接收即算应答一个节点都不接收发送节点就会认为出错。4. 错误计数和错误状态错误帧如何记账理解了五类错误检测机制接下来必须把错误计数讲清楚。因为在CAN协议里错误帧的发送不是有错误就发一次而是受到一套闭环反馈控制的——错误会累积累积到一定程度节点会改变自己的行为状态。这个机制设计得非常精妙但也很容易让初学者不知所措。4.1 接收错误计数和发送错误计数CAN控制器内部维护两个8位的计数器接收错误计数REC和发送错误计数TEC。每个节点各自独立计数互不相同。计数规则的关键逻辑可以用一句话概括检错责任方加8被迫牵连方加1。什么意思举个例子A节点发送一帧报文B节点收到后发现CRC错误。这时B作为发现CRC错误的节点REC增加8。A作为发送节点TEC增加8因为发送出去的帧被确认出错。其他节点呢可能只加1。因为它们也接收了这帧虽然没有主动发现错误但也间接卷入了这个坏的帧传输过程。这个设计背后的逻辑是CAN协议认为总线上的错误是集体事件任何一帧出错所有节点都脱不了干系。但发现错误的一方和引发错误的一方应该承担更大的责任计数加得更多。注意这还不是最简单的部分。更关键的是当节点发出主动错误标志——也就是那个6个显性位——之后如果它发现自己的错误标志也被破坏了它的计数还会额外增加8。这是因为错误标志被破坏意味着错误风暴正在发生多个节点同时检测到错误大家都在发错误标志总线上一片混乱。协议认为这种混乱本身就是更严重的错误状态。4.2 三种错误状态主动、被动、总线关闭根据REC和TEC的数值节点会被划分到三种状态之一状态TEC条件REC条件行为表现主动错误TEC 128REC 128可正常收发检测到错误时发主动错误帧6显性位可拉低总线被动错误TEC 128 或 REC 128同上仍可收发但只能发被动错误帧6隐性位且每次发送前需要等待额外8个隐性位总线关闭TEC 255—彻底退出总线不再收发任何帧直到硬件复位或请求总线恢复被动错误状态是一个过渡状态它至少发起了80个额外隐性位后才被允许发送这个禁言机制是为了给总线上其他节点腾出空间让它们先把错误排干净。达到总线关闭状态就是节点自杀了。它不再参与任何总线活动。如果软件层不干预这个节点会一直沉默。由于路径上很多控制器默认的恢复策略是请求进入总线恢复模式所以不少工程师看到设备突然失联、过一会儿又自己出现多半就是某个节点触发了总线关闭然后经过一段时间的恢复流程重新上线。4.3 计数器的真正用途快速定位谁在搞事错误计数在项目调试中非常有用。很多CAN分析仪都支持读取节点的REC和TEC值或者直接显示节点当前错误状态。当你怀疑某个节点有故障时第一步不是去盲改电路而是把所有节点的错误计数值记录下来对比一下。正常工作的总线上各节点REC/TEC基本接近0偶发一次错误会短暂跳一下然后在正常传输成功后按规则逐次减1正常收发成功一次计数器减1。如果某个节点的REC一直在涨说明它频繁收到坏帧如果TEC一直在涨则多半是它每次发送的帧都有问题。这套记账机制的价值在于错误帧不是孤立出现的它是计数记账流程的外显。你的抓包工具里看到满屏错误帧只是表面现象背后的REC/TEC变化规律会直接告诉你该怀疑谁。5. 错误帧在总线上的实际产生过程从检测到发送的完整时间线多一层理解就多一分排查效率。我建议你用时间线的角度来看一次完整的错误帧产生过程而不是把它当成一个静态的波形。这样遇到具体问题时你能清楚地知道错误标志出现在哪个位窗口从而反推是哪一类错误。假设总线上有A、B、C三个节点A正在发送一帧数据A逐位发送B和C同步接收。此时总线上位流全部合法。当发送到数据段的某个位时不巧总线上出现一个电磁干扰尖峰把本来应该是隐性位的电平翻转成了显性位。B节点采样到这个位时发现和自己收到的CRC计算结果不一致——当然它还没收到CRC段实际上更早的时候B的位监视机制就可能察觉异常电平。B确认检测到错误后它会等待当前位结束然后在下一个位的起始处立刻发出主动错误标志也就是6个显性位。A和C同时监听到B拉低总线。A通过位监视发现自己的隐性位被覆盖成显性于是也发起错误帧。C则可能因为检测到填充错误或格式错误同样发起错误帧。这时总线上会出现多节点共同发错误标志的叠加状态。叠加的结果就是错误标志的6个显性位被拉得更坚实总线上的显性电平可能持续超过6个位时间。这正是前面提到的错误标志被破坏的情况。所有节点完成错误标志发送后各自进入8个隐性位的错误界定符阶段。这个阶段总线恢复为隐性电平节点们重新同步。错误界定符结束总线进入空闲。A节点重新开始发送刚才被中断的那帧报文。如果紧接着又有错误就再触发一轮。以上是整个过程的教科书式时间线。但你用分析仪看的时候看到的是一帧错误帧紧跟在一帧数据帧后面逻辑上它们其实是同一次传输过程的产物——错误帧打断了数据帧数据帧随后重新开始。6. 实测中的特殊场景错误风暴、被动错误节点、第13位6.1 错误风暴坏节点如何拖垮整条总线这是CAN系统中非常常见且极具破坏力的现象。当一个节点的TEC不断累积超过128进入被动错误状态后它发错误帧的行为会变弱——它只能发隐性的被动错误标志。但问题在于如果此时它还在不停地尝试发送一帧频率很高的报文比如控制循环里的周期心跳帧而且每次发送都会失败它就会陷入一个发送失败—TEC增加—继续发送—再失败的死循环。最可怕的是一个处于被动错误状态的节点如果在错误界定符之后的8个隐性位期间检测到了总线错误它会立即再次发送错误标志。由于被动节点的错误标志是隐性的它不会真的拉低总线但如果总线上有其他主动错误状态的节点也在发错误标志叠加起来就会形成持续的电平抖动让总线看似忙乱不堪。实际项目里错误风暴的典型症状是全车报文大面积丢失但用示波器看总线电平并不是完全卡死而是一堆看似不规则的窄脉冲。这种时候别急着怀疑物理层先找出那个TEC值异常高、一直沉默又一直尝试重发的节点把它断掉总线往往就能恢复。6.2 第13位问题错误帧的隐性界定符为什么会被破坏错误帧的14位结构中主动错误标志6位、隐性错误界定符8位从错误帧的起始位算起第13位和第14位是界定符的最后两个隐性位。有个老工程师总结过一种现象错误帧的第13位与错误帧本身的界定符冲突会导致错误帧之后紧接着另一帧错误帧。简单说就是如果错误标志发出后总线上还有节点因为之前的错误状态而处于错误后恢复时序的不同步阶段它在界定符的第13位附近还会认为自己在发错误帧从而又来一轮6个显性位。这会导致总线上错误帧连错误帧看着就像刷屏。这种第13位问题多发生在错误风暴阶段多个节点错误状态不同步、恢复时序不一致。处理办法没有捷径还是回到根源找到那个把计数器推到极高状态的节点。6.3 接收超载时错误帧的NRC式触发有些入门者会发现一个有趣现象在某节点接收缓冲区严重溢出的时候总线上也会出现错误帧。这是因为CAN控制器在无法再接收新报文时会主动发送一个过载帧。过载帧和错误帧在波形上看起来有点像——都包含标志位和界定符但过载帧的标志是合法的标志占据位它不触发错误计数器增加。所以如果错误帧集中在某个节点缓冲区溢出的时间点前后出现你要先排查是缓冲区溢出导致的过载帧还是真正的物理层错误。区分方法很简单——过载帧里的6个显性标志位后跟的8个隐性界定符内不会再有其他节点插入错误标志而真错误帧则可能引起多节点共同发标志。7. 拿到一只错误帧后怎么做现场排查链路纸上谈兵讲完进入最实际的部分——你在调试现场抓包工具里出现了错误帧接下来按什么顺序排查7.1 第一步确认错误类型和发生频率先不要动任何硬件把抓包工具的统计窗口打开记录以下三个指标错误帧的类型分布位错误、填充错误、CRC错误、格式错误、ACK错误各占多少错误帧是否集中在特定ID的报文上错误帧是持续出现还是偶发出现这三个指标的答案几乎能直接缩小排查范围特征指向的可能原因全是CRC错误且分散在多个ID外部电磁干扰布线问题全是ACK错误且集中在某一发送节点接收节点滤波器配置或同步问题位错误集中在同一发送节点该节点收发器驱动异常或总线接口短路错误帧偶发时间与继电器/电机动作吻合开关瞬态干扰需要加强滤波/接地错误帧持续不停且某节点计数爆表错误风暴节点主动退出前兆7.2 第二步核对波特率和采样点配置错误帧还有一个极其常见但容易被忽略的原因同一总线上有节点波特率不一致或者采样点设置不当。波特率偏差会导致接收节点在每一位的采样点处读到不稳定的电平。虽然CAN协议对位偏差有一定的容忍度通常允许±1.5%左右的总线位时钟偏差但如果两个节点的晶振各自偏差0.5%且方向相反加起来就可能超限。采样点设置也有讲究。CAN标准推荐采样点位于位的70%到80%左右。但很多开发板默认的采样点要么太靠前要么太靠后对一些容差小的收发器来说距离稍长就会出问题。排查方法把所有节点的波特率寄存器配置和采样点百分位拉出来比对同时测量每个节点实际输出的位时间确认没有偏差。这一步用示波器做最准先测出参考节点输出的显性位和隐性位的实际时长再测目标节点两者位时长相差超过2%基本就可以宣判同步失败。7.3 第三步物理层层面的逐项检查如果波特率一致错误依然是CRC或格式错误为主那就按顺序检查终端电阻总线两端是否正确各接了120欧终端电阻我见过不少人只在一端接了一个另一端空着。此时总线上反射严重长距离下会非常容易出现CRC错误。末端电阻的实际阻值用万用表测一下正常时总线两端测得的等效电阻应该在60欧左右两个120欧并联。总线极性CAN_H和CAN_L有没有接反接反的时候静态看起来波形还是有的但差分信号会呈现反过来的形态多数节点无法正确解码错误帧会大量出现。布线结构CAN要求是直线型总线从总线主干上分支出去的长度越短越好一般建议不超过1米。如果你的分支线很长会产生反射。反射叠加到正常信号上就可能造成采样错误。地线CAN收发器的地必须与所有节点地相连。地电位跳变会直接反映在CAN_H/CAN_L的共模电压上一旦收发器承受不了共模范围输出就会异常。7.4 第四步软件与配置层面的陷阱物理层查完如果还是一头雾水就需要回到软件层找原因了。常见的有某个节点的报文发送频率高到超出了总线负载能力。CAN总线的负载率建议控制在70%以下超过85%时错误重传机制会开始占有大量带宽发生雪崩效应。表面看起来就是错误帧越来越多。接收节点的验收滤波器把本应接收的帧给滤掉了导致ACK错误。这种问题最隐蔽因为滤波配置逻辑出错并不影响其他帧但发送端会一直以为没人收到。错误中断处理函数里做了耗时操作导致节点看到新错误时还在忙旧的没能及时发送错误标志。这种情况少见但在MCU主频很低的场景下确实发生过。8. 常见误区与经验总结8.1 误区一错误帧越少越好最好为零这个说法不全对。错误帧出现是坏事但一点错误都没有不代表总线健康只能说明当前负载轻、干扰小。在强干扰环境下偶发的CRC错误几乎是不可避免的。真正要关注的是错误率是否在可接受范围内以及错误发生后系统能否通过重发机制自行恢复。如果你把错误帧完全压制到零很可能你同时也在降低总线灵敏性——比如说错误检测被过度抑制或者节点错误状态恢复过快。8.2 误区二总线关闭是收发器坏了总线关闭不等于硬件故障。它只是协议层面的自我保护反应——就像人溺水时会闭气不是肺坏了是应激反应。当节点进入总线关闭状态后软件层要负责按规定的恢复时序清零TEC让节点重新参与通信。很多设备出现时好时坏的毛病其实是软件没有正确实现总线关闭恢复逻辑而不是硬件真的不可靠。8.3 误区三错误帧只和物理层有关错误帧的触发原因物理层占比确实高但软件层同样能制造错误帧。滤波配置错误、发送缓冲区溢出处理不当、加载率过高导致重传风暴这些都能让总线上出现大量错误帧。排查时应遵循先物理层后软件层的顺序但不能在物理层查到没问题后就提前收工。要是把所有错误帧都归结于干扰那等于承认自己没办法解决它——这在项目交付时是交不了差的。8.4 经验建议总结基于我的反复实践总结了三条最实用的建议第一调试CAN总线时抓包工具里同时打开错误类型统计和节点计数器的显示。错误帧类型只是表层信息节点REC/TEC数值才是底层逻辑。两者对照定位速度能快一倍以上。第二不要把错误帧抓包记录只当证据存起来就完事要带着时间戳去对比其他事件。重点看错误帧出现的时间点是否与某个开关动作、某个电机启动时刻一致。这是最廉价也最有效的一个排查入口。第三每次修改总线参数波特率、采样点、终端电阻、滤波器后都重新抓一段长时间日志而不是只看几秒钟的波形。CAN错误往往有偶发性短时间观察很容易得出一切正常的误判。CAN错误帧这个东西说难也不难——它机制清晰、规律明确、波形可见。只要你把五类错误检测机制、错误计数记账规则和错误帧波形结构这几块吃透再拿一条真实总线的抓包数据练一练很快就能建立看到错误帧就能反推问题方向的能力。真到项目联调那天这个技能会帮你省下大把熬夜排查的时间。
阅读完成 · 觉得有帮助?
咨询建站