dot_l equ 30h ;30单元存储百分之一秒值
dot_h equ 31h ;31单元存储十分之一秒值
sec_l equ 32h ;32单元存储秒个位值
sec_h equ 33h ;33单元存储秒十位值
min_l equ 34h ;34单元存储分个位值
min_h equ 35h ;35单元存储分十位值
hou_l equ 36h ;36单元存储时个位值
hou_h equ 37h ;37单元存储时十位值
dot equ 38h ;38单元为百分之一秒计数器(0.00s-0.99s)
sec equ 39h ;39单元为秒计数器(00s-59s)
min equ 40h ;40单元为分计数器(00m-59m)
hou equ 41h ;41单元为时计数器(00h-00h)
dis_b equ 42h ;dis_b(42单元)作为位码选通数码管
dis_r equ 43h ;dis_r(43单元)为取段码时的偏移量
key_t equ 44h ;44单元为键按下的次数标记
K bit p1.4 ;K键与P1.4相连
org 0000h
ajmp start
org 000bh ;定时器0的中断入口地址
ajmp time0 ;跳到定时器0的中断服务程序处
org 001bh ;定时器1的中断入口地址
ajmp time1 ;跳到定时器1的中断服务程序处
org 0030h
start:
mov p2,#0xff ;关所有数码管
mov p1,#0xff ;p1为准双向口,作输入时先写1
mov dis_b,#0x7f ;初始选通P2.7口数码管
mov dis_r,#0 ;初始化偏移量为0
mov dot,#0 ;百分之一秒计数器清零
mov sec,#0 ;秒计数清零
mov min,#0 ;分计数清零
mov hou,#0 ;时计数清零
mov key_t,#0 ;键按下次数清零
mov tmod,#00010001b ;定时/计数器0、1工作于方式1
mov th0,#0xd8 ;预置定时常数55536(d8f0),产生10ms时基信号
mov tl0,#0xf0
mov th1,#0xfc ;预置定时常数64536(fc18),产生1ms间隔用于动态显示
mov tl1,#0x18
setb ea ;开总中断
setb et0 ;定时/计数器0允许中断
setb et1 ;定时/计数器1允许中断
clr tr0 ;关定时/计数器0
setb tr1 ;开定时/计数器1
lop: jb K,lop ;键(P1.4)未按下则返回
lcall d_10ms ;延时10ms消抖
jb K,lop ;是抖动则返回重新扫描
jnb K,$ ;等待键松开
lcall key_to ;调用键处理部分
ajmp lop ;循环显示
key_to: ;键处理子程序
inc key_t ;键按下次数加1
mov a,key_t ;按下次数送入a
cjne a,#1,key_2 ;不是1次继续检测是否是第2次
setb tr0 ;第1次按下启动定时器0
ret
key_2: cjne a,#2,key_3 ;也不是2次继续检测是否是第3次
clr tr0 ;第2次按下关闭定时器0
ret
key_3: cjne a,#3,back ;也不为3则结束
mov dot,#0 ;第3次按下将四个计数器清零
mov sec,#0
mov min,#0
mov hou,#0
mov key_t,#0 ;按键次数清零
back: ret
;--------------------------------------------------------------------------------
time0: ;定时器0中断服务程序
push psw ;保护现场
push acc
inc dot ;百分之一秒计数器加1
mov a,dot ;计数器值送入a
cjne a,#100,over ;未计到100则返回继续计数
mov dot,#0 ;计到100后清零
inc sec ;秒计数器加1(进位10ms*100=1s)
mov a,sec ;秒计数值送入a
cjne a,#60,over ;未计到60则返回继续计数
mov sec,#0 ;计到60后秒计数器清零
inc min ;分计数器加1(进位60s=1m)
mov a,min ;分计数值送入a
cjne a,#60,over ;未计到60则返回继续计数
mov min,#0 ;计到60后分计数器清零,重新计时
inc hou ;时计数器加1(进位60m=1h)
mov a,hou ;时计数器送入a
cjne a,#100,over ;未计到100则返回继续计数
mov hou,#0 ;计到100后清零
over: mov th0,#0xd8 ;重置定时常数
mov tl0,#0xf0
pop acc ;恢复现场
pop psw
reti ;中断返回
;--------------------------------------------------------------------------------
time1: ;定时器1中断服务程序
push psw ;保护现场
push acc
push b
;以下是百分之一秒计数器值个位十位分开
mov a,dot ;百分之一秒计数器值送入a(被除数)
mov b,#10 ;除数10送入b
div ab ;a除以b
mov dot_h,b ;余数b(百分之一秒值)送入百分之一秒存储单元
mov dot_l,a ;商a(十分之一秒值)送入十分之一秒存储单元
;以下是秒计数器值个位十位分开
mov a,sec ;秒计数器值送入a(被除数)
mov b,#10 ;除数10送入b
div ab
mov sec_h,b ;余数b(秒个位值)送入秒个位存储单元
mov sec_l,a ;商a(秒十位值)送入秒十位存储单元
;以下是分计数器值个位十位分开
mov a,min ;分计数器值送入a(被除数)
mov b,#10 ;除数10送入b
div ab
mov min_h,b ;余数b(分个位值)送入分个位存储单元
mov min_l,a ;商a(分十位值)送入分十位存储单元
;以下是时计数器值个位十位分开
mov a,hou ;时计数器值送入a(被除数)
mov b,#10 ;除数10送入b
div ab
mov hou_h,b ;余数b(小时个位值)送入时个位存储单元
mov hou_l,a ;商a(小时十位值)送入时十位存储单元
mov dptr,#table ;数码管段码表首址送入dptr
mov a,#dot_l ;取百分之一秒值的地址
add a,dis_r ;基址+偏移量
mov r0,a ;R0为欲显示值的地址
mov a,@r0 ;取欲显示值送入a
; dis_r : 0 1 2 3 4 5 6 7
;对应单元: dot_l dot_h sec_l sec_h min_l min_h hou_l hou_h
movc a,@a+dptr ;取对应值的段码
mov p2,dis_b ;位码送入P2口
mov r0,dis_b ;取位码判断是否为需加小数点的位[liuwentao]
cjne r0,#0xdf,b3 ;不是P2.5再判断是否为P2.3
ajmp add_dot ;是P2.5则段码加上小数点显示
b3: cjne r0,#0xf7,b1 ;也不是P2.3再判断是否为P2.1
ajmp add_dot ;是P2.3则段码加上小数点显示
b1: cjne r0,#0xfd,com ;也不是P2.1则正常送段码
add_dot: anl a,#0x7f ;是P2.5,P2.3,P2.1则段码和7f做与操作使对应位显示小数点
com: mov p0,a ;段码送入P0口
inc dis_r ;偏移量加1,下次中断时显示下个数
anl dis_r,#0x07 ;dis_r增到8时自动清0(使之在0到7间循环)
mov a,dis_b ;位码循环右移,下次中断时选通下个数码管
rr a
mov dis_b,a
mov th1,#0xfc ;重置定时常数
mov tl1,#0x18
pop b
pop acc ;恢复现场
pop psw
reti
d_10ms: mov r5,#20 ;1+(1+2*255)*20+2*20=10.261ms@12M
temp1: mov r6,#255 ;1+2*255
djnz r6,$
djnz r5,temp1