STM32G431RBT6串口收发不定长数据(空闲中断)

本文介绍了在STM32中,如何利用HAL库的空闲中断功能处理串口接收不定长数据,通过自定义中断回调函数和DMA传输,实现了高效的数据接收和发送管理。
摘要由CSDN通过智能技术生成

         在使用stm32的串口通信时,HAL库提供的函数HAL_UART_Receive_IT函数只能够接收固定长度的数据。这个中断只有在接受数据的数量到设定的数量以后,才被触发。我们在通信单片机时候,不可能是固定长度不变,如果单纯使用这种方法,每次数据量变化的时候,需要重新设置长度,很不方便。好在G431提供了另一个中断,叫做空闲中断,意思是当全部数据被接受后,出现了空闲帧,空闲中断被触发。利用这个方法即可实现串口接收不定长数据。我们首先要了解,空闲中断官方并没有给出回调函数,需要我们自己去判断空闲中断标志。

        __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)函数可以获得到关于串口的标志位信息,这里我们获取到了UART_FLAG_IDLE的状态,即为空闲中断的标志位,如果他为SET,则代表空闲中断被触发,进入到我们的回调函数。_HAL_UART_CLEAR_IDLEFLAG(&huart1);代表清楚我们空闲

uint8_t U1_Rxbuff[1024]; //接受数据缓存区
uint8_t U1_Txbuff[1024]; //发送数据缓存区
FIG uart1; //uart1的配置
typedef struct{
	uint8_t *start; //开始指针
	uint8_t *end; //结束指针
}POINT;

typedef struct{
	uint32_t Rxcounter; //记录接受信息量
	uint32_t Txcounter; //记录发送信息量
	uint8_t  TxState;    //发送状态
	uint8_t  RxState;   //接收状态
	POINT      RXLOCATION; //用来指向接收数据地址的指针结构体
	POINT     TXLOCATION; //用来指向发送数据地址的指针结构体
}FIG;

        其中我们定义了两个数据缓冲区U1_Rxbuff,U1_Txbuff,用来存储我们接收和发送的数据。uart1是我们串口一的接收和发送信息的状态变量,Rxcounter为我们接收信息时,信息的长度,Txcounter记录发送的信息量。TxState和RxState分别为,发送和接受的状态量。RXLOCATION和TXLOCATION是指针结构体,分别用来指向接收和发送数据的开始和结尾。

void U1_PtrInit(void)
{
	uart1.Rxcounter = 0; //初始化接收数据的数量
	uart1.RXLOCATION.start = U1_Rxbuff; //指针指向接收缓存区首地址

	uart1.Txcounter = 0; //初始化发送数据的数量
	uart1.TXLOCATION.start = U1_Txbuff; //指针指向发送缓存区首地址
	
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //开启空闲中断
	HAL_UART_Receive_DMA(&huart1,uart1.RXLOCATION.start,U1_RX_MAX); //开启DMA传输
	
	uart1.TxState=0; //初始化接收状态
	uart1.RxState=0; //初始化发送状态
}

        初始化状态量,将计数值清0,接收和发送的开始指针指向缓冲区的首地址,开启空闲中断,开启DMA传输,接收状态置0。

void HAL_UART_IdleCallBack(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1) //判断串口几
	{
		if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))//判断是否为空闲中断
		{
			__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清除空闲中断
			HAL_UART_DMAStop(&huart1); //停止DMA传输
			uart1.Rxcounter = U1_RX_MAX - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
			uart1.RXLOCATION.end = &U1_Rxbuff[uart1.Rxcounter-1]; //指针指向数据末尾
			HAL_UART_Receive_DMA(&huart1, uart1.RXLOCATION.start, U1_RX_MAX); //开启DMA传输
			uart1.RxState = 1; //接收状态置1
		}
	}
}
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 */
	HAL_UART_IdleCallBack(&huart1);
  /* USER CODE END USART1_IRQn 1 */
}

 

        这个函数就是我们的空闲中断回调函数,首先判断串口几发送来的数据,如何判断空闲中断是否被触发,如果被触发,清除空闲中断。随后停止DMA传输,这里一定要停止,如果不停止,再次开启DMA传输,它的计数值无法被重置,接收数量会出现异常。 __HAL_DMA_GET_COUNTER(&hdma_usart1_rx)这个函数的作用是获取当前接收数据的计数值,他在中断函数中实现过程是当我们开启DMA传输时,计数值会被置为我们给定的最大接收数据量,完成回调函数被触发也是因为计数值为0。但是空闲中断开启后计数值是不会被清零的,而是计数值 = 最大接收数量 - 当前数据接收量。所以我们要获取当前数据量 = 最大接收数量 - 计数值。如果不停止DMA传输,这个值在下次开启DMA传输时,不会被置为最大接收数量,出现计数异常。end指针指向最后一个数据量,接收状态置1,表示接收成功。

        由于HAL库官方并没有空闲中断的回调函数,我们需要把他放到串口中断服务函数里面。

void U1_Txdata(uint8_t *data_location, uint32_t data_len)
{
	uart1.TXLOCATION.start = U1_Txbuff; //指针指向缓冲区首地址
  	memcpy(uart1.TXLOCATION.start,data_location,data_len); //将指针指向的地址和接收首地址
	uart1.Txcounter = data_len; //发送长度为接收数据长度
	uart1.TXLOCATION.end = &U1_Txbuff[uart1.Txcounter-1]; //指向数据末端
	uart1.TxState = 1; //发送状态置1
}

        这个函数的作用很简单,就是将接收缓冲区的数据复制到发送缓冲区,如果嫌麻烦的话,也可以用接收缓冲区发送。data_location为复制数据的首地址,data_len为数据长度。

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		uart1.TxState=0; //发送完置1
	}
}

这个函数用来重置发送状态,等待下一次的发送。

while(1)
  {
	if(uart1.RxState == 1)
	{
		U1_Txdata(uart1.RXLOCATION.start ,uart1.RXLOCATION.end - uart1.RXLOCATION.start + 1);
		uart1.RxState = 0;
	}
	if(uart1.TxState == 1)
	{
		HAL_UART_Transmit_DMA(&huart1,uart1.TXLOCATION.start,uart1.TXLOCATION.end - uart1.TXLOCATION.start + 1);
		uart1.TxState=0;
	}  
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值