单片机模板六:定时器

一、定时器的基本原理

1、寄存器       

        顾名思义,定时器就是用来进行定时的。定时器内部有一个寄存器,每经过一个周期,寄存器会自动加一。标准的 51 单片机内部有 T0 和 T1 这两个定时器,而寄存器中TH0/TL0 用于 T0,TH1/TL1 用于T1。
       对于寄存器,我们将介绍两种——TCON和TMOD。

      (1) TMOD

       定时器/计数器模式控制寄存器TMOD是一个逐位定义的8位寄存器,但只能使用字节寻址,其字节地址为89H。
TF1——TF1=1表示T1有中断产生;
TR1——TR1=1表示T1开始运行;
TF0——TF0=1表示T0有中断产生;
TR0——TR0=1表示T0开始运行;
IE1——IE1=1表示INT1有中断产生;
IT1——IT1=1表示INT1为下降沿触发,IT1=0表示INT1为低电平触发;
IE0——IE0=1表示INT0有中断产生;
IT0——IT0=1表示INT0为下降沿(负跳变)触发,IT0=0表示INT0为低电平触发;
      

 (2)TCON

       TCON为控制寄存器,作用是控制定时器的启、停,标志定时器溢出和中断情况。位0~位3为T0定时/计数器的设置;位4~位7为T1定时/计数器的设置。

GATE:为门控位,GATE=0时,只要在编写程序时,使TCON中的TR0或TR1为1,就可以启动定时器/计数器工作。GATE=1时,不仅要在编写程序时,使TCON中的TR0或TR1为1,且需要外部引脚也为高电平,才能工作。

C/T:定时/计数模式切换,C/T=0时为定时模式,C/T=1时为计数模式。

M1/M0:用来选择定时计/计数器的工作方式,一般使用都是采用16位的计时计数器。

       对于定时器的 4 种工作模式,模式 0 是为了兼容老的 8048 系列单片机而设计的,现在的51 几乎不会用到这种模式,而模式 3 它的功能用模式2 完全可以取代,所以基本上也是不用的,那么我们就重点来学习模式 1 和模式 2
       模式 1 ,是 THn TLn 组成了一个 16 位的定时器,计数范围是 0 65535 ,溢出后,只要不对THn和 TLn 重新赋值,则从 0 开始计数。模式 2 ,是 8 位自动重装载模式,只有 TLn做加1 计数,计数范围 0 255 THn 的值并不发生变化,而是保持原值, TLn 溢出后, TFn就直接置1 了,并且 THn 原先的值直接赋给 TLn ,然后 TLn 从新赋值的这个数字开始计数。

(3)模式1

以定时器0为例——

1 TR0 和下边或门电路的结果要进行与运算, TR0 如果是 0 的话,与运算完了肯定是 0, 所以如果要让定时器工作,那么TR0 就必须置 1
2 、这里的与门结果要想得到 1 ,那么前面的或门出来的结果必须也得是 1 才行。在 GATE位为1的情况下,经过一个非门变成 0 ,或门电路结果要想是 1 的话,那 INT0 P3.2 引脚必须是1 的情况下,这个时候定时器才会工作,而 INT0 引脚是 0 的情况下,定时器不工作,这就是GATE 位的作用。
3 、当 GATE 位为 0 的时候,经过一个非门会变成 1 ,那么不管 INT0 引脚是什么电平,经过或门电路后都肯定是1 ,定时器就会工作。
4 、要想让定时器工作,就是自动加 1 ,从图上看有两种方式,第一种方式是那个开关打到上边的箭头,就是C/T = 0 的时候,一个机器周期 TL 就会加 1 一次,当开关打到下边的箭头,即C/T =1 的时候, T0 引脚即 P3.4 引脚来一个脉冲, TL 就加 1 一次,这也就是计数器功能。

(4)定时器操作步骤

1.选择工作方式(设置M0,M1的值) 

2.选择控制方式GATE(为0是只要软件设定好参数即可,为1则需要软件设定参数,且定时器/计数器的中断引脚需要为高电平)

3.确定定时器的工作模式,是定时模式还是计数模式 C/T

4.给定时器设初值(设置THX与TLX)

5.开启定时器中断(设置ET0或ET1)

6.开启总中断(设置EA的值)

7.定时器/计数器的选择T0/T1(设置TR1或TR0的值)

二、定时器的应用

1、定时器T0模式1
 

实现每隔1s,L1闪烁一次,即亮0.5s,灭0.5s;每隔10s,L8闪烁一次,即亮5s,灭5s。

代码:

#include <reg52.h>
sbit L1 = P0^0;
sbit L8 = P0^7;
//LED灯
void Select_HC573(unsigned char channel){
    switch(channel)
    {
        case 4:
            P2 = (P2 & 0x1f)|0x80;break;
        case 5:
            P2 = (P2 & 0x1f)|0xa0;break;
        case 6:
            P2 = (P2 & 0x1f)|0xc0;break;
        case 7:
            P2 = (P2 & 0x1f)|0xe0;break;
    }
}

//================================
void Init_T0()
{
    TMOD = 0x01;  //模式1,16位无自动重装
    /* TMOD只能高四位控制T1,此处不需要,所以全部置0
    低四位控制T0,且使用模式1*/
    
    TH0 = (65535-50000) / 256;  //高8位
    TL0 = (65535-50000) % 256;  //低8位
    
    ET0 = 1;  //T0的中断允许
    EA = 1;  //总中断
    
    TR0 =1;  //定时器0运行控制
}

unsigned char count = 0;
unsigned char count1 = 0;
//中断
void Service_T0() interrupt 1
{
    Select_HC573(4);
    TH0 = (65535-50000) / 256;  //模式1无自动重装,中断服务函数需重新赋初始值
      TL0 = (65535-50000) % 256;
    count++;
    count1++;
    
    if(count == 10)
    {
        L1 = ~L1;
        count = 0;
    }

    if(count1 == 100)
    {
        L8 = ~L8;
        count1 = 0;
    }    
    
}
//=================================

void Init_System()
{
    Select_HC573(5);
    P0 = 0x00;
    Select_HC573(4);
    P0 = 0xff;
}

void main()
{
    Init_T0();
    Init_System();
    while(1)
    {
    }
}

2、实现分、秒和毫秒的显示

当按下S4时,开始计时,再按一下S4,暂停计时;按下S5,计时清零。

代码:

#include <reg52.h>

sbit S4 = P3^3;
sbit S5 = P3^2;

unsigned char SMG_duanma[12]={
    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
    0xbf,0x7f};

unsigned char min;  
unsigned char sec;
unsigned char msec;

void Select_HC573(unsigned char channel)
{
    switch(channel)
    {
        case 4:
        P2 = (P2 & 0x1f) | 0x80;
        break;
        case 5:
        P2 = (P2 & 0x1f) | 0xa0;
        break;
        case 6:
        P2 = (P2 & 0x1f) | 0xc0;
        break;
        case 7:
        P2 = (P2 & 0x1f) | 0xe0;
        break;
    }
}

void SMG_bit(unsigned char pos,unsigned char dat)
{
    Select_HC573(6);
    P0 = 0x01 << pos;
    Select_HC573(7);
    P0 = dat;
}

void SMG_Delay(unsigned int t)
{
    while(t--);
}

void SMG_Display()
{
    SMG_bit(7,SMG_duanma[msec%10]);
    SMG_Delay(500);
    SMG_bit(6,SMG_duanma[msec/10]);
    SMG_Delay(500);
    
    SMG_bit(5,SMG_duanma[10]);
    SMG_Delay(500);
    
    SMG_bit(4,SMG_duanma[sec%10]);
    SMG_Delay(500);
    SMG_bit(3,SMG_duanma[sec/10]);
    SMG_Delay(500);
    
    SMG_bit(2,SMG_duanma[10]);
    SMG_Delay(500);
    
    SMG_bit(1,SMG_duanma[min%10]);
    SMG_Delay(500);
    SMG_bit(0,SMG_duanma[min/10]);
    SMG_Delay(500);
}

//==========定时器相关函数================
void Init_Time0()
{
    TMOD = 0x01;  //模式1,16位无自动重装
    
    TH0 = (65535-50000) / 256;  //高8位
    TL0 = (65535-50000) % 256;  //低8位
    
    ET0 = 1;  //T0的中断允许
    EA = 1;  //总中断
    
    TR0 =1;  //定时器0运行控制
}

void Service_Time0() interrupt 1
{
    
    TH0 = (65535-50000) / 256;
    TL0 = (65535-50000) % 256;
    msec++;
    
    if(msec == 20)
    {
        sec++;
        msec = 0;
        if(sec == 60)
        {
            min++;
            sec = 0;
        }
        if(min == 99)
        min = 0;
    }
}
//=================================

void Key_Delay(unsigned int t)
{
    while(t--);
}

void Key_fun()
{
    if(S4 == 0)
    {
        Key_Delay(100);  //延时消抖
        if(S4 == 0)
        {
            TR0 = ~TR0;  //暂停或启动
            while(S4 == 0)  //松手检测,数码管仍动态显示
            {
                SMG_Display();
            }
        }
    }
    
    if(S5 == 0)
    {
        Key_Delay(100);  //延时消抖
        if(S5 == 0)
        {
            min = sec = msec = 0;  //复位
            while(S5 == 0)
            {
                SMG_Display();
            }
        }
    }
}

void Init_System()
{
    Select_HC573(5);
    P0 = 0x00;
    Select_HC573(4);
    P0 = 0xff;
}

void main()
{
    Init_Time0();
    Init_System();
    while(1)
    {
        SMG_Display();
        Key_fun();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值