UART傳輸
前言
因這邊需要寫一個UI介面去操控STM32 進而控制sensor,因此這邊開始去了解STM32UART傳輸
但本身也不是很喜歡使用UART去控制元件,原因在於傳輸不好寫,寫不好容易有data last或造成MCU流程卡死問題
因此這邊傳輸長度是已知,接收長度也是已知的狀態下去Coding UART傳輸,針對不定長度接收會放下最底下欄位供參考
環境
- STM32CubeIDE
- Nucleo F401RE Board
- STM32CubeMX
設定步驟
- STM32CUBEMX設定UART,關鍵是要打開UART中斷,以及打開TX/RX的DMA
Enable UART IRQ
Enable UART DMA channels
PS:這邊會選擇DMA開啟的原因為避免Data lost與程式因為中斷而卡死,因如果單用IT中斷來說在中段接收時候如果程式運行太快
會導致資料lost,但DMA的缺點為你必須知道資料長度不然會無法順利執行下一步(因這邊UI與MCU撰寫都是由我編輯因此長度都是已知不會有例外)
涵式庫差異
傳輸
使用輪詢-> HAL_UART_Transmit
使用中斷—> HAL_UART_Transmit_IT
使用DMA-> HAL_UART_Transmit_DMA
接收
使用輪詢-> HAL_UART_Receive
使用中斷—> HAL_UART_Receive_IT
使用DMA-> HAL_UART_Receive_DMA
- 輪詢(Polling):就是阻塞式詢問,CPU都不幹別的事了,就整天在那邊問你說:「現在有沒有要傳資料啊?」沒有要傳我就繼續等,總是在那邊詢問、等待。這種方最土法煉鋼、這就是輪詢的缺點,效率太低,占用cpu時間。
- 中斷(Interrupt):沒有收到數據時,執行其他的程序,收到數據後,進入中斷處理通訊。與輪詢相對來說,不用循環查詢狀態暫存器,可以有更多的時間運行其他程序。
- DMA(Direct Memory Access):直接記憶體存取。串列數據的接收與發送由DMA處理,DMA說:「我把接收、傳送的資料放在記憶體的某個位置,你如果需要就自己去那個位置提取」。DMA也可以分為輪詢與中斷方式。資料的發送與接收都不用CPU干預,通過DMA進行。 CPU有更多的時間運行其他程序。
Coding sample
這邊照上面步驟CubeMX在宣告部分會多這3個
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;
初始化
static void MX_DMA_Init(void);
static void MX_USART2_UART_Init(void);
這邊選用的接收為HAL_UARTEx_ReceiveToIdle_DMA(&huart2, &uRx_Data1,14),主要原因為HAL_UARTEx_ReceiveToIdle_DMA,算是裡面比較進階的函數。他會在收滿資料,或是UART IDLE一個字元以後呼叫callback
if( HAL_UARTEx_ReceiveToIdle_DMA(&huart2, &uRx_Data1,14) == HAL_OK)
{
if( uRx_Data1[0]=='a')
{flagstat=1;
i=0;}
else if(uRx_Data1[0]=='b')
{flagstat=2;
i=0;}
else if(uRx_Data1[0]=='c')
{flagstat=3;
i=0;}
else if(uRx_Data1[0]=='d')
{flagstat=4;
i=0;}
else if(uRx_Data1[0] >= '0' && uRx_Data1[0] <= '9')
flagstat=5;
else if(uRx_Data1[0]=='e')
flagstat=0;
printf("\n\r");
}
這邊&uRx_Data1是宣告unsigned char uRx_Data1[14];去接收資料,因這邊傳輸近來資料為ASCII 非int 宣告成int接收部分需要在自己轉換
PS:轉換再UI端實現轉換或在STM32 MCU內都可以
這邊因為已知傳輸data格式為:x,x,xx……中間以逗號做為區隔分號為最後一碼確認結束且第一碼是分辨哪種模式
因此這邊接收到資料會先做第一碼判別,確認模式
字串連結
這邊因為使用”,”做為每個數字分隔”;”作為最後字元接收,過程中都是數字。這邊要注意因為進來的DATA為ASCII所以一定要扣除 ‘0’
去使其轉變成INT格式
這邊輸出部分因為寫入下列範例printf資料UI部分就可以接收到了因此這邊沒再額外撰寫
int _write(int file, char *ptr,int len)
{
HAL_UART_Transmit(&huart2,(uint8_t *)ptr,len,1000);
return len;
}
Pingback: LDM_Module_RPS800(TOF Measuring) - AMS and STM32