| Autor |
Beitrag |
MasterM112
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 28.11.11 23:59
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 : 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
|
|
bummi
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: Di 29.11.11 00:24
such mal nach Tcomport / CPort / RxChar
oder exemplarisch
www.delphipraxis.net...stelle-einlesen.html
_________________ Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
|
|
MasterM112 
Hält's aus hier
Beiträge: 11
|
Verfasst: 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
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: 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.
_________________ Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
|
|
MasterM112 
Hält's aus hier
Beiträge: 11
|
Verfasst: 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.
|
|
bummi
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: Di 29.11.11 11:18
hol Dir mal
sourceforge.net/projects/comport/
da ist auch ein Beispiel dabei
_________________ Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
|
|
MasterM112 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mi 30.11.11 21:52
Okay, ich schau es mir mal an
Danke
|
|
MasterM112 
Hält's aus hier
Beiträge: 11
|
Verfasst: 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:
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
      
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: 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
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 
|
|
MasterM112 
Hält's aus hier
Beiträge: 11
|
Verfasst: 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
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: 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.
_________________ Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: 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).
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
MasterM112 
Hält's aus hier
Beiträge: 11
|
Verfasst: 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ß
|
|
jaenicke
      
Beiträge: 19341
Erhaltene Danke: 1752
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 16.02.12 00:30
Ich verstehe wie jfheins auch nicht warum du es dir so dermaßen schwer machst, wenn du das Übertragungsformat frei festlegen kannst. Wenn du ein festes Format hättest, wüsstest du ganz genau in welchen Bytes welche Daten stehen und damit hat sich das schon fast.
Aber wie dem auch sei:
Wie sieht denn dein aktueller Quelltext aus und was passiert?
Und was für Daten du bekommst und was damit passiert solltest du eigentlich beim Debuggen sehen:
www.delphi-treff.de/...s-delphi-7/debugger/
wiki.delphigl.com/in..._den_Delphi_Debugger
|
|
MasterM112 
Hält's aus hier
Beiträge: 11
|
Verfasst: 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
      
Beiträge: 19341
Erhaltene Danke: 1752
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
Hält's aus hier
Beiträge: 11
|
Verfasst: 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
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: 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.
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|