先上代碼算法
#include <reg52.h> void Init(); void main(){ Init(); } void Init(){ TMOD = 0x01; TH0 = 0x4b; TL0 = 0xfc; //定時器時間50ms,針對11.0592MHz頻率CPU ET0 = 1; EA = 1; TR0 = 1; } void Timer0() interrupt 1 { TH0 = 0x4b; TL0 = 0xfd; //Timer循環體,運行過程放這裏 }
示例代碼就要有示例代碼的樣子,簡簡單單的才能把問題說清楚!函數
先解釋下幾個變量,TMOD,TH0,TL0,ET0,EA,TR0,這些變量不是我定義的,而是<reg52.h>頭文件中的,先掌握用法,再深究原理。學習
TMOD:選擇定時器的模式,不一樣的模式主要是能數到的最大數不一樣,通常就用模式1,最大可數到65535spa
TH0:TL0:設置起始值,TH0 故名思議就是數字轉爲16進制的高8位,TL0爲低八位code
TR0:啓動、中止定時器,1啓動,0中止,這個比較好理解吧blog
EA:容許系統進行中斷,1容許,0禁止,算是個權限之類的東西it
ET0:容許定時器0進行中斷,1容許,0禁止入門
到這裏你確定還會有疑問,我接着給你解釋!class
1.定時器定時時間怎麼算的啊,0x4bfc轉爲10進制並非50啊?變量
——確實不是50,在講定時器時間的算法以前,先得說下這個定時器的原理。
在咱們高級語言習慣中,定時器就是給他設定一個數,他一秒數一下,數到那個值後進行一次定時操做。可是在嵌入式中並非這樣,也是由於這樣錯誤的想法,我不理解了好久。
在嵌入式中,定時器的實現原理是,他從某個數開始數,一直數到上限(如65535),到65536的時候定時器溢出,進行一次操做,而咱們給的0x4bfc是定時器的起始值,也就是說定時器將從這個值開始數,一直數到65535,中間所耗費的時間就是50ms。
2.彷佛明白了,那這個時間具體怎麼算啊?
——恩,這個問題稍有些複雜,回答這個問題以前,仍是要繼續引入幾個概念。
時鐘週期T1:晶振振盪週期,公式 T1 = 1/頻率 ,如11.0592MHz的晶振頻率 T1 = 1/11.0592 us
機器週期T2:機器執行一條基本指令的時間,公式 T2 = 12 * T1 ,如11.0592MHz的機器週期約爲 1.085 us
因此,要定時50ms的計算過程
50ms = 50000us = 50000/1.085 機器週期 = 46083 次
也就是說,要讓計時器數 46083 次就行了,要數到65535,那麼很天然就知道是要從 65535 - 46083 = 19452 數起
19452D = 0x4bfc
因此 TH0 = 0x4b, TL0 = 0xfc
3.我有注意到,TH0 TL0 TR0 ET0 後面都有0,感受挺奇怪的?
——你看的很仔細,沒錯,這個0是有意義的。事實上,單片機裏有兩個定時器,TH0表示第一個定時器,TH1表示第二個,另外幾個以T開頭的都表示定時器變量,也都有T_0和 T_1兩種,E開頭的表示與中斷相關。
4.interrupt 1 裏面的1是什麼意思,能換成其餘數字嗎?
——後面的1是中斷號,Timer0 這個函數名稱你能夠隨便取,可是後面這個數字倒是固定的,由於它是用來講明這個函數是誰的中斷函數,1表示是定時器1來中斷,3表示定時器2中斷。事實上,還有幾個額外的中斷類型,可是做爲入門,就不在這裏列舉了。
5.爲何在中斷函數 Timer0 裏又從新設置了一次 TH0 和 TL0 呢,這是必須的嗎?
——上面有提到過,這個函數裏面的過程是在定時器數到65536溢出後執行的,可是有個問題是溢出完後TH0 和 TL0就會被重置爲0,若是你不從新設定的話它會從0開始數起,因此是必須的,定時器1和定時器2都是這樣的。
定時器簡單的理解到這就差很少了,關於中斷還須要繼續學習,另外幾種中斷方式原理上都是有共通點的!