嵌入式学习笔记 - U(S)ART 模块HAL 库函数总结
一 串口发送方式:
①轮训方式发送,也就是主动发送,这个容易理解,使用如下函数:
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,调用机制如下图