如何设置定时器
How to set Timer
有什么方法可以用 xor ah,ah
将定时器设置为 60 秒
Enter_Again:
xor ah, ah ; I should put 60 seconds here
int 16h ; The user should press S before 60 seconds
mov bl,al
cmp al,"S"
您不能使用INT16 来设置定时器。 INT16 简单地从键盘读取一个字符。
xor ah, ah 将 ah 寄存器置零,以便调用 INT16 函数 0,读取键盘字符。要获取时间,请检查 INT21,函数 0x2C,获取系统时间。
您之前的问题表明您 运行 在 DOS 下。没有使键盘输入超时的 BIOS 或 DOS 调用。您可以锁定(链)到 Interrupt 0x1c 上,这是一个用户中断例程,每秒调用约 18.2 次。一分钟大约有 1092 个这样的中断。您的计时器中断可以简单地调用旧用户中断,然后增加滴答计数。
然后您的主程序可以检查是否按下了一个键,BIOS 调用 Int 16h/AH=1. If the Zero Flag (ZF) is set by this call no key is present in the keyboard buffer. This call doesn't block waiting for characters, it only checks if the keyboard buffer is empty and if it isn't returns the most recent key without removing it from the buffer. You will want to use Int 16h/AH=0 从键盘缓冲区中删除字符 IF 一个键被按下,然后检查它是否是 S。按下的键的 ASCII 值在寄存器 AL 中。未能从缓冲区中删除字符将不允许您在未来正确检查键盘缓冲区中的下一个字符。
如果您要查找的键没有被按下,那么您只需将当前全局计时器滴答计数与 1092 进行比较。如果没有达到,您返回并再次检查键盘缓冲区中的字符。
此示例代码设置了一个用户定时器中断处理程序,并使用上述基本机制等待 S 被按下。如果超时,程序将退出并显示一条消息。如果在超时到期之前按下 S,程序会打印一条消息,然后退出。在退出回到 DOS 之前,中断向量需要恢复到程序启动时的状态。
.model small
.stack 100h
KBD_TIMEOUT EQU 60*182/10 ; 1092 = ~60 seconds (18.2hz*60)
; Max timer value is 65535 which is approximately
; 3600 seconds (one hour)
.data
s_in_time_str db "'S' pressed within 60 seconds$"
s_not_in_time_str db "'S' NOT pressed within 60 seconds$"
.code
; User timer interrupt handler called by Int 08h
; It occurs approximately every 18.2 times a second
; Upon entry CS is the only register that has an expected value
; CS is the code segment where the interrupt handler and the
; interrupt handler data reside
user_timer_int PROC
; Call (chain) to the original interrupt vector
; by pushing flags register and doing a FAR CALL to old vector
pushf
call dword ptr [cs:int1c_old_ofs]
; Increase timer tick by 1
inc word ptr [cs:timer_tick]
iret
user_timer_int ENDP
; Setup interrupt handlers needed by this program
set_interrupts PROC
push ds
; Hook our timer interrupt handler to the user interrupt timer vector
mov ax, 351ch ; AH=35h (Get interrupt vector)
; AL=1Ch (User timer interrupt vector)
int 21h ; Get interrupt vector
; Int 21h/ah=35 will return interrupt vector address in ES:BX
mov [cs:int1c_old_ofs], bx
mov ax, es
mov [cs:int1c_old_seg], ax
mov ax, 251ch ; AH=25h (Set interrupt vector)
; AL=1Ch (User timer interrupt vector)
; Set DS:DX to our user interrupt routine
; DS:DX = CS:user_timer_int
push cs
pop ds
mov dx, offset user_timer_int
int 21h ; Set interrupt vector
pop ds
ret
set_interrupts ENDP
; Restore interrupts to original state
restore_interrupts PROC
push ds
; Restore user timer interrupt vector to original routine
mov ax, 251ch ; AH=25h (Set interrupt vector)
; AL=1Ch (User timer interrupt vector)
; Set DS:DX to our user interrupt routine
; DS:DX = CS:user_timer_int
mov dx, [cs:int1c_old_ofs]
mov cx, [cs:int1c_old_seg]
mov ds, cx
int 21h ; Set interrupt vector
pop ds
ret
restore_interrupts ENDP
main PROC
mov ax, @data
mov ds, ax ; Initialize the data segment
call set_interrupts
; Reset timer to 0
mov word ptr [cs:timer_tick], 0
sti ; Ensure interrupts are enabled
key_chk_loop:
hlt ; Wait (HLT) until next interrupt occurs
mov ah, 1
int 16h ; AH=1 BIOS Check if keystroke pressed
; ZF flag set if no key pressed, AL=ASCII char pressed
jz no_key ; If no key pressed check if we have timed out
mov ah, 0
int 16h ; AH=0 BIOS get keystroke (removes it from keyboard buffer)
; If a key has been pressed we need to remove it from the
; keyboard buffer with Int 16/AH=0.
cmp al, 'S' ; If a key has been pressed was it 'S'?
je s_in_time ; If so print pressed message and exit
no_key:
; Check if the counter has reached the timeout
cmp word ptr [cs:timer_tick], KBD_TIMEOUT
jb key_chk_loop ; If time out hasn't been reached go back&check kbd again
timed_out:
; Print timed out message and exit
mov ah, 9h
mov dx, offset s_not_in_time_str
int 21h
jmp finished
s_in_time:
; Print success message and exit
mov ah, 9h
mov dx, offset s_in_time_str
int 21h
finished:
; Restore interrupts to original state before returning to DOS
call restore_interrupts
; Exit back to DOS
mov ax, 4c00h
int 21h
main ENDP
; Place the interrupt data in the code segment instead of the data segment
; to simplify the interrupt handler
int1c_old_ofs dw 0 ; Offset of original int 1c vector
int1c_old_seg dw 0 ; Segment of original int 1c vector
timer_tick dw 0 ; Timer tick count (incremented 18.2 times a second)
END main
注意:由于这段代码是在假设这是在DOS下编写的,所以我使用DOS服务Int 21h/AH=35h (DOS get current interrupt vector) and Int 21h/AH=25h(DOS设置中断向量)来替换用户定时器用我们自己的中断,然后在返回 DOS 之前将中断向量恢复到原来的状态。您可以直接用 reading/modifying 实模式中断向量 table 替换那些 DOS 调用。在 DOS 下最好使用 DOS 服务。
有什么方法可以用 xor ah,ah
Enter_Again:
xor ah, ah ; I should put 60 seconds here
int 16h ; The user should press S before 60 seconds
mov bl,al
cmp al,"S"
您不能使用INT16 来设置定时器。 INT16 简单地从键盘读取一个字符。
xor ah, ah 将 ah 寄存器置零,以便调用 INT16 函数 0,读取键盘字符。要获取时间,请检查 INT21,函数 0x2C,获取系统时间。
您之前的问题表明您 运行 在 DOS 下。没有使键盘输入超时的 BIOS 或 DOS 调用。您可以锁定(链)到 Interrupt 0x1c 上,这是一个用户中断例程,每秒调用约 18.2 次。一分钟大约有 1092 个这样的中断。您的计时器中断可以简单地调用旧用户中断,然后增加滴答计数。
然后您的主程序可以检查是否按下了一个键,BIOS 调用 Int 16h/AH=1. If the Zero Flag (ZF) is set by this call no key is present in the keyboard buffer. This call doesn't block waiting for characters, it only checks if the keyboard buffer is empty and if it isn't returns the most recent key without removing it from the buffer. You will want to use Int 16h/AH=0 从键盘缓冲区中删除字符 IF 一个键被按下,然后检查它是否是 S。按下的键的 ASCII 值在寄存器 AL 中。未能从缓冲区中删除字符将不允许您在未来正确检查键盘缓冲区中的下一个字符。
如果您要查找的键没有被按下,那么您只需将当前全局计时器滴答计数与 1092 进行比较。如果没有达到,您返回并再次检查键盘缓冲区中的字符。
此示例代码设置了一个用户定时器中断处理程序,并使用上述基本机制等待 S 被按下。如果超时,程序将退出并显示一条消息。如果在超时到期之前按下 S,程序会打印一条消息,然后退出。在退出回到 DOS 之前,中断向量需要恢复到程序启动时的状态。
.model small
.stack 100h
KBD_TIMEOUT EQU 60*182/10 ; 1092 = ~60 seconds (18.2hz*60)
; Max timer value is 65535 which is approximately
; 3600 seconds (one hour)
.data
s_in_time_str db "'S' pressed within 60 seconds$"
s_not_in_time_str db "'S' NOT pressed within 60 seconds$"
.code
; User timer interrupt handler called by Int 08h
; It occurs approximately every 18.2 times a second
; Upon entry CS is the only register that has an expected value
; CS is the code segment where the interrupt handler and the
; interrupt handler data reside
user_timer_int PROC
; Call (chain) to the original interrupt vector
; by pushing flags register and doing a FAR CALL to old vector
pushf
call dword ptr [cs:int1c_old_ofs]
; Increase timer tick by 1
inc word ptr [cs:timer_tick]
iret
user_timer_int ENDP
; Setup interrupt handlers needed by this program
set_interrupts PROC
push ds
; Hook our timer interrupt handler to the user interrupt timer vector
mov ax, 351ch ; AH=35h (Get interrupt vector)
; AL=1Ch (User timer interrupt vector)
int 21h ; Get interrupt vector
; Int 21h/ah=35 will return interrupt vector address in ES:BX
mov [cs:int1c_old_ofs], bx
mov ax, es
mov [cs:int1c_old_seg], ax
mov ax, 251ch ; AH=25h (Set interrupt vector)
; AL=1Ch (User timer interrupt vector)
; Set DS:DX to our user interrupt routine
; DS:DX = CS:user_timer_int
push cs
pop ds
mov dx, offset user_timer_int
int 21h ; Set interrupt vector
pop ds
ret
set_interrupts ENDP
; Restore interrupts to original state
restore_interrupts PROC
push ds
; Restore user timer interrupt vector to original routine
mov ax, 251ch ; AH=25h (Set interrupt vector)
; AL=1Ch (User timer interrupt vector)
; Set DS:DX to our user interrupt routine
; DS:DX = CS:user_timer_int
mov dx, [cs:int1c_old_ofs]
mov cx, [cs:int1c_old_seg]
mov ds, cx
int 21h ; Set interrupt vector
pop ds
ret
restore_interrupts ENDP
main PROC
mov ax, @data
mov ds, ax ; Initialize the data segment
call set_interrupts
; Reset timer to 0
mov word ptr [cs:timer_tick], 0
sti ; Ensure interrupts are enabled
key_chk_loop:
hlt ; Wait (HLT) until next interrupt occurs
mov ah, 1
int 16h ; AH=1 BIOS Check if keystroke pressed
; ZF flag set if no key pressed, AL=ASCII char pressed
jz no_key ; If no key pressed check if we have timed out
mov ah, 0
int 16h ; AH=0 BIOS get keystroke (removes it from keyboard buffer)
; If a key has been pressed we need to remove it from the
; keyboard buffer with Int 16/AH=0.
cmp al, 'S' ; If a key has been pressed was it 'S'?
je s_in_time ; If so print pressed message and exit
no_key:
; Check if the counter has reached the timeout
cmp word ptr [cs:timer_tick], KBD_TIMEOUT
jb key_chk_loop ; If time out hasn't been reached go back&check kbd again
timed_out:
; Print timed out message and exit
mov ah, 9h
mov dx, offset s_not_in_time_str
int 21h
jmp finished
s_in_time:
; Print success message and exit
mov ah, 9h
mov dx, offset s_in_time_str
int 21h
finished:
; Restore interrupts to original state before returning to DOS
call restore_interrupts
; Exit back to DOS
mov ax, 4c00h
int 21h
main ENDP
; Place the interrupt data in the code segment instead of the data segment
; to simplify the interrupt handler
int1c_old_ofs dw 0 ; Offset of original int 1c vector
int1c_old_seg dw 0 ; Segment of original int 1c vector
timer_tick dw 0 ; Timer tick count (incremented 18.2 times a second)
END main
注意:由于这段代码是在假设这是在DOS下编写的,所以我使用DOS服务Int 21h/AH=35h (DOS get current interrupt vector) and Int 21h/AH=25h(DOS设置中断向量)来替换用户定时器用我们自己的中断,然后在返回 DOS 之前将中断向量恢复到原来的状态。您可以直接用 reading/modifying 实模式中断向量 table 替换那些 DOS 调用。在 DOS 下最好使用 DOS 服务。