STM32 CAN控制器硬件資源與用法

1、硬件結構圖

以STM32F4為例,他有2個can控制器,分別為 CAN1 CAN2。

每個CAN控制器,都有3個發送郵箱、2個接收fifo,每個接收fifo又由3個接收郵箱組成。也即每個CAN控制器都有9個郵箱,其中3個供發送用,3個供接收fifo0用,3個供接收fifo1用。

STM32F4有2個CAN,也即有18個郵箱。

下圖來自數據手冊,可以清楚的看到單片機內部的2個CAN控制器的硬件結構。

這個結構圖對于編寫收發驅動程序至關重要。

2、發送數據

我們由stm32提供的庫函數來看一下發送過程,我加了幾條中文注釋,發送;流程應該很清楚了

uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage)
{uint8_t transmit_mailbox = 0;/* Check the parameters */assert_param(IS_CAN_ALL_PERIPH(CANx));assert_param(IS_CAN_IDTYPE(TxMessage->IDE));assert_param(IS_CAN_RTR(TxMessage->RTR));assert_param(IS_CAN_DLC(TxMessage->DLC));/* Select one empty transmit mailbox */if ((CANx->TSR&CAN_TSR_TME0) == CAN_TSR_TME0){//如果發送郵箱[0]空閑,則記下該郵箱的編號0,退出iftransmit_mailbox = 0;}else if ((CANx->TSR&CAN_TSR_TME1) == CAN_TSR_TME1){//如果發送郵箱[1]空閑,則記下該郵箱的編號1,退出iftransmit_mailbox = 1;}else if ((CANx->TSR&CAN_TSR_TME2) == CAN_TSR_TME2){//如果發送郵箱[2]空閑,則記下該郵箱的編號2,退出iftransmit_mailbox = 2;}else{//如果發送郵箱全不空閑,則標記為全不可用transmit_mailbox = CAN_TxStatus_NoMailBox;}if (transmit_mailbox != CAN_TxStatus_NoMailBox)//至少有一個發送郵箱空閑{/* Set up the Id */CANx->sTxMailBox[transmit_mailbox].TIR &= TMIDxR_TXRQ;if (TxMessage->IDE == CAN_Id_Standard)//記錄CAN地址(std標準地址、或ext擴展地址){assert_param(IS_CAN_STDID(TxMessage->StdId));  CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->StdId << 21) | \TxMessage->RTR);}else{assert_param(IS_CAN_EXTID(TxMessage->ExtId));CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) | \TxMessage->IDE | \TxMessage->RTR);}/* Set up the DLC */TxMessage->DLC &= (uint8_t)0x0000000F;CANx->sTxMailBox[transmit_mailbox].TDTR &= (uint32_t)0xFFFFFFF0;CANx->sTxMailBox[transmit_mailbox].TDTR |= TxMessage->DLC;//記錄要發送的字節數/* Set up the data field */ //填充要發送的字節內容CANx->sTxMailBox[transmit_mailbox].TDLR = (((uint32_t)TxMessage->Data[3] << 24) | ((uint32_t)TxMessage->Data[2] << 16) |((uint32_t)TxMessage->Data[1] << 8) | ((uint32_t)TxMessage->Data[0]));CANx->sTxMailBox[transmit_mailbox].TDHR = (((uint32_t)TxMessage->Data[7] << 24) | ((uint32_t)TxMessage->Data[6] << 16) |((uint32_t)TxMessage->Data[5] << 8) |((uint32_t)TxMessage->Data[4]));/* Request transmission */ //啟動發送CANx->sTxMailBox[transmit_mailbox].TIR |= TMIDxR_TXRQ;}return transmit_mailbox;
}

根據數據手冊目錄可見,3個發送郵箱均有4個相關寄存器:

分別是TIxR、TDTxR、TDLxR、TDHxR,其中x為0、1、2,分別對應3個郵箱,例如TDT0R代表郵箱[0]的TDTxR寄存器。

在硬件上,每個郵箱的這4個寄存器是按順序的,也即依次為:TI0R、TDT0R、TDL0R、TDH0R、TI1R、TDT1R、TDL1R、TDH1R、TI2R、TDT2R、TDL2R、TDH2R。

如果我們把以上12個寄存器地址都宏定義為以上名稱,當然沒問題,但是使用起來不是很方便,尤其不方便使用循環。在ST庫函數中,是這樣定義的:

他把每個郵箱的4個寄存器,都作為結構體的一個成員,這樣3個郵箱就可以用結構體數組來描述了 ,而且與硬件順序一致,如下所示:

這樣CAN1的TI0R寄存器,就可以用CAN1->sTxMailBox[0].TIR來引用了。

3、接收數據

以CAN1為例,CAN1在初始化時,就要先給CAN1的兩個FIFO綁定過濾器,當CAN1的總線收到消息后,會先由CAN1的FIFO0過濾器進行篩選,篩選通過的報文,會分別進入FIFO0的3個郵箱中空閑的1個,供CPU來調取,接收結束;如果未通過篩選,則進入FIFO1的過濾器進行篩選,如果通過篩選,則會進入FIFO1 3個空閑郵箱中的1個,供CPU來調取。

一般簡單的使用場景中,只給fifo0激活過濾器就幾乎能滿足日常需求了,fifo1的過濾器直接設置為全失能就行了,這樣就假裝fifo1不存在就好了。

下面 根據ST的官方庫函數,看一下接收過程:

第一步,先查詢某FIFO中消息的數量(顯然,最多有3條,也即該FIFO的3個郵箱都有數據時)

uint8_t CAN_MessagePending(CAN_TypeDef* CANx, uint8_t FIFONumber)
{uint8_t message_pending=0;/* Check the parameters */assert_param(IS_CAN_ALL_PERIPH(CANx));assert_param(IS_CAN_FIFO(FIFONumber));if (FIFONumber == CAN_FIFO0)//查詢FIFO0的3個郵箱中中,有幾個有數據{   //0x03就是寄存器RFxR低2 bits(FMPx)的掩碼,見下圖RFxR寄存器描述message_pending = (uint8_t)(CANx->RF0R&(uint32_t)0x03);}else if (FIFONumber == CAN_FIFO1)//查詢FIFO1的3個郵箱中中,有幾個有數據{message_pending = (uint8_t)(CANx->RF1R&(uint32_t)0x03);}else{message_pending = 0;}return message_pending;//返回消息的數量
}
void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage)
{/* Check the parameters */assert_param(IS_CAN_ALL_PERIPH(CANx));assert_param(IS_CAN_FIFO(FIFONumber));/* Get the Id */RxMessage->IDE = (uint8_t)0x04 & CANx->sFIFOMailBox[FIFONumber].RIR;//提取消息的ID類型if (RxMessage->IDE == CAN_Id_Standard)//如果消息類型是std標準幀{RxMessage->StdId = (uint32_t)0x000007FF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 21);}else//如果消息類型是ext擴展幀{RxMessage->ExtId = (uint32_t)0x1FFFFFFF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 3);}//提取RTR比特,是1遠程幀還是0數據幀RxMessage->RTR = (uint8_t)0x02 & CANx->sFIFOMailBox[FIFONumber].RIR;/* Get the DLC *///提取字節數RxMessage->DLC = (uint8_t)0x0F & CANx->sFIFOMailBox[FIFONumber].RDTR;/* Get the FMI */RxMessage->FMI = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDTR >> 8);/* Get the data field */RxMessage->Data[0] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDLR;RxMessage->Data[1] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 8);RxMessage->Data[2] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 16);RxMessage->Data[3] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 24);RxMessage->Data[4] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDHR;RxMessage->Data[5] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 8);RxMessage->Data[6] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 16);RxMessage->Data[7] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 24);/* Release the FIFO *//* Release FIFO0 */if (FIFONumber == CAN_FIFO0)//清除郵箱占用標志{CANx->RF0R |= CAN_RF0R_RFOM0;}/* Release FIFO1 */else /* FIFONumber == CAN_FIFO1 */{CANx->RF1R |= CAN_RF1R_RFOM1;}
}

3.1 篩選器

接收時 ,可以設置者篩選器(手冊或庫函數中稱為filter),說白了就是根據CAN的ID來設置白名單或黑名單,直接丟棄我們不想要的報文,以便減輕CPU負擔。

列表模式(我管他叫做白名單):只有報文的ID出現在該列表中,該報文才會進入接收郵箱,否則直接被丟棄。

屏蔽模式(我管他叫做黑名單):如果報文攜帶的ID復合黑名單規則,則該報文直接被丟棄,否則才允許進入郵箱。

STM32F4?共有28個篩選器組,每個篩選器都有2個u32的寄存器,分別是CAN_FxR0和CAN_FxR1,其中x為0~27共28組。

篩選器的配置

1、尺度配置:篩選器可配置為雙16位或單32位,以應對不同需求。通過寄存器FS1R的28個bit的0或1分別對應這28個篩選器組的尺度配置。0=雙16位1=單32位

2、模式配置。CAN_FM1R寄存器的32個bit中的28個,用于指定28個篩選器組工作于哪種模式,0=屏蔽模式,1=列表模式

3、給FIFO分配篩選器。CAN_FFA1R寄存器32個bit中的28個,用于指定28個篩選器要分配給哪個FIFO。如果bit5=0代表篩選器5分配給FIFO0,如果bit5=1代表篩選器5分配給FIFO1,其他bit雷同。

4、篩選器內容配置:

3.2 FIFO0和FIFO1

兩個CAN各有2個FIFO,每個FIFO又各有3個郵箱,但是與發送郵箱不同的,接收FIFO的這6個附屬郵箱,無法被直接訪問。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/899621.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/899621.shtml
英文地址,請注明出處:http://en.pswp.cn/news/899621.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【C++ 繼承】—— 青花分水、和而不同,繼承中的“明明德”與“止于至善”

歡迎來到ZyyOvO的博客?&#xff0c;一個關于探索技術的角落&#xff0c;記錄學習的點滴&#x1f4d6;&#xff0c;分享實用的技巧&#x1f6e0;?&#xff0c;偶爾還有一些奇思妙想&#x1f4a1; 本文由ZyyOvO原創??&#xff0c;感謝支持??&#xff01;請尊重原創&#x1…

Qt warning LNK4042: 對象被多次指定;已忽略多余的指定

一、常規原因&#xff1a; pro或pri 文件中源文件被多次包含 解決&#xff1a;刪除變量 SOURCES 和 HEADERS 中重復條目 二、誤用 對于某些pri庫可以使用如下代碼簡寫包含 INCLUDEPATH $$PWDHEADERS $$PWD/*.hSOURCES $$PWD/*.cpp但是假如該目錄下只有頭文件&#xff0c;沒…

Visual Studio Code 無法打開源文件解決方法

&#x1f308; 個人主頁&#xff1a;Zfox_ &#x1f525; 系列專欄&#xff1a;Linux &#x1f525; 系列專欄&#xff1a;C從入門到精通 目錄 一&#xff1a;&#x1f525; 突發狀況 二&#xff1a;&#x1f525; 共勉 一&#xff1a;&#x1f525; 突發狀況 &#x1f42c;…

js文字兩端對齊

目錄 一、問題 二、原因及解決方法 三、總結 一、問題 1.text-align: justify; 不就可以了嗎&#xff1f;但是實際測試無效 二、原因及解決方法 1.原因&#xff1a;text-align只對非最后一行文字有效。只有一行文字時&#xff0c;text-align無效&#xff0c;要用text-alig…

LeetCode算法題(Go語言實現)_20

題目 給你兩個下標從 0 開始的整數數組 nums1 和 nums2 &#xff0c;請你返回一個長度為 2 的列表 answer &#xff0c;其中&#xff1a; answer[0] 是 nums1 中所有 不 存在于 nums2 中的 不同 整數組成的列表。 answer[1] 是 nums2 中所有 不 存在于 nums1 中的 不同 整數組成…

每天認識一個設計模式-橋接模式:在抽象與實現的平行宇宙架起彩虹橋

一、前言&#xff1a;虛擬機橋接的啟示 使用過VMware或者Docker的同學們應該都接觸過網絡橋接&#xff0c;在虛擬機網絡配置里&#xff0c;橋接模式是常用的網絡連接方式。選擇橋接模式時&#xff0c;虛擬機會通過虛擬交換機與物理網卡相連&#xff0c;獲取同網段 IP 地址&…

java筆記02

運算符 1.隱式轉換和強制轉換 類型轉換的分類 1.隱式轉換&#xff1a; 取值范圍小的數值 轉換為 取值范圍大的數值 2.強制轉換&#xff1a; 取值范圍大的數值 轉換為 取值范圍小的數值隱式轉換的兩種提升規則 取值范圍小的&#xff0c;和取值范圍大的進行運算&#xff0c;小的…

Redis-07.Redis常用命令-集合操作命令

一.集合操作命令 SADD key member1 [member2]&#xff1a; sadd set1 a b c d sadd set1 a 0表示沒有添加成功&#xff0c;因為集合中已經有了這個元素了&#xff0c;因此無法重復添加。 SMEMBERS key: smembers set1 SCARD key&#xff1a; scard set1 SADD key member1 …

李飛飛、吳佳俊團隊新作:FlowMo如何以零卷積、零對抗損失實現ImageNet重構新巔峰

目錄 一、摘要 二、引言 三、相關工作 四、方法 基于擴散先前的離散標記化器利用廣告 架構 階段 1A&#xff1a;模式匹配預訓練 階段 1B&#xff1a;模式搜索后訓練 采樣 第二階段&#xff1a;潛在生成建模 五、Coovally AI模型訓練與應用平臺 六、實驗 主要結果 …

CSS3:現代Web設計的魔法卷軸

一、布局革命&#xff1a;從平面到多維空間 1.1 Grid布局的次元突破 星際戰艦布局系統 .galaxy {display: grid;grid-template-areas: "nav nav nav""sidebar content ads""footer footer footer";grid-template-rows: 80px 1fr 120p…

美觀快速的react 的admin框架

系統特色&#xff1a; - &#x1f3a8; 精心設計的UI主題系統&#xff0c;提供優雅的配色方案和視覺體驗 - &#x1f4e6; 豐富完整的組件庫&#xff0c;包含大量開箱即用的高質量組件 - &#x1f528; 詳盡的組件使用示例&#xff0c;降低開發者的學習成本 - &#x1f680…

【C++】 string底層封裝的模擬實現

目錄 前情提要Member functions —— 成員函數構造函數拷貝構造函數賦值運算符重載析構函數 Element access —— 元素訪問Iterator —— 迭代器Capacity —— 容量sizecapacityclearemptyreserveresize Modifiers —— 修改器push_backappendoperator(char ch)operator(const …

計算機網絡相關知識小結

計算機網絡 1.計算機網絡&#xff1a;獨立計算機&#xff0c;通信線路連接&#xff0c;實現資源共享 2.組成&#xff1a;資源子網和通信子網 3.拓撲分類 4.范圍&#xff1a;LAN, MAN. WAN 5、有線和無線 6.按照方向&#xff1a;單工、雙工&#xff0c;全雙工 7.傳輸對象方式&a…

16-CSS3新增選擇器

知識目標 掌握屬性選擇器的使用掌握關系選擇器的使用掌握結構化偽類選擇器的使用掌握偽元素選擇器的使用 如何減少文檔內class屬性和id屬性的定義&#xff0c;使文檔變得更加簡潔&#xff1f; 可以通過屬性選擇器、關系選擇器、結構化偽類選擇器、偽元素選擇器。 1. 屬性選擇…

【彈性計算】異構計算云服務和 AI 加速器(四):FPGA 虛擬化技術

《異構計算云服務和 AI 加速器》系列&#xff0c;共包含以下文章&#xff1a; 異構計算云服務和 AI 加速器&#xff08;一&#xff09;&#xff1a;功能特點異構計算云服務和 AI 加速器&#xff08;二&#xff09;&#xff1a;適用場景異構計算云服務和 AI 加速器&#xff08;…

Java進階——位運算

位運算直接操作二進制位&#xff0c;在處理底層數據、加密算法、圖像處理等領域具有高效性能和效率。本文將深入探討Java中的位運算。 本文目錄 一、位運算簡介1. 與運算2. 或運算異或運算取反運算左移運算右移運算無符號右移運算 二、位運算的實際應用1. 權限管理2. 交換兩個變…

OpenAI深夜直播「偷襲」谷歌!GPT-4o原生圖像生成:奧特曼帶梗圖,AGI戰場再燃戰火

引言&#xff1a;AI戰場的「閃電戰」 當谷歌剛剛發布「地表最強」Gemini 2.5 Pro時&#xff0c;OpenAI立即以一場深夜直播「閃電反擊」——GPT-4o的原生圖像生成功能正式上線&#xff01;從自拍變梗圖到相對論漫畫&#xff0c;奧特曼&#xff08;OpenAI團隊&#xff09;用一連…

鴻蒙harmonyOS:筆記 正則表達式

從給出的文本中&#xff0c;按照既定的相關規則&#xff0c;匹配出符合的數據&#xff0c;其中的規則就是正則表達式&#xff0c;使用正則表達式&#xff0c;可以使得我們用簡潔的代碼就能實現一定復雜的邏輯&#xff0c;比如判斷一個郵箱賬號是否符合正常的郵箱賬號&#xff0…

[首發]烽火HG680-KD-海思MV320芯片-2+8G-安卓9.0-強刷卡刷固件包

烽火HG680-KD-海思MV320芯片-28G-安卓9.0-強刷卡刷固件包 U盤強刷刷機步驟&#xff1a; 1、強刷刷機&#xff0c;用一個usb2.0的8G以下U盤&#xff0c;fat32&#xff0c;2048塊單分區格式化&#xff08;強刷對&#xff35;盤非常非常挑剔&#xff0c;usb2.0的4G U盤兼容的多&a…

Python-數據處理

第十五章 生成數據 安裝Matplotlib&#xff1a;通過pip install matplotlib命令安裝庫。繪制折線圖的核心語法為&#xff1a; import matplotlib.pyplot as plt x_values [1, 2, 3] y_values [1, 4, 9] plt.plot(x_values, y_values, linewidth2) plt.title(&quo…