Parameter Speichern

Monsignore

Level-2
Beiträge
91
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Forum!

Ich bin gerade dabei mit Twincat 3 mir ein paar Bausteine vorzubereiten die Bibliothekfähig sind. Ich möchte diverse Parameter welche ich über die HMI einstellen kann Persistent in der PLC abspeichere nach einem Neustart bzw. Kaltstart wiederherstellen. Und genau hier stehe ich etwas auf dem Schlauch. Die HMI wird über Propertys GET/SET HMI.Para angebunden und schreibt so ihre Werte auf die Variablen. Jedoch wie der Weg zurück funktioniert ist mir derzeit noch unklar. Meine Ansätze wäre der FB_Init gewesen jedoch bin ich hier nicht wirklich weitergekommen.

Wie handhabt ihr das bzw. hat da einer eine Idee wie ich hier Licht ins Dunkle bringe?

Danke
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Remanente Variablen - PERSISTENT, RETAIN
Die kannst Du auch in allen Funktionsbausteinen verwenden und durch die Instanziierung multiplizieren. Ist super, wenn Du objektorientiert programmieren willst.
Aber ein Wort zur Vorsicht. Persistente Variablen gehen bei Stromausfall verloren. Darum ist eine USV / 1Sekunden-USV erforderlich, die im Fall des Stromausfall über CX-spezifische Mechanismen die PLC runterfahren und die Daten auf der Festplatte speichern. DIese werden dann bei Hochstart automatisch mit den letzten gespeicherten Werten initialisiert.
Ich würde das HMI auf jeden Fall zusätzlich mit der Funktion ausstatten, alle persistenten Werte in einer Datei als Backup speichern zu können, um es später bei Datenverlust zurück sichern zu können.
Alternativ kannst Du auch einen CX mit NOVRAM einsetzen. Oder eine EL6080.
Auf jeden Fall sollte die SPS für die Datensicherheit zuständig sein und nicht das HMI.
 
Zuletzt bearbeitet:
Danke schonmal für eure Antworten. Es werden immer CX mit 1Sekunden USV verwendet. Was ich noch vergessen habe zu erwähnen dass ich die Parameter dass die HMI Parameter Propertys auf eine Struktur referenzieren. Ich habe eine HMI Struktur welche drei Unterstrukturen hat. Persistent sollen aber nur die Parameter Variablen sein und da tue ich mich noch schwer wie ich das am besten umsetze.
 
Die Parameter Struktur seperat als Persistent deklarieren und in der Sammeltstruktur nur die Referenz auf deine Parameter Struktur deklarieren ("Reference to ST_Parameter").

Habe gerade kein TwinCAT zur Verfügung.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Habe zu diesem Thema mal ein Video gemacht, habe gut 10 Jahre in der Logistik Branche alle Daten von Hochregalen in der PLC verwaltet. Die Lagerdaten waren natürlich extrem wichtig.

Um diese Inhalte anzuzeigen, benötigen wir die Zustimmung zum Setzen von Drittanbieter-Cookies.
Für weitere Informationen siehe die Seite Verwendung von Cookies.
 
Was ich noch vergessen habe zu erwähnen dass ich die Parameter dass die HMI Parameter Propertys auf eine Struktur referenzieren. Ich habe eine HMI Struktur welche drei Unterstrukturen hat. Persistent sollen aber nur die Parameter Variablen sein und da tue ich mich noch schwer wie ich das am besten umsetze.
Gehe weg von der alten strukturorientierten Programmierung, hin zur Objektorientierung. Sonst bist Du nur am um-mappen der Variablen oder machst alles nur global. Beides ist doof.

Suche Dir ein Objekt in der realen Welt und baue einen kompletten Funktionsbaustein dafür. In dem Funktionsbaustein definierst Du das HMI-Interface, nur für das eine Objekt. Ich mache das das so: stConfig ( persistent ) für Konfigurationseinstellungen des Objekts, stMas ( persistent ) für Maschineneinstellungen rund um das Objekt und stHMI (nicht persistent) für alle Soll- und Ist-Werte und die restliche HMI-Steuerung.

Jedes Objekt erhält damit ein eigenes HMI-Interface und du musst die Objekte nur noch so oft instanziieren, wie Du reale Objekte hast. Die SPS-HMI-Schnittstelle und auch die SPS-Hardware-Schnittstelle erweitert sich dadurch voll automatisch ohne zusätzliche Arbeit. Wenn Du das HMI nach den gleichen Grundsätzen gestaltest, sparst Du einen riesigen Haufen Arbeit.
 
@automation-consult
Danke deinen Kanal kenne ich und sehe mir gerne jedes Video an, sehr informativ!

@asci25
Genau das habe ich gerade vor z.b einen FB_AI zu erstellen. Dieser FB soll:
  • Mit der Hardware verlinkt werden
  • Den Rohwert skalieren
  • Alarmieren über den Eventlogger
  • Schnittstellen zur HMI haben (Control=Steuerung R/W durch HMI, Para=Parameter R/W+Persistent, View=Anzeige)
Ich hätte mir gedacht dass ich mir ein Interface I_AI_Sensor erstelle, dazu noch Ctrl, Para und View Struktur. Würdet ihr die Bausteine vom Eventlogger in den FB_AI integrieren oder extern behandeln?

Danke für eure Mithilfe
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Würdet ihr die Bausteine vom Eventlogger in den FB_AI integrieren oder extern behandeln?
Prinzipiell integrieren.

Aber, ich bin vom TC2 und dem Eventlogger ein gebranntes Kind. Beim TC2-Eventlogger konnte man nur 2048 ADS Instanzen erzeugen und nicht wieder zerstören. Das hatte zur Folge, dass man maximal nur 2048 Meldungen hatte und das sehr massiv auf die Performance ging. Da ich über 10000 verschiedene Fehlermeldungen hatte, habe ich mir damals etwas einfallen lassen müssen. Den lokalen fbEventlog habe ich im FB integriert. Dieser hatte jedoch eine Schnittstelle zu einem globalen Eventlogggerbaustein, der maximal 200 Meldungsbausteine integriert hatte. Über die Schnittstelle hat sich der lokale fbEventlog einen gerade freien Meldungsbaustein gesucht und die Meldung abgeschickt und so lange die Verbindung gehalten, bis die Meldung komplett verarbeitet und gelöscht war. Dann wurde der Meldungsbaustein für die nächste Meldung freigegeben. Ab TC3 hatte ich die globale Schnittstelle auf VAR_STAT und Vererbung umgestellt.
Bis TC3.1.4024 hat das funktioniert.
Jetzt beim Umstieg auf TC3.2.4026 und den TC3 Eventlogger lasse ich das Prinzip so. Wenn ich allerdings neu beginnen müsste, würde ich wahrscheinlich zuerst wieder versuchen, für jede Meldung lokal einen eigenen Baustein zu haben. Ich könnte mir vorstellen, dass Beckhoff dazugelernt hat.

Ich hätte mir gedacht dass ich mir ein Interface I_AI_Sensor erstellen

Mache die Objekte aber nicht zu kleinteilig. Ein reales Objekt, dass Du in einem Softwareobjekt darstellen kannst, ist ein Zylinder oder Ventil mit Rückmeldungen oder ein frequenzgesteuerter Antrieb mit allen Sensoren und Sicherungsrückmeldungen usw. Integriere auch gleich die Wartungszähler mit rein. Du kannst dann auch mehrere Objekte, so wie in der realen Welt zu einem größeren Objekt zusammenfassen. Wenn Du dann eine größere Baugruppe noch einmal hast, erzeugst Du nur eine neu Instanz, bindest Hardware und HMI - und fertig. Und da werden dann auch schnell Konfigurationsparameter wichtig, weil es ja doch einen Unterschied geben wird.
 
Prinzipiell integrieren.

Aber, ich bin vom TC2 und dem Eventlogger ein gebranntes Kind. Beim TC2-Eventlogger konnte man nur 2048 ADS Instanzen erzeugen und nicht wieder zerstören. Das hatte zur Folge, dass man maximal nur 2048 Meldungen hatte und das sehr massiv auf die Performance ging. Da ich über 10000 verschiedene Fehlermeldungen hatte, habe ich mir damals etwas einfallen lassen müssen. Den lokalen fbEventlog habe ich im FB integriert. Dieser hatte jedoch eine Schnittstelle zu einem globalen Eventlogggerbaustein, der maximal 200 Meldungsbausteine integriert hatte. Über die Schnittstelle hat sich der lokale fbEventlog einen gerade freien Meldungsbaustein gesucht und die Meldung abgeschickt und so lange die Verbindung gehalten, bis die Meldung komplett verarbeitet und gelöscht war. Dann wurde der Meldungsbaustein für die nächste Meldung freigegeben. Ab TC3 hatte ich die globale Schnittstelle auf VAR_STAT und Vererbung umgestellt.
Bis TC3.1.4024 hat das funktioniert.
Jetzt beim Umstieg auf TC3.2.4026 und den TC3 Eventlogger lasse ich das Prinzip so. Wenn ich allerdings neu beginnen müsste, würde ich wahrscheinlich zuerst wieder versuchen, für jede Meldung lokal einen eigenen Baustein zu haben. Ich könnte mir vorstellen, dass Beckhoff dazugelernt hat.



Mache die Objekte aber nicht zu kleinteilig. Ein reales Objekt, dass Du in einem Softwareobjekt darstellen kannst, ist ein Zylinder oder Ventil mit Rückmeldungen oder ein frequenzgesteuerter Antrieb mit allen Sensoren und Sicherungsrückmeldungen usw. Integriere auch gleich die Wartungszähler mit rein. Du kannst dann auch mehrere Objekte, so wie in der realen Welt zu einem größeren Objekt zusammenfassen. Wenn Du dann eine größere Baugruppe noch einmal hast, erzeugst Du nur eine neu Instanz, bindest Hardware und HMI - und fertig. Und da werden dann auch schnell Konfigurationsparameter wichtig, weil es ja doch einen Unterschied geben wird.
OT:

Wie setzt du einen Wartungszähler um? Am Beispiel eines Zylinders dann die Schaltzyklen? Wo speicherst du das? Daten Persistent innerhalb eines FB zu speichern war meiner Erinnerung relativ komplex...

Von dir würde ich gern mal ein Programm sehen, was du so von dir gibst würde ich behaupten die sind sehr nahe an dem was ich mir für meine Programme wünschen würde. Mach doch mal Tutorials :P
 
Wie setzt du einen Wartungszähler um? Am Beispiel eines Zylinders dann die Schaltzyklen? Wo speicherst du das? Daten Persistent innerhalb eines FB zu speichern war meiner Erinnerung relativ komplex...
Das hinterlässt Fragezeichen. Kommt Deine Erinnerung vielleicht aus CodeSYS? Was hattest Du für Controller?

Hier ist mein Deklarationsausschnitt. Der FB_StandardDevice kann viele Geräte abbilden und die Zähler sind manchmal Zyklenzähler und sonst Zeitzähler. Das wird per Parameter festgelegt. Das mache ich so seit 15 Jahren, stammt aus TC2 und ist in TC3 rein gewachsen.

C-ähnlich:
FUNCTION_BLOCK FB_StandardDevice_2P EXTENDS FB_RemoteBase
...
VAR
....
END_VAR
VAR PERSISTENT
    { attribute 'TcHmiSymbol.ShowRecursively' }{ attribute 'TcHmiSymbol.AddSymbol' }
    stConfig                            : ST_StandardDevice_2P_CONFIG;
    { attribute 'TcHmiSymbol.ShowRecursively' }{ attribute 'TcHmiSymbol.AddSymbol' }
    stMas                                : ST_StandardDevice_2P_MAS;

    {attribute 'no_init'}
    nCnt_OpHours                        : UDINT;        (* Operation counter: operation hours *)
    nCnt_OpSec                            : UINT;
    {attribute 'no_init'}
    nCnt_TotalOpHours                    : UDINT;        (* Operation counter: total operation hours *)
    nCnt_TotalOpSec                        : UINT;
END_VAR
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das hinterlässt Fragezeichen. Kommt Deine Erinnerung vielleicht aus CodeSYS? Was hattest Du für Controller?

Hier ist mein Deklarationsausschnitt. Der FB_StandardDevice kann viele Geräte abbilden und die Zähler sind manchmal Zyklenzähler und sonst Zeitzähler. Das wird per Parameter festgelegt. Das mache ich so seit 15 Jahren, stammt aus TC2 und ist in TC3 rein gewachsen.

C-ähnlich:
FUNCTION_BLOCK FB_StandardDevice_2P EXTENDS FB_RemoteBase
...
VAR
....
END_VAR
VAR PERSISTENT
    { attribute 'TcHmiSymbol.ShowRecursively' }{ attribute 'TcHmiSymbol.AddSymbol' }
    stConfig                            : ST_StandardDevice_2P_CONFIG;
    { attribute 'TcHmiSymbol.ShowRecursively' }{ attribute 'TcHmiSymbol.AddSymbol' }
    stMas                                : ST_StandardDevice_2P_MAS;

    {attribute 'no_init'}
    nCnt_OpHours                        : UDINT;        (* Operation counter: operation hours *)
    nCnt_OpSec                            : UINT;
    {attribute 'no_init'}
    nCnt_TotalOpHours                    : UDINT;        (* Operation counter: total operation hours *)
    nCnt_TotalOpSec                        : UINT;
END_VAR
Ne war Beckhoff, hatte es aber selbst nicht getestet / benötigt und nur irgendwo nachgelesen. Aber gut zu wissen. Das werde ich in Zukunft vermutlich nun auch mit einbauen :)
 
C-ähnlich:
FUNCTION_BLOCK FB_StandardDevice_2P EXTENDS FB_RemoteBase

VAR PERSISTENT
[...]
END_VAR

Jetzt muss ich mich doch mal einhaken: Wird bei dieser Variante nicht die gesamte FB-Instanz im persistierenden Speicherbereich abgelegt? Zumindest war so mein Verständnis bislang. Hast du damit Performance-Themen bei großen Anlagen?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Unter TC2 war es so, dass eine persistente Variable in den Lokaldaten dafür sorgte, dass der Platz für den ganzen Baustein im persistenten Speicher verbucht wurde.
Daher hatte ich persistente Daten als InOut übergeben.
Mit TC3 hatte ich bisher zu wenig Berührung.
 
Unter TC2 war es so, dass eine persistente Variable in den Lokaldaten dafür sorgte, dass der Platz für den ganzen Baustein im persistenten Speicher verbucht wurde.
Daher hatte ich persistente Daten als InOut übergeben.
Mit TC3 hatte ich bisher zu wenig Berührung.
Mit TC2 hatte ich nichts zu tun, aber wir handhaben auch über InOut. Meine auch, dass irgendwo in der Doku erwähnt ist, dass man eine persistierende Deklaration in FB vermeiden soll aus Performancegründen. Haben aber die Performance nie verglichen. Eleganter ist aber definitiv die Variante von asci25. Daher meine Rückfrage.
 
Unter TC2 war es so, dass eine persistente Variable in den Lokaldaten dafür sorgte, dass der Platz für den ganzen Baustein im persistenten Speicher verbucht wurde.
Das habe ich so nicht beobachtet. Aber von den Retain-Variablen in Codesys kenne ich das beschriebene Verhalten. Und da gab es schnell Probleme mit dem stromausfallsicheren Speicher. Ich glaube, das gab es je nach Controller auch Limitierungen. Im Dunkeln schweben mir da so noch 8MB vor meinen Augen. War aber bei Wago.

Da Persistent aber auf der Festplatte abgelegt wird, gibt es keine Speicherprobleme und da die nur beim Hochfahren des Systems einmalig eingelesen werden, hat man auch keine Performance-Probleme. Wichtig ist nur, dass die gesamten Daten einmal durch den TcRouter müssen, also muss der Routerspeicher immer größer als die gesamten persistenten Daten sein.

Meine auch, dass irgendwo in der Doku erwähnt ist, dass man eine persistierende Deklaration in FB vermeiden soll aus Performancegründen.
Die TwinCAT-Doku schreibt auch nichts dazu. Eher im Gegenteil werden Deklarationen auf Bausteinebene sogar als Möglichkeit erwähnt.

Die Verwendung von IO-Variablen würde ich generell einstellen. Wenn man so was braucht ist ein Input als Pointer Of besser. Wenn man eine IO-Variable in der Deklaration hat, kann man die Aktionen nicht mehr flexibel einsetzen, bzw einfach von außen aufrufen. Das macht aber wieder Sinn, wenn man z.B. einen Fasttask mit im FB haben möchte. Das ist aber wieder ein anderes Thema.
 
Zuletzt bearbeitet:
Zurück
Oben