| Autor |
Beitrag |
spacemanspiff
      
Beiträge: 53
Erhaltene Danke: 1
|
Verfasst: Di 04.01.11 10:48
Hallo zusammen,
mein Delphi-Programm muss mit einem Messsystem via RS232 kommunizieren. Ich nutze dazu die Komponente TComPort aus "System". Nur um die berechnete Baudrate und die korrekte Verdrahtung zu testen, habe ich in Delphi zwei Edit-Fields und einen Button eingebaut. Schreibe ich etwas in Feld 1 und betätige dann den Knopf, schickt Delphi es über die serielle Schnittstelle an das Messsystem. Dieses liest die Zeichen und schickt sie wieder zurück (Echo). Das Ereignis "OnRxChar" der TComPort-Komponente reagiert darauf, liest die Zeichen (zwei Terminalsymbole: erst #13/CR, dann #10/LF) und gibt diese in Textfeld 2 aus.
Das klappt auch alles wunderbar. Habe also mit dem eigentlichen Vorhaben losgelegt, Input/Output-Befehle definiert und diese in Delphi implementiert und im Debug-Modus des Messsystems geprüft. Die Kommandos kommen korrekt an und werden auch korrekt interpretiert. Nun wollte ich mich um die Delphi-Seite kümmern und habe ein Problem, dass mir nicht ganz begreiflich ist.
Folgendes: Wenn keine Messung läuft, schickt das Messsystem dem Delphi-Programm alle 500ms eine Info bestehend aus 4 Chars ('S', Statusbyte, CR, LF). Ich habe auch bereits längere Folgen gesendet und via Breakpoint im Watch überprüft. Bisher kam immer alles korrekt an. Wenn ich aber den Breakpoint entferne und das Programm laufen lasse, lässt sich das Programm nicht mehr bedienen. Ich kann das Fenster nicht verschieben, es nicht in den Vordergrund holen, wenn es im Hintergrund ist und es zeichnet sich auch nicht neu. Als sei das Programm damit überlastet alle 500ms ein paar Bytes zu empfangen, das geht doch nicht...
Hat jemand eine Idee, woran das liegen könnte?
Hier mal der Code der Methode, die auf "OnRxChar" aufgerufen wird
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| procedure TMAIN.UARTGetString( Sender: TObject ); var C: AnsiChar; CR, LF: Boolean; i: Integer; begin for i := 0 to 9 do begin SI[i] := ' '; end; CR := False; LF := False; i := 0; try repeat C := ' '; C := ComPort1.ReadAnsiChar(); if C = #13 then begin CR := True end else if ( C = #10 ) and ( CR = True ) then begin LF := True end else begin CR := False end; if not CR and not LF then SI[i] := C; Inc( i ); until LF; DeviceRequest( SI ); except on E: EComError do begin ShowMessage( E.Message ); end; end; end; |
Auf der Zeile "DeviceRequest( SI );" sass immer der Breakpoint. SI ist ein array von AnsiChars. Es war auch mal ein String, aber ich habe schon ein wenig herumgedoktort, um der Ursache auf den Grund zu kommen. Die Funktion DeviceRequest interpretiert die empfangene Befehlsfolge, ist hier aber nicht weiter von Bedeutung, da sie momentan nur anhand eines Labels anzeigt, ob sich das System im Leerlauf befindet oder nicht. Das macht sie mit bitweisen Operationen auf dem Statusbyte.
So. Hoffe, jemand hat eine zündende Idee
Vielen Dank und beste Grüße,
Thomas
|
|
bummi
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: Di 04.01.11 11:13
Ich kenne Deine Comportcomponente nicht, ich verwende die ComPort Library .
Aber es sieht für mich aus als ob Du blockierend liest.
Intern wird auch Deine Komponente mit einem Thread arbeiten der Synchronized OnXXXX Ereignisse liefert. In einem dieser Ereignisse sammelst Du die Daten in einem globalen (klassenprivaten) Puffer, wertest aus ob ein Kommando/Status komplett ist, schneidest den kompletten Teil aus Deinem Puffer aus und rufst eine Routine von Dir mit den geparsten Daten auf welches das gewünschte tut.
_________________ Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
|
|
Xion
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Di 04.01.11 14:47
spacemanspiff hat folgendes geschrieben : | | Als sei das Programm damit überlastet alle 500ms ein paar Bytes zu empfangen, das geht doch nicht... |
Schreibe mal in deine procedure ein Application.ProcessMessages; Dann wird immer, wenn die procedure durchlaufen wird, das Fenster verschoben usw..
Kannst du jetzt flüssig das Fenster verschieben, dann wird deinen procedure viel zu oft aufgerufen (Endlosschleife). "Ruckelt" das Fenster jetzt alle 500ms durch die Gegend beim verschieben, dann blockierst du beim Aufruf dein Programm durch das Auslesen (bzw. deine Komponente macht das).
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
spacemanspiff 
      
Beiträge: 53
Erhaltene Danke: 1
|
Verfasst: Di 04.01.11 15:39
Danke für Eure Antworten,
bin grad mit meinem Arbeitskollegen zusammen auf die Lösung gestossen.
Es lag daran, dass das OnRxChar-Event nicht schnell genug verlassen wurde. Ich habe die Funktion umgeschrieben, so dass sie sich bei dem Event den Char aus dem Empfanspuffer holt, kurz schaut, ob es eins der beiden Terminalsymbole ist, den Char entsprechend weiterleitet und die Prozedur dann wieder verlassen wird. Jetzt haut es hin... also zumindest mit dem Status, jetzt kommen ein paar mehr Bytes, aber das wird schon hinhauen
@Xion: Das mit Application.ProcessMessages ist ein sehr guter Hinweis. Den werde ich mal im Hinterkopf behalten.
Vielen Dank für die Mithilfe
Beste Grüße,
Thomas
|
|
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Di 04.01.11 15:40
Die ganze repeat-until-Schleife ist mir suspekt.
Da der Comport-Transfer Event-gesteuert ist, kann man doch gleich vor Aufruf der Auswertung eine Maske definieren, wann eine OnRxChar-Routine angesprungen werden soll.
Aber mit diesem Codeschnipsel allein kann ich Dir nicht weiterhelfen.
"Als sei das Programm damit überlastet alle 500ms ein paar Bytes zu empfangen, das geht doch nicht..."
Es tut in Wirklichkeit viel mehr, weil falsch programmiert!
|
|
Xion
      

Beiträge: 1952
Erhaltene Danke: 128
Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
|
Verfasst: Di 04.01.11 18:39
hathor hat folgendes geschrieben : | | Die ganze repeat-until-Schleife ist mir suspekt |
Die Schleife hatte ich garnicht gesehen. Klar, du rufst solange ReadAnsiChar auf, bis es ein LF ist. Wenn nur alle 500ms ein Zeichen kommt, dann dauert jeder Aufruf 500ms (blockierend). Deshalb gibt es ja das Event  Damit musst du nicht drauf warten, ob ein Zeichen kommt, sondern du kriegst gesagt, dass eins da ist. Dann kannst du den Puffer auslesen (aber auch nur dann).
_________________ a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
|
|
spacemanspiff 
      
Beiträge: 53
Erhaltene Danke: 1
|
Verfasst: Mi 05.01.11 09:23
@hathor
Die repeat-until-Schleife gibt es nicht mehr.
Wie man diese Maske definiert weiß ich leider nicht, da dies mein erstes Dephi-Projekt ist. Ich komme aus der C/Assember/Microcontroller-Ecke. Daher weiß ich auch nicht, was daran flasch programmiert ist. Generell weiß ich auch nicht, was im Hintergrund alles gekapselt abläuft. Ich schätze mal, so was kommt mit der Zeit.
Die Methode, die bei OnRxChar angesprungen wird, sieht nun so aus:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| procedure TMAIN.UARTGetChar(Sender: TObject); var C: AnsiChar; begin try C := ComPort1.ReadAnsiChar(); if C = #13 then begin CR := True end else if (C = #10) and (CR = True) then begin LF := True end else begin CR := False end; if not CR and not LF then SI := SI + C; except on E: EComError do begin ShowMessage(E.Message); end; end; end; |
@Xion
Nein, es kommt nicht alle 500ms ein einziges Zeichen, sondern alle 500ms ein Datenpaket: [Bezeichner][Byte1]...[ByteN][CR][LF].
Von einer Checksumme habe ich vorerst abgesehen, da das Messystem kein Gedächtnis hat und IMO nicht über eine Funktion verfügt, die es mir erlaubt ein Datenpaket neu anzufordern. Kommt evtl später.
|
|
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 05.01.11 12:06
Hast Du Dir schon mal die TComPort.hlp-Datei angeguckt?
Was Du machst, ist "suboptimal".
Wozu fragst Du #13 ab?
Danach kommt doch immer ein #10 !
Warte das Ende eines Strings ab und bilde dann einen neuen String.
------------
msdn.microsoft.com/e...ibrary/ms810467.aspx
Hier steht, wie man eine Maske (EV_RXFLAG) definiert:
"The event character was received and placed in the input buffer. The event character is specified in the EvtChar member of the DCB structure discussed later. The "Caveat" section below also applies to this flag."
"EV_RXFLAG inform about the receiving of a random character (z.B.#10 - Klick gemacht???) and its placing into the front-end buffer. The random character is specified in the DCB structure for the given device, which is recorded into the device by SetCommState function."
TComPort.OnRxFlag
property OnRxFlag: TNotifyEvent;
Description
Write OnRxFlag event handler to take specific action when event charachter arrives. Set EventChar property to set event charachter ASCII code.
Note
An event charachter is also placed in input buffer. The only difference between event and non-event charachter is that event charachter triggers OnRxChar and OnRxFlag events, while non-event charachter triggers only OnRxChar event.
|
|
spacemanspiff 
      
Beiträge: 53
Erhaltene Danke: 1
|
Verfasst: Mi 05.01.11 16:03
Ja, die help-Datei habe ich mir bereits angesehen...
Kannst mir auch sagen, warum das suboptimal ist? Oder nur, dass es das ist und ich rate rum? Wie gesagt komme ich aus ner anderen Ecke.
Wozu ich #13 abfrage? Weil #13 oder auch #10 Bestandteil der Daten sein kann, nur halt nicht direkt hintereinander. Somit ist das Datenpaket erst dann komplett, wenn die Bytereihenfolge #13, #10 erscheint.
|
|
bummi
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: Mi 05.01.11 18:06
Du brauchst ja nicht zu tun bis #13#10 in Deinem Buffer sind....
_________________ Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
|
|
|