Newbie sucht Hilfe... DS3231 RTC mit MEZ/MESZ Umschaltung gesucht

Hallo Leute,

ist mein erster Post deshalb stell ich mich mal kurz vor:

Mein Name ist Chris, bin 32 Jahre, begeisterter Modellbauer und sonst auch technisch recht fit was Elektronik angeht.
Bis auf die Mikrokontroller eben :o, das möchte ich nun ändern...

Und zwar möchte ich eine Steuerung zur Kellerlüftung aufbauen, diese jedoch gerne über eine RTC Uhr zeitgesteuert frei geben. Das ganze mit 2 I2C Displays.

Hardware:

Arduino Uno R3
RTC DS3231 (setTime und normale Uhr funktioniert)
2x I2C Display (Ansteuerung funktioniert)
2x DHT22
4fach Relais Board

Ich möchte mich schrittweise an mein Ziel heran tasten.... hab auch schon kleinere Arduino Erfolge, aber eben die autom. Uhr mit MESZ/MEZ Umschaltung bekomm ich einfach garnicht hin...

Normale Uhr mit RTC, und auch das set ist soweit erfolgreich...aber wo bzw wie ich die Umschaltung da integrieren muss... grrrr, da bin ich am Verzweifeln.

Ich hab schon einige Beiträge hier im Forum über eben so eine Uhr gelesen und auch ausprobiert, aber immer die ich nenns mal "Automatik" bekomm ich nicht hin. Auch mit DS1307 sketch/libs hatte ich keine Erfolge...

Kann mir Jemand einen Sketch mit (funktions-)zugehöriger Lib nennen für eine DS3231 incl automatischer Zeitumstellung...???

MfG Chris

Hallo Loschder,

mit der Funktion

boolean sommerzeit()

{
  DateTime now = RTC.now();
  if (now.month()<3 || now.month()>10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
  if (now.month()>3 && now.month()<10) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
  if (now.month()==3 && now.day()<25) return false; // keine Sommerzeit bis 25.März
  if (now.month()==10 && now.day()<25) return true; // Sommerzeit bis 25.Okt.
  if (now.month()==3 && (now.hour() + 24 * now.day())>=(1 + 24*(31 - (5 * now.year() /4 + 4) % 7)) 
     || now.month()==10 && (now.hour() + 24 * now.day())<(1 + 24*(31 - (5 * now.year() /4 + 1) % 7)))
    return true;
  else
    return false;
}

bekommst du den boolean Wert Sommerzeit true/false, den du in den Programm einarbeiten kannst.

Gruß Ardubu

Hallo,

da kann man dir helfen. Lies mal in dem Thread, da findet man den Code von jurs.

http://forum.arduino.cc/index.php?topic=234453.new;topicseen#new

Hallo,

den Code von jurs habe ich schon gefunden - aber mir sind da einige dinge nicht wirklich klar:

Wo genau werden diese Zeilen eingefügt? Über void setup? Alle über void setup?

Wie wird die Umsetzung true/false auf die Stundenzeit gemacht?

Wie gesagt, bin totaler Neuanfänger...
Meinen ersten Arduino habe ich vor 2 Wochen in den Händen gehalten :sunglasses:

Ich hänge mal den sketch ein - vielleicht kann mir ja mal Jemand erläutern was wo wie hin muss

by the way - wie mache ich das mit der Funktion "für Forum kopieren" - und dann hier einfügen??
Also wie bekomm ich das Fenster um den Sketch?
(CODE TAGS PLEASE!)

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
#include "LiquidCrystal_I2C.h"              // Library für LCD aufgerufen
LiquidCrystal_I2C lcd(0x27,20,4);           // LCD Adresse auf 0x27 gesetzt, 16 Zeichen / 2 Zeilen LCD

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  lcd.init();                                 // Initialisierung des LCD                                            
  lcd.backlight();                            // LCD Hintergrundbeleuchtung aktivieren

  // set the initial time here:
  // DS3231 seconds, minutes, hours, day, date, month, year
  // setDS3231time(30,25,17,7,28,03,15);
}
void readDS3231time(byte *second, byte *minute,byte *hour,byte *dayOfWeek,byte *dayOfMonth,
byte *month,byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
void displayTime()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  // send it to the serial monitor
  Serial.print(hour, DEC);
  // convert the byte variable to a decimal number when displayed
  Serial.print(":");
  if (minute<10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second<10)
  {
    Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print(" ");
  if (dayOfMonth<10)
  {
    Serial.print("0");
  }
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  if (month<10)
  {
    Serial.print("0");
  }
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print(" Wochentag: ");
  switch(dayOfWeek){
  case 1:
    Serial.println("Sonntag");
    break;
  case 2:
    Serial.println("Montag");
    break;
  case 3:
    Serial.println("Dienstag");
    break;
  case 4:
    Serial.println("Mittwoch");
    break;
  case 5:
    Serial.println("Donnerstag");
    break;
  case 6:
    Serial.println("Freitag");
    break;
  case 7:
    Serial.println("Samstag");
    break;
  }
   lcd.setCursor(0, 0);                       // Anfang auf Stelle 0, Zeile 0 setzen

   if (hour<10)
  {
    lcd.print("0");
  }
    lcd.print(hour);                  // Temp innen: auf LCD ausgeben
    lcd.setCursor(2, 0);                      // Anfang auf Stelle 13, Zeile 0 setzen
    lcd.print(":");                             // Wert aus "t1" ausgeben (Temperatur1)
    lcd.setCursor(3, 0);                      // Anfang auf Stelle 19, Zeile 0 setzen
  if (minute<10)
  {
    lcd.print("0");
  }
    lcd.print(minute);                            // C auf LCD ausgeben
    lcd.setCursor(5, 0);                       // Anfang auf Stelle 0, Zeile 1 setzen
    lcd.print(":");                 // Feuchte rel: auf LCD ausgeben
    lcd.setCursor(6, 0);            // Anfang auf Stelle 13, Zeile 1 setzen
  if (second <10)
  
   {lcd.print("0");
   lcd.setCursor(7,0);
   }
   lcd.print(second);                             // Wert aus "h1" ausgeben (Luftfeuchtigkeit1)
   
}
void loop()
{
  displayTime(); // display the real-time clock data on the Serial Monitor,
  delay(1000); // every second
    
   
    
}

Loschder:
Hallo,

by the way - wie mache ich das mit der Funktion "für Forum kopieren" - und dann hier einfügen??
Also wie bekomm ich das Fenster um den Sketch?

http://forum.arduino.cc/index.php/topic,148850.0.html

Hallo,

das sind alles Funktionen, die regelmäßig aufgerufen werden müssen.

setup wird nur einmal beim Start oder nach Reset vom µC aufgerufen. Nimmt man für irgendwelche einmaligen Starteinstellungen. loop ist die Hauptschleife die immer und immer wieder ohne Pause durchlaufen wird. Das eigentliche Programm, wenn man so will.

Die Funktionen müssen also in der loop regelmäßig aufgerufen werden.

Die Sommerzeit Funktion, berechnet "nur" und gibt dir true oder false zurück, ob gerade Sommer oder Winterzeit ist. Das muß man dann in seiner Zeitauslese oder Zeitanzeigefunktion mit einbauen. Man muß ja die Stunde und ggf. den Tag korrigieren.

Ich gebe Dir mal meinen Code dafür, der basiert auf jurs Code und ist nur ganz leicht modifiziert für meine Zwecke.
Am Ende, für dich auskommentiert, setze ich alles zusammen in einen String, für spätere einfachere Handhabung.

Und nimm lieber für Tag, Stunde, Monat usw. globale Variablen. Lokale Variablen und dann mit Zeigern zugreifen finde ich hier Overkill, weil Du die ständig erneuerst.

void RtcRequestEverySecond()
{
 static unsigned long prevMillis = 0;
 if (millis()-prevMillis<1000) return; // Zeit noch nicht erreicht, Funktion abbrechen
 prevMillis+=1000;                     // addiere 1000 
 if (read_RTC_DS3231 (RTC_I2C_ADDRESS) == true)     // RTC auslesen, wenn Fehlerstatus "wahr", dann
   {
    Serial.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;
            Tag = Tag + 1;
           }
        }        
     }
 // 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 "RtcRequestEverySecond"

RTC auslesen

// Funktionen für DS3231 von jurs im deutschen Arduino Forum
boolean read_RTC_DS3231 (int i2c_adresse)
{                                          // aktuelle Zeit aus RTC auslesen
  boolean error = false;                   // Fehlerstatus setzen
  Wire.beginTransmission(i2c_adresse);     // Connect
  Wire.write(0);                           // Anfrage ab/der Register Nummer
  if (Wire.endTransmission() > 0 )         // war Connect fehlerfrei?
    { 
     error = true;                         // I2C Busfehler
     return error;                         // Abruch
    } 
  Wire.requestFrom(i2c_adresse, 7);        // 7 Bytes in Folge anfordern/lesen
  if (Wire.available() > 0 )               // sind Daten vorhanden?
    {
     Sekunde   = bcdToDec(Wire.read() & 0x7F);  // Maske für die ersten 7 Bits alleine
     Minute    = bcdToDec(Wire.read() );
     Stunde    = bcdToDec(Wire.read() & 0x3F);  // Umschaltung auf 24h statt 12h (AM/PM)
                          Wire.read();          // wäre der Wochentag
     Tag       = bcdToDec(Wire.read() );             
     Monat     = bcdToDec(Wire.read() );
     Jahr      = bcdToDec(Wire.read() );
    }    
  return error;  
}

umwandeln zwischen bcd und dezimal

byte decToBcd(byte val) // Hilfsfunktion zum Lesen/Schreiben der RTC
// Convert decimal number to binary coded decimal
// Hilfsfunktion für die Echtzeituhr
{
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)  // Hilfsfunktion zum Lesen/Schreiben der RTC
// Convert binary coded decimal to decimal number
// Hilfsfunktion für die Echtzeituhr
{
  return ( (val/16*10) + (val%16) );
}

Loschder:
Wie wird die Umsetzung true/false auf die Stundenzeit gemacht?

Im Endeffekt mußt Du mit Zeiten rechnen: Also auf eine UTC- oder Zonenzeit eine Stunde dazuzählen (beim Auslesen der Uhrzeit) oder abziehen (vor dem Stellen der Uhrzeit), oder auch nicht, abhängig davon, ob es sich um Sommerzeit handelt.

Viele setzen dafür irgendeine "Time Library" ein, die sie sich zusätzlich installiert und per #include-Zeile mit in das Programm eingebunden haben.

Gängig zum Rechnen mit Zeit ist zum Beispiel die "Unix-Zeit", also die Anzahl der Sekunden seit 01.01.1970 um 0:00:00 Uhr.

Wenn Du keine Time-Library verwendest, würdest Du zum Rechnen mit Unix-Zeit zwei Funktionen benötigen, die eine Datums-/Zeitangabe in Unix-Zeit und zurück verwandeln kann.

Wenn Du so eine Funktion hast, wäre die Programmlogik wie folgt zum Auslesen der Uhrzeit:

  • Zeit aus der RTC auslesen
  • wenn es keine Sommerzeit ist ==> Zeit direkt verwenden
  • wenn es Sommerzeit ist: In Unixzeit umwandeln, 3600 addieren, Ergebnis in Datum/Zeit zurückwandeln

Und zum Stellen der Uhrzeit:

  • wenn keine Sommerzeit herrscht ==> Zeit direkt in die RTC einspeichern
  • wenn es Sommerzeit ist: In Unixzeit umwandeln, 3600 abziehen, in Datum/Zeit zurückwandeln und in RTC einspeichern

Falls Du keine der bestehenden Time-Libraries verwenden möchtest und auch keine Funktionen finden kannst, sag Bescheid, dann könnte ich mal suchen oder etwas zaubern, was man "ohne extra installierte Time-Library" mit eigenem Code machen könnte.

Hmm,

ok - hab die Variablen nun globalisiert :wink:

Das heist es sollte eigentlich eine UTC Zeit vorhanden sein auf welche man mit "true" or "false"

entweder "3600 millis" oder eben "7200" aufrechnet, richtig?

Gibt es denn eine Lib welche dies schon alles enthält?

Nur, wenn man die "korrigierte" Zeit in die RTC zurückschreibt und man nimmt die Spannung weg, wird zwar die RTC gepuffert, aber wenn der µC wieder Strom bekommt, ist die Bedingung wieder wahr und wird wieder ausgeführt, oder? Ansonsten müßte man noch das EEPROM mitverwenden und die Info, ob Sommerzeit oder Winterzeit ausgeführt wird, als Flag abspeichern.
Eine eierlegende Wollmilchsau, also eine Lib, die Sommer u. Winterzeit berücksichtigt, die RTC über Taster mit stellen kann und ggf. auch wahlweise DCF77, GPS oder NTP Anbindung zur Zeitkorrektur akzeptiert, wäre schon genial. Allerdings wirds dann sicherlich schon mit dem internen Speicher enge :smiley:

Hallo,

mir ist keine Lib bekannt. Man braucht auch keine. Mit paar kleinen Funktionen ist alles erledigt. Die RTC stellt man, falls nötig immer nach UTC Zeit und den Rest machen die Funktionen. Ich habe lieber Funktionen die ich verstehe als Lib's wo ich nicht weis was die machen und viel zu viel an Bord haben, was wiederum wertvollen Speicher belegen könnte.

Es ist aber jeden frei gestellt, die Sommerzeitkorrektur in eine bestehende Lib einzubauen.

EEprom bringt keinen Vorteil. Man muß dennoch ständig abfragen ob Sommer oder Winter ist. Ob das nun eine Variable oder EEprom ist, ist völlig egal. Beim EEprom mußte wieder unnötig mehr Dinge beachten, brauchst wieder mehr Code, der unnötig ist.

Grrrrrr....

Jedes mal wenn ich den if/else Teil rein schreiben möchte bekomme ich Fehler

Kann da mal Jemand reinschauen was ich falsch mache und mich erleuchten...???

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
#include "LiquidCrystal_I2C.h"              // Library für LCD aufgerufen
LiquidCrystal_I2C lcd(0x27,20,4);           // LCD Adresse auf 0x27 gesetzt, 16 Zeichen / 2 Zeilen LCD


//variable global
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
/***  In loop() some of the above variables wil be reentered with new values  ***/
boolean DST         =  false;               // Reset flag “Daylight Saving Time” to Winter time


// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  lcd.init();                                 // Initialisierung des LCD                                           
  lcd.backlight();                            // LCD Hintergrundbeleuchtung aktivieren
  Serial.println();
  Serial.println("Debugging activated");
  Serial.println();
}
void readDS3231time(byte *second, byte *minute,byte *hour,byte *dayOfWeek,byte *dayOfMonth,
byte *month,byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
void dst ()
{
/*-------- utility code from jurs ----------*/
boolean DST(int year, byte month, byte day, byte hour, byte tzHours)
// European Daylight Savings Time calculation by "jurs" for German Arduino Forum
// input parameters: "normal time" for year, month, day, hour and tzHours (0=UTC, 1=MEZ)
// return value: returns true during Daylight Saving Time, false otherwise

  if (month<3 || month>10) return fals
  if (month<3 || month>10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
  if (month>3 && month<10) return true;  // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
  if (month==3 && (hour + 24 * day)>=(1 + tzHours + 24*(31 - (5 * year /4 + 4) % 7)) || month==10 && (hour + 24 * day)<(1 + tzHours + 24*(31 - (5 * year /4 + 1) % 7)))
    return true;
  else
    return false;
}

 
}

void displayTime()
{
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  // send it to the serial monitor
  Serial.print(hour, DEC);
  // convert the byte variable to a decimal number when displayed
  Serial.print(":");
  if (minute<10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second<10)
  {
    Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print(" ");
  if (dayOfMonth<10)
  {
    Serial.print("0");
  }
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  if (month<10)
  {
    Serial.print("0");
  }
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print(" Wochentag: ");
  switch(dayOfWeek){
  case 1:
    Serial.println("Sonntag");
    break;
  case 2:
    Serial.println("Montag");
    break;
  case 3:
    Serial.println("Dienstag");
    break;
  case 4:
    Serial.println("Mittwoch");
    break;
  case 5:
    Serial.println("Donnerstag");
    break;
  case 6:
    Serial.println("Freitag");
    break;
  case 7:
    Serial.println("Samstag");
    break;
  }
   lcd.setCursor(0, 0);               // Anfang auf Stelle 0, Zeile 0 setzen

   if (hour<10)                       // Wenn Stunden einstellig -> 0 davor setzen
  {
    lcd.print("0");
  }
    lcd.print(hour);                  // Stunden auf LCD ausgeben
    lcd.setCursor(2, 0);              // Anfang auf Stelle 2, Zeile 0 setzen
    lcd.print(":");                   // : auf Display ausgeben
    lcd.setCursor(3, 0);              // Anfang auf Stelle 3, Zeile 0 setzen
  if (minute<10)                      // Wenn Minuten einstellig -> 0 davor setzen 
  {
    lcd.print("0");
  }
    lcd.print(minute);                // Minuten auf LCD ausgeben
    lcd.setCursor(5, 0);              // Anfang auf Stelle 5, Zeile 0 setzen
    lcd.print(":");                   // : auf LCD ausgeben
    lcd.setCursor(6, 0);              // Anfang auf Stelle 6, Zeile 0 setzen
  if (second <10)                     // Wenn Sekunden einstellig-> 0 davor setzen
 
   {lcd.print("0");                
   lcd.setCursor(7,0);                // Anfang auf Stelle 7, Zeile 0 setzen
   }
   lcd.print(second);                 // Wert aus "h1" ausgeben (Luftfeuchtigkeit1)
   
}
void loop()
{
  displayTime();                       // display the real-time clock data on the Serial Monitor,
  delay(1000);                         // every second   
}

Loschder:
Das heist es sollte eigentlich eine UTC Zeit vorhanden sein auf welche man mit "true" or "false"

entweder "3600 millis" oder eben "7200" aufrechnet, richtig?

Wenn Du eine Linuxzeit in UTC hast, würdest Du für Localtime 3600 oder 7200 Sekunden (nicht 'millis') draufrechnen.

Wenn Du eine Zonenzeit "UTC plus eine Stunde" in Sekunden hast, würdest Du für Localtime 0 oder 3600 Sekunden draufrechnen.

Du könntest zur Verwaltung und zum Rechnen mit Zeiten einerseits eine fertige Time-Library einsetzen. Ganz gerne genommen wird wohl zum Beispiel diese hier verlinkte:
http://playground.arduino.cc/Code/Time
Für Arduino IDE-Versionen ab 1.5.7 und höher mußt Du die neueste Libraryversion haben, sonst gibt es Compilerfehler.

Man könnte sich aber auch geeignete Umrechnungsfunktionen zur Umwandlung von Zeiten Linuxtime->YMDHMS bzw. YMDHMS->Linuxtime selberschreiben und in einem Sketch oder einer Includedatei verwenden. Die Time-Library an sich bietet keine spezielle Sommerzeitunterstützung (also nichtmal USA-Sommerzeit), so dass man selbst mit Verwendung der Library noch etliche Zeilen Code dazuschreiben müßte. Ich kann mich ja mal in einer ruhigen Minute dransetzen, etwas Code ohne extra Library zu schreiben.

Hallo,

jurs, da mußte nichts extra schreiben, habe ich schon getan. Geht ganz simpel. Ich poste es nochmal.

void RtcRequestEverySecond()
{
 static unsigned long prevMillis = 0;
 if (millis()-prevMillis<1000) return; // Zeit noch nicht erreicht, Funktion abbrechen
 prevMillis+=1000;                     // addiere 1000 
 if (read_RTC_DS3231 (RTC_I2C_ADDRESS) == true)     // RTC auslesen, wenn Fehlerstatus "wahr", dann
   {
    Serial.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;
            Tag = Tag + 1;
           }
        }        
     }
 // 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 "RtcRequestEverySecond"

@Loschder

ich glaube, Du versuchst irgendwas von allen Teilen der Welt zusammenzukopieren und stellst nun fest, es funktioniert nicht. Du hast zwar oben globale Variablen definiert, verwendest aber in der Funktion immer noch Zeiger. Wenn dann mußte alles ändern und zwar richtig.

Ich sehe auch nirgends, dass die Funktion zur Sommerzeit Feststellung verwendest. Eine problematisch if Abfrage sehe ich eben so wenig.

Und was soll das werden? void dst ()

Eine Funktion namens DST gibt es doch schon.

Ich glaube, Du solltest langsamer anfangen und nicht gleich alles wild zusammenwürfeln.

Hallo Doc,

wo genau soll das hingesetzt werden???

Doc_Arduino:
jurs, da mußte nichts extra schreiben, habe ich schon getan. Geht ganz simpel. Ich poste es nochmal.

Und wenn Du diesen Code:

     if (Sommerzeit_aktiv() == true)
        {                                     // wenn Sommerzeit, dann
         Stunde = Stunde + 1;                 // Sommerzeitkorrektur   
         if (Stunde >=24) 
           {
            Stunde = 0;
            Tag = Tag + 1;
           }
        }

dann am letzten Tag des Monats in der letzten Stunde aufrufst, wird aus dem 31.03.2015 23:15 dann der 32.03.2015, beispielsweise?

Hallo,

@ Loschder: das ist eine Funktion, die kannste sonstwo hinschreiben, nur nicht in setup oder in loop. Sondern außerhalb von denen. Ich schreibe alle Funktionen unter loop.

@ jurs: upps, hast recht. Ist ein Bug, kein Feature. :slight_smile: Fiel mir noch gar nicht auf.

Doc_Arduino:
@ jurs: upps, hast recht. Ist ein Bug, kein Feature. :slight_smile: Fiel mir noch gar nicht auf.

Mit Zeitfunktionen, die "fast immer" richtig funktionieren und nur "ganz selten" Fehler produzieren, stehst Du allerdings nicht ganz alleine da. Selbst Weltfirmen wie Apple mit dem iPhone haben schon mehrmals Schlagzeilen gemacht, dass sie Zeitumstellungen und Jahreswechsel nicht richtig auf die Reihe bekommen. Kleine Auswahl:
Gute Ausrede: iPhone-Fehler lässt Nutzer ausschlafen
Fehlfunktion: iPhone-Nutzer lästern über Apples Weckerpanne
US-Sommerzeit: iPhone-Nutzer beklagen erneute Weckerpanne

So gesehen müssen Hobbyprogrammierer, die selbst etwas programmieren, eigentlich vorgewarnt sein, dass es bei Zeit- und Datumsroutinen zwar leicht passieren kann, es aber nicht ausreicht wenn die Funktionen nur "fast immer funktionieren".

BTW, jetzt fällt mir auch ein, weshalb ich vor zwei Jahren meinen EU-Sommerzeit-Dreizeiler ausgearbeitet hatte. Grund war eine Meldung hier im Forum, dass diese Library den Anfang der Sommerzeit 2013 auf das falsche Datum gelegt hat:
https://code.google.com/p/ds1307new/

Die Library hatte die Sommerzeit vorher richtig behandelt, aber in 2013 war plötzlich der Beginn der Sommerzeit um eine Woche falsch. Im März 2013 hat der Autor dieser Library, der auch hier Teilnehmer am Forum ist, dann nach Diskussion im Forum eine korrigierte Fassung veröffentlicht.

Wenn man etwas fertiges sucht, könnte man durchaus diese Library verwenden. Gravierende Fehler sind mir nicht bekannt, die funktioniert für RTC und Zeit-/Datumsberechnung, einschließlich korrekter Behandlung von EU-Sommerzeit. Allerdings kommt mir diese Library teils recht ressourcenfressend und ineffektiv programmiert vor. Wenn man also etwas direkt einsetzbares sucht, kann man die DS1307new_v1.24.zip durchaus verwenden.

Bei mir würde das allerdings deutlich anders aussehen, wenn ich vergleichbare Zeit-/Datumsroutinen schreiben würde. Ich muss ich erst nochmal überlegen, wie es gleichzeitig funktional, effektiv und leicht verwendbar gemacht werden kann. Und natürlich so, dass die Funktionen möglichst "immer" und nicht nur "fast immer" die richtige Zeit und das richtige Datum verwenden.

Hallo,

schön formuliert. :slight_smile:

Ich bin bei meinem Projekt zwar fast fertig, aber eben noch nicht ganz. Es lief schon paar Tage ohne Pause, aber eben zufällig in der Winterzeit. So fiel das Problem nicht auf. Das wäre mir erst aufgefallen wenn es fertig gewesen wäre und ich im Sommer die Logfiles ausgeschaut hätte. Dann hätte ich mich sicherlich schwer gewundert und geärgert. Danke jedenfalls für den Hinweis.

Die Nest Thermostate waren jetzt im Gespräch und negativ aufgefallen. User hat die Uhrzeit gestellt und dennnoch lief es falsch.

Wegen der 1h Problem. Mir fiele jetzt nur ein, dass man den Tag mit jeden Sommermonat vergleicht und ggf. korrigiert. Zum Glück fällt der Februar weg. :wink: Es wäre aus meiner einfachen Sichtweise nur eine größere Ansammlung von if Abfragen. Ich wette aber Du machts das eleganter mit irgendwelchen tollen Formeln. :wink:

Hallo Leute,

ja Ihr habt Recht....da wurde immer so einiges zusammen kopiert -> schlussendlich funktionierte gar nix mehr :zipper_mouth_face:

Also hab ich alles verworfen und nochmal von vorne begonnen.

Hier mal mein übersichtliches Beispiel auf welchem ich gerne aufbauen möchte(jurs boolean bereits integriert):

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib

#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 rtc;



void setup () {

  Serial.begin(9600);
#ifdef AVR
  Wire.begin();
#else
  Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due
#endif
  rtc.begin();

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
}

void loop () 
 
  {
    DateTime now = rtc.now();
    
   
  if (now.day()<10)
  {
    Serial.print("0");
  }
    Serial.print(now.day(), DEC);
    Serial.print('/');
  if (now.month()<10)
  {
    Serial.print("0");
  }
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.year(), DEC);
    Serial.print(' ');
    switch(now.dayOfWeek()){
  case 0:
    Serial.println("Sonntag");
    break;
  case 1:
    Serial.println("Montag");
    break;
  case 2:
    Serial.println("Dienstag");
    break;
  case 3:
    Serial.println("Mittwoch");
    break;
  case 4:
    Serial.println("Donnerstag");
    break;
  case 5:
    Serial.println("Freitag");
    break;
  case 6:
    Serial.println("Samstag");
    break;
  
    }
    Serial.print(' ');
    if (now.hour()<10)
    {
    Serial.print("0");
    }
    Serial.print(now.hour(), DEC);
    Serial.print(':');
     if (now.minute()<10)
    {
      Serial.print("0");
    } 
    Serial.print(now.minute(), DEC);
    Serial.print(':');
      if (now.second()<10)
    {
      Serial.print("0");
    }
    Serial.print(now.second(), DEC);
    Serial.println();
    
    Serial.print(" seit Mitternacht 01/01/1970 = ");
    Serial.print(now.unixtime());
    Serial.print("s = ");
    Serial.print(now.unixtime() / 86400L);
    Serial.println("d");
    
    
    Serial.println();
    delay(1000);

}
boolean summertime_EU(int year, byte month, byte day, byte hour, byte tzHours)
// European Daylight Savings Time calculation by "jurs" for German Arduino Forum
// input parameters: "normal time" for year, month, day, hour and tzHours (0=UTC, 1=MEZ)
// return value: returns true during Daylight Saving Time, false otherwise
{
  if (month<3 || month>10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
  if (month>3 && month<10) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
  if (month==3 && (hour + 24 * day)>=(1 + tzHours + 24*(31 - (5 * year /4 + 4) % 7)) || month==10 && (hour + 24 * day)<(1 + tzHours + 24*(31 - (5 * year /4 + 1) % 7)))
    return true;
  else
    return false;

}

Ist die Stelle für boolean summertime_EU korrekt?

Was genau is die variable tzHours? Timezone? Ist tzHours UTC=0 und MEZ=1, oder UTC=1 und MEZ=2?Oder bin ich ganz falsch?

Wenn ich nun "summertime_EU" auswerten und meine Zeit korrigiert haben möchte, kann/muss ich dies mit if Abfragen machen?

Sorry für die Fragen, aber ich verhaspel mich mit den Basics immer noch sehr...

Mfg und Danke im Voraus,
Chris

Loschder:
Was genau is die variable tzHours? Timezone?

Ja, das steht für "virtuelle Zeitzone" (timezone) in Stunden Abweichung zur UTC-Zeit.

Loschder:
Ist tzHours UTC=0 und MEZ=1, oder UTC=1 und MEZ=2?Oder bin ich ganz falsch?

Bei einer Zeitangabe in UTC ==> tzHours=0
Bei einer Zeitangabe in UTC+1 Winterzeit ==> tzHours=1
Bei einer Zeitangabe in UTC+2 Sommerzeit ==> tzHours=2

Loschder:
Wenn ich nun "summertime_EU" auswerten und meine Zeit korrigiert haben möchte, kann/muss ich dies mit if Abfragen machen?

Ja, mit if-Abfragen.

Für eine DS1307 mit 56 Bytes batteriegepuffertem RAM-Speicher stehen Dir dabei grundsätzlich zwei Strategien zur Verfügung:

  1. Sommerzeit mit tatsächlicher Uhrzeitumstellung
  2. Sommerzeit mit Umrechnung beim Auslesen

Zu 1.: Du kannst die Uhr grundsätzlich auf lokaler Zeit laufen lassen und zweimal im Jahr umstellen. Beim Stellen der Uhr vermerkst Du in einem Byte des DS1307 Uhren-RAM, ob die Zeit aktuell Sommer- oder Winterzeit ist. Und im laufenden Betrieb prüfst Du, ob die Zeit über eine Umstellszeit drüberläuft, und wenn das der Fall ist, verstellst Du die gespeicherte Uhrzeit und änderst die Speicherstelle im Uhren-RAM, in der Du speicherst, ob sie gerade auf Sommer- oder Winterzeit läuft.

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.

Ich persönlich würde Möglichkeit 2 bevorzugen, weil das weniger fehleranfällig ist und auch mit den viel genauer laufenden DS3231 Modulen funktioniert, die überhaupt kein batteriegepuffertes RAM haben. D.h. man ist mit Möglichkeit 2 bei der Hardware flexibler und auch von den Anwendungen her hat man mehr Möglichkeiten, wenn man z.B. im selben Programm UTC-Zeitangaben neben lokaler Zeit zu verwenden hat, beispielsweise bei Sonnenstandsberechnungen, für astronomische oder meteorologische Anwendungen.

Ich glaube, ich werde mich mal an ein paar eigenen RTC-Libraryfunktionen versuchen. Außer der ds1307new Library, scheint es sonst ja überhaupt keine brauchbare Alternative als "Time-Library mit EU-Sommerzeitunterstützung" zu geben.