第2章:CAN协议详解——数据帧、远程帧、错误帧、过载帧与帧间隔

大家好,我是老张。今天咱们来啃CAN协议里最核心的部分——五种帧结构。说实话,我刚入行那会儿,光看协议文档看得头大,后来在项目里亲手抓了几次波形,才真正搞明白。这一章,我就把当年踩过的坑和积累的经验,一股脑儿倒给你们。

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

数据帧,说白了就是CAN总线上最常用的消息格式。它负责把数据从一个节点送到另一个节点。你想想看,就像寄快递,总得有收件地址、发件人、包裹内容吧?CAN数据帧也一样。

标准格式的数据帧长这样:

SOF + 11位ID + RTR + IDE + r0 + 4位DLC + 0~8字节数据 + 15位CRC + CRC分隔符 + ACK槽 + ACK分隔符 + EOF

嗯,这里要注意,扩展格式是29位ID,结构稍有不同。我个人习惯把标准帧叫“短地址”,扩展帧叫“长地址”。

关键字段解读:

  • SOF(Start of Frame):一个显性位,告诉总线“我要发消息了”。
  • ID(标识符):决定消息优先级。ID越小,优先级越高。我在项目中遇到过,两个节点同时发消息,ID小的那个总能抢到总线。
  • RTR(Remote Transmission Request):数据帧里这位置0,远程帧里置1。
  • DLC(Data Length Code):数据长度,0到8字节。别问我为什么是8,这是CAN协议定死的。
  • 数据段:0~8字节,想传啥传啥。但要注意字节序,不同厂商可能不一样。
  • CRC:15位校验码,加上1位分隔符。用来检测传输错误。
  • ACK:接收节点如果正确收到,会在ACK槽里回一个显性位。发送节点会检查这个。

我的经验:调试时,我习惯先看ACK位。如果总线上没有ACK响应,八成是节点没收到或者ID没对上。我曾经花了一整天查一个bug,最后发现是CAN收发器的终端电阻没焊好。

2.2 远程帧:问别人要数据

远程帧,说白了就是“请求帧”。一个节点想从另一个节点拿数据,就发个远程帧过去。结构跟数据帧几乎一样,区别就两点:

  • RTR位为1(隐性)
  • 没有数据段

你可能会问:“没有数据段,那DLC干嘛用的?”问得好!DLC在这里表示你期望对方返回的数据长度。比如你发个远程帧,DLC=8,对方就知道你要8字节数据。

避坑指南:我曾经在项目里犯过一个低级错误——远程帧的ID设错了。结果对方节点根本没响应,总线上一片死寂。后来抓波形才发现,ID差了一个bit。记住,远程帧的ID必须和目标数据帧的ID完全一致。

2.3 错误帧:总线的“警报器”

错误帧,是CAN总线自我保护的机制。当节点检测到错误,就会立刻发错误帧,通知所有节点“刚才那包数据有问题,别用了”。

错误帧分两部分:

  • 错误标志:6个连续显性位(主动错误)或6个连续隐性位(被动错误)
  • 错误分隔符:8个隐性位

为什么会这样?因为CAN总线采用“错误主动”和“错误被动”两种状态。主动错误的节点可以破坏总线,被动错误的节点只能默默发隐性位。

错误类型有5种:

  1. 位错误:发送节点发现总线上的电平跟自己发的不一致。
  2. 填充错误:连续5个相同电平后,没看到填充位。
  3. CRC错误:接收节点算出来的CRC跟发过来的对不上。
  4. 格式错误:固定格式的位(比如CRC分隔符)不是隐性。
  5. ACK错误:发送节点没收到ACK响应。

我记得有一次,客户反馈说总线偶尔会“卡死”。我抓了一整天波形,发现是某个节点在不停发错误帧。最后查出来,那个节点的晶振频率偏了,导致位时序不对。嗯,硬件问题有时候就是这么隐蔽。

2.4 过载帧:总线说“我忙,等会儿”

过载帧,说白了就是“忙帧”。当接收节点来不及处理数据,或者总线出现某些异常条件,节点就会发过载帧,让发送节点等一等。

结构跟错误帧很像:

  • 过载标志:6个显性位
  • 过载分隔符:8个隐性位

过载帧和错误帧的区别在于:过载帧是“主动请求延迟”,错误帧是“被动报告问题”。你想想看,一个是你自己说“慢点”,另一个是系统报警“出错了”。

我的建议:如果总线上频繁出现过载帧,别急着怀疑协议栈。先看看接收节点的CPU负载是不是太高了,或者中断响应是不是太慢了。我曾经遇到过,一个节点用了个慢速的MCU,CAN中断处理不过来,结果过载帧满天飞。

2.5 帧间隔:总线的“休息时间”

帧间隔,就是两帧之间的空闲时间。CAN总线规定,每发完一帧,必须等3个隐性位才能发下一帧。这3个隐性位叫“间歇场”。

帧间隔的结构:

  • 间歇场:3个隐性位
  • 总线空闲:任意长度的隐性位(直到有节点开始发SOF)

这里有个细节:被动错误节点在间歇场之后,还要多等8个隐性位(叫“挂起传输”)。为什么?为了让主动错误节点有机会先抢到总线。

避坑指南:我曾经在写CAN驱动时,忽略了帧间隔的要求。结果两个节点连续发帧,中间没有间歇场,总线直接报错。后来查协议文档才发现,帧间隔是强制性的,不是可选的。

2.6 五种帧的对比总结

好了,咱们把五种帧放在一起对比一下:

帧类型 用途 数据段 RTR位 触发条件
数据帧 发送数据 0~8字节 0(显性) 节点主动发送
远程帧 请求数据 1(隐性) 节点主动请求
错误帧 报告错误 N/A 检测到错误
过载帧 请求延迟 N/A 接收节点忙
帧间隔 帧间分隔 N/A 每帧结束后

你想想看,这五种帧配合起来,就构成了CAN总线完整的通信机制。数据帧和远程帧负责“干活”,错误帧和过载帧负责“异常处理”,帧间隔负责“节奏控制”。

核心要点:

  • 数据帧和远程帧的ID必须一致才能配对
  • 错误帧会破坏当前传输,所有节点都要丢弃数据
  • 过载帧不会破坏数据,只是请求延迟
  • 帧间隔是强制性的,不能省略

好了,这一章就到这里。下一章咱们聊聊CAN的位时序和同步机制,那可是理解CAN通信质量的关键。到时候我会分享一个我当年调试位时序的案例,保证让你印象深刻。

课后练习:用CAN分析仪抓一段总线数据,找出里面的数据帧、远程帧和错误帧。看看它们的ID、DLC和ACK位有什么规律。我当年就是这么学的,效果比看书好十倍。

公众号:蓝海资料掘金营,微信deep3321