如何设定计时器 [英] How to set Timer

查看:117
本文介绍了如何设定计时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么方法可以使用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"

推荐答案

您先前的问题建议您在DOS下运行.没有BIOS或DOS调用会使键盘输入超时.您可以闩锁(链接)到中断0x1c ,这是用户中断该例程每秒被调用约18.2次.一分钟大约是这些中断的1092.您的计时器中断可以简单地调用旧的用户中断,然后增加滴答计数.

Your previous questions suggest you are running under DOS. There is no BIOS or DOS call that times out keyboard input. You can latch (chain) onto Interrupt 0x1c which is a user interrupt routine that gets called about 18.2 times a second. One minute is about 1092 of these interrupts. Your timer interrupt can simply call the old user interrupt and then increment a tick count.

然后,您的主程序可以检查是否已通过BIOS调用按下了键 Int 16h/AH = 1 .如果通过此调用设置了零标志( ZF ),则键盘缓冲区中没有键.此调用不会阻止等待字符,它只会检查键盘缓冲区是否为空,并且是否不返回最新键,而不会将其从缓冲区中删除.您将要使用 Int 16h/AH = 0 从以下位置删除字符:键盘缓冲区 IF 已被按下,然后检查它是否为 S .按键的ASCII值在寄存器 AL 中.无法从缓冲区中删除字符将使您以后无法正确检查键盘缓冲区中的下一个字符.

Your main program can then check if a key has been pressed with BIOS call 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 to remove the character from the keyboard buffer IF one has been pressed and then check if it was S. The ASCII value of the key pressed is in register AL. Failure to remove the character from the buffer will not allow you to properly check the keyboard buffer in the future for the next character.

如果尚未按下您要查找的键,则只需将当前的全局计时器滴答计数与1092进行比较.如果尚未到达,请返回并再次检查键盘缓冲区中的字符.

If the key you are looking for hasn't been pressed then you simply compare the current global timer tick count with 1092. If it hasn't been reached you go back and check the keyboard buffer again for a character.

此示例代码设置了一个用户计时器中断处理程序,并使用上述基本机制来等待 S 被按下.如果超时,则程序退出并显示一条消息,指出这一点.如果在超时到期前按 S ,程序将显示一条消息,然后退出.在退出DOS之前,必须将中断向量恢复到程序启动时的状态.

This sample code sets up a user timer interrupt handler and uses the basic mechanism described above to wait for S to be pressed. If it times out the program exits with a message indicating that. If S is pressed before the time out expires the program prints a message to that effect and then exits. Before exiting back to DOS the interrupt vectors need to be restored to what they were when the program started.

.model small
.stack 100h

KBD_TIMEOUT EQU 1092            ; 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 = 25h (DOS设置中断向量)用我们自己的用户计时器中断替换,然后将中断向量恢复到其原始状态,然后再返回DOS.您可以通过直接读取/修改实模式中断向量表来替换那些DOS调用.在DOS下,最好使用DOS服务.

Note: Since this code was written with the assumption this was under DOS, I use DOS services Int 21h/AH=35h (DOS get current interrupt vector) and Int 21h/AH=25h (DOS Set Interrupt Vector) to replace the user timer interrupt with our own and then restore the interrupt vector back to its original state before returning to DOS. You could replace those DOS calls by reading/modifying the real mode interrupt vector table directly. Under DOS it is preferable to do it using the DOS services.

这篇关于如何设定计时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆