串口接收中断函数原型:
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
单纯的
DMA(或中断)
必须要接收到指定数量的数据才能完全读走数据,否则数据会一直被缓存无法读取。适合定长数据帧。
对于串口接收不定长数据有
方式:《 串口空闲中断+DMA 》 。
想让串口接收不定长数据,需要我们开启串口的空闲中断(IDLE)。空闲中断指:stm32的数据总线在接受数据过程中,如果在接收一个字节所需要的时间内没有在接收到新数据,单片机就会进入串口空闲中断,表面此时不定长数据已经接收完成了。即会自动触发单片机的空闲中断IDLE标志位,引发空闲中断。
空闲中断的优点在于省去了帧头帧尾的检测,进入中断程序即意味着已经接收到一组完整数据,及时对数据处理或将数据转移出缓冲区即可。
注:串口空闲中断在串口无数据接收的情况下,是不会产生的。产生的条件是当清除空闲标志位后,必须有接收到第一个数据后,才开始触发,一旦接收的数据断流,没有接收到数据,即产生空闲中断。
当我们要接收不定长数据时,常常将串口接收空闲中断结合DMA使用。有了DMA,数据的一个个接收不会经过再叨扰触发串口中断,而是每当数据接收完毕后才会触发串口空闲中断。
代码思路:
//定义:
uint8_t Rx_buf[50]; //接收缓冲区
uint16_t Rx_long=0; //接受数据的长度
uint8_t Buf_long =50; //接收缓冲区大小
①首先要在主函数里定义一个接收数据的缓冲区,一般用数组。在串口初始化时要开启串口的空闲中断。
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//使能空闲中断
②然后在主函数里使能串口DMA接收
HAL_UART_Receive_DMA(&huart1,(uint8_t *)buf,buf_long); //使能串口DMA接收
--------------------此时只要接收数据停止时,就会触发空闲中断。
③在中断函数中写入要进行的内容
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE)==SET)//判断是否为空闲中断 SET表示发送了空闲中断
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2);//清除空闲中断标志位
HAL_UART_DMAStop(&huart2); //停止DMA
//Rx_long = Buf_long- __HAL_DMA_GET_COUNTER(huart->hdmarx);
Rx_long = Buf_long-__HAL_DMA_GET_COUNTER(&hdma_usart2_rx);//计算接收数据的长度
HAL_UART_Transmit(&huart2,Rx_buf,Rx_long,10); //将接收的数据发送显示在电脑上
HAL_UART_Receive_DMA(&huart2,Rx_buf,Buf_long); //重新开启DMA转运
}
/* USER CODE END USART2_IRQn 1 */
}
④下载程序,实验现象
注:我们设置的缓冲区长度大小为50字节。如果待接收的数据大于缓冲区长度,这时串口接收就会无法接收该数据。若出现此问题,把缓冲区的长度改大即可。