昆明理工大学信息工程与自动化学院学生实验报告
( 2014 — 2015 学年第 2 学期)
课程名称:嵌入式技术开课实验室:信自楼402 2015年5月5日
一、实验目的
掌握定时器T0、T1的方式选择和编程方法,了解中断服务程序的设计方法,学会实时程序的调试技巧。
二、实验原理
89C51单片机有五个中断源(89C52有六个),分别是外部中断请求0、外部中断请求1、定时器/计数器0溢出中断请求、定时器/计数器0溢出中断请求及串行口中断请求。
每个中断源都对应一个中断请求位,它们设置在特殊功能寄存器TCON和SCON中。
当中断源请求中断时,相应标志分别由TCON和SCON的相应位来锁寄。
五个中断源有二个中断优先级,每个中断源可以编程为高优先级或低优先级中断,可以实现二级中断服务程序嵌套。
在同一优先级别中,靠内部的查询逻辑来确定响应顺序。
不同的中断源有不同的中断矢量地址。
中断的控制用四个特殊功能寄存器IE、IP、TCON (用六位)和SCON(用二位),分别用于控制中断的类型、中断的开/关和各种中断源的优先级别。
中断程序由中断控制程序(主程序)和中断服务程序两部分组成:
1)中断控制程序用于实现对中断的控制;
2)中断服务程序用于完成中断源所要求的中断处理的各种操作。
C51的中断函数必须通过interrupt m进行修饰。
在C51程序设计中,当函数定义时用了interrupt m修饰符,系统编译时把对应函数转化为中断函数,自动加上程序头段和尾
段,并按MCS-51系统中断的处理方式自动把它安排在程序存储器中的相应位置。
在该修饰符中,m的取值为0~31,对应的中断情况如下:
0——外部中断0
1——定时/计数器T0
2——外部中断1
3——定时/计数器T1
4——串行口中断
5——定时/计数器T2
其它值预留。
89C51单片机内设置了两个可编程的16位定时器T0和T1,通过编程,可以设定为定时器和外部计数方式。
T1还可以作为其串行口的波特率发生器。
定时器T0由特殊功能寄存器TL0和TH0构成,定时器T1由TH1和TL1构成,特殊功能寄存器TMOD控制定时器的工作方式,TCON控制其运行。
定时器的中断由中断允许寄存器IE,中断优先权寄存器IP中的相应位进行控制。
定时器T0的中断入口地址为000BH,T1的中断入口地址为001BH。
定时器的编程包括:
1)置工作方式。
2)置计数初值。
3)中断设置。
4)启动定时器。
定时器/计数器由四种工作方式,所用的计数位数不同,因此,定时计数常数也就不同。
三、实验内容
在实验板上完成如下功能:
●用定时器 T0 的方式1,实现第一个发光二极管以200ms 的间隔闪烁;
●用定时器 T1 的方式1,实现数码管前两位59s 循环计时。
实验板数码管电路原理如图1 所示。
计算初值公式
定时模式1 th0=(216-定时时间) / 256
tl0=(216-定时时间) % 256
四、实验步骤
1、按实验要求在KeilC中创建项目,编辑、编译程序。
代码1:
#include <reg52.h>
sbit LED=P1^0;
void main()
{
TMOD = 0x01; //选用计数模式和选用模式1
TH0 = (65536-50000)/256; //给计数器装初值,公式 (2^16-定时时间) / 256 TL0 = (65536-50000)%256; //给计数器装初值,公式 (2^16-定时时间) % 256 EA = 1; //开发所有中断
ET0 = 1; //开启定时器T0中断
TR0 = 1; //启动T0定时器
while(1);
}
void Time() interrupt 1
{
unsigned int num;
TH0 = (65536-50000)/256; //给计数器重装初值,公式 (2^16-定时时间) / 256
TL0 = (65536-50000)%256; //给计数器重装初值,公式 (2^16-定时时间) % 256
num++;
if(num==4)
{
LED=~LED;
num=0;
}
}
代码2:
#include <reg52.h>
sbit DULA=P2^6;
sbit WELA=P2^7;
void delay();
unsigned char num,i,j;
unsigned char code DIG_CODE[17] = {
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void main()
{
TMOD = 0X10; //选用计数模式和选用模式1
TH1 = 0x3c; //给计数器装初值,公式 (2^16-定时时间) / 256
TL1 = 0xb0; //给计数器装初值,公式 (2^16-定时时间) % 256
EA = 1; //开发所有中断
ET1 = 1; //开启定时器T1中断
TR1 = 1; //启动T1定时器
while(1)
{
if(num==60) num=0;
i=num/10;
j=num%10;
WELA=1;
P0=0xfe;
WELA=0;
DULA=1;
P0=DIG_CODE[i];
DULA=0;
delay();
WELA=1;
P0=0xfd;
WELA=0;
DULA=1;
P0=DIG_CODE[j];
DULA=0;
delay();
}
}
void Time() interrupt 3
{ unsigned int k;
k++;
while(k==20)
{
TH1 = 0x3c; //给计数器装初值
TL1 = 0xb0;
num++;
k=0;
}
}
void delay()//消隐
{ unsigned char a, b;
for (b=38;b>0;b--)
{
for (a=130;a>0;a--);
}
}
2、将编译生成的目标码文件(后缀为.Hex)下载到实验板电路中。
3、在实验板中运行程序,观察实验运行结果并记录。
五、思考
1.若用定时器1方式2,程序如何修改?
首先改T/C的方式控制寄存器 TMOD,TMOD值应该为0x10,(GATE=0),初值给定方式2为(2^8-给定时间)。
2.若显示从“99”开始递减,程序如何修改?
#include <reg52.h>
sbit DULA=P2^6;
sbit WELA=P2^7;
void delay();
unsigned char num,i,j;
unsigned char code DIG_CODE[17] = {
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void main()
{
num=99;
TMOD = 0X10; //选用计数模式和选用模式1
TH1 = 0x3c; //给计数器装初值,公式 (2^16-定时时间) / 256
TL1 = 0xb0; //给计数器装初值,公式 (2^16-定时时间) % 256
EA = 1; //开发所有中断
ET1 = 1; //开启定时器T1中断
TR1 = 1; //启动T1定时器
while(1)
{
if(num==0) num=99;
i=num/10;
j=num%10;
WELA=1;
P0=0xfe;
WELA=0;
DULA=1;
P0=DIG_CODE[i];
DULA=0;
delay();
WELA=1;
P0=0xfd;
WELA=0;
DULA=1;
P0=DIG_CODE[j];
DULA=0;
delay();
}
}
void Time() interrupt 3
{ unsigned int k;
k++;
while(k==20)
{
TH1 = 0x3c; //给计数器装初值
TL1 = 0xb0;
num--;
k=0;
}
}
void delay()//消隐
{ unsigned char a, b;
for (b=38;b>0;b--)
{
for (a=130;a>0;a--);
}
}
六、实验总结
通过此次实验我了解定时器/计数器的使用,也熟悉了中断的原理,通过完成老师布置的任务,加上课后完成的思考题,我已经熟悉掌握了中断的使用。
我初步掌握定时器T0、T1的方式选择和编程方法,同时我还了解中断服务程序的设计方法,学会实时程序的调试技巧。
当然通过这次实验我还加深了定时器的使用以及定时器设置方法的应用,同时我还懂得了中断对于程序的作用和定时时间的设定。