Wasseralarm akustisch und visuell mit Quittier-Taste

Hallo zusammen,
Ich möchte für mein Aquarium einen Wasseralarm realisieren. Dieser soll bei detektiertem Wasser im Takt anfangen zu Piepsen und eine LED soll rot blinken.
Der akustische Alarm soll temporär per Tastendruck quittiert werden können. Sollte nach beispielsweise 60 Sekunden immer noch Wasser am Sensor anliegen, soll dieser wieder anfangen zu piepsen.
Wird kein Wasser mehr erkannt, ist der Akustische Alarm still und die LED leuchtet nun Grün konstant.

Mein Sketch funktioniert bis auf ein "Detail":
Wenn die Taste gedrückt wird, wird dieser erkannt. Die Zeile "Alarm quittiert" wird für die bestimmte Zeit aufgerufen, nur der akustische Alarm piepst weiter mit dem rot blinkenden LED. Sollte aber nur das LED für diese bestimmte Zeit blinken.

Ich vermute der Fehler liegt irgendwo in den Wiederholungen, dass sich der Befehl des Piezo-aktivieren und deaktivieren überschneiden. Ich stehe aber auf dem Schlauch und komme auf keinen grünen Zweig. Bitte beachtet, dass ich seit rund einem Monat mich mit Arduino befasse und somit Fehler im Sketch, in der Darstellung und in meinem Verständnis nicht auszuschliessen sind. :slight_smile:

/*
***ribaribi***
Projekt: Wasseralarm
Datum: 20210718

Beschreibung: Bei erfassen von Wasser, Blinkt und Piepst ein Alarm im Takt.
Das Piepsen kann man für eine bestimmte Zeit Quittieren. (z.B 60s). Ein LED blinkt weiter.
Ist nach dieser Zeit îmmernoch Wasser da sein, fänkt das Piepsen wieder an. 
Ist kein Wasser mehr dedektiert, wird kein Alarm ausgegeben und die LED leuchtet grün.
 */

int Wassersensor = A6;  //Feuchtigkeitssensor
int Alarm = 14;         //Piezo-Speaker
int LEDRot = 26;        //RGB LED
int LEDGruen = 28;      //RGB LED
int LEDBlau = 30;       //RGB LED (Blau derzeit nicht verwendet)
int Taste2_PIN = 40;    //Quittiertaste

int Taste2;
int Quittiert;

//Verzögerung

const unsigned long Alarmverzoegerung = 30 * 1000L;  // Unterbruch des Alarms in ms
unsigned long Quittiermoment;
unsigned long Restzeit;


void setup()
{
  Serial.begin(9600);
  pinMode (Alarm, OUTPUT); 
  pinMode (LEDRot, OUTPUT);
  pinMode (LEDGruen, OUTPUT);
  pinMode (LEDBlau, OUTPUT);
  pinMode(Taste2_PIN, INPUT_PULLUP);

  digitalWrite (LEDRot, HIGH);      //Alarm (Wasser erkannt)
  digitalWrite (LEDGruen, LOW);     //Situation OK
  digitalWrite (LEDBlau, HIGH);     //Nicht verwendet
}

void loop() {

  Taste2 = digitalRead(Taste2_PIN);
  Wassersensor = analogRead(A6);
  
  Serial.print("Feuchtigkeits-Messwert:");
  Serial.println(Wassersensor);
  delay(500);


  //Alarm
  if (Wassersensor > 100 ) //Ist der Sensorwert grösser als "100", dann...
  {
    digitalWrite(Alarm, HIGH);    //...soll der Piezo-Speaker piepsen
    digitalWrite(LEDRot, LOW);    //und die rote LED soll aufleuchten.
    delay(500);

    digitalWrite(Alarm, LOW);     //...wieder leise sein.
    digitalWrite(LEDRot, HIGH);   //rote LED wieder löschen
    digitalWrite(LEDGruen, HIGH); //grüne LED bleibt dunkel.
    delay (500);

  }
  else 
  {
    digitalWrite(LEDGruen, LOW);  //grüne LED leuchtet konstant
    digitalWrite(Alarm, LOW);     //Alarm ist still.
  }

  //Verzögerung

  if (Taste2 == LOW)                  //Wenn Quittiertaste gedrückt
  { 
    Quittiermoment = millis();        //Zeitpunkt des Tastendrucks wird gemerkt
    Serial.println("Taste gedrückt"); //Zur Kontrolle 
  }
  
  if (millis() - Quittiermoment < Alarmverzoegerung) //Abfallverzögerung des Tasters
  {
    digitalWrite(Alarm, LOW); //...soll er leise sein.
    Restzeit = (Alarmverzoegerung - (millis() - Quittiermoment)) / 1000;
    Serial.println("Alarm quittiert"); //Zur Kontrolle
  } 
  else 
  {
    Restzeit = 0;
  }
}    

Hier noch aus dem Seriell Monitor:

Feuchtigkeits-Messwert:373
Taste gedrückt // Hier wurde der Tastendruck erkannt
Alarm quittiert // Der nächste Schritt ist auch eingetreten, Pieps aber weiter
Feuchtigkeits-Messwert:373
Alarm quittiert // Wiederholt sich so oft bis die eingestellte Zeit durch ist.
Feuchtigkeits-Messwert:0 //Sensor aus dem Wasser gezogen

Hier ein Bild der RGB-LED, Feuchtigkeitssensor und der Piezo-Speaker:

Der Code hinter dieser Bedingung weiß leider nichts davon, dass ein paar Zeilen später der Alarm quittiert wurde. Da solltest du dir einen Merker setzen und mit dem das Einschalten des Piepsers ggf. verhindern.


Gruß Walter

1 Like

Hallo Walter

Vielen Dank für deinen Beitrag. Dies macht durchaus Sinn. :slight_smile:
Nun komme ich erst Morgen dazu dies zu überprüfen ob dies so funktioniert. Vielleicht siehst du aber schon vorher ob das stimmen könnte oder ob ich es nur schlimmer gemacht habe:

/*
***ribaribi***
Projekt: Wasseralarm
Datum: 20210718

Beschreibung: Bei erfassen von Wasser, Blinkt und Piepst ein Alarm im Takt.
Das Piepsen kann man für eine bestimmte Zeit Quittieren. (z.B 60s). Ein LED blinkt weiter.
Ist nach dieser Zeit immer noch Wasser da sein, fängt das Piepsen wieder an. 
Ist kein Wasser mehr detektiert, wird kein Alarm ausgegeben und die LED leuchtet grün.
 */

int Wassersensor = A6;  //Feuchtigkeitssensor
int Alarm = 14;         //Piezo-Speaker
int LEDRot = 26;        //RGB LED
int LEDGruen = 28;      //RGB LED
int LEDBlau = 30;       //RGB LED (Blau derzeit nicht verwendet)
int Taste2_PIN = 40;    //Quittiertaste

int Taste2;
bool Quittiert;

//Verzögerung

const unsigned long Alarmverzoegerung = 30 * 1000L;  // Unterbruch des Alarms in ms
unsigned long Quittiermoment;
unsigned long Restzeit;


void setup()
{
  Serial.begin(9600);
  pinMode (Alarm, OUTPUT); 
  pinMode (LEDRot, OUTPUT);
  pinMode (LEDGruen, OUTPUT);
  pinMode (LEDBlau, OUTPUT);
  pinMode(Taste2_PIN, INPUT_PULLUP);

  digitalWrite (LEDRot, HIGH);      //Alarm (Wasser erkannt)
  digitalWrite (LEDGruen, LOW);     //Situation OK
  digitalWrite (LEDBlau, HIGH);     //Nicht verwendet
}

void loop() {

  Taste2 = digitalRead(Taste2_PIN);
  Wassersensor = analogRead(A6);
  
  Serial.print("Feuchtigkeits-Messwert:");
  Serial.println(Wassersensor);
  delay(500);


  //Alarm
  if (Wassersensor > 100 ) //Ist der Sensorwert grösser als "100", dann...
  {
     if (Quittiert == false) 
     {
    digitalWrite(Alarm, HIGH);    //...soll der Piezo-Speaker piepsen
    digitalWrite(LEDRot, LOW);    //und die rote LED soll aufleuchten.
    delay(500);

    digitalWrite(Alarm, LOW);     //...wieder leise sein.
    digitalWrite(LEDRot, HIGH);   //rote LED wieder löschen
    digitalWrite(LEDGruen, HIGH); //grüne LED bleibt dunkel.
    delay (500);
    }
   else
    {
    digitalWrite(LEDRot, LOW);    //und die rote LED soll aufleuchten.
    delay(500);

    digitalWrite(LEDRot, HIGH);   //rote LED wieder löschen
    digitalWrite(LEDGruen, HIGH); //grüne LED bleibt dunkel.
    delay (500);
    }
  }
  else 
  {
    digitalWrite(LEDGruen, LOW);  //grüne LED leuchtet konstant
    digitalWrite(Alarm, LOW);     //Alarm ist still.
  }

  //Verzögerung

  if (Taste2 == LOW)                  //Wenn Quittiertaste gedrückt
  { 
    Quittiermoment = millis();        //Zeitpunkt des Tastendrucks wird gemerkt
    Serial.println("Taste gedrückt"); //Zur Kontrolle 
  }
  
  if (millis() - Quittiermoment < Alarmverzoegerung) //Abfallverzögerung des Tasters
  {
    //digitalWrite(Alarm, LOW); //...soll er leise sein.
    Quittiert = true;
    Restzeit = (Alarmverzoegerung - (millis() - Quittiermoment)) / 1000;
    Serial.println("Alarm quittiert"); //Zur Kontrolle
  } 
  else 
  {
    Quittiert = false;
    Restzeit = 0;
  }
}

Ich hoffe das funktioniert so mit den If-If- else-else....
Mal schauen was es mir rausspuckt, wenn ich das Morgen ins IDE einpflege. Bin gerade nur mit einem kleinen Tablet unterwegs.

Ich wünsche einen schönen Sonntagabend.

Lg ribaribi

Sieht auf den ersten schnellen Blick so aus, als würde es funktionieren. Es kompiliert ohne Fehler, aber ich habe es nicht ausprobiert.

Die Variable Restzeit harrt noch einer echten Verwendung :slight_smile:

Beim Einbau der Zusatzbedingung "ist schon quittiert" hast Du es m.E. etwas umständlicher gemacht als nötig. Die rote LED soll ja immer blinken, wenn der Wasserstand zu hoch ist. Deshalb den Code nur einmal hinschreiben - wenn Du da dran später mal etwas ändern willst, müsstest Du an zwei Stellen dasselbe tun. Das ist immer eine mögliche Fehlerquelle.
Schau mal, ob DIr das hier auch gefallen könnte:

  if (Wassersensor > 100 ) //Ist der Sensorwert grösser als "100", dann...
  {
    if (Quittiert == false)
    {
      digitalWrite(Alarm, HIGH);    //...soll der Piezo-Speaker piepsen
    }
    digitalWrite(LEDRot, LOW);    //und die rote LED soll aufleuchten.
    delay(500);

    // das könnte man sogar weglassen und wie die grüne LED den Piepser immer ausschalten.
    if (Quittiert == false) 
    {
      digitalWrite(Alarm, LOW);     //...wieder leise sein.
    }
    digitalWrite(LEDRot, HIGH);   //rote LED wieder löschen
    digitalWrite(LEDGruen, HIGH); //grüne LED bleibt dunkel.
    delay (500);
  }

Für später:
Wenn noch mehr Bedingungen und Zustände (jetzt: Wasser hoch/niedrig, Zeit läuft, quittiert oder nicht...) in das Programm sollen, wird die sequentielle Bearbeitung, Schachtelung von Bedingungen und das delay() vermutlich irgendwann zum Problem.

Das wünsche ich auch!

Super, danke für die rasche Antwort.

Betreffend delay. Kennst du da eine alternative?

Ich habe eben einige Teilprogramme (inkl. dieses) welche ich zu einem späteren Zeitpunkt "verheiraten" möchte zu einem.

Somit nehme ich deinen Input zum delay() sehr ernst.

:face_with_monocle::slight_smile:

Wenn die Teilprogramme es ertragen, dass sie jeweils für eine Sekunde (die beiden delays zum Blinken der LED) angehalten werden... kannst Du es so lassen.

Ansonsten für heute nur noch die Stichworte, um die Alternative erarbeiten zu können:
millis()
BlinkWithoutDelay (Beispielcode in der IDE)
Zustandsautomat

Bis denne!

1 Like

Das funktioniert nicht so, wie Du willst.
Ich setz mich mal hin und bau da was - aber erstmal muss ich verstehen, was Du da hast :wink:
Es wird.
Versprochen. :wink:

1 Like

Willst du die Leute hier auf den Arm nehmen? Du hast die Alternative doch in deinem Sketch drin, die da 'millis' heißt.

Ich habe die Antwort schon vorher freundlich bekommen. Aber danke für deine Teilnahme am Thema. Und nein, kein Interesse Leute auf den Arm zu nehmen.

Ich hab das begleitet - Nein, das wollte der TO nicht.
Er hat nur nicht den Zusammenhang zwischen dem Einen und dem Anderen gezogen.

Genauso habe ich das auch heraus gelesen.
Du bist doch sonst nicht so harsch?

Das ist harsch? Ne einfache Frage war das.

Walter, perfekt funktioniert. :slight_smile: Nun werde ich mich später an das millis() delay() Thema machen. Muss aber erst die Jungs ins Bett bringen. :smiley:

Boom und es funktioniert. :boom: Und danke für's Augenöffnen im Bezug auf millis() & delay() an diejenigen die Verständnis dafür haben, dass nicht jeder von Natur aus Programmierer ist und gleich den Durchblick hat was er macht. Aber die Ahaa-Effekte :bulb: kommen nach und nach. :slight_smile:

Hier noch der funktionierende Sketch:

/*
  Autor: ribaribi
  Projekt: Wasseralarm mit Quittiertaste 
  Datum: 20210719

  Beschreibung: Bei erfassen von Wasser, Blinkt und Piepst ein Alarm im Takt.
  Das Piepsen kann man für eine bestimmte Zeit Quittieren. (z.B 60s). Ein LED blinkt weiter.
  Ist nach dieser Zeit immer noch Wasser da sein, fängt das Piepsen wieder an.
  Ist kein Wasser mehr detektiert, wird kein Alarm ausgegeben und die LED leuchtet grün.
*/

int Wassersensor    = A6;      //Feuchtigkeitssensor
const byte Alarm    = 14;      //Piezo-Speaker
const byte LEDRot   = 26;      //RGB LED
const byte LEDGruen = 28;      //RGB LED
const byte LEDBlau  = 30;      //RGB LED (Blau derzeit nicht verwendet)
int Taste2_PIN      = 40;      //Quittiertaste

int Taste2;
bool Quittiert;

//Blinken
const unsigned long EIN_Zeit_LEDRot =  500; //ms
const unsigned long AUS_Zeit_LEDRot =  500; //ms

//Piepsen
const unsigned long EIN_Zeit_Alarm = 750;
const unsigned long AUS_Zeit_Alarm = 750;

//Verzögerung
const unsigned long Alarmverzoegerung = 30 * 1000L;  // Unterbruch des Alarms in ms
unsigned long Quittiermoment;   // Der Moment, wenn die Quittiertaste betätigt wird
unsigned long Restzeit;


void setup()
{
  Serial.begin(9600);
  pinMode (Alarm, OUTPUT);
  pinMode (LEDRot, OUTPUT);
  pinMode (LEDGruen, OUTPUT);
  pinMode (LEDBlau, OUTPUT);
  pinMode (Taste2_PIN, INPUT_PULLUP);

  digitalWrite (LEDRot, HIGH);      //Alarm (Wasser erkannt)
  digitalWrite (LEDGruen, LOW);     //Situation OK
  digitalWrite (LEDBlau, HIGH);     //Nicht verwendet
}

void loop() {

  Taste2 = digitalRead(Taste2_PIN);
  Wassersensor = analogRead(A6);

  Serial.print("Feuchtigkeits-Messwert:");
  Serial.println(Wassersensor);
  delay(500);


  //Alarm
  if (Wassersensor > 100 ) //Ist der Sensorwert grösser als "100", dann...
  {
    if (Quittiert == false)         //Merker ob Quittiertaste betätigt
    {
      digitalWrite(LEDRot, (millis() % (EIN_Zeit_LEDRot + AUS_Zeit_LEDRot)) < EIN_Zeit_LEDRot);
      digitalWrite(Alarm, (millis() % (EIN_Zeit_Alarm + AUS_Zeit_Alarm)) < EIN_Zeit_Alarm);
      digitalWrite(LEDGruen, HIGH);   //grüne LED bleibt dunkel.
    }
    else
    {
      digitalWrite(LEDRot, (millis() % (EIN_Zeit_LEDRot + AUS_Zeit_LEDRot)) < EIN_Zeit_LEDRot);
      digitalWrite(LEDGruen, HIGH);   //grüne LED bleibt dunkel.
    }
  }
  else
  {
    digitalWrite(LEDRot, HIGH);       //rote LED löscht
    digitalWrite(LEDGruen, LOW);      //grüne LED leuchtet konstant
    digitalWrite(Alarm, LOW);         //Alarm ist still.
  }

  //Verzögerung

  if (Taste2 == LOW)                  //Wenn Quittiertaste gedrückt
  {
    Quittiermoment = millis();        //Zeitpunkt des Tastendrucks wird gemerkt
    Serial.println("Taste gedrückt"); //Zur Kontrolle
  }

  if (millis() - Quittiermoment < Alarmverzoegerung) //Abfallverzögerung des Tasters
  {
    Quittiert = true;                 //Quittiertaste betätigt
    Restzeit = (Alarmverzoegerung - (millis() - Quittiermoment)) / 1000;
    Serial.println("Alarm quittiert"); //Zur Kontrolle
  }
  else
  {
    Quittiert = false;          //Quittiertaste ist nicht betätigt.
  }
}

Vielen Dank nochmal für die zielführenden Tipps.

Liebe Grüsse :raised_hand_with_fingers_splayed:

ribaribi :fish:

Da ist noch ein delay drin :stuck_out_tongue:
Aber, wenn es funktioniert, wie du willst, warum nicht.

Ist dieses delay() nicht notwendig für das ausbremsen des Seriell Monitor damit dieses nicht zu schnell durchläuft? :sweat_smile:

Man kann jedes delay durch millis umschreiben.
Aber, wie gesagt, wenns funktioniert, warum nicht?

1 Like