一 串口發送方式:
①輪訓方式發送,也就是主動發送,這個容易理解,使用如下函數:
HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
②中斷方式發送,使用如下函數
HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
過程如下:
首先使能發送中斷__HAL_UART_ENABLE_IT(huart, UART_IT_TXE); 如果發送數據寄存器為空(第一次發送前為空),則進入USARTx_IRQHandler()中斷向量入口,這個中斷向量里面會調用總的串口中斷處理函數HAL_UART_IRQHandler(&huart1);
里面有發送中斷處理分支部分UART_Transmit_IT(huart),連續發送想要發送的多個字節下圖紅線部分所示,每調用一次發送一個字節數據,字節發送結束后發送寄存器變為空時再次進入此中斷,每發一次huart->TxXferCount減一次,減為0時,失能發送中斷,打開發送完成中斷,如下圖黃色色部分所示
然后再次回到USARTx_IRQHandler,調用 發送完成處理分支UART_EndTransmit_IT(huart);
UART_EndTransmit_IT函數會調用發送完成回調函數HAL_UART_TxCpltCallback(huart);
用戶可以自行定義此函數進行相應處理
③ DMA 方式發送:
HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
二 串口接收方式:
1)輪訓方式接收,也就是主動去檢查,這個容易理解,使用如下函數
HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
2)DMA方式接收
HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
3)中斷方式接收,有兩種方式,這里過程比較多比較難理解詳細講述:
不使用HAL庫函數,直接寄存器方式,如下圖,直接在中斷向量表入口里面通過判斷接收標志位RXNE,直接讀寄存器DR,這樣每一個收到一個字節會進一次中斷
使用HAL庫函數的回調函數,注意這里有兩種接收方式以及相應的兩種回調函數:
① 標準回調函數(接收完成回調函數):HAL_UART_RxCpltCallback()
接收到啟動時設置的字節數(啟動接收時需要設置接收數據長度)后的回調函數
a) 首先通過HAL_UART_Receive_IT(&huart1,(uint8_t *)RxBuff,BUFFSIZE)啟動,這個啟動函數要在初始化時首次啟動,并且要在接收完定長數據后回調函數中再次啟動,如下圖
里面有開啟中斷接收數據的條件
以及條件賦值語句,這是選擇進入標準回調函數的條件,
b) 發生中斷時(接收到一個字節時)中斷向量里面會調用總的串口中斷處理函數HAL_UART_IRQHandler(&huart1);此函數會調用?UART_Receive_IT(huart);
此函數里面會對數據進行接收保存,如下,從此函數可以看出,不開啟上面的a)步驟的條件,UART_Receive_IT是不會讀接收寄存器的是數據的,如下圖,所以想要使用HAL庫回調函數接收數據,必須在初始化時通過HAL_UARTEx_ReceiveToIdle_IT或者HAL_UART_Receive_IT()函數開啟接收狀態,這是HAL庫函數決定的。
c)此函數最終還會調用定長數據接收回調函數HAL_UART_RxCpltCallback(huart);如下圖
用戶可以在回調函數中對數據進行想要的處理。
② 接收完成或者空閑回調函數HAL_UARTEx_RxEventCallback()
接收完成或者空閑回調函數。當接收到預先設置好的字節數或者接收空閑(IDLE中斷)時會回調這個函數
?a) 首先通過HAL_UARTEx_ReceiveToIdle_IT(&huart1,(uint8_t *)RxBuff,BUFFSIZE);開啟接收狀態如下圖
里面有開啟進入空閑回調函數的條件如下圖
以及開啟中斷接收數據的條件,如下圖
b) 發生中斷時,串口中斷向量入口會調用總處理函數HAL_UART_IRQHandler(&huart1)
此函數會調用函數UART_Receive_IT進行數據讀取,從此函數可以發現如果不開啟上面的a)步驟的條件,UART_Receive_IT是不會讀接收寄存器的是數據的,如下圖,所以想要使用HAL庫回調函數接收數據,必須在初始化時通過HAL_UARTEx_ReceiveToIdle_IT或者HAL_UART_Receive_IT()函數開啟接收狀態,這是HAL庫函數決定的。
c)以及最終調用完成或者空閑回調函數HAL_UARTEx_RxEventCallback(huart, nb_rx_data);
首先第一個情況下UART_Receive_IT里面在發送完成條件下,同標準回調函數一樣,也調用了此回調函數
另外注意黃線所示語句,huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;如果這是一個發送滿一個RxBuffer量程的情況,就賦值接收模式為標準模式,就不會進入下面這個情況進行空閑模式分析與調用。
第二個情況:
首先有個條件,就是在第a)步驟中提及的條件,啟動了HAL_UARTEx_ReceiveToIdle_IT空閑接收狀態,并且前面沒有接收滿一個量程,上面紫色字體所述,如下圖
其次是接收未滿一個RxBuffer量程的條件,圓圈處代表總線空閑,接收未達到RxBuffer 滿量程,進行此函數調用
兩個回調函數的使用總結如下:
比如定義接收緩沖區大小為RxBuffer[10],也就是函數HAL_UART_Receive_IT(&huart1,(uint8_t *)RxBuff,BUFFSIZE)或者HAL_UARTEx_ReceiveToIdle_IT(&huart1,(uint8_t *)RxBuff,BUFFSIZE);中的BUFFERSIZE=10,調用機制如下圖