Ausgänge gleichzeitig einschalten und unabhängig voneinander ausschalten

Hallo,

ich bin eigentlich noch Anfänger beschäftige mich aber schon etwas länger mit dem Arduino. Ich habe mir jetzt ein kleines Projekt in den Kopf gesetzt, dass ich gerne umsetzen möchte und stehe damit meinem Programmcode noch ganz am Anfang und benötige Hilfe.

An den A0-A5 habe ich je 1 Taster angeschlossen. An den I/O 2-12 habe ich Relais angeschlossen die 11 Förderschnecken einschalten sobald der I/O auf LOW ist. Die Taster stellen so zu sagen je 1 Rezept dar welches zur Mischung der Zutaten in den Förderschnecken benötigt wird. Die Menge der einzelnen Zutat ergibt sich durch die Einschaltdauer des entsprechenden Relais. Um Zeit zu sparen sollen alle Zutaten die benötigt werden gleichzeitig anlaufen und nach einer definierten Zeit pro Zutat unterschiedlich aufhören.

Ich hatte das jetzt mal mit Delays versucht. Das klappt auch ist allerdings nicht praktikabel da ja bekanntermaßen das Programm anhält. Des Weiteren ist das zusammenaddieren und subtrahieren von den verschiedenen Laufzeiten sehr mühselig, gerade wenn sich die Rezepturen laufend ändern. Da ich später noch ein Display mit dem Produktionsfortschritt integrieren möchte ist das Delay damit endgültig raus.

Ich habe mich jetzt schon ein wenig mit den Millis() beschäftigt und denke, dass es damit schon besser klappen könnte. Allerdings komme ich mit den Beispielen nicht wirklich weiter da meistens nur ein oder 2 Led's in einem bestimmten abstand ein und wieder ausgeschaltet werden. Bei mir gibt es ja aber in dem Sinn kein Loop.

Hat jemand eine Idee wie ich das realisieren könnte?

Vielen Dank schon mal.

Liebe Grüße Sebastian

Ja, die Basics erst einmal fleißig durcharbeiten und dann erst an das Projekt wagen. millis() sollte verstanden werden, dann spielt die Anzahl der Leds keine Rolle.

Du legst ein struct für jedes Rezept an, in dem du die Zeiten defenierst, wie lange diese laufen dann baust du dir einzelne Funktionen, bei denen du abfragst, ob genug Zeit vergangen ist. Wenn keines der Ausgänge mehr aktiv ist, ist das Rezept beendet

Benutze millis() für die Zeitbestimmung. Siehen Beispiel "blink without dealy"

Grüße Uwe

Und einfache Dinge kannst du hier nachlesen:

http://www.netzmafia.de/skripten/hardware/Arduino/Arduino_Programmierhandbuch.pdf

oder hier:

http://www.arduino-tutorial.de/programmieren/

Du kannst aber auch Dr. Google befragen, der ist sehr auskunftsfreudig.

Wenn du dann eine direkte Frage zu einem Problem in deinem Sketch hast, werden wir dir gern weiter helfen.

Du mußt eine Loop() basteln, die ständig, ohne delay() durchläuft.

Dann würde ich zwei Zweige trennen (über if()), einen wenn keine Dosierung läuft und auf Tasterabfragen gewartet wird, und einen im dem die Dosierung läuft.

zum Beispiel so:
loop(){

  • if (keine Dosierung aktiv)*
  • wurde Taster gedrückt? ja: Zeit merken, alle Förderschnecken starten*
  • else*
  • Zeit für Schnecke1 abgelaufen? ja: Schnecke1 stoppen.*
  • Zeit für Schnecke2 abgelaufen? ja: Schnecke2 stoppen.*
  • Zeit für Schnecke3 abgelaufen? ja: Schnecke3 stoppen.*
  • …*
  • ( kann man auch in for-Schleife machen)*
    }

die Zeiten für die verschiedenen Zutaten würde ich in einem Array ablegen.
Das kann dann so aussehen: (ungetesteter Code, nur als Beispiel!)

// Array um die Zutaten pro Rezept festzulegen [Föderzeit in millisekunden]
const unsigned long Rezepte[4] = { 500,  4000,  1000,  1000};  

// ein Array, um die Zuordung der  Zutaten zu den Pins festzulegen
const int Schnecke[Anzahl_Zutaten] = {5,8,11,3};

  
boolean Dosierungaktiv = false;
int Zutat_Nr;
unsigned long Dosierstart;

void setup() {
  // PinMode definitionen etc.
}

void loop() {
  if (!Dosierungaktiv) {                                 // Wenn keine Dosierung, dann Taster abfragen
     if (analogRead(A0) < 512 ){                           // Wenn Taster gedrückt wurde, 
        Dosierstart = millis();                              //    Zeit merken,
        for (int i = 0; i < 4; i++) {                        //    alle Dosierschnecken starten ,
          digitalWrite(Schnecke[i], LOW);
        }
        Dosierungaktiv = true;                            //    und Status setzen.
      }
    }
  } else {                                                // wenn Dosierung aktiv
    for (int i = 0; i < 4; i++){                            // für jede Zutat abfragen,
      if ( millis() - Dosierstart > Rezepte[i]){            // ob die Dosierzeit abgelaufen ist
        digitalWrite(Schnecke[i], HIGH);                    // dann entsprechendes Ventil abschalten
      }
    }
    boolean AlleAus = false;
    for (int i = 0; i < 4; i++){                              // Wenn alle Ventile abgeschalten sind
      AlleAus = AlleAus && (digitalRead(Schnecke[i]) == LOW);  
    }
    if (AlleAus) Dosierungaktiv = false;                          // Status zurücksetzen
  }
} // end loop()

Um das ganze flexibler zu machen, kann man die festen Grenzen der Arrays mit Konstanten ersetzen, auf die dann auch in den for Schleifen abgefragt wird.
Aus
Rezepte[4] = { 500, 4000, 1000, 1000};

for (int i = 0; i < 4; i++) {

wird
const int Anzahl_Zutaten = 4
Rezepte[Anzahl_Zutaten ] = { 500, 4000, 1000, 1000};

for (int i = 0; i < Anzahl_Zutaten ; i++) {

Der nächste Schritt ist dann, das alles auf mehrere Rezepte aufzubohren. Dafür wird das Rezepte-Array 2-dimensional und bei der Tasterabfrage muss geprüft werden, welcher gedrückt wurde.

Das könnte dann so aussehen: (ungetesteter Code, nur als Beispiel)

const int Anzahl_Rezepte = 3;  // wieviele verschiedene Rezepte sind angelegt
const int Anzahl_Zutaten = 4;  // wieviele verschiedene Zutaten sind angelegt


// Array um die Zutaten pro Rezept festzulegen [Föderzeit in millisekunden]
// Beispiel: 3 Rezepte, 4 Zutaten
const unsigned long Rezepte[Anzahl_Rezepte][Anzahl_Zutaten] = {{ 500,  4000,  1000,  1000}, 
                                                               { 1000,  4500,  4000,  2000}, 
                                                               { 3000,  1500,  2000,  3500}   };

// ein Array, um die Zuordnung der Taster zu den Rezepte festzulegen                                                  
const int Taster[Anzahl_Rezepte] = {A0, A1, A2};

// ein Array, um die Zuordung der  Zutaten zu den Pins festzulegen
const int Schnecke[Anzahl_Zutaten] = {5,8,11,3};

  
boolean Dosierungaktiv = false;
int Rezept_Nr;
int Zutat_Nr;
unsigned long Dosierstart;

void setup() {
  // PinMode definitionen etc.

}

void loop() {
  if (!Dosierungaktiv) {                                     // Wenn keine Dosierung, dann Taster abfragen
    for (int i = 0; i < Anzahl_Rezepte; i++){
      if (analogRead(Taster[i]) < 512 ){                       // Wenn Taster gedrückt wurden, 
        Rezept_Nr = i;                                           //    Ausgewähltes Rezept merken,
        Dosierstart = millis();                                  //    Zeit merken,
        for (int i = 0; i < Anzahl_Zutaten; i++) {               //    Dosierschnecken starten ,
          digitalWrite(Schnecke[i], LOW);
        }
        Dosierungaktiv = true;                                   //    und Status setzen.
      }
    }
  } else {                                                  // Solange Dosierung aktiv
    for (int i = 0; i < Anzahl_Zutaten; i++){                 // für jede Zutat abfragen,
      if ( millis() - Dosierstart > Rezepte[Rezept_Nr][i]){   // ob die Dosierzeit abgelaufen ist
        digitalWrite(Schnecke[i], HIGH);                      // dann Ventil abschalten
      }
    }
    boolean AlleAus = false;
    for (int i = 0; i < Anzahl_Zutaten; i++){               // Wenn alle Ventile abgeschalten sind
      AlleAus = AlleAus && (digitalRead(Schnecke[i]) == LOW);  
    }
    if (AlleAus) Dosierungaktiv = false;                             // Status zurücksetzen
  }
} // end loop()

Es gibt viele verschiedene Möglichkeiten sowas zu implementieren, es wurden schon welche genannt, es werden noch mehr genannt werden. Es gibt nicht DIE Richtige. Wichtig ist, dass du dir die Version suchst, die du verstehst und die dir liegt. Nimm die obige nur als Beispiel.

Im Attachment eine (ungetestete) Version als .ino mit seriellen Ausgaben.

parallel_Dosieren.ino (2.87 KB)

Hi,

vielen lieben Dank für die Anregungen. Ich werde mich damit jetzt erst mal auseinandersetzten und berichten.

LG Sebastian

Hallo Günther, das hat mir sehr weitergeholfen, nur leider hab eich einen fehler im Code,
ich denke hier hängt es

boolean AlleAus = false;
for (int i = 0; i < Anzahl_Zutaten; i++){ // Wenn alle Ventile abgeschalten sind
AlleAus = AlleAus && (digitalRead(Ventil*) == LOW); *

  • }*
    ich hoffe du hast einen Tip, da ich als neuling einfach auf dem Schlauch stehe.
    Die Schleife endet nicht

Dualpower:
Ich hoffe du hast einen Tip, da ich als neuling einfach auf dem Schlauch stehe.
Die Schleife endet nicht

Welche Schleife endet nicht ?

Ich sehe keine Schleife in deinem Code-Fragment.

Der Fehler liegt meist im geheimen teil des Sketches. Also poste bitte den kompletten Sketch.

Und verwende dazu Code-Tags, damit der Sketch lesbar wird.

Schaltfläche </> oben links im Editorfenster.

Hallo,
haben den Code eigentlich komplett übernommen.

ich denke dieser bereich scheint das Probel zu machen (Dosierungaktiv wird niczt false)

boolean AlleAus = false;
for (int i = 0; i < Anzahl_Zutaten; i++){ // Wenn alle Ventile abgeschalten sind
AlleAus = AlleAus && (digitalRead(Schnecke*) == LOW);*

  • }*
  • if (AlleAus) Dosierungaktiv = false; *
    [/color]
    Bitte entschuldigt aber ich bin absoluter anfänger und versuche mich zurecht zufinden und zu lernen.
    Ausserdem habe ich eine weitere frage wenn ich in meinen Rezepten unterschiedliche mengen an Zutaen habe, wie könnte das aussehen?
    ```
    *const int Anzahl_Rezepte = 3;  // wieviele verschiedene Rezepte sind angelegt
    const int Anzahl_Zutaten = 4;  // wieviele verschiedene Zutaten sind angelegt

// Array um die Zutaten pro Rezept festzulegen [Föderzeit in millisekunden]
// Beispiel: 3 Rezepte, 4 Zutaten
const unsigned long Rezepte[Anzahl_Rezepte][Anzahl_Zutaten] = {{ 500,  4000,  1000,  1000},
                                                              { 1000,  4500,  4000,  2000},
                                                              { 3000,  1500,  2000,  3500}  };

// ein Array, um die Zuordnung der Taster zu den Rezepte festzulegen                                               
const int Taster[Anzahl_Rezepte] = {A0, A1, A2};

// ein Array, um die Zuordung der  Zutaten zu den Pins festzulegen
const int Schnecke[Anzahl_Zutaten] = {5,8,11,3};

boolean Dosierungaktiv = false;
int Rezept_Nr;
int Zutat_Nr;
unsigned long Dosierstart;

void setup() {
  // PinMode definitionen etc.

}

void loop() {
  if (!Dosierungaktiv) {                                    // Wenn keine Dosierung, dann Taster abfragen
    for (int i = 0; i < Anzahl_Rezepte; i++){
      if (analogRead(Taster[i]) < 512 ){                      // Wenn Taster gedrückt wurden,
        Rezept_Nr = i;                                          //    Ausgewähltes Rezept merken,
        Dosierstart = millis();                                  //    Zeit merken,
        for (int i = 0; i < Anzahl_Zutaten; i++) {              //    Dosierschnecken starten ,
          digitalWrite(Schnecke[i], LOW);
        }
        Dosierungaktiv = true;                                  //    und Status setzen.
      }
    }
  } else {                                                  // Solange Dosierung aktiv
    for (int i = 0; i < Anzahl_Zutaten; i++){                // für jede Zutat abfragen,
      if ( millis() - Dosierstart > Rezepte[Rezept_Nr][i]){  // ob die Dosierzeit abgelaufen ist
        digitalWrite(Schnecke[i], HIGH);                      // dann Ventil abschalten
      }
    }
boolean AlleAus = false;
    for (int i = 0; i < Anzahl_Zutaten; i++){              // Wenn alle Ventile abgeschalten sind
      AlleAus = AlleAus && (digitalRead(Schnecke[i]) == LOW);
    }
    if (AlleAus) Dosierungaktiv = false;                            // Status zurücksetzen
  }
} // end loop()*
```

Ok, das ist ja auch nur ein Beispiel-Sketch. Hat Gunther auch beigeschrieben.

Da solltest du dir Debug-Abfragen einbauen, um an den entsprechenden Stellen zu prüfen, was in den einzelnen Variablen steht.

Sorry, aber ohne entsprechende Kenntnisse der Basics bzw. Grundlagen solltest du nicht einfach irgend einen Sketch kopieren und denken, der funktioniert.

Hallo,
gibt es jemanden der mich bei diesem Code Unterstützen kann?
Das ist genau sowas was ich benötige, ich möchte Magnetventile ansteuern zum Dosieren von Flüssigkeiten.

12 Magnetventile mit unterschiedlichen Rezepten:
z.B. Ventil 1,4,8,9 sollen zeitgleich beginnen und nach x sec. abschalten

  1. Ventil 3 sec.
  2. Ventil 1 sec.
  3. Ventil 0,5 sec.
  4. Ventil 2 sec.

Die Rezepte sind mit unterschiedlichen Zutaten mal eine mal 3, 4 oder 5 zutaten.

Ich würde mich sehr freuen wenn mir jemand weiterhelfen würde.

Dank!

Hallo, hier werden sehr viele dein Vorhaben unterstützen, aber programmieren musst du selber, das machen wir nicht für dich.

Also lerne die Grundlagen und bearbeite den "Mustersketch" entsprechend deinen Wünschen. Den postest du und wir helfen dir. Denn nur du hast deine Hardware und weißt was die machen soll.

Es gab hier schon einige Freds, in denen das Thema “Cocktailmaschine” behandelt wurden.

z.B.: http://forum.arduino.cc/index.php?topic=214079.0
oder http://forum.arduino.cc/index.php?topic=382875.0http://forum.arduino.cc/index.php?topic=382875.0

Wenn du nach Cocktail im Forum suchst, wirst du sicher noch mehr finden.

Wie das mit dem “parallelen” Verarbeiten von verschiedenen Aktionen geht ist hier http://forum.arduino.cc/index.php?topic=354263.20 in Post #24 beschrieben, auch agmue hat eine sehr gute Beschreibung geliefert: Anleitung Ein Endlicher Automat entsteht

Wenn du dann anfängst dein Programm Schritt für Schritt aufzubauen, und nach jedem Schritt testest, dann wir dir hier bei Problemen gerne geholfen.

z.B.: Schritt1: Ein Ventil (Pumpe) nach Tastendruck eine gewisse Zeit ansteuern
Schritt2: Zwei Ventile nach Tastendruck unterschiedliche Zeiten ansteuern.
Schritt3: “Rezepte” (Ansteuerzeiten) in einem Array anlegen und Auswählen.
Schritt4: Display ansteuern
u.s.w.

Hallo, das hört sich gut an, ich werde womöglich am WE was zeit bekommen und meinen angepassten Code mit Problemem hier Posten.

Dualpower:

    boolean DosierungAus = false;

for (int i = 0; i < Anzahl_Zutaten; i++)  {          // Wenn alle Ventile abgeschalten sind
      DosierungAus = DosierungAus && (digitalRead(Ventil[i]) == LOW);
     
    }

Danach ist DosierungAus immer false;
False && irgendwas ist immer false.

Soll digitalRead(Ventil*) == LOW die Abfrage sein, ob das jeweilige Ventil aus ist?*
Dann würde ich die Abfrage andersrum stellen:
DosierungAus = DosierungAus || digitalRead(Ventil*) == HIGH*
Gruß Tommy

Tommy56:
Dann würde ich die Abfrage andersrum stellen:

DosierungAus = DosierungAus || digitalRead(Ventil[i]) == HIGH

Nö, das funktioniert nicht. Aber die Idee dahinter stimmt :slight_smile:

Ich habe mal den ganzen Sketch geringfügig überarbeitet, so geht es:

const int Anzahl_Rezepte = 6;  // anzahl Rezepte
const int Anzahl_Zutaten = 6;  // anzahl zutaten

const unsigned long Rezept[Anzahl_Rezepte][Anzahl_Zutaten]  = {
  { 500,  1000, 1500,  2000, 2500,  3000},
  { 3000,  500,    0,    0,    0,    0},
  { 2700,    0,    0,    0,    0,    0},
  {    0,    0, 2000, 3000,    0,    0},
  {    0,    0,    0,    0,    0, 3000},
  {    0, 2000,    0,    0,    0,    0}
};

// Taster
const int Taster[Anzahl_Rezepte] = {A0, A1, A2, A3, A4, A5};

// Ventile
const int Ventil[Anzahl_Zutaten] = {4, 5, 6, 7, 8, 9};

boolean Dosierungaktiv = false;
unsigned long StartZeit;
int Rezept_Nr;
int Zutat_Nr;

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < Anzahl_Rezepte; i++) {
    pinMode(Taster[i], INPUT);
    digitalWrite(Taster[i], HIGH);
  }
  for (int i = 0; i < Anzahl_Zutaten; i++) {
    pinMode(Ventil[i], OUTPUT);
  }
  Serial.print("\n\nBitte Rezept waehlen");
  //
  for (int i = 0; i < Anzahl_Zutaten; i++) digitalWrite(Ventil[i], HIGH);
  //
}

void loop() {
  if (!Dosierungaktiv) {                                       // Wenn keine Dosierung, dann Taster abfragen
    for (int i = 0; i < Anzahl_Rezepte; i++) {
      if (analogRead(Taster[i]) < 512) {                     // Wenn Taster gedrückt wurden,
        Rezept_Nr = i;                                       //    Ausgewähltes Rezept merken,
        StartZeit = millis();                                 //    Zeit merken,
        Serial.print("\nRezept_Nr: "); Serial.print(Rezept_Nr);
        for (int z = 0; z <= Anzahl_Zutaten; z++) {           //    Dosierung Ventil i starten
          digitalWrite(Ventil[z], LOW);
        }
        Dosierungaktiv = true;                                 //    und Status setzen.
      }
    }
  } else {                                                     // Solange Dosierung aktiv
    for (int i = 0; i < Anzahl_Zutaten; i++) {                 // für jede Zutat abfragen,
      unsigned long currentMillis = millis();
      if ( currentMillis - StartZeit > Rezept[Rezept_Nr][i]) {      // ob die Dosierzeit abgelaufen ist
        digitalWrite(Ventil[i], HIGH);
      }
    }
    boolean DosierungAus = true;
    for (int i = 0; i < Anzahl_Zutaten; i++)  {           // Wenn alle Ventile abgeschalten sind
      DosierungAus = DosierungAus && digitalRead(Ventil[i]);
    }
    if (DosierungAus) {
      Dosierungaktiv = false;                  // Status zurücksetzen
      Serial.print("\n\nBitte Rezept waehlen");
    }
  }
} // end loop()a

Die Rezepte sind für mich als Hobby-Cocktail-Mixer noch etwas eintönig, aber das läßt ja leicht ändern :wink:

agmue: Nö, das funktioniert nicht. Aber die Idee dahinter stimmt :)

Du hast Recht.

Gruß Tommy

addiere doch in einer Schleife alle digitalRead(Ventil[i])in ein byte. Wenn das 0 ist, sind alle aus. Alternativ bei negativer Logik addierst du eben!digitalRead(Ventil[i])

@ agmue
Perfekt funtioniert, danke.
Als nächstes möchte ich ein zweizeiliges Display für die Ausgabe des aktuellen Rezeptes, einen Zähler und Später eine Füllstandanzeige -überwachung (ultraschall) einbinden.

LG

agmue:
Nö, das funktioniert nicht. Aber die Idee dahinter stimmt :slight_smile:

Ich habe mal den ganzen Sketch geringfügig überarbeitet, so geht es:

const int Anzahl_Rezepte = 6;  // anzahl Rezepte

const int Anzahl_Zutaten = 6;  // anzahl zutaten

const unsigned long Rezept[Anzahl_Rezepte][Anzahl_Zutaten]  = {
  { 500,  1000, 1500,  2000, 2500,  3000},
  { 3000,  500,    0,    0,    0,    0},
  { 2700,    0,    0,    0,    0,    0},
  {    0,    0, 2000, 3000,    0,    0},
  {    0,    0,    0,    0,    0, 3000},
  {    0, 2000,    0,    0,    0,    0}
};

// Taster
const int Taster[Anzahl_Rezepte] = {A0, A1, A2, A3, A4, A5};

// Ventile
const int Ventil[Anzahl_Zutaten] = {4, 5, 6, 7, 8, 9};

boolean Dosierungaktiv = false;
unsigned long StartZeit;
int Rezept_Nr;
int Zutat_Nr;

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < Anzahl_Rezepte; i++) {
    pinMode(Taster[i], INPUT);
    digitalWrite(Taster[i], HIGH);
  }
  for (int i = 0; i < Anzahl_Zutaten; i++) {
    pinMode(Ventil[i], OUTPUT);
  }
  Serial.print("\n\nBitte Rezept waehlen");
  //
  for (int i = 0; i < Anzahl_Zutaten; i++) digitalWrite(Ventil[i], HIGH);
  //
}

void loop() {
  if (!Dosierungaktiv) {                                      // Wenn keine Dosierung, dann Taster abfragen
    for (int i = 0; i < Anzahl_Rezepte; i++) {
      if (analogRead(Taster[i]) < 512) {                    // Wenn Taster gedrückt wurden,
        Rezept_Nr = i;                                      //    Ausgewähltes Rezept merken,
        StartZeit = millis();                                //    Zeit merken,
        Serial.print("\nRezept_Nr: “); Serial.print(Rezept_Nr);
        for (int z = 0; z <= Anzahl_Zutaten; z++) {          //    Dosierung Ventil i starten
          digitalWrite(Ventil[z], LOW);
        }
        Dosierungaktiv = true;                                //    und Status setzen.
      }
    }
  } else {                                                    // Solange Dosierung aktiv
    for (int i = 0; i < Anzahl_Zutaten; i++) {                // für jede Zutat abfragen,
      unsigned long currentMillis = millis();
      if ( currentMillis - StartZeit > Rezept[Rezept_Nr][i]) {      // ob die Dosierzeit abgelaufen ist
        digitalWrite(Ventil[i], HIGH);
      }
    }
    boolean DosierungAus = true;
    for (int i = 0; i < Anzahl_Zutaten; i++)  {          // Wenn alle Ventile abgeschalten sind
      DosierungAus = DosierungAus && digitalRead(Ventil[i]);
    }
    if (DosierungAus) {
      Dosierungaktiv = false;                  // Status zurücksetzen
      Serial.print(”\n\nBitte Rezept waehlen");
    }
  }
} // end loop()a



Die Rezepte sind für mich als Hobby-Cocktail-Mixer noch etwas eintönig, aber das läßt ja leicht ändern ;)

Dualpower: Perfekt funtioniert, danke.

Freut mich :)