How to set Timer

廉价感情. 提交于 2020-07-10 05:59:27

问题


Is there any way I can set timer 60 seconds with 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"

回答1:


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.

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.

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.

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

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.




回答2:


You cannot use INT16 to set a timer. INT16 simply reads a character from the keyboard.

xor ah, ah zeros the ah register so that you are calling INT16 function 0, Read Keyboard Character. To get the time, checkout INT21, function 0x2C, Get System Time.



来源:https://stackoverflow.com/questions/55901791/how-to-set-timer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!