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
    Zitat Zitat von Codec
    Naja, wenn er 'ne permanente While-Schleife hat, die die Daten ausliest, dann geht da schon
    was. Ich halte PHP hier allerdings für extrem unangebracht und würde eher auf Python, Perl
    oder C zurückgreifen.

    Mit wconsd (Directlink zum Download) kannst du die serielle Schnittstelle (unter Windows)
    an einen Netzwerksocket binden, vllt. hilft dir das in irgendeiner Weise.

    Ich weis nicht ob du unter Linux mit PHP das serielle Interface direkt auslesen kannst,
    aber wie bereits gesagt, schätz ich mal, dass du ein eigenes Modul für PHP schreiben müsstest.

    Insofern PHP ihrem Einsatzort gerecht werden mag, waere ein Script immer von einer angemessenen Timeout-Zeit beschraenkt.

  2. #2
    Zitat Zitat von Mog
    Insofern PHP ihrem Einsatzort gerecht werden mag, waere ein Script immer von einer angemessenen Timeout-Zeit beschraenkt.
    Schmarrn, set_time_limit(0);

    Geändert von Dingsi (01.09.2006 um 13:17 Uhr)

  3. #3
    Zitat Zitat von Fu

    rofl. PHP ist einfach nur schwachsinnig. xD


    Ruby rockt. :P


    In dem fall wuerde ich aber auch schauen inwiefern ich Speicher allokiere und freigebe. Ich denke nicht, dass PHP da einen sehr effizienten GC hat.

    Geändert von Mog (01.09.2006 um 13:36 Uhr)

  4. #4
    Danke, die Vorschläge klingen ganz brauchbar (wenn auch nach viel Arbeit ;_;).

    Ich habe gestern entdeckt, dass es bei Assembler mit dem Interrupt 14h möglich ist, direkt auf die serielle Schnittstelle zuzugreifen. Ich habe, um das erstmal auszuprobieren, folgendes Programm geschrieben:

    Code:
    ; ************************************
    ; Auslesen der seriellen Schnittstelle
    ; ************************************
    
    daten segment
      signal db 0 ; Variable Signal, 1 Byte groß
    daten ends
    
    stapel segment byte stack
      dw 128 dup(?)
    stapel ends
    
    code segment
    assume cs:code,ds:daten,es:nothing,ss:stapel
    
    start:
      ; Serielle Schnittstelle initialisieren
      mov ah, 00h
      mov dx, 00h ; Nummer der Schnittstelle (0: COM1)
      int 14h
      
      ; Zeichen empfangen
      mov ah, 02h
      mov dx, 00h
      int 14h
      
      ; Zeichen in "signal" speichern
      mov [signal], al
      
      ; Ausgabe
      mov ax, daten
      mov ds, ax
      mov dx, offset [signal]
      
      mov ah,9h
      int 21h
    
      mov ah,4ch
      int 21h
    
    code ends
    
    end start
    Das Programm soll ein Zeichen (8 Bit) aus der seriellen Schnittstelle (in diesem Fall COM1) auslesen (landet in AL), das Zeichen unter der Variablen "signal" speichern und diese dann ausgeben.

    Weil ich an diesem Computer keine seriellen Schnittstellen habe, habe ich es am Computer meiner Eltern probelaufen lassen. Allerdings wurde nicht wie erwartet ein Zeichen ausgegeben (schließlich habe ich "signal" ja nur den 8 Bit großen Inhalt von AL übergeben), sondern mehrere Zeilen wilder ASCII-Zeichen.

    Als ich das Programm mit DEBUG Schritt für Schritt ausgeführt habe, habe ich allerdings andere Zeichen ausgegeben bekommen, darunter sogar ein wenig Klartext, der mir verriet, dass der COM-Port bereit ist.

    Kennt sich vielleicht jemand etwas besser mit Assembler aus und kann mir sagen, wo diese ganzen ASCII-Zeichen herkommen? (Eigentlich wollte ich ja zunächst nur ein einzelnes Zeichen empfangen.)

  5. #5
    Hm, TASM. Also INT 21h mit AH=9 gibt eine $-terminierte Zeichenkette aus (also werden solange Zeichen ausgegeben, bis im Speicher ein $ steht). Zum Ausgeben eines einzelnen Zeichens sollte AH auf 2 gesetzt werden und das Zeichen muss sich in DL befinden. Also etwa so:
    Code:
      ; Ausgabe
      mov dl, [signal]
      mov ah,2h
      int 21h
    Ob du das Gerät richtig ansprichst, kann ich dir aufgrund mangelnder Produktinformationen aber nicht sagen. Eventuell solltest du aber überprüfen, ob die Schnittstelle erfolgreich initialisiert wurde.

    freundliche Grüße, Rolus

  6. #6
    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

  7. #7
    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?

  8. #8

  9. #9
    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.

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

  11. #11
    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

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

Berechtigungen

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