Zeitverzögertes ausschalten mit Abbruchmöglichkeit

Irgendwie sehe ich gerade den Wald vor lauter Bäumen nicht.

Ich will an sich was recht einfaches programmieren:

Ich drücke einen Taster, Pumpe soll 30 Sek. pumpen. Drücke ich innerhalb dieser Zeit nochmals, soll sie ausgehen.

Ich brauche die Funktion naturlich in einem grösseren Programm, hier de relevante Code:

Anschalten soll Pi36 wenn subir_nivelState HIGH ist. Die Variable wird in einem anderenprogrammteil gesetzt. Die Abschaltung nach 30 Sek. geht, nur den Abbruch krieg ich nicht hin.

static long subirNivelTime;
      if (subir_nivelState && !subir_nivelAusgangState)   //sperren gegen mehrfachaufrufe, geht
      {
      subirNivelTime=millis();
      subir_nivelAusgangState=1;
      subir_nivelState=0;
      digitalWrite(36, HIGH);    // Pumpe anschalten
      Serial.println("Pumpe starten");
      }

      if (millis()-subirNivelTime  > 30000 && subir_nivelAusgangState)  // Dauer des Hochpumpens, geht
      {
       digitalWrite(36, LOW);    // Pumpe abschalten
       subir_nivelAusgangState=0;
       subir_nivelLastState=0;
       Serial.println("Hochpumpzeit vorbei");
      }

      if (subir_nivelAusgangState && subir_nivelState && !filterspueltzurueck)    // das soll die Abbruchroutine werden, geht NICHT
      {
       digitalWrite(36, LOW);    // Pumpe abschalten
       subir_nivelAusgangState=0;
       Serial.println("Hochpumpen abgebrochen"); 
      }

Wer kann mir da mal auf die Sprünge helfen?

Hallo,

da ich zufällig was ähnliches programmiert habe, eine LED mit unterschiedlichen ein/aus Zeiten blinken lassen, aber nur auf Tastendruck, hab ich mal den Teil abgeändert für Dich. Bei mir funktioniert es.

Ich verwende aber die Bounce2 Library für meine Tastenerkennung- und Entprellung. Aber den Teil kannste ja bestimmt an Deinen Code anpassen. Den Rest solltest Du 1:1 übernehmen können.

Grob erklärt, wird der Pumpenstatus mit jeden Tastendruck umgeschalten und damit ein- und ausgeschalten. Zusätzlich wird immer, wenn die Pumpe eingeschalten wurde, also Pumpenstatus High, wird sich die akutelle Zeit gemerkt. Dann wird geprüft ob die Zeit abgelaufen ist, wenn ja, wird Pumpe ausgeschalten und der Pumpenstatus auf Low zurück.

#include <Bounce2.h>

byte Taster_Pumpe = 6;               // Taster an Pin 6 gegen Masse
#define Pumpe_Pin 41                 // Schaltpin Pumpe ein/aus
#define Pumpeneinschaltdauer 5000    // maximale Pumpenlaufzeit
Bounce debouncer2 = Bounce();        // Instantiate a Bounce object Nr.2 ( Taster Pumpe )

void setup()  {
  
  digitalWrite(Pumpe_Pin, LOW);        // Schaltpin Pumpe aus
  pinMode(Pumpe_Pin, OUTPUT);          // Schaltpin Pumpe Ausgang
     
  // digitalen Eingang mit PullUp aktivieren  
  pinMode(Taster_Pumpe, INPUT);        // setzt Taster Pin als Eingang
  digitalWrite(Taster_Pumpe, HIGH);    // und aktiviert dessen PullUp Widerstand 

  debouncer2.attach(Taster_Pumpe);
  debouncer2.interval(30);             // Entprellzeit 30ms für den Taster
  
}   // Ende setup


void loop(void) {
 
   Pumpe_schalten();  // Pumpe ein- oder ausschalten mittels Taster
     
}   // Ende loop


/* ------------------------------------------------------------------------------------------------ */


void Pumpe_schalten ()
{
  boolean stateChanged_2 = debouncer2.update();
  static boolean state_Pumpe = LOW;
  static unsigned long millis_now = 0;
  int state_2 = debouncer2.read();
  
  // wenn LOW Signal vom Taster erkannt, schalte Pumpe ein bzw. mit nächsten LOW wieder aus
  if ( stateChanged_2 && state_2 == LOW ) {
    if ( state_Pumpe == LOW ) {
      state_Pumpe = HIGH;                             // Tasterdruck, Pumpe einschalten
      millis_now = millis() + Pumpeneinschaltdauer;   // maximale Einschaltdauer setzen
      } 
      else {
        state_Pumpe = LOW;              // erneuter Tasterdruck, Pumpe ausschalten
      }
      digitalWrite(Pumpe_Pin, state_Pumpe); 
      
  }
  
  // wenn Pumpe läuft, dann nach eingestellter Zeit selbst wieder ausschalten
  if (millis() > millis_now)  {
       digitalWrite(Pumpe_Pin, LOW);      // ausschalten nach x sec.
       state_Pumpe = LOW;
  }    
    
}

das sieht doch ganz gut aus. da hätte ich auch selber drauf kommen können 8) 8)

werde es morgen gleich ausprobieren.

Danke einstweilen.

Hallo,

 if (subir_nivelAusgangState && subir_nivelState && !filterspueltzurueck)    // das soll die Abbruchroutine werden, geht NICHT
      {
       digitalWrite(36, LOW);    // Pumpe abschalten
       subir_nivelAusgangState=0;
       Serial.println("Hochpumpen abgebrochen"); 
      }

hab mir Deinen Code nochmal genauer angeschaut. Deine if Abfrage funktioniert bestimmt nicht. Auf was sollen den die 3 Variablen geprüft werden? Sind nur UND verknpüft. Irgendwie fehlt mir da ein Vergleich auf was geprüft werden soll?

Das muß bestimmt so aussehen ... wobei ich jetzt Deine benötigten Logikzustände nicht kenne.

 if (subir_nivelAusgangState == HIGH && subir_nivelState == HIGH && filterspueltzurueck == LOW)    //
      {
       digitalWrite(36, LOW);    // Pumpe abschalten
       subir_nivelAusgangState=0;
       Serial.println("Hochpumpen abgebrochen"); 
      }

Kannste nur ausprobieren. Viel Glück!

meine Logikverknüpfung kann man schon so machen, macht genau das gleiche wie deine. das Problem ist nur, dass die Bedingung subir_nivelState ==High beim nächsten Programmdurchlauf schon wieder erfüllt ist, da ich mein Finger nicht so schnell vom Taster bekomme. und somit wird sofort abgebrochen. Schnalze ich nur kurz auf den Taster und ist er vor der nächsten Abfrage somit wieder LOW, funktioniert es. und die Wartezeit wird nicht abgebrochen.

Dann mußt Du den Zustand des Tasters in einer Variablen abspeichern und nur etwas ausführen wenn der Zustand des Tasters verschieden vom Status des Tasters ist.

taster= digitalRead(PinTaster);
if(taster == HIGH && taster != statustaster)  // taster gerade gedrückt
{
mach was
}
statustaster = taster;

Grüße Uwe

ElEspanol: meine Logikverknüpfung kann man schon so machen, macht genau das gleiche wie deine. das Problem ist nur, dass die Bedingung subir_nivelState ==High beim nächsten Programmdurchlauf schon wieder erfüllt ist, da ich mein Finger nicht so schnell vom Taster bekomme. und somit wird sofort abgebrochen. Schnalze ich nur kurz auf den Taster und ist er vor der nächsten Abfrage somit wieder LOW, funktioniert es. und die Wartezeit wird nicht abgebrochen.

Je komplexer ein Sketch wird und je vielfältiger geschaltete Abhängigkeiten auftreten, desto eher bietet sich ein Aufbau des Programms unter Beachtung des EVA-Prinzips an. - Eingabe (Abfrage von Eingängen und Sensorwerten) - Verarbeitung (Logische Abhängigkeiten berücksichtigen und zu Variablenzuständen verarbeiten) - Ausgabe (Variablenzustände physikalisch an den Ausgängen setzen)

Für Deinen Zweck bietet es sich an, zunächst mal im Rahmen der "Eingabe" die Taster sauber abzufragen. Wenn Du auf die Aktion "Schalter wird betätigt" reagieren möchtest, dann ist es egal, wie lange ein Schalter gedrückt wird und welchen Zustand er augenblicklich hat, sondern Du mußt auf den Statuswechsel von "Schalter unbetätigt" auf "Schalter betätigt" reagieren. Das kann man abfragen und beispielsweise nur zu diesem Statusübergang ein "true" von einer Abfragefunktion zurückbekommen.

Das zweite ist der unterbrechbare Schaltvorgang mit Zeitsteuerung. Das verarbeitet man am besten so, dass Du Dir in zwei Statusvariablen merkst wann der Vorgang gestartet wurde und dass er gestartet wurde:

static unsigned long pumpeStartzeit;
static boolean pumpeGeschaltet;

Beim Starten der Pumpe mittels Schalter setzt Du dann

pumpeStartzeit=millis();
pumpeGeschaltet=true;

Beim Ablaufen der Pumpenlaufzeit setzt Du den Schaltstatus zurück:

if (pumpeGeschaltet && millis()-pumpeStartzeit>30000) pumpeGeschaltet=false;

Und wenn der Abbruch-Button betätigt wurde, setzt Du ebenfalls den logischen Pumpenstatus auf false.

Und wenn alles im Programm verarbeitet wurde, dann hast Du am Ende nach der Verarbeitung eine Ausgabefunktion, die dann den logischen Pumpenstatus auf dem Pumpen-Pin ausgibt:

digitalWrite(36,pumpeGeschaltet);

Die logische Trennung von "Verarbeitung" und "Ausgabe" hat den Vorteil, dass Du im Rahmen der "Verarbeitung" hunderte von Funktionen und Bedingungen haben kannst, die vielleicht eventuell aber möglicherweise auch nicht den Einschaltstatus virtuell in der Variablen "pumpeGeschaltet" verändern können, ohne dass etwas geschaltet wird. Und erst wenn die allerletzte Bedingung verarbeitet wurde, wird dann das tatsächlich geschaltet, was der letztendliche Status von "pumpeGeschaltet" zu diesem Zeitpunkt ist.

Hallo jurs,

danke für die ausführliche Erläuteung. Ohne zu wissen, was EVA ist, hab ich ein Grossteil schon so programmiert. Aber manchmal komme ich mir einfach vor wie Herr Alzheimer. Da fallen mir die einfachsten Basics nicht mehr ein.

Das Programm ist in der Tat sehr umfangreich geworden, und noch nicht ganz fertig. Am Mega sind fast ALLE I/O-Ports in Benutzung, dann noch 2 mcp23017 voll beschaltet, eine I2c LCD 2004 Anzeige, evtl. noch eine weitere 1602, Ethernet Port, RTC, 4 x DS18B20, DHT11, SR04, I2C range extender und ein Ar... voll Taster und kontroll-LEDs.

Hallo,

Du hast einen voll belegten Mega? Willst Du ein Space-Shuttle steuern? :D

nein, nur meinen Pool mit Überlaufkante 8) 8)

Panel im Technikraum, Bedienpanel neben dem Pool, Unterwassertaster, alle möglichen Temperaturen loggen, per Webseite auf den Mega zugeifen, Fehlerbenachrichtigung per SMS, automatischer Ruckspielfilter, alle Ventile elektisch, Wasserniveausteuerung, Wasserspiegelnachtabsenkung, und etc. pp

Die Vitalfunktionen laufen über ene Siemens LOGO 220V, da trau ichdem Mega noch nicht ganz. Weil bei einer dummen Fehlfunktion könnten für 500€ Wasser übern Jordan gehen. Das ganze wird zusammengebunden mit MOC3020 und Optokoppler mit LED-Birnenvorschaltelektronik.

Sind bereits ca. 46kilobyte erzeugter Arduinocode. Bis 256 hab ich ja noch Luft XD XD XD

Hallo,

schönes Projekt. :)