2. CAN协议详解:CAN数据帧结构、远程帧、错误帧、过载帧、帧间隔
大家好,我是你们的老朋友。今天咱们来聊聊CAN协议里最核心的东西——各种帧结构。说实话,我刚接触CAN的时候,也被这几种帧搞得有点晕。但后来我发现,只要搞懂了数据帧,其他的都是它的变种。
CAN总线上一共就五种帧:数据帧、远程帧、错误帧、过载帧,还有帧间隔。嗯,咱们一个一个来拆解。
2.1 数据帧——最常用的那个
数据帧,说白了就是用来发数据的。你在项目里90%以上的时间都在跟它打交道。我习惯把它分成七段来看,就像七节车厢的火车。
| 段名称 | 位数 | 作用 |
|---|---|---|
| 帧起始 | 1 bit | 显性电平,告诉总线“我要开始发了” |
| 仲裁段 | 11或29 bit | ID + RTR位,决定谁能抢到总线 |
| 控制段 | 6 bit | IDE、保留位、DLC(数据长度) |
| 数据段 | 0~64 bit | 你要发的实际数据 |
| CRC段 | 16 bit | 校验数据有没有传错 |
| ACK段 | 2 bit | 接收节点告诉发送方“我收到了” |
| 帧结束 | 7 bit | 隐性电平,收工 |
这里有个细节我得提醒你:仲裁段里的RTR位。标准帧里RTR=0表示数据帧,远程帧RTR=1。扩展帧里还有个SRR位,道理差不多。
我个人习惯:调试的时候,先看DLC对不对。有一次我排查了半天,结果发现DLC写成了0,数据段根本没发出去。你想想看,这种低级错误多坑人。
2.2 远程帧——只问不拿
远程帧很有意思。它不携带数据,只发一个请求。说白了就是:“喂,谁有某某ID的数据?给我发一份。”
远程帧的结构跟数据帧几乎一样,唯一的区别就是RTR位=1。控制段里的DLC写的是你期望接收的数据长度。
避坑指南:我曾经在项目里用远程帧请求传感器数据,结果对方节点没处理好,一直重复发。总线直接被塞爆了。所以用远程帧的时候,一定要确认接收方有对应的处理逻辑。
2.3 错误帧——总线的“交警”
错误帧是CAN总线自我纠错的机制。当某个节点检测到错误,它会立刻发一个错误帧,通知所有人:“刚才那包数据有问题,别用了。”
错误帧分两部分:
- 错误标志:6个连续显性位。主动错误节点发6个显性位,被动错误节点发6个隐性位。
- 错误界定符:8个连续隐性位。用来把错误帧跟后面的帧隔开。
为什么会这样设计?你想想看,6个显性位违反CAN的位填充规则(连续5个相同位就要插一个相反位),所以其他节点一看就知道出错了。
注意:如果节点进入被动错误状态,它发的错误帧是隐性位。这时候其他节点可能检测不到错误。我遇到过这种情况,排查起来特别头疼。建议你在设计时监控节点的错误计数器。
2.4 过载帧——我忙,等等
过载帧的作用很简单:接收节点告诉发送方“我处理不过来了,你慢点发”。
结构跟错误帧很像:
- 过载标志:6个显性位
- 过载界定符:8个隐性位
说实话,过载帧在实际项目中用得不多。现在的MCU处理速度都很快,很少出现处理不过来的情况。但如果你在做一些老旧的系统,或者总线负载特别高,还是要注意一下。
2.5 帧间隔——喘口气
帧间隔就是两帧之间的空闲时间。它让总线上的节点有时间准备接收下一帧。
帧间隔分两种情况:
- 主动错误节点:3个隐性位(间歇场)+ 总线空闲
- 被动错误节点:3个隐性位(间歇场)+ 8个隐性位(暂停场)+ 总线空闲
嗯,这里要注意:被动错误节点多了一个暂停场。这是为了让它在发完错误帧后多休息一会儿,别老抢总线。
我的经验:调试CAN通信时,用示波器看帧间隔特别有用。如果帧间隔太短,说明总线负载太高;如果帧间隔太长,说明节点处理速度慢。我曾经靠这个判断出一个节点的中断优先级设置有问题。
2.6 位填充——保证同步的小技巧
这个不是单独的帧,但跟所有帧都相关。CAN协议规定:连续发送5个相同位后,必须插入一个相反位。
比如你发了5个1,第6位必须插一个0。接收方看到这个0就知道是填充位,会自动去掉。
为什么要这么做?因为CAN节点靠电平跳变来同步时钟。如果长时间没有跳变,时钟就会漂移。你想想看,要是发了一长串0,接收方都不知道什么时候该采样了。
避坑指南:我曾经在写CAN驱动时,手动构造数据帧,结果忘了位填充。总线上的节点全乱了。后来我学乖了,直接用硬件CAN控制器,让它自动处理位填充。除非你在做非常底层的实现,否则别自己搞位填充。
2.7 总结一下
好了,咱们把CAN的五种帧都过了一遍。记住几个关键点:
- 数据帧是主力,远程帧是请求
- 错误帧和过载帧是异常处理
- 帧间隔是必要的喘息时间
- 位填充是保证同步的机制
说实话,这些内容看起来多,但你在实际项目中用几次就熟了。下一章咱们聊聊CAN的硬件接口和收发器选型,那个更贴近实战。
有什么问题,欢迎在评论区交流。咱们下期见。