第2章:CAN总线基础
各位同学,今天我们来聊聊CAN总线。说实话,CAN总线是我在车载网络领域打交道最多的协议之一。从早期的动力系统到现在的智能座舱,到处都有它的身影。我个人觉得,理解CAN总线是进入车载网络世界的第一道门槛。
2.1 CAN总线的工作原理
CAN总线,全称是Controller Area Network。它最早是博世公司为汽车开发的。为什么汽车需要它?你想想看,一辆车里有几十个ECU,如果每个ECU之间都拉一堆线,那车重得飞不起来。
CAN总线的工作原理,说白了就是一条双绞线,把所有节点都挂上去。节点之间通过这条线通信。我习惯把CAN总线比作一个会议室——谁想发言,谁就抢话筒。
这里有个关键点:CAN总线是多主总线。什么意思?就是每个节点都可以主动发消息,不需要等主机来问。这在汽车里太重要了——比如安全气囊要爆的时候,它可没时间等主机轮询。
核心要点:
- CAN总线使用差分信号传输,抗干扰能力强
- 两条线:CAN_H和CAN_L,电压差决定逻辑电平
- 显性电平(逻辑0)和隐性电平(逻辑1)
- 总线空闲时,所有节点都输出隐性电平
我在项目中遇到过一个问题:某次测试时,CAN总线突然通信中断。查了半天,发现是CAN_H和CAN_L接反了。嗯,这种低级错误,犯过一次就再也不会忘了。
2.2 CAN报文帧结构
CAN总线上传输的数据,我们叫它报文帧。总共有四种类型:数据帧、远程帧、错误帧、过载帧。其中数据帧是最常用的,我估计你90%的时间都在跟它打交道。
2.2.1 数据帧
数据帧就是用来传输数据的。它的结构是这样的:
帧起始(SOF) + 仲裁场 + 控制场 + 数据场 + CRC场 + ACK场 + 帧结束(EOF)
我来拆开讲讲:
- 帧起始(SOF):1个显性位,告诉总线「我要开始发了」
- 仲裁场:包含11位ID(标准帧)或29位ID(扩展帧),还有RTR位
- 控制场:6位,包含IDE位、保留位和数据长度码(DLC)
- 数据场:0-8字节,这就是你要传的数据
- CRC场:15位CRC校验码+1位CRC界定符
- ACK场:2位,接收节点确认收到
- 帧结束(EOF):7个隐性位
个人经验:数据长度码(DLC)最多只能表示8字节。为什么是8?因为CAN总线设计时考虑到实时性,8字节刚好够传一个发动机状态或一个车轮速度。后来CAN FD扩展到了64字节,那是后话了。
2.2.2 远程帧
远程帧,说白了就是「请求帧」。一个节点发远程帧,意思是「谁有数据?给我一份」。远程帧和数据帧结构很像,区别在于RTR位是隐性(1)。
我曾经踩过一个坑:远程帧的数据场是空的,但DLC必须填上你期望接收的数据长度。有一次我忘了设DLC,结果对方节点发过来的数据长度不对,解析全乱套了。
2.2.3 错误帧
错误帧是CAN总线自我纠错的机制。当节点检测到总线错误时,它会主动发送错误帧。错误帧由两部分组成:
- 错误标志:6个连续显性位(主动错误)或6个连续隐性位(被动错误)
- 错误界定符:8个隐性位
这里要注意:错误帧不是用来传数据的,它是用来告诉其他节点「刚才那帧有问题,大家别用了」。
避坑指南:我曾经调试一个项目,发现CAN总线频繁出现错误帧。查到最后,是终端电阻没接对。CAN总线两端必须各接一个120欧姆电阻,少一个都不行。这个细节,新手特别容易忽略。
2.2.4 过载帧
过载帧,顾名思义,就是节点忙不过来了。当一个节点处理不过来时,它会发过载帧,让发送节点等一等。过载帧的结构和错误帧很像,但触发条件不同。
过载帧的格式:
- 过载标志:6个显性位
- 过载界定符:8个隐性位
说实话,过载帧在实际项目中不太常见。现在的MCU处理能力都挺强,很少出现处理不过来的情况。但如果你在做网关或者数据记录仪,还是要注意一下。
2.3 CAN总线仲裁机制
仲裁机制,这是CAN总线最巧妙的设计之一。为什么需要仲裁?因为多个节点可能同时发数据,总线上只能有一个说话。
CAN总线的仲裁机制,我总结成一句话:ID越小,优先级越高。
具体怎么仲裁?看这个例子:
节点A发送ID: 0x123 (二进制: 0001 0010 0011)
节点B发送ID: 0x456 (二进制: 0100 0101 0110)
仲裁过程:
位1: A发0, B发0 → 都是显性,继续
位2: A发0, B发1 → A显性,B隐性 → A获胜
为什么A赢了?因为A的ID第二位是0(显性),B是1(隐性)。显性位会覆盖隐性位,所以A继续发,B退出发送。
关键理解:
- 仲裁是在发送ID的过程中完成的
- 仲裁失败的节点自动转为接收模式
- 仲裁不破坏数据,失败的节点下次再试
- ID越小,优先级越高(0x000优先级最高)
我记得刚学CAN总线时,有个问题困扰了我很久:如果两个节点ID相同怎么办?答案是:CAN协议不允许两个节点有相同的ID。每个节点必须有唯一的ID,否则仲裁会出问题。
还有一个细节:数据帧和远程帧也能仲裁。数据帧的RTR位是显性(0),远程帧是隐性(1)。所以数据帧的优先级高于远程帧。这个设计很合理——你想想看,传数据肯定比请求数据更紧急。
实用建议:设计CAN网络时,把关键消息的ID设小一点。比如安全气囊、刹车系统这些,ID可以设成0x001、0x002。车窗、空调这些非安全相关的,ID设大一点。这个习惯,我在做第一个项目时就养成了。
好了,CAN总线的基础知识就讲到这里。下一章我们会深入CAN的物理层和位时序,到时候再聊。