Hallo zusammen, ich habe leider ein kleines Problem beim Auslesen eines virtuellen Com-Ports. Folgende Sachlage: Ich habe von Microsoft ein kleines Codebeispiel genommen und es entsprechend meinen Anforderungen zum Testen angepasst (siehe Code im anhang): https://msdn.microsoft.com/de-de/library/windows/desktop/aa363201(v=vs.85).aspx Wenn ich beispielsweise meinen Arduino Nano an den PC anschließe und das Programm starte, bleibt er in der ReadFile Funktion in Zeile 27 hängen und liest nichts aus. Wenn ich jetzt mit einem Terminalprogramm (zB HTerm) einmal mit dem COM verbinde und die Verbindung wieder trenne, funktioniert mein Code hingegen einwandfrei. Also: Damit der Code funktioniert, muss ich zuerst mit einem anderen Programm einmal auf den COM zugreifen. Danach klappt alles ohne Probleme, bis ich a) den Rechner neustarte oder b) den Nano aus- und wieder einstecke. Das Ganze ist reproduzierbar und tritt bei jedem beliebigen Com-Port auf mehreren Rechnern so auf. Hat jemand von euch eine Idee, was im angehängten Code noch fehlt? Noch eine kleine Anmerkung: Getestet wurde auf W7, 64 Bit. Gruß Nik
Über den DCB stellst Du sehr viel mehr ein als Baudrate/Parity/Stop, z.B. Flusskontrolle. Wenn Du die vorherige Einstellung einfach so übernimmst (GetCommState), bekommst Du eben auch das was vorher war. Initialisiere Deinen DCB vollständig, dann funktioniert es.
Danke für deine schnelle Antwort! Die Intitialisierung sollte nun vollständig sein (siehe Code im Anhang). Leider hat es das Problem nicht behoben. Gibt es noch andere Fehlerquellen? Gruß Nik
char buffer[1024] = { 0 }; ... WriteFile(hCom, buffer, sizeof(buffer), &nBytesRead, NULL); ... ReadFile(hCom, buffer, sizeof(buffer), &nBytesRead, NULL); ... Drei mal darfst raten was da passiert ...
Zusätzlich zu dcb.Parity musst Du noch dcb.fParity auf FALSE setzen. Übrigens, hat jetzt mit dem Problem nichs zu tun, aber schreibe mal lieber TEXT("\\\\.\\COM2") anstelle von TEXT("COM2"), und zwar darum: https://support.microsoft.com/en-us/kb/115831
Hans-Georg L. schrieb: > char buffer[1024] = { 0 }; > ... > WriteFile(hCom, buffer, sizeof(buffer), &nBytesRead, NULL); > ... > ReadFile(hCom, buffer, sizeof(buffer), &nBytesRead, NULL); > ... > > Drei mal darfst raten was da passiert ... Schickst du auch genug Zeichen ?
Es werden zunächst einmal 1024 Byte gesendet, damit ich an der Arudino Nano Rx-LED sehe, ob was ankommt (und ja, das tut es). Dass da keine Nutzdaten, sondern nur die Start- und Stopbits übertragen werden, ist nicht schlimm, da der Arduino eh nichts mit den Daten macht. Danach lese ich zyklisch den Buffer aus. Der Arduino sendet ca. viermal pro Sekunde eine 42 raus. Das Ergebnis ist auf dem Bild im Anhang zu sehen. Wie gesagt, der Code ist erstmal nur zu Testzwecken, bis es mal so läuft wie es soll.
Danke für die Tipps. Er sträubt sich leider immernoch :\.
Nik schrieb: > Der Arduino sendet ca. viermal pro Sekunde eine 42 raus. Und wie lange hast Du der Angelegenheit schon zugesehen? Das dürfte 250 Sekunden dauern, bis die von ReadFile() angeforderten 1000 Bytes zusammenkommen.
Bei 4 Bytes in der Sekunde dauert es 255 Sekunden, bis ReadFile zurückkehrt. Zuzüglich der einen Sekunde beim Sleep davor brauchst Du in Summe 256 Sekunden bis was passiert. Wartest Du das auch ab?
Okay, da lag wohl das Problem. Also die Read Funktion scheint ohne vorherige Verbindung eines anderen Programms mit dem COM-Port erst zurückzukehren, wenn das komplette Bufferarray voll ist, so wie ich das gerade sehe. Je nach Größe kann das dann entsprechend lang dauern. Sobald HTerm einmal lief und ich meinen Code dann wieder ausführe, kehrt die Readfunktion direkt zurück und schreibt mir in nBytesRead die Anzahl der neuen Bytes, welche ich dann aus dem Buffer auslesen kann. Lässt sich dieses Verhalten irgendwie erklären?
Die COM Schnittstele benutzt auch noch die Struktur COMMTIMEOUTS. Darin ist festgelegt wie lange Pause zwischen den Zeichen sein darf, kann also sein das du immer in einen Timeout läufst. lass dir mal das Ergebnis von ReadFile ausgeben ...
1 | bool result; |
2 | |
3 | result = ReadFile( .......); |
4 | if ( ! result ) |
5 | {
|
6 | // error handling
|
7 | LPTSTR lpMsgBuf; |
8 | |
9 | FormatMessage( |
10 | FORMAT_MESSAGE_ALLOCATE_BUFFER | |
11 | FORMAT_MESSAGE_FROM_SYSTEM | |
12 | FORMAT_MESSAGE_IGNORE_INSERTS, |
13 | NULL, |
14 | GetLastError(), |
15 | 0, // Default language |
16 | (LPTSTR) &lpMsgBuf, |
17 | 0, |
18 | NULL
|
19 | );
|
20 | |
21 | LogMsg(_T("Port Read Error: %s"),lpMsgBuf); |
22 | LocalFree( lpMsgBuf ); |
23 | |
24 | }
|
LogMsg ist eine Funktion von Mir das musst du anpassen.
:
Bearbeitet durch User
Die angesprochenen COMMTIMEOUTS werden das Phänomen erklären, dass Dir HTerm Dein Programm "repariert". Wenn Du sowieso im Sekundentakt pollen willst, kannst Du auch vor derm ReadFile-Aufruf einfach mal ClearCommError aufrufen: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363180(v=vs.85).aspx In der von der Funktion ausgefüllten COMSTAT Struktur kannst Du dann sehen, wie viele Bytes es gerade zu lesen gibt (cbInQue). ReadFile wird dann halt nur noch aufgerufen, wenn cbInQue > 0 ist und nicht mehr nur mit sizeof(buffer), sondern mit min(stat.cbInQue, sizeof(buffer)).
VIELEN DANK! Das konnte das Problem nun beheben. Habe den Code jetzt mit Hilfe der ClearCommError Funktion zum laufen bekommen. So wird jetzt immer geprüft, wie viele neue Bytes empfangen wurden und dann die Anzahl, sollte sie größer 0 sein, als maximale Byteanzahl der Read-Funktion übergeben. Jetzt ist es nur noch verbesserungswürdig, dass der gesamte Codeablauf durch die Sleep Funktion gebremst wird. Wenn parallel noch was empfangen werden soll, wird das unschön. Ohne Sleep verbraucht das Programm allerdings 25% meiner CPU-Ressourcen. Gibts da noch Tricks, das anzupassen bzw. ein Stichwort, nach was man da mal schauen könnte? Habe leider bisher nur etwas Programmiererfahrung in C.
Nik schrieb: > Jetzt ist es nur noch verbesserungswürdig, dass der gesamte Codeablauf > durch die Sleep Funktion gebremst wird. vergiss den Quatsch mit dem ClearCommError. Wenn du nicht weißt wie viele Byte zum Lesen da sind, dann ist das einfachste immer 1 Byte zu lesen. Und schon funktioniert alles.
Über ClearCommError bekomme ich in cbInQue die Anzahl der zur Verfügung stehenden Bytes geschrieben. Funktioniert eigentlich bestens.
Nik schrieb: > Über ClearCommError bekomme ich in cbInQue die Anzahl der zur Verfügung > stehenden Bytes geschrieben. Funktioniert eigentlich bestens. ja, nur das es sinnlos CPU-Zeit kostet. weil viel zu oft keine Daten da sind. Bei deinem Code sehe ich keinen Nachteil immer ein Byte zu lesen. dann geht die CPU auf 0% und der kleine Overhead wegen dem mehrfach lesen speilt bei COM keine Rolle.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.