最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

CH32串口接收方案(IDLE+DMA+FreeRTOS+NOTIFY)

2023-04-09 21:35 作者:老閑漁  | 我要投稿

????????為大家分享一種串口不定長數(shù)據(jù)接收方案,CPU占用極低,響應(yīng)速度極快,避免了各種無意義的消耗,可以應(yīng)用在任何其他的單片機中,這是我在實際項目當(dāng)中琢磨出來的,目前網(wǎng)上好像沒怎么看到這種做法

首先介紹一下該方案所需的基礎(chǔ)知識:

1. IDLE中斷

????????單片機的串口Idle中斷是一種特殊的中斷,它會在串口接收完數(shù)據(jù)并進(jìn)入空閑狀態(tài)時觸發(fā),單片機就可以及時處理接收到的數(shù)據(jù)。這個中斷可以在串口通信中避免單片機一直等待數(shù)據(jù)接收而導(dǎo)致系統(tǒng)停止響應(yīng)的情況。原理是單片機在接收串口數(shù)據(jù)時,設(shè)置一個計時器,當(dāng)串口接收完數(shù)據(jù)后,會觸發(fā)計時器,計時器計時結(jié)束后就會觸發(fā)Idle中斷,單片機就可以立即停止接收數(shù)據(jù),并執(zhí)行相應(yīng)的中斷服務(wù)程序,從而實現(xiàn)對接收數(shù)據(jù)的及時處理

2. DMA

????????DMA(Direct Memory Access,直接內(nèi)存訪問)是一種通過硬件控制數(shù)據(jù)傳輸?shù)募夹g(shù)。使用DMA可以使單片機在數(shù)據(jù)傳輸過程中騰出CPU的時間和資源,提高系統(tǒng)的效率和性能。在傳統(tǒng)的單片機系統(tǒng)中,數(shù)據(jù)傳輸通常是通過CPU來實現(xiàn)的,CPU需要不停地從外設(shè)中讀取數(shù)據(jù),然后再將數(shù)據(jù)寫入內(nèi)存或者反過來,這樣會消耗大量的CPU時間和資源。而使用DMA技術(shù)可以避免這種情況,因為DMA可以通過硬件控制數(shù)據(jù)傳輸,而不需要CPU的干預(yù)。當(dāng)數(shù)據(jù)傳輸完成后,DMA會向CPU發(fā)送一個中斷請求,通知CPU數(shù)據(jù)已經(jīng)傳輸完成,CPU可以繼續(xù)執(zhí)行其他的任務(wù),從而提高了系統(tǒng)的效率和性能。

3. RTOS

????????RTOS(Real-Time Operating System,實時操作系統(tǒng))是一種專門用于實時應(yīng)用的操作系統(tǒng)。它提供了一些重要的功能,例如任務(wù)調(diào)度、中斷處理、內(nèi)存管理、進(jìn)程間通信等,我使用的是FreeRTOS實時操作系統(tǒng),其他的操作系統(tǒng)例如RTT,UCOS都是一樣的

4. Notify

????????FreeRTOS中的任務(wù)通知是一種輕量級的進(jìn)程間通信機制,它可以用于不同任務(wù)之間的通信和同步。任務(wù)通知可以讓任務(wù)之間更加靈活地進(jìn)行信息傳遞,從而實現(xiàn)更加復(fù)雜的系統(tǒng)行為。任務(wù)通知是由發(fā)送者向接收者發(fā)送信號的一種機制。當(dāng)發(fā)送者需要向接收者發(fā)送一個信號時,它可以使用任務(wù)通知API將一個通知值發(fā)送給接收者。接收者可以在任何時候等待通知值,當(dāng)通知值到達(dá)時,接收者就會被喚醒,并且可以根據(jù)通知值來執(zhí)行相應(yīng)的操作。任務(wù)通知可以在一定程度上代替二值信號量或者計數(shù)信號量,并且任務(wù)通知更加快速輕便,官方稱任務(wù)通知比二值信號量快了至少45%(不清楚其他的操作系統(tǒng)有沒有任務(wù)通知,但是原理都是類似的,本質(zhì)就是實現(xiàn)一個二值信號量的效果)



下面是整個方案運行的思路:

????????首先配置好串口的收發(fā),完成串口的初始化,并且啟用idle空閑中斷,然后配置dma,為串口外設(shè)指定dma通道(注意不要使能dma的中斷),創(chuàng)建一個串口數(shù)據(jù)處理任務(wù),在任務(wù)的死循環(huán)中等待通知,當(dāng)串口接收到一幀數(shù)據(jù)后觸發(fā)中斷,在中斷處理函數(shù)中需要做幾件事情:停止dma通道、復(fù)位中斷標(biāo)志位、計算數(shù)據(jù)的大小、發(fā)送任務(wù)通知、復(fù)位dma計數(shù)、重新使能dma通道,做完這些事之后中斷結(jié)束,串口數(shù)據(jù)處理任務(wù)接到通知,開始直接處理數(shù)據(jù)

(由于發(fā)送任務(wù)通知的時候,從dma中得到了數(shù)據(jù)長度傳遞給了任務(wù),這帶來了超多好處

????????1.只有觸發(fā)中斷的時候計算一次,運算次數(shù)少,常規(guī)做法需要在中斷中不斷累加計數(shù)

????????2.數(shù)據(jù)處理任務(wù)可以直接根據(jù)數(shù)據(jù)長度進(jìn)行數(shù)據(jù)處理,無需其他額外的計算步驟

????????3. 接收數(shù)據(jù)的緩沖數(shù)組不需要每次用完都memset清空,因為得到了準(zhǔn)確的數(shù)據(jù)大小,不存在操作越界的問題

對于CPU來說,就像做夢一樣,突然有人叫了你一下,醒來發(fā)現(xiàn)數(shù)據(jù)都喂到嘴巴里了)

代碼實現(xiàn):

1.操作系統(tǒng)的移植

????????STM32可以使用CUBE直接生成(真好),CH32部分系列可以使用官方移植好的完整工程(真好),GD32可以參考網(wǎng)上教程自行移植 (笑)

2. 串口配置

????????這段代碼是用來初始化USART1串口模塊,主要包含以下幾個部分:

  1. 定義并初始化用于GPIO、USART和NVIC初始化的結(jié)構(gòu)體變量 GPIO_InitStructure、USART_InitStructureNVIC_InitStructure。

  2. 使能 GPIOA 和 USART1 的時鐘。

  3. 配置 GPIOA 的第 9 個引腳為 USART1 的發(fā)送引腳,配置 GPIOA 的第 10 個引腳為 USART1 的接收引腳。

  4. 配置 USART1 的波特率、數(shù)據(jù)位長度、停止位、校驗位、硬件流控制以及發(fā)送和接收模式。

  5. 使能 USART1 的空閑中斷。

  6. 配置 USART1 的中斷優(yōu)先級和使能中斷。

  7. 使能 DMA1 的通道 5 和通道 4,用于 USART1 的接收和發(fā)送。(但是實際上沒用到通道4)

  8. 使能 USART1 模塊。

3.DMA通道配置

????????這段代碼是用來初始化DMA1通道5,定義并初始化用于DMA初始化的結(jié)構(gòu)體變量 DMA_InitStructure,最后初始化 DMA1 的通道5。

4.中斷處理函數(shù)

????????首先在文件頂部申明中斷處理函數(shù),這是申明格式,后面的__attribute__申明一定要加,不然GCC編譯器不知道這是個中斷函數(shù),其他單片機的申明方法不一樣,需要自行查明

????????函數(shù)實現(xiàn),首先失能了dma通道,然后讀取串口的發(fā)送和接收寄存器,這一步是為了復(fù)位中斷標(biāo)志位,如果不這么做中斷標(biāo)志位就無法被復(fù)位,會無限進(jìn)中斷,下一步發(fā)送任務(wù)通知,

????????使用xTaskNotifyFromISR函數(shù)

????????參數(shù)分別為(目標(biāo)任務(wù)句柄,通知值(這里發(fā)送數(shù)據(jù)大小),指定通知如何更新任務(wù)的通知,NULL)

????????????不過即使發(fā)送了通知任務(wù)也沒法執(zhí)行,因為現(xiàn)在還卡在中斷里(笑)

????????然后重新設(shè)置dma計數(shù)(比如一開始設(shè)定dma傳輸數(shù)據(jù)大小為20個,接收到3個數(shù)據(jù)后觸發(fā)中斷,此時計數(shù)值為17,所以每次需要將計數(shù)值恢復(fù)到原始大小,不然會導(dǎo)致下次計算出錯)

????????最后重新打開dma通道(這一步是為了復(fù)位內(nèi)存地址,否則數(shù)據(jù)無法放在正確的內(nèi)存里,會導(dǎo)致嚴(yán)重的內(nèi)存越界問題)

5. 數(shù)據(jù)處理任務(wù)

????????首先定義一個變量用于存放任務(wù)通知值(串口數(shù)據(jù)大?。?,然后使能串口dma接口,隨后在死循環(huán)中用xTaskNotifyWait函數(shù)做任務(wù)阻塞,這個任務(wù)會一直卡在這里不執(zhí)行

????????參數(shù)為(進(jìn)入通知時對通知值的操作(這里給0,不操作),退出通知時通知值的操作(給0,不操作),接收通知值的變量地址,超時時間(最大超時))

????????當(dāng)接收到數(shù)據(jù)后,由中斷發(fā)送通知,這里會被解除阻塞狀態(tài),后面的代碼得以執(zhí)行,這里就直接放自己需要的數(shù)據(jù)出來代碼就可以了,我這里只是簡單的把接收到的數(shù)據(jù)原樣打印出來


后記:

????????這個方法雖好,但是其實稍微有點復(fù)雜,首先是基于操作系統(tǒng)的,如果是裸機程序則無法使用,其次大部分單片機并沒有st那樣的代碼生成工具(CUBE),各種配置過程繁瑣復(fù)雜,很容易出錯,如果用stm32過程會輕松很多

????????操作系統(tǒng)提供了多線程的方便,但也會帶來操作系統(tǒng)的問題,在中斷里面使用操作系統(tǒng)的API一定要使用帶FromISR結(jié)尾的,否則會造成各種死機問題,同時還需要保證該中斷的優(yōu)先級低于操作系統(tǒng)的可屏蔽中斷的優(yōu)先級,否則會出現(xiàn)錯誤的中嵌套,導(dǎo)致死機

????????下面給出完整的代碼,僅供參考:

????????????????????感謝閱讀(≧?≦)?


CH32串口接收方案(IDLE+DMA+FreeRTOS+NOTIFY)的評論 (共 條)

分享到微博請遵守國家法律
凤阳县| 盖州市| 昌邑市| 牡丹江市| 固镇县| 井研县| 阿尔山市| 麻阳| 郑州市| 淮滨县| 邛崃市| 泽州县| 阜宁县| 贵溪市| 黔江区| 堆龙德庆县| 木里| 元江| 白沙| 武安市| 宝山区| 诸暨市| 湖北省| 沙洋县| 新乡市| 绵阳市| 扶沟县| 宁化县| 淮安市| 南丹县| 中牟县| 方正县| 赞皇县| 舟曲县| 永德县| 怀化市| 潜山县| 故城县| 永胜县| 钟山县| 双辽市|