蓝桥杯嵌入式竞赛:STM32G431RBT6空闲中断DMA串口不定长收发实现
目录
1、cubemx配置
(1)串口选择异步模式,波特率9600,打开串口接收中断
(2)打开dma接收、发送请求,选择normal搬运,数据类型设置为字节
2、在初始化中加入以下代码:空闲中断使能、打开DMA发送、接收请求
3、在stm32g4xx_it.c中找到USART1_IRQHandler(void),重写中断服务函数
4、编写空闲中断回调函数
5、主函数while接收
空闲中断:顾名思义当串口空闲时候触发中断,当串口接收到数据时,数据是以字节为单位进行传送,当最后一字节接收后一段时间(通常很短)没有接收到下一字节数据,就会触发空闲中断。利用空闲中断的这个特性,可以实现串口数据的不定长接收。
1、cubemx配置
(1)串口选择异步模式,波特率9600,打开串口接收中断
(2)打开dma接收、发送请求,选择normal搬运,数据类型设置为字节
2、在初始化中加入以下代码:空闲中断使能、打开DMA发送、接收请求
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //空闲中断标志位清除
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, (uint8_t *)rx, 20);
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)rx,20);
3、在stm32g4xx_it.c中找到USART1_IRQHandler(void),重写中断服务函数
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
//HAL_UART_IRQHandler(&huart1); //屏蔽
/* USER CODE BEGIN USART1_IRQn 1 */
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)!=RESET)
{
ucTemp=1;
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_DMAStop(&huart1);
idle_rxcallback(&huart1);
}
/* USER CODE END USART1_IRQn 1 */
}
将中断函数中的回调函数HAL_UART_IRQHandler(&huart1)屏蔽掉,检查空闲中断的标志位,若置位则将uc_Temp置1,然后清除空闲中断标志位(若不清除程序会一直卡在中断里,导致其余代码无法执行)。清除标志位之后停止DMA,然后调用idle_rxcallback(&huart1);回调函数。
注意:回调函数是自己编写,什么名字都可以!!!
不要开启其它串口中断,否则程序可能会卡死在串口中断中。
4、编写空闲中断回调函数
void idle_rxcallback(UART_HandleTypeDef *huart)
{
rx_num=0;
rx_num=20-__HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //DMA传输的剩余数据量
HAL_UART_Receive_DMA(&huart1, (uint8_t *)rx, 20);
}
在空闲中断中打开DMA的接收搬运,此代码中我添加了对接收数据的计数,没有这个需求的也可以不加。
5、主函数while接收
if(ucTemp==1)
{
ucTemp=0;
//printf("%s",rx); //串口回显
strcpy(tx,rx);
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)tx,20);//串口回显
sprintf(text,"rx_num:%02d",rx_num);
LCD_DisplayStringLine(Line1, (u8 *)text);
memset(rx,0,sizeof((unsigned char)rx));
memset(tx,0,sizeof((unsigned char)tx));
}
在主函数中检查uc_Temp标志位,若标志位等于1,则说明空闲中断被触发,一帧串口数据接收完成,可以进行数据处理,处理后,再将标志位置0,等待下一帧数据接收完成。
作者:grandbear