Aquarien Dim Programmierung per RTC

Hey Leute,

Da ich ja am rumtüfteln bin um einen Aquarium-LED-Dimm-Controller zu bauen habe ich jetzt bereits meine RTC zum laufen gebracht.
Jedenfalls zeigt mein Display bzw der Serial Monitor ziemlich gut die Uhrzeit an.
Wie ich meine LEDs dimme habe ich schon in einem anderen Thread erfragt. Jedenfalls kann ich über SerialWrite 0-226 Schritte (die Schritte bis 255 führen leider zum Spannungsabfall => LEDs bleiben aus => 226 ist die dunkelste “Stabile” Stufe) dimmen.

Jetzt würde ich gerne mein Programm beginnen zu schreiben.
Wie bewerkstellige ich denn das Auslesen der Uhrzeit, sodass ich bsp. sagen kann

“if 8 Uhr morgens {Sonnenaufgang simmulieren, Schritte von 226 runterzählen auf Null in einem bsp. intervall von 1 Stunde}”
und
“if 20 Uhr abends {Sonnenuntergang simmulieren, Schritte von 0 auf 226 bzw. auf 227 ums komplett auszustellen, in einem bsp. intervall von 1 Stunde}”

?

Grüße :slight_smile:

VIERcntHOLZ: Wie ich meine LEDs dimme habe ich schon in einem anderen Thread erfragt. Jedenfalls kann ich über SerialWrite 0-226 Schritte (die Schritte bis 255 führen leider zum Spannungsabfall => LEDs bleiben aus => 226 ist die dunkelste "Stabile" Stufe) dimmen.

Jetzt würde ich gerne mein Programm beginnen zu schreiben.

Das mit dem Spannungsabfall hört sich so an als wenn Du möglicherweise versuchst, mehr als 20 mA aus einem Arduino-Pin zu ziehen.

Ich würde mal zuerst die Spezifikation bzw. den Vorwiderstand und Stromaufnahme der LED prüfen und die fehlerhafte Schaltung korrigieren, bevor ich mit dem programmieren anfange.

Setzt deine komplette Schaltung mit Bildern rein.

Für deine Abfrage kannste am besten deine Zeit in Sekunden oder Minuten umrechnen!

int totalMinutesToday = h * 60 + min;

Danach reicht eine einfache verschachtelte If.Anweisung,

if(totalMinutes > x &&totalMinutes <= y) // tu was
else if(totalMinutes > y && totalMinutes <= z) // tu was anderes
else // was ich sonst mach wenn nichts zutrifft.

jurs:

VIERcntHOLZ:
Wie ich meine LEDs dimme habe ich schon in einem anderen Thread erfragt. Jedenfalls kann ich über SerialWrite 0-226 Schritte (die Schritte bis 255 führen leider zum Spannungsabfall => LEDs bleiben aus => 226 ist die dunkelste “Stabile” Stufe) dimmen.

Jetzt würde ich gerne mein Programm beginnen zu schreiben.

Das mit dem Spannungsabfall hört sich so an als wenn Du möglicherweise versuchst, mehr als 20 mA aus einem Arduino-Pin zu ziehen.

Also soweit ich das, bzw. die Jungs aus dem anderen Thread beurteilen können, liegt das daran, dass meine KSQs einen 1-10Volt Dimmbarkeit haben, sprich, 10%, also von 0 volt bis 1 Volt ist “unstable”, und diese 10% sind diese Schritte von 226-255

Habs grad hinbekommen meine Zeit auszulesen und in eine Variable zu schreiben.. jedoch habe ich grad ein Problem:

int uhr;

als Variable, unten die berechnung über

uhr = now.hour()*3600;

gibt nur Müll raus, da kam ich dann drauf, dass das ja irgendwas bei 68000 sekunden schon sind, problem nur, int umfasst gar nicht so große zahlen. Ich ein long genommen, dann gibt er mir aber irgendwie "2864" aus, obwohl die Range ja locker für die Sekunden ausreichen sollte?

jemand ne Idee? :(

unsigned long uhr = now.hour() * 3600UL;

Das UL ist wichtig. Sonst wird immer noch in int gerechnet.

VIERcntHOLZ: uhr = now.hour()*3600;

gibt nur Müll raus

Guten Morgen!

Integer mal Integer ergibt auf der rechten Seite wieder Integer. Dann ist die Zahl bei der Berechnung schon lange übergelaufen, schon bevor Du sie an die Variable "uhr" zuweisen möchtest.

Integer mal long ergibt long, also rechne am einfachsten mit einer long-Konstanten 3600L das Ergebnis aus: uhr = now.hour()*3600L;

Aaaahh! Wer soll denn darauf kommen! :D

Vielen Dank! :)

So, habe jetzt schonmal mit der Programmierung begonnen.
Die Sekunden since Midnight erfasst er jetzt korrekt und ich kann diese auslesen.
meine Überlegung wäre jetzt, für die Sunset und Sunrise Ereginisse eigene voids anzulegen.

In diesen Voids lasse ich meine Dimmschritte eig lediglich rauf, bzw. runterzählen, hier im Trockenmodus versucht über den Serial Monitor.

Also eigentlich die 226 Schritte gleichmäißig auf eine Stunde verteilt → 15,929 Pro Step.

Jetzt ist das Problem, dass sich offensichtlich mein Delay aus dem Loop mit dem Delay aus den Ereignissen überschneidet.
Meine Uhrzeit wird nicht mehr sekündlich aktualisiert.

Ich hoffe ich habe es verständlich erklärt ^^’

hier der code:

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

RTC_DS1307 RTC;

unsigned long SecSinceMidnight;

void setup () {
    Serial.begin(9600);
    Wire.begin();
    RTC.begin();
}

void loop () {
    DateTime now = RTC.now();
    SecSinceMidnight = now.hour()*3600L + now.minute()*60 + now.second();
    Serial.println(SecSinceMidnight);
    delay(1000);
    
    if (SecSinceMidnight==73510){
      sunrise();
    }
    
    if (SecSinceMidnight==70950){
      sunset();
    }
   }
   
void sunrise() {
   for (int i = 226; i < 0; i--) {
  Serial.println(i);
  delay(15929);
 }
  }
  
void sunset() {
 for (int i = 0; i < 226; i++) {
  Serial.println(i);
  delay(15929);
 }
  }

Sowas wie "eine void" gibt es nicht. Die Dinger heißen Funktionen. Oder Methoden wenn sie zu Klassen gehören.

"void" ist lediglich der Rückgabewert der Funktion. In diesem Fall nichts. Man kann da aber auch Datentypen zurückgeben.

Akzeptiert! :P

Ich finde diese Umsetzung nicht so optimal.
Besser wäre es doch eine Funktion zu haben die in Abhängigkeit der Minute des Tages den Dimmwert zurückgibt.

Ich habe sowas früher schon mal versucht und eine Funktionsvorschrift errechnet.
Hatte auch funktioniert.
guntherb hat mir einen Weg gezeigt wie dies einfacher und besser zu machen ist.
Hier sein Vorschlag von damals:

int LED_PWM (int _MoD){              // _MoD = Minute of Day
  const int Tablength = 9;
  const int Tab[Tablength][2]={ {  0 ,   5 },
				{360 ,  10 },
				{400 ,  18 },
				{440 ,  39 },
				{520 , 111 },
				{600 , 194 },
				{640 , 226 },
				{680 , 248 },
				{720 , 255 }};

      _MoD = 1440 - _MoD;  // Werte oberhalb 720 nach unten spiegeln, wegen Symetrie


      // In Tabelle das passende Wertepaar suchen
      int i = 0;
      while (i < Tablength && _MoD > Tab[i][0])  i++;  
      
      // aus dem ermittelten Wertepaar und dem nächsten darüber den korrekten Wert interpolieren
      int _out = (   ((Tab[i][1] - Tab[i-1][1])*( _MoD - Tab[i-1][0] ))
      		 	  / (Tab[i][0] - Tab[i-1][0] ))
     		 + Tab[i-1][1];    
     return _out;
}

Du kannst in dem Array markante Punkte definieren, die Werte dazwischen werden als lineare Funktionen berechnet.
Beim dem Beispiel sind nur die Wertepaare bis 12 Uhr eingetragen, dannach wird gespiegelt.
Das gibt eine symetrische Kurve, es geht natürlich auch asymetrisch
Wenn du die Zeile _MoD = 1440 - _MoD; wegmachst und ein paar Nachmittagswerte… einträgst.

rudirabbit: Ich finde diese Umsetzung nicht so optimal. Besser wäre es doch eine Funktion zu haben die in Abhängigkeit der Minute des Tages den Dimmwert zurückgibt.

Da geb ich dir Recht, jedoch möchte ich, wenn ich das richtig verstanden habe, ja nicht "sprunghaft" von einer Helligkeitsstufe zur nächsten wechseln, sondern innerhalb bsp. 60 minuten die 227 Helligkeitsstufen so "weich wie möglich" gestalten und auch gerne alle auskosten, wenn ich diese schon habe? Hoffe das ist ersichtlich, was ich damit meinte

Je mehr Stützpunkte du definierst desto feiner wird das Ganze. Wenn du dir das ganze in einer Tabelle grafisch aufzeichnest und an den Stellen wo du es besonders smooth haben willst mehr Stützpunke machst kannst du dir die Wertepaare leicht erstellen

Die Werte zwischen den Punkten werden durch die C-Funktion berechnet. Es ist die lineare Funktion welche durch die beiden Punkte geht. "Sprunghaft" ist das ganze mit Sicherheit nicht.

Alternativ kann man es noch mit einem Polynom lösen. So habe ich damals angefangen, glaube es war 4. oder 5. Ordnung.

Die lineare Interpolationsmethode ist aber der bessere Weg. IHMO kann man damit fast alles "erschlagen".

rudirabbit: Die Werte zwischen den Punkten werden durch die C-Funktion berechnet. Es ist die lineare Funktion welche durch die beiden Punkte geht. "Sprunghaft" ist das ganze mit Sicherheit nicht.

bedeutet das, dass wenn ich bsp. 60 Punkte für 60 Minuten kalkuliere, und es bsp. von 22 auf 23 springt, er den Übergang berechnet und dann langsam hochfährt, zu punkt 23, oder dass er bei erreichen des punktes 23 sofort auf diesen Wert springt?

Ok - Asche auf mein Haupt deine Anforderungen sind etwas anders. :blush: Das was ich meinte war eine Dimmung für ein Salzwasserbecken über den ganzen Tag.

Du willst quasi innerhalb einer definierten Zeit am Morgen innerhalb einer Stunde hochdimmem und am Abend runterdimmen. Dann ist deine Aktualisierung jede Sekunde schon mal richtig.

Mit If die Sekunde abfragen wann es losgehen sollen und dann innerhalb von 60 Minuten den Dimmwert vom 227 Stufen hoch oder runterdimmen. Ist eine lineare Funktion zwischen zwei Punkten. Mir geht gerade die Zeit aus dies zu berechnen, WAF Problem.

Haha, richtig! :P

Ich bin ja so weit, dass ich die Zeitabfrage loopen lasse, und wenn bsp. x Sekunden abgelaufen sind, bsp. für 8 uhr Morgens, soll er bsp. in eine Funktion springen, die dafür sorgt, dass innerhalb 60 Minuten, logischerweise in gleichen Abständen (bei 227 steps wäre das irgendwas bei 16 Sekunden pro Step) runtercounted (Da 227 = Aus; 0 = an). Abends bsp. um 18 Uhr, sprich y Sekunden, geht er bsp in die Sunset Funktion , in der das gleiche eigentlich symmetrisch abgebildet ist.

Das "in die FUnktionien springen" klappt astrein, problem ist nur, dass für die Delays, sprich für die Stunde, nicht mehr die RTC "updated" und ausgibt (Nötig, bsp für andere LEDs die aber erst gegen 45 Minuten nach start des Dimprozesses eingeschaltet (Eingeschaltet, nicht auch hochgedimmt) werden sollen. Nach ablauf der Stunde, bzw. des Dimprozesses, würde er die Minutenzahl logischerweise wieder jede Sekunde updaten.

Was ich bräuchte wäre eine loop funktion, bsp. die IMMER läuft, also alle Sekunde den Sekundencounter updated, und, bsp im hintergrund, mit anderen Delays die Helligkeit steuert.

Oder geht das auch anders/einfach? :(

Hallo, so in etwa

sunrise,sunset must du noch definieren, und in presec merkt er sich die Sekunde damit nur alle Sekunde der Dimmwert geschrieben wird.

Dimmt dann ab sunrise,sunset innerhalb einer Stunde hoch oder runter.
Teste es mal, ich hoffe es funzt so. :astonished:
Braucht zwar keine Delays, finde den Code aber trotzdem nicht schön.

void loop() {
 
  if (SecSinceMidnight<sunrise) Dimmwert=0;
  
  if (SecSinceMidnight>=sunrise && SecSinceMidnight<=sunrise+3600)
         Dimmwert=0.075555* float(SecSinceMidnight-sunrise);
 
 if (SecSinceMidnight>sunrise+3600 && SecSinceMidnight<sunset)Dimmwert=272;
 
  
  if (SecSinceMidnight>=sunset && SecSinceMidnight<=sunset+3600)
        Dimmwert=-0.075555*float(SecSinceMidnight-sunset)+272.0; 

if (SecSinceMidnight>sunset+3600) Dimmwert=0;


if (SecSinceMidnight!=presec) {
                                //Schreibe Dimmwert
                                presec=SecSinceMidnight;
                              }
}

oder besser gleich so,

void loop() { 

               


if (SecSinceMidnight!=presec) {                                         // Dies wird jede Sekunde ausgeführt

  if (SecSinceMidnight<sunrise) Dimmwert=272;
  
  if (SecSinceMidnight>=sunrise && SecSinceMidnight<=sunrise+3600)
         Dimmwert=-0.075555* float(SecSinceMidnight-sunrise)+272.0;
 
 if (SecSinceMidnight>sunrise+3600 && SecSinceMidnight<sunset)Dimmwert=0;
 
  
  if (SecSinceMidnight>=sunset && SecSinceMidnight<=sunset+3600)
        Dimmwert=0.075555*float(SecSinceMidnight-sunset); 

if (SecSinceMidnight>sunset+3600) Dimmwert=272;



                                //Schreibe Dimmwert
                                presec=SecSinceMidnight;
                              }
}

PS: Ich sehe gerade mein Code arbeitet verkehrt rum.
Dimm Wert 0 ist bei dir 100% und 272 ist dunkel bzw aus.
Der untere Code sollte jetzt aber passen.
Ist nur der Teil in der Loop in dem es um die Dimm-logig geht.
SecSinceMidnight zb. must du natürtlich von deiner RTC holen, ebenso das Schreiben des des Dimmwerts.
Aber das funktioniert bei dir ja schon alles.

Das “in die FUnktionien springen” klappt astrein, problem ist nur, dass für die Delays, sprich für die Stunde, nicht mehr die RTC “updated” und ausgibt

.
Genau das ist das Grund warum man nicht mit langen Delays arbeiten soll, man hält den Processor für diese Zeit an (bis auf die Interrups geht nichts mehr).
Auch Schleifen aus denen er ewig nicht rauskommt bewirken das Selbe.

Danke dir Rudi :slight_smile:

Musste zwar die Funktion neu berechnen, weil meine Dimmbaren Werte von 0-227 und nciht von 0-272 gingen, aber die Logik dahinter habe ich verstanden! :slight_smile:

eine Frage jedoch noch, was genau meinst du mit

if (SecSinceMidnight!=presec)

Was ist in diesem Fall presec?
SecSinceMidnight ungleich presec?

€dit: hat geklappt! :D habe statt . ein Komma geschrieben -.-

Aber dennoch eine Frage:

da ich ja jetzt meine Steps von 0-226 gerechnet bekomme, jedoch mit Nachkommastellen, kann Arduino damit umgehen?

also mit:

analogWrite(x, 128);

bsp. gehts natürlich wunderbar, was aber wenn es bsp:

analogWrite(x, 128.28); //also unter 0.5

//ODER

analogWrite(x, 128.79); // also über 0.5 ist?

was dann? :)