Zeitsteuerung

Hallo zusammen,
ich könnte etwas Hilfe bei meinem ersten Arduino Projekt gebrauchen.
Ich möchte meine Solarzirkulationspumpe, welche mit vier Geschwindigkeiten laufen kann, gerne abhängig von der Vorlauftemperatur der Solaranlage über vier Relais ansteuern.
Soll heißen, wenn die Vorlauftemperatur nach zwei Minuten bei Pumpenstufe 2 immer noch über 64°C beträgt soll auf Stufe 3 geschalten werden, wenn Vorlauftemperatur nach 2 Minuten unter 58°C fällt auf Stufe 1 usw.
Mein Sketch funktioniert schon mal nicht schlecht aber ich würde gerne die "delay´s", die gebraucht werden um die Wassertemperatur im Solarvorlauf zeitverzögert abzunehmen, mit der "millis" Funktion ersetzen.
Ich check aber die Sache mit den "millis" nicht.
Oder gibt es noch ne andere Zeitfunktion mit der das programm nicht komplett angehalten wird?

Hier mein Projekt, vielleicht hat jemand Lust sich das mal anzuschauen.
Danke schon mal.

int TMP36= A0; //Der Sensor am Pin A0 "TMP36"
int sensorwert;
int temperatur = 0; //Unter der Variablen "temperatur" wird später der Temperaturwert abgespeichert.
int t=500; //Der Wert für „t“ gibt im Code die zeitlichen Abstände zwischen den einzelnen Messungen vor.
int rel1 = 2;
int rel2 = 3;
int rel3 = 4;
int rel4 = 5;
int rel1a=digitalRead(rel1);
int rel2a=digitalRead(rel2);
int rel3a=digitalRead(rel3);
int rel4a=digitalRead(rel4);

#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_I2C.h> // LiquidCrystal_I2C Bibliothek einbinden
LiquidCrystal_I2C lcd(0x3F, 16, 2); 

void setup() {
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);

Serial.begin(9600); //Im Setup beginnt die serielle Kommunikation, Temperatur an den serial monitor.

lcd.init(); //Im Setup wird der LCD gestartet 
lcd.backlight(); //Hintergrundbeleuchtung einschalten (lcd.noBacklight(); schaltet die Beleuchtung aus). 
}

void loop() 
{
sensorwert=analogRead(TMP36); //Auslesen des Sensorwertes.
temperatur= map(sensorwert, 0, 409, -50, 150); //Umwandeln des Sensorwertes mit Hilfe des "map" Befehls.
Serial.print(temperatur); //Nun wird der Wert „temperatur“ über die serielle Kommunikation an den PC gesendet.
Serial.println(" Grad Celsius"); // Im seriellen Monitor wird hinter der Temperatur die Einheit eingeblendet.
delay(t); // Nach jeder Messung ist je eine kleine Pause mit der Dauer „t“ in Millisekunden.

lcd.setCursor(0, 0);//Position des ersten Zeichens (0,0) bedeutet das erste Zeichen in der ersten Zeile. 
lcd.print("Solartemperatur"); 
lcd.setCursor(0, 1); 
lcd.print(temperatur); 
lcd.setCursor(3, 1);
lcd.print("C");

rel1a=digitalRead(rel1);
rel2a=digitalRead(rel2);
rel3a=digitalRead(rel3);
rel4a=digitalRead(rel4);

if (rel1a == 0 && rel2a == 0 && rel3a == 0 && rel4a == 0) //Relais 1 einschalten
{
digitalWrite(rel1, HIGH);
digitalWrite(rel2, LOW);
digitalWrite(rel3, LOW);
digitalWrite(rel4, LOW);
lcd.setCursor(7, 1);
lcd.print("Stufe 1");
}

Serial.println(rel1a);
Serial.println(rel2a);
Serial.println(rel3a);
Serial.println(rel4a);

if (temperatur > 64 && rel1a == 1 && rel2a == 0 && rel3a == 0 && rel4a ==0) //Relais 2 einschalten
do
{
digitalWrite(rel1, LOW);
digitalWrite(rel2, HIGH);
digitalWrite(rel3, LOW);
digitalWrite(rel4, LOW);
sensorwert=analogRead(TMP36);
temperatur=map(sensorwert, 0, 409, -50, 150);
Serial.print(temperatur); 
Serial.println(" Grad Celsius"); 
lcd.setCursor(7, 1);
lcd.print("Stufe 2");
delay(120000);
}
while (temperatur > 58 && temperatur <= 65 && rel1a == 0 && rel2a == 1 && rel3a == 0 && rel4a == 0);
//delay(5000);

if (temperatur <= 58 && rel1a == 0 && rel2a == 1 && rel4a == 0 && rel4a == 0) //Relais 2 ausschalten
{
digitalWrite(rel1, HIGH);
digitalWrite(rel2, LOW);
digitalWrite(rel3, LOW);
digitalWrite(rel4, LOW);
lcd.setCursor(7, 1);
lcd.print("Stufe 1");
}

if (temperatur > 64 && rel1a == 0 && rel2a == 1 && rel3a == 0 && rel4a == 0) //Relais 3 einschalten
do
{
digitalWrite(rel1, LOW);
digitalWrite(rel2, LOW);
digitalWrite(rel3, HIGH);
digitalWrite(rel4, LOW);
sensorwert=analogRead(TMP36);
temperatur=map(sensorwert, 0, 409, -50, 150);
Serial.print(temperatur); 
Serial.println(" Grad Celsius"); 
lcd.setCursor(7, 1);
lcd.print("Stufe 3");
delay(120000);
}
while (temperatur > 58 && temperatur <= 65 && rel1a == 0 && rel2a == 0 && rel3a == 1 && rel4a == 0);
//delay(5000);

if (temperatur <= 58 && rel1a == 0 && rel2a == 0 && rel3a == 1 && rel4a == 0) //Relais 3 ausschalten
{
digitalWrite(rel1, LOW);
digitalWrite(rel2, HIGH);
digitalWrite(rel3, LOW);
digitalWrite(rel4, LOW);
 lcd.setCursor(7, 1);
lcd.print("Stufe 2");
}
 
if (temperatur > 64 && rel1a == 0 && rel2a == 0 && rel3a == 1 && rel4a == 0) //Relais 4 einschalten
do
{
digitalWrite(rel1, LOW);
digitalWrite(rel2, LOW);
digitalWrite(rel3, LOW);
digitalWrite(rel4, HIGH);
sensorwert=analogRead(TMP36);
temperatur=map(sensorwert, 0, 409, -50, 150 );
Serial.print(temperatur); 
Serial.println(" Grad Celsius"); 
lcd.setCursor(7, 1);
lcd.print("Stufe 4");
delay(120000);
}
while (temperatur > 58 && rel1a == 0 && rel2a == 0 && rel3a == 0 == rel4a == 1);
//delay(5000);

if (temperatur <= 58 && rel1a == 0 && rel2a == 0 && rel3a == 0 && rel4a == 1) //Relais 4 ausschalten
{
digitalWrite(rel1, LOW);
digitalWrite(rel2, LOW);
digitalWrite(rel3, HIGH);
digitalWrite(rel4, LOW);
lcd.setCursor(7, 1);
lcd.print("Stufe 3");
}

Serial.print(temperatur); 
Serial.println(" Grad Celsius"); 
}

Das Serial print kommt dann irgendwann mal raus.

Bitte setze Deinen Sketch in Code Tags [code] und [/code] (ohne die *), das kannst Du auch jetzt noch machen, dann ist er besser lesbar.
Dann suche hier im Forum nach der Nachtwächtererklärung, die ist sehr gut verständlich.

Ich check aber die Sache mit den "millis" nicht.

Dann sieh dir doch BlinkWithoutDelay genau an.
Damit sollte das dann ebenso hinzubringen sein.

Deine delays müssen jedenfalls komplett raus.

Hallo,
wenn ich dein Programm richtig verstanden habe benötigst Du eigendlich ein paar Zeitverzögerungen, mit denen Du nach einem Schaltvorgang der Pumpe den Messwert abfragst um die Reaktion des Schaltvorganges messen zu können. Um das mit millis(0) zuverstehen und zu lernen hast Du ja bereits Antworten bekommen.

Um Verzögerungszeiten in Deinem konkreten Fall zu realisieren gibts wie immer mehrere Möglichkeiten.
Ich würde mir dazu eine Funktion mit Parameter Übergabe bauen die einen bool wert zurückliefert der TRUE ist wenn die Zeit abgelaufen ist und und der parameter start TRUE ist. Die Funktion kannst Du vorher schön testen und wenn sie funktioniert in deinen Sketch einbauen und dann beliebig oft verwenden.

bool delayon( bool start, unsigend long altzeit, unsigend long delayzeit)

für die zu übergebenden Parameter kannst Du dann ausserhalb der Funktion aussagekräftige Namen vergeben und im Allgemeinteil entsprechend dem Datenformat global definieren. Die Fuktion selbst kannst Du dann im loop absolut aufrufen.

schönes neuse Jahr ans Forum

Heinz

also ich hab jetzt folgendes gemacht:

Zunächst habe ich mal STRG-T gedrückt, damit das lesbar wird.

Dann die Serielle Verbindung auf 115200 erhöt.
dann die pinMode auf deine Pins geändert (wozu hast du sie sonst angelegt)

Enumeration state für den Status eingeführt

alle "Todos" aus dem If in eigene (Sub)Funktionen verschoben

Messungen und Serial-Ausgabe nur alle t Millisekunden - Einfach nach Beispiel BlinkWithoutDelay
Alle Ausgaben im Loop in dieses If gegeben

Die Relais lesen wir bei jedem Durchgang aus, daher habe ich das ganz an den Anfang des loop gestellt.

Dann habe ich deine Ifs noch zusätzlich vom state abhängig gemacht und beim "Hochschalten" jeweils noch auf den zeitablauf abgefragt

dann in den "Todos" das Auslesen der Sensoren und die doppelten Ausgaben auskommentiert - das wird ohnehin alle 500ms aktualisert

/*
   Ich möchte meine Solarzirkulationspumpe, welche mit vier Geschwindigkeiten laufen kann, gerne abhängig von der Vorlauftemperatur der Solaranlage über vier Relais ansteuern.

   http://forum.arduino.cc/index.php?topic=588139.msg0#new
*/


const int TMP36 = A0; //Der Sensor am Pin A0 "TMP36"
int sensorwert;
int temperatur = 0; //Unter der Variablen "temperatur" wird später der Temperaturwert abgespeichert.
//int t = 500; //Der Wert für „t" gibt im Code die zeitlichen Abstände zwischen den einzelnen Messungen vor.
const int rel1 = 2;
const int rel2 = 3;
const int rel3 = 4;
const int rel4 = 5;
int rel1a = digitalRead(rel1);
int rel2a = digitalRead(rel2);
int rel3a = digitalRead(rel3);
int rel4a = digitalRead(rel4);

unsigned long previousMillis = 0;
const unsigned long interval = 500;           //gibt im Code die zeitlichen Abstände zwischen den einzelnen Messungen vor.

unsigned long previousMillisStufe = 0;
unsigned long intervalStufe = 120000;            //setzen wir abhängig der Stufe, daher kein const


#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_I2C.h> // LiquidCrystal_I2C Bibliothek einbinden
LiquidCrystal_I2C lcd(0x3F, 16, 2);

enum stati {Stufe1, Stufe2, Stufe3, Stufe4}; // ja ich weis, stati ist nicht die Mehrzahl von Status.
stati state = Stufe1;


void do_stufe1()
{
  digitalWrite(rel1, HIGH);
  digitalWrite(rel2, LOW);
  digitalWrite(rel3, LOW);
  digitalWrite(rel4, LOW);
  lcd.setCursor(7, 1);
  lcd.print("Stufe 1");

  Serial.println(F("Stufe 1"));
  state = Stufe1;
  previousMillisStufe = millis();
  intervalStufe = 5000;
}

void do_stufe2()
{
  digitalWrite(rel1, LOW);
  digitalWrite(rel2, HIGH);
  digitalWrite(rel3, LOW);
  digitalWrite(rel4, LOW);
  //sensorwert = analogRead(TMP36);
  //temperatur = map(sensorwert, 0, 409, -50, 150);
  //Serial.print(temperatur);
  //Serial.println(" Grad Celsius");
  lcd.setCursor(7, 1);
  lcd.print("Stufe 2");

  Serial.println(F("Stufe 2"));
  state = Stufe2;
  previousMillisStufe = millis();
  intervalStufe = 5000;
}

void do_stufe3()
{
  digitalWrite(rel1, LOW);
  digitalWrite(rel2, LOW);
  digitalWrite(rel3, HIGH);
  digitalWrite(rel4, LOW);
  //sensorwert = analogRead(TMP36);
  //temperatur = map(sensorwert, 0, 409, -50, 150);
  //Serial.print(temperatur);
  //Serial.println(" Grad Celsius");
  lcd.setCursor(7, 1);
  lcd.print("Stufe 3");

  Serial.println(F("Stufe 3"));
  state = Stufe3;
  previousMillisStufe = millis();
  intervalStufe = 5000;
}

void do_stufe4()
{
  digitalWrite(rel1, LOW);
  digitalWrite(rel2, LOW);
  digitalWrite(rel3, LOW);
  digitalWrite(rel4, HIGH);
  //sensorwert = analogRead(TMP36);
  //temperatur = map(sensorwert, 0, 409, -50, 150 );
  //Serial.print(temperatur);
  //Serial.println(" Grad Celsius");
  lcd.setCursor(7, 1);

  Serial.println(F("Stufe 4"));
  lcd.print("Stufe 4");
  state = Stufe4;
  previousMillisStufe = millis();
  intervalStufe = 5000;
}


void setup() {
  pinMode(rel1, OUTPUT);
  pinMode(rel2, OUTPUT);
  pinMode(rel3, OUTPUT);
  pinMode(rel4, OUTPUT);
  Serial.begin(115200); //Im Setup beginnt die serielle Kommunikation, Temperatur an den serial monitor.
  Serial.println(F("\nSolarzirkulationspumpe"));
  Serial.println(F("Ausgaben wie Fixtext mit dem F-Makro spart RAM!!!"));
  lcd.init(); //Im Setup wird der LCD gestartet
  lcd.backlight(); //Hintergrundbeleuchtung einschalten (lcd.noBacklight(); schaltet die Beleuchtung aus).
}


void loop()
{
  rel1a = digitalRead(rel1);
  rel2a = digitalRead(rel2);
  rel3a = digitalRead(rel3);
  rel4a = digitalRead(rel4);


  if (millis() - previousMillis >= interval)
  {
    sensorwert = analogRead(TMP36);                 //Auslesen des Sensorwertes.
    temperatur = map(sensorwert, 0, 409, -50, 150); //Umwandeln des Sensorwertes mit Hilfe des "map" Befehls.
    Serial.print(temperatur);                       //Nun wird der Wert „temperatur" über die serielle Kommunikation an den PC gesendet.
    Serial.println(" Grad Celsius");                // Im seriellen Monitor wird hinter der Temperatur die Einheit eingeblendet.

    lcd.setCursor(0, 0);//Position des ersten Zeichens (0,0) bedeutet das erste Zeichen in der ersten Zeile.
    lcd.print("Solartemperatur");
    lcd.setCursor(0, 1);
    lcd.print(temperatur);
    lcd.setCursor(3, 1);
    lcd.print("C");

    Serial.print(temperatur);
    Serial.println(" Grad Celsius");

    Serial.println(rel1a);
    Serial.println(rel2a);
    Serial.println(rel3a);
    Serial.println(rel4a);
    previousMillis = millis();
  }

  // und hier die eigentliche Statemaschine für deine Relais

  if (rel1a == 0 && rel2a == 0 && rel3a == 0 && rel4a == 0) //Relais 1 einschalten   - das kann eigentlich nur ganz am Anfang erfüllt sein oder?
  {
    do_stufe1();
  }


  if (state == Stufe1 && temperatur > 58 && (millis() - previousMillisStufe >= intervalStufe)) //Relais 2 einschalten
  {
    do_stufe2();
  }

  if (state == Stufe2 && temperatur <= 58) // achtung, hier habe ich keinen Zeitablauf drinnen, kannst aber auch machen
  {
    do_stufe1();
  }

  if (state == Stufe2 && (millis() - previousMillisStufe >= intervalStufe) && temperatur > 64) //Relais 3 einschalten
  {
    do_stufe3();
  }
  if (state == Stufe3 &&  temperatur <= 58) //Relais 3 ausschalten
  {
    do_stufe2();
  }

  if (state == Stufe3 && (millis() - previousMillisStufe >= intervalStufe) && temperatur > 64) //Relais 4 einschalten
  {
    do_stufe4();
  }

  if (state == Stufe4 && temperatur <= 58) //Relais 4 ausschalten
  {
    do_stufe3();
  }
}

Also einmal ein BlinkWithoutDelay für die Ausgabe, und dann eine Statemaschine für deine Schalterei.
Es kompiliert, es gibt was aus, es reagiert auf einen Poti, es zahlt die Status hoch und runter.

Logikfehler musst jetzt noch selber ausbessern.

Die IFs kannst noch zusammen räumen ja eigentlich die ganzen do_irgendwas lassen sich auch auf eine einzige Funktion zusammenführen, aber so verstehst du hoffentlich das Prinzip da es auf deinen alten Code aufbaut.

Zeitaufwand: ja doch über 60min, hat gefuchst.

void do_stufe1()
{
...
  state = Stufe1;
...
}

Wie kommt das Programm jemals aus dieser Stufe heraus?

Danke für die vielen Antworten,
ich war auch fleissig und hab meinen Sketch überarbeiten und er funktioniert sogar obwohl ich das mit den "millis" immer noch nicht richtig kapiere.

Danke noiasca für deine Bemühungen. Den Sketch werd ich auf jeden Fall auch mal bei Gelegenheit testen.
Meiner sieht jetzt so aus und muß sich in den nächsten Tagen bei Sonnenschein in der Praxis bewähren.

int TMP36 = A0; //Der Sensor TMP36 am Pin A0
int sensorwert;
int temperatur = 0; //Unter der Variablen "temperatur" wird der Temperaturwert abgespeichert.
int rel1 = 2;
int rel2 = 3;
int rel3 = 4;
int rel4 = 5;
int rel1a = digitalRead(rel1);
int rel2a = digitalRead(rel2);
int rel3a = digitalRead(rel3);
int rel4a = digitalRead(rel4);
int t = 500;
unsigned long startzeit = 0;
#define verzoegerung 120000UL
#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_I2C.h> // Vorher hinzugefügte LiquidCrystal_I2C Bibliothek einbinden
LiquidCrystal_I2C lcd(0x3F, 16, 2); //Hier wird festgelegt um was für einen Display es sich handelt. In diesem Fall eines mit 16 Zeichen

void setup() {
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);

lcd.init(); //Im Setup wird der LCD gestartet
lcd.backlight(); //Hintergrundbeleuchtung einschalten (lcd.noBacklight(); schaltet die Beleuchtung aus).
}

void loop()
{
sensorwert = analogRead(TMP36); //Auslesen des Sensorwertes.
temperatur = map(sensorwert, 0, 409, -50, 150); //Umwandeln des Sensorwertes mit Hilfe des "map" Befehls.
delay (t);
lcd.setCursor(0, 0);//Hier wird die Position des ersten Zeichens festgelegt. (0,0) bedeutet das erste Zeichen in der ersten Zeile.
lcd.print("Solartemperatur");
lcd.setCursor(0, 1);//
lcd.print(temperatur);
lcd.setCursor(3, 1);
lcd.print("C");

rel1a = digitalRead(rel1);
rel2a = digitalRead(rel2);
rel3a = digitalRead(rel3);
rel4a = digitalRead(rel4);

//Relais 1 einschalten
if (rel1a == 0 && rel2a == 0 && rel3a == 0 && rel4a == 0)
{
digitalWrite(rel1, HIGH);
digitalWrite(rel2, LOW);
digitalWrite(rel3, LOW);
digitalWrite(rel4, LOW);
lcd.setCursor(7, 1);
lcd.print("Stufe 1");
startzeit = millis();
}

//Relais 2 einschalten
if (millis() - startzeit >= verzoegerung && temperatur > 64 && rel1a == 1 && rel2a == 0 && rel3a == 0 && rel4a == 0)
do
{
startzeit = millis();
digitalWrite(rel1, LOW);
digitalWrite(rel2, HIGH);
digitalWrite(rel3, LOW);
digitalWrite(rel4, LOW);
sensorwert = analogRead(TMP36);
temperatur = map(sensorwert, 0, 409, -50, 150);
delay (t);
lcd.setCursor(7, 1);
lcd.print("Stufe 2");
}
while (temperatur > 58 && temperatur <= 65 && rel1a == 0 && rel2a == 1 && rel3a == 0 && rel4a == 0);

//Relais 2 ausschalten
if (millis() - startzeit >= verzoegerung && temperatur <= 58 && rel1a == 0 && rel2a == 1 && rel4a == 0 && rel4a == 0)
{
startzeit = millis();
digitalWrite(rel1, HIGH);
digitalWrite(rel2, LOW);
digitalWrite(rel3, LOW);
digitalWrite(rel4, LOW);
lcd.setCursor(7, 1);
lcd.print("Stufe 1");
}

//Relais 3 einschalten
if (millis() - startzeit >= verzoegerung && temperatur > 64 && rel1a == 0 && rel2a == 1 && rel3a == 0 && rel4a == 0)
do
{
startzeit = millis();
digitalWrite(rel1, LOW);
digitalWrite(rel2, LOW);
digitalWrite(rel3, HIGH);
digitalWrite(rel4, LOW);
sensorwert = analogRead(TMP36);
temperatur = map(sensorwert, 0, 409, -50, 150);
delay(t);
lcd.setCursor(7, 1);
lcd.print("Stufe 3");
}
while (temperatur > 58 && temperatur <= 65 && rel1a == 0 && rel2a == 0 && rel3a == 1 && rel4a == 0);

//Relais 3 ausschalten
if (millis() - startzeit >= verzoegerung && temperatur <= 58 && rel1a == 0 && rel2a == 0 && rel3a == 1 && rel4a == 0)
{
startzeit = millis();
digitalWrite(rel1, LOW);
digitalWrite(rel2, HIGH);
digitalWrite(rel3, LOW);
digitalWrite(rel4, LOW);
lcd.setCursor(7, 1);
lcd.print("Stufe 2");
}

//Relais 4 einschalten
if (millis() - startzeit >= verzoegerung && temperatur > 64 && rel1a == 0 && rel2a == 0 && rel3a == 1 && rel4a == 0)
do
{
startzeit = millis();
digitalWrite(rel1, LOW);
digitalWrite(rel2, LOW);
digitalWrite(rel3, LOW);
digitalWrite(rel4, HIGH);
sensorwert = analogRead(TMP36);
temperatur = map(sensorwert, 0, 409, -50, 150 );
delay(t);
lcd.setCursor(0, 1);
lcd.print(temperatur);
lcd.setCursor(7, 1);
lcd.print("Stufe 4");
}
while (temperatur > 58 && rel1a == 0 && rel2a == 0 && rel3a == 0 == rel4a == 1);

//Relais 4 ausschalten
if (millis() - startzeit >= verzoegerung && temperatur <= 58 && rel1a == 0 && rel2a == 0 && rel3a == 0 && rel4a == 1)
{
startzeit = millis();
digitalWrite(rel1, LOW);
digitalWrite(rel2, LOW);
digitalWrite(rel3, HIGH);
digitalWrite(rel4, LOW);

lcd.setCursor(7, 1);
lcd.print("Stufe 3");
}

}

Moko:
Bitte setze Deinen Sketch in Code Tags [code] und [/code] (ohne die *), das kannst Du auch jetzt noch machen, dann ist er besser lesbar.
...

Hallo,

das mit millis() hast Du konsequent angewedet.
Nachteil Deiner Lösung sind die Do ... While Schleifen , wenn Du da in einer Schleife bist macht der uP sonst nichts anderes und kreist nur in der Schleife rum und blokiert den Rest.

Heinz