3、CAN数据链路层(一):CAN帧格式分类与数据帧结构详解
各位同学,咱们今天正式进入CAN总线的核心地带——数据链路层。说实话,很多工程师学CAN总线,停留在物理层和收发器选型上,一谈到帧结构就头大。但我要告诉你,真正出问题的地方,十有八九都在这一层。
我个人习惯把数据链路层比作“交通规则”。物理层决定了车怎么跑,数据链路层决定了车什么时候该停、什么时候该让、撞车了怎么处理。你想想看,没有规则,高速公路上再好的车也得乱成一锅粥。
3.1 CAN帧格式分类:五种“车型”
CAN总线上一共跑着五种帧,就像路上跑着五种不同用途的车。我刚开始学的时候,总觉得记不住,后来在项目里调试过一次总线错误,就再也没忘过。
| 帧类型 | 英文名称 | 作用 | 优先级 |
|---|---|---|---|
| 数据帧 | Data Frame | 发送节点把数据传给其他节点 | 由ID决定 |
| 远程帧 | Remote Frame | 请求其他节点发送数据 | 由ID决定 |
| 错误帧 | Error Frame | 检测到总线错误时发出 | 最高 |
| 过载帧 | Overload Frame | 节点忙不过来时请求延迟 | 次高 |
| 帧间隔 | Interframe Space | 帧与帧之间的分隔 | — |
核心要点:数据帧和远程帧是“干活”的,错误帧和过载帧是“处理异常”的,帧间隔是“喘口气”的。记住这个分类,后面就好理解了。
3.2 数据帧结构详解:拆开看看里面长啥样
数据帧是咱们用得最多的帧。说白了,就是“我要发数据了,大家注意听”。一个标准的数据帧(11位ID)长这样:
SOF + 仲裁场 + 控制场 + 数据场 + CRC场 + ACK场 + EOF
嗯,这里要注意,CAN FD(灵活数据速率)的帧结构略有不同,咱们先讲经典CAN,那是基础。
3.2.1 SOF(帧起始)
SOF就是一个显性位(逻辑0)。它告诉总线上所有节点:“我要开始说话了”。我在项目中遇到过一个问题,某个节点的SOF波形上升沿不够陡,导致其他节点误判起始时刻。后来查出来是晶振精度不够,换了温补晶振就好了。
3.2.2 仲裁场
这是CAN总线最精彩的部分。仲裁场包含ID和RTR位。ID决定了消息的优先级——ID越小,优先级越高。
为什么会这样?因为CAN总线是“线与”机制。显性位(0)会覆盖隐性位(1)。当两个节点同时发送时,谁先发送0,谁就赢了。我刚开始做项目时,把两个节点的ID设成了相同的值,结果总线直接罢工。后来才知道,同一总线上不允许有相同ID的节点——这是硬性规定。
避坑指南:我曾经在量产前才发现,某个节点的ID和另一个节点的远程帧ID冲突了。排查了整整两天。建议你在设计阶段就画一张ID分配表,每个ID的用途、方向、周期都写清楚。
3.2.3 控制场
控制场有6个位:IDE位、保留位r0、DLC(数据长度代码)。DLC用4个位表示数据场有多少个字节,范围是0到8。
这里有个坑:DLC可以设为0,表示不发送数据。但有些初学者以为DLC=0就是没帧,其实不是——帧结构依然完整,只是数据场为空。我在调试一个电机控制器时,发现对方发来的数据帧DLC=0,但我的解析库直接报错。后来加了DLC判断才搞定。
3.2.4 数据场
数据场就是真正要传的数据,0到8个字节。为什么是8个?因为CAN总线设计之初,认为工业控制场景下,8个字节足够传递大部分控制信息了。比如一个电机的转速、电流、温度,三个float就12个字节了,所以需要拆成两帧发。
我个人习惯把数据场的字节分配做成一个Excel表格,每个bit的含义都标清楚。这样后期维护起来省心很多。
3.2.5 CRC场
CRC场包含15位CRC校验码和1位CRC界定符。CAN的CRC算法是专用的,不是标准的CRC-16。你想想看,如果CRC算错了,接收方就会认为数据有误,然后发送错误帧。
警告:千万不要自己实现CRC算法!直接用硬件CRC模块或者官方库。我曾经见过一个工程师手写CRC,结果在高温下计算错误,导致整个系统频繁报错。CAN控制器的硬件CRC是经过验证的,别折腾。
3.2.6 ACK场
ACK场有2个位:ACK Slot和ACK界定符。发送节点在ACK Slot发送隐性位(1),如果接收节点正确收到了数据,就把这个位拉成显性(0)。如果没人拉低,发送节点就知道——没人收到我的数据。
嗯,这里要注意,ACK是“所有接收节点”一起响应的。只要有一个节点正确接收,ACK Slot就是显性。所以你不能通过ACK来判断“所有节点都收到了”,只能判断“至少有一个节点收到了”。
3.2.7 EOF(帧结束)
EOF是7个隐性位(1)。它告诉总线:“这帧结束了,大家可以抢下一帧了”。如果EOF被破坏(比如被干扰成显性位),总线会认为帧不完整,然后发送错误帧。
3.3 其他帧类型速览
咱们快速过一下其他四种帧,后面章节会详细讲。
- 远程帧:结构跟数据帧几乎一样,区别是RTR位为隐性(1),且没有数据场。它相当于在喊:“谁有数据?发给我!”
- 错误帧:由6个显性位(错误标志)和8个隐性位(错误界定符)组成。一旦检测到错误,立刻打断当前帧。
- 过载帧:跟错误帧结构类似,但触发条件不同。节点忙不过来时主动发出,请求对方等一等。
- 帧间隔:3个隐性位。帧与帧之间必须有的“空档期”,给节点一点时间处理上一帧。
实战建议:用逻辑分析仪抓一次总线波形,对照着帧结构图看一遍。我当年就是这么学的,看完一遍,所有帧结构就刻在脑子里了。纸上得来终觉浅,绝知此事要躬行。
3.4 本章小结
这一章咱们把CAN的五种帧类型和数据帧的七个字段都过了一遍。记住,数据帧是主角,其他帧都是配角。下一章咱们会深入讲仲裁机制和位填充,那才是CAN总线真正“高级”的地方。
最后留个思考题:如果总线上同时出现一个数据帧和一个远程帧,且ID相同,谁会赢?答案下章揭晓。