Timer Steuerung (Zeitschaltuhr) mit RTC Modul

Hi Leute,

ich habe ein Programm für ein automatisiertes Mini-Gewächshaus geschrieben.
Vor ein paar Jahren habe ich das gleiche schon mal am Raspberry Pi gemacht. Nun dachte ich aber, dass sich der Arduino eigentlich sogar etwas besser dazu eignet... Ich bin absoluter Anfänger was Arduino und C++ angeht, aber ich fuchs mich durch. Es gibt noch ein paar Dinge zutun aber die wichtigsten Dinge funktionieren schon mal...

Ich habe jetzt folgendes Problem:
Ich möchte Lüfter im Gewächshaus über eine Zeitsteuerung aktivieren und deaktivieren. Es soll also möglich sein, einzustellen wie lange die Lüfter aktiv sein sollen z.B. 12 Minuten und über einen zweiten Wert, wie lange der Lüfter anschließend inaktiv bleiben soll, z.B. 31 Minuten.
Ich nutze ein RTC- Modul DS3231 mit der RTClib Bibliothek.

Ich hab die letzte 4 Stunden so viele Sachen ausprobiert (Schnipsel von anderen kopiert und bei mir eingebaut) - alle haben nicht so funktioniert wie ich es mir wünsche. Ich stehe also irgendwie immer noch bei Null :frowning:

Kann mir hier vielleicht jemand helfen?

#include <DHT.h>                           // DHT Bibliothek laden
#include "RTClib.h"                        // RTC-Libary laden

#define DHTPIN 4                           // Der DHT-Sensor wird an PIN 4 angeschlossen    
#define DHTTYPE DHT22                      // Es handelt sich um den DHT22 Sensor

#define PIN_RELAY2_LUFT 10                 // Lüfter

DHT dht(DHTPIN, DHTTYPE);                  // Der Sensor wird ab jetzt mit „dth“ angesprochen
RTC_DS3231 rtc;

int luefter_steuerung = 1;                 // Lüftersteuerung nach Luftfeuchtigkeit = 0, Lüftersteuerung nach Zeitschaltuhr = 1
int luftfeuchte_max = 90;                  // Maximale Luftfeuchtigkeit ueber derer die Luefter zum trocknen einschalten sollen (Bedingung: Lüftersteuerung = 0)
int luefter_aktiv = 12;
int luefter_inaktiv = 31;

void setup(void)
{
    Serial.begin(9600);                                 // Start serieller Monitor
    dht.begin();                                        // DHT22 Sensor starten  

    rtc.begin();                                        // RTC Modul starten
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));     // Aktuelle PC-Uhrzeit übernehmen
    
    pinMode(PIN_RELAY2_LUFT, OUTPUT);                   // Pin an Relais 2 auf Ausgabe stellen
    digitalWrite(PIN_RELAY2_LUFT, HIGH);                // Pin an Telais 2 zu Beginn ausschalten   
}


void loop(void){

    DateTime now = rtc.now();                                                         // Uhrzeit über RTC Modul abfragen
    
    float DHT_Luftfeuchtigkeit = dht.readHumidity();                                  // die Luftfeuchtigkeit auslesen und definieren als „DHT_Luftfeutchtigkeit“
    float DHT_Temperatur = dht.readTemperature();                                     // die Temperatur auslesen und definieren als „DHT_Temperatur“

    if (luefter_steuerung == 0 && DHT_Luftfeuchtigkeit >= luftfeuchte_max) {          // Wenn Luftfeuchtigkeit höher max. Grenzwert, dann
      digitalWrite(PIN_RELAY2_LUFT, LOW);                                             // Relais 2 (Lüfter) einschalten
      Serial.println("Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN");  // serielle Monitor Ausgabe: "Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN"
    } 
    else if (luefter_steuerung == 0) {                                                 // Sonst noch wenn
      digitalWrite(PIN_RELAY2_LUFT, HIGH);                                            // Relais 2 (Lüfter) ausschalten
      Serial.println("Luftfeuchtigkeit UND Bodentemperatur OK");                      // serielle Monitor Ausgabe: "Luftfeuchtigkeit UND Bodentemperatur OK"   
      }

    
    if (luefter_steuerung == 1 && XXXXXXXXXXX) {
      digitalWrite(PIN_RELAY2_LUFT, LOW);                                                                 // Relais 2 (Lüfter) einschalten
      Serial.println("Zeitsteuerung: Lüfter EIN");                                                        // serielle Monitor Ausgabe: "Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN"
    } 
    else (luefter_steuerung == 1 && XXXXXXXXXXX) {                                                        // Sonst wenn
      digitalWrite(PIN_RELAY2_LUFT, HIGH);                                                                // Relais 2 (Lüfter) ausschalten
      Serial.println("Zeitsteuerung: Lüfter AUS");                                                        // serielle Monitor Ausgabe: "Luftfeuchtigkeit UND Bodentemperatur OK"
    }
                                                    
      }

    delay(2000);                                                                      // Pause (2000 = 2 Sekunden)
}

Vielen Dank :slight_smile:

PS: der Code hier ist stark eingekürzt

#include <DHT.h>                           // DHT Bibliothek laden
#include "RTClib.h"                        // RTC-Libary laden

#define DHTPIN 4                           // Der DHT-Sensor wird an PIN 4 angeschlossen    
#define DHTTYPE DHT22                      // Es handelt sich um den DHT22 Sensor

#define PIN_RELAY2_LUFT 10                 // Lüfter

DHT dht(DHTPIN, DHTTYPE);                  // Der Sensor wird ab jetzt mit „dth“ angesprochen
RTC_DS3231 rtc;

bool luefter_steuerung = true;                 // Lüftersteuerung nach Luftfeuchtigkeit = 0, Lüftersteuerung nach Zeitschaltuhr = 1
const byte luftfeuchte_max = 90;                  // Maximale Luftfeuchtigkeit ueber derer die Luefter zum trocknen einschalten sollen (Bedingung: Lüftersteuerung = 0)
const uint16_t luefter_aktiv = 12;
const uint16_t luefter_inaktiv = 31;
bool isActive = false;

void setup(void) {
  Serial.begin(9600);                                 // Start serieller Monitor
  dht.begin();                                        // DHT22 Sensor starten

  rtc.begin();                                        // RTC Modul starten
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));     // Aktuelle PC-Uhrzeit übernehmen

  pinMode(PIN_RELAY2_LUFT, OUTPUT);                   // Pin an Relais 2 auf Ausgabe stellen
  digitalWrite(PIN_RELAY2_LUFT, HIGH);                // Pin an Telais 2 zu Beginn ausschalten
}

void loop(void) {
  DateTime now = rtc.now();                                                         // Uhrzeit über RTC Modul abfragen
  float DHT_Luftfeuchtigkeit = dht.readHumidity();                                  // die Luftfeuchtigkeit auslesen und definieren als „DHT_Luftfeutchtigkeit“
  float DHT_Temperatur = dht.readTemperature();                                     // die Temperatur auslesen und definieren als „DHT_Temperatur“
  if (!luefter_steuerung) {
    if ( DHT_Luftfeuchtigkeit >= luftfeuchte_max) {          // Wenn Luftfeuchtigkeit höher max. Grenzwert, dann
      digitalWrite(PIN_RELAY2_LUFT, LOW);                                             // Relais 2 (Lüfter) einschalten
      Serial.println("Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN");  // serielle Monitor Ausgabe: "Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN"
    }
    else  {                                                 // Sonst noch wenn
      digitalWrite(PIN_RELAY2_LUFT, HIGH);                                            // Relais 2 (Lüfter) ausschalten
      Serial.println("Luftfeuchtigkeit UND Bodentemperatur OK");                      // serielle Monitor Ausgabe: "Luftfeuchtigkeit UND Bodentemperatur OK"
    }
  }
  else {
    static uint16_t Abwarten = 0;
    uint16_t MinutenZahl = now.hour() * 60 + now.minute();
    if (MinutenZahl - Abwarten >= luefter_inaktiv && !isActive) {
      Abwarten += luefter_aktiv;
      digitalWrite(PIN_RELAY2_LUFT, LOW);                                                                 // Relais 2 (Lüfter) einschalten
      Serial.println("Zeitsteuerung: Lüfter EIN");                                                        // serielle Monitor Ausgabe: "Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN"
    }
    if (MinutenZahl - Abwarten >= luefter_aktiv && isActive) {
      Abwarten += luefter_inaktiv;
      digitalWrite(PIN_RELAY2_LUFT, HIGH);                                                                // Relais 2 (Lüfter) ausschalten
      Serial.println("Zeitsteuerung: Lüfter AUS");                                                        // serielle Monitor Ausgabe: "Luftfeuchtigkeit UND Bodentemperatur OK"
    }
  }
  delay(2000);                                                                      // Pause (2000 = 2 Sekunden)
}
1 Like

Hi Kolaha,

ich danke dir erstmal dafür, dass du dir die nimmst mir zu helfen Zeit
Vielen Dank für deinen Code :slight_smile:

Ich hab ihn gerade mal ausprobiert. Das Programm läuft zwar ohne Fehler anzuzeigen, umschalten tut aber leider noch nichts. Ich habe jetzt mal das Programm nochmal auf das aller nötigste eingekürzt. Theoretisch sollte die Zeitschaltung jetzt eine Minute aktiv sein und dann zwei Minuten inaktiv, mit unendlicher Wiederholung:


#include "RTClib.h"

RTC_DS3231 rtc;

bool luefter_steuerung = 1;                 // 0= Lüftersteuerung nach Luftfeuchtigkeit, 1 = Lüftersteuerung nach Zeitschaltuhr
const uint16_t luefter_aktiv = 1;
const uint16_t luefter_inaktiv = 2;
bool isActive = false;

void setup(void) {
  Serial.begin(9600);

  rtc.begin();
}

void loop(void) {
  
  DateTime now = rtc.now();

  if (luefter_steuerung == 0) {
      Serial.println("Zeitsteuerung deaktiviert");
    }

  else {
    static uint16_t Abwarten = 0;
    uint16_t MinutenZahl = now.hour() * 60 + now.minute();
    if (MinutenZahl - Abwarten >= luefter_inaktiv && !isActive) {
      Abwarten += luefter_aktiv;
      Serial.println("Zeitsteuerung aktiv: EIN");
    }
    if (MinutenZahl - Abwarten >= luefter_aktiv && isActive) {
      Abwarten += luefter_inaktiv;
      Serial.println("Zeitsteuerung aktiv: AUS");
    }
  }
  delay(2000);
}

Wenn ich den Code so ausführe, wird einfach die ganze Zeit "Zeitsteuerung aktiv: EIN
" ausgegeben (Lüfter wäre dauerhaft aktiv).
Könntest du vielleicht hinter den Code noch schreiben was da genau gemacht wird? Ich würde gern ein bisschen lernen und verstehen was da genau passiert :slight_smile:
Vielen vielen Dank

Gruß Thomas

ich frag mich warum nimmst du nicht einfach millis()? RTC is nötig um etwas nach Uhrzeit zu machen oder besser nach Tagen.

Ich hatte gelesen, dass Millis sich wohl nach 50 Tagen oder so reseten. Ich weiß nicnt ob ich das richtig verstanden habe, aber daraus habe ich geschlussfolgert, dass das über RTC sinnvoller wäre. Was sagst du?

für regelmesiges Lüfterschalten genug ist einfache Flip-Flop Schaltung

wenn's unbedingt mit arduino muss, dann richtige millis()-Formel macht's. RTC dann unnötig.

#include <DHT.h>                           // DHT Bibliothek laden
//#include "RTClib.h"                        // RTC-Libary laden

#define DHTPIN 4                           // Der DHT-Sensor wird an PIN 4 angeschlossen    
#define DHTTYPE DHT22                      // Es handelt sich um den DHT22 Sensor

#define RELAY2_PIN 10                 // Lüfter

DHT dht(DHTPIN, DHTTYPE);                  // Der Sensor wird ab jetzt mit „dth“ angesprochen
//RTC_DS3231 rtc;

bool luefter_steuerung = true;                 // Lüftersteuerung nach Luftfeuchtigkeit = 0, Lüftersteuerung nach Zeitschaltuhr = 1
const byte luftfeuchte_max = 90;                  // Maximale Luftfeuchtigkeit ueber derer die Luefter zum trocknen einschalten sollen (Bedingung: Lüftersteuerung = 0)
const uint16_t luefter_aktiv = 12;
const uint16_t luefter_inaktiv = 31;

void setup(void) {
  Serial.begin(9600);                                 // Start serieller Monitor
  dht.begin();                                        // DHT22 Sensor starten

  //  rtc.begin();                                        // RTC Modul starten
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));     // Aktuelle PC-Uhrzeit übernehmen

  digitalWrite(RELAY2_PIN, HIGH);                // Pin an Telais 2 zu Beginn ausschalten
  pinMode(RELAY2_PIN, OUTPUT);                   // Pin an Relais 2 auf Ausgabe stellen
}

void loop(void) {
  static uint32_t Timer = 0;
  static bool isActive = false;

  float DHT_Luftfeuchtigkeit = dht.readHumidity();                                  // die Luftfeuchtigkeit auslesen und definieren als „DHT_Luftfeutchtigkeit“
  float DHT_Temperatur = dht.readTemperature();                                     // die Temperatur auslesen und definieren als „DHT_Temperatur“

  if (!luefter_steuerung) {
    if ( DHT_Luftfeuchtigkeit >= luftfeuchte_max) {          // Wenn Luftfeuchtigkeit höher max. Grenzwert, dann
      digitalWrite(RELAY2_PIN, LOW);                                             // Relais 2 (Lüfter) einschalten
      Serial.println("Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN");  // serielle Monitor Ausgabe: "Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN"
    }
    else  {                                                 // Sonst noch wenn
      digitalWrite(RELAY2_PIN, HIGH);                                            // Relais 2 (Lüfter) ausschalten
      Serial.println("Luftfeuchtigkeit UND Bodentemperatur OK");                      // serielle Monitor Ausgabe: "Luftfeuchtigkeit UND Bodentemperatur OK"
    }
  }
  else {
    if ( isActive ) {
      if (millis() - Timer >= luefter_aktiv * 60000 ) {
        isActive = false;
        Timer = millis();
        digitalWrite(RELAY2_PIN, HIGH);                                                                // Relais 2 (Lüfter) ausschalten
        Serial.println("Zeitsteuerung: Lüfter AUS");                                                        // serielle Monitor Ausgabe: "Luftfeuchtigkeit UND Bodentemperatur OK"
      }
    } else {
      if (millis() - Timer >= luefter_inaktiv * 60000 ) {
        isActive = true;
        Timer = millis();
        digitalWrite(RELAY2_PIN, LOW);                                                                 // Relais 2 (Lüfter) einschalten
        Serial.println("Zeitsteuerung: Lüfter EIN");                                                        // serielle Monitor Ausgabe: "Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN"
      }
    }
  }
  delay(2000);                                                                      // Pause (2000 = 2 Sekunden)
}

Rhetorische Frage:
Welche Code-Version wird von Anfängern wohl bevorzugt?
Die Code-Version die am leichtesten verständlich ist.
Hier die Funktion Lüfter ein Zeitintervall A eingeschaltet, ein anderes Zeitintervall B ausgeschaltet


#define EIN LOW   // Relais is low-aktiv umgekehrte Logik: LOW entspricht eingeschaltet
#define AUS HIGH  // HIGH entspricht ausgeschaltet

const byte PIN_RELAY2_LUFT = 10;

void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

unsigned long MyLuefterTimer = 0;  // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED    = 2;

// für die korrekte Berechnung von Variablen vom Typ unsigned long "UL" an die Zahl anhängen
//                                          2 Minuten * 60 Sekunden * 1000 Millisekunden
const unsigned long LuefterLaueftIntervall =   2      * 60          * 1000UL;
const unsigned long LuefterAusIntervall    =   1      * 60          * 1000UL;
unsigned long SchaltIntervall;
boolean LuefterLaueft;


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();
  pinMode(PIN_RELAY2_LUFT, OUTPUT);

  // Initialisierung mit Lüfter wird eingeschaltet
  LuefterLaueft = true;
  SchaltIntervall = LuefterLaueftIntervall;
  digitalWrite(PIN_RELAY2_LUFT, EIN);

  MyLuefterTimer = millis(); // In der Timer-Variable den akteuellen Zeitstempel speichern
}


void LuefterIntervallSchaltung() {
    if ( TimePeriodIsOver(MyLuefterTimer, SchaltIntervall) ) {
    // Luefter wird geschaltet.
    // Der Zeitstempel des Schaltens wird in Variable MyLuefterTimer gespeichert
    // und automatisch bei jedem "Ablauf" des Timers von der 
    // function TimePeriodIsOver  aktualisiert = neu gespeichert
    // wenn die Anzahl Millisekunden vergangen ist die in der Variable
    // SchaltIntervall steht dann wird der Code in der If.Bedingung ausgeführt

    if (LuefterLaueft) {
      digitalWrite(PIN_RELAY2_LUFT, AUS);
      LuefterLaueft = false;
      SchaltIntervall = LuefterAusIntervall;
    }
    else {
      digitalWrite(PIN_RELAY2_LUFT, EIN);
      LuefterLaueft = true;
      SchaltIntervall = LuefterLaueftIntervall;      
    }    
  }
}

void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 250);
  LuefterIntervallSchaltung();
}

Und hier die Version mit zusätzlichem komfortablen debug-output

// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * 

https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298
#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);
// usage: dbgi("2:my fixed text",myVariable,1000);
// myVariable can be any variable or expression that is defined in scope
// third parameter is the time in milliseconds that must pass by until the next time a 
// Serial.print is executed
// end of macros dbg and dbgi
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * 


#define EIN LOW   // Relais is low-aktiv umgekehrte Logik: LOW entspricht eingeschaltet
#define AUS HIGH  // HIGH entspricht ausgeschaltet

const byte PIN_RELAY2_LUFT = 10;

void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

unsigned long MyLuefterTimer =  0;  // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED    = 13;

// für die korrekte Berechnung von Variablen vom Typ unsigned long "UL" an die Zahl anhängen
//                                          2 Minuten * 60 Sekunden * 1000 Millisekunden
const unsigned long LuefterLaueftIntervall =   2      * 60          * 1000UL;
const unsigned long LuefterAusIntervall    =   1      * 60          * 1000UL;
unsigned long SchaltIntervall;
boolean LuefterLaueft;


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println( F("Setup-Start") );
  PrintFileNameDateTime();
  pinMode(PIN_RELAY2_LUFT, OUTPUT);

  // Initialisierung mit Lüfter wird eingeschaltet
  LuefterLaueft = true;
  SchaltIntervall = LuefterLaueftIntervall;
  digitalWrite(PIN_RELAY2_LUFT, EIN);

  MyLuefterTimer = millis(); // In der Timer-Variable den akteuellen Zeitstempel speichern
}


void LuefterIntervallSchaltung() {

    // dbgi: "printe" nur EINMAL alle 1000 Millisekunden 
    dbgi("1:",LuefterLaueft,1000);
    dbgi("2:",SchaltIntervall,1000);
    dbgi("Laufzeit",millis() - MyLuefterTimer,1000);
    dbgi("",0,1000);
    
    if ( TimePeriodIsOver(MyLuefterTimer, SchaltIntervall) ) {
    // Luefter wird geschaltet.
    // Der Zeitstempel des Schaltens wird in Variable MyLuefterTimer gespeichert
    // und automatisch bei jedem "Ablauf" des Timers von der 
    // function TimePeriodIsOver  aktualisiert = neu gespeichert
    // wenn die Anzahl Millisekunden vergangen ist die in der Variable
    // SchaltIntervall steht dann wird der Code in der If.Bedingung ausgeführt

    if (LuefterLaueft) {
      digitalWrite(PIN_RELAY2_LUFT, AUS);
      LuefterLaueft = false;
      SchaltIntervall = LuefterAusIntervall;
      dbg("Lüfter",LuefterLaueft);    // gib bei JEDEM Aufruf auf die serielle Schnittstelle aus
      dbg("Lüfter",SchaltIntervall);
    }
    else {
      digitalWrite(PIN_RELAY2_LUFT, EIN);
      LuefterLaueft = true;
      SchaltIntervall = LuefterLaueftIntervall;      
      dbg("Lüfter",LuefterLaueft);
      dbg("Lüfter",SchaltIntervall);
    }    
  }
}

void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 250);
  LuefterIntervallSchaltung();
}

Die Zahlenwerte der function millis() springen nach 49,7 Tagen vom Maxwert auf 0.

aber

Wenn man die Variablen die man für das Timing benutzt als Variablen-Typ
unsigned long deklariert
dann funktioniert die If-Bedingung

if ( millis() - StartZeit >= Intervall)

immer

Die Berechnung millis() - StartZeit führt immer zu einem positiven Ergebnis.
Das ist eine Eigenheit der unsigned Integermathematik.
unsigned heißt ohne Vorzeichen = nur positive Zahlen.
Deswegen kann das Programm Jahrzehntelang laufen und es funktioniert.

vgs

@kolaha
Danke für deine Zeichnung - die ich als Laie leider nicht wirklich verstehe.
Der Code funktioniert tatsächlich :smiley: Vielen Dank dafür.
So richtig versteh ich die ganzen Befehle aber noch nicht. Kannst du vielleicht hinter die Zeilen schreiben was da gemacht wird? So lernt mans besser :smiley:

Eine Frage. Wenn man mit Millis arbeitet und diese nach 49,7 Tagen zurückgesetzt werden. Was passiert dann? Bleibt der Code oder die Zeitschalt-Funktion auch einfach stehen? Muss man dann den Arduino neustarten? Die Steuerung soll ja in ein Gewächshaus eingebaut werden was 365 Tage im Jahr laufen soll.

@StefanL38
Ich bin erstmal dankbar für jeden der mir hier versucht zu helfen :wink:
Auch Danke an dich für deine Zeit und deine Mühe.
Als Anfänger versteh ich deinen Code auf den ersten Blick zwar auch nicht wirklich aber ich werd mich mal reinfuchsen und ein bisschen damit experimentieren :slight_smile:

Danke :slight_smile:

Deine Frage:

Wird hier beantwortet
Superkurzantwort: millis() funktioniert immer

Kurzantwort: richtig programmiert funktioniert die Verwendung von millis() immer.
Jetzt nimm dir die 5 Minuten die ausführliche Antwort wirklich zu lesen

ein Beispiel. scheint mit uint8_t nicht zu funzen

void setup(void) {
  Serial.begin(115200);
}

void loop(void) {
  static uint16_t x = 2000;
  static uint16_t Timer = 0; // Simuliert millis(), aber 8 Bit werden schon nach 255 überlaufen
  static uint16_t Wert = 0; // hier wird simuliertes gespeichert für spätere Abgleichen
  Timer += x;
  if (Timer - Wert >= x ) {
    Serial.print(Timer - Wert);
    Serial.print('\t');
    Serial.println(Timer);
    Wert = Timer;
  }
  delay(30);
}

@StefanL38
Ich habe letzte Nacht deinen Code mal ausgiebig getestet und in mein Hauptprogramm eingebaut.
LÄUFT! :partying_face:
Vielen Dank dafür.

Also sorgt diese Zeile:
unsigned long currentMillis = millis();
dafür, dass da nach 49 Tagen nichts abstürzt. Sehr gut. Genau wie ich es mir gewünscht hab :smiley:

Den zweiten Code mit "debug-output" hab jetzt noch nicht genau verstanden. Welche Funktion ist da jetzt anders buw was heißt debug-output?
Sorry für die Anfänger-Fragen :slight_smile:

@kolaha
Ich danke dir vielmals für deine Hilfe und deine Zeit :smiley:
Vielen vielen Dank :blush:

Es ist eine

andere

Zeile die dafür sorgt, dass die Timing-Funktion endlos funktioniert.

diese Art der Berechnung

mit anderen Worten
aktuelle Uhrzeit minus Startzeit >= Wartezeit

Mit dem sorgfälig Lesen bzw. sorgfältig zitieren hast du es wohl nicht.
Ich übrigens auch nicht immer.

Es ist das Zusammenspiel von zwei Sachen:

  1. der Deklarierung als variable vom Typ unsigned log
    unsigned long myTimerVariable;
    Wie du richtig zitiert hast
    und
  2. Die Ermittlung des Zeitunterschiedes durch diese Art der Minus-Rechnung zu machen
if (millis() -  StartZeit >= Intervall) {
  // Code
}

Beispiele mit einfachen Zahlen:
Angenommen der Maximalwert von unsigned long läge bei 10000

Bei einer Variable vom Typ unsigned long
führt diese Rechnung zum Ergebnis
9900 - 9800 = +100

Aber - Spezialität der Integer-Mathematik - auch bei dieser Rechnung

0080 - 9920 = + 100

Im zweiten Beispiel hatte millis() den Überlauf vom Maximalwert 10000 und steht jetzt bei einer kleinen Zahl 80.
Dann führt die Berechnung 80 - 9920
speziell bei **unsigned-**integer-Mathematik ebenfalls zum Ergebnis plus 100
Und deswegen ist der Überlauf und neustart bei 0 kein Problem.

Wenn man zu allen schlechten Code-Beispielen einfach immer die Klappe hält und niemals eine Bewertung auspricht, dann sinkt die Qualität.

Deshalb erlaube ich mir auch wenn ich etwas wirklich schlecht programmiert finde das auch wirklich explizit als schlecht zu bezeichnen. Wenn daraus eine Diskussion entsteht um so besser.

vgs

@StefanL38

"Mit dem sorgfälig Lesen bzw. sorgfältig zitieren hast du es wohl nicht."

Vielleicht kannst du dir vorstellen, dass ein Anfänger, selbst wenn er alles liest, nicht alles sofort versteht und deshalb manchmal auch Dinge fragt die schon mal irgendwo in einer Flut aus Informationen irgendwo mitgeschickt wurden. Wenn ich etwas nicht verstanden habe, frag ich nach - wie jeder der lernen möchte. Das hier ist mein allererstes Arduino-Projekt! Ich habe auch noch nie etwas mit C++ gemacht... Ich bin immer sehr sehr dankbar für jede Hilfe, ich fände es aber auch gut, wenn man respektvoll miteinander umgeht. Danke!

PS: Auch "indirekte Seitenhiebe" gegen andere Helfende sind absolut unnötig!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.