1 引言
單片機(jī)的定時(shí)器是單片機(jī)里最“活躍”的部件之一,很多程序、應(yīng)用系統(tǒng)都離不開(kāi)定時(shí)器。由于定時(shí)器的應(yīng)用與單片機(jī)的其他硬件相關(guān),存在著一定的復(fù)雜性。而定時(shí)器也是單片機(jī)應(yīng)用中解決某類復(fù)雜問(wèn)題的最為有效的方法,應(yīng)用非常廣泛[1]。定時(shí)器的應(yīng)用,可以說(shuō)即簡(jiǎn)單又復(fù)雜。對(duì)于簡(jiǎn)單應(yīng)用場(chǎng)合,時(shí)間要求較長(zhǎng),不算很精確的場(chǎng)合,用起來(lái)就簡(jiǎn)單,對(duì)于復(fù)雜應(yīng)用場(chǎng)合,時(shí)間要求即短又精確的場(chǎng)合,用起來(lái)就要復(fù)雜。本文以STC90C51RC/RD+系列單片機(jī)定時(shí)器為研究對(duì)象,并給出幾個(gè)示例程序。 STC90C51RC/RD+系列單片機(jī)是宏晶科技推出的新一代超強(qiáng)抗干擾/高速/低功耗的單片機(jī),指令代碼完全兼容傳統(tǒng)8051單片機(jī),12時(shí)鐘/機(jī)器周期和6時(shí)鐘/機(jī)器周期可以任意選擇。
2 定時(shí)器/計(jì)數(shù)器應(yīng)用
2.1 STC90C51RC/RD+系列單片機(jī)定時(shí)/計(jì)數(shù)器
STC90C51RC/RD+系列單片機(jī)共3個(gè)16位定時(shí)器/計(jì)數(shù)器,其中定時(shí)器0還可以當(dāng)成2個(gè)8位定時(shí)器使用。定時(shí)器0和定時(shí)器1,與傳統(tǒng)8051的定時(shí)器完全兼容,當(dāng)在定時(shí)器1做波特率發(fā)生器時(shí),定時(shí)器0可以當(dāng)兩個(gè)8位定時(shí)器用。
STC90C51RC/RD+系列單片機(jī)內(nèi)部設(shè)置的兩個(gè)16位定時(shí)器/計(jì)數(shù)器T0和T1都具有計(jì)數(shù)方式和定時(shí)方式兩種工作方式。對(duì)每個(gè)定時(shí)器/計(jì)數(shù)器(T0和T1),在特殊功能寄存器TMOD中都有一控制位C/T來(lái)選擇T0或T1為定時(shí)器還是計(jì)數(shù)器。定時(shí)器/計(jì)數(shù)器的核心部件是一個(gè)加法(也有減法)的計(jì)數(shù)器,其本質(zhì)是對(duì)脈沖進(jìn)行計(jì)數(shù)。只是計(jì)數(shù)脈沖來(lái)源不同:如果計(jì)數(shù)脈沖來(lái)自系統(tǒng)時(shí)鐘,則為定時(shí)方式,此時(shí)定時(shí)器/計(jì)數(shù)器每12個(gè)時(shí)鐘或者每6個(gè)時(shí)鐘得到一個(gè)計(jì)數(shù)脈沖,計(jì)數(shù)值加1;如果計(jì)數(shù)脈沖來(lái)自單片機(jī)外部引腳(T0為P3.4,T1為P3.5),則為計(jì)數(shù)方式,每來(lái)一個(gè)脈沖加1。
當(dāng)定時(shí)器/計(jì)數(shù)器工作在定時(shí)模式時(shí),可在燒錄用戶程序時(shí)在STC-ISP編程器中設(shè)置是系統(tǒng)時(shí)鐘/12還是系統(tǒng)時(shí)鐘/6后讓T0和T1進(jìn)行計(jì)數(shù)。當(dāng)定時(shí)器/計(jì)數(shù)器工作在計(jì)數(shù)模式時(shí),對(duì)外部脈沖計(jì)數(shù)不分頻。
定時(shí)器/計(jì)數(shù)器0有4種工作模式:模式0(13位定時(shí)器/計(jì)數(shù)器),模式1(16位定時(shí)器/計(jì)數(shù)器模式),模式2(8位自動(dòng)重裝模式),模式3(兩個(gè)8位定時(shí)器/計(jì)數(shù)器)。定時(shí)器/計(jì)數(shù)器1除模式3外,其他工作模式與定時(shí)器/計(jì)數(shù)器0相同,T1在模式3時(shí)無(wú)效,停止計(jì)數(shù)。
定時(shí)器2是一個(gè)16位定時(shí)/計(jì)數(shù)器。通過(guò)設(shè)置特殊功能寄存器T2CON中的C/T2位,可將其作為定時(shí)器或計(jì)數(shù)器。
定時(shí)器2有3種操作模式:捕獲、自動(dòng)重新裝載(遞增或遞減計(jì)數(shù))和波特率發(fā)生器。這3種模式由T2CON中的位進(jìn)行選擇。
2.2 定時(shí)器/計(jì)數(shù)器應(yīng)用
與傳統(tǒng)8051單片機(jī)相比,STC90C51RC/RD+系列單片機(jī)性能更優(yōu)越,就以定時(shí)/計(jì)數(shù)器為例,在筆者應(yīng)用單片機(jī)定時(shí)器定時(shí),輸出脈沖過(guò)程中發(fā)現(xiàn),如果需要用兩個(gè)以上定時(shí)器同時(shí)工作,在定時(shí)時(shí)間較長(zhǎng)情況下,前者的定時(shí)器能夠勝任;但是,當(dāng)兩個(gè)同時(shí)工作的定時(shí)器至少有一個(gè)定時(shí)時(shí)間較短時(shí),前者的定時(shí)器就會(huì)“罷工”。,鑒于此筆者選用STC90C51RC/RD+系列單片機(jī)作為研究對(duì)象。
如下幾個(gè)示例程序,從不同方面應(yīng)用STC90C51RC/RD+系列單片機(jī)的定時(shí)器,也充分展示了該類單片機(jī)的優(yōu)越性。所有程序都經(jīng)過(guò)keil軟件調(diào)試通過(guò),并生成*.hex文件燒入單片機(jī)實(shí)測(cè)。每一個(gè)程序都可作為一完整程序應(yīng)用。
應(yīng)用定時(shí)器進(jìn)行定時(shí)或計(jì)數(shù),不可避免要存在誤差,而每個(gè)程序存在誤差之處都以注釋的形式標(biāo)明。由于以下程序皆為C語(yǔ)言編寫(xiě),需要經(jīng)過(guò)編譯器編譯為匯編語(yǔ)言,所以,誤差的精確值不易算出,僅僅標(biāo)出產(chǎn)生誤差的語(yǔ)句。而如果采用匯編語(yǔ)言編寫(xiě),情況會(huì)好些。
1) 5秒內(nèi)計(jì)數(shù)脈沖個(gè)數(shù)
單片機(jī)外接的振蕩源頻率為11.0592MHz,利用定時(shí)器0定時(shí),每次定時(shí)50ms,循環(huán)100次,達(dá)到5s時(shí)間,利用定時(shí)器1計(jì)數(shù)5s內(nèi)外部脈沖個(gè)數(shù),并由串口傳輸給上位機(jī)。
本程序旨在說(shuō)明定時(shí)器0與定時(shí)器1同時(shí)工作的編程方法與思路。
#include<reg51.h>
#include<intrins.h>
/* 新增特殊功能寄存器定義 */
sfr IAP_DATA = 0xe2;
sfr IAP_ADDRH = 0xe3; //地址高8位
sfr IAP_ADDRL = 0xe4; //地址低8位
sfr IAP_CMD = 0xe5;
sfr IAP_TRIG = 0xe6;
sfr IAP_CONTR = 0xe7;
sfr RCAP2H = 0xcb;
sfr RCAP2L = 0xca;
sfr T2CON = 0xc8;
sfr T2MOD = 0xc9;
sbit TR2 = 0xca ;
typedef unsignedcharuchar;
typedef unsigned int uint;
sbit LED=P1^0;
sbit LLED=P1^1;
uchar flag_2s,flag_50ms;
uchar number_2s,number_50ms;
uint a,b;
void stc_init(void) //初始化
{
SCON = 0x50; //工作方式1
RCAP2H=0xff;
RCAP2L=0xda;
T2CON=0x34;
T2MOD = 0x00;
TMOD=0x51; //定時(shí)器1工作于模式1計(jì)數(shù)
TH1=0x00;
TL1=0x00;
TH0=0x4C;
TL0=0x01;
TR1=1;
TR2=1;
TR0=1;
EA=1;
ET0=1;
}
void delay(uchar xms)
{
uchar i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void stc_timer (void) interrupt 1
{
TH0=0x4c;重新賦值,賦值之后才能繼續(xù)計(jì)數(shù),故而,會(huì)產(chǎn)生誤差。
TL0=0x01;
LLED=!LLED;
flag_50ms =1;
number_50ms++;
if(number_50ms==100)
{
number_50ms=0;
a=TL1; 此處讀出計(jì)數(shù)器值,由于計(jì)數(shù)器正在計(jì)數(shù),故而存在誤差。
b=TH1;
TR1=0; 執(zhí)行到此,定時(shí)器才停止計(jì)數(shù)。
TH1=0x00;
TL1=0x00;
TR1=1;
}
}
void main(void) 主函數(shù),將脈沖個(gè)數(shù)發(fā)送給上位機(jī)。
{
stc_init();
do
{
delay(200);
SBUF=a;
while(TI==0);
TI=0;
delay(1000);
SBUF=b;
while(TI==0);
TI=0;
delay(1000);
}
while(1);
}
2) 定時(shí)器T0計(jì)數(shù)50個(gè)脈沖所需時(shí)間
/*查50個(gè)脈沖所需時(shí)間,脈沖由定時(shí)器T1發(fā)出,每50msP1.1取反,形成脈沖,將P1.1連接到T0(14號(hào))引腳,即可計(jì)數(shù),定時(shí)器T0計(jì)數(shù)輸入脈沖個(gè)數(shù),50(0x32)先顯示,之后,顯示50ms的個(gè)數(shù),再次顯示TL1的值,最后顯示TH1的值,此兩個(gè)值是時(shí)間零頭*/
……
……省略號(hào)部分與第一個(gè)程序相同
uchar flag_2s,flag_50ms;
uchar number_2s,number_50ms;
uchar number_pulse;
uint a,b,c;//計(jì)數(shù)用,計(jì)數(shù)50ms之外的零頭
uint time;//time為50個(gè)脈沖總時(shí)間(ms)
uint pulse;//查脈沖數(shù)
void stc_init(void) //初始化
{
SCON = 0x50; //工作方式1
RCAP2H=0xff;
RCAP2L=0xda;
T2CON=0x34;
T2MOD = 0x00;
TMOD=0x15; //定時(shí)器0工作于模式1計(jì)數(shù)
TH0=0x00;
TL0=0x00;
TH1=0x4C;
TL1=0x01;
TR1=1;
TR2=1;
TR0=1;
EA=1;
ET0=0;
ET1=1;
}
void stc_timer (void) interrupt 3
{
TH1=0x4c; 重新賦值,賦值之后才能繼續(xù)計(jì)數(shù),故而,會(huì)產(chǎn)生誤差。
TL1=0x01;
LLED=!LLED;
number_50ms++;
}
void main(void)
{
number_50ms=0;
LLED=0;
stc_init();
pulse=TL0;
do
{pulse=TL0;
}
while(pulse!=50);
//以下6條在循環(huán)體外
TR1=0;
a=TL1; 此處讀出計(jì)數(shù)器值,由于計(jì)數(shù)器正在計(jì)數(shù),故而存在誤差。
b=TH1;
TR1=1;
TH0=0x00;
TL0=0x00;
do
{
delay(200); 延時(shí)子程序與第一個(gè)程序相同
SBUF=pulse;
while(TI==0);
TI=0;
delay(1000);
SBUF=number_50ms;
while(TI==0);
TI=0;
delay(1000);
SBUF=a;
while(TI==0);
TI=0;
delay(1000);
SBUF=b;
while(TI==0);
TI=0;
delay(1000);
delay(1000);
}
while(number_50ms<103);//按照此條件,最后顯示出的number_50ms為
//0x66(102)因?yàn)檠舆t所致,103是根據(jù)實(shí)際顯示數(shù)值所定
}
3) 定時(shí)器T2計(jì)數(shù)T1波特率發(fā)生器
/*脈沖由定時(shí)器T0發(fā)出,一定時(shí)間后p1.2取反,形成脈沖, T1波特率發(fā)生器,發(fā)出38k方波,T2計(jì)數(shù),T2計(jì)數(shù)脈沖輸入端為p1.0
……省略號(hào)部分與第一個(gè)程序相同
……
uchar flag_2s,flag_50ms;
uchar number_2s,number_50ms;
uchar number_pulse;
uint a,b,c,PPP;//計(jì)數(shù)用,計(jì)數(shù)50ms之外的零頭
uint time;//time為50個(gè)脈沖總時(shí)間(ms)
uint pulse;//查脈沖數(shù)
void stc_init(void) //初始化
{
SCON = 0x50; //工作方式1
RCAP2H=0X00; //定時(shí)器t2初始化
RCAP2L=0x00;
TH2=RCAP2H; //定時(shí)器2賦初值
TL2=RCAP2L;
T2CON=0X02;
TMOD=0x21; //定時(shí)器1工作于模式2
TH1=0xfd;
TL1=0xfd;
TR1=1;
TH0=0x40;
TL0=0x00;
TR0=1;
TR2=1;
EA=1;
ET0=1;
ET1=0;
}
void stc_timer (void) interrupt 1
{
TH0=0x40;
TL0=0x00;
LLED=!LLED;
}
void main(void)
{
LED=0;
number_50ms=0;
LLED=0;
pulse=0;
stc_init();
while(pulse!=20)
{
TR2=0;
pulse=TL2;
TR2=1;
EA=0;
SBUF=pulse;
while(TI==0);
TI=0;
EA=1;
delay(1000);
}
}
3 定時(shí)/計(jì)數(shù)器誤差分析
由于單片機(jī)的機(jī)器周期為1μs~2μs,定時(shí)誤差一般應(yīng)在5μs~25μs之內(nèi),對(duì)于一般應(yīng)用,此誤差可以忽略,但是對(duì)于精確度要求比較高的應(yīng)用場(chǎng)合,此誤差必須進(jìn)行校正[2]。定時(shí)誤差是定時(shí)溢出后轉(zhuǎn)入執(zhí)行定時(shí)處理語(yǔ)句段之間所耗費(fèi)的時(shí)間,此時(shí)間主要由定時(shí)溢出轉(zhuǎn)入定時(shí)處理語(yǔ)句段所必須執(zhí)行的指令或硬件過(guò)程產(chǎn)生.而且,在轉(zhuǎn)入、轉(zhuǎn)出定時(shí)器中斷服務(wù)子程序過(guò)程都有延遲,即產(chǎn)生誤差[1]。再有,如果像第一個(gè)程序那樣,利用循環(huán)定時(shí)以產(chǎn)生更長(zhǎng)定時(shí),執(zhí)行循環(huán)處理及控制指令時(shí)亦會(huì)產(chǎn)生誤差,影響時(shí)間的精確性。
綜上,雖然利用硬件定時(shí)會(huì)節(jié)省CPU的時(shí)間,并且,能產(chǎn)生較為“準(zhǔn)確”的定時(shí),但“準(zhǔn)確”是相對(duì)的,誤差會(huì)由于指令的執(zhí)行而產(chǎn)生。為了得到更加精確的定時(shí),這些誤差是不容忽視的。
4 結(jié)束語(yǔ)
定時(shí)器是單片機(jī)里最“活躍”的部件之一,很多單片機(jī)的應(yīng)用系統(tǒng)都是需要應(yīng)用定時(shí)器。本文以STC90C51RC/RD+系列單片機(jī)作為研究對(duì)象,避開(kāi)傳統(tǒng)8051單片機(jī)的弊端,通過(guò)幾個(gè)示例程序,展示了STC90C51RC/RD+系列單片機(jī)定時(shí)器的應(yīng)用。程序并不復(fù)雜,也存在一定誤差,如果想得到非常精確的定時(shí),對(duì)于定時(shí)器的誤差是必須考慮的,尤其是反復(fù)應(yīng)用定時(shí)器的程序中,更要詳盡考慮誤差的產(chǎn)生原因及指令,必要時(shí)要做出修正。
參考文獻(xiàn):
[1] 王暄.單片機(jī)定時(shí)器的應(yīng)用與誤差糾正[J].電子元器件應(yīng)用,2002,(5):15.
[2] 沈威羽.單片機(jī)定時(shí)器的應(yīng)用與誤差糾正[J].經(jīng)營(yíng)管理者,2009,(1):20.
作者簡(jiǎn)介:朱旭光(1980-),男,碩士,講師,研究方向:計(jì)算機(jī)網(wǎng)絡(luò)技術(shù),微機(jī)控制等。