基本介紹
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框圖:

時鍾的來源:
1.外部時鍾,晶振
2.外部引腳T0,T1
12MHz,每1微妙觸發一次計數
相關寄存器

TCON:定時器/計數器T0,T1的控制寄存器,目前我們只要配置其中TF0和TR0即可。

TMOD:定時器模式寄存器,不可位尋址,高八位為定時器1工作模式設置,第八位為定時器0工作模式設置,但是我們只要定時器0,16位的工作模式,因此設置M1為0,M0為1,其它不用設置,因此TMOD低八位為0x01

涉及到的中斷,我們只關注紅框中的幾個


PT0為中斷優先級,目前不做特殊關注。
中斷號

根據上面的資料,我們可以設置一個定時器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);
}
}
}
