第2章:CAN协议数据链路层——CAN帧结构详解
大家好,我是老李。今天咱们来啃CAN协议里最核心的一块——数据链路层。说白了,就是CAN总线上的消息到底长什么样,怎么打包、怎么发送、怎么识别。
我记得刚入行那会儿,看CAN帧结构就像看天书。后来踩了不少坑,才慢慢摸清楚门道。今天我把这些经验掰开揉碎了讲给你听。
2.1 标准帧 vs 扩展帧:ID长度决定一切
CAN协议里,帧ID是最关键的东西。它决定了消息的优先级,也决定了谁能抢到总线。
标准帧的ID是11位,范围0x000~0x7FF。扩展帧的ID是29位,范围更大。你想想看,11位最多2048个ID,29位能到5亿多个。现在车上的ECU越来越多,标准帧有时候真不够用。
核心区别:
- 标准帧:11位ID,IDE位=0
- 扩展帧:29位ID,IDE位=1
- 扩展帧比标准帧多出18位ID,帧长度也相应增加
我在项目中遇到过一件事:某次给一个商用车做网关,客户要求兼容两种帧格式。结果发现,标准帧和扩展帧虽然ID不同,但仲裁时扩展帧的优先级反而低。为什么?因为扩展帧的IDE位在仲裁场里靠后,标准帧先发完IDE=0,就已经赢了。
我的习惯:只要不是老平台,我建议直接用扩展帧。29位ID够用,而且现在主流MCU都支持。别给自己找麻烦。
2.2 数据帧:真正干活儿的帧
数据帧就是用来传数据的。它分标准数据帧和扩展数据帧,结构上就差在ID长度上。
一个完整的数据帧包含:
- 帧起始(SOF):1位显性,告诉总线“我要发消息了”
- 仲裁场:ID + RTR位 + IDE位
- 控制场:保留位 + DLC(数据长度码)
- 数据场:0~8字节,真正要传的数据
- CRC场:15位CRC + 1位CRC界定符
- ACK场:应答位 + 应答界定符
- 帧结束(EOF):7位隐性
嗯,这里要注意:DLC虽然叫数据长度码,但它只能表示0~8。CAN FD出来之前,数据场最大就是8字节。我刚开始做的时候,以为DLC能设成9,结果总线直接报错。血的教训。
避坑指南:我曾经在写驱动时,把DLC设成了0,但数据场还放了4个字节。结果接收方只读到0字节,数据全丢了。记住:DLC必须和数据场实际长度一致。
2.3 远程帧:问别人要数据
远程帧,说白了就是“请求帧”。它没有数据场,只有ID和RTR位。RTR位在远程帧里是隐性(1),在数据帧里是显性(0)。
为什么要有远程帧?举个例子:发动机ECU想知道当前车速,就发一个远程帧,ID设成车速消息的ID。仪表盘收到后,就知道该发车速数据了。
但说实话,远程帧现在用得越来越少了。为什么?因为大部分系统都改成周期性发送了。你想想看,远程帧是“请求-应答”模式,效率低,还容易丢。我建议你:除非有特殊需求,否则别用远程帧。
我的经验:远程帧的RTR位是隐性,数据帧的RTR位是显性。仲裁时,数据帧永远比远程帧优先级高。所以如果你用远程帧,一定要确保数据帧能及时响应。
2.4 错误帧:总线的“交警”
错误帧是CAN协议里最智能的设计之一。它由6个显性位组成,专门用来通知总线“出错了”。
错误帧分两种:
- 主动错误帧:6个显性位,由检测到错误的节点发出
- 被动错误帧:6个隐性位,由错误计数器超标的节点发出
我记得有一次调试,总线莫名其妙地一直报错。用示波器一看,错误帧一个接一个。后来发现是一个节点的终端电阻焊错了,导致信号反射。嗯,硬件问题有时候比软件还难查。
避坑指南:我曾经遇到一个案例,某个节点频繁发送错误帧,导致整个总线瘫痪。后来发现是晶振频率偏差太大,导致位时序不对。所以,CAN节点的时钟精度一定要达标,尤其是高速CAN。
2.5 过载帧:总线太忙了,等等
过载帧和错误帧长得很像,也是6个显性位。但它的作用不一样:过载帧是接收方告诉发送方“我处理不过来了,你慢点”。
过载帧触发的条件:
- 接收方内部缓冲区满了
- 接收方处理速度跟不上总线速度
说实话,过载帧在现在的CAN系统里很少见了。为什么?因为大部分MCU的CAN控制器都有硬件FIFO,能缓存好几帧数据。除非你用的是特别老的芯片,或者总线负载特别高,否则基本碰不到过载帧。
我的建议:如果你在项目中看到过载帧,先别急着调软件。检查一下接收中断的优先级,看看是不是被其他高优先级中断抢占了太多时间。
2.6 帧间隔:总线的“呼吸”
帧间隔,就是两帧之间的空闲时间。它由3个隐性位组成,叫“间歇场”。
为什么要有帧间隔?因为总线需要时间恢复隐性电平,也给其他节点一个机会去竞争总线。
帧间隔的规则:
- 任何两帧之间必须有至少3个隐性位的间歇场
- 如果节点进入被动错误状态,间歇场之后还要加8个隐性位的“挂起传输”
嗯,这里有个细节:帧间隔不是固定的。如果总线一直空闲,节点可以连续发送。但一旦有节点发送了帧,就必须等3个隐性位才能发下一帧。
总结一下:
| 帧类型 | 作用 | 关键特征 |
|---|---|---|
| 数据帧 | 传输数据 | 有数据场,0~8字节 |
| 远程帧 | 请求数据 | 无数据场,RTR=1 |
| 错误帧 | 通知错误 | 6个显性位 |
| 过载帧 | 请求延迟 | 6个显性位 |
| 帧间隔 | 总线空闲 | 3个隐性位 |
好了,这一章的内容就到这儿。CAN帧结构是基础中的基础,你把它吃透了,后面学CAN FD和CANopen就轻松多了。下一章我们讲CAN FD,那个数据场能到64字节,爽得很。
记住:纸上得来终觉浅,绝知此事要躬行。找个开发板,用示波器抓几帧看看,比看十遍书都管用。