【STM32+cubemx】0006 HAL庫開發:uart串口和DMA傳輸


上一節我們使用中斷結合環形fifo,實現了比較方便、高效地串口收發,這個方法在幾乎所有的單片機上都可以使用,就連最基礎的51單片機也能支持。而到了stm32這款強大的單片機,有更多的用法可以實現高效的串口收發,本節我們就介紹使用DMA傳輸串口數據。

先簡單介紹一下DMA,DMA全稱為:Direct Memory Access,即直接存儲器訪問。它可以獨立地將數據從一個地址空間復制到另外一個地址空間,而不占用CPU的資源。

DMA尤其在高速、大容量的數據傳輸時特別有用:如果使用中斷傳輸,CPU會在傳輸數據的一段時間內多次進入中斷處理,也會占用很多CPU的時間;而使用DMA,CPU只用作一些初始化操作,之后DMA會自動將數據從一個地址復制到另一個地址,數據量很大時,能減輕很多CPU的工作。

1)cubemx生成代碼

首先還是在cubemx中生成代碼,選擇器件、設置SYS(調試接口)、設置RCC(外部晶振時鍾源)。

然后設置串口引腳,選擇uart1,異步串口,選完后,已經使用的串口引腳PA9和PA10會變成綠色;然后選擇開啟串口全局中斷(使用DMA時中斷一定要打開):

然后,設置DMA,在DMA選項卡下面,添加RX和TX,然后將RX的mode改成Circular,

即設置為循環接收:(其他參數,可以選擇地址自增、數據寬度等等,這里都默認)

之后,在時鍾選項卡設置主時鍾為72M;在project Manager選項卡設置工程名和路徑,生成工程代碼。

2)HAL庫函數的使用

生成的工程中,已經有比較完善的初始化代碼。

發送時,可以直接調用HAL_UART_Transmit_DMA函數實現,如下圖:

直接使用DMA發送了16個字節的數據,這里我們看一下效果,在發送之后直接設置斷點。我們前面講的中斷發送,如果在發送函數之后直接斷點停止的話,一般只能發出兩個字節的數出來,后面的要等程序跑起來,進中斷處理后才能發出來。而DMA發送,可以看到,它是不受斷點影響的,即使CPU被斷點中斷,數據仍然可以都發出來,圖中看以看到16個數據都發送完了。

接收時,可以調用HAL_UART_Receive_DMA函數,如下圖:

這里我們可以在斷點停止時,用串口調試助手發送20個字節數據,當再次運行時,可以看到rx_data里的數據發生了變化,說明DMA在CPU未運行時也在收數據。

另外,還可以看到,因為設置了循環收16個字節,但是發送了20個字節,所以16個字節之后的4個字節又覆蓋了頭4個字節:

3)接收程序改寫

HAL庫生成的DMA的接收/發送函數,與中斷的函數一樣,有以下特點:發送時如果上一次的數據還未發完,則本次數據不會發送,仍然繼續發送上一次未發完的數據。接收數據要提前設定長度,不方便使用。

好在發送的時間點是可以由軟件控制的,所以發送時的矛盾並不特別突出。而接收不行,接收時程序並不知道外界什么時候會發數過來,也不知道每次發多少個,所以一般會改寫接收的函數,使用空閑中斷結合DMA來接收數據,具體做法是:

打開串口的空閑中斷;打開DMA接收,接收長度設為一個較大的值,保證不會被填滿;當空閑中斷產生時,說明一段數據已收完,此時把數據拷貝走,並再次開啟DMA接收。

由於每收完一段數據都會產生空閑,在空閑時能產生中斷進行處理,所以可以實現不定長度的數據接收。

代碼實現如下:

首先添加初始化函數,開啟接收中斷、空閑中斷,打開DMA接收(這里接收數組設置為32字節,一般建議設置大一點,確保不會溢出):

在中斷服務函數中添加如下:

這部分代碼的作用是:檢查是否是空閑中斷,如果是,則獲取已經接收的字節數,並置標志位;然后再次打開接收中斷、開啟DMA接收。

這里注意一下長度的獲取,是用設置的最大長度減去未填充的空間得到的。

主循環中,只要檢測標志位,然后將已收到的數據處理完即可(這里是將數據發回)。

運行后用串口調試助手發數和接收,可以看到與預期一致:

好了,這一節的內容基本講完了。

歡迎關注我的公眾號,可留言“資料”獲取相關資料和軟件:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM