先前我们介绍了定时器/计数器的概念与作用原理,下面我通过两个应用案例来分别演示定时器和计数器的用法。
第一个案例是用数码管配合定时器中断制作秒表,同理也可以自己改变时间单位制作不同精度的电子钟,修改方式我已经附在代码注释中了。
#include <reg52.h>
unsigned char code Tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C};
unsigned char Dat[]={0,0}; //用数组储存数码管要显示的数字
unsigned char Second,t;
void Delay() //为了消影需要延时函数,可以忽略延时带来的定时误差
{
unsigned char i;
for(i=0;i<50;i++);
}
void main()
{
EA = 1; //总中断允许
ET0 = 1; //允许T0中断
TMOD =0x01; //计时器0工作方式1
TH0 = -50000/256; //高位赋初值,用表达式减少了计算的麻烦
TL0 = -50000%256; //低位赋初值
TR0 = 1; //开启计时器0
while(1)
{ //进行数据分割
Dat[0]=Second/10; //累计时间的十位存入数组
Dat[1]=Second%10; //累计时间的各位存入数组
P0=Tab[Dat[0]]; //读取数码管相应的数字段码
P1=0xfe; //位选开启十位数码管,注意仿真图,十位接在P1.0上
Delay();
P1=0xff; //消影
P0=Tab[Dat[1]]; //个位同理
P1=0xfd;
Delay();
P1=0xff;
}
}
void intserv1 (void) interrupt 1 using 1
{
TH0= -50000/256; //减法赋值的简写
TL0= -50000%256;
t++; //记录1s的二十分之一
if(t==20) //累积到1s后置零,秒数加1
{ //如果要更改秒表的精确程度,修改这里再添加一个用于显示精确位数的数码管即可
/*if(t==2) //比如改为t==2,就是每0.1s在数码管显示一次,输出时再加一个用于显示十分位的数码管
{t=0; //同时将second的归零值改为100,不过要注意两件事情
num++; //一是变量在命名second容易出现语意不明,应改为num加注释说明
if(Second>=600) Second=0;
}*/ //二是带小数点显示的段码与先前用到的不同,需要重新设置数组
t=0;
Second++;
if(Second>=60) Second=0; //到一分钟后重新开始
}
}
仿真效果如下,为了让输出的电平更稳定,笔者采用了74LS245芯片,它是8路同相三态双向总线收发器,用来驱动LED或者其他的设备,可双向传输数据。
数码管定时秒表
为了不浪费太多时间,我在演示视频中剪去了中间计数的一部分,大家主要看1分钟自动置零的效果就可以了。
第二个案例是计数器,要求是双击按键切换灯光,再次双击切换另一种灯光。
#include <reg51.h>
unsigned char F=0;
void Delay(unsigned int i)
{
unsigned int j;
for(;i>0;i--)
for(j=0;j<125;j++);
}
void main( )
{ //顺序可以调换,记住要配置TMOD、TCON、IE和初值
TMOD=0x50; //设置定时器T1工作方式1
TH1=0xff; //向TH1写入初值的高8位
TL1=0xfe; //向TL1写入初值的低8位
EA=1; //开启总中断允许
ET1=1; //定时器T1中断允许
TR1=1; //启动定时器T1
while(1)
{
if(F==1) //第一次双击,灯光标志位为1,进入模式1
{
P1=0xff; //LED全部闪烁
Delay(500) ;
P1=0x00;
Delay(500);
}
if(F==2) //第二次双击,灯光标志位为2,进入模式2
{
P1=0xaa; //LED奇偶位交替闪烁
Delay(500) ;
P1=0x55;
Delay(500);
}
if(F==3) //第三次双击,清空标志位,关闭灯光
{ F=0;
P1=0xff;
}
}
}
void T1_int(void) interrupt 3 //计数器T1中断服务函数
{
TH1=0xff; //重新赋值
TL1=0xfe;
F++; //灯光执行标志+1,中断只做赋值,不执行具体程序,可以有效减少运行时间
}
大家可以自行改变按键对应的执行程序,与其他外设组合,比如让数码管显示不同的图案,也可以更改标志位的复制逻辑,单双击赋予不同的意义。总的来说思路都相同,只是需要注意在中断服务函数里应尽量少执行操作,将重点的操作置于主函数内部,通过改变标志位的数值来执行不同的程序。?
按键计数器控制LED点亮
今天和大家分享了两个定时器/计数器的应用,因为笔者所学专业对单片机要求不高,亟待分享的内容只剩下几个类似的应用,这个专栏也快要走到尾声了,感谢大家一路的陪伴,我们明天再见。