51单片机中定时器/计数器讲解

控制/MCU

1813人已加入

描述

在学习定时/计数器之前,我们先了解一下在单片机中什么是定时/计数器。

在51单片机中有两个定时/计数器T0和T1,在其增强型的52单片机中有三个定时/计数器T0、T1和T2。

定时/计数器系统是单片机内部的一个独立的硬件系统,其与CPU和晶振通过内部连接相互作用。当CPU开启其功能后,定时计数器便在晶振的作用下开始独立工作。

定时/计数器本质上是一个16位加1计数器,由高8位(TH0或TH1)和低8位(TL0或TL1)两个寄存器组成。但是由于累加是在晶振的驱动下,所以可以当做计时器。通过设置相应的寄存器可以选择启用其定时功能或者计数功能。当计数器溢出则溢出标志位置1。

在此介绍其两个特殊功能寄存器:TMOD-定时计数器工作模式寄存器和TCON-定时/计数器控制寄存器。

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

TMOD用来确定定时/计数器的工作方式及功能选择。

计数器

GATE-门控制位

(若GATE为0,则定时/计数器启动和暂停只与相应TCON寄存器中的运行控制位有关;若GATE为1,则定时计数器启动和暂停由相应TCON寄存器中的运行控制位和外部中断引脚上的电平状态共同控制)

C/T'-定时器模式和计数器模式选择位

(为0定时器模式,为1计数器模式)

M1、M2-工作方式选择位

计数器

工作方式1:THx和TLx两个8位寄存器组合构成一个16位定时/计数器。THx存放高8位,TLx存放低8位。

工作方式2:THx存放初值,待TLx累加溢出时,THx内的初值自动重装入TLx开始累加,循环往复。

介绍了应用较多两种工作方式。

定时器的计算

定时/计数器本质上是一个16位加1计数器,在晶振的驱动下,每过一个机器周期(12个时钟周期)就自行加1。因此加1则意味着时间过了12/fs,其中f为晶振频率。假如我们应用定时器模式工作方式1。此模式下定时最长时间为((2^16-1)x12/f)s。本开发板上晶振为11.0592MHz,则最长定时时间约为71ms。所以当定时时间大于71ms时,我们可以迭代使其达到。

假如我们要定时100ms,我们可以定时50ms,再迭代2次。定时50ms要重装初值,假如用T0。定时50ms约需要累加(0.05s/(12/f))=46083次。故需要将(65535-46083)=19452(0x4bfc)装入TH0和TL0中。

TCON-定时/计数器控制寄存器 (可位寻址)

计数器

TF1-定时计数器1溢出标志位

(为1溢出申请中断。中断方式硬件自动清0,查询方式需软件清0)

TR1-定时计数器1运行控制位

(若GATE==1且INT1为高电平,TR1为1运行;若GATE==0,TR1为1运行;TR1需软件清0关闭)

TF0-定时计数器0溢出标志位

(为1溢出申请中断。中断方式硬件自动清0,查询方式需软件清0)

TR0-定时计数器0运行控制位

(若GATE==1且INT0为高电平,TR0为1运行;若GATE==0,TR0为1运行;TR0需软件清0关闭)

IE1-外部中断1请求标志

(为1表明正在向CPU申请中断,CPU转向中断服务程序后,硬件清0)

IT1-外部中断1触发方式选择位

(为1为跳变沿触发方式(负跳变),为0为低电平触发方式)

IE0-外部中断0请求标志

(为1表明正在向CPU申请中断,CPU转向中断服务程序后,硬件清0)

IT0-外部中断0触发方式选择位

(为1为跳变沿触发方式(负跳变),为0为低电平触发方式)

定时计数器应用

题目:定时/计数器1做计数器1,工作模式2,使用定时/计数器0做定时器0让LED小灯100毫秒闪烁一次,计数器1记录LED闪烁次数,并且用数码管实时显示计数数值。硬件需要将P1^0与P3^5连接起来,使计数器得到触发。

查询方式

查询方式就是利用计数器计数溢出会使相应的溢出标志位置1来进行是否计数完成或计时完成。

1/*定时/计数器1做计数器1,工作模式2,使用定时器0让LED小灯100毫秒闪烁一次,
  2计数器1记录LED闪烁次数,并且用数码管实时显示计数数值。*/
  3#include < reg52.h >
  4#define uchar unsigned char
  5#define uint  unsigned int
  6
  7sbit we = P2^7;
  8sbit du = P2^6;
  9sbit LED = P1^0;
 10  
 11uchar code leddata[]={ 
 12
 13                0x3F,  //"0"
 14                0x06,  //"1"
 15                0x5B,  //"2"
 16                0x4F,  //"3"
 17                0x66,  //"4"
 18                0x6D,  //"5"
 19                0x7D,  //"6"
 20                0x07,  //"7"
 21                0x7F,  //"8"
 22                0x6F,  //"9"
 23                0x77,  //"A"
 24                0x7C,  //"B"
 25                0x39,  //"C"
 26                0x5E,  //"D"
 27                0x79,  //"E"
 28                0x71,  //"F"
 29                0x76,  //"H"
 30                0x38,  //"L"
 31                0x37,  //"n"
 32                0x3E,  //"u"
 33                0x73,  //"P"
 34                0x5C,  //"o"
 35                0x40,  //"-"
 36                0x00,  //熄灭
 37                0x00  //自定义
 38
 39                         };
 40
 41void delay(uint t_ms) //ms级延时
 42{
 43    uchar i;
 44    while(t_ms--)
 45        for(i = 114; i > 0 ; i--);
 46}
 47
 48void display(uchar i) //数码管显示函数
 49{
 50    uchar bai, shi, ge;
 51    bai = i / 100;        //显示百位
 52    shi = i % 100 / 10; //显示十位
 53    ge  = i % 10;           //显示个位
 54
 55    P0 = 0xff;              //清除断码
 56    we = 1;                    //打开位选
 57    P0 = 0xfe;              //1111 1110 
 58    we = 0;                   //关闭位选
 59
 60    du = 1;                   //打开段选
 61    P0 = leddata[bai];
 62    du = 0;                   //关闭段选
 63    delay(5);             //延时5毫秒
 64
 65    P0 = 0xff;             //清除断码
 66    we = 1;                  //打开位选
 67    P0 = 0xfd;             //1111 1101  
 68    we = 0;                  //关闭位选
 69
 70    du = 1;                         //打开段选
 71    P0 = leddata[shi]; 
 72    du = 0;                         //关闭段选
 73    delay(5);                   //延时5毫秒
 74
 75    P0 = 0xff;                   //清除断码
 76    we = 1;                        //打开位选
 77    P0 = 0xfb;                   //1111 1011  
 78    we = 0;                        //关闭位选
 79
 80    du = 1;                         //打开段选
 81    P0 = leddata[ge]; 
 82    du = 0;                         //关闭段选
 83    delay(5);                   //延时5毫秒 
 84}
 85
 86void main()
 87{
 88    uchar a;       //50次数计数
 89    TMOD = 0x61;//T0为定时器,工作模式1 16位计数器,T1为计数器,工作模式28位自动重装
 90    TH0 = 0x4b;
 91    TL0 = 0xfc;  //0x4bfc    定时50ms
 92    TH1 = 20;     //8位自动重装
 93    TL1 = 0;      //当TL1溢出时自动装入TH1的值  
 94    TR0 = 1;      //启动T0
 95    TR1 = 1;      //启动T1
 96    while(1)
 97    {
 98        if(TF0 == 1)   //判断T0是否溢出
 99        {
100            TH0 = 0x4b;
101            TL0 = 0xfc;//0x4bfc 定时50ms
102            TF0 = 0;     //清零便于下次判断
103            a++;          //50毫秒计数加1 
104        }
105        if(a == 2)    //判断是否到100毫秒
106        {
107            a = 0;       //清零便于下次记录50ms的次数
108            LED = ~LED;  //闪烁LED1
109        }           
110        display(TL1);//显示T1计数值
111    }
112}

中断方式

中断方式就是利用计数器计数溢出会使相应的溢出标志位置1,申请中断。

1/*定时/计数器1做计数器1,工作模式2,使用定时器0让LED小灯100毫秒闪烁一次,
  2计数器1记录LED闪烁次数,并且用数码管实时显示计数数值。*/
  3#include < reg52.h >
  4#define uchar unsigned char
  5#define uint  unsigned int
  6
  7sbit du = P2^6;
  8sbit we = P2^7;
  9sbit LED = P1^0;
 10
 11uchar code leddata[]={ 
 12
 13                0x3F,  //"0"
 14                0x06,  //"1"
 15                0x5B,  //"2"
 16                0x4F,  //"3"
 17                0x66,  //"4"
 18                0x6D,  //"5"
 19                0x7D,  //"6"
 20                0x07,  //"7"
 21                0x7F,  //"8"
 22                0x6F,  //"9"
 23                0x77,  //"A"
 24                0x7C,  //"B"
 25                0x39,  //"C"
 26                0x5E,  //"D"
 27                0x79,  //"E"
 28                0x71,  //"F"
 29                0x76,  //"H"
 30                0x38,  //"L"
 31                0x37,  //"n"
 32                0x3E,  //"u"
 33                0x73,  //"P"
 34                0x5C,  //"o"
 35                0x40,  //"-"
 36                0x00,  //熄灭
 37                0x00  //自定义
 38
 39                         };
 40
 41void delay(uint t_ms) //ms级延时
 42{
 43    uchar i;
 44    while(t_ms--)
 45        for(i = 114; i > 0 ; i--);
 46}
 47
 48void display(uchar i) //数码管显示函数
 49{
 50    uchar bai, shi, ge;
 51    bai = i / 100;          //显示百位
 52    shi = i % 100 / 10;   //显示十位
 53    ge  = i % 10;             //显示个位
 54
 55    P0 = 0xff;               //清除断码
 56    we = 1;                    //打开位选
 57    P0 = 0xfe;              //1111 1110百位显示
 58    we = 0;                   //关闭位选
 59
 60    du = 1;                  //打开段选
 61    P0 = leddata[bai];
 62    du = 0;                  //关闭段选
 63    delay(5);             //延时5毫秒
 64
 65    P0 = 0xff;           //清除断码
 66    we = 1;                //打开位选
 67    P0 = 0xfd;          //1111 1101十位显示  
 68    we = 0;                //关闭位选
 69
 70    du = 1;               //打开段选
 71    P0 = leddata[shi]; 
 72    du = 0;                //关闭段选
 73    delay(5);          //延时5毫秒
 74
 75    P0 = 0xff;          //清除断码
 76    we = 1;               //打开位选
 77    P0 = 0xfb;         //1111 1011个位显示  
 78    we = 0;              //关闭位选
 79
 80    du = 1;              //打开段选
 81    P0 = leddata[ge]; 
 82    du = 0;              //关闭段选
 83    delay(5);         //延时5毫秒 
 84}
 85
 86void main()
 87{
 88    TMOD = 0x61;  //T0为定时器,工作模式1 16位计数器,T1为计数器,工作模式28位自动重装
 89    TH0 = 0x4b;
 90    TL0 = 0xfc;   //0x4bfc    定时50ms
 91    TH1 = 10;      //8位自动重装
 92    TL1 = 0;        //当TL1溢出时自动装入TH1的值
 93    EA  = 1;        //打开总中断允许位
 94    ET0 = 1;       //打开定时/计数器0中断允许位
 95    TR0 = 1;       //启动T0
 96    TR1 = 1;       //启动T1      
 97    while(1)
 98        display(TL1); //显示当前计数值
 99}
100
101void timer() interrupt 1
102{
103    uchar a;     //用来记迭代次数
104    TH0 = 0x4b;
105    TL0 = 0xfc;//0x4bfc 定时50ms
106    TF0 = 0;     //清零便于下次判断
107    a++;           //50毫秒计数加1   
108    if(a==2)   //判断是否到100ms
109    {
110        LED=~LED;//LED灯闪烁
111        a=0;         //清零重记
112    }
113}

代码亲测有效,请注意硬件电路与代码的对应关系。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分