第2章:CAN协议基础回顾:CAN 2.0A/B帧格式、CAN ID与仲裁、CAN总线物理层要点

各位同学,咱们开始第二讲。在做Bootloader之前,我建议先把CAN协议的基础再过一遍。别嫌啰嗦,我见过太多人栽在帧格式和仲裁上。说白了,Bootloader升级失败,十有八九是协议细节没吃透。

2.1 CAN 2.0A与2.0B:标准帧和扩展帧

CAN协议最早是1986年由Bosch公司开发的。后来分成了两个版本:CAN 2.0A和CAN 2.0B。它们最大的区别,就是ID的长度。

  • CAN 2.0A(标准帧):11位ID。帧头比较短,适合节点不多的系统。
  • CAN 2.0B(扩展帧):29位ID。帧头更长,能容纳更多节点和更复杂的优先级设计。

我个人习惯在Bootloader里统一用扩展帧。为什么?因为29位ID可以方便地嵌入更多信息,比如目标节点地址、数据包序号、命令类型等。你想想看,一个ID就能搞定的事情,何必再额外加数据字节?

关键点:CAN 2.0B的控制器可以接收2.0A的帧,但反过来不行。如果你的Bootloader要兼容老设备,记得检查CAN控制器是否支持2.0B。

2.2 CAN帧格式详解

一个完整的CAN数据帧,由以下几个部分组成。我当年刚学的时候,总觉得这些字段记不住。后来做项目时反复查手册,慢慢就刻在脑子里了。

字段 长度 说明
SOF 1 bit 帧起始,显性电平表示总线开始传输
仲裁场 11或29 bit 包含ID和RTR位,决定谁能抢到总线
控制场 6 bit 包含IDE位、保留位和DLC(数据长度码)
数据场 0~8 byte 实际传输的数据。Bootloader里通常填满8字节
CRC场 16 bit 循环冗余校验,检测传输错误
ACK场 2 bit 接收节点发送显性电平确认收到
EOF 7 bit 帧结束,隐性电平

嗯,这里要注意:DLC字段虽然可以表示0到8,但在Bootloader里我建议固定用8。因为升级数据包通常都是整块传输,用满8字节效率最高。我曾经遇到一个项目,工程师为了省带宽把DLC设成可变长度,结果解析逻辑搞得一团糟,最后还得改回来。

2.3 CAN ID与仲裁机制

仲裁是CAN总线最巧妙的设计之一。说白了,就是多个节点同时发数据时,谁优先级高谁先发。

仲裁的规则很简单:ID值越小,优先级越高。为什么?因为显性电平(逻辑0)会覆盖隐性电平(逻辑1)。所以ID全是0的节点,在仲裁时肯定赢。

在Bootloader场景下,我建议这样分配ID:

  • 主机(上位机):使用低优先级ID,比如0x7FF(标准帧最大ID)。因为主机只负责下发数据,不需要抢总线。
  • 从机(目标设备):使用高优先级ID,比如0x001。因为从机需要及时回复确认帧,不能让主机等太久。

避坑指南:我曾经在一个项目中,把主机和从机的ID设反了。结果主机每次发数据都要跟从机抢总线,升级速度慢得像蜗牛。后来改成主机用高ID、从机用低ID,问题立刻解决。

2.4 CAN总线物理层要点

物理层决定了你的Bootloader能不能稳定工作。我见过不少案例,协议栈写得完美,但物理层没搞好,升级到一半就断线。

几个关键参数:

  • 总线电平:CAN_H和CAN_L的差分电压。显性时约2V,隐性时约0V。
  • 终端电阻:必须在总线两端各接一个120Ω电阻。没有终端电阻,信号会反射,导致通信错误。
  • 波特率:常见的有125kbps、250kbps、500kbps、1Mbps。Bootloader里我建议用250kbps或500kbps,兼顾速度和稳定性。

你想想看,如果终端电阻没接,或者接了一个120Ω但另一个是100Ω,总线上的信号就会像弹簧一样来回弹。我曾经在实验室里排查了一整天,最后发现是终端电阻焊错了位置。

警告:千万不要在Bootloader升级过程中改变波特率!一旦双方速率不匹配,整个总线都会瘫痪。我见过有人试图在升级中途切换波特率来提速,结果所有节点都掉线了,最后只能断电重启。

2.5 小结

这一章我们回顾了CAN 2.0A/B的帧格式、ID仲裁机制和物理层要点。这些内容看似基础,但每一个细节都可能成为Bootloader升级的绊脚石。下一章,我会带你看看如何把这些知识应用到实际的Bootloader协议设计中。

记住:CAN总线不是玄学,是工程。把基础打牢,后面的路就好走了。