51單片機之寄存器-3.1單片機定時器
講定時器之前我們來看看如何操作鬧鐘,這個生活中的小例子,相信大家都很熟悉。首先我們要設(shè)定定時時間,定時多久呢?我們通過調(diào)節(jié)如圖中紅色區(qū)域指針來告訴鬧鐘定時多久。然后開啟鬧鐘,怎么樣開啟呢?如上圖中藍色部分,按下按鈕讓鬧鐘知道現(xiàn)在要開啟定時的功能了。很簡單的兩個動作,鬧鐘設(shè)置就完成了。之后就是鬧鐘自己的事情了。你就可以去干別的事情了,比如看電影,睡覺,喝茶等等。那么定時的時間到了怎么樣告訴你呢?大家都知道,通過響鈴來告訴你時間到了。懂得了鬧鐘的過程,那么類比一下就很容易明白單片機定時器。前面講過,單片機是人設(shè)計的產(chǎn)品,自然反映人的思維過程。只不過在單片機中,它把日常用的詞匯專業(yè)化了,功能復(fù)雜了一點。現(xiàn)在我們來按照鬧鐘的思維講述單片機定時器。
本文引用地址:http://m.butianyuan.cn/article/201611/319546.htm首先我們看看如何開啟定時器,在鬧鐘中我們使用手來按下按鈕,這樣鬧鐘定時就開啟了。在單片機中只有0和1,那么很容易想到采用0和1控制定時的開關(guān),并給它取個名字(TR0). 如何理解這個名字了,T表示timer, R表示run,0表示定時器,合起來就表示定時器0運行控制,這樣很容易就記住了定時器的開關(guān)控制。那么下一個問題,定時多長時間。講這個問題之前我們先來看看鬧鐘如何計時的。秒鐘每走一格就是1s,走10格我們就知道走了10s,也就是說我們可以通過查看格子的數(shù)目來知道時間的量。在單片機中如何計時呢?如上圖,有兩個寄存器TH0和TL0,很容易想到,可以用TH0和TL0中存放的數(shù)據(jù)來知道時間。鬧鐘中每一個格子是1秒鐘,那么在TH0和TL0中每放一個數(shù)是多少時間呢。定時器計時是通過晶振來完成的。這里我們使用的晶振大小為11.0592M,表示一秒鐘時間內(nèi),晶振運行11.0592次,那么運行一次的時間為[1/(11.0592M)]S, TH0和TL0中每計數(shù)一次需要晶振運行12次(至于為什么,后面我們會講到),因此需要的時間為12×[1/(11.0592M)]S. 為了方便計算我們把它換成微秒單位: (12/11.0592)Us. 可見時間長度是通過TH0和TL0來完成的。那么能不能只用一個TL0來計數(shù)呢?當(dāng)然可以。因此這里就涉及到了計時模式的問題,TH0+TL0構(gòu)成16bit的計時器,或者只使用TL0或者使用TH0(8bit)和TL0低5位。那么我用TH0高4位和TL0低7位可不可以?不可以,我們不去追問為什么,單片機工程師設(shè)計的,我們要做的就是了解它的規(guī)則。既然工作模式有這么多,那么單片機怎么知道要使用哪種工作模式。很明顯需要有個寄存器來告訴單片機這個信息,這個寄存器叫TMOD. 如上圖所示的M0和M1,很容易知道2個位就能產(chǎn)生4種組合情況(00/01/10/11),這樣分別對應(yīng)與定時器的4種工作模式。最后一個問題,到點響鈴。鬧鐘定時到了會發(fā)出響鈴來通知你,那么在單片機中到點了會通知CPU,怎么通知呢,如上圖所示中的TF0(F-full表示滿了,也就是溢出), TH0/TL0滿了TF0就會由0變1,然后通過硬件通知CPU時間到了。這樣就完成了整個定時過程。從以上分析可以看出,定時器的操作過程與鬧鐘非常相似,只不過單片機的定時器在計數(shù)方面復(fù)雜了一點,多了幾種工作模式?,F(xiàn)在相信大家已經(jīng)大概了解單片機定時器了。
?現(xiàn)在我們根據(jù)所講的內(nèi)容,舉一個簡單例子,通過定時器0來控制LED亮一秒滅一秒。按照上面過程,我們一步一步來分析
(1) 確定定時多長時間
前面講了定時時間是通過TH0和TL0來控制的,那么使用TH0和TL0之前先要設(shè)定工作模式,用16bit還是8bit或者其他。這里我們選擇16bit。怎么選呢?表1中給出了定時器0和1工作模式的控制寄存器,8個位的初始化值都是0,綠色部分用來控制定時器1,黃色部分用來控制定時器0,現(xiàn)在我們只看黃色部分。一共4個控制位,Gate,C/T,M1,M0. 很容易看到,Gate,C/T都要設(shè)置0,現(xiàn)在要選中16bit的工作模式,那么M1M0=01. 因此TMOD=00000001=0X01 假設(shè)在圖2中,TL0,TH0初始值為0,那么16bit最多可以裝下65535,考慮到溢出,因此這里取65536,每裝一個數(shù)需要(12/11.0592)Us,那么裝65536需要,UnitT=65536×(12/11.0592)約等于71000Us,也就是71ms. 現(xiàn)在我要定時1s,很明顯,TH0和TL0不夠用,那是不是要多增加幾個TH0和TL0,沒有必要。我們可以通過軟件來解決硬件上的不足,最簡單的方式就是使用循環(huán)多次。比如我讓UnitT為10ms,那么循環(huán)100次就是1秒了。那么怎么設(shè)置UnitT=10000Us, UnitT=(65536-X) × (12/11.0592)=10000Us, 其中X為TH0和TL0組成的16bit的初始值。將這個等式改進一下:
UnitT=(65536-X) / 0.9216, 在該式中UnitT×0.9216要小于65536,并且要保證UnitT×0.9216為正整數(shù),因此UnitT的取值范圍為:
10000
因此簡單來看,UnitT可以取10ms, 20ms, 30ms, 40ms, 50ms, 60ms, 70ms,
再根據(jù)我們最終要定時的時間為1000ms, 因此UnitT只能取10ms, 20ms, 50ms,這樣根據(jù)UnitT=(65536-X) / 0.9216就能計算出初始值X,
這里我們?nèi)nitT=50ms, X=19456,16進制表示為: 4C00H, 因此TH0= 0X4C, THL0=0X00.
因此這樣我們就確定了定時時間用的初始值,TH0和TL0,并且需要重復(fù)20次
(2) 啟動定時器
如何啟動定時器,查看表2定時器控制寄存器TCON,只要設(shè)置TR0=1即可。表2中涉及到中斷的問題我們暫時不管,這里我們只討論定時器,下一講談中斷。這里為什么能直接設(shè)置TR0,為什么在設(shè)置定時器工作模式時不能直接設(shè)置M1M0,而要通過TMOD來設(shè)置。這個涉及到尋址方式的問題,我們暫時不討論。
(3) 響鈴?fù)ㄖ?/p>
那么鬧鐘響鈴對應(yīng)定時器的哪個部分。前面我們設(shè)置了TH0和TL0,初始值為19456,然后不停的增大直到65535,再增大一個變成65536此時TH0和TL0裝不下了,因此溢出,此時單片機通過硬件將TF0從0變?yōu)?來通知CPU,查看表2中TF0的說明可知。因此TF0的值對應(yīng)著響鈴。
(4) 點亮LED
我們要讓LED延時1s后點亮或者熄滅,因此這里需要一個參數(shù)來對定時器TF0的溢出次數(shù)計數(shù),當(dāng)溢出20次時,表示定時到了1s。
這樣我們很容易的得出程序的框架圖,
參考代碼如下:
#include "reg52.h"
sbit LED=P1^0;
void main(void)
{
unsigned char CYC = 0;
TMOD=0X01;
TH0=0X4C;
TL0=0X00;
TR0=1;
while(1)
{
if (TF0==1)
{
TF0=0;
TH0=0X4C;
TL0=0X00;
CYC++;
if(CYC==20)
{
CYC=0;
if(LED==0)
{
P1=0XFF ;
LED=1;
}
else
{
LED=0;
P1=0X00;
}
}
}
}
}
評論