Datenerfassung über 2 RS232 Schnittstellen
-
Hallo,
verwende zur Zeit 2 Com Schnittstellen um Daten, die über einen RS485 Bus übertragen werden, zu erfassen. (Com1 = TxD, Com2 = RxD)
Habe für jede Com einen Thread gemacht und erhalte auch die übertragenen Werte.
Das Problem ist, dass ich nach einiger Zeit (immer verschieden) zuerst eine Antwort und dann den Befehl erhalte. Das sehe ich deshalb, da ich die Daten mit einem Zeitstempel versehen habe!! Das Problem liegt in meiner SW, denn die Daten die über den Bus gesendet werden habe ich schon kontrolliert.
Kann mir jemand weiterhelfen ??
lg
-
markus.z84 schrieb:
Das Problem liegt in meiner SW, denn die Daten die über den Bus gesendet werden habe ich schon kontrolliert.
Kann mir jemand weiterhelfen ??
lgDa musst du schon mal was zeigen, hellsehen kann hier keiner. Ich vermute, dass mit der Synchro deiner zwei Threads was nicht stimmt. Hast du konsequent bei den Variablenzugriffen mit Synchronisationsmitteln gearbeitet? Welches Idee des Datenhandling hast du denn implementiert (pollst du oder arbeitet das ganze mit Interrupts)?
-
hallo AndyDD,
zuerst verwende ich
m_hThread = CreateThread( NULL, 0, EventHandler, (LPVOID)this, CREATE_SUSPENDED, &dwId );
dann wird ein Event gemacht !
CCommPort *pPort = (CCommPort*)lpParam; DWORD dwMask = EV_RXCHAR; if ( !pPort->SetMask( dwMask ) ) { pPort ->OnEventError( COMM_SET_EVNT_MASK_ERROR ); TRACE ( _T("Thread event handling exiting with error Can't set Mask!\r\n") ); return 1; } OVERLAPPED o; DWORD dwResMask=0; o.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); o.Internal = 0; o.InternalHigh = 0; o.Offset = 0; o.OffsetHigh = 0; while (1) { // exit from thread if ( pPort->lReqTerminate == 0) { CloseHandle( o.hEvent ); SetEvent( pPort->m_hEventTerminate ); TRACE ( _T("Thread event handling exiting with 0!\r\n") ); return 0; } // handling comm events if ( !WaitCommEvent( pPort->m_hComm, &dwResMask, &o ) ) { DWORD dwError = GetLastError(); if ( dwError != ERROR_IO_PENDING ) { pPort ->OnEventError( COMM_WAIT_FOR_EVENT_ERROR ); CloseHandle( o.hEvent ); SetEvent( pPort->m_hEventTerminate ); TRACE ( _T("Thread event handling exiting with 1!\r\n") ); return 1; } else { DWORD dwBytesTransfer; GetOverlappedResult( pPort->m_hComm, &o, &dwBytesTransfer, TRUE ); } } if ( dwResMask & EV_RXCHAR ) { DWORD dwError; COMSTAT comStat; pPort ->ClearError( &dwError, &comStat ); pPort ->OnRxChar( comStat.cbInQue, pPort->m_hComm ); } } // while CloseHandle( o.hEvent ); return 0; }Werden nun daten an z.B.: Com1 gesendet, verlässt das Event der Com1 die Warteschleife und führt die Funktion OnRxCHar aus.
Diese Funktion sieht so aus:DWORD dwSymbolsRead = Read( (VOID*)buffer, 1 ); if(dwSymbolsRead > 0){ if(this->m_nPortSelect==2){ // Befehl Master if(buffer[0]!='\n'){ theApp.m_strDataHelp1 += (buffer[0]); }else{ ::EnterCriticalSection( &theApp.m_csPortRead ){ CRS485SpyMainApp::DataInfo neu1; neu1.m_strData.Format(theApp.m_strDataHelp1); theApp.m_vDataList.push_back(neu1); theApp.m_strDataHelp1.Delete(0,theApp.m_strDataHelp1.GetLength()); ::LeaveCriticalSection( &theApp.m_csPortRead ); } }else if(this->m_nPortSelect==1){ // Antwort Slave if(buffer[0]!='\n'){ theApp.m_strDataHelp2 += (buffer[0]); }else{ ::EnterCriticalSection( &theApp.m_csPortRead ); CRS485SpyMainApp::DataInfo neu2; neu1.m_strData.Format(theApp.m_strDataHelp2); theApp.m_vDataList.push_back(neu2); theApp.m_strDataHelp2.Delete(0,theApp.m_strDataHelp2.GetLength()); ::LeaveCriticalSection( &theApp.m_csPortRead ); } }in der Variable nPort Select wird definiert obe es sich um einen Befehl oder um eine Antwort handelt !!
Es wird immer 1 Zeichen eingelesen und dies solange bis zum /n. dann wird in einer CriticalSection der String in einem Vector gespeichert!!was ich jetz nicht verstehe warum es eine gewisse Zeit funktioniert und dann wieder nicht und wieder schon.....
lg
PS: bin nicht sicher ob ich das Programm zu 100% verstanden habe !!
-
markus.z84 schrieb:
Habe für jede Com einen Thread gemacht und erhalte auch die übertragenen Werte.
In deinem Post kann ich das nicht erkennen. Wie initialisierst du die Threads und vor allem wo und wo steht der von dir gepostete Code?
Ich denke, dass der Fehler nicht in dem von dir geposteten Code steht sondern das Problem mit der Threadsynchro zu tun hat. Aber das sagte ich ja bereits.
-
Steh zur Zeit sehr auf der Leitung, aber hoffe dass ich jetzt den "richtigen" Code poste.
Wird eine der Zwei Coms ausgewählt, dann wird die Funktion Open aufgerufen.
In dieser werden zuerst die Einstellungen für die jeweilige Schnittstelle übernommen und dann der Thread gestartet. Mit dem Thread wird zuvor nichts gemacht!!!Open ( CString sPortName, DWORD dwBaudRate, BYTE bDataBits, BYTE stopbit, BYTE parity, BYTE fc, int Portselect ) { if ( IsOpen() ) return FALSE; CString sPort = _T("\\\\.\\"); sPort += sPortName; m_hComm = CreateFile( sPort, GENERIC_READ | GENERIC_WRITE, 0, // must be opened with exclusive-access NULL, // no security attributes OPEN_EXISTING, // must use OPEN_EXISTING FILE_FLAG_OVERLAPPED, NULL // hTemplate must be NULL for comm devices ); TRACE ( _T("Error: %d\n"), GetLastError() ); if (m_hComm == INVALID_HANDLE_VALUE) { TRACE (_T("CreateFile failed with error %d.\n"), GetLastError()); CloseHandle( m_hComm ); m_hComm = INVALID_HANDLE_VALUE; return FALSE; } // reconfigure port DCB dcb; BOOL fSuccess = GetCommState(m_hComm, &dcb); if (!fSuccess) { TRACE (_T("GetCommState failed with error %d.\n"), GetLastError()); CloseHandle( m_hComm ); m_hComm = INVALID_HANDLE_VALUE; return FALSE; } dcb.BaudRate = dwBaudRate; dcb.ByteSize = bDataBits; dcb.Parity = parity; . . Hier werden die Einstellungen vorgenommen . . // Install new adjustment fSuccess = SetCommState(m_hComm, &dcb); if (!fSuccess) { TRACE (_T("SetCommState failed with error %d.\n"), GetLastError()); CloseHandle( m_hComm ); m_hComm = INVALID_HANDLE_VALUE; return FALSE; } // launch comm event handler DWORD dwId; m_hThread = CreateThread( NULL, 0, EventHandler, (LPVOID)this, CREATE_SUSPENDED, &dwId ); } if ( m_hThread != NULL ) { m_hEventTerminate = CreateEvent( NULL, FALSE, FALSE, _T("OnStopThread") ); lReqTerminate = 1; ResumeThread( m_hThread ); } else { CloseHandle( m_hComm ); m_hComm = INVALID_HANDLE_VALUE; return FALSE; } return TRUE; }Dieser Code befindet sich in einer Datei, die ich im Inernet gefunden habe, sie ist mit der Datei serial.cpp zu vergleichen jedoch ausführlicher !!
Ich hoffe dass du nun mehr erkennen kannst!! Bin mir jedoch überhaupt nicht sicher......
Weis zur Zeit nicht weiter !!!
-
Du hattest doch in deinem ersten Post geschrieben, dass du 2xRS232 verwendest und du hast für jede Schnittstelle einen Thread. Wie meinst du jetzt
markus.z84 schrieb:
Steh zur Zeit sehr auf der Leitung, aber hoffe dass ich jetzt den "richtigen" Code poste.
Wird eine der Zwei Coms ausgewählt, dann wird die Funktion Open aufgerufen.
In dieser werden zuerst die Einstellungen für die jeweilige Schnittstelle übernommen und dann der Thread gestartet. Mit dem Thread wird zuvor nichts gemacht!!!Dieser Code befindet sich in einer Datei, die ich im Inernet gefunden habe, sie ist mit der Datei serial.cpp zu vergleichen jedoch ausführlicher !!
Ich hoffe dass du nun mehr erkennen kannst!! Bin mir jedoch überhaupt nicht sicher......
Weis zur Zeit nicht weiter !!!Ich bin davon ausgegangen, dass beide COM-Ports initialisiert werden damit du auf die RS485 lesend und schreibend zugreifen kannst. Außerdem wollte ich wissen innerhalb welcher Klasse oder Memberfunktion dieser Code steht. hast du jetzt immer nur einen Thread aktiv? Dann hab ich das ganze irgendwie nicht verstanden...

-
Hab nun das problem fast gelöst!!
Verwende 2 Coms jedoch nur zum lesen der Daten. Eine Com verwende ich für die RxD und die zweite für die TxD Leitung des Busses.
Für die einzelnen Schnittstellen wird ein Thread gemacht der immer weiterläuft sobald ich etwas am Port einlese. Also ist immer nur einer aktiv.
Ich verwende eine andere Software die als Master Daten an einen Slave im RS485 Busses sendet. Der Slave antwortet auch.
Nun habe ich erkannt, dass die Software immer Daten sendet und nicht wartet bis der Slave antwortet oder die Antwort nicht kontrolliert ob sie für diesen Befehl oder fü einen anderen war. (Zeitproblem)
Bin der Meinung, dass durch dieses Verhalten der SW mein Programm die Probleme erhalten hat ! Jedoch werde ich noch einige Test machen um sicher zu gehen dass das das Problem war !!
Danke trotzdem
-
hatte gedacht ich habe das Problem gelöst, jedoch lag ich da falsch!!
habe nun die TxD und die RxD leitung des Busses mittels Diode auf nur EINE COM angehängt und erhalte immer eine Anfrage vom Master und kurze Zeit später die Antwort des SLAVES. (immer in richtiger reihenfolge)
Werden nun die beiden Leitungen über 2 verschiedene COM-Schnittstellen zum PC geführt erhalte ich des öfteren 3 Anfragen von verschiedenen Mastern und dann eine Antwort.
Es sieht so aus, als würde die Antwort zu spät kommen und ein neuer Befehl schon geschickt werden. Jedoch kann dies nicht sein, da der Master erst den nächsten Befehl schickt, wenn er die Antwort erhalten hat.Schätze habe ein Problem bei der Thread synkronisation.......
Finde jedoch nichts! Die darüber angeführten Codebeispiele müssten helfen..lg
-
also, wenn immer nur EIN Thread aktiv ist, ist es denn sinnvoll ZWEI Thread zu haben.. schein elegant aber vll. zu unsicher wegen der syncro...
kansnt du nich nicht EIN Thread machen, welcher beide Com port unterhält? so wie ich gelesen habe, schickst du bspw. mit Com1 ein Anfragebzw. Commando, und mit Com2 wartest du auf die antwort oder? Solange com2 auf die antwort wartet, kann com1 auch kleine "neue" Anfgrage schicken odeR? bin ich richtig?
-
also, wenn immer nur EIN Thread aktiv ist, ist es denn sinnvoll ZWEI Thread zu haben.. schein elegant aber vll. zu unsicher wegen der syncro...
kansnt du nich nicht EIN Thread machen, welcher beide Com port unterhält? so wie ich gelesen habe, schickst du bspw. mit Com1 ein Anfragebzw. Commando, und mit Com2 wartest du auf die antwort oder? Solange com2 auf die antwort wartet, kann com1 auch kleine "neue" Anfgrage schicken odeR? bin ich richtig?
-
BorisDieKlinge schrieb:
also, wenn immer nur EIN Thread aktiv ist, ist es denn sinnvoll ZWEI Thread zu haben.. schein elegant aber vll. zu unsicher wegen der syncro...
kansnt du nich nicht EIN Thread machen, welcher beide Com port unterhält? so wie ich gelesen habe, schickst du bspw. mit Com1 ein Anfragebzw. Commando, und mit Com2 wartest du auf die antwort oder? Solange com2 auf die antwort wartet, kann com1 auch kleine "neue" Anfgrage schicken odeR? bin ich richtig?
Unter Umständen ist das schon sinnvoll. Aber er hat ja sogar 3 Threads, du hast den GUI-Thread vergessen. Was die Synchronisierung angeht: erstens müssen sich die beiden Workerthreads untereinander synchronisieren. Da man hier auf das Abarbeiten von Ereignissen wartet wäre es hier sinnvoll mit Events zu arbeiten. Zweitens müssen sich die beiden Worker-Threads noch mit dem GUI- oder Mainthread synchronisieren. Da es sich hier meist um die "gemeinsame" Nutzung von Variablen handelt, sind hier CriticalSections nicht ganz verkehrt. Das alles scheint ja auch umgesetzt worden sein, aber irgendwo funktionierts nicht ganz so. Ich verwende CriticalSections immer über
CSingleLock locked(&m_criticalsection, TRUE);Dann hat man nicht den Stress mit Enter und Leave und die Aufräumarbeiten erledigt das CSingleLock-Objekt selbst. Ebenfalls arbeite ich nicht mit CreateThread; bisher hat das alles immer mit AfxBeginThread funktioniert. Dies hat aber keinen Einfluss auf die Synchro, um die muss man sich nach wie vor kümmern. Die Events hab ich immer als Member einer Klasse verwendet und diese dann mit SetEvent oder ResetEvent gesetzt oder wieder rückgesetzt.
-
ja klar, das es ein mainthread gibts ist klar^^ aber zwei trhead syncornisieren ist besser als 3 ... und 2 thread zu verwenden für Com 1 +2 ist nicht unbedingt "sicher"...
Pseudo:
DWORD ThreadFunc (LPPARAM *p Data){ while(1){ //hier Warten bis Com1 ein commando schickt (singleobject) while(1){ //Com2 auf daten warten lassen und lesen, wenn fertig aus schleife springen } } }
-
ja klar, das es ein mainthread gibts ist klar^^ aber zwei trhead syncornisieren ist besser als 3 ... und 2 thread zu verwenden für Com 1 +2 ist nicht unbedingt "sicher"...
Pseudo:
DWORD ThreadFunc (LPPARAM *p Data){ while(1){ //hier Warten bis Com1 ein commando schickt (singleobject) while(1){ //Com2 auf daten warten lassen und lesen, wenn fertig aus schleife springen } } }
-
ja klar, das es ein mainthread gibts ist klar^^ aber zwei trhead syncornisieren ist besser als 3 ... und 2 thread zu verwenden für Com 1 +2 ist nicht unbedingt "sicher"...
Pseudo:
DWORD ThreadFunc (LPPARAM *p Data){ while(1){ //hier Warten bis Com1 ein commando schickt (singleobject) while(1){ //Com2 auf daten warten lassen und lesen, wenn fertig aus schleife springen } } }
-
ja klar, das es ein mainthread gibts ist klar^^ aber zwei trhead syncornisieren ist besser als 3 ... und 2 thread zu verwenden für Com 1 +2 ist nicht unbedingt "sicher"...
Pseudo:
DWORD ThreadFunc (LPPARAM *p Data){ while(1){ //hier Warten bis Com1 ein commando schickt (singleobject) while(1){ //Com2 auf daten warten lassen und lesen, wenn fertig aus schleife springen } } }
-
ja klar, das es ein mainthread gibts ist klar^^ aber zwei trhead syncornisieren ist besser als 3 ... und 2 thread zu verwenden für Com 1 +2 ist nicht unbedingt "sicher"...
Pseudo:
DWORD ThreadFunc (LPPARAM *p Data){ while(1){ //hier Warten bis Com1 ein commando schickt (singleobject) while(1){ //Com2 auf daten warten lassen und lesen, wenn fertig aus schleife springen } } }
-
ja klar, das es ein mainthread gibts ist klar^^ aber zwei trhead syncornisieren ist besser als 3 ... und 2 thread zu verwenden für Com 1 +2 ist nicht unbedingt "sicher"...
Pseudo:
DWORD ThreadFunc (LPPARAM *p Data){ while(1){ //hier Warten bis Com1 ein commando schickt (singleobject) while(1){ //Com2 auf daten warten lassen und lesen, wenn fertig aus schleife springen } } }
-
Was soll den der Quatsch? Ob ich nun einen oder zwei Threads synchronisiere ist glaub ich nicht der Mega-Aufwand, wenn man es konsequent durchzieht. Solche Konstrukte wie du da grad gepostet hast sind totaler Käse, weil du ja nicht weißt an welcher Stelle das Event als erstes ankommt. Er geht zwar davon aus das es in einer gewissen Reihenfolge vorliegt, nur wird genau das sein Problem sein warum es nicht funktioniert. Ich würde wie schon vorhin gesagt jede COM in einen Thread stecken und die Synchronisierungsmechanismen klar und strukturiert durchziehen. Dann kann man ja auch sehen in welcher Reihenfolge was wo ankommt. Außerdem hab ich nie behauptet das bei zwei Threads was sicherer ist...

-
hallo leute,
hab erst jetzt die ganzen Antworten gesehen!!
erstmal danke für eure Hilfe und ich werd versuchen die lösungsvarianten einzeln zu testen und dann die ergebnisse zu posten
-
wenn definitv klar ist, das Com 1 ne anfrage sendet, und com 2 auf die antwort wartet. und das konsiquent durchgezogen wird, werden events richtig ankommen?
wenn du jemand ne frage stellst bekommst ne antwort, oder bekommst du ne antwort ohne davor ne frage gestellt zu haben? du kannst ne frage stellen und es kommt keine antwort, gibts keine reaktion frägst evtl. nochmal^^ timeout..