AT89C51数字电子钟
扫描二维码
随时随地手机看文章
该数字钟可实现精度误差≤1S/天的变精度时钟,并能方便地调节时钟、时间、定时时间等.
LED1bitp1.0 ;LED定义
led2bitp1.1
led3bitp1.2
led4bitp1.3
led5bitp1.4
led6bitp1.5
led7bitp1.6
led8bitp1.7
s1bitp0.0 ;数码管位数定义
s2bitp0.1
s3bitp0.2
s4bitp0.3
s5bitp0.4
s6bitp0.5
s7bitp0.6
s8bitp0.7
led_dataequp2 ;数码管定义
key1bitp3.5 ;按键定义
key2bitp3.6
key3bitp3.7
keyequ56h
time_hequ57h ;定时初值高位
time_lequ58h ;低位
t_hequ60h ;时分秒对应的地址
t_sequ61h
t_mequ62h
timeequ63h ;时钟计数单元
timer_hequ64h ;定时时单元
timer_mequ65h ;定时分单元
timsetbit00h ;设置时间标志
disstartequ70h ;显示单元首地址
int_dataequ45h ;中断数据地址
count_dataequ44h ;计数单元地址
timer_dataequ43h ;定时地址
;**************以上为预定义部分
;**************以下程序开始
org00h ;程序开始地址
jmpmain ;跳转到代码开始处
org1bh ;定时器T1中断服务程序入口
jmptim1
org030h ;主程序开始的地址30H
main: MOV sp,#30h ;首先定义堆栈
lcallrest ;初始化
lcallpro_set ;设置定时器开始工作
lpp:lcalltime_set ;接受用户设置时间
lcalltimer ;时钟处理
lcalltime_pro ;时间格式处理,码型变化等
lcalltime_display ;显示
jmplpp
;*************初始化程序***************************
rest: MOV a,#00h ;累加器清零
MOV b,#00h
MOV p0,#0 ;数码管禁止显示
MOV t_h,#0 ;时单元
MOV t_m,#0 ;分单元
MOV t_s,#0 ;秒单元
MOV time,#00h ;计数溢出次数,溢出20次为一秒
clrtimset ;定时设置标志位,0->增加1->减少
MOV timer_h,#12 ;定时器时单元,设置定时为12:00
MOV timer_m,#00h ;定时器分单元
MOV p2,#255 ;禁止显示数码管
clrbeep ;禁止蜂鸣器
ret ;返回
;***************定时器T1中断服务程序****
tim1:clrtr1 ;首先停止定时操作
MOV th1,time_h ;
MOV tl1,time_l
inctime ;自增
MOV a,time ;取得溢出次数
cjnea,#20,retend ;如果满20此表示到1秒
cplp1.0 ;取反p1.0,p1.1指示秒钟
cplp1.1
MOV time,#00h ;重新开始等待1秒
inct_s ;秒单元加1
retend:setbtr1 ;定时开始
reti ;中断返回
;*****************设置定时器初始化,定时时间为50ms****
pro_set: MOV dptr,#0000h ;数据指针清零
MOV tmod,#10h ;设置定时器1工作在方式1
MOV time_h,#3ch ;计算定时50ms需要的初值
MOV th1,time_h ;保存高位
MOV time_l,#0c1h ;低位
MOV tl1,time_l ;保存低位
setbea ;总的中断允许
setbet1 ;定时器1允许
setbtr1 ;定时器1开始运行
ret ;返回
;******************timer程序主要完成数据的处理**********
timer: MOV a,t_s ;取得秒单元数据
cjnea,#60,tend ;秒不到60返回
MOV t_s,#00h ;清除秒单元
inct_m ;为分单元加1
MOV a,t_m ;取得分单元数据
cjnea,#60,tend ;分不等于60返回
MOV t_m,#00h ;分单元清零
setbbeep ;整点短鸣提示
lcalldelay ;鸣叫延时
clrbeep ;停止蜂鸣器
inct_h ;同时为时单元加1
MOV a,t_h ;取得时单元数据
cjnea,#24,timetest ;如果不等于24,查看定时
MOV t_h,#00h ;时单元清零
jmptend ;返回
timetest:cjnea,timer_h,tend ;不等于定时的时单元,返回
MOV a,t_m ;取得定时的分单元
cjnea,timer_m,tend ;当前分不等于定时的分单元,返回
setbbeep ;定时到,蜂鸣提示
lcalldelay
clrbeep
lcalldelay
setbbeep
lcalldelay
clrbeep ;连续发出短音提示
tend:ret ;返回
;************time_display程序主要为显示时间值用*************
time_display: MOV r0,#disstart ;取得显示单元首地址
MOV r1,#01h ;从第一个数码管开始
MOV r2,#06h ;共6个数码管
dislp: MOV led_data,@r0 ;获得当前单元数据
incr0 ;指向下一个单元
MOV p0,r1 ;数码显示
MOV a,r1 ;为下一个数准备
rla ;下一个单元
MOV r1,a ;保存
lcalldelay5ms ;为了保证数码管亮度,
;但要防止闪烁,延时5ms
djnzr2,dislp ;重复显示,直到全部数据刷新过
ret ;返回
;*******time_pro时间处理,主要为bcd码转换,查表***********
time_pro:lcallbcd ;BCD码转换
MOV r0,#disstart ;获得显示单元首地址
MOV r2,#06h ;需要转换的个数
prlp: MOV a,@r0 ;取得当前需要转换的数据
MOV dptr,#tab_nu ;获得表头
MOV ca,@a+dptr ;获得转换后的数据
MOV @r0,a ;存回去
incr0 ;指向下一个
djnzr2,prlp ;重复转换,直到6个全部完成
ret ;返回
;****************码型变换****************************************
bcd: MOV r0,#disstart ;获得首地址
MOV a,t_s ;获得待转化的低位
MOV b,#10 ;转化进制,如果要进行十进制转换改为10
divab ;计算A/B
MOV @r0,b ;第一位转换完毕,保存低位转化后的数据
incr0 ;自增
MOV @r0,a ;保存高位
incr0 ;取第二个数据地址
MOV a,t_m ;获得第二个需要转换的数据
MOV b,#10 ;十六进制
divab ;计算
MOV @r0,b ;存低位
incr0
MOV @r0,a ;存高位
incr0 ;第三位
MOV a,t_h ;获得数据
MOV b,#10 ;十六进制
divab ;计算
MOV @r0,b ;存低位
incr0
MOV @r0,a ;存高位
ret ;完毕,返回
;***************************************************************************************
;********time_set设置时间*******************************************************
;* *
;* 检测用户按键,1->设置时单元2->设置分单元,3->设置增减方式 *
;* 如果需要增加时,先将方式设置为增加(默认为减),即,按下KEY3一下, *
;* 然后按KEY1,如果要减少时单元,需要再次按下KEY3,然后按KEY1; *
;* 分的设置也是如此。 *
;***************************************************************************************
time_set: MOV p0,#00h ;禁止数码管显示
MOV p2,#255 ;防止按键时闪烁
lcallpro_key ;查找用户按键情况
MOV a,key ;查找键值
jztsend ;如果等于0,表示没用按键,直接返回
cjnea,#1,tset1 ;是否等于1?没有到下一个处理程序
MOV key,#00h ;等于1,表示设置时请零,否则会引起重复设置
jbtimset,tset10 ;时间设置标志位,1->减少,0->增加
MOV a,t_h ;标志位0,增加,取得时单元
cjnea,#23,ts1 ;如果时单元不等于23,转移到增加操作
jmptsend ;等于23直接返回
ts1:inct_h ;时单元增加1
jmptsend ;返回
tset10: MOV a,t_h ;这里处理为减少的情况
jztsend ;如果时单元为0,直接返回
dect_h ;否则,数据减1
jmptsend ;返回,以下关于分的设置一样
tset1:cjnea,#2,tset2 ;如果按键不是2则转移到下一个处理
MOV key,#00h ;是2,表示设置分
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表示设置标志
MOV key,#00h ;清零
cpltimset ;标志取反
tsend:ret ;返回
;*********按键处理读取键盘*************************
;参见有关键盘查询的说明,和前面的有关程序
pro_key: ;键盘查询子程序
setbkey1 ;首先输出高电平,检测低电平的到来
setbkey2 ;不同电路,可能检测方式不一样
setbkey3
jbkey1,ke1 ;如果用户没有按第一个键,到第下个处理部分,
MOV key,#1 ;表示用户按了第一个键
lcalldelay20ms ;软件延时,防止干扰
jmppro_key ;重新查询,直到用户释放按键
ke1:jbkey2,ke2 ;处理第二个按键,如果没有到下一个处理部分
MOV key,#2 ;以下和第一个处理单元相似。
lcalldelay20ms
jmppro_key
ke2:jbkey3,ke3
MOV key,#3
lcalldelay20ms
jmppro_key
ke3:ret
;**************************************
;********定时器T0设置**************
;定时器工作在方式1,为提高精度,总定时时间为50ms,
;定时器溢出20次为1秒,
pro_timer: MOV tmod,#01h ;设置定时器为定时方式1
MOV th0,#0ffh ;初始化定时初值
MOV tl0,#0a1h ;
setbea ;总中断允许
setbet0 ;定时器0允许
setbtr0 ;开始定时
ret ;返回
;*****************************************
;***************软件延时*************
delay:pushpsw ;保存原来的寄存器内容
clrpsw.3 ;
clrpsw.4 ;设置新的寄存器组
MOV r0,#2 ;延时参数1
MOV r1,#250 ;延时参数2
MOV r2,#2 ;延时参数3
dl1:djnzr0,dl1 ;延时循环1
MOV r0,#250 ;
dl2:djnzr1,dl1 ;延时循环2
MOV r0,#240 ;
MOV r1,#248 ;
dl3:djnzr2,dl1 ;延时循环3
nop ;定时精度调整
poppsw ;恢复原来的寄存器
ret ;返回
;*****************************************
;***************键盘延时***************
delay20ms:pushpsw
clrpsw.3
clrpsw.4
MOV r0,#250
MOV r1,#40
d20:djnzr0,d20
MOV r0,#250
djnzr1,d20
poppsw
ret
;**************************************
;***********延时5ms****************
delay5ms:pushpsw
clrpsw.3
setbpsw.4
MOV r0,#250
MOV r1,#10
d5:djnzr0,d5
MOV r0,#250
djnzr1,d5
poppsw
ret
;************************************************************************************
;这是数字显示表格,其中带小数点的数字比不带小数点的数字大16
;比如0的显示代码为0;那么0.的显示代码为16;如此类推
tab_nu:db0c0h,0f9h,0a4h,0b0h,99h,92h,82h,0f8h ;数字0-7不带小数点代码
db80h,90h,88h,83h,0c6h,0a1h,86h,8eh ;数字8-f不带小数点代码
db40h,79h,24h,30h,19h,12h,02h,78h ;数字0-7带小数点代码
db00h,10h,08h,03h,46h,21h,06h,0eh ;数字8-f带小数点代码