STM32 HAL库 基于空闲中断实现不定长数据接受

一、什么是空闲中断

    IDLE中断产生条件:串口在接收完一个字符串,进入空闲状态时(IDLE置1)便会激发一个空闲中断。

    RXNE中断(串口接收中断):当串口接收到一个bit的数据时,(读取到一个停止位) 便会触发 RXNE接收数据中断。

区别:比如上位机一次性给单片机发送了114个字节,会产生114次RXNE中断,1次串口空闲中断。

注意:RXNE中断类似于HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);

回调函数是一种特殊的函数,它在特定事件发生时由系统或库调用,而不是由程序显式调用。当使用 HAL_UART_Receive_IT 函数启动UART接收中断后,每当接收到一个字符时,该回调函数就会被调用一次。

我们在接收中断中保存各个字节进缓冲数组,在传输结束触发空闲中断时将缓冲数组内容取出,即可实现不定长数据接收。

二、如何实现不定长数据收发

 第一步:在初始化时,添加需要的缓冲数组与标志位。开启串口空闲中断与接收中断。(这一步操作在main.c中)

 

7476bfba717245aa8a1af7192f9bcca4.png

9a6195f619d846b4ba687566966aa5ba.png

注意:由于初始化完成后,IDLE位默认为一,这里先清除,再开启串口空闲中断。

 第二步: 修改串口中断服务函数(在stm32f1xx_it.c中)

f4a40164edd14b57a2d863539fea4be2.pngd36136701a20460a9976c3f48590c990.pngeac96aa7e02b4054abfbf86e1017fea6.png

第三步:在后台中添加将串口收到的内容发出的程序,验证是否达到目的。(while(1)中添加)

0b14384bbf6640218df23498a0fa2abd.png

三、现象验证

蓝色内容是上位机发送,绿色内容是上位机接收。串口助手使用的是vofa+。

c8585ecb21d74c95847efebd062b650e.png

四、补充一:硬件连线以及CUBEMX配置(使用最小系统板+STLINKV2下载器)

下载使用SWD接口。使用串口需要使用USB转TTL模块。这是下载器接线。

679e09282c2e489e8a141490296b8aaf.jpeg

这是USB转TTL接线。用于调串口。

1c36a1eb4b83424e950847ce7d6a8f7d.jpeg

CUBEMX配置方面,选择外部高速时钟源,debug选择Serial Wire,打开串口一中断即可。

五、补充二:部分硬件底层逻辑

1.关于串口初始化结构体:

在usart.c中:自动生成了这个结构体变量。

2ed59b71aafb42d6941a83e42530346e.png

进去看一眼:

dbb5108478a84c8c98c6146c3fa90646.png

关注这个USART TypeDef*  Instance,进去看一眼:

6a19cc8916f34697947dce08d355ebfc.png

是寄存器级别的操作。

而在初始化中,CUBEMX生成的函数中帮我们调用了这个函数:

e4a7cc46bd8743fa8e0f89cae8f23bbf.png

也就是说,我们操作USART1就可以操作底层的寄存器了。

2.关于上面我们用到的DR寄存器:

    首先,TDR和RDR都是USART_DR寄存器的缓冲区,指的是USART_DR的0到8位,TDR和RDR共用一片物理空间,即DR寄存器。

    接收数据过程:  数据通过串口线一位一位传过来,先传到移位寄存器,当移位寄存器识别了这个数据帧之后,通过“并行通信”的方式“一次性”传递给RDR寄存器,当移位寄存器中的数据位传到RDR中时,RXNE会硬件置为1。我们在串口接收中断中去读取RDR缓冲区里面的数据内容,而一旦读取了RDR中的内容,RXNE标志位会硬件置0。下次还有数据传进来的时候,RXNE又会置1。如此循环往复。

c6da6999259f492a89f703ff951d5963.png

六、抄代码在这:

main.c:

/* USER CODE BEGIN 0 */
int flag = 0;
uint8_t RxBuff[256] = {0};
uint16_t Num = 0;
/* USER CODE END 0 */


 while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(flag == 1)
		{
			flag = 0;
			HAL_UART_Transmit(&huart1,RxBuff,sizeof(RxBuff),1000);
			memset(RxBuff,0,sizeof(RxBuff));
		}
  }
  /* USER CODE END 3 */

it.c:

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) //接收完,空闲中断置位
{
		flag = 1;
	__HAL_UART_CLEAR_IDLEFLAG(&huart1);
}
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))
{
	RxBuff[Num++] = USART1 -> DR;
}

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */


  /* USER CODE END USART1_IRQn 1 */
}

 

 

针对STM32G4HAL库串口空闲中断接收不定数据的问题,可以按照以下步骤进行解决: 1. 开启串口空闲中断,即在初始化串口时,将USART_CR1_REG中的USART_CR1_IDLEIE位设置为1。 2. 在串口空闲中断中,通过读取USART_ISR_REG寄存器中的位USART_ISR_RXNE和USART_ISR_IDLE来判断是接收到数据还是空闲中断。 3. 如果是接收到数据,则读取USART_RDR_REG寄存器中的数据,并将其存储到缓冲区中。 4. 如果是空闲中断,则通过计算接收到的数据度来确定数据度,并将其存储到缓冲区中。 5. 在数据度达到预定度时,可以通过回调函数或者其他方式来通知数据接收已经完成。 下面是一个示例代码: ```c uint8_t rx_buffer[100]; uint8_t rx_counter = 0; uint8_t rx_length = 0; uint8_t rx_flag = 0; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USARTx) { if(rx_flag == 0) { //接收到数据 if((__HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE) != RESET) && (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) == RESET)) { rx_buffer[rx_counter++] = (uint8_t)(huart->Instance->RDR & 0x00FF); } //空闲中断 else if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET) { rx_length = rx_counter; rx_counter = 0; rx_flag = 1; } } } } ``` 在上面的代码中,当接收到数据时,将数据存储到缓冲区中,并将计数器rx_counter加1。当空闲中断发生时,计算接收到的数据度,并将其存储到rx_length中。在接收完成后,将rx_flag设置为1,表示数据接收已经完成。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值