写此文章是为了梳理自己对串口的认识(做笔记),也是想看看自己有没有什么地方理解不到位,欢迎指正,谢谢!
首先先上一串代码
#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里。