USART空闲中断发送一帧完整的数据包(适合新手学习)

USART发送一帧完整的数据包

项目描述:

用一块STM32F103C8T6核心板(作为发送板)ADC采集来自手柄的电压信号,然后将数据发送给另一块STM32F103C8T6核心板(作为接收板)。最终,接收板在上位机(电脑)上打印出发送板采集到的电压信号。

硬件:

两块STM32F103C8T6核心
上位机(电脑)
摇杆(工具人,提供个电压信号)

发送板程序

int main()
{
    
    
	u16 valuex=0;
	u16 valuey=0;
	u8 a[4];
	float volx,voly;
	int i;
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	USART1_Init(9600);
	ADCx_Init();
	while(1)
	{
    
    
		valuex=Get_ADC_Value(ADC_Channel_1,10);
		valuey=Get_ADC_Value(ADC_Channel_2,10);
		a[0]=valuex;
		a[1]=valuex>>8;
		a[2]=valuey;
		a[3]=valuey>>8;
		for(i=0;i<4;i++)
		{
    
    
			USART_SendData(USART1,a[i]);
			while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
		}
			delay_ms(500);
	}
}

由于USART_SendData函数只能发送8位,所以说我们的两个u16的数据需要各自发送第八位和高八位数据,总共四个数据。如果是四个数据,一个一个的发,就会很慢,而且也无法判断这四个数据的先后顺序,导致接收板根本无法使用。
所以要发送一帧数据。发送一帧数据的有点就是很快,因为连续发四个数据只产生一次中断,四个数据之后才需要delay。而如果一个数据一个数据的发,要产生4次中断,要有4个delay,在对收发数据的速度有要求的场景下必须这样发送一整帧数据。发送一帧数据的方法有很多,现在介绍的是用空闲中断法,比较适合新手入门使用。

容易忽略的点:

for(i=0;i<4;i++)
		{
    
    
			USART_SendData(USART1,a[i]);
			while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
		}

这里的while不可省,这句是等待上一次发送完成再发送下一个数据。如果没有这句,就无法达到每次发四个数据,发完四个数据再delay一下的效果了。

while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

接收版程序

接收板的程序主要就是配置空闲中断,以及将数据printf出来。

u8 a[4]={
    
    0,0,0,0};
int j=0;
u16 temp,valuex,valuey;
float x,y;
void USART1_IRQHandler(void)  
{
    
    
	u8 clear=clear;
	USART_ClearFlag(USART1,USART_FLAG_TC);
		if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
		{
    
    
		a[j++]=USART1->DR;	
		}
	else if (USART_GetFlagStatus(USART1,USART_FLAG_IDLE)!=RESET)
	{
    
    
		clear=USART1->SR;
		clear=USART1->DR;
		valuex=a[0]+a[1]*256;
		x=(float)valuex*(3.3/4096);
		valuey=a[2]+a[3]*256;
		y=(float)valuey*(3.3/4096);
		printf("volx: %.2f\r\n",x);
		printf("voly: %.2f\r\n",y);
		j=0;
	}
}
接收中断:
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
		{
    
    
		a[j++]=USART1->DR;	
		}

这里a[j++]=USART1->DR; 就是把接收数据寄存器中的数据存进数组里,在这个过程结束的同时USART_IT_RXNE标志位也会reset(应该是硬件自动reset的),等待下一个数据发来。
a[j++]=USART1->DR;和a[j++]=USART_ReceiveData函数几乎是一样的,因为USART_ReceiveData函数里边主要就是“a[j++]=USART1->DR;”这一句。

空闲中断:
else if (USART_GetFlagStatus(USART1,USART_FLAG_IDLE)!=RESET)
	{
    
    
		clear=USART1->SR;
		clear=USART1->DR;
		valuex=a[0]+a[1]*256;
		x=(float)valuex*(3.3/4096);
		valuey=a[2]+a[3]*256;
		y=(float)valuey*(3.3/4096);
		printf("volx: %.2f\r\n",x);
		printf("voly: %.2f\r\n",y);
		j=0;
	}
}

用clear去先后读取SR(状态寄存器),DR(数据寄存器)这一步的作用是重置空闲中断的标志位。然后下面是,我们直接在这个空闲中断中进行了数据的处理,发送。
定义clear变量的时候,使用了clear=claer的作用是,防止编译时出warning,提示我们clear变量没有使用。

数据处理:

高八位乘256+第八位就可以复原数据。
*3.3/4096是因为我收集到的电压的范围是0~3.3V,这是处理ADC采集到的数据。

容易出错的地方:

不要忘记使能空闲中断!!!要在初始化函数中加上这一句

USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); 

另外注意:不要在中断函数的其它位置处理数据,因为处理数据需要时间,可能处理数据的过程中就会丢掉正在发来的下一个数据,导致整个接收过程都出问题。可以自己再写一个数据处理和发送的函数,或者就在空闲中断里处理,发送数据,因为我们主函数delay了10ms,时间足够。

工程文件压缩包已上传,可免费下载!

猜你喜欢

转载自blog.csdn.net/Rendezvous1/article/details/108050075
今日推荐