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?&%1mir 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