Hallo zusammen, ich versuche ein kleines Programm in C oder C++ zu schreiben das Daten per RS232 versendet versendet. Es geht darum einem Messgerät einen 4 Byte langen Datenrahmen zu senden, wobei in jedem Byte ein Befehl in Form einer Dezimalzahl drinsteht. Hat mir jemand einen Tipp wie ich auf die RS232-Schnittstelle zugreifen kann und wie man einen sollchen Datenrehmen generiert ? Danke schonmal vorab Schönen Samstag noch Gruß Michael
Michael schrieb: > Hat mir jemand einen Tipp wie ich auf die RS232-Schnittstelle zugreifen > kann Ist google heute kaputt? Aus einem anderen Programm zusammenkopiert sieht das etwa so aus, falls du von Windows sprichst:
1 | #include <windows.h> |
2 | |
3 | typedef HANDLE filehandle_t; |
4 | |
5 | // erste serielle Schnittstelle als Defaultwert, wenn nichts anderes
|
6 | // angegeben ist
|
7 | // (unter Windows sind die seriellen Schnittstellen ab 1 durchnummeriert,
|
8 | // also COM1:, COM2: etc.)
|
9 | // 1, 2... für COM1, COM2...
|
10 | const int DEFAULT_SERIAL = 1; |
11 | |
12 | |
13 | |
14 | void init_comm() |
15 | {
|
16 | const char *devicename = "COM1:"; |
17 | DWORD dwError; |
18 | BOOL fSuccess; |
19 | |
20 | SerielleSchnittstelle = CreateFile( devicename, |
21 | GENERIC_READ | GENERIC_WRITE, |
22 | 0, |
23 | NULL, |
24 | OPEN_EXISTING, |
25 | 0, |
26 | NULL
|
27 | );
|
28 | |
29 | if( SerielleSchnittstelle == INVALID_HANDLE_VALUE ) |
30 | {
|
31 | dwError = GetLastError(); |
32 | // Fehlerbehandlung...
|
33 | }
|
34 | |
35 | DCB dcb; // device control block: Parameter der ser. Schnittstelle |
36 | |
37 | // aktuelle Einstellungen der seriellen Schnittstelle holen:
|
38 | fSuccess = GetCommState(SerielleSchnittstelle, &dcb); |
39 | if( !fSuccess ) |
40 | {
|
41 | // Fehlerbehandlung...
|
42 | }
|
43 | |
44 | |
45 | dcb.BaudRate = CBR_9600; |
46 | dcb.ByteSize = 8; |
47 | dcb.Parity = NOPARITY; |
48 | dcb.fParity = FALSE; |
49 | dcb.StopBits =ONESTOPBIT; |
50 | |
51 | //dcb.Parity = EVENPARITY;
|
52 | //dcb.fParity = TRUE;
|
53 | |
54 | dcb.fOutxDsrFlow = FALSE; |
55 | dcb.fDtrControl = DTR_CONTROL_ENABLE; |
56 | dcb.fDsrSensitivity = FALSE; |
57 | |
58 | |
59 | dcb.fTXContinueOnXoff = FALSE; |
60 | dcb.fOutX = 0; // XON/XOFF aus |
61 | dcb.fInX = 0; // XON/XOFF aus |
62 | dcb.fErrorChar = FALSE; |
63 | dcb.fNull = FALSE; |
64 | |
65 | //dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
66 | dcb.fRtsControl = RTS_CONTROL_DISABLE; |
67 | |
68 | dcb.fOutxCtsFlow = false; |
69 | |
70 | fSuccess = SetCommState( SerielleSchnittstelle, &dcb ); |
71 | if (!fSuccess) |
72 | {
|
73 | // Fehlerbehandlung...
|
74 | }
|
75 | |
76 | COMMTIMEOUTS timeout; |
77 | |
78 | timeout.ReadIntervalTimeout = MAXDWORD; |
79 | timeout.ReadTotalTimeoutMultiplier = 0; |
80 | timeout.ReadTotalTimeoutConstant = 0; |
81 | timeout.WriteTotalTimeoutMultiplier = 100; |
82 | timeout.WriteTotalTimeoutConstant = 10000; |
83 | |
84 | if( !SetCommTimeouts( SerielleSchnittstelle, &timeout ) ) |
85 | {
|
86 | dwError = GetLastError(); |
87 | // Fehlerbehandlung...
|
88 | }
|
89 | |
90 | }
|
91 | |
92 | |
93 | |
94 | void exit_comm() |
95 | {
|
96 | CloseHandle( SerielleSchnittstelle ); |
97 | SerielleSchnittstelle = INVALID_HANDLE_VALUE; |
98 | }
|
99 | |
100 | |
101 | ...
|
102 | |
103 | DWORD nWritten = 0; |
104 | WriteFile( SerielleSchnittstelle, |
105 | "abcd", |
106 | strlen( "abcd" ), |
107 | &nWritten, |
108 | NULL
|
109 | );
|
110 | if( nWritten!=( 4 ) ) |
111 | {
|
112 | // Fehlerbehandlung...
|
113 | }
|
> und wie man einen sollchen Datenrehmen generiert ?
char-Array anlegen, füllen und mit WriteFile() wegschicken; siehe oben.
PS: Das const int DEFAULT_SERIAL = 1; kann weg; dafür fehlt am ANfang noch ein filehandle_t SerielleSchnittstelle;
Klaus Wachtler schrieb: > const char *devicename = "COM1:"; woher kommt immer der ":" in der MSDN finde ich ihn nicht?
Das mit COM1: habe ich aus dem Gedächtnis geschrieben, kann auch sein, daß der Doppelpunkt weg muß. Wenn ich mich recht entsinne, gehört er aber hin - sonst könnte ja auch eine Datei mit dem Namen COM1 gemeint sein.
Klaus Wachtler schrieb: > Wenn ich mich recht entsinne, gehört er aber hin - sonst könnte ja auch > eine Datei mit dem Namen COM1 gemeint sein. und mit : könnte ein laufwerk gemeint sein, nein er muss weg.
Laufwerke haben doch nur einen Buchstaben; zumindest unter DOS waren die Devices COM1:, COM2; LPT: etc.. Nachdem Windows doch eine DOS-GUI ist ... Ich mache aber nicht viel mit Windows, insofern überlasse ich es anderen, das zu probieren.
Es gibt übrigens noch weitere Namen mit ein paar Backslashes drin für die Geräte in neueren Win-Versionen, irgendwas in der Art \\dev\com1 oder so; die würden sicher auch gehen. (Habe aber gerade keine Lust, die genauen Namen herauszusuchen; ich sitze vor einem Napf mit leckerstem Essen.)
@Klaus Wachtler unter windows trennt der ":" hinter einen Dateiname den Streamnamen von Dateinamen. Eine Datei kann mehrere Inhalte haben Datei:1 Datei:2. Keine Ahnung für was das sinnvoll sein soll. Bin mir aber sicher das es COM1 ohne : sein muss. Besser ist gleich "\\.\COMx" zu verwenden, dann geht es auch mit x > 10
Peter II schrieb: > Bin mir aber sicher das es COM1 ohne : sein muss. kann gut sein! > > Besser ist gleich "\\.\COMx" zu verwenden, dann geht es auch mit x > 10 Genau das meinte ich; statt dev muß man natürlich einen Punkt nehmen, damit es nicht zu sehr nach Unix aussieht. Nur zur Sicherheit: die \ in den Namen müssen in einem C-String natrlich gedoppelt werden, also z.B. "\\\\.\\COM1" im Quelltext.
Im Umkehrschluß heißt das aber dann doch, daß man keine Datei mit dem schönen Namen COM1 erzeugen und verwenden kann? Vielleicht gibt es dann in Windows10SP325 einen Workaround dafür...
Klaus Wachtler schrieb: > Im Umkehrschluß heißt das aber dann doch, daß man keine Datei mit dem > schönen Namen COM1 erzeugen und verwenden kann? ja so ist es. (ebenso wie NUL, LPT1 .. http://msdn.microsoft.com/en-us/library/aa365247.aspx aber immerhin ist es gut dokumentiert. > Vielleicht gibt es dann in Windows10SP325 einen Workaround dafür... das es bis jetzt noch niemand wirklich gestört hat, glaube ich kaum das sie auf diesen Feature verzichten.
Peter II schrieb: > aber immerhin ist es gut dokumentiert. Das hilft einem durchschnittlichen Endanwender, der nach einem Dateinamen gefragt wird, nur bedingt :-) Naja, mich soll es nicht stören.
Hallo zusammen, ich versuch im Moment das selbe und habe schon beim initialisieren des Prots Probleme.. Ich programmiere unter Visual Studio mit C++ bei diesem Code #include <windows.h> #include <iostream> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <conio.h> #include <string> HANDLE SerielleSchnittstelle; void main(){ SerielleSchnittstelle = CreateFile(gszPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (SerielleSchnittstelle == INVALID_HANDLE_VALUE); // error opening port; abort } kommen die Fehler: error C2065: 'gszPort': nichtdeklarierter Bezeichner warning C4390: ';': Leere kontrollierte Anweisung aufgetreten; ist dies beabsichtigt IntelliSense: Der Bezeichner ""gszPort"" ist nicht definiert. diesen Teil des Codes habe ich von MSDN.. Danke schonmal im Voraus Gruß Lars
Lars schrieb: > SerielleSchnittstelle = CreateFile(gszPort, GENERIC_READ | > GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); Das sind aber erstmal C Grundlagen die da fehlern. du verwendest eine variable gszPort die du überhaupt nicht deklarier hast. Wenn man schon kopiert, dann sollte man alles kopieren oder oder man muss wirklich auch mal selber denken.
Bei Microsoft steht da auch nicht mehr.. also kopiert habe ist alles.. Ich habe auch schon zu deklarieren z.B. mit const char *gszPort = "portname"; Darauf folgt die Meldung: error C2664: 'CreateFileW': Konvertierung des Parameters 1 von 'const char *' in 'LPCWSTR' nicht möglich
Lars schrieb: > Ich habe auch schon zu deklarieren z.B. mit const char *gszPort = > > "portname"; > error C2664: 'CreateFileW': Konvertierung des Parameters 1 von 'const > char *' in 'LPCWSTR' nicht möglich das ist doch schon mal der richtige ansatz. das LPCWSTR zeigt dir das der compiler hier unicode will und ein char* ist nun mal kein unicode. Stell das Projekt auf nicht unicode ein und schon sollte es gehen. Wenn du unicode brachst dann darst du nicht char* verwenden sonder musst wchar* (oder so ähnlich) verwenden.
Hi, falls du char* verwenden willst , brauchst du CreateFileA
1 | bool SerialPort::SerialOpen(const std::string port, _PortSettings* set) |
2 | {
|
3 | bool status; |
4 | hComm = CreateFileA(port.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, |
5 | OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); |
6 | if(hComm == INVALID_HANDLE_VALUE) {status = false;} |
7 | else { ... ; status = true;} |
8 | |
9 | return status; |
10 | }
|
wobei hComm ein HANDLE ist. Gruß
Danke für eure Tipps hat mir sehr geholfen.. Werde mich jetzt erstmal einwenig mit den DCB-Einstellungen beschäftigen müssen.. Wie kann ich den festlegen welcher COM-Port angesprochen werden soll ? Könnt ihr mir einen gutes Programm empfehlen mit dem ich die Kommunikation auf der RS232 Schnittstelle mitschreiben kann ? Ist vielleicht ganz Praktisch wenn es ans senden und empfangen geht. Diesen Code habe ich bis jetzt zustande gebracht und er compiliert schonmal ohne fehler.. ;) #include <windows.h> #include <iostream> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <conio.h> #include <string> using namespace std; HANDLE SerielleSchnittstelle; DWORD dwError; BOOL fSuccess; const char *gszPort = "portname"; void open(){ SerielleSchnittstelle = CreateFileA(gszPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); //if (SerielleSchnittstelle == INVALID_HANDLE_VALUE) { //Handle the error. //return; //} //COM-Port config DCB dcb; // device control block: Parameter der ser. Schnittstelle /* // aktuelle Einstellungen der seriellen Schnittstelle holen: fSuccess = GetCommState(SerielleSchnittstelle, &dcb); if( !fSuccess ) { // Fehlerbehandlung... } */ dcb.BaudRate = CBR_9600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.fParity = FALSE; dcb.StopBits =ONESTOPBIT; //dcb.Parity = EVENPARITY; //dcb.fParity = TRUE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fDsrSensitivity = FALSE; dcb.fTXContinueOnXoff = FALSE; dcb.fOutX = 0; // XON/XOFF aus dcb.fInX = 0; // XON/XOFF aus dcb.fErrorChar = FALSE; dcb.fNull = FALSE; //dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fOutxCtsFlow = false; /* fSuccess = SetCommState( SerielleSchnittstelle, &dcb ); if (!fSuccess) { // Fehlerbehandlung... } */ COMMTIMEOUTS timeout; timeout.ReadIntervalTimeout = MAXDWORD; timeout.ReadTotalTimeoutMultiplier = 0; timeout.ReadTotalTimeoutConstant = 0; timeout.WriteTotalTimeoutMultiplier = 100; timeout.WriteTotalTimeoutConstant = 10000; if( !SetCommTimeouts( SerielleSchnittstelle, &timeout ) ) { dwError = GetLastError(); // Fehlerbehandlung... } } void exit() { CloseHandle( SerielleSchnittstelle ); SerielleSchnittstelle = INVALID_HANDLE_VALUE; } void write(){ DWORD nWritten = 0; WriteFile( SerielleSchnittstelle, "abcd", strlen( "abcd" ), &nWritten, NULL ); if( nWritten!=( 4 ) ) { // Fehlerbehandlung... } } Gute Nacht dann erstmal..
Das ist schon mal Mist:
1 | const char *gszPort = "portname"; |
Du mußt portname schon durch den korrekten Namen der seriellen Schnittstelle ersetzen. Und damit sollte dann auch diese Frage beantwortet sein Lars schrieb: > Wie kann ich den festlegen welcher COM-Port angesprochen werden soll? Wie die Namen aussehen steht im schon geposteten Link: http://msdn.microsoft.com/en-us/library/aa365247.aspx
Jean Player schrieb: > Hi, > falls du char* verwenden willst , brauchst du CreateFileA NEIN! man sollte immer CreateFile verwenden, der compiler entscheidet welches für diesen Projekt das richtige ist. Man sollte nicht Unicode und nicht unicode mischen. also Projekt richtig einstellen dann geht es auch ohne das A.
Hi, Peter II schrieb: > NEIN! man sollte immer CreateFile verwenden, der compiler entscheidet > welches für diesen Projekt das richtige ist. Grundsätzlich schon richtig. Aber wenn ich den Namen des COM Ports als UTF8 string bekommen hätte(aus welchem Grund auch immmer, sei jetzt dahin gestellt) und UNICODE wäre an. Würde ich es mir auch schenken und ein converting zu UTF16 machen und stattdessen CreateFileA benutzen (solange man weiss was man macht ). >Man sollte nicht Unicode und nicht unicode mischen. Wie du schon sagst, man sollte nicht aber kann :-) > also Projekt richtig einstellen dann geht es auch ohne das A. Also im Visual Studio Menu : -->Project -->Properties -->Configuration Properties -->C/C++ -->Preprocessor -->Preprocessor Definitions Unicode abstellen. GRUß
Hallo zusammen, habe bei der Einstellung nun WIN32 _DEBUG _CONSOLE %(PreprocessorDefinitions) UNICODE, _UNICODE drinstehen. Leider nimmt er den Befehl ohne A immernochnicht an..
Ok Kommando zurück ;) hab jetzt unter den Projekteinstellungen -> Konfigurationseigenschaften -> Zeichensatz -> Multibyte Zeichensatz verwenden eingestellt und jetzt gehts auch ohne A
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.