51單片機定時器應用(C程序)
基本的51單片機內部有兩個16位可編程的定時器/計數器T0和T1。它們各自具有4種工作狀態,其控制字和狀態均在相應的特殊功能寄存器中,可以通過軟件對控制寄存器編程設置,使其工作在不同的定時狀態或計數狀態。
現在,許多廠家生產的8051兼容單片機上,還加入了定時器/計數器2,使單片機的應用更為靈活,適應性更強。
很多8051單片機的書籍都對定時器/計數器有詳細的介紹,我們在此不再詳細地討論。但因為編寫或或閱讀程序時經常要查閱定時器/計數器的設置情況,因此我們僅對一些編程時經常要用到的較重要的寄存器和設置方式進行簡要簡介。
1 定時器/計數器簡介
8051單片機的定時器/計數器基本結構如圖1-1所示,定時器T0由兩個8位計數器TH0和TL0構成,定時器T1也由兩個8位計數器TH1和TL1構成,TMOD寄存器控制定時器的工作方式,TCON寄存器控制定時器的啟動和停止以及定時器的狀態。

圖1-1 定時器/計數器結構
在作定時器使用時,輸入的時鐘脈沖是由晶體振蕩器的輸出經12分頻后得到的。實際上,定時器就是單片機機器周期的計數器。因為每個機器周期包含晶體振蕩器的12個振蕩周期,而每一個機器周期定時器加1,故其頻率為晶振頻率的1/12。如果晶振頻率為12MHz,則定時器每接收一個輸入脈沖的時間為1μs。
選擇計數器工作方式時,計數脈沖來自相應的外部輸入引腳T0(P3.4)或T1(P3.5)。在這種情況下,當檢測到輸入引腳上的電平由高跳變到低時,計數器就加1。
2 控制和狀態寄存器
(1)定時器控制寄存器(TCON)
TCON為定時器/計數器的控制寄存器,同時也鎖存外部中斷請求標志,各位定義如下。
? TF1:定時器/計數器1中斷請求標志位。當定時器計數滿溢出回零時,由硬件置位,并可申請中斷。當CPU響應中斷并進入中斷服務程序后,TF1自動清零。
? TR1:定時器/計數器1運行控制位,靠軟件置位或清除。置位時,定時器/計數器1接通工作,清除時停止工作。
? TF0:定時器/計數器0中斷請求標志位,其功能和操作情況類同于TF1。
? TR0:定時器/計數器0運行控制位,其功能和操作情況類同于TR1。
? IEl:外部中斷1的中斷申請標志,檢測到在INT引腳上出現的外部中斷信號的下降沿時,由硬件置位,申請中斷。進入中斷服務程序后被硬件自動清除。
? IT1:外部中斷1的類型控制位。IT1=1,由下跳沿觸發;IT1=0,由低電平觸發。可以由軟件來設置或清除。
? IE0:外部中斷0的中斷申請標志。其功能和操作情況類同于IE1。
? IT0:外部中斷0的類型控制位。其功能和操作情況類同于IT1。
(2)工作方式寄存器(TMOD)。TMOD確定定時器的工作方式及功能選擇,不能位尋址。其中,高4位用于控制定時器1,低4位用于控制定時器0。TMOD各位的定義如下。
? GATE:門控位,當GATE=1時,只有?I?N?T?0或?I?N?T?1引腳為高電平,且TR0或TR1置1時,定時器/計數器才工作。當GATE=0時,定時器/計數器僅受TR0或TR1的控制,而不管?I?N?T?0或?I?N?T?1引腳的電平是高還是低。
? C/?T:定時器/計數器功能選擇位,C/?T=0時,設置為定時功能;C/?T=1時,設置為計數功能。
? M1 M0 :工作方式選擇位。由M1M0共2位形成4種編碼,對應以下4種工作方式。
n M1M0=00:工作方式0(13位方式)。
n M1M0=01:工作方式1(16位方式)。
n M1M0=10:工作方式2(8位自動裝入時間常數方式)。
n MlM0=11:工作方式3(2個8位方式——僅對T0)。
3 定時器/計數器設置實例
以定時器/計數器T0為例,在方式0下,TL0的低5位和TH0的8位構成13位計數器,因此計數工作方式時,計數值的范圍是:1~8192(213)。
當設定為定時工作方式時,定時時間的計算公式為:
(213-計數初值)×晶振周期×12 或(213-計數初值)×機器周期
這樣,我們可以算出,若單片機系統的外接晶振頻率為6MHz,則該系統的最小定時時間為:
[213-(213-1)]×[1/(6×106)]×12=2×10-6=2(?s)
最大定時時間為:
(213-0)×[1/(6×106)]×12=16384×10-6=16384(?s)=16.384(ms)
或:最小定時單位×1013=16384(?s)=16.384(ms)
【例】某單片機系統的外接晶振頻率為6MHz,使用定時器1,以方式0定時,從P1.0輸出2ms方波的計算和設置方法如下:
① 計算計數初值。欲產生2ms的等寬正方波脈沖,只需在P1.0端以1ms為周期交替輸出高低電平即可實現,為此定時時間應為1ms。使用6MHz晶振,則機器周期為:
機器周期=12/晶振頻率=12/(6×106)=2(?s)
方式0為13位計數結構。設待求的計數初值為X,則:
(213-X)×2×10-6=1×10-3
求解得:
X=7692
化為二進制數表示為1111000001100。
用十六進制表示,高8位為F0H,放入TH1;低5位為0CH,放入TL1。
② TMOD寄存器初始化。為把定時器/計數器1設定為方式0,設置M1M0=00;為實現定時功能,應使C/?T =0;為實現定時器/計數器1的運行控制,設置GATE=0。定時器/計數器0不用,有關位設定為0。因此TMOD寄存器應初始化為00H。
③ 由定時器控制寄存器TCON中的TR1位控制定時的啟動和停止,TR1=1啟動,TR1=0停止。
若使其工作在方式1,定時器/計數器為16 位定時器/計數器,即加法計數器由 TH0 全部8位和TL0全部8位構成16位,其余與方式0完全相同,因此計算TH0和TL0初值的方法也和工作方式0類似,只是需注意原來13位的地方現在要換成16位。
4 定時器/計數器2
8051單片機中,有一部分型號有三個定時器/計數器,如Intel的8032、Atmel的89C52、89C55、Philips的89C51RC、89C58,等等。這些單片機的第三個定時器/計數器叫T2,其控制寄存器是T2CON,它的各位定義如下:
? TF2:定時器2溢出標志。定時器溢出時置位,并申請中斷,只能靠軟件清除。當RCLK或TCLK =1 時TF2 將不會置位。
? EXF2:定時器2外部標志。當EXEN2為1,且T2EX 引腳上出現負跳變產生捕獲或重裝時EXF2置位,申請中斷。若已允許定時器2 中斷,EXF2=1 將使CPU 從中斷向量處執行定時器2中斷子程序。EXF2 位必須用軟件清零。當定時器/計數器2工作在向上遞增或向下遞減計數器模式(方式控制寄存器T2MOD的DCEN位=1)時,EXF2 不能激活中斷。
? RCLK:接收時鐘標志。靠軟件置位或清除。RCLK=1時,用定時器2溢出脈沖作為串行口(工作于方式1或3時)的接收時鐘。RCLK=0時,用定時器1的溢出脈沖作為接收時鐘。
? TCLK:發送時鐘標志。靠軟件置位或清除。TCLK=1時,用定時器2溢出脈沖作為串行口(工作于方式1或3時)的發送時鐘。TCLK=0時,用定時器1的溢出脈沖作為發送時鐘。
? EXEN2:定時器2外部允許標志。靠軟件置位或清除。當EXEN2=1時,如果定時器2未用作串行口的波特率發生器,在T2EX端出現負跳變脈沖時,激活定時器2捕獲或重裝,并置EXF2標志為1,請求中斷。EXEN2=0時,T2EX端的外部信號無效。
? TR2:定時器2啟動/停止控制位。靠軟件置位或清除。TR2=1時,啟動定時器2,否則停止。
? C/?T?2:定時器2定時方式或計數方式控制位。C/?T?2=0,選擇定時方式;C/?T?2=1時,選擇對外部計數方式(下降沿觸發)。
? CP/?R?L?2:捕獲/重裝載選擇。CP/?R?L?2=1時,如果EXEN2=1,且T2EX端出現負跳變脈沖時發生捕獲操作,即把TH2和TL2的內容傳遞給RCAP2H和RCAP2L。CP/?R?L?2=0時,若定時器2溢出或EXEN2=1,T2EX端出現負跳變脈沖,會出現重裝載操作,即把RCAP2H和RCAP2L的內容傳遞給TH2和TL2。當RCLK=1或TCLK=1時,該位無效,在定時器2溢出時強制其自動重裝載。
通過軟件設置T2CON,可使定時/計數器以三種基本工作方式之一工作。第一種為捕捉方式。設置為捕捉方式時,和定時器0 或定時器1 一樣以16 位方式工作。這種方式通過復位EXEN2來選擇。當置位EXEN2時,如果T2EX有負跳變電平,將把當前的數鎖存在(RCAP2H和RCAP2L)中。這個事件可用來產生中斷。
第二種工作方式為自動重裝方式,其中包含了兩個子功能,由EXEN2來選擇,當EXEN2復位時,16 位定時器溢出將觸發一個中斷并將RCAP2H 和RCAP2L 中的數裝入定時器中。當EXEN2 置位時,除上述功能外,T2EX 引腳的負跳變將產生一次重裝操作。
最后一種方式用來產生串行口通信所需的數據傳輸率,這通過同時或分別置位RCLK 和TCLK來實現。在這種方式中,每個機器周期都將使定時器加1,而不像定時器0 和1 那樣,需要12個機器周期。這使得串行通信的數據傳輸率更高。
定時器2還有一個不可尋址的方式控制寄存器T2MOD,其內容如下:
? —:保留位。
? T2OE:定時器2輸出允許位。
? DCNE:置位時,允許定時器2作為向上/向下計數器。
5 編程實例
【例1】這是一個簡單的定時器程序,由一個循環組成,在點亮接在P1.0 口的LED之后,延時一段時間,再滅掉LED,又延時一段時間,之后循環到前面。按全速運行,可以看到P1.0口上接的LED 燈不斷地閃爍。
#include //包括一個52標準內核的頭文件
sbit P10 = P1^0; //要控制的LED燈
sbit K1= P3^2; //按鍵K1
//用定時器中斷閃爍LED
void main(void) //主程序
{
TMOD=0x01; //定時器0,16位工作方式
TR0=1; //啟動定時器
ET0=1; //打開定時器0中斷
EA=1; //打開總中斷
while(1) //程序循環
{
; //主程序在這里就不斷自循環,實際應用中,這里是做主要工作
}
}
//定時器0中斷
timer0() interrupt 1 // 定時器0中斷是1號
{
TH0=0x00; //寫入定時器0初始值0x0005
TL0=0x06;
P10=~P10; //反轉LED燈的亮和滅
}
程序中,使用了定時器0,工作在方式1,即16位工作方式。
【例2】這是一個跑馬燈程序,使用了定時器2。
#include //包括一個52標準內核的頭文件
sbit P10 = P1^0; //頭文件中沒有定義的IO就要自己來定義了
sbit P11 = P1^1;
sbit P12 = P1^2;
sbit P13 = P1^3;
bit ldelay=0; //長定時溢出標記,預置是0
//定時器中斷方式的跑馬燈
void main(void) //主程序
{
unsigned char code ledp[4]={0xfe,0xfd,0xfb,0xf7};//預定的寫入P1的值
unsigned char ledi; //用來指示顯示順序
RCAP2H =0x10; //賦T2的預置值0x1000,溢出30次就是1秒鐘
RCAP2L =0x00;
TR2=1; //啟動定時器
ET2=1; //打開定時器2中斷
EA=1; //打開總中斷
while(1) //主程序循環
{
if(ldelay) //發現有時間溢出標記,進入處理
{
ldelay=0; //清除標記
P1=ledp[ledi]; //讀出一個值送到P1口
ledi++; //指向下一個
if(ledi==4)ledi=0; //到了最后一個燈就換到第一個
}
}
}
//定時器2中斷
timer2() interrupt 5 // 中斷向量是5
{
static unsigned char t;
TF2=0;
t++;
if(t==30) //T2的預置值0x1000,溢出30次就是1秒鐘,晶振22.118400 MHZ
{
t=0;
ldelay=1; //每次長時間的溢出,就置一個標記,以便主程序處理
}
}


評論