-
Zu deiner Frage nach den einzelnen Bits abfragen ... sowas macht man idR mit AND und einer Konstanten.
Das AND wird bitweise auf die ganze Zahl angewendet.
Zur Erinnerung: 0 AND 0 = 0, 1 AND 0 = 0; 0 AND 1 = 0; 1 AND 1 = 1
Wenn die verwendete Konstante nun gerade die Zweierpotenz ist, die dein Bit repraesentiert (z.B. 1 SHL 5 = 32 = 00100000b = nur bit 5 gesetzt [merke nullindexiert]) und man diese Konstante mit der Zahl AND verknuepft, dann kommt nur dann ein Ergebniss ungleich 0 raus, wenn das entsprechende Bit gesetzt ist.
10110110b AND
00100000b
00100000b
01011010b AND
00100000b
00000000b
Das geht natuerlich auch, wenn du mehere Bits gleichzeitig abfragen willst. Hierbei treten dann 3 verschiedenen Faelle ein
a) Zahl AND Konstante == Konstante -> alle Bits aus Konstante sind gesetzt
b) Zahl AND Konstante != 0 -> mindestens ein Bit stimmt ueberein, Wert sind die uebereinstimmenden Bits
c) Zahl AND Konstante == 0 -> keines der Bits ist gesetzt.
Und um die Sache komplett zu machen: mit OR kann man Bits in einem Wert setzen und mit XOR abwechselnd an und aus stellen.
-
Joa, die AND-Verknüpfung wende ich in meinem Programm auch mehrfach an. Meine Frage war eher, wie man ein Byte, also zum Beispiel irgendein Statusregister, das einen interessiert, in Form von Einsen und Nullen auf dem Bildschirm ausgeben kann. Ich habe nur Möglichkeiten gefunden, ASCII-Zeichen auszugeben, die durch die Kombination aus Einsen und Nullen im auszugebenden Byte codiert sind.
Ich gebe also das Register, das ich betrachten will, als ASCII-Zeichen aus und erhalte ein Apostroph (oder irgendwas in der Art). Das Problem war nur, dass ich zwischen "acute accent", "accent grave", dem Apostroph, "left single quotation mark" und "right single quotation mark" keinen großen Unterschied entdecken konnte, zumindest nicht in der von DOS verwendeten Schriftart.
Das Problem hat sich aber inzwischen gelöst. Ich muss das Programm ja bloß mit DEBUG Schritt für Schritt ausführen lassen und prüfen, welcher Wert im jeweiligen Register steht.
Hier ist mal der aktuelle Quelltext. Ich habe keine Ahnung, warum es nicht funktioniert.
Code:
; ------------------------------
; Kommunikation mit einem Multimeter
; an der seriellen Schnittstelle
;
; Verwendetes Verfahren: POLLING
; Der Empfangspuffer wird auf
; empfangene Zeichen geprüft und
; gegebenenfalls ausgelesen.
; ------------------------------
segment stapel stack
resb 80h ; 128 Byte für den Stack
segment code
; ------------------------------
; Hauptprogramm
; ------------------------------
..start:
mov ax, daten
mov ds, ax
call initialisieren
call status_out ; Status der seriellen Schnittstelle prüfen (nur Test, wird später entfernt)
call d_senden ; Um Datenübertragung vom Multimeter zu starten
call timer_start
schleife_empfang:
call timer_check
ja ende_schleife ; Wenn mehr als 5 Sekunden nichts empfangen
call zeichen_empfangen_check ; Zeichen im Empfangsregister?
jne schleife_empfang ; Wenn nein, zurück zum Anfang ...
; sonst (wenn Zeichen im Empfangsregister sind)
call zeichen_empfangen
call zeichen_ausgeben
call timer_start
call counter_up_and_check
jb schleife_empfang
; Wird wiederholt, solange noch keine
; 14 Bytes empfangen worden sind
ende_schleife:
; Beenden
mov ah, 4Ch
int 21h
; Ende des Programmes
; ------------------------------
; Unterprogramme
; ------------------------------
; ---------------
initialisieren:
; ---------------
; Empfangsregister auslesen (muss für Initialisierung leer sein)
mov dx, [com1]
in al, dx
; Interrupts ausschalten
mov dx, [com11]
mov al, 00h
out dx, al
mov dx, [com14] ; Modem Control
mov al, 00000011b
; PC betriebsbereit >> .......1
; PC will senden (nicht empfangsbereit) >> ......1.
; Interrupts aus >> ....0...
out dx, al
; Empfangsregister auslesen (doppelt hält besser)
mov dx, [com1]
in al, dx
; DLAB einschalten
mov dx, [com13]
mov al, 10000000b
; DLAB >> 1.......
out dx, al
; Einstellen der Baudrate: 115200/Baudrate(=9600) = 12
; Low Byte = 12
mov dx, [com1]
mov al, 00001100b
out dx, al
; High-Byte = 0
mov dx, [com11]
mov al, 00h
out dx, al
; DLAB ausschalten
mov dx, [com13]
mov al, 00h
out dx, al
; Line Control setzen
mov dx, [com13]
mov al, 00000110b
; Kodierung (7 Bit) >> ......10
; 2 Stopbits >> .....1..
; keine Parität >> ..000...
out dx, al
ret
; ---------------
zeichen_empfangen_check:
; ---------------
mov dx, [com15] ; Line Status
in al, dx
and al, 00000001b
cmp al, 00000001b
; Empfangsregister enthält Daten >> .......1
ret
; ---------------
zeichen_empfangen:
; ---------------
mov dx, [com1]
in al, dx
mov [zeichen], al
ret
; ---------------
zeichen_ausgeben:
; ---------------
mov ah, 02h
mov dl, [zeichen]
int 21h
ret
; ---------------
d_senden:
; ---------------
; Sendet "D" und setzt PC auf empfangsbereit
; PC will ein Zeichen senden
mov dx, [com14]
mov al, 00000011b
out dx, al
; Zeichen ins Senderegister
mov dx, [com1]
mov al, 44h; "D" in ASCII
out dx, al
mov dx, [com15]; Line Status
d_senden_warten_bis_senderegister_leer:
nop
in al, dx
and al, 01100000b
cmp al, 01100000b
jne d_senden_warten_bis_senderegister_leer
; PC auf empfangsbereit setzen
mov dx, [com14]
mov al, 00000001b
out dx, al
ret
; ---------------
timer_start:
; ---------------
; Timer wird auf 0 gesetzt
; 18,2 Erhöhungen pro Sekunde
mov ah, 01h
mov cx, 0000h
mov dx, 0000h
int 1Ah ; Zugriff auf Systemuhr
ret
; ---------------
timer_check:
; ---------------
mov ah, 00h
int 1Ah
; Gibt Timerstand in DX aus
cmp dx, 005Bh ; 5 Sekunden
ret
; ---------------
counter_up_and_check:
; ---------------
; Überprüft, ob schon 14 Bytes empfangen wurden
mov ah, [counter]
inc ah
mov [counter], ah
cmp ah, 0Eh
ret
; ---------------
status_out:
; ---------------
push ax
push dx
mov dx, [com15]
in al, dx
mov dl, al
mov ah, 02h
int 21h
pop dx
pop ax
ret
; ------------------------------
; Variablen
; ------------------------------
segment daten
zeichen db 00h ; Zum Zwischenspeichern eines empfangenen Bytes
counter db 00h ; Zähler
meldung_1: db '!', 13, 10, '$'
com1 dw 03F8h ; Adresse des COM1-Ports / I/O-Register / DLL
com11 dw 03F9h ; Interrupt-Enable-Register (IER) / DLH
com12 dw 03FAh ; Interrupt-ID-Register (IIR)
com13 dw 03FBh ; Line-Control-Register
com14 dw 03FCh ; Modem-Control-Register
com15 dw 03FDh ; Line-Status-Register
com16 dw 03FEh ; Modem Status Register
Ach ja, das Gerät hat nur die Anschlüsse TxD (Senden), RxD (Empfangen), GND (Erdung/Masse), RTS (Request-To-Send, PC will Daten empfangen) und DTR (Data-Terminal-Ready, PC signalisiert, dass er eingeschaltet ist).
-
Wegen der Binaerausgabe ...
Wenn du die einzelnen Bits abfragen kannst, kannst du auch entsprechend eine Kette von Einsen und Nullen auf dem Bildschirm ausgeben. Eine Nette moeglichkeit waere beispielsweise ein Right Shift oder Right Rotate, wobei das ausgeschobene Bit ins Carryflag kommt. Dann koenntest du sowas machen ...
Code:
MOV CX, 8 ; Schleifenzaehler auf 8 bit
MOV AL, Datenbyte ; Da steht das auszugebende Byte drin
:Start_Schleife ; Label fuer die Schleife
RCR AL,1 ; Rotiert nach Rechts durch Ca<rry Flag
JC CarryIsSet ; Wenn CarryFlag 1 ist, springe zur Ausgabe von "1"
CALL SCHREIBE_0 ; Gib eine "0" aus und ruecke Cursor nach rechts
JMP NEXT_LABEL ; Springe ans Ende der Schleife
:CarryIsSet
CALL SCHREIBE_1 ; Gib eine "1" aus und ruecke Cursor nach rechts
:NEXT_LABEL ; Das Ende der Schleife
LOOP Start_Schleife ; Wiederhole Schleife bis alle 8 bit abgearbeitet sind
CALL SCHREIBE_BLANK ; Gib ein Leerzeichen aus und ruecke Cursor nach rechts
Wie du die Unterprogramme/Makros zum Ausgeben der Buchstaben machst, solltest du eigentlich wissen ...
-
Aus irgendeinem Grund hat es sich mein Programm anders überlegt und funktioniert jetzt, dabei bin ich der Meinung, nichts gemacht zu haben. Falls es jemanden interessiert ist hier nochmal der Quelltext des funktionierenden Programms. Es ist zwar sehr speziell an diese eine Aufgabe angepasst, aber mit ausreichend Kommentaren versehen, so dass man es mit ein paar Veränderungen auch für andere Aufgaben umschreiben könnte.
Code:
; ------------------------------
; Kommunikation mit einem Multimeter
; an der seriellen Schnittstelle
;
; Verwendetes Verfahren: POLLING
; Der Empfangspuffer wird auf
; empfangene Zeichen geprüft und
; gegebenenfalls ausgelesen.
;
; ------------------------------
segment stapel stack
resb 80h ; 128 Byte für den Stack
; ------------------------------
; Variablen
; ------------------------------
segment daten
zeichen: resb 1 ; Zum Zwischenspeichern eines empfangenen Bytes
datei_name: db 'messwert.dat'
datei_handle: resb 1
messwert: times 56 db 'x'
counter: db 00h ; Zähler
com1 dw 03F8h ; Adresse des COM1-Ports / I/O-Register / DLL
com11 dw 03F9h ; Interrupt-Enable-Register (IER) / DLH
com12 dw 03FAh ; Interrupt-ID-Register (IIR)
com13 dw 03FBh ; Line-Control-Register
com14 dw 03FCh ; Modem-Control-Register
com15 dw 03FDh ; Line-Status-Register
com16 dw 03FEh ; Modem Status Register
segment code
; ------------------------------
; Hauptprogramm
; ------------------------------
..start:
; Das Segment "daten" als Datensegment festlegen
; (da liegen unsere Variablen)
mov ax, daten
mov ds, ax
call initialisieren
call d_senden
call timer_start
schleife_empfang:
; Wird wiederholt, solange noch keine
; 14 Bytes empfangen worden sind
call timer_check
ja ende_schleife ; Wenn mehr als 5 Sekunden nichts empfangen
call zeichen_empfangen_check ; Zeichen im Empfangsregister?
jne schleife_empfang ; Wenn nein, zurück zum Anfang ...
; sonst (wenn Zeichen im Empfangsregister sind)
call zeichen_empfangen
call zeichen_in_string_speichern
call zeichen_ausgeben
call timer_start
call counter_up_and_check
jb schleife_empfang
ende_schleife:
call string_in_datei_schreiben
; Beenden
mov ah, 4Ch
int 21h
; Ende des Programmes
; ------------------------------
; Unterprogramme
; ------------------------------
; ---------------
initialisieren:
; ---------------
; Empfangsregister auslesen (muss für Initialisierung leer sein)
call zeichen_empfangen
; Interrupts ausschalten
mov dx, [com11]
mov al, 00h
out dx, al
mov dx, [com14] ; Modem Control
mov al, 00000011b
; PC betriebsbereit >> .......1
; PC will senden (nicht empfangsbereit) >> ......1.
; Interrupts aus >> ....0...
out dx, al
; DLAB einschalten
mov dx, [com13]
mov al, 10000000b
; DLAB >> 1.......
out dx, al
; Einstellen der Baudrate: 115200/Baudrate(=9600) = 12
; Low Byte = 12
mov dx, [com1]
mov al, 00001100b
out dx, al
; High-Byte = 0
mov dx, [com11]
mov al, 00h
out dx, al
; DLAB ausschalten
mov dx, [com13]
mov al, 00h
out dx, al
; Line Control setzen
mov dx, [com13]
mov al, 00000110b
; Kodierung (7 Bit) >> ......10
; 2 Stopbits >> .....1..
; keine Parität >> ..000...
out dx, al
ret
; ---------------
d_senden:
; ---------------
; Sendet "D" und setzt PC auf empfangsbereit
; PC will ein Zeichen senden
mov dx, [com14]
mov al, 00000011b
out dx, al
; Zeichen ins Senderegister
mov dx, [com1]
mov al, 44h; "D" in ASCII
out dx, al
mov dx, [com15]; Line Status
d_senden_warten_bis_senderegister_leer:
nop
in al, dx
and al, 01100000b
cmp al, 01100000b
jne d_senden_warten_bis_senderegister_leer
; PC auf empfangsbereit setzen
mov dx, [com14]
mov al, 00000001b
out dx, al
ret
; ---------------
zeichen_empfangen_check:
; ---------------
mov dx, [com15] ; Line Status
in al, dx
and al, 00000001b
cmp al, 00000001b
; Empfangsregister enthält Daten >> .......1
ret
; ---------------
zeichen_empfangen:
; ---------------
mov dx, [com1]
in al, dx
mov [zeichen], al
ret
; ---------------
zeichen_ausgeben:
; ---------------
mov ah, 02h
mov dl, [zeichen]
int 21h
ret
; ---------------
zeichen_in_string_speichern:
; ---------------
mov bx, messwert
mov ax, [counter]
add bx, ax
; Zeichen
mov al, [zeichen]
; Zeichen in String speichern
mov byte [ds:bx], al
ret
; ---------------
string_in_datei_schreiben:
; ---------------
; Datei erstellen
mov ah, 3Ch ; Erstellen
lea dx, [datei_name]
int 21h
; Datei öffnen
mov ah, 3Dh ; Öffnen
mov al, 01h ; Zugriffsmodus, nur schreiben
lea dx, [datei_name]
int 21h
mov [datei_handle], ax
; Datei beschreiben
mov ah, 40h ; Schreiben
mov bx, [datei_handle]
mov cx, 38h ; 56 Zeichen (eine Messung)
mov dx, messwert ; Offset von messwert
; Datei schließen
mov ah, 3Eh ; Schließen
mov bx, [datei_handle]
int 21h
ret
; ---------------
timer_start:
; ---------------
; Timer wird auf 0 gesetzt
; 18,2 Erhöhungen pro Sekunde
mov ah, 01h
mov cx, 0000h
mov dx, 0000h
int 1Ah ; Zugriff auf Systemuhr
ret
; ---------------
timer_check:
; ---------------
mov ah, 00h
int 1Ah
; Gibt Timerstand in DX aus
cmp dx, 005Bh ; 5 Sekunden
ret
; ---------------
counter_up_and_check:
; ---------------
; Überprüft, ob schon 14 Bytes empfangen wurden
mov ah, [counter]
inc ah
mov [counter], ah
cmp ah, 0Eh ; 14 Bytes empfangen?
ret
Jetzt versuche ich noch, das Ganze interruptgesteuert ablaufen zu lassen, das wäre natürlich etwas eleganter. Um das Ganze zu testen habe ich erstmal versucht, bei Tastatureingabe bzw. dem entsprechenden Interrupt eine bestimmte Aktion auszuführen, aber irgendwie funktioniert es nicht. Weiß vielleicht jemand, woran es liegen könnte? Ich habe inzwischen rausgefunden, dass offensichtlich irgendwas schiefläuft, während ich die Speicheradresse meiner Interrupt-Service-Routine in die Interrupt-Vektor-Tabelle schreibe. Es funktioniert aber auch nicht, wenn ich die vorgefertigten Funktionen dafür benutze, das habe ich schon ausprobiert.
Code:
; ------------------------------
; Interrupt-Test
;
; Bei Tastatureingabe wird eine
; eigene Interruptroutine vor der
; Standard-ISR aufgerufen
; ------------------------------
segment daten
alter_iv: resb 4 ; 4 Byte für alten Interrupt-Vektor
segment code
..start:
mov ax, daten
mov ds, ax
call iv_ersetzen
call timer_start
; 5 Sekunden warten
; Zeit zum Ausprobieren
schleife:
nop
nop
nop
call timer_check
jb schleife
; Beenden
mov ah, 4Ch
int 21h
; ---------------
iv_ersetzen:
; ---------------
; Alten IV speichern
xor ax, ax
mov es, ax
mov bx, 0024h
mov ax, word [es:bx]
mov word [alter_iv], ax
mov ax, word [es:bx+2]
mov word [alter_iv+2], ax
; Neuen IV in Tabelle eintragen
xor ax, ax
mov es, ax
mov bx, 0024h
cli
mov word [es:bx], cs
lea ax, [neue_isr]
mov word [es:bx+2], ax
sti
ret
; ---------------
neue_isr:
; ---------------
pushf
pusha
push es
; Eigene ISR
in al, 60h ; Eingegebenes Zeichen (Scancode)
mov bx, 0B800h
mov es, bx ; ES auf den Bildschirmspeicher
mov bx, 0000h ; Erstes Zeichen, oben links vermutlich
mov byte [es:bx], al
pop es
popa
; Alte ISR
call far dword [alter_iv]
iret
; ---------------
timer_start:
; ---------------
; Timer wird auf 0 gesetzt
; 18,2 Erhöhungen pro Sekunde
mov ah, 01h
mov cx, 0000h
mov dx, 0000h
int 1Ah ; Zugriff auf Systemuhr
ret
; ---------------
timer_check:
; ---------------
mov ah, 00h
int 1Ah
; Gibt Timerstand in DX aus
cmp dx, 005Bh ; 5 Sekunden
ret