📄 clock.asm
字号:
sta segment STACK
db 200h dup(?)
top label word
sta ends
code segment
assume cs:code,ds:code,ss:sta
main proc far
push ds
mov ax,0
push ax
mov ax,seg NEWINT1C
mov ds,ax ;DS指向代码段
mov dx,offset NEWINT1C ;DX指向新中断入口地址
mov ax,251ch ;中断类型号1c
int 21h ;设置中断向量
mov ax,351ch
int 21h ;测试新中断
mov ax,3100h
int 21h ;终止并驻存内存
ret
main endp
CLOCK DB 0
MINU DB 0
SECOND DB 0
BEEP_TIME DB 0
LAST_SEC DB 0
DISPLAY_DATA DB 0,0,':',0,0,':',0,0
NEWINT1C proc far
pushf
push es
push ds
push ax
push bx
push cx
push dx
push di
push si
xor ax,ax
mov es,ax
push cs
pop ds
mov al,es:[0449h] ;取显示模式
mov cx,es:[046eh] ;取BIOS的时间
mov dx,es:[046ch]
mov ax,cx ;取得的计数时间在cx:dx中
mov bx,dx
shl dx,1
rcl cx,1
shl dx,1
rcl cx,1
add dx,bx
adc ax,cx
xchg dx,ax ;以上几命令使dx:ax=cx:dx*5
mov cx,0e90bh
div cx
mov bx,ax
xor ax,ax
div cx ;以上几命令使dx:ax除以E90B的平方
mov dx,bx
mov cx,00c8h
div cx
cmp dl,100
jb clock_0
sub dl,100
clock_0:
cmc
rcl ax,1
mov dl,0
rcl dx,1
mov cl,60
div cx
mov second,dl
div cl
mov minu,ah ;记录分钟数
mov clock,al ;记录小时数
code1:
jmp short code2 ;当扬声器打开时此处为空,使不转移向code2
dec beep_time ;减少发声时间
jz turn_sp_off
cmp last_sec,1 ;每十分钟一次短响
jz dat0
cmp last_sec,59 ;每59分钟59秒一次短响加长响
jnz dat1
mov cl,6
mov ch,3
mov bx,800h ;长响时间
jmp short dat2
dat0:
mov cl,3
mov ch,2
mov bx,200h ;短响时间
dat2:
mov al,beep_time
xor ah,ah
div cl
cmp ah,ch
jz short speak_on1
or ah,ah ;在报时一秒后停响
jz dat1
in al,61h ;位触发方式发声
and al,0fch ;关断定时器通道2的门控
out 61h,al
dat1:
jmp short disp_clock
turn_sp_off:
in al,61h
and al,0fch
out 61h,al ;恢复61h端口,关掉扬声器
code2:
mov al,ah ;把分钟数存到al中
mov ah,dl ;把秒数存到ah中
or ah,ah
jz is_sec0
cmp ah,1
jz is_sec1
cmp al,59 ;判断是否是在地59分钟
jnz disp_clock
cmp ah,59 ;59秒
jnz disp_clock
mov beep_time,15
mov bx,800h
jmp short speak_on
is_sec1:
mov last_sec,0ffh
jmp short disp_clock
is_sec0:
or al,al
jz is_min0
mov cl,10 ;是否是每十分钟响一次的模式
div cl
or ah,ah
jnz disp_clock
mov cl,3
mul cl
dec al
mov beep_time,al
inc ah
mov bx,200h
jmp short speak_on
is_min0:
mov beep_time,18
mov bx,400h
speak_on:
cmp last_sec,ah ;是则不进行操作
mov last_sec,ah
jz disp_clock
speak_on1:
mov al,0b6h ;位组合格式:通道2,两字节计数,模式3,二进制码
out 43h,al ;幻数方式寄存器
mov ax,bx ;频率送到ax
out 42h,al ;频率计数值送通道2
mov al,ah
out 42h,al
in al,61h ;打开扬声器
or al,3
out 61h,al
mov word ptr code1,9090h ;使得code1地址处为空,而不跳到code2
disp_clock:
mov al,clock
mov si,offset display_data
push si
call hex_to_asc ;使16进制数转为ASC II码输出
mov al,minu
call hex_to_asc
mov al,second
call hex_to_asc
pop si
cmp byte ptr [si],'0' ;第一个数为‘0’则不输出
jnz mov_data
mov byte ptr [si],' '
mov_data:
mov ax,0b800h ;缓冲区
v_buffer:
or ax,ax
jz i1cquit
mov es,ax
mov di,72*2
clock_place:
mov cx,8
cld
mov ah,0eh ;字体取黄色
is_vga:
lodsb
stosw
loop is_vga
i1cquit:
pop si
pop di
pop dx
pop cx
pop bx
pop ax
pop ds
pop es
popf
iret
NEWINT1C endp
HEX_TO_ASC PROC NEAR
cbw
mov cl,10
div cl
add ax,'00'
mov ds:[si],ax
add si,3
ret
HEX_TO_ASC ENDP
code ends
end main
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -