第2章:CAN协议基础:CAN协议分层、CAN报文帧格式

各位工程师朋友,大家好。今天我们聊聊CAN协议的基础。说实话,很多刚入行的朋友一上来就盯着波特率、终端电阻这些参数调,结果出了问题根本不知道从哪查起。我个人习惯是,先把协议本身吃透,再去碰硬件。这一章,我们就从CAN协议的分层结构和五种报文帧格式说起。

2.1 CAN协议的分层结构

CAN协议本身其实不复杂,但它分了两层:物理层数据链路层。你想想看,这就像寄快递——物理层是快递车和公路,数据链路层就是包裹上的面单和打包规则。

  • 物理层:负责信号的传输,比如差分电压、位时序、同步。说白了,就是0和1怎么在CAN_H和CAN_L两根线上跑起来。
  • 数据链路层:负责组帧、仲裁、错误检测、应答。这一层决定了谁能发、发什么、发错了怎么办。

我在项目中遇到过一位同事,他调CAN通信死活不通,最后发现是物理层的位采样点设置不对。嗯,这里要注意:物理层出问题,数据链路层再牛也白搭。

2.2 CAN报文帧格式概览

CAN总线上跑的数据,我们叫它“报文”。一共有五种帧类型:

帧类型 用途 谁发
数据帧 发送数据 发送节点
远程帧 请求数据 接收节点
错误帧 报告总线错误 检测到错误的节点
过载帧 请求延迟发送 接收节点(忙时)
帧间隔 帧与帧之间的分隔 总线空闲

我个人建议,先把数据帧和远程帧搞明白,这两个是日常开发中最常见的。错误帧和过载帧属于“异常处理”,帧间隔则是总线的“呼吸节奏”。

2.3 数据帧(Data Frame)

数据帧是CAN总线上最常用的帧。它负责把数据从一个节点传到另一个节点。数据帧又分两种格式:标准帧(11位ID)扩展帧(29位ID)

一个完整的数据帧包含以下几个段:

  • 帧起始(SOF):1个显性位,告诉总线“我要开始发了”。
  • 仲裁段:包含ID和RTR位。标准帧11位ID,扩展帧29位ID。RTR位用来区分数据帧(显性)和远程帧(隐性)。
  • 控制段:包含IDE位、保留位和DLC(数据长度码)。DLC告诉你后面跟了多少字节数据,范围0~8。
  • 数据段:0~8字节的数据。这是真正要传的内容。
  • CRC段:15位CRC校验码+1位CRC界定符。用来检查数据有没有传错。
  • ACK段:1位ACK槽+1位ACK界定符。接收节点如果正确收到,会在ACK槽发显性位应答。
  • 帧结束(EOF):7个隐性位,表示帧结束。

重点记忆:数据帧的仲裁段决定了总线的优先级。ID越小,优先级越高。我在调试多节点通信时,经常用这个特性来保证关键报文不被抢断。

2.4 远程帧(Remote Frame)

远程帧说白了就是“请求帧”。一个节点想从另一个节点拿数据,就发一个远程帧。远程帧和数据帧的结构几乎一样,唯一的区别是:远程帧没有数据段,而且RTR位是隐性(1)。

举个例子:ECU_A想知道ECU_B的当前车速,ECU_A就发一个远程帧,ID填车速对应的ID。ECU_B收到后,就会发一个数据帧回来。

避坑指南:我曾经在项目中遇到一个bug,远程帧的DLC设置错了,导致接收节点不知道要回多少字节的数据。记住:远程帧的DLC必须和期望返回的数据帧的DLC一致,否则对方可能不回数据。

2.5 错误帧(Error Frame)

错误帧是CAN总线自我保护的机制。任何一个节点检测到错误,就会立刻发送错误帧,通知其他节点“刚才那帧有问题,别用了”。

错误帧由两部分组成:

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

错误帧有主动和被动两种模式。主动错误节点发6个显性位,被动错误节点发6个隐性位。嗯,这里要注意:如果一个节点频繁发错误帧,它可能会从主动错误状态变成被动错误状态,甚至进入总线关闭状态。

警告:我曾经调试过一个项目,总线莫名其妙频繁报错。最后发现是一个节点的CAN收发器供电不稳,导致它不断发错误帧,把整个总线都拖垮了。所以,遇到总线错误,先查硬件供电和终端电阻。

2.6 过载帧(Overload Frame)

过载帧的作用是“请求等一下”。当一个节点太忙,处理不过来时,它可以发过载帧,让发送节点等一等再发。

过载帧的结构和错误帧很像:

  • 过载标志:6个显性位。
  • 过载界定符:8个隐性位。

过载帧在实际项目中用得不多。我做了这么多年,也就碰到过一两次。一般出现在节点CPU负载过高,或者中断响应不及时的情况下。

2.7 帧间隔(Interframe Space)

帧间隔不是真正的“帧”,它是帧与帧之间的空闲时间。说白了,就是总线喘口气的时间。

帧间隔包含:

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

对于被动错误节点,帧间隔还会多一个“挂起传输”段(8个隐性位)。这是为了让被动错误节点在发完一帧后多等一会儿,避免它抢总线。

总结一下:五种帧格式,数据帧和远程帧是“干活”的,错误帧和过载帧是“处理异常”的,帧间隔是“休息”的。你只要把数据帧的结构记熟,其他帧基本都能触类旁通。

好了,这一章的内容就到这里。下一章我们聊聊CAN的位时序和同步,这可是调通物理层的关键。有什么问题,欢迎在群里交流。