3、CAN数据链路层协议:CAN帧结构
各位工程师朋友,咱们今天聊聊CAN数据链路层的核心——帧结构。说实话,搞懂帧结构,你就掌握了CAN通讯的“语法”。我刚开始接触CAN时,对着协议文档看了三天,脑子里还是一团浆糊。后来自己动手抓了几次波形,才真正明白每一比特的意义。
CAN总线上的数据,是以“帧”为单位传输的。就像我们说话,一句一句地说。每一帧都有固定的格式,包含多个场(Field)。咱们一个一个拆开看。
3.1 标准帧结构:SOF到EOF
一个完整的CAN数据帧,由7个部分组成。我习惯把它想象成一封挂号信:
- SOF(帧起始):1个显性位。相当于信封上的“开始”标记。总线空闲时,谁先拉低电平,谁就抢到了发言权。
- 仲裁场:包含11位标识符(ID)和1位RTR位。这是帧的“地址”,决定了优先级。
- 控制场:6位。包含IDE位、保留位r0、以及4位DLC(数据长度码)。DLC告诉你数据场有多少字节。
- 数据场:0~8字节。这就是你要发送的实际数据。比如转向角度、车速信号。
- CRC场:15位CRC序列 + 1位CRC界定符。这是校验码,确保数据没被干扰。
- ACK场:2位。接收节点如果正确收到,会在ACK槽位发送显性位,告诉发送方“我收到了”。
- EOF(帧结束):7个隐性位。表示这帧结束了。
核心要点:SOF和EOF是帧的“边界”。仲裁场决定了谁能说话。CRC是数据完整性的最后防线。
嗯,这里要注意:EOF必须是7个连续的隐性位。如果少于7个,总线会认为帧不完整,触发错误帧。我在调试一个EPS(电动助力转向)项目时,就遇到过因为电磁干扰导致EOF被拉低,整条总线疯狂报错的情况。
3.2 标准帧 vs 扩展帧
为什么要有两种帧?说白了,就是地址不够用了。标准帧的ID只有11位,最多2048个不同的ID。对于早期的简单系统,够用了。但现在的汽车,一个网关要管理几十个ECU,11位ID根本不够分。
扩展帧把ID扩展到了29位。怎么做到的?它把控制场里的IDE位利用起来了:
| 特性 | 标准帧 | 扩展帧 |
|---|---|---|
| ID长度 | 11位 | 29位 |
| 仲裁场结构 | 11位ID + RTR | 11位基础ID + SRR + IDE + 18位扩展ID + RTR |
| 控制场IDE位 | 显性(0) | 隐性(1) |
| 帧长度 | 较短 | 较长 |
| 兼容性 | 所有节点都支持 | 需要节点支持扩展帧 |
我个人习惯:在转向系统中,如果节点不多(比如只有方向盘转角传感器、EPS控制器、ESC),用标准帧就够了。但如果要跟ADAS(高级驾驶辅助)系统交互,建议用扩展帧,因为ADAS的ID分配往往很复杂。
避坑指南:我曾经在一个项目中,混合使用了标准帧和扩展帧。结果发现,标准帧的优先级总是高于扩展帧。为什么?因为标准帧的IDE位是显性(0),而扩展帧的IDE位是隐性(1)。在仲裁时,显性位胜出。所以,如果你希望某个消息优先发送,用标准帧。
3.3 远程帧与错误帧
这两种帧比较特殊,不是用来传数据的。
远程帧:说白了,就是“请求帧”。一个节点发送远程帧,告诉另一个节点:“请把你那个ID的数据发给我”。远程帧没有数据场,但DLC字段必须与请求的数据长度一致。你想想看,这就像你给同事发了个空信封,上面写着“请把报告放进来”。
远程帧的结构和数据帧几乎一样,唯一的区别是RTR位为隐性(1)。数据帧的RTR是显性(0)。
错误帧:这是CAN总线的“自我修复”机制。当任何节点检测到总线错误(比如位错误、填充错误、CRC错误、格式错误、ACK错误),它会立即发送错误帧。错误帧由6个连续的显性位(错误标志)和8个隐性位(错误界定符)组成。
错误帧的作用是:强制中断当前传输,通知所有节点“刚才那帧有问题,别用了”。然后发送节点会自动重发。这就是CAN总线可靠性高的原因之一。
重要提醒:错误帧不是用来“纠正”错误的,而是用来“通知”错误的。如果总线错误率太高,节点会进入“错误被动”甚至“总线关闭”状态。我在调试一个转向柱锁模块时,就遇到过因为线束接触不良,导致节点频繁发送错误帧,最后把自己“关”出总线的情况。
3.4 知识体系图:CAN帧结构全景
下面这张图,是我自己总结的CAN帧结构全景图。你可以把它当作一个“速查手册”。
这张图把标准帧、扩展帧、远程帧、错误帧都放在了一起。你可以看到,它们共享相同的SOF、控制场、CRC、ACK、EOF结构,区别主要在仲裁场和数据场。我个人建议你把这张图打印出来,贴在工位上,调试时一眼就能找到问题。
好了,关于CAN帧结构,咱们就聊到这里。记住:SOF是开始,EOF是结束,仲裁场决定谁说话,CRC保证数据没错,ACK告诉发送方“我收到了”。远程帧是“请求”,错误帧是“报警”。搞懂这些,你就能读懂CAN总线上跑的任何一帧数据了。
公众号:蓝海资料掘金营,微信deep3321