home *** CD-ROM | disk | FTP | other *** search
- ;***********************************************************
- ;* ZEIT.ASM: ZEIT-MESSUNGEN MIT DEM TIMER 8253 *
- ;* (c) 1991 toolbox & Peter Monadjemi *
- ;***********************************************************
- .MODEL SMALL
-
- TIMER0_DATA EQU 40h
- TIMER_MODUS EQU 43h
- MODUS_8259 EQU 20h
-
- WARTEN MACRO ; Kleine Verzögerung für das Umschalten
- JMP $+2 ; auf die einzelnen Portregister
- JMP $+2
- JMP $+2
- ENDM
- .DATA
-
- SAVE_FLAGS DW ? ; Hier werden die Flags zwischengesp.
- TIMER_STAND DW ? ; Anzahl der gemessenen Timerimpulse
- REF_STAND DW ? ; Vergleichswert
- TIMER_OVERFLOW DB ? ; Überlaufflag falls Zeitsspanne > 54 ms
-
- TEXT1 DB 0Dh,0Ah,'Gemessene Zeit: '
- ZAEHLER_ADR DB 5 DUP(?)
- DB ' Mikrosekunden.', 0dh, 0ah,'$'
-
- TEXT2 DB 'Timer - Überlauf, weil gemessener '
- DB 'Zeitraum zu groß !',0Dh,0Ah,'$'
-
- .CODE
- PUBLIC TIMER_START, TIMER_STOP, TIMER_READ
-
- TIMER_START PROC
-
- PUSH AX ; Zunächst AX retten
- PUSHF ; dann die Flags nach AX
- POP AX ; um sie von dort
- MOV SAVE_FLAGS,AX ; zwischenzuspeichern
- STI ; Interrupts wieder zulassen
- MOV AL,34h ; Timer-Modus 2 setzen
- OUT TIMER_MODUS,AL
- WARTEN ; Kurze Verzögerung
- XOR AL,AL ; Timer0 auf Null setzen
- OUT TIMER0_DATA,AL ; Zuerst das niederwertige
- WARTEN ; Kurze Verzögerung
- OUT TIMER0_DATA,AL ; dann das höherwertige Byte
-
- WARTEN ; Kurze Verzögerung
-
- CLI ; Keine Interrupts bitte
- MOV AL,34h ; Timer wieder aktivieren
- OUT TIMER_MODUS,AL ; d.h. in Modus 2 schalten
- WARTEN ; Kurze Verzögerung
- XOR AL,AL ; Timer 0 wie gehabt auf Null setzen
- OUT TIMER0_DATA,AL
- WARTEN
- OUT TIMER0_DATA,AL
- POP AX ; Interruptflag und AX wiederholen
- RET ; Rückkehr zum Messprogramm
- TIMER_START ENDP
-
- TIMER_STOP PROC ; Timer ausschalten
- PUSH AX ; AX retten
- PUSH CX ; CX retten
- MOV AL,0 ; Timer einfrieren
- OUT TIMER_MODUS,AL ; dazu Bit 4,5 auf Null
- MOV AL,0Ah ; 8259A auf Auftreten
- OUT MODUS_8259,AL ; eines Interrupts checken
- WARTEN ; Kurze Verzögerung
-
- IN AL,MODUS_8259 ; Trat Interrupt wegen
- ; Überlauf auf?
- AND AL,01h ; Ergebnis, d.h. Bit 0
- MOV TIMER_OVERFLOW,AL ; in einer Variablen speichern
-
- STI ; Interrupts wieder zulassen
- IN AL,TIMER0_DATA ; Timer0 einlesen
- WARTEN ; Kurze Verzögerung
- MOV AH,AL ; Erst das niederwertige Byte
- IN AL,TIMER0_DATA ; dann das höherwertige Byte
- XCHG AH,AL
- NEG AX ; Differenz berechnen
- MOV TIMER_STAND,AX ; und abspeichern
-
- MOV REF_STAND,0 ; Referenzzähler auf Null
- MOV CX,32 ; 32 Leer-Durchläufe
- CLI ; Auch hier keine Interrupts
- L1:
- CALL REF_TIMER_EIN ; Timer0 einschalten
- CALL REF_TIMER_AUS ; Timer0 ausschalten
- LOOP L1 ; das ganze 32 Mal
-
- STI ; Wieder Interrupts erlaubt
- ADD REF_STAND,16 ; Mittelwert bilden: +0.5
- MOV CL,5 ; dann Speichervariable
- SHR REF_STAND,CL ; durch 32 teilen
- MOV AX,REF_STAND ; Referenzwert nach AX und
- SUB TIMER_STAND,AX ; von gemessener Zeit abziehen
-
- MOV AX,SAVE_FLAGS ; Die alten Flags wiederholen
- PUSH AX ; Flagregister zurück
- POPF
-
- POP CX ; Register wiederholen
- POP AX
- RET
- TIMER_STOP ENDP
-
- REF_TIMER_EIN PROC ; Referenztimer-Modul
- PUSH AX
- PUSHF
- MOV AL,34h ; Timer einschalten
- OUT TIMER_MODUS,AL
- WARTEN
- XOR AL,AL ; und auf Null setzen
- OUT TIMER0_DATA,AL
- WARTEN
- OUT TIMER0_DATA,AL
- POPF
- POP AX
- RET
- REF_TIMER_EIN ENDP
-
- REF_TIMER_AUS PROC
- PUSH AX
- PUSHF
- MOV AL,0 ; Timer wieder ausschalten
- OUT TIMER_MODUS,AL
- WARTEN
- IN AL,TIMER0_DATA ; Zählerstand ablesen
- WARTEN
- MOV AH,AL
- IN AL,TIMER0_DATA
- XCHG AH,AL
- NEG AX
- ADD REF_STAND,AX ; Auf Referenzzähler addieren
- POPF
- POP AX
- RET
- REF_TIMER_AUS ENDP
-
- TIMER_READ PROC ; Ausgabe des Zählerstandes
- PUSHF ; Register retten
- PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH DI
-
- CMP TIMER_OVERFLOW,0; Trat Überlauf auf?
- JZ PRINT_ZEIT ; Nein, dann Zeit anzeigen
- MOV DX,OFFSET TEXT2 ; Ansonsten Fehlermeldung
- MOV AH,09
- INT 21h
- JMP SHORT ENDE
-
- PRINT_ZEIT:
- MOV AX,TIMER_STAND ; Zählerstand nach AX
- MOV DX,8381 ; in Mikrosek. umrechnen
- MUL DX
- MOV BX,10000
- DIV BX
-
- MOV BX,10 ; und nacheinander jede Ziffer
- MOV DI,5 ; in den Puffer ZAEHLER_ADR
- L2: ; eintragen
- XOR DX,DX ; DX auf Null setzen
- DIV BX ; Letzte Ziffer abtrennen
- ADD DL,'0' ; In ASCII-Code umwandeln
- MOV ZAEHLER_ADR-1[DI],DL
- DEC DI ; Zähler minus eins
- CMP DI,0 ; Schon Null?
- JNE L2 ; Nein, dann weiter
-
- MOV AH,09 ; Text ist jetzt im Puffer
- MOV DX,OFFSET TEXT1 ; daher ges.Text ausgeben
- INT 21h
-
- ENDE:
- POP DI ; Register wieder herstellen
- POP DX
- POP CX
- POP BX
- POP AX
- POPF
- RET
- TIMER_READ ENDP
- END
- ;***********************************************************
- ;* Ende von ZEIT.ASM *