基本介绍

51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成
定时器作用:

  • 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
  • 替代长时间的Delay,提高CPU的运行效率和处理速度

STC89C52有3个定时器(T0、T1、T2),T0和T1与传统的51单片机兼容,T2是此型号单片机增加的资源
注意定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的

STC89C52的T0和T1均有四种工作模式:

  • 模式0:13位定时器/计数器
  • 模式1:16位定时器/计数器(常用)
  • 模式2:8位自动重装模式
  • 模式3:两个8位计数器
    我们一般选模式1

工作模式1框图:

cubeMX 定时器1 定时器模式1_工作模式

时钟的来源:
1.外部时钟,晶振
2.外部引脚T0,T1

12MHz,每1微妙触发一次计数

相关寄存器

cubeMX 定时器1 定时器模式1_#include_02

TCON:定时器/计数器T0,T1的控制寄存器,目前我们只要配置其中TF0和TR0即可。

cubeMX 定时器1 定时器模式1_工作模式_03

TMOD:定时器模式寄存器,不可位寻址,高八位为定时器1工作模式设置,第八位为定时器0工作模式设置,但是我们只要定时器0,16位的工作模式,因此设置M1为0,M0为1,其它不用设置,因此TMOD低八位为0x01

cubeMX 定时器1 定时器模式1_工作模式_04

涉及到的中断,我们只关注红框中的几个

cubeMX 定时器1 定时器模式1_#include_05

cubeMX 定时器1 定时器模式1_cubeMX 定时器1_06


PT0为中断优先级,目前不做特殊关注。中断号

cubeMX 定时器1 定时器模式1_初值_07

根据上面的资料,我们可以设置一个定时器0的初始化函数,调出1个100us的定时器周期。
TH0,TL0,是计数器的高8位和低8位,最大65535,溢出则触发中断,1个机器周期为1us,那么100us的初始值应该是65535-100=65435。

void Timer0_Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 65435%256;		//设置计数器初值低八位
	TH0 = 65435/256;		//设置计数器初值高八位
	TF0 = 0;		//累计溢出时置1,中断响应后置0,清除TF0标志,防止生效后就产生中断
	TR0 = 1;		//定时器0开始计时

	ET0=1;		//开启定时器0中断
	EA=1;		//中断中开关    
	PT0=0;		//中断优先级,默认为0
}

定时器应用

LED闪烁

#include <REGX52.H>
#include <Timer0.h>

sbit LED=P1^0;
unsigned int T0Count=0;

void main(){
	
	Timer0_Init();
	while(1);
}


void Timer0_Routine() interrupt 1
{
	
	
	TH0 = 64535/256;		//设置定时初值
	TL0 = 64535%256;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		P1_0=~P1_0;
		
	}
}

Timer0.h

#include <REGX52.H>

/**
  * @brief  定时器0初始化,100us@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0_Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式保留定时器1的配置
	TMOD |= 0x01;		//设置定时器模式0 0 0 1
        TH0 = 64535/256;		//设置定时初值
	TL0 = 64535%256;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}

那么定时器的回调函数执行的时间周期是怎么来的?
一个机器周期包括12个时钟周期,设单片机工作于12Mhz晶振,则时钟周期为1/12us,则它的一个机器周期就是12*(1/12 )=1us,定时器是cpu的一部分,它定时的最小单位就是一个机器周期

小试身手

下面来尝试下用定时器来实现倒计时,代码如下:

#include <REGX52.H>
#include <Timer0.h>
#include <LCD1602.h>
#include <Delay.h>

sbit LED=P1^0;
sbit BEER =P2^3 ;	
unsigned int T0Count=0;
unsigned char hour,minute,sec;//时分秒
unsigned long int totelSec;//总秒数

void main(){
	
	Timer0_Init();
	LCD_Init();
	hour=0;
	minute=0;
	sec=10;
	totelSec=hour*60*60+minute*60+sec;
	LCD_ShowString(1,2,"Timer   :  :  ");
	LCD_ShowNum(1,8,hour,2);
	LCD_ShowNum(1,11,minute,2);
	LCD_ShowNum(1,14,sec,2);
	
	while(1);
}

void playBeer(unsigned char times,unsigned char ms){
	unsigned char i;
	for(i=0;i<times;i++){
		BEER=0;
		Delay(ms);
		BEER=1;
		Delay(ms);
	}

}


void Timer0_Routine() interrupt 1
{
	
	
	TH0 = 64535/256;		//设置定时初值
	TL0 = 64535%256;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		totelSec--;
		LCD_ShowNum(1,8,totelSec/(60*60),2);
		LCD_ShowNum(1,11,totelSec/60%60,2);
		LCD_ShowNum(1,14,totelSec%60,2);
		//时间到
		if(totelSec==0){
			LCD_ShowString(1,1," Timer is over    ");
			TR0 = 0;		//定时器0停止
			playBeer(6,200);
			LCD_ShowString(1,2,"Timer   :  :  ");
			LCD_ShowNum(1,8,totelSec/(60*60),2);
			LCD_ShowNum(1,11,totelSec/60%60,2);
			LCD_ShowNum(1,14,totelSec%60,2);
			
		}
		
	}
}