📄 clock.asm
字号:
;前段时间刚自己写了一个,电子时钟,有年月日时分秒,提供设置时间功能,每秒钟自动跳动显示最新时间。
;显示是通过点阵显示的。
.model small
.stack
.data
;-------------------data--------------------------------------------------
YEAR dw ?
MONTH db ?
DAY db ?
HOUR db ?
MIN db ?
SEC db ?
MSEC db ?
monthDay db 0,31,28,31,30,31,30,31,31,30,31,30,31
runFlag db 0 ;----1.Yes 2.No---是否闰年
FUNKEY db ? ;功能设置使用
keySw db 00h ;是否按键开关
SWITCH db 0FFh ;刷新开关,真,则不断在定时器中断函数中刷新,否则不刷新
n db 0dh,0ah,'$'
count dw 1
sMsg db '***** welcome to my clock ****',0dh,0ah,'$'
qMsg db '**** Please Input q to quit ****',0dh,0ah,'$'
testStr db 02h,02h,02h,0dh,0ah
db 2,0,2,0dh,0ah
db 2,2,2,0dh,0ah,'$'
s0 db 0,2,2,2,0
db 1,2,0,2,0
db 2,2,0,2,0
db 3,2,0,2,0
db 4,2,2,2,0
db '$'
s1 db 0,0,2,0,0
db 1,0,2,0,0
db 2,0,2,0,0
db 3,0,2,0,0
db 4,0,2,0,0
db '$'
s2 db 0,2,2,2,0
db 1,0,0,2,0
db 2,2,2,2,0
db 3,2,0,0,0
db 4,2,2,2,0
db '$'
s3 db 0,2,2,2,0
db 1,0,0,2,0
db 2,2,2,2,0
db 3,0,0,2,0
db 4,2,2,2,0
db '$'
s4 db 0,2,0,2,0
db 1,2,0,2,0
db 2,2,2,2,0
db 3,0,0,2,0
db 4,0,0,2,0
db '$'
s5 db 0,2,2,2,0
db 1,2,0,0,0
db 2,2,2,2,0
db 3,0,0,2,0
db 4,2,2,2,0
db '$'
s6 db 0,2,2,2,0
db 1,2,0,0,0
db 2,2,2,2,0
db 3,2,0,2,0
db 4,2,2,2,0
db '$'
s7 db 0,2,2,2,0
db 1,0,0,2,0
db 2,0,0,2,0
db 3,0,0,2,0
db 4,0,0,2,0
db '$'
s8 db 0,2,2,2,0
db 1,2,0,2,0
db 2,2,2,2,0
db 3,2,0,2,0
db 4,2,2,2,0
db '$'
s9 db 0,2,2,2,0
db 1,2,0,2,0
db 2,2,2,2,0
db 3,0,0,2,0
db 4,0,0,2,0
db '$'
num dd 0
xpoint db ?
ypoint db ?
;-------------------------------------------------------------------------
.code
PUSHA1 MACRO
PUSH DS
PUSH AX
PUSH BX
PUSH CX
PUSH DX
ENDM
POPA1 MACRO
POP DX
POP CX
POP BX
POP AX
POP DS
ENDM
leaNum macro outNum
lea di, s&outNum
endm
;--------------------Main---------------------------------------------------
start:
mov ax, @data
mov ds, ax
push ds
call GETTIME ;取得系统时间
call initUI ;初始化界面
;save old interrupt vector
mov al, 1ch ;al<=vector number
mov ah, 35h ;to get interrupt vector
int 21h ;call DOS
push es ;save registers for restore(old base address)
push bx ;save offset of interrupt 1CH
push ds
;set new interrupt vector
mov dx, offset tUpdate ;dx<=offset of procedure ring
mov ax, seg tUpdate ;ax<=segment of procedure ring
mov ds, ax ;ds<=ax
mov al, 1ch ;al<=vector#
mov ah, 25h ;to set interrupt vector
int 21h ;call DOS
pop ds ;restore ds
in al, 21h ;set interrupt mask bits
and al, 11111100b
out 21h,al
sti
delay:
cmp ds:[keySw], 0FFh ;check if any key is pressed
jz exitdelay ;exit delay if any key is pressed
jmp delay
exitdelay:
;restore old interrupt vector
pop dx ;restore registers(restore the old offset)
pop ds ;restore old base of interrupt
mov al,1ch ;al<=vector#
mov ah,25h ;to restore interrupt
int 21h ;call DOS
pop ds ;restore ds
;读敲入的按键
mov ah,07h
int 21h
cmp al,'q'
je endmain
mov ds:[keySw],00h
jmp start
endmain:
mov dh, 10h
mov dl, 0h
call MOVCUR
mov ax,4c00h ;exit
int 21h
;main endp
;-----------------------------------------------------------------------
;--dl = '0','1','2',3,4,5,6...'9'
;--(do) di = offset s0,s1...s9
;--(used) MOVCUR(dh:row,dl:col)
BigOutput proc near
PUSHA1
mov bl,dl
sub bl,'0'
mov dh,xpoint
mov dl,ypoint
;---set di
cmp bl,0
je js0
cmp bl,1
je js1
cmp bl,2
je js2
cmp bl,3
je js3
cmp bl,4
je js4
cmp bl,5
je js5
cmp bl,6
je js6
cmp bl,7
je js7
cmp bl,8
je js8
cmp bl,9
je js9
js0: leaNum 0
jmp jout
js1: leaNum 1
jmp jout
js2: leaNum 2
jmp jout
js3: leaNum 3
jmp jout
js4: leaNum 4
jmp jout
js5: leaNum 5
jmp jout
js6: leaNum 6
jmp jout
js7: leaNum 7
jmp jout
js8: leaNum 8
jmp jout
js9: leaNum 9
jmp jout
jout:
;---print di
mov cx,5
mov dh,xpoint
mov dl,ypoint
out2:
push dx
mov al,[di]
inc di
add dh,al
call MOVCUR
push cx
mov cx,4
out1:
mov al,[di]
inc di
mov dl,al
mov ah,02h
int 21h
loop out1
pop cx
pop dx
loop out2
POPA1
add ypoint,4
ret
BigOutput endp
;------------------------------------------------------------------------
tUpdate proc near
push ds ;save the working registers
push ax
push bx
push cx
push dx
mov ax, @data ;allot data segment
mov ds, ax
sti
;---55ms-1000ms count for timer interval(约18.2次为1秒)
add count,55d
cmp count,1000
jl exit
sub count,1000
call CALTIME ;更新时间
;检测刷新开关是否打开
mov bl,ds:[SWITCH]
cmp bl,00
jz exit
;检测是否有按键按下,取适当的值进行退出控制
PUSHA1
MOV AH, 0BH ;检测是否输入消息(按键消息)
INT 21H
INC AL
JNE nokey
mov ds:[keySw],0FFh ;设置已经被按键
POPA1
jmp exit
nokey:
POPA1
call DISPLYY ;显示年份
call DISPLYMONTH ;显示月份
call DISPLYD ;显示日期
call DISPLYH ;显示小时
call DISPLYM ;显示分钟
call DISPLYS ;显示秒
exit:
cli
mov al,20h ;set EOI
out 20h,al
pop dx ;restore the reg.
pop cx
pop bx
pop ax
pop ds
iret ;interrupt return
tUpdate endp
;--------------------------------------------------------------------
;关闭定时刷新开关
closeSw proc near
PUSHA1
mov bl,0h
mov ds:[SWITCH],bl ;关闭刷新开关
POPA1
ret
closeSw endp
;----------------------------------------------------------
;打开定时刷新开关
openSw proc near
PUSHA1
mov bl,0FFh
mov ds:[SWITCH],bl ;打开刷新开关
POPA1
ret
openSw endp
;---------------------------------------------------------------------------
;初始化显示界面,可以在此处添加额外的设置选项
initUI proc near
PUSHA1
;设置显示方式(40×25 黑白文本,16级灰度)
mov ah,0h
mov al,02h
int 10h
;显示头标题
mov dh,00h
mov dl,02h
call MOVCUR
mov dx,offset sMsg ;dx<=offset of sMsg
mov ah,09h ;to display sMsg
int 21h ;call DOS
;显示结尾标题
mov dh,0Fh
mov dl,02h
call MOVCUR
mov dx,offset qMsg ;dx<=offset of qMsg
mov ah,09h ;to display qMsg
int 21h ;call DOS
POPA1
ret
initUI endp
;--------------------------------------------------------------------------
;移动光标(dh:row,dl:col)
; dh ;参数设置行
; dl ;参数设置列
MOVCUR proc near
PUSHA1
;设置光标位置
mov ah,2h
mov bh,0
int 10h
POPA1
ret
MOVCUR endp
;-------------------------------------------------------------------------
;显示年
DISPLYY PROC NEAR
PUSHA1
;设置光标位置
mov dh,2h ;set Row No.
mov dl,1d ;set Column NO.
call MOVCUR
mov xpoint,dh
mov ypoint,dl
mov dx,ds:[YEAR]
call output ;调用output函数输出小时
mov dl,2
mov ah,02h
int 21h
POPA1
RET
DISPLYY ENDP
;----------------------------------------------------------
;显示月份
DISPLYMONTH PROC NEAR
PUSHA1
;设置光标位置
mov dh,2h ;set Row No.
mov dl,20d ;set Column NO.
mov xpoint,dh
mov ypoint,dl
call MOVCUR
mov dh,0
mov dl,ds:[MONTH]
call output
mov dl,2
mov ah,02h
int 21h
POPA1
RET
DISPLYMONTH ENDP
;----------------------------------------------------------
;显示日期
DISPLYD PROC NEAR
PUSHA1
;设置光标位置
mov dh,2h ;set Row No.
mov dl,30d ;set Column NO.
call MOVCUR
mov xpoint,dh
mov ypoint,dl
mov dh,0
mov dl,ds:[DAY]
call output
POPA1
ret
DISPLYD endp
;----------------------------------------------------------
;显示小时
DISPLYH PROC NEAR
PUSHA1
;设置光标位置
mov dh,9h ;set Row No.
mov dl,1d ;set Column NO.
call MOVCUR
mov xpoint,dh
mov ypoint,dl
mov dh,0
mov dl,ds:[HOUR]
call output ;调用output函数输出小时
;输出点阵:
mov dh,0Ah
mov dl,0Ah
call MOVCUR
mov dl,2
mov ah,02h
int 21h
mov dh,0Ch
mov dl,0Ah
call MOVCUR
mov dl,2
mov ah,02h
int 21h
POPA1
RET
DISPLYH ENDP
;----------------------------------------------------------
;显示分钟
DISPLYM PROC NEAR
PUSHA1
;设置光标位置
mov dh,9h ;set Row No.
mov dl,13d ;set Column NO.
call MOVCUR
mov xpoint,dh
mov ypoint,dl
mov dh,0
mov dl,ds:[MIN]
call output
;输出点阵:
mov dh,0Ah
mov dl,16h
call MOVCUR
mov dl,2
mov ah,02h
int 21h
mov dh,0Ch
mov dl,16h
call MOVCUR
mov dl,2
mov ah,02h
int 21h
POPA1
RET
DISPLYM ENDP
;----------------------------------------------------------
;显示秒
DISPLYS PROC NEAR
PUSHA1
;设置光标位置
mov dh,9h ;set Row No.
mov dl,25d ;set Column NO.
call MOVCUR
mov xpoint,dh
mov ypoint,dl
mov dh,0
mov dl,ds:[SEC]
call output
POPA1
ret
DISPLYS endp
;----------------------------------------------------------
;调用DOS中断取得系统时间
GETTIME PROC NEAR
PUSHA1
mov ah,2ah ;get the System data,CX(year) DH(month) dl(day)
int 21h
mov ds:[YEAR], CX ;取得小时
mov ds:[MONTH], DH ;取得分钟
mov ds:[DAY], DL ;取得秒
mov ah,2ch ;get the System time,CH:CL=(H:M),DH:DL=(s:1/100s)
int 21h
mov ds:[HOUR], CH ;取得小时
mov ds:[MIN], CL ;取得分钟
mov ds:[SEC], DH ;取得秒
mov ds:[MSEC], DL
POPA1
ret
GETTIME endp
;----------------------------------------------------------
;调整时间,累加秒,分,时
CALTIME proc near
PUSHA1
;调整秒
inc ds:[SEC]
cmp ds:[SEC],60d
jb endc
mov ds:[SEC],0h
setM: ;调整分钟
inc ds:[MIN]
cmp ds:[MIN],60d
jb endc
mov ds:[MIN],0h
setH: ;调整小时
inc ds:[HOUR]
cmp ds:[HOUR],24d
jb endc
mov ds:[HOUR],0h
setD: ;调整日期
inc ds:[DAY]
cmp DS:[MONTH],2
jne setMonthDay
;如果是二月
call runOrnot ;判断是否闰年
cmp runFlag,1
jne setMonthDay
;是闰年而且二月
mov bl,29
jmp cmpMonthDay
setMonthDay:
xor ax,ax
mov al,DS:[MONTH]
mov di,ax
mov bl,monthDay[di]
cmpMonthDay:
inc bl
cmp ds:[DAY],bl
jb endc
mov ds:[DAY],1h
setMonth: ;调整月份
inc ds:[MONTH]
cmp ds:[MONTH],13d
jb endc
mov ds:[MONTH],1h
setY: ;调整年份
inc ds:[YEAR]
endc:
POPA1
ret
CALTIME endp
;---------------------------------------------------------------------------
;判断是否闰年
runOrnot proc near
mov ax, DS:[YEAR]
mov bx, 0003h
and ax, bx
cmp ax, 0
jne SetRun0 ;------mod 4 !=0-----exp 1999
;------mod 4 ==0-----
mov ax, DS:[YEAR]
mov cl, 100d
div cl
cmp ah,0
jne SetRun1 ;------mod 100!=0----exp 1996
;------mod 100==0----
xor bx, bx
mov bl, al
mov ax, bx
mov cl, 4d
div cl
cmp ah,0
jne SetRun0 ;------mod 400!=0----exp 1700
;------mod 400!=0--------------------exp 2000
SetRun1:
mov DS:[runFlag],1
ret
SetRun0:
mov DS:[runFlag],0
ret
runOrnot endp
;---------------------------------------------------------------------------
;输出字符(dx中存放十进制数值)
output proc near
PUSHA1
mov ax,dx ;put the final num into ax
mov dx,00h
mov cx,0h
trans:
mov bx,000ah ;this loop put the char into memory
div bx ;divide 10d
add dl,30h ;transform to character
mov dh,0h
push dx
inc cx
mov dx,00h
cmp ax,00h
jg trans
cmp cx,01h
jg print
addZero: ;增加前导0,,比如:02
mov dh,0
mov dl,'0'
push dx
inc cx
print: ;this loop output the char
cmp cx,0h
jle endout
pop dx
mov dh,0
dec cx
call BigOutput
; mov ah,02h
; int 21h ;call DOS output ability
jmp print
endout:
POPA1
ret
output endp
end start ;end assemble
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -