日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32的can现场总线实验心得

發布時間:2025/4/16 编程问答 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32的can现场总线实验心得 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近在搞stm32實驗板的can現場總線實驗,之前只是搞過STC51的串口通信,相比之下,發覺can總線都挺復雜的。開始時,知道自己是新手,只知道can總線跟串行通信,485通信,I2C通信一樣都是用來傳輸數據通信的,對其工作原理一竅不通,還是從基礎開始看書看資料,先了解它的基本原理吧。

?

原來can總線有以下特點

主要特點

支持CAN協議2.0A2.0B主動模式

波特率最高可達1兆位/

支持時間觸發通信功能

發送

3個發送郵箱

發送報文的優先級特性可軟件配置

記錄發送SOF時刻的時間戳

接收

?3級深度的2個接收FIFO

14個位寬可變的過濾器組-由整個CAN共享

?標識符列表

FIFO溢出處理方式可配置

記錄接收SOF時刻的時間戳

可支持時間觸發通信模式

禁止自動重傳模式

16位自由運行定時器

定時器分辨率可配置

可在最后2個數據字節發送時間戳

管理

中斷可屏蔽

?郵箱占用單獨1塊地址空間,便于提高軟件效率

?

?

看完這些特點后,疑問一個一個地出現,

1.?什么是時間觸發功能?

2.?發送郵箱是什么來的?

3.?報文是什么來的?

4.?什么叫時間戳?

5.?什么叫接收FIFO?

6.?什么叫過濾器?

好了,帶著疑問往下看,看完一遍后,

報文:

報文包含了將要發送的完整的數據信息

發送郵箱:

共有3個發送郵箱供軟件來發送報文。發送調度器根據優先級決定哪個郵箱的報文先被發送。

接收過濾器:

共有14個位寬可變/可配置的標識符過濾器組,軟件通過對它們編程,從而在引腳收到的報文中選擇它需要的報文,而把其它報文丟棄掉。

?

接收FIFO

共有2個接收FIFO,每個FIFO都可以存放3個完整的報文。它們完全由硬件來管理

?

工作模式

bxCAN3個主要的工作模式:初始化、正常和睡眠模式。

?

初始化模式

*軟件通過對CAN_MCR寄存器的INRQ位置1,來請求bxCAN進入初始化模式,然后等待硬件對CAN_MSR寄存器的INAK位置1來進行確認

*軟件通過對CAN_MCR寄存器的INRQ位清0,來請求bxCAN退出初始化模式,當硬件對

CAN_MSR寄存器的INAK位清0就確認了初始化模式的退出。

*當bxCAN處于初始化模式時,報文的接收和發送都被禁止,并且CANTX引腳輸出隱性位(高電平)

正常模式

在初始化完成后,軟件應該讓硬件進入正常模式,以便正常接收和發送報文。軟件可以通過

CAN_MCR寄存器的INRQ位清0,來請求從初始化模式進入正常模式,然后要等待硬件對

CAN_MSR寄存器的INAK位置1的確認。在跟CAN總線取得同步,即在CANRX引腳上監測到11個連續的隱性位(等效于總線空閑)后,bxCAN才能正常接收和發送報文。

過濾器初值的設置不需要在初始化模式下進行,但必須在它處在非激活狀態下完成(相應的FACT位為0)。而過濾器的位寬和模式的設置,則必須在初始化模式下,進入正常模式前完成。

睡眠模式(低功耗)

*軟件通過對CAN_MCR寄存器的SLEEP位置1,來請求進入這一模式。在該模式下,bxCAN的時鐘停止了,但軟件仍然可以訪問郵箱寄存器。

*當bxCAN處于睡眠模式,軟件想通過對CAN_MCR寄存器的INRQ位置1,來進入初始化式,

那么軟件必須同時對SLEEP位清0才行

*有2種方式可以喚醒(退出睡眠模式)bxCAN:通過軟件對SLEEP位清0,或硬件檢測CAN

總線的活動。

?

工作流程

那么究竟can是怎樣發送報文的呢?

發送報文的流程為:

應用程序選擇1個空發送郵箱;設置標識符,數據長度和待發送數據;

然后對CAN_TIxR寄存器的TXRQ位置1,來請求發送。TXRQ位置1后,郵箱就不再是空郵箱;而一旦郵箱不再為空,軟件對郵箱寄存器就不再有寫的權限。TXRQ位置1后,郵箱馬上進入掛號狀態,并等待成為最高優先級的郵箱,參見發送優先級。一旦郵箱成為最高優先級的郵箱,其狀態就變為預定發送狀態。一旦CAN總線進入空閑狀態,預定發送郵箱中的報文就馬上被發送(進入發送狀態)。一旦郵箱中的報文被成功發送后,它馬上變為空郵箱;硬件相應地對CAN_TSR寄存器的RQCPTXOK位置1,來表明一次成功發送。

?

如果發送失敗,由于仲裁引起的就對CAN_TSR寄存器的ALST位置1,由于發送錯誤引起的

就對TERR位置1

?

原來發送的優先級可以由標識符和發送請求次序決定:

由標識符決定

當有超過1個發送郵箱在掛號時,發送順序由郵箱中報文的標識符決定。根據CAN協議,標

識符數值最低的報文具有最高的優先級。如果標識符的值相等,那么郵箱號小的報文先被發

送。

由發送請求次序決定

通過對CAN_MCR寄存器的TXFP位置1,可以把發送郵箱配置為發送FIFO。在該模式下,發送的優先級由發送請求次序決定。

該模式對分段發送很有用。

?

時間觸發通信模式

在該模式下,CAN硬件的內部定時器被激活,并且被用于產生時間戳,分別存儲在

CAN_RDTxR/CAN_TDTxR寄存器中。內部定時器在接收和發送的幀起始位的采樣點位置被采樣,并生成時間戳(標有時間的數據)。

?

?

接著又是怎樣接收報文的呢?

接收管理

接收到的報文,被存儲在3級郵箱深度的FIFO中。FIFO完全由硬件來管理,從而節省了CPU

的處理負荷,簡化了軟件并保證了數據的一致性。應用程序只能通過讀取FIFO輸出郵箱,來讀取FIFO最先收到的報文。

?

有效報文

根據CAN協議,當報文被正確接收(直到EOF域的最后1位都沒有錯誤),且通過了標識符

過濾,那么該報文被認為是有效報文。

?

接收相關的中斷條件

*?一旦往FIFO存入1個報文,硬件就會更新FMP[1:0]位,并且如果CAN_IER寄存器的FMPIE位為1,那么就會產生一個中斷請求。

*?當FIFO變滿時(即第3個報文被存入),CAN_RFxR寄存器的FULL位就被置1,并且如果CAN_IER寄存器的FFIE位為1,那么就會產生一個滿中斷請求。

*?在溢出的情況下,FOVR位被置1,并且如果CAN_IER寄存器的FOVIE位為1,那么就會產生一個溢出中斷請求

?

?

標識符過濾

CAN協議里,報文的標識符不代表節點的地址,而是跟報文的內容相關的。因此,發送者以廣播的形式把報文發送給所有的接收者。(注:不是一對一通信,而是多機通信)節點在接收報文時-根據標識符的值-決定軟件是否需要該報文;如果需要,就拷貝到SRAM里;如果不需要,報文就被丟棄且無需軟件的干預。

為滿足這一需求,bxCAN為應用程序提供了14個位寬可變的、可配置的過濾器組(13~0),

以便只接收那些軟件需要的報文。硬件過濾的做法節省了CPU開銷,否則就必須由軟件過濾從而占用一定的CPU開銷。每個過濾器組x232位寄存器,CAN_FxR0CAN_FxR1組成。

?

?

過濾器的模式的設置

通過設置CAN_FM0RFBMx位,可以配置過濾器組為標識符列表模式或屏蔽位模式。

為了過濾出一組標識符,應該設置過濾器組工作在屏蔽位模式。

為了過濾出一個標識符,應該設置過濾器組工作在標識符列表模式。

應用程序不用的過濾器組,應該保持在禁用狀態。

?

過濾器優先級規則

位寬為32位的過濾器,優先級高于位寬為16位的過濾器

對于位寬相同的過濾器,標識符列表模式的優先級高于屏蔽位模式

位寬和模式都相同的過濾器,優先級由過濾器號決定,過濾器號小的優先級高

?

128?過濾器機制的例子

?

上面的例子說明了bxCAN的過濾器規則:在接收一個報文時,其標識符首先與配置在標識符

列表模式下的過濾器相比較;如果匹配上,報文就被存放到相關聯的FIFO中,并且所匹配的

過濾器的序號被存入過濾器匹配序號中。如同例子中所顯示,報文標識符跟#4標識符匹配,

因此報文內容和FMI4被存入FIFO

如果沒有匹配,報文標識符接著與配置在屏蔽位模式下的過濾器進行比較。

如果報文標識符沒有跟過濾器中的任何標識符相匹配,那么硬件就丟棄該報文,且不會對軟

件有任何打擾。

?

接收郵箱FIFO

在接收到一個報文后,軟件就可以訪問接收FIFO的輸出郵箱來讀取它。一旦軟件處理了報文(如把它讀出來),軟件就應該對CAN_RFxR寄存器的RFOM位進行置1,來釋放該報文,

以便為后面收到的報文留出存儲空間。

?

?

中斷

bxCAN占用4個專用的中斷向量。通過設置CAN中斷允許寄存器(CAN_IER),每個中斷源都

可以單獨允許和禁用。

?

?發送中斷可由下列事件產生:

?發送郵箱0變為空,CAN_TSR寄存器的RQCP0位被置1

?發送郵箱1變為空,CAN_TSR寄存器的RQCP1位被置1

?發送郵箱2變為空,CAN_TSR寄存器的RQCP2位被置1

FIFO0中斷可由下列事件產生:

?FIFO0接收到一個新報文,CAN_RF0R寄存器的FMP0位不再是‘00’。

?FIFO0變為滿的情況,CAN_RF0R寄存器的FULL0位被置1

?FIFO0發生溢出的情況,CAN_RF0R寄存器的FOVR0位被置1

FIFO1中斷可由下列事件產生:

?FIFO1接收到一個新報文,CAN_RF1R寄存器的FMP1位不再是‘00’。

?FIFO1變為滿的情況,CAN_RF1R寄存器的FULL1位被置1

?FIFO1發生溢出的情況,CAN_RF1R寄存器的FOVR1位被置1

���?錯誤和狀態變化中斷可由下列事件產生:

?出錯情況,關于出錯情況的詳細信息請參考CAN錯誤狀態寄存器(CAN_ESR)

?喚醒情況,在CAN接收引腳上監視到幀起始位(SOF)

?CAN進入睡眠模式。

?

工作流程大概就是這個樣子,接著就是一大堆煩人的can寄存器,看了一遍總算有了大概的了解,況且這么多的寄存器要一下子把他們都記住是不可能的。根據以往的經驗,只要用多幾次,對寄存器的功能就能記住。

?

好了,到讀具體實驗程序的時候了,這時候就要打開“STM32庫函數”的資料

因為它里面有STM32打包好的庫函數的解釋,對讀程序很有幫助。

?

下面是主程序:

int?main(void)

{

//??int?press_count?=?0;

char?data?=?'0';

int?sent?=?FALSE;

?

#ifdef?DEBUG

??debug();

#endif

?

??/*?System?Clocks?Configuration?*/

??RCC_Configuration();

?

??/*?NVIC?Configuration?*/

??NVIC_Configuration();

??

??/*?GPIO?ports?pins?Configuration?*/

??GPIO_Configuration();

?

??USART_Configuration();

?

??CAN_Configuration();

?

??Serial_PutString("\r\n偉研科技?http://www.gzweiyan.com\r\n");

??Serial_PutString("CAN?test\r\n");?

?

??while(1){

????if(GPIO_Keypress(GPIO_KEY,?BUT_RIGHT)){

??????GPIO_SetBits(GPIO_LED,?GPIO_LD1);//檢測到按鍵按下

?

??????if(sent?==?TRUE)

????????continue;

??????sent?=?TRUE;

??????data++;

??????if(data?>?'z')

????????data?=?'0';

??????CAN_TxData(data);

????}

????else{//按鍵放開

??????GPIO_ResetBits(GPIO_LED,?GPIO_LD1);??

??????sent?=?FALSE;

????}

??}

}

?

前面的RCC、NVIC、GPIO、USART配置和之前的實驗大同小異,關鍵是分析CAN

_Configuration()

函數如下:

void?CAN_Configuration(void)//CAN配置函數

{

??CAN_InitTypeDef????????CAN_InitStructure;

??CAN_FilterInitTypeDef??CAN_FilterInitStructure;

?

??/*?CAN?register?init?*/

??CAN_DeInit();

//??CAN_StructInit(&CAN_InitStructure);

?

??/*?CAN?cell?init?*/

??CAN_InitStructure.CAN_TTCM=DISABLE;//禁止時間觸發通信模式

??CAN_InitStructure.CAN_ABOM=DISABLE;//,軟件對CAN_MCR寄存器的INRQ位進行置1隨后清0后,一旦硬件檢測

?????????????????????????????????????//到128次11位連續的隱性位,就退出離線狀態。

?

??CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通過清除CAN_MCR寄存器的SLEEP位,由軟件喚醒

?

??CAN_InitStructure.CAN_NART=ENABLE;//DISABLE;CAN報文只被發送1次,不管發送的結果如何(成功、出錯或仲裁丟失)

?

??CAN_InitStructure.CAN_RFLM=DISABLE;//在接收溢出時FIFO未被鎖定,當接收FIFO的報文未被讀出,下一個收到的報文會覆蓋原有

????????????????????????????????????????????????????????????//的報文

?

??CAN_InitStructure.CAN_TXFP=DISABLE;//發送FIFO優先級由報文的標識符來決定

//??CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack;

??CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;?//CAN硬件工作在正常模式?

??CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;//重新同步跳躍寬度1個時間單位

??CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;//時間段1為8個時間單位

??CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;//時間段2為7個時間單位

??CAN_InitStructure.CAN_Prescaler?=?9;?//(pclk1/((1+8+7)*9))?=?36Mhz/16/9?=?250Kbits設定了一個時間單位的長度9

??CAN_Init(&CAN_InitStructure);

?

??/*?CAN?filter?init?過濾器初始化*/

??CAN_FilterInitStructure.CAN_FilterNumber=0;//指定了待初始化的過濾器0

??CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定了過濾器將被初始化到的模式為標識符屏蔽位模式

??CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//給出了過濾器位寬1個32位過濾器

?

??CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;//用來設定過濾器標識符(32位位寬時為其高段位,16位位寬時為第一個)

?

??CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;//用來設定過濾器標識符(32位位寬時為其低段位,16位位寬時為第二個

?

??CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//用來設定過濾器屏蔽標識符或者過濾器標識符(32位位寬時為其高段位,16位位寬時為第一個

?

??CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;//用來設定過濾器屏蔽標識符或者過濾器標識符(32位位寬時為其低段位,16位位寬時為第二個

?

??CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;//設定了指向過濾器的FIFO0

?

??CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//使能過濾器

??CAN_FilterInit(&CAN_FilterInitStructure);

?

??/*?CAN?FIFO0?message?pending?interrupt?enable?*/?

??CAN_ITConfig(CAN_IT_FMP0,?ENABLE);//使能指定的CAN中斷

}

?

?

?

?

?

?

再看看發送程序:

TestStatus?CAN_TxData(char?data)

{

??CanTxMsg?TxMessage;

?

??u32?i?=?0;

??u8?TransmitMailbox?=?0;

/*

??u32?dataLen;

??dataLen?=?strlen(data);

??if(dataLen?>?8)

??dataLen?=?8;

??*/

??/*?transmit?1?message生成一個信息?*/

??TxMessage.StdId=0x00;//?設定標準標識符

??TxMessage.ExtId=0x1234;//?設定擴展標識符

??TxMessage.IDE=CAN_ID_EXT;//?設定消息標識符的類型

??TxMessage.RTR=CAN_RTR_DATA;//?設定待傳輸消息的幀類型

/*??TxMessage.DLC=?dataLen;

for(i=0;i<dataLen;i++)

TxMessage.Data[i]?=?data[i];?

*/

??TxMessage.DLC=?1;?//設定待傳輸消息的幀長度

??TxMessage.Data[0]?=?data;//?包含了待傳輸數據

?

?

??TransmitMailbox?=?CAN_Transmit(&TxMessage);//開始一個消息的傳輸

?

??i?=?0;

??while((CAN_TransmitStatus(TransmitMailbox)?!=?CANTXOK)?&&?(i?!=?0xFF))//通過檢查CANTXOK位來確認發送是否成功

??{

????i++;

??}

??

?

?

??return?(TestStatus)ret;

}

?

?

CAN_Transmit()函數的操作包括:

1.?[選擇一個空的發送郵箱]

2.?[設置Id]*

3.?[設置DLC待傳輸消息的幀長度]

4.?[請求發送]

請求發送語句:

CAN->sTxMailBox[TransmitMailbox].TIR?|=?TMIDxR_TXRQ;//對CAN_TIxR寄存器的TXRQ位置1,來請求發送

?

?

?

發送方面搞定了,但接收方面呢?好像在主程序里看不到有接收的語句。立刻向師兄求救。

原來是用來中斷方式來接收數據,原來它和串口一樣可以有兩種方式接收數據,一種是中斷方式一種是輪詢方式,若采用輪詢方式則要調用主函數的CAN_Polling(void)函數。

?

接著又遇到一個問題,為什么中斷函數CAN_Interrupt(void)的最后要關中斷呢?

因為一旦往FIFO存入1個報文,硬件就會更新FMP[1:0]位,并且如果CAN_IER寄存器的FMPIE位為1,那么就會產生一個中斷請求。所以中斷函數執行完后就要清除FMPIE標志位。這時我才回想起來,原來我對CAN的理解還不夠,對程序設計的初衷不夠明確,于是我重新看了一遍CAN的工作原理,這時后我發現比以前容易理解了,可能是因為看了程序以后知道了大概的流程,然后看資料就有了針對性。

?

發送者以廣播的形式把報文發送給所有的接收者(注:不是一對一通信,而是多機通信)節點在接收報文時-根據標識符的值-決定軟件是否需要該報文;如果需要,就拷貝到SRAM里;如果不需要,報文就被丟棄且無需軟件的干預。一旦往FIFO存入1個報文,硬件就會更新FMP[1:0]位,并且如果CAN_IER寄存器的FMPIE位為1,那么就會產生一個中斷請求。所以中斷函數執行完后就要清除FMPIE標志位。

??????????????????????????????????????????????????????????????

??????????????????????????????????????????????????????????By:becarson

???????????????????????????????????????????????http://becarsonfeng.blog.163.com

???????????????????????????????????????????????????????????

轉載于:https://www.cnblogs.com/skl374199080/p/3274089.html

總結

以上是生活随笔為你收集整理的STM32的can现场总线实验心得的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。