Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Seriell Empfangene Daten auswerten
MasterM112 - Mo 28.11.11 23:59
Titel: Seriell Empfangene Daten auswerten
Hallo,
vorab, ich habe leider nicht soviel Ahnung von Delphi, daher benötige ich bei einem Projekt Hilfe.
Also, ich habe eine Mikrocontroller-Schaltung die mehrere Sensoren auswertet und dann Seriell an den PC überträgt.
Das Übertragungsformat ist beliebig, habe mir aber in etwa folgendes überlegt:
$spannung1|xx,xx$spannung2|xx,xx$zustand1|true*****
Ich möchte nun diese Zeile in Delphi "einlesen", d.H.
die verschiedenen Werte als Variable haben.
Eine Variable wird vom Controller mit $Varname|Varwert gesendet, am Ende des gesamten Datensatzes kommen z.B. ***** .
Nun habe ich ein Programm, was mir wenn ich auf einen Button drücke den serielen Buffer als String ausgibt.
Drücke ich den Button erhalte ich als String z.B. das:
x,xx$spannung2|xx,xx$zustand1|true*****$spannung1|xx,xx$spannung2|xx,xx$zustand1|true*****$spannung1|xx,xx$spa
(je nachdem wo die Übertragung halt gerade ist.)
Ich möchte nun allerdings nicht immer einmal pro Sekunde auf einen Button drücken, sondern würde gerne wenn im Buffer die Zeichenfolge ***** erscheint den Bufferinhalt an eine Variable übergeben, sodass ich immer einen Vollständigen Datensatz habe und nicht einen zufällig unterbrochenen.
Mein Programm basiert auf dieser Grundlage hier :
http://alexmogurenko.com/Examples/ComPort.zip
Der Bereich wo der Buffer gelesen wird:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure TfrmMain.btReadClick(Sender: TObject); begin if (ComPort_ = nil) then begin exit; end;
readBuf := ''; readBuf := ComPort_.Read(); if (readBuf <> '') then begin mmRead.Text := readBuf; end; end; |
Könnte mir da evtl. jemand helfen ?
Wie ich den String dann später wieder in Variablen aufteile denke ich bekomme ich hin, nur dafür müsste ich den ersteinmal vollständig "empfangen".
Achso, habe Delphi 7 ;)
Gruß
Dirk
MasterM112 - Di 29.11.11 00:42
Okay, werde da dann nochmal suchen.
Das TComPort würde dem Empfang also vereinfachen ?
Habe mit dem aktuellen Programm es nähmlich schon so weit, das ich Werte über Buttons dahinschicken kann und den Buffern in das Textfeld bekomme ;) Fehlt im Prinziep nur noch eine "Intelligente" Veränderung des Buttons ("Gucke ob im Buffer ***** steht, wenn ja, schreibe den Buffer in eine Var").
Was sagt mir der verlinkte Thread ? Das Protokoll des Controllers habe ich ja bzw. kann es selbst bestimmen.
Gruß
Dirk
bummi - Di 29.11.11 07:59
Ich weiß nicht was Deine Komponente kann, die erwähnte handelt alles intern in einem Thread und gibt Dir Antworten in Ereignissen zurück. Wenn das Protokoll so einfach wie beschrieben ist, hast Du das Programm in 5 Min. fertig.
MasterM112 - Di 29.11.11 10:06
Denke auch das das sehr einfach ist,
allerdings schaffe ich es halt nicht :/ (Zu wenig Ahnung).
Habe versucht die genannte Funktion z.B. in eine While Schleife zu packen, um sozusagen erstmal immer Daten aus dem Buffer zu bekommen ( weiß nicht genau wie man den Buffer auf Inhalt prüft ), allerdings reagiert das Programm dann nicht mehr.
MasterM112 - Mi 30.11.11 21:52
Okay, ich schau es mir mal an ;)
Danke
MasterM112 - Mo 12.12.11 20:27
Hallo,
habe nun etwas weiter gemacht und comport verwendet.
Das Funktioniert soweit, bekomme meinen "Datenstring" in der Konsole angezeigt.
Allerdings komme ich nun nicht ganz weiter, beim Teilen des Strings.
Ich erhalte als String immer soetwas:
Quelltext
1: 2: 3: 4: 5: 6:
| $Poti1|0$Poti2|1023$Foto1|470 $Poti1|0$Poti2|1023$Foto1|477 $Poti1|0$Poti2|1023$Foto1|468 $Poti1|0$Poti2|920$Foto1|176 $Poti1|56$Poti2|830$Foto1|136 $Poti1|132$Poti2|830$Foto1|462 |
Das möchte ich als erstes in 3 Strings aufteilen, die immer durch das Zeichen $ getrennt sind.
Danach möchte ich die einzelden Strings in eine Integervariable wandeln.
Allerdings scheitert es schon am ersten Schritt:
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: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152:
| unit ComMainForm;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, CPort, CPortCtl;
type TForm1 = class(TForm) ComPort: TComPort; Memo: TMemo; Button_Open: TButton; Button_Settings: TButton; Edit_Data: TEdit; Button_Send: TButton; NewLine_CB: TCheckBox; Panel1: TPanel; Bt_Store: TButton; Bt_Load: TButton; ComLed1: TComLed; ComLed2: TComLed; ComLed3: TComLed; ComLed4: TComLed; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; ComLed5: TComLed; ComLed6: TComLed; Label1: TLabel; Label6: TLabel; Panel2: TPanel; Label7: TLabel; Label8: TLabel; Label9: TLabel; Label10: TLabel; Button1: TButton; Panel3: TPanel; Panel4: TPanel; Display1: TLabel; Label12: TLabel; Label13: TLabel; Panel5: TPanel; Panel6: TPanel; Display2: TLabel; Label14: TLabel; Label15: TLabel; Panel7: TPanel; Panel8: TPanel; Display3: TLabel; Label16: TLabel; Label17: TLabel; Label11: TLabel; Label18: TLabel; Label19: TLabel; Label20: TLabel; Label21: TLabel; Label22: TLabel; Button2: TButton; procedure Button_OpenClick(Sender: TObject); procedure Button_SettingsClick(Sender: TObject); procedure Button_SendClick(Sender: TObject); procedure ComPortOpen(Sender: TObject); procedure ComPortClose(Sender: TObject); procedure ComPortRxChar(Sender: TObject; Count: Integer); procedure Bt_LoadClick(Sender: TObject); procedure Bt_StoreClick(Sender: TObject); procedure Button2Click(Sender: TObject); private public end;
var Form1: TForm1; Eingehend: String; s : String; StrL : TStringList;
implementation
{$R *.DFM}
procedure TForm1.Button_OpenClick(Sender: TObject); begin if ComPort.Connected then ComPort.Close else ComPort.Open; end;
procedure TForm1.Button_SettingsClick(Sender: TObject); begin ComPort.ShowSetupDialog; end;
procedure TForm1.Button_SendClick(Sender: TObject); var Str: String; begin Str := Edit_Data.Text; if NewLine_CB.Checked then Str := Str + #13#10; ComPort.WriteStr(Str); end;
procedure TForm1.ComPortOpen(Sender: TObject); begin Button_Open.Caption := 'Trennen'; Label10.Caption := 'Port geöffnet'; Label10.Font.Color := clGreen; end;
procedure TForm1.ComPortClose(Sender: TObject); begin if Button_Open <> nil then Button_Open.Caption := 'Verbinden'; Label10.Caption := 'Port geschlossen'; Label10.Font.Color := clRed; end;
procedure TForm1.ComPortRxChar(Sender: TObject; Count: Integer); begin ComPort.ReadStr(Eingehend, Count); Memo.Text := Memo.Text + Eingehend; s:=Eingehend; s:=StringReplace(s,'$',',',[rfReplaceAll]); StrL:=TStringList.Create; StrL.CommaText:=S; Label20.Caption:=StrL[0]; Label21.Caption:=StrL[1]; Label22.Caption:=StrL[2]; StrL.Free; end;
procedure TForm1.Bt_LoadClick(Sender: TObject); begin ComPort.LoadSettings(stRegistry, 'HKEY_LOCAL_MACHINE\Software\Dejan'); end;
procedure TForm1.Bt_StoreClick(Sender: TObject); begin ComPort.StoreSettings(stRegistry, 'HKEY_LOCAL_MACHINE\Software\Dejan'); end;
end. |
Der Teil:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.ComPortRxChar(Sender: TObject; Count: Integer); begin ComPort.ReadStr(Eingehend, Count); Memo.Text := Memo.Text + Eingehend; s:=Eingehend; s:=StringReplace(s,'$',',',[rfReplaceAll]); StrL:=TStringList.Create; StrL.CommaText:=S; Label20.Caption:=StrL[0]; Label21.Caption:=StrL[1]; Label22.Caption:=StrL[2]; StrL.Free; end; |
Ist der wo "empfangen" wird.
Allerdings kommt sobald ein Datensatz empfangen wird:
Projekt ComExample.exe raised exeption class EStringListError with message 'List index out of bounds (2)'. Process stopped. Use Step or Run to continue.
Ideas ?
Kann damit leider nicht so viel Anfangen :(
Gruß
Dirk
Moderiert von
Martok: Quote- durch Delphi-Tags ersetzt
jfheins - Mo 12.12.11 21:25
ich tippe mal folgendes:
Zu dem Zeitpunkt wo das Empfangen-Event aufgerufen wird ist zwar *etwas* da, aber noch nicht alles. daher hast du keine 2 $, weshalb der Zugriff auf den Index 2 fehlschlägt. Das hätte mna durch debuggen aber eigentlich rausfinden müssen :gruebel:
Mal davon abgesehen hätte ich das ein wenig anders gelöst. Ein (oder zwei) Byte für den Typ (Poti1,Poti2,usw.) und dann 2 Bytes für den eigentlichen Wert. Die Konvertierung in Text kannste dann im PC machen. Hat z.B. den Vorteil dass du einfach 3 (oder 4) Bytes liest und diese dann in einen (packed) record kopieren kannst. Und du weißt genau, wieviele Bytes ankommen müssen. Und die Datenübertragung geht schneller. Aber das nur so nebenbei :mrgreen:
MasterM112 - Mo 12.12.11 23:33
| Zitat: |
| Das hätte mna durch debuggen aber eigentlich rausfinden müssen |
Sorry, bin der größte DAU was Delphi angeht :/
Verstehe nun aber das Problem,
was ja aufjedenfall ein Problem ist, weil später nicht immer alle Daten übertragen werden sollen sondern nur wenn sich etwas ändert bzw. in größeren Zeitintervallen dann der ganze Datensatz oder auf Anforderung.
Das ganze in Bytes zu übertragen kann auch gemacht werden, da es aber ein Übungsprojekt ist hab ich es für die verständlichkeit erstmal so angedacht. Sind ja nicht die Welt an Daten was da übertragen wird ;)
Die Interessantere Frage ist, wie löse ich das Problem ;)
Ich könnte am Ende des Datensatzes noch eine Art Abschlusscode (****) wie im Einganspost genannt setzten, nur müsste das auch irgendwie ausgewertet werden.
Habe einige Codesteine gefunden, mit dem man den String nach dem Abschlusszeichen durchsuchen kann, mal gucken ob ich das irgendwie verwendet bekomme.
Gruß
Dirk
bummi - Mo 12.12.11 23:45
mein üblicher Ansatz bei dem Kram ist alles was reinkommt an einen Puffer anzuhängen, danach eine Routine aufzurufen die versucht soviel wie möglich aus dem Puffer zu interpretieren und weiterzureichen und verarbeitetes aus dem Puffer zu entfernen.
Was in jedem Fall vorhanden sein muss ist eine rudimentäre Art von Protokoll.
Wenn ich Dein bisheriges richtig verstehe ist #13#10 der "Satztrenner", Pipe eine Art =, wenn Du den Puffer
in einer Schleife nach dem ersten #13#10 durchsucht, den String bis dahin einer Auswertefunktion übergibst und den String #13#10 aus dem Puffer entfernst sollte durchlaufen.
Martok - Di 13.12.11 08:04
Das kann die CPortLib sogar selber: TComPortPacket macht exakt das.
Dem sagt man, wie die Terminatorzeichen aussehen und das macht das Puffern und durchsuchen selber. Im Endeffekt bekommst du dann pro Paket (hier: pro Zeile) ein Ereignis, bei dem du sicher sein kannst dass wirklich alles da ist (außer beim ersten Paket, das auch partiell reinrutschen kann).
MasterM112 - Mi 15.02.12 20:55
Hallo und sorry, das ich mich solange nicht gemeldet habe, habe mich erstmal mit der anderen "Seite" des Projektes befasst und die Hardware weiter aufgebaut.
Bin leider im Dezember vollkommen gescheitert und will das ganze nun nochmal in Angriff nehmen.
TComPortPacket, wie verwende ich das ? Google gibt mir dazu leider ganze 5 Ergebnisse :(
Erhalte die Daten nun in diesem Format:
###START###
$time=00:00:00
$date=01.01.2012
$temp=22,6
$druck=1024
$wasserstoff=1024
$sauerstoff=1024
$pumpe=1
$status=ok
[...]
###ENDE###
d.H. er müsste mit der Auswertung erst Anfangen wenn ###ENDE### auftritt, so würden immer alle Daten vollständig ankommen.
Scheitere aber aktuell schon am Elementearen, z.B. wenn ich mir einfach Zahlen geben lasse:
896
1020
760
110
520
etc. stehen die im Beispiel "ComPort Library example" in der Konsole richtig drinn, wenn ich den gleichen Wert ins Edit oder Label übertrage erhalte ich dort entweder nichts oder die letzten beiden Stellen der Zahl.
Beim Weiterverarbeiten funktioniert StrToInt auch nicht, obwohl ja eigendlich nur Zahlen kommen.
Bin verwirrt.
Gruß
MasterM112 - Do 16.02.12 16:11
Könnte ich auch machen, das Senden der Daten sit sicherlich nicht das Problem.
Allerdings kenne ich mich da in der auswertung genausowenig aus.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.ComPortRxChar(Sender: TObject; Count: Integer); var Str: String; begin ComPort.ReadStr(Str, Count); Memo.Text := Memo.Text + Str; Label7.Caption := Str; end; |
Hier erhalte ich z.B: beim Empfangen von 878 im Label mal 78 und mal nichts, obwohl im Memo es richtig steht.
jaenicke - Do 16.02.12 16:26
Was zusammenhängend ankommt weißt du schlicht nicht. Wie schon einmal geschrieben:
Pack die Daten dort nur in einen Puffer (so wie in das Memo) und interpretiere dann den Puffer. Sprich such darin nach Start- und Endsequenzen.
MasterM112 - Do 16.02.12 16:33
und wie mache ich sowas ?
Mit TComPortPacket oder ComPort.ReadStr ?
Gibt es noch irgendwo mehr Beipspiele zu Comport, wo ich mir das evtl. ableiten könnte ?
Gruß
Martok - Do 16.02.12 22:00
Mitgeliefert gibts nur ein ganz einfaches, aber versuchs doch einfach mal. Die Eigenschaften sind eigentlich alle selbsterklärend...
- TComPort aufs Form legen und konfigurieren bzw. GUI zusammenklicken
- TComPortPacket aufs Form legen, ComPort zuweisen, Start/Stop-Sequenzen festlegen
- OnPacket-Ereignis zuweisen und dort mit den Daten arbeiten.
Wenn du das Protokoll sowieso selber machst, kannst du dir ja was ganz einfaches machen, z.B. wie im allerersten Post Werte mit | trennen.
'$20120224122530|22.6|1024|whatever'#13#10 wäre doch was? Startzeichen wäre dann $ und Endsequenz #13#10.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!