单片机学习(三)定时器篇

2019-04-15 19:27发布

一、定时器介绍        定时/计数器T0和T1分别是由两个8位的专用寄存器组成,即定时/计数器T0由TH0和TL0组成,T1由TH1和TL1组成。此外,其内部还有2个8位的特殊功能寄存器TMOD和TCON,TMOD负责控制和确定T0和T1的功能和工作模式,TCON用来控制T0和T1启动或停止计数,同时包含定时/计数器的状态。 [1]  TF1:定时器1溢出标志。定时/计数器溢出时由硬件置位。中断处理时由硬件清除。或用软件清除。 TF0:定时器0溢出标志。定时/计数器溢出时由硬件置位。中断处理时由硬件清除,或用软件清除。 二、单片机的内部框图与定时器工作原理分析
从上面的图中红线可以看出由TMOD选择由那个定时器工作,工作于什么方式;
从上面的图中蓝线可以看出由TCON决定定时器是否启动;
从上面的图中黄线可以看出外部技术输入由TH和TL进行累计;
从上面的图中紫线可以看出当TH和TL计数溢出时会向TCON进行申请报告;
从上面的图中绿线可以看出所有的定时中断都由TCON向CPU进行中断申请;
从上面的图中黑线可以看出外部中断直接向CPU进行中断申请; 三、寄存器介绍 TCON:
TF0和TF1:定时器/计数器溢出标志位。                     当定时器/计数器0(或定时器/计数器1)溢出时,由硬件自动使TF0(或TF1)置1,并向CPU申请中断。                     CPU响应中断后,自动对TF1清零。TF1也可以用软件清零。  TR0和TR1:定时器/计数起运行控制位。  
                     TR0(或TR1)=0,停止定时器/计数器0(或定时器/计数器1)工作。
                     TR0(或TR1)=1,启动定时器/计数器0(或定时器/计数器1)工作。   TMOD:
GATE:门控位。  
             GATE=0,只要用软件使TR0(或TR1)置1就能启动定时器/计数器0(或定时器/计数器1);
             GATE=1,只有在(或)引脚为高电平的情况下,且由软件使TR0(或TR1)置1时,才能启动定时器/计数器0(或定时器/计数器1)工作。不管GATE处于什么状态,只要TR0(或TR1)=0定时器/计数器便停止工作。
C/T: 定时器/计数器工作方式选择位。
           C/T =0,为定时工作方式;
           C/T=1,为计数工作方式。  
M0、M1:工作方式选择位,确定4种工作方式。


IE:
EA = 1, CPU开放总中断;     
ET0 = 1,允许T0中断;
TR TL:定时器寄存器
注意:由于reg52.h的库定义了大部分的寄存器所以可以直接给TCON TMOD IE赋值操作或者是单独寄存器操作。


四、中断程序执行方法和定时计数公式
中断程序执行方法有直接中断和查询两种方法,查询即查询TF位是否置位为1
定时初值计算公式为:
定时时间=(计数最大值 – 计数初值)×机器周期 
机器周期T = 12/晶振频率


或者是用取模的方式
TH0=(计数最大值 – 定时时间)/256;
TL0=(计数最大值 – 定时时间)%256;


首先解析为什么要设定初值?
当设定定时器为16为计数器时,则计数最大值为2^16 = 65536;
TH和TL分别为8位,即TL每逢256进一位,所以除掉256就能看出TH进了多少位,取模则是余下多少位
举个例子,2位计数器最大计数为4,要将初值6分到两个2位计数器,由于低位逢四进1所以剩下2 即TL = 2然后高位是1即TH=1,按照上面的方法:2^4 = 16,2^2 = 4; TH = (16-(16-6))/4=1(整型不算小数); TL = (16-(16-6))%4=2;可见结果是一样的。 一般的我们选取初值 TH0 = 0x3c,TLO = 0xb0,这时寄存器跑满时的时间为50ms,可以使这个过程进行20次,间隔也就是1s。 五、程序设计 //通过定时器中断实现数码管显示从0~59,间隔为1s #include
sbit LED1 = P1^0;
#define DataPort P1     //宏定义,如果换接口,需要修改这里
sbit Seg_Latch = P2^2;   //段锁存
sbit Bit_Latch = P2^3;   //位锁存
unsigned char code Seg_Code[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};  //段码从0~9
unsigned char code Bit_Code[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};  //位码,控制8个LED灯
void delayls(void);
void Display(unsigned char m,unsigned char num,unsigned int n);
static unsigned int n = 0;
int main(void)
{
        unsigned char i;
        TMOD = 0x01;
        TH0 = 0x3c;
        TL0 = 0xb0;
        EA = 1;        //开中断
        ET0 = 1;
        //因为只有一个中断,所以IP不用设置
        TR0 = 1;   //开启定时器0,等待中断到来
        while(1)
        {
                Display(1,2,n);
        }
}
void T0_ISR(void) interrupt 1
{
        unsigned char i;
        
        EA = 0;   //屏蔽其他中断
        TH0 = 0x3c;   //重新赋值,保证每次都是 50ms
        TL0 = 0xb0;
        i++;
        if(i == 20)
        {
                i = 0;
           
                if(n < 60)
                {
                    n++;
                }
                else
                {
                    n = 0;
                }
        }
        
        EA = 1;
}
  void Display(unsigned char m,unsigned char num,unsigned int n)   //m表示从第几个数码管开始控制,num表示到第几个数码管,n表示要显示的数字
{
        unsigned char i,j,a[5],l;
        a[0] = n / 10;
        a[1] = n % 10;
        for(j = m-1;j < num;j++)
        {
                DataPort = 0;   //初始化
                Seg_Latch = 1;  
                Seg_Latch = 0;  
                            
                DataPort = Bit_Code[j];  //送位码
                Bit_Latch = 1;    //位开门
                Bit_Latch = 0;    //关门
                
                DataPort = Seg_Code[a[j]];  //送段码
                Seg_Latch = 1;  //段开门
                Seg_Latch = 0;   //关门     
        }          }