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外設的標識符過濾器配置 及更多功能。