|
作者 舒新生
相信有很多愛好單片機(jī)的朋友都用單片機(jī)制作過(guò)電子鐘,這的確是一個(gè)很好的鍛煉課題?墒钱(dāng)在你享受成功的快樂(lè)或是在朋友面前炫耀的時(shí)候,你會(huì)突然間發(fā)現(xiàn)你當(dāng)初對(duì)著電視校準(zhǔn)的電子鐘的時(shí)間竟然變快或是變慢了。于是你就嘗試用各種方法來(lái)調(diào)整它的走時(shí)精度,但是最終的效果還是不盡人意,只好每過(guò)一段時(shí)間手動(dòng)調(diào)整一次了。漸漸的你有點(diǎn)煩了,不再去管它或是直接棄之不用。
我和大家一樣對(duì)此深有體會(huì),于是我開始查找翻閱資料,試圖找出一個(gè)解決的好方法。終于有一天……
廢話太多——stop
原因分析:
1.單片機(jī)電子鐘的計(jì)時(shí)脈沖基準(zhǔn)是由外部晶振的頻率經(jīng)過(guò)12分頻后提供,采用內(nèi)部的定時(shí)/計(jì)數(shù)器來(lái)實(shí)現(xiàn)計(jì)時(shí)功能。所以,外接晶振頻率精確度直接影響電子鐘計(jì)時(shí)的準(zhǔn)確性。
2. 單片機(jī)電子鐘利用內(nèi)部定時(shí)/計(jì)數(shù)器溢出產(chǎn)生中斷(12M晶振一般為50ms)再乘以相應(yīng)的倍率來(lái)實(shí)現(xiàn)秒、分、時(shí)的轉(zhuǎn)換。大家都知道從定時(shí)/計(jì)數(shù)器產(chǎn)生中斷請(qǐng)求到響應(yīng)中斷需要3-8個(gè)機(jī)器周期(如不明白請(qǐng)參考其它資料),定時(shí)中斷子程序中的數(shù)據(jù)入棧和重裝定時(shí)/計(jì)數(shù)器的初值還需要占用數(shù)個(gè)機(jī)器周期,還有從中斷入口轉(zhuǎn)到中斷子程序也要占用一定的機(jī)器周期。 例如:
ORG 00H
LJMP START
ORG 0BH
LJMP TIMER ;2個(gè)機(jī)器周期
ORG 30H
START:
MOV 30H, #0
MOV 31H, #0
MOV 32H, #0
MOV 33H, #0
MOV 20H, #10
MOV 21H, #2
MOV SP, #40H
MOV IP, #00H
MOV IE, #82H ;開EA﹑ET0
MOV TMOD, #01H ;定時(shí)器模式1
MOV TH0, #03CH ;50MS初裝值
MOV TL0, #0B0H
SETB TR0 ;啟動(dòng)TR0
LOOP:
……
TIMER: ;定時(shí)器中斷子程序
PUSH ACC ;2個(gè)機(jī)器周期
PUSH PSW ;2個(gè)機(jī)器周期
MOV TL0, #0B0H+6+3
MOV TH0, #03CH
……
RETI
END
從上面的例子大家可以看出從中斷入口到定時(shí)/計(jì)數(shù)器初值的低8位裝入需要占用2+2+2=6個(gè)機(jī)器周期。所以我們?cè)诰幊虝r(shí)一般會(huì)把這8個(gè)機(jī)器周期加入定時(shí)/計(jì)數(shù)器的初值。但是從定時(shí)/計(jì)數(shù)器溢出中斷請(qǐng)求到執(zhí)行中斷需要幾個(gè)機(jī)器周期(3-8個(gè)機(jī)器周期)我們很難確定其準(zhǔn)確值,因此導(dǎo)致了電子鐘計(jì)時(shí)不準(zhǔn)。
解決方法:
1.采用高精度晶振方案
雖然采用高精度的晶振可以稍微提高電子鐘計(jì)時(shí)的精確度,但是其并不是導(dǎo)致電子鐘計(jì)時(shí)不準(zhǔn)的主要因素,而且高精度的晶振價(jià)格較高,所以不必采用此方案。
2.動(dòng)態(tài)同步修正方案
從程序入手,采用動(dòng)態(tài)同步修正方法給定時(shí)/計(jì)數(shù)器賦初值。動(dòng)態(tài)同步修正方法:由于定時(shí)/計(jì)數(shù)器溢出后又會(huì)從0開始自動(dòng)加數(shù),固在給定時(shí)/計(jì)數(shù)器再次賦值前將定時(shí)/計(jì)數(shù)器低位(TL0)中的值和初始值相加后一并送入定時(shí)/計(jì)數(shù)器中,此時(shí)定時(shí)/計(jì)數(shù)器中的值即為動(dòng)態(tài)同步修正后的準(zhǔn)確值。例如:
TIMER:
PUSH ACC
PUSH PSW
MOV A, #0B0H
ADD A, TL0 ;初值和TL0中的數(shù)相加即為同步修正值
MOV TL0, A ;修正值送定時(shí)/計(jì)數(shù)器低8位
MOV TH0, #03CH
……
RETI
采用了此種方法后相信你的電子鐘的精度已經(jīng)大大提高了。別走開,后面內(nèi)容更精彩。
3.自動(dòng)調(diào)整方案
采用了同步修正方案后電子鐘的精度雖然提高了很多,但是由于晶振頻率的偏差和一些其它未知因素(同一塊電路板、同樣的程序換了一片單片機(jī)后走時(shí)誤差卻不一樣,不知是何原因)的影響,時(shí)間長(zhǎng)了仍然會(huì)有積累誤差。為此我設(shè)計(jì)出了此自動(dòng)調(diào)整方案,實(shí)際也是一種容錯(cuò)技術(shù)。其自動(dòng)調(diào)整原理為:實(shí)測(cè)出誤差1秒所需的時(shí)間,然后每隔這樣一段時(shí)間后就對(duì)秒進(jìn)行加1或減一調(diào)整。例如:電子鐘每過(guò)50小時(shí)就慢1秒,其自動(dòng)調(diào)整程序如下:
TIMER: ;定時(shí)中斷程序
PUSH ACC ;數(shù)據(jù)保護(hù)
PUSH PSW
……
T_3:
INC A_1
MOV A, A_1
CJNE A, #50, RETI_1 ;到50小時(shí)了嗎?
INC S_1 ;到50小時(shí)秒加1
MOV A_1, #OOH
RETI_1:
POP PSW
POP ACC
RETI
使用此方法調(diào)整較費(fèi)時(shí)間,但是效果非常好,經(jīng)實(shí)驗(yàn)一次調(diào)整可以將月誤差控制在1秒左右,如按此方法再次測(cè)出誤差1秒所需的天數(shù)并進(jìn)行二次調(diào)整,其精度會(huì)更高。
電子鐘源程序:(修改后)修改前的源程序可以到論壇<單片機(jī)技術(shù)交流>里看我發(fā)的<簡(jiǎn)單的電子鐘源程序>一文
S_1 EQU 30H ;秒寄存器
M_1 EQU 31H ;分寄存器
H_1 EQU 32H ;時(shí)寄存器
A_1 EQU 33H ;自動(dòng)調(diào)整寄存器
ORG 00H
LJMP START
ORG 03H
RETI
ORG 0BH ;定時(shí)中斷入口
LJMP TIMER
ORG 13H
RETI
ORG 1BH
RETI
ORG 30H
START:
MOV S_1, #0 ;秒、分、時(shí)寄存器清0
MOV M_1, #0
MOV H_1, #0
MOV A_1, #0
MOV 20H, #10 ;0.5秒鐘中斷次數(shù),0.5s=500ms=50msx10
MOV 21H, #2 ;2個(gè)0.5秒即為1秒
MOV SP, #40H ;堆棧指針設(shè)置
MOV IE, #82H ;開定時(shí)器0中斷及總中斷
MOV TMOD, #01H ;定時(shí)器0模式1
MOV TH0, #03CH ;50ms初值
MOV TL0, #0B0H
SETB TR0 ;啟動(dòng)定時(shí)器0
LOOP:
ACALL DISP ;調(diào)用顯示
JNB P3.4, MT ;查詢分調(diào)整鍵
JNB P3.5, HT ;查詢時(shí)調(diào)整鍵
AJMP LOOP
MT: ;分調(diào)整
ACALL DISP
JNB P3.4, MT ;鍵消抖
INC M_1 ;分加1
MOV A, M_1
CJNE A, #60, LOOP ;沒(méi)到60分返回,到60分清0
MOV M_1, #0
AJMP LOOP
HT: ;時(shí)調(diào)整
ACALL DISP
JNB P3.5, HT
INC H_1
MOV A, H_1
CJNE A, #24, LOOP
MOV H_1, #0
AJMP LOOP
DISP: ;顯示子程序
MOV DPTR, #NUMTAB ;表地址送數(shù)據(jù)指針
MOV A, M_1 ;分送A
MOV B, #10
DIV AB ;十進(jìn)制調(diào)整
ADD A, R0 ;查表偏移量調(diào)整
MOVC A, @A+DPTR ;查表
MOV P1, A ;分十位送p1口顯示
CLR P3.2 ;開分十位顯示
ACALL D1MS ;延時(shí)1ms
SETB P3.2 ;關(guān)顯示
MOV A, B ;分個(gè)位p1口顯示
ADD A, R0
MOVC A, @A+DPTR
MOV P1, A
CLR P3.3
ACALL D1MS
SETB P3.3
MOV A, H_1 ;時(shí)送A
MOV B, #10
DIV AB
ADD A, R0
MOVC A, @A+DPTR
MOV P1, A
CLR P3.0 ;顯示時(shí)十位
ACALL D1MS
SETB P3.0
MOV A, B
ADD A, R0
MOVC A, @A+DPTR
MOV P1, A
CLR P3.1 ;顯示時(shí)個(gè)位
ACALL D1MS
SETB P3.1
RET ;返回
TIMER: ;定時(shí)中斷程序
PUSH ACC ;數(shù)據(jù)保護(hù)
PUSH PSW
MOV A, #0B0H ;同步修正
ADD A, TL0
MOV TL0, A ;重置50ms定時(shí)值
MOV TH0, #03CH
DJNZ 20H, RETI_1 ;到0.5秒了嗎?
MOV 20H, #10
CPL 25H.0 ;取反秒點(diǎn)閃爍標(biāo)志位
JNB 25H.0, T_1 ;標(biāo)志位為0轉(zhuǎn)T_1
MOV R0, #0 ;查表偏移量寄存器置0(不顯示秒點(diǎn))
AJMP T_2
T_1:
MOV R0, #10 ;查表偏移量寄存器置10(顯示秒點(diǎn),秒點(diǎn)每秒閃爍1次)
T_2:
DJNZ 21H, RETI_1 ;到1秒了嗎?
MOV 21H, #2
INC S_1 ;秒加1
MOV A, S_1
CJNE A, #60, RETI_1 ;到60秒了嗎?
MOV S_1, #0 ;到60秒清0
INC M_1 ;分加1
MOV A, M_1
CJNE A, #60, RETI_1 ;到60分了嗎?
MOV M_1, #0
INC H_1 ;時(shí)加1
MOV A, H_1
CJNE A, #24, T_3 ;到24小時(shí)了嗎?
MOV H_1, #00H
T_3: ;自動(dòng)調(diào)整
INC A_1
MOV A, A_1
CJNE A, #50, RETI_1
INC S_1
MOV A_1, #OOH
RETI_1:
POP PSW
POP ACC
RETI
D1MS: ;1毫秒延時(shí)
MOV R7, #2
D_1:
MOV R6, #250
DJNZ R6, $
DJNZ R7, D_1
RET
NUMTAB:
DB 10H,0D3H,48H,41H,83H,21H,20H,53H,00H,01H;不顯示秒點(diǎn)
DB 14H,0D7H,4CH,45H,87H,25H,24H,57H,04H,05H;顯示秒點(diǎn)
END
由于本人接觸單片機(jī)的時(shí)間不長(zhǎng),文章中難免有錯(cuò)誤之處,還請(qǐng)大家多指教。如有其他問(wèn)題可以在論壇上討論。本文可以自由傳播,但請(qǐng)注明作者及出處。
|