STM32-HAL库串口空闲中断DMA接收数据Demo

一、Demo说明

  • 主控stm32f103rct6
  • 串口1、2、3、4采用DMA+空闲中断方式实现接收数据
  • 串口5采用接收中断+空闲中断实现接收数据
  • 定时器1执行定时任务

二、HAL库配置

1. 系统配置

  • 开启SWD下载
  • 开启外部时钟

2. 串口1配置(串口2/3/4类似)

  • 配置波特率
  • 添加接收DMA
  • 开启中断

3. 定时器配置

4. 时钟选择

硬件电路外部接有8M晶振所以选择外部8M晶振

5. 工程生成

三、代码编写

1. 初始化

串口接收使用DMA+空闲中断实现,初始化中需要开启串口空闲中断,以及串口5的接收中断。

void UserSys_Init(void)
{
	HAL_NVIC_EnableIRQ(UART5_IRQn);
	__HAL_UART_ENABLE_IT(&huart5, UART_IT_IDLE);
	HAL_UART_Receive_IT(&huart5,(uint8_t*)&g_usart5_recv_byte,1);
	
	HAL_NVIC_EnableIRQ(UART4_IRQn);
	__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
	HAL_UART_Receive_DMA(&huart4, (uint8_t*)g_USART4_Recv_Data, RECV_DATA_MAX_LEN);
	
	HAL_NVIC_EnableIRQ(USART3_IRQn);
	__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
	HAL_UART_Receive_DMA(&huart3, (uint8_t*)g_USART3_Recv_Data, RECV_DATA_MAX_LEN);

	HAL_NVIC_EnableIRQ(USART2_IRQn);
	__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
	HAL_UART_Receive_DMA(&huart2, (uint8_t*)g_USART2_Recv_Data, RECV_DATA_MAX_LEN);
	
	HAL_NVIC_EnableIRQ(USART1_IRQn);
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
	HAL_UART_Receive_DMA(&huart1, (uint8_t*)g_USART1_Recv_Data, RECV_DATA_MAX_LEN);
	
	HAL_TIM_Base_Start_IT(&htim1);
}

2. 串口空闲中断

2.1. 自定义串口空闲中断服务函数
  • 串口5无法使用DMA传输,所以使用接收中断和空闲中断的方式实现,使用接收中断将数据保存后,利用空闲中断处理数据;
  • 串口1、2、3、4采用空闲中断+DMA方式,具体流程如下:
    • 判断是否为空闲中断
    • 清除空闲中断标志
    • 关闭DMA传输,关闭空闲中断(在主函数数据处理完成后开启)
    • 备份数据
    • 标志位置1
/** 空闲中断回调函数
  * @brief  HAL_UART_IdleCpltCallback
  * @param  huart 串口
  * @retval None
  */
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{
	//USART5 IDLE/RXNE
	if(huart == &huart5)
	{
		//RXNE
		g_USART5_Recv_Data[usart5_recv_cnt++] = g_usart5_recv_byte;
		HAL_UART_Receive_IT(&huart5,(uint8_t*)&g_usart5_recv_byte,1);
		
		//IDLE
		if(RESET != __HAL_UART_GET_FLAG(&huart5,UART_FLAG_IDLE))
		{
			g_usart5_recv_len = usart5_recv_cnt;
			__HAL_UART_CLEAR_IDLEFLAG(&huart5);//Clear the UART IDLE pending flag.(Otherwise it will continue to interrupt)

			memset(g_USART5_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
			memcpy(g_USART5_Recv_Data_BAK,g_USART5_Recv_Data,g_usart5_recv_len);
			memset(g_USART5_Recv_Data,0,RECV_DATA_MAX_LEN);
			usart5_recv_cnt = 0;
			g_USART5_Recv_Flag = 1;
		}		
	}
	//USART4 IDLE
	if(huart == &huart4)
	{
		if(RESET != __HAL_UART_GET_FLAG(&huart4,UART_FLAG_IDLE))
		{
			__HAL_UART_CLEAR_IDLEFLAG(&huart4);
			HAL_UART_DMAStop(&huart4);						//关闭DMA传输
			__HAL_UART_DISABLE_IT(&huart4, UART_IT_IDLE);	//关闭空闲中断
			
			g_usart4_recv_len = RECV_DATA_MAX_LEN - (__HAL_DMA_GET_COUNTER(&hdma_uart4_rx));//计算接收数据长度
			
			memset(g_USART4_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
			memcpy(g_USART4_Recv_Data_BAK,g_USART4_Recv_Data,g_usart4_recv_len);
			memset(g_USART4_Recv_Data,0,RECV_DATA_MAX_LEN);	//处理数据
			
			g_USART4_Recv_Flag = 1;		//标志位置位
		}
	}
	//USART3 IDLE 
	if(huart == &huart3)
	{
		if(RESET != __HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE))
		{			
			__HAL_UART_CLEAR_IDLEFLAG(&huart3);//Clear the UART IDLE pending flag.(Otherwise it will continue to interrupt)
			HAL_UART_DMAStop(&huart3);
			__HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE);
			g_usart3_recv_len = RECV_DATA_MAX_LEN - (__HAL_DMA_GET_COUNTER(&hdma_usart3_rx));
			
			memset(g_USART3_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
			memcpy(g_USART3_Recv_Data_BAK,g_USART3_Recv_Data,g_usart3_recv_len);
			memset(g_USART3_Recv_Data,0,RECV_DATA_MAX_LEN);
			g_USART3_Recv_Flag = 1;
		}
	}
	//USART2 IDLE 
	if(huart == &huart2)
	{
		if(RESET != __HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE))
		{			
			__HAL_UART_CLEAR_IDLEFLAG(&huart2);//Clear the UART IDLE pending flag.(Otherwise it will continue to interrupt)
			HAL_UART_DMAStop(&huart2);
			__HAL_UART_DISABLE_IT(&huart2, UART_IT_IDLE);
			g_usart2_recv_len = RECV_DATA_MAX_LEN -(__HAL_DMA_GET_COUNTER(&hdma_usart2_rx));
			
			memset(g_USART2_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
			memcpy(g_USART2_Recv_Data_BAK,g_USART2_Recv_Data,g_usart2_recv_len);
			memset(g_USART2_Recv_Data,0,RECV_DATA_MAX_LEN);
			g_USART2_Recv_Flag = 1;
		}
	}
	//USART1 IDLE 
	if(huart == &huart1)
	{
		if(RESET != __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))
		{			
			__HAL_UART_CLEAR_IDLEFLAG(&huart1);//Clear the UART IDLE pending flag.(Otherwise it will continue to interrupt)
			HAL_UART_DMAStop(&huart1);
			__HAL_UART_DISABLE_IT(&huart1, UART_IT_IDLE);
			g_usart1_recv_len = RECV_DATA_MAX_LEN -(__HAL_DMA_GET_COUNTER(&hdma_usart1_rx));
			memset(g_USART1_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
			memcpy(g_USART1_Recv_Data_BAK,g_USART1_Recv_Data,g_usart1_recv_len);
			memset(g_USART1_Recv_Data,0,RECV_DATA_MAX_LEN);
			g_USART1_Recv_Flag = 1;
		}
	}
}
2.2. 中断复位函数中调用

在中断服务函数中调用

3. 主函数中数据处理

  • 判断接收标志位
  • 标志位清零
  • 数据解析操作
  • 开启空闲中断、开启DMA接收
void Board_Run(void)
{
	/*uart5--接收*/
	if(g_USART5_Recv_Flag)
	{
		g_USART5_Recv_Flag = 0;
		//数据处理 g_USART5_Recv_Data_BAK
		HAL_UART_Transmit(&huart1,g_USART5_Recv_Data_BAK,g_usart5_recv_len,0xff);
		
	}
	/*uart4--接收*/
	if(g_USART4_Recv_Flag)
	{
		g_USART4_Recv_Flag = 0;	
		/* USER CODE BEGIN 解析数据 内容:g_USART4_Recv_Data_BAK,长度:g_usart4_recv_len*/
		HAL_UART_Transmit(&huart1,g_USART4_Recv_Data_BAK,g_usart4_recv_len,0xff);
		
		/* USER CODE END */
		/*解析完成打开中断*/
		HAL_UART_AbortReceive(&huart4);
		__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
		HAL_UART_Receive_DMA(&huart4, (uint8_t*)g_USART4_Recv_Data, RECV_DATA_MAX_LEN);
	}
	/*usart3--接收*/
	if(g_USART3_Recv_Flag)
	{
		g_USART3_Recv_Flag=0;
		/* USER CODE BEGIN 解析数据 内容:g_USART3_Recv_Data_BAK,长度:g_usart3_recv_len*/
		HAL_UART_Transmit(&huart1,g_USART3_Recv_Data_BAK,g_usart3_recv_len,0xff);
		
		/* USER CODE END */
		HAL_UART_AbortReceive(&huart3);
		__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
		HAL_UART_Receive_DMA(&huart3, (uint8_t*)g_USART3_Recv_Data, RECV_DATA_MAX_LEN);
	}
	/*usart2--接收*/
	if(g_USART2_Recv_Flag)
	{
		g_USART2_Recv_Flag=0;
		/* USER CODE BEGIN 解析数据 内容:g_USART2_Recv_Data_BAK,长度:g_usart2_recv_len*/
		HAL_UART_Transmit(&huart1,g_USART2_Recv_Data_BAK,g_usart2_recv_len,0xff);
		
		/* USER CODE END */
		HAL_UART_AbortReceive(&huart2);
		__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
		HAL_UART_Receive_DMA(&huart2, (uint8_t*)g_USART2_Recv_Data, RECV_DATA_MAX_LEN);
	}
	/*usart1--接收*/
	if(g_USART1_Recv_Flag)
	{
		g_USART1_Recv_Flag=0;
		/* USER CODE BEGIN 解析数据 内容:g_USART1_Recv_Data_BAK,长度:g_usart1_recv_len*/
		HAL_UART_Transmit(&huart1,g_USART1_Recv_Data_BAK,g_usart1_recv_len,0xff);
		
		/* USER CODE END */
		HAL_UART_AbortReceive(&huart1);
		__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
		HAL_UART_Receive_DMA(&huart1, (uint8_t*)g_USART1_Recv_Data, RECV_DATA_MAX_LEN);
		
	}
}

四、源码地址

https://download.csdn.net/download/LJ_96/89771971

猜你喜欢

转载自blog.csdn.net/LJ_96/article/details/142463350