| 上一篇 | 下一篇 |
|---|---|
目 录
- CAN(车企会用)
CAN(车企会用)
CAN in Automation(CiA) 官网。
CAN 总线结构其实和 USB 很类似,内部都是 TX 和 RX ,通过对应的芯片电路将传输信号改成差分信号,也有点类似 RS485 。但是 CAN 总线的通信方式又和 IIC 类似。
CAN 总线通常用于 MCU 级的通信。
1)简介
CAN(Controller Area Network),是 ISO 国际标准化的 串行通信协议,使用差分信号传输,半双工 。制定目的是:为了满足汽车产业的"减少线束的数量"、"通过多个 LAN ,进行大量数据的高速通信"的需求。CAN 的发展史如下:

-
低速 CAN(ISO11519)通信速率 10~125Kbps ,总线长度可达 1000 米
-
高速 CAN (ISO11898)通信速率 125Kbps~1Mbps ,总线长度 ≤40 米【也被叫做 经典 CAN】
-
CAN FD 通信速率可达 5Mbps ,并且兼容经典 CAN ,遵循 ISO11898-1 做数据收发
1.1)CAN 总线拓扑图

CAN 总线由两根线(CANL 和 CANH)组成,允许挂载多个设备节点,每个节点都有自己的 CAN 控制器(通常是节点自己的 MCU)和 CAN 收发器,都有自己的时钟源(低速 CAN:能挂20个,高速 CAN:能挂30个)。但 CAN 总线是半双工,同一时间只有一个节点发送数据。
通讯流程大概是(结合下面物理层的说明再看): MCU 通过控制器连接 CAN 收发器,从 TX 线告诉 CAN 收发器要发高电平还是低电平,然后 CAN 收发器将其转换成差分信号发送到 CAN 总线上,接收的话是 CAN 收发器 读取 CAN 总线上的差分信号,然后从 RX 线告诉 CAN 控制器收到的是高电平还是低电平。
P.S.: CAN 设计最厉害的地方之一就是:没有公共时钟、每个节点时钟都有误差,却依然可以稳定同步通信。
低速和高速 CAN 的结构中最后的黑色电阻是:终端电阻,用于阻抗匹配,以减少回波反射,增强稳定性。结构差异和芯片电路差异决定了两者的功能差异。
1.2)特点
- 多主控制:每个设备都可以主动发送数据
- 系统的柔软性:没有类似地址的信息,添加设备不改变原来总线的状态,但是有ID
- 通信速度:速度快,距离远
- 具有错误检测&错误通知&错误恢复功能
- 故障封闭:可以判断故障类型,并且进行隔离
- 连接节点多:用户可根据速度与数量找到平衡
CAN 总线协议已广泛应用在汽车电子、工业自动化、船舶、医疗设备、工业设备等方面。
2)物理层
CAN 使用差分信号进行数据传输,根据 CAN_H 和 CAN_L 上的电位差来判断总线电平(类似 USB )。
总线电平分为 显性电平(dominant,D,逻辑0) 和 隐性电平(recessive,R,逻辑1) ,二者必居其一,显性电平(0)具有优先权,相当于线与逻辑(0&1/0=0,1&1=1) (当多个节点同时向总线发送数据时,就会发生"位竞争",无论有多少个节点在发送隐性电平,只要有一个节点发送显性电平,总线上的物理电平就是显性电平0) 。
发送方通过使总线电平发生变化,将消息发送给接收方(类似 IIC )。
高速 CAN 和低速 CAN 的电平逻辑如下:

| 电平 | 高速 CAN | 低速 CAN | 总线表现 |
|---|---|---|---|
| 显性电平(0) | U C A N _ H -- U C A N _ L = 2 V U_{CAN\H}~--~U{CAN\_L}= 2V UCAN_H -- UCAN_L=2V | U C A N _ H -- U C A N _ L = 3 V U_{CAN\H}~--~U{CAN\_L}= 3V UCAN_H -- UCAN_L=3V | 拉高 CAN_H,拉低 CAN_L,程度不一样 |
| 隐性电平(1) | U C A N _ H -- U C A N _ L = 0 V U_{CAN\H}~--~U{CAN\_L}= 0V UCAN_H -- UCAN_L=0V | U C A N _ H -- U C A N _ L = − 1.5 V U_{CAN\H}~--~U{CAN\_L}= -1.5V UCAN_H -- UCAN_L=−1.5V | 拉低 CAN_H,拉高 CAN_L,程度不一样 |
常用的 CAN 收发器芯片有:TJA1050、TJA1042、SIT1050T,SIT1050T 支持高速 CAN ,传输速率可达 1Mbps ,正点原子就用的这个。
正点原子的 STM32F103ZET6 战舰板 上的 CAN 收发器芯片如下:

引脚信息如下:
- D:CAN 发送引脚
- R:CAN 接收引脚
- Vref:参考电压输出,默认悬空
- CANL:低电位 CAN_L 电压输入输出端
- CANH:高电位 CAN_H 电压输入输出端
- RS:高速 / 静音模式选择(低电平为高速)
这个匹配电阻看实际场景,串联的 CAN 设备,开头和结尾的设备加匹配电阻,中间的不要加。
3)协议层
CAN 总线依赖 分布式时钟 + 边沿驱动同步 机制,每个节点都需要有自己的时钟源。
CAN 总线以"帧"形式进行通信。CAN 协议定义了 5 种类型的帧:数据帧、遥控帧、错误帧、过载帧、间隔帧,其中数据帧最为常用。
这 5 种帧的描述如下表:
| 帧类型 | 帧作用 |
|---|---|
| 数据帧 (Data Frame) | 用于发送单元向接收单元传输数据的帧 |
| 遥控帧 (Remote Frame) | 用于接收单元向具有相同 ID 的发送单元请求数据的帧 |
| 错误帧(Error Frame) | 用于当检测出错误时,向其他单元通知错误的帧 |
| 过载帧(Overload Frame) | 用于接收单元通知其他帧:自己尚未做好接收准备的帧 |
| 间隔帧(Inter Frame Space) | 用于将数据帧、遥控帧与前面的帧分离开来的帧 |
(ID下面解释)
3.1)数据帧
也叫做报文,后面都称呼为报文
数据帧由 7 段组成。数据帧又分为标准帧(CAN2.0A协议)和扩展帧(CAN2.0B协议),扩展帧是在标准帧的基础上增加了更多的标识符位,以支持更大的地址空间。主要体现在仲裁段和控制段,帧结构如下(图中的数字表示位数):

① 各个段的作用及内部构成如下(标准帧):
- 帧起始: 表示数据帧开始的段,显性信号
- SOF --- 1位 (Start of Frame):是一个 显性位(必须为逻辑
0),这个显性电平(逻辑0)是帧起始的"有效触发信号" ------ 所有节点通过检测总线从 隐性(空闲态,逻辑1)→ 显性(逻辑0)的下降沿跳变 来识别帧的开始并同步时序。
- SOF --- 1位 (Start of Frame):是一个 显性位(必须为逻辑
- 仲裁段: 表示该帧优先级的段
- ID --- 11位 (Identifier):这是报文的优先级标识。在仲裁段,ID 值越小,优先级越高,用于多节点间的仲裁,可以当地址用,但不是地址。
- RTR --- 1位 (Remote Transmission Request):远程传输请求位
0:表示这是一个数据帧(Data Frame),后面跟着数据段。1:表示这是一个遥控帧(Remote Frame),它不携带数据(没有数据段),而是请求具有相同 ID 的节点发送数据。
- 控制段: 表示数据的字节数及保留位的段
- IDE --- 1位 (Identifier Extension):标识符扩展位,用于决定此帧是标准数据帧还是扩展数据帧
0:表示这是一个标准帧 (Standard Frame),使用 11 位 ID(范围是 0~0x7FF)。1:表示这是一个扩展帧 (Extended Frame),使用 29 位 ID(11位 + 18位,这 29 位整体叫做扩展 ID ,范围是 0~0x1FFF FFFF)。
- RO --- 1位 (Reserved Bit):保留位,必须为隐性(逻辑1)。未来可能用于新功能。
- DLC --- 4位(Data Length Code):数据长度码,指明数据段中包含的数据字节数。DLC 十进制取值范围是 0~8(0000~1000),表示数据段的数据长度可以是 0~8 个字节(0~64位)。例如 DLC=5 表示有 5 个字节的数据。
- IDE --- 1位 (Identifier Extension):标识符扩展位,用于决定此帧是标准数据帧还是扩展数据帧
- 数据段: 数据的内容,一帧可发送 0~8 字节数据
- Data Field --- 0~64位:实际要传输的数据内容。长度由 DLC 决定。
- CRC段: 检查帧的传输错误的段
- CRC --- 15位(Cyclic Redundancy Check):循环冗余校验码,用于检测帧中从 SOF 到 CRC 段之前的所有位是否发生错误。接收方会重新计算 CRC 并与接收到的 CRC 进行比较。
- DEL --- 1位 (Delimiter):分隔符,一个隐性位(逻辑
1),用于分隔 CRC 段和 ACK 段。
- ACK段: 表示确认正常接收的段
- ACK --- 1位(Acknowledgment):应答位,发送方在 ACK 段的时序内发送一个隐性位(逻辑1)后,正确接收并校验无误的接收方会在该位上发送一个显性位(逻辑0)作为应答(ACK),表示"我收到了"。
- DEL --- 1位 (Delimiter):分隔符,一个隐性位(逻辑
1),用于分隔 ACK 段和 EOF 段。
- 帧结束: 表示数据帧结束的段,7个隐性信号
- EOF --- 7位(End of Frame):由 7 个连续的隐性位组成(1111111),标志着一个 CAN 帧的结束。
② 扩展帧的 仲裁段和控制段:
-
......同标准帧......
-
仲裁段: 表示该帧优先级的段
- ID --- 11位(Identifier):......同标准帧......
- SRR --- 1位 (Substitute Remote Request):替代远程请求位,始终为隐性位(逻辑1),它的存在是为了保持帧结构的对齐和一致性。
- IDE --- 1位 (Identifier Extension):标识符扩展位,在扩展帧中,此位为显性位(逻辑0),明确指示这是一个扩展帧。
- Extended Identifier --- 18位:扩展标识符,这是 29 位 ID 中的低 18 位,与前面的 11 位 ID 共同构成完整的 29 位标识符。
- RTR --- 1位(Remote Transmission Request):......同标准帧......
-
控制段: 表示数据的字节数及保留位的段
- RO --- 1位(Reserved Bit):......同标准帧......
- RO --- 1位(Reserved Bit):......同标准帧......两个 RO 位,这是为了保持与标准帧的控制段长度一致,方便硬件设计。
- DLC --- 4位(Data Length Code):......同标准帧......
-
......同标准帧......
③ 有关应答过程的描述(ACK 位的变化):
CAN 总线没有独立的回复帧,回复是在发送的那个数据帧中的 ACK 段的时序内完成的。正确机制( CAN 协议规定)如下:
-
发送方行为:
在 ACK 位时段内,发送方主动将总线驱动为隐性电平(逻辑1) ,但同时持续监听总线实际电平(发送与监听同步进行)。
-
接收方行为:
所有正确接收且 CRC 校验无误的节点,在同一时刻( ACK 位时段)将总线强制驱动为显性电平(逻辑0)。
-
总线结果:
由于显性电平(0)具有物理层优先权,只要 至少有一个 接收节点发送显性位,总线电平即被"覆盖"为显性(0)。
-
发送方判断:
- 若监听到 ACK 位时段内总线为 显性(0) → 应答成功(至少一个节点正确接收)
- 若监听到 ACK 位时段内总线仍为 隐性(1) → 应答失败(无节点应答,触发错误处理)
3.2)位时序
CAN 总线以 "位同步" 机制实现对电平的正确采样(和其他通信协议很不同)。
先简单说一下:
CAN 总线上有节点发出帧起始信号了,其余节点会自动对齐,利用自身的时钟源建立时序,并对总线电平进行采样,后续过程中会不断调整自身时序,来对齐 CAN 总线上的数据位信号(位同步),从而采样到可靠的位电平(总线只管传输信号,接收节点要自己对齐数据位去采样)。
详细解释如下:
CAN 总线上时序信号不是一直存在的,没有节点发数据时,就处于空闲状态,此时总线电平是隐性电平(逻辑 1 ),此时所有节点都在监听。当某个节点要发送数据帧(或其他功能帧)时,会先发出 SOF 信号(帧起始位),总线会从隐性(逻辑1)变成显性(逻辑0),此时其余节点检测到总线从隐性→显性跳变时,就会依赖自身(本地)的时钟源,立即重置自身(本地)时序,将当前时刻定义为 新位周期的 SS 段起点(无论之前计时到哪),那么这些节点就做到了 "听到预备的口令,自行占到了同一起跑线上" ......
(一脸懵的话,跳转到 "3.3.1)位时序和同步的总结",先大概了解以下整个过程)
...... 而这个位周期、SS 段的解释如下 ......
CAN 控制器(发送方/接收方)将 每个位的时间周期 划分为四段:同步段(SS) 、传播时间段(PTS) 、相位缓冲段1(PBS1) 和 相位缓冲段2(PBS2) ,每段又由多个位时序 Tq 组成,用于同步、补偿延迟、确定采样点(解释:物理层上,每个数据位会以连续、完整的电平持续整个位时间,这个完整的位时间被划分为了四段)。
图解如下:

四个时间段的描述如下:
| 段 | 作用 | 关键说明 |
|---|---|---|
| SS(Sync Segment) | 检测位边沿,用于同步 | 理想边沿应落在 SS 内;若偏移,触发重同步 |
| PTS(Propagation Segment) | 补偿物理延迟(线缆传播+节点延迟),用于 "等待" 信号稳定 | 长度需 ≥ 最大往返延迟,总线长度越长,此值应越大 |
| PBS1(Phase Buffer Segment 1) | 采样点前的缓冲区 | 采样点通常位于 PBS1 结束处(如位时间75%~87.5%) |
| PBS2(Phase Buffer Segment 2) | 采样点后的缓冲区 + 重同步调整区 | 重同步时可伸缩(缩短/延长) |
- Tq (Time Quantum) :时间量子,是位定时的最小单位(由系统时钟经预分频得到)。
- 电平跳变时间显著短于 1 个 Tq 。
- 位时间 = SS + PTS + PBS1 + PBS2(单位:Tq)。例如:1 + 3 + 5 + 4 = 13 Tq,根据位时序,可以计算 CAN 通信的波特率。。
- 采样 :在 PBS1 结束时刻(即 SS+PTS+PBS1 处),控制器 单次采样 总线电平,作为该位的逻辑值。
3.3)位时序的同步
只看 隐性 → 显性 跳变边沿
节点监测到总线上信号的跳变在 SS 段范围内时,则表示节点与总线的时序是同步,此时采样点的电平可代表该位的电平(就是说:采样点的值要有效,跳变电平就必须位于 SS 段内)。但是由于每个节点自身的时钟频率误差、传输上的相位延迟,都会引起偏差。
CAN 为了实现对总线电平信号的正确采样,数据同步分为硬件同步和再同步。
① 硬件同步(用于帧起始位)
所谓硬件同步,就是在 3.2)位时序中 "详细解释如下" 说的,详细解释如下:
当 CAN 总线处于空闲时,每个节点的位时序是一直在循环运行的(比如说 SS(1Tq) → PTS(2Tq) → PBS1(3Tq) → PBS2(3Tq) → SS(1Tq) → ......),此时 CAN 总线上有个发送节点发送了帧起始信号(隐性 → 显性的跳变),此时:
-
当接收节点检测到边沿并不处于它的位时序的 SS 段内 ,那么它会立即:清零当前位时间计数器,把这个边沿 "定义为新的 SS 段起点",这就叫硬件同步(硬同步);

-
当接收节点检测到边沿恰好正处在它的位时序的 SS 段内,也会执行硬件同步,只是效果几乎不会变化。
总结就是: 当节点在空闲状态检测到 隐性 → 显性 跳变边沿(SOF帧起始信号)时,无论当前位时间处于哪个段,都会立即将该边沿定义为新的 SS 段起点,从而重新对齐位时间。
② 再同步(用于普通数据位)
也叫重同步
当帧起始位和接收节点位时序的 SS 段对齐之后,该节点就会持续循环 四段 位时序,并始终检查后续 每一个 隐性 → 显性 边沿 是否处于对应位周期的 SS 段内。即使接收节点对齐了发送节点的帧起始位,但是节点之间时钟频率的差异,仍会导致后续普通数据位的错位,因此有了 "再同步"。
再同步是利用普通数据位的边沿信号进行同步。情况分为两种:超前 和 滞后(边沿信号相对于 SS 段,即边沿信号超前或滞后)。
-
超前: 边沿信号位于接收节点的 PBS2 时段内
-
描述: 边沿信号在 PBS2 时段内,也就是在下一个位时序的 SS 段前面不远处。可以理解为:上一个边沿信号过去之后,位时序还没来得及跑到新的 SS 段,新的边沿信号就来了(边沿信号有点快了,总是超前)。
-
同步调整方式: 接收节点会减少当前位周期中 PBS2 时段的长度,超前多少就减少多少,比如说距离下一个 SS 段还有 2Tq,那就将 PBS2 减少 2Tq 。
-
举例:

-
-
滞后: 边沿信号位于接收节点的 PTS+PBS1 时间段内
-
描述: 边沿信号在 PTS+PBS1 时段内,也就是在当前位时序的 SS 段后面不远处。可以理解为:上一个边沿信号过去之后,位时序已经跑到新的 SS 段后面一点了,新的边沿信号才来(边沿信号有点慢了,总是滞后)。
-
同步调整方式: 接收节点会增加当前位周期中 PBS1 时段的长度,滞后多少就增加多少,比如说距离本周期的 SS 段已经过去 2Tq,那就将 PBS1 增加 2Tq 。
-
举例:

-
(这个超前和滞后是有规定的,可以有多种理解,但是一般都按照上述理解来遵循)
同步调整中,增加或减少的长度(Tq个数)的最大值被叫做 SJW(再同步补偿宽度,单位是 Tq) ,其范围一般是为:1~4 Tq 。限定了 SJW 的最大值后,再同步时,就不能增加或减少超过 SJW 最大值的长度,当误差大于 SJW 最大值时,就会产生错误。
SJW 值较大时,吸收误差能力更强,但是通讯速度会下降。
③ 位时序同步的总结
CAN 位同步的本质是------每个节点以总线边沿为参考,动态校准自身位时序 。硬同步实现帧级对齐,再同步实现位级微调,共同保障在噪声/时钟漂移环境下,所有节点能在精确的采样点读取总线电平。这是CAN高可靠性的物理层基石。
同步机制全流程(以接收节点视角):
-
空闲监测
- 节点持续检测总线是否连续 7 个隐性位(EOF 后空闲)。
- 各节点的位时序发生器处于"待机"状态,自由推进四段计时。
-
帧起始(SOF)→ 硬同步
- 检测到隐性→显性跳变(SOF 下降沿)。
- 立即重置本地时序 :将当前时刻定义为 新位周期的 SS 段起点(无论之前计时到哪)。
- 效果:所有节点在 SOF 边沿实现"起跑线对齐"。
-
后续每位 → 重同步(动态微调)
-
节点按预设四段推进时序(例如:SS=1Tq,PTS=2Tq,PBS1=6Tq,PBS2=4Tq)。
-
在 SS 段预期窗口内监测边沿:
- ✅ 边沿落在 SS 内 → 无需调整,按原定时推进。
-
-
⚠️ 边沿提前(早于 SS 起点)→ 缩短 PBS1(下一位总时间减 n Tq)。
- ⚠️ 边沿滞后(晚于 SS 终点)→ 延长 PBS1(下一位总时间加 n Tq)。
-
调整量受 "再同步跳转宽度 SJW " 限制(通常≤4 Tq),避免过度抖动。
-
采样点固定:在 PBS1 结束时刻(一般是位时间 75% 处)单次采样电平。
-
帧结束 → 回归空闲监测
- 检测到 7 个隐性位(EOF)后,停止四段循环,返回步骤 1 。
3.4)CAN 总线仲裁
CAN 总线处于空闲状态时,最先开始发送消息的单元(节点)获得发送权。
多个单元(节点)同时开始发送时,从仲裁段(报文ID)的第一位开始进行仲裁。连续输出显性电平最多的单元可继续发送(ID越小的,可优先发送) ,即 首先出现隐性电平的单元失去对总线的占有权变为接收 。
比如有两个单元(节点)同时发送:

竞争失败的单元(节点),在转为接收状态工作之后,会自动检测总线空闲,在第一时间再次尝试发送。
4)控制器(只介绍 STM32 搭载的)
CAN 总线上的每个节点都有独立的控制器,可控制发送与接收
4.1)控制器介绍
STM32 F1/F4/F7 用的 CAN 控制器是 bxCAN ,支持 CAN 2.0A 和 CAN 2.0B Active 版本协议( H7 后来用的是 FDCAN )。
(bxCAN 是 ST 公司对这种控制器的命名)
CAN 2.0A 只能处理标准数据帧,扩展帧的内容会识别错误,而 CAN 2.0B Active 可以处理标准数据帧和扩展数据帧。另一种协议 CAN 2.0B Passive 只能处理标准数据帧,扩展帧的内容会忽略。所以一般都用 CAN 2.0B Active 。
bxCAN 主要特点:
- 波特率最高可达 1M bps(取决于具体型号和时钟配置)
- 支持时间触发通信(CAN 的硬件内部定时器可以在 TX/RX 的帧起始位的采样点位置生成时间戳)
- bxCAN 内部有一个 16 位自由运行的定时器(称为 CAN Time Stamp Timer),它会在每次发送或接收到一帧 CAN 报文的起始位(SOF, Start of Frame)被采样的时刻,自动记录当前定时器的值。
- 具有 3 级并行发送邮箱
- bxCAN 内部有 3 个独立的发送缓冲区,每个叫一个 "Mailbox"(邮箱)。
- 可以同时把最多 3 帧不同的 CAN 报文写入这 3 个邮箱,硬件会根据 报文 ID 的优先级(CAN 的仲裁机制)自动决定哪个先发,发送完成后,会产生中断或状态标志。3 个邮箱是并行的,优先级由 ID 决定,不是先进先出。
- 具有 3 级深度的 2 个接收 FIFO
- 接收 FIFO 是 CAN 控制器中用于临时存储接收到的 CAN 报文的一种硬件缓冲结构。先收到的报文,先被读取;后收到的,排在后面。
- bxCAN 有两个独立的接收队列(FIFO0 和 FIFO1),每个 FIFO 最多能缓存 3 帧接收到的报文,那么总共就是 6 个报文。
- 接收到的报文根据过滤器配置,被自动分配到 FIFO0 或 FIFO1,如果某个 FIFO 已满(3 帧未读),再有新帧进来且匹配该 FIFO,就会发生 溢出错误(Overrun),新帧会被丢弃。
- 可变的过滤器组 (最多 28 个,也叫筛选器)( F103 只有 14 个)
- CAN 总线是广播式的,所有节点都能收到所有报文。为了只处理自己关心的消息,bxCAN 提供了 硬件过滤器(Filter Bank)。
4.2)控制器模式
总共有工作模式、测试模式、调试模式,调试模式用的很少,不展开说
① 工作模式
CAN 控制器的工作模式有三种:初始化模式 、正常模式 和 睡眠模式 。

其中英文单词是寄存器的一些标志位。
有关睡眠模式和睡眠唤醒的函数配置后面也暂时不讲。
② 测试模式
CAN 控制器的测试模式有三种:静默模式 、环回模式 和 环回静默模式 。测试模式是在初始化模式下进行配置的。
这些模式通过配置 CAN 控制器的 测试寄存器 来启用,不会影响总线上的其他节点 (尤其在静默类模式下),非常适合在不干扰实际通信的情况下进行软件验证或硬件诊断。
-
正常模式:节点正常工作的模式
-
描述:可向总线发送或接收数据
-
图解:

-
-
静默模式:可用于节点监听统计总线的流量
-
描述:只能向总线发送隐性电平 1 不能发送显性电平 0 ,可从总线接收数据,相当于"只听不说"。用于:
- 在线监听/总线分析:可监控总线流量,而不会参与仲裁或影响通信。
- 故障诊断:检测本节点是否因错误帧干扰总线。
-
图解:

-
-
环回模式:用于节点自检,但会影响总线
-
描述:发送的数据直接传回到输入(总线可监测数据),不能从总线接收数据。用于:
- 软件自检:验证 CAN 驱动、发送/接收逻辑、中断处理是否正常。
- 协议栈测试:在没有外部 CAN 设备的情况下测试应用层逻辑。
- 开发初期验证:无需连接真实 CAN 网络即可调试代码。
-
图解:

-
-
环回静默模式:用于节点自检,不会影响总线
-
描述:发送的数据直接传回到输入(总线不可监测到数据),不能从总线接收数据。用于:
- 最安全的自检模式:既能测试本机收发逻辑,又绝对保证不干扰外部CAN总线。
- 适用于在线系统中进行后台自检(例如汽车 ECU 在运行中做健康检查)。
-
图解:

-
总结如下:
| 模式 | 是否驱动总线 | 是否接收外部报文 | 发送数据去向 | 典型用途 |
|---|---|---|---|---|
| 正常模式 | ✅ 是 | ✅ 是 | 发送到总线 | 正常通信 |
| 静默模式 | ❌ 否(不发显性位) | ✅ 是 | 不发送(或仅隐性) | 总线监听、嗅探 |
| 环回模式 | ❌ 否(内部环回) | ❌ 否(忽略总线) | 内部接收FIFO | 软件自检、离线测试 |
| 环回静默模式 | ❌ 否 | ❌ 否 | 内部接收FIFO | 安全自检、在线诊断 |
4.3)控制器框图
bxCAN 控制器的结构框图主要包含四个部分:
- CAN 内核:
- 包含各种控制/状态/配置寄存器,可以配置模式、波特率等
- 发送邮箱:
- 用来缓存待发送的报文,最多可以缓存 3 个发送报文
- 接收FIFO:
- 缓存接收到的有效报文,最多可以缓存 6 个接收报文
- 接收过滤器:
- 筛选有效报文,STM32F103 系列的只有 14 组过滤器
图解如下:

F1 非互联型产品的 CAN 控制器框图如下:

4.4)发送处理
发送报文过程的图解如下:

一个完整发送周期的具体流程如下(先看看流程,寄存器位啥的先不用记住):
-
选择空置邮箱
-
含义:在发送前,软件必须先选择一个当前处于"空置状态"的邮箱。
-
如何判断?
通过读取
CAN_TSR寄存器中的TME(Transmission Mailbox Empty)位来判断:TME[i] = 1→ 邮箱 i 空闲,可写入TME[i] = 0→ 邮箱 i 正在使用或已挂起
-
-
设置 ID/DLC/DATA → 使邮箱退出空置状态
-
操作:软件向选中的邮箱写入:
TIDr:标识符(ID)TDTR:数据长度码(DLC)和时间戳TDLr/TDHR:数据内容(8 字节)
-
结果 :该邮箱从"空置"变为"非空",即退出空置状态。
-
硬件行为:CAN 控制器检测到邮箱被填满后,会自动将其加入"待发送列表"。
-
-
请求数据发送 → 邮箱会进入挂号状态
-
操作 :软件向
CAN_TSR寄存器的TXRQ位写 1,表示"请求发送"。 -
结果 :该邮箱进入"挂号状态"(Pending Transmission)。
-
说明:"挂号"意味着它已经准备好发送,但还没有开始。
-
此时邮箱不会立即发送,而是等待总线空闲且它成为最高优先级的候选者。
-
-
邮箱进入预定发送状态
-
条件:当以下两个条件同时满足时,邮箱进入"预定发送状态":
-
总线进入空闲状态(即没有其他节点正在发送)
-
该邮箱中的报文 ID 是当前所有"挂号"邮箱中优先级最高的
发送优先级由邮箱中报文的 ID 决定。ID 数值越低,优先级越高。如果 ID 值相同,邮箱编号小的先被发送(类似DMA,邮箱编号:0,1,2)。
-
-
结果:该邮箱被调度为下一个发送者,进入"预定发送状态"。
-
-
发送状态
-
动作 :控制器开始将该邮箱中的报文发送到 CAN 总线上。
- 过程:
- 发送 SOF(帧起始)
- 发送仲裁段(ID)
- 发送控制段(DLC)
- 发送数据段
- 发送 CRC 和 ACK 等
- 过程:
-
状态标志 :
CAN_TSR中的TXOK位会被置 1(表示发送成功),RQCP位也会置 1(表示请求完成)。
-
-
报文被成功发送 → 邮箱返回空置状态
-
条件:报文完整发送完毕,并且未发生错误(无错误中断)。
-
结果:
- 邮箱恢复为空置状态(
TME位变 1)- 可以再次被用于发送新报文
- 软件可通过查询
TXOK或中断处理程序知道发送完成
- 邮箱恢复为空置状态(
-
4.5)接收处理
接收报文的图解如下:

一个完整接收周期的具体流程如下(先看看流程,寄存器位啥的先不用记住):
-
空置 FIFO
-
含义:FIFO 中没有有效报文,当前为空。
-
标志位 :
CAN_RF0R寄存器中的FMP0(Fill Level of FIFO0)位为 0(表示 0 帧)。 -
状态:等待总线上的报文到来并匹配过滤器。
-
-
收到有效报文 → FIFO 状态变成挂号_1
-
有效报文:指的是数据帧直到 EOF 段的最后一位都没有错误,且通过过滤器组对标识符过滤。
-
条件:总线上收到一帧 CAN 报文,并且该报文的 ID 通过了配置的过滤器(Filter)。
- 结果:
- 该报文被硬件自动存入 FIFO 的第一个位置(最前面)。
- FIFO 状态变为 "挂号_1",表示有 1 帧待读。
- 结果:
-
提示 :此时可以通过读取
FMP位知道当前 FIFO 中有多少帧(这里是 1 帧)。例如:FMP0 = 1→ FIFO0 有 1 帧数据。
-
-
不读则继续 → 收到有效报文 → 状态变成挂号_2
-
条件:CPU 没有及时读取第一帧报文。
-
后续:又有一帧新的、符合过滤器的报文到达。
-
结果:
- 新报文被存入 FIFO 的第二个位置。
- FIFO 状态变为 "挂号_2",表示有 2 帧待读。
-
注意:FIFO 是先进先出,所以最早进来的在前面。
-
-
不读则继续 → 收到有效报文 → 状态变成挂号_3
-
条件:前两帧仍未被读取。
-
后续:第三帧有效报文到达。
- 结果:
- 第三帧被存入 FIFO 的第三个位置。
- FIFO 状态变为 "挂号_3",表示已满(3 帧)。
- 结果:
-
重要提醒:此时 FIFO 已达到最大容量!
-
-
继续收到有效报文,FIFO 已满 → 进入溢出状态
-
条件:FIFO 已满(3 帧),又有新报文通过过滤器。
- 结果:
- 发生溢出(Overrun)!
- 新报文无法存入,会被丢弃。
- FIFO 状态变为 "溢出状态"。
- 结果:
-
标志位 :
CAN_RF0R寄存器中的RF0O(Receive FIFO 0 Overrun)位被置 1,表示发生了溢出错误。 -
⚠️ 关键问题 :丢掉哪个报文?
-
这取决于是否启用了 FIFO 锁定功能(FIFO Locking Mode):
是否启用锁定 丢弃规则 ❌ 未启用(默认) 丢弃最新的报文(即第4帧) → 保留原来的3帧 ✅ 启用 丢弃最旧的报文(即第1帧) → 保留最近的3帧 如果系统要求实时性高,应启用锁定模式,防止"老数据"长期滞留。
-
-
-
出现报文丢失问题 → 读取全部报文 → 返回空置状态
-
操作:CPU 必须尽快读取 FIFO 中的所有报文。
-
读取方式 :连续调用
HAL_CAN_GetRxMessage()三次(直到FMP变为 0)。 -
结果:
- 所有报文被清空。
- FIFO 状态恢复为 "空置状态"。
- 如果之前发生了溢出,
RF0O位必须由软件清除(通常通过写 1 清除)。
- 所有报文被清空。
-
4.6)接收过滤器
在 CAN 总线上,所有节点都能 "听到" 所有的报文(广播式通信)。如果一个节点不加选择地处理每一帧报文,会:占用大量 CPU 时间,增加中断频率,所以需要一个 硬件过滤器 。只让关心的报文进入 FIFO,其他全部丢弃 ------ 这就是 "接收过滤器" 的作用。
STM32F103 系列的只有 14 组过滤器(0~13)。
每个过滤器组都有两个 32 位寄存器 CAN_FxR1 和 CAN_FxR2(F1中,x=0~13,是过滤器组编号),这俩寄存器都是用来存储报文(数据帧)中的仲裁段信息(ID+IDE+RTR)的。
这两个寄存器所存储的 ID 长度叫做 位宽:可设置为 32 位或 16 位 (位宽决定了所存储的 ID 信息长度):
-
32 位: 使用整个 32 位寄存器存储完整的 ID 信息(标准/扩展帧)
-
16 位: 将 32 位寄存器分成两部分,每部分 16 位,用于存储部分 ID
-
具体如下:
过滤器组 x 32位(完整包含 标准ID的11位 + 扩展ID的18位) 16位(每部分仅包含 标准ID的11位 + 扩展ID的高3位) CAN_FxR1 STDID[10:0]、EXTID[17:0]、IDE、RTR STDID[10:0]、EXTID[17:15]、IDE、RTR CAN_FxR2 STDID[10:0]、EXTID[17:0]、IDE、RTR STDID[10:0]、EXTID[17:15]、IDE、RTR
每个过滤器组还可以设置 选择模式:屏蔽位模式、标识符列表模式 (选择模式决定了匹配 ID 的方式):
- 屏蔽位模式:("关键词"机制,常用于范围匹配、字段匹配)
- 功能: 可以选择出一组符合某个条件的报文(比如 ID 在某个范围内)
- 寄存器存储内容: 使用
CAN_FxR1存储 目标 ID (要匹配的值),CAN_FxR2存储 屏蔽码(Mask) - 规则: 屏蔽码中为 1 的位 → 必须完全匹配,屏蔽码中为 0 的位 → 任意值都行,满足 (收到的 ID & 屏蔽码) == (目标 ID & 屏蔽码) 才算符合条件。
- 补充: 位宽设置为 16 位的话,一个寄存器的整个 32 位就可以一半用来存储目标 ID ,一半用来存储屏蔽码,相当于虽然关键词变少了(能屏蔽的位少了,更宽泛了),但是能筛选出 2 组符合条件的报文。
- 标识符列表模式:("白名单"机制,精确控制哪些 ID 能被接收)
- 功能: 只接收几个特定的 ID 报文(比如只收 0x100 和 0x200)
- 寄存器存储内容:
CAN_FxR1和CAN_FxR2都用来存储 具体的 ID 值 - 规则: 如果 收到的 ID 等于
CAN_FxR1或CAN_FxR2中的任何一个,就算匹配 。 - 补充: 位宽设置为 16 位的话,一个寄存器的整个 32 位就可以存储两个具体 ID,相当于虽然只能规定 16 位的 ID ,但是能筛选出 4 个特定的报文。
✅ 位宽和选择模式的配置共同决定了这一组过滤器的功能。 ✅
具体举例如下:
配置了四组过滤器,各自的配置如下图所示:

以第一组过滤器(位宽:32位,选择模式:屏蔽位模式)为例:
假设过滤器的编号为 0 ,目标 ID 为 0xFFFF0000(11111111111111110000000000000000),屏蔽码为 0xFF00FF00(11111111000000001111111100000000),表示收到的报文的 ID 的 位 24~31 和 位 8~15 需要和目标 ID 一致,其余位随便。符合条件的报文才能进 FIFO 。

实际使用中,IDE 和 RTR 位其实也是要和目标 ID 一致的 。
4.7)STM32 的 CAN 位时序与波特率
前面 3.2)介绍的位时序是制定 CAN 协议的公司规定的,但 ST 公司向来喜欢做一些修改,不过还好只是时间段的合并。
STM32 的 CAN 外设位时序分为三段:同步段 SYNC_SEG(SS) 、时间段1(BS1) 、时间段2(BS2)。 其中 BS1=PTS+PBS1 。

注意,上述图片中:
- 二进制系统中,比特率=波特率;
- BRP[9:0] 是分频寄存器值,实际分频系数 = BRP[9:0] + 1;
- TS1[3:0] 是位时序控制寄存器中用来设置 BS1 时段的 tq 个数,实际 BS1 时段的 tq 个数 = TS1[3:0] +1;
- TS2[2:0] 是位时序控制寄存器中用来设置 BS2 时段的 tq 个数,实际 BS2 时段的 tq 个数 = TS2[2:0] +1;
总结,STM32 中 CAN 通信的波特率计算公式如下::
波特率 = 1 1 ∗ t q + t q ∗ ( T S 1 [ 3 : 0 ] + 1 ) + t q ∗ ( T S 2 [ 2 : 0 ] + 1 ) \large 波特率=\frac{1}{1*tq+tq∗(TS1[3:0]+1)+tq∗(TS2[2:0]+1)} 波特率=1∗tq+tq∗(TS1[3:0]+1)+tq∗(TS2[2:0]+1)1
通信双方波特率需要一致才能通信成功。
在 STM32F103 系列中,bxCAN1 挂载在 APB1 总线上, t P C L K t_{PCLK} tPCLK(APB1 时钟周期)= 1/APB1时钟频率 = 1/36000000(查手册)。
举例如下:
STM32F103ZET6,设 TS1=8、TS2=7、BRP=3,波特率 = 36000 / [( 9 + 8 + 1 ) * 4] = 500Kbps。
STM32F407ZET6,设 TS1=6、TS2=5、BRP=5,波特率 = 42000 / [( 7 + 6 + 1 ) * 6] = 500Kbps。
这两个板子的 CAN 通信波特率相同,那这两个板子就可以进行 CAN 通信。