2. CAN总线基础:从历史到帧结构,一次讲透
大家好,我是你们的车载系统讲师。今天咱们聊聊CAN总线的基础知识。说实话,CAN总线这东西,我刚开始接触的时候也觉得挺枯燥的——不就是两根线在那传数据吗?但后来在项目里踩过几次坑,才真正体会到,理解这些基础有多重要。
好,咱们直接进入正题。
2.1 CAN协议的历史:为什么会有CAN?
上世纪80年代,汽车里的电子设备越来越多。各种传感器、控制器之间要通信,线束变得又粗又重。我记得有个老工程师跟我说过,那时候一辆豪华车的线束总长度能超过2公里,重量几十公斤。你想想看,这得多浪费燃油?
1983年,德国博世公司开始研发一种新的串行通信协议。1986年,CAN(Controller Area Network)正式发布。它的目标很明确:
- 减少线束:用两根线代替一堆乱七八糟的线
- 高可靠性:汽车环境恶劣,通信不能掉链子
- 实时性:刹车信号、发动机数据,延迟必须可控
1993年,CAN成为国际标准ISO 11898。到现在,几乎每辆车上都有CAN总线。我做过的一个项目里,一辆车上有5条不同的CAN网络,分别负责动力、车身、信息娱乐等不同域。嗯,这就是CAN的生命力。
核心要点:CAN总线诞生的初衷,就是解决汽车电子设备增多带来的线束复杂和通信可靠性问题。它不是为了追求高速,而是为了在恶劣环境下稳定工作。
2.2 物理层特性:差分信号与总线电平
CAN总线的物理层,说白了就是两根线:CAN_H和CAN_L。为什么用两根线?因为要用差分信号。
2.2.1 差分信号
差分信号是什么意思?就是信号不是用一根线对地电压来表示,而是用两根线之间的电压差来表示。CAN_H和CAN_L的电压差,决定了总线上的逻辑电平。
- 显性电平(Dominant):CAN_H比CAN_L高,电压差约2V。逻辑上代表0。
- 隐性电平(Recessive):CAN_H和CAN_L电压相等,电压差约0V。逻辑上代表1。
为什么用差分信号?抗干扰能力强。我在一个项目中遇到过,发动机点火时会产生很强的电磁干扰。如果是单端信号,数据早就乱套了。但差分信号不一样,干扰会同时作用在两根线上,电压差基本不变。说白了,就是干扰被抵消了。
个人经验:我曾经在调试一个CAN网络时,发现总线偶尔出现错误帧。排查了半天,最后发现是CAN_H和CAN_L的线束绞合不够紧密。差分信号对线束的绞合度有要求,绞得越密,抗干扰越好。这个细节,很多新手会忽略。
2.2.2 总线电平
CAN总线的电平状态,我习惯用一张表来记:
| 状态 | CAN_H电压 | CAN_L电压 | 电压差 | 逻辑值 |
|---|---|---|---|---|
| 隐性 | 2.5V | 2.5V | 0V | 1 |
| 显性 | 3.5V | 1.5V | 2V | 0 |
注意,显性电平会覆盖隐性电平。也就是说,如果多个节点同时发送,只要有一个节点发送显性电平(0),总线就是显性状态。这就是CAN总线仲裁的基础。
避坑指南:我曾经遇到过一个问题,CAN总线在长距离传输时,信号反射导致误码。后来发现是终端电阻没接好。CAN总线两端必须各接一个120Ω的终端电阻,用来匹配阻抗,消除信号反射。这个电阻,千万别省。
2.3 CAN帧结构:数据是怎么传的?
CAN总线上的数据,是以帧(Frame)为单位传输的。帧结构,说白了就是数据包的格式。CAN协议定义了四种帧类型:
- 数据帧:传输数据
- 远程帧:请求数据
- 错误帧:报告错误
- 过载帧:延迟下一帧
咱们一个一个说。
2.3.1 数据帧
数据帧是最常用的帧类型。它分为标准帧(11位ID)和扩展帧(29位ID)。我平时用得最多的是标准帧,简单够用。
数据帧的结构如下:
帧起始(1bit) + 仲裁场(12/32bit) + 控制场(6bit) + 数据场(0-8byte) + CRC场(16bit) + 应答场(2bit) + 帧结束(7bit)
我来拆解一下:
- 帧起始:1个显性位,表示一帧开始
- 仲裁场:包含ID和RTR位。ID决定了优先级,数值越小优先级越高
- 控制场:包含IDE位、保留位和DLC(数据长度码)
- 数据场:0到8个字节,实际传输的数据
- CRC场:循环冗余校验,检测传输错误
- 应答场:接收节点发送显性位,表示收到
- 帧结束:7个隐性位,表示一帧结束
你想想看,一帧最多传8个字节数据。为什么这么少?因为CAN总线追求的是实时性和可靠性,不是吞吐量。8个字节,对于汽车上的控制信号来说,完全够用了。
核心要点:数据帧的ID决定了优先级。ID越小,优先级越高。在总线上,多个节点同时发送时,ID小的节点会赢得仲裁,继续发送。这就是CAN总线的非破坏性逐位仲裁机制。
2.3.2 远程帧
远程帧,说白了就是“请求数据”。一个节点发送远程帧,告诉另一个节点:“把你的数据发给我”。
远程帧的结构和数据帧很像,区别在于:
- RTR位为隐性(1),表示这是远程帧
- 数据场为空(0字节)
我记得在调试一个传感器节点时,主控需要定期获取传感器数据。我用的就是远程帧来触发传感器发送数据。这样,传感器不需要一直发,省电又省带宽。
2.3.3 错误帧
错误帧,是CAN总线自我纠错的重要机制。当节点检测到总线错误时,会发送错误帧,通知其他节点。
错误帧由两部分组成:
- 错误标志:6个连续相同位(显性或隐性)
- 错误界定符:8个隐性位
CAN协议定义了五种错误类型:
- 位错误
- 填充错误
- CRC错误
- 格式错误
- 应答错误
我曾经在一个项目中,发现CAN总线频繁出现错误帧。排查下来,是某个节点的晶振频率偏差太大,导致位时序不对。嗯,这个坑我印象很深。
避坑指南:我曾经遇到过,某个节点发送错误帧太频繁,导致整个CAN网络瘫痪。后来发现是那个节点的收发器坏了,一直发送显性错误标志。CAN协议有错误限制机制,节点错误次数过多会自动离线。但在此之前,网络已经被拖垮了。所以,硬件质量很重要。
2.3.4 过载帧
过载帧,用于延迟下一帧的发送。当一个节点来不及处理接收到的数据时,可以发送过载帧,让其他节点等一等。
过载帧的结构和错误帧类似:
- 过载标志:6个显性位
- 过载界定符:8个隐性位
说实话,过载帧在实际项目中用得不多。我做了这么多年,也就遇到过一次。那是一个低速CAN网络,某个节点处理能力太弱,偶尔需要过载帧来缓冲。大部分情况下,只要设计合理,过载帧很少出现。
2.4 小结
好,咱们把今天的内容捋一捋:
- CAN总线诞生于80年代,为了解决汽车线束复杂和通信可靠性问题
- 物理层用差分信号,抗干扰能力强。显性电平(0)覆盖隐性电平(1)
- 四种帧类型:数据帧、远程帧、错误帧、过载帧
- 数据帧最常用,ID决定优先级,最多传8字节数据
下一章,咱们会深入CAN的仲裁机制和位时序。这些东西,在Android Automotive的CAN HAL层开发中会频繁用到。到时候,我会结合具体的代码,带大家实战一把。
今天就到这里。有什么问题,欢迎交流。