Netzteil 160W 12V für Daytime LED Cluster hinter TC420

strauch

Active Member
Hallo Olli,

das schaut sehr interessant aus, darf ich fragen ob du einen Blick in deinen Arduino Quelltext erlaubst? Ich will auch meine Beleuchtung mit einem Arduino "schalten" aber im 12V Bereich. Wenn ich das richtig sehe hast du eine RTC angeschlossen. Ich hab mir einen Arduino UNO-Wifi geordert und will die Zeit per NTP synchronisieren. Bin aber noch nicht zur Programmierung gekommen.

Grüße

André
 

omr

Member
Moin André,

den Code poste ich heute Abend, da muss ich erstmal drin etwas aufräumen :)

Viele Grüße,
Olli
 

omr

Member
Arduino, Daytime Cluster & Meanwell PWM

Moin,

hier der Code. Ich übernehme keine Haftung...

Die Main Loop holt die Zeit aus der Echtzeituhr, berechnet die Sekunden seit Mitternacht, vergleicht diesen Counter mit vordefinierten Ereignissen und setzt die entsprechenden I/O-Pins.

In der Loop steht eine Delay von 1s, da zu Debugging-Zwecken noch eine Ausgabe auf dem seriellen Monitor erfolgt. Wenn das nicht mehr erforderlich ist, kann man den Wert runtersetzen.

ToDo: Displayansteuerung, weitere Relais-Ereignisse, Wolkensimulation...

VG, Olli

Code:
// Includes
#include <Time.h>
#include <Wire.h>
//#include <LiquidCrystal.h>
#include "RTClib.h"

// Konstanten
const int DS1307_ADRESSE = 0x50; // I2C Addresse der Echtzeituhr
const int RELAY_1 = 7;  // I/O-Pin Relais 1 
const int RELAY_2 = 6;  // I/O-Pin Relais 2
const int RELAY_3 = 5;  // I/O-Pin Relais 3
const int RELAY_4 = 4;  // I/O-Pin Relais 4
const int FADER_1 = 9;  // PWM-Pin LED-Modul 1
const int FADER_2 = 10; // PWM-Pin LED-Modul 2

// Alle Zeiten: Sekunden nach Mitternacht (0 - 86399)
const long CO2_START =    21600; // 06:00
const long DAWN_START =   25200; // 07:00
const long SIESTA_START = 46800; // 13:00
const long SIESTA_END =   54000; // 16:00
const long CO2_STOP =     72000; // 20:00
const long DUSK_START =   79200; // 22:00

const long FADE_DUR = 3600; // 60min dimmen

const int DAY_STATE[] = { 255 , 255 };      // 100% PWM Tagmodus
const int SIESTA_STATE[] = { 63 , 63  };  // 25% PWM Mittagspause
const int NIGHT_STATE[] = { 0 , 0 };        // 0% PWM Nacht

// Variablen
long Counter;
int StateChan1, StateChan2;

//LiquidCrystal lcd(8, 11, 13, 12, 3, 2);   // LCD-Pins initialiseren
RTC_DS1307 RTC;   // Alias für Ehctzeituhr                                                                                                                                                                            

void fader(long StartTime, const int StartState[], const int EndState[], int Output[2]) {
  float PerSecondDelta0 = (float) (EndState[0] - StartState[0]) / FADE_DUR;
  float PerSecondDelta1 = (float) (EndState[1] - StartState[1]) / FADE_DUR;
  long Elapsed = Counter-StartTime;
  Output[0] = StartState[0] + PerSecondDelta0 * Elapsed;
  Output[1] = StartState[1] + PerSecondDelta1 * Elapsed;
}

long SecondsSinceMidnight() {
  DateTime now = RTC.now();
  long hr = now.hour();
  long min = now.minute();
  long sec = now.second();
  long Total = hr * 3600 + min * 60 + sec;
  return Total;
}

// PWM-Tastverhaeltnis setzen
void set_state(const int STATE[]) {
  if (STATE[0] >= 0 && STATE[0] <= 255) {
    analogWrite(FADER_1, STATE[0]);
    StateChan1 = STATE[0]; }
  if (STATE[1] >= 0 && STATE[1] <= 255) {
    analogWrite(FADER_2, STATE[1]);
    StateChan2 = STATE[1]; }
}

void determine_state() {
  // CO2 schalten
  if ( Counter >= CO2_START && Counter < CO2_STOP) {
    digitalWrite(RELAY_1, HIGH);
  } else {
    digitalWrite(RELAY_1, LOW);
  }

  if ( Counter >= 0 && Counter < DAWN_START ) { // Nacht
      set_state(NIGHT_STATE);
      Serial.print("STATE 1\n"); //debug
      
  } else if ( Counter >= DAWN_START && Counter < (DAWN_START+FADE_DUR) ) { // Sonnenaufgang
    int State[2];
    fader(DAWN_START, NIGHT_STATE, DAY_STATE, State);
    set_state(State);
    Serial.print("STATE 2\n"); //debug
    
  } else if ( Counter >= (DAWN_START+FADE_DUR) && Counter < SIESTA_START ) { // vor Mittagspause
    set_state(DAY_STATE);
    Serial.print("STATE 3\n"); //debug

  } else if ( Counter >= SIESTA_START && Counter < (SIESTA_START+FADE_DUR) ) { // Dimmen zur Mittagspause
    int State[2];
    fader(SIESTA_START, DAY_STATE, SIESTA_STATE, State);
    set_state(State);
    Serial.print("STATE 4\n"); //debug
  
  } else if ( Counter >= SIESTA_START+FADE_DUR && Counter < (SIESTA_END) ) { // Mittagspause
    set_state(SIESTA_STATE);
    Serial.print("STATE 5\n"); //debug

  } else if ( Counter >= SIESTA_END && Counter < (SIESTA_END+FADE_DUR) ) { // Dimmen von Mittagspause
    int State[2];
    fader(SIESTA_END, SIESTA_STATE, DAY_STATE, State);
    set_state(State);
    Serial.print("STATE 6\n"); //debug

  } else if ( Counter >= (SIESTA_END+FADE_DUR) && Counter < DUSK_START ) { // nach Mittagspause
    set_state(DAY_STATE);
    Serial.print("STATE 7\n"); //debug

  } else if ( Counter >= DUSK_START && Counter < (DUSK_START+FADE_DUR) ) { // Sonnenuntergang
    int State[2];
    Serial.print(State[1]);
    fader(DUSK_START, DAY_STATE, NIGHT_STATE, State);
    set_state(State);
    Serial.print("STATE 8\n"); //debug
  
  } else if ( Counter >= (DUSK_START+FADE_DUR) && Counter < 86400 ) { // Nacht
    set_state(NIGHT_STATE);
    Serial.print("STATE 9\n"); //debug
  
  } else {
    Serial.print("STATE NOT MATCHED"); //debug
    }
}

void digitalClockDisplay() {
   DateTime now = RTC.now(); 
    Serial.print(now.day(), DEC);
    Serial.print('.');
    Serial.print(now.month(), DEC);
    Serial.print('.');
    Serial.print(now.year(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
}

void setup() {
  pinMode(RELAY_1, OUTPUT);
  pinMode(RELAY_2, OUTPUT); 
  pinMode(RELAY_3, OUTPUT); 
  pinMode(RELAY_4, OUTPUT);
  pinMode(FADER_1, OUTPUT);
  pinMode(FADER_2, OUTPUT);
  
  // Serielle Kommunikstion initialisieren
  Serial.begin(9600);
  // I2C initialisieren
  Wire.begin();
  // RTC initialisieren
  RTC.begin();
  // RTC auf compile time des Scetches setzen
  RTC.adjust(DateTime(__DATE__, __TIME__));
}

void loop() {
  Counter = SecondsSinceMidnight();
 
  determine_state();
  
  Serial.print("Counter: ");
  Serial.print(Counter);
  Serial.println(); 
  Serial.print("Channel 1, 2: "); 
  Serial.print(StateChan1); 
  Serial.print(", "); 
  Serial.print(StateChan2); 
  Serial.println(); 
  
  digitalClockDisplay();
  
  delay(1000);
}
 

Wuestenrose

Well-Known Member
'N Abend...

omr":2adrbkep schrieb:
Schaltplan des PWM-Treiber-Teils:


Du hast die 4 nicht verwendeten Gatter unbeschaltet gelassen? Bei CMOS-Bausteinen keine gute Idee, unter ungünstigen Umständen führt das zur Zerstörung des ICs. Entweder die Eingänge nach Vcc oder GND klemmen oder, was ich in derartigen Anwendungen gerne mache, die Gatter parallelschalten.

Grüße
Robert
 

steppy

Active Member
Hi,
hast du den Inverter aus einem bestimmten Grund eingebaut? Die Signalinvertierung geht ja auch problemlos in Software. Interessant fände ich auch ob die Software so bleiben soll oder ob du da noch weitere Pläne hast?

Gruß
Stefan
 

omr

Member
Moin Stefan,

das geht (einfach) in Software, wenn man 0 für voll und 255 für aus nimmt, ja. Finde ich unlogisch.

Geht komplexer in Software, wenn man direkt an den Countern rumschraubt und diese invertiert.

Ich fand die Verwendung eines Inverters logischer. Der FET soll bei "ein" ja sperren und dadurch die 10V am MW abfallen lassen.

Wie schon oben geschrieben, es gibt noch weitere Pläne: Schaltsteckdosen (Heizer nachts aus für Nachtabsenkung), Display, Wolkensimulation, ...

Viele Grüße,
Olli
 

omega

Well-Known Member
Re: Arduino, Daytime Cluster &amp; Meanwell PWM

Hallo Olli,

omr":31yja4ei schrieb:
In der Loop steht eine Delay von 1s, da zu Debugging-Zwecken noch eine Ausgabe auf dem seriellen Monitor erfolgt. Wenn das nicht mehr erforderlich ist, kann man den Wert runtersetzen.
ich bin ja kein Freund von Delay, aber so übersichtlich, wie Dein Sketch noch ist, geht das aus meiner Sicht Ok. :wink:

Wenn Du den Delay dann aber mal verkürzt, würde ich manche Aufgaben nicht mehr bei jedem Loop-Aufruf erledigen. Z.B. die Uhrzeit, Status etc. auf dem zukünftigen Display auszugeben, dauert verhältnismäßig lange und stiehlt Rechenzeit für andere Aufgaben. Mit einem globalen Zähler kann man ja die Loop-Aufrufe zählen. Wird der Delay z.B. auf 10ms reduziert, reicht es zum Refreshen der Uhrzeit auf dem Display, dies nur alle 100 Loop-Aufrufe zu tun und dann den Zähler auf 0 resetten.
EDIT: die RTC lese ich auch nicht in jedem Loop-Aufruf sondern (timer-gesteuert) nur alle 30 Minuten.

Wenn's interessiert: Bei meinem Arduino läuft das Event-getrieben (wie in jeder modernen GUI-Anwendung) und Timer-getriggert:
- Tastenentprellung per Software alle 10ms, entprellte Taste erzeugt einen Key-Event
- Timer-Events alle 20ms (selber Timer, nutzt jeden 2. Tick), über die 50x pro Sekunde (wegen 12bit) gefadet und über Zähler eingeschränkt die Uhrzeit angezeigt wird
- zusätzliche Events werden erzeugt bei Änderungen an Uhrzeit, Lichtschaltzeiten, für das Hochdrehen der LEDs und Auslösen der Kamera für meine Zeitrafferaufnahmen etc.
Die Main-Loop prüft nur noch, ob ein Event anliegt, und wenn ja, leitet sie dessen Verarbeitung (Dispatching) ein. Bis auf die Initialisierung laufen alle Aufgaben in Event-Handlern voneinander entkoppelt ab. Das macht die ganze Sache übersichtlicher und einfacher zu handhaben, wenn's mal größer wird:
Neue Aufgabe -> neuen Event generieren oder an vorhandenen dran hängen -> neuen Event-Handler schreiben und zu diesem Event registrieren.
Und: es wird nur der Code ausgeführt, für den ein Event vorliegt. Das spart Rechenzeit. Mit Zählern wie oben beschrieben für's Display geht das aber auch.

Der Rest kann im Groben auf http://laus-hiel.de/mikrocontroller/default.html nachgelesen werden.

Grüße, Markus
 

strauch

Active Member
Hallo Olli und Markus,

danke für eure Sketches/Infos. Da muss ich mich mal in Ruhe reindenken.

Grüße

André
 

omr

Member
Moin Markus,

kannst Du da eine weiterführende Website bzgl. Timer/Event-Scheduling auf dem Arduino empfehlen?

Viele Grüße,
Olli (dessen weitere Hobbys auch Astronomie und Fotografie sind)
 

omega

Well-Known Member
Hallo Olli,

das Event Driven Framework habe ich mir selbst geschrieben.
Aber da gäb's z.B. Cosa und QP.
Cosa soll z.T. erheblich schneller sein als die Arduino-eigenen Funktionen, speziell bei den I/O-Pins, siehe diesen Blog und dessen Older Posts.

Grüße, Markus
 

omr

Member
Moin Markus,

danke für die Links, ich werde mir jetzt erstmal eine Eclipse-basierte Entwicklungsumgebung für den Arduino aufsetzen.

Als Fingerübung habe ich mal die anderen Tipps (keine delays, Timer verwenden, RTC nur alle halbe Stunde auslesen) zusammengetippt, hier ist der Rumpf-Sketch, vllt. hilft das ja jemandem.

Viele Grüße,
Olli

Code:
#include <TimeLib.h>
#include <Wire.h>
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

const int RELAY_1 = 7;  // I/O-Pin Relais 1 
const int RELAY_2 = 6;  // I/O-Pin Relais 2
const int RELAY_3 = 5;  // I/O-Pin Relais 3
const int RELAY_4 = 4;  // I/O-Pin Relais 4
const int FADER_1 = 9;  // PWM-Pin LED-Modul 1
const int FADER_2 = 10; // PWM-Pin LED-Modul 2

long OverflowCounter;

void setup()  {

  // Timer 2
  noInterrupts();         // Alle Interrupts temporär abschalten
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 131;            // Timer vorbelegen
  TCCR2B |= (1 << CS22)|(1 << CS21)|(1 << CS20); // Prescaler 1024 für Timer 2
  TIMSK2 |= (1 << TOIE1);   // Timer Overflow Interrupt aktivieren
  interrupts();             // alle Interrupts scharf schalten
  OverflowCounter = 0;
  
  Serial.begin(9600);
  setSyncInterval(1800); // Zeit alle halbe Stunde syncen
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");   
}

ISR(TIMER2_OVF_vect)    // Interrupt alle 8ms        
{
  TCNT2 = 131;          // Zähler erneut vorbelegen
  OverflowCounter++;
}

void loop()
{
  switch (OverflowCounter) {
    case 1:              // alle 8ms
      break;
    case 25:             // alle 200ms
      break;
    case 125:            // alle 1s
      OverflowCounter = 0;
      digitalClockDisplay();
      break;
  }
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(".");
  Serial.print(month());
  Serial.print(".");
  Serial.print(year()); 
  Serial.println(); 
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}
 

strauch

Active Member
omr":2288rwuu schrieb:
Als Fingerübung habe ich mal die anderen Tipps (keine delays, Timer verwenden, RTC nur alle halbe Stunde auslesen) zusammengetippt, hier ist der Rumpf-Sketch, vllt. hilft das ja jemandem.

Hallo Olli,

ja mir hilft das sehr vielen Dank. Ich komme gerade kaum dazu meine Sachen für das Aquarium fertig zu machen und das spart mir dann einiges an Einarbeitungszeit. Vielen Dank

Grüße

André
 

omr

Member
Moin,

der folgende Code ist jetzt für den LED-Teil in Benutzung.

Die Daytime-Cluster haben die Erwartungen erfüllt bis übertroffen. Gerechnet sind die Cluster mit gut 40lm/l (bei 60cm Wassertiefe und teilweiser Abschattung durch Schwimmpflanzen).

2x Daytime Cluster 150.8 (80W), 120lm/Watt, 19200lm gesamt - auf 450l.

Die bisherige Beleuchtung war mit 30lm/l gerechnet.

Die Daytime Cluster sind bei 50% PWM schon deutlich heller als die alte Beleuchtung. Auf 100% zu gehen traue ich mich derzeit noch nicht, erst werden einige Wochen mit 80% folgen.

Ich bin auf den Verbrauch an Makronährstoffen und Eisen gespannt. CO2 habe ich schon etwas höher gedreht.

Ich habe mal damit experimentiert, den für das PWM genutzten Timer1 auf 16bit Auflösung zu drehen - um mehr als 256 Dimmstufen zur Verfügung zu haben.

1. brauche ich nicht, ich sehe keine Steps
2. das Initialisieren des Timers / der Pins auf 16bit führt zu einem "Flackern" der Pinzustände während des Setups, das ist nicht schön. Daher bin ich bei 8bit geblieben.

Viele Grüße,
Olli

Code:
#include <TimeLib.h>
#include <Wire.h>
#include <DS1307RTC.h>

const int FADER_1 = 9;  // PWM-Pin LED 1
const int FADER_2 = 10; // PWM-Pin LED 2

// Diese Variable wird mit millis() als Timer genutzt
unsigned long mstime;

// Die Helligkeitswerte (0-255) und Uhrzeiten (in min) sind jetzt als Array gespeichert.
// Minuten, um kein long verwenden zu müssen
// Von 06:59 bis 07:00 wird auf 25 (10%) gedimmt, da das die Einschaltschwelle der Module ist

int Fader[12][2] = { 
  {   0,    0 },
  {   0,  419 }, // 06:59
  {  25,  420 }, // 07:00
  { 210,  480 }, // 08:00
  { 210,  780 }, // 13:00
  { 110,  810 }, // 13:30
  { 110,  990 }, // 16:30
  { 210, 1020 }, // 17:00
  { 210, 1260 }, // 21:00
  {  25, 1380 }, // 23:00
  {   0, 1381 }, // 23:01
  {   0, 1440 }  // 24:00
};
 
void setup() {
  Serial.begin(9600);
  while (!Serial) ;         // wait until Arduino Serial Monitor opens
  setSyncProvider(RTC.get); // Definition der RTC als Zeitquelle
  setSyncInterval(1800);    // Systemzeit alle 30min mit der RTC syncen
  
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with RTC");
  else
     Serial.println("RTC has set system time");   
  
  // PWM definiert auf 0% setzen
  analogWrite(FADER_1, 0);
  analogWrite(FADER_2, 0);

  // ms seit Programmstart in Variable speichern - dient dem Timing der main loop
  mstime = millis();
}

void loop() {
  // jede Sekunde die Funktion fader() ausführen
  if (millis() - mstime >= 1000)
    fader();
}

// holt die Tageszeit als Sekunden seit Mitternacht aus der Systemzeit
long SecondsSinceMidnight() {
  long hr = hour();
  long min = minute();
  long sec = second();
  long Total = hr * 3600 + min * 60 + sec;
  return Total;
}

// Hier findet die Berechnung des Helligkeitswertes auf Basis des Arrays "Fader" statt.
// Auf eine getrennte Behandlung beider Balken habe ich verzichtet, beide werden synchron gedimmt.
void fader() {
  long currentTime = SecondsSinceMidnight();
  if (currentTime == 0)
    currentTime++;
  for(int i = 0; i < 11; i++){
      if (currentTime <= (long) Fader[i][1] * 60) {
        float fadeValue3 = (float) (currentTime - (long) Fader[i-1][1] * 60) / ((long)Fader[i][1] *60 - (long) Fader[i-1][1] *60);
        int fadeValue = fadeValue3 * (Fader[i][0] - Fader[i-1][0]) + Fader[i-1][0];
        Serial.println(fadeValue);
        analogWrite(FADER_1, fadeValue);
        analogWrite(FADER_2, fadeValue);
        break;
      } 
  }
  mstime = millis(); //Timing-Varaible neu setzen
}
 

Ähnliche Themen

Oben