2. CAN协议帧结构:五种帧类型的深度解析
各位工程师朋友,咱们今天来啃一块硬骨头——CAN总线的帧结构。说实话,我刚入行那会儿,看着这五种帧类型也是头大。但后来在项目里被坑过几次,才真正理解了它们的重要性。你想想看,如果连报文长什么样都搞不清楚,那诊断协议UDS更是无从谈起。
CAN总线上一共就五种帧:数据帧、远程帧、错误帧、过载帧、帧间隔。咱们一个一个来拆解。
2.1 数据帧——最常用的“快递员”
数据帧,说白了就是用来发送数据的。我在项目中调试ECU时,90%的时间都在跟它打交道。
一个标准数据帧(CAN 2.0A)长这样:
SOF + 11位ID + RTR + IDE + r0 + DLC + 数据段(0-8字节) + CRC + ACK + EOF
咱们拆开来看:
- SOF(Start of Frame):1个显性位,告诉总线“我要开始说话了”。
- 标识符(ID):11位(标准帧)或29位(扩展帧)。这玩意儿决定了优先级——ID越小,优先级越高。我见过新手把两个节点设成相同ID,结果总线直接瘫痪。
- RTR(Remote Transmission Request):数据帧里这一位是显性(0)。如果是隐性(1),那就是远程帧了。
- IDE(Identifier Extension):标准帧里是显性(0),扩展帧里是隐性(1)。
- r0:保留位,必须为显性。
- DLC(Data Length Code):4位,表示数据段有多少字节。范围0~8。注意,DLC可以写0~8,但超过8的数值在CAN协议里是无效的。
- 数据段:0~8字节,你想发啥就发啥。UDS诊断报文就塞在这里面。
- CRC:15位CRC校验 + 1位隐性定界符。保证数据没被干扰。
- ACK:2位。发送方发隐性,接收方如果收到正确的帧,就在ACK Slot位拉成显性。嗯,这里要注意:如果总线上没有节点应答,发送方会检测到隐性,然后重发。
- EOF(End of Frame):7个隐性位,表示帧结束。
关键点:数据帧的RTR位为0,远程帧的RTR位为1。这是区分两者的唯一标志。
2.2 远程帧——只问不拿的“侦察兵”
远程帧的结构跟数据帧几乎一模一样,唯一的区别就是RTR位为隐性(1),而且没有数据段。
远程帧的作用是:请求对方发送数据。比如节点A发一个远程帧,ID=0x123,节点B看到这个ID是自己的,就会发一个ID=0x123的数据帧回去。
我个人习惯:尽量少用远程帧。为什么?因为远程帧的优先级比同ID的数据帧低(RTR隐性位导致仲裁时输给显性位)。而且,如果多个节点同时响应同一个远程帧,总线会乱套。我在一个项目里就吃过这个亏——两个ECU同时响应远程帧,结果CRC校验失败,总线一直报错。
避坑指南:我曾经在一个OBD诊断项目中,用远程帧去请求发动机转速数据。结果发现,远程帧发出去后,目标ECU要等好几个毫秒才响应。后来改成用数据帧主动上报,延迟直接降到微秒级。所以,能不用远程帧就别用。
2.3 错误帧——总线的“交警”
错误帧是CAN总线自己产生的,用来告诉所有节点:“刚才那帧有问题,大家别用了。”
错误帧由两部分组成:
- 错误标志:6个连续相同位(显性或隐性)。
- 错误界定符:8个隐性位。
错误帧有两种:
- 主动错误帧:6个显性位。由处于“主动错误”状态的节点发出。
- 被动错误帧:6个隐性位。由处于“被动错误”状态的节点发出。注意,被动错误帧的6个隐性位可能会被其他节点的显性位覆盖。
CAN总线有错误计数机制:每个节点都有发送错误计数(TEC)和接收错误计数(REC)。当TEC或REC超过127时,节点进入“被动错误”状态;超过255时,节点进入“总线关闭”状态,彻底离线。
我记得有一次调试,一个ECU的CAN收发器坏了,不停地发错误帧。整个总线上的其他节点都被干扰,诊断通信完全中断。后来用CANalyzer一抓,发现错误帧满天飞。所以,错误帧是排查总线故障的第一线索。
2.4 过载帧——总线的“请稍等”
过载帧的作用是:告诉发送方“我忙,慢点发”。
过载帧的结构跟错误帧很像:
- 过载标志:6个显性位。
- 过载界定符:8个隐性位。
什么情况下会触发过载帧?
- 接收方内部条件没准备好(比如缓冲区满了)。
- 在帧间隔期间检测到显性位(这属于非法情况)。
说实话,我在实际项目中很少见到过载帧。因为现在的CAN控制器处理速度都很快,缓冲区也够大。但如果你在做低速CAN或者负载很高的系统,还是要注意一下。
2.5 帧间隔——总线的“休息时间”
帧间隔不是一帧,而是帧与帧之间的空闲时间。它由三部分组成:
- 间歇场:3个隐性位。
- 总线空闲:任意长度的隐性位(直到有节点开始发送)。
- 暂停发送场(仅被动错误节点):8个隐性位。被动错误节点在发送完一帧后,必须多等这8个位才能继续发送。
你想想看,如果没有帧间隔,总线上的帧会连在一起,接收方根本分不清哪里是结尾哪里是开头。所以,帧间隔是CAN总线正常工作的基础。
2.6 五种帧的关系——一张图看懂
下面我用一张SVG图来总结这五种帧的关系和流转过程:
2.7 实战经验:如何用CANalyzer抓帧分析
光看理论不够,咱们来点实战。我在调试UDS诊断时,经常用CANalyzer抓总线报文。下面是一个典型的抓包结果:
时间戳 ID DLC 数据 帧类型
0.001234 0x7DF 8 02 01 05 00 00 00 00 00 数据帧(诊断请求)
0.001567 0x7E8 8 03 01 05 41 00 00 00 00 数据帧(诊断响应)
0.002001 0x123 0 -- 远程帧(请求数据)
0.002345 0x123 8 01 02 03 04 05 06 07 08 数据帧(响应远程帧)
0.003000 -- -- -- 错误帧(CRC错误)
你看,诊断请求和响应都是数据帧。远程帧很少见,但偶尔会出现在一些老旧的ECU中。错误帧一旦出现,就要立刻排查——可能是终端电阻没接好,或者CAN收发器坏了。
小技巧:我习惯在CANalyzer里设置一个触发条件——当错误帧出现时自动暂停抓取。这样就能第一时间定位到问题帧。另外,帧间隔时间也能反映总线负载:如果帧间隔很短(小于3个位时间),说明总线快满了。
2.8 总结
五种帧结构,说白了就是CAN总线的“交通规则”。数据帧和远程帧是正常车辆,错误帧和过载帧是事故处理车,帧间隔是红绿灯。搞懂了这些,你就能读懂CAN总线上的一切通信。
我个人建议:先把数据帧吃透,因为UDS诊断报文全是用数据帧传输的。远程帧能不用就不用。错误帧和过载帧要能识别,但不用深究细节——CAN控制器会自动处理它们。帧间隔嘛,知道有这么回事就行。
嗯,这一章就到这儿。下一章咱们聊聊CAN总线仲裁机制——为什么两个节点同时发数据不会冲突?这可是CAN总线的精髓所在。
公众号:蓝海资料掘金营,微信deep3321