打印

楼上请把**仔细看完,不对TL0赋值是我比较自豪的地方。

[复制链接]
12485|55
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
救火车|  楼主 | 2008-10-7 19:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
刚刚发现软件的一个小BUG,在选择T0的工作方式时,误把TR1置位了,造成TMOD的值显示错误。我已经更正了程序。请大家重新下载。在这里我向新手朋友表示歉意。

今天结合救火车单片机实验室编写的小软件《定时器时间计算工具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购买。我今后写的技术贴,可以在这块板子上直接运行。会方便一些。
                                  
其实51的定时器中断没什么难的!祝大家重阳节快乐!
                                救火车  QQ849046309
                                   qm999cn@qq.com   
                                   2008-10-7 夜  [url=https://bbs.21ic.com/upfiles/img/200711/20071122192938672.jpg]

相关帖子

沙发
zyok| | 2008-10-7 19:29 | 只看该作者

留那么大块空白干什么,点都不协调...

使用特权

评论回复
板凳
救火车|  楼主 | 2008-10-7 19:40 | 只看该作者

方式3的时候有用

使用特权

评论回复
地板
xwj| | 2008-10-7 19:45 | 只看该作者

呵呵,啥时候搞的网站啊? 也不宣传宣传???

使用特权

评论回复
5
oufuqiang| | 2008-10-7 21:11 | 只看该作者

好贴要顶!

使用特权

评论回复
6
hotpower| | 2008-10-7 21:14 | 只看该作者

http://www.qm999.cn/JHC-51-A/JHC-51-A.html

使用特权

评论回复
7
szhgx26| | 2008-10-7 22:57 | 只看该作者

版主也卖广告,烦!

一律向“钱“看

使用特权

评论回复
8
hotpower| | 2008-10-8 00:33 | 只看该作者

哈哈~~~根是歪的~~~

使用特权

评论回复
9
救火车|  楼主 | 2008-10-8 07:09 | 只看该作者

哈哈!

一多半儿技术和一少半儿广告。
大家都受益。

不谈广告的事了。
还请hotpower大叔对我的小软件多提意见。

使用特权

评论回复
10
wang1987| | 2008-10-8 16:35 | 只看该作者

迷糊

觉得有点迷糊,在中断程序中只MOV TH0,#0EEH,那TL0呢?不明白?

使用特权

评论回复
11
救火车|  楼主 | 2008-10-8 17:51 | 只看该作者

楼上请把**仔细看完,不对TL0赋值是我比较自豪的地方。

使用特权

评论回复
12
hotpower| | 2008-10-8 18:58 | 只看该作者

TL0开始为0,中断肯定不动~~~

使用特权

评论回复
13
lovekcx| | 2008-10-8 19:21 | 只看该作者

先顶下 坐下来慢慢看

使用特权

评论回复
14
martial| | 2008-10-9 08:22 | 只看该作者

收藏先!

使用特权

评论回复
15
ljp98| | 2008-10-9 08:42 | 只看该作者

好货啊

谢了。

使用特权

评论回复
16
箫笑| | 2008-10-9 16:37 | 只看该作者

多谢,仔细研究下,正好有用,我现在用timer来定时一个几十秒的时间,误差有10%之多,头疼.....

使用特权

评论回复
17
luoyilq| | 2008-10-10 14:32 | 只看该作者

比较有意思

使用特权

评论回复
18
救火车|  楼主 | 2008-10-10 20:05 | 只看该作者

请hotpower抽空看一下我编的小软件。

如有错误我马上改正,免得教错了新手。

使用特权

评论回复
19
hq_y| | 2008-10-10 20:29 | 只看该作者

呵呵,真的费了不少功夫

使用特权

评论回复
20
zyok| | 2008-10-10 20:32 | 只看该作者

浪费时间,没什么用的东西~~

只是LZ醉翁之意不在酒而已。。。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

113

主题

1249

帖子

2

粉丝