2. CAN协议帧结构:标准帧与扩展帧、数据帧、远程帧、错误帧、过载帧、帧间隔

好,咱们今天来啃一块硬骨头——CAN协议的帧结构。说实话,我刚入行那会儿,看着协议栈里一堆ID、DLC、CRC,头都大了。但后来我发现,只要搞懂了这几种帧是干什么的,CAN总线在你眼里就不再是黑盒子了。

CAN总线上跑的数据,说白了就五种帧:数据帧远程帧错误帧过载帧,以及帧间隔。其中数据帧又分标准帧和扩展帧。嗯,咱们一个一个来拆解。

2.1 数据帧:最常用的“快递包裹”

数据帧是CAN通信的主角。你想发一个传感器值、一个车速信号,都得用它。它就像快递包裹,把数据从发送节点送到接收节点。

数据帧的结构,我习惯把它分成七段:

  • 帧起始(SOF):一个显性位,告诉总线“我要开始发数据了”。
  • 仲裁场:包含ID和RTR位。ID决定了优先级,数字越小优先级越高。
  • 控制场:包含IDE位、保留位和DLC(数据长度码)。DLC告诉你这个帧里装了多少字节数据。
  • 数据场:0~8字节,真正的数据内容。
  • CRC场:15位CRC校验码+1位CRC界定符。用来检查数据有没有传错。
  • 应答场(ACK):接收节点如果正确收到数据,会在这里拉一个显性位作为回应。
  • 帧结束(EOF):7个隐性位,表示帧传输完毕。

重点记忆:数据帧的RTR位必须是显性(0),这是它和远程帧最核心的区别。

2.2 标准帧 vs 扩展帧:ID长度的区别

标准帧的ID是11位,扩展帧的ID是29位。为什么要有两种?

我举个例子。早期CAN总线用在汽车上,节点不多,11位ID(最多2048个不同ID)完全够用。后来车上的ECU越来越多,11位ID不够分了,于是扩展帧应运而生。

它们的区别主要体现在仲裁场:

特性 标准帧 扩展帧
ID长度 11位 29位
IDE位 显性(0) 隐性(1)
SRR位 隐性(1),替代RTR位
最大节点数 2048 5.3亿
兼容性 所有控制器都支持 需要控制器支持扩展帧

我在项目中遇到过一个问题:一个老款ECU只支持标准帧,但新设计的网关用了扩展帧。结果两者无法通信。后来我加了一个ID转换层,把扩展帧的高18位映射成标准帧的虚拟ID,才解决了问题。嗯,这里要注意:标准帧和扩展帧不能在同一总线上混用,除非你做了协议转换。

2.3 远程帧:请求数据的“挂号信”

远程帧,说白了就是“我要数据,你发给我”。它和数据帧长得几乎一样,唯一的区别是RTR位是隐性(1),而且没有数据场。

你想想看,一个节点想读取另一个节点的传感器值,它不需要自己发数据,只需要发一个远程帧,目标节点收到后就会自动回复一个数据帧。

远程帧的典型应用场景:

  • 诊断工具请求ECU的故障码
  • 主节点轮询从节点的状态
  • 网关请求特定信号值

我的经验:远程帧虽然方便,但不要滥用。我曾经在一个项目中,主节点每10ms发一次远程帧轮询所有从节点,结果总线负载率直接飙到80%。后来改成了事件触发+周期上报的混合模式,负载率降到了30%。

2.4 错误帧:总线的“交警”

错误帧是CAN总线自我纠错的核心机制。当任何节点检测到总线错误时,它会立即发送错误帧,通知所有节点“刚才那帧数据有问题,大家别用了”。

错误帧由两部分组成:

  • 错误标志:6个连续相同位(显性或隐性,取决于错误类型)
  • 错误界定符:8个隐性位

错误类型有五种:

  1. 位错误:发送节点监控总线,发现发送的位和总线上的位不一致。
  2. 填充错误:连续5个相同位后没有插入填充位。
  3. CRC错误:接收节点计算的CRC和发送的CRC不匹配。
  4. 形式错误:固定格式的位(如EOF、ACK界定符)出现错误电平。
  5. 应答错误:发送节点没有收到ACK应答。

避坑指南:我曾经调试过一个项目,总线频繁出现错误帧。查了半天,发现是一个节点的终端电阻焊错了,120欧姆焊成了12欧姆。结果信号反射严重,CRC错误频发。所以,物理层的问题往往比协议层更隐蔽

2.5 过载帧:总线的“请稍等”

过载帧的作用很简单:接收节点告诉发送节点“我忙不过来,你慢点发”。它和错误帧结构类似,但触发条件不同。

过载帧的触发条件:

  • 接收节点内部缓冲区满了,无法处理新数据
  • 接收节点检测到总线上的位填充规则被破坏(但这不是错误,只是过载)

过载帧由过载标志(6个显性位)和过载界定符(8个隐性位)组成。嗯,这里要注意:过载帧不能连续发送,两次过载帧之间必须有至少3个隐性位间隔。

2.6 帧间隔:总线的“呼吸时间”

帧间隔,就是两帧数据之间的空闲时间。它让总线上的节点有时间处理上一帧数据,并为下一帧做准备。

帧间隔由三部分组成:

  • 间歇场:3个隐性位
  • 总线空闲:任意长度的隐性位,直到有节点开始发送
  • 暂停发送场(仅被动错误节点):8个隐性位,让被动错误节点有更多时间恢复

为什么要有帧间隔?你想想看,如果节点连续发帧,接收节点可能来不及处理。帧间隔就像给总线一个“喘息”的机会。

实战要点:在OBD通信中,诊断请求和响应之间必须满足帧间隔要求。我见过一个案例,诊断仪连续发送请求帧,没有留帧间隔,结果ECU直接进入了bus-off状态。所以,写代码时一定要在发送循环中加入帧间隔延时

2.7 总结:五种帧的对比

帧类型 用途 数据场 RTR位 优先级
数据帧 发送数据 0~8字节 显性(0)
远程帧 请求数据 隐性(1)
错误帧 报告错误 N/A 最高
过载帧 请求延迟 N/A
帧间隔 总线空闲 N/A 最低

我个人习惯,在调试CAN总线时,先用逻辑分析仪抓一帧数据,看看是标准帧还是扩展帧,RTR位是0还是1。这能快速判断通信是否正常。记住一句话:数据帧干活,远程帧要活,错误帧报警,过载帧喊停,帧间隔休息。搞懂了这五种帧,CAN协议你就入门了。