折腾来折腾去

pikipity的blog

第六章 计时器/计数器

计时器与计数器使用的寄存器和它们的工作原理是一样的,当计时时脉从“0”变为“1”的时候,内部的累加器加一,当累加器溢出的时候,检查中断,如果中断置能,便进入中断,否则重新开始计数。它们唯一的不同就是使用的计时时脉不一样,计时器使用的是内部时脉,因为内部时脉很稳定,所以可以用来计算时间;计数器使用的是从 T1 或者 T0 口输入的外部时脉,如果这个外部时脉的信号代表一个事件发生的次数,那么计时/计数器就是在计算这个事件发生的次数。8051中有两个计时/计数器– Timer0 和 Timer1。

控制寄存器

计时/计数器由两个寄存器来控制,它们分别为 TCON 和 TMOD。Timer0 和 Timer1 各有16位用来存放累加数目的寄存器(根据使用的模式不一样,这16位的功能不一样,不一定全部用来计数)。存放 Timer0 累加数目的寄存器是 TH0(高八位)和 TL0(低八位);存放 Timer1 累加数目的寄存器是 TH1(高八位)和 TL1(低八位)。

TCON

TCON 允许位元寻址。每一位代表的意思如下:

TF1  TR1  TF0  TR0  IE1  IT1  IE0  IT0
  • TF1 和 TF0: Timer1/Timer0 的溢出旗标。当用来存放累加数目的寄存器(也就是 THx 和 TLx)溢出的时候硬件自动置一,当进入对应中断向量的时候硬件自动清零。
  • TR1 和 TR0:Timer1/Timer0 的运行控制位。置一则开启 Timer1/Timer0,Timer1/Timer0 便开始计时或者计数;清零则关闭 Timer1/Timer0,Timer1/Timer0 停止计时或者计数(其实还会受到 TMOD 中 GATE 位的影响,在设置的时候需要注意)。
  • IE1 和 IE0: 外部中断 INT1/INT0 边缘触发旗标。当检测到外部中断信号源边缘的时候,硬件自动置一,进入 INT1/INT0 所对应的的中断服务时,硬件自动清零
  • IT1 和 IT0:INT1/INT0 触发方式控制位。当置一的时候,外部中断源处于下降沿的时候触发对应的外部中断服务;清零的时候,外部中断源处于低电平(也就是“0”)的时候触发对应的外部中断服务(如果一直处于低电平,就会不停的触发中断服务,使用 INT1/INT0 的时候需要注意)。

由于 IEx 和 ITx 是用来控制外部中断 INTx 的,这一部分先不管它们,以后再介绍。TFx 会在进入中断之后硬件自动清零,所以当我们使用计时/计数器的中断服务的时候一般不用管这一位。所以对于计时/计数器,一般真正使用的只有 TRx 位,用来启动和停用 计时/计数器。

TMOD

TMOD 不可以位元寻址。TMOD是用来选择8051的计时/计数器工作模式的。在8051中,计时/计数器有四种模式,区别主要是集中在 THx 和 TLx 的16位如何使用的问题上,这四种模式分别为:

|—+—+——————-| |M1 |M0 |计时/计数器模式 | |:-:|:-:|:—————–:| |0 |0 |13位计时器 | |0 |1 |16位计时/计数器 | |1 |0 |8位自动重载计时/计数器| |1 |1 |两个8位计时/计数器 | |—+—+——————-|

  • 13位计时器:一般很少用到,现在的部分8051系列已经去掉了这个功能。使用 THx 的8位和TLx 的第5位组成的13位来存放累加的数字。
  • 16位计时/计数器:非常常用,用 THx 和 TLx 的整个16位来存放累加数字。可以存放的数字很大,但是每次进入中断之后都需要软件重新载入下次计时/计数的初始值。
  • 8位自动重载计时/计数器:TLx 用来存放累加的数字,当 TLx 溢出之后,会自动将 THx 中的数字加载到 TLx 中,作为下次计时/计数的初始值。虽然可以存放的数字不大,但是不用每次进入中断之后用软件重新载入,方便,且速度更快。
  • 两个8位计时/计数器:一般很少用到,现在的部分8051系列已经去掉了这个功能。在这个功能下,Timer1 不能使用,所有跟 Timer1 有关的控制位都转而控制 TH0,TL0则继续由 Timer0 的控制位控制。及其没有用处,因为得到的效果还不如用 Timer0 和 Timer1 分别设置为两个8位自动重载计时/计数器。

TMOD 每一位对应的意思如下(前四位对应 Timer1,后四位对应 Timer0):

GATE  C/T  M1  M0  GATE  C/T  M1  M0
  • GATE:选择开启方式是硬件控制还是软件控制。当置一的时候,开启方式是硬件控制,当 TCON 中 TRx 置一且 INTx 为高的时候,对应的计时/计数器才开始计时/计数,否则不开启;当清零的时候,开启方式为软件控制,TRx 置一就可以开启。
  • C/T:计时器和计数器选择位。置一则为计数器,清零则为计时器。
  • M1 和 M0:计时/计数器模式选择位,对应的模式见上表。

设置思路

在使用计时/计数器的时候要先对其进行设置,例如选择哪个计时/计数器,什么模式,初值为何,都要预先设置,但由于涉及的寄存器有四个,所以考虑的时候有些复杂,下面介绍的是设置的基本思路。

首先,你要明确以下几个问题,然后再开始设置:

  1. 你要使用哪个计时/计数器,是 Timer0 还是 Timer1?用做计时器还是计数器?
  2. 你所使用的计时/计数器什么时候开启?开启方式是什么,是软件开启还是硬件开启?
  3. 你所使用的计时/计数器的工作模式是上面四种中的哪一个?
  4. 开启的时候,计时/计数的初值是多少?每次运行完中断之后的重载值是多少?

明确了以上问题,就可以开始设置计时/计数器了。可以遵照下面几步走:

  1. 设置 TMOD。建议 Timer0 和 Timer1 分开设置,运用 ANLORL 两个命令,在不干扰另一个计时/计数器的情况下,设置自己需要的那一个。虽然命令行数增加,运行时间增加,但是多消耗的时间很少可以忽略,好处是不会混淆。ANL 用来清零,需要清零的位放零,其他位放一,ORL用来置一,需要置一的位放一,其他位放零。例如要设置使用 Timer0作为计数器,软件开启,模式为16位计时/计数器,可以这样设置 TMOD:

    ANL TMOD,#11110101B
    ORL TMOD,#00000101B
    
  2. 设置计时/计数的初值,根据选择的模式和需要,对 THx 和 TLx 进行赋值。当将其作为计时器的时候会有个计时周期(也就是多久进行一次加一操作)的问题。

    对于 8051而言,存在两种时间:时钟周期和机械周期。时钟周期就是时钟电路的振荡频率所对应的周期,也就是 $$\frac{1}{f{osc}}$$。机械周期是 CPU 完成一个基本操作(取指令,读或写数据等)所需要的时间,8051中12个时钟周期等于一个机械周期,也就是$$\frac{12}{f{osc}}$$。计时器的计时周期就是机械周期,对于$$12MHz$$震荡频率而言,也就是$$1\mu s$$。这样我们就可以计算出我们需要的初值是多少了。如果选择的模式是16位计时/计数器,我们可以用如下方式进行赋值(x就是你要预设的初值):

     MOV TH0,#HIGH (65536-x)
     MOV TL0,#LOW (65536-x)
    

    如果是8位自动重载计时/计数器,可以这样设置初值(y是要重载的值,x是预设的初值):

     MOV TH0,#(256-y)
     MOV TL0,#(256-x)
    
  3. 开启,跟你的需要,在必要时候,将 TRx 置一。

AT89C51 制作的时钟(图片来自 Engineers Garage)



Comments