51單片機--定時器


基本介紹

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);
			
		}
		
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM