如何设置定时器

问题描述 投票:0回答:2

有什么办法,我可以在xor中设置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"
assembly x86 dos x86-16 bios
2个回答
3
投票

您以前的问题表明您在DOS下运行。没有BIOS或DOS调用超时键盘输入。你可以锁定(链)到Interrupt 0x1c,这是一个用户中断例程,每秒调用大约18.2次。一分钟是这些中断中的大约1092个。您的定时器中断可以简单地调用旧用户中断,然后递增滴答计数。

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

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

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

.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=35h(DOS获取当前中断向量)和Int 21h/AH=25h(DOS设置中断向量)来替换用我们自己的用户定时器中断然后恢复中断向量在返回DOS之前回到原始状态。您可以通过直接读取/修改实模式中断向量表来替换这些DOS调用。在DOS下,最好使用DOS服务。


0
投票

您不能使用INT16来设置计时器。 INT16只是从键盘上读取一个字符。

xor啊,啊寄存器啊,这样你就是调用INT16函数0,读取键盘字符。要获得时间,请检查INT21,功能0x2C,获取系统时间。

© www.soinside.com 2019 - 2024. All rights reserved.