在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

【GD32F303紅楓派開發板使用手冊】第三十講 CAN -CAN通信實驗

聚沃科技 ? 2024-07-05 11:13 ? 次閱讀
wKgaomZVdiiAfR9BAB3mDFhHnZc972.png

30.1實驗內容

通過本實驗主要學習以下內容:

30.2實驗原理

30.2.1CAN概述

CAN 是Controller Area Network的縮寫,是由德國BOSCH公司開發的,已成為ISO國際標準化的串行通信協議。其主要應用場合為汽車和工業控制。CAN具有傳輸距離長,傳輸可靠、強大的糾錯機制等特點,其高性能和可靠性已被廣泛認同,現在已經成為汽車、工業自動化、醫療設備等領域應用最廣泛的總線之一。

30.2.2CAN總線拓撲

CAN總線拓撲圖如下:

wKgZomaHYsiAWvRyAAItASjUeEI275.png

CAN 控制器根據兩根線上的電位差來判斷總線電平,一般將兩根線分別命名為CAN_H和CAN_L。總線電平分為顯性電平和隱性電平,二者必居其一。發送方通過使總線電平發生變化,將消息發送給接收方。 當CAN總線上的電位差為0V時,表示隱性電平,隱性電平代表邏輯“1”;當CAN總線上有電位差時(大概在2.5V左右),表示顯性電平,顯性電平代表邏輯“0”。總線空閑時,默認為隱性電平,即總線電位差為0。

wKgZomaHYtaALFZOAAEmmitVmDM170.png

關于電位差、隱性/顯性電平及邏輯電平,非常容易弄混,讀者需要熟記。

CAN總線的特點可以總結為:

  1. 多主

與USART-485這種一主多從類型總線不同,CAN總線是多主控制,即總線上沒有主機從機之分,所有設備都是處于平等的地位。

  1. 消息格式

CAN總線上的消息都以固定格式發送。當兩個以上的單元同時開始發送消息時,根據標識符(Identifier以下稱為ID)決定優先級。ID并不是表示發送的目的地址,而是表示訪問總線的消息的優先級。

  1. 通信速度快,通信距離遠

CAN最高可達1Mbps波特率,理論最遠距離可達10Km,當然此時通訊速率較低,只有5Kbps以下。

  1. 具有錯誤檢測、錯誤通知和錯誤恢復功能

CAN總線具有強大的錯誤檢測、通知和恢復功能。當一個單元發生錯誤時其他單元會進行報錯,正在發送的單元檢測到錯誤后,會立即強制結束當前發送,并嘗試重新發送(功能可配置),當發送錯誤的次數達到一定值后,該單元會自動從總線中退出,直到應用程序讓其重新加入總線為止。

  1. 半雙工異步通訊

CAN的總線的查分信號,決定了CAN總線實際為半雙工通訊,另外由于CAN總線沒有時鐘線,所以是異步通訊,故要求CAN總線上的所有單元的波特率都要設置一致。

30.2.3CAN幀的種類

CAN總共有如下五種類型的幀種類:

  • 數據幀

用于數據傳輸的幀,也是最常用的一種幀種類

  • 遙控幀

接收單元向具有相同ID的發送單元請求數據時所需要的幀種類

  • 錯誤幀

一種非常重要的幀種類,錯誤幀是當總線上有錯誤時,檢測到錯誤的單元向其他單元通知錯誤的幀。

  • 過載幀

用于接收單元通知其他單元其還沒有準備好的幀種類

  • 幀間隔

用于幀和幀之間分離的幀

30.2.4CAN協議的解析

介紹了CAN的一些基本指示后,可能讀者還是不太明白幀ID是什么,CAN的發送和接收是怎么實現的,是否就像串口一樣發送數據就可以?實際上CAN需要遵循CAN協議,這樣每個CAN單元才可以準確無誤的發送和接收數據,CAN強大的錯誤檢測、錯誤通知等機制也是依托于標準CAN協議。下面以數據幀來解析下CAN的協議。

數據幀的格式如下圖,其中D表示顯性位,即邏輯“0”,R表示隱性位,即邏輯“1”,D/R表示隱性位或顯性位,另外下圖中的數字表示bit位數:

wKgaomaHYueAOKkkAAEiZnRurC4328.png
  • 幀開始

每次CAN通訊都始于幀開始段,幀開始是1個bit位的顯性電平(邏輯“0”),由發送方發出,接收方檢測到一個bit邏輯“0”,開始準備接收數據。

  • 仲裁段

好了,我們終于看到了幀ID的廬山真面目了。數據幀分為兩種——標準幀和擴展幀,標準幀的幀ID由11bit組成,擴展幀有11+18共29bit組成。需要注意,無論是標準幀ID還是擴展幀ID,都不允許設置最高7bit為1(即不允許幀ID=0b,1111111xxx··),以為幀結束段就是7個“1”組成。

沖裁段中的 RTR 位用于標識是否是遠程幀(0:數據幀;1:遠程幀),IDE位為標識符選擇位(0:使用標準標符;1:使用擴展標識符),SRR位為代替遠程請求位,為隱性位,它代替了標準幀中的RTR位。

我們需要先明確一個概念,CAN總線上的每個單元并不是只能發送固定幀ID,而是可以發送任意幀ID,幀ID不代表CAN設備號,代表的是當前數據幀/遠程幀的ID號。當一幀數據發送到總線后,所有接收方會對幀ID進行識別,當識別到是自己需要的ID時,則會將該幀數據收取到內部;而當識別到不是自己需要的ID時,則不會接收數據。

因為有可能出現兩個或更多CAN單元同時發送數據的情況,此時幀ID還起到仲裁的作用,各發送單元從幀ID的第一位開始進行仲裁。連續輸出顯性電平最多的單元可繼續發送,比如兩個CAN單元同時發送數據,其中單元一發出的數標準幀的ID為0b,00110000000,而單元二發出的標準幀ID為0b,00100000000,可以看到發送到第4位時,單元一發出的是邏輯“1”,單元二的是邏輯“0”,因為總線上“0”比“1”優先級搞,所以此時單元二獲得總線發送權,單元一將自動停止發送。

  • 控制段

控制段由6個bit組成,其中DLC占用4個bit,表示要發送的字節數。

  • 數據段

數據段即幀載有的有效數據了,CAN最多一次可發送8個字節(CANFD最多可以發送64字節,這個后面介紹帶CANFD功能的開發板時再細說),也就是說上面描述的DLC最大值為0b,1000。

  • CRC段

CRC段總共有16bit,其中15個bit表示CRC值,另1個bit為CRC界定符。此段CRC的值計算范圍包括:幀起始、仲裁段、控制段、數據段。發送會根據發送的數據來計算出一個CRC值并通過CRC段發到總線,接收方以同樣的算法計算CRC值并和發送方發出的CRC段進行比較,當不一致時接收方會向總線報錯。

ACK段用來確認接收方是否正常接收。ACK段由ACK槽(ACK Slot)和ACK界定符2個位組成。

發送單元的 ACK,發送2個位的隱性位,而接收到正確消息的單元在ACK槽(ACK Slot)發送顯性位,通知發單元正常接收結束,這個過程叫發送ACK/返回ACK。發送ACK的是在既不處于總線關閉態也不處于休眠態的所有收單元中,接收到正常消息的單元(發送單元不發送ACK)。

  • 幀結束

幀結束由7個bit的邏輯“1”組成,表示該幀結束。

30.2.5CAN的波特率

前面有提到CAN的波特率,波特率代表每秒鐘傳輸的位數(1位就表示1bit),我們來看下GD32F303的波特率是怎么計算的。

首先需要了解一個概念,CAN時序的最小單位是一個叫Tq的東西,CAN的每個位即每個bit是由若干個Tq組成的,那么這個Tq的長度是多少呢?GD32F303的CAN是掛載在APB1總線的:

wKgZomaHYveACdiOAAIqpf39r5k384.png

如果讀者將GD32F303的主頻配置為最高120M,且將APB1的時鐘配置為最高60M的話,那么CAN的時鐘就是60M,然后CAN有個分頻系數,在位時序寄存器CAN_BT中:

wKgaomaHYwWAIqX7AABG1YrFoNU787.png

一個Tq占用的時間計算公式:分頻系數/CAN時鐘,舉個例子,我們設置這個分頻系數為6的話,一個Tq的時間就是6/60M = 100us,也可以說Tq的傳輸速率為10M。那么由多少個Tq組成CAN的一個位呢?還是看CAN_BT寄存器:

wKgZomaHYxOAQQL5AABGOo6dri0581.pngwKgaomaHYxOAdPkOAABNcg7mVtE895.png

寄存器中有BS1和BS2,這兩個位域用于設置位段1和位段2(關于位段后面會介紹),一個CAN位占用的Tq個數等于位段1+位段2+1,舉個例子,設置位段1為5(即BS1=4),設置位段2為4(即BS2=3),那么一個CAN位占用的Tq個數為5+4+1=10。好,現在就可以來算CAN的波特率了,按照CAN分頻系數為6,位段1為5,位段2為4,一個位占用的時間為6/60M*10 = 1ms,也就是波特率=1M。我們可以把這個計算轉化為公式:

wKgaomaHYzqATn9qAAAGbJRLotk609.png

30.2.6CAN的位時序和采樣點

我們現在來看下上一節提到的位段1和位段2。CAN總線控制器將位時間分為3個部分。

  • 同步段(Synchronization segment),記為SYNC_SEG。該段占用1個時間單元(1 ×????)。
  • 位段1(Bit segment 1),記為BS1。該段占用1到16個Tq(由位時序寄存器配置)。相對于CAN協議而言,BS1相當于傳播時間段(Propagation delay segment)和相位緩沖段1(Phase buffer segment 1)。
  • 位段2(Bit segment 2),記為BS2。該段占用1到8個Tq(由位時序寄存器配置)。相對于CAN協議而言,BS2相當于相位緩沖段2(Phase buffer segment 2)。

位時序圖:

wKgZomaHY0KALQA5AABVIE_iwlo786.png

這里提到的BS1(即位段1)和CAN時序寄存器中的BS1[3:0]位域不是一個概念,位段1=BS1[3:0]+1

說完位時序我們來介紹下GD32F303的采樣點。

對于接收方來說,需要對發送方發出的每個bit進行采樣,那么具體是采樣哪個點呢?按照CAN標準來說,采樣點為BS1和BS2的交界處,即:

wKgaomaHY0-AaNzdAABc6t4ouE4782.png

而GD32F303為了更好的容錯性,會在標準采樣點前一個以及前前一個Tq加了兩個采樣點,取兩個有效位,所以GD32F303的采樣點為:

wKgZomaHY16AYABLAABjuUUrmQM028.png

如果三個采樣點分別采樣到的為010,則認為該位為“1”。

30.2.7GD32F303 CAN過濾器

前面提到CAN節點發送數據的時候,幀ID是任意的,那么接收方是不是任意ID都可以接收呢?當然是可以的,但一般不會這么做,一個CAN節點一般只接收一個ID或幾個ID的報文,那么如何實現呢?這就要介紹CAN的過濾器了,只有總線上的報文幀ID通過了CAN節點的過濾,才會被接收。

GD32F303共有14個過濾器組(對于互聯性GD32F305/F307,是28個過濾器組),每個過濾器組有兩個過濾器寄存器。程序中需要設置過濾器對應哪個接收FIFO(接收FIFO會在下一節中介紹)。

GD32F303過濾器(x) 數據(y) 寄存器(CAN_FxDATAy)(x= 0...13, y = 0,1)( 僅CAN0可用):

wKgZomaHY2uAJlXuAABMuCbXevE963.png

過濾器可以配置為2種位寬:32-bit位寬和16-bit位寬。32-bit位寬CAN_FDATAx包含字段:SFID[10:0],EFID[17:0],FF和FT。

wKgaomaHY3eAe2HwAAAhNZ3Tim0128.png

16-bit 位寬CAN_FDATAx包含字段:SFID[10:0],FT,FF和EFID[17:15]。

wKgZomaHY4SAeIeRAAAtaDgj7FQ620.png

過濾器可以設置為兩種模式——掩碼模式和列表模式:

  • 掩碼模式

對于一個待過濾的數據幀的標識符(Identifier),掩碼模式用來指定哪些位必須與預設的標識符相同,哪些位無需判斷。掩碼模式有兩種位寬:32bit和16bit。

一個 32-bit 位寬掩碼模式過濾器如下:

wKgaomaHY5KACpdwAAAy6dqf76Q390.png

可以看到,在掩碼模式下,FDATA0用于目標ID,FDATA1用于Mask。舉個例子,設置FDATA0為0x55550000,FDATA1為0xFF00FF00(第31~24以及第15~8位為1),那么意味著總線上的報文ID的第31~24以及第15~8位必須和FDATA0相應位相同,就可以通過這個過濾器,而其他位則不需要關心,也就是說幀ID為0x55xx00xx可以通過過濾器。

明白了32bit掩碼模式過濾器,16位位寬就很好理解了。一個16-bit位寬掩碼模式過濾器如下:

wKgaomaHY6CAGowuAAA6Uo_eCBQ260.png

和32-bit的不用,16-bit位寬掩碼過濾器的ID為FDATA0的高16bit,Mask為FDATA0的低16bit,這也意味著16-bit位寬掩碼模式可以設置28個過濾ID掩碼類型。

  • 列表模式

列表模式和掩碼模式不同,列表模式設置了一個個具體ID,只有和這些ID完全相同的幀才可以通過過濾器,同樣分成兩種位寬模式。

32-bit位寬列表模式過濾器:

wKgZomaHY8uAN2RKAAAuLzQpXGg893.png

16-bit位寬列表模式過濾器:

wKgZomaHY9aAXNpAAAAtj4s1ug0204.png

30.2.8GD32F303 CAN的發送和接收

通過上面的學習,我們已經基本了解了CAN的工作原理了,這節我們來講GD32F303 CAN的收發。首先我們需要了解GD32F303 CAN的結構框圖:

wKgZomaHY-GAJv_8AACNsuw6NGA543.png

可以看到,GD32F303是有3個發送郵箱和兩個深度為3的接收FIFO,下面我們分別介紹數據發送和數據接收。

  • 數據發送

發送寄存器的框圖:

wKgaomaHY-uAZ6VYAACIC-gnEik130.png

三個發送郵箱對于三組發送寄存器TMIx、TMPx、TMDATA0x和TMDATA1x(x=0,1,2):

發送郵箱標識符寄存器(CAN_TMIx)

wKgaomaHY_eAT4v6AAD4yWEK4Pk539.pngwKgZomaHZAGAabTOAAB7w3KehXQ105.png

發送郵箱屬性寄存器(CAN_TMPx):

wKgZomaHZBGAUmrCAAEPkOnzGdo094.png

發送郵箱 data0 寄存器(CAN_TMDATA0x):

wKgZomaHZByAGidBAAAY-Wxxy5o701.pngwKgZomaHZCSAZIoWAABYjoPbXuI530.png

發送郵箱 data1 寄存器(CAN_TMDATA1x):

wKgaomaHZC-AIKgZAAB3SpRHy5g121.png

當需要發送數據時,選擇一個空閑(empty)的郵箱(讀取CAN_TSTAT寄存器獲取),然后將該郵箱對應TMIx、TMPx、TMDATA0x和TMDATA1x寄存器填好后,使能TMIx的TEN位,寄存器中的數據就自動轉移到郵箱。

實際上數據到郵箱后也不一定就馬上發送到總線,因為有可能總線上正有數據發送,或者其他的郵箱中也有數據,這就涉及到CAN發送郵箱的調度:

當發送郵箱被填入新的數據后,郵箱狀態從empty轉到pending狀態。當超過1個郵箱處于pending狀態時,需要對多個郵箱進行調度,這時發送郵箱處于scheduled狀態。當調度完成后,發送郵箱中的數據開始向CAN總線上發送,這時發送郵箱處于transmit狀態。當數據發送完成,郵箱變為空閑,可以再次交給應用程序使用,這時發送郵箱重新變為empty狀態。

發送郵箱狀態轉換圖:

wKgZomaHZDyAeHDHAAAsGboqfE0615.png

當多個發送郵箱處于等待狀態下時,可以通過CAN_CTL的TFO位的值可以決定發送順序:

當TFO為1,所有等待發送的郵箱按照先來先發送(FIFO)的順序進行。

當TFO為0,具有最小標識符(Identifier)的郵箱最先發送。如果所有的標識符(Identifier)相等,具有最小郵箱編號的郵箱最先發送。

  • 數據接收

接收寄存器的框圖:

wKgZomaHZEaAdrflAACO3xSjmEs052.png

兩個接收FIFO對應了兩組接收寄存器RFIFOMIx,RFIFOMPx,RFIFOMDATA0x和RFIFOMDATA1x(x=0,1):

接收 FIFO 郵箱標識符寄存器(CAN_RFIFOMIx):

wKgaomaHZFGAfmC_AAAoaswpmgY135.pngwKgaomaHZGSAfBwKAADxhmnrmN8267.png

接收 FIFO 郵箱屬性寄存器(CAN_RFIFOMPx) :

wKgaomaHZFuAcilCAACjELkA7GA755.png

接收 FIFO 郵箱data0寄存器(CAN_RFIFOMDATA0x) :

wKgZomaHZHuAfYs2AAByWfoIkh8957.png

接收 FIFO 郵箱data1寄存器(CAN_RFIFOMDATA1x) :

wKgaomaHZIWAIMkYAAB0UWW1Nao537.png

當總線上報文通過CAN接收過濾器后(過濾器需要設置對應的FIFO號),數據就會保存到接收郵箱中,每個接收FIFO包含3個接收郵箱,用來接收存儲數據幀。這些郵箱按照先進先出方式進行組織,最早從CAN網絡接收的數據,最早被應用程序處理。

寄存器CAN_RFIFOx包含FIFO狀態信息和幀的數量。當FIFO中包含數據時,可以通過寄存器CAN_RFIFOMIx,CAN_RFIFOMPx,CAN_RFIFOMDATA0x和CAN_RFIFOMDATA1x讀取數據,之后將寄存器CAN_RFIFOx的RFD置1釋放郵箱。

用戶可以通過讀取寄存器CAN_RFIFOx來獲取FIFO的一些信息,比如接收FIFO中目前還有多少個郵箱內容沒有被讀取,是否有FIFO溢出的情況等。關于溢出時的處理方式,可以通過CAN_CTL寄存器的RFOD位來進行設置(讀者可閱讀GD32F30x用戶手冊來查看相關寄存器含義)。

30.2.9GD32F303 CAN工作模式

CAN 總線控制器有3種工作模式:

  • 睡眠工作模式;
  • 初始化工作模式;
  • 正常工作模式。

睡眠工作模式

芯片復位后, CAN總線控制器處于睡眠工作模式。該模式下CAN總線控制器的時鐘停止工作并處于一種低功耗狀態。

將CAN_CTL寄存器的SLPWMOD位置1,可以使CAN總線控制器進入睡眠工作模式。 當進入睡眠工作模式后,CAN_STAT寄存器的SLPWS位將被硬件置1。

將CAN_CTL寄存器的AWU位置1,并當CAN檢測到總線活動時,CAN總線控制器將自動退出睡眠工作模式。將CAN_CTL寄存器的SLPWMOD位清0,也可以退出睡眠工作模式。

由睡眠模式進入初始化工作模式:將CAN_CTL寄存器的IWMOD位置1,SLPWMOD位清0。

由睡眠模式進入正常工作模式:將CAN_CTL寄存器的IWMOD位和SLPWMOD位清0。

初始化工作模式

如果需要配置 CAN 總線通信參數,CAN總線控制器必須進入初始化工作模式。將CAN_CTL寄存器的IWMOD位置1,使CAN總線控制器進入初始化工作模式,將其清0則離開初始化 工作模式。在進入初始化工作模式后,CAN_STAT寄存器的IWS位將被硬件置1。

由初始化模式進入睡眠模式: CAN_CTL 寄存器的SLPWMOD位置1,IWMOD位清0。

由初始化模式進入正常工作模式: CAN_CTL 寄存器的SLPWMOD位和IWMOD位清0。

正常工作模式
在初始化工作模式中配置完CAN 總線通信參數后,將CAN_CTL寄存器的IWMOD位清0可以進入正常工作模式并與CAN總線網絡中的節點進行正常通信。

由正常工作模式進入睡眠工作模式: CAN_CTL 寄存器的SLPWMOD位置1,并等待當前數據收發過程結束。

由正常工作模式初始化工作模式: CAN_CTL 寄存器的IWMOD位置1,并等待當前數據收發過程結束。

30.2.10GD32F303 CAN通信模式

CAN 總線控制器有4種通信模式:

  • 靜默(Silent)通信模式;
  • 回環(Loopback)通信模式;
  • 回環靜默(Loopback and Silent)通信模式;
  • 正常(Normal)通信模式。

靜默(Silent)通信模式

在靜默通信模式下,可以從 CAN 總線接收數據,但不向總線發送任何數據。將CAN_BT寄存器中的SCMOD位置1,使CAN總線控制器進入靜默通信模式,將其清0可以退出靜默通信模式。

靜默通信模式可以用來監控CAN 網絡上的數據傳輸。

回環(Loopback)通信模式

在回環通信模式下,由 CAN 總線控制器發送的數據可以被自己接收并存入接收FIFO,同時這些發送數據也送至CAN網絡。將CAN_BT寄存器中的LCMOD位置1,使CAN總線控制器進入回環通信模式,將其清0可以退出回環通信模式。本實驗中就用到了CAN的回環通訊模式。

回環通信模式通常用來進行CAN 通信自測。

回環靜默(Loopback and Silent)通信模式

在回環靜默通信模式下, CAN 的RX和TX引腳與CAN網絡斷開。CAN總線控制器既不從CAN網絡接收數據,也不向CAN網絡發送數據,其發送的數據僅可以被自己接收。將CAN_BT寄存器中的LCMOD位和SCMOD位置1,使CAN總線控制器進入回環靜默通信模式,將它們清0可以退出回環靜默通信模式。

回環靜默通信模式通常用來進行CAN 通信自測。對外TX引腳保持隱性狀態(邏輯1),RX引腳保持高阻態。

正常(Normal)通信模式

CAN 總線控制器通常工作在正常通信模式下,可以從CAN總線接收數據,也可以向CAN總線發送數據。這時需要將CAN_BT寄存器的LCMOD位和SCMOD位清0。

30.3硬件設計

本實驗CAN的硬件設計如下:

wKgaomaHZJSABaSJAAD3k2bG5s8279.png

30.4代碼解析

30.4.1CAN 配置函數

在driver_can.c中定義了driver_can_config函數,用于CAN的基本參數和過濾器配置:

C
void driver_can_config(typdef_can_general can_general)
{
rcu_periph_clock_enable(can_general.rcu_can); //CAN時鐘使能
rcu_periph_clock_enable(can_general.rcu_IO_port); //IO時鐘使能
if(can_general.can_remap != 0) //如IO有remap,需要配置remap功能
{
rcu_periph_clock_enable(RCU_AF);
gpio_pin_remap_config(can_general.can_remap,ENABLE);
}
gpio_init(can_general.IO_port,GPIO_MODE_IPU,can_general.gpio_speed,can_general.pin_rx); //CAN RX IO配置
gpio_init(can_general.IO_port,GPIO_MODE_AF_PP,can_general.gpio_speed,can_general.pin_tx); //CAN TX IO配置

can_struct_para_init(CAN_INIT_STRUCT, &can_general.can_parameter); //CAN初始化結構體的初始化
can_struct_para_init(CAN_INIT_STRUCT, &can_general.can_filter); //CAN過濾器結構體的初始化

can_deinit(can_general.can_port); //CAN的deinit

can_general.can_parameter.time_triggered = DISABLE; //時間觸發功能
can_general.can_parameter.auto_bus_off_recovery = DISABLE;//busoff自恢復功能
can_general.can_parameter.auto_wake_up = DISABLE; //自動喚醒功能
can_general.can_parameter.no_auto_retrans = DISABLE;//自動重發功能,需要注意DISABLE為使能自動重發
can_general.can_parameter.rec_fifo_overwrite = DISABLE;//接收溢出模式
can_general.can_parameter.trans_fifo_order = DISABLE;//發送郵箱順序配置
can_general.can_parameter.working_mode = CAN_LOOPBACK_MODE;//回環模式
can_general.can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;//再同步補償
can_general.can_parameter.time_segment_1 = CAN_BT_BS1_5TQ;//BS1設置,注意這里設置為5,寄存器BS1[3:0]實際為4
can_general.can_parameter.time_segment_2 = CAN_BT_BS2_4TQ;//BS2設置,注意這里設置為4,寄存器BS2[2:0]實際為3

/* 1MBps */
#if CAN_BAUDRATE == 1000 //波特率設置
can_general.can_parameter.prescaler = 6;
/* 500KBps */
#elif CAN_BAUDRATE == 500
can_general.can_parameter.prescaler = 12;
/* 250KBps */
#elif CAN_BAUDRATE == 250
can_general.can_parameter.prescaler = 24;
/* 125KBps */
#elif CAN_BAUDRATE == 125
can_general.can_parameter.prescaler = 48;
/* 100KBps */
#elif CAN_BAUDRATE == 100
can_general.can_parameter.prescaler = 60;
/* 50KBps */
#elif CAN_BAUDRATE == 50
can_general.can_parameter.prescaler = 120;
/* 20KBps */
#elif CAN_BAUDRATE == 20
can_general.can_parameter.prescaler = 300;
#else
#error "please select list can baudrate in private defines in main.c "
#endif
/* initialize CAN */
can_init(can_general.can_port, &can_general.can_parameter);//CAN初始化

/* initialize filter */
can_general.can_filter.filter_number=0; //過濾器號
can_general.can_filter.filter_mode = CAN_FILTERMODE_MASK;//掩碼模式
can_general.can_filter.filter_bits = CAN_FILTERBITS_32BIT;//掩碼位寬
can_general.can_filter.filter_list_high = 0x3000<<1; //掩碼和ID設置
can_general.can_filter.filter_list_low = 0x0000;
can_general.can_filter.filter_mask_high = 0x3000<<1;
can_general.can_filter.filter_mask_low = 0x0000;
can_general.can_filter.filter_fifo_number = CAN_FIFO0; //過濾器關聯接收FIFO號
can_general.can_filter.filter_enable = ENABLE; //過濾器使能
can_filter_init(&can_general.can_filter); //過濾器初始化

can_general.can_filter.filter_number=1;
can_general.can_filter.filter_list_high = 0x5000<<1;
can_general.can_filter.filter_list_low = 0x0000;
can_general.can_filter.filter_mask_high = 0x5000<<1;
can_general.can_filter.filter_mask_low = 0x0000;
can_general.can_filter.filter_fifo_number = CAN_FIFO1;

can_filter_init(&can_general.can_filter);

if(can_general.can_rx_use_interrupt == SET)//打開CAN接收中斷
{
can_interrupt_enable(can_general.can_port, CAN_INT_RFNE0);
can_interrupt_enable(can_general.can_port, CAN_INT_RFNE1);
}
}

其中波特率CAN_BAUDRATE在driver_can.h中預定義:

C
/* select CAN baudrate */
/* 1MBps */
#define CAN_BAUDRATE 1000
/* 500kBps */
/* #define CAN_BAUDRATE 500 */
/* 250kBps */
/* #define CAN_BAUDRATE 250 */
/* 125kBps */
/* #define CAN_BAUDRATE 125 */
/* 100kBps */
/* #define CAN_BAUDRATE 100 */
/* 50kBps */
/* #define CAN_BAUDRATE 50 */
/* 20kBps */
/* #define CAN_BAUDRATE 20 */

30.4.2CAN 發送函數

在driver_can.c中定義了CAN發送函數:

C
void driver_can_transmit(typdef_can_general can_general,can_trasnmit_message_struct *transmit_message)
{
can_message_transmit(can_general.can_port,transmit_message);
}

30.4.3CAN中斷接收函數

在bsp_can.c中定義了CAN FIFO0和FIFO1的中斷接收處理函數:

C
void can0_rx0_interrupt_handler(void)
{
can_message_receive(CAN0, CAN_FIFO0, &can0_receive_message_fifo0);//將數據從FIFO中轉移到接收寄存器組中
if((0x300 == can0_receive_message_fifo0.rx_sfid)&&(CAN_FF_STANDARD == can0_receive_message_fifo0.rx_ff)&&(2 == can0_receive_message_fifo0.rx_dlen)){
can0_receive_fifo0_flag = SET;
}else{
can0_receive_fifo0_flag = RESET;
}
}

C
void can0_rx1_interrupt_handler(void)
{
can_message_receive(CAN0, CAN_FIFO1, &can0_receive_message_fifo1);//將數據從FIFO中轉移到接收寄存器組中
if((0x500 == can0_receive_message_fifo1.rx_sfid)&&(CAN_FF_STANDARD == can0_receive_message_fifo1.rx_ff)&&(2 == can0_receive_message_fifo1.rx_dlen)){
can0_receive_fifo1_flag = SET;
}else{
can0_receive_fifo1_flag = RESET;
}
}

30.4.4main函數實現

main函數實現如下:

C
int main(void)
{
driver_init();//delay函數初始化
bsp_uart_init(&BOARD_UART);//BOARD_UART串口初始化
bsp_can_config(BSP_CAN);//BOARD_CAN初始化
nvic_irq_enable(USBD_LP_CAN0_RX0_IRQn,0,0);//使能CAN0 FIFO0 NVIC
nvic_irq_enable(CAN0_RX1_IRQn,0,0);//使能CAN0 FIFO1 NVIC
while (1)
{
bsp_can_transmit(BSP_CAN,&bsp_can_transmit_message_1);//發送一幀數據
printf("\r\n can0 transmit data:%x,%x", bsp_can_transmit_message_1.tx_data[0], bsp_can_transmit_message_1.tx_data[1]);//發送數據打印
delay_ms(1000); //延時1s
bsp_can_transmit(BSP_CAN,&bsp_can_transmit_message_2);//發送一幀數據
printf("\r\n can0 transmit data:%x,%x", bsp_can_transmit_message_2.tx_data[0], bsp_can_transmit_message_2.tx_data[1]);//發送數據打印
delay_ms(1000);
bsp_can_transmit(BSP_CAN,&bsp_can_transmit_message_3);//發送一幀數據
printf("\r\n can0 transmit data:%x,%x", bsp_can_transmit_message_3.tx_data[0], bsp_can_transmit_message_3.tx_data[1]);//發送數據打印
delay_ms(1000);
if(can0_receive_fifo0_flag == SET)
{
printf("\r\n can0_fifo0 receive ID = %x data:%x,%x", can0_receive_message_fifo0.rx_sfid,can0_receive_message_fifo0.rx_data[0], can0_receive_message_fifo0.rx_data[1]);//接收數據打印
can0_receive_fifo0_flag = RESET; //標志位清除
}
if(can0_receive_fifo1_flag == SET)
{
printf("\r\n can0_fifo1 receive ID = %x data:%x,%x", can0_receive_message_fifo1.rx_sfid,can0_receive_message_fifo1.rx_data[0], can0_receive_message_fifo1.rx_data[1]);//接收數據打印
can0_receive_fifo1_flag = RESET;
}
}
}

BSP_CAN實參結構體初始化在bsp_can.c中:

C
typdef_can_general BSP_CAN =
{
.can_port = CAN0,
.rcu_can = RCU_CAN0,
.rcu_IO_port = RCU_GPIOB,
.IO_port = GPIOB,
.pin_tx = GPIO_PIN_9,
.pin_rx = GPIO_PIN_8,
.can_remap = GPIO_CAN_PARTIAL_REMAP,
.gpio_speed = GPIO_OSPEED_50MHZ ,
.can_rx_use_interrupt = SET
};

main函數中實現的功能是每隔1s,分別發送幀ID為0x300,0x500和0x400的文到CAN總線,每幀發送兩個數據,數據結構體初始化在bsp_can.c中:

C
can_trasnmit_message_struct bsp_can_transmit_message_1 = {
.tx_sfid = 0x300,
.tx_efid = 0x00,
.tx_ft = CAN_FT_DATA,
.tx_ff = CAN_FF_STANDARD,
.tx_dlen = 2,
.tx_data[0] = 0x55,
.tx_data[1] = 0xAA,
};

can_trasnmit_message_struct bsp_can_transmit_message_2 = {
.tx_sfid = 0x500,
.tx_efid = 0x00,
.tx_ft = CAN_FT_DATA,
.tx_ff = CAN_FF_STANDARD,
.tx_dlen = 2,
.tx_data[0] = 0x01,
.tx_data[1] = 0x02,
};

can_trasnmit_message_struct bsp_can_transmit_message_3 = {
.tx_sfid = 0x400,
.tx_efid = 0x00,
.tx_ft = CAN_FT_DATA,
.tx_ff = CAN_FF_STANDARD,
.tx_dlen = 2,
.tx_data[0] = 0x02,
.tx_data[1] = 0x01,
};

因為使用了回環模式,故發送的報文同時也會被CAN接收,而由于過濾器的配置,ID為0x300的會被接收到FIFO0中,ID為0x500的會被接收到FIFO1中,而ID為0x400的由于無法通過過濾器,被CAN舍棄。

30.5實驗結果

使用USB-TypeC線,連接電腦和板上USB to UART口后,配置好串口調試助手,即可看到CAN發送和接收數據的情況:

wKgZomaHZKSAV2MXAAAjvK87Umw242.png

教程GD32 MCU方案商聚沃科技原創發布,了解更多GD32 MCU教程,關注聚沃科技官網

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 單片機
    +關注

    關注

    6037

    文章

    44558

    瀏覽量

    635227
  • CAN通信
    +關注

    關注

    5

    文章

    93

    瀏覽量

    17838
  • CAN
    CAN
    +關注

    關注

    57

    文章

    2754

    瀏覽量

    463698
  • 通信
    +關注

    關注

    18

    文章

    6032

    瀏覽量

    135990
  • 開發板
    +關注

    關注

    25

    文章

    5050

    瀏覽量

    97456
  • GD32
    +關注

    關注

    7

    文章

    403

    瀏覽量

    24351
收藏 人收藏

    評論

    相關推薦

    STM32CUBEMX開發GD32F303(8)----USART收發配置

    本章STM32CUBEMX配置STM32F103,并且在GD32F303中進行開發,同時通過GD32303C_START開發板內進行驗證。
    的頭像 發表于 11-29 10:40 ?3183次閱讀
    STM32CUBEMX<b class='flag-5'>開發</b><b class='flag-5'>GD32F303</b>(8)----USART收發配置

    GD32F303】星空介紹

    一、開發板介紹星空GD開發板是由旗點科技推出的一款GD32開發板,板載
    發表于 09-11 17:55

    【星空GD32F303開發板試用體驗】開發記錄匯總

    本帖最后由 申小林一號 于 2021-10-15 14:47 編輯 開貼日期:2021年10月11日該貼主要是用于記錄星空開發板使用記錄以及學習GD32F303芯片的一個過程,將所有的
    發表于 10-11 16:09

    【星空GD32F303開發板試用體驗】開箱+環境搭建

    本帖最后由 lustao 于 2021-10-19 09:29 編輯 感謝 發燒友學院以及廣州旗點智能科技有限公司為我和孩子提供此產品星空GD32F303開發板。收到了星空
    發表于 10-18 14:15

    【星空GD32F303開發板試用體驗】開箱+環境搭建

    https://bbs.elecfans.com/jishu_2179209_1_1.html感謝 發燒友學院以及廣州旗點智能科技有限公司為我和孩子提供此產品星空gd32F303開發板。收到了星空
    發表于 11-02 15:36

    【星空GD32F303開發板試用體驗】+板卡概覽

    本帖最后由 cooldog123pp 于 2021-11-6 21:07 編輯 星空GD開發板是由旗點科技推出的一款GD32開發板
    發表于 11-06 21:05

    星空GD32F303開發板的相關資料下載

    一、開發板介紹星空GD開發板是由旗點科技推出的一款GD32開發板,板載
    發表于 12-10 08:27

    GD32F303開發板介紹

    目錄如下,持續更新~~【1】星空GD32F303開發板介紹 與 文章目錄1. 串口基礎概念USART數據格式一般分為啟動位、數據幀、可能的奇偶校驗位、停止位,如圖4.34所示。啟動位:發送方想要
    發表于 01-17 08:06

    STM32CUBEMX開發GD32F303(14)----IIC之配置OLED

    本章STM32CUBEMX配置STM32F103,并且在GD32F303中進行開發,同時通過開發板內進行驗證。
    的頭像 發表于 07-26 13:52 ?2038次閱讀
    STM32CUBEMX<b class='flag-5'>開發</b><b class='flag-5'>GD32F303</b>(14)----IIC之配置OLED

    GD32F303固件庫開發

    的可以加群申請:615061293 。 GD32F303固件庫開發(1)----前期準備與燒錄 使用GDLINK、jlink、串口下載程序到GD芯片。 [https://blog.csdn.net
    的頭像 發表于 07-27 09:27 ?1177次閱讀
    <b class='flag-5'>GD32F303</b>固件庫<b class='flag-5'>開發</b>

    GD32F303紅楓開發板使用手冊】第二 GPIO-流水燈實驗

    GD32F303系列MCU最多可支持?112?個通用I/O?引腳(GPIO),分別為?PA0 ~ PA15,?PB0 ~ PB15,?PC0 ~ PC15,PD0 ~ PD15,?PE0
    的頭像 發表于 05-29 10:02 ?1661次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第二<b class='flag-5'>講</b> GPIO-流水燈<b class='flag-5'>實驗</b>

    GD32F303紅楓開發板使用手冊第三講 GPIO-按鍵查詢檢測實驗

    GD32F303系列MCU GPIO輸入配置結構如下圖所示,輸入可配置上下拉電阻,通過施密特觸發器后可通過備用功能輸入或者通過輸入狀態寄存器進行讀取。
    的頭像 發表于 05-30 10:02 ?881次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第三講</b> GPIO-按鍵查詢檢測<b class='flag-5'>實驗</b>

    GD32F303紅楓開發板使用手冊】第五 FMC-片內Flash擦寫讀實驗

    MC即Flash控制器,其提供了片上Flash操作所需要的所有功能,在GD32F303系列MCU中,Flash前256K字節空間內,?CPU執行指令零等待,具有相同主頻下最快的代碼執行效率。FMC也
    的頭像 發表于 06-02 10:05 ?786次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第五<b class='flag-5'>講</b> FMC-片內Flash擦寫讀<b class='flag-5'>實驗</b>

    GD32F303紅楓開發板使用手冊】第十六 USART-DMA串口收發實驗

    在前面ADC章節中,我們介紹了DMA的工作原理,這里就不多做介紹。從GD32F303用戶手冊中可以查到,各串口的TX和RX分別對應DMA的不同通道,比如USART0的TX對應DMA0的通道3,而RX對應DMA0的通道4。
    的頭像 發表于 06-15 09:54 ?1086次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第十六<b class='flag-5'>講</b> USART-DMA串口收發<b class='flag-5'>實驗</b>

    GD32F303紅楓開發板使用手冊】第二十 SPI-SPI NAND FLASH讀寫實驗

    通過本實驗主要學習以下內容: ?SPI通信協議,參考19.2.1東方紅開發板使用手冊 ?GD32F303 SPI操作方式,參考19.2.2
    的頭像 發表于 06-20 09:50 ?904次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第二十<b class='flag-5'>講</b> SPI-SPI NAND FLASH讀寫<b class='flag-5'>實驗</b>
    主站蜘蛛池模板: 国产视频三区| 在线国产播放| 天天插天天搞| 亚洲一卡2卡3卡4卡5卡乱码| 午夜肉伦伦影院| 黄 色 免费网 站 成 人| 日本加勒比黑人| 午夜爽视频| 欧美色欧美亚洲高清在线视频| 97人人射| 黑人性xx| 日韩精品视频免费观看| 亚洲天天在线| 中文字字幕码一二区| 日本三级成人中文字幕乱码| 在线三级网址| 久草视频一区| 久操视频在线播放| 亚洲第一成人影院| 国产成人精品亚洲日本在线| 99热99操99射| 四虎永久地址4hu紧急入口| 波多野结衣在线视频观看| 四虎黄色网| 色女人网| 天堂网资源www| 福利视频一区二区三区| 国产在线色视频| www.av天天| 色多多在线观看视频| 天天干网址| 在线观看成人网| 福利天堂| 亚洲码在线| 黄色三级在线看| 人色网| 日本丶国产丶欧美色综合| 全免费一级午夜毛片| 亚洲天堂ww| 亚洲精品午夜久久aaa级久久久| 女主播扒开内衣让粉丝看个够|