定時器是生活中常見的一種定時裝置,常見的定時器有機械定時器和電子定時器
使用的時候我們給他設(shè)置時間,當(dāng)我們指定的時間到了以后定時器會給我們提醒
其實,每天都跟我們打交道的單片機里面也有一個簡單的定時器,他一直站在單片機的角落,為機器精確的定時默默的奉獻出自己的一份力量
(1)單片機的心臟與機器周期
總所周知,單片機的心臟——晶振是一顆很重要的原件,晶振負(fù)責(zé)給單片機提供穩(wěn)定的周期頻率,保證單片機的穩(wěn)定運行
晶振是一顆能產(chǎn)生穩(wěn)定脈沖頻率的電子期間,通電的時候,晶振每一秒發(fā)出脈沖頻率的次數(shù)分之一成為晶振頻率
晶振頻率 = 1秒/1秒內(nèi)晶振發(fā)出脈沖的次數(shù)
我們把晶振頻率記作f,晶振周期記作T
晶振周期T= 1/晶振頻率
在單片機里面,單片機完成一次操作所用的時間叫做機器時間。這里不得不說明,在匯編里面,單片機的機器時間是12個晶振周期,但是在C語言里面,這個周期是不固定的,這也就是為什么用空循環(huán)來延遲,得不到精確的時間
void delay(unsigned int xms) //調(diào)用時需提供參數(shù)xms的實際值。
{
unsigned int i,j; //定義無符號整型變量i、j
for(i=0; i< xms; i++) //后面沒帶";",下一條語句是循環(huán)體。參數(shù)xms延時x毫秒。
for(j=0; j< 110; j++); //后面帶";",表示這個for語句的循環(huán)體是空語句。
}//這個值得學(xué)習(xí),這里的代碼是延遲代碼
//復(fù)制請注明原作者 謝謝
//復(fù)制請注明原作者 謝謝
這也就是為什么我們不太建議用這個延遲精確時間的緣由
因為C51在匯編狀態(tài)的機器周期是12,所以可以認(rèn)為單片機的機器周期值就是12
本小節(jié)講到這里就結(jié)束啦,這一節(jié)大家就要記住
·單片機的機器周期值是12,機器頻率 = 12f(晶振周期)
·f(晶振頻率) = 1/晶振1秒脈沖次數(shù)
·T(晶振周期)=1/f
(2)認(rèn)識定時器的結(jié)構(gòu)
單片機里面的定時器結(jié)構(gòu)圖示如下(這個是我自己畫的,有點丑)
如圖所示,C51定時器原理如圖,定時器里面有一個寄存器,單片機每經(jīng)過一次機器周期就會自動給這個寄存器+1,一直加,直到寄存器滿溢出,溢出后寄存器自動恢復(fù)0,并且給出一個信號告訴我們寄存器滿了.這就是定時器一次定時的工作流程
(3)定時器結(jié)構(gòu)
C51中,一共有兩組定時器,記作T0,T1定時器不僅能定時,還可以當(dāng)計數(shù)器使用。我們本節(jié)主要討論定時器。
定時器由三個寄存器組成
- 計數(shù)寄存器
C51里面的定時器有兩組(TH0,TL0)(TH0,TL1),每組由高八位和低八位組成的十六位寄存器
TH1,TL1屬于定時器1,TH0,TL0屬于定時器0
這里有個特別重要的概念!!,定時器的溢出
定時器的溢出不是滿了就算溢出,而是,滿了再加一才算溢出,拿T0舉例,現(xiàn)在T0的寄存器的數(shù)值是0xFFFF(65535,1111 1111 1111 1111),這時候再加一,才會溢出(也就是65535+1 = 65536才溢出),這就意味著我們計算的時候,溢出值要用65536來計算
為了方便使用定時器,我們需要給定時器的寄存器設(shè)置初始值,下面先介紹如何計算定時器初始值
假設(shè)單片機使用11.0592MHz的晶振,那么……
機器的頻率f = 1/11059200
前面我們知道,定時器會在每一次機器周期自動+1,也就是說定時器每加一一次的時間是機器周期t ,t = 12/晶振周期T
定時器計數(shù)計到65536才算溢出
假設(shè)延遲S(注意單位是秒),1000毫秒 = 1秒
計算的時候要使用Hz作為頻率單位,1MHz = 1 000 000Hz
假設(shè)定時器計數(shù)N次,溢出
那么步長N = (晶振頻率f * 要延遲的秒數(shù)S)/ 12(機器周期)
初始值X = 65536 - 步長N
/*
小練筆,假設(shè)晶振頻率是11.0592MHz
單片機周期是12
現(xiàn)在要延遲20ms
計算步長和初始值
20ms = 0.02s
步長N = 11059200 * 0.02/12 = 18432
初始值X=65536-N = 47104
*/
細(xì)心的朋友可能發(fā)現(xiàn)了,如果從0開始計時,C51定時器定時的時長最大值是0.07111
那我要如何延遲超過71ms的時間呢,這里有個方法:重復(fù),讓定時器重復(fù)延遲多次,達到我們想要的時間,不過這就算是后話了,后面實例的時候再說吧
2.TCON寄存器
TCON寄存器在機器里的地址:0x88,可位尋址,復(fù)位值(單片機復(fù)位的時候寄存器的值) = 0x00(0000 0000)
在定時器里面,TCON寄存器主要有兩個作用,開關(guān)定時器,復(fù)位和檢測定時器是否溢出
TF :
檢測定時器是否溢出,沒有溢出的時候是0,溢出的時候是1。
當(dāng)定時器溢出的時候要我們手動給TF寄存器寫0復(fù)位
TR:定時器開關(guān),寫0的時候關(guān)閉定時器自動計數(shù)定時,寫1的時候啟用定時器計數(shù)定時。
TF1,TR1屬于定時器1,TF0,TR0屬于定時器0
注意這個寄存器是可位尋址的(可以直接訪問寄存器中的某個地址),舉個栗子哈,如果我們要哦將TR1寫0,我們不用操作整個寄存器,只需要
TR1 = 0;
即可
以下是TCON寄存器在定時器下的使用方法合集(這些關(guān)鍵字在reg52.h里面已經(jīng)被定義,使用的時候像下面一樣用直接用)
TR0 = 0;//關(guān)閉Timer0
TR0 = 1;//打開Timer0
TR1 = 0;//關(guān)閉Timer1
TR1 = 1;//打開Timer1
//----------------------------------------
if (TF0 == 1){TF0 = 0;}//判斷Timer0是否溢出,如果溢出,重置溢出判斷位
if(TF1 ==1){TF1 = 0;}//判斷Timer1是否溢出,如果溢出,重置溢出判斷位
//特別提醒,溢出后一定要記得重置TF
特別提醒,溢出一定要記得重置TF位
3.TMOD寄存器
TMOD寄存器在機器里的地址:0x89,不可位尋址,復(fù)位值(單片機復(fù)位的時候寄存器的值) = 0x00(0000 0000)
TMOD寄存器設(shè)置寄存器的模式,我們先來看看TMOD寄存器的結(jié)構(gòu)
高位對應(yīng)Timer1,低位對應(yīng)Timer0
名稱 | 功能 |
---|---|
GATE | 置1的時候為門控位,正常使用定時器置0 |
C/T | 切換定時,計數(shù)器。置1使用計數(shù)器,置0使用定時器 |
M1 | 定時器模式設(shè)置,請看下表 |
M0 |
我們發(fā)現(xiàn),定時器有兩組模式設(shè)置位,這兩組模式設(shè)置為能組合出4種模式
M1 | M0 | 模式功能 |
---|---|---|
0 | 0 | 兼容8048單片機13位定時/計數(shù)器 |
0 | 1 | 16位定時/計數(shù)器 |
1 | 0 | 把一個定時器的寄存器拆開成兩個八位,第一個八位滿了就把這個值給到另一個8位,繼續(xù)計時 |
1 | 1 | 禁用Timer1,這時候Timer0相當(dāng)于兩個8位Timer |
最常用的是M1 = 0,M0 = 1的16位定時器
總結(jié),TMOD定時器的設(shè)置方法:設(shè)置一個16位定時器
功能 | 設(shè)置值 | 說明 |
---|---|---|
GATE | 0 | 不使用門控位 |
C/T | 0 | 設(shè)置值位0的時候使用定時器 |
M1 | 0 | 使用16位定時器 |
M0 | 1 |
這里必須要說明,TMOD寄存器是不可位尋址的,我們不能直接訪問這個寄存器里面的某一個地址。這就是說我們不能用GATE1 = 0;之類的方法來設(shè)置TMOD寄存器,修改的時候一次性修改整個TMOD寄存器
//按照上面的式設(shè)置寄存器
TMOD = 0x01;//TMOD寄存器修改值位0x01---》 0000 0001 16位定時器,Timer0 模式1
TMOD = 0x10;//TMOD寄存器修改值位0x01---》 0001 0000 16位定時器,Timer1 模式1
這樣就完成了最基本的16位定時器設(shè)置
定時器結(jié)構(gòu)
這里大家做個簡單的了解就行
我們可以看到,OSC是晶振,/d得到機器周期,這就是給寄存器+1的信號
這個信號經(jīng)過C/T(定時/計數(shù)器選擇)當(dāng)C/T = 0的時候選擇定時器,當(dāng)C/T = 1的時候選擇計數(shù)器
GATE是一個門控位置,GATE的信號經(jīng)過一個非門取反,也就是說GATE = 0的時候非門的一端輸出1,GATE = 0的時候非門的一端輸出0GATE配合Intr(這是一個外部中斷輸入口,沒有信號的時候置0),這個電路后面經(jīng)過一個或門,只要有一路或者兩路為高電平就輸出高電平,兩路都輸出低電平的時候輸出低電平
TR是使用定時/計數(shù)器的總開關(guān),這里有個與門,只有兩路都輸入高電平的時候才會輸出高電平,輸出高電平的時候控制后面的開關(guān),把信號輸入到計數(shù)器的寄存器
當(dāng)計數(shù)器的寄存器溢出的時候就出發(fā)TF,TF = 1;
到了這,就不難理解這些寄存器怎么設(shè)置了
首先,我們把GATE設(shè)置成0,因為我們用不上Intr外部中斷輸入,Intr = 0,GATE設(shè)置成0以后機器經(jīng)過或門的時候輸出1。
或門輸出1的時候,我們置TR = 1,這樣與門輸出1,信號就能通到計數(shù)寄存器上了
這時置C/T = 0,讓脈沖源來自機器周期的脈沖信號
修改M0=1,M1=0。使用16位寄存器
一個標(biāo)準(zhǔn)16位定時器設(shè)置值
GATE | C/T | M0 | M1 | TF | TR | TH | TL |
---|---|---|---|---|---|---|---|
0 | 0 | 1 | 0 | 0 | 1 | 根據(jù)需要設(shè)置值 |
以下是定時器操作的全部代碼,我們以Timer0為例子
#include< reg52.h >
void main()
{//注意設(shè)置定時器初始值要在main函數(shù)里面設(shè)置
TMOD = 0x01;
/*設(shè)置定時器模式寄存器TMOD為 0000 0001
GATE = 0
C/T = 0
M1 =0
M0 = 1
標(biāo)準(zhǔn)16位定時器
*/
//先設(shè)置定時器初始值
TL0 = 0x3A;//設(shè)置定時器初始值低位
TH0 = 0x8E;//設(shè)置定時器初始值高位
TR0 = 0;//記得一定要設(shè)置定時器開啟
while(1)
{
if (TF0 == 1)
{//這里可以先放下你的定時器計時滿了以后要執(zhí)行的代碼
//溢出后你需要先給你的定時器再次設(shè)置初始值
TL0 = 0x3A;//設(shè)置定時器初始值低位
TH0 = 0x8E;//設(shè)置定時器初始值高位
TF0 = 0;//設(shè)置好初始值后再復(fù)位定時器
}
}
}
以上就是最基本的操作方法咯,前面我們說過,如果只使用定時器,單片機最長延遲71ms,如果需要延遲更長的時間,可以利用單片機重復(fù)延遲
使用11.0592MHz的晶振,在這里,我們計算出延遲1ms的初始值是921.6
這里,如果初始值設(shè)置為921,時間會略微段短一點,設(shè)置為922,又會略微長一點,這就是為什么我們要精確定時的時候,使用11.0592MHz的晶振會不準(zhǔn),使用12MHz的晶振是不錯的解決辦法,可惜使用了12MHz的晶振,又無法進行正常的串口通訊(這個后面再提吧)
這里我取的數(shù)值是922,因為偏差比921小
以下是延遲函數(shù)delay()的參考代碼
#include< reg52.h >
void main()
{//注意設(shè)置定時器初始值要在main函數(shù)里面設(shè)置
TMOD = 0x01;
/*設(shè)置定時器模式寄存器TMOD為 0000 0001
GATE = 0
C/T = 0
M1 =0
M0 = 1
標(biāo)準(zhǔn)16位定時器
*/
TL0 = 0x03;//設(shè)置定時器初始值低位
TH0 = 0x9A;//設(shè)置定時器初始值高位
void delay(unsigned int Ms)//延遲函數(shù),輸入的單位是毫秒
{
unsigned int counter = 0;
TR0 =1;//啟用定時器
for(counter = 0;counter< Ms;counter++)
{
while(TF0 !=0){}//循環(huán)一直進行,直到TF0不再是0
TL0 = 0x03;//設(shè)置定時器初始值低位
TH0 = 0x9A;//設(shè)置定時器初始值高位
TF0 = 0;//復(fù)位溢出位,復(fù)位之前一定要先設(shè)置好初始值
}
TR0 = 0;//關(guān)閉定時器
}
while(1)
{
delay(1);//測試定時器
delay(10);
delay(100);
delay(1000);
}
}
這個參考代碼不算特別完整,僅供多次定時器延遲達到一個長于71ms的一種方法
-
單片機
+關(guān)注
關(guān)注
6043文章
44623瀏覽量
638834 -
寄存器
+關(guān)注
關(guān)注
31文章
5368瀏覽量
121241 -
晶振
+關(guān)注
關(guān)注
34文章
2902瀏覽量
68347 -
定時器
+關(guān)注
關(guān)注
23文章
3256瀏覽量
115423 -
C51單片機
+關(guān)注
關(guān)注
12文章
164瀏覽量
34856
發(fā)布評論請先 登錄
相關(guān)推薦
52單片機有幾個定時器?52單片機定時器1和52單片機定時器2程序?qū)Ρ?/a>
C51單片機定時器Timer的使用及產(chǎn)生1ms系統(tǒng)Tick的詳細(xì)資料說明
![<b class='flag-5'>C51</b><b class='flag-5'>單片機</b><b class='flag-5'>定時器</b>Timer的使用及產(chǎn)生1ms系統(tǒng)Tick的詳細(xì)資料說明](https://file.elecfans.com/web1/M00/9B/93/pIYBAF0kSZiATQpfAARTYcKYLdo705.png)
使用STC單片機實現(xiàn)PCA定時器的C51配套例程免費下載
C51單片機與C52單片機內(nèi)部的資源區(qū)別
![<b class='flag-5'>C51</b><b class='flag-5'>單片機</b>與<b class='flag-5'>C</b>52<b class='flag-5'>單片機</b>內(nèi)部的資源區(qū)別](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論