Timer systemowy

cepa

Timer systemowy zawarty w każdym komputerze PC, generuje standardowo 18,2 razy na sekunde
przerwanie programowe 1CH. Aby je praktycznie wykorzystać (np: w grze), musimy się pod nie
podpiąć zamieniając oryginalny adres procedury przerwania 1CH na adres naszej procedurki.
Aby to zrobić możemy użyć funkcji DOS'a: 25H i 35H. Pierwsza z nich umożliwia zapis wektora
(adresu) procedury przerwania w tablicy przerwań, druga umożliwa odczyt tego adresu.
Ponieważ po zakończeniu programu który przejąłby przerwanie, ustawione przez niego procedury
przerwan nadal działają (co doprowadza do zawieszenia komputera), musimy pod koniec pracy
programu przywrócic adres oryginalnej procedury obsługi przerwania 1CH. Dlatego też ogólny
schemat działania programu wygląda następująco:

  1. pobierz adres oryginalnej procedury obsługi przerwania 1CH
  2. podepnij nową procedure
  3. wykonuj program
  4. przywróc starą procedure

Uwaga ! Jeżeli w procedurze obsługi dowolnego przerwania zamierzasz korzystać ze zmiennych
dostępnych dla całego programu wtedy musisz sie do nich odwołać przez rejestr CS, np:
MOV BYTE [CS:zmienna],10

To będzie na tyle teori, oto przykładowy kod (NASM). Program po uruchomieniu będzie wkołko
wyświetlał napis Timer co taki sam odcinek czasu.

;-------
        CPU 186
        BITS 16


        ORG 100H
        JMP main


timer_int:                                            ; procedura obslugi przerwania 1CH
        STI
        MOV BYTE [CS:can_print],1                     ; ustaw zmienna can_print na 1
        CLI
        IRET


install_timer:
        MOV AX,351CH                                  ; pobierz adres starej procedury
        INT 21H                                       ; przerwania 1CH i wrzuc go do
        MOV [CS:old_timer_int],BX                     ; zmiennej old_timer_int (ES:BX)
        MOV [CS:old_timer_int + 2],ES
        MOV AX,251CH                                  ; ustaw nowa procedure
        MOV DX,timer_int                              ; laduj jej adres do DS:DX
        PUSH DS
        PUSH CS
        POP DS
        INT 21H
        POP DS
        RET


remove_timer:
        MOV AX,251CH                                  ; przywroc stara procedure
        LDS DX,[CS:old_timer_int]
        INT 21H
        RET


main:
        CALL install_timer                            ; instaluj timer
main_loop:
        CMP BYTE [can_print],1                         ; jezeli can_print = 1
        JNE main_loop                                  ; to wyswietl napis "Timer"
        MOV BYTE [can_print],0
        PUSH DS
        PUSH CS
        POP DS
        MOV DX,timer_text
        MOV AH,09H
        INT 21H
        POP DS
        JMP main_loop
exit:
        CALL remove_timer                             ; usun timer (tu nie dojdzie nigdy)
        MOV AX,4C00H
        INT 21H


old_timer_int                          DD 0
timer_text                             DB 'Timer',10,13,'$'
can_print                              DB 0
;-------

3 komentarzy

Dodałem kolorowanie składni :-)

a co jeśli podczas wykonywania programu wystąpi błąd krytyczny i się on wyłączy. Czy wtedy system zawiesi się całkiem, czy przywróci może właściwe "ustawienia" timera ??

to zalezy pewnie od tego co będzie zawierała procedurka timera, jak nie bedzie operowac na duzych zmiennych itp, to pewnie nic sie nie stanie, a w przeciwnym wypadku to reset i po klopocie , zreszta problem dotyczy tylko czystego dosa :P