Probleme mit dem Schalten von Funktionen

Wie die Überschrift schon aussagt habe ich grade Probleme mit dem Schalten einzelner Funktionen :confused:
Es handelt sich um einen Aquarien Computer der einmal den PH Wert und den Salzgehalt des Wassers überwachen und Regeln soll und Er soll einmal am Tag Futter geben.
Das mit der Anzeige der Werte der Messung Funktioniert das es sich jede Sekunde aktuallisiert.
Die anderen beiden milli abfragen gehen allerdings nicht bzw da tut sich nix.
an Der Verkabelung wird es nicht liegen ,da das Setup das auch Relais Schaltet funktioniert
wäre toll wenn mich da mal jemand mit der Nase draufstoßen könnte wo mein Fehler liegt :confused: . Ich häng seit 2 Tagen vor der " Nachtwächterschaltung " und " Blink ohne delay " und komm nicht drauf. Liegt es evtl an den Delays in meinen Funktionen? Wenn ja wie kann ich sonst die Relais Zeitgenau Schalten (wegen der Ausgabemenge des jeweilig geschalteten Gerätes ist das recht wichtig )

Hier erstmal der Sketch ,ich hoffe ich hab ihn so einfach verständlich wie möglich geschrieben

// PH und EC Werte

float ECMA = 3.6 ;// EC Wert Maximum
float ECOD =2.5 ; //PEC Wert oberer durschnitt
float PHM = 3.5 ;// PH Wert minimum
float PHMA = 9 ;// PH Wert Maximu
float PHUD =5.9 ; // PH Wert unterer durchschnitt
float PHOD =7 ; //PH Wert oberer durschnitt

//Relais laufzeit in Sekunden

// Relaislaufzeit Bei Systemstart
float WALS = 1 ;       //Wasseraufbereiter
float PDLS = 1 ;       // Pflanzendünger




//Relais laufzeit bei Abfragen

float ML = 1 ;       // PH Minus
float PL = 1 ;       // PH Plus
float FULS = 1;        // Futter
const int  ecPin = A1; 
const int  phPin = A2 ;
const int  analogOutPin = 11; 

 //Relais

const int FU = 2; 
const int plus = 3; 
const int minus = 4;
const int PD = 5; 
const int WA = 6; 


unsigned long monitorMillis;
unsigned long abfrage;
unsigned long Futter;


int outputValue;
int ecSensorValue;
int phSensorValue;  
float ecWert;
float phWert;



//Sender
#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

//LCD

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void Abfragen(){

    
   

  
  
   if (ecWert > ECMA ) 
    {mySwitch.send(21777 , 24); //Ein OsmoseWasser
     delay(50);
     delay ( 30 * 60 * 1000 ) ;
    } 
    if (phWert > PHMA)
    {digitalWrite(minus, LOW); //PH-
     delay(ML*1000); 
     digitalWrite(minus, HIGH);
     delay(15 * 60 * 1000);
  }
  if (phWert < PHM)
    {digitalWrite(plus, LOW); //PH+
     delay(PL*1000); 
     digitalWrite(plus, HIGH);
     delay(15 * 60 * 1000);
  }
  }

void Essen()
{
    digitalWrite(FU, LOW); //Futter
     delay(FULS*1000); 
     digitalWrite(FU, HIGH);
     delay(500);
  }

  void Anzeige()

  {
 
   if (Serial.available()) {
    delay(100);
    lcd.clear();
    while (Serial.available() > 0)
    {
      lcd.write(Serial.read());
    }}
   {
    monitorMillis = millis();
    // serial monitor:
    Serial.print(" PH = ");
    Serial.println(phWert, 1);
    Serial.print(" EC = ");
    Serial.println(ecWert, 2);
  
  // LCD
  lcd.setCursor(0, 0); //Start at character 0 on line 0
  lcd.print("PH " );
  lcd.setCursor(4, 0);
  lcd.print(phWert, 1);
  lcd.setCursor(0, 1);
  lcd.print("EC " );
  lcd.setCursor(4, 1);
  lcd.print(ecWert, 2);

  } }

void setup() {
  
  //Sender
  
   mySwitch.enableTransmit(10);
   
   //LCD
   
  lcd.begin(16,2); 
  for(int i = 0; i< 3; i++)
  lcd.backlight();
  delay(250);

  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0,0); //Start at character 0 on line 0
  lcd.print("PH " );
  lcd.setCursor(4,0);
  lcd.print(phWert );
  lcd.setCursor(0,1);
  lcd.print("EC " ); 
  lcd.setCursor(4,1);
  lcd.print(ecWert ); 
  
 //Relais
   
  digitalWrite(FU, HIGH);
 digitalWrite(plus, HIGH);
  digitalWrite(minus, HIGH);
  digitalWrite(PD, HIGH); 
  digitalWrite(WA, HIGH); 
  pinMode(FU, OUTPUT); 
  pinMode(plus, OUTPUT); 
  pinMode(minus, OUTPUT); 
  pinMode(PD, OUTPUT); 
   pinMode(WA, OUTPUT); 

  Serial.begin(9600); 
   
 //Nach Wasserwechsel
 
    digitalWrite(WA, LOW); //Wasseraufbereiter
     delay(WALS*1000);
     digitalWrite(WA, HIGH);
     delay(500);
     digitalWrite(PD, LOW); // Pflanzendünger
     delay(PDLS*1000);
     digitalWrite(PD, HIGH);
     delay(500);
   
     } 

void loop(){ {
  //PH und EC messung
  
 phSensorValue = analogRead(phPin);
 outputValue = map(phSensorValue, 0, 1023, 0, 14);
 analogWrite(analogOutPin, outputValue); 
 phWert = analogRead(phPin)* 14.000 / 1024.0;
 
 ecSensorValue = analogRead(ecPin);
 outputValue = map(ecSensorValue, 0, 1023, 0, 5000);  
 ecWert = analogRead(ecPin)* 5.000 /  1024, 2; } 


  if (millis() - monitorMillis >= 1000)  
    {Anzeige(); } 
   if (millis() - abfrage >= 5 * 60 * 1000)
   { Abfragen();} 

   if (millis() - Futter >= 2 * 24 * 60 * 60 * 1000)
   { Essen();} }
   if (millis() - abfrage >= 5 * 60 * 1000)

   if (millis() - Futter >= 2 * 24 * 60 * 60 * 1000)

Das Produkt ist zu groß für einen int, versuchs mal so

   if (millis() - abfrage >= 5 * 60 * 1000L)

   if (millis() - Futter >= 2 * 24 * 60 * 60 * 1000L)

Die Formattierung des Kodes ist gruselig. Versuch mal Strg-T in der IDE.

OT: Mit was misst du den Salzgehalt?

Whandall:
.......
Das Produkt ist zu groß für einen int, versuchs mal so

   if (millis() - abfrage >= 5 * 60 * 1000L)

if (millis() - Futter >= 2 * 24 * 60 * 60 * 1000L)



Die Formattierung des Kodes ist gruselig. Versuch mal Strg-T in der IDE.

Hallo
Danke werde ich nachher mal testen , gibt es irgendwo eine Deutschsprachige Erklärung wegen der Buchstaben hinter den Zahlen ? Ich hab das öfter schon mal gesehen weiß aber nicht welchen Nutzen das hat und hab dazu auch nichts über Google gefunden was evtl. an den falschen such begriffen liegt die ich benutzt habe :blush:

ElEspanol:
OT: Mit was misst du den Salzgehalt?

Mit einer EC Sonde die an einem einem Messumformer angeschlossen ist

L = long
UL = unsigned long

Wenn man das nicht tut wird der Standard Datentyp verwendet ist das ist int. Wodurch dann auch in int gerechnet wird

AHHH ! Ok jetzt hab ich was gefunden , Danke
und was ist mit :

Whandall:
Die Formattierung des Kodes ist gruselig. Versuch mal Strg-T in der IDE.

Gemeint ?

Schau mal in der IDE unter Werkzeuge -> Automatische Formatierung Strg+T

Gruß Tommy

Hmm ne, also an den Produkten hat das nicht (alleine ) gelegen :confused:

Ich habe den Sketch noch mal soweit geändert das ich eine neue Funktion eingefückt habe die alle 5sek. geschaltet werden soll . aber es tut sich nix :slightly_frowning_face: komischer weise klappt das bei der Anzeige alles ohne Probleme das sie sich jede Sekunde ändert.
Gibt es noch andere Optionen um Funktionen ohne ein Delay im loop zu schalten?
Mit der Biblieotehk INTERVAL um die es in diesem LINK geht habe ich auch schon rum gespielt allerdings das selbe Ergebnis

hier noch mal der von mir veränderte Sketch

// PH und EC Werte

float ECMA = 3.6 ;// EC Wert Maximum
float ECOD = 2.5 ; //PEC Wert oberer durschnitt
float PHM = 3.5 ;// PH Wert minimum
float PHMA = 9 ;// PH Wert Maximu
float PHUD = 5.9 ; // PH Wert unterer durchschnitt
float PHOD = 7 ; //PH Wert oberer durschnitt

//Relais laufzeit in Sekunden

// Relaislaufzeit Bei Systemstart
float WALS = 1 ;       //Wasseraufbereiter
float PDLS = 1 ;       // Pflanzendünger




//Relais laufzeit bei Abfragen

float ML = 1 ;       // PH Minus
float PL = 1 ;       // PH Plus
float FULS = 1;        // Futter
const int  ecPin = A1;
const int  phPin = A2 ;
const int  analogOutPin = 11;

//Relais

const int FU = 2;
const int plus = 3;
const int minus = 4;
const int PD = 5;
const int WA = 6;


unsigned long monitorMillis;
unsigned long abfrage;
unsigned long Futter;


int outputValue;
int ecSensorValue;
int phSensorValue;
float ecWert;
float phWert;



//Sender
#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

//LCD

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void Abfragen() {






  if (ecWert > ECMA )
  { mySwitch.send(21777 , 24); //Ein OsmoseWasser
    delay(50);
    delay ( 30 * 60 * 1000 ) ;
  }
  if (phWert > PHMA)
  { digitalWrite(minus, LOW); //PH-
    delay(ML * 1000);
    digitalWrite(minus, HIGH);
    delay(15 * 60 * 1000);
  }
  if (phWert < PHM)
  { digitalWrite(plus, LOW); //PH+
    delay(PL * 1000);
    digitalWrite(plus, HIGH);
    delay(15 * 60 * 1000);
  }
}

void Essen()
{
  digitalWrite(FU, LOW); //Futter
  delay(FULS * 1000);
  digitalWrite(FU, HIGH);
  delay(500);
}

void Anzeige()

{

  if (Serial.available()) {
    delay(100);
    lcd.clear();
    while (Serial.available() > 0)
    {
      lcd.write(Serial.read());
    }
  }
  {
    monitorMillis = millis();
    // serial monitor:
    Serial.print(" PH = ");
    Serial.println(phWert, 1);
    Serial.print(" EC = ");
    Serial.println(ecWert, 2);

    // LCD
    lcd.setCursor(0, 0); //Start at character 0 on line 0
    lcd.print("PH " );
    lcd.setCursor(4, 0);
    lcd.print(phWert, 1);
    lcd.setCursor(0, 1);
    lcd.print("EC " );
    lcd.setCursor(4, 1);
    lcd.print(ecWert, 2);

  }
}

void nurso()

{ digitalWrite(WA, LOW); //Wasseraufbereiter
  delay(WALS * 1000);
  digitalWrite(WA, HIGH);
  delay(500);
}

void setup() {

  //Sender

  mySwitch.enableTransmit(10);

  //LCD

  lcd.begin(16, 2);
  for (int i = 0; i < 3; i++)
    lcd.backlight();
  delay(250);

  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0); //Start at character 0 on line 0
  lcd.print("PH " );
  lcd.setCursor(4, 0);
  lcd.print(phWert );
  lcd.setCursor(0, 1);
  lcd.print("EC " );
  lcd.setCursor(4, 1);
  lcd.print(ecWert );

  //Relais

  digitalWrite(FU, HIGH);
  digitalWrite(plus, HIGH);
  digitalWrite(minus, HIGH);
  digitalWrite(PD, HIGH);
  digitalWrite(WA, HIGH);
  pinMode(FU, OUTPUT);
  pinMode(plus, OUTPUT);
  pinMode(minus, OUTPUT);
  pinMode(PD, OUTPUT);
  pinMode(WA, OUTPUT);

  Serial.begin(9600);

  //Nach Wasserwechsel

  digitalWrite(WA, LOW); //Wasseraufbereiter
  delay(WALS * 1000);
  digitalWrite(WA, HIGH);
  delay(500);
  digitalWrite(PD, LOW); // Pflanzendünger
  delay(PDLS * 1000);
  digitalWrite(PD, HIGH);
  delay(500);

}

void loop() {
  {
    //PH und EC messung

    phSensorValue = analogRead(phPin);
    outputValue = map(phSensorValue, 0, 1023, 0, 14);
    analogWrite(analogOutPin, outputValue);
    phWert = analogRead(phPin) * 14.000 / 1024.0;

    ecSensorValue = analogRead(ecPin);
    outputValue = map(ecSensorValue, 0, 1023, 0, 5000);
    ecWert = analogRead(ecPin) * 5.000 /  1024, 2;
  }


  if (millis() - monitorMillis >= 1000)
  {
    Anzeige();
  }
  if (millis() - abfrage >= 5 * 1000L)
  {
    nurso ;
  }

  if (millis() - Futter >= 2 * 24 * 60 * 60 * 1000L)
  {
    Essen();
  }


}

Aktiviere die Warnungen in der IDE

Dann wirst du auf sowas hingewiesen:

  if (millis() - abfrage >= 5 * 1000L)
  {
    nurso ;
  }

Der Name der Funktion ohne die Klammern ist lediglich die Adresse

Ansonsten musst du die Zeit des letzten Aufrufs speichern. Dann machst du millis() - letzterAufruf. Und wenn diese Zeit größer als das Intervall ist wird die Funktion aufgerufen. Bei dir fehlt das Speichern dieser Zeit

Mit der Biblieotehk INTERVAL um die es in diesem LINK geht habe ich auch schon rum gespielt allerdings das selbe Ergebnis

Da fühle ich mich direkt angesprochen!

INTERVAL funktioniert!
Es tut genau das, was es soll.

Zu deinem Code...
Den habe ich so nicht verstanden.

Mir fehlen klare Abgrenzungen und Benennungen der Teilgebiete.
Auch was es eigentlich, in welcher Zeit und in welchen Abständen zu tun hat, ist mir nicht ganz klar.

Ich vermute, du möchtest mehrere, quasi parallel laufende, Endliche Automaten/Schrittketten bauen.

Vielleicht solltest du diese mal auf Papier bannen.

Serenifly:
Aktiviere die Warnungen in der IDE

Dann wirst du auf sowas hingewiesen:

  if (millis() - abfrage >= 5 * 1000L)

{
    nurso ;
  }



Der Name der Funktion ohne die Klammern ist lediglich die Adresse


Ansonsten musst du die Zeit des letzten Aufrufs speichern. Dann machst du millis() - letzterAufruf. Und wenn diese Zeit größer als das Intervall ist wird die Funktion aufgerufen. Bei dir fehlt das Speichern dieser Zeit

Ja das mit den Klammern ist mir dann auch ca 2 min nach dem ich den Post abgeschickt hatte aufgefallen :smiley:
Nach dem ich diese dazu geschrieben hatte , hat das program das setup durchlaufen lassen und dann nach 5 Sekunden die Funktion "nurso" eingeschaltet . allerdings diese dann in dauerschleife laufen lassen und das soll es ja auch nicht.
Ich hab das jetzt so verstanden das die Zeitspeicherung mit

unsigned long monitorMillis;
unsigned long abfrage;
unsigned long Futter;

gespeichert wird. Oder wofür sind die sonst ?

combie:
Da fühle ich mich direkt angesprochen!

INTERVAL funktioniert!
Es tut genau das, was es soll.

Zu deinem Code...
Den habe ich so nicht verstanden.

Mir fehlen klare Abgrenzungen und Benennungen der Teilgebiete.
Auch was es eigentlich, in welcher Zeit und in welchen Abständen zu tun hat, ist mir nicht ganz klar.

Ich vermute, du möchtest mehrere, quasi parallel laufende, Endliche Automaten/Schrittketten bauen.

Vielleicht solltest du diese mal auf Papier bannen.

:smiley: Das sollte nicht Heißen das INTERVAL nicht Funktioniert, sondern nur das ich anscheinen zu begriff stutzig bin die richtigen befehle einzugeben bzw die Beschreibungen falsch verstehe und dadurch nicht richtig umsetze .
Ja gut was es tun soll könnt ich ja noch mal erklären Also er soll (wenn er fertig ist die jetzigen Zeiten und Werte sind eigentlich nur Test halber weil das Program noch nicht fertig ist und das Testen dadurch einfacher ist)
es sollen alle 15 min die Wasserwerte abgefragt werden .Wenn sie vom eingegebenen Wert abweichen , dann soll eine Funktion gestartet werden die nach Ausführung dann wieder 15 min Pausiert bevor sie noch mal aus geführt werden kann .
de 2te Funktion ist dann das alle 2 Tage 1 mal futter gegeben werden soll . das in einer bestimmten Menge in der Schaufel eines Futterautomaten liegt (heißt diese Funktion darf auch nur einmal alle 48 Stunden laufen
Dieses PH EC Steuer gerät hängt dann noch mit 2 Anderen Arduinos zusammen der eine Überwacht /Regelt den Wasserstand und die Temperatur und der 3te Wechselt jede Woche eine bestimmte menge Wasser Die Anderen 2 Laufen mittlerweile mit Hilfe dieses Forums Stabil

Jan2381:
Ja das mit den Klammern ist mir dann auch ca 2 min nach dem ich den Post abgeschickt hatte aufgefallen :smiley:
Nach dem ich diese dazu geschrieben hatte , hat das program das setup durchlaufen lassen und dann nach 5 Sekunden die Funktion "nurso" eingeschaltet . allerdings diese dann in dauerschleife laufen lassen und das soll es ja auch nicht.
Ich hab das jetzt so verstanden das die Zeitspeicherung mit

unsigned long monitorMillis;

unsigned long abfrage;
unsigned long Futter;



gespeichert wird. Oder wofür sind die sonst ?

In den Variablen wird ohne extra Zuweisung gar nichts außer 0 gespeichert. Deine Funktion "nurso" wurde ausgeführt weil die 5 Sekunden vergangen sind. Da aber in der Variable "abfrage" immer noch 0 steht ist die Zeit immer noch abgelaufen wenn er das nächste Mal prüft. Du musst am Ende der Funktion "nurso" Deine Variable mit der aktuellen "Zeit" füllen.

Also z.B. so:

void nurso()

{ digitalWrite(WA, LOW); //Wasseraufbereiter
  delay(WALS * 1000);
  digitalWrite(WA, HIGH);
  delay(500);
  abfrage = millis();
}

Damit sind beim nächsten Durchlauf der Abfrage ob die Zeit vergangen ist eben noch keine 5 Sekunden um und die Funktion wird nicht ausgeführt.

Gruß, Jürgen

Wobei es sehr unübersichtlich ist, auswerten und akualisieren der Variablenabfrageso verstreut vorzunehmen.

Mir gefällt es so besser:

  if (millis() - abfrage >= 5 * 1000L)
  {
    nurso ();
    abfrage += 5*1000L;
  }

Das bewirkt, dass nurso() alle 5 Sekunden drankommt.
Und nicht 5 Sekunden, nachdem es fertig ist, was ein großer Unterschied ist, da nurso() mit bösen delays gespickt ist.

michael_x:
Wobei es sehr unübersichtlich ist, auswerten und akualisieren der Variablenabfrageso verstreut vorzunehmen.

Mir gefällt es so besser:

  if (millis() - abfrage >= 5 * 1000L)

{
    nurso ();
    abfrage += 5*1000L;
  }




Das bewirkt, dass nurso() alle 5 Sekunden drankommt. 
Und nicht 5 Sekunden, nachdem es fertig ist, was ein großer Unterschied ist, da nurso() mit bösen delays gespickt ist.

Stimmt! Danke michael_x,

manchmal schreibt man einfach zu schnell und denkt nicht groß darüber nach... :wink:

Und wiedereinmal Vielen Dank an dieses Forum für die super Hilfe und Unterstützung .
Das war das was ich gebraucht habe . Jetzt läuft es so wie ich es wollte.

Eine Frage habe ich dann doch noch für die ich bei Google keine Antwort gefunden habe die mir gefällt.
Und zwar : Gibt es eine Möglichkeit eine if schleife zu verlassen obwohl die Bedingung nicht erfüllt ist ?

wen im program z.b. heißt :

  if (phWert > 8)
    {digitalWrite(minus, LOW); //PH-
     delay(ML*1000); 
     digitalWrite(minus, HIGH);
 
  }
  }

und der PH wert höher als 8 ist öffnet sich 15min nach start ein Magnet Ventil das CO2 ins Wasser gibt um den PH wert zu senken . Das CO2 braucht logischerweise etwas zeit sich auszubreiten allerdings prüft der Arduino nach gefühlten 5 sek wieder und schaltet das Relais (weil die werte logischerweise noch nicht stimmen können)
ibt es eine schönere metode als es durch delay zu machen ?
Ich könnte jetzt ja auch

  if (phWert > 8)
    {digitalWrite(minus, LOW); //PH-
     delay(ML*1000); 
     digitalWrite(minus, HIGH);
     delay(15UL * 60UL * 1000UL);
  }

Schreiben allerdings könnte ich dann ja logischerweise auch die nächsten 15min keine aktuellen Werte mehr auf dem LCD ablesen.
unter Google ,Youtoube usw hab ich jetzt nur gefunden das die schleife durchlaufen wird bis die Bedingung erfüllt ist.
Ich hoffe hier auf eine Andere Antwort :slight_smile:

Ich hoffe hier auf eine Andere Antwort

Nöö!

  1. Es gibt keine IF Schleifen.
  2. Wenn dir das Delay nicht gefällt, dann verzichte darauf.

(ist doch nicht zu kompliziert, oder?)

Wie schon erwähnt ist if() eine Anweisung und keine Schleife.... sie prüft nur, ob etwas wahr ist, und führt gegebenenfalls den Inhalt aus... nix mit Schleife

Hier findest Du eine gute Anleitung, wie man Schritt für Schritt das delay() durch millis() ersetzen kann... dann kannst Du jeweils eine Anzeige- und eine Pumproutine schreiben, welche unabhängig voneinander behandelt werden.

Die Holzfällermethode wäre es, einen loop()-Durchgang auf 1 Minute zu normieren und bei jedem Durchgang eine Zählervariable zu inkrementieren (welche beim Erreichen der 16. Minute auf 0 zurücksetzt).... in der if()-Anweisung fragst Du dann einmal auf %5 (also modulo) ab, bei true wird dann das Display aktualisiert (Displayaktualisierung alle 5 Minuten), und zusätzlich bei der 15. Minute die Pumpenansteuerung. Aber wie gesagt, ist eine unschöne Lösung...

Ja genau so etwas hab ich gesucht .
Danke ! Ich habe Fertig