CLK_PRG: fehlerhafter Startwert

Begonnen von mg, 20. Mai 2014, 15:12:42

Vorheriges Thema - Nächstes Thema

0 Mitglieder und 1 Gast betrachten dieses Thema.

mg

Hallo Leute

Programmiersystem: TIA12 SCL
Controller: CPU315
Baustein im Oscat: CLK_PRG

Nach einem Änderungsdownload wurden alle (od. viele, das kann ich im nachhinein nicht mehr sagen) Baugruppen gestoppt und neu gestartet.
Danach stand der Wert für "last" auf einem niedrigen negativen Wert (3-stellig), aber der Wert für "tx" irgendwo im x-stelligen negativen Bereich (-24Tage und noch ein bischen was).

Der PWM_DC rechnet aus der Differenz der beiden eine Zeit aus die dem Taktzyklus entsprechen sollte. Das würde heißen, daß der PWM_DC dieser Wert in meinem Fall erst in 24 Tagen korrekt funktioniert.

Die Initialisierung des CLK_PRG hat offensichtlich NICHT funktioniert.

Es wäre schön, wenn man in einem der folgenden Updates auch diesen Fehler mal eliminieren könnte.

Vielen Dank

Mario


Omalik

Hallo Mario

Hast du schon was herausgefunden? Habe auch Probleme mit dem CLK_PRG Baustein. Er macht nicht das was ich erwarte.

Gruss

mg

Naja ich habe schon was rausgefunden.

In der STIME_V1_5 wird ein ähnliches Verfahren verwendet. Das war anscheinend ein großes Problem dort.
ABER: ... da mir die Erklärung dieses Bausteins zu sparsam ist, kann ich den CLK_PRG zwar auf das selbe System ändern, aber was dort drinnen wirklich 100%tig passiert, ist mir noch nicht bis ins letzte Detail bekannt UND solange bleibt das für mich eine Problem.

Obs funktioniert weiß ich auch nicht, ... evtl weiß jemand wie ich das am besten testen soll!

Mario

HIER WÄRE EINE HILFE VON GKOBLER ODER DALBI HILFREICH.

mg

Hallo Leute

... die Entwickler   :-X (eigentlich traurig)
Ich habe das nun selber probiert. Aber ich habe leider keine Station zum Probieren zu hause (muß das immer bei einer in Betrieb befindlichen SPS über VPN machen und dabei stelle ich bei einem Fehler u.U. gleich einen ganzen Betrieb ab!!!)
Trotzdem konnte ich nicht mehr länger warten und testete mal an dem ganzen Zeugs rum. Im Endeffekt habe ich das folgendermaßen gemacht ...
Die folgende Änderung sollte meiner Meinung funktionieren aber das Ganze kann ich erst nach 18 weiteren Tagen sagen (dann kommt es zum nächsten Überlauf)
So lange ist das Zeugs noch ungetestet!


(* // START -------------------------------- DAS IST MEINER MEINUNG FALSCH (mg 5.8.2014) --------------------------------------------
(* read actual startup info *)
(* OB1_SCAN_1  BYTE  -  B#16#01: Abschluss des Neustarts (Warmstarts)
                     -  B#16#02: Abschluss des Wiederanlaufs
                     -  B#16#03: Abschluss des freien Zyklus
                     -  B#16#04: Abschluss des Kaltstarts
                     -  B#16#05: Erster OB 1-Zyklus der neuen Master-CPU nach
                                 Master-Reserve-Umschaltung und STOP des
                                 bisherigen Masters *)

#ERR := RD_SINFO (TOP_SI => #TOP_SI, START_UP_SI => #START_UP_SI);

(* read system time *)
#tx := DINT_TO_TIME(DWORD_TO_DINT("T_PLC_MS"()));

(* reset last_time on system startup *)
IF #TOP_SI.EV_NUM = 1 OR #TOP_SI.EV_NUM = 2 OR #TOP_SI.EV_NUM = 4 THEN
    #init := false;
END_IF;
 
(* initialize on startup *)
IF NOT #init THEN
    #init := TRUE;
    #last := #tx - #PT;
END_IF;
*)
// ENDE -------------------------------- DAS IST MEINER MEINUNG FALSCH (mg 5.8.2014) --------------------------------------------
// und wird ersetzt durchf die folgenden 2 Zeilen *)

"IDB_STIME"();
#tx := "IDB_STIME".tx;

(* hier muss die korrektur für step7 stattfinden
plctime muss den vollen wertebereich von time ausnutzen:
wenn bei step7 time -24tage bis plus 24 tage ist dann muss der timer auch beim überlauf auf -24tage springen
und auf keinen fall auf 0 !!!!
für siemens muss ein weiterer fb im main eingebunden werden der sicherstellt das alle 32 bits durchgezählt werden.
es kann nur ein fb sein den er muss sich das oberste (32te) bit merken.
oder etwa spring s7 bei überlauf auf -24 tage????? dann wäre keine korrektur nötig.
*)

(* generate output pulse when next_pulse is reached *)
#Q := #tx - #last >= #PT;
IF #Q THEN #last := #tx; END_IF;
 
 
(* revision hiostory

hm 25 feb 2007  rev 1.1
    rewritten code for higher performance
    pt can now be changed during runtime

hm  17. sep 2007    rev 1.2
    replaced time() with t_plc_ms() for compatibility reasons

hm  25. oct. 2008   rev 1.3
    optimized code
   
mg   5. aug. 2014   rev 1.4
    problem with the internal-time variable after the overflow
*)

mg

noch eine Änderung

Nach einem Download kann es sein, daß die Initialisierung nicht funktioniert .... deshalb folgende Änderung


(* // START -------------------------------- DAS IST MEINER MEINUNG FALSCH (mg 5.8.2014) --------------------------------------------
(* read actual startup info *)
(* OB1_SCAN_1  BYTE  -  B#16#01: Abschluss des Neustarts (Warmstarts)
                     -  B#16#02: Abschluss des Wiederanlaufs
                     -  B#16#03: Abschluss des freien Zyklus
                     -  B#16#04: Abschluss des Kaltstarts
                     -  B#16#05: Erster OB 1-Zyklus der neuen Master-CPU nach
                                 Master-Reserve-Umschaltung und STOP des
                                 bisherigen Masters *)

#ERR := RD_SINFO (TOP_SI => #TOP_SI, START_UP_SI => #START_UP_SI);

(* read system time *)
#tx := DINT_TO_TIME(DWORD_TO_DINT("T_PLC_MS"()));

(* reset last_time on system startup *)
IF #TOP_SI.EV_NUM = 1 OR #TOP_SI.EV_NUM = 2 OR #TOP_SI.EV_NUM = 4 THEN
    #init := false;
END_IF;
 
(* initialize on startup *)
IF NOT #init THEN
    #init := TRUE;
    #last := #tx - #PT;
END_IF;
*)
// ENDE -------------------------------- DAS IST MEINER MEINUNG FALSCH (mg 5.8.2014) --------------------------------------------
// und wird ersetzt durchf die folgenden 2 Zeilen *)

"IDB_STIME"();
#tx := "IDB_STIME".tx;

(* hier muss die korrektur für step7 stattfinden
plctime muss den vollen wertebereich von time ausnutzen:
wenn bei step7 time -24tage bis plus 24 tage ist dann muss der timer auch beim überlauf auf -24tage springen
und auf keinen fall auf 0 !!!!
für siemens muss ein weiterer fb im main eingebunden werden der sicherstellt das alle 32 bits durchgezählt werden.
es kann nur ein fb sein den er muss sich das oberste (32te) bit merken.
oder etwa spring s7 bei überlauf auf -24 tage????? dann wäre keine korrektur nötig.
*)
 
(* generate output pulse when next_pulse is reached *)
#Q := #tx - #last >= #PT;
IF #Q OR NOT "IDB_STIME".init THEN #last := #tx; END_IF;
 
 
(* revision hiostory

hm 25 feb 2007  rev 1.1
    rewritten code for higher performance
    pt can now be changed during runtime

hm  17. sep 2007    rev 1.2
    replaced time() with t_plc_ms() for compatibility reasons

hm  25. oct. 2008   rev 1.3
    optimized code
   
mg   5. aug. 2014   rev 1.4
    problem with the internal-time variable after the overflow
   
mg  18. aug. 2014   rev 1.4a
    INIT after download/restart
*)

psyche

also ich interpretiere mir das gerade aus deinen geposteten codeschnippseln. habe gerade kein step7 zur hand.

wenn du beim download probleme bekommst, liegt das meine meinung nach daran das du den STime IDB mit runter lädst. Das ist eine ganz schlechte idee.
wenn Stime gerade einen negativen wert hat und du lädst den Stime IDB neu runter, wird der wert auf einmal positiv werden, da du das gespeicherte bit31 zurücksetzt und ausserdem einen init auslöst.

IF #Q OR NOT "IDB_STIME".init THEN #last := #tx; END_IF;

diese änderung ist meiner meinung nach nutzlos, da "IDB_STIME".init nur nach einem CPU neustart oder IDB download false ist. Nach dem ersten Aufruf von STime ist init wieder true. Und das passiert, wenn ich mich richtig erinnere hier :


(* read system time *)
#tx := DINT_TO_TIME(DWORD_TO_DINT("T_PLC_MS"()));


-----


"IDB_STIME"();
#tx := "IDB_STIME".tx;


oben alles wegschneiden und das hier stehenlassen wird auch nicht funktionieren.
erstens wird dann STime nicht mehr ausgeführt, die Zeit ändert sich also nicht mehr.
zweitens ist die initialisierungs routine wichtig für einen cpu neustart. Ohne kann die zeit #last irgendwo stehen.

der code passt meiner meinung nach so wie er ist. probleme entstehen nur wenn die zeit unvorhergesehene sprünge macht. z.B. durch einen IDB download.
das einzige was ich mir hier zur sicherheit noch vorstellen kann wäre sowas :

IF #Q OR #tx - #last < T#0ms THEN #last := #tx; END_IF;

das hält zumindest die auswirkungen in grenzen. sprich die zeit des ersten impulses nach dem fehler stimmt nicht mehr. im schlimmsten fall 2x #PT


oder aber ich habe dich komplett falsch verstanden und habe nur bullshit geschrieben  ;D

mg

Hallo Psyche

Danke für Deine Antworten. Ich habe die Änderung deshalb so ausgeführt, weil ich irgendwie gemerkt habe, daß sich die CLK_PRG nach kurzer Zeit bei einer CPU315 verrechnet. Ich habe weiters erkannt, daß CLK_PRG einen ähnlichen Inhalt wie die S5_TIME hat. Erst hatte ich die CLK_PRG so verändern wollen, daß die Änderungen von der S5_TIME in die CLK_PRG einfließen aber das habe ich gleich mal den ganzen Betrieb stillgelegt. Dann habe ich mir die Teile von der S5_Time_V1.5 nochmals angeschaut (die funktioniert bei mir) und erkannt, daß ich die "neue" S5_Time_V1.5 als Funktion in die CLK_PRG einbinden kann. Leider ist es einmal zu dem obigen Effekt gekommen, daß die CLK_Prg nach einem erneuten Änderungsdownload (bin zumindest "nach 3 Monaten" der Meinung daß es nur ein Änderungsdownlaod war) zu einem Fehler der CLK_Prg kam. Deshalb setzte ich die Werte bei einem solchen Fehler einfach gleich. Ich verwende die CLK_PRG in Zusammenhang mit der PWM_DC. Ich weiß nicht wo die CLK_PRG sonst noch verwendet wird. Zumindest in diesem Zusammenhang funktioniert das Ganze mal bis jetzt. Leider taucht der Fehler NUR im Sommer auf. Im Winter braucht die Steuerung den PWM_DC nicht.

Ich bin über jeden Kommentar froh. DANKE !!!

Mg

psyche

S5_Time ? Meinst du STime ?

Poste mal deinen kompletten aktuellen CLK_PRG. Sonst kenn ich mich jetzt gar nicht mehr aus.

Btw, für was braucht man denn PWM_DC ? Kann mir gerade keine praktische Anwendung vorstellen  ;D

mg

Hallo Psyche

a) Ja STime
b) siehe Anhang
c) PWM_DC: Da gibt es viele Anwendungen dafür. In diesem Fall verwende ich es zum leistungsmäßigen Takten eines Befeuchterventilsventils für die Zusatzkühlungkühlung eines Tischkühlers (Außeneinheit). Aber auch die meisten Elektroheizungen werden so leistungsmäßig geregelt.

Die CLK_PRG Probleme gibt es nur bei der S7-315. Bei der 1500er funktioniert die erstaunlicherweise.

So nun noch was zu mir selbst, damit Du über meine Ahnungslosigkeit Bescheid weißt:  ... ich bin mit der S7 zwangsbeglückt worden (bin eigentlich aus der Prozeßtechnik). Und ich machte bis vor 2 Jahren keine S7-Steuerungen. Aber alles ändert sich mal. Wir schreiben mit der S7 eigentlich NUR Prozeßkälteanlagen und neuerdings mache ich ein bischen Lüftung dazu (und M-Bus wurde auch schon entwickelt). Ich habe meine Software natürlich nun so aufgebaut wie ich das aus der Codesys-Welt kenne (Leider geht bei der S7 der CFC noch nicht ... da muß ich mich halt mit dem FUP abfinden, aber das geht auch, wenn auch die Übersichtlichkeit stark darunter leidet). Also die ganzen OB's, DB's usw. sind mir kaum vertraut und nicht will sie auch nicht verwenden sonst schreibe ich alles im SCL. Natürlich wollte ich viele meiner eigenen Bausteine aus dem Codesys verwenden (ging auch erstaunlich gut). Inzwischen haben wir schon eine ganz gute (interne) LIB für die Siemens S7. Mein EINZIGSTER OB ist immer noch der OB1. Alles andere wird ausprogrammiert. Somit bin ich als Entwickler für das Zeugs VÖLLIG daneben. Trotzdem funktionieren bereits 4 Anlagen PERFEKT! Ich werde das System wie ich es bisher gemacht habe auch so beibehalten. Ich habe auch bereits mit mehreren ORIGINAL-SIEMENS-Programmierern darüber gesprochen und die haben mir auch zu nichts anderem geraten.

Mit besten Dank

Mg

[gelöscht durch Administrator]

psyche

Guten Morgen,

so, ich habe immer noch kein Step7 zur Hand aber ich hab das ganze mal in Codesys geladen.
Du hast ja nur noch 4 Zeilen Code übrig  :o Das ging in der Codebox hier im Forum irgendwie unter.

Also noch mal von vorne :

"IDB_STIME"();
#tx := "IDB_STIME".tx;


Hier öffnest du den STIME IDB und liest die aktuelle Zeit aus. Das verursacht eine Reihe von Problemen:
1. Du rufst nirgends den STime auf, also kann STime auch nicht die aktuelle Zeit in seinen IDB schreiben. Da es offensichtlich trotzdem funktioniert, benutzt du anscheinend den STime irgendwo anders im Programm. Durch Zykluszeitschwankungen kannst du hier eine Ungenauigkeit in der Zeitmessung verursachen.
2. Der Init-Abschnitt ist weg. Ich denke hier liegt auch dein Problem. Beim Anlauf der CPU (nach Fehler, Hardware download, Stromausfall (!), etc) fängt die Systemzeit wieder bei 0 an. Wird das nicht abgefangen, kann die Zeit irgendwo liegen. Im ungünstigsten Fall wartest du dann 24 Tage auf den nächsten Impuls.


IF #Q OR NOT "IDB_STIME".init THEN #last := #tx; END_IF;


Wie schon geschrieben, das "IDB_STIME".init ist nutzlos. Ausser du hast ein Konstrukt geschaffen in dem STime erst nach CLK_PRG aufgerufen wird. Was aus verschiedenen Gründen auch nicht sonderlich Schlau wäre.

Es übrigens praktisch wenn STime ein Bit ausgeben würde das im Init-Zyklus true ist. Das würde einem die Init Routine in den Nachfolgebausteinen ersparen.
Im Nachhinein leider umständlich einzubauen.

Zusammengefasst reagieren Zeit-Funktionen immer sehr sensibel auf Störungen (Downloads, Neustarts, etc).
Aber mit deinen Änderungen hast du es meiner Meinung nach mehr schlechter als besser gemacht. So wie der Code war, müsste er schon funktionieren.
Die Probleme lagen hauptsächlich im STime <= V1.4.

Wie schon geschrieben, wenn du noch ein wenig Sicherheit reinbringen willst dann mach lieber was in der Richtung :
IF #Q OR #tx - #last < T#0ms THEN #last := #tx; END_IF;
Das verhindert das sich der Baustein "aufhängt". Obwohl das eigentlichgar nicht passieren sollte.

psyche

Sie dir mal das hier an :
http://www.oscat.de/community/index.php/topic,2244.msg11666.html#msg11666

Wenn du in deinem Programm dann noch IDB_STime.Init_happened auswertest, sollte das ganze fehlerfrei laufen.

mg

#11
Hallo Psyche

So wie ich das sehe empfiehlst Du die (obige) Lösung mit dem geänderten "init" UND mit deiner S_Time. Habe ich das richtig verstanden? Mir wäre das Lieb. Weil ich die S_Time gerne in diesen Baustein einbinden würde. Sonst habt man wieder x ähnliche Bausteine die derart (wie die S_Time) geändert werden müssen.


        "IDB_STIME"();
#tx := "IDB_STIME".tx;
IF #Q OR "IDB_STIME".init_happened THEN #last := #tx; END_IF;



Ich muß ehrlich sagen ich habe mich um die S_Time GAR NICHT gekümmert ich habs verwendet und (wie Du) erwartet daß es stimmt. Bisher hatte ich keine Probleme. Aber ich werde mal ein Projekt starten  (im Moment nichts in Aussicht) wo ich die Änderungen einbinde und dann hätte ich auch ein paar Testergebnisse. Evtl. kann ich auch ein bestehendes ändern. Welche CPU wäre sinnvoll (1511, 1513, 315) könnte ich anbieten.

Danke Mg

psyche

#12
Hi,

STime ist die Wurzel allen Übels, weil es ja die Zeit für alle Zeit basierten Funktionen aufbereitet. Jeder Fehler der dort passiert, wird an nachfolgende Bausteine übergeben.


FUNCTION_BLOCK CLK_PRG
TITLE = 'CLK_PRG'
//
//clk_prg uses the internal sps time to generate a clock with programmable period time.
//the period time is defined for 10ms .. 65s
//the first cycle after start is a clk pulse and then depending on the programmed period time a delay.
//every pulse is only valid for one cycle.
//the accuracy of clk_prg is depending on the accuracy of the system clock.
//
//uses: T_PLC_MS [FC64]
//      STIME [FB64],IDB_STIME [DB64]
//
VERSION : '1.4'
AUTHOR  : hugo
NAME    : CLK_PRG
FAMILY  : GENERAT

VAR_INPUT
  PT : TIME := t#10ms;
END_VAR
VAR_OUTPUT
  Q : BOOL := 0;
END_VAR
VAR
  last : TIME;
  tx: TIME;
END_VAR
VAR_TEMP
END_VAR

BEGIN
(* read system time *)
tx := DINT_TO_TIME(DWORD_TO_DINT("T_PLC_MS"()));

(* generate output pulse when next_pulse is reached *)
Q := tx - last >= pt OR tx - last < t#0ms;
IF Q THEN last := tx; END_IF;
 
 
(* revision hiostory

hm 25 feb 2007  rev 1.1
    rewritten code for higher performance
    pt can now be changed during runtime

hm  17. sep 2007    rev 1.2
    replaced time() with t_plc_ms() for compatibility reasons

hm  25. oct. 2008   rev 1.3
    optimized code
   
psyche 05.10.2014 rev 1.4
  nearly completely revised because of bugs in init procedure

*)
END_FUNCTION_BLOCK



Ich würde es so machen, wenn du meinen STime benutzt.
Maximaler Fehler ist hier  2x PT. D.H. wenn während der Programmbearbeitung ein CPU Neustart oder ein IDB download stattfindet und PT= T#1s ist, kann die Periodendauer zwischen dem letzten Impus und dem neuen Impuls zwischen T#10ms und T#2s liegen.
Wenn deine Anlage das nicht ab kann, musst du IDB_STime.Init_happened verwenden um einen geführten Neustart zu erreichen.
Aber immer daran denken, Init_happened muss nach Verwendung manuell zurück gesetzt werden.

Welche CPU du verwendest ist egal, dass ist alles Hardware neutral.
Wenn du das testest, wäre feedback nett.