TIA Seltsames Verhalten der TON-Timer bei der S7-1200

Beiträge
9.191
Reaktionspunkte
2.950
Zuviel Werbung?
-> Hier kostenlos registrieren
Um einen Zeitimpuls (z.B. Sekundenimpuls) zu generieren, habe ich bei der 300/400er oder auch bei den
Codesys-Steuerungen bisher oft einen TON-Timer verwendet, der am Eingang IN mit den negierten eigenen Ausgang Q
beschaltet ist. Der Ausgang Q steht dann nach Ablauf der Zeit für genau einen Zyklus auf true.

Bei der S7-1200 funktioniert das nicht mehr, bzw. ist es von der Programmierung abhängig ob es funktioniert.

Ich habe mir ein kleines Testprogramm mit 4 verschiedenen Varianten von TON-Aufrufen geschrieben, aufgerufen im OB1.
Um die verschiedenen Varianten von der Funktion her vergleichen zu können, wird wenn der Ausgang Q eines Timers auf true
steht eine Integer-Variable inkrementiert.

Code:
FUNCTION_BLOCK "IECTimerTest"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      "PT" : Time := T#3s;   // Zeitwert für alle Timer
   END_VAR

   VAR_OUTPUT 
      "TON1_CNT" : Int;
      "TON2_CNT" : Int;
      "TON3_CNT" : Int;
      "TON4_CNT" : Int;
   END_VAR

   VAR 
      "TON1" : TON_TIME;
      "TON2" : TON_TIME;
      "TON3" : TON_TIME;
      "TON4" : TON_TIME;
      "TON2_Q" : Bool;
   END_VAR
BEGIN
	(* Test Timer 1 
	 * Abfrage Q nach Timeraufruf, Zähler zählt nicht
	 *)
	#TON1(IN:=NOT #TON1.Q, PT:= #PT);
	IF #TON1.Q THEN
	  #TON1_CNT := #TON1_CNT + 1;
	END_IF;
	
	
	(* Test Timer 2
	 * Q über Hilfsvariable auf Eingang, Zähler zählt
	 *)
	#TON2(IN:=NOT #TON2_Q, PT:= #PT, Q => #TON2_Q);
	(* Timer 2 Zählimpuls, zählt *)
	IF #TON2.Q THEN
	  #TON2_CNT := #TON2_CNT + 1;
	END_IF;
	
	
	(* Test Timer 3
	 * Abfrage Q vor dem Timeraufruf, Zähler zählt
	 *)
	IF #TON3.Q THEN
	  #TON3_CNT := #TON3_CNT + 1;
	END_IF;
	#TON3(IN:=NOT #TON3.Q, PT:= #PT);
	
	
	(* Test Timer 4
	 * wie 1, aber mit Zeitverzögerung zwischen TON-Aufruf
	 * und der Abfrage des Ausgangs Q. Je größer die Zeit für Wait, desto
	 * schneller zählt der Zähler.
	 *)
	#TON4(IN:=NOT #TON4.Q, PT:= #PT);
	"Wait"(T := t#10ms);
	IF #TON4.Q THEN
	  #TON4_CNT := #TON4_CNT + 1;
	END_IF;
END_FUNCTION_BLOCK

Die Funktion Wait wartet in einer Schleife bis die parametrierte Zeit abgelaufen ist:

Code:
FUNCTION "Wait" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      "PT" : Time;
   END_VAR

   VAR_TEMP 
      "starttime" : DTL;
      "acttime"  : DTL;
      "diff" : Time;
      "RD_SYS_T_RET_VAL" : Int;
   END_VAR
BEGIN
	(* Verweilt in der Funktion bis die an PT parametrierte Zeit abgelaufen ist. *)
	#RD_SYS_T_RET_VAL := RD_SYS_T(OUT => #starttime);
	REPEAT
	  #RD_SYS_T_RET_VAL := RD_SYS_T(#acttime);
	  #diff := T_DIFF(IN1 := #acttime, IN2 := #starttime);
	UNTIL #diff >= #PT END_REPEAT;
	
END_FUNCTION


Ergebnis:

* Timer Variante 1
Abfrage Q nach dem Timeraufruf. Zähler zählt überhaupt nicht bzw. hochsporadisch.

* Timer Variante 2
Timer-Ausgang Q über Hilfsvariable auf Eingang zurückgelegt. Zähler zählt.

* Timer Variante 3
Abfrage Timer-Ausgang Q vor dem Timeraufruf. Zähler zählt.

* Timer Variante 4
Grundsätzlich wie Variante 1, aber mit Zeitverzögerung zwischen TON-Aufruf und der Abfrage des Ausgangs Q.
Je größer die Zeit für Wait, desto schneller zählt der Zähler.


Jetzt versuche ich mir dieses Verhalten irgendwie zu erklären.
Die einzige Möglichkeit die mir einfällt wäre, dass die TON-Timer bei der 1200 nicht im OB1 Zyklus wenn sie vom Programmablauf
an der Reihe sind, sondern unabhängig davon in einer Art internen Task aufgerufen werden.
Das wirft meine Vorstellung vom geordneten Ablauf in einer SPS etwas durcheinander.

Gibt es noch eine andere Erklärung für dieses Verhalten?

Vielleicht kann das ja jemand mit TIA V12, einem neueren Firmwarestand oder sogar mit einer 1500er testen.

Meine Testumgebung:
TIA V11 Sp3 Upd4
1214 DC/DC/Relais HW2, FW V2.2.0
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In FUP ist das Verhalten genauso wie mit SCL, wobei ich da nur Variante 1 probiert habe.
Ich habe auch nochmal mit dem TIA ein identisches Testprogramm für die 300/400er erstellt, da ist das Verhalten wie immer - also es funktioniert problemlos.

Ich habe das Testprogramm jetzt eine Weile durchlaufen lassen, und Variante 2 zeigt auch Aussetzer in der Auswertung. Irgendwie scheint der TON nicht zu mögen dass man ihn mit seinen eigenen Daten als Parameter beschaltet.
 
Ich bin mir nicht sicher, doch ich meine, dieses Verhalten gibt es auch schon bei S7-300, da funktioniert die direkte Rückführung nur sporadisch, aber nicht 100% sicher. Jedenfalls nutze ich da auch schon lange generell einen Zwischen-Merker, um den Ausgang auf den Eingang zurückzuführen.
Oder war das nur in PLCSIM??? Oder ist es abhängig von der CPU und der Firmwareversion?

Harald
 
Zuletzt bearbeitet:
Das ist jetzt beim TON ein Problem was sich wohl einfach umschiffen ließe.

Ich habe nur Bedenken das sich solche negativen Seiteneffekte auch bei anderen Programmteilen wiederfinden.

Eine TON-Instanz ist ja erstmal eine Struktur mit Variablen. Theoretisch spricht überhaupt nichts dagegen es so zu programmieren, denn TON1.Q sollte eine BOOL-Variable wie jede andere Variable auch sein. Warum sollte man hierfür eine weitere Variable verwenden?
Das merkwürdige ist ja, dass man wenn man den Instanz-DB online beobachtet sehen kann wie die Zeiten nach Ablauf von PT aktualisiert werden obwohl die Abfrage auf Q nicht funktioniert.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich kann mir nur vorstellen, daß Siemens da irgendeinen Mechanismus eingebaut hat, der den Timer am Laufen und Rücksetzen hält unabhängig vom Anwenderprogramm. Vollkommen azyklisch zum OB1.

Vielleicht ist der Ausgang TONx.Q nicht einen ganzen Zyklus lang true, sondern nur solange, wie auflösungsabhängig die abgelaufene Zeit gleich der Vorgabezeit ist?
Vielleicht ist TONx.Q gar keine Variable, sondern eine Methode, die nur ein Ergebnis liefert, wenn sie aufgerufen wird?

Wie ist das eigentlich, wenn das Programm rund um den Timer nur einmal/wenige male(/oder nie) aufgerufen wird und noch vor Ablauf des Timers dann immer übersprungen wird und nur noch beobachtet? Startet er dann trotzdem neu?

(ich weiß, das klingt jetzt sehr verworren, doch es ist schon spät)

Harald
 
Hi

vielleicht hilf euch diese Erklärung

https://www.sps-forum.de/simatic/63317-step-7-basic-aufruf-timer-funktionsbaustein.html#post443410

PN/DP hat vermutlich Recht. So wie sich das Teil verhält, scheint es sich um eine Methode zu handeln, die ein Ergebnis liefert wenn sie aufgerufen wird. ET und Q sind, um es mal mit C# auszudrücken, Getter. TON, TOF und TP sind dann so was wie Setter. Und die Instanz ist vom Typ IEC_TIMER. Warum da SCL bei den statischen Instanzen TON als Typ anzeigt ist mir nun wieder schleierhaft. In FUP kann man sogar array [ 1..100] of IEC_TIMER anlegen. Oder ganz global im DB. Und diesen dann in KOP und FUP wie bei den alten BCD Timern überall wiederverwenden. (Aber immer schön die Instanzen auseinander halten -- vor allem zeitlich )
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

Zugegeben: Bin ein bisschen spät dran, um noch einen Beitrag zum Thema zu leisten.
Aber bin durch ein anderes Thema (Modbus TCP Kommunikation von SENTRON PAC3200) auf das seltsame Verhalten der TON-Timer bei S7-1200 gestoßen, das Thomas_v2.1 beschrieben hat.

Das seltsame Verhalten tritt nach wie vor auf, auch auf der S7-1500 (CPU 1518-4 PN/DP Firmware V2.6 mit TIA Portal V15.1).

Inzwischen findet man auch Siemens-Beiträge, die das Verhalten erklären:
Unter Was ist bei der Programmierung von IEC Timern in einer S7-300/S7-400 und in einer S7-1200/S7-1500 zu beachten? wird angemerkt:

Ein weiterer Unterschied besteht bei den Steuerungen in der Aktualisierung der Timer-Variablen.

  • Bei S7-300/S7-400 werden die Timer-Variablen "Q" und "ET" aktualisiert, wenn der Timer aufgerufen wird.
  • Bei S7-1200/S7-1500 wird der Timer aktualisiert, wenn der Timer aufgerufen wird oder wenn auf die Timer-Variablen "Q" und "ET" zugegriffen wird.

Genauer erläutert Siemens das in der TIA Portal Hilfe zum Beispiel beim Abschnitt «TON: Einschaltverzögerung erzeugen (S7-1200, S7-1500)». Dort steht:
Die Aktualisierung der Anweisungsdaten geschieht in den folgenden Fällen:

  • Bei einem Aufruf der Anweisung, wenn die Ausgänge ET oder Q verschaltet sind. Wenn die Ausgänge nicht verschaltet sind, dann wird der aktuelle Zeitwert am Ausgang ET nicht aktualisiert.
  • Bei einem Zugriff auf die Ausgänge Q oder ET.

Ein ziemlich sinnloser Aufruf der Anweisung, in dem die Ausgänge ET und Q nicht verschaltet sind, führt tatsächlich dazu, dass die Anweisungsdaten nicht aktualisiert werden.
Code:
FUNCTION_BLOCK "TestTakt"   VAR_INPUT 
      StartTestTOn : Bool;
      RunTestTOn : Bool;
   END_VAR

   VAR 
      TestTOn : TON_TIME;
   END_VAR

   VAR_TEMP 
      RetValTime : UDInt;
      DisplayQ : Bool;
   END_VAR

BEGIN

    #TestTOn(IN := #StartTestTOn,
             PT := T#60s);
    
END_FUNCTION_BLOCK

Beim Beobachten über Instanz-DB oder watch table bleibt ET auf 0 – obwohl die Zeit bei Flankenwechsel des Eingangsparameters IN auf true intern startet. Bei abgelaufener Zeit bleibt auch Q auf false, solange die Ausgangsdaten nur im DB oder über watch table beobachtet werden.
Sieht dann in der Beobachtungstabelle so aus:

WatchTable.png

Anhang anzeigen 50284
Erst nach Erweitern des Programmcodes um einen Zugriff auf Q werden die Anweisungsdaten aktualisiert, allerdings erst wenn die Programmzeile mit Q per #RunTestTOn:=true ausgeführt wird.
Code:
If #RunTestTOn Then
   #DisplayQ := #TestTOn.Q;
End_If;

Anhang anzeigen 50285
WatchTableDisplay.png


Mit den Hinweisen von Siemens kann ich mir das seltsame Verhalten der TON-Timer, das Thomas_v2.1 beschrieben hat, einigermaßen erklären:
Der Test Timer 1 ist ja in erster Linie ein Aufruf von TON_TIME, bei dem die Ausgänge ET und Q nicht verschaltet sind und damit durch den Aufruf selbst nicht aktualisiert werden.
Code:
    (* Test Timer 1 
     * Abfrage Q nach Timeraufruf, Zähler zählt nicht
     *)
    #TON1(IN:=NOT #TON1.Q, PT:= #PT);
    IF #TON1.Q THEN
      #TON1_CNT := #TON1_CNT + 1;
    END_IF;

Aber auf den Ausgang Q wird zweimal zugegriffen und damit werden ET und Q zweimal aktualisiert:
Wenn die Zeit PT:=T#3s verstrichen ist, wird beim Auswerten des Eingangsparameters IN der Zustand von Q aktualisiert. Es ergibt sich Q:=true, und damit für IN:= NOT Q := false. Die Startbedingung des Timers fällt ab, der Parameter Q wird zurückgesetzt.
Beim Zugriff auf Q in der IF-Abfrage wird Q nochmals aktualisiert auf Q=false. Somit wird das Hochzählen des Counters in der THEN-Anweisung nie ausgeführt, während der Timer selbst aber lustig weiterläuft und alle 3 Sekunden neu gestartet wird.

Bei Test Timer 3 findet das Hochzählen vor dem Timer-Aufruf statt. Hier ist bei Erreichen der 3 Sekunden der Zugriff auf Q in der IF-Abfrage; die Aktualisierung ergibt Q=true und der Counter wird hochgezählt. Beim anschließenden Aufruf des Timers ist "Q=true" nach wie vor der aktuelle Zustand. Damit wird wieder IN:=false erreicht und im nächsten Durchlauf durch die IF-Abfrage ist Q=false.

Test Timer 2 zählt auch brav hoch, weil hier ein Aufruf von TON_TIME mit Beschaltung von Q gemacht wird und die Rückführung IN:= NOT TON2_Q mit der Hilfsvariable gemacht wird statt mit Q. Damit erreicht man bei abgelaufener Zeit eine einmalige Aktualisierung von TON2_Q und Q:=true und Q=true gilt auch noch bei der IF-Abfrage.

Interessant ist dann noch Test Timer 4: Hier spielt der Zufall eine Rolle, ob hochgezählt wird oder nicht.
Wenn zum Beispiel bei einer Wait-Time von 10 Millisekunden und einer TON-Zeit von 3 Sekunden der OB1-Zyklus mit TON-Aufruf gerade dann ausgeführt wird, wenn ET im Bereich von 2,990 bis 2,999 Sekunden liegt, dann wird bei #TON4( IN:= NOT #TON4.Q, PT := #PT ) erst mal der IN-Parameter ausgewertet und dabei Q aktualisiert. Da die Zeit noch nicht abgelaufen ist, gilt Q=false und damit IN:=true und die Zeit läuft während der anschließenden Wait-Time weiter. Bei Erreichen von PT=3 Sekunden während der Wartezeit bleibt ET ebenfalls auf 3 Sekunden stehen. Wenn dann Q in der anschließenden IF-Abfrage aktualisiert wird, gilt einmalig Q=true und der Counter zählt hoch.
Wenn aber der Aufruf von TON im OB1-Zyklus gerade dann ausgeführt wird, wenn zum Beispiel ET=2,989 s ist, dann beträgt nach der Wartezeit von 10 ms in der IF-Abfrage der aktualisierte Wert von ET=2,999 ms. Der Timer ist noch nicht abgelaufen, Q ist weiterhin auf false und es wird nicht hochgezählt. Wenn wir annehmen, für das Ende des aktuellen OB1-Zyklus braucht die CPU eine Millisekunde und für den Anfang des nächsten Zyklus ebenfalls eine Millisekunde für die Code-Bearbeitung bis zur Stelle mit dem Aufruf von #TON4, dann haben wir den selben Zustand wie beim Test Timer 1: ET und Q werden aktualisiert bei Ermittlung des Wertes am Eingangsparameter IN: ET:=T#3S, damit wird Q:=true und IN:=false. Und folglich wird in der IF-Abfrage Q erneut ausgewertet mit Q:=false → Hochzählen entfällt.




Langer Rede kurzer Sinn: Das Verhalten der IEC-Timer bei der S7-1200/1500 ist schon seltsam, wenn man das unterschiedliche Verhalten bei S7-300/400 gewohnt ist. Aber mit der Erklärung in der TIA-Portal-Hilfe lässt sich das Verhalten logisch erklären. Allerdings finde ich es ein wenig hinterlistig von Siemens, dass die Konsequenzen des geänderten Verhaltens nicht mit Beispielen verdeutlicht werden. Ein paar Beispiele mit richtiger und falscher Anwendung wären gerade bei solchen Änderungen hilfreich und würden locker in den Programmier-Styleguide oder in die Handbücher für Migration von S7-300/400 auf S7-1200/1500 reinpassen.

Zum anderen hat der Beitrag von HelleBarde das Ganze kurz und knapp beschrieben: Q und ET sind nicht mehr Variablen des Instanz-DBs, sondern Methoden, die ein Ergebnis liefern, wenn sie aufgerufen werden.
ET und Q sind, um es mal mit C# auszudrücken, Getter.


Servus,
Beydall

 
Zuletzt bearbeitet:
Zurück
Oben