2. CAN帧结构:数据帧、远程帧、错误帧、过载帧、帧间隔、位填充机制
各位同学,咱们今天聊聊CAN总线最核心的东西——帧结构。说实话,搞车载芯片这么多年,我见过太多工程师在CAN通信上栽跟头,归根结底就是没把帧结构吃透。你想想看,一辆车上几十个ECU,全靠这几类帧在一条双绞线上沟通,要是连帧格式都搞不清楚,那调试起来真是欲哭无泪。
CAN总线上一共定义了五种帧类型:数据帧、远程帧、错误帧、过载帧和帧间隔。另外还有个位填充机制,虽然不算帧类型,但它是保证通信可靠性的关键。咱们一个一个来拆解。
核心要点:CAN帧结构的精髓在于——用最少的线(两根)实现最可靠的通信。每一帧的设计都考虑了抗干扰、优先级仲裁和错误检测。
2.1 数据帧——最常用的帧
数据帧,顾名思义,就是用来传输数据的。我在项目中调试CAN通信时,90%的时间都在跟数据帧打交道。它分为标准格式(11位ID)和扩展格式(29位ID),结构上由七个场组成。
咱们先看标准数据帧的结构:
帧起始(1bit) + 仲裁场(12bit) + 控制场(6bit) + 数据场(0~8字节) + CRC场(16bit) + 应答场(2bit) + 帧结束(7bit)
这里我重点说几个容易踩坑的地方:
- 帧起始(SOF):一个显性位,标志着总线从空闲变为忙碌。嗯,这里要注意,SOF是同步的基础,所有节点都要在SOF的下降沿重新同步。
- 仲裁场:包含ID和RTR位。标准帧ID是11位,扩展帧是29位。RTR位在数据帧里是显性(0),在远程帧里是隐性(1)。
- 控制场:IDE位、保留位和DLC(数据长度码)。DLC只有4位,但只能表示0~8,别想着用它表示更多字节。
- 数据场:0~8字节,这是真正干活的地方。我曾经遇到过一个项目,工程师把DLC设成8但只发了3个有效字节,接收方解析时直接崩了。
- CRC场:15位CRC校验码+1位隐性分隔符。CRC覆盖的范围是从帧起始到数据场结束。
- 应答场:2位,ACK Slot和ACK分隔符。发送节点发隐性位,接收节点如果正确收到就在ACK Slot发显性位来应答。
- 帧结束(EOF):7个隐性位,标志着帧的结束。
我的经验:调试CAN通信时,先拿示波器抓SOF到EOF的完整波形。数一数EOF是不是7个隐性位,这是判断帧结构是否完整的最快方法。
2.2 远程帧——请求数据的利器
远程帧的结构跟数据帧几乎一样,唯一的区别是RTR位为隐性(1),而且没有数据场。说白了,远程帧就是用来问别人要数据的。
举个例子:发动机ECU想获取车速信息,它就可以发一个远程帧,ID设为车速传感器的ID。车速传感器收到后,就会发一个同ID的数据帧回来。
我个人习惯在项目初期用远程帧做节点存活检测。发一个远程帧,如果对方在指定时间内没回应,那基本可以断定这个节点挂了或者总线有问题。
避坑指南:我曾经在一个项目中,多个节点同时发远程帧请求同一个ID的数据,结果总线负载瞬间飙升。后来我加了个请求间隔定时器,才把问题解决。记住,远程帧虽然好用,但别滥用。
2.3 错误帧——总线的纠错机制
错误帧是CAN总线最强大的特性之一。任何节点检测到错误,就会立即发送错误帧,通知所有节点丢弃当前数据。
错误帧由两部分组成:
- 错误标志:6个相同极性的位(显性或隐性)。主动错误节点发6个显性位,被动错误节点发6个隐性位。
- 错误分隔符:8个隐性位。
CAN总线定义了五种错误类型:
| 错误类型 | 检测条件 | 我的经验 |
|---|---|---|
| 位错误 | 发送节点监控总线,发现发送的位与总线状态不一致 | 最常见的是阻抗不匹配导致的位错误 |
| 填充错误 | 连续6个相同极性的位出现 | 位填充机制就是为了防止这个 |
| CRC错误 | 接收节点计算的CRC与发送的不一致 | 总线干扰严重时经常出现 |
| 格式错误 | 固定格式的位出现错误值 | 比如EOF必须是隐性位 |
| 应答错误 | 发送节点没收到ACK | 接收节点没正确接收或节点掉线 |
2.4 过载帧——流量控制
过载帧的作用是告诉总线:我忙不过来了,慢点发。它跟错误帧结构类似,也是由过载标志(6个显性位)和过载分隔符(8个隐性位)组成。
触发过载帧的条件有两个:
- 接收节点内部条件未准备好,比如接收缓冲区满了。
- 在帧间隔的间歇场检测到显性位。
说实话,过载帧在实际项目中用得不多。现在的CAN控制器处理能力都很强,很少出现缓冲区溢出的情况。但如果你在做低端MCU的项目,还是得留个心眼。
2.5 帧间隔——总线休息时间
帧间隔不是一帧,而是帧与帧之间的空闲时间。它分为三个场:
- 间歇场:3个隐性位。所有节点在间歇场结束后才能开始发送。
- 总线空闲:任意长度的隐性位,直到有节点开始发送。
- 暂停发送场:仅被动错误节点需要,8个隐性位。
这里有个细节:间歇场是帧间隔的固定部分,任何节点都不能在间歇场发送数据。我曾经见过一个新手,在间歇场强行拉低总线想抢发数据,结果直接触发了过载帧。
2.6 位填充机制——保证同步的秘诀
位填充机制是CAN总线最巧妙的设计之一。规则很简单:发送节点在连续发送5个相同极性的位后,自动插入一个相反极性的位。
为什么要这么做?原因有两个:
- 保证同步:接收节点靠跳变沿来同步时钟。如果长时间没有跳变,时钟漂移会导致采样错误。
- 防止误判:连续6个相同位会被识别为错误标志。
位填充覆盖的范围是从SOF到CRC场结束。CRC分隔符、ACK场和EOF不参与填充。
举个例子:假设数据流是"00000",发送节点会在后面加一个"1",变成"000001"。接收节点看到5个0后,自动把后面的1去掉,还原成"00000"。
我在项目中遇到过一个问题:某个节点在高温下频繁报填充错误。排查后发现是晶振漂移导致采样点偏移,接收节点把正常的位序列误判成了连续6个相同位。后来换了温漂系数更低的晶振,问题就解决了。
2.7 知识体系总览
下面这张图展示了CAN帧结构的完整知识体系,我建议你把它存下来,调试时对照着看:
这张图把CAN帧结构的核心要素都串起来了。从五种帧类型到数据帧的七个场,从位填充机制到五种错误类型,再到帧间隔的三个子场,一目了然。
最后说一句,CAN帧结构看起来复杂,但只要你理解了设计者的初衷——可靠、实时、抗干扰——每个字段的设计意图就都清晰了。我在做车载芯片架构时,经常跟团队说:先把帧结构吃透,再去调驱动、写应用层,否则出了问题你连排查方向都没有。
实战建议:找一块带CAN控制器的开发板,用逻辑分析仪抓几帧数据,对照着本文的帧结构图逐位解析。亲手做过一遍,比看十遍书都管用。
公众号:蓝海资料掘金营,微信deep3321