实验5-单片机单片机串行口中断实验
之前做的一次实验,51单片机串行口中断实验,感觉不够完美,待改进。如有问题欢迎指正。
实验目的:
掌握串行口的工作方式;掌握不同串行口工作方式下的通讯方法。
实验目标:
放置两个单片机,通过串行口线的互连,应用方式1和方式3,同时设计发送和接受程序,完成两个方式的应用,将发送和接收的内容在虚拟串口中显示。
实验环境:
MDK-ARM V5.21a、Proteus 8.6
Proteus原理图
方式1:
方式3:
选择元器件:
DEVICES | 说明 |
---|---|
AT89C51 | MCU |
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=fosc1≈90.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×(256−X)(其中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.《单片机原理与接口技术》张毅刚
资源