2. CAN总线基础:CAN协议分层、CAN报文帧格式、位填充机制
各位同学好,我是你们的老朋友。今天咱们来聊聊CAN总线最核心的东西——协议分层、报文帧格式,还有那个容易被忽略但极其重要的位填充机制。
说实话,我刚开始接触CAN总线时,觉得这东西不就是两根线嘛,能有多复杂?直到我在一个车载项目中,因为对帧格式理解不到位,导致ECU之间通信老是丢数据。排查了整整两天,最后发现是远程帧用错了地方。嗯,从那以后,我再也不敢小看这些基础概念了。
2.1 CAN协议分层:别被OSI七层吓到
很多人一听到「协议分层」就头大,觉得这是搞理论的人才会关心的事。其实不然。你想想看,CAN总线只定义了物理层和数据链路层,说白了就是只管「怎么把信号发出去」和「怎么把数据组织好」。上层的东西,比如你发的是什么数据、怎么解析,那是应用层的事。
我个人习惯把CAN协议分成这么几层来看:
- 物理层:负责信号的传输。差分信号、双绞线、CAN_H和CAN_L的电平定义,都在这一层。我在调试一个商用车项目时,就遇到过因为线束太长导致信号反射,波形都畸变了。后来加了终端电阻才搞定。
- 数据链路层:这是CAN协议的精髓所在。它负责把数据封装成帧、进行错误检测、仲裁、应答等。说白了,就是保证你发的数据能完整、有序地到达目的地。
- 应用层:这一层CAN协议本身不管,由你自定义。比如J1939、CANopen这些高层协议,都是在数据链路层之上做的封装。
重点记住:CAN只负责传输,不负责解释。你发的0x123这个ID代表什么含义,那是应用层的事。
2.2 CAN报文帧格式:四种帧,各有各的脾气
CAN总线上一共有四种帧:数据帧、远程帧、错误帧、过载帧。我见过不少新手,只知道数据帧,其他三种基本没概念。结果出了问题,连错误帧都认不出来。
2.2.1 数据帧——最常用的那个
数据帧就是用来传输数据的。它分为标准帧(11位ID)和扩展帧(29位ID)。结构上,它由这么几部分组成:
| 字段 | 说明 | 我的经验 |
|---|---|---|
| SOF(帧起始) | 1位显性位,告诉总线「我要发数据了」 | 这个位是同步用的,很重要 |
| 仲裁场 | 包含ID和RTR位 | ID越小优先级越高,这是仲裁的关键 |
| 控制场 | 包含IDE位、DLC(数据长度) | DLC最大是8,别想着发超过8字节 |
| 数据场 | 0-8字节的数据 | 我习惯用0x00填充未使用的字节 |
| CRC场 | 15位CRC校验 + 1位CRC界定符 | CRC算不对,接收方会直接丢掉 |
| ACK场 | 2位,接收方应答 | 如果没人应答,发送方会重发 |
| EOF(帧结束) | 7位隐性位 | 标志着帧的结束 |
小技巧:我在实际项目中,经常用CAN分析仪抓波形。看到SOF后的第一个显性位,就知道帧开始了。如果波形上连续出现多个显性位,那多半是错误帧。
2.2.2 远程帧——请求数据用的
远程帧长得很像数据帧,但它没有数据场。它的作用是:一个节点向另一个节点请求数据。比如,你想让某个传感器把当前值发过来,就可以发一个远程帧。
我曾经在一个项目中,用远程帧来轮询多个传感器。结果发现,如果传感器响应太慢,总线会被阻塞。后来我改成了定时发送数据帧的方式,问题就解决了。所以,远程帧虽好,但别滥用。
2.2.3 错误帧——出了事它先跳出来
错误帧是CAN总线自己产生的。当某个节点检测到错误时,就会主动发送错误帧。它的结构很简单:6个连续显性位(错误标志)+ 8个隐性位(错误界定符)。
我记得有一次,在测试台上,CAN总线突然疯狂报错。我一看波形,全是错误帧。排查了半天,发现是一个节点的晶振频率偏了,导致位时序不对。嗯,硬件问题有时候就是这么隐蔽。
2.2.4 过载帧——我忙不过来,等等
过载帧和错误帧结构类似,但作用不同。它表示「我处理不过来了,你慢点发」。在实际项目中,过载帧比较少见。我做了这么多年,也就碰到过一两次,还是在总线负载极高的情况下。
2.3 位填充机制——看着简单,坑不少
位填充,说白了就是:连续发送5个相同位后,自动插入一个相反位。比如你发了5个连续的1,CAN控制器会自动在后面加一个0。
为什么要这么做?因为CAN总线是靠电平跳变来同步时钟的。如果长时间没有跳变,接收方的时钟就会漂移,导致采样错误。你想想看,如果连续发30个1,接收方怎么知道什么时候该采样?
注意:位填充只在SOF到CRC场之间有效。EOF和错误帧、过载帧的固定格式部分,不进行位填充。我曾经见过有人把EOF里的连续隐性位也做了位填充,结果整个帧都乱了。
位填充的规则很简单:
- 发送方:每5个相同位后,插入1个相反位
- 接收方:收到5个相同位后,自动删除后面的那个相反位
这个机制有个副作用:实际发送的位数可能会比理论值多。比如你发一个8字节的数据帧,理论上是108位(标准帧),但加上位填充后,可能变成120位左右。我在计算总线负载率时,通常会按130位来估算,留点余量。
另外,位填充还有一个重要作用:错误检测。如果接收方在数据场中检测到连续6个相同位,那就说明出错了——因为位填充机制不允许出现6个连续相同位。这就是错误帧中「6个连续显性位」的由来。
总结一下:位填充是CAN总线可靠性的基石之一。它保证了时钟同步,也提供了错误检测的手段。别小看这个机制,没有它,CAN总线在长距离、高波特率下根本没法稳定工作。
好了,这一章的内容就到这里。下一章咱们聊聊CAN总线的仲裁机制和错误处理,那才是真正体现CAN总线设计精妙的地方。有什么问题,欢迎在课后交流。