CAN总线基础回顾:CAN2.0A/B协议帧格式、物理层特性与仲裁机制

各位同学,咱们正式开始之前,我先说句实在话。CAN总线这东西,看着简单,但真要在项目里用好,坑不少。我这些年调试过的CAN节点少说也有上百个,从最初的懵懂到现在的得心应手,中间踩过的雷能写本书。今天这一章,咱们就把CAN总线最核心的三个东西掰开揉碎了讲清楚:帧格式长什么样、物理层要注意什么、仲裁到底是怎么抢到总线的。

一、CAN2.0A/B协议帧格式

CAN总线上的数据,是以“帧”为单位传输的。就像寄快递,你得把东西装进一个标准箱子里,贴上标签,才能发出去。CAN的帧格式,就是这个标准箱子。

CAN2.0规范定义了两种帧格式:标准帧(CAN2.0A)和扩展帧(CAN2.0B)。它们最大的区别,就是ID的长度不同。

核心区别一句话:标准帧ID是11位,扩展帧ID是29位。扩展帧兼容标准帧,但反之不一定。

1. 标准帧(CAN2.0A)结构

标准帧的ID只有11位,最多支持2048个不同的ID。在J1939协议里,标准帧用得不多,但理解它是理解扩展帧的基础。

字段 位数 说明
SOF 1 帧起始,显性电平(0)
ID 11 标识符,决定优先级
RTR 1 远程帧请求位,0=数据帧,1=远程帧
IDE 1 标识符扩展位,标准帧中为显性(0)
r0 1 保留位
DLC 4 数据长度,0~8字节
Data 0~64 数据段,最多8字节
CRC 15 循环冗余校验
ACK 2 应答位
EOF 7 帧结束,隐性电平(1)

我记得刚入行那会儿,有个老工程师跟我说:“标准帧的11位ID,就像门牌号,越小的数字优先级越高。” 这句话我一直记着,后面讲仲裁的时候你就明白了。

2. 扩展帧(CAN2.0B)结构

扩展帧的ID是29位,由11位基本ID和18位扩展ID组成。J1939协议用的就是扩展帧,因为29位ID可以承载更多的信息,比如源地址、目标地址、PDU格式等等。

字段 位数 说明
SOF 1 帧起始
ID(Base) 11 基本ID
SRR 1 替代远程请求位,扩展帧中为隐性(1)
IDE 1 标识符扩展位,扩展帧中为隐性(1)
ID(Extended) 18 扩展ID
RTR 1 远程帧请求位
r1, r0 2 保留位
DLC 4 数据长度
Data 0~64 数据段
CRC 15 循环冗余校验
ACK 2 应答位
EOF 7 帧结束

个人经验:我在调试J1939协议栈时,经常遇到扩展帧ID解析错误的问题。原因往往是高低字节顺序搞反了。记住,CAN控制器发送ID时,是先发高位再发低位,跟咱们平时写代码的习惯不一样。

二、CAN总线物理层特性

物理层这东西,很多人觉得不重要,反正买现成的收发器就行了。但我要告诉你,物理层搞不好,通信质量直接拉胯。我曾经在一个项目中,因为终端电阻没配好,导致总线信号反射严重,数据帧CRC错误率高达30%。

1. 差分信号

CAN总线使用两条线:CAN_H和CAN_L。它靠这两条线的电压差来传输信号。这就是差分信号。

  • 显性电平(逻辑0): CAN_H比CAN_L高2V左右(CAN_H≈3.5V,CAN_L≈1.5V)
  • 隐性电平(逻辑1): CAN_H和CAN_L电压相等(约2.5V)

为什么要用差分?说白了就是抗干扰。外界噪声同时作用在两条线上,电压差不变,信号就不会受影响。这在工业现场、车载环境里太重要了。

2. 终端电阻

CAN总线两端必须各接一个120Ω的终端电阻。为什么是120Ω?因为CAN总线的特性阻抗大约是120Ω,接上匹配电阻可以消除信号反射。

避坑指南:我曾经在一个项目中,为了省成本,只在总线一端接了120Ω电阻。结果总线长度超过50米后,通信时好时坏。后来加上另一端的电阻,问题立刻解决。记住:终端电阻必须接在总线的最远端,不是随便找个地方焊上去就行。

3. 总线长度与波特率

CAN总线的通信距离和波特率成反比。波特率越高,能传的距离越短。下面这个表是我实际项目中验证过的经验值:

波特率 最大总线长度(经验值) 典型应用场景
1 Mbps 40 m 车内ECU通信
500 kbps 100 m 工业控制
250 kbps 250 m J1939常用速率
125 kbps 500 m 远距离监控
50 kbps 1000 m 楼宇自动化

你想想看,J1939协议为什么常用250kbps?因为250kbps既能保证250米的总线长度,又能满足大多数车辆和工业设备的实时性要求。这是工程上的一个平衡点。

三、CAN总线仲裁机制

仲裁,是CAN总线最精妙的设计之一。多个节点同时发送数据时,谁优先级高谁先发,低优先级的自动退让。整个过程不需要主控制器干预,完全靠硬件实现。

1. 仲裁原理

CAN总线是“线与”逻辑:显性电平(0)会覆盖隐性电平(1)。当两个节点同时发送数据时,它们会逐位比较ID。谁的ID先出现显性位(0),谁就赢得仲裁。

举个例子:

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

从最高位开始比较:

  • 第1位:A=0,B=0 → 相同,继续
  • 第2位:A=0,B=1 → A是显性(0),B是隐性(1)
  • 总线电平被A拉低为0,B检测到总线电平与自己发送的不一致,立即退出

结果:节点A赢得仲裁,继续发送剩余数据。节点B等待总线空闲后重发。

关键点:ID值越小,优先级越高。0x100的优先级高于0x200。这就是为什么J1939协议里,优先级高的报文(如发动机控制报文)会分配较小的ID。

2. 非破坏性仲裁

CAN总线的仲裁是“非破坏性”的。什么意思?就是赢得仲裁的节点可以继续发送数据,不会因为仲裁过程而丢失任何信息。输掉的节点只是停止发送,但不会损坏数据。

这一点跟以太网的CSMA/CD完全不同。以太网发生冲突时,所有节点都要停止发送,等待随机时间后再重试。CAN总线没有这个浪费,所以实时性更好。

3. 仲裁与J1939的关系

J1939协议充分利用了CAN的仲裁机制。它的29位ID被划分为多个字段:优先级(P)、保留位(R)、数据页(DP)、PDU格式(PF)、PDU特定(PS)、源地址(SA)。其中,优先级字段占3位,取值范围0~7,0最高,7最低。

我建议你在设计J1939应用层时,把关键报文(如刹车控制、发动机转速)的优先级设为3或更低(数值更小),把非关键报文(如温度、状态信息)的优先级设为6或7。这样,紧急报文总能抢到总线。

我的习惯:在项目初期,我会用Excel把所有报文的ID、优先级、发送周期列出来,然后模拟仲裁场景,确保高优先级报文不会因为ID冲突而被阻塞。这一步看似繁琐,但能避免后期很多麻烦。

四、本章知识体系图

下面这张图,把CAN总线基础的核心知识点串起来了。你可以把它当作一个快速索引。

CAN总线基础核心知识体系 帧格式 物理层特性 仲裁机制 标准帧 (11位ID) 扩展帧 (29位ID) 差分信号 终端电阻 线与逻辑 非破坏性 核心要点:ID越小优先级越高,显性电平覆盖隐性电平 J1939基于扩展帧,优先级字段占3位(0~7)

好了,这一章的内容就到这里。帧格式、物理层、仲裁机制,这三个东西是CAN总线的基石。后面的J1939协议栈移植,全是建立在这些基础之上的。你把这些搞透了,后面学起来就轻松多了。