IF-Bedingung unterbrechen, bis ein Reed-Schalter geöffnet und wieder geschlossen wird. Hier für ein Projekt einer automatischen Füllstation

Hi zusammen!

Ich benötige eure Hilfe. Bisher konnte ich als mittlerweile nicht mehr komplett blutiger Anfänger, sondern blutiger Anfänger mit Pflaster auf meinen Wunden, alle meine Ideen, Probleme, etc. mit Lesen, Suchen, Lernen und nach trail and error Prinzip lösen.

Doch nun gehen mir die Ideen aus und selbst die Idee "wonach" ich suchen soll. Ich versuche es euch mal plausibel zu erklären. Wahrscheinlich lacht ihr mich aus und ich habe einfach zu kompliziert gedacht, um es in einen Code zu packen.

Ok. Anchors aweigh!

Mein Ziel ist es die IF-Struktur zu unterbrechen/überspringen, bis der Reed Schalter, nachdem vorher die Bedingung wahr geworden, erst wieder durchlaufen wird, bis der Schalter geöffnet wurde. D.h. bleibt er weiterhin geschlossen, dann soll nichts passieren, bis er geöffnet und wieder geschlossen wird.

In dem Code könnt ihr sehen was eigentlich passieren soll. Für diesen Post habe ich versucht den Code zu vereinfachen und habe ihn mit einfachen Begriffen geschrieben. Ich nutze sonst eine andere Bibliothek und auch Funktionen, aber für mein Problem ist es ganz egal. Hauptsache ihr wisst worum es geht.

Vielleicht habt ihr einen Tipp für mich, um mich in die richtige Bahn zu lenken. Ich probiere liebend gern alles möglich aus. Danke euch schonmal.

#include <Stepper.h>

int reed_schalter;
int led;
int relais;
Stepper my_stepper = Stepper(200, 2, 3);

void setup() {
  reed_schalter = 4;
  led = 5;
  relais = 6;
  pinMode(led, OUTPUT);
  pinMode(reed_schalter, INPUT_PULLUP);
  pinMode(relais, OUTPUT);
}

void loop() {
  if (digitalRead(reed_schalter) == LOW) {  // Wenn Reed Schalter geschlossen ist
    digitalWrite(led, LOW);                  // LED aus
    my_stepper.step(50);                    // Stepper macht 50 Schritte vorwärts
    digitalWrite(relais, HIGH);            // Relais wird eingeschaltet
    delay(1000);                                   // Haltezeit des Relais
    digitalWrite(relais, LOW);             // Relais wird nach der Haltezeit (Delay) ausgeschaltet
    my_stepper.step(-50);                  // Stepper macht 50 Schritte rückwärts
    digitalWrite(led, HIGH);                // LED an
  } else {
    digitalWrite(led, HIGH);                // LED an
  }
}

Schau mal in die Beispiele der IDE. StateChangeDetection dürfte das sein, was Du suchst. Evtl. brauchst Du zusätzlich Debounce (Entprellen), denn Reedkontakte prellen ziemlich heftig.

Gruß Tommy

Hi Tommy,

Ich schaue mir das mal an. Vielleicht löst es mein Problem.

Könntest du mir das mit dem Debounce genauer erklären? Soweit funktioniert es für meine Bedürfnisse reibungslos.

Der Kontakt prellt mechanisch, so dass bei einer einmaligen Betätigung mehrere Impulse entstehen. Die Prellzeit ist meist <= 20 ms. Durch Dein delay liest Du erst später ein, so dass es nicht zu Auswirkungen kommt. Behalte es aber im Hinterkopf, denn von langen delay wirst Du Dich früher oder später verabschieden.

Gruß Tommy

#include <Stepper.h>

int reed_schalter;
int led;
int relais;
Stepper my_stepper = Stepper(200, 2, 3);

bool merker;
void setup()
{
  reed_schalter = 4;
  led = 5;
  relais = 6;
  pinMode(led, OUTPUT);
  pinMode(reed_schalter, INPUT_PULLUP);
  pinMode(relais, OUTPUT);
}

void loop()
{
  if (digitalRead(reed_schalter) == LOW)    // Wenn Reed Schalter geschlossen ist
  {
    if (merker == false)
    {
      merker = true;
      digitalWrite(led, LOW);                  // LED aus
      my_stepper.step(50);                    // Stepper macht 50 Schritte vorwärts
      digitalWrite(relais, HIGH);            // Relais wird eingeschaltet
      delay(1000);                                   // Haltezeit des Relais
      digitalWrite(relais, LOW);             // Relais wird nach der Haltezeit (Delay) ausgeschaltet
      my_stepper.step(-50);                  // Stepper macht 50 Schritte rückwärts
      digitalWrite(led, HIGH);                // LED an
    }
  }
  else
  {
    digitalWrite(led, HIGH);                // LED an
    merker = false;
  }
}

Die Pins hätte man aber auch gleich als Initialisierung setzen können und nicht durch Zuweisung im setup. :wink:

Gruß Tommy

Das war nicht die Aufgabe :wink:

Das würde zumindest ein paar Zeilen sparen. Habe da mittlerweile so viele verschiedene Konstellationen gesehen. Hab mich zu Beginn für diese Variante entschieden, weil es für mich noch "einfacher" ist alles zu trennen und zu verstehen.

Dennoch ein guter Tipp am Rande nebenbei. :wink: :smile:

Dann sei mir die Bemerkung erlaubt, dass Dein delay(1000) da ganz schnell rausgehört und der Code nonblocking umzustellen ist.

Deine Aussage war, das Du das blos hingekliert hast, um Dein Problem zu zeigen.
Darum habe ich auch nur Dein Problem gelöst.
Kein debounce, kein const für die Pins, kein delay() aufgelöst.

Ich bin bei jeglicher Art von Bemerkungen dabei. Aber verstehe was du meinst. Hat mit meinem eigentlichen Problem nichts zu tun. Der Delay war meine Lösung um das Relais für den Zeitraum X einzuschalten und dann auszuschalten.

Wie wäre denn hier eine klügere Lösung. Auch gern mit deinen anderen Anmerkungen.

Las mir nen Moment - ich sitz im Zug und schreib Dir das um.
Häng es dann hier dran. - ich mach keinen neuen Post auf!

#include <Stepper.h>

constexpr byte reed_schalter {4};
constexpr byte led {5};
constexpr byte relais {6};

Stepper my_stepper = Stepper(200, 2, 3);

enum class STATUS {warten, stepOne, stepTwo};

STATUS status = STATUS::warten;

uint32_t lastSwitchTime;

constexpr bool relaisEin {LOW};
constexpr bool relaisAus {!relaisEin};

void setup()
{
  pinMode(led, OUTPUT);
  pinMode(reed_schalter, INPUT_PULLUP);
  pinMode(relais, OUTPUT);
  digitalWrite(led, HIGH);                // LED an
  digitalWrite(relais, relaisAus);              // Relais wird nach der Haltezeit (Delay) ausgeschaltet
}

void loop()
{
  checkStepper();
}

void checkStepper()
{
  switch (status)
  {
    case STATUS::warten:
      if (digitalRead(reed_schalter) == LOW)    // Wenn Reed Schalter geschlossen ist
      {
        status = STATUS::stepOne;
      }
      break;
    case STATUS::stepOne:
      digitalWrite(led, LOW);                  // LED aus
      my_stepper.step(50);                    // Stepper macht 50 Schritte vorwärts
      digitalWrite(relais, relaisEin);            // Relais wird eingeschaltet
      lastSwitchTime=millis();
      status = STATUS::stepTwo;
      break;
    case STATUS::stepTwo:
      if (millis() - lastSwitchTime > 1000)
      {
        digitalWrite(relais, relaisAus);              // Relais wird nach der Haltezeit (Delay) ausgeschaltet
        my_stepper.step(-50);                  // Stepper macht 50 Schritte rückwärts
        digitalWrite(led, HIGH);                // LED an
        status = STATUS::warten;
      }
      break;
  }
}

Der Sketch verzichtet auf das debounce der Taste.
Grund: Innerhalb der Schrittkette vergeht mindestens 1000 ms - damit ist eine dazugefügte Überprüfung unnütz.

Der Code compiliert fehler- und warnungsfrei.
Wenn Fargen sind, frag.
Ist aber IMHO selbsterklärend.

EDIT: Noch eine Anmerkung.
Du kannst mit dem letzten State case STATUS::stepTwo: darauf prüfen, ob der reed wieder HIGH ist und davon den Übergang zum warten-State abhängig machen.

Super, vielen Dank. Ich wusste warum ich hier im Forum an der richtigen Stelle bei euch bin.

Ich bin praktisch bei Null angefangen und versuche gern so lange zu probieren bis es klappt, aber manches ist sicher logisch, aber schwierig zu verstehen. Mit den ganzen Variablen, Funktionen, und, und, und :face_with_spiral_eyes: :smile:

Ich bin fasziniert. Innerhalb von Minuten hingezaubert. Und ich...kann nur meinen Hut ziehen. Vielen Dank.

Im Ganzen kann ich deinen Code mit meinem jetzt gefühlt noch laienhafteren Wissen nachvollziehen. Werde mir das jetzt Stück für Stück vornehmen, damit ich auch alles verstehe und nicht nur "abschreibe". Hilft mir zum lernen sonst nicht weiter.
Viele neue Begriffe, welche ich mal irgendwo gelesen habe, aber nicht nutzen musste oder konnte. Es macht es mir durch deine Lösung einfacher alles umzusetzen.

Ich hatte noch eine Zeile vergessen für den zeitlichen Merker.
Hab ich ergänzt. :wink:

Ich sage nochmals lieben Dank. Mache mich jetzt an´s Werk und versuche das für mich so einzubauen. Gebe dann eine Rückmeldung.

1 Like

Hi, endlich bin ich dazu gekommen deinen Code ausgiebig zu nutzen und den Versuch gestartet, es auf mein Vorhaben umzulegen. Doch so ganz will es noch nicht klappen. Der "Haarknoten" hängt wohl noch irgendwo fest. :smile:

Ich habe mal einfach meinen gesamten Sketch eingesetzt, damit du meinen Stand sehen kannst. Ja, es ist noch viel Luft zum kürzen und zu vereinfachen, aber für mich ist es noch übersichtlicher. Wenn alles so läuft, wie ich es mir vorstelle, dann wird optimiert. Daher geh nicht so hart mit mir ins Gericht. :grimacing: :wink:

Nun erstmal zu meinen Problempunkten. Insgesamt gibt es 5 Positionen, an der die "gleichen" Füll- und Prüfvorgänge ablaufen sollen. An den Positionen 1-4 sind noch meine ersten Grundgerüste zu sehen (welche so funktionieren, aber ohne die Abfrage, ob der Reed-Schalter nach dem Ablauf erst wieder geöffnet wurde, um erst danach wieder von vorn zu beginnen und mit Delay als meine Laien-"Notlösung".).

An Position 5 habe ich versucht deinen Lösungsvorschlag umzusetzen. Sobald ich den Kontakt schließe beginnt der switchcase zu starten. Soweit schonmal gut.

Der erste Case greift und der Stepper fährt an die Position 5 des zweiten Case, aber schaltet hier nicht das Relais ein. Springt in den dritten Case und fährt nach den millis den Stepper zurück und die LED schaltet, wie erwartet wieder ein. Also das Relais wird völlig ignoriert und hab null Ideen, warum es ignoriert wird.

Die letzte Prüfung, ob der Reed nach dem durchlaufen erst wieder geöffnet wurde, um dann erst erneut mit dem ganzen Ablauf zu starten fehlt noch. Oder ich hab dich dort missverstanden, oder du mich.

Vielleicht hast du Gelegenheit und schaust mal drüber.

/*
Stepper filling station by m0rph3xx https://forum.arduino.cc/u/morphexx/summary
Driver DRV8825 from AZ
*/

//----------------------------------------------------------------------------------------------------------------------

//STEPPER AND home_switch (MICROSWITCH)
#include <AccelStepper.h>  // Library created by Mike McCauley at http://www.airspayce.com/mikem/arduino/AccelStepper/

// Define a stepper and the pins it will use
#define dir_pin 2   // Pin 2 connected to DIR pin
#define step_pin 3  // Pin 3 connected to STP pin
// #define MS0 x        // Pin x connected to MS1 pin
// #define MS1 x        // Pin x connected to MS1 pin
// #define MS2 x        // Pin x connected to MS2 pin
// #define SLEEP_PIN x  // Pin x connected to SLEEP pin

AccelStepper stepper(AccelStepper::DRIVER, step_pin, dir_pin);  // Pin 2 connected to STP pin and Pin 3 connected to DIR pin of AZ DRV8825

int position[5] = { 90, 165, 240, 315, 395 };  // Number of steps for positions 1-5 of the shot glasses

int home_switch = 10;  //PIN home switch (MICROSWITCH) - Pin to set home/zero for stepper after startup/reset

//----------------------------------------------------------------------------------------------------------------------

// REED SWITCH AND LED
int switch_pin_01 = 4;  //PIN Reed switch 1
int led_pin_01 = A1;    //PIN LED 3mm green 1
int switch_pin_02 = 5;  //PIN Reed switch 2
int led_pin_02 = A2;    //PIN LED 3mm green 2
int switch_pin_03 = 6;  //PIN Reed switch 3
int led_pin_03 = A3;    //PIN LED 3mm green 3
int switch_pin_04 = 7;  //PIN Reed switch 4
int led_pin_04 = A4;    //PIN LED 3mm green 4
int switch_pin_05 = 8;  //PIN Reed switch 5
int led_pin_05 = A5;    //PIN LED 3mm green 5

//----------------------------------------------------------------------------------------------------------------------

//RELAY AND BUTTON
int relay_pin = 9;         //PIN RELAY - Relay requires 5V
int button_grey_pin = 11;  //PIN BUTTON GREY - Pin to activate the relay (pump) manually via grey foil button

constexpr bool relayOn{ HIGH };       // Turn relay on
constexpr bool relayOff{ !relayOn };  // Turn relay off

//----------------------------------------------------------------------------------------------------------------------

enum class STATUS_05 { checkSwitch_05,
                       stepONE_05,
                       stepTWO_05 };  // Switch case for switch 5 of 5 in total

STATUS_05 status_05 = STATUS_05::checkSwitch_05;  // Status (switch case) for switch 5 of 5 in total

uint32_t lastSwitchTime;

//----------------------------------------------------------------------------------------------------------------------

void setup() {
  //STEPPER HOMING WITH home_switch - Enable internal pull-up for the switch

  pinMode(home_switch, INPUT_PULLUP);

  pinMode(dir_pin, OUTPUT);
  pinMode(step_pin, OUTPUT);
  //  pinMode(MS0, OUTPUT);
  //  pinMode(MS1, OUTPUT);
  //  pinMode(MS2, OUTPUT);
  //  pinMode(SLEEP_PIN, OUTPUT);

  //  digitalWrite(SLEEP_PIN, HIGH);  // Wake up AZ DRV8825
  //  delay(5);  // Wait for stepper driver wake up

  /* Configure type of Steps on AZ DRV8825:

  The DRV8825 driver has three input pins for microstep resolutions:
  " MS0
  " MS1
  " MS2

  By setting appropriate logic levels on these pins, we can set the drive mode of the motor to
  drive mode of the motor to one of these six modes:

  M0    M1    M2    Microstep resolution
  LOW   LOW   LOW   Full step
  HIGH  LOW   LOW   Half step
  LOW   HIGH  LOW   Quarter step
  HIGH  HIGH  LOW   Eighth step
  LOW   LOW   HIGH  Sixteenth step
  HIGH  LOW   HIGH  1/32 step
  LOW   HIGH  HIGH  1/32 step
  HIGH  HIGH  HIGH  1/32 step

  Remember that you don’t need to manually set the pins
  The DRV8825 handles this configuration for you based on the desired mode.
  
  Alternatively, to save pins on the microcontroller, the modes can be permanently connected
  via the 5V pin of the controller (5V=HIGH, disconnected=LOW).
  */

  //  digitalWrite(MS0, LOW);  // Configures to Full Steps
  //  digitalWrite(MS1, LOW);  // Configures to Full Steps
  //  digitalWrite(MS2, LOW);  // Configures to Full Steps

  //----------------------------------------------------------------------------------------------------------------------

  // Start homing of stepper motor at startup

  while (digitalRead(home_switch)) {  // Do this until the switch is activated
    digitalWrite(dir_pin, LOW);       // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(step_pin, HIGH);
    delay(5);  // Delay to slow down speed of Stepper
    digitalWrite(step_pin, LOW);
    delay(5);
  }

  while (!digitalRead(home_switch)) {  // Do this until the switch is not activated
    digitalWrite(dir_pin, HIGH);
    digitalWrite(step_pin, HIGH);
    delay(10);  // More delay to slow even more while moving away from switch
    digitalWrite(step_pin, LOW);
    delay(10);
  }

  stepper.setMaxSpeed(1000);      // Set Maximum Speed of stepper (Slower to get better accuracy)
  stepper.setAcceleration(400);   // Set acceleration of stepper
  stepper.setCurrentPosition(0);  // Set the current position to 0 steps

  //----------------------------------------------------------------------------------------------------------------------

  // REED SWITCH AND LED - Enable internal pull-up for the reed switch - LED on
  pinMode(switch_pin_01, INPUT_PULLUP);
  pinMode(led_pin_01, OUTPUT);
  digitalWrite(led_pin_01, HIGH);  // Turn LED 1 on
  pinMode(switch_pin_02, INPUT_PULLUP);
  pinMode(led_pin_02, OUTPUT);
  digitalWrite(led_pin_02, HIGH);  // Turn LED 2 on
  pinMode(switch_pin_03, INPUT_PULLUP);
  pinMode(led_pin_03, OUTPUT);
  digitalWrite(led_pin_03, HIGH);  // Turn LED 3 on
  pinMode(switch_pin_04, INPUT_PULLUP);
  pinMode(led_pin_04, OUTPUT);
  digitalWrite(led_pin_04, HIGH);  // Turn LED 4 on
  pinMode(switch_pin_05, INPUT_PULLUP);
  pinMode(led_pin_05, OUTPUT);
  digitalWrite(led_pin_05, HIGH);  // Turn LED 5 on

  //----------------------------------------------------------------------------------------------------------------------

  // RELAY AND BUTTON - Enable internal pull-up for the button
  pinMode(relay_pin, OUTPUT);
  pinMode(button_grey_pin, INPUT_PULLUP);
  digitalWrite(relay_pin, LOW);  // Turn the RELAY off
}

//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------

void loop() {

  prefilling();  // Pre-fill the hose with function prefilling

  //----------------------------------------------------------------------------------------------------------------------

  // FILLING SHOT GLASSES - Stepper moves to 1 of the 5 positions of the shot glasses
  if (digitalRead(switch_pin_01) == LOW) {
    delay(100);
    digitalWrite(led_pin_01, LOW);   // Turn the LED off
    stepper.moveTo(position[0]);     // Set desired move / Position defined by variable
    stepper.runToPosition();         // Moves the motor to target position w/ acceleration/ deceleration and it blocks until is in position
    filling();                       // Filling the shot glass with function filling
    backtohome();                    // Move back to position 0 with funtion backtohome
    digitalWrite(led_pin_01, HIGH);  // Turn the LED on
  }

  //------------------

  if (digitalRead(switch_pin_02) == LOW) {
    delay(100);
    digitalWrite(led_pin_02, LOW);   // Turn the LED off
    stepper.moveTo(position[1]);     // Set desired move / Position defined by variable
    stepper.runToPosition();         // Moves the motor to target position w/ acceleration/ deceleration and it blocks until is in position
    filling();                       // Filling the shot glass with function filling
    backtohome();                    // Move back to position 0 with funtion backtohome
    digitalWrite(led_pin_02, HIGH);  // Turn the LED off
  }

  //------------------

  if (digitalRead(switch_pin_03) == LOW) {
    delay(100);
    digitalWrite(led_pin_03, LOW);   // Turn the LED off
    stepper.moveTo(position[2]);     // Set desired move / Position defined by variable
    stepper.runToPosition();         // Moves the motor to target position w/ acceleration/ deceleration and it blocks until is in position
    filling();                       // Filling the shot glass with function filling
    backtohome();                    // Move back to position 0 with funtion backtohome
    digitalWrite(led_pin_03, HIGH);  // Turn the LED on
  }

  //------------------

  if (digitalRead(switch_pin_04) == LOW) {
    delay(100);
    digitalWrite(led_pin_04, LOW);   // Turn the LED off
    stepper.moveTo(position[3]);     // Set desired move / Position defined by variable
    stepper.runToPosition();         // Moves the motor to target position w/ acceleration/ deceleration and it blocks until is in position
    filling();                       // Filling the shot glass with function filling
    backtohome();                    // Move back to position 0 with funtion backtohome
    digitalWrite(led_pin_04, HIGH);  // Turn the LED on
  }

  //------------------

  fillingGlassPos05();  // Test of the Position 5 for implementation with switch case as function
  /*
  if (digitalRead(switch_pin_05) == LOW) {
    delay(100);
    digitalWrite(led_pin_05, LOW);   // Turn the LED off
    stepper.moveTo(position[4]);     // Set desired move / Position defined by variable
    stepper.runToPosition();         // Moves the motor to target position w/ acceleration/ deceleration and it blocks until is in position
    filling();                       // Filling the shot glass with function filling
    backtohome();                    // Move back to position 0 with funtion backtohome
    digitalWrite(led_pin_05, HIGH);  // Turn the LED on
  }
  */
  //------------------
}

// ----------------------------------------------------------------------------------------------------------------------

void fillingGlassPos05() {
  // Function: Filling shot glass on Position 5 out of 5 in total
  switch (status_05) {
    case STATUS_05::checkSwitch_05:
      if (digitalRead(switch_pin_05) == LOW) {
        delay(100);
        status_05 = STATUS_05::stepONE_05;
      }
      break;
    case STATUS_05::stepONE_05:
      digitalWrite(led_pin_05, LOW);     // Turn the LED off
      stepper.moveTo(position[4]);       // Set desired move / Position defined by variable
      stepper.runToPosition();           // Moves the motor to target position w/ acceleration/ deceleration and it blocks until is in position
      digitalWrite(relay_pin, relayOn);  // Start filling the shot glass
      lastSwitchTime = millis();
      status_05 = STATUS_05::stepTWO_05;
      break;
    case STATUS_05::stepTWO_05:
      if (millis() - lastSwitchTime > 2000) {
        digitalWrite(relay_pin, relayOff);  // Turn off relay (pump)
        backtohome();                       // Move back to position 0 with funtion backtohome
        digitalWrite(led_pin_05, HIGH);     // Turn the LED on
        status_05 = STATUS_05::checkSwitch_05;
      }
      break;
  }
}

void prefilling() {
  // Function: RELAY AND BUTTON - If the button_grey_pin reads low, the button is pressed. To pre-fill the hose.
  if (digitalRead(button_grey_pin) == LOW) {
    delay(100);
    digitalWrite(relay_pin, HIGH);  // Turn the RELAY on for as long as the button is pressed
  } else {
    digitalWrite(relay_pin, LOW);
  }
}

void filling() {
  // Function: Filling shot glasses
  digitalWrite(relay_pin, HIGH);  // Turn on relay (pump)
  delay(1000);                    // Filling time of the shot glass
  digitalWrite(relay_pin, LOW);   // Turn off relay (pump)
  delay(1000);                    // Drip-off time of the filling hose
}

void backtohome() {
  // Function: Returning the stepper to the zero point - Identical to homing routine in setup loop
  while (digitalRead(home_switch)) {  // Do this until the switch IS activated
    digitalWrite(dir_pin, LOW);       // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(step_pin, HIGH);
    delay(5);  // Delay to slow down speed of Stepper
    digitalWrite(step_pin, LOW);
    delay(5);
  }

  while (!digitalRead(home_switch)) {  // Do this until the switch IS NOT activated
    digitalWrite(dir_pin, HIGH);
    digitalWrite(step_pin, HIGH);
    delay(10);  // More delay to slow even more while moving away from switch
    digitalWrite(step_pin, LOW);
    delay(10);
  }
  stepper.setMaxSpeed(1000);      // Set Maximum Speed of stepper (Slower to get better accuracy)
  stepper.setAcceleration(400);   // Set acceleration of stepper
  stepper.setCurrentPosition(0);  // Set the current position to 0 steps
}

Hey ihr Beiden,
@my_xy_projekt
@Tommy56

Ich habe mal ein Diagramm erstellt. Vielleicht ist es für euch leichter zu verstehen, was ich eigentlich versuche. Falls ihr noch Lust und Zeit habt mich zu unterstützen.

Ich habe mittlerweile alles mögliche von euch probiert, aber noch nicht mit dem gewünschten Erfolg. Nach vielem Lesen und überlegen, denke ich das ich irgendwie den Status des Reed-Schalters erfassen und auswerten sollte. Ich habe die Libary Bounce2 gefunden. Lässt mich evtl. ein wenig Gehirnschmalz sparen. :face_with_spiral_eyes: :smile:

Wäre ich mit dieser Richtung auf dem Holzweg? @Tommy56 hat die StateDetection schonmal ins Spiel gebracht. Scheine ich nicht völlig auf dem Irrpfad zu sein.

Also, wenn ihr Zeit habt, dann gebt mir gern ein paar Tipps.

Danke euch und evtl. allen anderen auch.

Huch - irgendwie ist der Code da oben an mir vorbei gegangen.
Schau ich drauf.

1 Like

kommentiert, ungetestet.

/*
  Stepper filling station by m0rph3xx https://forum.arduino.cc/u/morphexx/summary
  Driver DRV8825 from AZ
*/

//----------------------------------------------------------------------------------------------------------------------

//STEPPER AND home_switch (MICROSWITCH)
#include <AccelStepper.h>  // Library created by Mike McCauley at http://www.airspayce.com/mikem/arduino/AccelStepper/

// Define a stepper and the pins it will use
#define dir_pin 2   // Pin 2 connected to DIR pin
#define step_pin 3  // Pin 3 connected to STP pin
// #define MS0 x        // Pin x connected to MS1 pin
// #define MS1 x        // Pin x connected to MS1 pin
// #define MS2 x        // Pin x connected to MS2 pin
// #define SLEEP_PIN x  // Pin x connected to SLEEP pin

AccelStepper stepper(AccelStepper::DRIVER, step_pin, dir_pin);  // Pin 2 connected to STP pin and Pin 3 connected to DIR pin of AZ DRV8825

//  pinMode(MS0, OUTPUT);
//  pinMode(MS1, OUTPUT);
//  pinMode(MS2, OUTPUT);
//  pinMode(SLEEP_PIN, OUTPUT);
//  digitalWrite(SLEEP_PIN, HIGH);  // Wake up AZ DRV8825
//  delay(5);  // Wait for stepper driver wake up
/* Configure type of Steps on AZ DRV8825:

  The DRV8825 driver has three input pins for microstep resolutions:
  " MS0
  " MS1
  " MS2

  By setting appropriate logic levels on these pins, we can set the drive mode of the motor to
  drive mode of the motor to one of these six modes:

  M0    M1    M2    Microstep resolution
  LOW   LOW   LOW   Full step
  HIGH  LOW   LOW   Half step
  LOW   HIGH  LOW   Quarter step
  HIGH  HIGH  LOW   Eighth step
  LOW   LOW   HIGH  Sixteenth step
  HIGH  LOW   HIGH  1/32 step
  LOW   HIGH  HIGH  1/32 step
  HIGH  HIGH  HIGH  1/32 step

  Remember that you don’t need to manually set the pins
  The DRV8825 handles this configuration for you based on the desired mode.

  Alternatively, to save pins on the microcontroller, the modes can be permanently connected
  via the 5V pin of the controller (5V=HIGH, disconnected=LOW).
*/
//  digitalWrite(MS0, LOW);  // Configures to Full Steps
//  digitalWrite(MS1, LOW);  // Configures to Full Steps
//  digitalWrite(MS2, LOW);  // Configures to Full Steps
//----------------------------------------------------------------------------------------------------------------------
// Start homing of stepper motor at startup



// REED SWITCH AND LED and Number of steps for positions 1-5 of the shot glasses
constexpr byte shotNums {5};
struct SHOT
{
  const byte switchPin;
  const byte ledPin;
  const uint16_t position;
} shot[shotNums] =
{
  {4, A1, 90,},
  {5, A2, 165,},
  {6, A3, 240,},
  {7, A4, 315,},
  {8, A5, 395,},
};

//RELAY AND BUTTON

constexpr byte relayPin {9};         //PIN RELAY - Relay requires 5V
constexpr byte homePin {10};  //PIN home switch (MICROSWITCH) - Pin to set home/zero for stepper after startup/reset
constexpr byte prefillPin {11};  //PIN BUTTON GREY - Pin to activate the relay (pump) manually via grey foil button

constexpr bool relayOn{ HIGH };       // Turn relay on
constexpr bool relayOff{ !relayOn };  // Turn relay off

constexpr bool ledOn{ LOW };
constexpr bool ledOff{ !ledOn };

enum class STATUS   // was es alles so gibt
{
  checkSwitch,      // Tastenabfrage für Start
  prefill,          //
  fillpos,
  filling,
  fillend,
  homepos,
  backtohome,
};

STATUS status = STATUS::checkSwitch;
byte activeShot;
uint32_t switchTime;

constexpr uint32_t fillTime {2000};
constexpr uint32_t pauseTime {800};
//----------------------------------------------------------------------------------------------------------------------
void setup()
{
  //STEPPER HOMING WITH home_switch - Enable internal pull-up for the switch
  pinMode(homePin, INPUT_PULLUP);
  pinMode(dir_pin, OUTPUT);
  pinMode(step_pin, OUTPUT);
  stepper.setMaxSpeed(1000);      // Set Maximum Speed of stepper (Slower to get better accuracy)
  stepper.setAcceleration(400);   // Set acceleration of stepper
  stepper.setCurrentPosition(0);  // Set the current position to 0 steps
  //----------------------------------------------------------------------------------------------------------------------
  // REED SWITCH AND LED - Enable internal pull-up for the reed switch - LED on
  for (byte b = 0; b < shotNums; b++)
  {
    pinMode(shot[b].switchPin, INPUT_PULLUP);
    pinMode(shot[b].ledPin, OUTPUT);
    digitalWrite(shot[b].ledPin, ledOn);
  }
  //----------------------------------------------------------------------------------------------------------------------
  // RELAY AND BUTTON - Enable internal pull-up for the button
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, relayOff);  // Turn the RELAY off
  pinMode(prefillPin, INPUT_PULLUP);
}

void loop()
{
  fillingGlass();
}

void fillingGlass()
{
  if (!digitalRead(homePin))                                  // Taste ausgelöst
  {
    if (STATUS::checkSwitch == status)                        // Im Ruhezustand:
    { status = STATUS::backtohome; }                          // Ausgangsposition (mit Editierfunktion)
    else                                                      // Im Füllmodus:
    { status = STATUS::fillend; }                             // Abbruch!
  }
  switch (status)
  {
    case STATUS::checkSwitch:
      if (!digitalRead(prefillPin))                           //
      { status = STATUS::prefill;}
      else                                                    // Nur wenn nicht Vorfillen ausgelöst
      {
        for (byte b = 0; b < shotNums; b++)                   // Nacheinander Abfrage aller Tasten
        {
          if (!digitalRead(shot[b].switchPin))                // Taste ausgelöst?
          {
            activeShot = b;                                   // Auswahl übernehmen
            stepper.moveTo(shot[activeShot].position);        // Auslaufposition setzen
            switchTime = millis();                            // Startzeit merken
            status = STATUS::fillpos;                         // Nächsten Step setzen
          }
        }
      }
      break;
    case STATUS::backtohome:
      back2Home();                                            // EditierFunktion aufrufen
      status = STATUS::checkSwitch;                           // Zwangsweise in den Wartemodus
      break;
    case STATUS::prefill:                                     // wenn ausgelöst
      digitalWrite(relayPin, relayOn);                        //
      if (digitalRead(prefillPin))                            // Wenn Taste losgelassen
      {
        digitalWrite(relayPin, relayOff);
        status = STATUS::checkSwitch;                         // Zurück auf Anfang
      }
      break;
    case STATUS::fillpos:
      ledBlink(shot[activeShot].ledPin, 70);                  // Kleines blinkblink AuslaufLED
      if (millis() - switchTime > pauseTime)                  // Zwangspause abgelaufen
      {
        digitalWrite(relayPin, relayOn);                      // Füllen starten
        switchTime = millis();                                // Startzeit merken
        status = STATUS::filling;                             // Nächster Schritt
      }
      break;
    case STATUS::filling:
      ledBlink(shot[activeShot].ledPin, 200);                 // blinkblink
      if (millis() - switchTime > fillTime)                   // Füllzeit abgelaufen
      { status = STATUS::fillend; }                           // Nächster Schritt
      break;
    case STATUS::fillend:
      digitalWrite(shot[activeShot].ledPin, ledOff);          // gesichert AUS machen
      digitalWrite(relayPin, relayOff);                       // Füllen beenden
      switchTime = millis();                                  // merken
      status = STATUS::homepos;                               // nächster Schritt
      break;
    case STATUS::homepos:
      if (millis() - switchTime > pauseTime)                  // Zwangspause -> es tropft nach!
      {
        stepper.moveTo(0);                                    //
        if (checkBtnFree())                                   // Funktionsaufruf
        {
          digitalWrite(shot[activeShot].ledPin, ledOn);       // LED wieder an
          status = STATUS::checkSwitch;                       // fange an von Vorn
        }
      }
      break;
  }
  stepper.runToPosition();
}
//
bool checkBtnFree()                                           // gibt true zurück, wenn kein Btn ausgelöst
{
  bool isFree = true;                                         // Vorbelegung
  for (byte b = 0; b < shotNums; b++)
  {
    if (!digitalRead(shot[b].switchPin))                      // Eine Taste gedrückt?
    { isFree = false; }
  }
  if (!digitalRead(homePin) ||                                // Hier eine Taste gedrückt?
      !digitalRead(prefillPin))
  { isFree = false; }
  return isFree;
}
//
void back2Home()                                              //
{
  if (!digitalRead(shot[0].switchPin))                        // erste shot-Taste
  {
    digitalWrite(dir_pin, LOW);                               // verschiebt in Richtung A
    oneStep();
    stepper.setCurrentPosition(0);                            // Null- / Startpunkt
  }
  else if (!digitalRead(shot[shotNums - 1].switchPin))        // letzte shot-Taste
  {
    digitalWrite(dir_pin, HIGH);                              // verschiebt in Richtung B
    oneStep();
    stepper.setCurrentPosition(0);                            // ...
  }
  stepper.moveTo(0);
}
//
void oneStep()                                                // Macht wie es heisst
{
  digitalWrite(step_pin, HIGH);
  delay(5);
  digitalWrite(step_pin, LOW);
  delay(5);
}
//
void ledBlink(const byte led, const byte blinkTime)           //
{
  static uint32_t lastMillis = 0;
  if (millis() - lastMillis > blinkTime)
  {
    digitalWrite(led, !digitalRead(led));
    lastMillis = millis();
  }
}