Daten über RS232 empfangen



  • Hallo,

    Ich möchte über die Serielle Schnittstelle Schalterzustände abfragen können. Dazu habe ich das RS-232-I/O-Board IO 88 von ELV. Hardwaremässig läuft auch alles (getestet mit dem dazugehöhrigen Testprogramm). Die Serial.h Datei habe ich auch im Projektverzeichnis. Das ganze programmiere ich auf dem Bloodsheed dev c++ compiler. Nun habe ich aber probleme die Daten auszulesen (habe auch nicht sooovile kentnisse im programmieren 😉 )
    Ich dachte mit dem Befehl "CharVomPortLesen ();" könnte ich die Daten empfangen, aber bei mir kommt da nichts raus.

    Ich hoffe jemand kann mir auf die Sprünge helfen. Thanks Sonic

    meine serial.h

    /*
     *  serial.h -- kleine Bibliothek fuer die Ein-/Ausgabe auf den seriellen Port
     */
    
    #ifndef _SERIAL_H
    #define _SERIAL_H
    
    #include <stdio.h>
    #include "windows.h"
    
    #define PORTNAME  "COM1"
    #define BAUDRATE  9600
    #define BYTESIZE  8
    #define PARITY    NOPARITY
    #define STOPBITS  ONESTOPBIT
    
    void *port;
    
    /*
     * portInitalisieren() -- der Port wird mit den Grundeinstellungen initalisiert 
     */
    void portInitalisieren()
      {
      DCB dcbConfig;
    
      // Port oeffnen
      port = CreateFile(
        PORTNAME,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);
    
      if (port == INVALID_HANDLE_VALUE)
        {
        printf("Fehler beim Oeffnen des Ports\n");
        exit(-1);
        }
    
      // Parameter des Port holen
      if (GetCommState(port, &dcbConfig))
        {
        dcbConfig.BaudRate = BAUDRATE;
        dcbConfig.ByteSize = BYTESIZE;
        dcbConfig.Parity = PARITY;
        dcbConfig.StopBits = STOPBITS;
        dcbConfig.fBinary = TRUE;
        dcbConfig.fParity = TRUE;
        }
      else
        {
        printf("Fehler beim Holen der Konfiguration\n");
        exit(-1);
        }
    
      // Parameter des Port setzen
      if (!SetCommState(port, &dcbConfig))
        {
        printf("Fehler beim Setzen der Konfiguration\n");
        exit(-1);
        }
      }
    
    /*
     * charVomPortLesen() -- liest ein Character vom Port
     */
    char charVomPortLesen()
      {
      char zeichen;
      DWORD eventMask;
      DWORD anzImBuffer;
    
      // Setzen der CommMask
      if (!SetCommMask(port, EV_RXCHAR))
        {
        printf("Fehler beim Setzen der CommMaske\n");
        exit(-1);
        }
    
      // Warten auf CommEvent
      if (WaitCommEvent(port, &eventMask, NULL))
        {
        // Lesen bis was kommt
        do
          {
          ReadFile(port, &zeichen, 1, &anzImBuffer, NULL);
          } while (anzImBuffer == 0);
        }
      else
        {
        printf("Fehler beim Warten auf CommEvent\n");
        exit(-1);
        }
    
      return zeichen;
      }
    
    /*
     * charAufPortSchreiben() -- schreibt ein Character auf den Port
     */
    void charZumPortSchreiben(char zeichen)
      {
      unsigned long anzGeschrieben;
    
      if (WriteFile(port, &zeichen, 1, &anzGeschrieben, NULL) == 0)
        {
        printf("Fehler beim Schreiben auf Port\n");
        exit(-1);
        }
      }
    
    #endif
    


  • Dieser Thread wurde von Moderator/in c.rackwitz aus dem Forum ANSI C in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Das Programmieren der seriellen Schnittstelle ist nicht ganz einfach und ich Rate Dir zu einer fertigen Klasse... oder wenn Du es doch unbedingt selber machen willst, kannst Du es dort zumindest abschauen wie es geht:
    http://www.codeproject.com/system/serial.asp



  • Die do-while-Schleife sollte so aussehen:

    DWORD         dwSetMask = EV_RXCHAR | EV_ERR; 
    DWORD         dwEvtMask; 
    OVERLAPPED    o;
    
    memset (&o, 0, sizeof (OVERLAPPED)); // Struktur mit 0en füllen
    o.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); // einen Event setzten
    
    SetCommMask (hCom, dwSetMask); // Empfangssignale definieren
    
    do  // in Endlos-Schleife auf Empfangssignale warten:
    {
        WaitCommEvent (hCom, &dwEvtMask, &o); // Event mit Empfangssignalen verknüpfen
        if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) // warten bis Event
        {
            if (dwEvtMask & EV_RXCHAR) // Zeichen an RxD empfangen:
            {
                bRet = ReadFile (hCom, &InString, sizeof (InString), &dwRead, NULL);
                if (!bRet)
                { // Fehlerausgabe:
                    LPVOID lpMsgBuf;
                    FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
                    FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                    (LPTSTR) &lpMsgBuf, 0, NULL);
                    MessageBox (NULL, (LPCTSTR)lpMsgBuf, "Error: ReadFile", 
                                MB_OK | MB_ICONINFORMATION);
                    LocalFree (lpMsgBuf);
                }
                else
                { // Ausgabe (oder Verarbeitung) der empfangenen Bytes:
                    // ...
                }
            }
            if (dwEvtMask & EV_ERR) 
            {
                MessageBox (NULL, "Error empfangen", "Error: ReadFile", MB_OK);
                break; // Schleifen-Abbruch
            }
        }
    }
    while (1);
    

    CommTimeOuts und BufferSize setzen ist auch nicht verkehrt:

    SetCommTimeouts (hCom, &ct);
    // Zwischenspeicher des serial-Drivers einstellen (für read und write):
    SetupComm (hCom, COM_BUFFER_SIZE, COM_BUFFER_SIZE);
    

    Das sind nur Code-Schnipsel aus einem kleinen Projekt, anpassen musst Du sie selber.

    Die Empfangs-Schleife sollte in einem eigenen Thread laufen, sonst muss man die Funktion char charVomPortLesen() dauernd aufrufen.

    "serial.h", wozu braucht man die?

    Blackbird



  • Danke erstmal für die Unterstützung, das Ziel soll sein dass ich 4 Schalterstellungen über die Schnittstelle einlesen kann und die dann in einem Textfile protokolliere.

    "serial.h", wozu braucht man die?

    Blackbird

    Zum den Com1 konfigurieren, kann man das einfacher lösen ?

    Gruss Sonic



  • Deine Funktion void portInitalisieren() braucht keine "serial.h". Alle Prototypen und defines werden von "windows.h" includiert.
    Vielleicht solltest Du statt void doch das HANDLE (der COM-Schnittstelle) zurueckgeben?

    Wenn Dein Programm ein Windows-Programm sein soll, so brauchst Du folgende Funktionen:

    int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd); // Windows erstellt damit ein Fenster

    LRESULT CALLBACK WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // die Prozedur, in der alle Nachrichten, auch Deine selbstdefinierten, auflaufen ... Auch kann hier eine Listbox erstellt werden. Ein Timer koennte im Sekundentakt die IO88 abfragen.

    DWORD WINAPI ComThread (LPVOID lpParam); // ein Thread, der die COM oeffnet und eventgesteuert serielle Daten einliest.

    Die Namen und Parameter der Thread-Funktion sind nur Beispiel. Deine Funktion portInitalisieren() und mein Code-Schnipsel koennen Teil dieser Thread-Funktion sein.
    Dieser Thread sendet alle empfangenen Bytes mit SendMessage zur Editbox.

    Mehr ist nicht zu tun, der teufel steckt aber im detail.

    Blackbird



  • Hab mich mal in das Thema noch mehr vertieft und jetzt ist mir auch einiges klarer geworden, hab auch noch andere Klassen im Netz gefunden. Aber ich habe immer noch Probleme beim abfragen der Daten. Für das Interface gibt es spezielle Befehlssätze.

    Beschreibung hier:
    http://www.elv-downloads.de/service/manuals/IO88/472-69.asp?&%1

    mir ist aber nicht ganz klar wie ich die einbinden muss.

    Gruss Sonic



  • So, hab nochmal ein bisschen gearbeitet, aber funktionieren tuts immer noch nicht 😞

    /* 
    *  serial.h -- kleine Bibliothek fuer die Ein-/Ausgabe auf den seriellen Port 
    */ 
    
    #ifndef _SERIAL_H 
    #define _SERIAL_H 
    
    #include <stdio.h> 
    #include "windows.h" 
    
    #define PORTNAME  "COM1" 
    #define BAUDRATE  9600 
    #define BYTESIZE  8 
    #define PARITY    EVENPARITY 
    #define STOPBITS  ONESTOPBIT 
    
    void *port; 
    
    /* 
    * portInitalisieren() -- der Port wird mit den Grundeinstellungen initalisiert 
    */ 
    
    void portInitalisieren() 
      { 
      DCB dcbConfig; 
    
      // Port oeffnen 
      port = CreateFile( 
        PORTNAME, 
        GENERIC_READ | GENERIC_WRITE, 
        0, 
        NULL, 
        OPEN_EXISTING, 
        0, 
        NULL); 
    
      if (port == INVALID_HANDLE_VALUE) 
        { 
        printf("Fehler beim Oeffnen des Ports\n"); 
        exit(-1); 
        } 
    
      // Parameter des Port holen 
      if (GetCommState(port, &dcbConfig)) 
        { 
        dcbConfig.BaudRate = BAUDRATE; 
        dcbConfig.ByteSize = BYTESIZE; 
        dcbConfig.Parity = PARITY; 
        dcbConfig.StopBits = STOPBITS; 
        dcbConfig.fBinary = TRUE; 
        dcbConfig.fParity = TRUE; 
        } 
      else 
        { 
        printf("Fehler beim Holen der Konfiguration\n"); 
        exit(-1); 
        } 
    
      // Parameter des Port setzen 
      if (!SetCommState(port, &dcbConfig)) 
        { 
        printf("Fehler beim Setzen der Konfiguration\n"); 
        exit(-1); 
        } 
      } 
    
    /* 
    * byteVomPortLesen() -- liest ein Character vom Port 
    */ 
    
    byte byteVomPortLesen() 
      { 
      byte zeichen; 
      DWORD eventMask; 
      DWORD anzImBuffer; 
    
      // Setzen der CommMask 
      if (!SetCommMask(port, EV_RXCHAR)) 
        { 
        printf("Fehler beim Setzen der CommMaske\n"); 
        exit(-1); 
        } 
    
      // Warten auf CommEvent 
      if (WaitCommEvent(port, &eventMask, NULL)) 
        { 
        // Lesen bis was kommt 
        do 
          { 
          ReadFile(port, &zeichen, 1, &anzImBuffer, NULL); 
          } while (anzImBuffer == 0); 
        } 
      else 
        { 
        printf("Fehler beim Warten auf CommEvent\n"); 
        exit(-1); 
        } 
    
      return zeichen; 
      } 
    
    /* 
    * byteAufPortSchreiben() -- schreibt ein Character auf den Port 
    */ 
    
    void byteZumPortSchreiben(byte zeichen) 
      { 
      unsigned long anzGeschrieben; 
    
      if (WriteFile(port, &zeichen, 1, &anzGeschrieben, NULL) == 0) 
        { 
        printf("Fehler beim Schreiben auf Port\n"); 
        exit(-1); 
        } 
      } 
    #endif
    
    #include <stdio.h> 
    #include "serial.h" 
    byte b[10]; 
    int i;
    main() 
    { 
    printf("Port wird initialisiert:\n"); 
    portInitalisieren(); 
    
    // Protokoll absenden um den Status zu empfangen.. 
    byteZumPortSchreiben(0x02); // STX 
    byteZumPortSchreiben(0x49); // Kommando "I" 
    byteZumPortSchreiben(0x05); // ENQ 
    byteZumPortSchreiben(0x12); // DC2 
    byteZumPortSchreiben(0x03); // ETX 
    
    // Kurz warten.. 
    sleep(50); 
    
    // Hier muss das Antwort-Protokoll empfangen werden. 
    
    printf("byte wird vom Port gelesen:\n"); 
    for( i = 0; i < 10; i++) 
       { 
           b[i]=byteVomPortLesen(); 
           printf("%d Wert\n", b[i]); 
       }
    
    getchar(); 
    getchar(); 
    }
    

    hat jemand noch einen Tip?

    Gruss Sonic



  • Aufruf mit: progname <COM-Port-Nummer>

    // DOS32-Programm zum Senden/Empfangen von Bytes über COM (9600-8N1)
    // Es wird Bytes als Start gesendet.
    // Alle empfangenen Bytes werden zurückgesendet.
    // OS: W95, W98, W98SE, WinME, WinNT, Win2000, WinXP
    // Note: Fast keine Fehlerbehandlung implementiert!
    #include <windows.h>
    #include <stdio.h>
    
    #define COM_BUFFER_SIZE 256       // Read- und Write-Buffer-Size
    #define BAUDRATE  CBR_9600 // 9600 Baud
    #define BYTESIZE  8 
    #define PARITY    EVENPARITY 
    #define STOPBITS  ONESTOPBIT 
    #define HELP_STRING TEXT("Aufruf mit: progname <COM-Port-Nummer>\r\n")
    char COMMAND1[] = {(0x02), (0x49), (0x05), (0x12), (0x03)};
    
    // Hauptprogramm: Aufruf mit: progname <COM-Port-Nummer>
    int main (int argc, char **argv)
    {
      DCB           dcb;    
      DWORD         iBytesWritten;
      BOOL          bRet      = true;
      DWORD         dwRead    = 0;
      DWORD         dwSetMask = EV_RXCHAR | EV_ERR; 
      DWORD         dwEvtMask; 
      OVERLAPPED    o;
      COMMTIMEOUTS  ct;
      unsigned char InString[COM_BUFFER_SIZE + 1];
      TCHAR         szCOM[6];
    
      if (argc == 2 &&                              // progname + COM-Port-Nummer ?
          atoi (argv[1]) > 0 && atoi (argv[1]) < 5) // COM1 ... COM4?
        wsprintf (szCOM, TEXT("COM%s"), argv[1]);   // String "basteln" ...
      else
      { 
        printf (TEXT("\r\nERROR:\t %s"), HELP_STRING);
        return (1); // und tschüß ...
      }
    
      memset (&o, 0, sizeof (OVERLAPPED)); // Struktur mit 0en füllen
      o.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); // einen Event setzten
    
      HANDLE hCom = CreateFile (szCOM, GENERIC_WRITE | GENERIC_READ, 0, NULL, 
                                OPEN_EXISTING, 0, NULL);                     
    
      if (hCom == INVALID_HANDLE_VALUE)
      { // Fehlerausgabe:
        LPVOID lpMsgBuf;
        FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
                        FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
        MessageBox (NULL, (LPCTSTR)lpMsgBuf, "Error: CreateFile", MB_OK | MB_ICONINFORMATION);
        LocalFree (lpMsgBuf);
        return (1); // und tschüß ...
      }
    
      dcb.DCBlength = sizeof(DCB);  // Laenge des Blockes MUSS gesetzt sein!
      GetCommState (hCom, &dcb);    // COM-Einstellungen holen und aendern
      dcb.BaudRate  = BAUDRATE;     // Baudrate
      dcb.ByteSize  = BYTESIZE;     // Datenbits
      dcb.Parity    = PARITY;       // Parität
      dcb.StopBits  = STOPBITS;     // Stopbits
      SetCommState (hCom, &dcb);    // COM-Einstellungen speichern
    
      GetCommTimeouts (hCom, &ct);
      // Warte-Zeit [ms] vom Beginn eines Bytes bis zum Beginn des nächsten Bytes 
      ct.ReadIntervalTimeout         = 1000 / BAUDRATE * (dcb.ByteSize + 
                                                         (dcb.Parity == NOPARITY ? 0 : 1) + 
                                                         (dcb.StopBits == ONESTOPBIT ? 1 : 2)) * 2;
      ct.ReadTotalTimeoutMultiplier  = 0;  // [ms] wird mit Read-Buffer-Size multipliziert
      ct.ReadTotalTimeoutConstant    = 50; // wird an ReadTotalTimeoutMultiplier angehängt
      ct.WriteTotalTimeoutMultiplier = 0;
      ct.WriteTotalTimeoutConstant   = 0;
      SetCommTimeouts (hCom, &ct);
    
      // Zwischenspeicher des serial-Drivers einstellen (für read und write):
      SetupComm (hCom, COM_BUFFER_SIZE, COM_BUFFER_SIZE);
      SetCommMask (hCom, dwSetMask); // Empfangssignale definieren
    
      // Byte(s) senden:
      if (!WriteFile (hCom, &COMMAND1, 5, &iBytesWritten, NULL)) // Senden der Bytes
      { // Fehlerausgabe:
        LPVOID lpMsgBuf;
        FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
                        FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
        MessageBox (NULL, (LPCTSTR)lpMsgBuf, "Error: WriteFile", MB_OK | MB_ICONINFORMATION);
        LocalFree (lpMsgBuf);
      }
      else
        printf ("%d Byte(s) sent.", iBytesWritten);
    
      do  // in Endlos-Schleife auf Empfangssignale warten:
      {
        WaitCommEvent (hCom, &dwEvtMask, &o); // Event mit Empfangssignalen verknüpfen
    
        if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) // warten bis Event
        {
          if (dwEvtMask & EV_RXCHAR) // Zeichen an RxD empfangen:
          {
            bRet = ReadFile (hCom, &InString, sizeof (InString), &dwRead, NULL);
    
            if (!bRet)
            { // Fehlerausgabe:
              LPVOID lpMsgBuf;
              FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
                              FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
                              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                              (LPTSTR) &lpMsgBuf, 0, NULL);
              MessageBox (NULL, (LPCTSTR)lpMsgBuf, "Error: ReadFile", 
                          MB_OK | MB_ICONINFORMATION);
              LocalFree (lpMsgBuf);
            }
            else
            { // Ausgabe (oder Verarbeitung) der empfangenen Bytes:
              InString[dwRead] = '\0'; // in "zero-ended"-String verwandeln
              printf (TEXT("\r\n\tRxD (%d Byte(s)): %s"), dwRead, InString);
              WriteFile (hCom, &InString, dwRead, &iBytesWritten, NULL); // Senden der Bytes
            }
          }
    
          if (dwEvtMask & EV_ERR) 
          {
            MessageBox (NULL, "Error empfangen", "Error: ReadFile", MB_OK);
            break; // Schleifen-Abbruch
          }
        }
      }
      while (1);
    
      CloseHandle (hCom);     // COM schließen
      CloseHandle (o.hEvent); // Event-Handle zurückgeben
    
      return (0);
    }
    

    Den Daten-Empfang solltest Du in einen eigenen Thread packen. Öffen und Schließen des Ports irgendwo zentral. Schreiben, da wo Du willst.
    Die Empfangs-Daten der IO88 sind keine lesbaren ASCII-Zeichen - also vor der Ausgabe noch umwandeln.

    Blackbird


Anmelden zum Antworten