一、CPU时序的有关知识
    振荡周期:为单片机提供定时信号的振荡源的周期(晶振周期或外加振荡周期)

    状态周期:2个振荡周期为1个状态周期,用S表示。振荡周期又称S周期或时钟周期。
    机器周期:1个机器周期含6个状态周期,12个振荡周期。
    指令周期:完成1条指令所占用的全部时间,它以机器周期为单位。
    例如:外接晶振为12MHz时,51单片机相关周期的具体值为:
        振荡周期=1/12us;
        状态周期=1/6us;
        机器周期=1us;
        指令周期=1~4us;
二、定时器的预备知识
    51单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器/计数器。
    定时器/计数器和单片机的CPU是相互独立的。定时器/计数器工作的过程是自动完成的,不需要CPU的参与。
    51单片机中的定时器/计数器是根据机器内部的时钟或者是外部的脉冲信号对寄存器中的数据加1。
    有了定时器/计数器之后,可以增加单片机的效率,一些简单的重复加1的工作可以交给定时器/计数器处理。CPU转而处理一些复杂的事情。同时可以实现精确定时作用。
三、定时/计数器的工作原理
    定时/计数器实质上是一个加1计数器。它随着计数器的输入脉冲进行自加1,也就是每来一个脉冲,计数器就自动加1,,当加到计数器为全1时,再输入一个脉冲就使计数器回零,且计数器的溢出使相应的中断标志位置1,向CPU发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。
    可见,由溢出时计数器的值减去计数初值才是加1计数器的计数值。
四、51单片机定时器结构
    定时/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器THx和TLx组成。TMOD是定时/计数器的工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。

 

五、定时/计数器的控制

    1、工作方式寄存器TMOD
        工作方式寄存器TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1。其格式如下:

 

        GATE是门控位, GATE=0时,用于控制定时器的启动是否受外部中断源信号的影响。只要用软件使TCON中的TR0或TR1为1,就可以启动定时/计数器工作;GATA=1时,要用软件使TR0或TR1为1,同时外部中断引脚INT0/1也为高电平时,才能启动定时/计数器工作。即此时定时器的启动条件,加上了INT0/1引脚为高电平这一条件。
        C/T :定时/计数模式选择位。C/T =0为定时模式;C/T =1为计数模式。
        M1M0:工作方式设置位。定时/计数器有四种工作方式。

 

     2、控制寄存器TCON
        TCON的低4位用于控制外部中断,已在前面介绍。TCON的高4位用于控制定时/计数器的启动和中断申请。其格式如下:

        TF1(TCON.7):T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。T1工作时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。
        TR1(TCON.6):T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。
        TF0(TCON.5):T0溢出中断请求标志位,其功能与TF1类同。
        TR0(TCON.4):T0运行控制位,其功能与TR1类同。
 

 

六、定时/计数器的工作方式:
    1、方式0
        方式0为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。

        定时器模式时有:N=t/ Tcy 
        计数初值计算的公式为:X=213-N。
        定时器的初值还可以采用计数个数直接取补法获得。
        计数模式时,计数脉冲是T0引脚上的外部脉冲。
        门控位GATE具有特殊的作用。当GATE=0时,经反相后使或门输出为1,此时仅由TR0控制与门的开启,与门输出1时,控制开关接通,计数开始;当GATE=1时,由外中断引脚信号控制或门的输出,此时控制与门的开启由外中断引脚信号和TR0共同控制。当TR0=1时,外中断引脚信号引脚的高电平启动计数,外中断引脚信号引脚的低电平停止计数。这种方式常用来测量外中断引脚上正脉冲的宽度。  
    2、方式1 
        方式1的计数位数是16位,由TL0作为低8位,TH0作为高8位,组成了16位加1计数器 。


        计数个数与计数初值的关系为:X=216-N

    3、方式2 
        方式2为自动重装初值的8位计数方式。

        计数个数与计数初值的关系为:X=28-N 
        工作方式2特别适合于用作较精确的脉冲信号发生器。

    4、方式3 
        方式3只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1=0,停止计数。 

 

         工作方式3将T0分成为两个独立的8位计数器TL0和TH0 。

 

七、程序初始化需做如下工作

  1. 对TMOD赋值,以确定T0和T1的工作方式。

  2. 计算初值,并将其写入TH0、TL0或TH1、TL1。

  3. 中断方式时,则对EA赋值,开放定时器中断。

  4. 使TR0或TR1置位,启动定时/计数器定时或计数。

八、计数器初值的计算
    机器周期也就是CPU完成一个基本操作所需要的时间。
    机器周期=1/单片机的时钟频率。
    51单片机内部时钟频率是外部时钟的12分频。也就是说当外部晶振的频率输入到单片机里面的时候要进行12分频。比如说你用的是12MHZ的晶振,那么单片机内部的时频率就是12/12MHZ,当你使用12MHZ的外部晶振的时候。机器周期=1/1M=1us。而我定时1ms的初值是多少呢,1ms/1us=1000。也就是要计数1000个数,初值=65535-1000+1(因为实际上计数器计数到66636才溢出)=64536=FC18H

下面这个程序可以控制小灯的熄灭

//定时器0实验												  *
//实现现象:下载程序后D1小灯循环点亮1秒,熄灭1秒。使用单片机内部定时器可以实现准确延时。
 
#include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器
 
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
 
sbit led=P2^0;	 //定义P20口是led
 
// 函 数 名         : Timer0Init
// 函数功能		   : 定时器0初始化
// 输    入         : 无
//输    出         : 无
 
void Timer0Init()
{
	TMOD|=0X01;	//选择为定时器0模式,工作方式1,仅用TR0打开启动。
 
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;	
	ET0=1;		//打开定时器0中断允许
	EA=1;		//打开总中断
	TR0=1;		//打开定时器			
}
 
// 函 数 名       : main
// 函数功能		 : 主函数
// 输    入       : 无
// 输    出    	 : 无
 
void main()
{	
	Timer0Init();  //定时器0初始化
	while(1);		
}
 
// 函 数 名         : void Timer0() interrupt 1
// 函数功能		   : 定时器0中断函数
// 输    入         : 无
// 输    出         : 无
 
void Timer0() interrupt 1
{
	static u16 i;
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;
	i++;
	if(i==1000)
	{
		i=0;
		led=~led;	
	}	
}

下面这个程序使用单片机内部的定时器,显示屏间隔一秒依次显示0-F

//定时器1实验												  *
//实现现象:下载程序后数码管最后一位间隔一秒循环显示0-F。使用单片机内部定时器可以实现准确延时。
//注意事项:如果不想让点阵模块显示,可以将74HC595模块上的JP595短接片拔掉。																				  
 
 
#include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器
 
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
 
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
 
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
u8 n=0;
 
//函 数 名         : Timer1Init
//函数功能		   : 定时器1初始化
//输    入         : 无
//输    出         : 无
 
void Timer1Init()
{
	TMOD|=0X10;//选择为定时器1模式,工作方式1,仅用TR1打开启动。
 
	TH1=0XFC;	//给定时器赋初值,定时1ms
	TL1=0X18;	
	ET1=1;//打开定时器1中断允许
	EA=1;//打开总中断
	TR1=1;//打开定时器			
}
 
//函 数 名       : main
//函数功能		 : 主函数
//输    入       : 无
//输    出    	 : 无
 
void main()
{	
	LSA=0;
	LSB=0;
	LSC=0;
	Timer1Init();  //定时器1初始化
	while(1);		
}
 
//函 数 名         : void Timer1() interrupt 3
//函数功能		   : 定时器0中断函数
//输    入         : 无
//输    出         : 无
 
void Timer1() interrupt 3
{
	static u16 i;
	TH1=0XFC;	//给定时器赋初值,定时1ms
	TL1=0X18;
	i++;
	if(i==1000)
	{
		i=0;
		P0=smgduan[n++];
		if(n==16)n=0;	
	}	
}