3、CAN总线基础回顾:CAN物理层、数据链路层、报文格式(标准帧/扩展帧)、位填充与CRC校验

各位同学,咱们今天聊点实在的。CAN总线这东西,做车载的没人不知道。但说实话,很多人用了好几年,真问到物理层怎么工作的、位填充到底干嘛用,反而支支吾吾。我当年刚入行时也这样,直到有一次在台架上抓了一整天波形,才真正把这些基础吃透。

嗯,咱们今天就把CAN总线的老底翻一翻。从物理层到数据链路层,再到报文格式和校验机制,一条龙讲清楚。

3.1 物理层:差分信号与总线电平

CAN物理层,说白了就是两根线——CAN_H和CAN_L。它靠差分电压来传递信号。为什么用差分?抗干扰能力强啊。你想想看,车里面电磁环境多恶劣,要是用单端信号,早被各种电机、点火系统干翻了。

CAN总线有两种逻辑状态:

  • 显性(Dominant):CAN_H比CAN_L高2V左右,逻辑上代表"0"
  • 隐性(Recessive):CAN_H和CAN_L电压接近,逻辑上代表"1"

这里有个关键点:显性电平会覆盖隐性电平。也就是说,只要有一个节点发显性,总线就是显性。这就是CAN总线仲裁的基础——谁先发"0",谁就赢。

重要参数速查表:

参数高速CAN(ISO 11898-2)低速CAN(ISO 11898-3)
最大速率1 Mbps125 kbps
显性电平CAN_H ≈ 3.5V, CAN_L ≈ 1.5VCAN_H ≈ 5V, CAN_L ≈ 0V
隐性电平CAN_H ≈ 2.5V, CAN_L ≈ 2.5VCAN_H ≈ 2.5V, CAN_L ≈ 2.5V
终端电阻120Ω(两端各一个)不需要

我的经验:我在项目中遇到过好几次CAN通信间歇性中断的问题。查到最后,都是终端电阻出了问题。要么是电阻焊点虚焊,要么是电阻值漂移。记住,高速CAN两端必须各有一个120Ω电阻,少了它,信号反射会让你怀疑人生。

3.2 数据链路层:帧结构与仲裁机制

数据链路层,负责把物理层的比特流组织成有意义的帧。CAN的帧结构设计得非常精巧,我每次讲到这里都觉得当年的工程师们是真厉害。

CAN帧主要分四种:数据帧、远程帧、错误帧、过载帧。咱们最常用的是数据帧,今天重点讲它。

一个标准数据帧长这样:

SOF | 11位ID | RTR | IDE | r0 | DLC | 数据段(0-8字节) | CRC(15位) | CRC分隔符 | ACK | EOF(7位)

你可能会问:为什么ID只有11位?嗯,这是标准帧。后来发现11位不够用,又搞了个扩展帧,ID扩展到29位。咱们后面细说。

仲裁机制是CAN总线最精彩的部分。多个节点同时发送时,谁优先级高谁先发。怎么判断优先级?看ID。ID数值越小,优先级越高。

举个例子:

  • 节点A发ID=0x100(二进制:00100000000)
  • 节点B发ID=0x200(二进制:01000000000)

两者同时发SOF后,开始逐位比较ID。第一位都是0,没问题。第二位,A是0(显性),B是1(隐性)。显性覆盖隐性,A赢了,B乖乖退出发送,转为接收。

避坑指南:我曾经在项目中遇到过一个诡异问题——某个节点总是发不出报文。查了三天,最后发现是ID设成了0x000。你想想看,全零的ID优先级最高,但同时也意味着它永远在仲裁中获胜。问题是,它发送的数据还没准备好,总线就被它占死了。所以,千万别把ID设成全零,除非你清楚自己在干什么。

3.3 报文格式:标准帧 vs 扩展帧

标准帧和扩展帧的区别,说白了就是ID长度不同。标准帧11位ID,扩展帧29位ID。扩展帧多出来的18位放在标准帧的r0和DLC之间。

扩展帧的结构:

SOF | 11位基本ID | SRR | IDE | 18位扩展ID | RTR | r1 | r0 | DLC | 数据段 | CRC | ...

注意看,扩展帧里有个SRR位(替代远程请求位)。这个位在扩展帧里必须发隐性(1),目的是保证标准帧在仲裁中永远优先于扩展帧。嗯,这是设计者故意留的后门——兼容性优先。

什么时候用标准帧,什么时候用扩展帧?

  • 标准帧:大多数传统车载网络(动力、底盘、车身)都用标准帧。11位ID够用,帧短,总线利用率高。
  • 扩展帧:需要大量节点或复杂网络时用。比如J1939协议(商用车、工程机械)就强制用扩展帧,29位ID可以编码源地址、目标地址、PDU格式等。

我个人习惯是:能用标准帧就别用扩展帧。为什么?帧短意味着传输时间短,出错概率低。我在一个项目中见过有人为了"未来扩展"全用扩展帧,结果总线负载率直接飙到80%,后来全改回标准帧才解决问题。

3.4 位填充与CRC校验

这两个机制,是CAN总线可靠性的两大护法。没有它们,车载网络早乱套了。

3.4.1 位填充(Bit Stuffing)

位填充的规则很简单:发送方连续发送5个相同电平后,自动插入一个相反电平。接收方看到5个相同电平后,自动把第6位丢弃。

为什么要这么做?

  • 保证时钟同步:CAN总线没有单独的时钟线,接收方靠电平跳变来同步时钟。如果长时间没有跳变(比如连续发15个"1"),接收方的时钟就会漂移,导致采样错误。
  • 防止误判:连续相同电平可能被误认为是帧结束或错误标志。

举个例子:

原始数据:11111 00000 11111
填充后:  111110 000001 111110
(下划线是插入的填充位)

我的经验:位填充有个副作用——它会增加帧长度。最坏情况下,每5位就插入1位填充,帧长度最多增加20%。我在做CAN负载率计算时,一般会预留20%的余量,就是考虑到位填充的影响。你算负载率时别忘了这茬。

3.4.2 CRC校验

CRC(循环冗余校验)是CAN帧的"指纹"。发送方根据帧内容计算出一个15位的CRC值,放在帧里。接收方收到后重新计算,如果对不上,就知道数据出错了。

CAN用的CRC多项式是:

x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1

这个多项式能检测出:

  • 所有单比特错误
  • 所有双比特错误
  • 所有奇数个错误
  • 所有长度≤15的突发错误
  • 99.997%的其他错误

说白了,CRC的检错能力非常强。我做了这么多年车载,真正因为CRC漏检导致数据错误的情况,一次都没遇到过。但要注意,CRC只能检错,不能纠错。发现错误怎么办?发错误帧,让发送方重传。

避坑指南:我曾经在一个项目中遇到CRC校验频繁失败的问题。查来查去,发现是CAN控制器配置错了——CRC计算范围设成了只包含数据段,没包含ID和控制段。记住,CAN的CRC计算范围是从SOF到数据段结束,包括ID、控制位、DLC和数据字节。少算一个字节,校验就废了。

3.5 小结

好了,CAN总线的基础咱们过了一遍。物理层的差分信号、数据链路层的仲裁机制、标准帧和扩展帧的区别、位填充和CRC校验——这些都是你以后用CANalyzer分析问题时必须烂熟于心的东西。

下一章,咱们开始真正上手CANalyzer。我会带你从新建工程开始,一步步配置通道、设置过滤器、录制报文。到时候你会发现,今天讲的这些基础,每一个都会在实际操作中用到。

嗯,今天就到这儿。有什么问题,咱们下节课聊。