Forum: PC-Programmierung RS232 VS 2012 SP4 Error C2664


von Stefan F. (spezies31)


Lesenswert?

Hallo zusammen,

ich versuche eine serielle Schnittstelle mithilfe von C++ auszulesen. 
Ich habe mich vorher auf Google und im Forum umgeschaut und leider 
nichts passendes zu meiner eigenen Anwendung gefunden (Korrekturen 
werden einem nicht übel genommen :-D)

Zunächst einmal mein Code:


//Headerdateien

#include <stdio.h>  //Standard Input/Output Bibliothek
#include <Windows.h>


//Hauptprogramm Start

int main()
{

  //Öffnen der seriellen Schnittstelle

  DCB          sDcb;
  HANDLE       hFile;
  COMMTIMEOUTS sTo;


   hFile=CreateFile("\\\\.\\COM1",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXIST 
ING,FILE_ATTRIBUTE_NORMAL,0);
    if(hFile==INVALID_HANDLE_VALUE)return 0;
      memset(&sDcb,0,sizeof(sDcb));
      sDcb.DCBlength       = sizeof(sDcb);
      sDcb.BaudRate        = 9600;    // Baudrate
      sDcb.fParity         = FALSE;
      sDcb.fBinary         = TRUE;
      sDcb.Parity          = NOPARITY;// Kein Paritybit
      sDcb.StopBits        = ONESTOPBIT;
      sDcb.fOutxCtsFlow    = FALSE;
      sDcb.fOutxDsrFlow    = FALSE;
      sDcb.fDtrControl     = DTR_CONTROL_ENABLE;
      sDcb.fRtsControl     = RTS_CONTROL_ENABLE;
      sDcb.fDsrSensitivity = FALSE;
      sDcb.fAbortOnError   = FALSE;
      sDcb.ByteSize        = 8;       // 8 Datenbits

    if(!SetCommState(hFile,&sDcb))
    {
      CloseHandle(hFile);
      return 0;
    }

  sTo.ReadIntervalTimeout = MAXDWORD; // 0 ms Read-Tomeout
  sTo.ReadTotalTimeoutMultiplier = 0;
  sTo.ReadTotalTimeoutConstant   = 0;
  sTo.WriteTotalTimeoutMultiplier= 1; // 1*2 ms Write Timeout
  sTo.WriteTotalTimeoutConstant  = 2;
    if(!SetCommTimeouts((HANDLE)hFile,&sTo))
    {
       CloseHandle(hFile);
       return 0;
    }



  //Lesezugriff auf die serielle Schnittstelle

  DWORD dwCount;
  char  cData[16];

  ReadFile(hFile,cData,16,&dwCount,0);


  return 0;
}


Mit diesem Code bekomme ich folgenden Compilerfehler:

Fehler  1  error C2664: 'CreateFileW': Konvertierung des Parameters 1 
von 'const char [9]' in 'LPCWSTR' nicht möglich 
c:\users\master\documents\visual studio 
2012\projects\rs232_auslesen_02\rs232_auslesen_02\rs232_auslesen_02.cpp 
23  1  RS232_auslesen_02


Das Beispiel habe ich von folgender Seite:

http://members.inode.at/anton.zechner/az/Seriell.htm


Jetzt möchte ich gerne wissen ob jemand weiß was das Problem ist. 
Außerdem würde es mich interessieren ob das wirklich die einfachste Art 
und Weiße ist die Daten aus der seriellen Schnittstelle zu lesen. Für 
meine Anwendung ist es nur notwendig, dass ich die Daten danach noch im 
C++ Programm weiterverarbeiten kann. Eventuell notwendige Bibliotheken 
oder Programme für einfachere Lösungen können ohne Probleme installiert 
werden.

Ich möchte auch noch anmerken das ich ein ziemlich blutiger Anfänger mit 
C++ bin. Außer einem Semester in meinem Grundstudium habe ich keine 
Erfahrung damit.


Vielen Dank im voraus für eure Hilfe

Spezies31

von Peter II (Gast)


Lesenswert?

Stefan F. schrieb:
> Fehler  1  error C2664: 'CreateFileW': Konvertierung des Parameters 1
> von 'const char [9]' in 'LPCWSTR' nicht möglich

du hast eine Unicode projekt und übergibst kein Unicode.

teste mal mit

CreateFile(TEXT("\\\\.\\COM1"), ....

von Stefan F. (spezies31)


Lesenswert?

Hallo Peter II,

danke ich hatte nur die Lösung gefunden den Zeichensatz nicht 
festzulegen aber so ist das natürlich angenehmer (kann man nicht 
vergessen).

Ich hätte zudem noch drei andere Fragen:

1. Wird mit dem oberen Code die Serielle Schnittstelle dauernd 
abgefragt? Also bekomme ich immer den aktuellen Wert oder bekomme ich 
nur einen Wert.

2. Warum funktioniert meine Dauerschleife nicht (nachträglich 
eingefügt)?

Code der Dauerschleife:

...

while(TRUE)
{

...

Sleep(1000);
}
...

Die Dauerschleife soll das Datenabfragen nur immer wieder wiederholen, 
da beim Starten der .exe das Fenster sofort wieder zugeht (Sonst sehe 
ich ja nichts).

3. Ich lese beim googeln immer wieder von Lösungen mit dem 
"serialport"-Befehl und das man dafür das .Net Framework installiert 
haben muss. Könnte jemand kurz und prägnant die Möglichkeiten eine 
serielle Schnittstelle auszulesen aufzählen? Nur damit ich mal einen 
Überblick habe was es da alles gibt und was die vermutlich schnellste 
Technik in meinem Fall ist.


Mit freundlichen Grüßen

Spezies31

von Peter II (Gast)


Lesenswert?

Stefan F. schrieb:
> 1. Wird mit dem oberen Code die Serielle Schnittstelle dauernd
> abgefragt? Also bekomme ich immer den aktuellen Wert oder bekomme ich
> nur einen Wert.

sie wird so oft gelesen wie du read aufrufst
1
 DWORD dwCount;
2
  char  cData[16];
3
4
  ReadFile(hFile,cData,16,&dwCount,0);

hier liest du maximal 16 zeichen (im return von ReadFile steht die 
anzahl die wirklich gelesen wurden).

Wenn du noch mehr lesen musst, dann musst du halt readFile mehrfach 
ausführen.

> Warum funktioniert meine Dauerschleife nicht (nachträglich
> eingefügt)?
wo hast du sie eingefügt und was macht sie nicht?`

> Könnte jemand kurz und prägnant die Möglichkeiten eine
> serielle Schnittstelle auszulesen aufzählen?
du hast doch schon alles was du brauchst, was fehlt dir denn da noch?

von Stefan F. (spezies31)


Lesenswert?

Hallo Peter II,

erstmal danke für die Antwort.

Zunächst mal erkläre ich was ich tun will. Ich will zeitlich unbegrenzt 
(24/7) die Daten einer seriellen Schnittstelle (RS232) in regelmäßigen 
Abständen lesen und den aktuellen Wert in einer Variablen speichern.

Meine Idee dafür war, das ich einfach über den ReadFile Befehl eine 
Endlosschleife mit Wartezeit verwende. Diese habe ich wie folgt 
eingebaut:

//Headerdateien

#include <stdio.h>  //Standard Input/Output Bibliothek
#include <Windows.h>


//Hauptprogramm Start

int main()
{


  while(TRUE)
  {


  //Öffnen der seriellen Schnittstelle

  DCB          sDcb;
  HANDLE       hFile;
  COMMTIMEOUTS sTo;


   hFile=CreateFile(TEXT("\\\\.\\COM1"),GENERIC_READ|GENERIC_WRITE,0,0,OPEN 
_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
    if(hFile==INVALID_HANDLE_VALUE)return 0;
      memset(&sDcb,0,sizeof(sDcb));
      sDcb.DCBlength       = sizeof(sDcb);
      sDcb.BaudRate        = 9600;    // Baudrate
      sDcb.fParity         = FALSE;
      sDcb.fBinary         = TRUE;
      sDcb.Parity          = NOPARITY;// Kein Paritybit
      sDcb.StopBits        = ONESTOPBIT;
      sDcb.fOutxCtsFlow    = FALSE;
      sDcb.fOutxDsrFlow    = FALSE;
      sDcb.fDtrControl     = DTR_CONTROL_ENABLE;
      sDcb.fRtsControl     = RTS_CONTROL_ENABLE;
      sDcb.fDsrSensitivity = FALSE;
      sDcb.fAbortOnError   = FALSE;
      sDcb.ByteSize        = 8;       // 8 Datenbits

    if(!SetCommState(hFile,&sDcb))
    {
      CloseHandle(hFile);
      return 0;
    }

  sTo.ReadIntervalTimeout = MAXDWORD; // 0 ms Read-Tomeout
  sTo.ReadTotalTimeoutMultiplier = 0;
  sTo.ReadTotalTimeoutConstant   = 0;
  sTo.WriteTotalTimeoutMultiplier= 1; // 1*2 ms Write Timeout
  sTo.WriteTotalTimeoutConstant  = 2;
    if(!SetCommTimeouts((HANDLE)hFile,&sTo))
    {
       CloseHandle(hFile);
       return 0;
    }



  //Lesezugriff auf die serielle Schnittstelle

  DWORD dwCount;
  char  cData[16];

  ReadFile(hFile,cData,16,&dwCount,0);




  Sleep(1000);
  }

  return 0;
}



So wie ich das verstanden habe sollte mit diesem Code jede Sekunde eine 
Com-Schnittstelle geöffnet werden und 16 Zeichen aus der RS232 
Schnittstelle lesen. Allerdings verstehe ich dann nicht so richtig woher 
das Programm weiß wo/wann das Startbit kommt (sprich die 
Synchronisation).

Wie ich mir dann den effektiven Wert der Nachricht (z.B. Gewicht in kg 
oder eine Länge in Metern) aus der Nachricht rausziehe ist mir erstmal 
egal. Es geht mir nur darum mal in einem Wort oder Byte die 
Informationen einer Nachrichtenübertragung zu speichern.



Zu meiner Frage nach den Möglichkeiten zum auslesen von RS232 
Schnittstellen wollte ich auf vielleicht bekannte Bibliotheken raus mit 
denen man durch ein paar Zeilen Code ziemlich einfach eine RS232 
Schnittstelle auslesen kann. Beim googeln habe ich schon ein paar 
gefunden wie z.B.:

http://www.teuniz.net/RS-232/

Ich habe mich dann aber für den (anscheinend) Standardweg mit den 
ReadFile-Befehlen entschieden und mir ein Beispiel an folgendem Code 
genommen habe:

http://www.progforum.com/showthread.php?5504-RS232-Schnittstelle-mit-C-auslesen


Ich verwende Visual Studio 2012 SP4. Die meisten der von mir gefundenen 
Bibliotheken gibt es aber nicht für dieses Visual Studio und verursachen 
bei mir Compilerfehler (kann auch sein das ich evtl. etwas beim 
einbinden falsch mache da bin ich mir nicht so sicher).

von Peter II (Gast)


Lesenswert?

Stefan F. schrieb:
> Meine Idee dafür war, das ich einfach über den ReadFile Befehl eine
> Endlosschleife mit Wartezeit verwende. Diese habe ich wie folgt
> eingebaut:

naja, warum ständig den Port öffnen und dann nicht mal schließen?

Normalerweise öffnet man ihn einmal und liest ihn dann regelmäßig aus. 
Nur wenn es einen fehler gibt, kann man ihn erneut öffnen.

> . Allerdings verstehe ich dann nicht so richtig woher
> das Programm weiß wo/wann das Startbit kommt (sprich die
> Synchronisation).
dem Programm ist das egal, es kommt von der Hardware ein zeichen an und 
das liest du aus. Start und Stop macht schon selbständig die Hardware.

Das Programm könnte so aussehen

Port öffnen
while(1) {
  Daten lesen
  If Fehler beim Lesen {
     Port schließen
     Port öffnen
  }
}
Port schließen

> Zu meiner Frage nach den Möglichkeiten zum auslesen von RS232
> Schnittstellen wollte ich auf vielleicht bekannte Bibliotheken raus mit
> denen man durch ein paar Zeilen Code ziemlich einfach eine RS232
> Schnittstelle auslesen kann. Beim googeln habe ich schon ein paar
> gefunden wie z.B.:
ich verstehe nicht, was man an den 4 Funktionen noch vereinfachen will

CreateFile
SetCommState
SetCommTimeouts
ReadFile


Auch mit einer Lib musst du die Timeouts und Parameter setzen, genauso 
musst du ein Read machen. Was erhoffst du dir von einer Lib? Es gibt 
auch keine lib für eine while-schleife.

Beim suchen ein passenden Lib hast du mehr zeit verbracht als mit dem 
eigentlichen Programm.

von Stefan F. (spezies31)


Lesenswert?

Hallo Peter II,

erstmal wieder Danke für die schnelle und gute Antwort.

Mein Programm läuft jetzt so wie ich es mir vorgestellt habe.
Mein Code sieht jetzt so aus:
1
//Headerdateien
2
3
#include <stdio.h>    //Standard Input/Output Bibliothek
4
#include <Windows.h>  //Funktionen für die Kommunikation über RS232
5
6
7
//Hauptprogramm Start
8
9
int main()
10
{
11
12
  //Öffnen der seriellen Schnittstelle
13
  
14
  DCB          sDcb;
15
  HANDLE       hFile;
16
  COMMTIMEOUTS sTo;
17
18
  
19
   hFile=CreateFile(TEXT("\\\\.\\COM1"),GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
20
    if(hFile==INVALID_HANDLE_VALUE)return 0;
21
      memset(&sDcb,0,sizeof(sDcb));
22
      sDcb.DCBlength       = sizeof(sDcb);
23
      sDcb.BaudRate        = 9600;    // Baudrate
24
      sDcb.fParity         = FALSE;
25
      sDcb.fBinary         = TRUE;
26
      sDcb.Parity          = NOPARITY;// Kein Paritybit
27
      sDcb.StopBits        = ONESTOPBIT;
28
      sDcb.fOutxCtsFlow    = FALSE;
29
      sDcb.fOutxDsrFlow    = FALSE;
30
      sDcb.fDtrControl     = DTR_CONTROL_ENABLE;
31
      sDcb.fRtsControl     = RTS_CONTROL_ENABLE;
32
      sDcb.fDsrSensitivity = FALSE;
33
      sDcb.fAbortOnError   = FALSE;
34
      sDcb.ByteSize        = 8;       // 8 Datenbits
35
36
    if(!SetCommState(hFile,&sDcb))
37
    {
38
      CloseHandle(hFile);
39
      return 0;
40
    }
41
42
  sTo.ReadIntervalTimeout = MAXDWORD; // 0 ms Read-Tomeout
43
  sTo.ReadTotalTimeoutMultiplier = 0;
44
  sTo.ReadTotalTimeoutConstant   = 0;
45
  sTo.WriteTotalTimeoutMultiplier= 1; // 1*2 ms Write Timeout
46
  sTo.WriteTotalTimeoutConstant  = 2;
47
    if(!SetCommTimeouts((HANDLE)hFile,&sTo))
48
    {
49
       CloseHandle(hFile);
50
       return 0;
51
    }
52
53
54
55
  //Lesezugriff auf die serielle Schnittstelle (komplett)
56
57
    //Dauerschleife für ständiges Lesen
58
59
    while(1)
60
    {
61
62
      //einzelner Lesezugriff
63
      DWORD dwCount;
64
      char  cData[1];
65
66
      ReadFile(hFile,cData,1,&dwCount,0); //Lesen von 1 Byte (Größe einer char-Variablen) an Daten
67
68
      printf_s("Folgender Char wurde gelesen: %c \n",cData[0]);
69
70
71
      //Wenn ein Fehler auftritt erneutes öffnen des COM Ports
72
73
      if(ReadFile==FALSE)
74
      {
75
        //Öffnen der seriellen Schnittstelle
76
  
77
        DCB          sDcb;
78
        HANDLE       hFile;
79
        COMMTIMEOUTS sTo;
80
81
  
82
         hFile=CreateFile(TEXT("\\\\.\\COM1"),GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
83
          if(hFile==INVALID_HANDLE_VALUE)return 0;
84
          memset(&sDcb,0,sizeof(sDcb));
85
          sDcb.DCBlength       = sizeof(sDcb);
86
          sDcb.BaudRate        = 9600;    // Baudrate
87
          sDcb.fParity         = FALSE;
88
          sDcb.fBinary         = TRUE;
89
          sDcb.Parity          = NOPARITY;// Kein Paritybit
90
          sDcb.StopBits        = ONESTOPBIT;
91
          sDcb.fOutxCtsFlow    = FALSE;
92
          sDcb.fOutxDsrFlow    = FALSE;
93
          sDcb.fDtrControl     = DTR_CONTROL_ENABLE;
94
          sDcb.fRtsControl     = RTS_CONTROL_ENABLE;
95
          sDcb.fDsrSensitivity = FALSE;
96
          sDcb.fAbortOnError   = FALSE;
97
          sDcb.ByteSize        = 8;       // 8 Datenbits
98
99
          if(!SetCommState(hFile,&sDcb))
100
          {
101
            CloseHandle(hFile);
102
            return 0;
103
          }
104
105
          sTo.ReadIntervalTimeout = MAXDWORD; // 0 ms Read-Tomeout
106
          sTo.ReadTotalTimeoutMultiplier = 0;
107
          sTo.ReadTotalTimeoutConstant   = 0;
108
          sTo.WriteTotalTimeoutMultiplier= 1; // 1*2 ms Write Timeout
109
          sTo.WriteTotalTimeoutConstant  = 2;
110
            if(!SetCommTimeouts((HANDLE)hFile,&sTo))
111
              {
112
               CloseHandle(hFile);
113
               return 0;
114
              }
115
116
      }//IF-Anweisung zu für Neuöffnung des Ports bei einem Fehler
117
118
    }//Endlosschleife zu
119
120
121
  return 0;
122
}


Tut mir leid wegen der etwas verschobenen Formatierung.

Ich habe einen Befehlssatz gefunden "ComTools.h" und "ComTools.cpp" mit 
denen man es in 5 Zeilen Code machen kann. Aber ich finde die Version 
mit windows.h wesentlich übersichtlicher.

Warum ich nach anderen Möglichkeiten gefragt habe, war weil ich etwas 
verwirrt war wie das alles von statten gehen soll. Jetzt läuft die 
Übertragung aber und ich denke ich habe es verstanden.

Vielen Dank nochmal für deine Hilfe. Falls ich noch Probleme habe melde 
ich mich nochmal.


---

Wenn Du den Text oberhalb des Texteingabefeldes gelesen hättest, 
wüsstest Du, daß dieses Forum Tags für die Quelltextformatierung 
anbietet ...
[ c ] [ /c ]

-rufus

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Stefan F. schrieb:
> Mein Code sieht jetzt so aus:

warum ist der code zum öffnen der Schnittstelle Doppelt? Code den man 
mehrfach braucht legt man in eine Funktion.
1
ReadFile(hFile,cData,1,&dwCount,0);
warum wertest du den Return code nicht aus?

1
 if(ReadFile==FALSE)

wo kommt denn ReadFile her?

Und warum schließt du den Comport am ende nicht? (oder auch wenn ein 
Fehler aufgetreten ist)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Stefan F. schrieb:
> if(ReadFile==FALSE)

Das ist garantiert nicht das, was Du willst.

Vor allem: Das ist nie FALSE, denn ReadFile ist eine Funktion, und die 
hat eine Adresse, und die ist nicht Null.

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
Noch kein Account? Hier anmelden.