comm ansteuerung auf allen windowssystemen ohne nt
-
hallo kann mir jemand helfen, ich versuche verzweifelt ein peripheriegerät uber die comm-schnittstellen anzusteuern. ich schicke ein startcommand mit 300 baud und sobald ich eine verbindung habe möchte ich die baudrate verstellen können (z.b 4800 bps). alles ist auf win 98 kein problem, aber auf 2000 und xp habe ich keine chance, but why?
danke im voraus
-
Hab das selbst auf sämtlichen (95-me und NT4 - XP) Systemen exerziert und hatte nie Probleme... Wie änderst du denn die Baudrate? bzw. wie äussert sich das "nicht gehen"?
-junix
-
ich weiss ist ein wenig viel code, aber ist wohl am besten so...
als umschaltbefehl brauche ich:char to4800[]=".040\r\n";
to4800[0]='\6';dies befindet sich ganz zuunterst im code...
XXXXXXXXXXXXXXHauptprogrammXXXXXXXXXXXXXXXXXX char* startCommand="/?!\r\n"; int dwToWrite=5; Serial serialPort; serialPort.ModeSet(300,7,ONESTOPBIT,EVENPARITY); serialPort.Open(port,300,7,ONESTOPBIT,EVENPARITY); serialPort.SendData(startCommand,dwToWrite); if (baudRate == 300) { lengthOfFile = serialPort.ReadData(output); start = 31; } else { lengthOfFile = serialPort.ReadData4800(output); start = 30; } XXXXXXXXXXXXXXXXXXXKlasse SerialXXXXXXXXXXXXXXXXXXXXX #include "stdafx.h" #include "serial.h" // Headerdefinitionen CSerial::CSerial() : hComm(INVALID_HANDLE_VALUE) { } CSerial::~CSerial() { Close (); } BOOL CSerial::ModeSet (int nBaud, int nBits, int nStopp, int nParity) // Ändern von Baudrate (nBaud), Bits (nBits), Parität (nParity) { if (INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet? return (FALSE); DCB dcb; // Struktur vom Typ DCB erzeugen ZeroMemory (&dcb, sizeof(dcb)); // ..und schön löschen (wichtig!) // Die bestehenden Parameter holen. Bei Fehler ist hier Schluss! if (!GetCommState (hComm, &dcb)) { Close (); MessageBox (NULL, "Fehler beim Ändern der COM-Port Parameter\nGetCommState()", NULL, NULL); return (FALSE); } // neue Parameter in die Struktur kopieren (Baud: z.B. 9600) dcb.BaudRate = nBaud; // neue Parameter in die Struktur kopieren (Bits: z.B. 7 oder 8) dcb.ByteSize = (BYTE)nBits; // neue Parameter in die Struktur kopieren (Parität:(siehe MSDN)) dcb.Parity = (BYTE)nParity; // Anzahl Stoppbits (siehe MSDN) dcb.StopBits = (BYTE)nStopp; // neue Parameter setzen. Bei Fehler ist hier Schluss! if (!SetCommState (hComm, &dcb)) { Close (); MessageBox (NULL, "Fehler beim Ändern der COM-Port Parameter\nSetCommState()", NULL, NULL); return (FALSE); } return (TRUE); // fertig } BOOL CSerial::Open (int nPort, int nBaud, int nBits, int nStopp, int nParity) { if (INVALID_HANDLE_VALUE != hComm) // COM-Port überhaupt geöffnet? return (TRUE); char szPort[15]; // Aus einer "1" in nPort schreiben wir so "COM1" in szPort z.B.. wsprintf (szPort, "\\\\.\\COM%d", nPort); hComm = CreateFile (szPort, // COM-Port öffnen GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // nicht OVERLAPPED, wir holen uns den Port exclusiv if (hComm == INVALID_HANDLE_VALUE) { MessageBox (NULL, "Fehler beim Öffnen des COM-Ports!\nCreateFile()", NULL, NULL); return (FALSE); } // Alte Timeouts merken. Bei Fehler ist hier Schluss! if (!GetCommTimeouts(hComm, &timeouts_alt)) { Close (); MessageBox (NULL, "Fehler beim Öffnen des COM-Ports!\nGetCommTimeouts ()", NULL, NULL); return (FALSE); } // Eine Struktur vom Typ COMMTIMEOUTS erzeugen und neue Timeouts setzen COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = 2000; timeouts.ReadTotalTimeoutMultiplier = 2000; timeouts.ReadTotalTimeoutConstant = 2000; timeouts.WriteTotalTimeoutMultiplier = 2000; timeouts.WriteTotalTimeoutConstant = 2000; // Neue Timeouts setzen. Bei Fehler ist hier Schluss! if (!SetCommTimeouts(hComm, &timeouts)) { Close (); MessageBox (NULL, "Fehler beim Öffnen des COM-Ports!\nSetCommTimeouts()", NULL, NULL); return (FALSE); } DCB dcb; // Struktur vom Typ DCB erzeugen ZeroMemory (&dcb, sizeof(dcb)); // ..und schön löschen (wichtig!) // Die bestehenden Parameter holen. Bei Fehler ist hier Schluss! if (!GetCommState (hComm, &dcb)) { Close (); MessageBox (NULL, "Fehler beim Öffnen des COM-Ports!\nGetCommState()", NULL, NULL); return (FALSE); } dcb_alt = dcb; // alte Parameter sichern dcb.DCBlength = sizeof(DCB); dcb.fBinary = TRUE; // muss immer "TRUE" sein! dcb.fParity = TRUE; dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fDsrSensitivity = FALSE; dcb.fTXContinueOnXoff = TRUE; dcb.fOutX = FALSE; dcb.fInX = FALSE; dcb.fErrorChar = FALSE; dcb.fNull = FALSE; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fAbortOnError = FALSE; dcb.wReserved = 0; // muss immer "0" sein! // neue Parameter in die Struktur kopieren (Baud: z.B. 9600) dcb.BaudRate = nBaud; // neue Parameter in die Struktur kopieren (Bits: z.B. 7 oder 8) dcb.ByteSize = (BYTE)nBits; // neue Parameter in die Struktur kopieren (Parität:(siehe MSDN)) dcb.Parity = (BYTE)nParity; // Anzahl Stoppbits (siehe MSDN) dcb.StopBits = (BYTE)nStopp; dcb.fParity = (dcb.Parity != NOPARITY); // neue Parameter setzen. Bei Fehler ist hier Schluss! if (!SetCommState (hComm, &dcb)) { Close (); MessageBox (NULL, "Fehler beim setzen der COM-Port Parameter\nSetCommState()", NULL, NULL); return (FALSE); } return(TRUE); } BOOL CSerial::Close (void) { if (INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet? return(TRUE); if (!SetCommTimeouts(hComm, &timeouts_alt)) { MessageBox (NULL, "Fehler beim Schließen des COM-Ports\nSetCommTimeouts()", NULL, NULL); return (FALSE); } // alte Parameter zurückschreiben. Bei Fehler ist hier Schluss! if (!SetCommState (hComm, &dcb_alt)) { MessageBox (NULL, "Fehler beim Schließen des COM-Ports\nSetCommState()", NULL, NULL); return (FALSE); } CloseHandle (hComm); // Port schließen hComm = INVALID_HANDLE_VALUE; // das Handle zurücksetzen return (TRUE); } BOOL CSerial::WriteCommByte (unsigned char ucByte) // Das zu übertragene Byte (ucByte) { if (INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet? return(FALSE); // ein Zeichen direkt übertragen. Bei Fehler ist hier Schluss! if (!TransmitCommChar(hComm, ucByte)) { MessageBox (NULL, "Fehler beim Schreiben auf COM-Port!\nTransmitCommChar()", NULL, NULL); } return (TRUE); } int CSerial::SendData (const char *buffer, int iBytesToWrite) // Buffer (*buffer), mit den zu sendenen Zeichen und deren Anzahl (iBytesToWrite) { if(INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet? return(0); DWORD dwBytesWritten = 0; // die angegebene Anzahl der Bytes schreiben WriteFile(hComm, buffer, iBytesToWrite, &dwBytesWritten, NULL); return ((int) dwBytesWritten); // die Anzahl der geschriebenen Bytes zurückgeben } int CSerial::ReadData (char *buffer) // Buffer (*buffer), der die Zeichen bekommt { if (INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet? return(0); DWORD dwRead = 0; char chRead; int i = 0; while (ReadFile(hComm, &chRead, 1, &dwRead, NULL)) // wurde ein Zeichen gelesen? { if (dwRead != 1) // ..wenn nicht, dann ist hier Schluß break; buffer[i++] = chRead; // wann ja, dann das Zeichen in den Buffer schreiben } return (i); // die Anzahl der gelesenen Bytes zurückgeben } BOOL CSerial::WriteABuffer(char *lpBuf, DWORD dwToWrite) { OVERLAPPED osWrite = {0}; DWORD dwWritten; BOOL fRes; // Create this writes OVERLAPPED structure hEvent. osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (osWrite.hEvent == NULL) // Error creating overlapped event handle. return FALSE; // Issue write. if (!WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, &osWrite)) { if (GetLastError() != ERROR_IO_PENDING) // WriteFile failed, but it isn't delayed. Report error and abort. fRes = FALSE; else { // Write is pending. if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, TRUE)) fRes = FALSE; else // Write operation completed successfully. fRes = TRUE; } }else // WriteFile completed immediately. fRes = TRUE; CloseHandle(osWrite.hEvent); return fRes; } int CSerial::ReadData4800 (char *buffer) // Buffer (*buffer), der die Zeichen bekommt { int dwToWrite=8; //Anzahl der zu schreibenden Zeichen int lengthOfFile=0; //Zähler für die Anzahl der Zeichen int posNumber; //Stelle an die in numberString geschrieben werden muss bool readNumb; //Nummer wurde bereits gelesen char ch; //Hilfsvariable zum Merken des vorgegangenen Zeichens int start; //Position, an der Nummer beginnt bool readError; //Zeigt an ob Lesefehler gewesen DWORD dwRead; //Anzahl der gelesenen Zeichen char chRead; //aktuellgelesenes Zeichen // char output[maxSize]; //ausgelesenen Daten bool first = true; bool now = false; int counter = 0; char to4800[]=".040\r\n"; //Befehl zum Umschalten auf 4800 Baud to4800[0]='\6'; posNumber=0; readNumb=false; ch=' '; start=0; readError=false; do{ if (ReadFile(hComm, &chRead, 1, &dwRead, NULL)){ // A byte has been read; process it. buffer[lengthOfFile]=chRead; if (now){ //Der Befehl zum Umschalten auf 4800 Baud if (counter==5){ //wird 5 Zeichen nach dem Punkt in der WriteABuffer(to4800,dwToWrite); //Zählerbezeichnung gesendet ModeSet(4800,7,ONESTOPBIT,EVENPARITY); now=false; } counter++; } if ((first) && (chRead=='.')) { now=true; counter=1; first=false; } lengthOfFile++; }else // An error occurred in the ReadFile call. break; }while (dwRead); //Lese solange, solange es etwas zu lesen gibt ModeSet(300,7,ONESTOPBIT,EVENPARITY); return (lengthOfFile); // die Anzahl der gelesenen Bytes zurückgeben }
-
etwas habe ich noch vergessen, es ist so das es zum zielgerät eine verbindung herstellt, jedoch nur während den ersten zeichen, d.h. bis es umschalten sollte auf 4800 bps. steht auch ziemlich zuunterst im vorderen beitrag..
danke schon mal
-
marc_ch schrieb:
etwas habe ich noch vergessen, es ist so das es zum zielgerät eine verbindung herstellt, jedoch nur während den ersten zeichen
Hmmm ja, was ähnliches hatte ich auch. Das erste Zeichen wurde mit 19200bps versendet und dann nach kurzen Init-Sequenzen wurde die Baudrate auf einen möglichst hohen Wert gesetzt (wurde mittels eines etwas umständlicheren Protokolls erwirkt).
Das aber nur am Rande. Zu deinem problem. Nach meinem kurzen Überfliegen kann ich keine Fehler feststellen. Du setzt das DCB-Struct wieder sauber (wo ich ehrlichgesagt den fehler vermutet hatte). Ich hatte nicht die Musse, deinen Code zu analysieren. Aber kommt das Programm bei ModeSet auch wirklich bei SetCommState() vorbei? (->Debugtip: Breakpoint da setzten und schauen ob das Programm da anhält)
Besteht allenfalls die Möglichkeit, dass ein Protokollfehler zu Stande kommt? (Stellt dein Zielgerät die Baudrate auch wirklich auf 4800?) (->Debugtip: Bau dir ein Testtool bei dem du den Comm-port beliebig öffnen und schliessen kannst und beliebige Strings versenden kannst. Verbinde zum Target, setzte den Baudrate-ändern-String ab, und schliessen den Port. Öffne ihn anschliessend wieder mit 4800 und versuch mit dem Target zu kommunizieren. Antwortet es?)
Meine Anregungen zur Fehlersuche ... sorry, mehr fällt mir im Moment nicht ein...
-junix
-
Ahja und als Intermezzo noch etwas stilistisches: Normalerweise, wenn man schon eine kapselnde Funktion schreibt wie z.B. du deine ModeSet, dann verwendet man innerhalb der Klasse ebenfalls nur noch konsequent diese Funktion um Fehler vorzubeugen... Geht auch etwas weg von Copy-Paste-Programmierung (Du hast z.B. bei Open() den ganzen Klimbim aus ModeSet übernommen...) (o:
Das aber nur so nebenbei.
-junix
-
Aber kommt das Programm bei ModeSet auch wirklich bei SetCommState() vorbei? (-Debugtip: Breakpoint da setzten und schauen ob das Programm da anhält)
=>
vielen dank für die hilfe, nur geht es noch immer nicht, ich bin ganz sicher das es dort vorbei kommt, denn sonst gibt er eine Fehlermeldung aus und das habe ich schon getestet, aber schau dir mal die methode ReadData4800 an, stimmt der umschaltbefehl oder ist er nur win98 tauglich? du hast auch erwähnt das du ein ähnliches problem hattest, als du nach der grösst möglichen baudrate gesuchtb hast, das wäre ein längerfristiges ziel von mir, könntest du mir etwas auf die sprünge helfen? bin ein ziemlicher newbie in c++ einzig java kenne ich ziemlich gut und das ist für mein problem nicht geeignet...
-
könnte es sein das die ReadData4800 methode overlapped ist und der rest nicht?
-
Da fällt mir was auf... Funktioniert das Lesen/Schreiben überhaupt unter den NT-Derivaten? Ich hatte damals das Problem, dass unter 2000 sich die Write-Funktion aufgehängt hat (hatte sie im Overlapped-Modus). Als ich dem Fehler nachgegangen bin, bemerkte ich, dass zwei Parameter der Overlapped-Struktur welche in der SDK-Doku als Ignored unter NT/2000 dokumentiert waren, nicht 0 waren. Als ich sie explizit auf 0 setzte, war alles bester Ordnung. Initialisier die Struktur mal ordentlich mit 0 und versuchs nochmal.
Was das finden der höchsten Baudrate betrifft, so war das ein rel. umständlicher Ablauf, den ich hier auch nicht ohne Weiteres schildern kann... gehört eigentlich auch nicht weiter zum Thema. Vielleicht dazu soviel:
Wir haben immer ein definiertes Byte hin und her geschickt. Jeder hat immer gewartet, bis der andere das byte zurückgeschickt hat oder ein Timeout eingetreten ist.
Das lief in etwa so:
1. Der Host sendet die neue Baudrate 2. Der Host fällt in eine definierte Warteschleife um zu warten, bis sich das Target auf die neue Baudrate eingestellt hat. (und stellt sich natürlich selbst um) 3. Der Host sendet ein definiertes Byte (z.B. 0x55) und errechnet seine private Checksumme (bei uns war das schlichtes invertieren) 4. Das Target empfängt das Byte, errechnet daraus seine Checksumme. 5. Diese Checksumme sendet das Target an den Host. 6. Der Host sendet die empfangene Checksumme an das Target zurück 7. Beide vergleichen die jeweils selbst errechnete und die empfangene Checksumme miteinander. sind sie identisch, bleibt die neue Baudrate erhalten. Ansonsten gehen beide zurück auf die alte Baudrate.
Mit dem Ganzen zauber ist die Kommunikation in beide Richtungen geprüft. Das Spiel wird solange wiederholt, bis beide einander verstehen. Dabei ist die Baudrate jeweils sinkend...
(also z.B. 230 400, 115 200, 57 600, ...)-junix
-
Das oben beschrieben Verfahren zur Ermittlung der max. Baudrate ist übringes Programmiersprachenunabhängig (o;
-junix
-
ja klingt einleutend, werde ich so versuchen und hoffe das es klappt, aber zuerst muss ich ja einmal auf 4800 baud umschalten können und das geht nicht, habe jetzt noch die writeABuffer methode herausgenommen weil sie overlapped ist, aber alle anderen parameter die das overlapped struktur betreffen sind auf NULL gesetzt. sorry das ich so afdringlich nachfrage, aber sonst komme ich nicht weiter, habe keine idee zu einem lösungansatz
-
wie ist der befehl zum umschalten auf 4800 bps? habe das gefühl das meiner nur win98-spezifisch ist....
-
Ne, Isser ned, ganz normal das DCB-Struct füllen und dann mit SetCommStatus setzen... das ist schon in Ordnung...
-junix
-
hallo,
ich muss nochmal nachahken, habe es noch immer nicht geschafft auf win 2000 zu kommunizieren, das programm hängt sich immer wieder auf. du hast geschrieben du hättest ein ähnliches problem gehabt weil der write befehl auf overlapped gesetzt war. ist es richtig das er so auf nicht overlapped ist?WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, NULL)
oder hat noch ein anderer parameter einfluss auf diese struktur ausser der hinterste der jetzt auf null ist? oder muss man ih aders setzen?
-
o shit, habe vergessen mich einzuloggen. und deutsche splache schwele splache.