STM32串口通信的 USART_ClearFlag(USART1,USART_FLAG_TC); 添加后程序出现bug;( USART_ClearFlag(USART_TypeDef* USART)

引言:串口通信是一种很重要的通信方式,我在在平时制作项目的时候经常会使用到串口通信,有时候因为很多模块需要使用串口通信来实现和MCU的通信和数据传输,有时候在调试程序的时候需要用到串口使用printf()的重定向来对程序运行进行监视和调试,最近我在制作一个小项目的时候就遇见了一个问题,就是在串口中断函数中,当向上位机发送一个数据之后,如果此时调用库函数USART_ClearFlag(USART1,USART_FLAG_TC); 就会发现程序莫名其妙的发生故障,但是将这一句去掉之后程序就可以正常运行了,对于一个具有强迫症的我的说,就很无语也很不理解很想知道为什么会这个样子,接下来我们就来讨论一下串口中断中要不要添加USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG); 

一、拓展了解:

        USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG); 作用是清除相应的标志位,函数入口参数有两个,USART_TypeDef* USARTx和uint16_t USART_FLAG;

        USART_TypeDef* USARTx: 是对应的串口号,比如这里是串口1,就写USATR1;(注意:串口四在STM32F103里是UART4,少了一个‘S’,具体怎么表示可以右键,go to difinition 进行查看;

        uint16_t USART_FLAG:是清楚的标志位,有接受标志位、发送标志位等等,结合使用情况,同样右键+go to difinition 进行查看;

 二、问题所在

        之所以会有这样的问题,是因为在初学STM321系列开发板教程中所教的是在使用串口发送函数之后,需要调用标志位清楚函数将发送中断标志位清除,如下:

         在理论学习中这样的方式是没有任何问题出现的,但是在实际项目中串口交换的数据就不是那么简单的单一数据的接收和数据发送了,数据量非常大。可是此时,当我按照上图例程里面的思路写好了串口中断函数,发现程序会出现运行的bug,会莫名的卡死!!

        就在百思不得其解的时候我发现当我把USART_ClearFlag(USART1,USART_FLAG_TC)这一句去掉就可以正常运行程序了。下面是教学视频里的串口中断函数和例程里的中断函数对比:

        例程中使用了USART_ClearFlag(USART1,USART_FLAG_TC);并且程序正常运行:

         实际中需要这样处理,不能调用USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);否则程序混乱:(最后一行的注解表示不能添加的语句)

u8 RX_STA_DEMO;							//接受标志位,第一个握手信号标志位0x80,第二个0x08
u8 RX_BUF_DEMO[USART_RX_LEN];			//数据存放数组,0x5a,0x5a为握手信号
void USART1_IRQHandler(void)            //串口1中断服务程序
{
	u8 data_one=0;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		data_one = USART_ReceiveData(USART1);		//接收数据	
		if((RX_STA_DEMO & 0x80) !=SET)				//没有接受完成数据则开始处理接收
		{
			if((RX_STA_DEMO & 0x40))				//  是否接收到倒数第二个握手信号0x0d
			{
				if(data_one == 0x0a)				//  这一次是不是最后一个握手信号0x0a
				{	
					RX_STA_DEMO |= 0x80;			//    是则标志位置1表示接收完成一组数据
				}
				else 								//  握手信号是错误的则数据错误
					RX_STA_DEMO &= 0x00;			//    错误数据便清除标志位	
			}
			else if(data_one == 0x0d)				//判断数据是不是倒数第二个握手信号0x0d
			{
				RX_STA_DEMO |= 0x40;				//  是就第二个握手信号标志位置一
			}
			else
			{
				RX_BUF_DEMO[RX_STA_DEMO & 0x3F]=data_one;	//不是握手信号则接收数据存放到BUF
				RX_STA_DEMO++;								//统计接收数据的个数
				if(RX_STA_DEMO>USART_RX_LEN-1)RX_STA_DEMO=0;//超过最大数据,清零重新接收
			}
		}
		USART_SendData(USART1,data_one);
		while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
	}
//	USART_ClearFlag(USART1,USART_FLAG_TC);			//不能加上这句!!!
} 

三、总结

        在参阅了其他各大STM32开发板教程,并结合实际使用情况后,最终得出结论: 在使用串口中断函数处理数据时,不用调用函数 USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG) 清除发送完成标志位,否则程序可能会发生异常混乱!

注:以上是我个人在项目中遇到的情况和总结,如果大家有什么问题或者了解具体原因的希望能在评论区留下指导建议,非常感谢!

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
void usart_init(uint32_t baudrate) { /*UART 初始化设置*/ g_uart1_handle.Instance = USART_UX; /* USART_UX */ g_uart1_handle.Init.BaudRate = baudrate; /* 波特率 */ g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */ g_uart1_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */ g_uart1_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */ g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */ g_uart1_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */ HAL_UART_Init(&g_uart1_handle); /* HAL_UART_Init()会使能UART1 */ /* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */ HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE); } void HAL_UART_MspInit(UART_HandleTypeDef *huart) { GPIO_InitTypeDef gpio_init_struct; if (huart->Instance == USART_UX) /* 如果是串口1,进行串口1 MSP初始化 */ { USART_TX_GPIO_CLK_ENABLE(); /* 使能串口TX脚时钟 */ USART_RX_GPIO_CLK_ENABLE();/* 使能串口RX脚时钟 */ USART_UX_CLK_ENABLE(); /* 使能串口时钟 */ gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* 串口发送引脚号 */ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* IO速度设置为高速 */ HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* 串口RX脚 模式设置 */ gpio_init_struct.Mode = GPIO_MODE_AF_INPUT; HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 串口RX脚 必须设置成输入模式 */ #if USART_EN_RX HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART1中断通道 */ HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 组2,最低优先级:抢占优先级3,子优先级3 */ #endif }
05-17
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值