51单片机Proteus仿真+Keil工程-实验5-单片机串行口中断实验

实验5-单片机单片机串行口中断实验

  之前做的一次实验,51单片机串行口中断实验,感觉不够完美,待改进。如有问题欢迎指正。

实验目的:

  掌握串行口的工作方式;掌握不同串行口工作方式下的通讯方法。

实验目标:

  放置两个单片机,通过串行口线的互连,应用方式1和方式3,同时设计发送和接受程序,完成两个方式的应用,将发送和接收的内容在虚拟串口中显示。

实验环境:

   MDK-ARM V5.21a、Proteus 8.6

Proteus原理图

   方式1:
在这里插入图片描述
   方式3:
在这里插入图片描述

选择元器件:

DEVICES说明
AT89C51MCU
BUTTON按键
CAP普通电容
CAP-ELEC电解电容
CRYSTAL晶振
RES电阻
RESPACK-8排阻

  51单片机的P0口做IO口使用时是漏极开路输出,其引脚一般需要在片外接一定阻值的上拉电阻,此时端口不存在高阻抗的悬浮状态,因此它是一个准双向口。同时,P0口每一位的驱动能力是P1~P3口的两倍,每位可以驱动8个LSTTL(Low-power Schottky TTL,即低功耗肖特基TTL)输入,89C51等单片机任何一个端口想要获得较大的驱动能力,必须采用低电平输出。
  时钟晶体振荡频率为 f o s c = 11.0592 M H Z f_{osc}=11.0592MHZ fosc=11.0592MHZ
  时钟周期相当于 T o s c = 1 f o s c ≈ 90.42 n s T_{osc}=\frac{1}{f_{osc}} \approx 90.42ns Tosc=fosc190.42ns
  复位电路的话通过给89C51等单片机的复位引脚RST加上大于2个机器周期的高电平(即24个时钟振荡周期)就可以使单片机复位。

KEIL工程:

方式1:
  1.甲乙两机以方式1进行串行通信,双方晶体振荡器频率均为11.0592MHz,波特率为2400bit/s。甲机的TXD脚、RXD脚分别与乙机的RXD、TXD脚相连。
  2.为观察串行口传输的数据,电路中添加了两个虚拟终端来分别显示串行口发出的数据。添加虚拟终端,只需单击Proteus左侧工具箱中的虚拟仪器图标图,在预览窗口中显示的各种虚拟仪器选项,单击“VIRTUAL TERMINAL"项,并放置在原理图编辑窗口,然后把虚拟终端的“RXD”端与单片机的“TXD”端相连即可。
  3.当串行通信开始时,甲机首先发送数据AAH,乙机收到后应答BBH,表示同意接收。甲机收到BBH后,即可发送数据。如果乙机发现数据出错,就向甲机发送FFH,甲机收到FFH后,重新发送数据给乙机。
  4.选择定时器TI为方式2定时,波特率不倍增,即SMOD=0,经过计算: 2 S M O D 32 × 11.0592 M 12 = 2400 × ( 256 − X ) ( 其 中 S M O D = 0 ) , X = 244 D = F 4 H \frac{2^{SMOD}}{32}×\frac{11.0592M}{12}=2400×(256-X)(其中SMOD=0),X=244D=F4H 322SMOD×1211.0592M=2400×256X(SMOD=0),X=244D=F4H,可得写入T1的初值应为F4H。
  5.以下双机通信程序,该程序可以在甲乙两机中运行,不同的是在程序运行之前,要人为地设置TR。若选择TR=0,表示该机为发送方;若TR=1,表示该机是接收方。程序根据TR设置,利用发送函数send( )和接收丽数receive( )分别实现发送和接收功能。

  甲机串口通信程序:

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define TR 0					//接收发送的区别值,TR=0为发送
uchar buf[10]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a};//发送的10个数据
uchar sum;
void delay(uint i);
void init();
void send(void);	//甲机发送函数
void receive(void);	//甲机接收函数

void main(void)
{
	init();
	if(TR==0)//TR=0为发送
	{send();}
	if(TR==1)//TR=1为接收
	{receive();}
}
void delay(uint i)
{
	uchar j;
	for(;i>0;i--)
		for(j=0;j<125;j++);
}
void init()
{
	TMOD=0x20;	//T1的方式2定时
	TH1=0xf4;	//波特率为2400
	TL1=0xf4;
	PCON=0x00;	//SMOD=0
	SCON=0x50;	//串行口方式1,REN=1允许接收
	
	TR1=1;		//启动定时器T1
}
void send(void)//甲机发送函数
{
	uchar i;
	do{
		delay(1000);
		SBUF=0xaa;			//发送联络信号
		while(TI==0);		//等待数据发送完毕
		TI=0;
		while(RI==0);
		RI=0;				//等待乙机应答
	}while(SBUF!=0xbb);		//乙机未准备好继续联络
	do{
		sum=0;				//校验和变量清零
		for(i=0;i<10;i++)
		{
			delay(1000);
			SBUF=buf[i];
			sum+=buf[i];	//求校验和
			while(TI==0);
			TI=0;
		}
		delay(1000);
		SBUF=sum;			//发送校验和
		while(TI==0);TI=0;
		while(RI==0);RI=0;
	}while(SBUF!=0x00);		//出错,重新发送
	while(1);
}
void receive(void)
{
	uchar i;
	RI=0;
	while(RI==0); RI=0;
	while(SBUF!=0xaa);		//判断甲机是否发出请求
	SBUF=0xbb;				//发送应答信号BBH
	while(TI==0);			//等待发送结束
	TI=0;
	sum=0;
	for(i=0;i<10;i++)
	{
		while(RI==0);RI=0;	//接收校验和
		buf[i]=SBUF;		//接收一个数据
		sum+=buf[i];		//求校验和
	}
	while(RI==0);
	RI=0;					//接收甲机的校验和
	if(SBUF==sum)			//比较校验和
	{
		SBUF=0x00;			//校验和相等,则发送00h
	}
	else
	{
		SBUF=0xFF;			//出错发送FFH,重新接收
		while(TI==0);TI=0;
	}
}

  乙机串口通信程序:

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define TR 1					//接收发送的区别值,TR=1为接收
uchar idata buf[10];//={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a};//发送的10个数据
uchar sum;
void delay(uint i);
void init();
void send(void);			//乙机发送函数
void receive(void);			//乙机接收函数

void main(void)
{
	init();
	if(TR==0)				//TR=0为发送
	{	
		send();				//调用发送函数
	}
	else
	{
		receive();			//调用接收函数
	}
}
void delay(uint i)
{
	uchar j;
	for(;i>0;i--)
		for(j=0;j<125;j++);
}
void init()
{
	TMOD=0x20;				//T1的方式2定时
	TH1=0xf4;				//波特率为2400
	TL1=0xf4;
	PCON=0x00;				//SMOD=0
	SCON=0x50;				//串行口方式1,REN=1允许接收
	TR1=1;					//启动定时器T1
}
void send(void)//乙机发送函数
{
	uchar i;
	do{
							//delay(1000);
		SBUF=0xaa;			//发送联络信号
		while(TI==0);TI=0;	//等待数据发送完毕
		while(RI==0);RI=0;	//等待乙机应答
	}while(SBUF!=0xbb);		//乙机未准备好,继续联络
	do{
		sum=0;				//校验和变量清零
		for(i=0;i<10;i++)
		{
			//delay(1000);
			SBUF=buf[i];
			sum+=buf[i];	//求校验和
			while(TI==0);
			TI=0;
		}
		//delay(1000);
		SBUF=sum;			//发送校验和
		while(TI==0);TI=0;
		while(RI==0);RI=0;
	}while(SBUF!=0);		//出错,重新发送
}
void receive(void)			//乙机接收函数
{
	uchar i;
	RI=0;
	while(RI==0); RI=0;
	while(SBUF!=0xaa)		//判断甲机是否发出请求
	{
		SBUF=0xff;
		while(TI!=1);TI=0;
		delay(1000);
	}
	SBUF=0xbb;				//发送应答信号BBH
	while(TI==0);			//等待发送结束
	TI=0;
	sum=0;					//清校验和
	for(i=0;i<10;i++)
	{
		while(RI==0);RI=0;	//接收校验和
		buf[i]=SBUF;		//接收一个数据
		sum+=buf[i];		//求校验和
	}
	while(RI==0);
	RI=0;					//接收甲机的校验和
	if(SBUF==sum)			//比较校验和
	{
		SBUF=0x00;			//校验和相等,则发送00h
	}
	else
	{
		SBUF=0xFF;			//出错发送FFH,重新接收
		while(TI==0);TI=0;
	}
}

方式3:
  先比较方式2与方式1,有两点不同之处:
  1. 方式2接收/发送11位信息,第0位为起始位,第1~8位为数据位,第9位是程控位,由用户设置的TB8位决定,第10位是停止位1,这是方式2与方式1的一个不同点。
  2. 方式2的波特率变化范围比方式1小,方式2的波特率=振荡器频率/n。
  当SMOD=0时,n=64。
  当SMOD=1时,n=32。
  而方式3和方式2相比,除了波特率的差别外,其他都相同。
  甲机串口通信程序:

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define TR 0					//接收发送的区别值,TR=0为发送
sbit p=PSW^0;					//p位定义为PSW寄存器的第0位,即奇偶校验位
uchar buf[10]="I LOVE YOU";//{0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//发送的8个数据
void delay(void);
void init();
void send(uchar dat);	//甲机发送函数
void receive(void);		//甲机接收函数

void main(void)
{
	uchar i;
	init();
	if(TR==0)		//TR=0为发送
	{
		while(1)
		{
			for(i=0;i<8;i++)
			{
				send(buf[i]);
				delay();//大概200ms发送一次数据
			}
		}
	}
	if(TR==1)		//TR=1为接收
	{
		receive();
	}
}
void send(uchar dat)
{
	TB8=P;
	SBUF=dat;
	while(TI==0);
	;
	TI=0;	
}
	
void init()
{
//	TMOD=0x20;	//T1的方式2定时-方式2
//	SCON=0x90;	//串行口方式2,REN=1允许接收
//	PCON=0x00;	//SMOD=0
//	
//	TH1=0xfd;	//波特率为9600
//	TL1=0xfd;
//	TR1=1;		//启动定时器T1
	
	//Success
	TMOD=0x20;	//T1的方式2定时-方式2
	SCON=0xc0;	//串行口方式3,REN=1允许接收
	PCON=0x00;	//SMOD=0
	
	TH1=0xfd;	//波特率为9600
	TL1=0xfd;
	TR1=1;		//启动定时器T1
	REN=1;
}

void delay(void)
{
	uchar m,n;
	for(m=0;m<250;m++)
		for(n=0;n<125;n++);
}

  乙机串口通信程序:

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define TR 1					//接收发送的区别值,TR=1为接收
sbit p=PSW^0;					//p位定义为PSW寄存器的第0位,即奇偶校验位
uchar idata buf[10];//={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a};//发送的10个数据
void delay(void);
void init();
void send(void);			//乙机发送函数
uchar receive(void);		//乙机接收函数

void main(void)
{
	init();
	if(TR==0)				//TR=0为发送
	{	
		//send();				//调用发送函数
	}
	else
	{
		while(1)
		{
			P1=receive();			//调用接收函数
		}
		
	}
}

void init()
{
//	TMOD=0x20;	//T1的方式2定时-方式2
//	SCON=0x90;	//串行口方式2,REN=1允许接收
//	PCON=0x00;	//SMOD=0
//	
//	TH1=0xfd;	//波特率为9600
//	TL1=0xfd;
//	TR1=1;		//启动定时器T1
//	REN=1;
	
	//Success
	TMOD=0x20;	//T1的方式2定时-方式2
	SCON=0xd0;	//串行口方式3,REN=1允许接收
	PCON=0x00;	//SMOD=0
	
	TH1=0xfd;	//波特率为9600
	TL1=0xfd;
	TR1=1;		//启动定时器T1
	REN=1;
}
void delay(void)
{
	uchar m,n;
	for(m=0;m<250;m++)
		for(n=0;n<125;n++);
}
uchar receive(void)
{
	uchar dat;
	while(RI==0);
	;
	RI=0;
	ACC=SBUF;
	if(RB8==P)
	{
		dat=ACC;
		return dat;
	}
}

参考文献
1.《单片机原理与接口技术》张毅刚
资源

返回目录

  • 12
    点赞
  • 131
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值