正点原子STM32串口例程解析

       学习32,串口的使用很重要,特别是现在学的越多就觉得在很多方面通信才是主角,原子历程写的挺好,但是我看论坛里好像没怎么有这个的解析那就按自己的理解写写吧,希望能帮助到正在学习的同学。然后写在前面,初学者或者想深入学习一定要多看看参考手册。
       在主函中使用以下语句实现将接收到的数据发送出去:

if(USART_RX_STA&0x8000)
		{					   
			len=USART_RX_STA&0x3fff;
			printf("\r\n您发送的消息为:\r\n\r\n");
			for(t=0;t<len;t++)
			{
				USART_SendData(USART1, USART_RX_BUF[t]);
				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
			}

       首先USART_RX_STA是什么呢?在"usart.c"里面有说明这是个接收状态标记,它既指接收状态又表明接收到数据的位数,具体使用在下文的串口中断部分中进行说明解释。

u16 USART_RX_STA=0;       //接收状态标记

       USART_RX_STA的值在USART1_IRQHandler串口接收中断函数中被改变,这里USART_RX_STA&0x8000就是判断是否已经接收到了0x0a,0x0a是LF(line feed)换行的意思,光标到达下一行,也是判断数据接收结束的标志。
       提一下,中断中是以是否接收到0x0d 0x0a这两个数据,判断数据是否发送结束的。假如你发的数据没有回车(0x0d )、换行(0x0a)那么单片机是不会停止接收的(在PC中回车、换行使用回车按键就都包含了,感兴趣可以具体查查)。
       程序使用数组进行数据的存储,于是这段代码也就引出一个BUG,具体描述不会描述就简单说下,嘴笨是硬伤。
       比如我给单片机发送 0x01 0x02 0x03 0x04 0x05 0x06 0x0d,这时候程序还在运行继续等待接收,
                             再发送 0x07 0x08 0x0d 0x0a这时候接收结束,看看最后输出什么?
       导致这个BUG的原因就是数组存储了信息,知道出错但没有清除,只是提一下,注意一点就行,一般使用还是可以的。

if(Res==0x0d)USART_RX_STA|=0x4000;

这句话呢就是判断是否接收到回车(0x0d ),接收到了回车,那么让USART_RX_STA标志位第二位为1。

if(USART_RX_STA&0x4000)
{
if(Res!=0x0a)USART_RX_STA=0;
else USART_RX_STA|=0x8000;	
				}

这句话呢就是判断是否接收到换行(0x0a),如果收到换行并进行判断确认收到换行符那么让USART_RX_STA标志位最高位为1。不是很懂的话,那就看看后面的那个图。至此中断就差不多说明白了,要是还有其他问题,看看下面的注释,这里我是想说怎么进行的数据处理,毕竟我觉得这一块是个难点。

void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
	u8 Res;
         //中间变量,读取的数据进行保存
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
		//查看RXNE寄存器是否为空,以此判断是否有数据发送过来
		//接收中断(接收到的数据必须是0x0d 0x0a结尾)
		//这里判断发送接收完成的依据就是串口数据0x0d 0x0a,
		//0x0d是CR(carriage return)回车的意思,光标回到最左边,
		//0x0a是LF(line feed)换行的意思,光标到达下一行,
		//但是在PC上回车和换行是在一起的就是按下回车按键
		//当然可以更改程序使用其他进行判断例如使用0x2a也就是*进行结束判断
		{
		Res =USART_ReceiveData(USART1);//(USART1->DR);	
		//读取接收到的数据,存放到变量Res中
		if((USART_RX_STA&0x8000)==0)
			//判断接收是否未完成
			//接收完成未清除标志位,还是会不断进入到接收中断,所以使用标志进行判断,
		  	//当接收完成便不会跳入到判断,从而不执行任何指令,空等待
			//使用条件判断是否已经接收完数据,这里判断接收完的依据就是收到了0x0a;
			//具体判断在后面
			{
			if(USART_RX_STA&0x4000)
			//如果接收到了0x0d,那么再进一步执行是否接收到0x0a的判断
				{
				if(Res!=0x0a)USART_RX_STA=0;
			//没有接收到0x0a那么说明,数据未正确传输或者接收错误,重新开始判断,
			//但是这里没有将接收到的数据进行清空,也没有退出接收中断,此程序只是从头开始执行接收判断
				else USART_RX_STA|=0x8000;	
			//接收完成了,收到了0x0a那么标志位USART_RX_STA将会变成0x8000(使用或指令,只改变最高位),将不再进行数据检测与存储
				}
			else 
				//还没收到0X0D,说明数据还未发送结束继续进行数据的检测与存储
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				//收到了数据0x0d,标志位USART_RX_STA变成0x4000(使用或指令,只改变次高位)
				else
					{
				//如果没有接收到数据0x0d,执行判断是否存储数组已满,已满则重新开始接收
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
				//将接收到的数据写进数组,标志位USART_RX_STA与上0X3FFF清除前两位以防止标志位与8000和4000冲突
					USART_RX_STA++;
				//数组地址加一,向后排
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
				//接收数据错误,超出数组大小,又开始接收向数组重新写  
					}		 
				}
			}   		 
     } 

} 

       判断接收结束再判断此次接收数据的长度,USART_RX_STA也表明接收数据的位数,要想将接收到的数据全部发送出去就需要知道,一共接收到了几位然后一位一位的传出去,所以len=USART_RX_STA&0x3fff;就实现了将数据长度赋值给变量len,然后使用for循环依次将接收到的数据发送出去。这里也许会糊涂为什么是0x3fff呢?看下图能理解么?
       接收到0x0d ,USART_RX_STA的值变成0x4000,又接收到0x0a,USART_RX_STA的值变成0xC000那么很容易发现数据的的前两位是作为标志位了,所以用来记录其他数据位数就只有0x3fff。
正点原子STM32串口例程解析_第1张图片

if(USART_RX_STA&0x8000)
	//如果在串口接收中断中接收到0x0a,数据已接收完毕
		{					   
			len=USART_RX_STA&0x3fff;
	//得到此次接收到的数据长度,传给for循环,循环依次发出接收到的数据
			printf("\r\n您发送的消息为:\r\n\r\n");
			for(t=0;t<len;t++)
	//通过for循环依次将接收到的数据发送出去
			{
				USART_SendData(USART1, USART_RX_BUF[t]);
				//向串口1发送数据,USART_SendData是库函数控制DR寄存器
				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
				//等待发送结束,看TC寄存器的状态  TC:发送完成 (Transmission complete) 
			}

       差不多就是这样,不懂的可以评论,有错误也请指正。一般使用串口不是这么判断使用的,具体看有没有时间,有时间整理一份。过些时候将注释的文件上传以便下载阅读。

你可能感兴趣的:(STM32,stm32,串口通信)