STM32 HAL库串口空闲中断 + DMA 收发不定长数据

串口接收缓冲区定义

usart.h

#define BUFFER_SIZE 64

typedef struct
{
	uint8_t  buff[BUFFER_SIZE];
	uint32_t length;
	uint32_t rx_flag;
}uart_rx_msg;

/* 串口接收消息缓冲 */
extern uart_rx_msg rs422_rx_msg;
extern uart_rx_msg rs485_rx_msg;
extern uart_rx_msg rs232_rx_msg;

usart.c

/* 串口接收消息缓冲 */
uart_rx_msg rs422_rx_msg;
uart_rx_msg rs485_rx_msg;
uart_rx_msg rs232_rx_msg;

//在每个串口初始化函数里初始化缓冲BUF
/* 初始化缓冲区  */
memset(rs485_rx_msg.buff,0,BUFFER_SIZE);
rs485_rx_msg.rx_flag = 0;
rs485_rx_msg.length = 0;	

memset(rs232_rx_msg.buff,0,BUFFER_SIZE); 
rs232_rx_msg.length = 0;
rs232_rx_msg.rx_flag = 0;

memset(rs422_rx_msg.buff,0,BUFFER_SIZE);
rs422_rx_msg.length = 0;
rs422_rx_msg.rx_flag = 0;

使能IDLE中断和DMA接收

	//使能IDLE中断
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); 
	//DMA接收函数
	HAL_UART_Receive_DMA(&huart1,rs232_rx_msg.buff,BUFFER_SIZE);

空闲中断回调函数

HAL库没有实现空闲中断回调,需自己实现,然后放到USART_IRQHandler中断函数中

void uart_dma_isr_process(UART_HandleTypeDef *huart)
{
	if(huart->Instance == huart1.Instance)
	{
			uint32_t temp;
			//获取IDLE标志位
			if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET)//idle标志被置位
			{ 
				__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
				//停止DMA搬运
				HAL_UART_DMAStop(&huart1); 
				// 获取DMA中未传输的数据个数   
				temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
				//总计数减去未传输的数据个数,得到已经接收的数据个数
				rs232_rx_msg.length =  BUFFER_SIZE - temp; 
				// 接受完成标志位置1	
				rs232_rx_msg.rx_flag = 1;	
			}
	}
	if(huart->Instance == huart4.Instance)
	{
			uint32_t temp;
			//获取IDLE标志位
			if(__HAL_UART_GET_FLAG(&huart4,UART_FLAG_IDLE) != RESET)//idle标志被置位
			{ 
				__HAL_UART_CLEAR_IDLEFLAG(&huart4);//清除标志位
				//停止DMA搬运
				HAL_UART_DMAStop(&huart4); 
				// 获取DMA中未传输的数据个数   
				temp  =  __HAL_DMA_GET_COUNTER(&hdma_uart4_rx);
				//总计数减去未传输的数据个数,得到已经接收的数据个数
				rs485_rx_msg.length =  BUFFER_SIZE - temp; 
				// 接受完成标志位置1	
				rs485_rx_msg.rx_flag = 1;	
			}
	}
	if(huart->Instance == huart6.Instance)
	{
			uint32_t temp;
			//获取IDLE标志位
			if(__HAL_UART_GET_FLAG(&huart6,UART_FLAG_IDLE) != RESET)//idle标志被置位
			{ 
				__HAL_UART_CLEAR_IDLEFLAG(&huart6);//清除标志位
				//停止DMA搬运
				HAL_UART_DMAStop(&huart6); 
				// 获取DMA中未传输的数据个数   
				temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart6_rx);
				//总计数减去未传输的数据个数,得到已经接收的数据个数
				rs422_rx_msg.length =  BUFFER_SIZE - temp; 
				// 接受完成标志位置1	
				rs422_rx_msg.rx_flag = 1;	
			}
	}
 }

DMA收,根据标志位进行数据回显

		if(rs422_rx_msg.rx_flag == 1)  //接收完成标志
		{	
//			can_send_msg(0x01,rs422_rx_msg.buff,rs422_rx_msg.length);
//			can_send_msg(0x02,rs422_rx_msg.buff,rs422_rx_msg.length);
			//将接收到的数据回发
			HAL_UART_Transmit_DMA(&huart6,rs422_rx_msg.buff, rs422_rx_msg.length);
			rs422_rx_msg.length = 0;//清除计数
			rs422_rx_msg.rx_flag = 0;//清除接收结束标志位
			memset(rs422_rx_msg.buff,0,rs422_rx_msg.length);
		}
		HAL_UART_Receive_DMA(&huart6,rs422_rx_msg.buff,BUFFER_SIZE);//重新打开DMA接收

USART_IRQHandler调用回调函数

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	uart_dma_isr_process(&huart1);
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}
使用STM32串口空闲中断DMA可以实现接收不定数据的功能,具体步骤如下: 1. 配置串口DMA 首先需要配置串口DMA,使其能够正常工作。具体配置方法可以参考STM32的官方文档或者其他相关资料。 2. 配置接收数组和接收计数器 在代码中定义一个接收数组和一个接收计数器,用于存储接收到的数据和记录接收到的数据度。 3. 配置空闲中断空闲中断中判断接收数据是否完成,如果完成则将接收到的数据发送出去。具体实现方法如下: ```c void HAL_UART_IDLECallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { uint32_t tmp_flag = 0; uint32_t temp; tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE); //获取空闲中断标志 if((tmp_flag != RESET)) //判断是否是空闲中断 { __HAL_UART_CLEAR_IDLEFLAG(&huart1); //清除空闲中断标志 HAL_UART_DMAStop(&huart1); //停止DMA传输 temp = huart1.hdmarx->Instance->CNDTR; //获取DMA缓存区剩余数据量 uart1_rx_len = UART_RCV_BUF_SIZE - temp; //计算接收到的数据度 HAL_UART_Transmit(&huart1, uart1_rx_buf, uart1_rx_len, 0xffff); //将接收到的数据发送出去 HAL_UART_Receive_DMA(&huart1, uart1_rx_buf, UART_RCV_BUF_SIZE); //重新开启DMA传输 } } } ``` 4. 启动DMA传输 在代码中启动DMA传输,将串口接收到的数据存储到接收数组中。具体实现方法如下: ```c HAL_UART_Receive_DMA(&huart1, uart1_rx_buf, UART_RCV_BUF_SIZE); ``` 以上就是使用STM32串口空闲中断DMA实现接收不定数据的方法。如果您有任何问题,请随时提出。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值