Serial Comunication Send and Receive

RubenMts

Level-2
Beiträge
23
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo ich habe ein Problem mit der SeriellenKommunication über eine EL6022 Klemme. Ich möchte über SendString und ReceiveString verschiedene Telegramme an eine Vakuumpumpe versenden. Dabei handelt es sich zum einen um eine Druckabfrage und Start bzw. Stop befehle. Mein Problem ist das Handling der Antworten der Pumpe. Ich habe das ganze Programm gerade so aufgebaut, das in jedem Zyklus einmal der Druck abgefragt wird und (je nach GUI zustand) auch die Pumpe gestartet bzw. gestoppt wird. Dabei werden zwei Strings an den TXBuffer übergeben. Die Pumpe antwortet anschließend mit einem String für den Druck und wiederholt den Start/Stop String um das Starten zu bestätigen. Ich würde am liebsten jeden Zyklus den ganzen RXBuffer über die Funktion ReceiveString auslesen und muss diesen FB daher öffters aufrufen, je nach dem wie voll der Buffer ist. Aus diesem grund würde ich eine Whileschleife verwenden, welche die Entsprechenden Strings über ReceiveString erhält und anschließend interpretiert. Ich habe nur das Gefühl das eine solche Whileschleife eine sehr unschöne Lösung für mein Problem ist. Das ist das erste mal, dass ich mit einer Seriellen Schnittstelle arbeite und ich frage mich ob ich mich darauf beschränken sollte pro Cycletime nur ein String zu versenden und zu empfangen. Ich hoffe das Problem wird ersichtlich und ihr könnt mir weiterhelfen. 1705226712819.png
 

Anhänge

  • 1705226779027.png
    1705226779027.png
    49,8 KB · Aufrufe: 6
Vielleicht ganz grundsätzlich dazu :
Deine SPS arbeitet zyklisch - das heißt, dass du mit einer Schleife den Zyklus festhältst. So erreichst du also nichts außer einer möglichen Zykluszeit-Überschreitung.
Dann kann ich mir beim allerbesten Willen nicht vorstellen, dass du jeden SPS-Zyklus einen String übertragen oder empfangen bekommst. Deine SPS wird im Millisekunden-Bereich arbeiten - da kommt deine serielle Schnittstelle nicht ansatzweise mit.
Besser wäre hier (für das Empfangen) den Buffer abzufragen und wenn er die gewünschte Anzahl von Zeichen enthält diesen auszulesen.
Insgesamt würde ich hier eine Art Statemachine (also Schrittkette wenn du so willst) erstellen, die die Sachen nacheinander erledigt - also :
1: String senden
2: warten bis gesendet
3: warten bis Lese-Puffer-Inhalt korrekt
4: Lese-Puffer auslesen
5: Lese-Puffer auswerten
6: wieder zu 1
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Vielleicht ganz grundsätzlich dazu :
Deine SPS arbeitet zyklisch - das heißt, dass du mit einer Schleife den Zyklus festhältst. So erreichst du also nichts außer einer möglichen Zykluszeit-Überschreitung.
Dann kann ich mir beim allerbesten Willen nicht vorstellen, dass du jeden SPS-Zyklus einen String übertragen oder empfangen bekommst. Deine SPS wird im Millisekunden-Bereich arbeiten - da kommt deine serielle Schnittstelle nicht ansatzweise mit.
Besser wäre hier (für das Empfangen) den Buffer abzufragen und wenn er die gewünschte Anzahl von Zeichen enthält diesen auszulesen.
Insgesamt würde ich hier eine Art Statemachine (also Schrittkette wenn du so willst) erstellen, die die Sachen nacheinander erledigt - also :
1: String senden
2: warten bis gesendet
3: warten bis Lese-Puffer-Inhalt korrekt
4: Lese-Puffer auslesen
5: Lese-Puffer auswerten
6: wieder zu 1
Danke, das habe ich auch schon einmal probiert, hatte aber Porbleme mit dem Handling unterschiedlicher Strings. Also kann ich davon ausgehen das meine SPS deutlich schneller läuft als die serielle Übertragung? Die Backround Kommunication läuft in einer 2ms task und mein Programm in einer 10ms Task. Die Baudrate ist 9600.
Ich würde nun also einen FB_SendAndReceive erstellen und in dem die von dir Beschriebene Statemachine aufbauen. In main rufe ich diesen FB dann jeden Zyklus auf. Dann würde ich in main noch eine State machine machen die den String erstellt je nachdem was gerade ausgeführt werden soll.
Also:
1: Druck abfragen
2: Pumpe starten
3: Pumpe stoppen
Über HMI Schaltflächen kann dann der State gewechselt werden. Ich hatte auf jeden Fall da schon das Problem, das der TXBuffer vollgelaufen ist weil zu viele Druckabfragen gemacht wurden(Da hatte ich die Backround Kommunikation aber noch nicht im schnellen Task separiert). Sollte ich also in dem FB_SendAndReceive einbauen das erst geprüft wird ob das Telegram bereits im TXBuffer enthalten ist?
 
Ich hatte auf jeden Fall da schon das Problem, das der TXBuffer vollgelaufen ist weil zu viele Druckabfragen gemacht wurden(Da hatte ich die Backround Kommunikation aber noch nicht im schnellen Task separiert). Sollte ich also in dem FB_SendAndReceive einbauen das erst geprüft wird ob das Telegram bereits im TXBuffer enthalten ist?
Das heißt ja, dass du viel zu schnell hintereinander sendest. Du solltest also überprüfen, ob der Sendevorgang komplett erfolgt ist (danach müßte der TXBuffer also wieder leer sein).
Mein Beispiel mit der Statemachine war auch erstmal ein Ansatz - du wirst du ggf. noch weitere Schritte einplanen müssen.
Dein FB kann in jedem Zyklus aufgerufen werden - den nächsten Schritt darfst du aber immer erst zulassen wenn du sicher bist, dass der vorherige komplett erfüllt worden ist ...
 
Das heißt ja, dass du viel zu schnell hintereinander sendest. Du solltest also überprüfen, ob der Sendevorgang komplett erfolgt ist (danach müßte der TXBuffer also wieder leer sein).
Mein Beispiel mit der Statemachine war auch erstmal ein Ansatz - du wirst du ggf. noch weitere Schritte einplanen müssen.
Dein FB kann in jedem Zyklus aufgerufen werden - den nächsten Schritt darfst du aber immer erst zulassen wenn du sicher bist, dass der vorherige komplett erfüllt worden ist ...
1705233082953.png

1705233123500.png
Dankeschön, ich habe hier mal meinen FB eingefügt. Ich kann leider erst am Dienstag Testen ob es damit läuft, dann melde ich mich hier nochmal :)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo @RubenMts
das wird so nicht funktionieren. Im Schritt "TRIGGER" wird der fbSendString-Baustein nur aufgerufen, wenn der Busy-Ausgang FALSE ist.
Da aber sich das Senden über mehrere Zyklen ziehen kann und der Baustein nach dem ersten Aufruf auf Busy = TRUE wechselt, wirst du immer in dem TRIGGER-Schritt bleiben.
Mache es so wie im READ-Schritt. Dort rufst du auch fbReceiveString permanent auf.

-Stirni
 
Hallo @RubenMts
das wird so nicht funktionieren. Im Schritt "TRIGGER" wird der fbSendString-Baustein nur aufgerufen, wenn der Busy-Ausgang FALSE ist.
Da aber sich das Senden über mehrere Zyklen ziehen kann und der Baustein nach dem ersten Aufruf auf Busy = TRUE wechselt, wirst du immer in dem TRIGGER-Schritt bleiben.
Mache es so wie im READ-Schritt. Dort rufst du auch fbReceiveString permanent auf.

-Stirni
Oh ja guter Punkt. Danke!
 
Moin, ich habe das Programm jetzt so aufgebaut das ich für jede pumpe FB_PumpCommunication dauerhaft aufrufe.



1705490879800.png
Diese Ruft dann den Send_Parameter_Receive_AnswerFB auf.
Bisher scheint alles sehr gut zu funktionieren. Auch bei mehreren Pumpen.

1705491059650.png
Vielen Dank für eure Hilfe! Das ist eine meiner ersten SPS Programme daher bin ich noch sehr unsicher wie FBs etc am besten aufgebaut und verwendet werden sollten.
VG Ruben
 

Anhänge

  • 1705490954034.png
    1705490954034.png
    69,8 KB · Aufrufe: 6
Sorry war vorhin etwas kurz.

Im ersten Bild bei Request_Preasure die Abfrage des Start/Stop Buttons würde ich mit einem ELSE machen. Du fragst ja einen boolschen Wert auf zwei Zustände hin ab aber er kann ja bloß zwei Zustände haben ( WAHR / FALSCH ).


Im zweiten Bild in Zeile 4 "Execute := True" ist keine Abfrage sondern eine Zuweisung. Das heißt, die wird niemals FALSE werden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Sorry war vorhin etwas kurz.

Im ersten Bild bei Request_Preasure die Abfrage des Start/Stop Buttons würde ich mit einem ELSE machen. Du fragst ja einen boolschen Wert auf zwei Zustände hin ab aber er kann ja bloß zwei Zustände haben ( WAHR / FALSCH ).


Im zweiten Bild in Zeile 4 "Execute := True" ist keine Abfrage sondern eine Zuweisung. Das heißt, die wird niemals FALSE werden.
Oh ja, das ist mir garnicht aufgefallen. Komisch das es trotzdem funktioniert. Erklärt aber auch warum ich im ersten Bild den CheckPressure command abfragen kann ohne Execute auf true zu setzen. Jetzt hab ich das Gefühl, das der FB_pumpCommucication so nicht mehr funktionieren wird.
 
Zuletzt bearbeitet:
wenn Execute ein Bool ist dann brauchst du ja auch grundsätzlich nicht schreiben "if Execute = true ..." sondern du kannst ganz einfach "IF Execute ... " schreiben.
Was mir an deinem Code auch nicht so gut gefällt ist das bedingte Aufrufen des Timers. Das wird hier funktionieren - ist aber eigentlich unsauber.
Besser wäre wenn du den Timer außerhalb deines CASE programmierest (also absolut aufrufst) und als IN-Bedingung dann "setParameterState = READ" stehen hast.
 
wenn Execute ein Bool ist dann brauchst du ja auch grundsätzlich nicht schreiben "if Execute = true ..." sondern du kannst ganz einfach "IF Execute ... " schreiben.
Was mir an deinem Code auch nicht so gut gefällt ist das bedingte Aufrufen des Timers. Das wird hier funktionieren - ist aber eigentlich unsauber.
Besser wäre wenn du den Timer außerhalb deines CASE programmierest (also absolut aufrufst) und als IN-Bedingung dann "setParameterState = READ" stehen hast.
Ja habe ich geändert. Das mit dem Timer wird mir nicht ganz ersichtlich wie das gemeint ist. Noch eine etwas andere Frage: Wenn ich eine Case anweisung habe und von einem Case in den nächsten wechsel, wird dieser erst im nächsten Zyklus aufgerufen oder?
 
wenn Execute ein Bool ist dann brauchst du ja auch grundsätzlich nicht schreiben "if Execute = true ..." sondern du kannst ganz einfach "IF Execute ... " schreiben.
Was mir an deinem Code auch nicht so gut gefällt ist das bedingte Aufrufen des Timers. Das wird hier funktionieren - ist aber eigentlich unsauber.
Besser wäre wenn du den Timer außerhalb deines CASE programmierest (also absolut aufrufst) und als IN-Bedingung dann "setParameterState = READ" stehen hast.
Der Aufruf ist nicht unsauber und auch nicht besser wenn außerhalb der Schrittkette aufgerufen. Ich beispielsweise finde diese Art besser als außerhalb aufzurufen, da so alles übersichtlich innerhalb des Schrittes aufgerufen wird und man nicht irgendwo hin scrollen muss um den Aufruf zu sehen.
Wenn ein Schritt erweitert wird, einfach wieder mit TRUE und am Ende des Schritts mit FALSE aufrufen und gut ist.
Was ich jedoch noch machen würde: Am Anfang der Schrittkette mit FALSE aufrufen, damit wenn die Schrittkette abgebrochen werden sollte auch wieder alles sauber initialisiert ist.
Ist aber eben Geschmackssache.

-Stirni
 
Zurück
Oben