oscat.lib > oscat.lib fuer Step 7
Die STime Misere
psyche:
So, nachdem ich die letzten Tage größere Probleme mit Zeit basierten Oscat-Funktionen hatte, habe ich mir den STime noch mal vorgenommen.
Dabei bin ich auf noch viel mehr Probleme gestoßen.
Um es kurz zu machen :
- Die Init Prozedur über RD_SINFO funktioniert grundsätzlich nur wenn STime über OB1 aufgerufen wird. Und da bin ich mir auch nicht ganz sicher.
Wenn man andere OB's für seine Programme benutzt (z.B. OB35 Weckalarm, etc) ist Init komplett ohne Funktion.
- Die Überlauf Erkennung ist viel zu anfällig für Störungen
Ich habe mir das mal zum Anlass genommen und den STime komplett überarbeitet.
Darin neu :
- Wenn man die Plattform Unabhängigkeit bewahren will, ist es unmöglich im Baustein einen Neustart der CPU, und damit einen Systemuhr Reset zu erkennen.
Ich habe kurz mit dem Gedanken gespielt im OB100 (Wird beim Warmstart aufgerufen) ein IDB_STime.init := false einzufügen. Das ist zwar sicher aber man muss es manuell erledigen. Deswegen habe ich das wieder verworfen. Alle anderen Methoden die mir eingefallen sind, kann man auch nur als "dirty" bezeichnen.
Ich habe mich daher entschieden eine max_Cycletime einzuführen, auf dessen Grundlage ich die Plausibilität der zurückgelieferten Systemzeit bewerten kann.
- Ein Systemzeit Überlauf wird jetzt nur noch erkannt wenn last_time > T#24D_20H_31M_23S_647MS - max_Cycletime ist, also wenn der Systemtimer im letzten Zyklus bereits kurz vor dem Überlauf stand. Selbst für den extrem unwahrscheinlichen Fall das in diesem Zeitfenster ein CPU Neustart stattfindet, ist der Zeitfehler maximal max_Cycletime, was man in den meisten Fällen verschmerzen kann (zumindest in meinen Fällen).
- Ein CPU Neustart wird jetzt dadurch erkannt, dass der Systemtimer < max_Cycletime ist und last_time nicht kurz vor dem Überlauf stand.
In diesem Fall wird ein Init ausgelöst, die Zeit auf 0 gesetzt und das Bit Init_happened gesetzt.
- Mit Init_happened habe ich eine Möglichkeit hinzugefügt, in nachfolgenden Funktionen einen erfolgten Init auszuwerten. Da STime ja durchaus mehrmals pro Zyklus aufgerufen werden kann, kann Init_happened leider nicht automatisch zurückgesetzt werden. Wenn man das Bit auswerten will, muss man es am Ende des Zyklusses manuell zurücksetzen.
- Der Time_Tck Bug bei CPU's <V2.01 Firmware wird gefixt. Tritt der Bug auf, wird der Zyklus ignoriert und die verstrichene Zeit im nächsten Zyklus aufgeholt.
Ich habe das Ganze ziemlich ausführlich im Simulator getestet, aber falls jemandem noch was einfällt, immer raus damit.
getestete Reaktionen des Bausteins :
- Überlauf Systemtimer --> tx wird auf Negativ gesetzt, beziehungsweise auf Positivs falls tx vorher schon Negativ war.
- Neustart CPU --> Init wird ausgelöst, tx beginnt wieder bei Positiv 0, Init_happened wird gesetzt
- IDB download oder manuelles IDB_STime.init setzen --> tx wird einen Zyklus lang 0, im nächsten Zyklus wird tx auf Systemtimer gesetzt mit positivem Wert. --> Nicht empfehlenswert, verursacht ganz sicher Probleme.
- Time_Tck Bug tritt auf --> Fehlerhafte Zeit wird ignoriert und im nächsten Zyklus nachgeholt.
--- Code: ---FUNCTION_BLOCK STIME
TITLE = 'STIME'
//
//this function block makes sure that the timer of a siemens sps counts from 0 - 2^32-1.
//
VERSION : '1.6'
AUTHOR : dalbi
NAME : STIME
FAMILY : MEASURE
VAR_INPUT
END_VAR
VAR_OUTPUT
tx : DWORD;
at_tx AT tx : ARRAY[0..31] OF BOOL;
END_VAR
VAR
last_time: DWORD;
bit31: BOOL;
init: BOOL := false;
max_Cycletime : TIME := t#2s; // Max cycletime default 2 second. Can be adjust when you need longer cycletimes.
Init_happened : BOOL := false; // An Init happened (CPU restart, etc). Time resetted to T#0ms or actual Timer value. Reset this manuell when you use it
cycle : INT := 0; // Value of error Cycles
(* TX_Sim : TIME; // Actual time ONLY for simulation
*)
END_VAR
VAR_TEMP
lastBit31:BOOL;
TimeDiff:TIME;
last_time_temp : DWORD; // last_time but always positive
at_last_time_temp AT last_time_temp : ARRAY[0..31] OF BOOL;
END_VAR
(* this FB is only necessary for siemens sps
the siemens sps timer counts from 0 to 2^31-1 and starts at 0 sfter overrun.
this means that the bit 31 (the highest bit ) will never be used and therefore
a problem arises when t2 - t1 is checked.
t2 - t1 is always valid also in an timer overrun situation where the time t1 is very high and t2 is very low.
the result of the subtraction t2 - t1 however is still valid.
this calculation does not work for soiemens because the highest bit is not used.
this module stores the highest bit, changes the highest bit at every overrun occurence and stuffs ther highest bit in the output.
the output is then used by t_plc_us and t_plc_ms.
the correction needs and fb and not a function because the value of the highest bit has to be stored.
do never use this function block in a codesys environment. the timer in codesys is correct and runs from 0 to 2^32-1
*)
(* read the system timer *)
tx := DINT_TO_DWORD(TIME_TO_DINT(TIME_TCK()));
(* only for simulation
TX_Sim := TX_Sim + t#10ms;
tx := DINT_TO_DWORD(TIME_TO_DINT(TX_Sim));*)
(* Check if Init necessary*)
(* On warmstarts the Siemens CPU's sets the systemtimer to 0 and also when a overrun occurs*)
last_time_temp := last_time;
at_last_time_temp[7] := false; (*set the last_time to a positiv value. Make savings on calculations*)
IF DWORD_TO_DINT(tx) < TIME_TO_DINT(max_Cycletime) AND DWORD_TO_DINT(last_time_temp) < TIME_TO_DINT(T#24D_20H_31M_23S_647MS - max_Cycletime) AND DWORD_TO_DINT(last_time_temp) > TIME_TO_DINT(max_Cycletime)THEN
init := false;
END_IF;
(* reset last_time on system startup *)
IF NOT init THEN
last_time := 0;
bit31 := false;
init := true;
Init_happened := true;
END_IF;
(* check for overrun *)
IF DWORD_TO_DINT(tx) < TIME_TO_DINT(max_Cycletime) AND DWORD_TO_DINT(last_time_temp) > TIME_TO_DINT(T#24D_20H_31M_23S_647MS - max_Cycletime) THEN
(* an overrun has occured, change the value of the highest bit *)
bit31 := NOT bit31;
END_IF;
(* stuff the highest bit into the timer value *)
at_tx[7] := bit31;
(* Check for Time_Tck bug on older S/-300 CPU's Firmware < 2.01*)
TimeDiff := DINT_TO_TIME(DWORD_TO_DINT(tx)) - DINT_TO_TIME(DWORD_TO_DINT(last_time));
IF (TimeDiff > max_Cycletime OR TimeDiff <T#0ms) AND cycle = 0 THEN
tx := last_time;
cycle := cycle +1;
ELSE
(* remember the last system time for the next overrun check *)
last_time := tx;
cycle := 0;
END_IF;
(* revision history
DA 14.9.2007 rev 1.0
original version
DA 24.2.2008 rev 1.1
added self reset on system startup
DA 2.5.2008 rev 1.2
correct a problem running under OB35
DA 12.3.2009 rev 1.3
correct a problem run on different CPUs
DA 22.12.2009 rev 1.4
correct a problem on startup
DA 19.09.2011 rev 1.5
correct a error in code
psyche 01.10.2014 rev 1.6
nearly completely revised because of many bugs
*)
END_FUNCTION_BLOCK
DATA_BLOCK IDB_STIME STIME
//
// Instance data block for "STIME"
//
BEGIN
END_DATA_BLOCK
--- Ende Code ---
mg:
Hallo Psyche
Ich habe seit ein paar Tagen die neue STime V1.6 bei einer 315 DP/PN (neueste FW) am laufen. (die STime 1.5 war untragbar ... hatte immer wieder Fehler, aber ich war lange nicht mehr vorort so hat sich das Ganze hinausgezögert)
Die Anlage bezeichne ich als SEHR kritisch.
Es sind massenhaft Regelbausteine drinnen und ich sollte in 1-2 Monaten eine Rückmeldung erhalten.
Mg
(hatte den diesen Kommentar ursprünglich bei http://www.oscat.de/community/index.php/topic,2195.0.html platziert ... nun korrigiert)
allerdings ACHTUNG: Es betrifft zumindest den Originalen CLK-PRG auch
mg:
Wäre schön wenn ich auch mal was vom OSCAT-TEAM zu diesem Thema höre. Das betrifft ja einen Großteil aller Bausteine!!!
Mg
psyche:
Ich habe vor 8 Monaten komplett auf die V1.6 umgestellt.
~10 CPU's, Laufzeitmessungen, Presszeitrechner, Zykluszeitmessungen, etc.
Seit dem kein einziges Problem mehr gehabt.
Ich benutze allerdings großteils Siemens Regler und selbst geschriebene Routinen, teilweise auf OSCAT Basis.
Wie das ganze mit den OSCAT Bausteinen harmoniert weiß ich also nicht, gehe aber davon aus, dass das ebenfalls passt.
wo:
@psyche:
Danke für die Mühe, ich hatte auch schon einige Probleme damit.
MfG
wo
Navigation
[0] Themen-Index
[#] Nächste Seite
[*] Vorherige Sete
Zur normalen Ansicht wechseln