https://blog.youkuaiyun.com/qq_45413245/article/details/104585026
HAL_UART_Receive_IT和HAL_UART_IRQHandler相互配合;HAL_UART_Receive_IT用于打开串口数据接收中断(RxNEIE),并将用于保存接收数据的变量地址传递给指针pRxBuffPtr。串口在接收到1Byte数据后会产生中断,在中断处理函数中调用HAL_UART_IRQHandler,HAL_UART_IRQHandler再调用UART_Receive_IT将DR寄存器上的值赋值给pRxBuffPtr所指向的变量,同时将RxXferCount递减,待RxXferCount减至0(即数据读取完毕),然后关闭接收中断,调用回调函数HAL_UART_RxCpltCallback,这就完成了一个数据接收的完整流程。
1.(HAL_UART_Receive_IT打开接收中断,保存接收数据地址)-->2.(串口接收到数据产生中断调用USART1_IRQHandler) -->3.(HAL_UART_IRQHandler)--> 4.(UART_Receive_IT读取DR保存到pRxBuffPtr指向的变量,RxXferCount !=0重复流程2-4) --> 5.(关接收中断,调用回调函数HAL_UART_RxCpltCallback)
既然用到指针pRxBuffPtr就涉及一个问题:如果使用局部变量来保存接收数据就要注意,在产生中断读取到数据前变量不能被回收,否则会导致pRxBuffPtr成为一个野指针。
如果不使用HAL_UART_Receive_IT,就要手动使能接收中断__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE)。手动使能接收中断后,因为pRxBuffPtr为NULL,需要在中断函数USART1_IRQHandler中直接读取DR寄存器的值。读取DR值后SR的RXNE位会被清零,在这之后再调用HAL_UART_IRQHandler的话,由于RXNE被清零条件判断不会操作pRxBuffPtr读取DR寄存器,中断不会被关闭,回调函数HAL_UART_RxCpltCallback也不会被执行。
/* 使能UART接收中断 */
void Enable_Rx_ISR(void)
{
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
}
void USART1_IRQHandler(void)
{
unsigned char c = 0;
if((USART1->SR &(1<<5)) != 0) // 判断USART1的状态寄存器的第五位即RXNE位是否被置位
{
c = USART1->DR; // 读取DR,SR寄存器RXNE位会被清零
ring_buffer_write(c, &test_buffer); // 将数据保存到环形缓冲区中
}
/* HAL库中的UART统一中断服务函数,通过形参判断是要处理谁的中断 */
HAL_UART_IRQHandler(&huart1); // 对于接收中断,这个函数没有任何作用
}