1.基本概念:
89C51有两个计数器T0和T1,每个计数器都是由两个8位的RAM 单元组成的,即每个计数器都是16 位的计数器,最大的计数容量是2的6次方=65536,记住是从0-65535。
定时器的本质也是计数器,只不过定时器的脉冲来自内部的晶振,而计数器的脉冲来自外部,当检测的脉冲的下降沿时,计数寄存器加一,直到溢出,然后单片机产生一个中断。所以需要定时时,先给计数寄存器设定一个初值,每有一个内部的脉冲时钟信号(相当与一段时间),计数器加一,直到溢出,一次定时完成。之后继续循环上述步骤。
2.内部结构:
3.相关寄存器:
-
定时/计数器方式寄存器TMOD(只能段寻址)
GATE—门控制位。
GATE=0,定时器/计数器启动与停止仅受TCON寄存器中TRX(X=0,1)来控制。
GATE=1,定时器计数器启动与停止由TCON寄存器中TRX(X=0,1)和外部中断引脚(INT0或INT1)上的电平状态来共同控制。
C/T—定时器和计数器模式选择位。
C/T=1,为计数器模式;C/T=0,为定时器模式。
M1M0—工作模式选择位。
-
定时器/控制器控制寄存器TCON(可以位寻址)
IT0:外部中断0触发方式控制位
当IT0=0时,为电平触发方式(低电平有效)
当IT0=1时,为边沿触发方式(下降沿有效)
IE0:外部中断0中断请求标志位 (硬件自动完成)
IT1:外部中断1触发方式控制位(同IT0)
IE1:外部中断1中断请求标志位 (同IE0)
TF0:定时/计数器T0溢出中断请求标志位
TF1:定时/计数器T1溢出中断请求标志位
TR1:定时器1运行控制位。
由软件清0关闭定时器1。当GATE=1,且INIT为高电平时,TR1置1启动 定时器1;当GATE=0时,TR1置1启动定时器1。
TR0—定时器0运行控制位,其功能及操作方法同TR1。 -
计数寄存器TH0/TL0(8位) , TH1/TL1(8位)
关于如何设初值,首先要明白几个周期的概念:***时钟周期:***
时钟周期也叫振荡周期或晶振周期,即晶振的单位时间发出的脉冲数,一般有外部的振晶产生,比如12MHZ=12×10的6次方,即每秒发出12000000个脉冲信号,那么发出一个脉冲的时间就是时钟周期,也就是1/12微秒。通常也叫做系统时钟周期。是计算机中最基本的、最小的时间单位。
***机器周期:***
在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段,每一阶段完成一项工作。例如,取指令、存储器读、存储器写等,这每一项工作称为一个基本操作。完成一个基本操作所需要的时间称为机器周期。8051单片机的机器周期由12个状态周期组成。
在标准的51单片机中,一般情况下,一个机器周期等于12个时钟周期,也就是机器周期=12*时钟周期,(上面讲到的原因)如果是12MHZ,那么机器周期=1微秒。单片机工作时,是一条一条地从RoM中取指令,然后一步一步地执行。单片机访问一次存储器的时间,称之为一个机器周期,这是一个时间基准。
机器周期不仅对于指令执行有着重要的意义,而且机器周期也是单片机定时器和计数器的时间基准。例如一个单片机选择了12MHZ晶振,那么当定时器的数值加1时,实际经过的时间就是1us,这就是单片机的定时原理。
接下来就是如何设初值了:
一般我们取12M晶振时,一个周期刚好是1us,计数1000个就是1ms,这是因为标准的51单片机是12时钟周期的(STC有6时钟和1时钟方式)。那么,如果我们晶振是12M,就比较好算,如果是其它的,就用12去除好了。比如是6M的,那么就是12/6=2,每个计数是2us,那么你要定时1ms就只要计数500个即可以。
定时器的初值跟定时器的工作方式,跟晶振频率都有关系。一个机器周期Tcy=晶振频率X12,计数次数N=定时时间t/机器周期Tcy,那么初值就X=65536-N,得出的数化成十六进制就行了。这里是用定时器O工作方式1做例子,如果是其它工作方式,就不能是65535了。工作方式0是8192,方式2,3是256。这里有一个公式:
TH=(65536-time/(12/ft))/256
其中,time就是要延时的100ms(要取100000us),ft是晶振频率。这个式子又可以简化成
TH=(65536-time*ft/12)/256
TL=(65536-time*ft/12)%256
4.实例分析:
通常定时器初始化过程如下:
(1)对TMOD赋值,以确定T0和 T1的工作方式。
(2)计算初值,并将初值写入TH0、TL0或TH1、TL1。
(3)中断方式时,则对IE赋值,开放中断。
(4)使TR0和TR1置位,启动定时器/计数器定时或计数。
产生一个1khz的方波
主程序:
采用定时器0的模式1
#include <reg51.h>
#include <intrins.h>
#define uint unsigned int
sbit led = P1^0 ;
void Time0_Init(void)
{
TMOD = 0x1 ; //定时器0模式1,C/T = 0 , GATE0 = 0 ;
TH0 = (65536 - 500)/256 ; //设初值
TL0 = (65536 - 500)%256 ;
ET0 = 1 ; //开定时器0中断
EA = 1 ; //开总中断
TR0 = 1 ; // 开定时器0
}
void Time0() interrupt 1
{
TH0 = (65536 - 500)/256 ; //重新设初值
TL0 = (65536 - 500)%256 ;
led = ~led ;
}
void main(void)
{
Time0_Init() ; // 定时器0初始化
led = 0 ;
while(1)
{
}
}
采用定时器0的模式2:
#include <reg51.h>
#include <intrins.h>
#define uint unsigned int
sbit led = P1^0 ;
uint T0_count = 0 ;
void Time0_Init(void)
{
TMOD = 0x2 ; //定时器0模式2 ,C/T = 0 ,GATE0 = 0 ;
TH0 = 256 - 100; //设初值
ET0 = 1 ;
EA = 1 ;
TR0 = 1 ; // 开定时器0
}
void Time0() interrupt 1
{
T0_count ++ ;//每次0.1ms加一
if(T0_count == 5)
{
led = ~led ;
T0_count = 0 ;
}
}
void main(void)
{
Time0_Init() ; // 定时器0初始化
led = 0 ;
while(1)
{
}
}
感觉自己水水的,请多指教。