小蜜蜂51单片机之串口通信的基本原理和应用+进阶应用

关键词:串口通信的基本原理;波特率;URAT;串口接收、发送数据;串口与中断

一、知识点

 1.单工、半双工、全双工;同步、异步;并行通信、串行通信

 2.波特率:含义;9600BPS对应参数

 3.UART的数据发送和接收:2个SBUF;无论数据发送还是接收,都会产生中断,若用中断查询,需要分清是发送还是接收

 4.异步8位UART并且允许接收:SCON=0x50

 5.查询方式和中断方式

6.MAX232芯片——计算机和单片机之间的电平转换

 详细参考:

【蓝桥杯单片机09】串行接口的基本原理与应用
https://bbs.21ic.com/icview-2478488-1-1.html?fromuser=
(出处: 21ic电子技术开发论坛)

二、实验

实验1:

实验目的:

所需部件:

1.串口通信初始化函数Init_Uart

2.串口的中断服务函数——用中断来查询单片机是否读成功

3.串口向上机位发送数据函数

4.main函数

实验步骤:

S1:辅助寄存器自定义(看开发板是否需要)

原因:

因为头文件中没有辅助寄存器AUXR的地址,而在串口通信的初始化中需要使AURX=0x00(只有AUXR第0位为0,串口才能正常收发数据),所以需要在前面进行自定义

sfr AUXR=0x8e;
S2:UART初始化函数
思路流程:

1.串口通信中需要利用定时器1产生波特率,采用8位自动重装10,而TMOD后四位管定时器0,所以不必管,可全部置为0——TMOD=0x20;

2.查数据手册知,采用8位自动重装(且产生9600BPS波特率)的重装值(TH0)为0xFD,自动重装中TL0=TH0,也为0xFD——TH0=0xfd; TL0=0xfd;

3.打开定时器1——TR1=1;

4.串口控制寄存器SCON一般固定——SCON=0x50

5.AUXR置0——AUXR=0x00;

6.打开串口中断开关——ES=1;EA=1;

代码:
void Init_Uart()
{
	TMOD=0x20;
	TH0=0xfd;
	TL0=0xfd;
	TR1=1;
	
	SCON=0x50;//串口控制寄存器,一般这个值是固定的
	AUXR=0x00;//上电后第0位可能不是0
	ES=1;
	EA=1;//打开串口的中断
}
S3: 用中断方式让串口接收上机位输来的数据(读)
思路流程:

1.判断是否读成功——if(RI==1)

2.如果读成功,就手动将RI清零,并设一个变量接收缓存寄存器SBUF中的数据——Urdat=SBUF;

3.单是执行上面2步,上机位看不到单片机是否接收到数据了,所以需要再将读到的字节发送到上机位,在串口助手中显示出来

4.用到串口向上机位发送数据函数,但定义在下面,会报错,有2种处理方法:①前面声明②将整个函数体挪到前面

代码:
unsigned char Urdat=0;
void ServiceUart() interrupt 4
{
	if(RI==1)
	{
		RI=0;
		Urdat=SBUF;
		SendByte(Urdat+1);
	}
}
S4:用查询方式让串口向上机位发送数据
思路:

1.发送的数据存在发送寄存器SBUF中——SBUF=dat;

2.检测是否发送成功数据,用空循环语句——while(TI==0);

3.手工清零发送成功标志位——TI=0;

代码:
void SendByte(unsigned char dat)
{
	SBUF=dat;
	while(TI==0);//直到发送完成后,TI=1,跳出空循环
	TI=0;//手工清零
}
S5:main函数完善
代码:
void main()
{
	Init_Uart();
	SendByte(0x5a);
	SendByte(0xa5);
	while(1)
	{
	
	}
}

完整代码:

#include <REGX52.H>

sfr AUXR=0x8e;//新增寄存器需要自定义,辅助寄存器
void SendByte(unsigned char dat);

void Init_Uart()
{
	TMOD=0x20;
	TH0=0xfd;
	TL0=0xfd;
	TR1=1;
	
	SCON=0x50;//串口控制寄存器,一般这个值是固定的
	AUXR=0x00;//上电后第0位可能不是0
	ES=1;
	EA=1;//打开串口的中断
}
//串口通信中需要利用定时器1产生波特率,采用8位自动重装10

unsigned char Urdat=0;
void ServiceUart() interrupt 4
{
	if(RI==1)
	{
		RI=0;
		Urdat=SBUF;
		SendByte(Urdat+1);
	}
}

void SendByte(unsigned char dat)
{
	SBUF=dat;
	while(TI==0);//直到发送完成后,TI=1,跳出空循环
	TI=0;//手工清零
}

void main()
{
	Init_Uart();
	SendByte(0x5a);
	SendByte(0xa5);
	while(1)
	{
	
	}
}

 实验2:

实验目的:

 实验2.1   通过串口向上位机发送字符串

大体和实验1相同,亮点在:

1.关闭蜂鸣器和继电器等设备,需要将HC573锁存器丰富完整(case0的增加)以及系统初始化函数,在main最开始调用
void Init_System()
{
	SelectHC573(5);//Ñ¡Ôñ·äÃùÆ÷ºÍ¼ÌµçÆ÷¶ÔÓ¦µÄY5ͨµÀ
	P0=0x00;//¹Ø±ÕʹÄܶË
	SelectHC573(4);//Ñ¡ÔñLED¶ÔÓ¦Y4ͨµÀ
	P0=0x00;
}
2. 发送字符串函数
思路:

①字符串用数组盛放,参数可用指针等价,表示数组的首地址。

②逐一发送数组中的字节(指针++,指针往下移,实现发送下一个字节)

③直到(while)碰到字符串的结束标志‘\0’

 代码:
void SendString(unsigned char *str)
{
	while(*str!='\0')
	{
		SendByte(*str++);
	}
}

 完整代码:

#include <REGX52.H>
sfr AUXR=0x8e;
void SendByte(unsigned char dat);

void SelectHC573(unsigned char channel)
{
	switch(channel)
	{
		case 4:P2=(P2&0x1f)|0x80;break;
		case 5:P2=(P2&0x1f)|0xA0;break;
		case 6:P2=(P2&0x1f)|0xC0;break;
		case 7:P2=(P2&0x1f)|0xE0;break;
		case 0:P2=(P2&0x1f)|0x00;break;//关闭锁存器所有开关
	}
}

void Init_System()
{
	SelectHC573(5);//选择蜂鸣器和继电器对应的Y5通道
	P0=0x00;//关闭使能端
	SelectHC573(4);//选择LED对应Y4通道
	P0=0x00;
}

//*************************串口通信相关
void Init_Uart()
{
	TMOD=0x20;
	TH0=0xfd;
	TL0=0xfd;
	SCON=0x50;
	AUXR=0x00;
	ES=1;
	EA=1;
	TR1=1;
}

unsigned char URdat=0;
void ServiceUart() interrupt 4
{
	if(RI==1)
	{
		
	}
}

void SendByte(unsigned char dat)
{
	SBUF=dat;
	while(TI==0);
	TI=0;
}

void SendString(unsigned char *str)
{
	while(*str!='\0')
	{
		SendByte(*str++);
	}
}
//***********************************

void main()
{
	Init_System();
	Init_Uart();
	SendString("Welcome to DPJ World!\r\n");//\r是回车,\n是换行
	while(1)
	{
	
	}
}

实验现象:

上电后,蜂鸣器、继电器关闭,串口助手中的接收框显示发送的字符串

实验2.2   上位机通过串口控制LED&上位机读取下位机运行状态

沿用实验2.1,亮点是:

1.单片机需要从上位机处接收到指令command,读判断
unsigned char command=0x00;
unsigned char URdat=0;
void ServiceUart() interrupt 4
{
	if(RI==1)
	{
		command=SBUF;
		RI=0;
	}
}
2.对指令进行分析,并控制LED(0表示开灯,1表示关灯)
思路:

①command初始化为0x00,如果接收到,则高四位一定不为0——以if(command!=0x00)为界

②case 0xc0:发送字符串+清零command(否则在while循环中不断扫描,会不断输出字符串)+break(其余几个case沿用大格式)

③case 0xa0:让P0保持高四位不变,低四位变成~command

(P0|0x0f)——>P0的高四位不变,低四位全部置1,L1-L4全灭

(~command|0xf0)——>0xf0使得低四位为~command的低四位,高四位全为1,这样之后&后,P0的高四位还是保持不变。~command是因为0表示开灯,1表示关灯,要进行取反才能让command生效

④case 0xb0:总体思路与0xa0相同,而0xf0等要变化,~command要左移四位,P0的高四位控制L5-L8;

 代码:
void working()
{
	if(command!=0x00)
	{   //command高四位如果接收到,不是A,就是B,C,只有判断接受到command才对其分析
		switch(command&0xf0)
		{
			case 0xa0:P0=(P0|0x0f)&(~command|0xf0);command=0x00;break;
			case 0xb0:P0=(P0|0xf0)&((~command<<4)|0x0f);command=0x00;break;
			case 0xc0:SendString("The system is running!\r\n");command=0x00;break;
		}
	}
}

三、总结收获

1.串口通信的基本原理与相关知识

2.串口与上机位之间的收、发数据函数

3.串口与中断函数

4.学会关闭蜂鸣器和继电器,上电后进行初始化

5.通过串口控制LED、输出字符串、让上机位检测下机位(eg.单片机)的运行状态

感谢B站小蜜蜂老师的教程,本笔记资料及代码均来自教程,仅作为个人复习、整理和学习交流用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值