单片机定时/计数器的工作方式

描述

1硬件连接

定时器是单片机内部的特殊功能模块。

在控制系统中,常常要求有一些实时时钟以实现定时或者延时控制,如定时中断、定时检测、定时扫描等等,也往往要求有计数器,对外部事件进行计数。

要实现定时或者延时功能,一般有三种方法:软件定时,不可编程硬件定时,可编程硬件定时。

软件定时——让软件循环执行一段程序,程序本身并无执行目的,而是通过执行程序延时固定的时间,也就是以前的程序中经常使用的延时程序。这种方法降低了cpu的利用率。

不可编程硬件定时——如外部芯片555 时基电路,通过外部阻容,达到一定的延时功能,改变阻容大小可以改变延时长度。这种定时器取决于硬件,设定好以后不能通过软件更改。

可编程定时器——这种定时器的定时值可以通过软件确定和修改,使用灵活便捷。

本节所讲的定时器为第三种,可编程定时器,51单片机中T0/T1为2个相同的16位定时/计数器。

定时/计数器的结构:

计数器
图 1 定时/计数器的结构

TCON控制寄存器:

计数器

TCON用于控制外部中断和定时/计数器启动和中断,低4位用于控制外部中断,高4位用于控制定时/计数器T0和T1。

TCON.0~TCON.3(IT0、IE0、IT1、IE1)均为外部中断相关位,详见外部中断。

TR0(TCON.4):定时/计数器T0运行控制位。TR0=1时,T0开始工作;TR0=0时,T0停止工作。TR0由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。

TF0(TCON.5):定时/计数器T0溢出中断请求标志位。TF0=1时,申请进去定时器中断。T0计数溢出时由硬件自动置TF0为1。CPU响应中断后TF0由硬件自动清0。T0工作时,CPU可随时查询TF0的状态。所以,TF0可用作查询测试的标志。TF0也可以用软件置1或清0,同硬件置1或清0的效果一样。

TR1(TCON.6):定时/计数器T1运行控制位,其功能与TR0类同。

TF1(TCON.7):定时/计数器T1溢出中断请求标志位,其功能与TF0类同。

TMOD模式控制寄存器:

计数器

图 3 TMOD模式控制寄存器格式

TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1

GATE: 门控位。GATE=0时,只要用软件使TCON中的TR0或TR1为1,就可以启动

定时/计数器工作;GATA=1时,要用软件使TR0或TR1为1,同时外部中断引脚或也为高电平时,才能启动定时/计数器工作。即此时定时器的启动多了一条件。

计数器

M1M0:工作方式设置位。定时/计数器有四种工作方式,由M1M0进行设置。

计数器
表1 定时/计数器工作方式表

2定时/计数器的工作方式

一、方式0

方式0为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。

计数器
图 4 方式0工作原理图

计数初值计算初值的公式为:计数器

二、方式1

方式1的计数位数是16位,由TL0作为低8位、TH0作为高8位,组成了16位加1计数器。

计数器
图 5 方式1工作原理图

计数个数与计数初值的关系为:计数器

三、方式2

方式2为自动重装初值的8位计数方式。当TL0装满溢出时,系统自动将TH0中的数值装给TL0,TLO重新开始计数。

计数器
图 6 方式2工作原理图

计数个数与计数初值的关系为:计数器

四、方式3

方式3只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1=0,停止计数。工作方式3将T0拆分成为两个独立的8位定时/计数器TL0和TH0,两个计数器独立工作。

计数器
图 7 方式3工作原理图

计数个数与计数初值的关系为:计数器

3定时器0

#include< reg52.h > //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
sbit LED=P1^2;    //定义LED端口

/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
 TMOD |= 0x01;	  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响		     
 TH0=0x00;	      //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
 TL0=0x00;
 EA=1;            //总中断打开
 ET0=1;           //定时器中断打开
 TR0=1;           //定时器开关打开
}
/*------------------------------------------------
                    主程序
------------------------------------------------*/
main()
{
 Init_Timer0();
 while(1);
}

/*------------------------------------------------
                 定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 using 1
{
 TH0=0x00;		  //重新赋值
 TL0=0x00;

 LED=~LED;        //指示灯反相,可以看到闪烁

}

定时器0的程序代码

定时/计数器0 使用16位定时模式,计数初值为0,计数到65536 溢出,中断程序中LED取反,LED 以65536*2个时钟周期为周期闪烁。

计数个数与计数初值的关系为:计数器

4定时器1

#include< reg52.h > //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
sbit LED=P1^3;    //定义LED端口

/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer1(void)
{
 TMOD |= 0x10;	  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
 TH1=0x00;	      //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
 TL1=0x00;
 EA=1;            //总中断打开
 ET1=1;           //定时器中断打开
 TR1=1;           //定时器开关打开
}
/*------------------------------------------------
                    主程序
------------------------------------------------*/
main()
{
 Init_Timer1();
 while(1);
}
/*------------------------------------------------
                 定时器中断子程序
------------------------------------------------*/
void Timer1_isr(void) interrupt 3 using 1
{
 TH1=0x00;		 //重新赋值
 TL1=0x00;

 LED=~LED;       //LED闪烁

}

定时1的程序代码

5 产生1ms方波

#include< reg52.h > //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
sbit OUT=P1^2;    //定义OUT输出端口

/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
 TMOD |= 0x01;	              //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响		     
 TH0=(65536-500)/256;	      //给定初值,这里使用定时器最大值从500开始计数一直到65535溢出
 TL0=(65536-500)%256;		  //12M晶振计算指令周期1us,1ms方波半个周期500us,即定时500次
 EA=1;                        //总中断打开
 ET0=1;                       //定时器中断打开
 TR0=1;                       //定时器开关打开
}
/*------------------------------------------------
                    主程序
------------------------------------------------*/
main()
{
 Init_Timer0();
 while(1);
}
/*------------------------------------------------
                 定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 using 1
{
 TH0=(65536-500)/256;		  //重新赋值
 TL0=(65536-500)*256;        
                             							 
 OUT=~OUT;         			  //溢出然后输出端取反
                              //用示波器可看到方波输出
}

图 10 1ms方波的程序代码

示波器显示周期为1ms的方波信号。

6 产生多路不同频率的方波

#include< reg52.h > //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
 TMOD |= 0x01;	              //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响		     
 TH0=(65536-500)/256;	      //给定初值,这里使用定时器最大值从500开始计数一直到65535溢出
 TL0=(65536-500)%256;		  //12M晶振计算指令周期1us,1ms方波半个周期500us,即定时500次
 EA=1;                        //总中断打开
 ET0=1;                       //定时器中断打开
 TR0=1;                       //定时器开关打开
}
/*------------------------------------------------
                    主程序
------------------------------------------------*/
main()
{
 Init_Timer0();
 while(1);
}

/*------------------------------------------------
                 定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 using 1
{
 static unsigned char i;

 TH0=(65536-500)/256;		  	 //重新赋值
 TL0=(65536-500)*256;        

 i++;
 P1=i; //P1口8路输出不同频率,相当于一个分频器,高频用示波
       //器测量,低频可以直接用led观测
       //P1.0输出1ms方波,P1.1输出2ms,p1.2输出4ms,以此类推

}

图 11 多路不同频率方波的程序代码

中断部分,相当于一个分频器,在P1 口可以测量出8 路不同频率的方波。

P1 口测量不同频率方波,周期依次增大一倍。

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

全部0条评论

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

×
20
完善资料,
赚取积分