2、CAN总线基础:CAN协议起源与发展、CAN物理层特性、CAN数据帧结构详解

2.1 CAN协议的起源与发展——从一场“线束噩梦”说起

说起CAN总线,我得先跟你聊聊80年代的汽车电子。那时候,一辆豪华车里的电子控制单元(ECU)已经多起来了,但彼此之间还是用点对点的铜线连接。你想想看,光是线束的重量就能达到几十公斤,长度加起来能绕车好几圈。这不仅是成本问题,更是可靠性隐患——插头松动、线束磨损,故障排查起来简直让人崩溃。

1983年,德国博世公司决定解决这个痛点。他们牵头搞了一个项目,目标很明确:设计一种串行通信总线,让所有ECU共用两根线。1986年,CAN(Controller Area Network)协议正式发布。我记得第一次看到CAN的原始文档时,心里就一个感觉——这帮人真聪明。他们用差分信号、非破坏性仲裁、短帧结构,把抗干扰和实时性做到了极致。

后来,CAN协议在1993年成为国际标准ISO 11898。再往后,CAN 2.0A(11位标识符)和CAN 2.0B(29位标识符)相继推出。到了2012年,CAN FD(灵活数据速率)出现,把数据场从8字节扩展到了64字节,速率也飙到了5Mbps以上。嗯,这里要注意,CAN FD向下兼容经典CAN,但硬件必须升级。

核心要点:CAN总线从诞生起就是为了解决汽车线束过多、通信不可靠的问题。它的设计哲学是“简单、可靠、实时”。

2.2 CAN物理层特性——两根线里的大学问

CAN的物理层,说白了就是一对双绞线:CAN_H和CAN_L。它用的是差分电压传输,这招对付汽车里的电磁干扰特别管用。为什么?因为干扰信号会同时作用在两根线上,差分接收器一减,干扰就被抵消了。

咱们来看看具体的电平定义。CAN总线有两种状态:显性(Dominant)和隐性(Recessive)。显性状态对应逻辑0,隐性状态对应逻辑1。在ISO 11898标准里,显性时CAN_H比CAN_L高2V左右,隐性时两根线电压几乎相等(约2.5V)。

状态 CAN_H电压 CAN_L电压 差分电压 逻辑值
显性 3.5V 1.5V 2.0V 0
隐性 2.5V 2.5V 0V 1

我在项目中遇到过一个问题:某款车在低温环境下CAN通信偶尔丢帧。排查了半天,发现是终端电阻的阻值漂移了。标准要求CAN总线两端各接一个120Ω电阻,总阻值60Ω。如果电阻值不对,信号反射就会导致波形畸变。所以,我建议你在设计阶段就把终端电阻的选型和布局考虑进去,别等出了问题再补。

实战技巧:用示波器看CAN波形时,重点关注显性位的幅值是否达标。如果差分电压低于1.2V,通信就可能不稳定。我曾经在一条1米长的CAN线上测到过0.8V的显性幅值,结果就是时不时丢帧。

2.3 CAN数据帧结构详解——拆开看看里面有什么

CAN的数据帧,我习惯把它分成七个部分。你把它想象成一封信:有信封(帧起始、仲裁场)、正文(数据场)、校验(CRC场)和签名(ACK场)。咱们一个一个来看。

2.3.1 帧起始(SOF)

一个显性位,标志着数据帧的开始。它用来同步所有节点的时钟。说白了,就是告诉大家:“注意了,我要发数据了!”

2.3.2 仲裁场

这是CAN协议最精彩的部分。仲裁场包含标识符(ID)和RTR位。ID决定了消息的优先级——数值越小,优先级越高。为什么?因为CAN总线采用“线与”机制,显性位会覆盖隐性位。多个节点同时发送时,谁先发出隐性位谁就退出,剩下的那个继续发。

举个例子:ID=0x100的节点和ID=0x200的节点同时发送。0x100的二进制是0001 0000 0000,0x200是0010 0000 0000。从高位开始比,第二位0x100是0(显性),0x200是1(隐性),所以0x200退出,0x100胜出。整个过程没有数据丢失,这就是非破坏性仲裁。

避坑指南:我曾经在一个项目中,把两个节点的ID设成了0x100和0x101。你猜怎么着?0x100总是抢到总线,0x101几乎发不出消息。后来我把0x101改成了0x200,问题就解决了。记住,ID分配要留足间隔,别挤在一起。

2.3.3 控制场

控制场有6位,包括IDE位、保留位r0和DLC(数据长度码)。DLC用4位表示数据场的字节数,范围是0到8。注意,CAN FD里DLC可以表示0到64字节,但经典CAN最多8字节。

2.3.4 数据场

0到8字节的实际数据。我建议你尽量把数据塞满,别浪费。比如一个车速信号,你完全可以和发动机转速、油门开度打包在一个帧里发出去,减少总线负载。

2.3.5 CRC场

15位CRC校验码,加上1位CRC界定符。CAN的CRC算法很强大,能检测出所有单比特错误、双比特错误和大部分突发错误。嗯,这里要注意,CRC只覆盖SOF到数据场的部分,ACK场不参与校验。

2.3.6 ACK场

2位:ACK槽和ACK界定符。发送节点在ACK槽发隐性位,接收节点如果正确收到帧,就在ACK槽拉成显性位。这相当于接收方给发送方回了个“收到”。如果没人应答,发送节点就知道出问题了。

2.3.7 帧结束(EOF)

7个隐性位,标志着帧的结束。之后还有3位的ITM(帧间空间),用来让总线喘口气。

下面是一个标准数据帧的完整结构,我习惯用这个表格来跟团队沟通:

字段 位数 说明
SOF 1 帧起始,显性位
仲裁场 12(标准帧) 11位ID + 1位RTR
控制场 6 IDE + r0 + DLC
数据场 0~64 实际数据,经典CAN最多8字节
CRC场 16 15位CRC + 1位界定符
ACK场 2 ACK槽 + 界定符
EOF 7 帧结束,隐性位

2.4 小结与个人体会

CAN总线能活到现在,靠的就是它那套简洁而健壮的设计。物理层的差分信号抗干扰,数据层的非破坏性仲裁保证实时性,再加上短帧结构和强校验,让它在汽车这种恶劣环境里游刃有余。

我个人习惯,在项目初期就把CAN的物理层设计做扎实——终端电阻、线缆选型、节点布局,这些基础打好了,后面调试能省一半时间。你想想看,如果物理层就有问题,上层协议再完美也白搭。

下一章,咱们聊聊CAN的更高层协议,比如J1939和CANopen。到时候我会分享一些实际项目中的踩坑经历,保证让你少走弯路。

重要提醒:CAN总线虽然可靠,但不是万能的。在电磁环境极差(比如靠近大功率电机)或者线缆过长(超过40米)的场景下,建议增加CAN中继器或改用CAN FD。我曾经在一条50米的CAN线上吃过亏,信号衰减到接收端根本识别不了显性位。