;计算机在系统加电期间,把系统定时器初始化为每55ms发出一次中断请求。CPU在相应定时中断请求后转入08H号中断处理程序。
;BIOS提供的08H号中断处理程序中有一条中断指令“INT 1CH”。所以每秒要调用1000/55≈18.2次1CH号中断处理程序。
;而BIOS的1CH号中断处理程序实际上并没有执行任何工作,只有一条中断返回指令(IRET)
;这样安排的目的就是为应用程序留下一个软接口,应用程序只要提供新的1CH号中断处理程序,就能实现某些周期性的工作。
;本实验就是利用这个软接口实现“实时时钟显示”
CODE SEGMENT
ASSUME CS:CODE
YYY DW 0
MON DB 0
DDD DB 0
OLD1C DD 0
COUNT DW 0
HHH DB 0
MMM DB 0
SSS DB 0
NOZERO DB 0
TIMECOUNT DW 0
TIMEFLY DW 0
TIMEAGO DB 0
TIMENOW DB 0
SHOWTIME DW 0
START PROC FAR
CALL INPUTDEC ;输入定时时长,保存在BX中
MOV TIMEFLY,BX
PUSH CS
POP DS ;把CS的值赋给DS
;设置新的中断向量
MOV AX,351CH ;读取1C号中断向量
INT 21H ;ES:BX是读取出的中断向量
MOV CS:WORD PTR OLD1C,BX
MOV CS:WORD PTR OLD1C+2,ES ;保存原1C号中断向量
MOV DX,OFFSET INT1C
MOV AX,251CH ;设置中断向量,DS:DX=中断向量,AL=中断类型号
INT 21H ;此后每55秒就进入一次新的1CH号中断处理程序
CLOCKGO:
CMP SHOWTIME,5 ;显示时间到了吗?
JC CLOCKGO ;没到,循环;否则执行结束
;结束程序之前,应把1C号中断向量还原回去
LDS DX,CS:OLD1C
MOV AX,251CH
INT 21H
;结束程序,返回操作系统
MOV AH,4CH
INT 21H
START ENDP
INT1C PROC FAR
CMP COUNT,0 ;中断次数为0,经过大约一秒
JZ NEXT
DEC COUNT
IRET
NEXT:
MOV COUNT,17 ;置中断次数初值
STI
PUSH DS
PUSH ES
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV AH,2CH
INT 21H ;读系统时间
MOV HHH,CH ;小时
MOV MMM,CL ;分钟
MOV SSS,DH ;秒
CMP TIMEAGO,DH ;是不是新的一秒?
JNE GOON ;是,执行GOON,否则返回
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
IRET
GOON:
MOV TIMEAGO,DH ;新的一秒
INC TIMECOUNT ;计时器加一
MOV AH,2AH
INT 21H ;读系统日期
MOV YYY,CX ;年
MOV MON,DH ;月
MOV DDD,DL ;日
CALL CLS ;清屏
MOV BH,0
MOV DX,0105H
MOV AH,2
INT 10H ;设置光标位置(1,5)
MOV BX,YYY ;输出年
CALL OUTPUTDEC
CALL OUTPOINT ;点
MOV BL,MON ;输出月
MOV BH,0
CALL OUTPUTDEC
CALL OUTPOINT ;点
MOV BL,DDD ;输出日
MOV BH,0
CALL OUTPUTDEC
CALL WHITESPACE ;空格
MOV BL,HHH ;时
MOV BH,0
CALL OUTPUTDEC
CALL OUTMAOHAO ;冒号
MOV BL,MMM ;秒
MOV BH,0
CALL OUTPUTDEC
CALL OUTMAOHAO ;冒号
MOV BL,SSS ;秒
MOV BH,0
CALL OUTPUTDEC
MOV BX,TIMEFLY
CMP BX,TIMECOUNT ;比较定时是否已到
JNC RETURN ;没到,返回;否则继续执行显示方块
SHOWWORD:
INC SHOWTIME
MOV BH,0
MOV DX,0140H
MOV AH,2
INT 10H ;设置光标位置(1,65)
MOV AL,09
MOV CX,1
MOV BL,0CCH
MOV AH,9
INT 10H ;显示一红色方块
RETURN:
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
IRET
INT1C ENDP
;清屏
CLS PROC
MOV AX,0600H
MOV CX,0
MOV DX,184FH
MOV BH,7
INT 10H
RET
CLS ENDP
;十进制数输入(0—65535)
;输入数据存储在BX中,以回车符结束
INPUTDEC PROC
PUSH CX
MOV BX,0
P1:
MOV AH,1
INT 21H
CMP AL,0DH ;与回车符比较,判断是否结束
JE DECEXIT
SUB AL,30H ;ASCII码减去30,得本次所输数值
MOV AH,0 ;AH清0
XCHG AX,BX ;交换AX,BX
MOV CX,10
MUL CX ;AX(原BX中数,以前输的数)10
XCHG AX,BX ;交换AX,BX
ADD BX,AX ;将本次输的数加进BX中
JMP P1
DECEXIT:
POP CX
RET
INPUTDEC ENDP
;十进制输出(0-65535)
;数据保存在BX中
OUTPUTDEC PROC
PUSH CX
MOV NOZERO,0
MOV CX,10000
CALL PROCESS
MOV CX,1000
CALL PROCESS
MOV CX,100
CALL PROCESS
MOV CX,10
CALL PROCESS
MOV CX,1
CALL PROCESS
CMP NOZERO,0
JNE OUTPUTEXIT
MOV DL,30H
MOV AH,2
INT 21H
OUTPUTEXIT:
POP CX
RET
OUTPUTDEC ENDP
PROCESS PROC
MOV AX,BX
MOV DX,0
DIV CX
MOV BX,DX
MOV DL,AL
CMP DL,0
JNE OUTPUT ;该位不是0,输出
CMP NOZERO,0 ;该位是0,判断是否为首位
JNE OUTPUT ;不是首位,输出
JMP PROCEXIT ;是首位,退出
OUTPUT:
MOV NOZERO,1
ADD DL,30H
MOV AH,2
INT 21H
PROCEXIT:
RET
PROCESS ENDP
;输出点号
OUTPOINT PROC
MOV DL,'.'
MOV AH,2
INT 21H
RET
OUTPOINT ENDP
;输出冒号
OUTMAOHAO PROC
MOV DL,':'
MOV AH,2
INT 21H
RET
OUTMAOHAO ENDP
;输出空格
WHITESPACE PROC
MOV DL,20H
MOV AH,2
INT 21H
RET
WHITESPACE ENDP
CODE ENDS
END START