Zeitschaltuhr mit DS3231 aufbauen, ich komme nicht weiter

Hallo zusammen,

ich möchte mit einem UNO und einer DS3231 RTC eine Zeitschaltuhr aufbauen (in einer späteren Version mit mehreren Schaltkanälen).

Die RTC habe ich zum laufen gebracht und kann mir die Zeit an einem LCD anzeigen lassen.

Nun möchte ich zu bestimmten Schaltzeiten einen Ausgang ein und später wieder ausschalten.

Leider finde ich weder hier im Forum noch in den Weiten des Netzes eine brauchbare Lösung.

Mein bisheriger Sketch sieht wie folgt aus:

#include <LiquidCrystal_I2C.h>
#include "Wire.h"
#define ADDR_RTCDS3231 0x68
LiquidCrystal_I2C lcd(0x27,16,2);               // Definition Adresse auf 0x27, Display auf 16 Zeichen und 2 Zeilen festlegen

byte decToBcd(byte val) {  return( (val/10*16) + (val%10) );  }
byte bcdToDec(byte val)  {  return( (val/16*10) + (val%16) ); }

int Licht = 13;
int Lichtstunde = 17;
int Lichtminute = 00;

long Lichtdauer = 18000;
long Laufzeit = 0;

void displayTime()
{
  byte second, minute, hour;
  char sbuf[50];
  
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour);
    
  sprintf(sbuf, "%02d:%02d:%02d", hour, minute, second);
  Serial.print(sbuf);
  lcd.setCursor(0, 0);
  lcd.print(sbuf);
  }

void setDS3231time(byte second, byte minute, byte hour)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(ADDR_RTCDS3231);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.endTransmission();
}

void readDS3231time(byte *second,
     byte *minute,
     byte *hour)
{
  Wire.beginTransmission(ADDR_RTCDS3231);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(ADDR_RTCDS3231, 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);
  }

void setup() {
  pinMode(Licht, OUTPUT);
  lcd.begin();  // init LCD 1602
  Wire.begin();
  
  // DS3231 seconds, minutes, hours, day, date, dmonth, dyear
  // setDS3231time(00,00,20, 3,  22,07,15);  // (3 == )Mittwoch, 20:00:00 Uhr 22.07.15
}
void loop() {
  displayTime(); // display the real-time clock data on Monitor + LCD,

}

Mein Denkansatz ist, dass ich Variablen für die Schaltzeiten definiere, z.B. so:

int startstunde = 17;
int startminute = 00;
int startsekunde = 00;
int stopstunde = 18;
int stopminute = 00;
int stopsekunde = 00;

dann würde ich einen Vergleich zwischen Schaltzeiten und der aktuellen Zeit durchführen und dadurch eine Aktion durchführen:

// Start Ausgang
  if ("RTC-Stunde" == startstunde && "RTC-Minute" == startminute && "RTC-Sekunde" == startsekunde)
  {
    digitalWrite("Ausgang", HIGH);

Fürs Ausschalten würde ich dann analog dazu vorgehen.
Gegebenenfalls würde ich die Sekunden nicht in den Vergleich aufnehmen, da der Ausgang nur auf die Minute genau gesteuert werden muss.

Wie bekomme ich die Werte für "RTC-Stunde", "RTC-Minute" und "RTC-Sekunde" in Variablen, die ich dann nach meinem Beispiel oben vergleichen kann?

Oder bin ich total auf dem Holzweg?

In displayTime() sehe ich byte second, minute, hour;, da hast Du Deine Variablen. Nach dem Schema kannst Du eine eigene Funktion erstellen.

Chris779:
Nun möchte ich zu bestimmten Schaltzeiten einen Ausgang ein und später wieder ausschalten.

Leider finde ich weder hier im Forum noch in den Weiten des Netzes eine brauchbare Lösung.

Einen Zeitschaltuhr-Sketch habe ich hier mal als reply #22 gepostet:
http://forum.arduino.cc/index.php?topic=192958.msg1753355#msg1753355

Der Sketch is vorbereitet zum Schalten von drei verschiedene Ausgängen mit jeweils bis zu vier minutengenauen Ein- und Ausschaltzeiten pro Tag, sowie einem programmierbaren Kurzzeittimer, der nur sekundenweise schalten soll.

Ausgabe ist im Beispielcode nur für Serial, aber das läßt sich natürlich leicht um eine Ausgabe auf LCD erweitern.

agmue:
In displayTime() sehe ich byte second, minute, hour;, da hast Du Deine Variablen. Nach dem Schema kannst Du eine eigene Funktion erstellen.

second, minute und hour sind ja als "Byte" deklariert, muss ich dann meine Schaltzeiten auch als "Byte" deklarieren, oder muss man das umrechnen?

Chris779:
second, minute und hour sind ja als "Byte" deklariert, muss ich dann meine Schaltzeiten auch als "Byte" deklarieren, oder muss man das umrechnen?

byte startstunde, startminute, startsekunde;

if ("RTC-Stunde" == startstunde && "RTC-Minute" == startminute && "RTC-Sekunde" == startsekunde)

Die Variablen sind ja im Bereich bis 59 bzw. 23, da ist Byte ausreichend. Oder zielt Deine Frage in eine andere Richtung?

Nein, das hat gepasst.
ich habe die Istzeit als:

int Iststunde;
int Istminute;
int Istsekunde;

deklariert und im void displayTime

 Iststunde = hour;
 Istminute = minute;
 Istsekunde = second;

verknüpft, jetzt kann ich im loop mit

// Start Licht
  if (Iststunde == Lichteinstunde && Istminute == Lichteinminute )
  {
    digitalWrite(Licht, HIGH);
  }
// Stop Licht
  if (Iststunde >= Lichtausstunde && Istminute >= Lichtausminute )
  {
    digitalWrite(Licht, LOW);
    }

den Eingang "Licht" mit den Schaltzeizen ein und aus schalten.

Ich überlege gerade ob ich die Schaltbedingungen anstatt mit "==" mit ">=" bzw. "<=" verknüpfen soll?
Falls ich während der Schaltzeit einen Sromausfall habe ist der Schaltzustand ja undefiniert weil weder die eine noch die andere Bedingung mit "==" erfüllt ist.

Dann müsste ich die Schaltbedingungen aber doppelt verschachtelt abfragen, also bei der Einschaltzeit

"Istzeit >= Einschaltzeit && <= Ausschaltzeit" jeweils für Stunde, Minute und Sekunde?

int Iststunde;
int Istminute;
int Istsekunde;

Warum Integer? Das ist eine vorzeichenbehaftete Zahl bis 32767 (8 Bit Prozessor), was willst Du damit?

Chris779:
Ich überlege gerade ob ich die Schaltbedingungen anstatt mit "==" mit ">=" bzw. "<=" verknüpfen soll?

Auf Unix-Rechner gibt es die Zeit in Sekunden ab einem Datum. Damit kann man schön Relationen verwenden. Sowas müßtest Du Dir auch bauen. Möglicherweise gibt es eine Bibliothek dafür oder jurs hat eine Lösung im Ärmel.

agmue:

int Iststunde;

int Istminute;
int Istsekunde;


Warum Integer?

Wie soll ich sie dann benennen? ist hier "byte" die richtige Definition?

Auf Unix-Rechner gibt es die Zeit in Sekunden ab einem Datum. Damit kann man schön Relationen verwenden. Sowas müßtest Du Dir auch bauen. Möglicherweise gibt es eine Bibliothek dafür oder jurs hat eine Lösung im Ärmel.

Ich habe es mit

// Start Licht
  if ((Lichteinstunde >= Iststunde <=Lichtausstunde)    && (Lichteinminute >= Iststunde <=Lichtausstunde)  )
  {
    digitalWrite(Licht, HIGH);
  }
// Stop Licht
  if (Iststunde >= Lichtausstunde && Istminute >= Lichtausminute )
  {
    digitalWrite(Licht, LOW);
    }
[/quote]
probiert. Das scheint zu funktionieren, zumindest wenn ich die Stromversorgung zwischen den Schaltzeiten trenne.

Lichteinstunde = 15
Iststunde = 17
Lichtausstunde = 20

(15 >= 17 <= 20) == false :frowning:

Ich meinte beispielsweise ( ( ( ( ( ( ( year * 12 ) + month ) * 30 ) + date ) * 24 ) + hours ) * 60 ) + minutes, wobei month * 30 durch eine Funktion zu ersetzen wäre, die die variable Monatslänge im Jahr unter Berücksichtigung der Schaltjahre berechnet.

Die Time Bibliothek kann ein Datum in Unix-Zeit umrechnen

agmue:
Lichteinstunde = 15
Iststunde = 17
Lichtausstunde = 20

(15 >= 17 <= 20) == false :frowning:

Wie ist es dann richtig, und warum funktioniert es bei meinem Versuchsaufbau trotzdem???

Ich meinte beispielsweise ( ( ( ( ( ( ( year * 12 ) + month ) * 30 ) + date ) * 24 ) + hours ) * 60 ) + minutes, wobei month * 30 durch eine Funktion zu ersetzen wäre, die die variable Monatslänge im Jahr unter Berücksichtigung der Schaltjahre berechnet.

Ich kann dir nicht folgen, wozu brauche ich das bei meinem Beispiel, wenn nur die Stunde und die Minute abgefragt werden? Jahr, Monat, Tag, etc werden gar nicht ausgewertet?!

Serenifly:
Die Time Bibliothek kann ein Datum in Unix-Zeit umrechnen

Wofür brauche ich die Unix-Zeit? (bitte nicht falsch verstehen, ich bin Anfänger...)
Wenn ich nicht total daneben liege mache ich hier eigentlich nichts anderes als Zahlenkombinationen zu vergleichen?!

Wofür brauche ich die Unix-Zeit?

wenn deine Schaltzeiten über 24 Uhr hinausgehen

Hallo,

entweder nimmst die Mega Multi Funktion von jurs, Hut ab was er da programmiert hat.

Oder, wenn es keinen Tagesüberlauf gibt, kannste das vielleicht auch so lösen.

void Zeitintervall ()
{   
    static byte alter_Zeitbereich = 0;
    byte Zeitbereich = 0;  // default
    
    if ( _Stunde == 21 && _Minute <= 30 ) {   // zwischen 21:00 - 21:30 Uhr
      Zeitbereich = 3;   
    } 
    if ( _Stunde == 13 && _Minute <= 30 ) {   // zwischen 13:00 - 13:30 Uhr
      Zeitbereich = 2;   
    }  
    if ( _Stunde ==  5 && _Minute <= 30 ) {   // zwischen 05:00 - 05:30 Uhr
      Zeitbereich = 1;   
    }      
    switch (Zeitbereich)  { 
       case 1 :  ... Aktion ...  ; break;  
       case 2 :  ... Aktion ...  ; break;
       case 3 :  ... Aktion ...  ; break;
      default :  ... Aktion ...  ;    
    }   
}