第7章
思考题及习题7
1.如果采用的晶振的频率为24MHz,定时器/计数器工作在方式0、1、2下,其最大定时时间各为多少? 答:晶振的频率为24MHz, 机器周期为0.5µs。
方式0最大定时时间=0.5µs×213=0.5µs×8192=4096µs
方式1最大定时时间=0.5µs×216=0.5µs×65536=327686µs
方式2最大定时时间=0.5µs×28=0.5µs×256=128µs
2.定时器/计数器用作计数器模式时,对外界计数频率有何限制?
答:外部输入的计数脉冲的最高频率为系统振荡器频率的1/24。
3.定时器/计数器的工作方式2有什么特点?适用于哪些应用场合?
答:方式2为初值自动装入的8位定时器/计数器,克服了在循环定时或循环计数应用时就存在用指令反复装入计数初值影响定时精度的问题。
4.THx与TLx(x = 0,1反光书包)是普通寄存器还是计数器?其内容可以随时用指令更改吗?更改后的新值是立即刷新还是等当前计数器计满后才能刷新?
答:THx与TLx(x = 0,1)是计数器,其内容可以随时用指令更改,但是更改后的新值要等当前计数器计满后才能刷新。
5.Proteus虚拟仿真
使用定时器T0,采用方式2定时,在P1.0脚输出周期为400µs,占空比为4:1的矩形脉冲,要求在P1.0脚接有虚拟示波器,观察P1.0脚输出的亚克力抽奖箱矩形脉冲波形。
答:略
6.Proteus虚拟仿真
利用定时器T1的中断来使P1.7控制蜂鸣器发出1kHz的音频信号,假设系统时钟频率为12M
Hz。
答:利用定时器T1的中断控制P1.7引脚输出频率为1kHz的方波音频信号,驱动蜂鸣器发声。系统时钟为12MHz。方波音频信号的周期为1ms,因此T1的定时中断时间为0.5 ms,进入中断服务程序后,对P1.7求反。电路如图所示。
图 控制蜂鸣器发出1kHz的音频信号
先计算T1初值,系统时钟为12MHz,则方波的周期为1µs。1kHz的音频信号周期为1ms,要定时计数的脉冲数为a。则T1的初值:
TH1=(65 536 −a)/256; TL1=(65 536 −a) %256
参考程序如下:
#include<reg51.h> //包含头文件
sbit sound=P1^7; //将sound位定义为P1.7引脚
#define f1(a) (65536-a)/256 //定义装入定时器高8位的时间常数
#define f2(a) (65536-a)%256 //定义装入定时器低8位的时间常数
unsigned int i = 500;
unsigned int j = 0;
void main(void)
{
EA=1; //开总中断.
ET1=1; //允许定时器T1中断 .
TMOD=0x10; //TMOD=0001 000B,使用T1的方式1定时
TH1=f1(i); //给定时器T1高8位赋初值.
TL1=f2(i); //给定时器T1低8位赋初值.
TR1=1; //启动定时器T1
while(1)
{ //循环等待
i=460;
while(j<2000);
j=0;
i=360;
while(j <2000);
j=0;
}
}
void T1(void) interrupt 3 using 0 //定时器T1中断函数
{
TR1= 0; //关闭定时器T1
sound=~sound; //P1.7输出求反
TH1=f1(i); //定时器T1的高8位重新赋初值.
TL1=f2(i); //定时器T1的低8位重新赋初值.
j++;
TR1=1; //启动定时器T1
电子定时器}
7. Proteus虚拟仿真
制作一个LED数码管显示的秒表,用2位数码管显示计时时间,最小计时单位为“百毫秒”,计时范围0.1~9.9s。当第1次按下并松开计时功能键时,秒表开始计时并显示时间;第2次 按下并松开计时功能键时,停止计时,计算两次按下计时功能键的时间,并在数码管上显示;第3次按下计时功能键,秒表清0,再按1次计时功能键,重新开始计时。如果计时到9.9s时,将停止计时,按下计时功能键,秒表清零,再按下重新开始计时。
答:本秒表应用了AT89C51的定时器工作模式,计时范围0.1~9.9s。此外还涉及如何编写控制LED数码管显示的程序。
LED数码管显示的秒表原理电路如图所示。
图 LED数码管显示的秒表原理电路及仿真
参考程序如下:
#include<reg51.h> //包含51单片机寄存器定义的头文件
unsigned char code discode1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};
//数码管显示0~9的段码表, 带小数点
unsigned char code discode2[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,siv 0110x7d,0x07,0x7f,0x6f};
//数码管显示0~9的段码表,不带小数点
unsigned char timer=0; //记录中断次数
unsigned char second; //储存秒
unsigned char key=0; //记录按键次数 main() //主函数
{
TMOD=0x01; //定时器T0方式1定时
ET0=1; //允许定时器T0中断
EA=1; //总中断允许
second=0; //设初始值
P0=discode1[second/10]; //显示秒位0
P2=discode2[second%10]; //显示0.1s位0
while(1) //循环
{
if((P3&0x80)==0x00) //当按键被按下时
{
key++; //按键次数加1
switch(key) //根据按键次数分三种情况
{
case 1: //第一次按下为启动秒表计时
TH0=0xee; //向TH0写入初值的高8位
TL0=0x00; //向TL0写入初值的低8位,定时5ms
TR0=1; //启动定时器T0
break;
case 2: //按下两次暂定秒表
TR0=0; //关闭定时器T0
break;
case 3: //按下3次秒表清0
key=0; //按键次数清0
second=0; //秒表清0
P0=discode1[second/10]; //显示秒位0
P2=discode2[second%10]; //显示0.1s位0
break;
}
while((P3&0x80)==0x00); //如果按键时间过长在此循环
}
}
}
void int_T0() interrupt 1 using 0 //定时器T0中断函数
{
TR0=0; //停止计时,执行以下操作(会带来计时误差)
TH0=0xee; //向TH0写入初值的高8位
TL0=0x00; //向TL0写入初值的低8位,定时5ms
timer++; //记录中断次数
if (timer==20) //中断20次,共计时20*5ms=100ms=0.1s
{
timer=0; //中断次数清0
second++; //加0.1s
P0=discode1[second/10]; //根据计时时间,即时显示秒位
P2=discode2[second%10]; //根据计时时间,即时显示0.1s位
}
if(second==99) //当计时到9.9s时
{
TR0=0; //停止计时
second=0; //秒数清0
key=2; //按键数置2,当再次按下按键时,key++,即key=3,秒表清0复原
}
else //计时不到9.9s时
{
TR0=1; //启动定时器继续计时
}
空调衣}
8. Proteus虚拟仿真
制作一个采用LCD1602显示的电子钟,在LCD上显示当前的时间。显示格式为“时时:分分:秒秒”。设有4个功能键k1~k4,功能如下:
(1)k1—进入时间修改。
(2)k2—修改小时,按一下k2,当前小时增1。
(3)k3—修改分钟,按一下k3,当前分钟增1。
(4)k4—确认修改完成,电子钟按修改后的时间运行显示。
答:本题难点在于处理功能键K1~K4的输入,由于每个功能键都具有相应的一种或多种功能,因此程序中需要大量使用do{}while或while{}循环结构,以检测是否有按键按下的具体功能。按键检测函数如下:
void time_change()
{
unsigned char keyvalue0=0,keyvalue1=0;
单片机编程器 keyvalue0=keyscan();//检测是否有按键按下
if(keyvalue0)//如果有按键按下,继续检测
{
if(keyvalue0==1)//按键1,走时停止,开始判断更改值,直到按键4按下
{
while(~key0);//防抖,直到按键松开时才进行下一步的操作
TR0=0;//控制走时的中断停止
do{
keyvalue1=keyscan();//检测按键按下