3、CAN协议层:数据帧格式、远程帧、错误帧、过载帧、帧间隔
好,咱们今天来啃CAN协议层这块硬骨头。说实话,很多工程师做CAN驱动,寄存器配得溜,但一说到协议层就含糊。我个人觉得,不理解协议层,你写出来的驱动就是“盲人摸象”。
CAN协议定义了五种帧类型:数据帧、远程帧、错误帧、过载帧、帧间隔。咱们一个一个拆开讲。
3.1 数据帧:最常用的“快递包裹”
数据帧,说白了就是用来发送数据的。你在项目中90%的时间都在跟它打交道。
数据帧的格式分两种:标准帧(11位ID)和扩展帧(29位ID)。我刚开始做项目时,总觉得扩展帧高大上,啥都用29位。后来发现,很多老设备只认11位,踩过坑才老实。
来看标准帧的结构:
SOF | 11位ID | RTR | IDE | r0 | DLC | 数据段(0-8字节) | CRC | ACK | EOF
每个字段的含义:
| 字段 | 长度 | 说明 |
|---|---|---|
| SOF | 1 bit | 帧起始,显性电平(0),同步用 |
| ID | 11 bit | 标识符,决定优先级。数值越小,优先级越高 |
| RTR | 1 bit | 远程帧标志。数据帧里固定为显性(0) |
| IDE | 1 bit | 扩展标志。标准帧里固定为显性(0) |
| r0 | 1 bit | 保留位,必须为显性 |
| DLC | 4 bit | 数据长度,0~8字节 |
| 数据段 | 0~64 bit | 实际数据,最多8字节 |
| CRC | 15 bit | 循环冗余校验,检测传输错误 |
| ACK | 2 bit | 应答槽。发送方发隐性,接收方拉显性表示收到 |
| EOF | 7 bit | 帧结束,全部为隐性电平 |
重点:ID越小,优先级越高。如果两个节点同时发数据,ID小的节点会赢得仲裁,继续发送。ID大的节点自动退出发送,转为接收。
扩展帧呢?就是把11位ID扩展成29位。结构上多了个SRR位和IDE位。SRR位替代了标准帧的RTR位置,IDE位变成隐性(1)表示这是扩展帧。嗯,这里要注意,扩展帧的仲裁场更长,所以标准帧的优先级天然高于扩展帧——哪怕扩展帧的ID数值更小。
3.2 远程帧:只问不拿
远程帧,说白了就是请求数据。你发一个远程帧,告诉对方:“嘿,把你那个ID的数据发给我。”
远程帧的结构和数据帧几乎一样,唯一的区别是RTR位为隐性(1),而且没有数据段。DLC字段表示你期望对方回复的数据长度。
我记得有一次调试一个电机控制器,对方就是不响应我的远程帧请求。查了半天,发现是DLC设置不对。对方要求DLC=8,我设成了0。嗯,细节决定成败。
小技巧:远程帧在实际项目中用得不多。我个人习惯用数据帧直接发送请求命令,而不是用远程帧。因为远程帧的应答机制比较死板,不如自己控制灵活。
3.3 错误帧:总线上的“警报器”
错误帧,是CAN总线自我保护的机制。当节点检测到错误时,就会发出错误帧,通知所有节点:“刚才那帧数据有问题,别用!”
错误帧由两部分组成:
- 错误标志:6个连续相同位(显性或隐性)
- 错误界定符:8个隐性位
错误分两种:
- 主动错误:节点发6个显性位,强势打断当前传输
- 被动错误:节点发6个隐性位,不破坏总线,但告诉别人“我出错了”
我曾经在一个项目中,总线莫名其妙地频繁报错。用示波器一看,有个节点的CAN收发器坏了,一直发显性位,把整个总线都拉死了。这就是典型的“总线锁死”现象。解决办法?换芯片,然后在驱动里加总线恢复机制。
避坑指南:我曾经遇到过,错误帧发多了,节点会从“主动错误”状态变成“被动错误”状态,甚至进入“总线关闭”状态。这时候节点就彻底离线了。所以驱动里一定要监控错误计数器,及时复位。
3.4 过载帧:慢点,我跟不上
过载帧,是接收节点在说:“你发得太快了,我处理不过来,等等我!”
过载帧的结构和错误帧很像:
- 过载标志:6个显性位
- 过载界定符:8个隐性位
什么情况下会发过载帧?
- 接收节点内部缓冲区满了
- 接收节点在帧间隔期间需要额外延迟
你想想看,如果总线上有个节点处理速度慢,它就会频繁发过载帧。这其实是个信号——你的系统设计可能有问题,要么降低波特率,要么优化接收处理逻辑。
3.5 帧间隔:给总线喘口气
帧间隔,就是两帧之间的空闲时间。它让总线上的节点有时间同步状态,准备接收下一帧。
帧间隔的结构:
- 间歇场:3个隐性位
- 总线空闲:任意长度的隐性位(直到有节点开始发送)
对于被动错误节点,帧间隔里还会多一个暂停发送场(8个隐性位)。这是对“犯错”节点的惩罚——让它多等一会儿,别抢总线。
我记得有个项目,总线上挂了很多节点,波特率设得比较高。结果发现偶尔会有丢帧现象。用CAN分析仪抓包一看,帧间隔时间太短,节点来不及同步。后来把波特率降了一档,问题就解决了。嗯,有时候不是硬件不行,是协议层的时序没调好。
3.6 总结一下
这五种帧类型,构成了CAN通信的完整协议栈:
- 数据帧:发数据,最常用
- 远程帧:要数据,用得少
- 错误帧:报错误,保命用
- 过载帧:求减速,缓冲用
- 帧间隔:做隔离,同步用
写驱动的时候,你不需要手动构造错误帧或过载帧——CAN控制器硬件会自动处理。但你必须理解它们的工作原理,否则出了问题你都不知道从哪查起。
下一章,咱们聊聊CAN的位时序和同步机制。这东西是理解波特率的基础,也是很多驱动工程师的盲区。到时候见。