1. CAN总线基础:从物理层到帧结构
大家好,我是你们的CAN总线调试讲师。做嵌入式这些年,我调试过的CAN节点少说也有上百个了。说实话,CAN总线看起来协议不复杂,但真正出问题的时候,能把人折腾得够呛。这一章我们先打好基础,把CAN协议的核心概念、物理层特性和帧结构理清楚。
为什么要先讲这些?因为我在项目里见过太多人,上来就写代码、调收发,结果总线一直报错,连是硬件问题还是软件问题都分不清。嗯,基础不牢,后面排查故障会很痛苦。
1.1 CAN协议概述
CAN,全称Controller Area Network,控制器局域网。它最早是德国Bosch公司为汽车电子开发的串行通信协议。现在不光汽车在用,工业控制、医疗设备、机器人里也随处可见。
CAN协议有几个关键特点,我挑重要的说:
- 多主总线:总线上任何一个节点都可以主动发消息,不需要主从关系
- 基于消息的寻址:不是给每个节点分配地址,而是给每条消息分配一个ID
- 非破坏性仲裁:多个节点同时发送时,ID小的优先,不会冲突
- 错误检测与自动重发:硬件自动检测错误,出错后自动重发
- 实时性强:最坏情况下的响应时间可以计算
我个人习惯把CAN总线比作一个会议室。谁想发言都可以,但ID小的(优先级高的)先讲。如果有人讲错了,大家都会指出来,讲错的人会自动重讲一遍。这个比喻虽然简单,但能帮你快速理解CAN的核心机制。
核心要点:CAN总线不是靠节点地址通信,而是靠消息ID。你发送的消息,总线上所有节点都能收到,由每个节点的硬件过滤器决定要不要处理这条消息。
1.2 差分信号与物理层
CAN物理层用的是差分信号传输。说白了,就是两根线——CAN_H和CAN_L,通过它们之间的电压差来表示逻辑状态。
为什么会用差分信号?我在一个工业现场项目中遇到过强电磁干扰的环境,单端信号根本没法用,换上CAN总线就稳了。差分信号对共模干扰有天然的抑制能力,两根线受到的干扰基本一样,差值的跳变不受影响。
CAN总线的逻辑状态有两种:
| 状态 | CAN_H电压 | CAN_L电压 | 差分电压 |
|---|---|---|---|
| 显性(Dominant) | 约3.5V | 约1.5V | 约2V |
| 隐性(Recessive) | 约2.5V | 约2.5V | 约0V |
显性位会覆盖隐性位。仲裁的时候,显性位对应的ID位为0,隐性位为1。所以ID值越小,显性位越多,优先级越高。
避坑指南:我曾经遇到过一批板子CAN通信时好时坏,排查了半天,最后发现是CAN_H和CAN_L接反了。差分信号极性接反,总线还能工作,但通信极不稳定。所以焊接和接线时一定要仔细核对。
物理层还有一些关键参数:
- 终端电阻:总线两端各接一个120Ω电阻,用于阻抗匹配,防止信号反射
- 总线长度:与通信速率成反比,1Mbps时最长约40米,125kbps时可达500米
- 节点数量:标准CAN驱动最多支持110个节点,实际建议不超过30个
1.3 CAN帧结构
CAN总线上一共定义了四种帧类型。我刚开始学的时候觉得记不住,后来发现只要理解每种帧的用途,自然就记住了。
1.3.1 数据帧
数据帧是最常用的,用来发送数据。它由7个段组成:
- 帧起始(SOF):1个显性位,标志帧的开始
- 仲裁段:包含11位(标准帧)或29位(扩展帧)的ID,以及RTR位
- 控制段:包含IDE位、保留位和4位数据长度码(DLC)
- 数据段:0~8字节的数据
- CRC段:15位CRC校验码和1位CRC界定符
- ACK段:1位ACK槽和1位ACK界定符
- 帧结束(EOF):7个隐性位
标准帧和扩展帧的区别主要在仲裁段:
| 特性 | 标准帧 | 扩展帧 |
|---|---|---|
| ID长度 | 11位 | 29位 |
| ID范围 | 0x000~0x7FF | 0x00000000~0x1FFFFFFF |
| 仲裁段长度 | 12位 | 32位 |
| 兼容性 | 所有节点都支持 | 需要扩展帧支持 |
经验之谈:我建议在CMS32项目里优先使用标准帧。扩展帧虽然ID范围大,但仲裁段更长,总线利用率会降低。除非你的系统需要超过2048个不同的消息ID,否则标准帧完全够用。
1.3.2 远程帧
远程帧用来请求数据。它没有数据段,但DLC字段要设置为请求的数据长度。发送远程帧后,目标节点收到后会发送对应的数据帧。
远程帧和数据帧的区别:
- 远程帧的RTR位为隐性(1),数据帧的RTR位为显性(0)
- 远程帧没有数据段
- 远程帧的DLC表示请求的数据长度,而不是实际发送的数据长度
我记得有一次调试一个传感器节点,主机发远程帧请求数据,传感器就是不响应。查了半天,发现是传感器固件里把远程帧处理逻辑写错了。嗯,远程帧在实际项目中用得不多,但一旦用上,调试起来确实容易踩坑。
1.3.3 错误帧
错误帧是CAN总线自我纠错的核心机制。当任何节点检测到总线错误时,就会发送错误帧,通知其他节点。
错误帧由两部分组成:
- 错误标志:6个连续相同极性的位(主动错误节点发6个显性位,被动错误节点发6个隐性位)
- 错误界定符:8个隐性位
CAN节点有3种错误状态:
| 状态 | 条件 | 行为 |
|---|---|---|
| 主动错误 | 发送错误计数≤127 | 正常通信,检测到错误时发送主动错误帧 |
| 被动错误 | 发送错误计数128~255 | 只能发送被动错误帧,不能主动干扰总线 |
| 总线关闭 | 发送错误计数>255 | 完全断开与总线的连接 |
避坑指南:我曾经调试一个系统,发现某个节点时不时掉线,但过一会儿又自己恢复了。用CAN分析仪抓包一看,这个节点的发送错误计数一直在涨,到255后就总线关闭了,等计数降下来又重新连上。最后发现是它的CAN收发器供电不稳导致的。所以,遇到节点间歇性掉线,先查硬件供电和地线。
1.3.4 过载帧
过载帧用于节点在接收数据时,因为内部处理不过来而请求延迟。它和错误帧结构类似,也是由过载标志和过载界定符组成。
过载帧的触发条件:
- 接收节点内部缓冲区满,需要更多时间处理
- 在帧间隔期间检测到显性位
说实话,过载帧在实际项目中很少见到。现在的MCU处理速度都很快,只要软件设计合理,很少会出现处理不过来的情况。如果你在调试时频繁看到过载帧,那说明你的系统负载已经很高了,需要优化软件或者降低总线速率。
1.4 CAN总线知识体系总览
下面这张图把CAN总线的基础知识结构梳理了一下,方便你建立整体认知:
1.5 本章小结
这一章我们覆盖了CAN总线最基础的三块内容:协议概述、物理层和帧结构。你不需要一下子全记住,但至少要理解:
- CAN总线靠差分信号传输,抗干扰能力强
- 消息ID决定优先级,ID越小优先级越高
- 数据帧是最常用的帧类型,标准帧11位ID够用就优先用
- 错误帧是排查故障的重要线索,要学会看错误计数