2. CAN报文结构详解:标准帧与扩展帧的ID、DLC、数据场解析
CAN(Controller Area Network)报文是总线通信的基本数据单元。理解报文结构是进行ID过滤、DLC校验和数据解析的前提。本章将深入剖析标准帧与扩展帧的位域组成,重点对比仲裁场中11位ID与29位ID的差异,并解析DLC与数据场的编码规则。
2.1 标准帧与扩展帧的帧格式对比
CAN协议定义了两种帧格式:标准帧(CAN 2.0A)和扩展帧(CAN 2.0B)。两者在仲裁场长度、ID位数和DLC位置上有显著区别。下表列出了核心差异:
| 对比项 | 标准帧 (Base Frame) | 扩展帧 (Extended Frame) |
|---|---|---|
| ID 位数 | 11 位 (ID10 ~ ID0) | 29 位 (ID28 ~ ID0) |
| 仲裁场长度 | 12 位 (SOF + 11 ID + RTR + IDE) | 32 位 (SOF + 11 Base ID + SRR + IDE + 18 Ext ID + RTR) |
| IDE 位 | 显性 (0) | 隐性 (1) |
| SRR 位 | 无 | 隐性 (1),替代标准帧RTR位置 |
| DLC 位置 | 控制场第1~4位 | 控制场第1~4位(与标准帧相同) |
| 最大数据长度 | 8 字节 | 8 字节 |
| 总线利用率 | 较高(帧头开销小) | 较低(帧头多20位) |
实战提示:在MCU驱动开发中,标准帧常用于实时性要求高、节点数少的系统(如电机控制);扩展帧多用于车载网络(如J1939协议),需要更多ID空间来区分大量ECU和信号。
2.2 标准帧位域逐段解析
标准帧由7个场组成:SOF、仲裁场、控制场、数据场、CRC场、ACK场、EOF。下图展示了标准帧的完整位布局:
2.3 扩展帧位域逐段解析
扩展帧在仲裁场中增加了18位扩展ID,使ID总数达到29位。其仲裁场结构更复杂,包含SRR位和IDE位。下图展示了扩展帧的位布局:
2.4 ID结构与优先级仲裁
CAN总线采用逐位仲裁机制,ID数值越小,优先级越高。标准帧的11位ID范围是 0x000 ~ 0x7FF(2048个ID),扩展帧的29位ID范围是 0x00000000 ~ 0x1FFFFFFF(约5.36亿个ID)。
仲裁规则:
- 显性位 (0) 覆盖隐性位 (1)。
- 标准帧的IDE为显性 (0),扩展帧的IDE为隐性 (1),因此标准帧在IDE位赢得仲裁。
- 当标准帧与扩展帧ID相同时,标准帧优先发送。
- 扩展帧之间比较29位ID,数值小的优先。
2.5 DLC与数据场编码规则
DLC(Data Length Code)位于控制场,占用4位,编码方式如下:
| DLC 值 (二进制) | DLC 值 (十进制) | 数据场字节数 | 说明 |
|---|---|---|---|
| 0000 | 0 | 0 | 无数据,远程帧常用 |
| 0001 | 1 | 1 | 单字节数据 |
| 0010 | 2 | 2 | 双字节数据 |
| 0011 | 3 | 3 | 三字节数据 |
| 0100 | 4 | 4 | 四字节数据 |
| 0101 | 5 | 5 | 五字节数据 |
| 0110 | 6 | 6 | 六字节数据 |
| 0111 | 7 | 7 | 七字节数据 |
| 1000 ~ 1111 | 8 ~ 15 | 8 | DLC≥8时,数据场固定为8字节 |
驱动开发注意:DLC值大于8时,CAN控制器仍会发送/接收8字节数据。在MCU驱动中,必须根据DLC值截取有效数据,避免将无效字节误判为有效信号。例如,DLC=3时,只解析数据场前3个字节。
2.6 数据场字节序与位填充
数据场最多8字节,字节序(Endianness)由应用层协议定义。CAN协议本身不规定字节序,但常见约定如下:
- Motorola格式(大端序):高字节在前,低字节在后。例如16位信号
0x1234,Byte0=0x12,Byte1=0x34。 - Intel格式(小端序):低字节在前,高字节在后。例如16位信号
0x1234,Byte0=0x34,Byte1=0x12。
此外,CAN总线使用位填充机制:连续5个相同位后自动插入一个相反位,确保时钟同步。位填充不影响ID、DLC和数据场的逻辑值,但会增加帧长度。标准帧最大位数为111位(含填充),扩展帧最大位数为131位(含填充)。
2.7 报文解析实战示例
假设MCU从CAN控制器接收缓冲区读取到以下原始数据(以标准帧为例):
// 原始CAN帧数据(假设从硬件寄存器读取)
uint32_t id = 0x123; // 11位ID
uint8_t dlc = 0x04; // DLC = 4
uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00};
uint8_t ide = 0; // 标准帧
uint8_t rtr = 0; // 数据帧
解析步骤:
- ID提取:
id = 0x123,对应二进制0001 0010 0011,优先级较高。 - DLC校验:
dlc = 4,有效数据长度为4字节。 - 数据场解析:
data[0] ~ data[3]为有效数据,data[4] ~ data[7]忽略。 - 帧类型判断:
ide = 0且rtr = 0,为标准数据帧。