AT89C51數(shù)字電子鐘
該數(shù)字鐘可實(shí)現(xiàn)精度誤差≤1S/天的變精度時(shí)鐘,并能方便地調(diào)節(jié)時(shí)鐘、時(shí)間、定時(shí)時(shí)間等.
LED1bitp1.0 ;LED定義
led2bitp1.1
led3bitp1.2
led4bitp1.3
led5bitp1.4
led6bitp1.5
led7bitp1.6
led8bitp1.7
s1bitp0.0 ;數(shù)碼管位數(shù)定義
s2bitp0.1
s3bitp0.2
s4bitp0.3
s5bitp0.4
s6bitp0.5
s7bitp0.6
s8bitp0.7
led_dataequp2 ;數(shù)碼管定義
key1bitp3.5 ;按鍵定義
key2bitp3.6
key3bitp3.7
keyequ56h
time_hequ57h ;定時(shí)初值高位
time_lequ58h ;低位
t_hequ60h ;時(shí)分秒對(duì)應(yīng)的地址
t_sequ61h
t_mequ62h
timeequ63h ;時(shí)鐘計(jì)數(shù)單元
timer_hequ64h ;定時(shí)時(shí)單元
timer_mequ65h ;定時(shí)分單元
timsetbit00h ;設(shè)置時(shí)間標(biāo)志
disstartequ70h ;顯示單元首地址
int_dataequ45h ;中斷數(shù)據(jù)地址
count_dataequ44h ;計(jì)數(shù)單元地址
timer_dataequ43h ;定時(shí)地址
;**************以上為預(yù)定義部分
;**************以下程序開始
org00h ;程序開始地址
jmpmain ;跳轉(zhuǎn)到代碼開始處
org1bh ;定時(shí)器T1中斷服務(wù)程序入口
jmptim1
org030h ;主程序開始的地址30H
main: MOV sp,#30h ;首先定義堆棧
lcallrest ;初始化
lcallpro_set ;設(shè)置定時(shí)器開始工作
lpp:lcalltime_set ;接受用戶設(shè)置時(shí)間
lcalltimer ;時(shí)鐘處理
lcalltime_pro ;時(shí)間格式處理,碼型變化等
lcalltime_display ;顯示
jmplpp
;*************初始化程序***************************
rest: MOV a,#00h ;累加器清零
MOV b,#00h
MOV p0,#0 ;數(shù)碼管禁止顯示
MOV t_h,#0 ;時(shí)單元
MOV t_m,#0 ;分單元
MOV t_s,#0 ;秒單元
MOV time,#00h ;計(jì)數(shù)溢出次數(shù),溢出20次為一秒
clrtimset ;定時(shí)設(shè)置標(biāo)志位,0->增加1->減少
MOV timer_h,#12 ;定時(shí)器時(shí)單元,設(shè)置定時(shí)為12:00
MOV timer_m,#00h ;定時(shí)器分單元
MOV p2,#255 ;禁止顯示數(shù)碼管
clrbeep ;禁止蜂鳴器
ret ;返回
;***************定時(shí)器T1中斷服務(wù)程序****
tim1:clrtr1 ;首先停止定時(shí)操作
MOV th1,time_h ;
MOV tl1,time_l
inctime ;自增
MOV a,time ;取得溢出次數(shù)
cjnea,#20,retend ;如果滿20此表示到1秒
cplp1.0 ;取反p1.0,p1.1指示秒鐘
cplp1.1
MOV time,#00h ;重新開始等待1秒
inct_s ;秒單元加1
retend:setbtr1 ;定時(shí)開始
reti ;中斷返回
;*****************設(shè)置定時(shí)器初始化,定時(shí)時(shí)間為50ms****
pro_set: MOV dptr,#0000h ;數(shù)據(jù)指針清零
MOV tmod,#10h ;設(shè)置定時(shí)器1工作在方式1
MOV time_h,#3ch ;計(jì)算定時(shí)50ms需要的初值
MOV th1,time_h ;保存高位
MOV time_l,#0c1h ;低位
MOV tl1,time_l ;保存低位
setbea ;總的中斷允許
setbet1 ;定時(shí)器1允許
setbtr1 ;定時(shí)器1開始運(yùn)行
ret ;返回
;******************timer程序主要完成數(shù)據(jù)的處理**********
timer: MOV a,t_s ;取得秒單元數(shù)據(jù)
cjnea,#60,tend ;秒不到60返回
MOV t_s,#00h ;清除秒單元
inct_m ;為分單元加1
MOV a,t_m ;取得分單元數(shù)據(jù)
cjnea,#60,tend ;分不等于60返回
MOV t_m,#00h ;分單元清零
setbbeep ;整點(diǎn)短鳴提示
lcalldelay ;鳴叫延時(shí)
clrbeep ;停止蜂鳴器
inct_h ;同時(shí)為時(shí)單元加1
MOV a,t_h ;取得時(shí)單元數(shù)據(jù)
cjnea,#24,timetest ;如果不等于24,查看定時(shí)
MOV t_h,#00h ;時(shí)單元清零
jmptend ;返回
timetest:cjnea,timer_h,tend ;不等于定時(shí)的時(shí)單元,返回
MOV a,t_m ;取得定時(shí)的分單元
cjnea,timer_m,tend ;當(dāng)前分不等于定時(shí)的分單元,返回
setbbeep ;定時(shí)到,蜂鳴提示
lcalldelay
clrbeep
lcalldelay
setbbeep
lcalldelay
clrbeep ;連續(xù)發(fā)出短音提示
tend:ret ;返回
;************time_display程序主要為顯示時(shí)間值用*************
time_display: MOV r0,#disstart ;取得顯示單元首地址
MOV r1,#01h ;從第一個(gè)數(shù)碼管開始
MOV r2,#06h ;共6個(gè)數(shù)碼管
dislp: MOV led_data,@r0 ;獲得當(dāng)前單元數(shù)據(jù)
incr0 ;指向下一個(gè)單元
MOV p0,r1 ;數(shù)碼顯示
MOV a,r1 ;為下一個(gè)數(shù)準(zhǔn)備
rla ;下一個(gè)單元
MOV r1,a ;保存
lcalldelay5ms ;為了保證數(shù)碼管亮度,
;但要防止閃爍,延時(shí)5ms
djnzr2,dislp ;重復(fù)顯示,直到全部數(shù)據(jù)刷新過(guò)
ret ;返回
;*******time_pro時(shí)間處理,主要為bcd碼轉(zhuǎn)換,查表***********
time_pro:lcallbcd ;BCD碼轉(zhuǎn)換
MOV r0,#disstart ;獲得顯示單元首地址
MOV r2,#06h ;需要轉(zhuǎn)換的個(gè)數(shù)
prlp: MOV a,@r0 ;取得當(dāng)前需要轉(zhuǎn)換的數(shù)據(jù)
MOV dptr,#tab_nu ;獲得表頭
MOV ca,@a+dptr ;獲得轉(zhuǎn)換后的數(shù)據(jù)
MOV @r0,a ;存回去
incr0 ;指向下一個(gè)
djnzr2,prlp ;重復(fù)轉(zhuǎn)換,直到6個(gè)全部完成
ret ;返回
;****************碼型變換****************************************
bcd: MOV r0,#disstart ;獲得首地址
MOV a,t_s ;獲得待轉(zhuǎn)化的低位
MOV b,#10 ;轉(zhuǎn)化進(jìn)制,如果要進(jìn)行十進(jìn)制轉(zhuǎn)換改為10
divab ;計(jì)算A/B
MOV @r0,b ;第一位轉(zhuǎn)換完畢,保存低位轉(zhuǎn)化后的數(shù)據(jù)
incr0 ;自增
MOV @r0,a ;保存高位
incr0 ;取第二個(gè)數(shù)據(jù)地址
MOV a,t_m ;獲得第二個(gè)需要轉(zhuǎn)換的數(shù)據(jù)
MOV b,#10 ;十六進(jìn)制
divab ;計(jì)算
MOV @r0,b ;存低位
incr0
MOV @r0,a ;存高位
incr0 ;第三位
MOV a,t_h ;獲得數(shù)據(jù)
MOV b,#10 ;十六進(jìn)制
divab ;計(jì)算
MOV @r0,b ;存低位
incr0
MOV @r0,a ;存高位
ret ;完畢,返回
;***************************************************************************************
;********time_set設(shè)置時(shí)間*******************************************************
;* *
;* 檢測(cè)用戶按鍵,1->設(shè)置時(shí)單元2->設(shè)置分單元,3->設(shè)置增減方式 *
;* 如果需要增加時(shí),先將方式設(shè)置為增加(默認(rèn)為減),即,按下KEY3一下, *
;* 然后按KEY1,如果要減少時(shí)單元,需要再次按下KEY3,然后按KEY1; *
;* 分的設(shè)置也是如此?! ?
;***************************************************************************************
time_set: MOV p0,#00h ;禁止數(shù)碼管顯示
MOV p2,#255 ;防止按鍵時(shí)閃爍
lcallpro_key ;查找用戶按鍵情況
MOV a,key ;查找鍵值
jztsend ;如果等于0,表示沒(méi)用按鍵,直接返回
cjnea,#1,tset1 ;是否等于1?沒(méi)有到下一個(gè)處理程序
MOV key,#00h ;等于1,表示設(shè)置時(shí)請(qǐng)零,否則會(huì)引起重復(fù)設(shè)置
jbtimset,tset10 ;時(shí)間設(shè)置標(biāo)志位,1->減少,0->增加
MOV a,t_h ;標(biāo)志位0,增加,取得時(shí)單元
cjnea,#23,ts1 ;如果時(shí)單元不等于23,轉(zhuǎn)移到增加操作
jmptsend ;等于23直接返回
ts1:inct_h ;時(shí)單元增加1
jmptsend ;返回
tset10: MOV a,t_h ;這里處理為減少的情況
jztsend ;如果時(shí)單元為0,直接返回
dect_h ;否則,數(shù)據(jù)減1
jmptsend ;返回,以下關(guān)于分的設(shè)置一樣
tset1:cjnea,#2,tset2 ;如果按鍵不是2則轉(zhuǎn)移到下一個(gè)處理
MOV key,#00h ;是2,表示設(shè)置分
jbtimset,tset20 ;其余同上
MOV a,t_m
cjnea,#59,
ts2jmptsend
ts2:inct_m
jmptsend
tset20: MOV a,t_m
jztsend
dect_m
jmptsend
tset2:cjnea,#3,tsend ;等于3表示設(shè)置標(biāo)志
MOV key,#00h ;清零
cpltimset ;標(biāo)志取反
tsend:ret ;返回
;*********按鍵處理讀取鍵盤*************************
;參見有關(guān)鍵盤查詢的說(shuō)明,和前面的有關(guān)程序
pro_key: ;鍵盤查詢子程序
setbkey1 ;首先輸出高電平,檢測(cè)低電平的到來(lái)
setbkey2 ;不同電路,可能檢測(cè)方式不一樣
setbkey3
jbkey1,ke1 ;如果用戶沒(méi)有按第一個(gè)鍵,到第下個(gè)處理部分,
MOV key,#1 ;表示用戶按了第一個(gè)鍵
lcalldelay20ms ;軟件延時(shí),防止干擾
jmppro_key ;重新查詢,直到用戶釋放按鍵
ke1:jbkey2,ke2 ;處理第二個(gè)按鍵,如果沒(méi)有到下一個(gè)處理部分
MOV key,#2 ;以下和第一個(gè)處理單元相似。
lcalldelay20ms
jmppro_key
ke2:jbkey3,ke3
MOV key,#3
lcalldelay20ms
jmppro_key
ke3:ret
;**************************************
;********定時(shí)器T0設(shè)置**************
;定時(shí)器工作在方式1,為提高精度,總定時(shí)時(shí)間為50ms,
;定時(shí)器溢出20次為1秒,
pro_timer: MOV tmod,#01h ;設(shè)置定時(shí)器為定時(shí)方式1
MOV th0,#0ffh ;初始化定時(shí)初值
MOV tl0,#0a1h ;
setbea ;總中斷允許
setbet0 ;定時(shí)器0允許
setbtr0 ;開始定時(shí)
ret ;返回
;*****************************************
;***************軟件延時(shí)*************
delay:pushpsw ;保存原來(lái)的寄存器內(nèi)容
clrpsw.3 ;
clrpsw.4 ;設(shè)置新的寄存器組
MOV r0,#2 ;延時(shí)參數(shù)1
MOV r1,#250 ;延時(shí)參數(shù)2
MOV r2,#2 ;延時(shí)參數(shù)3
dl1:djnzr0,dl1 ;延時(shí)循環(huán)1
MOV r0,#250 ;
dl2:djnzr1,dl1 ;延時(shí)循環(huán)2
MOV r0,#240 ;
MOV r1,#248 ;
dl3:djnzr2,dl1 ;延時(shí)循環(huán)3
nop ;定時(shí)精度調(diào)整
poppsw ;恢復(fù)原來(lái)的寄存器
ret ;返回
;*****************************************
;***************鍵盤延時(shí)***************
delay20ms:pushpsw
clrpsw.3
clrpsw.4
MOV r0,#250
MOV r1,#40
d20:djnzr0,d20
MOV r0,#250
djnzr1,d20
poppsw
ret
;**************************************
;***********延時(shí)5ms****************
delay5ms:pushpsw
clrpsw.3
setbpsw.4
MOV r0,#250
MOV r1,#10
d5:djnzr0,d5
MOV r0,#250
djnzr1,d5
poppsw
ret
;************************************************************************************
;這是數(shù)字顯示表格,其中帶小數(shù)點(diǎn)的數(shù)字比不帶小數(shù)點(diǎn)的數(shù)字大16
;比如0的顯示代碼為0;那么0.的顯示代碼為16;如此類推
tab_nu:db0c0h,0f9h,0a4h,0b0h,99h,92h,82h,0f8h ;數(shù)字0-7不帶小數(shù)點(diǎn)代碼
db80h,90h,88h,83h,0c6h,0a1h,86h,8eh ;數(shù)字8-f不帶小數(shù)點(diǎn)代碼
db40h,79h,24h,30h,19h,12h,02h,78h ;數(shù)字0-7帶小數(shù)點(diǎn)代碼
db00h,10h,08h,03h,46h,21h,06h,0eh ;數(shù)字8-f帶小數(shù)點(diǎn)代碼