2. CAN总线基础:CAN协议物理层与数据链路层、CAN报文帧格式、CAN总线仲裁机制
好,咱们正式开始聊CAN总线。说实话,CAN总线是我入行车载网络接触的第一个协议,也是到目前为止,我见过最“聪明”的一个总线协议。为什么这么说?你想想看,它诞生于上世纪80年代,那时候的微控制器性能弱得可怜,但CAN协议的设计者硬是用一套精巧的机制,让多节点在一条双绞线上高效通信,还不打架。今天这一讲,我就带你把这套机制的核心——物理层、数据链路层、报文帧格式和仲裁机制——彻底吃透。
2.1 物理层:为什么是差分信号?
CAN总线的物理层,说白了就是一根双绞线,两根线分别叫CAN_H和CAN_L。它用的是差分信号传输。我刚开始接触时也纳闷:为什么不用单端信号?非得搞两根线?
原因很简单:抗干扰。车载环境有多恶劣?发动机点火、电机启停、电磁干扰到处都是。单端信号在这种环境下,信号很容易被“污染”。差分信号就不一样了——它传输的是两根线上的电压差。干扰来了,两根线上的电压同时被抬高或拉低,但差值基本不变。嗯,这就是它能在车里稳定跑几十米的原因。
关键参数:
- 隐性电平(Recessive):CAN_H ≈ 2.5V,CAN_L ≈ 2.5V,差分电压 ≈ 0V,逻辑值为“1”
- 显性电平(Dominant):CAN_H ≈ 3.5V,CAN_L ≈ 1.5V,差分电压 ≈ 2V,逻辑值为“0”
这里有个细节:显性电平会“覆盖”隐性电平。什么意思?就是只要有一个节点拉出显性电平,总线就是显性的。这个特性,是后面仲裁机制的基础。
个人经验:我在做某款车型的CAN网络测试时,遇到过总线信号畸变的问题。排查了半天,最后发现是CAN_H和CAN_L的绞距不够密。记住,双绞线的绞距直接影响共模抑制能力,别为了省成本随便用普通线缆。
2.2 数据链路层:CAN的核心智慧
数据链路层,是CAN协议最精彩的部分。它定义了报文怎么封装、怎么发送、怎么检测错误。我常说,CAN的数据链路层就像一套“交通规则”,让所有节点在一条路上有序行驶。
CAN的数据链路层分为两个子层:
- LLC(逻辑链路控制):负责报文过滤、通知等上层服务
- MAC(介质访问控制):负责帧封装、仲裁、应答、错误检测等
MAC层是重点。它采用CSMA/CA(载波监听多路访问/冲突避免)机制。每个节点在发送前先监听总线,空闲了才发。但万一两个节点同时发呢?这就引出了仲裁机制。
2.3 CAN报文帧格式:标准帧 vs 扩展帧
CAN报文有四种帧类型:数据帧、远程帧、错误帧、过载帧。咱们最常用的是数据帧。数据帧又分两种:标准帧(11位ID)和扩展帧(29位ID)。
我直接给你画个结构图:
标准帧(11位ID):
| SOF | 11位ID | RTR | IDE | r0 | DLC | 数据段(0-8字节) | CRC | ACK | EOF |
扩展帧(29位ID):
| SOF | 11位ID | SRR | IDE | 18位ID | RTR | r1 | r0 | DLC | 数据段(0-8字节) | CRC | ACK | EOF |
每个字段的含义,我挑几个重点说:
- SOF(Start of Frame):1位显性,表示帧开始
- ID(标识符):决定优先级,数值越小优先级越高
- RTR(Remote Transmission Request):区分数据帧(显性)和远程帧(隐性)
- DLC(Data Length Code):数据长度,0-8字节
- CRC(Cyclic Redundancy Check):15位CRC校验 + 1位隐性定界符
- ACK(Acknowledge):接收节点在ACK槽位拉显性,表示收到
避坑指南:我曾经在一个项目中,发现某个节点总是收不到某些报文。查了半天,原来是该节点的验收滤波配置错了,把扩展帧当标准帧过滤掉了。记住,标准帧和扩展帧的ID格式不同,滤波时要区分对待。
2.4 CAN总线仲裁机制:不丢数据的“吵架”
仲裁机制,是CAN总线最让我拍案叫绝的设计。多个节点同时发送时,它们不会“撞车”丢数据,而是通过逐位仲裁,让优先级最高的节点继续发送,其他节点自动转为接收。
怎么做到的?
- 每个节点在发送ID位时,同时监听总线电平
- 如果自己发送的是隐性(1),但总线上是显性(0),说明有更高优先级的节点在发
- 该节点立即停止发送,转为接收模式
- 优先级最高的节点(ID最小)不受影响,继续发送
举个例子:节点A的ID是0x100,节点B的ID是0x200。同时发送时,从ID的最高位开始比。0x100的二进制是0001 0000 0000,0x200是0010 0000 0000。第6位(从高位算起)上,A发0(显性),B发1(隐性),B检测到总线是显性,知道自己输了,乖乖退出。
关键点:仲裁过程不破坏任何数据,优先级低的节点只是“让行”,等总线空闲后再重发。这就是CAN总线“非破坏性逐位仲裁”的精髓。
你想想看,如果换成传统的以太网CSMA/CD,冲突了就得重传,效率低得多。CAN这种设计,在实时性要求高的车载环境里,简直是天作之合。
2.5 错误检测与处理
CAN总线有5种错误检测机制:
- 位错误:发送节点发送的电平与监听到的不一致
- 填充错误:连续5个相同电平后,没有插入相反电平
- CRC错误:接收节点计算的CRC与发送的不一致
- 格式错误:帧格式不符合规范
- 应答错误:发送节点在ACK槽没收到显性应答
一旦检测到错误,节点会发送错误帧(6个显性位 + 8个隐性位),通知所有节点丢弃当前报文。然后,出错节点会根据错误计数器决定是否进入“总线关闭”状态。
我的建议:在实际项目中,别把错误计数器设得太敏感。我见过一个案例,某个节点因为偶尔的电磁干扰频繁报错,结果把自己“关”出总线了。适当调整错误阈值,能提高系统的鲁棒性。
2.6 小结
CAN总线的基础,说白了就是三件事:物理层用差分信号抗干扰,数据链路层用CSMA/CA加仲裁避免冲突,报文帧格式用ID决定优先级。这些设计,让CAN在车载网络里稳坐“老大哥”的位置几十年。
下一讲,我们会深入CAN的更高层协议,比如J1939和CANopen。但今天这些基础,你得先刻在脑子里。嗯,就这样,咱们下节课见。