首页 理论教育单片机基于C语言应用实例-定时/计数器

单片机基于C语言应用实例-定时/计数器

【摘要】:定时/计数器从电路上来讲是一个脉冲计数器,当计数脉冲来自单片机内部机器周期时,我们习惯上称其为定时器,而当计数脉冲来自单片机外部的输入信号时,则称其为计数器。图7-7 定时/计数器0的结构两个8位寄存器都是用来保存计数值的,其使用方法非常灵活。① 0:仅当TCON寄存器的TR0=1时启动定时/计数器0。定时/计数器0对来自单片机片内的机器周期进行计数,每个机器周期计数器的值都会加1。

定时/计数器从电路上来讲是一个脉冲计数器,当计数脉冲来自单片机内部机器周期时,我们习惯上称其为定时器,而当计数脉冲来自单片机外部的输入信号时,则称其为计数器。8051系列单片机在片内集成了两个可编程的定时/计数器,分别称其为定时/计数器0(T0)和定时/计数器1(T1),二者都具有定时和计数的功能,其逻辑结构图如图7-6所示。

图7-6 定时器/计数器的逻辑结构

7.2.1 定时/计数器的结构

定时/计数器0和定时/计数器1都具有以下两种工作模式:

(1)计数器模式:在计数器工作模式时,两个定时/计数器可以分别对外部输入脉冲进行计数,其中T0使用P3.4引脚,T1使用P3.5引脚作为计数脉冲的输入端,一旦在输入端出现有效的下降沿,计数器的计数值会加1。

(2)定时器模式:在定时器工作模式时,两个定时/计数器可以分别对来自单片机内部的机器周期进行计数,每经过1个机器周期的时间,计数器的值都会加1,依据计数器所计脉冲的数量和机器周期的长度,就可以计算出时间。

8051系列单片机的定时/计数器0内部使用两个8位的寄存器来保存计数值,高8位的寄存器称为TH0,低8位的寄存器称为TL0,其结构如图7-7所示。

图7-7 定时/计数器0的结构

两个8位寄存器都是用来保存计数值的,其使用方法非常灵活。按照工作方式的不同,两个寄存器既可以组合在一起组成一个16位的寄存器,也可以分成两个8位的寄存器单独使用,定时/计数器0的工作方式由寄存器TMOD控制。可以将TH0和TL0形象地看成两个水杯,如图7-8所示。当其工作在16位模式时,可以共同用于盛水,而当其工作在8位模式时,可以分别盛水。当盛水量超过其最大容量时,水会溢出。

图7-8 定时/计数器0的结构示意

定时/计数器1的结构和定时/计数器0非常类似,也是由两个8位的寄存器构成,用来保存计数值,这两个寄存器分别称为TH1和TL1,具体结构如图7-9所示。

图7-9 定时/计数器1的结构

7.2.2 定时/计数器的工作原理

以定时/计数器0为例来说明定时/计数器是如何工作的。软件将定时/计数器0设置成16位定时器,定时/计数器0中的两个计数器TH0和TL0组合在一起用于保存计数值,其初值为0,如图7-10所示。

图7-10 定时/计数器的计数值为0

定时/计数器启动后,每隔一个机器周期,计数器的值都会加1,即当单片机使用的晶振频率为12 MHz时,每隔1 µs计数器的值就会加1,经过65 535 µs后,计数器的值会被加满,如图7-11所示。这时计数器只是加满的状态,并没有溢出,也不会引发中断。

图7-11 定时/计数器的计数值已满

再经过一个机器周期的时间后,计数器又加1并产生溢出,计数器又回到原来的初始状态,如图7-12所示。计数器产生计数溢出后,单片机会硬件置位TF0,并向CPU申请中断,如果该中断得到允许,单片机则开始执行中断服务程序。

图7-12 溢出后定时/计数器的值为空

从上面的例子我们可以看出,从开始计时到计数溢出,总计用了65 535+1 µs,即65 536 µs的时间。有了这个例子作为理论基础,我们就不难设计出产生50 ms计数溢出的定时器应用(晶振为12 MHz),具体做法如下:

用定时器计数的最大时间值减去需要设定的时间值,得到的数字即为定时器的初值,在计数器开始计数之前,把初值预先写入到定时器中,让定时器在这个初值的基础上开始计时,这样计数器从开始计数到计数溢出时正好是50 ms。

初值=计数器的最大计数值(65 536 µs)-目标时间(50 000 µs)=15 536 µs

初值计算好后,一个棘手的问题出现了:初值如何在两个8位的计数器寄存器之间进行分配呢?方法也很简单,就是将初值对256求模后,装入高8位的TH0中,而将初值对256求余后,装入低8位的TL0中,具体计算方法如下:

TH0=15536/256

TL0=15536%256

7.2.3 定时/计数器的控制寄存器

1.定时器控制寄存器TCON(Timer Control Register)

前面已介绍,此处略。

2.定时/计数器工作方式控制寄存器TMOD(Timer Mode Control Register)

TMOD寄存器用于选择定时/计数器的工作方式,其中高四位控制定时/计数器1,低四位控制定时/计数器0,不可以位寻址。

(1)bit7(GATE):定时/计数器1的门控位,即定时/计数器1开启方式选择位,用于设置定时/计数器1的启动方式。

① 0:仅当TCON寄存器的TR1=1时启动定时/计数器1。

② 1:由TCON寄存器的TR1=1和INT1引脚的高电平共同来启动定时/计数器1。

(2)bit6(C/T位):定时/计数器1模式选择位。

① 0:设定为定时器模式。定时/计数器1对来自单片机片内的机器周期进行计数,每个机器周期计数器的值都会加1。

② 1:设定为计数器模式。定时/计数器1对来自单片机引脚T1(P3.5)的脉冲信号进行计数。

(3)bit5、bit4(M1:M0)位:定时/计数器1工作方式选择位,具体设置见表7-2。

(4)bit3(GATE):定时/计数器0的门控位,即定时/计数器0开启方式选择位,用于设置定时/计数器0的启动方式。

① 0:仅当TCON寄存器的TR0=1时启动定时/计数器0。

② 1:由TCON寄存器的TR0=1和INT0引脚的高电平共同来启动定时/计数器0。

(5)bit2(C/T位):定时/计数器0模式选择位。

① 0:设定为定时器模式。定时/计数器0对来自单片机片内的机器周期进行计数,每个机器周期计数器的值都会加1。

② 1:设定为计数器模式。定时/计数器1对来自单片机引脚T0(P3.4)的脉冲信号进行计数。

(6)bit1、bit0(M1:M0位):定时/计数器0工作方式选择位,具体设置见表7-2。

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

7.2.4 定时/计数器的配置

按照TMOD寄存器上M1、M0位的设置不同,定时/计数器可以工作在四种工作方式下:

1.方式0:13位定时/计数器

当M1:M0位的值为00时,定时/计数器被设定为工作方式0。在方式0下,定时/计数器0被设定成为一个13位的计数器,由TL0的低5位和TH0的全部8位构成,其所能装入的最大数值为213 = 8192。定时/计数器0在方式0下的配置方法如图7-13所示。

图7-13 定时/计数器0的工作方式0

同样,定时/计数器1在方式0时也被设定成为一个13位的计数器,由TL1的低5位和TH1的全部8位构成,具体的配置方法如图7-14所示。(www.chuimin.cn)

图7-14 定时/计数器1的工作方式0

2.方式1:16位定时/计数器

当M1:M0的值为01时,定时/计数器被设置为工作方式1。定时/计数器0在被设定为方式1时,成为一个16位的计数器,由TL0的8位和TH0的8位构成,其能装入的最大数值为216=65536。定时/计数器0在方式1下的配置方法如图7-15所示。

图7-15 定时/计数器0的工作方式1

定时/计数器1在被设定为方式1时,也成为一个16位的计数器,如图7-16所示。

图7-16 定时/计数器1的工作方式1

3.方式2:8位初值自动重装定时/计数器

当定时/计数器工作在方式0和方式1时,计数溢出后计数器的值清零,如需再次定时或计数,需要用软件的方法给定时器装入初值,这样不仅会影响定时的精度,也会给程序设计带来不便,而方式2的初值自动重装定时/计数器可以很好地解决这个问题。

当M1:M0位的值为10时,定时/计数器被设置为工作方式2。定时/计数器0在被设定为方式2时,TL0用作计数,而TH0用作常数缓冲器,用来保存计数器的初值。当TL0产生计数溢出后,硬件会自动将TH0中的初值调出并且装入TL0中,为下一次计数做好准备。定时/计数器0在工作方式2下的结构如图7-17所示。

图7-17 定时/计数器0的工作方式2

工作方式2可以省去用户使用软件反复重装初值的麻烦,只要在初始化定时器时一次性把初值分别装入TL0和TH0中即可,既简化了操作,又能提高计数的精度。在工作方式2下,由于TH0用于保存初值,计数的只有8位的TL0,所以计数的最大值仅为255。

工作方式2非常适合用于那些需要重复计数的应用中,例如:可以通过此方式产生固定频率的脉冲信号,甚至是当作串行数据通信的波特率发送器使用。定时/计数器1在设定为方式2时,原理与定时/计数器0相同,如图7-18所示。

图7-18 定时/计数器1的工作方式2

4.方式3:两个8位定时器

当M1:M0的值为9时,定时/计数器0被设置为工作方式3。定时/计数器1不能工作在方式3下,如果把定时/计数器1设置为工作方式3,它会停止运行。在工作方式3下,定时/计数器0被拆分成两个独立的8位计数器TL0和TH0。

其中TL0既可以作为计数器使用,也可以作为定时器使用,原定时/计数器0的各控制位和引脚全部归TL0使用,其功能和操作方法与方式0或方式1类似。而TH0就没有那么多“资源”可利用了,只能作为简单的定时器使用,而且由于定时/计数器0的控制位已被TL0占用,因此只能借用定时/计数器1的控制位TR1和TF1,也就是TH0计数溢出时会置位TF1,TR1则用于控制TH0的启动和停止。定时/计数器0在工作方式3下的结构如图7-19所示。

图7-19 定时/计数器0的工作方式3

工作方式3下,TL0既能作为定时器也能作为计数器使用,而TH0由于没有了输入引脚只能作定时器使用,在该方式下定时/计数器0可以构成两个定时器或者一个定时器和一个计数器。当使用8051单片机的串行口通信时,定时/计数器1被用作波特率发生器的时基,这时能完成定时/计数任务的只剩下定时/计数器0。如果此时恰好需要两个定时器,就可以把定时/计数器0设定为方式3,将其拆分成TH0和TL0两个定时器。

编程向导:定时/计数器的初始化。

定时/计数器的初始化设置可分为以下5个步骤:

(1)编程TMOD寄存器,设置定时/计数器的工作方式。

(2)计算定时/计数器的初值,并将其写入TH0和TL0或TH1和TL1中。

(3)如果使用中断,还需设置IE寄存器,开启总中断EA和相应的定时器中断ET0或ET1。

(4)如果使用中断优先级,还需设置中断优先级寄存器IP。

(5)置位TCON寄存器的控制位TR0或TR1位,启动定时器。

7.2.5 定时/计数器的编程应用

定时/计数器是单片机的学习重点,必须要很好地理解和掌握。下面通过两个实训来进一步加深对定时/计数器的理解。

基于定时器的编程应用可以使用中断法或查询法两种,其中中断法可以减轻CPU的查询负担。

【实训7.2】编写基于中断法的秒计时器。程序要实现的目的是用四位数码管显示时间,高两位显示秒,低两位分别显示十分之一秒和百分之一秒。电路图如图7-20所示。

图7-20 中断法秒计时器电路图

分析:该实训和任务6.1的编程有相似之处,任务6.1中使用不精确延时方式下通过按键控制来让数码管显示数字,本实训要实现精确计时,并且在按键控制下实现不同功能。任务6.1的显示函数是有参函数,主要是通过全局变量“keynum”来传递需要显示的值,但本程序的四个显示数字是不同进制的,个位和十位是十进制,而百位和千位是六十进制,如果采用任务6.1的数据处理方法显然是不行的,对百位数显示的数字是0~9,但要带小数点,所以在程序中显示段码要和0x80进行或运算,即P1=seg[baiwei]|0x80,满10进1到千位,千位能显示的数字是0~5,所以要对“keynum”的范围进行限制,程序中要求“keynum>=6000”就行重新计数。在定时中断程序中,根据题意设定一次中断定时10 ms,即10000 µs,在晶振频率为12 MHz时,一个机器周期是1 µs,定时10000 µs的定时器初值就是65536-10000,TH0=(65536-10000)/256,TL0=(65536-10000)%256,工作在16位定时板式下。

秒计时器代码清单:

以上代码经正确编译后下载到系统板中,程序运行后数码管显示时间值为“00.00”,按K1键计时器启动,按K2键计时器停止,按K3键清零,按K4键计时器会暂停。具体的运行状态如图7-21所示。

图7-21 秒计时器(显示和按键部分)

在以上的程序中,是通过定时器的中断产生时基信号驱动数码管显示时间的。在某些应用中,也可以不使用中断,仅使用查询标志位的方法来达到定时或计数的目的。

【实训7.3】基于查询标志位的定时器应用。

在图7-22的基础上,使用查询法得到时基信号,让流水灯演示二进制的累加过程,具体程序见代码清单。

图7-22 流水灯演进电路图

分析:让流水灯每秒变化一次,从D1变化到D8,模拟二进制累加过程,从低位开始累加。用查询方式使用定时器,第50 ms计数一次,计满20次就是1 s。要点亮D1,则P0.0为低电平,但sec=1时,二进制代码为00000001,如果直接用P0=sec,则D1不亮,而D2~D8亮,没有达到我们的设计意图;如果用P0=256-sec,这里P0=11111110,则可以达到设计意图。

二进制数字累加器代码清单:

在Proteus环境下让程序运行,流水灯会每隔1 s变化一次,演示二进制的累加过程。具体状态如图7-23所示。

图7-23 二进制数字累加器Proteus模拟