1
. 实验三 定时器中断实验(Periodic Interrupt Timer)1 实验目的掌握定时器相关寄存器的配置,以及定时时间的计算等
2 实验内容定期器中断及查询方式控制P1.0口输出方波,用实验箱上的示波器观察波形,不同定时值对其影响。
3 实验器材STC89C51RC或实验箱。
4 实验步骤a.定时常数的确定
定时器/计数器的输入脉冲周期与机器周期一样, 为振荡频率的1/12。本实验中时钟频率为6.0 MHZ,现要采用中断方法来实现0.5秒延时,要在定时器1中设置一个时间常数,使其每隔0.1秒产生一次中断,CPU响应中断后将R0中计数值减一,令R0=05H,即可实现0.5秒延时。
时间常数可按下述方法确定:
机器周期=12÷晶振频率=12/(6×106)=2us
设计数初值为X,则(2e+16-X)×2×106=0.1,可求得X=15535
化为十六进制则X=3CAFH,故初始值为TH1=3CH,TL1=AFH
b.初始化程序
包括定时器初始化和中断系统初始化,主要是对IE、TCON、TMOD的相应位进行正确的设置,并将时间常数送入定时器中。由于只有定时器中断,IP便不必设置。
c.设计中断服务程序和主程序
中断服务程序除了要完成计数减一工作外,还要将时间常数重新送入定时器中,为下一次中断做准备。
3 程序下载调试
4 附注:定时器常用方式1和方式2(在实验五 单片机串口的应用中用到),方式2 为自动重装计数初值的8位定时器,主要用于串行通信中波特率的产生和短时精确定时(因为不必软件重装初值所以更精确)。
5 附注实验例程:#include
#define unchar unsigned char
#define unint unsigned int
sbit fangbo = P1^0;
void main()
{
TMOD = 0x01; //定时器0工作方式1
TH0 = 0x3c;
TL0 = 0xb0; //装入定时器初值定时50ms
ET0 = 1; //定时器0中断允许
EA = 1; //总中断允许
TR0 = 1; //定时器0开始计时
while(1); //等待
}
void time0() interrupt 1 //定时器0中断服务函数
{
TH0 = 0x3c;
TL0 = 0xb0; //重装计数器值
fangbo=~fangbo; //P1.0取反,产生方波
}
对应汇编代码:
FANGBO EQU P1.0
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP TIME
ORG 0010H
MAIN: MOV TMOD,#01H
MOV TH0,#03CH
MOV TL0,#0B0H
SETB ET0
SETB EA
SETB TR0
SJMP $ ;等待
TIME: MOV TH0,#03CH
MOV TL0,#0B0H
CPL FANGBO
RETI
END
查询方式C代码:
#include
#define unchar unsigned char
#define unint unsigned int
sbit fangbo = P1^0;
void main()
{
TMOD = 0x01; //定时器0工作方式1
TH0 = 0x3c;
TL0 = 0xb0; //装入定时器初值定时50ms
ET0 = 1; //定时器0中断允许
EA =0; //总中断允许
TR0 = 1; //定时器0开始计时
while(1) //死循环
{
while(!TF0); //查询中断标志并等待
TF0 = 0; //清除标志
TH0 = 0x3c;
TL0 = 0xb0; //重装初值
fangbo=~fangbo; //P1.0取反,产生方波
}
}
对应汇编代码:
FANGBO EQU P1.0
ORG 0000H
LJMP MAIN
ORG 0010H
MAIN: MOV TMOD,#01H
MOV TH0,#03CH
MOV TL0,#0B0H
SETB ET0
SETB TR0
TIME: JNB TF0,$
MOV TH0,#03CH
MOV TL0,#0B0H
CLR TF0
CPL FANGBO
SJMP TIME
END
附实验仿真电路:
注:实验箱中有模拟示波器,可通过电脑观察波形。
. 实验四 外部中断的应用一 实验目的通过此次实验学习51单片机外部中断的使用,并结合输入输出方式熟练掌握外部中断的应用
二 实验内容采用按键以中断方式控制一个LED灯的亮灭。
三 实验器材STC89C52RC 单片机、LED灯,独立按键或实验箱。
三 实验步骤- 程序的编写,采用中断方式判断键是否按下,并确定是否点亮二极管。
- 程序下载调试(可先进行仿真)。
四 附注中断方式可以提高CPU的效率,当发生中断事件时处理器可快速响应中断,没有中断事件时处理器正常工作,不必时刻查询中断事件的发生与否,提高代码效率。
本例中,若采用电平触发方式,则Key为低电平时Led亮,否则Led息灭;若采用边沿触发方式,则Key的每个下降沿,即Key由高变为低时,Led的状态改变一次。
五 实验附注例程#include
#define unchar unsigned char
#define unint unsigned int
sbit Led = P1^0;
sbit Key = P3^2; //外部中断0引角
void main()
{
IT0 = 0; //外部中断0采用电平触发方式;边沿触发为1下降沿有效
EA = 1; //中断允许
EX0 = 1; //开外部中断0
while(1);
}
void int0() interrupt 0
{
Led = 0; //Led 亮
while(Key == 0); //等待键释放
Led = 1; // Led 灭
}
/*
void int0() interrupt 0 //边沿触发方式中断函数。每次Key下降沿改变Led状态
{
Led = ~Led; //改变Led状态
}
*/
对应汇编代码:
KEY EQU P3.2
LED EQU P1.0
ORG 0000H
LJMP MAIN
ORG 0003H
LJMP INIT
ORG 0010
MAIN: CLR IT0 ;电平触发方式,边沿触发为SETB IT0
SETB EA
SETB EX0
SJMP $
INIT: CLR LED
JNB KEY,$
SETB LED
RETI
;INIT: CPL LED ;边沿触发方式中断程序
END
附实验仿真电路:
附图1
附图2 P0口上拉电阻
. 实验五 单片机串口的应用1 实验目的通过此次实验学习单片机串口的应用,掌握串口相关寄存器的配置,并学会用串口做简单的双机通信。
2 实验内容通过串口实现双机通信,用Key控制发光二极管。
3 实验器材STC89C52RC单片机、LED灯或实验箱。
4 实验步骤5 附注51单片机串行口的SBUF有两个:接收SBUF和发送SBUF,二者在物理结构上是独立的,单片机用它们来接收和发送数据。串行通讯的波特率随串行口工作方式选择的不同而不同,它除了与系统的振荡频率f,电源控制寄存器PCON的SMOD位有关外,还与定时器T1的设置有关。
1、在工作方式0时,波特率固定不变,仅与系统振荡频率有关,其大小为f/12。
2、在工作方式2时,波特率也只固定为两种情况:
当SMOD=1时, 波特率=f/32
当SMOD=0时, 波特率=f/64
3、在工作方式1和3时,波特率是可变的:
当SMOD=1时, 波特率=定时器T1的溢出率/16
当SMOD=0时, 波特率=定时器T1的溢出率/32
其中,定时器T1的溢出率=f/(12*(256-N)),N为T1的定时时间常数。
在实际应用中,往往是给定通讯波特率,而后去确定时间常数。例如:f=6.144MHZ,波特率等于1200,SMOD=0时,则1200=6144000/(12*32*(256-N)),计算得N=F2H。
本例程中设置串行口工作于方式1,SMOD=0,波特率为1200。
6 附注例程中断方式C代码:
#include
#define unchar unsigned char
#define unint unsigned int
sbit Key = P1^1;
sbit Led = P1^0;
void uartsend(unchar dat);
void Uartsend(unchar k) //串口发送子函数
{
SBUF = k; //发送数据
while(!TI); //待待发送结束
}
void main()
{
unchar tmp;
TMOD = 0x20; //定时器1工作方式2
TH1 = 0xfa;
TL1 = 0xfa; //装入定时器初值11.0592M晶振,波特率4800
PCON = 0; //波特率不倍增
ET1 = 0; //定时器1中断允许
EA = 1; //总中断允许
ES = 1; //串口中断允许
TR1 = 1; //定时器0开始计时
SCON = 0x50; //串口工作方工1,准备接收
while(1) //死循环
{
if(Key) //判断是否有键按下
{
Uartsend(0xaa); //用串口发送0xaa
while(Key); //等待键释放
}
else
{
Uartsend(0x55);
while(!Key);
}
}
}
void uart() interrupt 4
{
unchar temp;
if(RI) //判断是否为接收中断
{
temp = SBUF; //读数据
switch(temp) //判断数据
{
case 0x55:Led = 1;break;
case 0xaa:Led = 0;break;
default:break;
}
RI = 0; //清除中断标志
}
TI = 0; //清除中断标志
}
对应汇编代码:
KEY EQU P1.1
LED EQU P1.0
ORG 0000H
LJMP MAIN
ORG 0023H
LJMP UART
ORG 0100H
MAIN: MOV TMOD,#020H
MOV TH1,#0FAH
MOV TL1,#0FAH
MOV PCON,#00H
CLR ET1
SETB EA
SETB ES
SETB TR1
MOV SCON,#050H
KEYLED: JNB KEY,OFFL
MOV SBUF,#0AAH
KEY0: JB KEY,$
OFFL: MOV SBUF,#055H
KEY1: JNB KEY,$
SJMP KEYLED
UART: JNB RI,RRET
CLR RI
MOV R7,SBUF
CJNE R7,#0AAH,OFFLED
CLR LED
SJMP RRET
OFFLED: SETB LED
RRET: CLR TI
RETI
END
查询方式C代码:
#include
#define unchar unsigned char
#define unint unsigned int
sbit Key = P1^1;
sbit Led = P1^0;
void uartsend(unchar dat) //串口发送子函数
{
SBUF = dat; //发送数据
while(!TI); //待待发送结束
TI = 0; //清除中断标志
}
void uartrec() //串口接收数据子函数
{
unchar temp;
if(RI)
{
temp = SBUF; //读数据
switch(temp) //判断数据
{
case 0x55:Led = 1;break;
case 0xaa:Led = 0;break;
default:break;
}
RI = 0; //清除中断标志
}
}
void main()
{
TMOD = 0x20; //定时器1工作方式2
TH1 = 0xfa;
TL1 = 0xfa; //装入定时器初值11.0592M晶振,波特率4800
PCON = 0; //波特率不倍增
ET1 = 0; //定时器0中断允许
EA = 0; //总中断关闭
ES = 1; //串口中断允许
TR1 = 1; //定时器0开始计时
SCON = 0x50; //串口工作方工1,准备接收
while(1)
{
if(Key) //判断键是否按下
{
uartsend(0xaa);
while(Key)uartrec(); //等键释放并接收数据
}
uartsend(0x55);
while(!Key)uartrec();
}
}
对应汇编代码:
KEY EQU P1.1
LED EQU P1.0
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: MOV TMOD,#020H
MOV TH1,#0FAH
MOV TL1,#0FAH
MOV PCON,#00H
CLR ET1
CLR EA
SETB ES
SETB TR1
MOV SCON,#050H
KEYLED: JNB KEY,OFFL
MOV SBUF,#0AAH
JNB TI,$
CLR TI
SJMP KEY1
OFFL: MOV SBUF,#055H
JNB TI,$
CLR TI
KEY0: JB KEY,KEYLED
LCALL UARTRI
SJMP KEY0
KEY1: JNB KEY,OFFL
LCALL UARTRI
SJMP KEY1
UARTRI: JNB RI,RETT
CLR RI
MOV R7,SBUF
CJNE R7,#0AAH,OFFLED
CLR LED
RETT: RET
OFFLED: SETB LED
SJMP RETT
END
附实验仿真电路:
注:MCU1的TX接MCU2的RX,MCU1的RX接MCU2的TX。