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,时间足够。
工程文件压缩包已上传,可免费下载!