简述
51单片机有两个定时器T0和T1,而我们经常使用的单片机型号是STC89C52,比51多了一个定时器T2.定时器可以用来定时和计数。除了步进电机、超声波等比较特殊的用到定时器外,还可以用定时器进行倒计时、计数、对灯或蜂鸣器或其他的元器件进行状态的反转等。其实有的时候会用定时器体现“延时”的功能,但是用延时函数的话,会使整个程序停止运行,程序就会卡死,那用定时器就会解决这个问题。
1,工作方式
定时器是溢出中断的,定时器T0和T1有四种工作方式,T2有一种工作方式。工作方式是寄存器TMOD控制的,这个寄存器共有8位,高四位是控制定时器T1的,第四位是控制定时器T0的。
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 
| GATE | C/ | M1 | M0 | GATE | C/ | M1 | M0 | 
对T0和T1来说,M0和M1是设置工作方式的,其他通常置0,
| 0000 | 使用工作方式0 | 13位定时/计数器 | 
| 0001 | 使用工作方式1 | 16位定时/计数器 | 
| 0010 | 使用工作方式2 | 8位重装载定时/计数器 | 
| 0011 | 使用工作方式3 | T0分成两个独立的8位定时/计数器,T1是停止计数 | 
2,初值的计算
如果晶振是11.0592MHz的,内部的时钟频率是外部的12分频,所以内部就是12/11059200,那机械周期为 1/(12/11059200)=921600,加入定时1ms,循环1000次为1s,921600/1000=921.6,所以初值为
TH0=(65536-921)/256;
TL0=(65536-921)%256;
因为用的是方式1,是16位的,2的16次方是62236,2的8次方是256,又因为是溢出中断,所以就得到了上面的初值。如果晶振是12MHz的,那就是括号里就是65535-1000了
3, 定时器初始化
这里定时器T0用的是定时模式。还用到了中断允许寄存器里的EA,ET0和定时器控制寄存器TR0.
void Timer0Init()
{
	TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
//	TH0=0XFC;	//给定时器赋初值,定时1ms
//	TL0=0X18;
	//5ms / (1/(SYS/12))			SYS系统时钟
	TH0 = (65536-1000)/256;  //重新赋初值
	TL0 = (65536-1000)%256;
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//打开定时器
}定时器1初始化,因为是计数模式,所以从右往左数第5位和第七位(16位计数)置1,所以TMOD|=0x50
void Timer1Init(void)
{
	TMOD|=0X50;//选择为定时器1模式,工作方式1
	ET1=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR1=1;//打开定时器
}
4,中断函数
中断名称不一样,那中断号也不一样
| 名称 | 终端号 | 
| /INT0 外部中断0 | 0 | 
| T0 定时器0中断 | 1 | 
| /INT1 外部中断1 | 2 | 
| T1 定时器1中断 | 3 | 
| TR/RI 串行口中断 | 4 | 
uint i;
void Timer0() interrupt 1
{
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;
	i++;
	if(i==1000)
	{
		i=0;
		time_1s++;
	}
}
void Timer1() interrupt 3
{
}
5,引脚和现象
 由图可知定时器1对应的引脚是P3.5
由图可知定时器1对应的引脚是P3.5
 所以每次按下按键后,前两位数码管的计数值+1.
所以每次按下按键后,前两位数码管的计数值+1.
定时器没加任何条件,所以上电之后每过1秒,后两位数码管+1。
6, 52单片机的定时器T2
T2是16位自动重装载的,和T0,T1的工作方式2一样,只是T0和T1是8位的,作为定时器时,只需要在初始化函数中写入初值就行了,中断函数里就不用写了,中断号是5,引脚是P1.0。但是当P1.0作为I/O口时,T2就只能定时或者作为串口时钟,不用用于计数。
初始化函数
sfr T2MOD=0XC9;        //寄存器T2MOD定义
void Timer0Init()
{
                    //50微秒@11.0592MHz
    T2MOD = 0;      //---- --00  初始化模式寄存器  默认向上计数
    T2CON = 0;      //0000 0000  初始化控制寄存器 一个中断源,16位自动重装模式
    TL2 = 0x00;     //设置定时初值
    TH2 = 0x4C;     //设置定时初值
    RCAP2L = 0x00;      //设置定时重载值
    RCAP2H = 0x4C;      //设置定时重载值
    TR2 = 1;        //定时器2开始计时
    IE=0XA0;        //1010 0000 打开全局中断,定时器2中断
}中断函数
void timer_T2() interrupt 5       //中断函数
{
    static unsigned char count;     //定义变量,记录中断次数
    TF2=0;              //软件清零定时器2溢出标志位
    count++;
    if(count==20)       //时间为1秒
    {
        count=0;         //清零
        led=~led;        //状态取反
    }
}现象也是LED灯闪烁。



