二、CAN协议详解:CAN2.0A/B协议帧格式

好,咱们接着聊。上一章我讲了CAN总线的基本概念,说白了就是一条差分信号线,能让多个节点在一块儿通信。但光有物理层还不够,你得有个规矩,告诉大家什么时候该谁说话、说什么、说错了怎么办。这个规矩,就是CAN协议。

我个人习惯把CAN协议比作一个会议室里的发言规则。每个人都有一个编号(ID),谁编号优先级高谁先讲。讲的内容分几种:有的是正式发言(数据帧),有的是点名提问(远程帧),有的是喊“你刚才说错了”(错误帧),还有的是喊“慢点,我跟不上”(过载帧)。

嗯,咱们今天就一个一个拆开看。

2.1 帧格式总览:标准帧 vs 扩展帧

CAN2.0协议分两个版本:A和B。CAN2.0A只支持11位ID,也就是标准帧。CAN2.0B兼容A,同时支持29位ID,也就是扩展帧。

你想想看,11位ID最多只能有2048个不同的标识符。早期够用,后来汽车电子越来越复杂,一个车上几十个ECU,11位就不够分了。所以扩展帧就出来了,29位ID,能支持5亿多个标识符。

我在项目中遇到过一个坑:有些老设备只支持CAN2.0A,你发个扩展帧过去,它直接不理你,甚至报错。所以混用的时候一定要确认清楚。

特性 标准帧 (CAN2.0A) 扩展帧 (CAN2.0B)
ID长度 11位 29位
帧头开销 较小 稍大
兼容性 所有CAN控制器 需支持CAN2.0B
应用场景 简单系统、老设备 复杂网络、多节点

2.2 数据帧:最常用的帧

数据帧,说白了就是“我要说点正事”。这是咱们用得最多的帧类型。门控系统里,刷卡成功、指纹验证通过、电梯呼叫,这些信息都是用数据帧传的。

一个数据帧长什么样?我习惯把它分成七段来看:

  • 帧起始(SOF):一个显性位,告诉总线“我要开始说话了”。
  • 仲裁段:包含ID和RTR位。这里决定了谁能抢到总线。
  • 控制段:包含IDE位和DLC(数据长度码)。DLC告诉你后面跟了多少字节数据。
  • 数据段:0到8个字节,真正要传的信息。
  • CRC段:15位CRC校验码,加上一个隐性位作为界定符。
  • ACK段:接收节点在这里回应,告诉发送方“我收到了”。
  • 帧结束(EOF):7个隐性位,表示帧结束。

重点记住:数据段最多8个字节。为什么是8个?因为CAN总线设计之初就考虑到了实时性,8字节刚好够传一个控制命令或传感器数据,又不至于占用总线太久。

举个例子,门控系统里传一个“刷卡成功”的消息:

// 假设ID为0x123,数据长度为2字节
// 数据内容:0x01 表示刷卡成功,0x05 表示用户权限等级
帧起始: 0 (显性)
仲裁段: ID = 0x123 (二进制: 000100100011)
         RTR = 0 (数据帧)
控制段: IDE = 0 (标准帧)
         DLC = 2 (2字节数据)
数据段: 0x01 0x05
CRC段: 15位CRC + 1位界定符
ACK段: 接收节点拉低ACK槽
帧结束: 7个隐性位

2.3 远程帧:我要你说话

远程帧跟数据帧长得几乎一样,只有一个关键区别:RTR位是隐性(1)

远程帧的意思是:“我不说话,我要你说话。” 比如门控系统里的主控制器想知道某个门磁的状态,就可以发一个远程帧,指定ID,那个ID对应的节点收到后,就会回复一个数据帧。

避坑指南:我曾经在调试一个门禁系统时,发现主控发了远程帧后,从机没反应。查了半天,原来是从机程序里没实现远程帧响应。很多初学者以为远程帧是自动响应的,其实不是——你得在软件里手动处理。

远程帧没有数据段,DLC字段表示期望接收的数据长度。比如DLC=4,意思是“你回我一个4字节的数据”。

2.4 错误帧:出问题了

错误帧是CAN协议里最“暴力”的帧。一旦某个节点检测到错误,它会立刻发送6个连续的显性位,强行破坏当前帧,告诉所有人:“刚才那帧有问题,别用了!”

错误帧分两种:

  • 主动错误帧:由处于“主动错误状态”的节点发出。6个显性位,够狠。
  • 被动错误帧:由处于“被动错误状态”的节点发出。6个隐性位,比较温柔。

为什么会这样?CAN协议里每个节点都有一个错误计数器。连续出错多了,节点会从“主动错误”降级到“被动错误”,再严重就变成“总线关闭”状态,彻底闭嘴。

我记得有一次在实验室调试,一个节点因为硬件问题不停地发错误帧,整个总线都被它拖垮了。后来查出来是CAN收发器的共模电压出了问题。嗯,硬件设计上一定要做好隔离和滤波。

2.5 过载帧:慢点,我跟不上

过载帧跟错误帧有点像,但含义完全不同。过载帧的意思是:“我还没准备好,你等一下。”

什么时候会发过载帧?

  • 接收节点的内部缓冲区满了,处理不过来。
  • 接收节点在帧间隔期间需要额外的时间。

过载帧由6个显性位组成,后面跟着8个隐性位的过载界定符。它可以在帧间隔期间发送,但不能在帧中间发送。

注意:过载帧在现在的CAN网络中其实很少见了。因为现代CAN控制器处理速度很快,缓冲区也够大。但如果你在做低端MCU或者老旧系统的兼容设计,还是得考虑这个情况。

2.6 帧间隔:喘口气

帧间隔不是一种帧,而是一段空闲时间。任何节点在发送完一帧后,都必须等待至少3个隐性位(帧间隔),才能发送下一帧。

为什么要有帧间隔?说白了就是给总线一个“喘息”的机会。让接收节点有时间处理刚收到的数据,也让总线状态稳定下来。

帧间隔分两部分:

  • 间歇场:3个隐性位。所有节点在这段时间内都不能发送数据。
  • 总线空闲:任意长度的隐性位。直到有节点开始发送SOF。

对于被动错误节点,帧间隔还会多出8个隐性位的“挂起传输”时间。这是对犯错节点的一种惩罚机制。

2.7 实际应用中的帧选择

在门控系统里,我一般这样用:

  • 数据帧:传刷卡信息、门状态、电梯指令。占90%以上的通信量。
  • 远程帧:主控轮询各个门磁状态。但说实话,我现在更推荐用数据帧主动上报,效率更高。
  • 错误帧:硬件故障时自动触发。软件上基本不用管,但要做好日志记录。
  • 过载帧:基本用不到。如果出现了,说明你的系统设计有问题,得优化。

总结一下:CAN协议的五种帧,各有各的用途。数据帧和远程帧是“干活”的,错误帧和过载帧是“救场”的,帧间隔是“休息”的。搞懂了这些,你就能理解CAN总线为什么这么可靠了。

下一章咱们聊聊CAN的唤醒与休眠机制,这可是门控系统低功耗设计的关键。到时候我会分享一个我在项目里踩过的坑——休眠唤醒时序没调好,导致整个系统功耗翻了三倍。嗯,到时候细说。