Forum: Mikrocontroller und Digitale Elektronik Sommer-/Winterzeit umschalten


von Mampf F. (mampf) Benutzerseite


Lesenswert?

Guten Abend,

ich hab zwei Möglichkeiten, meine Sommer- und Winterzeit-Umstellung in 
einer kleinen Uhr zu implementieren.

- Triggern, wenn der letzte Sonntag im März 2:00 / Oktober 3:00 ist und 
die Zeit um eine Stunde vor oder zurück stellen.
- Die Zeit intern immer auf Winterzeit lassen und berechnen, ob das 
Aktuelle Datum + Zeit in der Sommerzeit liegt und dann einfach nur 
anders anzeigen.

Die erste Version gefällt mir nicht, weil ich eine RTC habe, die mit 
einem Supercap gepuffert ist. D.h. der Trigger könnte einfach übersehen 
werden, wenn die Uhr aus ist, aber die RTC weiter läuft.

Die zweite Version ist zwar sicherer, aber die Uhr-Einstellung ist 
schwieriger. Beispielsweise müsste man auch noch einen Überlauf der 
Stunden auf den nächsten Tag oder nächsten Monat implementieren, der bei 
Stunde+1 passieren könnte.

Wenn man dann Zeit und Datum einstellt, muss man das alles wieder zurück 
auf die Winterzeit rechnen, was dann auch wieder doof ist.

Wie habt ihr das so gemacht?

*edit*: Hmm, zu Version 1 könnte ich im Backup RAM noch speichern, ob 
zuletzt Winter- oder Sommerzeit "gesehen" wurde und dann ermitteln, ob 
sich das geändert hat und dann entsprechend korrigieren. Dann würde ich 
den Trigger nicht verpassen ...

: Bearbeitet durch User
von HolgerT (Gast)


Lesenswert?

Mampf F. schrieb:
> Wie habt ihr das so gemacht?

DCF77

von Achim H. (anymouse)


Lesenswert?

Mampf F. schrieb:
> - Triggern, wenn der letzte Sonntag im Oktober 3:00 ist und
> die Zeit um eine Stunde zurück stellen.

Also:


..
Okt 2:58
Okt 2:59
Okt 3:00 -> Okt 2:00
Okt 2:01
Okt 2:02
..
Okt 2:58
Okt 2:59
Okt 3:00 -> Okt 2:00
Okt 2:01
Okt 2:02
..
Okt 2:58
Okt 2:59
Okt 3:00 -> Okt 2:00
Okt 2:01
Okt 2:02
..

Ungefähr so? ;)

Mampf F. schrieb:
> *edit*: Hmm, zu Version 1 könnte ich im Backup RAM noch speichern, ob
> zuletzt Winter- oder Sommerzeit "gesehen" wurde und dann ermitteln, ob
> sich das geändert hat und dann entsprechend korrigieren. Dann würde ich
> den Trigger nicht verpassen ...

Nicht "könnte", sondern "muss".

----

Wie "klein" ist denn die Uhr? Sprich, auf welche Werkzeuge kannst Du 
zurückgreifen?

Prinzipiell fände ich die Option "Die Zeit intern immer auf Winterzeit 
lassen und berechnen, ob das Aktuelle Datum + Zeit in der Sommerzeit 
liegt und dann einfach nur anders anzeigen." komfortabler.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Wenn du die RTC abfragst, kannst du ja feststellen, ob du dich im 
Intervall 'Last Sunday in Oktober' bis 'Lest Sunday in March' befindest 
und dann entweder die RTC stellen, Flag setzen oder nur fürs Display 
umrechnen. Dann verschwendest du nix vom Supercap, weil das nur 
passiert, wenn der Core läuft.

: Bearbeitet durch User
von Mampf F. (mampf) Benutzerseite


Lesenswert?

Matthias S. schrieb:
> Wenn du die RTC abfragst, kannst du ja feststellen, ob du dich im
> Intervall 'Last Sunday in Oktober' bis 'Lest Sunday in March' befindest
> und dann entweder die RTC stellen, Flag setzen oder nur fürs Display
> umrechnen. Dann verschwendest du nix vom Supercap, weil das nur
> passiert, wenn der Core läuft.

Hmm ja, im Grunde ist das einfach, aber die ganzen Grenzfälle bereiten 
mir etwas Kopfzerbrechen (die in der Praxis vmtl niemals vorkommen 
würden).

Beispielsweise zu Variante 2:

Die Uhr wird gestartet und festgestellt, dass das letzte mal als sie 
gelaufen ist noch Sommerzeit war und jetzt ist Winterzeit. Aber der 
RTC-Counter (zählt von 0 bis 24*60*60) ist noch auf einem Zählerstand 
von <60*60, dann würde die Subtraktion vom Zähler wieder eine Korrektur 
im Datum erfordern.

Ich glaube mein Problem ist, dass die RTC so saudumm implementiert 
ist... Vlt sollte ich einfach Sekunden seit 2000 verwenden ... Das würde 
zumindest noch 50 Jahre funktionieren und ich müsste aus den Sekunden 
nur das Datum herausrechnen.

Die aktuelle Implementierung - von HAL inspiriert, vielen Dank an ST! ? 
- ist so, dass der RTC-Counter quasi nur die Sekunden pro Tag zählt, das 
Datum wird quasi in den Backup-Registern mitgeführt.

Wir der Core neu gestartet aktualisiert der Code das Datum so lange, bis 
der RTC-Counter wieder innerhalb einer Tagesgrenze ist.

Der STM32F103 hat leider keinen richtigen Calendar eingebaut.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Achim H. schrieb:
> Ungefähr so? ;)

Nicht ganz ... Letzter Sonntag im März um 2Uhr wird auf 3Uhr umgestellt. 
Letzter Sonntag im Oktober von 3Uhr auf 2Uhr.

> Wie "klein" ist denn die Uhr? Sprich, auf welche Werkzeuge kannst Du
> zurückgreifen?

Oh, die ist ganz ordentlich ausgestattet ... STM32F103 mit 64kB Flash 
und 20kB RAM.

Mit dem Clock von 48MHz kann ich da viel Rechenzeit verschwenden ohne, 
dass man es merkt :)

> Prinzipiell fände ich die Option "Die Zeit intern immer auf Winterzeit
> lassen und berechnen, ob das Aktuelle Datum + Zeit in der Sommerzeit
> liegt und dann einfach nur anders anzeigen." komfortabler.

Ja, würde das Uhr einstellen verkomplizieren ... Aber ich denke auch 
fast ...

von Peter D. (peda)


Lesenswert?

Mampf F. schrieb:
> - Die Zeit intern immer auf Winterzeit lassen und berechnen, ob das
> Aktuelle Datum + Zeit in der Sommerzeit liegt und dann einfach nur
> anders anzeigen.

So mache ich das auch.
Die RTC zählt 32Bit Sekunden Normalzeit und erst die Ausgaberoutine 
rechnet in menschliches Zeitformat und dann in Sommerzeit um.
Beim Stellen der Stunden (t+=3600) kann es passieren, daß mal 2 Stunden 
weitergezählt wird und mal nicht weitergezählt wird.

Beitrag "Berechnung Datum + Uhrzeit + Sommerzeit"

: Bearbeitet durch User
von Mampf F. (mampf) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Mampf F. schrieb:
>> - Die Zeit intern immer auf Winterzeit lassen und berechnen, ob das
>> Aktuelle Datum + Zeit in der Sommerzeit liegt und dann einfach nur
>> anders anzeigen.
>
> So mache ich das auch.
> Die RTC zählt 32Bit Sekunden Normalzeit und erst die Ausgaberoutine
> rechnet in menschliches Zeitformat und dann in Sommerzeit um.
> Beim Stellen der Stunden (t+=3600) kann es passieren, daß mal 2 Stunden
> weitergezählt wird und mal nicht weitergezählt wird.
>
> Beitrag "Berechnung Datum + Uhrzeit + Sommerzeit"

Wunderbar, ich glaube ich schmeiße meinen aktuellen Ansatz weg und 
integriere deine Version :)

*edit*: Hmm, mein ARM-GCC hat auch includes für <time.h> ... Vlt sollte 
ich mal mktime oder localtime_r testen^^

: Bearbeitet durch User
von Jacko (Gast)


Lesenswert?

Was soll denn die Uhr gesehen haben müssen?

Eine ordentliche Uhr mit Sommer-/Winterzeit gibt es nur mit
mitlaufendem Kalender. Oder man nimmt DCF, wo das genau so
von der PTB gemacht wird.

Um es ohne DCF übersichtlich zu programmieren, lässt du die Uhr
(und die RTC) in unbeirrbarer (außer Schaltsekunden) UTC laufen.

Je nach Kalender und Zeitzone wird daraus die ME(S)Z, oder
sonstwas errechnet und zur Anzeige gebracht.

Und beim Stellen der Uhr geht die Eingabe mit entsprechendem
kalendergerechtem utc-Versatz in die Uhr und die RTC.

Das lässt sich in sehr kleinen µCs unterbringen.

von W.S. (Gast)


Lesenswert?

Mampf F. schrieb:
> Wie habt ihr das so gemacht?

Zwei 32 Bit Zahlen im System: kanonischer Tag (ab 1.1.2000) und 
kanonische Uhrzeit (in 1 ms Einheiten).

Für Datum und Uhr einen RTC von Seiko-Epson per I2C und 0.22F im System.

Dazu beim Startup des Gerätes (Einschalten) oder Mitternacht die 
Systemuhr eingerichtet (für kanonischen Tag und Zeit) und diese 
Systemuhr mit dem RTC einmal richtig synchronisiert.

Im System werden nur die obigen 2 long Zahlen verwendet.

Stellt der Kunde die Uhr, dann nur auf den RTC wirkend. Anschließend das 
obige Synchronisieren.

W.S.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Peter D. schrieb:
> So mache ich das auch.
> Die RTC zählt 32Bit Sekunden Normalzeit und erst die Ausgaberoutine
> rechnet in menschliches Zeitformat und dann in Sommerzeit um.
> Beim Stellen der Stunden (t+=3600) kann es passieren, daß mal 2 Stunden
> weitergezählt wird und mal nicht weitergezählt wird.
>
> Beitrag "Berechnung Datum + Uhrzeit + Sommerzeit"

Ahja C ist ja wieder mal ein geiler Scheiß ;-)

Dein Code leicht umgeschrieben:
1
void gettime(uint32_t sec, RTC_TimeTypeDef_H24* time, RTC_DateTypeDef *date) {
2
  uint16_t day;
3
  uint16_t year;
4
  uint8_t month;
5
6
  time->RTC_Seconds = sec % 60;
7
  sec /= 60;
8
  time->RTC_Minutes = sec % 60;
9
  sec /= 60;
10
  time->RTC_Hours = sec % 24;
11
  day = sec / 24;
12
13
  year = STARTYEAR;
14
  for (int dpy;day>=(dpy=365+rtc_isLeapYear(year));day-=dpy,year++);
15
  date->RTC_Year = year - STARTYEAR;
16
  month = 1;
17
  for (int dpm;day>=(dpm=rtc_daysPerMonth(month,year));day-=dpm,month++);
18
19
  date->RTC_Month = month;
20
  date->RTC_Date = day + 1;
21
}

Kommt sogar das richtige raus^^ Hab mit 1Mio Zufalls-Zeiten und Daten 
getestet ... Jeweils den Weg Time+Date -> Timestamp und wieder zurück.

Den Timestamp bekomme ich über
1
uint32_t rtc_getTimestamp(RTC_TimeTypeDef_H24 *time, RTC_DateTypeDef *date) {
2
  uint32_t timestamp = 0;
3
  // add year
4
  uint32_t days = 0;
5
  for (int y = STARTYEAR; y < date->RTC_Year + STARTYEAR; y++) {
6
    days += 365 + rtc_isLeapYear(y);
7
  }
8
  // add month
9
  for (int m = 1; m < date->RTC_Month; m++) {
10
    days += rtc_daysPerMonth(m, date->RTC_Year + STARTYEAR);
11
  }
12
  // add remaining days
13
  days += date->RTC_Date - 1;
14
15
  timestamp += days * 24l * 60l * 60l;  // days to seconds
16
  timestamp += time->RTC_Hours * 60l * 60l;
17
  timestamp += time->RTC_Minutes * 60l;
18
  timestamp += time->RTC_Seconds;
19
  return timestamp;
20
}

Quasi das gleiche nur andersherum.

Und die (kanonischen) Helferlein:
1
uint8_t rtc_isLeapYear(uint16_t nYear) {
2
  if ((nYear % 4) != 0) {
3
    return 0;
4
  }
5
6
  if ((nYear % 100) != 0) {
7
    return 1;
8
  }
9
10
  if ((nYear % 400) == 0) {
11
    return 1;
12
  } else {
13
    return 0;
14
  }
15
}
16
17
uint8_t rtc_daysPerMonth(int m, int y) {
18
  if (m < 1 || m > 12)
19
    return 0;
20
21
  uint8_t dpm[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
22
  if (m == 2)
23
    return dpm[m - 1] + (rtc_isLeapYear(y) ? 1 : 0);
24
  else
25
    return dpm[m - 1];
26
}

: Bearbeitet durch User
von tnsz (Gast)


Lesenswert?

Meine Geräte arbeiten intern immer mit UTC/Unixzeit. Die Ausgabe erfolgt 
dann in MEZ/MESZ oder welche Zeitzone auch immer. Den Tag der 
Uhrenumstellung kann man in eine Tabelle packen....

von Mampf F. (mampf) Benutzerseite


Lesenswert?

tnsz schrieb:
> Meine Geräte arbeiten intern immer mit UTC/Unixzeit. Die Ausgabe
> erfolgt
> dann in MEZ/MESZ oder welche Zeitzone auch immer. Den Tag der
> Uhrenumstellung kann man in eine Tabelle packen....

Ja, ich mach es jetzt auch so.

Ist viel einfacher, wenn man einen Sekunden-Timestamp und die 
Konvertierungsfunktionen von timestamp zu time+date und andersherum hat.

Ich hatte irrtümlich geglaubt, ich könnte mir das sparen - macht alles 
aber nur viel komplizierter.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.