3. CAN总线帧类型:数据帧、远程帧、错误帧、过载帧、帧间隔
好,咱们今天聊聊CAN总线上跑的那些“消息包”。
说白了,CAN总线上的节点之间要通信,就得按规矩来。这个规矩,就是定义了五种不同的帧类型。我刚开始接触CAN协议栈的时候,觉得这东西挺枯燥的。后来在项目里被一个错误帧折腾了两天,才老老实实把每个帧的细节啃了一遍。
嗯,咱们一个一个来看。
3.1 数据帧:最常用的“快递员”
数据帧,顾名思义,就是用来装数据的。一个节点想给另一个节点发信息,就用它。我个人习惯把数据帧分成两部分来看:帧头和帧体。
- 帧起始(SOF):一个显性位,告诉总线“我要开始说话了”。
- 仲裁场:这里装着ID和RTR位。ID决定了消息的优先级,数字越小优先级越高。RTR位在这里必须是显性,表示这是数据帧。
- 控制场:包含IDE位和DLC(数据长度码)。DLC告诉你后面跟着几个字节的数据,范围是0到8。
- 数据场:0到8个字节,这就是你要传递的“干货”。
- CRC场:校验用的,保证数据没被干扰。
- ACK场:接收节点在这里回应,告诉发送方“我收到了”。
- 帧结束(EOF):7个隐性位,表示帧结束了。
重点提醒:数据帧的RTR位是显性(0),这是区分它和远程帧的关键。我在调试一个ECU时,发现对方一直不回数据,查了半天,原来是RTR位配置错了,发了个远程帧出去。
3.2 远程帧:只问不拿的“查询员”
远程帧的结构跟数据帧几乎一样,只有一个关键区别:RTR位是隐性(1),而且它没有数据场。
你想想看,远程帧的作用是什么?就是一个节点向另一个节点请求数据。比如,发动机ECU想请求车速传感器的数据,就发一个远程帧,ID填车速传感器的ID。车速传感器收到后,就会回复一个数据帧。
我曾经在一个项目中,用远程帧来做周期性数据请求。但后来发现,如果多个节点同时请求同一个数据,总线负载会瞬间飙升。所以,我建议你慎用远程帧,尤其是在高负载的网络上。
小技巧:远程帧的DLC必须与对应数据帧的DLC一致。否则,接收节点可能不知道要回复多少字节的数据。
3.3 错误帧:总线的“警报器”
错误帧是CAN总线自我保护的机制。任何一个节点检测到错误,就会立刻发送错误帧,通知所有节点“刚才那包数据有问题,别用了”。
错误帧由两部分组成:
- 错误标志:6个连续的显性位(主动错误)或6个连续的隐性位(被动错误)。
- 错误界定符:8个隐性位。
为什么会这样?因为CAN总线要求所有节点在检测到错误后,必须立刻破坏当前帧,让所有节点都意识到错误发生。然后,发送节点会自动重发刚才那帧数据。
我记得有一次在台架上测试,总线一直报错误帧。用示波器一看,发现是终端电阻没接好,信号反射导致位错误。嗯,硬件上的坑,往往比软件更难排查。
注意:如果一个节点频繁发送错误帧,它可能会从“主动错误”状态降级为“被动错误”状态,甚至进入“总线关闭”状态。这时候,它就彻底跟总线说拜拜了。
3.4 过载帧:总线的“稍等一下”
过载帧的作用很简单:告诉发送节点“我忙不过来,你慢点发”。
它跟错误帧结构类似,也是由过载标志(6个显性位)和过载界定符(8个隐性位)组成。但触发条件不同:
- 接收节点内部条件未准备好,比如接收缓冲区满了。
- 在帧间隔期间检测到显性位。
说实话,过载帧在实际车载网络中并不常见。因为现在的MCU处理速度都很快,缓冲区也够大。但在一些老旧的CAN控制器上,我还是见过因为过载帧导致总线通信不稳定的情况。
3.5 帧间隔:帧与帧之间的“喘息空间”
帧间隔不是一帧数据,而是两帧之间的空闲时间。它用来让总线上的节点有时间处理上一帧,并准备接收下一帧。
帧间隔包括:
- 间歇场:3个隐性位。
- 总线空闲:任意长度的隐性位,直到有节点开始发送。
对于被动错误节点,帧间隔还会多出一个“挂起传输场”(8个隐性位)。这是为了让主动错误节点优先发送,避免被动错误节点占用总线。
你想想看,如果没有帧间隔,节点刚发完一帧,紧接着又来一帧,处理不过来怎么办?所以,这个“喘息空间”是必须的。
3.6 实战中的帧类型选择
在实际项目中,我总结了几条经验:
| 场景 | 推荐帧类型 | 说明 |
|---|---|---|
| 周期性发送传感器数据 | 数据帧 | 最常用,直接发送即可 |
| 按需请求数据 | 远程帧 | 注意控制频率,避免总线过载 |
| 诊断请求/响应 | 数据帧 | 诊断协议(如UDS)通常使用数据帧 |
| 总线错误恢复 | 错误帧 | 硬件自动处理,软件无需干预 |
核心总结:数据帧和远程帧是“干活”的,错误帧和过载帧是“保命”的,帧间隔是“休息”的。把这五种帧搞明白,CAN总线通信的基本原理你就掌握了八成。
好了,这一章就到这里。下一章咱们聊聊CAN总线的位时序和同步机制,这可是时间同步的基础。到时候我会分享一个我在采样点配置上踩过的坑,保证让你印象深刻。