代码钢琴家 阅读(97) 评论(0)

 标准51架构的单片机有2个定时器 :T0  和  T1,他们2个的用法几乎一样。下面主要讲T0定时器的用法。

首先,一个机器要工作,总体上一般分为5个步骤:配置工作模式、设置工作参数、开始工作,检查工作状态,停止工作。

定时器的使用也是这3个步骤。

 

我们先来对定时器有一个宏观的了解。

 

可以看出:我们通过TR0(R是Run 的缩写)控制定时器的启动和停止。当定时器启动后,定时器开始工作。每一个定时器背后有2个8位 计数存储器帮他计数,程序每经过1个

机器周期,存储器就加1。但是呢,2个存储器的容量是有限的,最大计数到 2的16次方65536,再继续下去,就爆表了,这个时候,TF0(F 是Flow的缩写)就报警了,

它本身的值就会从0变为1。

 

顺便提一下:标准C51的1个机器周期为12个时钟周期。如果晶振的频率是11.0592MHz,那么时钟周期就是   1 / (11.0592x10^6) 秒   (1MHz = 10^6Hz)

那么,存储器每加1,程序就经过了  12 / (11.0592x10^6) 秒。这就是我们衡量的基础依据。

 

下面来认识2个寄存器,也就是我开始提到的配置工作模式和设置工作参数的2个寄存器。

 

TCON控制寄存器

 

低4位这里用不到,大家不用管。

高4为就是T0 和 T1有关的。

TF 就是溢出标志位,TR是定时器启动停止控制位。

 

TMOD 工作模式寄存器

高4位是定时器T1的模式控制,低4位是T0 的。

GATE和C/T,为了方便,这里也不做介绍。

T0和T1的工作模式,是由M0和M1共同来决定的

M1 M0 模式
0 1 TH和TL2个一起来计数。16位计数存储器模式
1 0 TH负责初始化TL,TL计数。8位重装模式

 

 

16位计数存储模式

我们来写一个延时函数,并控制一个LED的闪烁。

#include<reg51.h>
typedef unsigned int uint;
# define T0MODE_16  1


/**********函数声明**************/
void loop();
void delay(uint t);
/******************************/


sbit LED = P0^0;

void main()
{
    
    loop();


}

void loop()
{
       LED = 1;
       delay(1000);
       LED = 0;
       delay(1000);
}


void delay(uint t)  //延时 t ms
{
     uint i=0;
     TMOD = T0MODE_16;   //计时器0以16为存储计时器工作
     TH0 = 252 ;
     TL0 = 102; 
     TR0 = 1;


         for(;i!=t;)    
         {
       
          if(TF0==1)      //发生一次溢出,也就是过了1ms
           {
               TF0=0;       //溢出位清零,取消警报
               TH0 = 252 ; //重新配置初始值
               TL0 = 102;
               i++;           //溢出次数加1 ,溢出1次是1ms,溢出t次就是t ms
           }
         
 
        }
    
}     

疑问:下面2句是怎么得来的呢?

               TH0 = 252 ; 
               TL0 = 102;

前面我们知道:存储计数器加1,就代表1个机器周期,也就是12 / (11.0592x10^6) 秒,那么,经过1毫秒一共需要存储计数器加1加几次呢?

 12 / (11.0592x10^6)      -----     1

 

 1 x 10-3                               ------     x      求出 x≈922次

 而16位的存储计数器能够加1加65536次,所以一开始应该给TH0和TL0装初始值:65536-922 =64614,让他们只能计数922次就爆表溢出

(就像一个瓶子开始就装了水,再来装水就不能装很多了)

 

 

8位重装模式

8位重装模式是:只有TL0计数,TH0不变,他只为TL0提供初始值。当TL计数溢出后,TF0就为1,如果继续工作,TH0就把自己的值赋给TL0,再开始计数,如此循环下去。

上面些写了一个毫秒级的delay函数,下面用8位重装模式写一个控制微秒级别的函数。

 

计算方法和上面一样,大家可以自己算

void delayMicro(uint t)        .//延时t微秒
{
     int i=0;
     TMOD = T0MODE_8reload;     //TMOD = 2
     TH0= 255 ;    
     TL0= 255; 
     TR0=1;
               

     for(;i!=t;)
     {
        
        if(TF0==1)
        {
             TF0=0;  //自动重装
             i++;
        }
          
     }

    
}

 

 

最后,我们来用P0口模拟PWM输出,做一个呼吸灯 :)

 

#include<reg51.h>
typedef unsigned int uint;

# define T0MODE_16 1
# define T0MODE_8reload 2
# define TRUE 1
# define FALSE 0

/**************函数声明******************/
void loop();
void delay(uint t); 
void delayMicro(uint t);
/********************************/

sbit LED = P0^0;


void main()
{



    loop();



}

void loop()
{
    int step = 0;
    int again  = FALSE;

    while(1)
    {
        
        LED = again?0:1;
        delayMicro(step);

        LED = again?1:0;;
        delayMicro((500-step));

        step+=1;

        if(step>500)
        {
             step =0;
             again = again?FALSE:TRUE;
        }

     }
}


void delayMicro(uint t)        
{
     int i=0;
     TMOD = T0MODE_8reload;     //TMOD = 2
     TH0= 255 ;    
     TL0= 255; 
     TR0=1;
               

     for(;i!=t;)
     {
        
        if(TF0==1)
        {
             TF0=0;  //自动重装
             i++;
        }
          
     }

    
}