51单片机定时器及其应用(1)(时钟功能)
??STC89C51单片机有2个定时器,叫做定时器0和定时器1,可以用作普通定时器,计数器。普通定时器可以用来进行中断定时,波特率发生等,计数器可以用来对脉冲宽度进行测量,从而实现测频功能。其工作模式由定时器/计数器控制寄存器TMOD控制,TMOD寄存器各位如下: ?TMOD是一个8位寄存器,两边对称,分别控制着定时器0和定时器1,。GATE位,简单理解就是门位,为0就是关门,此时定时器的开启与停止仅由内部控制位决定,这个内部控制位就是TR1,后面会讲。当GATE=1时,相当于把门打开,定时器的开启与停止由外部和内部一起控制,对于定时器1来说,当GATE=1时,是有当INT1引脚为高且TR1=1时才能开启定时器。
C
/
T
ˉ
C/\bar{T}
C/Tˉ位很好理解,C就是count,T就是timer,为0工作在定时器模式,为1工作在定时器模式。M1和M0用于选择定时器/计数器的计数模式,因为定时器其实也是按脉冲进行计数,计数到一定值后溢出,产生中断,所有这里统一称为计数模式。当 M1和M0取值不同即为不同模式,如下图所示: THx(x=0,1),TLx(x=0,1)为两个8位寄存器,用来存放计数的值,写入不同的控制字可以实现不同功能,当M1=0,M0=0时,是一个13位定时器,这个功能比较鸡肋,也不常用,M1=0,M0=1时是一个16位定时器,这是比较常用的,16位最多可以存放的计数值为2^{16}=65536,51单片机每计数一个值的时间是一个机器周期,也就是12个时钟周期,T_{机器}=12T_{时钟}=12(1/12000000)=1us,从而得出最大计时时间为65.536ms,如何想要产生更大的计时时间,可以设置一个中间计数变量count,在中断程序中进行count++,则可以得到count*定时器计时时间的最终计时时间。M1=1,M0=0时,是一个8位具有重载初值功能的定时器,自动重载初值就是在计数器里面的值计满后,单片机会产生一个溢出中断,自动将计数值清0,因此每次在中断服务程中都需要进行重新赋计数值,而这种模式就省去了重新幅值这一步,由单片机自动进行赋值。M1=1,M0=1这个功能只有定时器0具有,是两片区域同时进行工作,其实就是两个定时器,我反正没用过。具体可以参见STC89C51单片机的芯片手册。 ?到这里基本知道单片机定时器配置了,但上面一直提到中断,这里解释一下,就好比请假要写请假条申请一样,单片机中断相当于一段时间出去干其他的事情,这要向上级申请,因此也就有了中断控制寄存器: 也就是请假条的格式,TF1为定时器1的溢出中断,TR1为定时器1的运行控制位,TF0和TR0为定时器0的相关位。IE1、IT1、IE0、IT0为外部中断位,以后会用到,这里只用到前4位。这相当于申请书的格式,那么批准的领导呢?因此会有个中断允许寄存器IE EA为总的领导,当EA=1时开启总中断,后面的ET2、ET1、ES等为分领导,用于开启后面的小中断。ET1和ET0也就是定时器1和定时器0的中断使能位。 到此我们就可以进行定时器中断配置了:
void InitTimer1(void)
{
TMOD = 0x10;
TH1 = 0xFC;
TL1 = 0x18;
EA = 1;
ET1 = 1;
TR1 = 1;
}
下面分享一个小项目,也就是常见的电子时钟,可以进行按键控制
#include <reg52.h>
sbit LED=P1^0;
sbit LED1=P1^1;
sbit Wei_Select=P2^6;
sbit Duan_Select=P2^5;
sbit KEY1=P3^7;
sbit KEY2=P3^6;
sbit KEY3=P3^5;
sbit KEY4=P3^4;
char Display_Code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
char Wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned int second=0;
unsigned int minute=0;
unsigned int hour=0;
unsigned int count=0;
unsigned int second_flag=0;
unsigned int minute_flag=0;
unsigned int hour_flag=0;
unsigned int Key_Flag=0;
void delay_ms(unsigned int Xms)
{
unsigned int i=0,j=0;
for(i=Xms;i>0;i--)
for(j=110;j>0;j--);
}
void InitTimer1(void)
{
TMOD = 0x10;
TH1 = 0xFC;
TL1 = 0x18;
EA = 1;
ET1 = 1;
TR1 = 1;
}
void display(unsigned int position,unsigned int number)
{
Duan_Select=0;
Wei_Select=1;
P0=Wei[position-1];
Wei_Select=0;
Duan_Select=1;
P0=Display_Code[number];
delay_ms(2);
}
void timer1() interrupt 3
{
TH1 = 0xFC;
TL1 = 0x18;
count++;
if(count==1000)
{
second++;
if(second==60)
{
minute++;
if(minute==60)
{
hour++;
minute=0;
if(hour==24)
{
hour=0;
}
}
second=0;
}
count=0;
}
}
void main()
{
InitTimer1();
while(1)
{
display(8,second%10);
display(7,second/10);
display(5,minute%10);
display(4,minute/10);
display(2,hour%10);
display(1,hour/10);
if(KEY1==0)
{
delay_ms(20);
if(KEY1==0)
{
ET1=0;
Key_Flag++;
}
switch(Key_Flag)
{
case 1: second_flag=1;hour_flag=0;minute_flag=0;break;
case 2: minute_flag=1;second_flag=0;hour_flag=0;break;
case 3: hour_flag=1;second_flag=0;minute_flag=0;Key_Flag=0;break;
default:break;
}
while(KEY1==0);
}
if(KEY2==0)
{
delay_ms(20);
if(KEY2==0)
{
if(second_flag==1)
second++;
if(minute_flag==1)
minute++;
if(hour_flag==1)
hour++;
}
while(KEY2==0);
}
if(KEY3==0)
{
delay_ms(20);
if(KEY3==0)
{
if(second_flag==1)
second--;
if(minute_flag==1)
minute--;
if(hour_flag==1)
hour--;
}
while(KEY3==0);
}
if(KEY4==0)
{
delay_ms(20);
if(KEY4==0)
{
ET1=1;
}
}
}
}
|