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 进行查看;

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

 二、问题所在

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

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

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

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

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

         实际中需要这样处理,不能调用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) 清除发送完成标志位,否则程序可能会发生异常混乱!

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

你可能感兴趣的:(stm32,arm,嵌入式硬件)