EERPOM wäre auch eine Option. Entweder das vom µC oder die meisten RTCs haben auch einen EEPROM Chip drauf.
jurs:
Zu 2.: Du läßt die Uhrzeit ständig auf Winterzeit laufen. Dann brauchst Du innerhalb der Uhr auch nicht abspeichern, ob es sich um Sommer- oder Winterzeit handelt. Das funktioniert dann auch mit RTCs ohne RAM, wie z.B. dem viel genauer laufenden DS3231 RTC-Modul. Und jedesmal nach dem Auslesen der Uhrzeit prüfst Du dann: Ist die ausgelesene Zeit Sommer oder Winterzeit, und bei Sommerzeit schlägst Du dann eine Stunde drauf.
Da ich ein DS3231 nutze bleibt wohl nur 2.
Hmm... einfach eine Stunde drauf??? Auf variable hour? Was ist mit Uhrzeit 23:00:00 bis 23:59:59 - da muss ja dann schon das Datum des Folgetages mit rein...
Gibt es hierfür Beispiele?
Lies dir nochmal jurs Kommentare zur Unix-Zeit durch.
Serenifly:
EERPOM wäre auch eine Option. Entweder das vom µC oder die meisten RTCs haben auch einen EEPROM Chip drauf.
Je länger ich drüber nachdenke, desto besser gefällt mir die Idee, die RTC generell auf UTC-Zeit laufen zu lassen. Das würde eine Library dann automatisch kompatibel machen zu Anwendungen, die etwas mit Sonnenstandsberechnung zu tun haben, astronomische und meteorologische Anwendungen, Synchronisierung über NTP-Zeitserver im Internet, Datentausch mit anderen Computern bei einheitlicher UTC-Zeitbasis etc., sowie unabhängig von externem Speicher wie EEPROM oder Uhren-RAM.
Intern zu verwalten wären dann einmal die Unix-Zeit (Sekunden seit 01.01.1970 UTC), und ein weiteres Zeitformat, das ich intern wie folgt darstellen würde:
struct sTime
{
int iYear;
byte bMonth;
byte bDay;
byte bHour;
byte bMinute;
byte bSecond;
byte bTimezone; // 0=UTC, 1=MEZ, 2=MESZ
};
Zum Auslesen der RTC bräuchte man dann nur Funktionen zum Lesen von "UTC time" und "local Time", wobei letztere ein paar Umrechnungen durchführen müßte. Abhängig von Datum und Zeit würden für "local Time" entweder eine oder zwei Stunden auf UTC draufgeschlagen werden.
Und zum Stellen der Uhrzeit würde die Funktion, abhängig ob Sommerzeit oder nicht, ein oder zwei Stunden abziehen müssen, um die Uhr auf UTC-Zeit laufen zu lassen.
Prinzipielle Probleme sehe ich da keine. Ich müßte mir nur mal näher ansehen, wie und mit welchen Algorithmen das möglichst effizient umgesetzt werden kann, damit ein Sketch mit solchen Routinen nicht bereits einen Großteil der Rechenzeit mit Umrechnungen verbringt.
Wäre folgender Ansatz auch machbar:
Ausgang ende winterzeit
Die Berechnung von Jurs erkennt den Tag der Umstellung - richtig?
Wenn summertime_EU = true Und DS3231 hour =2 -> set DS3231 hour +1 "und" set flag timeremember high
Wenn der Sommer vorüber geht
Am 1. Winterzeittag
Wenn summertime_EU = false & hour =3 & timeremeber = high -> set DS3231 hour -1 und set timeremeber low
// Wenn summertime_EU = false & hour= 3 & timeremeber = low -> do not set DS3231
Somit könnte man doch einfacher zw. Sommer und Winterzeit hin und her schalten...
MfG und frohe Ostern
Loschder:
Wenn der Sommer vorüber gehtAm 1. Winterzeittag
Wenn summertime_EU = false & hour =3 & timeremeber = high -> set DS3231 hour -1 und set timeremeber low
// Wenn summertime_EU = false & hour= 3 & timeremeber = low -> do not set DS3231Somit könnte man doch einfacher zw. Sommer und Winterzeit hin und her schalten...
Wenn Du ein "always on" Gerät hast, das ständig läuft, und von dem Du sicher sein kannst, dass es
- am Sommer-/Winterzeitumstelltag
- zur Sommer-/Winterzeitumstellstunde
aktiv ist und die Software dann auch läuft, wäre eine "Programmlogik mit Umstellung der Uhr" recht einfach.
Damit die Programmlogik wirklich zuverlässig funktioniert, müßte sie aber auch funktionieren, wenn das Gerät am Umstelltag ausgeschaltet in der Schublade liegt, und die Zeitumstellung beim nächsten Einschalten durchführen/nachholen.
Ich finde die Umstellung der Hardware sehr fehlerträchtig und programmiere daher was anderes. Erste Tests mit meinen Routinen sehen auch sehr vielversprechend aus, und das Timing finde ich auch OK.
Das reine Auslesen der RTC dauert bei meinen ersten Tests ca. 1060 µs (1,06 ms).
Das Auslesen und Umrechnen in lokale Zeit ca. 1760 µs (1,76 ms).
Für Anwendungen mit einer 1-Sekunden Zeitauflösung finde ich die zusätzliche Rechenzeit von 0,0007 Sekunden beim Auslesen nicht gravierend. Und wenn man ein paar Bytes zusätzlichen RAM-Speicherverbrauch akzeptiert, könnte man den Zeitbedarf auch weitestgehend wegoptimieren, indem man bei einer Änderung von nur Minuten oder Sekunden keine erneute Umrechnung durchführt, sondern die Minuten/Sekunden fortschreibt und erst dann einmal neu rechnet, wenn sich entweder Stunde, Tag, Monat oder Jahr geändert haben. Dann wäre der benötigte Extrazeitbedarf für eine auf UTC-Zeit laufende Uhr, von der die lokale Zeit gelesen wird, bei ca. 0,0007 Sekunden einmal pro Stunde.
Der ganze Plumpatsch mit Handling der Hardware und den Umrechnungen ist allerdings doch ein bisschen aufwändiger als gedacht und es kommen doch ein paar mehr Zeilen Code zusammen als gedacht, so dass ich doch die Freizeit von mehreren Tagen benötigen werden, das in geeigneter Form zusammenzupacken und ein Demoprogramm zu erstellen. Es sollen ja auch ein paar Kommentarzeilen als Dokumentation dabei sein, was die Funktionen machen. Ich bin aber auf einem guten Weg. Dauert allerdings noch ein paar Tage, bis ich was vorzeigen kann.
Hallo,
ich möchte Dir ja nicht vorgreifen, aber Formel braucht man dafür eigentlich nicht zusätzlich, wenn man Deine Sommererkennungsfunktion schon nutzt. Hab meinen Fehler ausgebügelt. Sollte jetzt sicher funktionieren.
Ich denke aber, Du schreibst eine komplette neue Funktion die alles enthält, damit man nicht mehr mehrere Funktionen benötigt. ???
void RtcRequest()
{
if (read_RTC_DS3231 (RTC_I2C_ADDRESS) == true) // RTC auslesen, wenn Fehlerstatus "wahr", dann
{
SERIAL_IMPL.println("DS3231 I2C Busfehler");
}
else // wenn kein Busfehler, dann
{
if (Sommerzeit_aktiv() == true) { // wenn Sommerzeit, dann
_Stunde = _Stunde + 1; // Sommerzeitkorrektur
if (_Stunde >=24) {
_Stunde = 0;
}
if ( _Tag >= 30 && _Monat == 4 || 6 || 9) { // Monatsüberlauf
_Tag = 1;
_Monat++;
}
if ( _Tag >= 31 && _Monat == 3 || 5 || 7 || 8 || 10) { // Monatsüberlauf
_Tag = 1;
_Monat++;
}
}
}
// Datum und Zeit für Ausgabe formatieren und in globalen String 'RtcDateTimeBuf' speichern
// snprintf(RtcDateTimeBuf,26,"%02d.%02d.%04d ; %02d:%02d:%02d",_Tag,_Monat,_Jahr,_Stunde,_Minute,_Sekunde)
} // Ende "RtcRequest"
Doc_Arduino:
Sollte jetzt sicher funktionieren.
Sicher?
Für 8 von 12 Monaten des Jahres behandelst Du nun einen Tagesüberlauf im Monat.
Aber was ist mit den übrigen 4 Monaten des Jahres?
Und meinst Du nicht, dass mit "_Monat++;" am Ende des Dezember ein Überlauf auf den 13. Monat stattfinden kann. Was passiert da wohl an Silvester in der letzten Stunde vor Mitternacht, wenn jemand auf die Uhr schaut?
Doc_Arduino:
Ich denke aber, Du schreibst eine komplette neue Funktion die alles enthält, damit man nicht mehr mehrere Funktionen benötigt. ???
Ich schreibe eine komplett neue Library.[/quote]
Hallo,
bitte alles in Ruhe lesen ...
In der RTC Auslesefunktion, frage ich Deine Sommerzeitfunktion ab. Und nur wenn diese true zurück gibt, weis ich das Sommerzeit ist. Deshalb muß ich auch nur die Sommermonate behandeln und bei Gefahr eines Monatsüberlauf den Tag entweder von 30 auf 1 oder von 31 auf 1 korrigieren. Wenn Winterzeit ist, wird gar nichts korrigiert, dann wird alles was von der RTC kommt 1:1 übernommen.
Meine RTC läuft dauerhaft auf Berliner Winterzeit. UTC+1. Das ist aber in der Sommerzeitfunktion schon voreingestellt.
Deshalb ist das die einfachste Methode aus meiner Sicht. Vielleicht eine Anregung für Deine Library. Die muß ja auch irgendwie eine Voreinstellung bekommen in welcher Zeitzone sie läuft. Okay, wenn sie allerdings auf reiner UTC Time läuft, dann muß man Winter und Sommer korrigieren. Eben das habe ich mir erspart. Jetzt weis ich auch wo unser Problem liegt. Ich habe Deine Sommerzeitfunktion fest auf UTC+1 angepaßt. Weil mein Arduino nur in Deutschland laufen wird. Wenn man Deine originale Sommerzeitfunktion hat, müßte man aber nur die Wintermonate hinzufügen und. Aber die Probleme habe ich mir schon vom Hals geschafft in dem alles von Haus aus in UTC+1 läuft.
Im Grunde kann aber jeder die Sommerzeitfunktion auf seine persönliche lokale Winterzeit anpassen und dann auch nur die Sommerzeit um eine Stunde wie ich korrigieren. Dann fällt bei allen die Winterzeit Korrektur weg. Mit blöden Februar und Dezember.
boolean Sommerzeit_aktiv () // ohne Parameterübergabe, nutzt globale Variablen!
// ausgehend das die RTC in der Zeitzone UTC + 1, also Winterzeit Berlin dauerhaft läuft, etwas modifiziert
// European Daylight Savings Time calculation by "jurs" for German Arduino Forum
// input parameters: "normal time" for year, month, day, hour
// return value: returns true during Daylight Saving Time, false otherwise
{
static int x1, x2, lastYear; // Zur Beschleunigung des Codes ein Cache für einige statische Variablen
int x3;
if (_Monat <3 || _Monat > 10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
if (_Monat >3 && _Monat < 10) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
// der nachfolgende Code wird nur für _Monat 3 und 10 ausgeführt
// Umstellung erfolgt auf _Stunde utc_hour=1, in der Zeitzone Berlin entsprechend 2 Uhr MEZ
// Es wird ein Cache-Speicher für die Variablen x1 und x2 verwendet,
// dies beschleunigt die Berechnung, wenn sich das _Jahr bei Folgeaufrufen nicht ändert
// x1 und x2 werden nur neu Berechnet, wenn sich das _Jahr bei nachfolgenden Aufrufen ändert
if (_Jahr != lastYear) // Umstellungsbeginn und -ende Berechnung
{
x1 = 1 + 1 + 24 * (31 - (5 * _Jahr / 4 + 4) % 7); // Umschaltwert Winter > Sommer
x2 = 1 + 1 + 24 * (31 - (5 * _Jahr / 4 + 1) % 7); // Umschaltwert Sommer > Winter
lastYear = _Jahr;
}
x3 = _Stunde + 24 * _Tag;
if (_Monat == 3 && x3 >= x1 || _Monat == 10 && x3 < x2) return true; else return false;
}
Hallo,
jetzt hab ich doch noch eine Syntax-Frage.
if ( _Tag >= 30 && _Monat == 4 || 6 || 9) { // Monatsüberlauf
mit obigen Code, bekomme ich aktuell zwar die richtige Zeit, aber als Datum 1.6.15. ???
Die UND Bedingung und _Tag >= wird völlig ignoriert.
dann habe ich eine Klammer gesetzt und das Datum paßt wieder
if ( _Tag >= 30 && (_Monat == 4 || 6 || 9) ) { // Monatsüberlauf
Jetzt bin ich mir aber nicht mehr sicher ob ich nicht doch das hier schreiben müßte
if ( _Tag >= 30 && (_Monat == 4 || _Monat == 6 || _Monat == 9) ) { // Monatsüberlauf
Compilerfehler gibts nirgends.
Doc_Arduino:
Meine RTC läuft dauerhaft auf Berliner Winterzeit. UTC+1. Das ist aber in der Sommerzeitfunktion schon voreingestellt.Deshalb ist das die einfachste Methode aus meiner Sicht. Vielleicht eine Anregung für Deine Library. Die muß ja auch irgendwie eine Voreinstellung bekommen in welcher Zeitzone sie läuft. Okay, wenn sie allerdings auf reiner UTC Time läuft, dann muß man Winter und Sommer korrigieren. Eben das habe ich mir erspart. Jetzt weis ich auch wo unser Problem liegt. Ich habe Deine Sommerzeitfunktion fest auf UTC+1 angepaßt.
OK, die Aussage "RTC läuft dauerhaft auf Berliner Winterzeit. UTC+1" hatte ich aus Deinem vorherigen Posting so nicht verstanden. In dem Fall kann man das natürlich so machen und braucht dann nur in den Sommermomonaten eine Stunde draufrechnen, um auf lokale Zeit zu kommen.
Die Programmlogik müßte natürlich trotzdem stimmig sein.
Ein logischer Ausdruck "4 || 6 || 9" bedeutet wohl soviel wie "4!=0 || 6!=0 || 9!=0" bzw. "true || true || true" und ist wohl nicht das, aus das Du als Bedingung testen möchtest.
Hallo,
Danke, das erklärt einiges. ![]()
Wünsche ruhigen Ostermontag.
Doc_Arduino:
Danke, das erklärt einiges.
Wünsche ruhigen Ostermontag.
OK, dann habe ich Deine Anregung mal aufgegriffen und statt einer angedachten "full-featured time library" erstmal eine "easy time library" gemacht, bei der die RTC stets auf Zonenzeit 'UTC+1' läuft, und je nachdem ob Sommerzeit herrscht, liefert die Auslesefunktion 'RTCreadLocalTime' entweder Winterzeit UTC+1 oder Sommerzeit UTC+2 zurück.
Die Library braucht nicht installiert zu werden, sondern wird als .h Datei auf einen 'Tab' des aktuellen Projekts gelegt. Ein Demo-Projekt ist beigefügt. Das Demo-Projekt hat zwei Tasks:
- Befehle vom Seriellen Monitor auswerten und ggf. die RTC-Zeit einstellen
- alle fünf Sekunden sowohl die Zonenzeit UTC+1 und die aktuelle lokale Zeit auslesen und anzeigen
Zum Testen kann man die Uhrzeit ggf. auf relevante Testzeitpunkte setzen, z.B. eine Minute vor Zeitumstellung, und sehen, wie dann die lokale Zeit gegenüber der Zonenenzeit am Umstellzeitpunkt plötzlich um eine Stunde vor- oder zurückspringt.
Beim Stellen der Uhrzeit bitte beachten: In dieser ersten Version muss die Zeitangabe beim Stellen der Uhr im Demoprogramm immer in Winterzeit angegeben werden. Also jetzt während der Sommerzeit beim Stellen der Uhr immer eine Stunde zurückrechnen bei der Zeiteingabe zum Stellen der Uhr.
Zum Anlegen eigener Projekte braucht man nur das Demoprojekt 'dateTimeLibEasyDemo' öffnen und dann mittels der Funktion 'Datei - Speichern unter' unter eigenem Namen abspeichern und kann das Projekt dann beliebig abwandeln und umprogrammieren, so hat man dann das gesamte Projekt in einem Ordner und braucht keine Library extra installieren.
Getestet habe ich mit Arduino 1.0.5 unter Windows. Als Dokumentation sind in der .h Datei Kommentare bei den einzelnen Funktionen enthalten.
Wer Fehler findet oder Verbesserungswünsche hat: Einfach in diesem Thread posten.
Frohe Ostern!
Demoprojekt ist im Dateianhang, den enthaltenen Ordner einfach in den Arduino-Sketchordner packen!
Im Anhang zu Reply #45 ist eine neuere Version der Library downloadbar!
dateTimeLibEasyDemo.zip (3.59 KB)
Hallo,
es funktioniert. Hab auch mal meine RTC verstellt für einen Monatswechsel, hat auch funktioniert. Würde sagen, alles i.O. Getestet mit IDE 1.0.6 und hterm.
Ich sage kurzum vielen DANK !
Hi, beschäftige mich auch seit ein paar Tagen mit den Arduino
und möchte mir einen Uhren-Sketch erstellen.
Wo ist mein Fehler?
Habe den Sketch von jurs (dateTimeLibEasyDemo) geladen.
Gebe in die Konsole z.B. set 2015 29 03 01 55 ein, aber die Zeit der RTC ändert sich nicht.
Gruß Djerun
Hallo,
bekommste Du keine Fehlermeldung?
Dein Fehler liegt aber in der Schreibweise vom set Befehl.
Guck nochmal genau hin, ist alles beschrieben.
Tip. Reihenfolge und ohne führende Null.
nein, es kommt keine Fehlermeldung.
auch wenn ich das Exempel aus dem Sketch kopiere und einfüge.
Keine Änderung im Monitor.
Gruß Djerun
Hallo,
was nutzt Du als Terminal? Da muß ein LF oder CR am Ende dran sein. Stell es gleich auf LR+CR ein. Das mußte ich in meinem "verstellten" hterm auch erst wieder einstellen. Muß man im Arduino IDE Terminal ebenfalls machen. Wenn das dann geklappt hat, gibts eine OK Meldung.
Ich benutze die Konsole vom Serial Monitor.
Hallo,
naja und ... weiter? Haste unten rechts "Sowohl NL als auch CR eingestellt, neben 9600 Baud Einstellung?