第2章:CAN总线基础回顾
各位同学,在正式开始Bootloader开发之前,咱们得先把CAN总线这个基础打牢。我做了这么多年汽车电子,见过太多人因为CAN基础不扎实,在刷写协议上栽跟头。这一章,我就带大家把CAN总线的几个核心知识点过一遍。
2.1 CAN物理层:信号怎么在线上跑
CAN总线用两根线——CAN_H和CAN_L,靠差分信号传输。说白了,就是看两根线的电压差来判断是0还是1。
| 信号状态 | CAN_H电压 | CAN_L电压 | 差分电压 |
|---|---|---|---|
| 显性(逻辑0) | 3.5V | 1.5V | 2.0V |
| 隐性(逻辑1) | 2.5V | 2.5V | 0V |
为什么用差分?抗干扰能力强。我在一个项目里遇到过,线束长了之后信号反射严重,后来发现是终端电阻没焊好。记住,CAN总线两端必须各接一个120Ω电阻,少了它,通信就别想了。
注意:终端电阻不是随便选的。120Ω是标准值,匹配的是双绞线的特性阻抗。我曾经见过有人用100Ω代替,结果高速通信时波形畸变,丢帧率飙升。
2.2 CAN数据帧结构:报文长什么样
CAN数据帧分好几类,咱们做Bootloader最常用的是数据帧。一个标准数据帧长这样:
SOF + 11位ID + RTR + IDE + r0 + 4位DLC + 0~8字节数据 + 15位CRC + CRC分隔符 + ACK + ACK分隔符 + EOF
我给大家拆开讲几个关键部分:
- SOF(Start of Frame):1个显性位,告诉总线上所有节点“我要发数据了”
- ID(标识符):11位(标准帧)或29位(扩展帧),决定优先级
- DLC(数据长度码):4位,表示数据段有几个字节,范围0~8
- 数据段:0~8字节,咱们刷写时用的数据就放这里
- CRC:15位校验,保证数据没被干扰
关键点:Bootloader刷写时,数据帧的DLC通常设为8。为什么?因为一次传8个字节效率最高。我见过有人用DLC=4传数据,刷一个256KB的固件,多花了一倍时间。
2.3 CAN总线仲裁机制:谁先说话
CAN总线是广播式的,所有节点都能同时发数据。那冲突了怎么办?靠仲裁。
仲裁的原理很简单:谁发的ID小,谁赢。因为显性位(0)会覆盖隐性位(1)。
举个例子:
- 节点A发ID=0x123(二进制:0001 0010 0011)
- 节点B发ID=0x456(二进制:0100 0101 0110)
从第一位开始比。A发0,B发0,平手。第二位,A发0,B发1。这时候A的显性位把B的隐性位覆盖了,B检测到总线上的电平和自己发的不一样,就知道输了,乖乖退出。
实战技巧:刷写时,诊断请求的ID通常设得比应用报文小。这样刷写指令永远优先。我习惯把刷写相关的ID设在0x700~0x7FF范围,比普通CAN报文优先级高。
2.4 CAN错误处理:出了问题怎么办
CAN总线有5种错误类型,我列个表:
| 错误类型 | 检测机制 | 常见原因 |
|---|---|---|
| 位错误 | 发送节点监控总线电平 | 总线短路、干扰 |
| 填充错误 | 检测连续5个相同位 | 同步丢失 |
| CRC错误 | 接收节点计算CRC | 数据被干扰 |
| 格式错误 | 检测固定格式位 | 协议违规 |
| 应答错误 | 发送节点未收到ACK | 接收节点故障 |
每个节点都有两个计数器:TEC(发送错误计数)和REC(接收错误计数)。错误多了,节点会进入三种状态:
- 主动错误:正常状态,能发能收,出错时发主动错误帧
- 被动错误:能发能收,但出错时只能发被动错误帧
- 总线关闭:彻底不能收发,等于离线
避坑指南:我曾经在一个项目中,刷写到一半ECU突然“失联”了。查了半天,发现是CAN控制器进入了总线关闭状态。原因是刷写时总线负载太高,连续发送失败导致TEC超标。后来我在刷写流程里加了错误恢复机制,每次发送失败后等待一段时间再重试,问题就解决了。
2.5 知识结构总览
下面这张图把CAN总线的基础知识串起来了,大家可以对照着看:
这张图把CAN总线的四个核心模块串起来了。物理层是基础,数据帧是载体,仲裁机制解决冲突,错误处理保证可靠性。做Bootloader开发,这四个模块缺一不可。
我的建议:刚开始学CAN的同学,别急着看协议栈代码。先把物理层和帧结构搞明白。我当年就是先拿示波器看CAN波形,看懂了显性隐性的变化,后面学仲裁和错误处理就顺了。