Forum: PC-Programmierung Serielleschnittstelle RS232 C++


von Fox X. (mr-fox)


Angehängte Dateien:

Lesenswert?

Hallo,

ich versuche grade Daten über die RS232 Schnittstelle zu Senden und zu 
Empfangen.

Ich Sende zwei Byte an die Hardware und erwarte dann eine Antwort von ca 
14 Byte.
Mein Programm bleibt allerdings beim Lesen stehen, da ich nicht weiß ob 
er wirklich sendet (hab kein Oszi um zu Messen), denke ich mal er wartet 
auf eine Antwort die nie kommt.

kann es sein das ich zu schnell bin und evt ein wait irgendwo brauche?
ich denke das er den Port richtig öffnet, wenn ich mit einen anderen 
Programm auf den Port nach den öffnen zugreifen will, bekomme ich eine 
Fehlermeldung das der Port bereits verwendet wird.

wäre nett wenn ihr mir weiter helfen könntet.
Ich nutze c++ in Visual Studio

ich habe diese Frage auch in einem anderen Forum gestellt, jedoch 
bekomme ich hier keine Antwort.

ich würde mich auch über eine Alternative Lösung freuen.

danke

von Peter II (Gast)


Lesenswert?

warum verwendest du *.txt für c++ dateien?

Das lesen sieht eigentlich gut aus. Ein wait (oder besser Sleep) ist 
nicht notwendig. Aber du beachtest nicht das das die Anzahl die Maximale 
anzahl von bytes ist, das read return dir anzahl der gelesen bytes. Wenn 
also 5 byte ankommen dann kann es schon passieren das read dann schon 
beendet. Damit hast du aber nicht die 14 byte gelesen.

Was macht eigentlich der .net code zwischen deinem C++ code? Oder ist 
das C++.net

von Fox X. (mr-fox)


Lesenswert?

Hallo,

danke für die antwort.

txt einfach nur daher, weil ich die Klasse schnell rauskopiert habe und 
irgendwo zwischenspeichern musste und nicht extra den Compiler starten 
wollte.

der c# Code kommt daher, das ich vorher die ganze Klasse in c# 
geschrieben habe, aber aus Kompatibilitätsgründen es nun doch in c++ 
umsetzen muss.
Ich hatte die Fragmente drin gelassen, weil ich mir nicht Sicher war ob 
der c++ an der Stelle so Funktioniert.
Der c# Code funktioniert einwand frei und Komuniziert auch wunderbar mit 
der Hardware in der c++ Klasse hängt er sich auf.

also in der Beschreibung steht das die Hardware mir 14 Byte als Antwort 
schickt. Hast du eine Lösung oder Ansatz für mich?

gruß

von Justus S. (jussa)


Lesenswert?

Fox Xx schrieb:
> (hab kein Oszi um zu Messen)

dann häng doch mal einen anderen PC dran (oder eine andere Schnittstelle 
auf dem PC, auf das Programm läuft) und schau, ob der was empfängt...

von Peter II (Gast)


Lesenswert?

Fox Xx schrieb:
> lso in der Beschreibung steht das die Hardware mir 14 Byte als Antwort
> schickt. Hast du eine Lösung oder Ansatz für mich?

ja, warte bis du 14 byte zuammen hast. Wenn du erst 4 byte ampfangen 
hast dann musst noch auf weitere 10byte warten.

von Fox X. (mr-fox)


Lesenswert?

gut und nun wartet er bis die kommen restlichen bytes kommen, wenn die 
natürlich nie kommen steht das programm.
wie löse ich das problem

in c# ist das arbeiten mit der rs232 so schön einfach.

von Peter II (Gast)


Lesenswert?

Fox Xx schrieb:

> gut und nun wartet er bis die kommen restlichen bytes kommen, wenn die
> natürlich nie kommen steht das programm.
> wie löse ich das problem
dann gibt es ein timeout, den kann man bei der schnittstelle einstellen.

>in c# ist das arbeiten mit der rs232 so schön einfach.
nein es ist dort genauso, wenn du es nicht beachtest hast dann hattest 
du bis jetzt glück das es funktioniert

http://msdn.microsoft.com/de-de/library/ms143549.aspx

von Purzel H. (hacky)


Lesenswert?

Man kann blockierend arbeiten, oder nicht blockierend. Aus Debug- und 
anderen Gruenden wuerd ich nicht blockierend bevorzugen. Man muss auch 
immer damit rechnen, dass das Kabel nicht eingesteckt wurde, resp erst 
nachtraeglich eingesteckt wird, sowie irgendwann gezogen wird. In allen 
Faellen sollte sich die Software nicht aufhaengen. Ein vernuenftiges 
Protokoll hilft da eine Menge

von Peter II (Gast)


Lesenswert?

Hex Oschi schrieb:
> Ein vernuenftiges Protokoll hilft da eine Menge
wenn keine Daten mehr kommen, hilft das Protokoll auch nicht mehr 
weiter.

von Fox X. (mr-fox)


Lesenswert?

wie soll das protokoll aussehen?

also ich denke in c# wird der timeout wohl irgend ein default haben, 
wundert mich das der in c++ kein hat.

könnt ihr mir beim einstellen des timeouts helfen?

von Peter II (Gast)


Lesenswert?

Fox Xx schrieb:
> könnt ihr mir beim einstellen des timeouts helfen?

http://msdn.microsoft.com/en-us/library/aa363437%28v=vs.85%29.aspx

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

> txt einfach nur daher, weil ich die Klasse schnell rauskopiert habe
> und irgendwo zwischenspeichern musste

wenn du das als cls_COM.c abgespeichert hättest, hätte das länger 
gedauert? Merkwürdig ....

von Purzel H. (hacky)


Lesenswert?

>>Hex Oschi schrieb:
>> Ein vernuenftiges Protokoll hilft da eine Menge
>
>wenn keine Daten mehr kommen, hilft das Protokoll auch nicht mehr
weiter.

Doch, das Protokol hilft das sich die Software nicht blockiert. Man kann 
das Device dann ja neu booten und die software macht weiter.

von Peter II (Gast)


Lesenswert?

Hex Oschi schrieb:
> Doch, das Protokol hilft das sich die Software nicht blockiert. Man kann
> das Device dann ja neu booten und die software macht weiter.
nein denn ein Protokoll ist nur für den Gut-Fall da, wenn jemand den 
Stecker zieht hilft das Protokoll nicht weiter. Dann muss man mit 
sinnvollen Timeouts arbeiten und dann zu einem Status zurückgehen von 
den man neu beginnen könnte.

von Fox X. (mr-fox)


Lesenswert?

das habe ich noch im Netz gefunden, würde das damit gehen?
Es ist ja möglich noch mehr Register einzustellen, welche wären den noch 
sinnvoll?
1
COMMTIMEOUTS cto;
2
ZeroMemory(&cto,sizeof(COMMTIMEOUTS));
3
4
cto.ReadIntervalTimeout            = 1000;
5
cto.ReadTotalTimeoutMultiplier    = 10;        
6
cto.ReadTotalTimeoutConstant    = 5;
7
8
BOOL bResTimeout = SetCommTimeouts(m_serialcon, &cto);
9
10
if (!bResState )
11
{
12
   return 0;
13
}

also ich denke mal das er hier nach 1000ms das lesen Abbricht oder?
aber was macht Multiplier und Constant?

> wenn du das als cls_COM.c abgespeichert hättest, hätte das länger
> gedauert? Merkwürdig ....

ja, weil ich den Code auf einem Stick hatte aber auf dem Rechner kein 
Compiler
Edit: ok, hätte das natürlich im Editor als .c speichern können, hab ich 
ehrlich gesagt aber auch überhaupt nicht dran gedacht.

> http://msdn.microsoft.com/en-us/library/aa363437%2...

verstehe ich nicht ganz wie ich das genau Programmieren soll, wenn ich 
das richtig verstehe, soll hier die Read Methode in einem anderen Thread 
arbeiten oder?
aber würde der Thread dann nicht auch endlos weiterlaufen wenn keine 
Daten kommen, bzw er würde die Empfangegenen 3 Bytes nie weiter reichen, 
weil er auf die anderen 10 Bytes wartet?

danke und gruß

von Peter II (Gast)


Lesenswert?

dafür muss man mehr wissen was du genau an daten erwartest bzw was von 
der gegenstelle gesendet wird.

Du hast gesagt das die Gegenstelle immer 14byte sendet. Dafür braucht 
man keinen Thread. Du sammelst einfach alle bytes bis du 14 hast und 
dann gibt du es zurück. Wenn du nach ein zu langen zeit nichts 
emfpfängst (über den Timeout festlege) dann muss du entscheiden wie es 
weiter gehen soll. In c++ ist es üblich eine Exception zu werfen.

von Uwe (Gast)


Lesenswert?

Ich hab da auch mal nen Problem gehabt, man mußte zwingend nen 
BuildCommDCB ausführen damit die Kommunikation funktioniert. Weil ALLE 
Elemente müssen initialisiert werden.
Also alle initalisiern oder BuildCommDCB :
typedef struct _DCB {
  DWORD DCBlength;
  DWORD BaudRate;
  DWORD fBinary  :1;
  DWORD fParity  :1;
  DWORD fOutxCtsFlow  :1;
  DWORD fOutxDsrFlow  :1;
  DWORD fDtrControl  :2;
  DWORD fDsrSensitivity  :1;
  DWORD fTXContinueOnXoff  :1;
  DWORD fOutX  :1;
  DWORD fInX  :1;
  DWORD fErrorChar  :1;
  DWORD fNull  :1;
  DWORD fRtsControl  :2;
  DWORD fAbortOnError  :1;
  DWORD fDummy2  :17;
  WORD  wReserved;
  WORD  XonLim;
  WORD  XoffLim;
  BYTE  ByteSize;
  BYTE  Parity;
  BYTE  StopBits;
  char  XonChar;
  char  XoffChar;
  char  ErrorChar;
  char  EofChar;
  char  EvtChar;
  WORD  wReserved1;
} DCB, *LPDCB;

 Nen sch.. Fehler der mir tagelang kopfschmerzen gemacht hat.

von Fox X. (mr-fox)


Lesenswert?

Peter II schrieb:
> dafür muss man mehr wissen was du genau an daten erwartest bzw was von
> der gegenstelle gesendet wird.
>
> Du hast gesagt das die Gegenstelle immer 14byte sendet. Dafür braucht
> man keinen Thread. Du sammelst einfach alle bytes bis du 14 hast und
> dann gibt du es zurück. Wenn du nach ein zu langen zeit nichts
> emfpfängst (über den Timeout festlege) dann muss du entscheiden wie es
> weiter gehen soll. In c++ ist es üblich eine Exception zu werfen.

was musst du den noch genau wissen?

uwe, muss ich wissen was die einzelnen Register bewirken?
einfach vor die Ini packen?
ist der Timeout mit drin?

gruß

von Peter II (Gast)


Lesenswert?

Fox Xx schrieb:
> was musst du den noch genau wissen?

wie das übertragungsprotokoll aussieht. Du behauptest das immer 14 
Zeichen gelesen werden sollen, das wiederspricht sich mit

PortLesen() == ">"

denn das ist nur 1 Zeichen.

Dann ist es wichtig zu wissen ob das Gerät von sich aus sendet oder ob 
du eine Anfrage hinschickt und darauf immer eine Antwort kommt (und in 
welcher zeit).

Wegen UWE:
es ist auch einfach möglich mit GetCommState die alten werte auszulesen 
und dann die werte anzupassen und dann sie wieder mit SetCommState zu 
setzten dann kannst du auf jeden fall keinen Vergessen.

von Fox X. (mr-fox)


Lesenswert?

also das Protokoll sieht so aus:

1. Es werden zwei Byte zwei ASCII zeichen an die Hardware geschickt.
2. Die Hardware schickt einmalig eine Antwort, zB 14 Zeichen.

also das Gerät sendet nicht selber.

ich hatte das oben etwas missverständlich ausgedrück sorry, also 
nochmal.
die Hardware sendet natürlich nicht immer genau 14 Zeichen, ich hatte 
das so geschrieben weil ich dachte ich hätte alle anderen Methoden aus 
der Datei entfernt und bezog mich daher nur auf die Methode 
"PositionLesen()", hier soll die Hardware laut der Beschreibung 14 
Zeichen als Antwort zurück senden, beginnend mit ">".
Laut meinen c# Code Funktioniert dies auch einwandfrei, lediglich in c++ 
bekomme ich es nicht hin.

Die Zeit ist eine gute frage, in meinen c# Code warte ich ein 
Augenblick, aber im Handbuch steht dazu nichts.

von Peter II (Gast)


Lesenswert?

Fox Xx schrieb:
> Zeichen als Antwort zurück senden, beginnend mit ">".

steht eventuell auch etwas über das ende drin? Zeilenumbruch? 0byte? 
Ohne ein Definiertes ende ist das Protokoll müll. Könnte ja sein das 
nach 10min noch etwas kommt.

von Fox X. (mr-fox)


Lesenswert?

nein,
>xxxxxxxxxxxxx
wobei x für Zahlen als ASCII stehen
also in c# hatte ich immer sofort die Antwort.

von Peter II (Gast)


Lesenswert?

Fox Xx schrieb:
> wobei x für Zahlen als ASCII stehen
> also in c# hatte ich immer sofort die Antwort.

und woher weiss du das die entwort vollständig war? Schau doch mal nach 
ob am ende ein 0x13 oder 0x12 kommt.

von Fox X. (mr-fox)


Lesenswert?

ok, nochmal sorry,*schäm
"ES werden alle Antworttelegramme mit einen CR (=hex13) 
vervollständigt."
"xxxxxxxx>"

von Peter II (Gast)


Lesenswert?

naja dann los.

Schreibe eine funktion die daten von der Serielen schnittstelle abruft 
bis eine CR kommt und sie dann als String zurück liefert

std::string s;
char c;
while( true ) {
  size_t r = readfile( c, 1 ... );
  if ( r != 1 ) {
     throw Exception("Fehler beim empfang");
  }
  if ( c == '\n' ) {
     break;
  }

  s += c;
}

return s;

so in der Art, man könnte auch mehre zeichen gleichzeitig empfangen aber 
man muss dann aber eh einzeln schauen ob das ende erreicht ist - für den 
anfang sollte es so aber gehen.

von Fox X. (mr-fox)


Lesenswert?

und wenn das CR nie kommt?
bzw wenn überhaupt nichts kommt?

von Uwe (Gast)


Lesenswert?


von Peter II (Gast)


Lesenswert?

Fox Xx schrieb:
> und wenn das CR nie kommt?
> bzw wenn überhaupt nichts kommt?
dann gibt es ja die exception - weil read nicht 1 zurückliefert. Wenn 
aber immer etwas kommt und nie ein \n dann geht dieser code nicht. Aber 
man könnte ja auch noch die länge begrenzen.

von Fox X. (mr-fox)


Lesenswert?

kennt ihr evt eine Klasse die sich um alles kümmert?
In der ich nur ein paar Methoden aufrufen muss wie "DatenLesen()"?

von Peter II (Gast)


Lesenswert?

Fox Xx schrieb:
> ennt ihr evt eine Klasse die sich um alles kümmert?
> In der ich nur ein paar Methoden aufrufen muss wie "DatenLesen()"?

was ist denn so schwer daran die funktion so zu schreiben wie ich sie 
schon hingeschrieben habe? Einfacher geht es nun wirklich nicht.

von Fox X. (mr-fox)


Lesenswert?

wird es morgen mal probieren,

was ist mit dem Registern von Uwe und oder dem Timeout?

Uwe schrieb:
> typedef struct _DCB {
>   DWORD DCBlength;
>   DWORD BaudRate;
>   DWORD fBinary  :1;
>   DWORD fParity  :1;
>   DWORD fOutxCtsFlow  :1;
>   DWORD fOutxDsrFlow  :1;
>   DWORD fDtrControl  :2;
>   DWORD fDsrSensitivity  :1;
>   DWORD fTXContinueOnXoff  :1;
>   DWORD fOutX  :1;
>   DWORD fInX  :1;
>   DWORD fErrorChar  :1;
>   DWORD fNull  :1;
>   DWORD fRtsControl  :2;
>   ...

von Peter II (Gast)


Lesenswert?

Versuch es doch mit den Timeout die du oben gefunden hast, etwas passen 
sie oder du musst sie verlängern oder kürzen.

Das von UWE brauchst du nicht wenn du

GetCommState
-> parameter anpassen
SetCommState

machst, den rest kannst du alles so lassen.

Selbst ohne Timeouts geht es, du könnte es passieren wenn jemand den 
stecker zieht das dein programm dann hängt.

von Hebel (Gast)


Lesenswert?

Hallo Fox Xx

in Deinem Code stimmt die Reihenfolge nicht.

DCB dcb;
dcb.DCBlength = sizeof(DCB);

zuerst Port-Config lesen
  GetCommState(m_PortHandle, &dcb)

// Konfigurationen des Ports setzen

wieso hier schon SetCommState und dann erst DCB-Parameter setzen?
Das  gehört hinter dcb.Binary=TRUE

*        if (SetCommState(m_PortHandle, &dcb))
*    {
*    m_StatusMeldung = "Fehler: Konnte Konfigurationen
*                nicht setzen!";
*      return false;
*    }
|
|        dcb.BaudRate    = m_Baudrate;      // Baud Rate
|        dcb.Parity      = m_Parity;        // Parity
|        dcb.ByteSize    = m_Databit;      // Data Bits
|        dcb.StopBits    = m_Stopbit;      // Stop Bits
|        dcb.fBinary = TRUE;
|--->

von Fox X. (mr-fox)


Lesenswert?

danke funktioniert

von Fox X. (mr-fox)


Lesenswert?

hi eine weitere frage zur rs232,

wenn ich jetzt keine ASCII Zeichen senden will, sondern Hex bzw Dezimal, 
gibt es da eine Lösung?

gruß

von Peter II (Gast)


Lesenswert?

Fox Xx schrieb:
> wenn ich jetzt keine ASCII Zeichen senden will, sondern Hex bzw Dezimal,
> gibt es da eine Lösung?
ja.

Wo sieht du den unterschied zwischen ASCII Hex und Dezimal? Wenn du dir 
darüber klar bist, dann sollte es auch klar sein wie man sie sendet.

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.