![]() |
Tserial abschiessen
Hallo,
ich kommuniziere per Tserial mit einem externen Gerät das über die Serielle Schnittstelle ständig nur am Senden ist. Empfangen wird dieses Dauerfeuer per:
Delphi-Quellcode:
Jetzt hab ich das Problem das das Beenden des Programms ehwig dauert, obwohl ich die Schnittstelle mit:
procedure TSS.tC_SerialRxData(Sender: TObject);
Var C : Char; begin While tC_Serial.ReadChar(C)>0 do Begin Case C of #2 : HS:=''; #3 : Begin tC_String:=HS; End; Else If Length(HS)<100 Then HS:=HS+C; End; End; end;
Delphi-Quellcode:
schliesse.
tC_Serial.Active:=false;
Stecke ich mein externes Gerät aus schliesst das Programm sofort. Gibt es eine Möglichkeit die TSerial Komponente sofort zu schliessen? |
Re: Tserial abschiessen
Das Problem ist, dass Dein Programm in der Schleife steckt
und keine Systemmeldungen verarbeitet.
Delphi-Quellcode:
Könnte vielleicht etwas Abhilfe bringen.
procedure TSS.tC_SerialRxData(Sender: TObject);
Var C : Char; begin While tC_Serial.ReadChar(C)>0 do Begin Application.ProcessMessages; // <---- Case C of #2 : HS:=''; #3 : Begin tC_String:=HS; End; Else If Length(HS)<100 Then HS:=HS+C; End; End; end; Grüße Klaus |
Re: Tserial abschiessen
Hallo Klaus01,
bringt leider auch nichts! Ich hab auch schon versucht in die Schleifenbedingung eine zweite Bedingung einzubauen.
Delphi-Quellcode:
Die boolsche Variable "sofort_beenden" wird beim schliesen im OnClose Ereignis auf true gesetzt.
procedure TSS.tC_SerialRxData(Sender: TObject);
Var C : Char; begin While (tC_Serial.ReadChar(C)>0) and not sofort_beenden do Begin Case C of #2 : HS:=''; #3 : Begin tC_String:=HS; End; Else If Length(HS)<100 Then HS:=HS+C; End; End; end; Aber leider auch ohne Erfolg... Ist es vielleicht möglich den Empfang komplett zu unterbinden? |
Re: Tserial abschiessen
Kannst Du mal einen Breakpoint in Deinem OnClose Ereignis setzen.
Und dann mal schauen ob direkt nach der Beendigung des Programms da hinein gesprungen wird. Wenn es da auch schon länger dauert, dann hängt Dein Programm vielleicht noch woanders in der Verarbeitung fest. Wenn Du die Zeichen von der Schnittstelle gelesen hast, mußt Du dann nich das Puffer der Schnittstelle leeren? Das würde mit ZapRXQueue gehen. Grüße Klaus |
Re: Tserial abschiessen
Er spring beim schliessen sofort "rein" und erst nach ca. 10sek. "raus"
Delphi-Quellcode:
procedure TSS.FormClose(Sender: TObject; var Action: TCloseAction);
begin showmessage('rein'); tC_Serial.Active:=false; showmessage('raus'); end; Zitat:
Delphi-Quellcode:
das Zeichen aus dem Puffer schmeisst. Weil der nächste Aufruf von readChar holt sich ja auch das nächste Zeichen.
readChar
Ich habs mal so versucht:
Delphi-Quellcode:
Aber leider immer noch das gleiche Spiel...
procedure TSS.FormClose(Sender: TObject; var Action: TCloseAction);
begin showmessage('rein'); tc_serial.ZapRxQueue; tC_Serial.Active:=false; showmessage('raus'); end; |
Re: Tserial abschiessen
Delphi-Quellcode:
Nach dem Einlesen, werden die Date da noch verarbeitet?
procedure TSS.tC_SerialRxData(Sender: TObject);
Var C : Char; begin While (tC_Serial.ReadChar(C)>0) and not sofort_beenden do Begin tc_serial.ZapRxQueue; // wenn dann hier den Puffer löschen Case C of #2 : HS:=''; #3 : Begin tC_String:=HS; End; Else If Length(HS)<100 Then HS:=HS+C; End; End; end; Grüße Klaus |
Re: Tserial abschiessen
Hi,
ich bin nicht ganz sicher, ob dein Design so sauber ist. Ich geh hier einfach mal davon aus, dass tC_SerialRxData eine Ereignisbehandlung ist, die aufgerufen wird, sobald Daten ankommen. Hier liegt dann schon eines deiner möglichen Probleme. Die Kommunikation dürfte wohl asynchron sein, dass heißt natürlich, dass du gar nicht weißt wann welches Datum ankommt. Beendest du also die Ereignisbehandlung und es kommen neue Daten an, so wird die Methode sofort wieder aufgerufen. An sich solltest du auch keine Schleife in einer solchen Behandlung setzen. Imho müsstest du hier vielmehr eine eigene Methode verwenden, in der die Schleife läuft. Was dein Problem mit dem Schließen angeht, versuch einfach mal die Ereignisbehandlung im onClose abzuschalten (tC_SerialRxData := nil) und dann noch die Schleife abbzubrechen (mit einem Flag). Gruß Der Unwissende |
Re: Tserial abschiessen
@Klaus01
habs mit
Delphi-Quellcode:
versucht.
tc_serial.ZapRxQueue;
Ja es wird noch korrekt empfangen. Aber das Problem ist nicht weg. @unwissender Des mit der eigenen Funnktion versuch ich mal. Wobei mir nicht klar ist warum ein Flag in einer eigenen Funktion, in der eine Schleife läuft, anders ist als ein Flag in der Schleife selbst. Das mit der Zitat:
|
Re: Tserial abschiessen
Deine Methode tC_SerialRxData wird immer dann aufgerufen, wenn Daten da sind. Wenn du also innerhalb dieser Methode sagst "stopp, will keine daten mehr", dann hat das überhaupt keine bedeutung, weil das event ja gleich wieder ausgelöst wird. du musst also das event komplett abschalten. und das geht so, wie Der_Unwissende es gesagt hat.
|
Re: Tserial abschiessen
Zitat:
Stell dir einfach mal vor, du bekommst 200 Byte gesendet. Da die Kommunikation asynchron ist, kommen die Bytes zufällig an. Nehmen wir mal den Fall an, es kommen erst 100 Byte, die lösen dein Event aus, es wird also einmal die Schleife gestartet und in Ruhe abgearbeitet. Währenddessen kommen nun auch irgendwann die nächsten 100 Byte an, jetzt wird wieder das Ereignis ausgelöst und hier läuft dann wieder das gleiche ab. Du reagierst also zweimal auf das Eintreffen von Daten in den Puffer. Natürlich kannst du bei asynchroner Kommunikation nie sagen wann wieviele Daten im Puffer landen, also ist es garantiert nicht das von dir erwünschte Verhalten! Wenn du jetzt aber eine eigene Methode verwendest, dann kannst du diese z.B. in einen Thread auslagern. Läuft dieser schon, dann liest der noch den aktuellen Puffer (und auch neu hinzukommende Zeichen) ein. Läuft der noch nicht, schmeißt du ihn an. Du kannst hier leicht abfangen, dass für jedes eintreffen von Daten ein eigener Thread gestartet wird. Beendest du dann dein Programm, wird der Thread auch einfach nicht mehr neu gestartet (nur ein Beispiel einer möglichen Lösung). An den Flags ändert das natürlich nichts! Zitat:
Wenn du im Objektinspektor doppelt auf ein Ereignis klickst, so wird für dich eine fertige Methode angelegt und der Editor springt in den Körper rein. Hinter den Kulissen wird dabei einfach die Adresse dieser Methode als Methodenzeiger für das Ereignis gespeichert. Deswegen steht im Objektinspektor dann der Name der Methode. Wenn du nun im Programm im OnCloseQuery einfach schreibst:
Delphi-Quellcode:
dann wird die Ereignisbehandlung abgeschaltet. Kommt jetzt ein neues Zeichen im Puffer an, gibt es keinen der benachrichtigt wird.
tc_serial.OnRxChar := nil;
Sauberer und mehr OO wäre es, auf der Ereignisbehandlung einfach ein Observer-Pattern (bzw. eine Implementierung dieses Pattern) aufzusetzen. Aber das ist dann noch eine andere Sache. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:15 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz