LED Zeitschaltung

Hallo zusammen,

Ich bin blutiger Anfänger und probiere gerade mit Zeiten und Pausen herum.
In dem Zuge möchte ich für meine kleine Tochter eine "Schlafenszeitampel" realisieren.

Im Prinzip geht es darum, dass während der Schlafenszeit (z.B. 20:30-5:30Uhr) eine rote LED leuchtet.
Dann soll für 2 Stunden eine grüne LED leuchten und nach 13 Stunden soll wieder die rote leuchten.
(Die Zeiten sind nicht nicht in Stein gemeißelt)

Realisiert habe ich es jetzt mit einem delay:
Arduino wird um 20:30Uhr eingeschaltet.

int ledRot   = 13;                      // definiere Variable für Pin 13
int ledGruen  = 12;                      // definiere Variable für Pin 12

void setup() {

  pinMode(ledRot, OUTPUT);              // definiere die LEDs als Ausgänge

  pinMode(ledGruen, OUTPUT);            //

}

 void loop() {
  digitalWrite(ledRot, LOW);            // mache die LEDs aus
  digitalWrite(ledGruen, LOW);        //

  digitalWrite(ledRot, HIGH);           // mache die rote LED an
  delay(32400000);                        // und warte 9 Stunden
  digitalWrite(ledRot, LOW);            // mache die rote LED aus
  digitalWrite(ledGruen, HIGH);       // danach mache die grüne LED an
  delay(7200000);                          // und warte 2 Stunden
  digitalWrite(ledGruen, LOW);        // mache die grüne LED aus
  delay(46800000);                        // warte 13 Stunden und fange wieder von vorne an
}

Soweit macht der Code auch das was ich will. Allerdings würde ich ihn jetzt gerne "smarter" machen.
Ich habe es mit millis versucht, aber damit komme ich (noch) nicht richtig klar.
Wie würdet ihr den Code schreiben? Ich würde gerne erstmal ohne eine Echtzeituhr arbeiten. (Eins nach dem Anderen)

Vielen Dank schon mal im Voraus!

Dann schaue Dir nochmal intensiv millis an.

Gruß Tommy

ich denke du sollst dir jetzt mal das Beispiel BlinkWithoutDelay ansehen und lernen und dann versuchen aus den deinen Ablauf ähnlich umsetzen.

Stichwort Statemachine.

Ich würde eine RTC nehmen und die Tageszeit in Sekunden umrechnen. Dann kannst Du einfach die Zeiten vergleichen. Als RTC würde sich ein DS3231 anbieten wei sehr genau. Auch weil nur mit einer RTC Du die richtige Zeit hast. Mit delay() bzw millis() bist Du immer vom Einschaltzeitpunkt abhängig.

Ansonsten solltest Du millis() verstehen da man diese Funktion öfters braucht.

schau dir mal BlinkwithoutDelay - Die Nachtwächtererklärung - Deutsch - Arduino Forum

Grüße Uwe

Hallo,

wie Uwe schon schrieb , bei der Anwendung wirst Du letztlich nicht ohne eine RTC auskommen. Dann kannst Du auch einfach die Uhrzeit abfragen und so machen was Du willst.
Wenn Dein Teil W-lan fähig ist kannst Du natürlich auch mittels NTP die Zeit aus dem Internet holen und dann intern laufen lassen. Die wird dann automatich synchronisiert.

Auf der anderen Seite kommst Du sowieso nicht um millis() herum, so schwer ist das nicht wenn man es mal begriffen hat.

Ich schließe mich den anderen an.

Dass Du Anfänger bist, glaube ich sofort. Code lügt nie :slight_smile: Naja ... fast nie.

Sieh Dir an, wie Du zeitliche Abläufe ohne delay() realisieren kannst (Stichwort: Endlicher Automat). Was mir hierzu eingefallen ist, habe ich vor einiger Zeit hier ins Netz gekippt. Das mit der RTC wäre eine gute Erweiterung, zumal man den Arduino bei Bedarf problemlos und schnell tauschen könnte. Die Laufzeitunterschiede sind auch unter baugleichen Arduinos nicht ohne. Für sehr lange delay()s gilt das umso mehr.

Gruß

Gregor

noiasca:
ich denke du sollst dir jetzt mal das Beispiel BlinkWithoutDelay ansehen und lernen und dann versuchen aus den deinen Ablauf ähnlich umsetzen.

Stichwort Statemachine.

Den Eintrag hatte ich auch schon gefunden. Ich schaffe es allerdings nicht die beiden LEDs aufeinander abzustimmen bzw ich weiß nicht, wie ich die grüne in abhängikeit von der roten steuern kann
Mein Ansatz war dieser:

unsigned long LED_Rot;  // Variable Speicher für Systemzeit.
int rotStatus = LOW;
int LedRot = 12;

unsigned long LED_Gruen;  // Variable Speicher für Systemzeit.
int gruenStatus = LOW;
int LedGruen = 11;


void setup() {
  pinMode(LedRot, OUTPUT);
  pinMode(LedGruen, OUTPUT); // teilt dem Arduino mit, dass das ein Ausgang ist.
}

void loop() {
  if (rotStatus == LOW) {
    if (millis() - LED_Rot> 2000 ) {
      digitalWrite(LedRot, HIGH);
      LED_Rot = millis();
      rotStatus = HIGH;
    }
  } else {
    if (millis() - LED_Rot> 1000) {
      digitalWrite(LedRot, LOW);
      rotStatus = LOW;
      delay(100);
    }
  

  if (rotStatus == LOW) {
    if (millis() - LED_Gruen> 1000 ) {
      digitalWrite(LedGruen, HIGH);
      LED_Gruen = millis();
      gruenStatus = HIGH;
    }
  
    } else {
    if (millis() - LED_Gruen> 1000) {
      digitalWrite(LedGruen, LOW);
      gruenStatus = LOW;
    }
  }
}
}

Die Zeiten sind erstmal klein gesetzt um das Ergebnis direkt zu sehen.

Nur zum Verständnis, warum ist in dem Falle Millis besser als delay?

skss:
Nur zum Verständnis, warum ist in dem Falle Millis besser als delay?

delay() blockiert die Ausführung des Sketches. Der Controller wartet ohne etwas anderes zu machen.
millis() ist ein Zähler der vergangenen Millisekunden seit einschalten. Du kannst immer mal wieder kontrollieren ob die Wartezeit abgelaufen ist und zwischen den Kontrollen etwas anderes machen.

Zu Deinem Sketch:
Sobald rotStatus bzw gruenStatus HIGH ist werden die jeweiligen (If ... == LOW) niemals mehr wahr.

Grüße Uwe

Hallo,

delay sollte eigendlich pause heissen, fur die angegebene Zeit macht das Program nichts mehr und wartet bis die Zeit abgelaufen ist. Damit kann dann nichts mehr anderen passieren, z.B Taster abfragen, eine andere LED einschalten, usw.

was meinst Du damit das Du die LED nicht aufeinander abstimmen kannst. ?

Rentner:
Hallo,

delay sollte eigendlich pause heissen, fur die angegebene Zeit macht das Program nichts mehr und wartet bis die Zeit abgelaufen ist. Damit kann dann nichts mehr anderen passieren, z.B Taster abfragen, eine andere LED einschalten, usw.

Das heißt, wenn ich mit dem Sketch mit delay arbeite ist es nicht schön, aber auch nicht falsch, da ich nichts anderes in der Zeit machen möchte oder?

was meinst Du damit das Du die LED nicht aufeinander abstimmen kannst. ?

Rein von der Logik würde ich doch sagen:
Rote LED leuchte für x Sekunden und gehe dann auf Low. Wenn Status der roten LED auf Low ist, dann setzte grüne LED für x Sekunden auf High.
Wenn grüne LED auf Low ist, setze die rote LED nach x Sekunden auf High und wiederhole das Ganze.
Diese Abhängigkeit bekomme ich nicht richtig hin.

Ausbaufähiger Vorschlag:

const byte LedRotPin = 12;
const byte LedGruenPin = 11;
unsigned long leuchtIntervall[] = {2000, 1000, 3000};
const byte intervalle = sizeof(leuchtIntervall) / sizeof(leuchtIntervall[0]);
unsigned long aktMillis, leuchtMillis;
byte schritt;

void setup() {
  pinMode(LedRotPin, OUTPUT);
  pinMode(LedGruenPin, OUTPUT);
  digitalWrite(LedRotPin, HIGH);
  digitalWrite(LedGruenPin, LOW);
}

void loop() {
  aktMillis = millis();
  if (aktMillis - leuchtMillis >= leuchtIntervall[schritt]) {
    leuchtMillis = aktMillis;
    schritt = (schritt + 1) % intervalle;
    switch (schritt)
    {
      case 0:
        digitalWrite(LedRotPin, HIGH);
        digitalWrite(LedGruenPin, LOW);
        break;
      case 1:
        digitalWrite(LedRotPin, LOW);
        digitalWrite(LedGruenPin, HIGH);
        break;
      case 2:
        digitalWrite(LedRotPin, LOW);
        digitalWrite(LedGruenPin, LOW);
        break;
    }
  }
}

Hallo,

kann es jetzt sein das ich mich falsch ausgedrückt habe. ??

wenn Du zwei Stunden mit delay warten willst wärend die grüne LED leuchtet kannst aber auch die Uhrzeit nicht mehr einlesen um dann wiederauf rot zu schalten. Ohne Uhr wird es aber nicht gehen, da delay nicht sehr genau ist. Ich weiss auch garnicht was man bei delay als längste zeit angeben kann.

Na ja in dem Beispiel blinkwithout delay hast Du eine LED die abhängig von LEDstate ein oder aus ist. Die zweite LED muss doch nur invertiert dazu sein.

Rentner:
Die zweite LED muss doch nur invertiert dazu sein.

Dann bekommst Du "beide aus" nicht hin.

agmue:
Ausbaufähiger Vorschlag:

Vielen Dank! Das funktioniert sehr gut.
Ich werde mir den Code morgen genauer ansehen. Ich denke das hilt mir sehr viel die millis Funktion besser zu verstehen und zu nutzen!

Rentner:
Hallo,

kann es jetzt sein das ich mich falsch ausgedrückt habe. ?

Nein ich hatte es falsch verstanden

Gruß Heinz :slight_smile:

So, ich habe mir jetzt eine DS1302 RTC besorgt.
Die Uhr ist gestellt und ich bekomme die korrekte Uhrzeit auch per den seriellen Monitor angezeigt.
Ich bekomme es allerdings nicht hin, die Stunde richtig abzugreifen.
Ich denke der richtige Weg wäre:
"Wenn die Stunde zwischen 19 und 6 ist dann schalte die rote LED an. Sonst schalte die grüne LED an"

Mein Code sieht so aus:

#include <DS1302.h>
#include <TimeLib.h>

 //DS1302 und LEDs initialisieren
 DS1302 rtc(10, 11, 12); //10=RST 11=DAT 12=CLK VCC=5V GND=GND
int LEDrot = 6; // Farbe blau an Pin 6
int LEDgruen = 5; // Farbe rot an Pin 5

 // Zeit Struktur initalisieren
 Time t;

 void setup()
 {
   // Uhr laufen lassen und Schreibschutz deaktivieren
   rtc.halt(false);
   rtc.writeProtect(false);


   // Setup Serial connection
   Serial.begin(9600);

   // The following lines can be commented out to use the values already stored in the DS1302
//     rtc.setDOW(FRIDAY);
//     rtc.setTime(20, 40, 30);
//     rtc.setDate(02, 11, 2018);

 pinMode(LEDrot, OUTPUT);
 pinMode(LEDgruen, OUTPUT);
 digitalWrite(LEDrot, LOW);
 digitalWrite(LEDgruen, LOW);

 }

 void loop()
 {


   t = rtc.getTime();
if (t.hour <= 19 && t.hour >= 6) {
    digitalWrite(LEDrot, HIGH);
    digitalWrite(LEDgruen, LOW);
    Serial.print("Rote LED an");
    }
else
{ 
  digitalWrite(LEDgruen, HIGH);
  digitalWrite(LEDrot, LOW);
  Serial.print("Gruene LED an");
}
   
  Serial.println("  ");
//    Serial.print(rtc.getDateStr(2));
//    Serial.print(" ");
   Serial.print(rtc.getTimeStr());
//  Serial.print(t.date, DEC); // tag
//  Serial.print(".");
//  Serial.print(t.mon,DEC);  // monat
//  Serial.print(".");
//  Serial.print(t.year, DEC);  //jahr
//  Serial.print("  ");
//  Serial.print(t.dow, DEC);  //wochentag mo=1, di=2 ...

//  Serial.println("  ");
//
  Serial.print(t.hour, DEC); //stunde
//  Serial.print(":");
//  Serial.print(t.min,DEC);  // minute
//  Serial.print(":");
//  Serial.print(t.sec, DEC);  //sekunde
//  Serial.print("  ");
Serial.println("  ");
 delay (5000);
 }

Als Ergebnis bekomme ich im seriellen Monitor immer nur:
*"Gruene LED an *
21:49:56.108 -> 21:49:3921 "

Was mache ich falsch?

Das hast du doch genau so programmiert :wink:

Wenn <= 19 Uhr und >= 6 Uhr machst du die Rote an.

ansonsten die Grüne.

Und um 21:49 ist halt größer als 19 Uhr damit geht es in den Else-Zweig und
da machst du die grüne an !!

Ulli

Hi

Ich sehe nicht, wo Du den Time-String 'zusammen baust', zumindest sehe ich nirgends ein '->'

-> 21:49:3921

Weiter kommen mir dort die Sekunden irgendwie merkwürdig vor - hatte schon lange keine Sekunde mehr gesehen, Die größer als 59 war - vll. ein Anfangspunkt zur Fehlersuche.

MfG

beeblebrox:
Das hast du doch genau so programmiert :wink:

Wenn <= 19 Uhr und >= 6 Uhr machst du die Rote an.

ansonsten die Grüne.

Und um 21:49 ist halt größer als 19 Uhr damit geht es in den Else-Zweig und
da machst du die grüne an !!

Ulli

Guter Denkanstoss!

Habe den Code geändert:

if (t.hour == 19 || t.hour == 20 || t.hour == 21 || t.hour == 22 || t.hour == 23 || t.hour == 00 || t.hour == 01 || t.hour == 02 || t.hour == 03|| t.hour == 04 || t.hour == 05 || t.hour == 06) {
    digitalWrite(LEDrot, HIGH);
    digitalWrite(LEDgruen, LOW);
    Serial.print("Rote LED an");
    }
else if (t.hour == 06 || t.hour == 07) {
    digitalWrite(LEDgruen, HIGH);
    digitalWrite(LEDrot, LOW);
    Serial.print("Grüne LED an");
    }

else
{ 
  digitalWrite(LEDgruen, HIGH);
  digitalWrite(LEDrot, HIGH);
  Serial.print("Beide LED's aus");
}

Nicht schön aber funktional :wink:

Achtung mit führenden Nullen. Diese werden als Oktalzahlen interpretiert. Bei deinem aktuellen Code ist das gerade noch kein Problem :slight_smile: weil die höchste verwendete Zahl einstweilen nur "07" ist. Solltest du aber irgendwann 08 oder 09 verwenden wird es "interssant". Denn diese Zahlen existieren im Okalsystem einfach nicht und das Programm macht dann höchstwahrscheinlich "lustige Dinge" :slight_smile: