51定时器/计数器的深入研究-精确定时

今天结合救火车单片机实验室编写的小软件《定时器时间计算工具1.0》,来讲述定时器的工作过程。
请到http://www.qm999.cn免费下载。我编这个小软件尽可能的模拟了51的定时器结构,相信你用过以后,一定会加深对定时器的理解。

一、定时器相关寄存器
与定时器有关的寄存器都在下面了。
TCON 的高4位  


TF1

TR1

TF0

TR0





TF1(TCON.7):定时器1的溢出中断标志位
TR1(TCON.6):定时器1的运行控制位
TF0(TCON.5):定时器0的溢出中断标志位
TR0(TCON.4):定时器0的运行控制位

TMOD


GATE1

C/T1

M1

M0

GATE0

C/T0

M1

M0


         定时器1       |          定时器0  

TH0、TL0、TH1、TL1
这个不用说了吧

中断允许控制寄存器IE中的三位。
ET0(IE.1)、ET1(IE.4)、EA(IE.7)

二、定时器的结构(以T0为例)
把定时器分为六个部分来研究。
脉冲源   控制端   数器   中断请求位  中断允许控制   中断服务程序
晶振或T0             TH0、TL0       TF0             ET0   EA      void Tm0() interrup1 using 1  
脉冲源:用作定时器时,取晶振作为脉冲源。每12个振荡周期(即一个机器周期)计数器(即TH0、TL0)加一。用作计数器时T0脚出现下降沿(管脚从1到0)跳变时,计数器加一。定时器和计数器的区别就是脉冲源不同,除此之外其他的工作过程完全相同。
配置TMOD的C/T0可以选择脉冲源。置0是定时器,置1是计数器。
控制端:相当于一个开关,开关打开时,脉冲源的信号才能传到计数器(TH0,TL0)中,计数器会不断增一。关闭这个开关,脉冲源的信号不能使计数器(TH0,TL0)增一。控制端的开启和关闭状态由TR0、GATE0和INT0脚电平决定。控制端的开启条件是TR0&(~GATE0 | INT0)如下图。

控制端的开启条件是TR0&(~GATE0 | INT0)如图。
一般情况下 令TR0=1   GATE0=0 开启控制端。TR0=0关闭控制端。
当需要INT0引脚控制计数器时  令TR0=1  GATE0=1  这样INT0脚为高电平时计数,低电平时停止计数,这样可以很方便的测量脉冲宽度。在任何一本51书中的定时器部分都有详述。也可以使用本文配套的小软件,来体会控制端的逻辑。GATE=1的这种用法,我以前也没有注意过,在整理本文时才发现的。这也是我最新的学习收获。

计数器,中断请求位:这里说的计数器是指TH0、TL0这两个寄存器。
每收到一个脉冲源输出的脉冲,这个计数器就会增一。计数器计满溢出时,会置位TF0,产生中断请求。注意,这里只是产生中断请求,是否能够进入中断程序,还要由中断允许位决定。
直接对TF0置位,也可以产生中断请求。
计数器TH0、TL0一共有四种计数方式
方式0(M1=0 M0=0)13位计数器。它由TH0的8位和TL0的低5位构成。TL0大于0x1F时就向TH0进位。TH0计满溢出就向TF0置位请求中断。
方式1(M1=0 M0=1)16位计数器。与方式1差不多。由TH0的8位和TL0的8位构成。TH0计满溢出就向TF0置位请求中断
方式2(M1=1 M0=0)8位定时器。TL0计满溢出时,置位TF0请求中断,并且将TH0中的数值重新装入TL0中。
方式3(M1=1 M0=1)这个方式只有定时器0有,把定时器0当成两个8位定时器来用。这部分很有趣,你可以使用演示软件研究。
定时器1没有方式3,如果设成方式3就相当于停掉了定时器1。
中断允许控制:上一步产生中断请求(TF0被置1),并不代表会响应中断。还要看中断允许控制位,这是一个开关,只有开关在开启状态,中断才会响应。每个中断源都有自己的分开关,比如T0的中断允许位是ET0,T1的中断允许位是ET1.还有一个总开总EA,它关闭时所有的中断都被禁止。必须是分开关和总开关都打开时,才能进入中断服务程序。
 
     开定时器                            关定时器
开启和关闭定时器控制端,你可以点击小软件来体会逻辑关系。
中断服务程序:如果中断条件都允许,程序跳转到中断服务程序。
ORG 0000
AJMP Main
ORG 000BH
LJMP Tim0
ORG 100H
Main:
MOV SP,#30H
MOV TMOD,#01H
MOV TH0,#0EEH
MOV TL0,#00H
SETB ET0
SETB EA
SETB TR0
WHILE:
。。。主程序
LJMP WHILE

TIM0:;TIMER0中断服务程序
PUSH  ACC
PUSH  PSW
MOV TH0,#0EEH
。。。其他程序
POP  PSW
POP  ACC
RETI


#include <reg51.h> //11.0592M
void timer0() interrupt 1 using 1    //5ms中断一次定时器中断处理函数
{
TH0=0xEE;    //重置定时初始值
。。。其他程序
}
void main (void)
{
TMOD|=0x01;   //选择定时器0,工作模式1,16位定时器
TH0=0xEE;    //置定时初始值
TL0=0x00;
ET0=1;   //开启定时器0中断允许,允许定时器0中断。
EA=1;    //开启全局中断允许。允许所有中断
TR0=1;   //开启控制端  
while(1)
{
。。。主程序
}
}







顺便把其他中断源的向量表也写出来。


中断源

        汇编语言

            C语言

中断向量

例子

中断序号

例子

外部中断0(INT0)

0003H

ORG 0003H

     0

void _INT0() interrupt 0 using 1

定时器T0中断

000BH

ORG 000BH

     1

void _T0() interrupt 1 using 1

外部中断1(INT1)

0013H

ORG 0013H

     2

void _INT1() interrupt 2 using 1

定时器T1中断

001BH

ORG 001BH

     3

void _T1() interrupt 3 using 1

串行口中断

0023H

ORG 0023H

    4

void _UART() interrupt 4 using 1

定时器T2中断

002BH

ORG 002BH

    5

void _T2() interrupt 5 using 1



定时器例程之一:精确定时1秒钟
我使用的硬件是救火车单片机工作室的JHC-51-A型学习板。晶振频率11.0592M。用定时器0的工作方式1实验。因为工作方式1,最大的计数是65536个机器周期。晶振是11.0592M时,最长溢出时间是71111.1111111111微秒,远远不够1秒,所以我把定时器溢出时间定成5毫秒。在定时器工具中输入5000,点 [计算TH0 TL0] 计算出 TH0 = 0xEF ,TL0 = 0x00.溢出时间是5毫秒,相当1秒的200分之一。[/url]

在定时器工具中输入5000,点 [计算TH0 TL0] 计算出 TH0 = 0xEF ,TL0 = 0x00.溢出时间是5毫秒,相当1秒的200分之一。在程序中声时一个外部变量,计200次中断,就是1秒。

unsigned char  ms_5=0;
void timer0() interrupt 1 using 1    //5ms中断一次定时器中断处理函数
{
TH0=0xEE;    //重置定时初始值
if  (++ms_5>=200)
{
ms_5=0;
//程序每1秒钟进入这里一次。

}
}
//主程序如下:
void main (void)
{
TMOD|=0x01;   //选择定时器0,工作模式1,16位定时器
TH0=0xEE;    //置定时初始值
TL0=0x00;
ET0=1;   //开启定时器0中断允许,允许定时器0中断。
EA=1;    //开启全局中断允许。允许所有中断
TR0=1;   //开启控制端  

到这里我们把定时器0做成了一秒钟的程序完成了。
有很多朋友会有这样的疑问,这样做的1秒钟到底准不准?有多大误差?
我可以负责任的告诉你,有误差,但可以控制到极其微小的程度。
下面我们发析一下误差的产生,以及控制方法。
第一、晶振的误差
    我们的晶振一般误差都是20PPM的,百万分之二十。想提高精度,只能选择误差更小的晶振,但它毕竟不是为精确定时设计的,很难达到时钟芯片晶振的精度。
第二、单片机中断系统的误差。
定时器产生中断请求以后,并不一定能马上响应这个中断。
单片机要把当前的指令执行完。51的指令是1到4个周期。如果赶上两周期指令,就会延误一个指令周期。最慢的情况会延误3个周期响应中断。这点误差倒是没什么关系。
但是如果单片机正处理其他的中断(同级或更高级)。要等其执行完其他中断,再执行一条主程序指令,才会响应定时器0中断。因为程序千差万别,所以其他中断占用的时间,就没准儿了。更要命的是,这类影响是随机的,你根本无法纠正。
看起来好像没有办法了,但是你深入研究定时器的工作原理以后,你会发现这个问题还是有可能解决的。请仔细看一下,我上面的中断程序,“TH0=0xEE;” 你是否注意到,我没有给TL0重新赋值。这可不是疏忽忘了。我们知道定时器只要开着,TH0和TL0就会不断的增一,增到FF FF,再增一就溢出,这时TF0被硬件置1(也就是中断请求)。我们要注意的就是不管定时器中断是否被响应,TH0和TL0仍然会不断增一,FF FF增一00 00 再增一 00 01 再增一 00 02 。这就是我为什么要选择5毫秒作为定时长度的原因。因为TH0=EE TL0=00。最主要的就是TL0=00。定时器在溢出产生中断以后,不论响应还是不响应,TL0并不停止计数。虽然中断响应有可能被延迟,但是延迟的时间仍然被计算。延迟的时间在下一次中断时会“补上”。这就是只对TH0重赋值的原因。从理论上说,真正是一个微秒都不差。研究出这个用法以后,着实让我兴奋了好长时间。呵呵。
还有一点需要注意。其他的中断占用的时间太长,TL0增数超过256,定时器中断响应时TH0已经大于0了,直接写TH0=0xEE;就有误差了.可以改成 TH0=TH0+0xEE;但这样也会有一点点问题,我们不在这里详细讨论。最好还是控制其他的中断占用时间不要超过240个机器周期。
第三、每秒钟最后一次入中断的误差。原因和上面说的相同,误差在下一秒也会“补上”。

定时器例程之二 :模拟时钟
这也是JHC-51-A的实验6-1的内容。
以下是部分程序
void init_timer0(void)
{
//以下为初始化定时器
TMOD|=0x01;   //选择定时器0,工作模式1:16位定时器
TH0=0xEE;    //置定时初始值
TL0=0x00;
//初始化完毕。
ET0=1;   //开定时器0中断,允许定时器0中断。
EA=1;    //开全局中断。允许所有中断
TR0=1;   //开始计数  
}
unsigned char time_allow;    //整点报时标志
unsigned char time_num;      //报时的次数 ,
unsigned char fmq_times;     //整点报时 蜂鸣器声音维持时间计数
unsigned char set_kk_times;   
unsigned char ms5_times;     //5ms中断计次
unsigned char hour,min,sec;  //定义时,分,秒。
void timer0() interrupt 1 using 1    //5ms中断一次定时器中断处理函数
{
//重新置位计数初始值   在工作方式1下,需要重新置位定时初始值,程序才会再一次进入中断,
//工作方式0,3也是如此,只有工作方式2不需要重新置位初始值。
TH0=0xEE;    //置定时初始值
if(++ms5_times>=200)  //5ms中断一次,计数200次 达到1s
{
    ms5_times=0;
dc1=0;          //处理小数点  点亮
sec++;          //时钟 秒+1
if(sec>=60)      //秒计数达到60
{
    sec=0;
min++;       //分钟+1
if(min>=60)   //分钟计数达到60 
{
    min=0;
hour++;   //小时+1
if(hour>23) hour=0; //24小时制,计数达到24,清零
}
}
}
if(0==sec)
{
if(0==min)             //如果时间达到整点。允许报时功能
{
     if(hour>12) time_num=hour-12; //如果时间超过12点,报时声音次数相应减 12
    else if(0==hour) time_num=12;     //如果时间为零点。报时声音为12次 
    else time_num=hour;           //报时次数为时间值
    time_allow=1;          //报时允许标志置位
    }
if(30==min)            //如果时间达到半点,允许报时功能
{
time_allow=1;      //报时标志置位
time_num=1;        //报时次数 1次
}
}
if(1==time_allow)          //如果报时允许
{
    if(fmq_times++>200) 
{
    fmq_times=0;
spk=1;         //蜂鸣器停止发声
time_num--;    //报时次数减 1 
}  
if(100==fmq_times) spk=0;  //蜂鸣器发声 
if(0==time_num) time_allow=0;    //报时结束 清零报时标志位
}
if(ms5_times==80) dc1=1; //处理小数点 熄灭
if(set_kk_times++>200) set_kk_times=0; 
disp_LED(display);   //刷新数码管
}

上面是实际效果图。时间是18点零2分

我的程序是基于这块板子调试的。有想学习单片机的朋友可以到我的网站
http://www.qm999.cn/JHC-51-A/JHC-51-A.html了解一下这块板子。也可以联系我的QQ购买。我今后写的技术贴,可以在这块板子上直接运行。会方便一些。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
摘要 随着时代的进步,电子行业的发展,定时器的应用也越来越广泛,单片机以其强大的 功能,成为许多功能电子产品的首选。本次电子定时器电路根据设计要求采用AT89C51单 片机来实现最大99秒倒计时,采用两位数码管显示。文章的核心主要是硬件介绍及连接 和软件编程两个大的方面。硬件电路主要包括AT89C51、晶振电路、数码管,发光二级管 ,按键。软件用汇编语言实现,主要包括主程序、倒计时、重启控制程序等软件模块。 采用软硬件配合基本能实现设定定时时间倒计时功能,达到了设计的要求和目的。并在 Proteus软件上进行了仿真和调试。 关键词 AT89C51单片机;定时器;倒计时 目录 摘要…………………………………………………………………………………………… 第一章 绪论 1.1定时器的发展 1.2 电子定时器的应用 1.3选题的目的和意义 1.4 本章小结 第二章 单片机的基础知识 3 2.1单片机简介 3 2.2单片机的特点 3 2.3 本章小节 第三章 功能实现及硬件介绍 4 3.1 设计功能实现 4 3.2 C51单片机引脚介绍 9 3.3时钟和复位电路 3.4数码管显示 10 3.5键盘 12 3.6电气原理图……………………………………………………… 3.7本章小结 第四章 软件设计 15 4.1 程序流程图 15 4.2定时1秒设计 16 4.3重新启动 17 4.4程序 17 4.5 本章小结 结论 参考文献 致谢 第一章 绪论 1.1定时器的发展 人类最早使用的定时工具是沙漏或水漏,但在钟表诞生发展成熟之后,人们开始尝试 使用这种全新的计时工具来改进定时器,达到准确控制时间的目的。传统的定时器都是 使用发条驱动式、电机传动式、电钟式等机械定时器。20世纪末,电子技术获得了飞速 的发展,在其推动下,现代电子产品几乎渗透了社会的备个领域,有力地推动了社会生 产力的发展和社会信息化程度的提高,同时也使现代电子产品性能进一步提高,产品更 新换代的节奏也越来越快。电子定时器相对传统定时器来说体积小,重量轻,造价低, 精度高,寿命长,而且安全可靠适用于频繁使用,在各个领域得到了广泛的应用。使相 当多需要人控制时间的工作变得简单了许多。 目前,单片机正朝着高性能和多品种方向发展趋势将是进一步向着CMOS化、低功耗、 小体积、大容量、高性能、低价格和外围电路内装化等几个方而发展,它从根本上改变 了传统的控制系统设计思想和设计方法。从前必须由模拟电路或数字电路实现的大部分 功能,现在己能用单片机通过软件方法来实现了。这种软件代替硬件的控制技术也称为 微控制技术,是传统控制技术的一次革命。 1.2电子定时器的应用 电子定时器大大地扩展了钟表原先的报时功能。诸如定时自动报警、按时自动打铃、 时间程序自动控制、定时广播、自动起闭路灯、定时开关烘箱、通断动力设备甚至各种 定时电气的自动启用等。 电子定时器经常用于延时自动关机、定时。延时自动关机可用于电视机、催眠器、路 灯及其他电器的延时断电及延时自停电源等。定时可用于照相定时曝光,定时闪光,定 时放大,水位定时报警,延时电铃,延时电子锁等,人们甚至将定时器用在了军事方面 ,制成了定时炸弹,定时雷管。 电子定时器影响着人类的生产和生活,随着电子技术的发展,电子定时器也在不断的 进步,将朝着更高精度,更多用途的方向为我们服务。 1.3 选题的的目的和意义 定时器与生活联系密切,我们亲身体会到它存在的价值,通过课程设计自己亲自完成 电子定时器的简单设计不仅可以将学到的理论知识应用于实践,更提高了我们思考问题 ,解决问题的能力,同时提高我们的学习兴趣。 1.4 本章小结 本章小结:本章主要介绍了定时器的现状,让我们对电子定时器的有了初步的了解, 为进一步设计及研究奠定了基础。 第二章 单片机的相关知识 2.1单片机简介 单片机全称为单片机微型计算机(Single Chip Microsoftcomputer)。从应用领域来看,单片机主要用来控制,所以又称为微控制器(M icrucontroller Unit)或嵌入式控制器。单片机是将计算机的基本部件微型化并集成在一块芯片上的微型 计算机。 2.2单片机的特点 l. 单片机的存储器ROM和RAM是严格区分的。RAM称为程序存储器,只存放程序,固定常数, 及数据表格。RAM则为数据存储器,用作工作区及存放用户数据。 2. 采用面向控制的指令系统。为满足控制需要,单片机有更强的逻辑控制能力,特别是单 片机具有很强的位处理能力。 3. 单片机的I/O通常是多功能的。由于单片机芯片上引脚数目有限,为了解决实际引脚数和 需要的信号线的矛盾,采用了引脚功能复用的方法,引脚处于何种功能,可由指令来设 置或由机器状态来区分。 2.3 本章小结 通过对单片机总体的介绍,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值