Hallo Leute, ich suche ein Tutorial, Buch oder ne Website auf dererklärt wird wie man mit dem gcc compiler die Com Ports unter Windows anspricht. Mir geht es nicht in erster Linie um fertig nutzbaren Code, sondern um eine gute Erklärung warum und wie. Ich habe mir schon einen Wolf gesucht nach einer vernünftigen Erläuterung, aber keine gefunden.Man liest immer wieder von der Win32 Api und der Windows.h sowie .net, aber erklärt wird nichts. Es ist doch nicht möglich das ich der einzige bin der da Probleme hat. Das ganze ganze Wurmt mich langsam! Betriebsystem: Windows 7 64bit Compiler: gcc (Boost ist auch installiert, ich möchte das aber mit Standard Bibliotheken schaffen) Danke für Eure Unterstützung Der Tueller
keine ahnung ob man bei Gcc die passende header dabei hat, aber es ist alles in der msnd beschrieben: http://msdn.microsoft.com/de-de/library/windows/desktop/aa363201%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa363140%28v=vs.85%29.aspx
Torben Müller schrieb: > Man liest immer wieder von der Win32 > Api und der Windows.h sowie .net, aber erklärt wird nichts. Das stimmt natürlich nicht, aber du musst das nicht beim Compiler suchen, sondern in der Windows-Doku. http://msdn.microsoft.com/en-us/library/ff802693.aspx neben der grundlegenden Comport-API gibt es im Netz natürlich noch hunderte abstrahierende Libraries, meistens als OO-Klasse. Gruss Reinhard
Danke für eure Antworten, ich werde mir die nächste Zeit die Artikel durcharbeiten un ausprobieren. Aber ist kein leichter Stoff. Der Tueller
Das Serial Port wurde leider von Microsoft von Beginn weg verbockt. Die legen einen Filehandle drueber, dh machen ein Blockdevice draus. Damit sind viele denkbare Verwendungen schon ausgeschlossen. Die Stichworte sind hier Latenz. Die Probleme zeigen sich auch nicht bei 1200Baud. Ein Protokoll sollte also auch fuer ein Blockdevice ausgelegt sein. Daten werden also gerne als Block uebertragen. Das Umschalten in die andere Richtung dauert dann. Unter Umschalten meine ich hier : Auf eine Antwort warten, auswerten und wieder was senden. Das Senden kann dann eine Verzoegerung von 100ms oder mehr haben. Auch ohne RS485, wo effektiv umgeschalten wird.
Viktor N. schrieb: > Das Serial Port wurde leider von Microsoft von Beginn weg verbockt. Die > legen einen Filehandle drueber, dh machen ein Blockdevice draus. Damit > sind viele denkbare Verwendungen schon ausgeschlossen. Die Stichworte > sind hier Latenz. Die Probleme zeigen sich auch nicht bei 1200Baud. keine Ahnung was du redest. MS hat wenigsten sinnvolle Möglichkeiten geschaffen timeout festzulegen. Und ich übertragen ohne Probleme mit weniger als 10ms umschaltzeit. Wenn du solche timing Problme hast, wird es wohl mehr ein Treiber problem sein als ein Designfehler. Und diese Treiber stammen meist nicht von MS.
rs232 ist doch bidirektional.. senden und auf Antwort "warten" wäre also sowieso falsch..??
Robert L. schrieb: > senden und auf Antwort "warten" wäre also sowieso falsch..?? Im Prinzip ja. Wenn du beide Enden im Griff hast, kannst du natürlich dafür sorgen, dass nur eine Antwort kommt, wenn du was gefragt hast, das heisst i.A. es gibt einen Master und einen Slave. Aber das ist eben eine Eigenschaft deines Protokolls und nicht der Schnittstelle! Universeller, aber logisch aufwendiger ist ein Design, bei dem zu jedem beliebigen Zeitpunkt etwas empfangen werden kann. Man stellt auch schnell fest, dass eine reines Frage-Antwort-Design seine logischen Beschränkungen hat, ein Beispiel: der Slave kann sich nach Herstellung der Verbindung nicht selbst anmelden, sondern der Master muss immer wieder fragen, ob da jemand ist. Gruss Reinhard
Hi Torben, Ich gebe Dir hier mal so eine Art Minimumcode. Du kannst hier jede Funktion bei google finden (oder im MSDN). Ich denke mal das hier hilft Dir, weil es alles ist was man im Bezug auf RS232 unter Windows braucht. Achte auf \\.\ vor dem Comport. Ohne dies funktioniert es nur mit Comports bis COM8 (glaube ich). Mit \\.\ funktionierern alle COMx. ---- Öffnen: HANDLE h = CreateFile( "\\\\.\\COM20", GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL ); if ( h == INVALID_HANDLE_VALUE ) { // ERROR } Schließen: CloseHandle( h ); Lesen: DWORD nBytesRead = 0; char buffer[1024]; ReadFile( h, buffer, sizeof(buffer), &nBytesRead, NULL ); Schreiben: DWORD tmp = 0; char buffer[1024]; WriteFile( h, buffer, sizeof(buffer), &nBytesRead, NULL ); DTR setzen/löschen: EscapeCommFunction( h, SETDTR ); EscapeCommFunction( h, CLRDTR ); RTS setzen/löschen: EscapeCommFunction( h, SETRTS ); EscapeCommFunction( h, CLRRTS ); DSR lesen: DWORD dw; GetCommModemStatus( h, &dw ); if ( dw & MS_DSR_ON ) { } CTS lesen: DWORD dw; GetCommModemStatus( h, &dw ); if ( dw & MS_CTS_ON ) { } DCD lesen: DWORD dw; GetCommModemStatus( h, &dw ); if ( dw & MS_RLSD_ON ) { } RI lesen: DWORD dw; GetCommModemStatus( h, &dw ); if ( dw & MS_RING_ON ) { } Baudrate / Parameter setzen: DCB dcb; dcb.DCBlength = sizeof(DCB); dcb.BaudRate = <BAUDRATE>; dcb.fBinary = TRUE; dcb.fParity = <TRUE/FALSE>; dcb.fOutxCtsFlow = <TRUE/FALSE>; dcb.fOutxDsrFlow = <TRUE/FALSE>; dcb.fDtrControl = <DTR_CONTROL_HANDSHAKE/0>; dcb.fDsrSensitivity = FALSE; dcb.fTXContinueOnXoff = TRUE; dcb.fOutX = FALSE; dcb.fInX = FALSE; dcb.fErrorChar = TRUE; dcb.fNull = FALSE; dcb.fRtsControl = <RTS_CONTROL_HANDSHAKE/0>; dcb.fAbortOnError = FALSE; dcb.wReserved = 0; dcb.XonLim = 5; dcb.XoffLim = 5; dcb.ByteSize = <8/...>; dcb.Parity = <EVENPARITY/MARKPARITY/NOPARITY/ODDPARITY/SPACEPARITY> dcb.StopBits = <ONESTOPBIT/ONE5STOPBITS/TWOSTOPBITS>; dcb.XonChar = 0; dcb.XoffChar = 0; dcb.ErrorChar = '#'; dcb.EofChar = '.'; dcb.EvtChar = '-'; SetCommState( h, &dcb ); Und jetzt das wichtigste, damit der Port "nonblocking" wird: COMMTIMEOUTS tos; tos.ReadIntervalTimeout = 100; tos.ReadTotalTimeoutMultiplier = 0; tos.ReadTotalTimeoutConstant = 100; tos.WriteTotalTimeoutMultiplier = 0; tos.WriteTotalTimeoutConstant = 100; SetCommTimeouts( h, &tos );
Nachtrag: Sieh meinen Code jetzt nicht als "fertig nutzbaren Code", sondern als "Erklärung in Code". ;)
Horst schrieb: > Ohne dies funktioniert es nur mit > Comports bis COM8 (glaube ich). Es ist COM9, die letzte noch einstellige Nummer. Danach funktionieren die DOS-Devicenamen nicht mehr (ja, hier lebt tatsächlich noch der DOS-Murks fort).
Wenn das funktioniert, wovon ich mal ausgehe. Dann bitte einen Wiki-Artikel machen.
weiß nicht genau, warum (vor allem C/C++ Programmierer?) immer das rad neu erfinden müssen gibts bei "euch" keine fertigen libraries ...
Robert L. schrieb: > weiß nicht genau, warum (vor allem C/C++ Programmierer?) immer das rad > neu erfinden müssen > gibts bei "euch" keine fertigen libraries ... wo wird denn etwas neu erfunden? Auch mit einer lib mutt du den ComPort öffnen, die parameter festlegen, daten übertragen und schließen. Viel mehr macht dieser code auch nicht.
naja a) ging es mir mehr ums prinzip (nicht um konkret diesen fall) b) ist das ganze dann "abstrahiert"(er), c) hat sich jemand (der sich auskennt!) Gedanken darüber gemacht, wie alles funktioniert... (alles mit sinnvollen Defaultwerten initialisiert..usw.) d) gibt es oft eine Anleitung/Beispiele.. usw. usw. oft auch einheitlicher (wenn nicht jeder seine eigene Suppe bäckt) austauschbarer/usw. (Basisklassen usw. ) und wenn man sich nur den code ansieht, als vorlage... konkret: es fehlt in dem oben genannten code, z.b. Funktionen um die vorhandenen Seriellen Schnittstellen aufzulisten.. sowas würde einer fertige Library sicher bieten..
Robert L. schrieb: > naja > a) ging es mir mehr ums prinzip (nicht um konkret diesen fall) schon klar > b) ist das ganze dann "abstrahiert"(er), von was soll man noch abstrahieren, platfomunabfhängig? > c) hat sich jemand (der sich auskennt!) Gedanken darüber gemacht, wie > alles funktioniert... (alles mit sinnvollen Defaultwerten > initialisiert..usw.) ist hier auch der fall > d) gibt es oft eine Anleitung/Beispiele.. sind sogar oben verlinkt, MSDN enthält das alles > oft auch einheitlicher (wenn nicht jeder seine eigene Suppe bäckt) > austauschbarer/usw. (Basisklassen usw. ) und wenn man etwas abseits des Formalfalles machen will, steht man wieder da. Jedes zusätzliche schicht verringt die Möglichkeiten. > konkret: es fehlt in dem oben genannten code, z.b. Funktionen um die > vorhandenen Seriellen Schnittstellen aufzulisten.. ist leider nicht vorgesehen, auch eine lib kann dabei nur Raten weil es keine offizelle möglichkeit dafür gibt. (Das gibt es erst in C#) > sowas würde einer fertige Library sicher bieten.. ich müsste nicht das die java lib für Com soetas bietet.
Die vorhandenen COM Ports frage man aus der Registry ab, das sind nur wenige Zeilen. Ansonsten lohnt sich nicht mal ein Wiki Eintrag, denn wenn man bei Google sucht, findet man schon zig Seiten mit dem selben Code.
>und wenn man etwas abseits des Formalfalles machen will, steht man >wieder da. Jedes zusätzliche schicht verringt die Möglichkeiten. für den allwissenden Programmierer ist das richtig.. für den otto-normal Programmierer eher umgekehrt.. ich würde mich grad etwas hart tun, ohne Abstraktionsschicht in ein MySQL file zu schreiben ;-) wegen java: ich glaub schon: http://www.java2s.com/Code/Java/Development-Class/Listtheports.htm
Peter II schrieb: > von was soll man noch abstrahieren, platfomunabfhängig? und ja, z.B: delphi <> Lazarus z.b. http://synapse.ararat.cz/doc/help/synaser.html#GetSerialPortNames usw. ich WILL vielleicht auch gar nicht immmer im Detail alles wissen, wissen woher die Information kommt, welche Ports es gibt... usw. (hab ja wichtigeres zu tun..)
Robert L. schrieb: > ich WILL vielleicht auch gar nicht immmer im Detail alles wissen, wissen > woher die Information kommt, welche Ports es gibt... usw. (hab ja > wichtigeres zu tun..) Ich habe noch kein Dokument von MS gesehen wo sie beschreiben wie man an die Liste der COM-Port kommt. Das auslesen der Registry ist also mehr ein HACK. Damit kann es in der nächsten version von Windows schon nicht mehr gehen. viele Programme die Ich kenne überlassen auch einfach die eingabe der Nutzer. Die brauchen überhaupt keine Liste. Ich habe auch noch nie die Liste der Comport abgefragt, obwohl ich schon einige Programme für den Com-Port geschrieben habe.
Robert L. schrieb: > wegen java: > > ich glaub schon: Nützt hier leider nichts, da nur für solaris und linux verfügbar. Das war aber nicht die Frage. Gruss Reinhard
wie gesagt MIR ist es einfach SCH.. egal offensichtlich gibt es mehrere Möglichkeit und es gibt leute die sich damit beschäftigen: http://www.naughter.com/enumser.html also WARUM ZUM TEUFEL soll man jedes mal das Rad neu erfinden?
zitat: C:\>javac ListPorts.java C:\>java ListPorts Serial port: COM7 Serial port: COM10 Serial port: COM3 Parallel port: LPT1 Parallel port: LPT2 ist das jetzt die C platte von einem solaris oder linux :-) http://pradnyanaik.wordpress.com/2009/04/07/communicating-with-ports-using-javaxcomm-package-for-windows/ (arduino IDE ist auch JAVA und die zeigt auch nur vorhandene COM ports an..)
Robert L. schrieb: > lso WARUM ZUM TEUFEL soll man jedes mal das Rad neu erfinden? wer erfinden denn das Rad neu? Die Liste der Comports war überhaupt nicht die Fragestellung. Es ging um den Zugriff auf einen ComPort. Und dabei hilft eine Lib nicht wirklich weiter weil es am ende genau das gleiche gemacht werden muss.
>ie Liste der Comports war überhaupt >nicht die Fragestellung. es gibt auch Leben außerhalb des Tellerrandes...
Peter II schrieb: > Ich habe noch kein Dokument von MS gesehen wo sie beschreiben wie man an > die Liste der COM-Port kommt. Das auslesen der Registry ist also mehr > ein HACK. Damit kann es in der nächsten version von Windows schon nicht > mehr gehen. Das ist sicherlich kein Hack, und den Schlüssel HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM gibts meines Wissens schon immer in der Registry. Was denkst du wohl, wo das Java Dingens die Ports herholt? Man kommt vielleicht etwas aufwändiger noch über die SetupAPI ran, aber da steht auch nix anderes drin...wenn sich da was an der Windows API aändert muss das Java Ding auch angepasst werden, denn das wird die COM ports sicher nicht würfeln.
Christian R. schrieb: > Das ist sicherlich kein Hack, und den Schlüssel > HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM gibts meines Wissens > schon immer in der Registry. > Was denkst du wohl, wo das Java Dingens die > Ports herholt? und dannn wundern sich immer die leute das in der nächsten Windows version ihre Software nicht mehr läuft. So lange es nicht offizell beschrieben ist, ist es ein Hack.
> So lange es nicht offizell >beschrieben ist, ist es ein Hack. komplett unerwähnt ist es mal nicht http://technet.microsoft.com/en-us/library/cc940908.aspx und .Net http://technet.microsoft.com/en-us/subscriptions/index/system.io.ports.serialport.getportnames%28v=vs.90%29.aspx
Robert L. schrieb: > und .Net > > http://technet.microsoft.com/en-us/subscriptions/i... .net würde MS aber mit anpassen wenn sie änderungen an Registry vornehmen.
M$ ändert oft nicht mal die Versionsnummer vom windows, weil sie angst haben, dass programme sich nicht mehr installieren lassen.. (windows 7 = NT6.1) (+ siehe gemeckere über altlasten) dass M$ sowas ändert ist extrem unwahrscheinlich.. (ausserdem spräche das ja sowieso FÜR die verwendung einer library, braucht man einfach nur diese aktualisieren, neu compilieren, fertig...)
Peter II schrieb: > So lange es nicht offizell > beschrieben ist, ist es ein Hack. Na wenn du meinst. Kann man immer noch einen der 8 anderen Wege nutzen: http://www.naughter.com/enumser.html
@ Reinhard Kern
>Man stellt auch schnell fest, dass eine reines Frage-Antwort-Design
seine logischen Beschränkungen hat, ein Beispiel: der Slave kann sich
nach Herstellung der Verbindung nicht selbst anmelden, sondern der
Master muss immer wieder fragen, ob da jemand ist.
Ein Master Slave Protokol ist viel einfacher wie ein Multimaster
Protokoll.
Ein Problem das man bekommt wenn jede Station einfach etwas vor sich hin
plappert, sind Kollisionen. Eine Loesung dafuer waere ein Token, eine
Andere waere CSMA/CD. Beide ansaetze sind viel komplizierter als ein
Master Slave Protokoll.
Man erspart sich auch viel Aerger, wenn man die Kommunikation statusfrei
haelt. Das bedeutet fuer die Kommunikation ist die Reihenfolge der
Befehle wichtig oder nicht. Man sollte statusfrei bleiben.
Das bedeutet :
HeizungToggle sollte man vermeiden, denn der Befehl kann verloren gehen.
Ersetzen mit HeizungEin & HeizungAus. Da kann man einen Befehl
wiederholen, wenn's denn sein muss, weil ein CRC Fehler gemeldet wurde.
Wow :-) Ich hätte nicht mit soviel Feedback gerechnet! > Wenn das funktioniert, wovon ich mal ausgehe. Dann bitte einen > Wiki-Artikel machen. Soweit bin ich noch lange nicht! Ich muss das gasnze ja auch erst mal selber verstehen. Ich gehöre nämlich auch zu denen die gerne das Rad neu erfinden ;-) Der Tueller
Der Vollständigkeit halber, hier wie man die verfügbaren Ports abfragen kann: char buffer[1024*32]; buffer[0] = 0; buffer[1] = 0; QueryDosDevice( NULL, buffer, sizeof(buffer) ); int ptr = 0; while ( 1 ) { if ( buffer[ptr] == 0 ) break; if ( buffer[ptr] == 'C' && buffer[ptr+1] == 'O' && buffer[ptr+2] == 'M' ) printf( "PORT: %s\n", &buffer[ptr] ); ptr += strlen( &buffer[ptr] )+1; } Torben, wenn Du fragen zu dem Code hast beantworte ich natürlich gerne.
Horst schrieb: > Der Vollständigkeit halber, hier wie man die verfügbaren Ports abfragen > kann: aber DosDevice funktionieren doch nur bis Com9 und auch tcp2com wird nicht erkannt oder nicht?
@Peter II: Ich habe das mit einem USB-RS232 der als COM20 konfiguriert war getestet. Das funktioniert. Sowie die virtuellen Ports von com0com werden auch erkannt.
Hi, also ich dachte ich schreib mal in diesen Thread weil es eigentlich ganz gut zum Thema passt. Ich hab es jetzt so gelöst:
1 | void send(CString PortSpecifier, CString data){ |
2 | |
3 | |
4 | DCB dcb; |
5 | DWORD byteswritten; |
6 | HANDLE hPort = CreateFile( PortSpecifier, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); |
7 | if (!GetCommState(hPort,&dcb)) |
8 | printf("error1"); |
9 | dcb.BaudRate = CBR_9600; //9600 Baud |
10 | dcb.ByteSize = 8; //8 data bits |
11 | dcb.Parity = NOPARITY; //no parity |
12 | dcb.StopBits = ONESTOPBIT; //1 stop |
13 | |
14 | if (!SetCommState(hPort,&dcb)) |
15 | printf("error2"); |
16 | |
17 | bool retVal = WriteFile(hPort,data,1,&byteswritten,NULL); |
18 | CloseHandle(hPort); //close the handle |
19 | |
20 | } |
und im Grunde will ich einfach z.b. eine "0" schicken und dass immer wieder. Das Funktioniert auch alles wunderbar, dass einzige Problem ist, dass ich diese 0 nur mit einer Frequenz von maximal ca 7-8Hz senden kann. Das Problem ist wahrscheinlich, dass ich das komplette Prozedere für jede 0 neu durchlaufe. Kennt vielleicht jemand ne Möglichkeit das schneller zu realisieren? ich müsste eher so auf minimal 100Hz kommen. Viele Grüße Jan
Jan L. schrieb: > Kennt vielleicht jemand ne Möglichkeit das schneller zu realisieren? ich > müsste eher so auf minimal 100Hz kommen. umschreiben? du brauchst du nocht ständig den Port zu öffnen und zu schließen. Dein Hauptprogramm muss den Port öffnen und dann besteht das senden wirklich nur aus senden:
1 | void send(CString PortSpecifier, CString data){ |
2 | bool retVal = WriteFile(hPort,data,1,&byteswritten,NULL); |
3 | }
|
Deine Fehlerauswertung lässt zu wünschen übrig. Den Rückgabewert von CreateFile musst Du auswerten, und nur, wenn der gültig ist, darfst Du mit hPort irgendwas anfangen. Wenn GetCommState einen Fehler zurückgibt, solltest Du nicht weitermachen, sondern den Kram abbrechen. Und den Rückgabewert von WriteFile in eine Variable zu packen, ist zwar nett, aber wenn Du die nicht auswertest, kannst Du das auch sein lassen. Schlussendlich solltest Du überlegen, ob ein CString-Objekt der WriteFile-Funktion übergeben werden kann. Und dann noch: Warum schreibst Du nur ein Byte mit einem WriteFile-Aufruf? Und warum öffnest und schließt Du die serielle Schnittstelle für jedes einzelne Byte?
ok, ich weiß nicht wieso ich es immer geöffnet und geschlossen hab... jetzt öffne ichs am anfang schreib rein solange ich will und schliesse ihn danach... funktioniert auch alles super. Ich schreib nur ein Byte weil ich den Comm Prot nur als Pulsgeber für mein Oszilloskop verwende um einfach meine Frequenz mit der ich arbeite ein bisschen im Blick zu behalten, bzw. nach zu prüfen ob diese konstant bleibt.
Jan L. schrieb: > Ich schreib nur ein Byte weil ich ... hust Und Du glaubst, daß so ein softwaregesteuertes Senden einzelner Bytes dazu taugt, eine Frequenz konstant zu halten?
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.