第5章 定时计数器.docx
《第5章 定时计数器.docx》由会员分享,可在线阅读,更多相关《第5章 定时计数器.docx(16页珍藏版)》请在冰豆网上搜索。
第5章定时计数器
第5章单片机定时/计数器原理及应用
5.1单片机定时器/计数器(Timer/Counter)概述
在工业检测、控制中,很多场合都要用到计数或者定时功能。
例如对外部脉冲进行计数、产生精确的定时时间、作串行口的波特率发声器等。
定时/计数器是单片机的一个重要部件,At89C51单片机内部有两个可编程的定时器/计数器,以满足多方面的需要。
它们具有两种工作模式(计数器模式、定时器模式)和四种工作方式(方式0、方式1、方式2、方式3),其控制字均在相应的特殊功能寄存器(SFR)中,通过对它的SFR的编程,可以方便的选择工作模数和工作方式。
定时器/计数器(Timer/Counter)本质上都是加法计数器,当对固定周期的脉冲信号计数时是定时器,对脉冲长度不确定的信号计数时是计数器。
每接收到一个计数脉冲,加法计数器的值就加一,当计满时发生溢出,并从0开始继续计数。
当设置为定时工作模式时,定时器对89C51片内振荡器输出的经12分频后的脉冲计数,即每个机器周期使定时器(T/C0或T/C1)的数值加1直至计满溢出。
当采用12MHz晶振时,一个机器周期为1µs。
当设置为计数工作模式时,通过引脚T0(P3.4)和T1(P3.5)对外部脉冲信号计数,当输入脉冲信号产生由1到0的下降沿时,定时器的值加1.
不管时定时还是计数工作模式,定时器T0或T1在对内部时钟或外部事件计数时,都不占用CUP时间,除非定时器/计数器溢出,才可能中断CPU的当前操作,计数器的计满溢出信号就是定时/计数器的输出,该信号使TCON的某位(TF0或TF1位)置1,作为定时器/计数器的溢出中断标志,定时器/计数器的内部结构框图如下图所示。
图5-1定时器/计数器结构框图
5.2与定时/计数器有关的特殊功能寄存器
1.计数寄存器TH和TL
定时器/计数器T/C0和T/C1都是16位寄存器,由TH高8位和TL低8位构成,在特殊功能寄存器(sfr)中,对应T/C0为TH0和TL0,对应T/C1为TH1和TL1,定时器/计数器T/C0和T/C1的初值分别通过TH0/TL0和TH1/TL1来设置,加法计数器是计满溢出时才申请中断,所以在给定时器/计数器赋初值时,不能直接输入所需的计数值,而应输入的是计数器计数的最大值与这一计数值的差值,设最大值为M,计数值为N,初值为X,则X的计算方法如下:
计数状态:
X=M-N
定时状态:
X=M-定时时间/T(T=12÷晶振频率)
2.定时器/计数器控制寄存器TCON
对TCON的相关位的说明:
TF0、TF1:
T0、T1溢出标志位。
TF0、TF1分别是定时器/计数器T0、T1的溢出标志位,加法计数器计满溢出时置1,申请中断,在中断响应后自动复0。
TF产生的中断申请是否被接受,还需要由中断是否开放来决定。
TR1、TR0:
T1、T0的运行控制位。
TR1、TR0分别是定时器/计数器T1、T0的运行控制位,通过软件置1后,定时器/计数器才开始工作,(如本设计案例中用到定时器T0,启动时用语句:
TR0=1;停止时用语句:
TR0=0;)在系统复位时被清0。
3.定时器/计数器方式控制寄存器TMOD
TMOD是8位寄存器,分为两组,高四位控制T1,低4位控制T0。
对TMOD的各个位的说明:
GATE位:
门控位。
GATE=1时,T0、T1是否计数要受到外部引脚输入电平的控制,INT0引脚控制T0,INT1引脚控制T1。
可用于测量在INT0和INT1引脚出现的正脉冲的宽度。
若GATE=0,即不使能门控功能,定时计数器的运行不受外部输入引脚INT0、INT1的控制
C/
位:
计数器模式和定时器模式的选择位。
C/
=0,为定时器模式,内部计数器对晶振脉冲12分频后的脉冲计数,该脉冲周期等于机器周期,所以可以理解为对机器周期进行计数。
从计数值可以求得计数的时间,所以称为定时器模式。
C/
=1,为计数器模式,计数器对外部输入引脚T0(P3.4)或T1(P3.5)的外部脉冲(负跳变)计数,允许的最高计数频率为晶振频率的1/24。
M1M0:
四种工作方式的选择位
表5-1定时/计数器工作方式
M1M0
方式
说明
00
0
13位定时器(TH的8位和TL的低5位)
01
1
16位定时器/计数器
10
2
自动重装入初值的8位计数器
11
3
T0分成两个独立的8位计数器,T1在方式3时停止工作
5.3定时/计数器的工作方式
1.方式0
方式0下,T0和T1工作在13位的定时/计数器方式,由TH的高8位和TL的低5位组成。
当T0的13位计数器加到全部为1以后,再加1就产生溢出,这时置TCON的TF0为1,同时把计数器全部变0,然后从0开始继续计数。
图5.2方式0(13位计数器)
方式0的计数长度M为2的13次方,初值也是13位二进制数,但要注意是高8位赋值给TH0,低5位前面补足3个0凑成8位赋给TL0。
例如,如要求计数值为1000,则初值为:
根据:
X=M-N
X=M-1000
=8192-1000
=1C18H
=1110000011000B
即赋初值时,TH0=0xE0,TL0=0x18。
2.方式1
方式1和方式0的工作原理基本相同,唯一不同是T0和T1工作在方式1时是16位的计数/定时器。
方式1时的计数长度M是2的16次方。
16位的初值直接拆成高低字节,分别送入TH和TL即可。
因为计数长度大,初值计算方便,方式1就定时/计数器最常用的方式,(如在本设计案例中,用的就是方式1:
TMOD|=0x01;)
图5.3方式1(16位计数器)
3.方式2
方式0和方式1的最大特点就是计数溢出后,计数器为全0,因而循环定时或循环计数应用时就存在反复设置初值的问题,这给程序设计带来许多不便,同时也会影响计时精度。
工作方式2就针对这个问题而设置,它具有自动重装载功能,即自动加载计数初值,所以也称为自动重加载工作方式。
在这种工作方式中,16位计数器分为两部分,即以TL0为计数器,以TH0作为预置寄存器,初始化时把计数初值分别加载至TL0和TH0中,当计数溢出时,不再象方式0和方式1那样需要“人工干预”,由软件重新赋值,而是由预置寄存器TH以硬件方法自动给计数器TL0重新加载。
图5.4方式2(自动重加载初值方式)
4.方式3
在方式3模式下,定时/计数器0被拆成两个独立的8位计数器TL0和TH0。
其中TL0既可以作计数器使用,也可以作为定时器使用,定时/计数器0的各控制位和引脚信号全归它使用。
其功能和操作与方式0或方式1完全相同。
TH0就没有那么多“资源”可利用了,只能作为简单的定时器使用,而且由于定时/计数器0的控制位已被TL0占用,因此只能借用定时/计数器1的控制位TR1和TF1,也就是以计数溢出去置位TF1,TR1则负责控制TH0定时的启动和停止。
由于TL0既能作定时器也能作计数器使用,而TH0只能作定时器使用而不能作计数器使用,因此在方式3模式下,定时/计数器0可以构成二个定时器或者一个定时器和一个计数器。
如果定时/计数器0工作于工作方式3,那么定时/计数器1的工作方式就不可避免受到一定的限制,因为自己的一些控制位已被定时/计数器借用,只能工作在方式0、方式1或方式2下,如果设置T1工作在方式3,则T1停止工作,相当于其他方式时令TR1=0
图5-12方式3(两个8位独立计数器)
5.5定时/计数器的应用
1.初始化步骤
在应用定时/计数器之前,要对它计数初始化编程,主要是对寄存器TCON和TMOD的编程以及计算和装载T/C(定时/计数器)的计数初值,一般有一下几个步骤:
(1)确定定时/计数器的工作方式——编程TMOD寄存器;
(2)计算定时/计数器的计数初值,并装载到TH和TL;
(3)定时/计数器在中断方式工作时,还必须开CPU总中断EA和相应中断源——编程IE寄存器;
(4)启动定时/计数器——编程TCON中的TR1或TR0;
2.应用举例
为了方便教学演示,本章应用实例全部是基于Proteus环境下的仿真实验。
例1已知单片机的晶振频率为fosc=12MHz,应用定时/计数器,在单片机引脚P1_3产生周期为2ms的方波信号。
(1)硬件设计
打开ProteusISIS编辑环境,按表X-1所列的元件清单添加元件。
表5-1
元件名称
所属类
所属子类
AT89C51
MicroprocessorICs
8051Family
CAP
Capacitors
Generic
CRYSTAL
Miscellancous
—
RES
Resistors
Generic
BUTTON
Switches&Relays
Switches
元件全部添加后,再到虚拟仪器库VirtualInstruments中添加示波器OSCILLOSCOPE,然后在ProteusISIS编辑区中按图X-1所示连接硬件原理图,可见,硬件电路是满足单片机基本运行条件的最小系统电路。
图5.6电路原理图
(2)软件设计
1)基本思路
周期为2ms的方波,即高低电平各为1ms,用定时/计数器定时1ms,每次时间一到让P1_3取反一次,就可以在该引脚上获得所要波形。
因为fosc=12MHz,机器周期=12/12MHz=1µs,而定时/计数器在定时模式时就是对fosc的12分频即机器周期进行计数,因此要定时1ms需要计数次数为1000次。
所以初值X=M-N=65536-1000;
2)源程序
下面分别采用中断方式和查询两种方式编程:
用定时/计数器0的方式1编程,采用查询方式。
#include
voidmain(void)
{
TMOD=0x01;//设置定时器0,采用方式1
TR0=1;//启动定时器T/C0
while
(1){
TH0=(65536-1000)/256;//装载计数初值
TL0=(65536-1000)%256;
do{}while(!
TF0);//查询等待TF0溢出标志
P1_3=!
P1_3;//P1_3取反
TF0=0;//软件清零TF0
}
}
用定时/计数器0的方式1编程,采用中断方式。
#include
voidtimer0(void)interrupt1µsing1
{
P1_3=!
P1_3;//P1_3取反
TH0=(65536-1000)/256;//重装计数初值
TL0=(65536-1000)%256;
}
voidmain(void)
{
TMOD=0x01;//设置定时器0,采用方式1
TH0=(65536-1000)/256;//装载计数初值
TL0=(65536-1000)%256;
EA=1;
ET0=1;
TR0=1;//启动定时器T/C
do{}while
(1);//等待定时器溢出中断
}
(3)调试与仿真
打开KeiluVision3,新建Keil项目,选择AT89C51单片机作CPU,新建C语言程序源文件,编写上述程序并将其导入到“SourceGroup1”中,在“OptionsforTarget”对话窗口中,选中“Optput”选项卡中的“CreateHESFile”选项和“Debug”选项卡中的“Use:
ProteusVSMSimulator”选项。
编译编译并调试以上C语言源程序。
接着在ProteusISIS中,选中AT89C51并单击鼠标左键,打开“EditComponent”对话窗口,设置单片机晶振频率为12MHz,在此窗口中的“ProgramFile”栏中,选择先前用Keil生成的.HEX文件。
在ProteusISIS的菜单栏中选择“File”→“SaveDesign”选项,保存设计。
在ProteusISIS的菜单栏中,打开“Debug”下拉菜单,在菜单中选中“UseRemoteDebugMonitor”选项,以支持与Keil的联合调试。
然后在Keil的菜单栏中选择“Debug”→”Start/StopDebugSession”选项,进入程序调试环境,按“F5”键,顺序运行程序,调出“ProteusISIS”界面,可以看到连接P1_3引脚上的虚拟示波器上有周期为2ms的方波信号输出,如图X-2所示。
图5.7仿真效果图
例2设计基于89C51单片机的模拟航标灯系统,使其具有:
白天航标灯熄灭;夜间按亮1s,灭1s的规律间歇发光的功能。
(1)硬件设计
打开ProteusISIS编辑环境,按表X-2所列的元件清单添加元件。
表5-2
元件名称
所属类
所属子类
AT89C51
MicroprocessorICs
8051Family
CAP
Capacitors
Generic
CRYSTAL
Miscellancous
—
RES
Resistors
Generic
BUTTON
Switches&Relays
Switches
LED-RED
0ptoelectronics
LEDs
NOT
SimulatorPrimitives
Gates
元件全部添加后,在ProteusISIS编辑区中按图X-3所示连接硬件原理图。
图5.8电路原理图
(2)软件设计
1)基本思路
题目要求定时1s,通过前面的学习可知,T/C的3种工作方式都不能满足这么长的定时要求,所以应该采用复合定时的方法,我们这里的基本思路是:
使T/C0工作在定时器方式1,定时50ms,定时时间到后对P1_0取反,即让P1_0引脚输出周期为100ms的方波脉冲。
另外,设置T/C1处在计数器方式2,对P1_0输出的脉冲进行计数,当计数满10次时,定时1s时间到,将P1_7端反相,即让P1_7引脚输出周期为2s的方波脉冲,用P1_7输出的信号控制LED按亮1s,灭1s的规律间歇发光;至于白天航标灯熄灭,可以通过外部中断来实现,所以在硬件连接中必须满足相应的要求,如图X-3中,用反相器将P1_0与P3_5/T1连接起来,用按钮开关模拟光敏器件连接到P3_2/INT0。
2)源程序
#include
voidmain(void)
{
TMOD=0x69;//设置T0为定时器方式0,并开启门控位,T1为计数器方式2
TH0=(65536-50000)/256;//载入计数初值
TL0=(65536-50000)%256;
TH1=256-10;
TL1=256-10;
IP=0x08;//设中断优先级
EA=1;//开总中断
ET0=1;
ET1=1;
EX0=1;
IT0=1;
TR0=1;
TR1=1;
do{}
while
(1);
}
voidint0()interrupt0using0//外部中断0,使LED在白天熄灭
{
P1_7=0;
}
voidtimer0()interrupt1using1//定时器中断0
{
P1_0=!
P1_0;//P1_0取反
TH0=(65536-50000)/256;//重载计数初值
TL0=(65536-50000)%256;
}
voidtimer1()interrupt3using2//定时器中断1
{
P1_7=!
P1_7;//P1_7取反
}
(3)调试与仿真
打开KeiluVision3,新建Keil项目,选择AT89C51单片机作CPU,新建C语言程序源文件,编写上述程序并将其导入到“SourceGroup1”中,在“OptionsforTarget”对话窗口中,选中“Optput”选项卡中的“CreateHESFile”选项和“Debug”选项卡中的“Use:
ProteusVSMSimulator”选项。
编译编译并调试以上C语言源程序。
接着在ProteusISIS中,选中AT89C51并单击鼠标左键,打开“EditComponent”对话窗口,设置单片机晶振频率为12MHz,在此窗口中的“ProgramFile”栏中,选择先前用Keil生成的.HEX文件。
在ProteusISIS的菜单栏中选择“File”→“SaveDesign”选项,保存设计。
在ProteusISIS的菜单栏中,打开“Debug”下拉菜单,在菜单中选中“UseRemoteDebugMonitor”选项,以支持与Keil的联合调试。
然后在Keil的菜单栏中选择“Debug”→”Start/StopDebugSession”选项,进入程序调试环境,按“F5”键,顺序运行程序,调出“ProteusISIS”界面,可以看到发光二极管按按亮1s,灭1s的规律间歇发光,当把连接到P3_2端的按钮开关按下时相当于白天,此时发光二极管熄灭不发光,同时单片机的内部定时/计数器也停止计数。
例3设计基于89C51单片机的简易数字时钟,按时:
分:
秒格式在LED上显示时间。
(1)硬件设计
打开ProteusISIS编辑环境,按表X-2所列的元件清单添加元件。
表X-2
元件名称
所属类
所属子类
AT89C51
MicroprocessorICs
8051Family
CAP
Capacitors
Generic
CRYSTAL
Miscellancous
—
RES
Resistors
Generic
BUTTON
Switches&Relays
Switches
7SEG-MPX6-CA-BLUE
0ptoelectronics
7-SegmentDisplays
RESPACK-8
Resistors
ResistorPacks
元件添加后,在ProteusISIS编辑区中按图X-3所示连接硬件原理图,图中“RP1”为排阻,相当于8个上拉电阻(为了绘图简便,下图中单片机的时钟和复位电路并没有画出,这是因为在Proteus仿真中时钟及复位电路可以缺省,但必须记住在实际应用电路中的时钟及复位电路是不能缺省的)。
图5.9电路原理图
(2)软件设计
1)基本思路
编程使T/C0工作在定时器方式1,定时100ms时溢出中断,用变量记录T/C0溢出中断的次数,当T/C0溢出中断满10次,即1s时间到,秒钟加1,将记录中断次数的变量清零;当秒钟满60时,分钟加1,秒钟清零;当分钟满60时,时钟加1,秒钟清零;当时钟满24时,时钟清零;接着又按上述规律开始新一轮计时。
2)源程序
#include
unsignedcharsec=0,min=0,hour=0,y=0;//定义时、分、秒等相关变量
unsignedchartab[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
voiddelay(unsignedcharx)//延时函数
{unsignedcharj;
while(x--)
for(j=0;j<125;j++)
{;;}
}
voiddisplay(void)//显示函数
{unsignedcharseclbit,sechbit,minlbit,minhbit,hourlbit,hourhbit;
sechbit=sec/10;seclbit=sec%10;
minhbit=min/10;minlbit=min%10;
hourhbit=hour/10;hourlbit=hour%10;
P0=tab[seclbit];
P2_5=1;delay
(1);P2_5=0;
P0=tab[sechbit];
P2_4=1;delay
(1);P2_4=0;
P0=tab[minlbit];
P0_7=0;
P2_3=1;delay
(1);P2_3=0;
P0=tab[minhbit];
P2_2=1;delay
(1);P2_2=0;
P0=tab[hourlbit];
P0_7=0;
P2_1=1;delay
(1);P2_1=0;
P0=tab[hourhbit];
P2_0=1;delay
(1);P2_0=0;
}
voidtimer0()interrupt1using1//100ms定时中断函数
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
y=y+1;
}
voidmain(void)
{
TMOD=0x01;//设置T/C0为定时方式1
TH0=(65536-50000)/256;//装入初值
TL0=(65536-50000)%256;
EA=1;//开总中断
ET0=1;//开T0中断
TR0=1;//启动定时器T0
while
(1)
{
if(y==10)
{sec=sec+1;//秒钟加1
y=0;}
if(sec==60)
{min=min+1;//分钟加1
sec=0;}
if(min==60)
{hour=hour+1;//时钟加1
min=0;
}
if(hour==24)
{hour=0;}
display();//调显示子函数
}
}
(3)调试与仿真
打开KeiluVision3,新建Keil项目,选择AT89C51单片机作CPU,新建C语言程序源文件,编写上述程序并将其导入到“SourceGroup1”中,在“OptionsforTarget”对话窗口中,选中“Optput”选项卡中的“CreateHESFile”选项和“Debug”选项卡中的“Use:
ProteusVSMSimulator”选项。
编译编译并调试以上C语言源程序。
接着在ProteusISIS中,选中AT89C51并单击鼠标左键,打开“EditComponent”对话窗口,设置单片机晶振频率为12MHz,在此窗口中的“ProgramFile”栏中,选择先前用Keil生成的.HEX文件。
在ProteusISIS的菜单栏中选择“File”→“SaveDesign”选项,保存设计。
在ProteusISIS的菜单栏中,打开“Debug”下拉菜单,在菜单中选中“UseRemoteDebugMonitor”选项,以支持与Keil的联合调试。
然后在Keil的菜单栏中选择“Debug”→”Start/StopDebugSession”选项,进入程序调试环境,按“F5”键,顺序运行程序,调出“ProteusISIS”界面,可以看到在6位数码管上按时:
分:
秒格式显示时钟,如图X-4所示。
本例中的数字时钟功能非常简单,没有时间调整等功能,读者可以在此基础上设计出功能更多的数字时钟,如万年历等。
图5.10仿真效果图