FUNCTION "BT_LT_3" : VOID
TITLE =BT_LT_3: Convert base time to local time (Summertime/Wintertime)
//Ersatz für FC61 BT_LT aus der S7-Standard-Library auf S7-300, die keinen
//Uhrzeitstatus besitzen (Im Uhrzeitstatus der CPU sind die Basiszeit sowie
//die für den jeweiligen Ort geltende Zeitzone, eine Sommerzeit-Kennung sowie
//eine Kennung für die Ankündigungsstunde hinterlegt und werden von der CPU
//aktualisiert.) BT_LT_3 benutzt keinen Regel-DB.
//
//Typisches Szenario:
//Eine S7-300-CPU besitzt keinen Uhrzeitstatus, die CPU-Uhr ist nach der lokalen
//Normalzeit (Winterzeit) gestellt und ggf. nach NTP-Verfahren synchronisiert.
//BT_LT_3 ermittelt, ob der am Eingang BT angegebene Zeitpunkt in der Sommerzeit
//liegt und gibt am Ausgang LT die ggf. als Sommerzeit korrigierte lokale Uhrzeit
//aus. BT muß ein gültiges DATE_AND_TIME inkl. Wochentag sein.
//
//BT_LT_3 berücksichtigt keine Zeitzone, sondern nur den Uhrzeit-Versatz in
//der Sommerzeit. Die Sommerzeit gilt vom letzten Sonntag im März 02:00 BT
//bis zum letzten Sonntag im Oktober 02:00 BT (03:00 ST).
//BT_LT_3 benutzt intern die folgende Funktion der S7-Standard-Library –
//IEC Function Blocks: FC(1) AD_DT_TM
AUTHOR : PN_DP
FAMILY : TIMEFUNC
NAME : BT_LT_3
VERSION : 1.0
VAR_INPUT
BT : DATE_AND_TIME ; //Basiszeit (z.B. CPU-Clock)
END_VAR
VAR_OUTPUT
LT : DATE_AND_TIME ; //Lokalzeit
SUMMER : BOOL ; //Sommerzeitkennung (0: Winter / 1: Sommer)
END_VAR
VAR_TEMP
AR1_Save : DWORD ;
AR2_Save : DWORD ;
tmpBT : DATE_AND_TIME ;
tmpLT : DATE_AND_TIME ;
DB_No : INT ;
LT_Offset : TIME ;
March : BOOL ;
END_VAR
BEGIN
[COLOR="Blue"]NETWORK
TITLE =Basiszeit von IN-Aktualparameter BT in TEMP kopieren
//DATE_AND_TIME (DT) wird bei FC als 6-Byte-POINTER übergeben und kann nicht
//direkt weitergereicht werden. Deshalb IN.BT nach TEMP umkopieren.[/COLOR]
//Adressregister sichern
TAR1 #AR1_Save;
TAR2 #AR2_Save;
[COLOR="blue"]//Pointer auf IN-Aktualparameter BT erstellen
L P##BT; // Adresse IN.BT
LAR1 ;
L W [AR1,P#0.0]; // POINTER.DB_Nr
T #DB_No;
L D [AR1,P#2.0]; // POINTER.Bereichsadresse
LAR1 ; // AR1: Adresse des IN-DT
LAR2 P##tmpBT; // AR2: Adresse des TEMP-DT
//DATE_AND_TIME (8 Byte) BT von IN nach TEMP kopieren
AUF DB [#DB_No];
L D [AR1,P#0.0];
T LD [AR2,P#0.0];
L D [AR1,P#4.0];
T LD [AR2,P#4.0];[/COLOR]
NETWORK
TITLE =Ermitteln ob Sommerzeit ist und Lokalzeit berechnen
//Die Sommerzeit gilt vom letzten Sonntag im März 02:00 BT
//bis zum letzten Sonntag im Oktober 02:00 BT (03:00 ST)
//AR2: Pointer auf tmpBT
//Der letzte Sonntag im März bzw. Oktober kann auf 25. bis 31. fallen
//vor 25.03. ist Winterzeit
L LW [AR2,P#1.0]; // tmpBT.Monat (BCD) + Tag (BCD)
L DW#16#325; // vor 25.03. ist WZ
<I ;
SPB WINZ;
//nach 31.10. ist Winterzeit
POP ; // tmpBT.Monat (BCD) + Tag (BCD)
L W#16#1031; // nach 31.10. ist WZ
>I ;
SPB WINZ;
//nach 31.03. (= 01.04.) bis vor 25.10. (= 24.10.) ist Sommerzeit
POP ; // tmpBT.Monat (BCD) + Tag (BCD)
L W#16#331; // bis 31.03. Umschaltwoche zu SZ
<=I ;
= #March; // Umschaltwoche WZ zu SZ
SPB SPEZ;
POP ; // tmpBT.Monat (BCD) + Tag (BCD)
L W#16#1025; // bis vor 25.10. ist SZ
<I ;
SPB SOMZ;
//hier nur noch 25.03.-31.03. und 25.10.-31.10.
//letzter Sonntag ?
SPEZ: L LB [AR2,P#7.0]; // tmpBT.Wochentag 1=So ... 7=Sa
UW W#16#F; // nur Bits .0-.3 (4 LSB)
L B#16#1;
-I ; // WoT: 0=So, 1=Mo, ... 6=Sa
SPZ SONN; // jetzt ist der Umschalt-Sonntag
//Akku1: Wochentag 0=So ... 6=Sa
L LB [AR2,P#2.0]; // tmpBT.Tag (BCD)
BTI ; // Tag (INT)
TAK ; // Akku1: WoT, Akku2: Tag
-I ;
//Ergebnis 19..24 sind Tage vor Umschalt-Sonntag
L 25;
<I ;
SPBN NACH;
//Vor Umschalt-Tag bzw. -Uhrzeit
VOR: U #March;
SPB WINZ; // März: noch ist Winterzeit
SPA SOMZ; // Okt.: noch ist Sommerzeit
//Nach Umschalt-Tag bzw. -Uhrzeit
NACH: U #March;
SPB SOMZ; // März: nun ist Sommerzeit
SPA WINZ; // Okt.: nun ist Winterzeit
//es ist jetzt der Umschalt-Sonntag
SONN: L LB [AR2,P#3.0]; // tmpBT.Stunde (BCD)
L B#16#2; // vor 02:00 Uhr?
<I ;
SPB VOR;
SPA NACH;
//Signalisierung Sommerzeit oder Winterzeit
SOMZ: S #SUMMER;
L T#1H; // 1 Stunde Zeitdifferenz SZ-WZ
SPA TLTO;
WINZ: R #SUMMER;
L T#0MS; // Winterzeit ist Basiszeit
TLTO: T #LT_Offset;
//Lokalzeit berechnen
CALL "AD_DT_TM" (
T := #tmpBT,
D := #LT_Offset,
RET_VAL := #tmpLT);
NETWORK
[COLOR="blue"]TITLE =Lokalzeit von TEMP in OUT-Aktualparameter LT kopieren
//DATE_AND_TIME (DT) wird bei FC als 6-Byte-POINTER übergeben, OUT kann nicht
//direkt von anderen FC beschrieben werden. Deshalb mit TEMP-Kopie arbeiten.
//Pointer auf OUT-Aktualparameter LT erstellen
L P##LT; // Adresse OUT.LT
LAR1 ;
L W [AR1,P#0.0]; // POINTER.DB_Nr
T #DB_No;
L D [AR1,P#2.0]; // POINTER.Bereichsadresse
LAR1 ; // AR1: Adresse des OUT-DT
LAR2 P##tmpLT; // AR2: Adresse des TEMP-DT
//DATE_AND_TIME (8 Byte) LT von TEMP nach OUT kopieren
AUF DB [#DB_No];
L LD [AR2,P#0.0];
T D [AR1,P#0.0];
L LD [AR2,P#4.0];
T D [AR1,P#4.0];[/COLOR]
//Adressregister wiederherstellen + BIE/ENO auf TRUE setzen
LAR1 #AR1_Save;
LAR2 #AR2_Save;
SET ;
SAVE ;
END_FUNCTION