Wie können wir helfen?

Print

Wie kann man die Sommerzeit in der HMI mit Hilfe eines Makros automatisch verwalten?

In diesem Beitrag zeigen wir Ihnen, wie Sie die Sommerzeit in der HMI mithilfe eines Makros automatisch verwalten können. Die Zeitumstellung wurde erstmals im Jahr 1916 vorgenommen. Seit 2002 wird die Zeitumstellung in allen Mitgliedstaaten der Europäischen Union einheitlich durchgeführt:

  • die Umstellung auf die Sommerzeit erfolgt in der Nacht des letzten Samstags im März
  • die Umstellung auf die Winterzeit erfolgt in der Nacht zum letzten Samstag im Oktober

Zur Erinnerung: Die EU-Länder sind derzeit in drei Zeitzonen eingeteilt:

  • Westeuropa (GMT): Irland und Portugal
  • Mitteleuropa (GMT 1): Österreich, Belgien, Kroatien, Tschechische Republik, Dänemark, Frankreich, Deutschland, Ungarn, Italien, Luxemburg, Malta, Niederlande, Polen, Slowakei, Slowenien, Spanien und Schweden
  • Osteuropa (GMT 2): Bulgarien, Zypern, Estland, Finnland, Griechenland, Lettland, Litauen und Rumänien.

Mit HMI-Tool

Fügen Sie im Makro-Editor ein neues Makro hinzu und kopieren Sie es.

#include "MacroInit.h"
// Returns the day-of-month of the last Sunday of a given month/year
// Uses the Tomohiko Sakamoto-inspired method (no division by 7 needed)
int LastSundayOfMonth(int month, int year)
{
// Day of week of the last day of the month (0=Sunday ... 6=Saturday)
// Zeller-like formula for day-of-week of day 1, then offset to last day
int y = year;
int m = month;
int daysInMonth;
switch(m)
{
case 1:  daysInMonth = 31; break;
case 2:
if ((y % 400 == 0) || (y % 4 == 0 && y % 100 != 0))
daysInMonth = 29;
else
daysInMonth = 28;
break;
case 3:  daysInMonth = 31; break;
case 4:  daysInMonth = 30; break;
case 5:  daysInMonth = 31; break;
case 6:  daysInMonth = 30; break;
case 7:  daysInMonth = 31; break;
case 8:  daysInMonth = 31; break;
case 9:  daysInMonth = 30; break;
case 10: daysInMonth = 31; break;
case 11: daysInMonth = 30; break;
case 12: daysInMonth = 31; break;
default: daysInMonth = 30; break;
}
// Compute day-of-week of the last day of the month
// Using Zeller's formula (0=Sunday, 1=Monday ... 6=Saturday)
if (m < 3) { m += 12; y -= 1; }
int k = y % 100;
int j = y / 100;
int dow = (daysInMonth + (13*(m+1))/5 + k + k/4 + j/4 - 2*j) % 7;
// Zeller returns: 0=Saturday, 1=Sunday, 2=Monday ... 6=Friday
// Normalize to: 0=Sunday, 1=Monday ... 6=Saturday
dow = (dow + 6) % 7;
// Subtract offset to reach last Sunday (dow==0)
return daysInMonth - dow;
}
void Macro_main(IN *p)
{
MarcoInit
// Automatic Daylight Saving Time (DST) management
// <!> This script must be called every minute
// DST start : last Sunday of March   - 02:00 -> 03:00 (clock forward +1h)
// DST end   : last Sunday of October - 03:00 -> 02:00 (clock back   -1h)
// LocalBit[50000]: 0 = summer time, 1 = winter time (backed up on power failure)
// Catchup window: up to 6 days after the DST Sunday (HMI was powered off)
int minute    = BCD2BIN(LocalWord[60001]); // Current minute
int hour      = BCD2BIN(LocalWord[60002]); // Current hour
int day       = BCD2BIN(LocalWord[60003]); // Day of month
int month     = BCD2BIN(LocalWord[60004]); // Month
int year      = BCD2BIN(LocalWord[60005]); // Year (needed for LastSundayOfMonth)
int dayOfWeek = BCD2BIN(LocalWord[60006]); // Monday=1 ... Sunday=7
// --- DST START : last Sunday of March at 02:00 -> 03:00 ---
// Window: from Sunday at 02:00 until the following Saturday at 23:59 (6 days catchup)
int lastSunMarch   = LastSundayOfMonth(3, year);
int daysSinceDSTStart = day - lastSunMarch; // Positive if we are past the last Sunday
int dstStartWindow = (daysSinceDSTStart == 0 && hour >= 2) || // Sunday from 02:00
(daysSinceDSTStart >= 1 && daysSinceDSTStart <= 6); // Mon to Sat catchup
if ((LocalBit[50000] == 1) &&
(month == 3)           &&
dstStartWindow)
{
LocalWord[60002] = BIN2BCD(hour + 1); // Shift clock forward by 1 hour
LocalBit[50000]  = 0;                 // Flag: now summer time
}
// --- DST END : last Sunday of October at 03:00 -> 02:00 ---
// Window: from Sunday at 03:00 until the following Saturday at 23:59 (6 days catchup)
int lastSunOctober = LastSundayOfMonth(10, year);
int daysSinceDSTEnd = day - lastSunOctober;
int dstEndWindow = (daysSinceDSTEnd == 0 && hour >= 3) || // Sunday from 03:00
(daysSinceDSTEnd >= 1 && daysSinceDSTEnd <= 6); // Mon to Sat catchup
if ((LocalBit[50000] == 0) &&
(month == 10)          &&
dstEndWindow)
{
LocalWord[60002] = BIN2BCD(hour - 1); // Shift clock back by 1 hour
LocalBit[50000]  = 1;                 // Flag: now winter time
}
}

Fügen Sie das Makro in die Liste „Globales Makro“ ein und stellen Sie die Ausführungshäufigkeit auf 60000 ms (1 Minute), um die Uhr jede Minute zu aktualisieren.

Wie es funktioniert

Das Programm läuft jede Minute und liest die aktuelle Zeit (Minute, Stunde, Tag, Monat, Jahr, Wochentag) aus Registern aus.
Da alle Zeitwerte im BCD-Format gespeichert sind, werden sie zunächst in Dezimalzahlen umgewandelt.
Eine Hilfsfunktion berechnet die Anzahl der Tage im aktuellen Monat, einschließlich der Schaltjahre.
Um den letzten Sonntag des Monats zu ermitteln, prüft der Code: dayOfWeek == 7 (Sonntag) und day 7 > daysInMonth.
Wenn es der letzte Sonntag im März um genau 03:00 Uhr ist, wird die Uhr auf 04:00 Uhr vorgestellt (Sommerzeit).
Ein Flag-Bit (LocalBit[65535]) wird gesetzt, um die Sommerzeit anzuzeigen.
Wenn es der letzte Sonntag im Oktober um genau 03:00 Uhr ist, wird die Uhr auf 02:00 Uhr zurückgestellt (Winterzeit).
Das Flag-Bit wird auf Winterzeit gesetzt, um wiederholte Korrekturen zu verhindern.
Dadurch werden Endlosschleifen vermieden, in denen dieselbe Stunde mehrfach verarbeitet würde.
Das System hält also die Ortszeit automatisch mit den offiziellen Regeln der Sommerzeit synchronisiert.

Sie können LB65535 durch LB51999 ersetzen, um den Wert zu sichern(HMI-Registertypen: LB, LW, RWI und remanente/speichernde Register)

Siehe auch Einstellen und Synchronisieren der ACE PLC-Uhr mit der HMI mithilfe eines Makros