Lichtsensor/Pumpe/ Zeit/Verzögerung

Hallo,

ich komme gerade mit meinem Programm wieder nicht weiter :). Kurze Erklärung: DC Motor Pumpe verbunden mit 2 Relay Module LCD-Display, digitalen Lichtsensor und Arduino Uno.
Das Programm sollte die Pumpe ausschalten, wenn der Wasserspiegel im Behälter erreicht wird und einschaltet, wenn das Wasser wieder im Behälter wird, aber mit zeitlicher Verzögerung 10 Sekunden (Zeit nötig um den Behälter wieder nachfüllen)
erstmal habe ich aber den Lichtwert kalibriert.
Alles funktioniert nur die Pumpe sich gleich nach, wenn das Wasser da ist wieder einschaltet.
Ich will, dass die Pumpe sich erstmal wieder automatisch einschalten lässt nach 10 Sekunden.
Ich habe es mit Millis versucht, aber irgendwie kommt es alle durcheinander :smiley:
Ich hoffe, ich habe es verständlich erklärt.
Danke

Der Sketsch Siehe Unten

#include <SPI.h>
#include <Wire.h>
#include <Digital_Light_TSL2561.h>
#include "rgb_lcd.h"
rgb_lcd lcd;
uint32_t previousMillis = 0;  
const int colorR = 255;
const int colorG = 0;
const int colorB = 0;
const int relaisIN1 = 4;
int output_value;
int eingabe;
int upButton = 2;
int downButton = 3;
int selectButton = 5;
int Pumpeein = 7;
int Kalibrierung = 8;
int menu = 1;
bool Sperre = true;

void setup() {
  Serial.begin(115200);
  pinMode(relaisIN1, OUTPUT);
  Wire.begin();
  TSL2561.init();
  lcd.begin(16, 2);
  pinMode(Pumpeein, INPUT_PULLUP);
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  pinMode(Kalibrierung, INPUT_PULLUP);
  lcd.setRGB(colorR, colorG, colorB);
  lcd.setCursor(0, 0);
  lcd.clear();
  lcd.print("Eingeschaltet");
  lcd.setCursor(0, 1);
  lcd.print("Drucken Sie Down");
}
void loop() {
//Serial.print("The Light value is: ");
  Serial.println(TSL2561.readVisibleLux());
  if (!digitalRead(Kalibrierung)) {
    output_value = TSL2561.readVisibleLux() + 50;
 
    lcd.clear();
    lcd.setCursor(6, 0);
    lcd.print("Sensor ist");
    lcd.setCursor(0, 0);

    lcd.print(TSL2561.readVisibleLux());
    lcd.setCursor(0, 1);
    lcd.print(output_value);
    lcd.setCursor(6, 1);
    lcd.print("kalibriert");
    Sperre = false;
    delay(100);
  }

  if (!digitalRead(downButton)) {
    menu++;
    updateMenu();
    delay(100);
    while (!digitalRead(downButton))
      ;
  }
  if (!digitalRead(upButton)) {
    menu--;
    updateMenu();
    delay(100);
    while (!digitalRead(upButton))
      ;
  }
  if (!digitalRead(selectButton)) {
    executeAction();

    delay(100);
    while (!digitalRead(selectButton))
      ;
  }
  if (!digitalRead(Pumpeein)) {
    digitalWrite(relaisIN1, LOW);
    delay(100);
    while (!digitalRead(Pumpeein))
      ;
 
  }
  if  (!Sperre  &&  output_value< TSL2561.readVisibleLux() ) {
    digitalWrite(relaisIN1, LOW); 
  }
  if (!Sperre  &&   output_value  >  TSL2561.readVisibleLux()  ){
   digitalWrite(relaisIN1, HIGH);
 }
}  



void updateMenu() {
  switch (menu) {
    case 0:
      menu = 1;
      break;
    case 1:
      lcd.clear();
      lcd.print(">Medium ist in ");
      lcd.setCursor(0, 1);
      lcd.print(" Medium ist out");
      break;
    case 2:
      lcd.clear();
      lcd.print(" Medium ist in");
      lcd.setCursor(0, 1);
      lcd.print(">Medium ist out");
      break;


    case 5:
      menu = 2;
      break;
  }
}

void executeAction() {
  switch (menu) {
    case 1:
      action1();
      break;

    case 2:
      action2();
      break;
  }
}

void action1() {

  lcd.clear();

  if (!digitalRead(selectButton)) {

    lcd.clear();
    lcd.print("Drucken Sie");
    lcd.setCursor(0, 1);
    lcd.print("Kalibrieren");

    delay(100);
  }
}

void action2() {

  if (!digitalRead(selectButton)) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Medium");
    lcd.setCursor(0, 1);
    lcd.print("nachfuellen");


    delay(100);
  }
}

Du suchst einen endlichen Automaten.
Da ich es nciht kompilieren kann, hier ein Ansatz - evtl. sind Schreibfehler drin, die sagt Dir aber der Kompiler.
Und schau, wann die Pumpenbedingung AUS schalten erfüllt sein soll, die must Du eintragen.

#include <SPI.h>
#include <Wire.h>
#include <Digital_Light_TSL2561.h>
#include "rgb_lcd.h"
rgb_lcd lcd;
uint32_t previousMillis = 0;
const int colorR = 255;
const int colorG = 0;
const int colorB = 0;
const int relaisIN1 = 4;
int output_value;
int eingabe;
int upButton = 2;
int downButton = 3;
int selectButton = 5;
int Pumpeein = 7;
int Kalibrierung = 8;
int menu = 1;
bool Sperre = true;

constexpr uint32_t pausezeit {5000};         // Zeit in ms
uint32_t lastmills;                          // Merker für Abschaltzeit und Pausenanfang
enum pumpenstatus {warten, pumpen, pause};   // Zustände, was die Pumpe machen soll

void setup()
{
  Serial.begin(115200);
  pinMode(relaisIN1, OUTPUT);
  Wire.begin();
  TSL2561.init();
  lcd.begin(16, 2);
  pinMode(Pumpeein, INPUT_PULLUP);
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  pinMode(Kalibrierung, INPUT_PULLUP);
  lcd.setRGB(colorR, colorG, colorB);
  lcd.setCursor(0, 0);
  lcd.clear();
  lcd.print("Eingeschaltet");
  lcd.setCursor(0, 1);
  lcd.print("Drucken Sie Down");
}
void loop()
{
  //Serial.print("The Light value is: ");
  Serial.println(TSL2561.readVisibleLux());
  if (!digitalRead(Kalibrierung))
  {
    output_value = TSL2561.readVisibleLux() + 50;
    lcd.clear();
    lcd.setCursor(6, 0);
    lcd.print("Sensor ist");
    lcd.setCursor(0, 0);
    lcd.print(TSL2561.readVisibleLux());
    lcd.setCursor(0, 1);
    lcd.print(output_value);
    lcd.setCursor(6, 1);
    lcd.print("kalibriert");
    Sperre = false;
    delay(100);
  }
  if (!digitalRead(downButton))
  {
    menu++;
    updateMenu();
    delay(100);
    while (!digitalRead(downButton))
      ;
  }
  if (!digitalRead(upButton))
  {
    menu--;
    updateMenu();
    delay(100);
    while (!digitalRead(upButton))
      ;
  }
  if (!digitalRead(selectButton))
  {
    executeAction();
    delay(100);
    while (!digitalRead(selectButton))
      ;
  }
  switch (pumpenStatus)
  {
    case warten:
      if (!digitalRead(Pumpeein))             // Taste gedrückt
      {
        digitalWrite(relaisIN1, LOW);         // Pumpe an machen
        pumpenStatus = pumpen;                //
      }
      break;
    case pumpen:
      if  ( )  // HIER BEDINGUNG EINTRAGEN WANN DIE PUMPE AUSGEHEN SOLL
      {
        digitalWrite(relaisIN1, HIGH);
        lastmilli = millis();
      }
      break;
    case pause:
      if (millis() - lastmillis > pausezeit)
      { pumpenStatus = warten; }
      break;
  }
}

void updateMenu()
{
  switch (menu)
  {
    case 0:
      menu = 1;
      break;
    case 1:
      lcd.clear();
      lcd.print(">Medium ist in ");
      lcd.setCursor(0, 1);
      lcd.print(" Medium ist out");
      break;
    case 2:
      lcd.clear();
      lcd.print(" Medium ist in");
      lcd.setCursor(0, 1);
      lcd.print(">Medium ist out");
      break;
    case 5:
      menu = 2;
      break;
  }
}
void executeAction()
{
  switch (menu)
  {
    case 1:
      action1();
      break;
    case 2:
      action2();
      break;
  }
}
void action1()
{
  lcd.clear();
  if (!digitalRead(selectButton))
  {
    lcd.clear();
    lcd.print("Drucken Sie");
    lcd.setCursor(0, 1);
    lcd.print("Kalibrieren");
    delay(100);
  }
}
void action2()
{
  if (!digitalRead(selectButton))
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Medium");
    lcd.setCursor(0, 1);
    lcd.print("nachfuellen");
    delay(100);
  }
}

Ist das der sketch der ohne millis funktioniert oder erwartest du darin schon das Verhalten mit einschaltverzögerung?

Du müsstest dir beim ausschalten den aktuellen wert von millis in einer statischen oder globalen variable merken. Und in dem einschalt if zusätzlich die Bedingung millis() - startwert > T10S ergänzen.

Nein du hast es nicht wirklich verständlich erklärt weil die Sätze verstümmelt sind.

Wenn was für ein Wasserspiegel erreicht wird?
"Behälter voll"
oder
"Behälter leer"

Hä???
Was wird denn mit dem Wasser??

Wer füllt jetzt den Behälter?
Die Pumpe?
oder
du manuell?

Soll das heißen
Die Pumpe schaltet sich sofort ein wenn das Wasser wieder da ist.?

Was bedeutet dann "Das Wasser da ist?
Bedeutet das
Behälter voll?
oder
Behälter leer?

Wird durch die Pumpe jetzt der Behälter
vollgefüllt
oder
leergepumpt?

Also noch mal als neuer Post in eher kurzen Sätzen aber mit jede Menge Wörtern die Aussagen machen die die gestellten Fragen beantworten.

vgs

Wie mißt Du den Wasserstand?
Grüße Uwe

Ich habe es geändert, paar Sachen waren für dich bestimmt irreführend. Jetzt mit dem Sketsch passiert aber einfach nichts, Pumpe geht nicht an und damit auch nicht aus.

#include <SPI.h>
#include <Wire.h>
#include <Digital_Light_TSL2561.h>
#include "rgb_lcd.h"
rgb_lcd lcd;
uint32_t previousMillis = 0;
const int colorR = 255;
const int colorG = 0;
const int colorB = 0;
const int relaisIN1 = 4;
int output_value;
int eingabe;
int upButton = 2;
int downButton = 3;
int selectButton = 5;
int Pumpeein = 7;
int Kalibrierung = 8;
int menu = 1;
bool Sperre = true;

constexpr uint32_t pausezeit {5000};         // Zeit in ms
uint32_t lastmillis;                          // Merker für Abschaltzeit und Pausenanfang
enum pumpenStatus {warten, pumpen, pause};   // Zustände, was die Pumpe machen soll
int pumpenStatus;
void setup()
{
  Serial.begin(115200);
  pinMode(relaisIN1, OUTPUT);
  Wire.begin();
  TSL2561.init();
  lcd.begin(16, 2);
  pinMode(Pumpeein, INPUT_PULLUP);
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  pinMode(Kalibrierung, INPUT_PULLUP);
  lcd.setRGB(colorR, colorG, colorB);
  lcd.setCursor(0, 0);
  lcd.clear();
  lcd.print("Eingeschaltet");
  lcd.setCursor(0, 1);
  lcd.print("Drucken Sie Down");
}
void loop()
{
  //Serial.print("The Light value is: ");
  Serial.println(TSL2561.readVisibleLux());
  if (!digitalRead(Kalibrierung))
  {
    output_value = TSL2561.readVisibleLux() + 50;
    lcd.clear();
    lcd.setCursor(6, 0);
    lcd.print("Sensor ist");
    lcd.setCursor(0, 0);
    lcd.print(TSL2561.readVisibleLux());
    lcd.setCursor(0, 1);
    lcd.print(output_value);
    lcd.setCursor(6, 1);
    lcd.print("kalibriert");
    Sperre = false;
    delay(100);
  }
  if (!digitalRead(downButton))
  {
    menu++;
    updateMenu();
    delay(100);
    while (!digitalRead(downButton))
      ;
  }
  if (!digitalRead(upButton))
  {
    menu--;
    updateMenu();
    delay(100);
    while (!digitalRead(upButton))
      ;
  }
  if (!digitalRead(selectButton))
  {
    executeAction();
    delay(100);
    while (!digitalRead(selectButton))
      ;
  }
   if (!digitalRead(Pumpeein)) {    // PUmpe ist aus wenn der Knopf gedruckt ist
    digitalWrite(relaisIN1, LOW);
    delay(100);
    while (!digitalRead(Pumpeein))
      ;
 
  }
  switch (pumpenStatus)
  {
    case warten:
      if (!Sperre  &&  output_value< TSL2561.readVisibleLux() )             
      {
        digitalWrite(relaisIN1, LOW);         // Pumpe aus machen
        pumpenStatus = pumpen;   
         lastmillis = millis();             //
      }
      break;
    case pumpen:
      if  (!Sperre  &&   output_value  >  TSL2561.readVisibleLux()   )  // HIER BEDINGUNG EINTRAGEN WANN DIE PUMPEanGEHEN SOLL
      {
        digitalWrite(relaisIN1, HIGH);
        pumpenStatus = pumpen; 
        
      }
      break;
    case pause:
      if (millis() - lastmillis > pausezeit)
      { pumpenStatus = warten; }
      break;
  }
}

void updateMenu()
{
  switch (menu)
  {
    case 0:
      menu = 1;
      break;
    case 1:
      lcd.clear();
      lcd.print(">Medium ist in ");
      lcd.setCursor(0, 1);
      lcd.print(" Medium ist out");
      break;
    case 2:
      lcd.clear();
      lcd.print(" Medium ist in");
      lcd.setCursor(0, 1);
      lcd.print(">Medium ist out");
      break;
    case 5:
      menu = 2;
      break;
  }
}
void executeAction()
{
  switch (menu)
  {
    case 1:
      action1();
      break;
    case 2:
      action2();
      break;
  }
}
void action1()
{
  lcd.clear();
  if (!digitalRead(selectButton))
  {
    lcd.clear();
    lcd.print("Drucken Sie");
    lcd.setCursor(0, 1);
    lcd.print("Kalibrieren");
    delay(100);
  }
}
void action2()
{
  if (!digitalRead(selectButton))
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Medium");
    lcd.setCursor(0, 1);
    lcd.print("nachfuellen");
    delay(100);
  }
}

Wenn was für ein Wasserspiegel erreicht wird?
"Behälter leer"

und einschaltet, wenn das Wasser wieder im Behälter wird,
Die Pumpe pumpt das Wasser aus dem Behälter.

aber mit zeitlicher Verzögerung 10 Sekunden (Zeit nötig um den Behälter wieder nachfüllen)
Behälter wird passiv nachgefüllt.

Soll das heißen
Die Pumpe schaltet sich sofort ein wenn das Wasser wieder da ist.?
Genau

Ich messe der Wasserstand mit digitalem Lichtsensor TSL 2561. Das funktioniert Wunderbar.

Dann stimmt was mit den Bedingungen nicht.

die Bedingung:

  • wann die Pumpe einschalten soll
    -> Behälter ist voll
    Wie wird das erkannt?

  • wann die Pumpe auschalten soll
    -> Behälter ist leer
    Wie wird das erkannt?

Wußte ich nicht, daß das funktioniert. Wie machst Du das?

Ich habe ein bißchen bei Adafruit nachgelesen.
Der Sensor kann Gesamthelligkeit und Infrarotanteil (und damit wohl auch sichtbaren Lichtanteil einzeln messen.

Ich nehme an, dass mit größer werdendem Abstand die Lichtintensität abnimmt.

Ich bin aber auch neugierig wie der Code dazu aussieht.
Also @maty247 poste doch mal deinen ganzen Sketch.
Er scheint recht gut struktiert zu sein wie man aus dem gekürzten Sketch sehen kann.

vgs

Mit den Bedingungen sollte eigentlich alles stimmen, weil bei dem ursprünglichen Code es funktioniert. Das einzige Problem war das Delay, weil in der Zeit funktionieren die Tasten nicht.
Wie wird das erkannt, ob der Behälter voll oder leer ist?
Das funktioniert, sodass der Behälter aus Glas besteht und ganz unten ist als Ausgang dünnes Glasröhrchen. Auf eine Seite der Röhrchen ist der Lichtsensor und auf der anderen Seite ist eine LED. Damit entstehen unterschiedliche Werte bei befülltem und leerem Behälter. Es erkennt sogar den Wasserspiegel. Das Licht ist in dem Fall sehr wichtig.

Wie wird das erkannt, ob der Behälter voll oder leer ist?
Das funktioniert, sodass der Behälter aus Glas besteht und ganz unten ist als Ausgang dünnes Glasröhrchen. Auf eine Seite der Röhrchen ist der Lichtsensor und auf der anderen Seite ist eine LED. Damit entstehen unterschiedliche Werte bei befülltem und leerem Behälter. Es erkennt sogar den Wasserspiegel. Das Licht ist in dem Fall sehr wichtig.

Das war der ganze Sketch. Das Einzige, was da nicht erwähnt, ist das LED die ist die ganze Zeit an. Deswegen muss sie gar nicht erwähnt werden. Weitere Details Siehe weitere Antworten.

#include <SPI.h>
#include <Wire.h>
#include <Digital_Light_TSL2561.h>
#include "rgb_lcd.h"
rgb_lcd lcd;
uint32_t previousMillis = 0;
const int colorR = 255;
const int colorG = 0;
const int colorB = 0;
const int relaisIN1 = 4;
int output_value;
int eingabe;
int upButton = 2;
int downButton = 3;
int selectButton = 5;
int Pumpeein = 7;
int Kalibrierung = 8;
int menu = 1;
bool Sperre = true;

constexpr uint32_t pausezeit {5000};         // Zeit in ms
uint32_t lastmillis;                         // Merker für Abschaltzeit und Pausenanfang
enum PUMPENSTATUS {kalibrieren, warten, pumpen, pause};   // Zustände, was die Pumpe machen soll
byte pumpenStatus = kalibrieren;
void setup()
{
  Serial.begin(115200);
  pinMode(relaisIN1, OUTPUT);
  Wire.begin();
  TSL2561.init();
  lcd.begin(16, 2);
  pinMode(Pumpeein, INPUT_PULLUP);
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(selectButton, INPUT_PULLUP);
  pinMode(Kalibrierung, INPUT_PULLUP);
  lcd.setRGB(colorR, colorG, colorB);
  lcd.setCursor(0, 0);
  lcd.clear();
  lcd.print("Eingeschaltet");
  lcd.setCursor(0, 1);
  lcd.print("Drucken Sie Down");
}
void loop()
{
  //Serial.print("The Light value is: ");
  Serial.println(TSL2561.readVisibleLux());
  if (!digitalRead(downButton))
  {
    menu++;
    updateMenu();
    delay(100);
    while (!digitalRead(downButton))
      ;
  }
  if (!digitalRead(upButton))
  {
    menu--;
    updateMenu();
    delay(100);
    while (!digitalRead(upButton))
      ;
  }
  if (!digitalRead(selectButton))
  {
    executeAction();
    delay(100);
    while (!digitalRead(selectButton))
      ;
  }
  switch (pumpenStatus)
  {
    case kalibrieren:
      if (!digitalRead(Kalibrierung))        // erzwingt das kalibrieren
      {
        Serial.println(F("KALIBRIERUNG"));
        kalibration();
        pumpenStatus = warten;                // nach kalibrieren gehts hier weiter
      }
      break;
    case warten:
      if (!digitalRead(Pumpeein))             // Taste gedrückt
      {
        Serial.println(F("ZYKLUSSTART"));
        pumpenStatus = pumpen;
      }
      break;
    case pumpen:
      if  (output_value < TSL2561.readVisibleLux()) // Sensorbedingung
      {
        Serial.println(F("BEHÄLTER LEER"));
        digitalWrite(relaisIN1, HIGH);        // Pumpe geht aus
        lastmillis = millis();                 // Zeit merken
        pumpenStatus = pause;
      }
      else
      {
        digitalWrite(relaisIN1, LOW);         //
      }
      break;
    case pause:
      // Hier wird bestimmt, wann die Pausezeit anfangen soll zu zählen!
      if (output_value < TSL2561.readVisibleLux())
      {
        lastmillis = millis();
        Serial.println(F("BEHÄLTER NACHFÜLLEN"));
      }
      if (millis() - lastmillis > pausezeit)  // Warten auf Nachfüllen
      {
        Serial.println(F("STARTE NEUEN ZYKLUS"));
        pumpenStatus = pumpen;                // Zyklus beginnt von vorn
      }
      break;
  }
}
//
void kalibration()
{
  output_value = TSL2561.readVisibleLux() + 50;
  lcd.clear();
  lcd.setCursor(6, 0);
  lcd.print("Sensor ist");
  lcd.setCursor(0, 0);
  lcd.print(TSL2561.readVisibleLux());
  lcd.setCursor(0, 1);
  lcd.print(output_value);
  lcd.setCursor(6, 1);
  lcd.print("kalibriert");
}
//
void updateMenu()
{
  switch (menu)
  {
    case 0:
      menu = 1;
      break;
    case 1:
      lcd.clear();
      lcd.print(">Medium ist in ");
      lcd.setCursor(0, 1);
      lcd.print(" Medium ist out");
      break;
    case 2:
      lcd.clear();
      lcd.print(" Medium ist in");
      lcd.setCursor(0, 1);
      lcd.print(">Medium ist out");
      break;
    case 5:
      menu = 2;
      break;
  }
}
void executeAction()
{
  switch (menu)
  {
    case 1:
      action1();
      break;
    case 2:
      action2();
      break;
  }
}
void action1()
{
  lcd.clear();
  if (!digitalRead(selectButton))
  {
    lcd.clear();
    lcd.print("Drucken Sie");
    lcd.setCursor(0, 1);
    lcd.print("Kalibrieren");
    delay(100);
  }
}
void action2()
{
  if (!digitalRead(selectButton))
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Medium");
    lcd.setCursor(0, 1);
    lcd.print("nachfuellen");
    delay(100);
  }
}

Neuer Versuch.
Schau auf dem Seriellen Monitor, was Dir ausgegeben wird.

Daß das funktioniert glaube ich Dir. Wie Du den Füllstand mißt habe ich aber nocht nicht verstanden.

Grüße Uwe

Macht er ja nicht.
Dafür braucht er ja die Pause.
Wenn am unteren Fußpunkt der Auslöser aktiviert ist, geht die Pumpe in Stop.
Jetzt muss der Behälter wieder voll werden. Um nicht sofort auszulösen, wennd er Auslöser unten inaktiv ist vergehen 10 Sekunden, die sind ausreichend um den Behälter neu zu füllen.
-> Manuell. z. B. mit einem Messbecher.
(Ich hab das jetzt sogar so gelöst, das ganz sicher der Auslöser erstmal inaktiv sein muss und erst ab dann die zeit zählt und nicht schon ab dem Punkt, wo der Behälter leer ist)

Und wie erkennt er daß der Behälter voll ist und die Pumpe aufhören soll zu pumpen?

Wenns Blöd kommt könnte sicha auch eine Luftblase vor dem Sensor blockieren und dieser dann immer leer melden.

Darum würde ich auch eine max Pumpzeit pro Stunde / Pro Füllung definieren.

Wie entleer sich der Behälter? ziemlich zufällig oder Konstant ein wenig?

Grüße Uwe

Du machst den selben Fehler.
Der pumpt den Behälter leer!

ok
Wie startet dann ein Pumpzyklus?