Zeitschaltuhr: DCF77 setzt RTC (DS3231) - Arduino hängt sich regelmäßig auf

Liebe Arduino Mitstreiter,

ich habe eine Zeitschaltuhr gebaut mit Hilfe einer Echtzeituhr und einem DCF77 Empfänger. Der Arduino soll je nach Uhrzeit etwas schalten. Da dies Hochgenau geschehen soll wird die Echtzeituhr in Regelmäßigen Abständen von einer Funkuhr neu geschrieben. Dies funktioniert weitestgehend wie gewünscht. Doch leider stürzt der Arduino regelmäßig ab. So das weder die angeschlossenen LED´s blinken noch die gewünschte Umschaltung funktioniert. :frowning: Bei einem Test ist mir jetzt aufgefallen das dieses Verhalten nicht eintritt wenn die Funkuhr keinen Empfang hat. Somit die RTC nicht neu beschrieben wird. Das heißt also irgendetwas muss ich an meinem Code ändern. Eventuell könnt ihr mir ja weiterhelfen. Hier mein Programm:

#include <DCF77.h> 
#include <DS1307RTC.h> 
#include <Time.h> 
#include <Wire.h> 


#define DCF_PIN 2 
#define DCF_INTERRUPT 0       
time_t time; 
DCF77 DCF = DCF77(DCF_PIN,DCF_INTERRUPT, true); 
int ledPinStatusDCF = 6;  //DCF77 Statusanzeige
int ledPin1 = 12 ;  //LED an, gleich Relais1 zieht an
int ledPin2 = 13 ; //LED an, gleich Relais2 zieht an
int Relais1 = 3 ;   //Schaltet Radio
int Relais2 = 7 ;  //Reserve Relais wird von Pin 7 geschaltet

//------Relais 1 Von Uhrzeit1 On bis Uhrzeit1 Off----------------------------------------
int OnStunde1 = 6;
int OnMinute1 = 0;
int OffStunde1 = 6;
int OffMinute1 = 5;
//------Relais 1 Von Uhrzeit2 On bis Uhrzeit2 Off
int OnStunde2 = 6;
int OnMinute2 = 30;
int OffStunde2 = 6;
int OffMinute2 = 35;
//------Relais 1 Von Uhrzeit3 On bis Uhrzeit3 Off
int OnStunde3 = 7;
int OnMinute3 = 0;
int OffStunde3 = 7;
int OffMinute3 = 5;
//------Relais 1 Von Uhrzeit4 On bis Uhrzeit4 Off
int OnStunde4 = 7;
int OnMinute4 = 30;
int OffStunde4 = 7;
int OffMinute4 = 35;
//------Relais 1 Von Uhrzeit5 On bis Uhrzeit5 Off
int OnStunde5 = 8;
int OnMinute5 = 0;
int OffStunde5 = 8;
int OffMinute5 = 5;
//------Relais 1 Von Uhrzeit6 On bis Uhrzeit6 Off
int OnStunde6 = 8;
int OnMinute6 = 30;
int OffStunde6 = 8;
int OffMinute6 = 35;
//------Relais 1 Von Uhrzeit7 On bis Uhrzeit7 Off
int OnStunde7 = 9;
int OnMinute7 = 0;
int OffStunde7 = 9;
int OffMinute7 = 5;
//------Relais 1 Von Uhrzeit8 On bis Uhrzeit8 Off
int OnStunde8 = 9;
int OnMinute8 = 30;
int OffStunde8 = 9;
int OffMinute8 = 35;
//------Relais 1 Von Uhrzeit9 On bis Uhrzeit9 Off
int OnStunde9 = 9;
int OnMinute9 = 30;
int OffStunde9 = 9;
int OffMinute9 = 35;

//--------------------Relais1-Ende------------------------------------

//------Relais 2 Von Uhrzeit1 On bis Uhrzeit1 Off
int OnStunde1Relais2 = 11;
int OnMinute1Relais2 = 0;
int OffStunde1Relais2 = 11;
int OffMinute1Relais2 = 2;

//------Relais 2 Von Uhrzeit2 On bis Uhrzeit 2 Off
int OnStunde2Relais2 = 11;
int OnMinute2Relais2 = 6;
int OffStunde2Relais2 = 11;
int OffMinute2Relais2 = 10;
//--------------------Relais2-Ende------------------------------------



void setup() { 
 pinMode(ledPinStatusDCF, OUTPUT); 
 pinMode(ledPin1, OUTPUT); 
 pinMode(Relais1, OUTPUT);
 pinMode(Relais2, OUTPUT);
 digitalWrite(Relais2, LOW);
 //Serial.begin(9600);  
 DCF.Start(); 
 setSyncProvider(RTC.get);
 
} 
void loop() { 
  time_t DCFtime = DCF.getTime(); 
  if (DCFtime!=0) { 
    tmElements_t tm;  
    breakTime(DCFtime, tm); 
    if (RTC.write(tm)) { 
      //Serial.println("RTC erfolgreich gesetzt!");  //DCF77 Empfang gut und RTC gesetzt -> LED leuchtet für 45 Sekunden
      //digitalClockDisplay(DCFtime);       
      digitalWrite(ledPinStatusDCF, HIGH); 
      delay(55000); 
      digitalWrite(ledPinStatusDCF, LOW); 
    } else { 
      delay(500);  
    }  
  } else { 
    digitalWrite(ledPinStatusDCF, HIGH);     //Fehler bei DCF77 Empfang -> LED blinkt
    delay(250); 
    digitalWrite(ledPinStatusDCF, LOW);   
    delay(250); 
  }

time_t t = now();
int aktminute=minute(t); //aktuelle Minute setzen
int akthour=hour(t); //aktuelle Stunde setzen


if ((akthour == OnStunde1)&&(aktminute==OnMinute1))
{
 digitalWrite(ledPin1, HIGH);
 digitalWrite(Relais1, HIGH);
}


if ((akthour == OffStunde1)&&(aktminute==OffMinute1))
{
 digitalWrite(ledPin1, LOW);
 digitalWrite(Relais1, LOW);
}
 
if ((akthour == OnStunde2)&&(aktminute==OnMinute2))
{
 digitalWrite(ledPin1, HIGH);
 digitalWrite(Relais1, HIGH);
}

if ((akthour == OffStunde2)&&(aktminute==OffMinute2))
{
 digitalWrite(ledPin1, LOW);
 digitalWrite(Relais1, LOW);
}
if ((akthour == OnStunde3)&&(aktminute==OnMinute3))
{
 digitalWrite(ledPin1, HIGH);
 digitalWrite(Relais1, HIGH);
}

if ((akthour == OffStunde3)&&(aktminute==OffMinute3))
{
 digitalWrite(ledPin1, LOW);
 digitalWrite(Relais1, LOW);
}
if ((akthour == OnStunde4)&&(aktminute==OnMinute4))
{
 digitalWrite(ledPin1, HIGH);
 digitalWrite(Relais1, HIGH);
}

if ((akthour == OffStunde4)&&(aktminute==OffMinute4))
{
 digitalWrite(ledPin1, LOW);
 digitalWrite(Relais1, LOW);
}

if ((akthour == OnStunde5)&&(aktminute==OnMinute5))
{
 digitalWrite(ledPin1, HIGH);
 digitalWrite(Relais1, HIGH);
}

if ((akthour == OffStunde5)&&(aktminute==OffMinute5))
{
 digitalWrite(ledPin1, LOW);
 digitalWrite(Relais1, LOW);
}
if ((akthour == OnStunde6)&&(aktminute==OnMinute6))
{
 digitalWrite(ledPin1, HIGH);
 digitalWrite(Relais1, HIGH);
}

if ((akthour == OffStunde6)&&(aktminute==OffMinute6))
{
 digitalWrite(ledPin1, LOW);
 digitalWrite(Relais1, LOW);
}
if ((akthour == OnStunde7)&&(aktminute==OnMinute7))
{
 digitalWrite(ledPin1, HIGH);
 digitalWrite(Relais1, HIGH);
}

if ((akthour == OffStunde7)&&(aktminute==OffMinute7))
{
 digitalWrite(ledPin1, LOW);
 digitalWrite(Relais1, LOW);
}

if ((akthour == OnStunde8)&&(aktminute==OnMinute8))
{
 digitalWrite(ledPin1, HIGH);
 digitalWrite(Relais1, HIGH);
}

if ((akthour == OffStunde8)&&(aktminute==OffMinute8))
{
 digitalWrite(ledPin1, LOW);
 digitalWrite(Relais1, LOW);
}

if ((akthour == OnStunde9)&&(aktminute==OnMinute9))
{
 digitalWrite(ledPin1, HIGH);
 digitalWrite(Relais1, HIGH);
}

if ((akthour == OffStunde9)&&(aktminute==OffMinute9))
{
 digitalWrite(ledPin1, LOW);
 digitalWrite(Relais1, LOW);
}



if ((akthour == OnStunde1Relais2)&&(aktminute==OnMinute1Relais2))
{
 digitalWrite(ledPin2, HIGH);
 digitalWrite(Relais2, HIGH);
}

if ((akthour == OffStunde1Relais2)&&(aktminute==OffMinute1Relais2))
{
 digitalWrite(ledPin2, LOW);
 digitalWrite(Relais2, LOW);
}

if ((akthour == OnStunde2Relais2)&&(aktminute==OnMinute2Relais2))
{
 digitalWrite(ledPin2, HIGH);
 digitalWrite(Relais2, HIGH);
}

if ((akthour == OffStunde2Relais2)&&(aktminute==OffMinute2Relais2))
{
 digitalWrite(ledPin2, LOW);
 digitalWrite(Relais2, LOW);
}
 }
 
  
 
//// Hilfsfunktion für serielle Ausgabe 
//void digitalClockDisplay(time_t _time){ 
//  tmElements_t tm;    
//  breakTime(_time, tm); 
//  Serial.println(""); 
//  Serial.print("Zeit: "); Serial.print(tm.Hour); 
//  Serial.print(":"); printDigits(tm.Minute); 
//  Serial.print(":"); printDigits(tm.Second); 
//  Serial.print(" Datum: "); Serial.print(tm.Day); 
//  Serial.print("."); Serial.print(tm.Month); 
//  Serial.print("."); Serial.println(tm.Year+1970); 
//} 
//// Hilfsfunktion für Formatierung 
//void printDigits(int digits){ 
//  Serial.print(":"); 
//  if(digits < 10) 
//    Serial.print('0'); 
//  Serial.print(digits); 
//}

Die LED an Pin 6 leuchtet 45 Sekunden sobald ein verwertbares Zeitsignal empfangen wird und die RTC gesetzt wird. Falls kein Zeitsignal empfangen wird und die RTC nicht gesetzt werden konnte, blinkt die LED im Viertelsekundentakt.

Viele Grüße,
DaHu

Du schreibst, das Schalten soll "hochgenau" ablaufen, arbeitest aber in deinem Sketch mit zahlreichen und teilweise auch sehr langen delays. Das passt absolut nicht zusammen.

Während dieser delays mach der Controller nichts außer warten.

Ersetze die delays durch eine Funktion mit millis. Sieh dir dazu das Beispiel "BlinkWithoutDelay" an.

Ok, das schau ich mir nocheinmal an. Wird aber das Problem nicht lösen.

Das Hochgenau ist sicher falsch formuliert. Ich meinte eher das es nach den Zeitumstellungen schnell wieder genau funktioneirt.

VG

DaHu:
Ok, das schau ich mir nocheinmal an. Wird aber das Problem nicht lösen.

Nur genau da wo dein Problem auftreten soll, hast du ein Delay von 55 Sek.

Wird aber das Problem nicht lösen.

Ich vermute wie HotSystems ebenfalls, dass genau an der Stelle das Problem sitzt. Es werden zwar Daten vom DCF gelesen, aber das Programm hat gar keine Chance diese auszuwerten. Statt dessen wird es gezwungen sich Schlafen zu legen. Ich denke, das muss an der Stelle ganz anders gelöst werden.

Man könnte das so formulieren. Testen kann ich es wegen fehlendem DCF77 nicht.

#include <DCF77.h>
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>

class aSetting {
  public:
    byte onStunde;
    byte onMinute;
    byte offStunde;
    byte offMinute;
    aSetting(byte onStd, byte onMin, byte offStd, byte offMin) {
      onStunde = onStd;
      onMinute = onMin;
      offStunde = offStd;
      offMinute = offMin;
    }
    bool isOn(byte aktStd, byte aktMin) {
      return ((onStunde == aktStd) && (onMinute == aktMin));
    }
    bool isOff(byte aktStd, byte aktMin) {
      return ((offStunde == aktStd) && (offMinute == aktMin));
    }
};

#define DCF_PIN 2
#define DCF_INTERRUPT 0
time_t time;
DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT, true);
const byte ledPinStatusDCF = 6;  //DCF77 Statusanzeige
const byte ledPin1 = 12 ;  //LED an, gleich Relais1 zieht an
const byte ledPin2 = 13 ; //LED an, gleich Relais2 zieht an
const byte Relais1 = 3 ;   //Schaltet Radio
const byte Relais2 = 7 ;  //Reserve Relais wird von Pin 7 geschaltet

aSetting r1Alarms[] = {
  aSetting( 6, 0, 6, 5),
  aSetting( 6, 30, 6, 35),
  aSetting( 7, 0, 7, 5),
  aSetting( 7, 30, 7, 35),
  aSetting( 8, 0, 8, 5),
  aSetting( 8, 30, 8, 35),
  aSetting( 9, 0, 9, 5),
  aSetting( 9, 30, 9, 35),
};

aSetting r2Alarms[] = {
  aSetting(11, 0, 11, 2),
  aSetting(11, 6, 11, 10),
};

void setup() {
  pinMode(ledPinStatusDCF, OUTPUT);
  pinMode(ledPin1, OUTPUT);
  pinMode(Relais1, OUTPUT);
  pinMode(Relais2, OUTPUT);
  digitalWrite(Relais2, LOW);
  //Serial.begin(9600);
  DCF.Start();
  setSyncProvider(RTC.get);

}
unsigned long letzterEmpfang;
unsigned long letztesBlinken;
bool blinkLed;

void loop() {
  static byte prevMinute = 99;
  unsigned long topLoop = millis();
  time_t DCFtime = DCF.getTime();
  if (DCFtime != 0) {
    tmElements_t tm;
    breakTime(DCFtime, tm);
    if (RTC.write(tm)) {
      //Serial.println("RTC erfolgreich gesetzt!");  //DCF77 Empfang gut und RTC gesetzt -> LED leuchtet für 45 Sekunden
      //digitalClockDisplay(DCFtime);
      letzterEmpfang = topLoop;
      blinkLed = false;
      digitalWrite(ledPinStatusDCF, HIGH);
    }
  } else {
    blinkLed = true;
    digitalWrite(ledPinStatusDCF, HIGH);
  }
  if (blinkLed) {
    if (topLoop - letztesBlinken >= 250) {
      digitalWrite(ledPinStatusDCF, !digitalRead(ledPinStatusDCF));
      letztesBlinken = topLoop;
    }
  } else if (topLoop - letzterEmpfang > 45000) {
    digitalWrite(ledPinStatusDCF, LOW);
  }
  time_t t = now();
  byte aktMinute = minute(t); //aktuelle Minute setzen
  byte aktStunde = hour(t); //aktuelle Stunde setzen

  if (aktMinute != prevMinute) {
    prevMinute = aktMinute;
    for (byte idx = 0; idx < sizeof(r1Alarms) / sizeof(r1Alarms[0]); idx++) {
      if (r1Alarms[idx].isOn(aktStunde, aktMinute)) {
        digitalWrite(ledPin1, HIGH);
        digitalWrite(Relais1, HIGH);
        break;
      }
      if (r1Alarms[idx].isOff(aktStunde, aktMinute)) {
        digitalWrite(ledPin1, LOW);
        digitalWrite(Relais1, LOW);
        break;
      }
    }
    for (byte idx = 0; idx < sizeof(r2Alarms) / sizeof(r2Alarms[0]); idx++) {
      if (r1Alarms[idx].isOn(aktStunde, aktMinute)) {
        digitalWrite(ledPin2, HIGH);
        digitalWrite(Relais2, HIGH);
        break;
      }
      if (r1Alarms[idx].isOff(aktStunde, aktMinute)) {
        digitalWrite(ledPin2, LOW);
        digitalWrite(Relais2, LOW);
        break;
      }
    }
  }
}

Danke HotSystems und RudiDL5 für die Hinweise und die Erklärung.

Wow Whandall,
du hast dir ja eine Mega Arbeit gemacht. Ich werde es passend einarbeiten und testen. Ich melde mich wenn das geschehen ist und es läuft.

Ich bin ziemlich sicher dass es zumindestens ansatzweise funktioniert.

In deinem Original hattest du eine Schaltzeit doppelt (die neunte von Relay1) und ich denke du hattest vergessen zu berücksichtigen, dass die Aktionen immer nur bei den Minutenwechseln wirklich sinnvoll sind.

DaHu:
Hier mein Programm:

Bist Du Dir eigentlich vollständig im klaren darüber, mit wie vielen verschiedenen Zeiten Dein Programm herrumfuhrwerkt und welche Zeit mit welcher anderen Zeit wie synchronisiert wird?

Also aus Deinen verwendeten Libraries würde ich vermuten, dass Du mit DREI verschiedenen Zeiten hantierst:

  1. Mit einer “Systemzeit”, die von der inkludierten <Time.h> Library verwaltet wird
  2. Mit einer “RTC-Zeit”, die von der inkludierten <DS1307RTC.h> Library UND zusätzlich auch noch von Deinem loop-Code verwaltet wird
  3. Mit einer “DCF77-Zeit”, die von der inkludierten <DCF77.h> Library verwaltet wird

Bist Du sicher, dass Du bei drei verschiedenen Zeiten im Programm und mit deren Synchronisierung untereinander noch den vollen Überblick hast?

Dein Code sieht für mich sehr fragwürdig aus.

Hallo @all,

Dank Whandall hab ich eine funktionierende Zeitschaltuhr die von einer Funkuhr synchronsiert wird.

Leider habe ich noch ein Problem mit der LED an Pin 6 (ledPinStatusDCF) die die Empfangssitutaion anzeigen soll.

Diese leuchtet sofort nach dem Einschalten. Weder beim Syncronisieren noch bei nicht angeschlossenem DCF Emüpfänger blinkt sie.

Ich habe einiges versucht allerdings finde ich den Fehler einfach nicht.

#include <DCF77.h>
#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>

class aSetting {
  public:
    byte onStunde;
    byte onMinute;
    byte offStunde;
    byte offMinute;
    aSetting(byte onStd, byte onMin, byte offStd, byte offMin) {
      onStunde = onStd;
      onMinute = onMin;
      offStunde = offStd;
      offMinute = offMin;
    }
    bool isOn(byte aktStd, byte aktMin) {
      return ((onStunde == aktStd) && (onMinute == aktMin));
    }
    bool isOff(byte aktStd, byte aktMin) {
      return ((offStunde == aktStd) && (offMinute == aktMin));
    }
};

#define DCF_PIN 2
#define DCF_INTERRUPT 0
time_t time;
DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT, true);
const byte ledPinStatusDCF = 6;  //DCF77 Statusanzeige
const byte ledPin1 = 12 ;  //LED an, gleich Relais1 zieht an
const byte ledPin2 = 13 ; //LED an, gleich Relais2 zieht an
const byte Relais1 = 3 ;   //Schaltet Radio
const byte Relais2 = 7 ;  //Reserve Relais wird von Pin 7 geschaltet

aSetting r1Alarms[] = {
  aSetting( 6, 0, 6, 5),
  aSetting( 6, 30, 6, 35),
  aSetting( 7, 0, 7, 5),
  aSetting( 7, 30, 7, 35),
  aSetting( 8, 0, 8, 5),
  aSetting( 8, 30, 8, 35),
  aSetting( 9, 0, 9, 5),
  aSetting( 9, 30, 9, 35),
};

aSetting r2Alarms[] = {
  aSetting(11, 0, 11, 2),
  aSetting(11, 6, 11, 10),
};

void setup() {
  pinMode(ledPinStatusDCF, OUTPUT);
  pinMode(ledPin1, OUTPUT);
  pinMode(Relais1, OUTPUT);
  pinMode(Relais2, OUTPUT);
  digitalWrite(Relais2, LOW);
  //Serial.begin(9600);
  DCF.Start();
  setSyncProvider(RTC.get);

}
unsigned long letzterEmpfang;
unsigned long letztesBlinken;
bool blinkLed;

void loop() {
  static byte prevMinute = 99;
  unsigned long topLoop = millis();
  time_t DCFtime = DCF.getTime();
  if (DCFtime != 0) {
    tmElements_t tm;
    breakTime(DCFtime, tm);
    if (RTC.write(tm)) {
      //Serial.println("RTC erfolgreich gesetzt!");  //DCF77 Empfang gut und RTC gesetzt -> LED leuchtet für 45 Sekunden
      //digitalClockDisplay(DCFtime);
      letzterEmpfang = topLoop;
      blinkLed = false;
      digitalWrite(ledPinStatusDCF, HIGH);
    }
  } else {
    blinkLed = true;
    digitalWrite(ledPinStatusDCF, HIGH);
  }

  if (blinkLed==true) {
    if (topLoop - letztesBlinken >= 250) {
      digitalWrite(ledPinStatusDCF, !digitalRead(ledPinStatusDCF));
      letztesBlinken = topLoop;
    }
  } else if (topLoop - letzterEmpfang > 45000) {
    digitalWrite(ledPinStatusDCF, LOW);
  }
  time_t t = now();
  byte aktMinute = minute(t); //aktuelle Minute setzen
  byte aktStunde = hour(t); //aktuelle Stunde setzen

  if (aktMinute != prevMinute) {
    prevMinute = aktMinute;
    for (byte idx = 0; idx < sizeof(r1Alarms) / sizeof(r1Alarms[0]); idx++) {
      if (r1Alarms[idx].isOn(aktStunde, aktMinute)) {
        digitalWrite(ledPin1, HIGH);
        digitalWrite(Relais1, HIGH);
        break;
      }
      if (r1Alarms[idx].isOff(aktStunde, aktMinute)) {
        digitalWrite(ledPin1, LOW);
        digitalWrite(Relais1, LOW);
        break;
      }
    }
    for (byte idx = 0; idx < sizeof(r2Alarms) / sizeof(r2Alarms[0]); idx++) {
      if (r1Alarms[idx].isOn(aktStunde, aktMinute)) {
        digitalWrite(ledPin2, HIGH);
        digitalWrite(Relais2, HIGH);
        break;
      }
      if (r1Alarms[idx].isOff(aktStunde, aktMinute)) {
        digitalWrite(ledPin2, LOW);
        digitalWrite(Relais2, LOW);
        break;
      }
    }
  }
}

Ich hoffe auf eure erneute Unterstützung.
VG DaHu

DaHu:
Ich habe einiges versucht allerdings finde ich den Fehler einfach nicht.

Für mich sieht es so aus, als wenn Du in Deiner loop()-Funktion mindestens zwei Variablen verwendest, die tatsächlich bei jedem Neustart der loop einen unbestimmten und eher zufälligen Wert haben, den sie vom aktuellen Zustand des RAM und den Werten auf dem Stack erhalten :

unsigned long letzterEmpfang;
unsigned long letztesBlinken;

aber Du scheinst vermutlich davon auszugehen, dass diese beiden Variablen zwischen den loop-Durchläufen ihren Wert beibehalten, den sie jeweils zuletzt zugewiesen bekommen haben.
Aber dafür, dass diese Werte "statisch bleiben und zwischen zwei loop()-Durchläufen den jeweils zuletzt zugewiesenen Wet behalten, müßten diese Variablen 'static deklariert' sein, also so:

static unsigned long letzterEmpfang;
static unsigned long letztesBlinken;