【江科大CAN】2.1 STM32 CAN外设(上)
2.1 STM32 CAN外设(上)
- 2.1.1 STM32 CAN外设简介
- 2.1.2 外围电路设计
- 2.1.3 STM32 CAN内部结构
- 2.1.4 发送流程详解
- 2.1.5 接收流程详解
- 2.1.6 关键配置位总结
STM32 CAN外设讲解
大家好,欢迎继续观看CAN总线入门教程。本节开始,我们正式进入本套课程的第二部分:STM32 CAN外设的讲解。经过前面五个视频的学习,相信大家已经对CAN总线的基本知识有了扎实的理解 [修改]
(更严谨,“了如指掌”略显绝对)。接下来,我们就在实践中验证所学的知识吧!
第二部分我们以STM32F103C8T6这款芯片为例,介绍其内部的CAN外设原理。学会了硬件原理,下一部分我们就可以写程序来解决实际项目的需求,完成从理论到实践的全过程。
注:本节课内容来源于STM32手册中对CAN外设的介绍。请打开资料链接(已更新部分资料):
- 新增STM32相关资料:参考文档、部分程序源码。
- 新增CAN收发器模块商家资料:参考文档、模块原理图、源代码(供参考)。
学习建议:学完视频后,请再详细查阅STM32F10xxx参考手册中文版中的第22章:控制器局域网 (bxCAN) 补充细节。
学习基础:后续内容需要STM32基础(了解基本概念、会编写下载程序、掌握GPIO输入输出、使用OLED调试工具)。相关基础可参考我之前的STM32入门教程。
2.1.1 STM32 CAN外设简介
- 内置bxCAN外设:支持CAN 2.0A 和 CAN 2.0B(即支持标准格式和扩展格式)。
- 功能核心:硬件自动完成CAN报文发送、按照过滤器自动接收指定报文。程序只需处理报文数据,无需关注总线电平细节(帧格式、位同步、仲裁、错误处理等均由硬件完成),使用便捷。
- 关键参数:
- 波特率:最高 1 Mbps(完美支持高速CAN)。
- 发送:3个可配置优先级的发送邮箱(发送缓冲区)。
- 接收:2个三级深度的接收FIFO(接收缓冲区,可缓存6个报文)。
- 14个过滤器组(互联型有28个):用于按ID过滤接收报文(只接收需要的报文)。
- 特色功能(了解即可):时间触发通信、自动离线恢复、自动唤醒、禁止自动重传、接收FIFO溢出方式可配置、发送优先级可配置、双CAN模式(互联型)等。
- STM32F103C8T6资源:内置 CAN1(仅一个CAN外设)。
2.1.2 外围电路设计
-
CAN拓扑结构:
- 节点 = CAN控制器 (STM32内部) + CAN收发器 (如TJA1050)。
- STM32引脚:CAN_TX -> PA12, CAN_RX -> PA11。
- 注意:如果CAN与USB需要同时使用,需要将CAN引脚重映射到PB8和PB9 。
-
收发器电路:
- 核心芯片:TJA1050。
- 关键连接:收发器
TXD
-> STM32CAN_TX (PA12)
, 收发器RXD
-> STM32CAN_RX (PA11)
。 - 供电:收发器 VCC 必须接5V(以满足总线电平规范)。
- 终端电阻:总线物理两端各接一个120Ω电阻。实验模块自带120Ω电阻。
- 实验说明:实验中(如三设备)未移除中间模块电阻(三个电阻)也能工作,但实际项目应严格按规范(仅保留总线物理两端的电阻)。
- 如果正常使用下,多设备连接,只需在总线物理两端各保留一个电阻。
- 模块附加电路:部分模块在
CAN_H/CAN_L
上串联10Ω电阻(抗噪)并接30pF电容(滤波),手册参考电路无此设计。
2.1.3 STM32 CAN内部结构
该框图可分为两个主要部分:
- 主 CAN (CAN1):位于框图上半部分。这是我们当前芯片 STM32F103C8T6 所拥有的唯一 CAN 外设资源,也是我们学习的核心。
- 从 CAN (CAN2):位于框图下半部分。
- 仅存在于互联型 (Connectivity Line) STM32 芯片中(如 STM32F107/STM32F105)。
- STM32F103C8T6 属于基本型,没有 CAN2,因此这部分无需关注。
- 互联型芯片特性:在互联型芯片中,CAN1 和 CAN2 并非完全独立。CAN2 主要作为 CAN1 的辅助,两者共同管理同一个 CAN 总线。这种设计主要是为了分担负载或提供冗余等高级功能。此处仅作了解。
聚焦主 CAN (CAN1) 部分:
框图上半部分清晰地展示了 CAN1 的核心构成,主要分为三大功能模块:
-
CAN 2.0B 主动核心 (bxCAN Core - CAN 2.0B Active) - 左侧模块:
- 这是 bxCAN 外设的“大脑”和“引擎”,包含了实现 CAN 2.0A/B 协议所需的全部核心逻辑电路(位定时、位填充/解填充、帧处理、仲裁、错误检测、ACK 处理、CRC 计算/校验等)。
- 核心与程序的接口:核心内部包含大量控制寄存器、状态寄存器和数据寄存器。
- 程序通过读写这些寄存器来配置 CAN 外设的工作模式、参数(如波特率)、启动/停止操作、查询状态(如发送/接收完成、错误标志)。
- 一句话总结:程序通过读写寄存器来完全控制和监视硬件 CAN 电路的运行。这些寄存器的详细描述可在 STM32 参考手册的“CAN 寄存器描述”章节查阅。后续视频中遇到关键寄存器时,我们会直接解释其功能和用法。
-
发送邮箱 (Transmit Mailboxes) - 中间模块:
- bxCAN 提供了 3 个独立的发送邮箱 (Mailbox 0, 1, 2)。
- 功能:每个邮箱都是一个存储单元,用于临时存放一个完整的待发送 CAN 报文(包含帧信息:ID、RTR、IDE、DLC 以及 0-8 字节数据)。
- 发送流程:
- 程序选择一个空置的发送邮箱。
- 将待发送报文的所有参数和数据写入该邮箱对应的寄存器。
- 设置该邮箱的 TXRQ (Transmit Request) 寄存器位为 1,请求发送。
- 后续自动化:一旦请求发送被置位,后续所有操作均由硬件自动完成,程序无需干预:
- 等待总线空闲 (Bus Idle)。
- 执行位同步 (Bit Synchronization)。
- 处理总线仲裁 (Arbitration)。
- 操作 CAN_TX 引脚输出波形。
- 执行位填充 (Bit Stuffing)。
- 处理错误检测与恢复 (Error Handling)。
- 等待/处理 ACK 槽。
- 发送 EOF 等。
- 设计目的:使用起来非常简单高效。程序只需“告诉”硬件发什么,硬件负责“搞定”整个发送过程。三个邮箱提供了发送缓冲,允许程序连续写入多个待发报文,硬件按策略依次发送,减少程序等待时间。
-
接收部分 (Receive Section) - 右侧模块:
- 该部分包含两个关键子模块:标识符过滤器 (Identifier Filters) 和 接收 FIFO (Receive FIFOs)。
- 基本接收流程:
- 当 CAN 总线上出现一个数据帧或远程帧的报文波形时,bxCAN 核心硬件电路会自动捕获并完整接收该报文。
- 接收到的报文首先经过标识符过滤器组。
- 过滤器作用:程序可以预先在 14 个过滤器组中配置过滤规则(例如,只接收特定 ID 范围的报文,或屏蔽某些 ID 的报文)。硬件会自动将接收到的报文 ID 与所有启用的过滤器规则进行比对。
- 过滤结果:
- 如果报文 ID 匹配了任何一个启用的过滤器规则,则该报文被视为“需要的”,允许进入下一步。
- 如果报文 ID 无法匹配任何一个启用的过滤器规则,则该报文直接被硬件丢弃(“扔掉”),不会通知程序。这极大地减轻了软件处理无关报文的负担。
- 通过过滤器的报文不会直接交给程序,而是存入接收 FIFO。
- 接收 FIFO (FIFO0 & FIFO1):
- bxCAN 提供了 2 个独立的接收 FIFO:FIFO0 和 FIFO1。
- FIFO 含义:First-In-First-Out,先进先出缓冲区队列。通俗地说,就是排队。
- 功能:每个 FIFO 相当于一个队列,队列深度为 3 个邮箱 (Mailbox)。也就是说,每个 FIFO 最多可以暂存 3 个通过过滤器的接收报文。
- 报文存储:通过过滤器的报文,会根据过滤器配置时指定的目标(由程序设定),自动进入 FIFO0 或 FIFO1 的队列末尾排队。
- 程序读取:程序通过读取 FIFO 对应的寄存器,可以从队列头部(最先进入的报文) 逐个读取报文数据和状态信息。读取后需要释放邮箱,腾出空间接收新报文。
- 优势:
- 缓冲作用:如果 CAN 总线报文接收速度很快,而程序未能及时读取,报文可以在 FIFO 中排队等待。
- 避免丢失:FIFO 的缓冲能力(每个 FIFO 最多 3 个报文)在一定程度上避免了因程序处理不及时导致的报文丢失,非常实用。
- 双 FIFO 设计目的:提供两个独立的接收队列。程序可以配置不同优先级的报文或不同类型的报文进入不同的 FIFO(例如,重要报文进 FIFO0,普通报文进 FIFO1)。这样,即使普通报文很多导致 FIFO1 排队甚至溢出,重要报文仍然可以在 FIFO0 中被及时接收和处理,降低了重要报文丢失的概率。
框图局限性:
手册提供的框图清晰地展示了主要功能模块(核心、发送邮箱、接收过滤器/FIFO)及其连接关系,但对于发送邮箱的状态流转、过滤器具体工作模式、FIFO 队列管理细节等描绘得不够详尽。因此,在接下来的内容中,我们将通过更详细的流程图和文字描述来深入解析这些关键流程的细节。
核心框图可划分为:
STM32 CAN 外设核心流程详解 (发送与接收)
为了更清晰地理解 CAN 报文在 STM32 bxCAN 外设中的具体流转过程,我们聚焦于发送和接收的核心流程。可以将 bxCAN 硬件逻辑视为一个强大的“管理员”。程序只需告诉它要发送什么报文,以及从它那里读取已接收且需要的报文,而总线操作的底层细节(等待空闲、波形输出、位同步、仲裁、错误处理等)均由管理员全权负责。
1. 发送流程 (如何发出一个报文?)
- 程序操作:
- 选择一个空置的发送邮箱 (邮箱 0、1 或 2)。
- 将报文的所有参数 (
ID
、Data
、IDE
(扩展标志)、RTR
(远程帧标志)、DLC
(数据长度码)) 写入该邮箱对应的寄存器。 - 设置该邮箱的 TXRQ (Transmit Request) 寄存器位为 1,发出请求发送命令。
- 管理员的工作:
- 收到发送请求后,自动接管后续所有操作。
- 等待总线进入 空闲 (Idle) 状态。
- 当总线空闲时,自动将该报文广播到 CAN 总线上,完成整个发送流程(包含位同步、仲裁、波形输出、位填充、错误检测、ACK 处理等)。
- 报文成功发送后,释放该邮箱,使其恢复空置状态。
- 为什么需要 3 个发送邮箱?
- 核心目的:防止因总线繁忙造成 CPU 等待 (发送拥堵)。
- 场景分析:
- 程序写入报文 A 到邮箱 0 并请求发送。
- 管理员发现总线正忙,报文 A 在邮箱 0 中等待。
- 此时程序又想发送报文 B。如果只有一个邮箱,程序必须等待邮箱 0 空闲(即报文 A 发送完成)才能写入报文 B,造成 CPU 等待。
- 有了三个邮箱,程序发现邮箱 0 被占用,可以立即将报文 B 写入邮箱 1 并请求发送。管理员会在总线空闲时依次发送邮箱 0 和邮箱 1 的报文。CPU 无需等待,可以继续执行其他任务。
- 同理,程序还可以将报文 C 写入邮箱 2。
- 极限情况:如果三个邮箱都写满且总线持续繁忙,此时程序再想发送新报文 (D) 时,才需要等待某个邮箱释放。这种情况表示总线非常拥堵,在实际应用中相对少见。
- 优势:三个邮箱提供了发送缓冲区,允许程序连续提交多个发送请求,显著减少了 CPU 因等待总线空闲而产生的阻塞时间。
- 发送策略配置 (
TXFP
位):- 当多个邮箱中都有待发报文且总线变为空闲时,管理员需要决定先发送哪个邮箱的报文?
- 策略可配置:
TXFP = 1
:先请求先发送 (FIFO 模式)。严格按照请求发送 (TXRQ=1) 的时间顺序处理邮箱(邮箱号顺序是次要的)。先请求的报文先发送。TXFP = 0
:按 ID 优先级发送。管理员会比较所有待发邮箱中报文的 ID 号,优先发送 ID 值最小的报文(优先级最高)。ID 值相等时,优先发送邮箱号小的报文(如邮箱 0 优于邮箱 1)。此模式允许高优先级报文“插队”。
2. 接收流程 (如何接收想要的报文?)
- 管理员的工作 (第一步:捕获与过滤):
- 当 CAN 总线上出现任何数据帧或远程帧时,管理员都会自动捕获并完整接收该报文。
- 接收到的报文首先经过 14 个标识符过滤器组。
- 过滤器作用:程序预先在过滤器组中配置规则(例如:只接收特定 ID 或 ID 范围的报文,屏蔽某些 ID 的报文)。硬件自动进行 ID 比对。
- 过滤结果:
- 报文 ID 匹配了任何一个启用的过滤器规则 -> 报文是**“需要的”** -> 允许进入下一步。
- 报文 ID 无法匹配任何启用的过滤器规则 -> 报文是**“不需要的”** -> 管理员直接丢弃该报文,不会通知程序。
- 过滤器意义:硬件级过滤极大地减轻了软件负担,软件无需处理海量的无关报文 ID 比对。
- 管理员的工作 (第二步:排队存储):
- 通过过滤器的报文(即“需要的”报文)不会直接交给程序。
- 它们会根据配置过滤器时指定的目标 FIFO (由程序设定),自动存入接收 FIFO0 或 FIFO1 的队列中排队等待。
- FIFO (先进先出队列):每个 FIFO (
FIFO0
,FIFO1
) 都是一个队列,深度为 3 个邮箱。意味着每个 FIFO 最多可暂存 3 个报文。 - 报文存储规则:
- 新报文总是排在队列的末尾。
- 示例:配置
Filter0
通过的报文进FIFO0
,Filter1
通过的报文进FIFO1
。- 报文 A (通过
Filter0
) -> 存入FIFO0
邮箱 0 (队首)。 - 报文 B (通过
Filter0
) -> 存入FIFO0
邮箱 1。 - 报文 C (通过
Filter1
) -> 存入FIFO1
邮箱 0 (队首)。 - 报文 D (通过
Filter0
) -> 存入FIFO0
邮箱 2。 - 此时
FIFO0
已满 (3个报文)。
- 报文 A (通过
- FIFO (先进先出队列):每个 FIFO (
- 程序操作 (读取):
- 程序通过轮询或中断方式,检查
FIFO0
和FIFO1
的队列状态 (FMPx
寄存器位指示队列中报文数量)。 - 当检测到某个 FIFO 队列长度大于 0 (有报文排队) 时:
- 程序读取该 FIFO 队列头部 (最先存入,邮箱 0) 的报文数据。
- 读取后,程序必须显式释放该邮箱 (
RFOMx=1
)。 - 队列管理:释放队首邮箱后:
- 邮箱 1 的报文前移到邮箱 0 (成为新队首)。
- 邮箱 2 的报文前移到邮箱 1。
- 队尾邮箱 (邮箱 2) 变为空置,可接收新报文。
- 这个过程模拟了现实中排队:新来者排到队尾,处理者从队首开始,处理完队首后后面的人依次前移。这就是 FIFO (先进先出) 名称的由来。
- 程序通过轮询或中断方式,检查
- FIFO 满溢处理 (
RFLM
位):- 当某个 FIFO 队列已满 (3 个邮箱均占用) 时,如果又收到一个需存入该 FIFO 的报文:
RFLM = 1
(锁定模式):新报文直接丢弃。RFLM = 0
(非锁定模式 - 默认):新报文覆盖该 FIFO 队列中最后接收的报文 (即邮箱 2 中的报文)。原邮箱 2 的报文丢失。
- 队列满溢必然导致报文丢失:要么丢弃新报文 (
RFLM=1
),要么覆盖最旧的排队报文 (RFLM=0
)。
- 当某个 FIFO 队列已满 (3 个邮箱均占用) 时,如果又收到一个需存入该 FIFO 的报文:
- 为什么需要 2 个接收 FIFO? (分流策略):
- 核心目的:降低重要报文在接收拥堵时的丢失概率。
- 类比:食堂设学生窗口和教师窗口。即使学生窗口排长队拥堵,教师仍能在教师窗口快速打饭,保证教师(重要角色)能准时吃饭。
- 应用:
- 将重要、紧急或数量较少的报文 (如关键控制指令、报警信号) 配置到
FIFO0
。 - 将普通、非关键或数量较大的报文 (如常规状态更新) 配置到
FIFO1
。
- 将重要、紧急或数量较少的报文 (如关键控制指令、报警信号) 配置到
- 优势:
- 即使
FIFO1
因大量普通报文涌入而频繁满溢,重要报文仍然可以在FIFO0
中被可靠接收(除非FIFO0
自己也满了)。 - 相比于所有报文挤在单一 FIFO 队列中(容易导致重要报文排在后面被覆盖或丢弃),双 FIFO 分流显著提高了重要报文的接收可靠性。
- 即使
- 注意:STM32 硬件本身并未赋予
FIFO0
和FIFO1
不同的优先级,它们是平级的。程序可以根据自身需求(报文重要性、类型、接收频率)灵活配置分流规则。
发送邮箱 vs. 接收 FIFO (本质都是缓冲队列)
- 共同点:两者都在数据写入速率 (
CPU
提交发送请求 /管理员
存入接收报文) 大于数据处理速率 (管理员
实际发送 /CPU
读取接收报文) 时,提供缓冲能力,避免数据丢失或 CPU 阻塞。 - 差异点:
- 接收 FIFO:只支持严格的先进先出 (FIFO) 排队策略。
- 发送邮箱:排队策略可配置 (
TXFP
位),支持 FIFO (TXFP=1
) 或 ID 优先级 (TXFP=0
)。
- 理想情况:如果数据处理速率远高于写入速率(发送:总线总是很快空闲;接收:CPU 总是及时读取),队列基本不会堆积,缓冲作用不明显。但在实际应用中,缓冲队列对于应对突发流量和短暂拥堵至关重要。
通过以上详细流程解析,STM32 CAN 外设 (bxCAN) 处理报文发送与接收的核心机制就非常清晰了。
2.1.4 发送流程详解
好的,这是按照您要求的格式(保留加粗,无省略知识点,无引用符号)校正优化后的文本,详细描述了 STM32 CAN 发送邮箱的状态流转及其寄存器标志位:
STM32 CAN 发送邮箱状态流转详解
接下来,我们深入探讨 发送邮箱在报文发送过程中经历的各种状态及其状态寄存器标志位的变化。理解这个状态机对于掌握发送流程和控制至关重要。
核心状态寄存器标志位 (需关注):
TME
(Transmit mailbox empty):发送邮箱空。1
表示邮箱空闲可用;0
表示邮箱已被占用(有报文待发或正在发送)。TXRQ
(Transmit request):发送请求。由程序置1
来请求发送该邮箱中的报文。硬件在发送完成或失败后清除此位。RQCP
(Request completed):请求完成。1
表示对该邮箱的发送请求已完成(无论成功或失败);0
表示请求未完成/正在进行中。TXOK
(Transmission OK):发送成功。1
表示报文成功发送(收到有效 ACK 且无错误);0
表示发送未成功或尚未完成。ABRQ
(Abort request):中止请求。由程序置1
来请求中止该邮箱的发送。NART
(No automatic retransmission):禁止自动重传(全局配置位)。0
启用自动重传;1
禁止自动重传。
发送邮箱状态机 (单个邮箱视角):
-
空置状态 (Empty):
- 标志位:
TME = 1
,RQCP = X
(任意),TXOK = X
(任意)。 - 含义:邮箱空闲,程序可向其写入新报文。
- 进入条件:初始状态,或发送完成/失败/中止后。
- 操作:程序写入报文参数 (
ID
,Data
,IDE
,RTR
,DLC
) 并设置TXRQ = 1
。
- 标志位:
-
挂号状态 (Pending):
- 标志位:
TME = 0
,TXRQ = 1
,RQCP = 0
,TXOK = 0
。 - 含义:报文已写入邮箱,发送请求 (
TXRQ=1
) 已发出,等待参与发送调度。 - 进入条件:在空置状态写入报文并设置
TXRQ=1
。 - 状态行为:
- 该邮箱的报文已准备好发送。
- 由于存在多个邮箱 (
0, 1, 2
),且可能都有待发报文,因此需要确定发送顺序。
- 后续状态:当该邮箱的报文根据
TXFP
配置的发送策略被确定为当前最高优先级时,进入预定状态。
- 标志位:
-
预定状态 (Scheduled):
- 标志位:
TME = 0
,TXRQ = 1
,RQCP = 0
,TXOK = 0
。(标志位与挂号状态相同,由内部逻辑区分)。 - 含义:该邮箱的报文已被管理员调度为“下一个发送”,一旦总线空闲 (
IDLE
),即开始发送。 - 进入条件:从挂号状态提升而来,前提是该邮箱报文的优先级是当前所有挂号邮箱中最高的。
- 优先级决定方式 (
TXFP
):TXFP = 1
(FIFO 模式 - 先请求先发送):优先级仅由请求发送 (TXRQ=1
) 的时间顺序决定。一旦进入预定状态,不会退回挂号状态(先来者不会“被插队”)。TXFP = 0
(ID 优先级模式):优先级由报文 ID 值决定(ID 值小者优先级高;ID 相等时邮箱号小者优先)。在这种模式下,如果一个具有更高优先级 (更小 ID) 的报文被写入另一个邮箱并请求发送 (TXRQ=1
),当前处于预定状态的邮箱可能被“抢占”,退回挂号状态等待。
- 优先级决定方式 (
- 后续状态:当检测到总线空闲 (
IDLE
) 时,进入发送状态。
- 标志位:
-
发送状态 (Transmit):
- 标志位:
TME = 0
,TXRQ = 1
,RQCP = 0
,TXOK = 0
。(标志位仍与挂号/预定状态相同,由内部逻辑区分)。 - 含义:该邮箱的报文正在被管理员实际发送到 CAN 总线上(进行位同步、驱动 TX 引脚、仲裁、填充、错误检测、等待 ACK 等操作)。
- 进入条件:从预定状态进入,当总线空闲时。
- 后续状态 (发送结束):
- 发送成功 (收到有效 ACK 且未检测到错误):
- 状态回到空置状态。
- 设置标志位:
TME = 1
,RQCP = 1
,TXOK = 1
。
- 发送失败 (仲裁丢失、未收到 ACK、检测到位错误等):
- 取决于
NART
位:NART = 0
(启用自动重传):状态回到预定状态 (TME=0
,TXRQ=1
,RQCP=0
,TXOK=0
)。硬件将自动尝试重发该报文,直到成功。NART = 1
(禁止自动重传):状态直接回到空置状态。- 设置标志位:
TME = 1
,RQCP = 1
,TXOK = 0
(表示请求已完成但发送失败)。
- 设置标志位:
- 取决于
- 程序中止 (
ABRQ = 1
):- 状态回到空置状态。
- 设置标志位:
TME = 1
,RQCP = 1
,TXOK = 0
(表示请求被中止,发送未成功)。
- 发送成功 (收到有效 ACK 且未检测到错误):
- 标志位:
关键状态转换补充:
- 中止发送 (
ABRQ
):程序可以在邮箱处于挂号状态 (TME=0
,TXRQ=1
,RQCP=0
,TXOK=0
) 或预定状态 (TME=0
,TXRQ=1
,RQCP=0
,TXOK=0
) 时(即报文尚未实际开始驱动总线波形),通过设置ABRQ = 1
来主动终止该次发送请求。效果与NART=1
时的发送失败相同:直接进入空置状态,RQCP=1
,TXOK=0
。 - 预定状态回退:仅发生在
TXFP=0
(ID 优先级模式) 且有更高优先级报文加入并请求发送时。该邮箱会从预定状态退回到挂号状态 (TME=0
,TXRQ=1
,RQCP=0
,TXOK=0
),等待再次被调度。
2.1.5 接收流程详解
接下来,我们聚焦于 接收 FIFO (FIFO0 或 FIFO1) 在报文接收、存储和读取过程中经历的状态及其状态寄存器标志位的变化。理解这个状态机对于掌握接收流程和管理 FIFO 队列至关重要。
STM32 CAN 接收 FIFO 状态流转详解
核心状态寄存器标志位 (需关注):
FMPx
(FIFO message pending - x=0 or 1):FIFO 中挂起的报文数量。这是一个 2 位字段:00b
:0 个报文 (FIFO 空)。01b
:1 个报文。10b
:2 个报文。11b
:3 个报文 (FIFO 满)。
FOVRx
(FIFO overrun - x=0 or 1):FIFO 溢出标志。1
表示自上次该标志被清除以来,该 FIFO 曾发生过溢出(即 FIFO 满时又收到新报文);0
表示未发生溢出。FULLx
(FIFO full - x=0 or 1):FIFO 满标志。1
表示该 FIFO 的 3 个邮箱已全部占用;0
表示 FIFO 未满(有至少一个空邮箱)。(注:此标志位在手册提供的流程图中未明确标出,但实际存在且重要)。RFOMx
(Release FIFO output mailbox - x=0 or 1):释放 FIFO 输出邮箱。程序通过置1
此位来释放当前位于 FIFO 队列头部的邮箱(即FIFOx
邮箱 0),使队列后续报文前移。
接收 FIFO 状态机 (单个 FIFO 视角):
-
空状态 (Empty):
- 标志位:
FMPx = 00b
(0),FOVRx = 0
,FULLx = 0
。 - 含义:FIFO 队列为空,无任何报文等待处理。所有 3 个邮箱均空闲。
- 进入条件:初始状态,或所有报文被读取释放后。
- 操作:等待有效报文存入。
- 标志位:
-
挂号一状态 (Pending 1):
- 标志位:
FMPx = 01b
(1),FOVRx = 0
,FULLx = 0
。 - 含义:FIFO 队列中有 1 个报文(位于邮箱 0),等待程序读取。FIFO 未满,未溢出。
- 进入条件:从空状态接收到第 1 个有效报文(通过过滤器且目标为此 FIFO)。
- 操作:程序可读取
FIFOx
邮箱 0 的数据。
- 标志位:
-
挂号二状态 (Pending 2):
- 标志位:
FMPx = 10b
(2),FOVRx = 0
,FULLx = 0
。 - 含义:FIFO 队列中有 2 个报文(邮箱 0 和 邮箱 1),按接收顺序排队。FIFO 未满,未溢出。
- 进入条件:从挂号一状态接收到第 2 个有效报文。
- 操作:程序可读取
FIFOx
邮箱 0 (队首) 的数据。 - 手册勘误说明:手册流程图此处将
FMPx
写作0x10
(十六进制 16),这是错误的。正确应为10b
(二进制 2) 或明确表示为2
。
- 标志位:
-
挂号三状态 (Pending 3 / Full):
- 标志位:
FMPx = 11b
(3),FOVRx = 0
,FULLx = 1
。 - 含义:FIFO 队列已满,3 个邮箱均已占用(邮箱 0, 1, 2)。FIFO 已满 (
FULLx=1
),但尚未溢出 (FOVRx=0
)。这是 FIFO 的最大容量状态。 - 进入条件:从挂号二状态接收到第 3 个有效报文。
- 操作:程序可读取
FIFOx
邮箱 0 (队首) 的数据。
- 标志位:
-
溢出状态 (Overrun):
- 标志位:
FMPx = 11b
(3),FOVRx = 1
,FULLx = 1
。 - 含义:FIFO 队列已满 (
FMPx=11b
,FULLx=1
) 的状态下,又收到了一个需存入该 FIFO 的有效报文。此时发生了溢出 (FOVRx=1
)。 - 进入条件:在挂号三状态 (已满) 时,接收到第 4 个 (及更多) 有效报文。
- 溢出处理 (取决于
RFLM
配置位):RFLM = 1
(锁定模式):新报文被直接丢弃。FIFO 内容 (FMPx=11b
) 保持不变。RFLM = 0
(非锁定模式 - 默认):新报文覆盖队列中最后接收的报文(即邮箱 2 中的旧报文)。FMPx
和FULLx
保持11b
和1
,表示队列仍满,但内容已更新(邮箱 2 被替换)。
- 状态维持:只要 FIFO 保持满状态 (
FMPx=11b
) 且不断有新的目标报文到来,FOVRx
将保持为1
,状态维持为溢出状态。每次新报文到来都会根据RFLM
执行丢弃或覆盖操作。
- 标志位:
FIFO 读取与释放操作:
- 操作前提:当
FMPx > 00b
(FIFO 非空) 时,程序可以读取FIFOx
邮箱 0 的报文数据。 - 关键操作 - 释放邮箱 (
RFOMx=1
):读取完邮箱 0 的数据后,程序必须置RFOMx=1
来释放该邮箱。 - 释放后的队列管理:
- 释放操作触发队列前移:
- 邮箱 1 的报文 -> 移动到邮箱 0 (成为新队首)。
- 邮箱 2 的报文 -> 移动到邮箱 1。
- 原邮箱 2 的位置变为空闲 (可接收新报文)。
FMPx
值减 1。- 如果
FOVRx=1
,它不会被自动清除,需要软件在适当时机手动清除。
- 释放操作触发队列前移:
- 状态转换 (释放后):
- 从溢出状态 (
FMPx=11b
,FOVRx=1
,FULLx=1
) 释放邮箱:FMPx
变为10b
(2)。FULLx
变为0
(队列未满)。- 状态直接进入挂号二状态 (
FMPx=10b
,FOVRx=1
,FULLx=0
)。 - 重要说明:不需要经过挂号三状态。溢出状态和挂号三状态的主要区别在于
FOVRx
标志位。释放邮箱后,FMPx
从 3 减为 2,队列未满,故直接进入挂号二状态。FOVRx=1
仍然有效,指示曾发生过溢出。
- 从挂号三状态 (
FMPx=11b
,FOVRx=0
,FULLx=1
) 释放邮箱:FMPx
变为10b
(2).FULLx
变为0
.- 状态进入挂号二状态 (
FMPx=10b
,FOVRx=0
,FULLx=0
)。
- 从挂号二状态 (
FMPx=10b
,FOVRx=0
,FULLx=0
) 释放邮箱:FMPx
变为01b
(1).- 状态进入挂号一状态 (
FMPx=01b
,FOVRx=0
,FULLx=0
)。
- 从挂号一状态 (
FMPx=01b
,FOVRx=0
,FULLx=0
) 释放邮箱:FMPx
变为00b
(0).- 状态回到空状态 (
FMPx=00b
,FOVRx=0
,FULLx=0
)。
- 从溢出状态 (
2.1.6 关键配置位总结
NART
(No automatic retransmission):1
:禁止自动重传。报文只发送一次(无论成功失败)。0
:启用自动重传 (默认)。发送失败会重试直至成功。
TXFP
(Transmit FIFO priority):1
:发送优先级由请求顺序决定 (先请求先发送)。0
:发送优先级由报文标识符(ID) 决定 (ID小者优先)。
RFLM
(Receive FIFO locked mode):1
:接收FIFO 锁定模式。FIFO满时新报文丢弃。0
:接收FIFO 非锁定模式 (默认)。FIFO满时新报文覆盖FIFO末尾旧报文。
本节总结
我们详细讲解了 STM32 bxCAN外设的核心结构、发送邮箱的状态流转、接收过滤器与双FIFO的工作机制以及关键配置位(NART
, TXFP
, RFLM
)。掌握了这些硬件原理,为下一部分编写实际通信程序奠定了坚实基础。
下一节预告:我们将深入探讨 CAN外设的标识符过滤器配置 及更多功能。