Autor Thema: FB für Systemzeiten  (Gelesen 9399 mal)

Offline radar17892

  • Sr. Member
  • ****
  • Beiträge: 712
  • Think easy!
    • mollgruppe
FB für Systemzeiten
« am: Januar 01, 2015, 13:21:37 Nachmittag »
Hallo,
hier ein Baustein den ich schon mehrfach verwendete, um Programmweite Systemzeiten zu generieren.
Er sollte möglichst am Anfang der Haupttask aufgerufen werden.
Der FB stellt zwei Blinker 1+5Hz, ein 1Hz und Tagesbeginn Triggersignal bereit und die TIME OF DAY, die täglich mit der System RTC syncronisiert wird.
Benötigte Bibliotheken sind: syslibrtc.lib und util.lib
Einfach einen neuen FB in ST erstellen, Deklarations- und Programmteil hineinkopieren.

FUNCTION_BLOCK Zeitsystem
(*
##################################################################################
Programmbeschreibung:
Erzeugung von Systemzeiten und Syncronisierung mit Systemuhr
benötigte LIB: Syslibrtc, util
##################################################################################
Änderungsindex
Name:TL Datum: 30.12.13 Grund:   neu
Name:TL Datum: 20.06.15 Grund:   Anlaufmerker hinzugefügt
##################################################################################
*)
VAR_INPUT
END_VAR
VAR_OUTPUT
BL_1: BOOL; (*Systemblinkausgang 1Hz*)
BL_5: BOOL; (*Systemblinkausgang 5Hz*)
TR_1: BOOL; (*Systemtriggerausgang 1Hz*)
TR_Tag: BOOL; (*Systemtrigger Tagesbeginn 0:00Uhr zB für tägliche Speicheraugaben*)
Syszeit: TOD; (*aktuelle Tageszeit*)
Anlauf: BOOL; (*Anlauf ist nur im 1.Zykl =1*)
END_VAR
VAR
T_sync: TON; (*Uhrzeitsyncronisationstimer*)
Sysblinker1: BLINK; (*Systemblinker 1Hz*)
Sysblinker5: BLINK; (*Systemblinker 5Hz*)
TR_Tag_beginnt: R_TRIG; (*Flankentrigger Tagesbeginn 0:00Uhr*)
Trigger_1: R_TRIG; (*Flankentrigger 1Hz*)
HM1: BOOL := FALSE; (*Hilfsmerker für Anlauf*)
END_VAR
VAR CONSTANT
Synctime: TIME := t#24h; (*Syncronisationszeit mit RTC*)
Blinkzeit1: TIME := t#500ms; (*1Hz Blinkzeit*)
Blinkzeit2: TIME := t#100ms; (*5Hz Blinkzeit*)
END_VAR

####################################
(*Systemanlauf*)
Anlauf:= NOT HM1;
IF NOT HM1
THEN HM1:= TRUE;
END_IF
(*Zeitsyncronisation*)
T_sync(IN:= NOT T_sync.Q, PT:= Synctime, Q=> , ET=> );
Syszeit:= DT_TO_TOD (SysRtcGetTime(T_sync.Q));
(*Trigger Tagesbeginn *)
TR_Tag_beginnt(CLK:= (Syszeit < TOD#00:00:01 ), Q=> TR_Tag);
(*Systemzeitsignale erzeugen*)
Sysblinker1(ENABLE:=TRUE , TIMELOW:= Blinkzeit1, TIMEHIGH:= Blinkzeit1, OUT=> BL_1);
Sysblinker5(ENABLE:= TRUE, TIMELOW:= Blinkzeit2, TIMEHIGH:= Blinkzeit2, OUT=> BL_5);
Trigger_1(CLK:= Sysblinker1.OUT, Q=> TR_1);


have a lot of fun
« Letzte Änderung: September 01, 2015, 23:57:36 Nachmittag von radar17892 »
Weil Einfach einfach Einfach ist!

Offline radar17892

  • Sr. Member
  • ****
  • Beiträge: 712
  • Think easy!
    • mollgruppe
Antw:FB für Systemzeiten
« Antwort #1 am: September 08, 2023, 13:02:25 Nachmittag »
Ich möchte euch die Weiterentwicklung des Uhrenbausteins vorstellen, mit dem ich diverse Zeitsignale erzeuge.
Mittlerweile ist er etwas umfangreicher, weil verschiedene Sachen mit der Visu gemacht werden können und auch der Versorgung
der Schaltuhren mit diversen Daten dient.
Zu der besonderen Steuerung des Anlaufmerkers mittels Event, werde ich noch einen Beitrag schreiben.


FUNCTION_BLOCK Uhr2
(*
##################################################################################
Programmbeschreibung:
Baustein zum lesen und stellen der System RTC
Für diverse Verwendungen wird die aktuelle Zeit als String und aufgesplittet
ausgegeben. Systemzeitsignale erzeugen (Blinker und Flanken)
Der Startmerker aus EventTask Start(FUN)ermöglicht den Anlaufmerker mit jedem
Starten aus beliebigen Zuständen zu setzen.
Der Zeitoffset ist auf -2 - +3h beschränkt, (sollte für Mitteleuropa ausreichen)
benötigt: strZeit, SysRtc23,
Test OK auf XV100 v3.5.12
##################################################################################
Änderungsindex
Name: TL Datum: 30.12.13 Version: 1.0 Grund:   neu
Name: TL Datum: 20.06.15 Version: 1.1 Grund:   Anlaufmerker eingefügt
Name: TL Datum: 09.03.19 Version: 1.2 Grund:   Änderung Anlaufmerker  durch Event,
RTC lesen und schreiben, Erweiterung mit Zeitdaten DB, 5Hz-Takt zu 0,5Hz geändert
Name: TL Datum: 15.02.21 Version: 1.3 Grund:   Ausgang Zeitstring
Name: TL Datum: 07.09.23 Version: 2.0 Grund:  FB's der EA23_SysLibRtc_Add entfernt und neu geschrieben
direkte Ausgänge der geplitteten Zeitdaten eingefügt, Offset für Zeitverschiebung
##################################################################################
*)
VAR_INPUT
lesen: BOOL; //Lesebefehl Uhrzeit
schreiben: BOOL; //Schreibbefehl Uhrzeit
OffsetUTC: SINT:=1;  //Zeitverschiebung in h
END_VAR
VAR_IN_OUT
Zeitdaten:strZeit; //InstanzDB mit Zeitwerten
END_VAR
VAR_OUTPUT
DatZeit: DATE_AND_TIME;// aktuelles Datum+Zeit
strDatZeit: STRING(22);// aktuelles Datum+Zeit als String
Uhrzeit: TOD;// aktuelle Tageszeit von RTC
Jahr: WORD;
Monat: BYTE;
Tag: BYTE;
Stunde: BYTE;
Minute: BYTE;
Sekunde: BYTE;
Wochentag: BYTE; //Mo=1 ...So=7
BL_05: BOOL; (*Systemblinkausgang 0,5Hz*)
BL_1: BOOL; (*Systemblinkausgang 1Hz*)
TR_05: BOOL; (*Systemtriggerausgang 0,5Hz*)
TR_1: BOOL; (*Systemtriggerausgang 1Hz*)
TR_Tag: BOOL; (*Systemtrigger Tagesbeginn 0:00Uhr zB für tägliche Speicheraugaben*)
Anlauf: BOOL; (*Anlaufmerker, nur im 1.Zykl =1 *)
Meldesystem: BOOL; (* Meldesystem nach Verzögerung aktiv schalten*)
END_VAR
VAR
SollDatZeit: DATE_AND_TIME;// SollZeit zur RTC
DatZeitUTC: DATE_AND_TIME;// aktuelles Datum+Zeit von RTC
SetFlanke:R_TRIG; //Flanke für Uhr stellen
readFlanke:R_TRIG;//Flanke für Uhr lesen
T_sync: TON; (*Uhrzeitsyncronisationstimer*)
Takt_05: TON; (*Takt 0,5Hz*)
Trig05: R_TRIG; (*Flankentrigger 0,5Hz*)
Trig1: R_TRIG; (*Flankentrigger 1Hz*)
TR_Tag_beginnt: R_TRIG; (*Flankentrigger Tagesbeginn 0:00Uhr*)
HM1: BOOL := 0; (*Hilfsmerker für Anlauferkennung*)
VerzMeldungen: TON; //Timer für verzögertes einschalten des Alarmsystems
Zeitstring: STRING[22]; //Arbeitsvariable
Schaltjahr: BOOL;
//Hilfsvariablen zum Uhr stellen
setYear: WORD;
setMonth: BYTE;
setDay: BYTE;
setHour: BYTE;
setMinute: BYTE;
setSecond: BYTE;
count: INT;
SET_DT: DATE_AND_TIME;
END_VAR
VAR CONSTANT
Synctime: TIME := t#24h; (*Syncronisationszeit mit RTC*)
END_VAR

#####################################################################

(*Anlaufmerker nur  im 1. Zykl true steuern*)
//der Startmerker wird beim "prepare to run-Event" durch Start(FUN) auf TRUE gesetzt
Anlauf:= ZeitDB.Startmerker; //Startmerker aus EventTask Start
ZeitDB.Startmerker:= FALSE;
(*Zeitsyncronisation alle 24h*)
T_sync(IN:= NOT T_sync.Q, PT:= Synctime, Q=> , ET=> );
(*Zeit aus der RTC holen*)
DatZeitUTC:= SysRtcGetTime(T_sync.Q OR SetFlanke.Q); //akt.UTC ausgeben
//Korrektur Zeitverschiebung
CASE OffsetUTC OF
-2: DatZeit:= DWORD_TO_DT(DT_TO_DWORD(DatZeitUTC) - 7200);
-1: DatZeit:= DWORD_TO_DT(DT_TO_DWORD(DatZeitUTC) - 3600);
0: DatZeit:= DatZeitUTC;
1: DatZeit:= DWORD_TO_DT(DT_TO_DWORD(DatZeitUTC) + 3600);
2: DatZeit:= DWORD_TO_DT(DT_TO_DWORD(DatZeitUTC) + 7200);
3: DatZeit:= DWORD_TO_DT(DT_TO_DWORD(DatZeitUTC) + 10800);
ELSE DatZeit:= DatZeitUTC;
END_CASE
Zeitdaten.DatZeit:= DatZeit ; //akt Zeit in DB schreiben
Uhrzeit:=DT_TO_TOD(DatZeit); //akt Uhrzeit als TIME OF DAY ausgeben
Zeitdaten.Uhrzeit:=Uhrzeit; //akt Uhrzeit in DB schreiben
(*Zeit in einen String schreiben und DT# entfernen für Visu*)
strDatZeit:= DELETE(DT_TO_STRING(DatZeit),3,1);
Zeitdaten.strDatZeit:=strDatZeit;
(*Zeit aufsplitten und in DB schreiben*)
Zeitstring:= strDatZeit;
//Jahr, Monat, Tag extrahieren
Jahr:= STRING_TO_WORD(LEFT(STR:= Zeitstring, SIZE:= 4));
Zeitstring:= (DELETE(STR:= Zeitstring, LEN:= 5, POS:= 1));
Monat:= STRING_TO_BYTE(LEFT(STR:= Zeitstring, SIZE:= 2));
Zeitstring:= (DELETE(STR:= Zeitstring, LEN:= 3, POS:= 1));
Tag:= STRING_TO_BYTE(LEFT(STR:= Zeitstring, SIZE:= 2));
//Zeit extrahieren
Stunde:= DWORD_TO_BYTE(TOD_TO_DWORD(Uhrzeit) / 3600000);
Minute:= DWORD_TO_BYTE(TOD_TO_DWORD(Uhrzeit) / 60000 - TOD_TO_DWORD(Uhrzeit) / 3600000 * 60);
Sekunde:= REAL_TO_BYTE(DWORD_TO_REAL(TOD_TO_DWORD(Uhrzeit) - TOD_TO_DWORD(Uhrzeit)/60000 * 60000) / 1000.0);
//Wochentag ermitteln
Wochentag := DWORD_TO_BYTE((DATE_TO_DWORD(DT_TO_DATE(DatZeit)) / 86400 + 3) MOD 7) + 1;
//Daten in DB schreiben
Zeitdaten.Jahr:= Jahr;
Zeitdaten.Monat:= Monat;
Zeitdaten.Tag:= Tag;
Zeitdaten.Stunde:= Stunde;
Zeitdaten.Minute:= Minute;
Zeitdaten.Sekunde:= Sekunde;
Zeitdaten.Wochentag:= Wochentag;

(*Trigger Tagesbeginn *)
TR_Tag_beginnt(CLK:= (Uhrzeit < TOD#00:00:01 ), Q=> TR_Tag);
(*Systemzeitsignale erzeugen (Blinker und Flanken)*)
Takt_05(IN:= NOT Takt_05.Q, PT:= T#1S, Q=> , ET=> );
IF NOT BL_05 AND Takt_05.Q THEN
BL_05:=TRUE;
ELSIF (BL_05 AND Takt_05.Q) THEN
BL_05:=FALSE;
END_IF
IF Takt_05.ET > T#500MS THEN
BL_1:=TRUE;
ELSE
BL_1:=FALSE;
END_IF
Trig05(CLK:= BL_05, Q=> TR_05);
Trig1(CLK:= BL_1, Q=> TR_1);
//Freigabe Alarmmeldungen 30s nach Anlauf
VerzMeldungen(IN:= NOT Anlauf, PT:= T#30S, Q=> Meldesystem, ET=> );
(*akt Zeit per Befehl auf die Sollzeit kopieren*)
readFlanke(CLK:= lesen, Q=> );
IF readFlanke.Q THEN
Zeitdaten.setJahr:= Zeitdaten.Jahr;
Zeitdaten.setMonat:= Zeitdaten.Monat;
Zeitdaten.setTag:= Zeitdaten.Tag;
Zeitdaten.setStunde:= Zeitdaten.Stunde;
Zeitdaten.setMinute:= Zeitdaten.Minute;
Zeitdaten.setSekunde:= Zeitdaten.Sekunde;
END_IF
(*SollZeit per Befehl in die RTC schreiben(Uhr stellen)*)
SetFlanke(CLK:= schreiben, Q=> );
IF SetFlanke.Q THEN
(*Sollzeit zu DT zusammenstellen und in die RTC schreiben*)
ACT_setDT();
END_IF
Dazu die Action ACT_setDT
(hier musste ich mir ein paar Zeilen aus der OSCAT leihen um den Monat in die DT zu bekommen)

(*Sollzeit zu DT zusammenstellen und in die RTC schreiben*)
//Daten aus DB holen
setYear:= Zeitdaten.setJahr;
setMonth:= Zeitdaten.setMonat;
setDay:= Zeitdaten.setTag;
setHour:= Zeitdaten.setStunde;
setMinute:= Zeitdaten.setMinute;
setSecond:= Zeitdaten.setSekunde;
// DT erstellen
IF setMonth > 2 THEN
count := (setMonth - 1) * 30;
IF setMonth > 7 THEN count := count + SHR(setMonth - 3,1); ELSE count := count + SHR(setMonth - 4,1); END_IF;
(* chech for leap year and add one day if true *)
IF SHL(setYear,14) = 0 THEN count := count + 1; END_IF;
ELSE
count := (setMonth - 1) * 31;
END_IF;
SET_DT := DWORD_TO_DT(((INT_TO_DWORD(count + setDay - 1) + SHR(WORD_TO_DWORD(setYear) * 1461 - 2878169, 2)) * 86400) + INT_TO_DWORD(setSecond) + INT_TO_DWORD(setMinute) * 60 + INT_TO_DWORD(setHour) * 3600);
//DT in RTC schreiben
SysRtcSetTime(ActDateAndTime:= SET_DT);

Und der zugehörige Zeit-DB, deklariert in der GVL
VAR_GLOBAL
   ZeitDB: strZeit; //ZeitDatenbaustein für FB Uhr
END_VAR

TYPE strZeit :
(* Struktur des Zeit Datenbaustein
Achtung, Änderung nur mit Abgleich IN_OUT (FB)Uhr*)
STRUCT
Startmerker:BOOL;//Systemmerker zur Erkennung Anlauf (Nicht beschreiben!!!)
DatZeit: DATE_AND_TIME;// aktuelles Datum+Zeit von RTC
strDatZeit: STRING(22);// aktuelles Datum+Zeit als String
Uhrzeit: TOD;// aktuelle Tageszeit von RTC
Jahr: WORD; //Istwert Jahr
Monat: BYTE; //Istwert Monat
Tag: BYTE; //Istwert Tag
Stunde: BYTE; //Istwert Stunde
Minute: BYTE; //Istwert Minute
Sekunde: BYTE; //Istwert Sekunde
Wochentag: BYTE; //Istwert Wochentag
setJahr: WORD; //Sollwert Jahr
setMonat: BYTE; //Sollwert Monat
setTag: BYTE; //Sollwert Tag
setStunde: BYTE; //Sollwert Stunde
setMinute: BYTE; //Sollwert Minute
setSekunde: BYTE; //Sollwert Sekunde
END_STRUCT
END_TYPE

Weil Einfach einfach Einfach ist!