3. CAN数据链路层:帧结构与核心机制
数据链路层,说白了就是CAN通信的“交通规则”。它规定了数据怎么打包、怎么发、怎么避免冲突。我做了这么多年CAN开发,大部分现场问题都出在这一层——不是帧结构配错了,就是仲裁没搞明白。
咱们先看整体框架,再逐个拆解。
3.1 四种帧结构
CAN总线上一共就四种帧。我见过不少工程师把远程帧和数据帧搞混,结果调试时死活收不到响应。咱们一个一个说清楚。
3.1.1 数据帧
数据帧是干活的主力。它负责把数据从发送节点送到接收节点。标准格式有11位ID,扩展格式有29位ID。我个人习惯在乘用车项目里用标准格式,够用且效率高。
数据帧的结构分为7个段:
- 帧起始(SOF):1个显性位,告诉总线“我要发数据了”。
- 仲裁段:包含ID和RTR位。标准帧11位ID,扩展帧29位ID。
- 控制段:IDE位、保留位、DLC(数据长度码)。DLC范围0~8。
- 数据段:0~8字节,真正要传的数据。
- CRC段:15位CRC序列 + 1位CRC界定符。
- ACK段:1位ACK槽 + 1位ACK界定符。
- 帧结束(EOF):7个隐性位。
关键点:数据帧的RTR位必须为显性(0),表示这是数据帧。远程帧的RTR位为隐性(1)。这是两者唯一的区别——嗯,就这一位。
3.1.2 远程帧
远程帧是用来“请求数据”的。节点发一个远程帧,告诉目标节点:“把你的数据发给我”。
我曾经在项目里遇到一个问题:某个传感器节点一直不发数据,查了半天发现是远程帧的DLC没配对。接收节点检查DLC,发现对不上,直接丢弃了请求。所以远程帧的DLC必须和目标数据帧的DLC一致。
| 对比项 | 数据帧 | 远程帧 |
|---|---|---|
| RTR位 | 显性(0) | 隐性(1) |
| 数据段 | 有(0~8字节) | 无 |
| 用途 | 发送数据 | 请求数据 |
| DLC | 实际数据长度 | 请求的数据长度 |
3.1.3 错误帧
错误帧是CAN总线的“自我修复机制”。任何节点检测到错误,就会主动发送错误帧。错误帧由两部分组成:
- 错误标志:6个连续显性位(主动错误)或6个连续隐性位(被动错误)。
- 错误界定符:8个隐性位。
你想想看,如果总线上有节点一直发错误帧,那整个网络就瘫痪了。我遇到过这种情况——一个节点的CAN收发器坏了,不停地发错误帧,其他节点全被拖死。排查时看示波器,总线上全是显性位,根本看不到正常帧。
避坑指南:我曾经在批量生产时发现一批ECU在高温下频繁进入错误被动状态。后来查出来是晶振精度不够,导致位时序漂移。所以选晶振时一定要看全温度范围的精度,别只看25°C的标称值。
3.1.4 过载帧
过载帧是节点用来“喊停”的。当接收节点来不及处理数据时,就发过载帧让发送节点等一等。过载帧的结构和错误帧很像:
- 过载标志:6个显性位。
- 过载界定符:8个隐性位。
说实话,过载帧在实际项目中用得不多。现在的MCU处理速度都够快,很少出现来不及处理的情况。但在一些老旧的CAN控制器上,我还是见过过载帧频繁出现。
3.2 仲裁机制
仲裁是CAN总线最巧妙的设计之一。它用的是CSMA/CA(载波监听多路访问/冲突避免),而不是以太网的CSMA/CD。说白了,就是“谁优先级高谁先走”。
仲裁过程是这样的:
- 所有节点监听总线,空闲时才能发送。
- 多个节点同时发送时,从ID的最高位开始逐位比较。
- 显性位(0)覆盖隐性位(1)。发送隐性位的节点检测到总线是显性,就知道自己输了,立即停止发送。
- 赢的节点继续发送完整帧,输的节点自动转为接收。
这就是“非破坏性仲裁”——赢的节点不受任何影响,输的节点也不丢数据,只是等下次再发。我刚开始学CAN时觉得这机制太优雅了,比以太网的碰撞检测高明多了。
经验之谈:ID越小,优先级越高。所以关键信号(比如刹车、转向)要用小ID。我在设计网络拓扑时,习惯把ID按功能安全等级分配:ASIL D的节点用0x001~0x0FF,ASIL B的用0x100~0x3FF,普通信号用0x400以上。
3.3 位填充
位填充是为了保证同步。CAN节点靠电平跳变来同步时钟。如果总线上连续出现太多相同的位,节点就会失去同步。
规则很简单:连续发送5个相同位后,自动插入1个相反位。
举个例子:
原始数据:11111 00000 11111
填充后: 111110 000001 111110
接收端收到后会去掉这些填充位,还原原始数据。位填充的范围是从SOF到CRC序列结束。ACK段、EOF和帧间隔不填充。
我记得有一次调试,发现总线负载率明明不高,但错误帧很多。查了半天,原来是某个节点的数据段里连续出现了十几个0,位填充后帧长度变长,导致位时序裕量不足。后来在应用层做了数据随机化处理,问题就解决了。
注意:位填充会导致实际帧长度不确定。标准数据帧最短47位,最长111位(含填充)。设计网络负载时,建议按最坏情况(每5位插入1位)来估算。
3.4 CRC校验
CRC是CAN总线的最后一道防线。它检测传输过程中有没有比特错误。
CAN用的CRC多项式是:
CRC-15: x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
计算范围:从SOF到数据段结束。生成15位CRC序列,放在CRC段。
接收节点用同样的多项式计算,如果结果和发送的CRC序列不一致,就说明有错误,节点会发送错误帧。
CRC的检错能力很强:
- 能检测所有单比特错误。
- 能检测所有双比特错误。
- 能检测所有奇数个错误。
- 能检测所有长度≤15的突发错误。
- 对长度16的突发错误,检错率99.997%。
说实话,我在实际项目中很少遇到CRC校验失败的情况。但一旦遇到,往往意味着物理层有问题——比如线束接触不良、共模干扰太大。有一次在电磁兼容测试中,CRC错误率突然飙升,后来发现是屏蔽层接地没做好。
避坑指南:我曾经在某个项目中,CRC错误率一直偏高,但示波器看波形又没问题。后来发现是CAN控制器的时钟分频配错了,导致采样点位置不对。所以调试时别光看波形,一定要检查位时序配置。
3.5 本章小结
数据链路层是CAN通信的核心。四种帧各司其职:数据帧传数据,远程帧要数据,错误帧纠错,过载帧流控。仲裁机制保证了多节点无冲突通信,位填充保证了时钟同步,CRC校验保证了数据完整性。
你想想看,一个只有两根线的总线,能实现这么多功能,是不是很巧妙?下一层咱们会讲物理层,到时候你会看到CAN收发器是怎么把这些逻辑信号变成差分信号的。