Code für ansteuerung von Pumpen funktioniert nicht

Hallo zusammen,
ich bin noch relativ neu im Bereich Arduino und habe vor kurzem mit meinem ersten "großen" Projekt angefangen.
Ich bin dabei einen Automat zu bauen, der Asbach und Cola automatisch mischt. :beers:
Dazu habe ich zwei Pumpen, die mit drei verschiedenen Tastern für unterschiedlich lange Zeit (unterschiedliche stärke der Mischung) eingeschaltet werden sollen.
Ich habe mal ein wenig rumprobiert, bekomme das Programm aber einfach nicht so hin wie ich es gerne hätte.
Mein aktueller Stand ist dashier:

int tasterGruen = 12;
int relaisSchlauch = 9;
int relaisLuft = 8;

int colaTimer;
int asbachTimer;

unsigned long lastMillis;

void setup()
{
  pinMode(tasterGruen, INPUT_PULLUP);
  pinMode(relaisSchlauch, OUTPUT);
  pinMode(relaisLuft, OUTPUT);
}

void loop()
{
  if (digitalRead(tasterGruen) == LOW)
  {
    asbachTimer = 2000;
    colaTimer = 2000;
    lastMillis = millis();
    pumpenAnsteuerung();
  }
}

void pumpenAnsteuerung()
{
  if ((millis() - lastMillis) <= colaTimer)
  {
    digitalWrite(relaisLuft, HIGH);
  }
  else
  {
    digitalWrite(relaisLuft, LOW);
  }

  
  if ((millis() - lastMillis) <= asbachTimer)
  {
    digitalWrite(relaisSchlauch, HIGH);
  }
  else
  {
    digitalWrite(relaisSchlauch, LOW);
  }
}

Was ich hier versucht habe ist folgendes:

  1. Taster Grün wird betätigt
  2. Variablen asbachTimer und colaTimer werden auf die entsprechende Zeit gesetzt.
    3.Die aktuelle millis() Zeit wird in lastMillis gespeichert
  3. Der Code springt in meine Funktion pumpenAnsteuerung
  4. relaisLuft und relaisSchlauch sollen so lange angesteuert werden wie millis() - lastMillis <= der Variable für die Zeit sind.

Der Code funktioniert in sofern, das die Pumpen beim betätigen des Tasters angehen, aber leider nicht mehr aus.
Könnt ihr mir bitte helfen? Ich weiß hier mit meinem kleinen wissen nicht mehr weiter.

Viele Grüße und danke im vorraus

Tobias

    lastMillis = millis();
    pumpenAnsteuerung();
...

void pumpenAnsteuerung()
{
  if ((millis() - lastMillis) <= colaTimer)

Die Differenz ist immer 0

Generell passt das Konzept aber nicht ganz. Die Verwendung von millis() ist schon eine gute Idee, aber der zeitliche Ablauf ist so nicht richtig. Du musst den Zeitpunkt des Tastendrucks von den restlichen Vorgängen trennen.

Und Taster müssen entprellt werden damit das nur einmal geschieht

Danke für deine schnelle Antwort.
Das heißt ich müsste mit dem Tastendruck direkt in die Funktion springen?
Wie löse ich dann die anderen Befehle am besten aus?

Durch den internen Pullup Widerstand werden meine Taster doch entprellt oder?

Die richtige Richtung:
Die Komponenten einzeln benennen und möglichst weit entkoppeln!
Für der Abfüllung einen (oder gar mehrere) endliche Automaten basteln.

Möchtest Du probieren?
Wenn ja, schreib was dabei raus kommt - ist quick & dirty.


// Forensketch - kompiliert fehlerfrei - reiner Test auf Basis von
// https://forum.arduino.cc/t/code-fur-ansteuerung-von-pumpen-funktioniert-nicht/900401?u=my_xy_projekt
const byte tasterGruen = 12;
const byte relaisSchlauch = 9;
const byte relaisLuft = 8;

unsigned int colaTimer;
unsigned int asbachTimer;

unsigned long lastMillis;

void setup()
{
  pinMode(tasterGruen, INPUT_PULLUP);
  pinMode(relaisSchlauch, OUTPUT);
  pinMode(relaisLuft, OUTPUT);
}

void loop()
{
  if ((digitalRead(tasterGruen) == LOW) && (pumpenAnsteuerung() == LOW))
  {
    asbachTimer = 2000;
    colaTimer = 2000;
    lastMillis = millis();
    pumpenAnsteuerung();
  }
  if (pumpenAnsteuerung()) pumpenAnsteuerung();
}

bool pumpenAnsteuerung()
{
  bool returnWert = false;
  if ((millis() - lastMillis) <= colaTimer)
  {
    digitalWrite(relaisLuft, HIGH);
    returnWert = true;
  }
  else
  {
    digitalWrite(relaisLuft, LOW);
  }
  if ((millis() - lastMillis) <= asbachTimer)
  {
    digitalWrite(relaisSchlauch, HIGH);
    returnWert = true;
  }
  else
  {
    digitalWrite(relaisSchlauch, LOW);
  }
  return returnWert;
}

Hi, danke für deine Mühe!
Ich habe deinen code gerade mal ausprobiert. Funktioniert alles so wie es soll. :+1:
Könntest du mir vielleicht erklären was genau du da gemacht hast?
Verstehe leider nicht alles zu 100%

Erkennst Du die Unterschiede zwischen dem Ursprungscode und dem von mir?
Wenn ja, dann frage, was ich da gemacht habe.
Ich erklär das dann auch gerne. Du musst aber wissen warum.
:wink:

Habe mal meine Vermutungen in den Code Kommentiert.

// Forensketch - kompiliert fehlerfrei - reiner Test auf Basis von
// https://forum.arduino.cc/t/code-fur-ansteuerung-von-pumpen-funktioniert-nicht/900401?u=my_xy_projekt
const byte tasterGruen = 12;
const byte relaisSchlauch = 9;
const byte relaisLuft = 8;

unsigned int colaTimer;
unsigned int asbachTimer;

unsigned long lastMillis;

void setup()
{
  pinMode(tasterGruen, INPUT_PULLUP);
  pinMode(relaisSchlauch, OUTPUT);
  pinMode(relaisLuft, OUTPUT);
}

void loop()
{
  if ((digitalRead(tasterGruen) == LOW) && (pumpenAnsteuerung() == LOW)) // Hier fragst du zusätzlich ab ob die Funktion nicht schon läuft.
  {
    asbachTimer = 2000;
    colaTimer = 2000;
    lastMillis = millis();
    pumpenAnsteuerung();
  }
  if (pumpenAnsteuerung()) pumpenAnsteuerung(); // Verstehe nicht was hier passiert.
}

bool pumpenAnsteuerung()
{
  bool returnWert = false; // Hier definierst du die Variable "returnWert" und setzt sie auf false
  if ((millis() - lastMillis) <= colaTimer)
  {
    digitalWrite(relaisLuft, HIGH);
    returnWert = true; // Wenn die Pumpen laufen setzt du die Variable auf true. Ich vermute um den zustand der Funktion PumpenAnsteuerung abfragen zu können?!
  }
  else
  {
    digitalWrite(relaisLuft, LOW);
  }
  if ((millis() - lastMillis) <= asbachTimer)
  {
    digitalWrite(relaisSchlauch, HIGH);
    returnWert = true;
  }
  else
  {
    digitalWrite(relaisSchlauch, LOW);
  }
  return returnWert; // Wo wird der returnWert denn verarbeitet?
}
1 Like

Nicht schlecht! Gut gemacht.
Deine wichtigste Frage

  return returnWert; // Wo wird der returnWert denn verarbeitet?

Warte ab.

Las mich mal oben anfangen.
Grundsätzlich: Wenn sich Daten nicht verändern können: const.
Immer auf den kleinsten möglichen Wert kürzen!: byte
Ein byte braucht ein byte. Ein int braucht 2 byte (manchmal auch mehr...) und kann negativ sein.
Aus diesem Grund beschreibe Pins wenigstens als uint8_t.
Also unsigned (immer positiver Wert).
So und nu:

  if ((digitalRead(tasterGruen) == LOW) && (pumpenAnsteuerung() == LOW)) // Hier fragst du zusätzlich ab ob die Funktion nicht schon läuft.

Genau.
Ich gehe immer davon aus, das es noch Taste gelb, rot, blau, rosa, regenbogen, pink gibt.

Die Bedingung macht: Wenn Taste gruen nicht gedrückt UND auch keine pumpenansteuerung aktiv, dann darf die Pumpe mit den übergebenen Werten starten.

Danach werden die Werte wie von Dir gewollt gesetzt.
Mit:

    pumpenAnsteuerung();

Wird die Pumpe ausgelöst.
In der Funktion von dir erkannt:

  bool returnWert = false; // Hier definierst du die Variable "returnWert" und setzt sie auf false

Das ist der Ausgangswert.
Dieser wird zurück gegegeben, wenn

    returnWert = true; // Wenn die Pumpen laufen setzt du die Variable auf true. Ich vermute um den zustand der Funktion PumpenAnsteuerung abfragen zu können?!

Na bitte! Richtig erkannt!

Es gibt einen Rückgabewert.
während void nichts ist und auch nichts zurück gibt, ist hier

bool pumpenAnsteuerung()

festgelegt, das ein boolWert zurückgegeben wird. (also true oder false)
das passiert in der letzten Zeile:

  return returnWert; // Wo wird der returnWert denn verarbeitet?

So und wo wird die verarbeitet ist relativ einfach:
An zwei Stellen!

Punkt 1:

  if ((digitalRead(tasterGruen) == LOW) && (pumpenAnsteuerung() == LOW)) // Hier fragst du zusätzlich ab ob die Funktion nicht schon läuft.

Genau. Die Pumpe läuft. Es gibt einen ReturnWert, der true ist - damit darf nicht erneut auf die Taste reagiert werden.
Punkt 2:

  if (pumpenAnsteuerung()) pumpenAnsteuerung(); // Verstehe nicht was hier passiert.

Das ist inhaltlich genau so:

  if (pumpenAnsteuerung()== HIGH) pumpenAnsteuerung();

Solange die Pumpensteuerung (ausgelöst durch irgendwas) läuft, muss gesichert sein, das die auch wieder aus geht.
Die Werte wann Schluss ist, hast Du mit dem Auslöser übergeben.

Verstanden wo ich hin will?

1 Like

Mega, vielen Dank !
Wieder was gelernt.

Willst noch mehr?
Dann empfehle ich mal Literatur. Nur lesen. Jeden Abend ein wenig. Aber von vorn bis hinten.
Nicht auswendig lernen.
Nur wissen das es da steht.
https://www.arduinoforum.de/code-referenz
pdf runterladen :wink:
Na denn. Herzlich willkommen!

Nachtrag:

Wenn Du das so willst, das Du auf LOW prüfst, wäre es lang:

  if (pumpenAnsteuerung()== LOW) pumpenAnsteuerung();

oder kurz:

  if (!pumpenAnsteuerung()) pumpenAnsteuerung();

Hallo
Ich habe auch noch eine Lösung für die Ansteuerung der Pumpen. Meine Lösung verwendet ein paar Elemente zum Lernen aus der OOP, wenn du schon dabei bist.
Nicht vergessen, wie im Sketch angegeben, die I/O Pins und die Förderzeit für die Getränke anpassen.
Eine Frage; Wofür sind die anderen Tasten?

//BLOCK COMMENT
// https://forum.arduino.cc/t/please-help-new-guy/900229
#define ProjectName "Code für ansteuerung von Pumpen funktioniert nicht"
// CONSTANT DEFINITION
// you may need to change these constants to your hardware
constexpr byte Input_[] {A0};
constexpr byte Output_[] {2, 3};
constexpr unsigned long AsbachTimer {2000};
constexpr unsigned long ColaTimer {2000};
// VARIABLE DECLARATION
enum {Gruen};
enum {Asbach, Cola};
struct Taster {
  byte pin;
} taster {Input_[Gruen]};
struct Relay_ {
  byte pin;
} relay_[] {
  {Output_[Asbach]},
  {Output_[Cola]},
};
struct TIMER {
  unsigned long stamp;
  unsigned long duration;
};
TIMER asbach {0, AsbachTimer};
TIMER cola {0, ColaTimer};
// FUNCTIONS
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);
  for (auto Input : Input_) pinMode(Input, INPUT_PULLUP);
  for (auto Output : Output_) pinMode(Output, OUTPUT);
}
void loop () {
  unsigned long currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);

  bool colaState = digitalRead(relay_[Cola].pin);
  bool asbachState = digitalRead(relay_[Asbach].pin);
  if (!colaState && !asbachState && !digitalRead(taster.pin)) {
    cola.stamp = currentTime;
    digitalWrite(relay_[Cola].pin, HIGH);
    asbach.stamp = currentTime;
    digitalWrite(relay_[Asbach].pin, HIGH);
  }
  if (currentTime - cola.stamp >= cola.duration && colaState) digitalWrite(relay_[Cola].pin, LOW);
  if (currentTime - asbach.stamp >= asbach.duration && asbachState) digitalWrite(relay_[Asbach].pin, LOW);
}
Viel Spass beim Lernen und Programmieren.

Gin Tonic!
Jede!
Die Letzte mit 100% Gin.

Hi, das muss ich mir mal in Ruhe ansehen...
Momentan verstehe ich nur Bahnhof :joy:
Aber trotzdem danke für deine Lösung!

Die Maschine hat drei Taster: Grün, Gelb und Rot. Sollen dann später für z.B. 20cl, 40cl und 60cl stehen.

Die Funktion pumpenAnsteuerung muß dauernd aufgerufen werden damit erkannt wird daß die Pumpenlaufzeit vorbei ist und die Pumpen ausgeschaltet werden müssen.

Die Funktion pumpenAnsteuerung wird nur solange aufgerufen wie der Taster gedrückt wird. Wenn Du den Taster kürzer als die Pumpenlaufzeiten druckst werden die Pumpen nicht ausgeschaltet.

Ist der Taster aber bei ender der Pumpenlaufzeit noch gedrückt beginnt der Zyklus von neuem.

Du mußt den Taster als start des Zyklusses programmieren, also eine Variable die anzeigt daß der zyklus läuft und ein neuer Zyklus darf erst starten wenn der Taster losgelassen und nochmal gedrückt wurde.

Grüße Uwe

:wink: Das tuts.

Und ja, der kam genau so von mir :wink:
Passt auf Euch auf.

Schreibt man mal langsam mit mitdenken und nachlesen dann habt ihr bereits 5 Antworten geschrieben.
Manchmal mag ich Euch nicht so gern. :wink:

Grüße Uwe

1 Like

Da fehlen aber noch ein oder mehrere Durchflussgeber

Lass den erstmal mit Zeiten arbeiten, um überhaupt ein "Erlebnis" zu haben.
Cocktailmaker abzuschreiben ist eines, aber das auch zu verstehn, ein anderes.
Gerade Du bist ja da auch nicht ganz unbeleckt.

@entenking
Ich will GIN!

// Forensketch - kleines Spiel - Basis:
// https://forum.arduino.cc/t/code-fur-ansteuerung-von-pumpen-funktioniert-nicht/900401/6?u=my_xy_projekt
const uint8_t tasterGruen = 12;
const uint8_t tasterRot = 11;
const uint8_t tasterGin = 10;
const uint8_t relaisSchlauch = 9;
const uint8_t relaisLuft = 8;

unsigned int colaTimer;
unsigned int asbachTimer;

unsigned long lastMillis;

void setup()
{
  pinMode(tasterGruen, INPUT_PULLUP);
  pinMode(tasterRot, INPUT_PULLUP);
  pinMode(tasterGin, INPUT_PULLUP);
  pinMode(relaisSchlauch, OUTPUT);
  pinMode(relaisLuft, OUTPUT);
}

void loop()
{
  auswahl();
  if (pumpenAnsteuerung()) pumpenAnsteuerung(); // Da alle Variablen global sind, prüfe ständig den Zustand ob noch was laufen soll...
}
void auswahl()
{
  if (!pumpenAnsteuerung())  // Nur wenn keine Pumpe läuft
  {
    if (!digitalRead(tasterGruen))  // Frage die Taste(n) ab
    {
      asbachTimer = 2000;
      colaTimer = 2000;
      lastMillis = millis();
      // pumpenAnsteuerung();   // Die Zeile kann entfallen, da alle Variablen global sind.
    }
    else if (!digitalRead(tasterRot))
    {
      asbachTimer = 3000;
      colaTimer = 1000;
      lastMillis = millis();
      // pumpenAnsteuerung();
    }
    else if (!digitalRead(tasterGin))
    {
      asbachTimer = 4000;
      colaTimer = 0;
      lastMillis = millis();
      //pumpenAnsteuerung();
    }
  }
}
bool pumpenAnsteuerung()
{
  bool returnWert = false; // Hier definierst du die Variable "returnWert" und setzt sie auf false
  if ((millis() - lastMillis) <= colaTimer)
  {
    digitalWrite(relaisLuft, HIGH);
    returnWert = true; // Wenn die Pumpen laufen setzt du die Variable auf true. Ich vermute um den zustand der Funktion PumpenAnsteuerung abfragen zu können?!
  }
  else
  {
    digitalWrite(relaisLuft, LOW);
  }
  if ((millis() - lastMillis) <= asbachTimer)
  {
    digitalWrite(relaisSchlauch, HIGH);
    returnWert = true;
  }
  else
  {
    digitalWrite(relaisSchlauch, LOW);
  }
  return returnWert; // Wo wird der returnWert denn verarbeitet?
}

Das mit den Durchflussgebern ist so ne Sache...
Ich hätte es gerne Lebensmittelecht und bin mir bei dieser China Elektronik da nicht so sicher. :sweat_smile: