Wie schon in der PN geantwortet, nun jedoch im vollen Umfang, weil keine Zeichenbegrenzung ...
... erstmal arbeite ich selbst nur mit TIA SCL. Sollte aber in den Grundlagen analog zu ST sein, nur die spezifischen Details ...
Ich habe einen UDT für meine BS-Speicher:
Code:
TYPE "udtRTM"
VERSION : 0.1
STRUCT
Total : Struct // Gesamtzähler
Hour : DInt; // Betriebsstunden
Minute : Int; // Betriebsminuten
Second : Int; // Betriebssekunden
END_STRUCT;
Charge : Struct // Chargenzähler
Hour : DInt; // Betriebsstunden
Minute : Int; // Betriebsminuten
Second : Int; // Betriebssekunden
END_STRUCT;
Maintenance : Struct // Wartungszähler
Intervall : Int; // Intervall
Warning : Int; // Vorwarnung
Hour : Int; // Stunden
Minute : Int; // Minuten
Second : Int; // Sekunden
END_STRUCT;
Flags : Struct // Statusanzeige
ResetCharge : Bool; // Chargenzähler rücksetzen
ResetMaintenance : Bool; // Wartungszähler rücksetzen
Warning : Bool; // Warnung Wartungszähler
Maintenance : Bool; // Meldung Wartungszähler
State : Int; // Status Wartung: 0 = OK, 1 = Vorwarnung, 2 = Wartung
END_STRUCT;
END_STRUCT;
END_TYPE
Dann habe ich einen remanenten DB, der für jedes Bauteil mit BS-Zähler eine Varibale dieses UDT enthält.
Jetzt der eigentliche Zähler.
Es ist eine Funktion, die 2 boolsche Eingänge enthält und einen InOut vom obigen UDT:
Code:
FUNCTION "FC RTM" : Void
TITLE = FC RTM
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : 'hucki'
VERSION : 0.1
//Betriebsstundenzähler
VAR_INPUT
ON : Bool; // Zähler aktiv
Clock : Bool; // Flanke vom Taktgeber
END_VAR
VAR_IN_OUT
RTM : "udtRTM"; // Betriebszähler
END_VAR
BEGIN
IF #ON THEN
// Totalzähler
#RTM.Total.Second := #RTM.Total.Second + BOOL_TO_INT (#Clock); // Sekunden erhöhen
#RTM.Total.Minute := #RTM.Total.Minute + BOOL_TO_INT (#RTM.Total.Second >= 60); // Minuten erhöhen
#RTM.Total.Hour := #RTM.Total.Hour + BOOL_TO_DINT(#RTM.Total.Minute >= 60); // Stunden erhöhen
#RTM.Total.Second := #RTM.Total.Second MOD 60; // Sekunden rückstellen
#RTM.Total.Minute := #RTM.Total.Minute MOD 60; // Minuten rückstellen
// Chargenzähler
#RTM.Charge.Second := #RTM.Charge.Second + BOOL_TO_INT (#Clock); // Sekunden erhöhen
#RTM.Charge.Minute := #RTM.Charge.Minute + BOOL_TO_INT (#RTM.Charge.Second >= 60); // Minuten erhöhen
#RTM.Charge.Hour := #RTM.Charge.Hour + BOOL_TO_DINT(#RTM.Charge.Minute >= 60); // Stunden erhöhen
#RTM.Charge.Second := #RTM.Charge.Second MOD 60; // Sekunden rückstellen
#RTM.Charge.Minute := #RTM.Charge.Minute MOD 60; // Minuten rückstellen
// Wartungszähler
#RTM.Maintenance.Second := #RTM.Maintenance.Second + BOOL_TO_INT(#Clock); // Sekunden verringern
#RTM.Maintenance.Minute := #RTM.Maintenance.Minute + BOOL_TO_INT(#RTM.Maintenance.Second >= 60); // Minuten verringern
#RTM.Maintenance.Hour := #RTM.Maintenance.Hour - BOOL_TO_INT(#RTM.Maintenance.Minute >= 60); // Stunden verringern
#RTM.Maintenance.Second := #RTM.Maintenance.Second MOD 60; // Sekunden rückstellen
#RTM.Maintenance.Minute := #RTM.Maintenance.Minute MOD 60; // Minuten rückstellen
IF #RTM.Maintenance.Hour < 0 THEN
#RTM.Maintenance.Second := 0; // Sekunden nullen
#RTM.Maintenance.Minute := 0; // Sekunden nullen
#RTM.Maintenance.Hour := 0; // Stunden nullen
END_IF;
END_IF;
IF #RTM.Flags.ResetCharge THEN
#RTM.Charge.Second := 0; // Sekunden nullen
#RTM.Charge.Minute := 0; // Minuten nullen
#RTM.Charge.Hour := 0; // Stunden nullen
#RTM.Flags.ResetCharge := False; // Reset löschen
END_IF;
IF #RTM.Flags.ResetMaintenance THEN
#RTM.Maintenance.Second := 0; // Sekunden nullen
#RTM.Maintenance.Minute := 0; // Minuten nullen
#RTM.Maintenance.Hour := #RTM.Maintenance.Intervall; // Stunden zurücksetzen
#RTM.Flags.ResetMaintenance := False; // Reset löschen
END_IF;
// Werte begrenzen
#RTM.Maintenance.Warning := MIN(IN1 := #RTM.Maintenance.Warning, IN2 := #RTM.Maintenance.Intervall); // Warnvorgaben begrenzen
IF #RTM.Maintenance.Hour > #RTM.Maintenance.Intervall THEN
#RTM.Maintenance.Hour := #RTM.Maintenance.Intervall; // Wartungsstunden begrenzen
#RTM.Maintenance.Minute := 0; // Wartungsminuten zurücksetzen
#RTM.Maintenance.Second := 0; // Wartungssekunden zurücksetzen
END_IF;
// Status-Flags
#RTM.Flags.Maintenance := #RTM.Maintenance.Hour <= 0 AND #RTM.Maintenance.Intervall > 0; // Status Wartung
#RTM.Flags.Warning := #RTM.Maintenance.Hour <= #RTM.Maintenance.Warning AND #RTM.Maintenance.Warning > 0; // Status Warnung
#RTM.Flags.Warning := #RTM.Flags.Warning AND NOT #RTM.Flags.Maintenance; // Status Warnung ggf. unterdrücken
// Ausgabe Status
#RTM.Flags.State := SEL(G := #RTM.Flags.Warning, IN0 := 0, IN1 := 1); // Warnung
#RTM.Flags.State := SEL(G := #RTM.Flags.Maintenance, IN0 := #RTM.Flags.State, IN1 := 2); // Wartung
END_FUNCTION
"Clock" ist die positive Flanke eines 1s-Taktmerkers (Wird bei Siemens durch die CPU erzeugt).
"On" gibt an, ob gezählt werden soll oder nicht. In der Regel hängt da der Ausgang des Verbrauchers dran. (Bei mir direkt hinter der Ansteuerung des jeweiligen Ausgangs.)
"RTM" ist die zum Ausgang gehörige BS-Variable, in die gezählt werden soll, aus obigen DB.
Zum Reseten eines Zählers setze ich von der Visu aus nur das Reset-Flag direkt im DB, damit die FC dann beim nächsten Aufruf den Auftrag ausführt.
PS: Beim Wartungszähler zeige ich nur die Stunden an. Deshalb zähle ich Minuten und Sekunden nicht rückwärts.