rs232
-
muss man zwischen einzelnen befehlen die an die schnittstelle gehen eine bestimmte zeit (vielleicht zur verarbeitung oder der geschwindigkeit der Baudrate) einhalten?
ist es normal, das die anwendung einfriert, wenn man daten zu schnell über den comport sendet?
danke im Vor-raus gerd
-
gerd01 schrieb:
muss man zwischen einzelnen befehlen die an die schnittstelle gehen eine bestimmte zeit (vielleicht zur verarbeitung oder der geschwindigkeit der Baudrate) einhalten?
Das kann dir bestimmt die Spezifikation deines Zielrechners (Targets) beantworten. Die Baudrate muss natürlich schon mit dem Ziel übereinstimmen...
gerd01 schrieb:
ist es normal, das die anwendung einfriert, wenn man daten zu schnell über den comport sendet?
Das liegt wohl eher daran, dass du - statt wie man es sollte - die REchenintensiven Aufgaben in einen Thread auszulagern sie einfach in einem Eventhandler ausführst. Deshalb kann die Applikation die NachrichtenQueue nichtmehr abarbeiten und dementsprechend sieht sie abgestürzt aus...
-junix
-
zu deiner 2.antowort:
nein, es ist ein thread, allerdings sieht die anwendund dann ebenfalls abgestürzt aus, wenn ich die codes zu schnell sende.
habe das beispiel aus dem netz, wo man in einem memofeld ein blinkenden cursor hat und eingeben kann. am comport habe ich einen loop-back stecker dran, der mir die ausgehenden daten gleich wieder in den memoblock zurückgibt-als empfangsdaten. klappt auch (sende ich beispielsweise ein "a", dann steht nachdem drücken des buchstabens im memo "aa") wenn ich jetzt zu schnell tippe, dann friert die anwendung ein. woran liegt das? hat es vielleicht damit zu tun, das man zwischen den einzelnen befehlen (daten) pausen lassen muss?
gruß gerd
-
*push*
-
*push again*
-
Synchronisationsprobleme würd ich spontan sagen... wartet die Applikation auf irgendwas das der Thread auslöst?
-junix
-
hier mal der code aus dem tutorial:
header form:
//--------------------------------------------------------------------------- #ifndef Unit1H #define Unit1H //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ExtCtrls.hpp> //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: // Von der IDE verwaltete Komponenten TPanel *Panel1; TMemo *Memo1; TMemo *Memo2; TEdit *Edit1; TButton *Button1; void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall FormCreate(TObject *Sender); void __fastcall Memo1KeyPress(TObject *Sender, char &Key); private: // Anwender-Deklarationen public: // Anwender-Deklarationen __fastcall TForm1(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif
cpp form
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "Unit2.h" //--------------------------------------------------------------------------- #pragma package(smart_init) HANDLE hComm = NULL; TRead *ReadThread; COMMTIMEOUTS ctmoNew = {0}, ctmoOld; #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { // BEENDE DEN THREAD. ReadThread->Terminate(); // WARTEN BIS DER THREAD BEENDET IST, // LEERE DEN INTERNEN COMM BUFFER, // STELLE DIE VORHERIGEN TIMEOUT SETTINGS WIEDER HER, // UND SCHLIESSE DEN COMPORT. Sleep(500); PurgeComm(hComm, PURGE_RXABORT); SetCommTimeouts(hComm, &ctmoOld); CloseHandle(hComm); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { DCB dcbCommPort; // COMM PORT ÖFFNEN. // ERSETZEN SIE "COM2" MIT EINEM STRING ODER "COM1", "COM3", ETC. UM EINEN // ANDEREN PORT ZU ÖFFNEN. hComm = CreateFile ("COM1",GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); // WENN DER PORT NICHT GEÖFFNET WERDEN KANN, ANWENDUNG BEENDEN if(hComm == INVALID_HANDLE_VALUE) { Application->MessageBoxA("Fehler","Fehler",mbOK); Application->Terminate(); } // COMM TIMEOUTS FÜR UNSER BEISPIEL SETZEN. GetCommTimeouts(hComm,&ctmoOld); ctmoNew.ReadTotalTimeoutConstant = 10; ctmoNew.ReadTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hComm, &ctmoNew); // BAUDRATE, PARITÄT, WORTLÄNMGE, UND STOPBITS SETZEN. // ES GIBT AUCH ANDERE WEGE DIESE ZU SETZEN ABER DIES IST DER EINFACHSTE. // WENN SIE SPÄTER ANDEREN CODE FÜR DIE BAUSRATE USW. HINZUFÜGEN WOLLEN, DENKEN // SIE DARAN, DASS DAS ARGUMENT FÜR BuildCommDCB EINEN POINTER AUF EIN // STRING SEIN MUSS. // DENKEN SIE AUCH DARAN, DASS DIE BuildCommDCB()-DEFAULTS NICHT FÜR HANDSHAKING // GESETZT SIND. dcbCommPort.DCBlength = sizeof(DCB); GetCommState(hComm, &dcbCommPort); BuildCommDCB("9600,N,8,1", &dcbCommPort); SetCommState(hComm, &dcbCommPort); // AKRIVIERE DEN THREAD ReadThread = new TRead(false); } //--------------------------------------------------------------------------- void __fastcall TForm1::Memo1KeyPress(TObject *Sender, char &Key) { // SENDE JEDE MEMO-EINGABE TransmitCommChar(hComm, Key); // DIES VERHINDERT DASS ANZEIGEN VON UNGÜLTIGEN ZEICHEN. // WENN SIE MIT EINEM GERÄT VERBUNDEN SIND WELCHES CHARACTER ZURÜCKSENDET, // SETZEN SIE EINFACH Key = 0. if(Key != 13 && (Key < ' ' || Key > 'z')) Key = 0; } //---------------------------------------------------------------------------
header thread
//--------------------------------------------------------------------------- #ifndef Unit2H #define Unit2H //--------------------------------------------------------------------------- #include <Classes.hpp> //--------------------------------------------------------------------------- class TRead : public TThread { private: protected: void __fastcall DisplayIt(void); // FÜGEN SIE DIESE ZEILE HINZU void __fastcall Execute(); public: __fastcall TRead(bool CreateSuspended); }; //--------------------------------------------------------------------------- #endif
cpp thread
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "Unit2.h" #pragma package(smart_init) extern HANDLE hComm; char InBuff[100]; //--------------------------------------------------------------------------- // Wichtig: Methoden und Eigenschaften von Objekten der VCL können nur in // in Methoden verwendet werden, die Synchronize aufrufen, z.B.: // // Synchronize(UpdateCaption); // // wobei UpdateCaption so aussehen könnte: // // void __fastcall Unit2::UpdateCaption() // { // Form1->Caption = "In Thread aktualisiert"; // } //--------------------------------------------------------------------------- __fastcall TRead::TRead(bool CreateSuspended) : TThread(CreateSuspended) { } //--------------------------------------------------------------------------- void __fastcall TRead::DisplayIt() { // ZEIGE DEN EMPFANGENEN TEXT AN. Form1->Memo1->SetSelTextBuf(InBuff); } //--------------------------------------------------------------------------- void __fastcall TRead::Execute() { //---- Place thread code here ---- DWORD dwBytesRead; // DAS THREAD-OBJECT SOLL AUTOMATISCH ZERSTÖRT WERDEN WENN DER THREAD // BEENDET WIRD. FreeOnTerminate = true; while(1) { // VERSUCHE DATEN VOM COM-PORT ZU LESEN // WENN KEINE DATEN DA SIND, WIRD EIN TIMOUT AUFTRETEN UND EIN ERNEUTER VERSUCH // GESTARTET. WENN DATEN DA SIND, WERDEN DIESE ANGEZEIGT. ReadFile(hComm, InBuff, 50, &dwBytesRead, NULL); if(dwBytesRead) { InBuff[dwBytesRead] = 0; // NULL-TERMINATE DEN STRING Synchronize(DisplayIt); } } } //---------------------------------------------------------------------------
wenn ich die applikation starte, erscheinen zwei memo felder nebeneinander. alles was in den rechten reinkommt, das ist ausgang, und in dem linken ist eingang. es funktioniert, wenn ich die daten langsam schreibe, also wenn ich einen ascii sende. nur wenn ich mehrere ascii schnell hintereinander sende, dann hängt sie wohl.
kannste ja ausprobieren.
ich kenne mich mit beiden: rs232 und TThread zuwenig aus, um eine lösung zu erfahren. würde mich freuen, wenn du mir weiterhelfen kannst!
gruß gerd
-
Voilà der Synchronize Aufruf ist es... Damit beschäftigst du das Formular zu stark und es kann die Messages nichtmehr abarbeiten... Deshalb sollte man Threads möglichst vom GUI über ne MessageBox wie z.B. die Windows Messages entkoppeln...
-junix
-
hallo,
könnte es sein, dass ich das problem vielleicht selber gelöst habe?
wie gesagt, ich kenne mich nicht mit threads aus!
ich habe folgendes unternommen, und es "scheint" zu funktionieren:
ich fügte der threadklasse eine weitere funktion zu (ist vielleicht etwas umfangreicher,ok) und benannte sie DisplayIt2. diese funktion tut allerdings nichts!
den code unten in der klasse änderte ich wie folgt ab:
while(1) { // VERSUCHE DATEN VOM COM-PORT ZU LESEN // WENN KEINE DATEN DA SIND, WIRD EIN TIMOUT AUFTRETEN UND EIN ERNEUTER VERSUCH // GESTARTET. WENN DATEN DA SIND, WERDEN DIESE ANGEZEIGT. ReadFile(hComm, InBuff, 50, &dwBytesRead, NULL); if(dwBytesRead) { InBuff[dwBytesRead] = 0; // NULL-TERMINATE DEN STRING Synchronize(DisplayIt); } else { Synchronize(DisplayIt2); } }
sollte dies der fehler sein, der jetzt gelöst ist, sage ich trotzdem danke, weil du mich mit dem synchronisieren drauf gebracht hattest. in der hilfe steht unter threads, das ständig "Synchronize()" ausgeführt werden muss, damit ein thread weiterarbeitet.
gruß gerd
-
Erscheint mir jetzt etwas unlogisch irgendwie....
-junix
-
in der hilfe steht für Synchronize:
Beschreibung
Synchronize löst den Aufruf einer bestimmten Methode aus, die vom VCL-Haupt-Thread ausgeführt werden soll. Durch dieses indirekte Verfahren werden Konflikte in Multithread-Anwendungen vermieden. Wenn Sie nicht sicher sind, ob ein Methodenaufruf Thread-sicher ist, rufen Sie die Methode vom VCL-Haupt-Thread aus auf, indem Sie sie an die Methode Synchronize übergeben.
Der Thread wird unterbrochen, während die angegebene Methode ausgeführt wird.
Hinweis
Unsichere Methoden können Sie auch durch kritische Sektionen oder mit Hilfe eines Synchronisierers, der mehrfaches Lesen, aber nur exklusives Schreiben zuläßt, schützen.
ps:es scheint ja zu funktionieren, oder bist du da anderer meinung?
gruß gerd
-
Was mir nicht klar ist: Wozu die leere funktion? Wieso funktionierts dann plötzlich?
-junix
-
weil er wahrscheinlich einfach nur synchronize aufrufen muss. ich stelle mir es so vor:
1. Synchronize-aufruf der funktion aus dem thread
2. in der funktion Synchronize werden intern irgendwelche sachen zur beruhigung der vcl übergeben, sodass sich alles wieder synchronisiert
3. aufruf der übergebenden funktionanders könnte ich es mir nicht erklären, was meinst du?
gruß gerd
-
Etwas vage würde ich sagen... Hab leider keine VCL Sourcen da sonst würde ich mir das mal reinziehen... Mir behagt das jedenfalls nicht, wenn ich nicht weiss wieso etwas plötzlich funktioniert... vor Allem wenn der Grund wiesos plötzlich Funktioniert nicht nachvollziehbar ist....
-junix
-
vielleicht kann es jemand anders bei interesse etwas nachvollziehen!
danke trotzdem erstmal!
gruß gerd