蓝桥杯,嵌入式,物联网,串口接收中断加空闲中断,最简单实用的方法

目录

文章目录

前言

一、串口的空闲中断?

二、使用步骤

1.打开串口中断(空闲中断加接受中断)

2.中断服务函数

总结


前言

之所以写这篇文章,是因为参加蓝桥杯的时候发现HAL库的串口很难用,以至于串口总是接收都有问题。这篇文章还适合刚刚使用HAL库,回调函数用不习惯的同学,本文章以物联网L071为例来写,嵌入式G431也同样适用。

一、串口的空闲中断

当使用串口接受数据的时候,你会发现不知道数据什么时间结束,网上也有一种方法教大家接受定长数据的教程,另一种方法就是在数据的后面加上结束位,这样就可以知道数据什么时间结束,从而去处理数据。这两种方法都有局限性,那什么样的方法更好呢?其实STM已经给了我们答案了,就是串口的空闲中断,这里先引用官方对串口空闲中断的解释:

此位由检测到空闲线路时硬件设置。如果出现以下情况,则生成中断
USART_CR1寄存器中的 IDLEIE=1。它由软件清除,将 1 写入 IDLECF
USART_ICR寄存器。
0:未检测到空闲线路
1:检测到空闲线路
注意:在设置 RXNE 位之前,不会再次设置空闲位(即新的空闲行)
发生)。
如果启用了静音模式 (MME=1),则在 USART 未静音 (RWU=0) 时设置空闲,
无论唤醒位选择何种静音模式。如果 RWU=1,则不设置空闲。

以上就是手册中对IDLE的解释,直白点来讲就是,当串口接受到数据后,它会自动检测后面还有没有数据,如果没有数据了,IDLE就置位,表示一帧数据接受完毕,它是在接受中断之后才置位的,如果没有接受的数据,空闲时它是不会置位的。

二、使用步骤

1.打开串口中断(空闲中断加接受中断)

在CubeMX中只需要将串口模式设置为Asynchronous,其他不用动打开串口中断 就可以了。

 生成工程后在min()函数中添加打开串口中断的函数

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

  __HAL_UART_CLEAR_IDLEFLAG(&huart2);         //清除串口空闲中断
	__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);  //打开串口空闲中断
	__HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE);  //打开串口接受中断

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

一定要先清除串口空闲中断,然后在打开串口空闲中断,因为串口初始化完成后会自动将IDLE置位,导致还没有接受数据就进入到中断里面去了,所以打开IDLE之前,先把它清楚掉。 

2.中断服务函数

在中断服务函数中添加处理空闲中断的函数。

void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */

  /* USER CODE END USART2_IRQn 0 */
//  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */
  if(__HAL_UART_GET_IT(&huart2,UART_IT_IDLE) !=RESET) {
		ucTemp = 1;
	__HAL_UART_CLEAR_IDLEFLAG(&huart2);
	}
	if(__HAL_UART_GET_IT(&huart2,UART_IT_RXNE) !=RESET) {
		ucRxBuff[ucNum++] = USART2->RDR;
	}
  /* USER CODE END USART2_IRQn 1 */
}

把串口中断函数中自动调用的函数注释掉,因为它每次调用完回调函数后都会关闭中断。(不使用回调函数,可以的提高串口接受的处理速度)当ucTemp置位时,代表数据接受完毕,然后清除空闲中断,下面是接受中断,接受中断不用清除。

在while(1)中处理接收到的数据

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(ucTemp == 1) {
			ucTemp = 0;    //清除标志位
			printf("%s\r\n",ucRxBuff);  //串口回显
			memset(ucRxBuff,0,20);    //清除缓冲区
			ucNum = 0;    //清除缓冲区指针
		}
  }
  /* USER CODE END 3 */

printf的重定向,同时keil中的USE Microlib打上勾

int fputc(int ch,FILE*f)
{
	HAL_UART_Transmit(&huart2,(uint8_t *)&ch,1,10);
	while(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_TXE) == RESET);
	return ch;
}


总结

如果有同学发现这样写还不能用,可以在串口初始化下面加上HAL_DELY(10),延迟一下,能用的同学可以略过,以上串口暂时在使用中没有发现什么问题,如果以上串口大家在使用中有什么问题,欢迎大家在下面留言,我们一起进步。

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值