第2章:CAN协议数据链路层——CAN帧结构详解

大家好,我是老李。今天咱们来啃CAN协议里最核心的一块——数据链路层。说白了,就是CAN总线上的消息到底长什么样,怎么打包、怎么发送、怎么识别。

我记得刚入行那会儿,看CAN帧结构就像看天书。后来踩了不少坑,才慢慢摸清楚门道。今天我把这些经验掰开揉碎了讲给你听。

2.1 标准帧 vs 扩展帧:ID长度决定一切

CAN协议里,帧ID是最关键的东西。它决定了消息的优先级,也决定了谁能抢到总线。

标准帧的ID是11位,范围0x000~0x7FF。扩展帧的ID是29位,范围更大。你想想看,11位最多2048个ID,29位能到5亿多个。现在车上的ECU越来越多,标准帧有时候真不够用。

核心区别:

  • 标准帧:11位ID,IDE位=0
  • 扩展帧:29位ID,IDE位=1
  • 扩展帧比标准帧多出18位ID,帧长度也相应增加

我在项目中遇到过一件事:某次给一个商用车做网关,客户要求兼容两种帧格式。结果发现,标准帧和扩展帧虽然ID不同,但仲裁时扩展帧的优先级反而低。为什么?因为扩展帧的IDE位在仲裁场里靠后,标准帧先发完IDE=0,就已经赢了。

我的习惯:只要不是老平台,我建议直接用扩展帧。29位ID够用,而且现在主流MCU都支持。别给自己找麻烦。

2.2 数据帧:真正干活儿的帧

数据帧就是用来传数据的。它分标准数据帧和扩展数据帧,结构上就差在ID长度上。

一个完整的数据帧包含:

  • 帧起始(SOF):1位显性,告诉总线“我要发消息了”
  • 仲裁场:ID + RTR位 + IDE位
  • 控制场:保留位 + DLC(数据长度码)
  • 数据场:0~8字节,真正要传的数据
  • CRC场:15位CRC + 1位CRC界定符
  • ACK场:应答位 + 应答界定符
  • 帧结束(EOF):7位隐性

嗯,这里要注意:DLC虽然叫数据长度码,但它只能表示0~8。CAN FD出来之前,数据场最大就是8字节。我刚开始做的时候,以为DLC能设成9,结果总线直接报错。血的教训。

避坑指南:我曾经在写驱动时,把DLC设成了0,但数据场还放了4个字节。结果接收方只读到0字节,数据全丢了。记住:DLC必须和数据场实际长度一致。

2.3 远程帧:问别人要数据

远程帧,说白了就是“请求帧”。它没有数据场,只有ID和RTR位。RTR位在远程帧里是隐性(1),在数据帧里是显性(0)。

为什么要有远程帧?举个例子:发动机ECU想知道当前车速,就发一个远程帧,ID设成车速消息的ID。仪表盘收到后,就知道该发车速数据了。

但说实话,远程帧现在用得越来越少了。为什么?因为大部分系统都改成周期性发送了。你想想看,远程帧是“请求-应答”模式,效率低,还容易丢。我建议你:除非有特殊需求,否则别用远程帧。

我的经验:远程帧的RTR位是隐性,数据帧的RTR位是显性。仲裁时,数据帧永远比远程帧优先级高。所以如果你用远程帧,一定要确保数据帧能及时响应。

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

错误帧是CAN协议里最智能的设计之一。它由6个显性位组成,专门用来通知总线“出错了”。

错误帧分两种:

  • 主动错误帧:6个显性位,由检测到错误的节点发出
  • 被动错误帧:6个隐性位,由错误计数器超标的节点发出

我记得有一次调试,总线莫名其妙地一直报错。用示波器一看,错误帧一个接一个。后来发现是一个节点的终端电阻焊错了,导致信号反射。嗯,硬件问题有时候比软件还难查。

避坑指南:我曾经遇到一个案例,某个节点频繁发送错误帧,导致整个总线瘫痪。后来发现是晶振频率偏差太大,导致位时序不对。所以,CAN节点的时钟精度一定要达标,尤其是高速CAN。

2.5 过载帧:总线太忙了,等等

过载帧和错误帧长得很像,也是6个显性位。但它的作用不一样:过载帧是接收方告诉发送方“我处理不过来了,你慢点”。

过载帧触发的条件:

  • 接收方内部缓冲区满了
  • 接收方处理速度跟不上总线速度

说实话,过载帧在现在的CAN系统里很少见了。为什么?因为大部分MCU的CAN控制器都有硬件FIFO,能缓存好几帧数据。除非你用的是特别老的芯片,或者总线负载特别高,否则基本碰不到过载帧。

我的建议:如果你在项目中看到过载帧,先别急着调软件。检查一下接收中断的优先级,看看是不是被其他高优先级中断抢占了太多时间。

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

帧间隔,就是两帧之间的空闲时间。它由3个隐性位组成,叫“间歇场”。

为什么要有帧间隔?因为总线需要时间恢复隐性电平,也给其他节点一个机会去竞争总线。

帧间隔的规则:

  • 任何两帧之间必须有至少3个隐性位的间歇场
  • 如果节点进入被动错误状态,间歇场之后还要加8个隐性位的“挂起传输”

嗯,这里有个细节:帧间隔不是固定的。如果总线一直空闲,节点可以连续发送。但一旦有节点发送了帧,就必须等3个隐性位才能发下一帧。

总结一下:

帧类型 作用 关键特征
数据帧 传输数据 有数据场,0~8字节
远程帧 请求数据 无数据场,RTR=1
错误帧 通知错误 6个显性位
过载帧 请求延迟 6个显性位
帧间隔 总线空闲 3个隐性位

好了,这一章的内容就到这儿。CAN帧结构是基础中的基础,你把它吃透了,后面学CAN FD和CANopen就轻松多了。下一章我们讲CAN FD,那个数据场能到64字节,爽得很。

记住:纸上得来终觉浅,绝知此事要躬行。找个开发板,用示波器抓几帧看看,比看十遍书都管用。