Blinktaktgeber Beispiel -- PROBLEM?

dast

Level-1
Beiträge
146
Reaktionspunkte
6
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo liebe SPS-Gemeinde,

ich versuche gerade mich in die SPS-Programmierung einzuarbeiten und bräuchte mal eure Hilfe :)

Aus einem meiner Bücher habe ich folgendes Beispiel, das einen Blinktaktgeber mit einstellbarer Puls- und Pausendauer darstellen soll:

Code:
FUNCTION_BLOCK SBLINK
VAR_INPUT
    ENABLE:BOOL;
    TIMEHIGH:TIME;
    TIMELOW:TIME;
END_VAR
VAR_OUTPUT
    OUT:BOOL;
END_VAR
VAR
    TIMER_1:TON;
    TIMER_2:TON;
END_VAR

Code:
TIMER_1 (IN := ENABLE AND NOT OUT, PT := TIMELOW);
TIMER_2 (IN := ENABLE AND OUT, PT := TIMEHIGH);
OUT := TIMER_1.Q OR OUT AND NOT TIMER_2.Q;

Und hier meine erste Frage:
In der letzten Zeile kommt AND vor OR, also mit Klammerung so: OUT := TIMER_1.Q OR (OUT AND NOT TIMER_2.Q);
Oder liege ich hier falsch?

So, und hier gleich meine zweite Frage:
Die Implementierung scheint doch ein Problem zu haben wenn ich ENABLE auf 0 setze und OUT gerade auf 1 steht.
Dann würde OUT doch für immer auf 1 bleiben, oder? Und das wäre für ein Blinklicht z.B. nicht so toll ...

Also so, oder?
Code:
                  ___________________________________________________        
ENABLE:    ______|                                                   |_______
                 :                                                   :       
                 :                                                   :       
                 :                                                   :       
TIMER_1.Q: __________________||__________________________||__________________
                 :<--[T_L]-->:              : <--[T_L]-->:           :       
                 :           :              :            :           :       
                 :           :              :            :           :       
TIMER_2.Q: _________________________________||_______________________________
                 :           : <---[T_H]--->             : <---[T_H]-:       
                 :           :              :            :           :       
                 :           :______________:            :___________________
OUT:       __________________|              |____________|           :

Eine Lösung wäre doch einfach OUT zusätzlich mit ENABLE zu verUNDEN, also:
OUT := ENABLE AND (TIMER_1.Q OR (OUT AND NOT TIMER_2.Q));
Oder?

Wenn ich jedoch möchte, dass die letzte Blinkperiode noch zu Ende geführt wird, dann könnte ich das doch auch so machen:
Code:
TIMER_1 (IN := ENABLE AND NOT OUT, PT := TIMELOW);
TIMER_2 (IN := OUT, PT := TIMEHIGH);
OUT := TIMER_1.Q OR OUT AND NOT TIMER_2.Q;
Also ohne dem ENABLE in der IN-Zuweisung von TIMER_2, oder?

Das würde dann so aussehn, oder?
Code:
                  ___________________________________________________        
ENABLE:    ______|                                                   |_______
                 :                                                   :       
                 :                                                   :       
                 :                                                   :       
TIMER_1.Q: __________________||__________________________||__________________
                 :<--[T_L]-->:              : <--[T_L]-->:           :       
                 :           :              :            :           :       
                 :           :              :            :           :       
TIMER_2.Q: _________________________________||__________________________||___
                 :           : <---[T_H]--->             : <---[T_H]--->:    
                 :           :              :            :           :  :    
                 :           :______________:            :______________:    
OUT:       __________________|              |____________|           :  |____

Und was sagen die Experten unter euch dazu?

Danke und Grüße,
Daniel.
 
Zuletzt bearbeitet:
Hallo,
wie du sicher schon festgestellt hast decken sich deine Überlegungen nicht so Recht mit der Praxis.
Für den reinen Blinktakt-Geber würde ich so vorgehen :
Code:
TIMER_1 (IN := NOT TIMER_2.Q PT := TIMELOW);
TIMER_2 (IN := TIMER_1.Q, PT := TIMEHIGH);
OUT := TIMER_1.Q ;
Der TON erwartet zum Laufen ein permanentes Signal am Eingang - das hattest du mit deiner Verschaltung nicht so Recht realisiert.

Wenn du jetzt noch eine Abhängigkeit zum Enable haben möchtest und gleichzeitig der Taktgeber durchlaufen soll mußt du mit einem zusätzlichen Hilfsbit arbeiten, das mit Enable gesetzt und mit Not Enable und Timer_2.Q rückgesetzt wird. Das würde ich dann noch zusätzlich an der Timer_1.IN als AND dranschalten ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi Larry,

danke für deine rasche Antwort.

Der TON erwartet zum Laufen ein permanentes Signal am Eingang - das hattest du mit deiner Verschaltung nicht so Recht realisiert.
Das versteh ich jetzt leider nicht ganz, sorry.
Meinst du jetzt meinen Lösungsvorschlag?
Stimmt meine Vermutung mit dem Ursprungsbeispiel aus dem Buch, dass der Blinker immer anbleibt, wenn ich ENABLE auf 0 setze wenn OUT gerade 1?

Wenn du jetzt noch eine Abhängigkeit zum Enable haben möchtest und gleichzeitig der Taktgeber durchlaufen soll mußt du mit einem zusätzlichen Hilfsbit arbeiten, das mit Enable gesetzt und mit Not Enable und Timer_2.Q rückgesetzt wird. Das würde ich dann noch zusätzlich an der Timer_1.IN als AND dranschalten ...
Könntest du mir das vielleicht in ST-Code-Form hinschreiben, dann check ichs vielleicht besser ... danke!

Danke und Grüße,
Daniel.
 
... wie der TON funktioniert läßt sich eigentlich aus der zugehörigen Beschreibung ganz gut rückschließen ...
Wie auch immer - es läuft nur, wenn an seinem IN ein permanentes TRUE ansteht, bis zum Ende. Nimmst du das weg so läuft der Timer nicht wenig - ein neuerliches TRUE startet ihn wieder von vorne.
Mit deinem, etwas gewöhnungsbedürftigen, Code hast du zu einem bestimmten Zeitpunkt möglicherweise eine Selbsthaltung drin.

Mein beschriebenes Beispiel zur Erweiterung kannst du nicht umsetzen ?
Code:
if Enable then Freigabe := true ; end_if ;
if not Enable and Timer_2.Q then Freigabe := false ; end_if ;

TIMER_1 (IN := Freigabe and NOT TIMER_2.Q PT := TIMELOW);
TIMER_2 (IN := TIMER_1.Q, PT := TIMEHIGH);
OUT := TIMER_1.Q ;
... so in etwa - ist aber q'n'd und nicht getestet ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Larry,

nochmals danke für deine Antwort!

Zuerst möchte ich kurz anmerken, dass das nicht mein Code ist, sondern 1 zu 1 aus einem meiner Bücher kopiert.
Ich möchte eigentlich nur die Implementierung des Autoren versuchen zu verstehen.
Dabei bin ich eben -- meines Erachtens -- auf das oben beschriebene Problem gestoßen und hab versucht das Problem zu beheben.

Ich hab jetzt ein wenig das Problem, dass ich nicht weiß auf was sich deine Aussagen beziehen.
Auf den Originalcode aus dem Buch, oder den Lösungsvorschlag von mir?

Auf jeden Fall mal danke für deine Beispielimplementierung, die hab ich -- glaub ich halt mal -- auch verstanden ;-)

Jetzt aber nochmal zurück zur dem Originalcode aus dem Buch (möchte die Implementierung halt wirklich verstehen):
Code:
TIMER_1 (IN := ENABLE AND NOT OUT, PT := TIMELOW);
TIMER_2 (IN := ENABLE AND OUT, PT := TIMEHIGH);
OUT := TIMER_1.Q OR OUT AND NOT TIMER_2.Q;
Das mit dem TON, dass dieser nur läuft, wenn an seinem IN ein permanentes TRUE ansteht, bis zum Ende, ist mir schon klar.
Aber das ist doch eh gegeben oder?
Code:
                   ___________________________________________________        
ENABLE:     ______|           ::             ::           ::          |____________
                  :           ::             ::           ::          :       
                  :           ::             ::           ::          :       
                  :____________:             ::____________:          :       
TIMER_1.IN: ______|           :|______________|           :|_______________________
                  :           ::             ::           ::          :       
                  :           ::             ::           ::          :       
TIMER_1.Q:  __________________||__________________________||_______________________
                  :<--[T_L]-->::             ::<--[T_L]-->::          :       
                  :           ::             ::           ::          :       
                  :           ::______________            ::__________:       
TIMER_2.IN: ___________________|             :|____________|          |____________
                  :           ::             ::           ::          :       
                  :           ::             ::           ::          :       
TIMER_2.Q:  _________________________________||____________________________________
                  :           ::<---[T_H]--->::           ::<---[T_H]-(abgebrochen)
                  :           ::             ::           ::          :       
                  :           :______________::           :________________________
OUT:        __________________|:             |____________|:          :
Hier mein Gedankengang dazu (bitte um Korrektur, wenn ich mir irre):
  • Zu Beginn ist OUT mal FALSE, ENABLE ebenso.
  • TIMER_1.IN ist FALSE, TIMER_2.IN auch.
  • Dadurch ist TIMER_1.Q und TIMER_2.Q auch auf FALSE.
  • Irgendwann wird dann ENABLE (z.B. durch einen Schalter) auf TRUE gesetzt.
  • Dadurch ist die Bedingung für TIMER_1.IN erfüllt und der TIMER läuft los.
  • Die Bedingung für TIMER_2.IN ist noch nicht erfüllt, daher bleibt TIMER_2.Q auch auf FALSE.
  • Ist die Zeit von TIMER_1 abgelaufen wird TIMER_1.Q auf TRUE gesetzt.
  • Für TIMER_2 ändert sich noch nichts, da OUT ja noch nicht aktualisiert wurde.
  • Im nächstes Schritt wird OUT aktualisiert und auf TRUE gesetzt.
  • Im nächsten Durchgang ist die Bedingung von TIMER_1.IN durch die Änderung von OUT natürlich nicht mehr erfüllt und TIMER_1.Q wird wieder FALSE.
  • Dadurch, dass OUT nun TRUE ist ist aber die Bedingung TIMER_2.IN erfüllt und für diesen TIMER beginnt die Zeit zu Laufen.
  • Ist die Zeit von TIMER_2 abgelaufen wird TIMER_2.Q auf TRUE gesetzt.
  • Dadurch wird nun OUT wieder auf FALSE gesetzt.
  • Dadurch ist Bedingung TIMER_1.IN wieder erfüllt und es beginnt dessen Zeit zu Laufen.
  • Die Bedingung von TIMER_2.IN ist durch OUT = FALSE jetzt natürlich nicht mehr erfüllt und es wird TIMER_2.Q auf FALSE gesetzt.
  • Und das ganze Spiel geht nun muter so weiter ...
Ist das so korrekt?

Das Problem mit der obigen Implementierung das ich entdeckt habe ist, wenn ENABLE dann auf FALSE gesetzt wird, wenn OUT gerade TRUE ist.
Dann würde OUT nämlich für immer auf OUT bleiben, da ja OUT = TRUE und TIMER_2.Q = FALSE und dadurch TIMER_1.Q OR OUT AND NOT TIMER_2.Q = TRUE, oder?

Stimmt das denn so?

Mein Lösungvorschlag/Fix (speziell für diese Implementierung) wäre nun gewesen einfach das ENABLE aus der TIMER_2.IN Bedingung zu entfernen:
Code:
TIMER_1 (IN := ENABLE AND NOT OUT, PT := TIMELOW);
TIMER_2 (IN := OUT, PT := TIMEHIGH);
OUT := TIMER_1.Q OR OUT AND NOT TIMER_2.Q;
Dann würde, wenn man ENABLE auf FALSE setzt während OUT = TRUE, die Blinkzeit (TIMEHIGH) noch fertig gemacht, aber nicht erneut gestartet, oder?

Danke für deine/eure Geduld mit mir!

Hallo Daniel,
jetzt mal nichts zur Problemmlössung, aber die Präsentation deiner Frage ist klasse
Danke!
 
Zuletzt bearbeitet:
Das Problem mit der obigen Implementierung das ich entdeckt habe ist, wenn ENABLE dann auf FALSE gesetzt wird, wenn OUT gerade TRUE ist.
Dann würde OUT nämlich für immer auf OUT bleiben, da ja OUT = TRUE und TIMER_2.Q = FALSE und dadurch TIMER_1.Q OR OUT AND NOT TIMER_2.Q = TRUE, oder?

Stimmt das denn so?

Das ist Richtig.
 
Mein Lösungvorschlag/Fix (speziell für diese Implementierung) wäre nun gewesen einfach das ENABLE aus der TIMER_2.IN Bedingung zu entfernen:
Code:
TIMER_1 (IN := ENABLE AND NOT OUT, PT := TIMELOW);
TIMER_2 (IN := OUT, PT := TIMEHIGH);
OUT := TIMER_1.Q OR OUT AND NOT TIMER_2.Q;
Dann würde, wenn man ENABLE auf FALSE setzt während OUT = TRUE, die Blinkzeit (TIMEHIGH) noch fertig gemacht, aber nicht erneut gestartet, oder?
Ist auch Richtig.
 
Zurück
Oben