51单片机串口通信详解,以代码为例子(个人见解)

写此文章是为了梳理自己对串口的认识(做笔记),也是想看看自己有没有什么地方理解不到位,欢迎指正,谢谢!

首先先上一串代码

#include<reg52.h>
#include<intrins.h>

#define uchar unsigned char
#define uint  unsigned int
//sbit BEEP=P2^5;
sbit IN1=P1^4;
sbit IN2=P1^5;
sbit IN3=P1^6;
sbit IN4=P1^7;
sbit led1=P2^1;
sbit led2=P2^2;

//sbit RCK=P3^5;	
//sbit SCK=P3^6;	
//sbit SER=P3^4;
//sbit LEDLEFTGO=P3^3;
//sbit LEDLEFT=P3^1;
//sbit LEDRIGHT=P3^0;
//sbit LEDRIGHTGO=P1^3;
//sbit LEDBACK=P1^2;
unsigned char num;
uchar PuZh[2] = "收到";

//--声明全局函数--//   
void UsartConfiguration();
void Delay_1ms(uint i);

void stop()
	         {   
				IN1=0;
				IN2=0;
				IN3=0;
				IN4=0;
//				LEDLEFT=0;
//				LEDRIGHT=0;
//				LEDLEFTGO=1;
//				LEDRIGHTGO=1;
//				LEDBACK=1;
//				
	
				}
void go()
			{      	
				IN1=1;
				IN2=0;
				IN3=1;
				IN4=0;		
//				LEDLEFTGO=0;
//				LEDRIGHTGO=0;
//				LEDLEFT=1;
//				LEDRIGHT=1;
//				LEDBACK=1;
			}
void back()
			{
				
				IN1=0;	
				IN2=1;	
				IN3=0;	
				IN4=1;
//				LEDLEFT=1;
//				LEDRIGHT=1;
//				LEDLEFTGO=1;
//				LEDRIGHTGO=1;
//				LEDBACK=0;			
			}
void left()//左
			{ 			
				IN1=0;	
				IN2=0;
				IN3=1;	
				IN4=0;
//				LEDLEFT=0;
//				LEDRIGHT=1;
//				LEDLEFTGO=1;
//				LEDRIGHTGO=1;
//				LEDBACK=1;
			}	
void right()
			{					
				IN1=1;
				IN2=0;	
				IN3=0;
				IN4=0;
//				LEDRIGHT=0;
//				LEDLEFT=1;
//				LEDLEFTGO=1;
//				LEDRIGHTGO=1;
//				LEDBACK=1;
			}	
void leftgo()
{

				IN1=0;
				IN2=0;	
				IN3=1;
				IN4=0;
//				LEDRIGHT=1;
//				LEDLEFT=0;
//				LEDLEFTGO=1;
//				LEDRIGHTGO=1;
//				LEDBACK=1;
}
void rightgo()
{

				IN1=1;
				IN2=0;	
				IN3=0;
				IN4=0;
//				LEDRIGHT=0;
//				LEDLEFT=1;
//				LEDLEFTGO=1;
//				LEDRIGHTGO=1;
//				LEDBACK=1;
}
void leftback()
{

				IN1=0;
				IN2=0;	
				IN3=0;
				IN4=1;
//				LEDRIGHT=1;
//				LEDLEFT=1;
//				LEDLEFTGO=1;
//				LEDRIGHTGO=1;
//				LEDBACK=0;
}
void rightback()
{
    led2=1;
	led1=0;
//				IN1=0;
//				IN2=1;	
//				IN3=0;
//				IN4=0;
//				LEDRIGHT=0;
//				LEDLEFT=1;
//				LEDLEFTGO=1;
//				LEDRIGHTGO=1;
//				LEDBACK=1;
}
void Com_Int(void) interrupt 4
{
	uchar i;
  uchar receive_data;
	
  EA = 0;
	
  if(RI == 1) //当硬件接收到一个数据时,RI会置位,进入中断
	{ 		
		RI = 0;
		receive_data = SBUF;//接收到的数据			
//		switch(receive_data)
//					{
//						case 8:{go();}break;// 2num=1;
//						case 2:{back(); }break;//8num=2;
//						case 4:{left(); }break;//4num=3;
//						case 6:{right();}break;//6num=4; 
//						case 5:{stop(); }break;//5num=0;
//						case 9:{rightgo();}break;//3num=4
//						case 7:{leftgo();}break;//1num=3;
//						case 1:{leftback();}break;//7num=3;
//						case 3:{rightback();}break;//9num=4;
//						default :break;					
//					}			
		if(receive_data == '8')	 
		{
				go();
		}
		if(receive_data == '2')	 
		{
				back();
		}if(receive_data == '4')	 
		{
				left();
		}if(receive_data == '6')	 
		{
				right();
		}if(receive_data == '5')	 
		{
				stop();
		}if(receive_data == '9')	 
		{
				rightgo();
		}if(receive_data == '7')	 
		{
				leftgo();
		}if(receive_data == '1')	 
		{
				leftback();
		}if(receive_data == '3')	 
		{
				rightback();
		}
		
		for(i=0; i<2; i++)
		{
			SBUF = PuZh[i];   //将要发送的数据放入到发送寄存器
			while(!TI);		    //等待发送数据完成,T1=0的时候才成立,硬件置1,发送中断请求标志位
			TI=0;			        //清除发送完成标志位
			Delay_1ms(1);
		}
		EA = 1;
}
}
void main()
{

	UsartConfiguration();//初始化串口
	
	while(1);	
}
	
void UsartConfiguration()
{	
	SCON=0X50;			//设置为工作方式1,8位数据,可变波特率
	TMOD=0X20;			//设置计数器工作方式2
	PCON=0X00;			//波特率不加倍
	TH1=0XFd;		//计数器初始值设置,9600@11.0592MHz
	TL1=0XFd;
	TR1=1;			//打开计数器
	ES = 1;         //开串口中断
    EA = 1;         //开总中断
}
void Delay_1ms(uint i)//1ms延时
{
  uchar x,j;
  
  for(j=0;j<i;j++)
    for(x=0;x<=148;x++);
}

关键的就是中断里面的代码和main函数里面的代码

1.串口进入中断的条件:收到数据;正确的初始化(EA,ES,波特率等等)

ps:当收到数据的时候,RXD逐位收到发送10位字符帧并经过一系列处理后,RI被硬件置1,这就是为什么在中断函数里面有用到if RI==1,意思就是收到数据了,进入中断了(RI置1了)程序继续向下执行,然后接下来就可以自己写程序,让单片机干你发送了什么数据之后该干的事,就比如我上面的程序,我用的是蓝牙串口,我在手机是发送一个”8”,单片机执行前进。

         SBUF = PuZh[i];  
            while(!TI);         
            TI=0;                    
            Delay_1ms(1);

这个代码的意思就是如果T1=0就代表单片机还没向我们的手机反馈它收到了,这时候进入死循环,等待一会单片机,如果单片机反馈它收到数据了("收到"),TI就被硬件自动置1,这时候就跳出死循环,TI我们手动置0,确保后面进入中断可以顺利进行,毕竟你不可能只发送一个数据。

主函数里的内容就是串口的初始化,然后死循环防止程序直接结束(想进中断都进不了)。

总结:上面的代码(串口通信)的意思就是,主函数初始化,死循环防止程序结束,等待收到数据进入中断执行想执行的东西。

为什么要用中断呢?

:发送数据不是固定的是随机的,利用中断可以提高CPU的使用效率,等到收到数据的时候才让CPU去干收到数据的时候它该干的事,在没有数据的时候单片机还可以先用CPU去干main涵数里的代码。

 

其实收到数据完成你想干的事的代码并非一定要全放在中断里,例如:


void main()
{
 
	u8 i;
	Tim1_Init();
	Serial_Init();
	Serial_Interrupt_Init();	
	while(1)
	{
		if(flag==1)
		{
			//发送字符串
			for(i=0;i<6;i++)
			{
				SBUF=table[i];
				//等待发送发送完成
				while(!TI);
				//清除标志位
				TI=0;
			}
			//发送接收到字符
			SBUF=a;
			while(!TI);
			TI=0;
			flag=0;
		}
	 delay(1000);
	}
}
void Serial_Interrupt_Init()
{
	//打开串口中断
	ES=1;
	//打开总中断
	EA=1;
}
//中断服务函数,串口中断后会自动跳到这里
void Serial_Interrupt() interrupt 4
{
	//清除标志位
	RI=0;
	//将接收到的数据位记录到a中
	a=SBUF;
	flag=1;
}

!!不用太在意代码的内容,只是用来举个例子

像上面的这个代码就是把想干的放在了主函数里,然而中断就是用来把收到的数据存在了a里,如后设置fiag以便主函数里面的程序可以在收到数据之后进行用if语句。两种方法其实本质都是一样的就是收到数据跳中断,收到的数据在SBUF里。

 

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Flamingo۶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值