Seite 2 von 2 ErsteErste 12
Ergebnis 21 bis 24 von 24

Thema: RS-232 (serielle Schnittstelle) auslesen

  1. #21
    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.

    Geändert von Ineluki (28.09.2006 um 21:53 Uhr)

  2. #22
    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).

    Geändert von derBenny (29.09.2006 um 14:48 Uhr)

  3. #23
    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 ...

  4. #24
    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

    Geändert von derBenny (17.06.2007 um 19:54 Uhr)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •