HAL庫中UART的三種收發方式
(一)阻塞收發
- 特點:簡單粗暴,占滿單片機資源進行收發
- 簡介:
- 發送:發送指定長度的資料,如果超時沒發送完成,則不再發送,回傳超時標志
- 接收:接收指定長度的資料,如果超時沒接收完成,則不再接收資料到指定緩沖區,回傳超時標志(HAL_TIMEOUT)
- 發送函式:
HAL_UART_Transmit() - 接收函式:
HAL_UART_Receive() - CubeMX配置 :

(二)中斷收發
- 特點:利用中斷收發,不會占滿資源
- 簡介:
- 發送:把發送緩沖區指標指向要發送的資料,設定發送長度,發送計數器初值,然后使能串口發送中斷,觸發串口中斷,
再然后,串口中斷函式處理,直到資料發送完成,而后關閉中斷,不再發送資料,串口發送完成回呼函式, - 接收:把接識訓沖區指標指向要存放接收資料的陣列,設定接收長度,接收計數器初值,然后使能串口接收中斷,接收到資料時,會觸發串口中斷,
再然后,串口中斷函式處理,直到接收到指定長度資料,而后關閉中斷,不再觸發接收中斷,呼叫串口接收完成回呼函式,
- 發送:把發送緩沖區指標指向要發送的資料,設定發送長度,發送計數器初值,然后使能串口發送中斷,觸發串口中斷,
- 發送函式:
HAL_UART_Transmit_IT() - 接收函式:
HAL_UART_Receive_IT() - CubeMX配置:

(三)DMA收發
-
特點:不占CPU資源
-
簡介:
- 串口DMA發送,以DMA方式發送指定長度的資料,
程序是,把發送緩沖區指標指向要發送的資料,設定發送長度,發送計數器初值,設定 DMA傳輸完成中斷的回呼函式,使能 DMA控制器中斷,使能 DMA控制器傳輸 使能UART的DMA傳輸請求,
然后,UART便會發送資料,直到發送完成,觸發DMA中斷,
DMA中斷處理,如果DMA模式是回圈模式,則直接呼叫 DMA傳輸完成中斷的回呼函式,
如果 DMA模式是正常模式,則先關閉DMA傳輸完成中斷,不再觸發DMA中斷,再 呼叫 DMA傳輸完成中斷的回呼函式,
DMA傳輸完成中斷的回呼函式處理程序,如果 DMA模式是回圈模式,則 直接呼叫串口發送完成回呼函式,
如果 DMA模式是正常模式,則先關閉 UART的DMA傳輸請求, 再使能串口傳輸完成中斷,直到傳輸完成,觸發中斷,
串口傳輸完成中斷處理,關閉中斷,呼叫串口發送完成回呼函式, - 串口DMA接收,以DMA方式接收指定長度的資料,
程序是,把 接識訓沖區指標 指向 要存放接收資料的陣列,設定接收長度,接收計數器初值,設定 DMA傳輸完成中斷的回呼函式,使能DMA控制器中斷,使能DMA控制器傳輸,使能UART的DMA傳輸請求,
然后,UART接收到資料,便會通過DMA把資料存到接識訓沖區,直到接收到指定長度資料,觸發DMA中斷,
DMA中斷處理,如果 DMA模式 是 回圈模式,則 直接 呼叫 DMA傳輸完成中斷的回呼函式,
如果 DMA模式是正常模式,則先關閉DMA傳輸完成中斷,不再觸發DMA中斷,再 呼叫 DMA傳輸完成中斷的回呼函式,
DMA傳輸完成中斷的回呼函式處理程序,如果 DMA模式是回圈模式,則直接呼叫串口接收完成回呼函式,
如果 DMA模式 是 正常模式,則先關閉 UART的DMA傳輸請求, 再呼叫串口接收完成回呼函式,
- 串口DMA發送,以DMA方式發送指定長度的資料,
-
發送函式:
HAL_UART_Transmit_DMA() -
接收函式:
HAL_UART_Receive_DMA() -
CubeMX配置

使用示例
以
HAL_UART_Transmit_IT為例
考慮到初始化代碼可以用CubeMX生成,為方便理解,省略了初始化代碼
int main(void)
{
/*初始化(已省略)*/
uint8_t uartbuff[20] = "test uart";
while (1)
{
HAL_UART_Transmit(&huart1,uartbuff,20,10);
}
}
在串口中使用printf()和scanf()
- 包含頭檔案
#include "stdio.h" - 重定義 fputc 以使用 printf()
int fputc(int c,FILE * f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&c,1,20);// 此處以阻塞發送為例,也可以使用其他兩種方式
return c;
}
- 重定義fgetc以使用scanf()
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);// 此處以阻塞接收為例,也可以使用其他兩種方式
return ch;
}
完成重定義后,就可以在代碼中使用printf()和scanf()了,使用方法同尋常c語言編程相同,輸入和輸出通過串口實作,可以使用串口除錯助手進行查看和操作,
回頭看整個流程
分析一下main.c檔案,從頭往下看,為方便閱讀,刪去了CubeMX生成的注釋
#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"
void SystemClock_Config(void);
/*此處重定義fputc和fgetc*/
int fputc(int c,FILE * f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&c,1,20);
return c;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
int main(void)
{
/****************這部分代碼可以使用CubeMX生成******************************/
/* 復位所有外設,初始化Flash介面和Systick */
HAL_Init();
/* 配置系統時鐘 */
SystemClock_Config();
/* 初始化所有已配置的外設,可以看到這里使用的是MX_XX_Init(),也就是呼叫使用CubeMX配置生成的初始化設定 */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
/****************這部分代碼可以使用CubeMX生成******************************/
/* 進入while回圈,執行用戶邏輯 */
while (1)
{
printf("test uart\n");
}
}
回呼函式
UART的中斷收發和DMA收發提供了回呼函式,當達到相應的條件后,會觸發回呼函式,用戶可以在回呼函式中撰寫自己需要實作的功能
例如:當使用HAL_UART_Transmit_IT()完成發送后,會觸發HAL_UART_TxCpltCallback
回呼函式,用戶可以在HAL_UART_TxCpltCallback中撰寫代碼實作自己需要的功能,
值得注意的是,回呼函式是使用弱定義關鍵字weak實作的,用戶需要重定義實作回呼函式,
__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
}
常見回呼函式:
HAL_UART_TxCpltCallback
HAL_UART_RxCpltCallback
HAL_UART_TxHalfCpltCallback
HAL_UART_RxHalfCpltCallback
HAL_UART_ErrorCallback
更多高級操作請查閱HAL庫官方檔案
或閱讀stm32f1xx_hal_uart.c中的相關介紹
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/277743.html
標籤:其他
