搜档网
当前位置:搜档网 › 汇编语言编程:在屏幕右上角显示系统时间

汇编语言编程:在屏幕右上角显示系统时间

汇编语言编程:在屏幕右上角显示系统时间



在系统加电初始化期间,把系统定时器初始化为每隔约55毫秒发出一次中断请求,CPU在响应定时器中断请求后转入8H号中断处理程序,BIOS提供的8H号中断处理程序中有一条中断指令INT 1CH,所以每秒要调用到约18.2次1CH号中断处理程序,而BIOS的1CH号中断处理程序实际上并没有做任何工作,只有一条中断返回指令。

------------------------------------------------------------------------------------------

系统 Int 08h

系统定时器

由系统时钟每秒大约调用18.2次(每小时65536次)

调用寄存器:无
返回寄存器:无

注释:
Int 08h是一个每秒钟要调用18.2次的中断,用于完成高级的各种计
数,该中断直接与系统时钟芯片的通道0相连。要编写实用程序中的TSR,如
SideKick,就会发现Int 08h对于由定时来触发的任务来说是特别有用的。此
中断要调用Int 1Ch(定时计数)。因此大多数TSR应该连接到Int 1Ch而不是
连接到Int 08h上。

由于每隔55毫秒此中断就被调用一次,因而,面向该中断的处理程序必
须尽可能快地执行。中断处理只能是处理器系统常规使用的一小部分。并且,
由于计时器被当作IRQ0(高优先级硬件中断),因而会优先于同一系统上的其
它中断而服务于中断Int 08h。若对该中断处理得不好,就会导致服务于其它
的重要中断(如磁盘服务)时出现问题。

注意,由于在Int 08h处理程序完成其处理之前调用了Int 1Ch(计时器的
用户拴接),因而,面向该中断的操作也领先于其它任何硬件中断请求而得以
执行。富有经验的软件设计人员则常常利用这一事实。

地址0040:006Ch是一个32位按天计算的时间(time-of-day)指示符,计
数自启动以来的时间计数。每当时间计数满24小时,位置0040:0070h就被
置为1,而当BIOS读它时,该位置被清除为零。如果经过了24小时而其间又
没有出现读取操作时,计算机的时间系统中便消失了一整天的时间,并又从零
开始计数。

通过递减位置0040:0040h处的值,该中断就能提供用于磁盘的发动机
自动关闭功能。当位置0040:0040h的值为零时,位于0040:003Fh处的发
动机状态中的发动机运行标志被重置为关掉磁盘发动机。

让计时器采用奇数频率来调用Int 08h(18.2次/秒)的原因在于设计者们
希望通过设置出时间显示来简化这项工作,以便位于0400:006Ch处的32
位值中的高位字正好能每小时增加一次,这样便允许把它与24(十进制)进行
简单的比较,以检测午夜翻转。

用3600(每小时的秒数)来除65536(低位字翻转的计数),其结果正好是
18.20——目标频

率。遗憾的是,计时器芯片的递减计数频率略为偏低了一点,
并且实际上在BIOS中检测到的计数数字是11,大于可能显示的结果,实际操
作中,由于不同的系统之间频率是不相同的,因而必须时常重新设置时钟。每
当引导系统时,这一进程通常就会发生;但是在一些拥有单独的实时时钟的系
统上,这些时钟也会在每周超出几秒或丢失几秒钟。

------------------------------------------------------------------------------------------

;看到了一个题目,要求设计一个程序,在屏幕右上角显示系统时间。
;
;当年,做而论道在学习微机原理的时候,就独立设计出了这样的程序,当然,弄了好多日子才成功。
;为了网友少走弯路,做而论道特地翻腾了好久,找出来当年的程序,多年不见,恍如隔世......
;
;80x86系统中,利用8253计数器,产生定时中断,周期是 55ms,频率是 18.2Hz。
;这个周期性的中断,在系统中的中断类型号是 08H,后来发现中断类型号为 1CH 的也是 55ms 中断一次。
;利用这个定时中断,可以干好多事情,查杀病毒就是其中之一。
;
;因为 DOS 系统管理下,系统中的中断向量,可以自行修改,可以用自己编写的程序,代替操作系统中的程序。
;
;下面的程序,就是修改了 INT 08H,使自己编写的程序,也能每秒钟执行18.2遍,目的就是在右上角显示系统时间。
;本程序,采用了程序驻留内存的方法。
;程序表面上看起来是结束了,可以接着执行其它程序,但是屏幕右上角的时钟,却不停的走时。
;呵呵,修改中断向量,程序驻留内存,这可不是简单的微机原理课程的知识。
;
;==============================================
CODE SEGMENT ;代码段.
ASSUME CS: CODE, DS: CODE
ORG 0100H
START:
JMP MAIN
;----------------------------------------------
NEW_08H_SERVICE PROC ;每隔55ms执行一次.
PUSH DS ;保护现场.
PUSH AX
PUSH BX
PUSH CX
PUSH DX
;--------------------------
MOV AX, CODE ;重新给DS段赋值.
MOV DS, AX
;--------------------------
MOV AH, 2
INT 1AH ;读出系统时间.
CMP DH, SEC
JZ E_NEW_08
MOV HOUR, CH
MOV MIN, CL
MOV SEC, DH
;--------------------------
MOV AH, 3 ;取出当前光标位置.
MOV BL, 0
INT 10H
PUSH DX
;--------------------------
MOV CURSOR, 0047H ;第0行、71列.
CALL SET_CURSOR
MOV AL, HOUR
CALL W_2_CHAR
MOV AL, ':' - 30H
CALL W_1_CHAR
MOV AL, MIN
CALL W_2_CHAR
MOV AL, ':' - 30H
CALL W_1_CHAR
MOV AL, SEC
CALL W_2_CHAR
;--------------------------
MOV AH, 2 ;恢复光标位置.
POP DX
INT 10H
;-

-------------------------
E_NEW_08:
POP DX ;恢复现场.
POP CX
POP BX
POP AX
POP DS
JMP CS: OLD08 ;转去执行原来的中断服务程序.
;--------------------------;下面是代码段中的变量区
CURSOR DW ?
SEC DB ?
MIN DB ?
HOUR DB ?
OLD08 DD ? ;用于存放原来的08H中断向量.
NEW_08H_SERVICE ENDP
;----------------------------------------------
SET_CURSOR PROC ;设定光标位置.
MOV DX, CURSOR
INC DX
MOV CURSOR, DX
MOV AH, 2
INT 10H
RET
SET_CURSOR ENDP
;----------------------------------------------
W_2_CHAR PROC
PUSH AX
MOV CL, 4
SHR AL, CL
AND AL, 0FH
CALL W_1_CHAR
POP AX
AND AL, 0FH
CALL W_1_CHAR
RET
W_2_CHAR ENDP
;----------------------------------------------
W_1_CHAR PROC ;显示1个字符.
MOV AH, 9
ADD AL, 30H ;AL中的数字,变成ASCII
; MOV BL, 1EH ;蓝色背景、黄色字符.
MOV BL, 2FH ;绿色背景、白色字符.
MOV CX, 1 ;显示一个字符.
INT 10H
CALL SET_CURSOR ;显示后,移动一次光标
RET
W_1_CHAR ENDP
;===============以上内容驻留内存,每隔55ms执行一次
MAIN:
MOV AX, CODE
MOV DS, AX
CLI ;关中断
MOV AX, 3508H ;读出原来的08H中断向量到OLD08
INT 21H
MOV WORD PTR OLD08, BX
MOV WORD PTR OLD08 + 2, ES
;--------------
MOV AX, 2508H ;把NEW_08H_SERVICE写人中断向量表.
MOV DX, OFFSET NEW_08H_SERVICE
INT 21H
STI ;开中断.
MOV DX, OFFSET MAIN ;设置驻留程序的末尾位置
INT 27H ;驻留并退出
;----------------------------------------------
CODE ENDS
END START
;==============================================

相关主题