3. CMS32 CAN控制器架构
各位同学,今天我们来啃CAN通信里最核心的一块——报文帧。说实话,这部分内容我第一次学的时候也觉得有点枯燥,但后来在项目里被坑过几次,才真正体会到这些概念有多重要。咱们慢慢聊,我尽量把每个知识点都讲透。
3.1 四种报文帧格式
CAN总线上跑的数据,一共就四种格式。你想想看,一个通信协议,只定义了四种报文,是不是挺简洁的?
| 帧类型 | 用途 | 谁发 |
|---|---|---|
| 数据帧 | 发送节点把数据传给其他节点 | 任意节点 |
| 远程帧 | 请求其他节点发送特定ID的数据 | 任意节点 |
| 错误帧 | 检测到总线错误时通知所有节点 | 检测到错误的节点 |
| 过载帧 | 接收节点忙不过来,请求延迟发送 | 接收节点 |
实际项目中,数据帧用得最多,远程帧偶尔用,错误帧和过载帧嘛——我希望你永远别在调试时看到它们。但真看到了也别慌,后面章节我会专门讲怎么处理。
3.1.1 数据帧结构详解
数据帧是CAN通信的主角。标准格式有11位ID,扩展格式有29位ID。我个人习惯用标准格式,除非项目里ID实在不够用。
一个标准数据帧长这样:
SOF | 11位ID | RTR | IDE | r0 | DLC | 0~8字节数据 | CRC | ACK | EOF
每个字段的含义:
- SOF(Start of Frame):1位显性位,告诉总线“我要发数据了”
- ID:11位标识符,决定优先级
- RTR(Remote Transmission Request):数据帧里是显性位(0),远程帧里是隐性位(1)
- DLC(Data Length Code):4位,表示数据字节数(0~8)
- 数据段:0~8字节,想传啥传啥
- CRC:15位校验码+1位分隔符
- ACK:2位,接收节点确认
- EOF:7位隐性位,帧结束
3.1.2 远程帧
远程帧说白了就是“请求帧”。节点A发一个远程帧,ID填成节点B的ID,节点B收到后就会发一个同ID的数据帧回来。
远程帧和数据帧的区别就两点:
- RTR位:远程帧是隐性(1),数据帧是显性(0)
- 没有数据段:远程帧的DLC虽然存在,但后面不跟数据字节
我记得有个项目,用远程帧做传感器数据轮询。主节点每隔100ms发一次远程帧,从节点收到后回复当前采样值。这种方式在节点少的时候挺好用,节点多了就得小心仲裁问题了。
3.1.3 错误帧与过载帧
这两种帧属于“异常情况”。
错误帧由6个连续的显性位(错误标志)加上8个隐性位(错误界定符)组成。任何节点检测到总线错误,都会立刻发错误帧。这时候整条总线上的节点都会收到通知。
过载帧结构类似,但触发条件不同——接收节点来不及处理数据时才会发。我在实际项目中很少见到过载帧,因为现在的MCU处理速度都够快。但如果你用低速MCU做CAN通信,就得留个心眼了。
3.2 仲裁机制与ID优先级
CAN总线最牛的地方之一,就是它的仲裁机制。多个节点同时发数据怎么办?不冲突,不丢包,谁优先级高谁先发。
原理其实很简单:总线电平是“线与”逻辑。显性位(逻辑0)会覆盖隐性位(逻辑1)。仲裁的时候,每个节点一边发自己的ID,一边监听总线。如果发现自己发的位是隐性,但总线上是显性,说明有更高优先级的节点在发数据,自己就乖乖退出发送。
举个例子:
节点A ID:0x100(二进制:001 0000 0000)
节点B ID:0x200(二进制:010 0000 0000)
仲裁过程:
第1位:A发0,B发0 → 总线0,继续
第2位:A发0,B发1 → 总线0(A的显性位覆盖了B的隐性位)
B检测到总线与自己发送不一致 → B退出仲裁
结果:节点A获胜,继续发送数据
所以ID值越小,优先级越高。0x000是最高优先级,0x7FF是最低优先级(标准帧)。
我建议你在设计系统时,把关键控制信号分配小ID,普通状态信息分配大ID。比如:
- 0x001~0x0FF:紧急控制指令(刹车、转向等)
- 0x100~0x2FF:周期性状态数据(车速、转速等)
- 0x300~0x7FF:诊断信息、配置参数等
3.3 位填充与CRC校验
这两个机制保证了CAN通信的可靠性。没有它们,总线上的数据分分钟出错。
3.3.1 位填充规则
位填充是为了保证总线上的电平有足够多的跳变,方便接收节点同步时钟。规则很简单:
连续发送5个相同电平的位后,自动插入一个相反电平的位。
比如你连续发了5个显性位(00000),发送器会在后面自动加一个隐性位(1)。接收器收到后,会自动把这个填充位去掉,还原原始数据。
位填充的范围包括:SOF、ID、控制字段、数据字段、CRC字段。但CRC界定符、ACK字段和EOF不参与填充。
3.3.2 CRC校验
CAN的CRC校验用的是15位CRC,生成多项式是:
x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
发送节点计算CRC值,放在CRC字段里。接收节点收到数据后,用同样的多项式重新计算,如果结果不一致,就说明数据在传输过程中被破坏了。
CRC校验覆盖的范围是:SOF、ID、控制字段、数据字段。也就是说,从帧开始到CRC字段之前的所有位,都要参与CRC计算。
实际项目中,CRC校验出错的概率其实不高。但如果你的系统工作环境电磁干扰严重(比如靠近大功率电机),CRC错误就会频繁出现。这时候可以考虑在应用层再加一层校验,比如每个数据包末尾加一个累加和。
3.4 知识体系总览
下面这张图把本章的核心概念串起来了,你可以对照着复习:
好了,这一章的内容就这些。四种帧格式、仲裁机制、位填充和CRC校验,是CAN通信的基石。你把这些搞懂了,后面学CANopen、J1939这些高层协议就会轻松很多。