STM32_HAL庫(kù)串口接收相關(guān)函數(shù)分析:
串口接收的程序整體分為三個(gè)部分:初始化部分,開(kāi)啟中斷部分,中斷函數(shù)部分:
- 初始化部分:
該部分主要完成相關(guān)引腳的初始化,串口的初始化(設(shè)置波特率,校驗(yàn)位,字長(zhǎng)等),為了邏輯清晰,把初始化相關(guān)代碼放在本文的最后。
- 開(kāi)啟中斷部分:
調(diào)用HAL_UART_Receive_IT函數(shù),開(kāi)啟中斷,這個(gè)函數(shù)原型如下:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
第一個(gè)參數(shù)是串口句柄,第二個(gè)參數(shù)指向自定義的接收緩沖數(shù)組,第三個(gè)參數(shù)很重要,它的值被賦給串口句柄的RxXferCount成員,規(guī)定了接收到幾個(gè)數(shù)據(jù)幀之后,會(huì)調(diào)用接收回調(diào)函數(shù)HAL_UART_RxCpltCallback,詳見(jiàn)下文。
- 中斷函數(shù)部分:中斷函數(shù)部分主要位兩個(gè)函數(shù):中斷函數(shù)和回調(diào)函數(shù)
以USART1的中斷函數(shù)為例:
當(dāng)調(diào)用HAL_UART_Receive_IT之后每次接收到一個(gè)字節(jié)的數(shù)據(jù)就會(huì)觸發(fā)USART1_IRQHandler中斷,USART1_IRQHandler中需要調(diào)用串口外設(shè)公用的中斷函數(shù)HAL_UART_IRQHandler,給其傳入初始化時(shí)使用的串口句柄g_uart1_handle。
在HAL_UART_IRQHandler內(nèi)部會(huì)判斷此次的中斷源,如果判斷出來(lái)是接收中斷(此中斷在HAL_UART_Receive_IT中已被開(kāi)啟),則調(diào)用另外一個(gè)HAL庫(kù)函數(shù)UART_Receive_IT,在該函數(shù)中會(huì)使串口句柄的RxXferCount成員遞減一,如果遞減一之后,RxXferCount變?yōu)榱懔耍瑒t關(guān)閉接收中斷,清除相關(guān)標(biāo)志位,調(diào)用回調(diào)函數(shù)HAL_UART_RxCpltCallback,否則函數(shù)直接返回。
可見(jiàn),RxXferCount的初始值決定了在接收幾個(gè)字節(jié)之后會(huì)調(diào)用回調(diào)函數(shù),上文提到過(guò),它的初始值由HAL_UART_Receive_IT的第三個(gè)參數(shù)決定。在實(shí)際應(yīng)用中,一般讓RxXferCount等于一即每接收到一個(gè)字節(jié),就調(diào)用一次回調(diào)函數(shù)。由于每次調(diào)用回調(diào)函數(shù)之后,都會(huì)關(guān)閉接收中斷(上一段提到過(guò)),所以再USART1_IRQHandler要再次開(kāi)啟中斷,為接收下一個(gè)字節(jié)做準(zhǔn)備
串口中斷函數(shù):
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&g_uart1_handle);/*串口公共中斷函數(shù)*/
HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, 1);/*再次開(kāi)啟中斷*/
}
串口接收回調(diào)函數(shù):(RxXferCount==0時(shí)才會(huì)調(diào)用)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-595554.html
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/*通過(guò)讀取自定義的g_rx_buffer[0]獲取此次接收的字符,然后在此回調(diào)函數(shù)中確定回調(diào)行為*/
}
初始化相關(guān)的代碼:
#define USART_TX_GPIO_PORT GPIOA
#define USART_TX_GPIO_PIN GPIO_PIN_9
#define USART_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口時(shí)鐘使能 */
#define USART_RX_GPIO_PORT GPIOA
#define USART_RX_GPIO_PIN GPIO_PIN_10
#define USART_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口時(shí)鐘使能 */
#define USART_UX USART1
#define USART_UX_IRQn USART1_IRQn
#define USART_UX_IRQHandler USART1_IRQHandler
#define USART_UX_CLK_ENABLE() do{ __HAL_RCC_USART1_CLK_ENABLE(); }while(0) /* USART1 時(shí)鐘使能 */
/******************************************************************************************/
#define USART_REC_LEN 200 /* 定義最大接收字節(jié)數(shù) 200 */
#define USART_EN_RX 1 /* 使能(1)/禁止(0)串口1接收 */
#define RXBUFFERSIZE 1 /* 緩存大小 */
extern UART_HandleTypeDef g_uart1_handle; /* HAL UART句柄 */
extern uint8_t g_usart_rx_buf[USART_REC_LEN]; /* 接收緩沖,最大USART_REC_LEN個(gè)字節(jié).末字節(jié)為換行符 */
extern uint16_t g_usart_rx_sta; /* 接收狀態(tài)標(biāo)記 */
extern uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL庫(kù)USART接收Buffer */
/******************************************************************************************/
/* 加入以下代碼, 支持printf函數(shù), 而不需要選擇use MicroLIB */
#if 1
#if (__ARMCC_VERSION >= 6010050) /* 使用AC6編譯器時(shí) */
__asm(".global __use_no_semihosting\n\t"); /* 聲明不使用半主機(jī)模式 */
__asm(".global __ARM_use_no_argv \n\t"); /* AC6下需要聲明main函數(shù)為無(wú)參數(shù)格式,否則部分例程可能出現(xiàn)半主機(jī)模式 */
#else
/* 使用AC5編譯器時(shí), 要在這里定義__FILE 和 不使用半主機(jī)模式 */
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
#endif
/* 不使用半主機(jī)模式,至少需要重定義_ttywrch\_sys_exit\_sys_command_string函數(shù),以同時(shí)兼容AC6和AC5模式 */
int _ttywrch(int ch)
{
ch = ch;
return ch;
}
/* 定義_sys_exit()以避免使用半主機(jī)模式 */
void _sys_exit(int x)
{
x = x;
}
char *_sys_command_string(char *cmd, int len)
{
return NULL;
}
/* FILE 在 stdio.h里面定義. */
FILE __stdout;
/* MDK下需要重定義fputc函數(shù), printf函數(shù)最終會(huì)通過(guò)調(diào)用fputc輸出字符串到串口 */
int fputc(int ch, FILE *f)
{
while ((USART_UX->SR & 0X40) == 0); /* 等待上一個(gè)字符發(fā)送完成 */
USART_UX->DR = (uint8_t)ch; /* 將要發(fā)送的字符 ch 寫(xiě)入到DR寄存器 */
return ch;
}
#endif
/******************************************************************************************/
#if USART_EN_RX /*如果使能了接收*/
/* 接收緩沖, 最大USART_REC_LEN個(gè)字節(jié). */
uint8_t g_usart_rx_buf[USART_REC_LEN];
/* 接收狀態(tài)
* bit15, 接收完成標(biāo)志
* bit14, 接收到0x0d
* bit13~0, 接收到的有效字節(jié)數(shù)目
*/
uint16_t g_usart_rx_sta = 0;
uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL庫(kù)使用的串口接收緩沖 */
UART_HandleTypeDef g_uart1_handle; /* UART句柄 */
/**
* @brief 串口X初始化函數(shù)
* @param baudrate: 波特率, 根據(jù)自己需要設(shè)置波特率值
* @note 注意: 必須設(shè)置正確的時(shí)鐘源, 否則串口波特率就會(huì)設(shè)置異常.
* 這里的USART的時(shí)鐘源在sys_stm32_clock_init()函數(shù)中已經(jīng)設(shè)置過(guò)了.
* @retval 無(wú)
*/
void usart_init(uint32_t baudrate)
{
/*UART 初始化設(shè)置*/
g_uart1_handle.Instance = USART_UX; /* USART_UX */
g_uart1_handle.Init.BaudRate = baudrate; /* 波特率 */
g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字長(zhǎng)為8位數(shù)據(jù)格式 */
g_uart1_handle.Init.StopBits = UART_STOPBITS_1; /* 一個(gè)停止位 */
g_uart1_handle.Init.Parity = UART_PARITY_NONE; /* 無(wú)奇偶校驗(yàn)位 */
g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 無(wú)硬件流控 */
g_uart1_handle.Init.Mode = UART_MODE_TX_RX; /* 收發(fā)模式 */
HAL_UART_Init(&g_uart1_handle); /* HAL_UART_Init()會(huì)使能UART1 */
/* 該函數(shù)會(huì)開(kāi)啟接收中斷:清除標(biāo)志位UART_IT_RXNE,并且設(shè)置接收緩沖以及接收緩沖接收最大數(shù)據(jù)量 */
HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
}
/**
* @brief UART底層初始化函數(shù)
* @param huart: UART句柄類(lèi)型指針
* @note 此函數(shù)會(huì)被HAL_UART_Init()調(diào)用
* 完成時(shí)鐘使能,引腳配置,中斷配置
* @retval 無(wú)
*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef gpio_init_struct;
if (huart->Instance == USART_UX) /* 如果是串口1,進(jìn)行串口1 MSP初始化 */
{
USART_TX_GPIO_CLK_ENABLE(); /* 使能串口TX腳時(shí)鐘 */
USART_RX_GPIO_CLK_ENABLE(); /* 使能串口RX腳時(shí)鐘 */
USART_UX_CLK_ENABLE(); /* 使能串口時(shí)鐘 */
gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* 串口發(fā)送引腳號(hào) */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 復(fù)用推挽輸出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* IO速度設(shè)置為高速 */
HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* 串口RX腳 模式設(shè)置 */
gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;
HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 串口RX腳 必須設(shè)置成輸入模式 */
#if USART_EN_RX
HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART1中斷通道 */
HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 組2,最低優(yōu)先級(jí):搶占優(yōu)先級(jí)3,子優(yōu)先級(jí)3 */
#endif
}
}
參考文獻(xiàn):《正點(diǎn)原子_HAL庫(kù)開(kāi)發(fā)指南》文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-595554.html
到了這里,關(guān)于STM32_HAL庫(kù)串口接收相關(guān)函數(shù)分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!