4、CAN总线帧结构(上):数据帧的组成、帧起始、仲裁场、控制场、数据场
各位同学,咱们今天来啃一块硬骨头——CAN总线的数据帧结构。
说实话,我刚入行那会儿,看着CAN帧的时序图,脑袋都是大的。什么SOF、IDE、DLC,一堆缩写看得人眼花。但后来我发现,只要你把帧结构拆开来看,其实没那么复杂。
今天咱们先讲数据帧的前半部分:帧起始、仲裁场、控制场、数据场。剩下的CRC场、ACK场和帧结束,咱们下节课再说。
4.1 数据帧的总体组成
一个标准的数据帧,总共由7个部分组成。我习惯把它记成「起、仲、控、数、循、应、结」——嗯,七个字,好记。
- 帧起始(SOF):1个显性位,告诉总线「我要开始说话了」。
- 仲裁场:包含11位标识符(标准帧)和RTR位,决定谁能抢到总线。
- 控制场:6位,包含IDE位、保留位和DLC(数据长度码)。
- 数据场:0~8字节,真正要传的数据。
- CRC场:15位CRC校验码+1位CRC界定符。
- ACK场:1位应答位+1位应答界定符。
- 帧结束(EOF):7个隐性位,表示帧的结束。
重要提醒:标准帧和扩展帧的区别主要在仲裁场。标准帧用11位标识符,扩展帧用29位。咱们这节课先以标准帧为例来讲。
4.2 帧起始(SOF)
帧起始就一个位,显性电平(逻辑0)。
你想想看,总线空闲的时候,所有节点都在发隐性电平(逻辑1)。突然有个节点把总线拉低,其他节点就知道——有人要发消息了。
我在项目中遇到过一个问题:有个同事把SOF的时序搞错了,导致整个网络同步失败。后来查了半天,发现是晶振偏差太大,SOF的采样点没对准。嗯,这里要注意,SOF的同步作用非常关键,它决定了后续所有位的采样时机。
个人经验:我建议你在做CAN节点设计时,SOF的边沿一定要干净利落。如果上升/下降沿太缓,其他节点可能采样不到正确的电平,导致同步失败。
4.3 仲裁场
仲裁场是CAN总线最精彩的部分。说白了,它就是决定「谁先说话」的机制。
标准帧的仲裁场包含两部分:
- 11位标识符(ID):从ID28到ID18,高位在前。
- RTR位:远程帧请求位。数据帧发显性(0),远程帧发隐性(1)。
为什么CAN总线能无损仲裁?因为它是「线与」逻辑。显性位会覆盖隐性位。谁先发显性位,谁就赢了。
举个例子:
节点A:ID = 0x7FF(二进制:111 1111 1111)
节点B:ID = 0x123(二进制:001 0010 0011)
仲裁过程:
第1位:A发1,B发0 → B赢(因为0是显性)
A检测到总线是0,跟自己发的1不一致,立刻退出
B继续发送剩余位
我曾经调试过一个ECU,发现它总是抢不到总线。后来用示波器一看,它的ID设成了0x7FF——全1,优先级最低。你想想看,只要总线上有别的节点发消息,它就得让。后来我把ID改小了一点,问题就解决了。
避坑指南:我曾经见过有人把两个节点的ID设成一样的。结果呢?两个节点同时发数据,仲裁场完全一致,一直仲裁到数据场才分出胜负。但数据场的内容不同,导致总线错误。所以,同一总线上ID必须唯一,这是铁律。
4.4 控制场
控制场一共6位,结构如下:
| 位 | 名称 | 说明 |
|---|---|---|
| Bit 0 | IDE | 标识符扩展位。标准帧发显性(0),扩展帧发隐性(1) |
| Bit 1 | r0 | 保留位,显性(0) |
| Bit 2~5 | DLC | 数据长度码,4位,表示数据场有多少字节 |
这里有个细节:IDE位其实是在仲裁场之后发的。标准帧的IDE是显性,扩展帧的IDE是隐性。接收端通过IDE位来判断后面是11位ID还是29位ID。
DLC的取值范围是0~8,对应数据场的字节数。但注意,DLC可以设成9~15,不过实际数据场还是最多8字节。我建议你不要这么干,因为有些CAN控制器会报错。
核心要点:控制场虽然只有6位,但它决定了帧的类型(标准/扩展)和数据长度。写代码的时候,DLC一定要跟实际数据长度匹配。我曾经见过一个bug:DLC设成8,但只发了4个字节,接收端读到的是乱码。
4.5 数据场
数据场是真正干活的地方。0~8个字节,想传什么传什么。
但这里有个问题:数据场的内容怎么组织?没有统一标准。有的用Intel格式(小端),有的用Motorola格式(大端)。
举个例子:
假设要传一个16位的车速值,0x1234
Intel格式(小端):
Byte0 = 0x34(低字节)
Byte1 = 0x12(高字节)
Motorola格式(大端):
Byte0 = 0x12(高字节)
Byte1 = 0x34(低字节)
我个人习惯用Intel格式,因为跟MCU的内存布局一致,省去转换的麻烦。但如果你跟别的ECU通信,一定要先确认对方用什么格式。不然的话,车速200km/h读出来变成0.78km/h,那就闹笑话了。
经验之谈:我建议你在设计CAN通信矩阵时,把每个信号的起始位、长度、字节顺序都写清楚。别嫌麻烦,后期调试的时候,这份文档能救你的命。
4.6 小结
好了,今天的内容就到这里。咱们把数据帧的前半部分捋了一遍:
- 帧起始:1位显性,同步用
- 仲裁场:11位ID + RTR,决定优先级
- 控制场:IDE + r0 + DLC,描述帧属性和数据长度
- 数据场:0~8字节,真正的数据
下节课咱们讲CRC场、ACK场和帧结束。到时候我会分享一个我当年调试CRC校验失败的案例,保证让你印象深刻。
记住一句话:CAN帧结构是基础中的基础。你把它吃透了,后面学CANopen、J1939都会轻松很多。