第1章:CAN总线数据帧详解

各位同学好,我是老张。今天咱们来聊聊CAN总线数据帧。说实话,这玩意儿我刚开始接触的时候也觉得挺枯燥的,不就是一堆0和1嘛。但后来在项目里吃过亏,才明白这些细节有多重要。

先问大家一个问题:你想想看,CAN总线上那么多节点,它们怎么知道哪条消息是发给自己的?又怎么保证数据不出错?答案就在数据帧的结构里。

1.1 标准帧与扩展帧

CAN总线有两种帧格式:标准帧和扩展帧。说白了,区别就在ID的长度上。

  • 标准帧:11位ID,最早期的CAN 2.0A规范
  • 扩展帧:29位ID,CAN 2.0B规范引入

我个人习惯在项目里优先用标准帧,除非节点数量真的很多。为什么?因为标准帧的仲裁场更短,总线利用率更高。我曾经在一个项目里,客户非要全部用扩展帧,结果总线负载率飙到80%以上,后来改成标准帧才降到60%。

关键区别:标准帧和扩展帧的ID长度不同,但数据场长度都是0-8字节。扩展帧的29位ID由11位基本ID和18位扩展ID组成。

1.2 数据帧结构

一个完整的数据帧,从开始到结束,一共7个场。我按顺序给大家捋一遍:

1.2.1 SOF(帧起始)

就1个显性位(逻辑0)。它告诉所有节点:注意了,我要开始发消息了!

1.2.2 仲裁场

这里包含ID和RTR位。标准帧是11位ID + 1位RTR,扩展帧是29位ID + 1位SRR + 1位IDE + 1位RTR。

嗯,这里要注意:仲裁场决定了消息的优先级。ID越小,优先级越高。我在调试一个电机控制系统时,就遇到过两个节点同时发消息,结果优先级低的那个一直发不出去,电机直接卡死。后来把紧急消息的ID设成0x001,问题就解决了。

1.2.3 控制场

标准帧是6位:IDE + r0 + DLC(4位)。扩展帧是6位:r1 + r0 + DLC(4位)。

DLC表示数据长度,范围0-8。注意,DLC可以设成0,表示没有数据场。我见过有人把DLC设成8但只发2个字节,这样浪费总线带宽,不推荐。

1.2.4 数据场

0-8个字节,就是你要传的实际数据。比如传感器温度值、电机转速等。

小技巧:如果数据超过8字节,可以用多个数据帧分段传输,或者用CAN FD(后续章节会讲)。

1.2.5 CRC场

15位CRC校验码 + 1位CRC分隔符。CRC算法是固定的,硬件自动计算。我曾经在项目中遇到CRC校验失败的问题,排查了半天,结果是终端电阻没接好,信号反射导致数据错误。

1.2.6 ACK场

2位:ACK槽 + ACK分隔符。发送节点发完数据后,会释放总线。接收节点如果正确收到数据,就在ACK槽里拉低总线(显性位)。如果没收到ACK,发送节点会重发。

这里有个坑:如果总线上只有一个节点,它自己发自己收,ACK槽是隐性位(1),发送节点会认为接收失败而不断重发。所以调试时至少要有两个节点。

1.2.7 EOF(帧结束)

7个隐性位(逻辑1)。表示帧结束,总线恢复空闲状态。

1.3 位填充机制

这个机制很有意思。CAN总线规定:连续发送5个相同位后,必须插入一个相反位。

举个例子:如果你要发00000,实际发的是000001。接收端收到后会自动去掉这个填充位。

为什么要这么做?因为CAN总线靠电平变化来同步时钟。如果连续太多相同的位,节点间的时钟会漂移,导致采样错误。

避坑指南:我曾经在一个项目里,用逻辑分析仪抓CAN波形,发现数据帧中间有一段连续12个隐性位。当时以为是硬件故障,查了半天才发现是位填充机制导致的。记住:位填充只发生在SOF到CRC场之间,EOF和ACK场不填充。

位填充的规则很简单:

  • 发送方:每5个相同位后插入1个相反位
  • 接收方:每5个相同位后删除1个相反位
  • 填充位不参与CRC计算

你想想看,如果数据里恰好有连续的5个0,填充位就是1。这样总线上的电平一直在变化,时钟同步就稳了。

小结

今天的内容就这些。数据帧是CAN通信的基础,每个场都有它的作用。我建议大家动手抓几个波形看看,用逻辑分析仪或者CAN分析仪都行。亲眼看到SOF、仲裁场、数据场这些波形,比看十遍书都管用。

下一章咱们讲远程帧和错误帧,到时候会聊到总线仲裁和错误处理机制,那才是真正考验功底的地方。

课后思考:如果总线上有两个节点同时发送相同ID的数据帧,会发生什么?提示:想想仲裁场和ACK场的工作机制。