新闻中心

EEPW首页>嵌入式系统>设计应用> 51单片机之寄存器-3.1单片机定时器

51单片机之寄存器-3.1单片机定时器

作者: 时间:2016-11-21 来源:网络 收藏
前面我们讲解了如何通过软件来延时,从而达到了提升了灯亮与灭的间隔时间,其过程是让cpu干别的事情,从而达到延时的效果。但是软件延时不是很精确,这里我们学习一种比较精确的硬件延时,也叫定时器。定时器怎么理解呢?这里举个简单的例子来说明。
图1 闹钟的操作

讲定时器之前我们来看看如何操作闹钟,这个生活中的小例子,相信大家都很熟悉。首先我们要设定定时时间,定时多久呢?我们通过调节如图中红色区域指针来告诉闹钟定时多久。然后开启闹钟,怎么样开启呢?如上图中蓝色部分,按下按钮让闹钟知道现在要开启定时的功能了。很简单的两个动作,闹钟设置就完成了。之后就是闹钟自己的事情了。你就可以去干别的事情了,比如看电影,睡觉,喝茶等等。那么定时的时间到了怎么样告诉你呢?大家都知道,通过响铃来告诉你时间到了。懂得了闹钟的过程,那么类比一下就很容易明白单片机定时器。前面讲过,单片机是人设计的产品,自然反映人的思维过程。只不过在单片机中,它把日常用的词汇专业化了,功能复杂了一点。现在我们来按照闹钟的思维讲述单片机定时器。

本文引用地址://m.amcfsurvey.com/article/201611/319546.htm
图2 定时器的操作示意图

首先我们看看如何开启定时器,在闹钟中我们使用手来按下按钮,这样闹钟定时就开启了。在单片机中只有0和1,那么很容易想到采用0和1控制定时的开关,并给它取个名字(TR0). 如何理解这个名字了,T表示timer, R表示run,0表示定时器,合起来就表示定时器0运行控制,这样很容易就记住了定时器的开关控制。那么下一个问题,定时多长时间。讲这个问题之前我们先来看看闹钟如何计时的。秒钟每走一格就是1s,走10格我们就知道走了10s,也就是说我们可以通过查看格子的数目来知道时间的量。在单片机中如何计时呢?如上图,有两个寄存器TH0和TL0,很容易想到,可以用TH0和TL0中存放的数据来知道时间。闹钟中每一个格子是1秒钟,那么在TH0和TL0中每放一个数是多少时间呢。定时器计时是通过晶振来完成的。这里我们使用的晶振大小为11.0592M,表示一秒钟时间内,晶振运行11.0592次,那么运行一次的时间为[1/(11.0592M)]S, TH0和TL0中每计数一次需要晶振运行12次(至于为什么,后面我们会讲到),因此需要的时间为12×[1/(11.0592M)]S. 为了方便计算我们把它换成微秒单位: (12/11.0592)Us. 可见时间长度是通过TH0和TL0来完成的。那么能不能只用一个TL0来计数呢?当然可以。因此这里就涉及到了计时模式的问题,TH0+TL0构成16bit的计时器,或者只使用TL0或者使用TH0(8bit)和TL0低5位。那么我用TH0高4位和TL0低7位可不可以?不可以,我们不去追问为什么,单片机工程师设计的,我们要做的就是了解它的规则。既然工作模式有这么多,那么单片机怎么知道要使用哪种工作模式。很明显需要有个寄存器来告诉单片机这个信息,这个寄存器叫TMOD. 如上图所示的M0和M1,很容易知道2个位就能产生4种组合情况(00/01/10/11),这样分别对应与定时器的4种工作模式。最后一个问题,到点响铃。闹钟定时到了会发出响铃来通知你,那么在单片机中到点了会通知CPU,怎么通知呢,如上图所示中的TF0(F-full表示满了,也就是溢出), TH0/TL0满了TF0就会由0变1,然后通过硬件通知CPU时间到了。这样就完成了整个定时过程。从以上分析可以看出,定时器的操作过程与闹钟非常相似,只不过单片机的定时器在计数方面复杂了一点,多了几种工作模式。现在相信大家已经大概了解单片机定时器了。

现在我们根据所讲的内容,举一个简单例子,通过定时器0来控制LED亮一秒灭一秒。按照上面过程,我们一步一步来分析

(1) 确定定时多长时间

前面讲了定时时间是通过TH0和TL0来控制的,那么使用TH0和TL0之前先要设定工作模式,用16bit还是8bit或者其他。这里我们选择16bit。怎么选呢?表1中给出了定时器0和1工作模式的控制寄存器,8个位的初始化值都是0,绿色部分用来控制定时器1,黄色部分用来控制定时器0,现在我们只看黄色部分。一共4个控制位,Gate,C/T,M1,M0. 很容易看到,Gate,C/T都要设置0,现在要选中16bit的工作模式,那么M1M0=01. 因此TMOD=00000001=0X01 假设在图2中,TL0,TH0初始值为0,那么16bit最多可以装下65535,考虑到溢出,因此这里取65536,每装一个数需要(12/11.0592)Us,那么装65536需要,UnitT=65536×(12/11.0592)约等于71000Us,也就是71ms. 现在我要定时1s,很明显,TH0和TL0不够用,那是不是要多增加几个TH0和TL0,没有必要。我们可以通过软件来解决硬件上的不足,最简单的方式就是使用循环多次。比如我让UnitT为10ms,那么循环100次就是1秒了。那么怎么设置UnitT=10000Us, UnitT=(65536-X) × (12/11.0592)=10000Us, 其中X为TH0和TL0组成的16bit的初始值。将这个等式改进一下:

UnitT=(65536-X) / 0.9216, 在该式中UnitT×0.9216要小于65536,并且要保证UnitT×0.9216为正整数,因此UnitT的取值范围为:

10000

因此简单来看,UnitT可以取10ms, 20ms, 30ms, 40ms, 50ms, 60ms, 70ms,

再根据我们最终要定时的时间为1000ms, 因此UnitT只能取10ms, 20ms, 50ms,这样根据UnitT=(65536-X) / 0.9216就能计算出初始值X,

这里我们取UnitT=50ms, X=19456,16进制表示为: 4C00H, 因此TH0= 0X4C, THL0=0X00.

因此这样我们就确定了定时时间用的初始值,TH0和TL0,并且需要重复20次

(2) 启动定时器

如何启动定时器,查看表2定时器控制寄存器TCON,只要设置TR0=1即可。表2中涉及到中断的问题我们暂时不管,这里我们只讨论定时器,下一讲谈中断。这里为什么能直接设置TR0,为什么在设置定时器工作模式时不能直接设置M1M0,而要通过TMOD来设置。这个涉及到寻址方式的问题,我们暂时不讨论。

(3) 响铃通知

那么闹钟响铃对应定时器的哪个部分。前面我们设置了TH0和TL0,初始值为19456,然后不停的增大直到65535,再增大一个变成65536此时TH0和TL0装不下了,因此溢出,此时单片机通过硬件将TF0从0变为1来通知CPU,查看表2中TF0的说明可知。因此TF0的值对应着响铃。

(4) 点亮LED

我们要让LED延时1s后点亮或者熄灭,因此这里需要一个参数来对定时器TF0的溢出次数计数,当溢出20次时,表示定时到了1s。

这样我们很容易的得出程序的框架图,

参考代码如下:

#include "reg52.h"

sbit LED=P1^0;

void main(void)

{

unsigned char CYC = 0;

TMOD=0X01;

TH0=0X4C;

TL0=0X00;

TR0=1;

while(1)

{

if (TF0==1)

{

TF0=0;

TH0=0X4C;

TL0=0X00;

CYC++;

if(CYC==20)

{

CYC=0;

if(LED==0)

{

P1=0XFF ;

LED=1;

}

else

{

LED=0;

P1=0X00;

}

}

}

}

}



评论


技术专区

关闭