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总线的基石。后面的J1939协议栈移植,全是建立在这些基础之上的。你把这些搞透了,后面学起来就轻松多了。