第3章:CAN数据链路层(上)——CAN帧的种类与数据帧结构详解
各位同学,欢迎来到CAN协议的核心地带。
前面我们聊了CAN的物理层,说白了就是信号怎么在线上跑。但信号本身是没有意义的,就像你听到一串敲门声,你得知道这是「快递到了」还是「隔壁老王借酱油」。CAN帧,就是给这些信号赋予意义的那套规则。
这一章我们重点啃数据链路层。我个人习惯把这一层叫做「交通规则层」——它规定了谁可以发消息、发什么、发完怎么确认。嗯,咱们一个一个来看。
3.1 CAN帧的四种类型
CAN总线上一共就四种帧,不多不少。我刚开始学的时候觉得这玩意儿好复杂,后来发现其实就四个角色:
- 数据帧:最常用的,用来发送数据。就像你给别人递纸条。
- 远程帧:请求别人发数据。相当于你喊一声「谁有数据?给我一份!」
- 错误帧:检测到错误时,任何节点都可以发。这是总线的「警报器」。
- 过载帧:节点忙不过来,要求对方慢点发。有点像「等等,我还没消化完」。
你想想看,这四种帧覆盖了正常通信、请求、异常处理、流量控制,是不是挺完整的?
重点记忆:数据帧和远程帧是「正常通信」用的,错误帧和过载帧是「异常处理」用的。我在项目中见过有人把远程帧和错误帧搞混,结果总线一直报错,排查了半天。
3.2 数据帧结构详解
数据帧是咱们打交道最多的。它的结构就像一封信,有信封、有正文、有签名。咱们从前往后拆开看。
3.2.1 SOF(帧起始)
SOF就是一个显性位(逻辑0)。它告诉所有节点:「注意,我要开始发消息了!」
为什么是显性位?因为总线空闲时是隐性电平(逻辑1)。一旦有人拉低,大家就知道有动静了。这个设计很巧妙,对吧?
3.2.2 仲裁场
这是CAN协议最精彩的部分。仲裁场包含两部分:
- 标识符(ID):11位(标准帧)或29位(扩展帧)。它决定了消息的优先级。
- RTR位:远程帧请求位。数据帧是显性,远程帧是隐性。
仲裁的原理说白了就是「谁的数字小,谁赢」。ID越小,优先级越高。我遇到过一个问题:两个节点同时发消息,ID大的那个自动退出发送,等下次再试。这就是非破坏性仲裁——不会损坏数据,只是排队。
避坑指南:我曾经在项目里把两个节点的ID设成了相同的值,结果总线直接乱套。记住:同一总线上,每个数据帧的ID必须唯一!远程帧可以和数据帧ID相同,但RTR位不同,所以能区分。
3.2.3 控制场
控制场有6位,但咱们只需要关心其中4位:
- IDE位:标识是标准帧(0)还是扩展帧(1)。
- r0位:保留位,必须为显性。
- DLC(数据长度码):4位,表示数据场有多少字节。范围0~8。
注意:DLC虽然可以表示0~15,但CAN协议规定数据场最多8字节。超过8的DLC值,实际数据长度还是8。这个坑我踩过——有一次我设了DLC=12,结果接收方只收到8个字节,剩下的全丢了。
3.2.4 数据场
这就是真正的数据内容了。0~8个字节,想发什么就发什么。但实际项目中,我们通常会把数据打包成特定格式,比如:
- 第一个字节:车速
- 第二个字节:发动机转速
- 第三、四字节:油门踏板位置
说白了,数据场就是你的「快递包裹」,里面装什么由你定。但要注意字节顺序——是大端还是小端?不同ECU可能不一样,得提前约定好。
3.2.5 CRC场
CRC(循环冗余校验)是保证数据完整性的关键。它包含两部分:
- CRC序列:15位校验码,由发送方计算。
- CRC界定符:1位隐性位,作为分隔。
接收方收到数据后,会用同样的算法重新计算CRC。如果结果不一致,说明数据在传输过程中被干扰了,就会触发错误帧。
注意:CRC只能检测错误,不能纠正错误。一旦发现CRC不对,整帧数据就作废了。所以CAN总线的可靠性,很大程度上依赖于重传机制。
3.2.6 ACK场
ACK场是「确认收据」。它包含:
- ACK槽:发送方发隐性位,接收方如果正确接收,就把它拉成显性。
- ACK界定符:1位隐性位。
这里有个细节:只要有一个节点正确接收了,ACK槽就是显性。也就是说,发送方只关心「有没有人收到」,不关心「有多少人收到」。我在调试时遇到过一种情况:总线上的节点都离线了,但发送方还在发,因为ACK槽一直是隐性,它就知道没人理它。
3.2.7 EOF(帧结束)
EOF是7个连续的隐性位。它告诉所有节点:「这帧发完了,你们可以抢总线了。」
为什么是7位?因为错误帧是6个显性位,7位隐性可以确保不会和错误帧混淆。这个设计很严谨,对吧?
3.3 完整的数据帧结构一览
咱们把上面讲的串起来,看一个标准数据帧的完整结构:
| 字段 | 位数 | 说明 |
|---|---|---|
| SOF | 1 | 帧起始,显性位 |
| 标识符 | 11 | 标准帧ID,决定优先级 |
| RTR | 1 | 数据帧为显性,远程帧为隐性 |
| IDE | 1 | 标准帧为显性,扩展帧为隐性 |
| r0 | 1 | 保留位,显性 |
| DLC | 4 | 数据长度,0~8 |
| 数据场 | 0~64 | 实际数据,最多8字节 |
| CRC | 15 | 校验码 |
| CRC界定符 | 1 | 隐性位 |
| ACK槽 | 1 | 接收方拉为显性表示确认 |
| ACK界定符 | 1 | 隐性位 |
| EOF | 7 | 帧结束,隐性位 |
标准帧总共是:1 + 11 + 1 + 1 + 1 + 4 + 0~64 + 15 + 1 + 1 + 1 + 7 = 44~108位。加上3位的帧间隔,实际占用总线的时间就是这么多。
3.4 扩展帧与标准帧的区别
扩展帧的ID是29位,结构上多了SRR位和扩展标识符。说白了,就是仲裁场变长了。但其他部分(数据场、CRC、ACK、EOF)完全一样。
我个人建议:能用标准帧就别用扩展帧。为什么?因为扩展帧的仲裁场更长,传输效率更低。只有在ID不够用的时候才考虑扩展帧。我在一个商用车项目里,标准帧的11位ID根本不够分配,最后不得不切到扩展帧。
核心总结:数据帧是CAN通信的基石。SOF负责同步,仲裁场决定谁先发,控制场告诉你怎么解析,数据场装内容,CRC保安全,ACK给反馈,EOF收尾。每一部分都有它的设计智慧。
下一章咱们聊远程帧和错误帧,这两个家伙虽然不常用,但关键时刻能救命。尤其是错误帧——我见过太多工程师因为不懂错误帧,被总线故障折磨得死去活来。到时候我给你们讲讲我当年踩过的坑。
好了,今天就到这儿。记住:CAN帧的结构,就像你的身份证——每个字段都有它的意义,少一个都不行。