3、CAN远程帧与错误帧:远程帧的作用、错误帧的触发机制、错误主动与错误被动状态
好,咱们接着聊。前面几章把数据帧和遥控帧的基本格式讲透了,这一章我重点说说两个容易被忽视、但实际项目中特别容易踩坑的东西——远程帧和错误帧。
说实话,远程帧在日常开发中用得不算多,但一旦用上,很多人就搞不明白。错误帧呢?嗯,这玩意儿你不想见它,但它总是不请自来。我刚开始做TCU的时候,就被错误帧折腾得够呛。
3.1 远程帧:它到底想干嘛?
远程帧,也叫遥控帧。说白了,它的作用就一句话:请求数据。
你想想看,CAN总线上那么多节点,每个节点都有自己的数据。但有时候,一个节点并不想一直往外发数据,它只想在需要的时候,跟别人说一声:“嘿,把你那个数据给我发一下。” 远程帧干的就是这个活儿。
远程帧的核心特征:
- 没有数据场(Data Field),长度固定为0
- RTR位为隐性(1),这是它和数据帧最明显的区别
- ID决定了它请求的是哪个节点的数据
我举个例子。在TCU里,发动机转速信号一般是发动机ECU周期性发送的。但假如TCU想临时请求一个发动机的瞬时油耗数据,而ECU平时不主动发这个,那TCU就可以发一个远程帧,ID填油耗对应的ID。ECU收到后,就知道有人要这个数据,于是立刻发一个数据帧回去。
这里有个坑,我当年就栽过——远程帧的ID仲裁规则和数据帧完全一样。如果总线上同时出现一个远程帧和一个数据帧,且ID相同,那数据帧会赢。为什么?因为数据帧的RTR位是显性(0),远程帧是隐性(1),显性位压倒隐性位。所以,远程帧在仲裁时其实是“弱势群体”。
我的经验: 我个人习惯,尽量少用远程帧。能用周期性发送解决的,就别搞“请求-应答”模式。因为远程帧一旦丢失,或者应答节点没来得及处理,整个通讯就可能卡住。我曾经在一个项目中,远程帧请求超时导致TCU误判传感器故障,查了两天才找到原因。
3.2 错误帧:总线上的“警报器”
错误帧,顾名思义,就是总线出问题的时候,节点主动发出来的一个“警报”。它不是一个正常通讯的帧,而是节点检测到错误后,用来通知其他节点的。
错误帧的结构很简单,就两部分:
- 错误标志(Error Flag): 6个连续的显性位(主动错误)或6个连续的隐性位(被动错误)
- 错误界定符(Error Delimiter): 8个连续的隐性位
你可能会问:“为什么是6个显性位?” 嗯,这是协议设计的一个巧妙之处。正常数据帧里,位填充规则不允许出现连续6个相同电平。所以,一旦总线上出现6个连续的显性位,所有节点都知道——出事了。
3.3 错误帧是怎么触发的?
CAN协议定义了5种错误类型。我一个个说,都是实战中常见的。
| 错误类型 | 触发条件 | 我遇到过的场景 |
|---|---|---|
| 位错误(Bit Error) | 发送节点发送的位与回读的位不一致 | 总线短路或终端电阻异常,发送0却读到1 |
| 填充错误(Stuff Error) | 连续出现6个相同电平 | 时钟漂移导致位采样偏移,误判填充位 |
| CRC错误 | 接收节点计算的CRC与发送的不一致 | 总线干扰导致数据位翻转,CRC校验失败 |
| 形式错误(Form Error) | 固定格式位(如CRC界定符)出现错误电平 | 某个节点发送了非法的隐性位 |
| 应答错误(ACK Error) | 发送节点没有收到显性ACK位 | 总线上只有一个节点,或者接收节点全部离线 |
这里我想特别说一下位错误。这是我最常遇到的。发送节点在发送一个位之后,会立即回读总线电平。如果它发的是显性0,但回读到的是隐性1,那就说明总线被其他节点拉高了,或者线路有问题。我曾经在台架上调试TCU,发现一踩油门就报位错误,最后查出来是CAN收发器的共模电感虚焊了。
3.4 错误主动与错误被动:节点的“自我救赎”
每个CAN节点内部都有两个计数器:发送错误计数器(TEC)和接收错误计数器(REC)。这两个计数器决定了节点处于什么状态。
状态分为三种:
- 错误主动(Error Active): TEC < 128 且 REC < 128。这是正常状态。节点检测到错误时,发送主动错误标志(6个显性位)。
- 错误被动(Error Passive): TEC ≥ 128 或 REC ≥ 128。节点检测到错误时,发送被动错误标志(6个隐性位)。被动节点不能主动拉低总线。
- 总线关闭(Bus Off): TEC > 255。节点彻底退出总线,不再参与任何通讯。
注意: 错误被动状态是个“灰色地带”。节点还能收发数据,但它发的错误标志是隐性的,其他主动节点可能根本不理它。我曾经在一个项目中,某个TCU节点因为线束接触不良,频繁进入错误被动状态。它自己觉得还在正常通讯,但其他节点收不到它的数据,导致整车功能紊乱。排查了三天,最后用CANoe看错误计数器才找到问题。
这里有个关键点:错误计数器不是对称的。发送成功会减1,发送失败会加8。接收成功减1,接收失败加1。所以,一个发送频繁出错的节点,TEC会涨得飞快,很快就进入总线关闭状态。
避坑指南: 我曾经在TCU的Bootloader设计中,忽略了错误计数器在刷写过程中的累积。刷写时总线负载高,偶尔出现CRC错误,TEC慢慢涨到128以上,节点进入被动状态,导致后续刷写超时。后来我在刷写前强制复位错误计数器,问题解决。
3.5 小结一下
远程帧和错误帧,一个主动请求,一个被动报警。远程帧用好了可以节省总线带宽,但用不好就是通讯隐患。错误帧呢,它其实是CAN总线自我修复机制的一部分。你不需要害怕它,但一定要理解它的触发逻辑和状态转换。
嗯,下一章我会讲CAN总线仲裁机制,那才是真正决定谁先说话的关键。到时候咱们再细聊。