Variablenkonflikt im TwinCat PLC ?!

Hans_der_Kann`s

Level-1
Beiträge
17
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Zusammen,

Ich habe mir ein kleines SPS Prokjekt gebastelt und beim Test des Programms treten Fehler auf, die ich mir nicht erklären kann. Vielleicht kann jemand von euch auf die Schnelle herrausfinden wo das Problem liegt..meine Vermutung ist, das die Variablen sich gegenseitig irgendwo blockieren...

Zur Funktion: Das Programm hat zwei Modi (Modus1 und Modus Zwei) in der jeweils die Ausgänge (verknüpft mit den globalen Variablen) eingestellt werden sollen. Zudem können in beiden Modi's die Funktion Automatik oder Manuell ausgewählt werden. Im Automatikmodus wir sowohl in Mod1 wie auch im Mod zwei ein Impuls erzeugt, der dann den Ausgang schaltet..nach einer gewissen Zeit erfolgt dann der zweite Ausgang usw. Dies funktioniert auch so, wie ich mir das vorstelle!
Das gleiche passiert im Modus2, nur das dort durch betätigen der Button_Manuell die Kanäle einzeln geschaltet werden können.

Mein Problem: Beim Start des Programms sollte das Programm im Modus1 starten (alle Kanäle MÜSSEN TRUE sein. sind sie aber nicht) Im manuell betrieb dann, werden beim betätigen der Manuell_Buttons die Kanäle nicht geschalten obwohl der Impuls kommt. Automatikmodus läuft einwandfrei.

Mein Programmierstil ist nicht der beste, es geht bestimmt anders besser, aber es funktioniert eigentlich. Ich hoffe das mir da jemand weiterhelfen kann. Das Programm befindet sich im Anhang. Wenn was zu der Funktion nicht klar ist, einfach kurz posten. Danke
 

Anhänge

  • SPS_Test.zip
    5 KB · Aufrufe: 11
Unbenannt.JPG
Du hast den Fehler schon selbet gefunden. Du schreibst mehrfach auf die gleichen Variablen, diese haben dann den Wert des letzten Bausteins. Du kannst auf dem Bild die Zutände der Bausteinausgänge ansehen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Es ist zum verzweifeln...ich hab jetzt alle meine Variablen in den FBs umbenannt...aber es geht immer noch nicht. Die Speicherwirkung der Variablen kann ich doch mit meiner IF..ELSE Bedingung umgehen...sie sollten also wieder zurückfallen wenn die Bedingung nicht erfüllt ist. Also alle Standardmäßig TRUE. Ich komm einfach nicht dahinter. Vielleicht kann mir jemand von euch einen Lösungsansatz geben. Oder muss ich es wohlmöglich programmiertechnisch komplett anders lösen?
 
Du schreibst nach jedem Bausteinaufruf die Outputs des FB's auf die globalen HW-Ausgänge. Der letzte Aufruf im MAIN ist der von LED_TEST_AUTO_MOD1, die HW-Ausgänge erhalten also immer die Werte der OUTPUT-Variablen dieses FB's. In diesem FB steht
Code:
IF( PlatGrundpos AND Button_Automatik  AND NOT Button_Mod2)

THEN
.....
END_IF;
Wenn die Bedingung nicht erfüllt ist, bleiben die OUTPUT-Variablen des FB's unverändert auf dem Wert FALSE, mit dem sie beim Programmstart automatisch initialisiert werden.
Du darfst die OUTPUT-Variablen der FB's im MAIN nicht 1:1 auf die HW-Ausgänge schreiben, sondern nur unter der im jeweiligen FB formulierten Bedingung.
 
zufriedenstellenden Ergebnis gekommen.
@StructuredTrash
Du schreibst nach jedem Bausteinaufruf die Outputs des FB's auf die globalen HW-Ausgänge. Der letzte Aufruf im MAIN ist der von LED_TEST_AUTO_MOD1, die HW-Ausgänge erhalten also immer die Werte der OUTPUT-Variablen dieses FB's.
Jepp, das hab ich dann gemerkt wo ich einfach mal die Ini der FBs im Main vertauscht habe..plötzlich gingen die AUTO_TESTs nicht mehr.
Du darfst die OUTPUT-Variablen der FB's im MAIN nicht 1:1 auf die HW-Ausgänge schreiben, sondern nur unter der im jeweiligen FB formulierten Bedingung.
Habe das jetzt so geändert das die globalen Variablen im FB gesetzt werden..funktioniert soweit..und ist jetzt auch übersichtlicher, und ich muss die Variablen nicht ins Main verknüpfen

Trotz der hilfreichen Beschreibung bin ich noch nicht auf den Trichter gekommen wie ich mein Prog umschreiben muss. Was mir noch nicht ganz einleuchtet ist die Abarbeitung des Progs. wie geht das genau vonstatten?
Hab auch schon versucht mit Hilfe einer SWITCH..CASE die FBs nach und nach abarbeiten zu lassen...das geht teilweise..krieg aber Probleme mit meinen IF..ELSE Bedingungen.
Mir Hilft jetzt wahrscheinlich nur noch ein Codebeispiel in dem ich seh wo mein Fehler liegt und wie mans umändern kann.
@gloeru
Danke für den Tipp...aber bist du dir sicher das der Link stimmt? Bringt mich hier auf
Control unit cycle time (TNcyc)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ups, der Link ist natürleich falsch, hier der Richtige: http://infosys.beckhoff.com/index.p...ntrol/html/tcplcctrl_onlinedebug.htm&id=13307

Du hast die Abarbeitung des Programms noch nicht begriffen!
Grundsätzlich wird im MAIN von oben nach unten alles abgearbeitet und erst ganz am Schluss die Signale auf die Hardware gelegt. Zuerst werden noch die Eingänge eingelesen. Während der Abarbeitung werden KEINE Ausgänge gesetzt.

Du schreibst jetzt mit dem 1. FB auf deine globale Variable (z.B: TRUE)
Danach schreibt der 2. Baustein ein FALSE auf genau die gleiche Variable.
etc FB3, FB 4...
Der letzte FB schriebt ein TRUE => Der Hardware-Ausgang wird TRUE.

Weiter spielt es keine Rolle was du im Baustein machst, der Wert des Baustein-Ausgangs ist in der Variabeldeklaration definiert. Also jeder aufgerufene Baustein gibt entweder False oder True zurück, egal was du innerhalb des Bausteins machst!
 
Trotz der hilfreichen Beschreibung bin ich noch nicht auf den Trichter gekommen wie ich mein Prog umschreiben muss. Was mir noch nicht ganz einleuchtet ist die Abarbeitung des Progs. wie geht das genau vonstatten?
Hab auch schon versucht mit Hilfe einer SWITCH..CASE die FBs nach und nach abarbeiten zu lassen...das geht teilweise..krieg aber Probleme mit meinen IF..ELSE Bedingungen.
Mir Hilft jetzt wahrscheinlich nur noch ein Codebeispiel in dem ich seh wo mein Fehler liegt und wie mans umändern kann.
Als Du das Programm geschrieben hast, bist Du offenbar von falschen Vorstellungen bezüglich der Abarbeitung ausgegangen. Da stellt sich die Frage, ob es überhaupt noch zu retten ist. Ein Versuch könnte etwa so aussehen:
Code:
IF Button_Start OR (* hier wohl noch weitere Bedingungen wie Start der SPS, Moduswechsel *)
THEN
   MODUS(...);
ELSE
   IF Button_Mod2
   THEN
      IF Button_Automatik
      THEN
         LED_TEST_AUTO_MOD2(...);
      ELSE
         LED_TEST_MANUELL_MOD2(...);
      END_IF;
   ELSE
      IF Button_Automatik
      THEN
         LED_TEST_AUTOMATIK_MOD1(...);
      ELSE
         LED_TEST_MANUELL_MOD1(...);
      END_IF;
   END_IF;
END_IF;
Problematisch bleiben dabei allerdings die ELSE-Zweige in den LED_TEST_AUTO-FB's, in denen die Hilfsvariablen dieser FB's zurückgesetzt werden. Das musst Du irgendwie anders lösen, z. B. durch einen Init-Schritt in der Ablaufkette. Ausserdem können auch die bedingten Aufrufe der TP-Bausteine zum Stolperstein werden. Die solltest Du besser im MAIN zyklisch aufrufen und ihre Ausgänge als INPUT-Variablen an die FB's übergeben.
 
Ich finde dies eine gefährliche Lösung von StructuredTrash! Die Funktionsbausteininstanz sollte wenn immer möglich in jedem Zyklus aufgerufen werden, andernfalls drohen Probleme, insbesondere bei Timern!! Wenn du nur Funktionen nutzt, darfst du diese wie oben beschrieben aufrufen...

Ich würde nur die Ausgangssignale abhängig vom Modus auf die HW ausgeben:
Code:
LED_TEST_AUTOMATIK_MOD1(...);
//Alle Bausteinaufrufe

IF Button_Start OR (* hier wohl noch weitere Bedingungen wie Start der SPS, Moduswechsel *) THEN    MODUS(...); ELSE    IF Button_Mod2    THEN       IF Button_Automatik       THEN          HWAusgang1:= LED_TEST_AUTO_MOD2.Automatik;       ELSE         HWAusgang1:= LED_TEST_MANUELL_MOD2.hand;       END_IF
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich finde dies eine gefährliche Lösung von StructuredTrash! Die Funktionsbausteininstanz sollte wenn immer möglich in jedem Zyklus aufgerufen werden, andernfalls drohen Probleme, insbesondere bei Timern!!
Ich habe doch geschrieben, dass er die TP's aus den FB's herausnehmen soll. Die werden ja auch im ursprünglichen Programm nur bedingt aufgerufen, was möglicherweise einen Teil der Probleme verursacht.
Ich würde nur die Ausgangssignale abhängig vom Modus auf die HW ausgeben:
Ich auch, und dazu sind FB's eigentlich nicht die richtige Wahl. Ich würde es eher mit Aktionen des MAIN-Programms machen. Mein Vorschlag geht auch eher in die Richtung, das bisherige Programm zu retten. Besser wäre es aber schon, ein Neues zu schreiben.
 
Hallo Zusammen, danke für die konstuktiven Lösungsansätze euerseits. Wollt eigentlich schon früher schreiben, weil....ES FUNKTIONIERT!!! Dank der Beschreibung bezüglich der Abarbeitung des Programms von gloeru hats dann gedämmert. Die ELSE Bedingungen in den FBs machen die Probleme. Mir war nicht klar das der letzte initialisierte FB die Variablen entglültig setzt und somit meine anderen Bedingungen quasi wieder außer kraft setzt. Letztendlich hab ich nur mal spaßeshalber die ELSE Bedingung aus meinem letzten FB AUTO_MOD1 gekillt...und siehe da...es hat funktioniert. Mir ist jetzt allerdings auch klar das ich mein Programm grundlegend umschreiben muss.Ich hab dazu auch schon einige Ansätze. Grundsätzlich würde ich aber schon gern an den FBs festhalten..rein zwecks der Übersicht...vermutlich ist es geschickter die Einsprungbedingung also z.b ( IF (PlatgrundPos AND Button_Start......) ins MAIN zu setzen und THEN ( eben die Ini der FBs mit Eingangsvariablen) und dort dann die HW Signale setzen.Ich werd die nächsten Tage dann mal mein Lösungsansatz reinstellen. Will ja nicht nur das es funktioniert...sondern auch halbwegs ordentlich programmiert ist:)Achso..zwecks den Timern..ihr schreibt das es gefährlich ist, diese im FB anzuwenden...wo könnte da ein Konflikt drohen..und wie kann man sowas umgehen?Ansonsten aber nochmals vielen Dank für die Beträge
 
Ausserdem können auch die bedingten Aufrufe der TP-Bausteine zum Stolperstein werden. Die solltest Du besser im MAIN zyklisch aufrufen und ihre Ausgänge als INPUT-Variablen an die FB's übergeben.
Ok gut, meine Frage wurde quasi beantwortet..werd mich auch hierzu um nen Lösungsweg bemühen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Tiptop, freut mich zu hören, dass unsere Hilfe genützt hat!

Kurz zu den Timern und FBs:
Solange du den entsprechenden FB in jedem Zyklus einmal aufrufst, kannst du auch Timer in FBs nutzen. (nicht in FCs)
Wenn du jetzt aber die FBs nur zwischendruch oder in gewissen Fällen aufrufst, kann es sein, das der Timer "den Takt" verliert und falsche Werte generiert.

Dass du wiederkehrende Aufgaben in FBs packst, ist richtig.

Ich empfehle dir, im FB nie direkt auf die HW zu schreiben, sondern nur im MAIN.
 
Die FB's der Standard-Lib wie Trigger, Timer, Counter erfordern einen Aufruf in jedem Programmzyklus, um richtig zu funktionieren. Dies gilt natürlich auch für eigene FB's, die solche Standard-FB's enthalten. Wenn Du einen FB schreiben willst, der von vornherein für einen bedingten Aufruf gedacht ist, musst Du entweder auf solche Standard-FB's verzichten oder Dein FB muss eine Busy-Variable verwalten und ausgeben, die Du dann in die Aufrufbedingung mit einbaust, etwa so:
Code:
IF Externe_Bedingung OR MyFB.Busy
THEN
   MyFB();
END_IF;
Wobei es je nach Umfang des FB's schon recht aufwändig werden kann, festzustellen, ob er nach Wegfall der externen Aufrufbedingung noch aufgerufen werden muss.

Zu Deinem Programm:
Modus 1 und 2 unterscheiden sich ja nur in der Ausgabe, die Manuell-/Automatiksteuerung ist dagegen für beide Modi gleich. Eigentlich brauchst Du doch nur je einen FB für Manuell und Automatik, während Du die Unterscheidung zwischen Modus 1 und 2 auf die Ausgabe beschränken kannst.
Als Alternative zu FB's kannst Du Dir mal Aktionen anschauen. Die sind eigentlich dazu gedacht, unterschiedliche Funktionalitäten einer POU von aussen aufrufen zu können, man kann sie aber genauso auch aus dem Hauptcode ihrer POU heraus quasi als Unterprogramme aufrufen. Der Vorteil von Aktionen ist, dass sie Zugriff auf die Variablen ihrer POU haben, Du sparst Dir damit die Übergabe von INPUT-/OUTPUT-Variablen.
 
Zurück
Oben