⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clock.asm

📁 asm源代码 dos下数字时钟 使用方法见程序
💻 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 + -