使用單片機時,編程會高頻率用到延時,如led燈閃爍,蜂鳴器長短鳴,秒表應用等等。首先考慮軟件延時,但這個時間不精確,占用硬件資源。使用延時函數是,其他函數不能運行。這個方案cut掉。硬件延時,嗯,誤差非常小。但成本較高,且參數調節不便。這個也不行。選擇采用定時器調節時間,不占用cpu時間,能與CPU并行工作,實現精確的定時和計數。又可以通過編程設置其他工作方式和其他參數,因此使用非常方便。下面介紹定時器的使用。
概述
定時器系統是單片機內部一個獨立的硬件部分,它與cpu和晶振通過內部某些控制線連接并相互作用,cpu一旦設置開啟定時功能后,定時器便在晶振的作用下自動計時,但定時器的計數器計滿后,會產生中斷。計數時間一次為12/晶振頻率。在晶振頻率為11.0595mhz時,計數一次時間約等于1.09us。
89c52單片機定時器系統有三個定時器/計數器,分別是定時器T0,定時器T1,T2定時器。他們既有定時器功能,也有計數器功能。T0,T1有四種工作方式,T2有三種工作模式。
內部結構
定時器結構
由上圖可知,定時器系統有兩個寄存器組成,分別是TCON,TMOD。還可看出tcon控制外部中斷,tmod控制定時器工作方式。tmod寄存器分為兩部分,高四位為t1定時器控制位,低四位為t0定時器控制位。t0定時器與th0,tl0兩個8位計數器有關,。t1定時器與th1,tl1兩個8位計數器有關。上圖信息就這么多,接下來看看兩個寄存器相關數據。
寄存器TCON
寄存器TCON
TF1:定時器 1 溢出標志。當定時器/計數器 1 溢出時,由 硬件置位;當主機響應中斷,
轉向中斷服務程序時,由硬件清零。
TR1:定時器 1 運行控制位, 由軟件置位/ 復位來開啟或關閉定時器/計數器 1。
TF0:定時器 0 溢出標志。當定時器/計數器 0 溢出時,由 硬件置位;當主機響應中斷,
轉向中斷服務程序時,由硬件清零。
TR0:定時器 0 運行控制位,由 軟件置位/ 復位來開啟或關閉定時器/計數器 0。
IE1:外部中斷 1 跳變中斷請求標志,當檢測到 INT1 發生 1 到 0 的跳變時,由硬件置位;當主機響應中斷, 轉向中斷服務程序時,由硬件清零。
IT1:外部中斷 1 觸發方式控制位,由 軟件置位或清零來選擇外部中斷 1 的跳變/電平觸發中斷請求。IT1=0 時,外部中斷 1 為電平觸發方式,當 INT1 輸入低電平時,置位 IE1。
采用電平觸發方式時,外部中斷源必須保持低電平有效,直到該中斷被 CPU 響應,同時在該中斷服務程序執行完之前,外部中斷源必須被清除,否則將產生另一次中斷。IT1=1 時,外部中斷 1 為邊沿觸發方式,在對 INT1 的相鄰兩次采樣中,如果一個周期中為高電平,接下來的周期為低電平,則置位 IE1,表示外部中斷 1 正在向 CPU 申請中斷。直到該中斷被CPU 響應時,才被 硬件清零。
IE0:外部中斷 0 跳變中斷請求標志,當檢測到 INT1 發生 1 到 0 的跳變時,由硬件置位;當主機響應中斷, 轉向中斷服務程序時,由硬件清零。
IT0:外部中斷 0 觸發方式控制位,應用同 IT1。
這個寄存器與中斷有關,支持位尋址,就是可以對其每一位進行單獨操作。定時器工作就是在一個特定的間隔(與晶振有關)加1,等到加到定時器溢滿時,會觸發外部中斷。這兩個定時器都是16位可編程定時器/計數器。最大可裝2的16次方。,就是65535.,定時器在晶振為11.0592MHZ時,間隔約等于1.09us。
(關于中斷的知識在上一篇文章有詳細介紹,在這里就不累贅。)
寄存器TMOD
寄存器TMOD
GATE:門控制位,當 GATEx=1 時,控制寄存器 TCON 的 TRx=1(x=0 或 1)。當 GATEx=0 時,定時器啟動與停止僅受寄存器中的TRx來控制(x=0 或 1)。
C / :定時器、計數器方式選擇位,該位為 1 時為計數器,為 0 時為定時器。
M0:定時器/計數器工作模式選擇位。
M1:定時器/計數器工作模式選擇位。
注:高四位是T1定時器控制位,低四位是T0定時器控制位
工作方式如下圖所示
4種工作方式
這個寄存器是控制定時器的工作方式與哪個定時器工作。tmod寄存器支持位尋址,編程時只可以是總線式,不可以單個控制。因為兩個定時器命名一樣,單個控制會弄混。下面示范寫法:
TMOD=0X01; // 0000 0001?
可以看出只有最低位為1,即T0定時器的M0=1;對照上圖數據可知,這是使用T0定時器的定時功能中的工作方式1,就是16位定時器。
TMOD=0X20; //0010 0000
這個看數據手冊得知是T1定時器的定時功能中的工作方式2,即具有自動重載的8位定時器。
附:定時器使用需要用到中斷,這里將中斷的中斷源優先級放在下面。
中斷源優先級
定時器使用
中斷函數
在介紹定時器使用時,先介紹中斷函數,C51的中斷格式如下
void 函數名()iinterrupt 工作組
{
中斷內容;
}
中斷函數不能返回值,所以前綴為void,函數名可以任意取,但一般建議使用有意義的名字,到時候檢查也可以明白是什么函數,interrupt是c語言中的一個關鍵字--中斷,記住就行。工作組就是對應中斷源,比如說,使用T1定時器,那中斷源就是定時器1中斷,這時工作組就是3。下面示范:
void timer_t1() interrupt 3
{
TH1=(0XE0);
TL1=(0X07);
}
上面這個實例很容易理解,對著手冊看就知道是T1定時器中斷。
定時器初值計算
中斷函數明白后,如何定時還是不清楚。開啟定時器后,定時器就會開始計數,每次加1的間隔是固定的,而且到達最大值就會溢出,觸發中斷。這樣子的話我們可以設定一個初值,初值到最大值的時間假設為50ms,那樣的話定是的效果就達到了。定時器加1時間間隔約等于1.09us,定時器在沒有賦值時默認初值為0,最大值為65535,計算可得655351.09us約等于72ms,沒有賦初值一次定時最大為72ms。可以設置一個初值,就拿50ms來說,501000/1.09約等于45872,也就是說經過45872次計數時間為50ms,那初值就是65535-45872=19663。
大概了解定時器,來看看如何使用,定時器是由16位可編程寄存器組成,分為高8位,即THX(X=1或X=0)低8位TLX(X=1或X=0)。為了更好定時,肯定會選擇賦初值。這里介紹一種簡單的方法,不用計算。既然它們分為兩部分,可以利用這一特點。舉個例子:
選擇10ms時間,T1定時器。這里以晶振為12MHZ為準,因為11.0592MHZ計算麻煩,這樣計數一次就是1us;
TH1=(65535-10000)/256;//表示初值為55535,/256表示高8位的初值,很好理解,低 8位最多存2的8次方=256個數,每滿一次高8位加1, /256表示高8位加了多少次。
TL1=(65535-10000)%256;// %256表示不滿256最后留下的數。
使用步驟
計算知道后,來看看定時器使用步驟:
對TMOD賦值,確定T0和T1的工作方式
計算初值,賦值TH0,TL0或TH1,TH1
對IE賦值,啟動中斷
TR0或TR1置位,啟動定時器
處理中斷函數,定時器中斷后變成默認值0,要重新賦初值
例程
#inlclude???//頭文件
sbit?led=P1^1;???//位定義
mian()??//主函數
{
????unsigned?char?count;??定義計數次數變量
????TMOD=0X01;???//設置定時器T0?定時器功能?工作模式1
????TH0=(65536-50000)/256;?????//賦初值???50ms
????TL0=(65536-50000)%256;
????EA=1;???//打開總中斷
????ET0=1;??//開定時器0中斷
????TR0=1;??//啟動定時器?
}
void?timer_t0()?intterrupt?1
{
????TH0=(65536-50000)/256;????//重新賦值
????TL0=(65536-50000)%256;
????count++;?????//每中斷一次加1
????if(count==20)??//count==20時,說明1秒到
????{
????????count=0;??//count清零,重新等待1秒的到來
????????led=~led;???//led狀態取反
????}
}
上面注釋已經很清楚,按照步驟來,一步一步設置參數,基本不會出錯。在中斷函數中設置一個標志位,中斷變化,變化成何值時,再狀態變化。基本就是這個套路。給個建議,中斷函數不要寫太多東西,不然會出錯。試想一下,假如進入中斷需5ms,但在中斷函數中命令要運行10ms,命令沒有運行完,又進入中斷,就會出錯。
總結
定時器就這樣子,不會很難,一些命令在數據手冊都有,忘記了就重新看一下,寫多了就會記住·,重要的是記住步驟,記住編程思想,在寫之前在腦中想一下步驟,或在紙上把思路畫一下,那里不通就會躍然于紙上,再稍加思索一般就行了。
評論
查看更多