Ergebnis 1 bis 20 von 24

Thema: RS-232 (serielle Schnittstelle) auslesen

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #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
  •