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 */
}

 

 

作者:Stwie Su

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 HAL库:利用空闲中断实现不定长数据接收详解

发表回复