日时钟中断:
系统日时钟中断源是系统8254 0#计数器,每55ms有一次中断请求。
中断类型码为08H
系统日时钟中断(8型中断服务子程序)处理流程:
(1)开中断保护现场,40H->DS
(2)对日时钟计数器进行一次加1计数
(3)执行INT 1CH
1CH为日时钟的外扩中断,用户可开发新的1CH中断
(4)向主8259A发出常规中断结束命令
MOV AL,20H
OUT 20H,AL
(5)恢复现场,执行IRET指令
例:利用PC系列机上的8254的0号定时计数器引发的日时钟中断,设计程序:每隔1S在PC终端屏幕上显示一行字符串'HELLO!',显示10行结束
(1)保存原来系统的1CH中断向量到数据段OLD1C双字单元
(2)置换1CH中断向量使其指向自己的中断服务子程序
(3)中断服务子程序每执行18次显示一次字符串
(4)在返回操作系统前恢复原来保存的1CH中断向量
数据段:
DATA SEGMENT USE16
MESG DB 'HELLO!',0DH,0AH,'$'
OLD1C DD ? ;保存1CH原本的中断向量,双字
ICOUNT DB 18 ;中断计数初值?
COUNT DB 10 ;显示行数
DATA ENDS
代码段:
CODE SEGMENT USE16
ASSUME CS:CODE,DS:DATA
BEG: MOV AX,DATA
MOV DS,AX
CLI ;关中断
CLI关中断是防止在WRITE1C如果有日时钟中断的话,会访问1CH,所以会出现一边读一边写的情况,可能会出现问题。
READ1C不关中断也可以,因为如果在读取的过程中有日时钟中断,那么会执行默认的1CH,即什么也不做,没有影响。
CALL READ1C;读取原本1CH的中断向量到OLD1C
CALL WRITE1C;写入新的中断向量
STI ;开中断
SACN:CMP COUNT,0
JNZ SACN ;是否已经显示10行,否则一直在这等待
CLI
CALL RESET;恢复1CH中断向量
STI
MOV AH,4CH
INT 21H
中断服务子程序SERVICE
SERVICE PROC
PUSHA
PUSH DS
MOV AX,DATA
MOV DS,AX ;因为在写入1CH中断向量时,把代码段段基址赋给了DS,因为下面用到了数据段的变量,为了能够正确找到变量,所以需要把数据段段基址赋给DS,以防DS存的是代码段的段基址。
DEC ICOUNT
JNZ EXIT ;ICOUNT初值为18,每次进入SERVICE中断服务子程序时,ICOUNT都要减1,当减到0时打印1行,并且把ICOUNT初值还原为18,COUNT减1;否则直接退出中断服务子程序
MOV ICOUNT,18
DEC COUNT
MOV AH,9
MOV DX,OFFSET MESG
INT 21H
EXIT: POP DS
POPA
IRET
SERVICE ENDP
READ1C子程序:
READ1C PROC
MOV AH,35H
MOV AL,1CH
INT 21H
MOV WORD PTR OLD1C,BX
MOV WORD PTR OLD1C+2,ES
RET
READ1C ENDP
WRITE1C PROC子程序:
WRITE1C PROC
PUSH DS ;在写中断向量时,会把中断服务程序的段基址赋给DS,但是DS原本存放的是数据段段基址,所以要在写中断向量的时候保护DS
MOV AX,SEG SERVICE
MOV DS,AX
MOV DX,OFFSET SERVICE
MOV AH,25H
MOV AL,1CH
INT 21H
POP DS
RET
WRITE1C ENDP
RESET子程序:
RESET PROC
;这里不保护DS的原因是之后的代码中不会在用到代码段的变量了。
MOV DX,WORD PTR OLD1C
MOV DS,WORD PTR OLD1C+2
MOV AH,25H
MOV AL,1CH
INT 21H
RET
RESET ENDP