Как установить таймер - PullRequest
       100

Как установить таймер

0 голосов
/ 29 апреля 2019

Есть ли способ, я могу установить таймер 60 секунд в xor ах, ах

 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"

Ответы [ 2 ]

3 голосов
/ 30 апреля 2019

Ваши предыдущие вопросы предполагают, что вы работаете под DOS.Нет вызова BIOS или DOS, который прерывает ввод с клавиатуры.Вы можете фиксировать (цепочку) на Прерывание 0x1c , которое является пользовательской процедурой прерывания, которая вызывается примерно 18,2 раза в секунду.Одна минута - это около 1092 таких прерываний.Ваше прерывание по таймеру может просто вызвать старое пользовательское прерывание, а затем увеличить счетчик тиков.

Ваша основная программа может затем проверить, была ли нажата клавиша с вызовом BIOS Int 16h / AH = 1 ,Если в этом вызове установлен нулевой флаг ( ZF ), то в буфере клавиатуры нет клавиши.Этот вызов не блокирует ожидание символов, он только проверяет, пуст ли буфер клавиатуры и возвращает ли он самый последний ключ без удаления его из буфера.Вам нужно будет использовать Int 16h / AH = 0 , чтобы удалить символ из буфера клавиатуры IF , один из которых был нажат, а затем проверить, был ли он 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 Set Interrupt Vector) для замены прерывания таймера пользователя нанаш собственный, а затем восстановить вектор прерывания обратно в исходное состояние, прежде чем вернуться в DOS.Вы можете заменить эти вызовы DOS, читая / изменяя таблицу векторов прерываний реального режима напрямую.Под DOS предпочтительно делать это с помощью служб DOS.

0 голосов
/ 30 апреля 2019

Вы не можете использовать INT16 для установки таймера.INT16 просто читает символ с клавиатуры.

xor ах, ну ну регистр ах, так что вы вызываете функцию INT16 0, чтение символа клавиатуры.Чтобы получить время, проверьте INT21, функцию 0x2C, Get System Time.

...