Serielle Schnittstelle ansprechen und Daten senden
-
Hallo,
ich habe ein kleines Problem das ich nicht gelöst bekomme. Es gibt zwar viele Dinge, die ich über Google finde aber alles, was ich bisher probiert habe, funktioniert einfach nicht. Das ist mein erster Versuch mit Seriellen Schnittstellen und leider fehlt mir jede Erfahrung.
Was ich versuche ist; Ein Programm für Windows Embedded CE 6.0 zu schreiben (mit Visual Studio 2008 auf XP) und das ganze in C++ natürlich. Das gerät soll nichts anderes machen als einen COM Port zu öffnen und dort darauf warten, dass ein einziger Buchstabe kommt, diesen einlesen und dann auf Konsole ausgeben. Das wars.
Das Gegenstück dazu läuft auf dem XP Rechner, der über ein RS232 Kabel an das Windows CE Board angeschlossen ist. Der soll auch nichts anderes machen als den COM Port zu öffnen und einen einzigen Buchstaben an den Port zu senden und das Programm zu beenden.Dafür habe ich mir hier diese kleine Klasse geschrieben. Ich weiß sie ist weit weg vom optimalen aber es soll nur diese einfache Aufgabe erfüllen und wenn das mal geklappt hat, werde ich versuchen es zu verbessern.
Die Klasse:
#include "ComPort.h" ComPort::ComPort(void) { hCom = INVALID_HANDLE_VALUE; } ComPort::~ComPort(void) { CloseHandle(hCom); } void ComPort::InitComPort(void) { DCB Dcb; COMMTIMEOUTS Cto; if((hCom = CreateFile(TEXT("COM1:"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) { Dcb.DCBlength = sizeof(Dcb); GetCommState(hCom, &Dcb); Dcb.BaudRate = CBR_115200; Dcb.fParity = false; Dcb.fNull = false; Dcb.StopBits = ONESTOPBIT; Dcb.Parity = NOPARITY; Dcb.ByteSize = 8; SetCommState(hCom, &Dcb); Cto.ReadIntervalTimeout = 0; Cto.ReadTotalTimeoutMultiplier = 0; Cto.ReadTotalTimeoutConstant = 0; Cto.WriteTotalTimeoutMultiplier = 0; Cto.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hCom, &Cto); cout << "Port opened" << endl; } else { cout << "Couldn't open Port" << endl << "ERROR: " << GetLastError() << endl; } } int ComPort::Read() { DWORD BytesRead = 0; char buf[100]; if(!ReadFile(hCom, buf, 1, &BytesRead, NULL)) { cout << "Error reading from Port" << endl; return -1; } cout << buf << endl; return BytesRead; } int ComPort::Write() { DWORD BytesWritten = 0; char buf[] = "Hallo"; if(!WriteFile(hCom, buf, 1, &BytesWritten, NULL)) { cout << "Error writing to Port" << endl; return -1; } return BytesWritten; }
Die Headerdatei dazu:
#pragma once #ifndef _COMPORT_H_ #define _COMPORT_H_ #include "windows.h" #include <iostream> using namespace std; class ComPort { public: ComPort(void); ~ComPort(void); void InitComPort(void); int Read(); int Write(); private: HANDLE hCom; }; #endif
Was nicht funktioniert ist eben das Versenden oder Empfangen.
Wenn ich das Programm auf WinCE starte, kommt die Meldung, dass der Port offen ist und allem anschein nach blockiert nun die Methode ReadFile() bis was reinkommt.Auf der Gegenseite passiert das selbe. Port wird anscheinend erfolgreicht geöffnet und es hängt in der Methode WriteFile(). Was auch immer sie macht, sie blockiert und nichts passiert anschließend. Also gehe ich davon aus, dass es nichts versendet.
Hat vielleicht jemand irgendwelche Tipps?
mfg
-
ohne mir deinen Code jetzt wirklich angesehen zu haben:
vom Prinzip her bist du den richtigen Weg gegangen. Aber: der Teufel steckt im Detail! Ich hab oft erlebt, dass die Hardwareflußsteuerung merkwürdigste Sachen macht. Was auf einer Maschine funktionierte, gab auf einer aneren bei gleicher Konfiguration die rote Karte.
Zwei Werkzeuge haben mir immer weiter geholfen: Sysinternals Portmonitor und die gute uralte Testbrücke. Die Testbrücke wird einfach beim Kabel zwischengesteckt und zeigt dann per LED die Stati der Leitungen. (gibt es sowas heute noch? Son einfacher SUB D Doppelstecker mit ein paar LEDs für 3,50?)
Ganz dumme Frage (sorry): hast du ein Nullmodemkabel genommen? Ein serielles Anschlusskabel funktioniert bei so einer Koppelung nicht.
Und, was auch immer gut für erste Tests war: Die Flusssteuerung per Brücken "kurzschlissen" und nur TX, RX und Ground durchverbinden.
Ulli
-
Hi Ulli, danke für deine Antwort.
vom Prinzip her bist du den richtigen Weg gegangen. Aber: der Teufel steckt im Detail! Ich hab oft erlebt, dass die Hardwareflußsteuerung merkwürdigste Sachen macht. Was auf einer Maschine funktionierte, gab auf einer aneren bei gleicher Konfiguration die rote Karte.
Zwei Werkzeuge haben mir immer weiter geholfen: Sysinternals Portmonitor und die gute uralte Testbrücke. Die Testbrücke wird einfach beim Kabel zwischengesteckt und zeigt dann per LED die Stati der Leitungen. (gibt es sowas heute noch? Son einfacher SUB D Doppelstecker mit ein paar LEDs für 3,50?)
Um die Flussteuerung habe ich mich gar nicht gekümmert. Wie könnte ich denn dieses Problem lösen? Wenn ich mich recht erinnere gibt es in den Einstellungen der einzelnen COM Ports unter XP die möglichkeit die Hardwareflusssteuerung zu deaktivieren.
Ganz dumme Frage (sorry): hast du ein Nullmodemkabel genommen? Ein serielles Anschlusskabel funktioniert bei so einer Koppelung nicht.
Also das Kabel ist beschriftet und es steht Nullmodem drauf.
Und, was auch immer gut für erste Tests war: Die Flusssteuerung per Brücken "kurzschlissen" und nur TX, RX und Ground durchverbinden.
Das geht jetzt leider über mein Horizont hinaus. So gut kenne mich nicht aus. Wie gesagt, das ist mein erster Versucht überhaupt, etwas mit Seriellen Verbindungen zu machen.
-
-
Du kannst dir auch mal HTerm anschauen. Das ist für solche Zwecke super geeignet, da man dort auch die Statusleitungen setzen kann.
Ulli schrieb:
Die Testbrücke wird einfach beim Kabel zwischengesteckt und zeigt dann per LED die Stati der Leitungen. (gibt es sowas heute noch? Son einfacher SUB D Doppelstecker mit ein paar LEDs für 3,50?)
Klar, Preis stimmt auch: http://www.reichelt.de/Jumperbox-Interface-Tester-etc-/COM-934/index.html?ACTION=3&GROUPID=792&ARTICLE=6747&SHOW=1&START=0&OFFSET=16&
Schneller als mit dem Teil kann man nicht rausfinden ob man ein Nullmodemkabel braucht oder nicht und ob Daten gesendet werden.
-
Eine dumme Frage hätte ich zu hterm. Ich habs vorher nie benutzt.
Im Prinzip ladde ich nur ein Programm auf das Embedded Windows, dass an den Comport Daten sendet. In dem Fall an Windows XP und hterm muss ich mit dem Comport des PC verbinden und falls mein Programm richtig programmiert ist, müsste sie in hterm was tun, oder?Sorry, ich bin etwas verzweifelt, da ich 2 Tage am tun bin und kann noch nichtmal ein Buchstaben verschicken.
-
Sorry, für den Doppelpost.
HA! Ich weiß jetzt wenigstens, dass mein Programm im Prinzip läuft. hterm konnte Zeichenketten empfangen. Danke nochmal dafür, ich hätte früher auf hterm kommen sollen.
Danke an euch beide.
-
Ulli schrieb:
Und, was auch immer gut für erste Tests war: Die Flusssteuerung per Brücken "kurzschlissen" und nur TX, RX und Ground durchverbinden.
Natürlich werden bei einem Nullmodemkabel die Datenleitungen nicht durchverbunden sonden gekreuzt.
Zu beachten ist ausserdem noch, das ein belegter oder bereits geöffneter COM-Port nicht noch einmal geöffnet werden kann.
-
Hallo,
ich bin gerade am Rumspielen, was mit dem Comport so alles drinnen ist und bin da auf eine Sache gestoßen, die, so wie ich es verstanden habe, eigentlich tun müsste, es tatsächlich aber nicht tut.
Folgendes Problem.
Ich habe beim Füllen des DCB (erster Post Codezeile 20 - 28 in der CPP Datei folgende zeile hinzugefügt:Dcb.EvtChar = 'X';
und wie folgt sieht meine Read-Methode aus:
int ComPort::Read() { DWORD mask; DWORD bytesRead = 0; char buf[1024] = ""; int i = 0; SetCommMask(hCom, EV_RXCHAR | EV_RXFLAG | EV_RXFLAG); while(true) { if(WaitCommEvent(hCom, &mask, 0)) { switch(mask) { case EV_RXCHAR: ReadFile(hCom, &buf[i++], 1, &bytesRead, NULL); cout << "Empfangen: " << buf[i-1] << endl; break; case EV_ERR: cout << "fehler beim lesen" << endl; break; case EV_RXFLAG: cout << "Eventchar empfangen" << endl; break; } } } return bytesRead; }
So wie ich das jetzt verstanden habe, sollte jetzt, wenn ein 'X' empfangen wird das Event EV_RXFLAG ausgelöst werden und der selbe Wert in der Variable mask stehen.
Das passiert aber nicht. Es wird immer nur das Event EV_RXCHAR ausgelöst, auch wenn ich 1000 'X' sende.
Mache ich was falsch?
-
Wenn ich den Code mit dem MSDN Beispiel
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363424(v=vs.85).aspx
vergleiche fällt auf das es gut wäre die Return-Werte von Systemaufrufen
zu prüfen:fSuccess = SetCommMask(hCom, EV_CTS | EV_DSR); if (!fSuccess) { ...
Im Beispiel wird CreateEvent() verwendet mit:
hCom = CreateFile( TEXT("\\\\.\\COM1"), GENERIC_READ | GENERIC_WRITE, 0, // exclusive access NULL, // default security attributes OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
Habe folgenden Hinweis gefunden:
To specify a COM port number greater than 9, use the following syntax: "\\.\COM10".
-
Wurde noch nicht erwähnt, lohnt sich aber extrem:
http://www.codeproject.com/Articles/992/Serial-library-for-C