Autor Beitrag
Blamaster
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Sa 05.07.08 11:47 
Hi,

wie kann man in Delphi auf eine Procedure warten ?

Folgendes soll passieren.

Ich habe jetzt mal beispielsweise folgenden code:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure TForm1.SerialPortNG1RxClusterEvent(Sender: TObject);
begin
Rs232in:= SerialPortNG1.ReadNextClusterAsString;
end;

end;

procedure TForm1.Button5Click(Sender: TObject);
begin
SerialPortNG1.SendString('sendcues'+#$0d#$0a);
AUF BEGINN UND ENDE DER PROCEDURE WARTEN
SerialPortNG1.SendString('20'+#$0d#$0a);
AUF BEGINN UND ENDE DER PROCEDURE WARTEN
SerialPortNG1.SendString('5'+#$0d#$0a);
AUF BEGINN UND ENDE DER PROCEDURE WARTEN
SerialPortNG1.SendString('6'+#$0d#$0a);
AUF BEGINN UND ENDE DER PROCEDURE WARTEN
SerialPortNG1.SendString('2'+#$0d#$0a);
end;


procedure TForm1.SerialPortNG1RxClusterEvent wird angesprungen, wenn über den Com Port daten an den Pc gesendet werden.

Wenn ich den Button klicke soll SerialPortNG1.SendString('sendcues'+#$0d#$0a); ausgeführt werden und danach gewartet werden bis SerialPortNG1RxClusterEvent angesteuert und beendet wird. Erst dann soll SerialPortNG1.SendString('20'+#$0d#$0a); ausgeführt werden. Danach wieder das selbe spielchen, bis das ende der Button5Click Procedure erreicht ist.

mfg blamaster
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Sa 05.07.08 12:13 
Normalerweise kann in Delphi immer nur eine Prozedur ausgeführt werden, d.h. es wird immer gewartet, bis eine Anweisung abgeschlossen ist. Vielleicht wird aber in der Prozedur, die du aufrufst, ein neuer Thread gestartet. In diesem Fall wird die Prozedur danach sofort verlassen, und die Anweisungen in dem Thread parallel zu deinem Hauptthread ausgeführt. Vielleicht solltest du dir mal, wenn vorhanden, den Quelltext der Prozedur SendString anschauen.

Wenn du bereit wärst, die Komponente zu ändern, dann könntest du dir auch mal comm_async anschauen. Da werden die Daten erst komplett gesendet, bevor die Programmausführung weitergeht.
Blamaster Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Sa 05.07.08 12:32 
Das Problem war bisher immer folgendes:

Wenn ich Daten mit Delphi (obige procedure) an den Microcontroller geschickt habe, führte das zu einem Datenchaos, das Delphi scheinbar alles zu sendenden strings sofort rausgeballert hat. Deswegen dachte ich mir nun soll der erste String gesendet werden. Daraufhin schickt der Microcontroller den empfangenen String wieder an den Pc zurück, damit das Delphi Programm weiß, das der String definitiv nun erfolgreich gesendet wurde. Dann soll es halt den nächsten String schicken und wieder auf bestätigung warten.

Hat da jemand von euch ne elegante Lösung für das Problem ?

mfg Blamaster
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Sa 05.07.08 12:42 
Du könntest eine Variable definieren, die immer den gesendeten String enthält. Nach dem Senden des Strings gehst du in eine Schleife, die darauf wartet, dass dieser String leer wird.

Im Ereignis "String empfangen" überprüfst du, ober der String dem gesendeten entspricht. Wenn das der Fall ist, wird die Variable geleert (was dazu führt, dass die Sendemethode weitermacht. Falls der String falsch ist oder ein Timeout in der Warteschleife auftritt, wird ein Fehler gemeldet.
Blamaster Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Sa 05.07.08 13:26 
Hi, das hört sich shconmal super an. Kannst du das an ein bisschen code bildlich machen kann mir das gerade noch nicht so ganz wirklich vorstellen.

mfg Blamaster
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: Sa 05.07.08 13:41 
Ok, ich versuch's mal...

ausblenden volle Höhe 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:
type
  TForm1 = class(TForm)
    {...}
  private
    // Variable für gesendeten String
    SendedString: String;

    // Sendet einen String und wartet auf die Antwort
    procedure SendString(const S: String);
  end;

  // Exception definieren
  ESerialPortError = Exception;

{...}

const
  // Wie lange darf die Gegenseite mit der Antwort warten?
  Timeout = 1000;

{...}

procedure TForm1.SendString(const S: String);
var Time: Cardinal;
begin
  // String mit #13#10 senden
  SerialPortNG1.SendString(S + #$0D#$0A);

  // Auf Antwort warten
  Time := GetTickCount;
  while Time+Timeout > GetTickCount do
    if SendedString = '' then Break;

  // Wenn kein String angekommen, Fehler Melden
  if SendedString <> '' then
    raise ESerialPortError.Create('Gegenseite antwortet nicht');
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  SendString('sendcuess');
  SendString('20');
  SendString('5');
  SendString('6');
  SendString('2');
end;

procedure TForm1.SerialPortNG1RxClusterEvent(Sender: TObject);
var S: String;
begin
  // String auslesen
  S := SerialPortNG1.ReadNextClusterAsString;

  // Wenn String ok, Empfang melden; sonst Fehler melden
  if S = SendedString then
    SendedString := ''
  else
    raise ESerialPortError.Create('Gegenstelle lieferte ungültige Antwort');
end;

Wenn ein Fehler auftritt, sorgt Delphi dafür, dass die gesamte Prozedur abbricht. Du solltest ihn jedoch noch mit

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
try
  {...}
except
  on E: ESerialPortError do
    Application.MessageBox(PChar('Fehler beim Senden eines Strings: '+E.Message), 'Fehler', MB_ICONERROR);
end;

oder etwas ähnlichem irgendwo abfangen.
Blamaster Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Sa 05.07.08 15:58 
Hi,

Thx erstmal.

Also so ganz funzen wollte der code so noch nicht. Ich habe ihn für Testzwecke etwas abgespeckt gehabt. also die abgleiche zwischen gesendetem und ankommendem strings entfernt.

ausblenden 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:
procedure TForm1.SendString(const S: String);
var Time: Cardinal;
begin
  SerialPortNG1.SendString(S + #$0D#$0A);
  Time := GetTickCount;
  while Time+Timeout > GetTickCount do
    if SendedString = '' then Break;
    if SendedString <> '' then
    raise ESerialPortError.Create('Gegenseite antwortet nicht');
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  SendString('20');
  SendString('5');
  SendString('6');
  SendString('2');
end;

procedure TForm1.SerialPortNG1RxClusterEvent(Sender: TObject);
var S: String;
begin
  S := SerialPortNG1.ReadNextClusterAsString;
  ShowMessage(S);
  SendedString := ''
end;


Wenn ich jetzt button 5 klicke sendet er die 20 diese bekomme ich dann auch über das ShowMessage(S); die 20 wieder zurückgegeben. Danach scheint er aber die weiteren SendString nicht mehr abzuarbeiten.

Woran kann das liegen ?

Edit. Habe jetzt nochwas getestet

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure TForm1.Button5Click(Sender: TObject);
begin
  SendString('20');
  ShowMessage('1');
  SendString('5');
  ShowMessage('2');
  SendString('6');
  ShowMessage('3');
  SendString('2');
end;


Wenn ich nun Button 5 klicke erreiche ich jedes Show Message und die werte werden auch alle an den controller gegeben.

Ich vermute also mal das es mit dem timing noch nicht klappt. Woran merkt den das programm momentan ob der µC die Daten auch verarbeitet hat und wieder empfangsbereit ist ?
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: So 06.07.08 12:22 
Zuerst mal, dass es hier keine Missverständnisse geben wird:

user profile iconBlamaster hat folgendes geschrieben:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure TForm1.SendString(const S: String);
var Time: Cardinal;
begin
  SerialPortNG1.SendString(S + #$0D#$0A);
  Time := GetTickCount;
  while Time+Timeout > GetTickCount do
    if SendedString = '' then Break;
    if SendedString <> '' then
    raise ESerialPortError.Create('Gegenseite antwortet nicht');
end;

Die markierte Zeile solltest du um eine Stelle ausrücken, die gehört nicht in die Schleife, sonst bräuchtest du ja ein begin ... end. In der Schleife wird einfach nur geprüft, ob der String inzwischen leer ist (also die Empfangs-Prozedur erfolgreich war). Weil ja auch ein Timeout auftreten kann (im Schleifenkopf definiert), muss am Schluss noch der Grund geprüft werden, warum die Schleife verlassen wurde. Sollte ein Timeout aufgetreten sein, ist ja die Variable noch nicht leer.

user profile iconBlamaster hat folgendes geschrieben:
Woran merkt den das programm momentan ob der µC die Daten auch verarbeitet hat und wieder empfangsbereit ist ?

Der Microcontroller sendet die Daten doch erst wieder zurück, wenn er sie komplett ausgewertet hat, oder? Die Schleife wartet ja darauf, dass sie wieder zurückgesendet werden. Natürlich gehe ich davon aus, dass er dann wieder Aufnamefähig ist.

Vielleicht hilft ein Application.ProcessMessages in der Schleife - das könntest du mal ausprobieren.