單片機學習之十四:定時器應(yīng)用(模式1)
開機后程序作如下的燈光變換:第一次led0、led2亮;第二次led1、led3亮;第三次led4、led6亮;第四次led5、led7亮;第五次led0、led2、led4、led6亮;第六次led1、led3、led5、led7亮;第七次8個二極管全亮;第八次8個二極管全滅。然后重頭開始循環(huán)。每次狀態(tài)轉(zhuǎn)換間隔時間是50ms。
二、實驗?zāi)康?/p>
掌握內(nèi)部定時/計數(shù)器的作定時功能(模式1)的應(yīng)用
三、實驗任務(wù)分析:
看到這個實驗題目,大家可能會說,這個試驗難度不大,我們只要把這幾種燈光對應(yīng)的輸出存到一個表里面,然后查表就可以啦,燈光轉(zhuǎn)換之間調(diào)用50ms的延時程序即可。 這樣的思路當然可以,但是,如果這樣作,我們就沒有必要寫這個試驗啦。今天,我們要老瓶裝新酒,看看這個50ms的定時時間除了用延時程序完成,還有沒有別的方法。以前的定時,我們常常采用延時程序來完成。其實這種方法不是很完美,由于程序的指令中還包含其他的判斷指令,所以延時程序作定時不是非常精確。由于日常的電子系統(tǒng)常常需要定時和計數(shù)的功能,所以MCS-51單片機內(nèi)部就自帶了兩個16位的寄存器,用來作定時/計數(shù)器,我們給它們起了名字,T0、T1。(我們的AT89S52里面有3個定時器,一般的程序兩個就夠啦,我們先介紹這兩個吧。)
現(xiàn)在就來學習這兩個定時/計數(shù)器的用法。這個試驗的實質(zhì),就是利用自帶的定時/計數(shù)器來產(chǎn)生50ms的定時。
先來看看這兩個定時/計數(shù)器的結(jié)構(gòu)吧,如下圖所示。
1、定時器的結(jié)構(gòu):
從圖上可以看出,定時/計數(shù)器的核心是一個加1計數(shù)器(注:16位,計數(shù)范圍從0000h~ffffh),根據(jù)K0開關(guān)的不同方向,這個計數(shù)器可以對兩個脈沖來源計數(shù),一個是系統(tǒng)的時鐘振蕩器,另外一個是外部的脈沖源。
2、定時器的工作方式
當計數(shù)器對系統(tǒng)時鐘脈沖計數(shù)的時候,由于系統(tǒng)時鐘是一個時間基準,所以脈沖數(shù)×脈沖周期就是一段固定時間,因此工作于定時方式;當計數(shù)器對外部的脈沖進行計數(shù)的時候(也就是對TX端計數(shù),TX端我們用到的時候再解釋吧),就可用于對外部事件計數(shù),工作于計數(shù)方式。我們這個試驗要產(chǎn)生50ms的定時,用的是定時功能,在后面的試驗里我們還要作計數(shù)功能的試驗。
我們發(fā)現(xiàn),當k0向上打的時候,工作于定時方式,向下打的時候工作于計數(shù)方式。那么k0又是由什么控制的呢?
K0是一位模擬開關(guān),方向受 這一位的控制,當 =0時,K0向上,工作于定時方式;當 =1時,K0向下,工作于計數(shù)方式。(注:數(shù)電教材的《AD轉(zhuǎn)換》一章有模擬開關(guān)的原理,大家可以查閱),
那么, 又是什么呢,它是特殊功能寄存器tmod中的一位。tmod是用來控制定時/計數(shù)器的工作方式的,是一個8位的寄存器,它的各位情況如下圖所示:
(注:tmod是我們又新接觸的一個特殊功能寄存器,和別的特殊功能寄存器一樣,在內(nèi)部RAM的特殊功能寄存器區(qū)。)
看到了吧, 是tmod寄存器的D2和D6位,所以,如果我們想讓T0工作于定時方式,就應(yīng)該把D2置0;如果要讓T0工作于計數(shù)方式,就應(yīng)該把D2置1。對T1的控制也是一樣的。
注意,在這里我要特別說明一點,我們不能用setb指令給tmod的某一位置1,也不能用clr指令給某一位置0。為什么呢?記得我們以前對ie寄存器可以這樣作:setb ea(開中斷),clr ea(關(guān)中斷),那么tmod寄存器為什么不行呢?
這是因為tmod寄存器是不能夠“位尋址”的,也就是說,我們不能單獨的對其中一位進行操作,而必須對整個寄存器進行賦值。而以前我們學過的ie、psw、tcon、acc這幾個特殊功能寄存器卻是可以“位尋址”的。具體的哪些寄存器可以位尋址,而哪些寄存器不行,大家可以參照相關(guān)教材,有很詳細的說明。
再看一下k1,它也是一個模擬開關(guān),當與門輸出是1的時候,開關(guān)閉合,啟動計數(shù)器;當與門輸出是0的時候,開關(guān)打開,計數(shù)器停止。至于它如何控制我們稍后介紹。
3、定時時間的計算
好啦,知道了怎樣選擇定時還是計數(shù)方式,我們就要考慮一下定時時間的計算了。要計算定時時間,我們就要知道計數(shù)器的輸入脈沖周期是多少。實際上,計數(shù)器是對機器周期計數(shù)的,而我們也知道,1個機器周期=12×振蕩周期,所以,計數(shù)器的輸入脈沖周期是:12×(1/12MHZ)=1us。
可見,要產(chǎn)生50ms的定時,只要計數(shù)器記50000個脈沖就可以啦。那么,怎樣讓計數(shù)器在記入了50000個脈沖后,向單片機發(fā)出一個消息,表示定時時間到呢?這就要用到我們以前學習過的概念-中斷啦。我們以前說過,單片機有5個中斷源,兩個是外部中斷 和 ,兩個是T0和T1的溢出中斷,還有一個是串行口中斷。我們以前用過外部中斷 ,這個試驗我們要用到T0的溢出中斷。
16位的計數(shù)器從0開始,記入216=65536個脈沖的時候,會向外面產(chǎn)生溢出,這個溢出把TFX置一,(注:TF0是T0的溢出中斷標志,TF1是T1的溢出中斷標志),從而向CPU申請中斷,在進入中斷處理程序后,由硬件對TFX清0,不需要我們操作。(注:順便說一下TF0和TF1,它是我們以前接觸過的tcon特殊功能寄存器中的兩位,tcon是一個可以“位尋址”的特殊功能寄存器,我們在試驗七中用這個寄存器設(shè)置過外部中斷的觸發(fā)方式,想不起來的話,回頭看看前面的實驗吧。)
4、計數(shù)初值的計算
繼續(xù)剛才的問題,16位的計數(shù)器要記入65536個脈沖才會產(chǎn)生溢出中斷,那么怎樣讓它在記入50000個脈沖后產(chǎn)生中斷呢?這就要用到我們在數(shù)電中間學習過的內(nèi)容啦。我們可以給計數(shù)器置一個初值65536-50000=15536,這樣計數(shù)器在記入50000個脈沖之后就會產(chǎn)生溢出中斷了。
那么,怎樣給計數(shù)器置初值呢?T0和T1是兩個16位的計數(shù)器,我們可以把它們分為高8位THX和低8位TLX。Cpu和T0、T1之間的關(guān)系如下圖所示(注:其中,P3.4和P3.5用作第二功能,是工作于計數(shù)方式的時候,外部的計數(shù)脈沖輸入,也就是定時/計數(shù)器結(jié)構(gòu)圖10-1中的TX端。)
我們以T0為例,要給它置入初值15536,就要對高8位的TH0和低8位的TL0分別置數(shù)。15536變換成16進制的數(shù)是3CB0(注:轉(zhuǎn)換方法可以查閱數(shù)電教材《進制轉(zhuǎn)換》一章),所以我們就這樣給T0置初值:mov th0,#3ch ;mov tl0,#0b0h,就可以啦。
5、計數(shù)器的啟動和停止
在給T0置入初值之后,并且在允許T0溢出中斷(注:由IE寄存器中的ET0控制,詳細說明可見試驗7),和cpu開啟中斷的前提下,我們就要啟動T0開始定時了。我們前面說過T0的啟動和停止是由圖10-1中與門的輸出決定的。當與門輸出是1的時候,T0啟動;當與門輸出是0的時候,T0停止。
那么什么時候與門輸出是1呢?從圖上可知有兩種情況。
(1)、當gate=0時,只需要tr0=1,即可啟動T0計數(shù)
(2)、當gate=1,并且tr0=1的時候,還需要int0=1才能啟動T0計數(shù)
在該試驗中,我們用到第一種情況,也就是我們把gate賦值0,然后通過對tr0的置1和置0來啟動和停止計數(shù)器。這是一種常用的方式,至于第二種方式,我們以后通過試驗給大家分析它們之間的不同。
Gate在哪里呢?大家再看看上面給出的tmod寄存器圖,就是d3和d7位。所以我們在對T0初始化的時候,要給d3賦值0。至于d4~d7都和T0沒有關(guān)系,可以是任何狀態(tài)。
再說說tr0的問題,它也是tcon寄存器中的一位,它的各位功能如下圖所示,我們把用到的作個簡單介紹。
1、TF0:T0的溢出中斷,當T0溢出的時候由硬件置位,在進入中斷服務(wù)程序后,由硬件清0,不用我們操作;TF1類似。(注:如果我們采用查詢方式,通過查詢TFx的狀態(tài)判斷是否到達定時,而不進入中斷服務(wù)程序,那就要對這1位用軟件清0啦!可不要忘啦?。?br /> TR0:當gate=0時,置一啟動T0計數(shù),置0停止T0計數(shù);TR1類似
好啦,現(xiàn)在基本上分析清楚了,我們來看看主程序和中斷服務(wù)程序的流程圖吧。
四、程序流程圖:
五、實驗程序
(注意:在作這個試驗的時候,不要忘了把JMP0跳線置于1、2的位置,選擇二極管顯示單元)
org 0000h
ajmp main
org 000bh ;T0溢出中斷入口地址
ajmp time0
org 0020h
main: clr p1.5
mov r1,#0ffh
mov sp,#70h ;設(shè)置堆棧
mov tmod,#01h ;T0初始化,工作于定時方式,詳細解釋見注釋
mov th0,#3ch ;T0置計數(shù)初值
mov tl0,#0b0h
setb et0 ;允許T0溢出中斷
setb ea ;cpu開中斷
setb tr0 ;啟動T0計數(shù)
ajmp $ ;等待
time0:inc r1 ;查表求燈光,輸出到p0口,詳細解釋見多位數(shù)碼顯示試驗
mov a,r1
mov dptr,#tab
movc a,@a+dptr
mov p0,a
cjne a,#0ffh,next
mov r1,#0ffh
next: mov th0,#3ch ;由于計數(shù)器已經(jīng)溢出,所以需要重設(shè)計數(shù)初值
mov tl0,#0b0h
reti
tab: db 0fah,
db 0aah,55h,00h,0ffh
end
六、幾點說明
我們來看看T0初始化的語句mov tmod,#01h,現(xiàn)在我們把tmod的各位功能詳細說明一下。
(1) d2是定時/計數(shù)方式選擇,這里應(yīng)該把d2置0,選擇T0工作于定時方式
(2)d3也應(yīng)該置0,這樣通過控制tr0即可啟動T0
(3)d1d0(M
M
M
M
M
(2) 在這個試驗中,由于定時50ms需要16位的計數(shù)器,故d1d0=01
從上面的分析可見,我們給tmod可以賦值:XXXX0001,可以是01h,也可以是
現(xiàn)在把這個程序下載到學習板上,看看效果吧。我們發(fā)現(xiàn),燈光變換的速度太快啦,幾乎沒有辦法看清楚,原因很簡單,因為50ms的定時太短了。16位的計數(shù)器定時最多能夠達到65.536ms,那么如果我們需要更長時間的定時,比如仍然是剛才的試驗,但是時間要求是1s,該怎么辦呢?
其實也很簡單,我們設(shè)一個計數(shù)器,初值是0,每次T0溢出中斷的時候,給這個計數(shù)器加一。在主程序里,我們反復檢測這個計數(shù)器的值,達到20的時候調(diào)用燈光子程序就可以啦。
下面就是這個定時1s的程序,其中,我們用r2作這個計數(shù)器。
org 0000h
ajmp main
org 000bh ;T0溢出中斷入口地址·
ajmp time0
org 0020h
main: clr p1.5
mov r1,#0ffh
mov r2,#00h ;給計數(shù)器r2賦初值0
mov sp,#70h ;設(shè)置堆棧
mov tmod,#01h ;設(shè)置T0工作方式
mov th0,#3ch ;T0置計數(shù)初值
mov tl0,#0b0h
setb et0 ;允許T0溢出中斷
setb ea ;cpu開中斷
setb tr0 ;啟動T0開始計數(shù)
wait: cjne r2,#20,wait ;定時時間未到,繼續(xù)查詢等待
acall light ;定時時間到,調(diào)用查表求燈光子程序
ajmp wait
;以下是查表求燈光子程序
light: mov r2,#00h ;計數(shù)器重新賦初值
inc r1 ;查表求燈光,詳細解釋見試驗5“多位數(shù)碼顯示”
mov a,r1
mov dptr,#tab
movc a,@a+dptr
mov p0,a
cjne a,#0ffh,next
mov r1,#0ffh
next: ret ;子程序返回
;以下是中斷服務(wù)程序
time0: inc r2 ;計數(shù)器加1
mov th0,#3ch ;重置計數(shù)初值
mov tl0,#0b0h
reti ;中斷返回
tab: db 0fah,
db 0aah,55h,00h,0ffh
end
好啦,把這個程序下載到學習板上,就會很清楚的看到燈光的變換方式啦。
在這個試驗里面,由于我們的定時時間較長,所以采用了16位的計數(shù)器,假如定時時間短的話,定時/計數(shù)器還可以采用別的工作方式,例如13位,或者8位等。
評論