📄 file12.asm
字号:
;多功能数字钟,可以设置时/分,不能设置秒
;准点报时。定时报时等
;现象,程序下载完成以后,数码显示000000,同时,最后两个数码管开始显示
;秒,同时,有两个led指示灯按照每秒一次的闪烁,
;用户可以利用三个按键来输入时/分,左边第一个输入时,中间的那个输入分
;第三个用来切换,输入时的增/减,按一次第三个按键,程序自动设置成
;增加/减少方式,比如我们在输入时的时候,应该输入12,结果输入了13,那
;我们只要按一次最右边的那个按键(模式设置),然后按最左边的这个(设置时)
;就可以调整为12了,分的设置也一样!
;每到正点都会发出短鸣,到了12:00会发出特殊的定时蜂鸣!
beep bit p3.7 ;蜂鸣器定义
segdata equ p0 ;数据 输出
sege equ p2.7 ;显示 选中
segb equ p2.6 ;位 选
segd equ p2.5 ;段 选
key1 bit p3.5 ;按键定义
key2 bit p3.4
key3 bit p3.3
key equ 56h
time_h equ 57h ;定时初值高位
time_l equ 58h ;低位
t_h equ 60h ;时分秒对应的地址
t_s equ 61h
t_m equ 62h
time equ 63h ;时钟计数单元
timer_h equ 64h ;定时时单元
timer_m equ 65h ;定时分单元
timset bit 00h ;设置时间标志
disstart equ 70h ;显示单元首地址
int_data equ 45h ;中断数据地址
count_data equ 44h ;计数单元地址
timer_data equ 43h ;定时地址
; ************** 以上为预定义部分
; ************** 以下程序开始
org 00h ; 程序开始地址
jmp main ; 跳转到代码开始处
org 1bh ; 定时器 T1 中断服务程序入口
jmp tim1
org 030h ;主程序开始的地址 30H
main:mov sp,#30h ;首先定义堆栈
lcall rest ;初始化
lcall pro_set ;设置定时器开始工作
lpp: lcall time_set ;接受用户设置时间
lcall timer ;时钟处理
lcall time_pro ;时间格式处理,码型变化等
lcall time_display ;显示
jmp lpp
; ************* 初始化程序 ***************************
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次为一秒
clr timset ;定时设置标志位,0->增加 1 ->减少
mov timer_h,#12 ;定时器时单元,设置定时为 12:00
mov timer_m,#00h ;定时器分单元
clr beep ;禁止蜂鸣器
ret ;返回
; *************** 定时器 T1 中断服务程序 ****
tim1: clr tr1 ;首先停止定时操作
mov th1,time_h ;
mov tl1,time_l
inc time ;自增
mov a,time ;取得溢出次数
cjne a,#20,retend ;如果满20此表示到 1 秒
cpl p1.0 ;取反p1.0,p1.1指示秒钟
cpl p1.1
mov time,#00h ;重新开始等待1秒
inc t_s ;秒单元加1
retend: setb tr1 ;定时开始
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 ;保存低位
setb ea ;总的中断允许
setb et1 ;定时器1允许
setb tr1 ;定时器1开始运行
ret ;返回
; ****************** timer 程序主要完成数据的处理 **********
timer: mov a,t_s ;取得秒单元数据
cjne a,#60,tend ;秒不到60返回
mov t_s,#00h ;清除秒单元
inc t_m ;为分单元加1
mov a,t_m ;取得分单元数据
cjne a,#60,tend ;分不等于60返回
mov t_m,#00h ;分单元清零
setb beep ;整点短鸣提示
lcall delay ;鸣叫延时
clr beep ;停止蜂鸣器
inc t_h ;同时为时单元加1
mov a,t_h ;取得时单元数据
cjne a,#24,timetest ;如果不等于24,查看定时
mov t_h,#00h ;时单元清零
jmp tend ;返回
timetest:cjne a,timer_h,tend ;不等于定时的时单元,返回
mov a,t_m ;取得定时的分单元
cjne a,timer_m,tend ;当前分不等于定时的分单元,返回
setb beep ;定时到,蜂鸣提示
lcall delay
clr beep
lcall delay
setb beep
lcall delay
clr beep ;连续发出短音提示
tend: ret ;返回
; ************ time_display 程序主要为显示时间值用 *************
time_display:mov r0,#disstart ;取得显示单元首地址
mov r1,#01h ;从第一个数码管开始
mov r2,#06h ;共6个数码管
clr sege ;显示选中
dislp:mov segdata,@r0 ;获得当前单元数据
setb segd
nop
clr segd
inc r0 ;指向下一个单元
mov segdata,r1 ;数码显示
setb segb
nop
clr segb
mov a,r1 ;为下一个数准备
rl a ;下一个单元
mov r1,a ;保存
lcall delay3ms ;为了保证数码管亮度,
;但要防止闪烁,延时3ms
djnz r2,dislp ;重复显示,直到全部数据刷新过
ret ;返回
; ******* time_pro 时间处理,主要为 bcd码转换,查表 ***********
time_pro: lcall bcd ;BCD码转换
mov r0,#disstart ;获得显示单元首地址
mov r2,#06h ;需要转换的个数
prlp:mov a,@r0 ;取得当前需要转换的数据
mov dptr,#tab_nu ;获得表头
movc a,@a+dptr ;获得转换后的数据
mov @r0,a ;存回去
inc r0 ;指向下一个
djnz r2,prlp ;重复转换,直到6个全部完成
ret ;返回
; **************** 码型变换 ****************************************
bcd: mov r0,#disstart ;获得首地址
mov a,t_s ;获得待转化的低位
mov b,#10 ;转化进制,如果要进行十进制转换 改为 10
div ab ;计算 A/B
mov @r0,b ;第一位转换完毕,保存低位转化后的数据
inc r0 ;自增
mov @r0,a ;保存高位
inc r0 ;取第二个数据地址
mov a,t_m ;获得第二个需要转换的数据
mov b,#10 ;十六进制
div ab ;计算
mov @r0,b ;存低位
inc r0
mov @r0,a ;存高位
inc r0 ;第三位
mov a,t_h ;获得数据
mov b,#10 ;十六进制
div ab ;计算
mov @r0,b ;存低位
inc r0
mov @r0,a ;存高位
ret ;完毕,返回
;***************************************************************************************
; * ******** time_set 设置时间 *******************************************************
; * *
; * 检测用户按键,1-> 设置时单元 2-> 设置分单元,3->设置增减方式 *
; * 如果需要增加 时,先将方式设置为 增加(默认为减),即,按下 KEY3一下, *
; * 然后按 KEY1 ,如果要减少时单元,需要再次按下KEY3,然后按KEY1; *
; * 分的设置也是如此。 *
;***************************************************************************************
time_set:mov p0,#00h ;禁止数码管显示
mov p2,#255 ;防止按键时闪烁
lcall pro_key ;查找用户按键情况
mov a,key ;查找键值
jz tsend ;如果等于0,表示没用按键,直接返回
cjne a,#1,tset1 ;是否等于1?没有到下一个处理程序
mov key,#00h ;等于1,表示设置时 请零,否则会引起重复设置
jb timset,tset10 ;时间设置标志位,1 ->减少,0->增加
mov a,t_h ;标志位 0 ,增加,取得时单元
cjne a,#23,ts1 ;如果时单元不等于23,转移到增加操作
jmp tsend ;等于23 直接返回
ts1: inc t_h ;时单元增加1
jmp tsend ;返回
tset10:mov a,t_h ;这里处理为减少的情况
jz tsend ;如果时单元为0,直接返回
dec t_h ;否则,数据减1
jmp tsend ;返回,以下关于分的设置一样
tset1:cjne a,#2,tset2 ;如果按键不是 2 则 转移到下一个处理
mov key,#00h ;是2,表示设置 分
jb timset,tset20 ;其余同上
mov a,t_m
cjne a,#59,ts2
jmp tsend
ts2:inc t_m
jmp tsend
tset20:mov a,t_m
jz tsend
dec t_m
jmp tsend
tset2:cjne a,#3,tsend ;等于 3 表示设置标志
mov key,#00h ;清零
cpl timset ;标志取反
tsend: ret ;返回
;******** 定时器 T0 设置 **************
;定时器工作在方式1,为提高精度,总定时时间为50ms,
;定时器溢出20次为1秒,
pro_timer:
mov tmod,#01h ;设置定时器为定时方式1
mov th0,#0ffh ; 初始化定时初值
mov tl0,#0a1h ;
setb ea ;总中断允许
setb et0 ;定时器0 允许
setb tr0 ;开始定时
ret ;返回
; *****************************************
; *************** 软件延时 *************
delay:push psw ; 保存原来的寄存器内容
clr psw.3 ;
clr psw.4 ; 设置新的寄存器组
mov r0,#2 ; 延时参数1
mov r1,#250 ; 延时参数2
mov r2,#2 ; 延时参数3
dl1:djnz r0,dl1 ; 延时循环1
mov r0,#250 ;
dl2:djnz r1,dl1 ; 延时循环2
mov r0,#240 ;
mov r1,#248 ;
dl3:djnz r2,dl1 ; 延时循环3
nop ; 定时精度调整
pop psw ; 恢复原来的寄存器
ret ; 返回
;*****************************************
pro_key: ;键盘查询子程序
setb key1 ;首先输出高电平,检测低电平的到来
setb key2 ;不同电路,可能检测方式不一样
setb key3
jb key1,ke1 ;如果用户没有按第一个键,到第下个处理部分,
mov key,#1 ;表示用户按了第一个键
lcall delay20ms ;软件延时,防止干扰
jmp pro_key ;重新查询,直到用户释放按键
ke1:jb key2,ke2 ;处理第二个按键,如果没有到下一个处理部分
mov key,#2 ;以下和第一个处理单元相似。
lcall delay20ms
jmp pro_key
ke2:jb key3,ke3
mov key,#3
lcall delay20ms
jmp pro_key
ke3:ret
;************ 定时20 ms *************
delay20ms:
push psw ; 保存原来的寄存器单元
clr psw.3 ; 设置新的寄存器
clr psw.4 ;
mov r0,#2 ; 延时参数1
mov r1,#250 ; 延时参数2
mov r2,#1 ; 延时参数3
de1:djnz r0,de1 ; 延时循环1
mov r0,#250 ; 重新设置循环数据
de2:djnz r1,de1 ; 开始第二道循环
mov r0,#240 ;
mov r1,#248 ;
de3:djnz r2,de1 ; 第三道循环
nop ; 修正定时精度
pop psw ; 恢复原来的寄存器组
ret ; 返回
;*********** end *******************
;*********** 延时 3ms ****************
delay3ms:
push psw
clr psw.3
setb psw.4
mov r0,#250
mov r1,#3
d5:djnz r0,d5
mov r0,#250
djnz r1,d5
pop psw
ret
;************************************************************************************
;这是数字显示表格,其中 带小数点的数字比不带小数点的数字大16
; 比如 0 的显示代码为 0;那么 0.的显示代码为 16;如此类推
tab_nu:
db 0c0h, 0f9h, 0a4h, 0b0h, 99h , 92h , 82h, 0f8h ; 数字0-7 不带小数点代码
db 80h , 90h, 88h , 83h , 0c6h, 0a1h, 86h, 8eh ; 数字8-f 不带小数点代码
db 40h , 79h, 24h , 30h , 19h , 12h , 02h, 78h ; 数字0-7 带小数点代码
db 00h , 10h, 08h , 03h , 46h , 21h , 06h, 0eh ; 数字8-f 带小数点代码
end ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -