4、CAN总线帧结构(上):数据帧的标准格式(CAN 2.0A)、ID(标识符)的作用、仲裁场、控制场、数据场
各位同学,今天我们正式进入CAN总线最核心的部分——帧结构。
说实话,搞懂帧结构,你就掌握了CAN通信的“语法”。就像学英语得先懂主谓宾,学CAN就得先搞清楚这帧数据是怎么组织的。我个人习惯把CAN数据帧比作一个“快递包裹”,每一段都有它的使命。
咱们这节课先讲标准格式,也就是CAN 2.0A。它定义了11位ID,是应用最广的基础格式。后面我们会单独讲扩展格式(CAN 2.0B),那个是29位ID,但基础逻辑是一样的。
4.1 数据帧的整体结构
一个标准数据帧,从开始到结束,总共包含7个场。我列个表,大家先有个整体印象:
| 场名称 | 位数 | 作用 |
|---|---|---|
| 帧起始(SOF) | 1 bit | 同步信号,标志一帧的开始 |
| 仲裁场 | 12 bits | 包含ID和RTR位,决定总线访问优先级 |
| 控制场 | 6 bits | 包含IDE、保留位、DLC(数据长度码) |
| 数据场 | 0~64 bits | 实际要传输的数据 |
| CRC场 | 16 bits | 校验数据完整性 |
| ACK场 | 2 bits | 接收节点应答确认 |
| 帧结束(EOF) | 7 bits | 标志帧结束 |
今天咱们重点讲前四个场:帧起始、仲裁场、控制场、数据场。CRC和ACK我们留到下节课细说。
核心要点:标准数据帧总位数 = 1 + 12 + 6 + 0~64 + 16 + 2 + 7 = 44~108 bits。加上3 bits的帧间隔,实际一帧最少47 bits。
4.2 帧起始(SOF)—— 同步的“发令枪”
SOF只有1个bit,固定为显性电平(逻辑0)。
为什么是显性?因为总线空闲时是隐性电平(逻辑1)。SOF从隐性跳变到显性,所有节点都能检测到这个下降沿,从而同步自己的时钟。说白了,这就是一个“大家注意,我要开始发了”的信号。
我在项目中遇到过一个问题:某个节点在总线繁忙时发送SOF,结果因为时钟偏差,SOF的下降沿被其他节点误判为毛刺。后来排查发现是晶振精度不够。嗯,这里要注意,CAN对时钟容差有要求,标准帧要求不超过1.58%。
4.3 仲裁场——ID(标识符)与RTR位
仲裁场是CAN总线最精妙的设计之一。它包含两部分:
- ID(标识符):11 bits,范围0x000~0x7FF(0~2047)。
- RTR位:1 bit,Remote Transmission Request,远程帧请求位。
4.3.1 ID的作用:不仅仅是“名字”
很多初学者以为ID就是地址,像I2C那样。其实不是。
CAN的ID有两个核心作用:
- 标识消息内容:比如0x123代表“发动机转速”,0x456代表“车速”。接收节点通过ID过滤器只接收自己关心的ID。
- 决定总线优先级:ID值越小,优先级越高。0x000是最高优先级,0x7FF是最低。
为什么会这样?因为仲裁机制是“线与”逻辑。显性电平(0)会覆盖隐性电平(1)。多个节点同时发送时,从ID的最高位开始逐位比较,谁先发出隐性(1)而别人发出显性(0),谁就退出竞争。
避坑指南:我曾经在一个项目中,把两个关键信号分别分配了ID=0x100和ID=0x200。结果发现0x100的信号总是优先发送,导致0x200的信号偶尔被延迟。后来我把优先级需求高的信号分配了更小的ID。记住:ID分配要按实时性需求来排,不是随便给的。
4.3.2 RTR位——数据帧 vs 远程帧
RTR位在数据帧中固定为显性(0),在远程帧中为隐性(1)。
远程帧的作用是:一个节点请求另一个节点发送数据。比如ECU_A发送一个远程帧,ID=0x123,RTR=1,意思是“谁有ID=0x123的数据,请发给我”。
仲裁时,如果数据帧和远程帧的ID相同,数据帧优先级更高(因为RTR=0覆盖RTR=1)。
4.4 控制场——IDE、保留位、DLC
控制场共6 bits,结构如下:
| 位序 | 名称 | 说明 |
|---|---|---|
| bit 0 | IDE | Identifier Extension,标准帧固定为显性(0) |
| bit 1 | r0 | 保留位,固定为显性(0) |
| bit 2~5 | DLC | Data Length Code,数据长度码,0~8 |
IDE位:区分标准帧和扩展帧的关键。标准帧IDE=0,扩展帧IDE=1。控制场之后,标准帧直接进入数据场,而扩展帧会插入18位扩展ID。
保留位r0:为了兼容未来扩展,目前固定为0。有些老协议里还有r1,现在统一为r0。
DLC(数据长度码):4 bits,表示数据场有多少个字节。取值范围0~8。注意:DLC=0表示没有数据场,但帧结构依然完整。
重要提醒:DLC虽然可以表示0~15,但CAN协议规定数据场最多8字节。DLC值9~15是无效的,实际传输时数据场长度仍按8字节处理。我曾经见过一个供应商的代码,DLC写成了10,结果接收方解析数据时越界了。所以,DLC一定要控制在0~8之间。
4.5 数据场——真正的“货物”
数据场是帧里唯一承载应用数据的地方。长度0~8字节,由DLC决定。
数据场的排列顺序是MSB优先(大端模式)。比如发送0x12 0x34,先发0x12的高位bit,再发低位bit。
我个人习惯在定义CAN矩阵时,把数据场的字节分配画成表格,这样一目了然:
| 字节 | bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 |
|---|---|---|---|---|---|---|---|---|
| Byte 0 | 发动机转速高8位 | |||||||
| Byte 1 | 发动机转速低8位 | |||||||
| Byte 2 | 水温 | 油压 | ||||||
| Byte 3 | 车速 | |||||||
| Byte 4~7 | 未使用(填充0) | |||||||
你想想看,如果DLC=4,那Byte 4~7虽然没数据,但接收方还是会读到4个字节的0。所以DLC要精确匹配实际数据长度,别浪费带宽。
4.6 标准帧结构总览(SVG图)
下面这张图把标准数据帧的完整结构画出来了。我建议你把它存下来,调试的时候对照着看。
4.7 标准格式 vs 扩展格式(快速对比)
虽然这节课讲标准格式,但我还是想提前做个对比,方便你理解两者的区别:
| 特性 | 标准格式(CAN 2.0A) | 扩展格式(CAN 2.0B) |
|---|---|---|
| ID长度 | 11 bits | 29 bits |
| IDE位 | 显性(0) | 隐性(1) |
| 仲裁场长度 | 12 bits | 32 bits |
| 最大ID数量 | 2048 | 536,870,912 |
| 兼容性 | 所有CAN控制器都支持 | 需要支持CAN 2.0B的控制器 |
我个人建议:如果项目对ID数量要求不高(比如少于100个),优先用标准格式。因为标准帧更短,总线利用率更高。只有在需要大量ID分配时,才考虑扩展格式。
实战经验:我在做车载网关项目时,遇到过标准帧和扩展帧混用的情况。有些老节点只支持标准帧,新节点用扩展帧。这时候网关要做ID转换,把扩展帧映射到标准帧的ID范围。嗯,这里要注意,映射时要避免ID冲突,否则仲裁会出问题。
4.8 小结
今天的内容就到这里。我们讲了标准数据帧的四个场:
- 帧起始(SOF):1 bit显性,同步信号。
- 仲裁场:11位ID + 1位RTR,ID越小优先级越高。
- 控制场:IDE + r0 + DLC,DLC决定数据长度。
- 数据场:0~8字节,大端模式传输。
记住:ID是CAN总线的灵魂。分配ID时,优先级高的信号用小的ID。DLC要精确,别浪费带宽。下节课我们讲CRC和ACK,看看CAN是怎么保证数据不出错的。