Lüfter mit zeitlichem Verzug zuschalten wenn Relais auf Durchlass steht

Hallo,

ich habe ein Relais, dessen Zustand von einem Temperatursensor gesteuert wird. Das Relais (im sketch "Heater" genannt) wiederum kontrolliert die Stromversorgung einer 12V Heizfolie . Ausserdem wird die vom Sensor gemessene Temperatur auf einem LCD angezeigt.

Nun möchte ich, dass ein PWM fähiger, ebenfalls via externen 12 V versorgter CPU Fan (im sketch "HeaterFan" genannt), dem Zustand des Heaters folgt. Wenn der Heater an ist soll analogWrite=150 gelten; wenn der Heater aus ist soll analogWrite=0 gelten. Das Besondere dabei ist, dass der Heaterfan mit Verzögerung dem Heater folgen soll: 120s nachdem der Heater angeschaltet wurde soll der Heaterfan an gehen und 240s nachdem der Heater ausgeschaltet wurde, soll der heaterfan aus gehen.

Kann mir bitte jemand sagen wie ich das am einfachsten in meinen Code reinbekomme?

Was ich sicher weiss: Die beiden Einzelkomponenten funktionieren wunderbar - das Relais schaltet in Abhängigkeit der Zeit und der PWM fan lässt sich wunderbar via analogWrite steuern.

Danke

edit:
Es muss irgendwie mit einer zusätzlichen Variablen gehen mMn - die kann zwei Werte haben. Immer beim Anschalten oder Ausschalten des Heaters ändert sich der Wert auf das Gegenteil des Ist-Werts. Mit dieser Variablen und unter Einhaltung der oben beschriebenen assymetrischen Verzugszeiten muss der PWM Signalpin irgendwie mit einer if-condition in Abhängigkeit gesetzt werden. Aber wie genau? Ich habe schon viel rumprobiert aber das funktioniert alles nicht.

#include "DHT.h" // Library von Adafruit
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
DHT dht1(8, DHT22); // Assign DHT22 (AM2302) Sensor to Pin 8
const int Heater = 4; // Assign Heater to Pin 4
const int HeaterFan = 9; // Assign HeaterFan to Pin 9
float T; // Temperature
const float maxT = 35; // The max temperature allowed
const float minT = 32; // The min temperature allowed
long DHTPreviousTime = 0; // Marker DHT22
const long DHTInterval = 2000; // DHT22 measuring interval

void setup() {
Serial.begin(9600); // Initiate Serial Monitor
lcd.begin(); // Initiate LCD
dht1.begin(); // Initiate DHT22 Sensor
pinMode(Heater, OUTPUT); // Initiate Heater Pin as output
digitalWrite(Heater, HIGH); // Set initial Heater state high (Relais is low triggered)
pinMode(HeaterFan, OUTPUT); // Initiate HeaterFan Pin as output
analogWrite(HeaterFan, 0); // Set initial HeaterFan state 0

void loop() {
unsigned long currentTime = millis(); // Update The Time
// Update T value
if (currentTime - DHTPreviousTime > DHTInterval) {
DHTPreviousTime = currentTime;
float T = dht1.readTemperature(); // Get temperature
// Display on LCD and Serial Monitor if DHT22 Sensor is not operational
if (isnan(RLF) || isnan(T)) {
Serial.println("Sensorfehler!");
lcd.clear();
lcd.print("Sensorfehler!");}
else {
// Display updated T values on LCD
lcd.clear();
lcd.print(String(" T: ") + String(T) + String(" \xDF") + String("C"));
}
// T depending Heating
if (T <= minT) {
digitalWrite(Heater, LOW); // am Relais verbunden ist COM-NO; Relais is low triggered
}
if (T >= maxT) {
digitalWrite(Heater, HIGH);
}
}
}

Dein Code, den Du nicht in Codetags gesetzt hast kompiliert nicht.
Es fehlt mindestens eine Klammer.
Aus diesem Grund auch von mir nur einen Code, der "hingerotzt" ist.

Sollte aber Deine Aufgabenstellung darstellen.

#include “DHT.h” // Library von Adafruit
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
DHT dht1(8, DHT22); // Assign DHT22 (AM2302) Sensor to Pin 8
const int Heater = 4; // Assign Heater to Pin 4
const int HeaterFan = 9; // Assign HeaterFan to Pin 9
float T; // Temperature
const float maxT = 35; // The max temperature allowed
const float minT = 32; // The min temperature allowed
long DHTPreviousTime = 0; // Marker DHT22
const long DHTInterval = 2000; // DHT22 measuring interval
const unsigned long einschaltverzoegerung = 120000;
unsigned long startmillis;
bool einschalt = false;

void setup() {
  Serial.begin(9600); // Initiate Serial Monitor
  lcd.begin(); // Initiate LCD
  dht1.begin(); // Initiate DHT22 Sensor
  pinMode(Heater, OUTPUT); // Initiate Heater Pin as output
  digitalWrite(Heater, HIGH); // Set initial Heater state high (Relais is low triggered)
  pinMode(HeaterFan, OUTPUT); // Initiate HeaterFan Pin as output
  analogWrite(HeaterFan, 0); // Set initial HeaterFan state 0
}
void loop() {
  unsigned long currentTime = millis(); // Update The Time
  // Update T value
  if (currentTime - DHTPreviousTime > DHTInterval) {
    DHTPreviousTime = currentTime;
    float T = dht1.readTemperature(); // Get temperature
    // Display on LCD and Serial Monitor if DHT22 Sensor is not operational
    if (isnan(RLF) || isnan(T)) {
      Serial.println(“Sensorfehler!”);
      lcd.clear();
      lcd.print(“Sensorfehler!”);
    }
    else {
      // Display updated T values on LCD
      lcd.clear();
      lcd.print(String(" T: “) + String(T) + String(” \xDF") + String(“C”));
    }
    // T depending Heating
    if (T <= minT) {
      digitalWrite(Heater, LOW); // am Relais verbunden ist COM-NO; Relais is low triggered
      einschalt = false;
    }
    if (T >= maxT && einschalt == false)
    {
      startmillis = millis();
      einschalt = true;
    }
    if (millis() - startmillis > einschaltverzoegerung && einschalt == true) {
      digitalWrite(Heater, HIGH);
    }
  }
}

Du koenntest evtl. merken, das das nicht tut was es soll.

Hi,

danke für deine Antwort. Bzgl der fehlenden Klammer muss das beim c&p passiert sein - sorry. Und auch allgemein bin ich Laie auf dem Gebiet Arduino. Deshalb gerne ausführlich :slight_smile:

unsigned long startmillis;
bool einschalt = false;

das verstehe ich; eine Zeitmarke (genutzt um das Einschalten des Heaters zu tracken) und eine zusätzliche bool Variable.

    // T depending Heating
    if (T <= minT) {
      digitalWrite(Heater, LOW); // am Relais verbunden ist COM-NO; Relais is low triggered
      einschalt = false;
    }
    if (T >= maxT && einschalt == false)
    {
      startmillis = millis();
      einschalt = true;
    }
    if (millis() - startmillis > einschaltverzoegerung && einschalt == true) {
      digitalWrite(Heater, HIGH);
    }

Das verstehe ich leider nicht. Zum Einen ist das Relais/Heater"low triggered" und dann ist auch die Abschaltverzögerung in deinem Entwurf nicht spezifiziert. Ganz grundsätzlich: Müsste da nicht irgendetwas mit dem HeaterFan passieren?
Ich drücke es mal mit meinen Worten aus:

  1. Wenn T<=minT geht das Relais LOW (und der Heizer damit an)
  2. Sobald der Heizer angeht gilt einschalt = true
  3. sobald Einschaltverzoegerung abgelaufen und falls immernoch gilt "einschalt = true" soll gelten: analogWrite(Heaterfan, 150);
  4. dann bleibt alles so wie es ist
  5. irgendwann ist T>=maxT, das Relais geht HIGH (Heizer aus)
  6. es soll ab dann gelten: einschalt = false
  7. sobald Abschaltverzoegerung abgelaufen und falls imemrnoch gilt "einschalt = false" soll gelten: analogWrite(Heaterfan, 0);

Müsste das so nicht funktionieren? Falls ja, wie verwandle ich das in Arduinocode?

Gebastelt - ich hab Deinen Post noch nicht durch - ich denke aber, das wir uns hier treffen:

// Forensketch - basiert auf: https://forum.arduino.cc/t/lufter-mit-zeitlichem-verzug-zuschalten-wenn-relais-auf-durchlass-steht/856635
// ungetestet - unkompiliert
// Bitte einige Änderungen zwischendurch beachten

#include “DHT.h” // Library von Adafruit
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
DHT dht1(8, DHT22); // Assign DHT22 (AM2302) Sensor to Pin 8
const int Heater = 4; // Assign Heater to Pin 4
const int HeaterFan = 9; // Assign HeaterFan to Pin 9
float T; // Temperature
const float maxT = 35; // The max temperature allowed
const float minT = 32; // The min temperature allowed
long DHTPreviousTime = 0; // Marker DHT22
const long DHTInterval = 2000; // DHT22 measuring interval
enum {an, aus}; // Stellt die Zustände LOW-aktiv dar

void setup() {
  Serial.begin(9600); // Initiate Serial Monitor
  lcd.begin(); // Initiate LCD
  dht1.begin(); // Initiate DHT22 Sensor
  pinMode(Heater, OUTPUT); // Initiate Heater Pin as output
  digitalWrite(Heater, HIGH); // Set initial Heater state high (Relais is low triggered)
  pinMode(HeaterFan, OUTPUT); // Initiate HeaterFan Pin as output
  analogWrite(HeaterFan, 0); // Set initial HeaterFan state 0
}
void loop()
{
  if (millis() - DHTPreviousTime > DHTInterval)
  {
    DHTPreviousTime = millis();
    float T = dht1.readTemperature(); // Get temperature
    // Display on LCD and Serial Monitor if DHT22 Sensor is not operational
    if (isnan(RLF) || isnan(T)) {
      Serial.println(“Sensorfehler!”);
      lcd.clear();
      lcd.print(“Sensorfehler!”);
    }
    else
    {
      // Display updated T values on LCD
      lcd.clear();
      lcd.print(String(" T: “) + String(T) + String(” \xDF") + String(“C”));
      //Ab hier komplett neu:
      heat();
    }
  }
}

void heat()
{
  static unsigned long startmillis = 0; // Merker für Startzeit der Einschaltverzoegerung
  const einschaltverzoegerung = 120000; // millis der Einschaltverzögerung
  enum {off, heat, fan};                // Zustände
  static switchT = off;                 // Auswahl
  if (T >= maxT) {                      // Wenn - dann (aus)
    switchT = off;
  }
  switch (switchT)                      // Schrittkette
  {
    case off:                           // wenn schritt aus:
      digitalWrite(Heater, aus);
      digitalWrite(Heaterfan, aus);
      if (T < minT)                     // aber die Grösse erreicht
      {
        switchT = heat;                 // nächster Schritt
      }
      break;
    case heat:                          // Wenn
      startmillis = millis();           // merken wann angefangen
      digitalWrite(Heater, an);         // Heizung starten
      switchT = fan;                    // nächster Schritt
      break;
    case fan:                           // letzter Schritt
      if (millis() - startmillis > einschaltverzoegerung) // Wenn Zeit abgelaufen
      {
        digitalWrite(Heaterfan, an);    // start noch den Fan
      }
      break;
  }
}
1 Like

Vielen Dank :slight_smile:

Hat es einen bestimmten Grund weshalb du die global ganz zu Beginn des loops vorhandene Abfrage rausgenommen hast:

unsigned long currentTime = millis();  

Dafür 1:1 an jeder Stelle direkt durch milis() ersetzt? Habe auch schon drüber nachgedacht ob das "sauberer" wäre, wenn ich das so machen würde.

Ansonsten verstehe ich es nicht alles sofort - mit switch case kenn ich mich nämlich noch weniger aus. Ich versuche das mal zu vrestehen und umzusetzen aber einfach wird das nicht! Irgendwie hatte ich die naive Hoffnung, dass das asymmetrisch zeitverzögerte Nachziehen des HeaterFan auch aufbauend mit dem Vorhandenen & mit der noob/basic syntax geht, die ich schon im sketch verwende.

Ja.
Jede nicht einzusetzende Variable ist freier Speicherplatz.

Wenn Du einen Wert nicht zweimal benutzen musst, dann immer den aktuellen Wert abfragen.

Beispiel:
In Deinem Code ist es wurscht, ob zwischen der ersten Auswertung und der zweiten Auswertung eine gewisse Zeit vergeht.

Ich mach das auch mit lesen von PIN's so.
also digitalRead(InputPin) gibt mit immer den Zustand wieder, der zum Zeitpunkt der Abfrage gültig ist.
Das geht für den größten Teil der Einsätze.
Aber es gibt ab und an den Fall, das genau dieser PinZustand weiter verwendet werden muss. Da reicht dann ein bool.

Das mit der switch/case ist eine reine Kette von Befehlsfolgen, in der vorhergehende die nachfolgenden nicht beeinflussen können.
Der zu entwickelnde Code wäre gedanklich anders aufzubauen.

  if (T >= maxT) 
  {
      digitalWrite(Heater, aus);
      digitalWrite(Heaterfan, aus);
  }
  if (T<=minT)
  {   
    digitalWrite(Heater, an);
  }

Das ist der Einstieg.
Aber wann und wie geht das jetzt mit dem Ventilator?
Also als erstes Zeit merken:

  if (T<=minT)
  {   
    digitalWrite(Heater, an);
    lastmillis=millis();
  }

Dieser Merker würde aber solange neu gestellt, wie die Bedingung T<=minT erfüllt ist. Das kann ggfls. schon ne Weile dauern.

Jetzt bau mal aus dem Schnipsel gedanklich weiter...
Also zum einen sperren, das nicht ständig lastmillis zurückgesetzt wird und dann auch noch, das der FAN tatsächlich einsetzt und das Ganze auch wieder ausgeht...

Es könnte vielleicht so gehen:

  if (T >= maxT)
  {
    digitalWrite(Heater, aus);
    digitalWrite(Heaterfan, aus);
    lastmillis = 0;
  }
  if (T <= minT && lastmillis != 0)
  {
    digitalWrite(Heater, an);
    lastmillis = millis();
  }
  if (millis() - lastmillis > 12000)
  {
    digitalWrite(HeaterFan, an);
    lastmillis=0;
  }

(Evtl. Schreibweise der Variablen anpassen)
Aber Du siehst selbst, das lastmillis in jeder Bedingung erforderlich ist und Du prüfst bei jedem Durchlauf alle Bedingungen - im Gegensatz zur Schrittkette, wo mit jedem Durchlauf nur eine Auswahl abgerufen wird.

1 Like

Hallo my_xy_projekt,

großen Dank für deine Mühe und dass du dich da gedanklich darauf eingelassen hast!

Ich habe leider erst wieder am Wochenende die Möglichkeit zum Ausprobieren. Deinen Code kann ich gut nachvollziehen und bin deshalb optimistisch, dass ich das umgesetzt bekomme :slight_smile: Dann noch um die Ausschaltverzögerung erweitern. Bin echt gespannt - danke nochmal!

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