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的硬件接口和收发器选型,那个更贴近实战。

有什么问题,欢迎在评论区交流。咱们下期见。