Ergebnis 1 bis 20 von 24

Thema: RS-232 (serielle Schnittstelle) auslesen

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Ganz generell wuerde ich dir empfehlen mit NASM zu assemblieren und den weltweiten Pseudostandart zu verwenden.

    Sonst ist es btw doch etwas uebertrieben fuer soetwas ASM zu benuetzen. Such dir lieber einen C-Codefetzen der ueber die API den Port anspricht. So wird es auch fuer dich verstaendlicher, denke ich. Mit Hochsprachen scheinst du ja besser vertraut zu sein.


    Die beiden Links koennten dir dabei eventuell helfen:
    http://msdn.microsoft.com/library/de...sdn_serial.asp
    (Der Umweg ueber CygWin)
    http://www.mingw.org/download.shtml#hdr2

  2. #2
    So, da es eine Gruppenarbeit ist und sich jeder um einen anderen Ansatz zum Auslesen der seriellen Schnittstelle kümmert (damit wir am Ende ein möglichst breites Spektrum an Möglichkeiten zumindest untersucht haben), arbeite ich trotz der gut gemeinten Ratschläge, das Problem mit einer höheren Sprache zu lösen, vorerst weiter mit Assembler (Aber zumindest den vorgeschlagenen Netwide Assembler).

    Ich habe dieses Programm geschrieben:
    Code:
    ; ------------------------------
    ; Empfängt 14 Byte vom Multimeter
    ; an der seriellen Schnittstelle
    ; und gibt sie aus.
    ; ------------------------------
    
    
    segment stapel stack 
      resb 80h ; 128 Byte für den Stack
      ; (auch wenn er hier nicht gebraucht wird)
    
    
    
    segment code
    
    ; ------------------------------
    ; Hauptprogramm
    ; ------------------------------
    
    ..start:
      mov ax, daten
      mov ds, ax
    
      call initialisieren
      call status_ausgeben
      
    
      ; Schleife von 13 bis 0
      ; d.h.: 14 Bytes empfangen (siehe Datenformat)
      ; Datenformat des A-4660-Multimeters:
        ; Byte      1 2 3 4 5 6 7 8 9 A B C D E
        ; Beispiel  D C - 1 . 9 9 9 9       V CR (CR: Zeilenumbruch)
     
      mov cx, 000Dh       
      schleife_auslesen:
        ; Status prüfen
          mov ah, 03h
          mov dx, [com1]
          int 14h
          and ah, 00000001b
          cmp ah, 00000001b ; Wenn Daten vorhanden sind ...
          je empfangen ; ... direkt empfangen, sonst ...
          call d_senden ; ... "D"-Befehl senden.
        empfangen:
          call zeichen_empfangen
          call zeichen_ausgeben
      loop schleife_auslesen
    
    
      ; Beenden
      mov ah, 4Ch
      int 21h
      
    ; Ende des Programmes  
    
    
    
    ; ------------------------------
    ; Unterprogramme
    ; ------------------------------  
      
    initialisieren:
      mov ax, 0000h
      mov dx, [com1]
      mov al, 10100111b
      ; Konfigurationsbyte
        ; Zeichenkodierung: 7 bit >> 10
        ; Stoppbits: 2            >> 1
        ; Parität: None           >> 00
        ; Durchsatz: 9600 bit/s   >> 111
      int 14h
      ret
    
    
    status_ausgeben:
      mov ah, 03h
      mov dx, [com1]
      int 14h
      mov dl, ah
      mov ah, 02h
      int 21h
      ret
    
    
    zeichen_empfangen:
      ; Zeichen empfangen
      mov dx, [com1]
      mov ax, 0000h
      mov ah, 02h
      int 14h
      mov [zeichen], al
      ret
    
    
    zeichen_ausgeben:
      mov dx, [com1]
      mov dl, [zeichen]
      mov ah, 02h
      int 21h
      ret
    
    
    d_senden:
      mov ah, 01h
      mov al, 44h ; ASCII für "D"
      mov dx, [com1]
      int 14h
      ret
      
      
      
    ; ------------------------------
    ; Variablen
    ; ------------------------------
    
    segment daten
      zeichen db 00h  ; Zum Zwischenspeichern eines empfangenen Bytes
      com1 dw 0000h
    Es überprüft, ob an der seriellen Schnittstelle Daten vorhanden sind und gibt sie aus. Wenn keine Daten vorhanden sind, wird der "D"-Befehl an das Gerät geschickt, der nach dem >> Informationsblatt des Gerätes (PDF, ~600 kB), (siehe Seite 3) die Datenübertragung aktivieren soll.

    Allerdings werden neben dem Status der seriellen Schnittstelle keine Daten ausgegeben, sondern nur "D"s, bzw, wie ich inzwischen herausgefunden habe, das, was gerade im AL-Register (und damit wegen einer Zuweisung in der Variable "zeichen") steht, in ASCII. Dabei sollte die Funktion "zeichen_empfangen" eigentlich das an der Schnittstelle vorhandene Zeichen in AL speichern (siehe >> Interrupt 14).

    Ist das Gerät kaputt (die Anzeige am Gerät selber funktioniert noch problemlos und richtig, es ist eben nur ein bischen älter) oder habe ich irgendetwas falsch gemacht?

  3. #3

  4. #4
    Zitat Zitat von Crash-Override
    http://dsdt.info/projekte/internet/?id=35
    vll ist das ja ganz interessant für dich.
    Nun habe ich mich 10 Minuten lang darüber geärgert, dass das Programm nicht funktioniert, bis mir einfiel, dass ich an diesem Computer gar keinen COM-Port habe. -_-
    Naja, das Messgerät ist leider Eigentum der Schule, wo es aus diesem Grund auch momentan steht, aber ich werde das Programm Montag in einer Freistunde mal ausprobieren, um zu sehen, ob das Gerät überhaupt funktioniert. Danke für den Link.

  5. #5
    Um mich etwas genauer mit der Funktionsweise der seriellen Schnittstelle zu beschäftigen und mir nicht bloß von Microsoft und ihrem Interrupt 14h den Arsch hinterhertragen zu lassen habe ich versucht, die serielle Schnittstelle mit einer Anleitung aus dem Internet selber zu initialisieren. Allerdings habe ich Probleme mit einem Assembler-Befehl. Es geht um out.
    Die allgemeine Syntax lautet:
    Code:
    out (Portadresse), (Allgemeines Register)
    Kann mir jemand Folgendes erklären:
    Code:
    Im Register "al" bzw "ah" steht das auszugebende
    Byte, in "dx" die Adresse von COM1.
    
    out dx, al     --> Funktioniert problemlos
    out dx, ah     --> "Invalid combination of opcode and operands"
    Sowohl AL als auch AH sind doch 8-Bit-Register, warum verhalten sie sich dann an dieser Stelle unterschiedlich?


    Damit kann ich allerdings noch leben. Was mir merkwürdig vorkommt ist allerdings, dass folgende Syntax des out-Befehls einen Fehler verursacht:
    Code:
    "com1" hat den Wert 03F8h, die Adresse von COM1.
    
    out [com1], al     --> "Invalid combination of opcode and operands"
    out 03F8h, al     --> "Warning: Unsigned byte value exceeds bounds"

    Geändert von derBenny (17.09.2006 um 10:46 Uhr)

  6. #6
    Out akzeptiert als zweiten Operanden prinzipiell nur al. Das hat vermutlich intern einige Vorteile und man muss sich einfach daran halten. Die Adresse darf, soweit ich weiß, bis 255 als Direktwert angegeben werden. Danach sollte man dafür das dx Register nutzen und und keine Variable.

    freundliche Grüße, Rolus

  7. #7
    Danke, das erwähnen viele Quellen, die ich im Internet gefunden habe, gar nicht.
    [FONT="Courier New"]out [com1], whatever[/FONT] wäre so schön anschaulich gewesen. Dadurch, dass ich nun vorher den zu versendenden Wert an AL und die Port-Adresse an DX senden muss, verdreifacht sich die Schreibarbeit und der Quelltext wird recht unübersichtlich, aber dagegen lässt sich wohl nicht viel machen.

    Gibt es eigentlich irgendeine Möglichkeit, einen Timer unter Assembler einzusetzen? Ich würde die Schleife, die auf Daten von dem Gerät wartet, ganz gerne unterbrechen, wenn nach beispielsweise 2 Sekunden noch keine Daten gesendet worden sind.

  8. #8
    Zitat Zitat von derBenny
    Gibt es eigentlich irgendeine Möglichkeit, einen Timer unter Assembler einzusetzen? Ich würde die Schleife, die auf Daten von dem Gerät wartet, ganz gerne unterbrechen, wenn nach beispielsweise 2 Sekunden noch keine Daten gesendet worden sind.
    Du könntest dir ja selbst einen kleinen Timer schreiben. Wie man die Uhrzeit ausliest etc. dürfte man mit Google schnell finden. Oder du nutzt einen fertigen, wie zum Beispiel den Timer der WinAPI. Am einfachsten wäre es aber, eine Schleife zu schreiben, die immer überprüft, ob ein neues Zeichen da ist, und nur dann vom Port liest, wenn ein neue Wert vorhanden ist.

    freundliche Grüße, Rolus

  9. #9
    Zitat Zitat von Rolus
    Am einfachsten wäre es aber, eine Schleife zu schreiben, die immer überprüft, ob ein neues Zeichen da ist, und nur dann vom Port liest, wenn ein neue Wert vorhanden ist.
    Das habe ich ja getan. Die Schleife bricht im Moment nur dann ab, wenn 14 Bytes von dem Gerät empfangen wurden (14 hängt mit dem Datenformat des Multimeters zusammen). Aber es kann ja auch vorkommen, dass das Gerät aus irgendeinem Grund nichts sendet, dann muss die Schleife nach einer gewissen Zeit auch abgebrochen und eine Fehlermeldung ausgegeben werden. Dafür brauche ich den Timer.

    Naja, ich werde einfach mal suchen, dafür gibt es sicher fertige DOS-Interrupts, die man aufrufen kann. Aber nicht mehr heute. ^^

  10. #10
    Ich habe das von Crash-Override gepostete Programm mal ausprobiert und festgestellt, dass das Gerät funktioniert. Man sendet ein großes "D" und das Gerät gibt die derzeitige Messwertanzeige zurück.
    Mein Programm funktioniert allerdings nicht, es gibt nichts aus und wird einfach kurz nach dem Start beendet (nichteinmal eine halbe Sekunde). Ich habe keine Ahnung, wo der Fehler liegt.
    Die Empfangsschleife wird mehrfach durchlaufen, dass habe ich schon überprüft. Genaueres kann ich nicht sagen, da das Gerät in der Schule steht und ich es hier (zuhause) nicht testen kann.

    Code:
    Der Quellcode ist überholt, ich nehm' ihn mal raus, bevor sich noch jemand die Mühe macht, ihn durchzulesen.
    Nachtrag:
    Ok, ich habe bei der Initialisierung vergessen, die Interrupts richtig einzustellen, das habe ich jetzt geändert (allerdings nicht im obigen Quelltext). Ich werde es morgen erstmal ausprobieren.

    Nachtrag #2:
    Es hat zwar noch nicht funktioniert, aber ich bin auf dem richtigen Weg. ^^

    Geändert von derBenny (21.09.2006 um 18:37 Uhr)

  11. #11
    Ich habe jetzt verschiedene Fehler beseitigt, aber das Programm läuft immernoch nicht. Irgendwas stimmt noch nicht. Ich überprüfe im Programm den Status der seriellen Schnittstelle und bekomme einen Apostroph raus (ASCII-Codierung des Statusbytes). Allerdings gibt es im ASCII-Zeichensatz 4 oder 5 verschiedene Apostrophen, die in meinen Augen alle relativ gleich aussehen, aber eben durch unterschiedliche Bitkombinationen codiert werden. Weiß zufällig jemand, wie ich die einzelnen Bits eines Bytes direkt ausgeben kann?

    Ja, ich bin tatsächlich skrupellos genug für einen tripple post.

    Nachtrag:
    Oh, vergesst es, ist nicht so wichtig. 3 der 5 möglichen Zeichen fallen raus, weil das höchste Bit, das eigentlich immer 0 ist, dann 1 sein müsste. Es gibt also noch zwei mögliche Statusmöglichkeiten:

    00100111 >> Daten vorhanden, Überlauf, Paritätsfehler, Senderegister enthält noch Daten
    01100000 >> Senderegister enthält noch Daten / sendet gerade Daten

    Irgendwie ergibt beides keinen Sinn. ;_;

    Geändert von derBenny (28.09.2006 um 21:05 Uhr)

  12. #12
    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)

Berechtigungen

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