第2章:CAN基础回顾

各位同学,在正式进入CANopen协议之前,咱们得先把CAN总线的基础打牢。说实话,我见过太多工程师一上来就啃CANopen协议栈,结果遇到总线通信问题就抓瞎——根源往往出在CAN底层。今天这一章,我就带大家把CAN总线的物理层、数据帧、仲裁机制和错误处理这四块硬骨头啃下来。

2.1 CAN总线物理层

CAN总线物理层,说白了就是信号怎么在线上跑。它用的是差分信号传输,两根线:CAN_H和CAN_L。我刚开始接触时也觉得奇怪,为什么非要用两根线?后来在项目现场吃过亏才明白——差分信号抗干扰能力是真的强。

关键参数:

  • 显性电平(Dominant):CAN_H ≈ 3.5V,CAN_L ≈ 1.5V,逻辑0
  • 隐性电平(Recessive):CAN_H ≈ 2.5V,CAN_L ≈ 2.5V,逻辑1
  • 总线终端电阻:120Ω(两端各一个)

嗯,这里要注意:显性电平会覆盖隐性电平。这个特性直接决定了后面的仲裁机制。我曾经在一个项目中,终端电阻没焊好,结果总线信号反射得一塌糊涂,通讯时好时坏。排查了整整两天才找到问题。

CAN总线的拓扑结构很简单,就是一条总线挂多个节点。节点数理论上可以到110个,但实际项目中我建议别超过30个。为什么?因为节点多了,总线负载电容变大,信号边沿会变缓,通讯距离和速率都会受影响。

总线长度 最大波特率
40m 1 Mbps
100m 500 kbps
500m 125 kbps
1km 50 kbps

你想想看,如果要在100米距离上跑1Mbps,信号早就畸变得没法看了。所以选波特率时,一定要先算好总线长度。

2.2 CAN数据帧结构

CAN数据帧有标准帧和扩展帧两种。标准帧11位ID,扩展帧29位ID。我个人习惯在CANopen中只用标准帧,因为11位ID已经够用了,扩展帧反而增加了协议处理的复杂度。

来看一个标准数据帧的结构:

SOF | 11位ID | RTR | IDE | r0 | DLC | 数据段(0-8字节) | CRC | ACK | EOF

每个字段的含义:

  • SOF(Start of Frame):1位显性位,同步所有节点
  • ID(Identifier):11位,决定优先级
  • RTR(Remote Transmission Request):区分数据帧和远程帧
  • DLC(Data Length Code):4位,表示数据字节数(0-8)
  • 数据段:最多8字节
  • CRC:15位校验 + 1位定界符
  • ACK:2位,接收节点应答
  • EOF:7位隐性位,帧结束

个人经验:DLC字段虽然可以表示0-8,但实际项目中我建议数据段尽量填满8字节。因为CAN帧的协议开销是固定的,多传几个字节并不会增加太多总线负载。我曾经优化过一个电机控制项目,把多个状态量打包到一个8字节帧里,总线利用率直接降了一半。

2.3 CAN总线仲裁机制

仲裁机制是CAN总线最巧妙的设计之一。多个节点同时发送时,谁优先级高谁先发。怎么判断优先级?看ID,ID越小优先级越高。

具体过程是这样的:所有发送节点在SOF之后同步开始逐位发送ID。每个节点在发送位的同时,也会监听总线电平。如果自己发送的是隐性位(1),但总线上是显性位(0),说明有更高优先级的节点在发送,自己就乖乖退出发送。

为什么会这样?因为显性位会覆盖隐性位。你想想看,如果两个节点同时发送,一个ID=0x100,一个ID=0x200。在ID的最高位,0x100是0(显性),0x200是1(隐性)。总线被拉成显性,0x200的节点检测到冲突,立刻停止发送。

避坑指南:我曾经在一个项目中,把两个节点的ID设成了0x100和0x101。结果发现0x100的节点总是能抢到总线,0x101的节点经常发不出去。后来才意识到,这两个ID太接近了,仲裁时几乎每次都是0x100赢。所以设计ID分配时,建议给不同优先级的节点留出足够的间隔。

仲裁机制的好处是:总线不会因为冲突而浪费带宽。失败的节点自动转为接收模式,等总线空闲后再重发。整个过程对上层协议完全透明。

2.4 CAN错误处理机制

CAN总线的错误处理机制,可以说是它能在工业环境中站稳脚跟的关键。它有一套完整的错误检测和故障隔离机制。

错误类型有五种:

  • 位错误:发送节点发送的位和监听到的位不一致
  • 填充错误:连续6个相同电平(违反位填充规则)
  • CRC错误:接收节点计算的CRC与发送的不一致
  • 形式错误:固定格式的位段出现非法电平
  • 应答错误:发送节点在ACK槽没收到显性位

每个节点都有两个计数器:发送错误计数器(TEC)和接收错误计数器(REC)。错误多了,计数器会累加。当TEC或REC超过某个阈值,节点状态会发生变化:

节点状态 条件 行为
错误主动 TEC < 128 且 REC < 128 正常发送,检测到错误时发送主动错误帧
错误被动 TEC > 127 或 REC > 127 只能发送被动错误帧,且发送前要等待8个隐性位
总线关闭 TEC > 255 完全断开与总线的连接

关键点:总线关闭状态是自动恢复的。节点会在检测到128次11个连续隐性位后,自动回到错误主动状态。这个机制保证了总线不会因为一个故障节点而瘫痪。

我记得有一次在现场调试,一个电机驱动器频繁报错。用CAN分析仪抓包发现,那个节点一直在发送主动错误帧。查了半天,原来是它的CAN收发器供电电压偏低,导致发送的显性位电平不够。其他节点收不到正确的信号,就不断回复错误帧。最后换了电源模块才解决。

嗯,这里要提醒大家:错误处理机制虽然强大,但不要完全依赖它。在项目开发阶段,我建议把每个节点的TEC和REC值通过CANopen的SDO读出来,监控错误计数器的变化趋势。如果某个节点的错误计数器持续增长,说明硬件或布线有问题,要尽早排查。

好了,CAN基础就回顾到这里。下一章我们正式进入CANopen协议的核心——对象字典和通信对象。到时候你会发现,有了CAN底层的扎实基础,理解CANopen会轻松很多。