4、CAN总线协议详解:CAN帧结构(数据帧、远程帧、错误帧)、位填充机制、仲裁机制(CSMA/CR)
各位工程师朋友,咱们今天聊聊CAN总线。说实话,搞过多轴协调控制的人都知道,CAN总线就像生产线上的“老黄牛”——皮实、可靠、实时性好。我最早接触CAN是在一个六轴机器人项目上,当时被各种帧结构搞得头大,后来摸透了才发现,其实核心就那么几块东西。
CAN总线的精髓,说白了就是“谁先抢到总线谁说话”。这个机制叫CSMA/CR,全称是“载波监听多路访问/冲突解决”。你想想看,多台设备挂在同一条总线上,同时发数据怎么办?CAN的解决办法很巧妙——靠ID仲裁,ID越小优先级越高。
4.1 CAN帧结构:数据帧
数据帧是咱们用得最多的。它负责把实际的控制数据发出去。比如你给伺服驱动器发一个位置指令,用的就是数据帧。
一个标准数据帧(11位ID)长这样:
帧起始(1bit) + 仲裁场(12bit) + 控制场(6bit) + 数据场(0~8字节) + CRC场(16bit) + ACK场(2bit) + 帧结束(7bit)
我习惯把数据帧拆成三块来记:
- 头部:帧起始 + 仲裁场 + 控制场。这部分决定了“谁在说话”和“说了多少”。
- 身体:数据场。0到8个字节,多轴控制时通常把位置、速度、电流打包进去。
- 尾部:CRC + ACK + 帧结束。用来保证数据没被干扰。
重要提醒:数据场最多8个字节。我在一个四轴同步项目中,曾经试图把四个轴的位置+速度塞进一帧里,结果发现8个字节根本不够用。后来改成每个轴单独发一帧,或者用扩展帧(29位ID)来区分。
4.2 远程帧
远程帧这东西,很多人容易忽略。它其实是个“请求帧”——我不发数据,我只问你要数据。
远程帧的结构和数据帧几乎一样,区别在于控制场里的RTR位(远程发送请求位)。数据帧的RTR=0,远程帧的RTR=1。而且远程帧没有数据场。
举个例子:你有一个温度传感器挂在CAN总线上。主控发一个远程帧,ID设为传感器的ID。传感器收到后,就知道“哦,主控在问我温度”,于是它发一个数据帧回来。
我的经验:远程帧在从站设备上用得比较多。主站一般不用远程帧去轮询,因为效率不如直接发数据帧高。我曾经在一个项目中用远程帧去读编码器位置,结果发现总线负载率飙升,后来改成从站主动上报,问题就解决了。
4.3 错误帧
错误帧是CAN总线的“安全阀”。一旦某个节点发现总线上的数据有问题,它就会主动发错误帧,通知所有节点“刚才那帧数据作废”。
错误帧由两部分组成:
- 错误标志:6个连续的显性位(主动错误)或6个连续的隐性位(被动错误)。
- 错误界定符:8个连续的隐性位。
为什么会这样设计?你想想看,正常数据帧里不可能出现6个连续相同电平(因为有位填充机制)。所以一旦出现6个连续显性位,所有节点都知道“出错了”。
避坑指南:我曾经在一个项目中,发现总线偶尔会莫名其妙地挂掉。排查了三天,最后发现是一个节点的CAN收发器坏了,它不停地发错误帧,把整个总线都拖垮了。所以,错误帧虽然能保护数据完整性,但一个故障节点也可能成为“总线杀手”。建议在软件里加一个错误计数机制,超过阈值就主动离线。
4.4 位填充机制
位填充,说白了就是“防连续相同位”。CAN总线规定:在发送数据时,如果连续出现5个相同电平,就必须插入一个相反电平。
比如你发的是:11111 00000,经过位填充后变成:111110 000001。
为什么要这么做?两个原因:
- 保证时钟同步:CAN总线没有单独的时钟线,所有节点靠数据信号的边沿来同步时钟。如果长时间没有跳变沿,节点间的时钟就会漂移。
- 区分错误帧:前面说了,错误帧用6个连续显性位来标识。如果没有位填充,正常数据也可能出现6个连续显性位,那就乱套了。
嗯,这里要注意:位填充只覆盖从帧起始到CRC场结束。ACK场和帧结束不参与位填充。
4.5 仲裁机制(CSMA/CR)
这是CAN总线最精彩的部分。多台设备同时发数据,怎么决定谁先发?靠ID仲裁。
过程是这样的:
- 所有节点监听总线,发现总线空闲后,可以开始发送。
- 发送时,每个节点逐位比较自己的ID和总线上的电平。
- 如果某个节点发送了隐性位(1),但总线上是显性位(0),说明有更高优先级的节点在发数据。这个节点立即停止发送,转为接收模式。
- 优先级最高的节点(ID最小)会赢得仲裁,继续发送完整的数据帧。
你想想看,这个过程完全是硬件自动完成的,不需要软件干预。所以CAN总线的实时性非常好,优先级高的消息永远不会被低优先级的消息阻塞。
实战要点:在多轴协调控制中,我习惯把同步信号(比如同步时钟)的ID设得最小,这样它总能第一时间抢到总线。位置指令的ID次之,状态反馈的ID最大。这样能保证同步信号零延迟,位置指令低延迟,状态反馈可以容忍一点延迟。
4.6 知识体系图
下面这张图把CAN帧结构、位填充和仲裁机制串起来了,方便你整体理解:
4.7 总结
CAN总线的帧结构、位填充和仲裁机制,是理解整个协议的基础。我个人觉得,搞多轴控制的人,至少要把数据帧和仲裁机制吃透。因为你在分配ID时,直接决定了系统的实时性表现。
最后说一句:别被那些复杂的帧格式吓到。实际开发中,大部分CAN控制器(比如SJA1000、MCP2515)都会帮你处理位填充和CRC校验。你真正需要关心的,就是ID分配和数据场怎么打包。
我的习惯:每次做新项目,我都会先画一张ID分配表,把每个节点的功能、优先级、数据长度都列清楚。这张表就是整个CAN通讯的“宪法”,后面所有代码都围绕它来写。省得后期改来改去,麻烦得很。