Daten per RS232 senden

Gast #2230320
Lesenswert?

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
#2230671
Lesenswert?

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.
#2230737
Lesenswert?

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.)
Gast #2230738
Lesenswert?

@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
#2230759
Lesenswert?

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.
Gast #2230773
Lesenswert?

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.
Gast #2237732
Lesenswert?

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
Gast #2237741
Lesenswert?

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.
Gast #2237753
Lesenswert?

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
Gast #2237760
Lesenswert?

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.
#2237804
Lesenswert?

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ß
Gast #2237906
Lesenswert?

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..
Gast #2237941
Lesenswert?

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
Gast #2238031
Lesenswert?

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.
#2238064
Lesenswert?

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ß

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren