再谈51系列(包括52)单片机定时器/计数器

         学过单片机的人都知道,中断定时是其中很重要的内容,可是却也是难点,其实说实在的,只有你认真看芯片手册,应该觉得还是比较简单的,因为那些设置内容在数据手册里几乎全部设置到,而且讲得很清楚了。个人认为: 芯片手册才是王道,看别人代码视频等只能当做辅助,认真研读芯片手册最重要
     说到单片机,自然数51系列最popular了,而51系列中最popular的又数52了,因此下面将以STC89C52RC为实例谈谈我对定时器/计数器的理解
  微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑

      首先说说定时器/计数器有什么区别,其实,定时器/计数器在硬件上用的是芯片内部的相同部分,因此我们总是看到把他们写成"定时器/计数器",但他们唯一区别在于:①作为计数器,在减到0以后,输出一个信号便结束,除非重新触发

   ②作为定时器,减到0以后,自动恢复初值重新计数,并不断产生信号


 下面简单列举几个例子


 根据芯片手册,可以得到引脚图和定时、计数设置的方法


再谈51系列(包括52)单片机定时器/计数器_第1张图片

这是80C52单片机引脚图,位于英文版第1页


再谈51系列(包括52)单片机定时器/计数器_第2张图片

这是定时/计数设置顺序,见中文版第55页


再谈51系列(包括52)单片机定时器/计数器_第3张图片

这是中断序列号,特别注意定时器/计数器2的中断号为5,见中文版P24


(1) 定时/计数器0和1

先看寄存器TMOD的功能描述,见中文版第51页

再谈51系列(包括52)单片机定时器/计数器_第4张图片


以下是实例

 ① 定时器(关于此段详细使用请看中文版P51-P55)

下面是间隔1s的流水灯:定时器0,工作方式1(16位定时/计数器),
/*每隔1s灯闪烁一次,但由于晶振11.0592M时最长定时71.777ms,因此
采用1s=1000ms=50ms*20次,即每次中断50ms,进入中断20次*/
/***(定时器与计数器不同在于它中断一次后能复位继续下一次)**/

#include<reg52.h>
void timer0_init(); /*中断初始化,使定时器/计数器开始工作*/
void led();    /*中断后对led进行操作*/
unsigned char code table[]={0xfe,0xfd,0xfb,0xf7,
                            0xef,0xdf,0xbf,0x7f};
int t,num;
void main(void)
{

timer0_init();
led();
}

void timer0() interrupt 1
{
t++;
}

void timer0_init()     
{
//设置工作方式控制字
TMOD=0x01;                //即设置TMOD为0000 0001,定时器0,工作方式1(16位定时/计数器)
//定时初值的计算并装入
/*由[12/(11.0592*10^6)]*x=50ms=50*10^3μs,得到x=46080*/
TH0=(65536-46080)/256;//求(65536-46080)构成的16为二进制数的高8位,H代表高/high,0代表定时器0  
TL0=(65536-46080)%256;//求(65536-46080)构成的16为二进制数的低8位,L代表低/low,0代表定时器0
//开放主机中断
EA=1;
ET0=1;               //0代表定时器0
//设置启/停位TRx
TR0=1;               //0代表定时器0
}

void led()
{
while(1)
  {
    if(t==20)
        {
        t=0;  //中断1s后使t清零
        P1=table[num];
        num++;
        if(num==8)
        num=0;
        }
    }
}


定时器1和0设置相同,不在赘述


计数器

下面是计数到1亮led5-8计数到2亮led1-4的程序:计数器0,方式1(16位定时/计数器)

由于

再谈51系列(包括52)单片机定时器/计数器_第5张图片
因此我们要使用计数器必须有外部信号输入,你可以把T0/P3.4接到示波器或者脉冲源上,这里由于是软件,因此从外部给他输入变化的电平,引入一个input_simulate()函数,用以模仿外部输入到T0/P3.4的信号

又由于计数器计数1次所需时间很短,肉眼无法分辨,因此这里在引进一个delay_ms(unsigned int z)延时函数,用以使计数到1暂停1s以便让人能看清

#include<reg52.h>
void counter0_init(); /*中断初始化,使定时器/计数器开始工作*/
void input_simulate();     /*模仿外部输入到T0/P3.4的信号*/
void delay_ms(unsigned int z);    /*延时函数,以便看到一次计数后led变化*/
void main()
{
counter0_init();    
input_simulate();

if(TL0==1)//进行判断
P1=0x0f;
delay_ms(1000);//延时1s

input_simulate();

if(TL0==2)
P1=0xf0;
delay_ms(1000);
}

void counter0_init()
{                                                
//设置工作方式控制字
TMOD=0X05;//即0000 0101,计数器0,方式2(16位定时/计数器)
//计数初值的计算并装入
TH0=0X00;
TL0=0X00;
//开放主机中断
ET0=1;
EA=1;
//设置启停位TRx
TR0=1;
}

void input_simulate()
{
T0=0;
T0=1;
}

void delay_ms(unsigned int z)
{
unsigned int x,y;
for(x=z;x>0;x--)
   for(y=110;y>0;y--);
}

计数器1和0设置相同,不在赘述

(2) 定时/计数器2

先看T2CON寄存器的功能描述,见中文版P67
再谈51系列(包括52)单片机定时器/计数器_第6张图片
定时器(关于此段详细使用请看中文版P67-P69)

下面是间隔1s的流水灯:定时器0,工作方式1(16位定时/计数器),

由于
再谈51系列(包括52)单片机定时器/计数器_第7张图片
因此每进入中断一次,需要用软件把定时器2要软件把TF2至0

#include<reg52.h>
void timer2_init(); /*中断初始化,使定时器/计数器开始工作*/
void led();     /*中断后对led进行操作*/
unsigned char code table[]={0xfe,0xfd,0xfb,0xf7,
                            0xef,0xdf,0xbf,0x7f};
int t,num;
void main()
{
timer2_init();
led();                                    
}

void timer0() interrupt 5
{
TF2=0;    /*特别注意定时器2要软件把TF2至0*/
t++;
}

void timer2_init()
{
//设置工作方式控制字
T2CON=0x04;/*设置T2CON为0000 0100,定时器2,内部定时器,16位自动重装*/
//计数初值的计算并并装入
/*由[12/(11.0592*10^6)]*x=50ms=50*10^3μs,得到x=46080*/
TH2=(65536-46080)/256;/*求(65536-46080)构成的16为二进制数的高8位,H代表高/high,0代表定时器0*/  
TL2=(65536-46080)%256;/*求(65536-46080)构成的16为二进制数的低8位,L代表低/low,0代表定时器0*/
//中断允许位ETx,EA的设置
ET2=1;
EA=1;
//启停位TRx的设置
TR2=1;
}

void led()
{
while(1)
    {
    if(t==20)
        {
        t=0;  /*中断1s后使t清零*/
        P1=table[num];
        num++;
        if(num==8)
        num=0;
        }
    }
}


计数器
下面是计数到1亮led5-8计数到2亮led1-4的程序:计数器2,方式1(16位定时/计数器)

由于

再谈51系列(包括52)单片机定时器/计数器_第8张图片

再谈51系列(包括52)单片机定时器/计数器_第9张图片

因此我们要使用计数器必须有外部信号输入,你可以把T2EX/P1.1接到示波器或者脉冲源上,这里由于是软件,因此从外部给他输入变化的电平,引入一个input_simulate()函数,用以模仿外部输入到T2EX/P1.1的信号

又由于计数器计数1次所需时间很短,肉眼无法分辨,因此这里在引进一个delay_ms(unsigned int z)延时函数,用以使计数到1暂停1s以便让人能看清

#include<reg52.h>
void counter2_init(); /*中断初始化,使定时器/计数器开始工作*/
void input_simulate();     /*模仿外部输入下降沿的信号*/
void delay_ms(unsigned int z);    /*延时函数,以便看到一次计数后led变化*/
void main()
{
counter2_init();

input_simulate();

if(T2EX==1)//进行判断
EXF2=0;
P1=0x0f;
delay_ms(1000);//延时1s

input_simulate();

if(T2EX==2)
EXF2=0;
P1=0xf0;
delay_ms(1000);
}

void counter2_init()
{
//设置工作方式控制字
T2CON=0X0D;/*即0000 1101,计数器0,方式2(16位定时/计数器)*/
//计数初值的计算并装入
TH2=0X00;
TL2=0X00;
//开放主机中断
ET2=1;
EA=1;
//设置启停位TRx
TR2=1;
}

void input_simulate(void)
{
T2EX=1;
T2EX=0;
}

void delay_ms(unsigned int z)
{
unsigned int x,y;
for(x=z;x>0;x--)
   for(y=110;y>0;y--);
}

以上就是关于52单片机的定时计数器的使用,其实说白了就一点,根据芯片手册设置电平,最后还是强调那一句: 芯片手册才是王道,看别人代码视频等只能当做辅助,认真研读芯片手册最重要


你可能感兴趣的:(再谈51系列(包括52)单片机定时器/计数器)