MCU 51-3定时器

51定时/计数器简介

51单片机有2个16位定时器/计数器:定时器0(T0为P3.4)和定时器1(T1为P3.5)。这里所说的16位是指定时/计数器内部分别有16位的计数寄存器。

当工作在定时模式时,每经过一个机器周期内部的16位计数寄存器的值就会加1,当这个寄存器装满时溢出。 我们可以算出工作在定时模式时最高单次定时时间为 65535*1.085us=时间(单位us)

当工作在计数器模式时,T0(P3.4引脚),T1(P3.5引脚) 每来一个脉冲计数寄存器加1

定时器作用:可以用于精确事件定时,PWM脉宽调制,波形发生,信号时序测量的方面。

使用51定时/计数器步骤

(1)启动定时/计数器(通过TCON控制器)

(2)设置定时/计数器工作模式(通过TMOD控制器)

(3)查询定时/计数器是否溢出(读TCON内TF位)

51定时/计数器控制寄存器

TF1(T1溢出标志位):当定时/计数器T1溢出时由硬件置“1”TF1,向CPU发出中断请求,一直保持到CPU响应时,才由硬件清“0”(TF1也可以由程序查询清“0”)

TR1(定时器T1运行控制位):该位由软件置“1”或清零。TR1= 1就允许T1开始计数TR1=0时禁止T1计数。

TF0(T0溢出标志位)

TR0(定时器T0运行控制位),配置方法与T1相同。

IE1、IT1、IE0、IT0与定时/计数器无关,是控制外部中断的。

51定时/计数器工作模式寄存器(不可位寻址

bit7       控制T1,置“1”时只有在P3.3脚为高及TR1置“1”时才可以启动T1,置“0”时TR1为“1”就允许T1启动。

bit6       置“1”时T1做计数器,置“0”时T1做定时器。

当工作在计数器模式时,T0(P3.4引脚),T1(P3.5引脚) 每来一个脉冲计数寄存器加1

bit5~4   M1 M0

M1 = 0,M0 = 0时 工作模式0。13位定时器模式,这是为了与8048兼容而设计的。16位计数器只用了13位,即TH0的高8位和TL0的低5位,组成一个13位定时器/计数器。

M1 = 0,M0 = 1,工作模式1 此时由TH1、TL1寄存器组成16位计数器,TH1 为16位的高8位,TL1为16位的低8位,当这个16位计数 器加满时,T1溢出。TF1被硬件置“1”。

M1 = 1,M0 = 0,工作模式2,时8位自动重装定时器,当TL1溢 出时,将TH1的值自动装入到TL1中,TF1被硬件置“1”。

M1 = 1,M0 = 1,工作模式3只适用于定时器0。如果使定时器1为工作方式3,则定时器1将处于关闭状态。 

当T0为工作方式3时,TH0和TL0分成2个独立的8位计数器。其中,TL0既可用作定时器,又可用作计数器,并使用原T0的所有控制位及其定时器回零标志和中断源。TH0只能用作定时器,并使用T1的控制位TRl、回零标志TFl和中断源。 
通常情况下,T0不运行于工作方式3,只有在T1处于工作方式2,并不要求中断的条件下才可能使用。这时,T1往往用作串行口波特率发生器,TH0用作定时器,TL0作为定时器或计数器。所以,方式3是为了使单片机有1个独立的定时器/计数器、1个定时器以及1个串行口波特率发生器的应用场合而特地提供的。这时,可把定时器l用于工作方式2,把定时器0用于工作方式3。

bit3~0 设置T0定时器的,和T1设置相同(除工作模式3)

定时器1:

/*定时器1,定时模式 工作模式1 16位计数器,
定时20秒后点亮LED1,数码管显示*/
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint  unsigned int
sbit we = P2^7;
sbit du = P2^6;

uchar code leddata[]={ 
 
                0x3F,  //"0"
                0x06,  //"1"
                0x5B,  //"2"
                0x4F,  //"3"
                0x66,  //"4"
                0x6D,  //"5"
                0x7D,  //"6"
                0x07,  //"7"
                0x7F,  //"8"
                0x6F,  //"9"
                0x77,  //"A"
                0x7C,  //"B"
                0x39,  //"C"
                0x5E,  //"D"
                0x79,  //"E"
                0x71,  //"F"
                0x76,  //"H"
                0x38,  //"L"
                0x37,  //"n"
                0x3E,  //"u"
                0x73,  //"P"
                0x5C,  //"o"
                0x40,  //"-"
                0x00,  //熄灭
                0x00  //自定义
 
                         };

void delay(uint z)
{
    uint x,y;
    for(x = z; x > 0; x--)
        for(y = 114; y > 0 ; y--);
}

void display(uchar i)
{
    uchar shi, ge;
    shi = i / 10;//求模  i除以10取商的整数部分
    ge  = i % 10;//求余  i除以10取余数部分

    P0 = 0xff; //清除断码
    we = 1;//打开位选
    P0 = 0xfe;//1111 1110 只选通第一位数码管
    we = 0;    //关闭位选

    du = 1;    //打开段选
    P0 = leddata[shi];
    du = 0;    //关闭段选
    delay(5);//延时5毫秒
    
    P0 = 0xff;//清除断码
    we = 1;    //打开位选
    P0 = 0xfd;//1111 1101  只选通第二位数码管
    we = 0;    //关闭位选
    
    du = 1;//打开段选
    P0 = leddata[ge]; 
    du = 0;    //关闭段选
    delay(5);//延时5毫秒    
}

void main()
{
        uchar a; //50次数计数
        uchar b;//秒计数
        TR1 = 1;//启动T1
        TMOD = 0x10;//T1为定时器,工作模式1 16位计数器
//在初值基础上加,溢出则定时时间到
//晶振是11.0592MHz 65535-(50 000/1.085)==0x4BFC
TH1 = 0x4b; TL1 = 0xfc;//0x4bfc 定时50ms while(1) { if(TF1 == 1)//判断T1是否溢出 { TH1 = 0x4b; TL1 = 0xfc;//0x4bfc 定时50ms TF1 = 0;//清零便于下次判断 a++;//50毫秒计数加1 } if(a == 20)//判断是否到1秒 { a = 0;//清零便于下次记录50ms的次数 b++;//秒加1 } if(b == 20)//检查是否到20秒 { TR1 = 0;//时间到关闭定时器1 P1 = 0xfe;//点亮LED1 } display(b);//显示秒的值 } }

 定时器0:

/*定时器0,定时模式 工作模式1 16位计数器,
定时20秒后点亮LED2,数码管显示*/
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint  unsigned int
sbit we = P2^7;
sbit du = P2^6;

uchar code leddata[]={ 
 
                0x3F,  //"0"
                0x06,  //"1"
                0x5B,  //"2"
                0x4F,  //"3"
                0x66,  //"4"
                0x6D,  //"5"
                0x7D,  //"6"
                0x07,  //"7"
                0x7F,  //"8"
                0x6F,  //"9"
                0x77,  //"A"
                0x7C,  //"B"
                0x39,  //"C"
                0x5E,  //"D"
                0x79,  //"E"
                0x71,  //"F"
                0x76,  //"H"
                0x38,  //"L"
                0x37,  //"n"
                0x3E,  //"u"
                0x73,  //"P"
                0x5C,  //"o"
                0x40,  //"-"
                0x00,  //熄灭
                0x00  //自定义
 
                         };

void delay(uint z)
{
    uint x,y;
    for(x = z; x > 0; x--)
        for(y = 114; y > 0 ; y--);
}

void display(uchar i)
{
    uchar shi, ge;
    shi = i / 10;//求模  i除以10取商的整数部分
    ge  = i % 10;//求余  i除以10取余数部分

    P0 = 0xff; //清除断码
    we = 1;//打开位选
    P0 = 0xfb;//1111 1011 只选通第三位数码管
    we = 0;    //关闭位选

    du = 1;    //打开段选
    P0 = leddata[shi];
    du = 0;    //关闭段选
    delay(5);//延时5毫秒
    
    P0 = 0xff;//清除断码
    we = 1;    //打开位选
    P0 = 0xf7;//1111 0111  只选通第四位数码管
    we = 0;    //关闭位选
    
    du = 1;//打开段选
    P0 = leddata[ge]; 
    du = 0;    //关闭段选
    delay(5);//延时5毫秒    
}

void main()
{
        uchar a; //50次数计数
        uchar b;//秒计数
        TR0 = 1;//启动T0
        TMOD = 0x01;//T0为定时器,工作模式1 16位计数器
        TH0 = 0x4b;
        TL0 = 0xfc;//0x4bfc    定时50ms                
        while(1)
        {
            if(TF0 == 1)//判断T0是否溢出
            {
                TH0 = 0x4b;
                TL0 = 0xfc;//0x4bfc    定时50ms
                TF0 = 0;//清零便于下次判断
                a++;//50毫秒计数加1    
            }
            if(a == 20)//判断是否到1秒
            {
                a = 0;//清零便于下次记录50ms的次数
                b++;//秒加1
            }
            if(b == 20)//检查是否到20秒
            {
                TR0 = 0;//时间到关闭定时器1
                P1 = 0xfd;//点亮LED2
            }

            display(b);//显示秒的值
        }
}

定时器1做计数器,定时器0定时:

/*定时器1做计数器,工作模式2,使用定时器0让LED1小灯100毫秒闪烁一次,
定时器1记录LED1闪烁次数,并且用数码管实时显示计数数值。*/
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint  unsigned int
sbit we = P2^7;
sbit du = P2^6;
sbit LED1 = P1^0;

uchar code leddata[]={ 
 
                0x3F,  //"0"
                0x06,  //"1"
                0x5B,  //"2"
                0x4F,  //"3"
                0x66,  //"4"
                0x6D,  //"5"
                0x7D,  //"6"
                0x07,  //"7"
                0x7F,  //"8"
                0x6F,  //"9"
                0x77,  //"A"
                0x7C,  //"B"
                0x39,  //"C"
                0x5E,  //"D"
                0x79,  //"E"
                0x71,  //"F"
                0x76,  //"H"
                0x38,  //"L"
                0x37,  //"n"
                0x3E,  //"u"
                0x73,  //"P"
                0x5C,  //"o"
                0x40,  //"-"
                0x00,  //熄灭
                0x00  //自定义
 
                         };

void delay(uint z)
{
    uint x,y;
    for(x = z; x > 0; x--)
        for(y = 114; y > 0 ; y--);
}

void display(uchar i)
{
    uchar bai, shi, ge;
    bai = i / 100; //显示百位
    shi = i % 100 / 10;    //显示十位
    ge  = i % 10;//显示个位

    P0 = 0xff; //清除断码
    we = 1;//打开位选
    P0 = 0xfe;//1111 1110 
    we = 0;    //关闭位选

    du = 1;    //打开段选
    P0 = leddata[bai];
    du = 0;    //关闭段选
    delay(5);//延时5毫秒
    
    P0 = 0xff;//清除断码
    we = 1;    //打开位选
    P0 = 0xfd;//1111 1101  
    we = 0;    //关闭位选
    
    du = 1;//打开段选
    P0 = leddata[shi]; 
    du = 0;    //关闭段选
    delay(5);//延时5毫秒
    
    P0 = 0xff;//清除断码
    we = 1;    //打开位选
    P0 = 0xfb;//1111 1011  
    we = 0;    //关闭位选
    
    du = 1;//打开段选
    P0 = leddata[ge]; 
    du = 0;    //关闭段选
    delay(5);//延时5毫秒    
}

void main()
{
        uchar a; //50次数计数
        TR0 = 1;//启动T0
        TR1 = 1;//启动T1
        TMOD = 0x61;//T0为定时器,工作模式1 16位计数器,T1为计数器,工作模式2,8位自动重装
        TH0 = 0x4b;
        TL0 = 0xfc;//0x4bfc    定时50ms
//P3.5来一个脉冲,计数器T1就会自动加1,这里的脉冲应是LED管脚处的脉冲,需要进行串联这两个引脚
TH1 = 0;//8位自动重装,TL1加到255后,会把TH1的0值装载到TL1里面 TL1 = 0;//当TL1溢出时自动装入TH1的值 while(1) { if(TF0 == 1)//判断T0是否溢出 { TH0 = 0x4b; TL0 = 0xfc;//0x4bfc 定时50ms TF0 = 0;//清零便于下次判断 a++;//50毫秒计数加1 } if(a == 2)//判断是否到100毫秒 { a = 0;//清零便于下次记录50ms的次数 LED1 = ~LED1;//闪烁LED1 } display(TL1);//显示T1计数值 } }

/*利用定时器0工作模式0,编写间隔一秒闪烁灯程序*/
# include <reg52.h>
sbit D1 = P1^0;//LED灯对于IO口位声明

void main()
{
//晶振11.0592MHz 8192-(5000/1.085) TMOD
= 0x00; //定时器0工作模式0,13位计数器 TH0 = (8192 - 4608) / 32;//TH储存13位中高8位 TL0 = (8192 - 4608) % 32;//TL储存13位中低5位,定时5毫秒 ET0 = 1; //开定时器0中断 TR0 = 1; //启动定时器0 EA = 1; //开总中断 while (1);//等待中断 } void Timer0() interrupt 1//定时器0中断服务程序 { static unsigned char i;//溢出次数计数静态变量 TH0 = (8192 - 4608) / 32; TL0 = (8192 - 4608) % 32;/*每次溢出后需给定时器0放置初值*/ i++; if (i == 200) //200次溢出后1秒时间到 { D1 = ~D1;//将LED灯状态取反 i = 0; // 清零溢出计次数 } }
/*晶振平率11.0592Mhz利用定时器0工作模式1,编写间隔一秒闪烁灯程序*/
# include <reg52.h>
sbit D1 = P1^0;//LED灯对应IO口位声明
void main()
{
    TMOD = 0x01;//设置定时器0的工作方式1 
    TH0    = 0x4c;//寄存器TH0中装入4C,或者该语句改为TH0 = (65536 - 46080) /256
    TL0 = 0x00;//寄存器TL0中装入00,或者该语句改为TL0 = (65536 - 46080) % 256
    ET0 = 1; //开定时器T0中断    
    EA  = 1; //开总中断,上一句和此句可以合并为一句IE=0x82H
    TR0 = 1; //启动定时器0
    while (1);//等待中断    
}
void Timer0() interrupt 1//定时器T0中断服务程序
{
    static unsigned char i;//静态计数变量
    TH0    = 0xDC;
    TL0 = 0x00;/*每次加1计数器计满溢出后,需给加1计数器重新装入初值*/
    i++;
    if (i == 20) //循环次数达到20次,1秒定时时间到
    {
        D1 = !D1;//将LED灯状态取反
        i = 0;//清零计数变量
    }
}
/*晶振频率12Mhz利用定时器0工作模式2,编写间隔500毫秒闪烁灯程序*/
# include <reg52.h>
sbit D1 = P1^0;//LED灯对于IO口位声明

void main()
{
    TMOD = 0x02;    //定时器0工作模式2,自动重装8位计数器
    TH0    = 256 - 200;//TH储存8位重装初值
    TL0 = 256 - 200;//TL储存8位初值,定时200微秒 
    ET0 = 1; //开定时器0中断
    TR0 = 1; //启动定时器0
    EA  = 1; //开总中断
    while (1);//等待中断    
}

void Timer0() interrupt 1//定时器0中断服务程序
{
    static unsigned int i;//溢出次数计数静态变量
    i++;
    if (i == 2500) //2500次溢出后500毫秒时间到
    {
        D1 = ~D1;//将LED灯状态取反
        i = 0;     //    清零溢出计次数
    }
}
当T0为工作方式3时,TH0和TL0分成2个独立的8位计数器。
其中,TL0既可用作定时器,又可用作计数器,
并使用原T0的所有控制位及其定时器回零标志和中断源。
TH0只能用作定时器,并使用T1的控制位TRl、回零标志TFl和中断源。 

/*
晶振频率12Mhz利用定时器0工作模式3 编写利用TL0计数器所对应的定时器实现间隔500毫秒闪烁一个LED灯 利用TH0计数器所对应的定时器实现间隔250毫秒闪烁另一个LED灯 */ # include <reg52.h> sbit D1 = P1^0;//LED灯对于IO口位声明 sbit D2 = P1^1; void main() { TMOD = 0x03; //定时器0工作模式3,2个独立的8位计数器 TH0 = 256 - 200;//TH0储存8位初值, 定时200微秒 TL0 = 256 - 200;//TL0储存8位初值,定时200微秒 ET0 = 1; //开定时器TL0中断 ET1 = 1; //开定时器TH0中断 TR0 = 1; //启动定时器TL0 TR1 = 1; //启动定时器TH0 EA = 1; //开总中断 while (1);//等待中断 } void TL0_Timer() interrupt 1//定时器TL0中断服务程序 { static unsigned int i;//溢出次数计数静态变量 TL0 = 256 - 200;//TL0初值重装,定时200微秒 i++; if (i == 2500) //2500次溢出后500毫秒时间到 { D1 = ~D1;//将第一个LED灯状态取反 i = 0; // 清零溢出计次数 } } void TH0_Timer() interrupt 3//定时器TH0中断服务程序 { static unsigned int i;//溢出次数计数静态变量 TH0 = 256 - 200;//TH0初值重装,定时200微秒 i++; if (i == 1250) //1250次溢出后250毫秒时间到 { D2 = ~D2;//将第二个LED灯状态取反 i = 0; // 清零溢出计次数 } }
/*
编写利用定时器0工作模式2,8位计数模式,用杜邦线一端接P1.1
另一端P3.4引脚,记录P1.1脉冲次数,每10次脉冲触发一次中断,
使计数器溢出产生中断点亮LED小灯*/
# include <reg52.h>
sbit D1 = P1^0;//LED灯对于IO口位声明
sbit IN = P1^1;//脉冲输出IO口

void main()
{
    unsigned int  b;//延时变量
    TMOD = 0x06;    //定时器0工作模式2,8位计数模式(00000110)
    TH0    = 256 - 10;    //TH储存8位重装初值
    TL0 = 256 - 10;    //TL储存8位初值
    ET0 = 1; //开定时器0中断
    TR0 = 1; //启动定时器0
    EA  = 1; //开总中断
    while (1)
    {
        IN = 1;//置高脉冲输出IO口
        for(b = 0; b < 60000 ; b++); //延时
        IN = 0;//置低脉冲输出IO口
        for(b = 0; b < 60000 ; b++);//延时        
    }
}

void Timer0() interrupt 1//定时器0中断服务程序
{
    D1 = ~D1;//将LED灯状态取反
}
原文地址:https://www.cnblogs.com/darren-pty/p/13283335.html