Millis() mit if Bedingung

Ich habe ein Problem mit den millis().
Wenn ich die Taste 0 auf meinem Keypad drücke, läuft das Programm ganz normal durch die if Bedingung.
Sobald er in die letzte Anweisung geht(also nach einander die Relais anschalten soll) geht nur das letzte Relais an, obwohl erst Relais 1, Relais2, und dann Relais4 angehen sollen.
Bei den anderen Tasten, wo vorher nichts passiert, funktioniert alles(Relais schalten so wie sie sollen).
Deshalb glaube ich, dass ich die currentMillis = millis() falsche setze.
Allerdings hab ich bisher noch keine Lösung gefunden. Vielleicht hat jemand ja eine Idee.

#include <Keypad.h>
#include <AccelStepper.h>
#include <PololuMaestro.h>

// Größe des Keypads definieren
const byte COLS = 4;  // 4 Spalten
const byte ROWS = 4;  // 4 Zeilen

// Die Ziffern und Zeichen des Keypads
char hexaKeys[ROWS][COLS] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};

byte colPins[COLS] = { 11, 12, 4, 5 };  // Pins für die 4 Spalten
byte rowPins[ROWS] = { 7, 6, 8, 9 };    // Pins für die 4 Zeilen

char Taste;  // Variable für die jeweils gedrückte Taste
Keypad Tastenfeld = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

const int relayPins[] = { A0, A1, A2, A3, A4, A5, A6 };
const int numRelays = sizeof(relayPins) / sizeof(relayPins[0]);

unsigned long previousMillis = 0;
int currentPatternIndex = 0;
bool patternActive = false;
int patternLength = 0;
const int *currentPattern = nullptr;
const unsigned long *relayIntervals = nullptr;

// Beispielmuster
const int pattern0[] = { 0, 1, 3 };
const unsigned long relayIntervals0[] = { 4000, 4000, 4000 };

const int pattern1[] = { 2, 3 };
const unsigned long relayIntervals1[] = { 2000, 3000 };

const int pattern2[] = { 0, 1, 3 };
const unsigned long relayIntervals2[] = { 4000, 4000, 4000 };

#ifdef SERIAL_PORT_HARDWARE_OPEN
#define maestroSerial SERIAL_PORT_HARDWARE_OPEN
#else
#include <SoftwareSerial.h>
SoftwareSerial maestroSerial(18, 19);
#endif

MicroMaestro maestro(maestroSerial);
const int open = 8000;
const int close = 6000;

AccelStepper stepper(1, 2, 3);


int endstop_1 = A14;
int endstop_2 = A15;

void setup() {
  Serial.begin(9600);
  maestroSerial.begin(9600);

  //Endstop
  pinMode(endstop_1, INPUT);
  pinMode(endstop_2, INPUT);

  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(1000);
  stepper.setSpeed(100);

  for (int i = 0; i < numRelays; i++) {
    pinMode(relayPins[i], OUTPUT);
    digitalWrite(relayPins[i], HIGH);  // Relais anfangs ausschalten (HIGH bedeutet ausgeschaltet für ein Relaismodul)
  }
}

void startPattern(const int pattern[], const unsigned long intervals[], int length) {
  currentPattern = pattern;
  relayIntervals = intervals;
  patternLength = length;
  currentPatternIndex = 0;
  patternActive = true;
  previousMillis = millis();
  digitalWrite(relayPins[currentPattern[currentPatternIndex]], LOW);
  Serial.print("Relais ");
  Serial.print(currentPattern[currentPatternIndex] + 1);
  Serial.println(" eingeschaltet");
}

void loop() {
  Taste = Tastenfeld.getKey();
  unsigned long currentMillis = millis();

  if (Taste) {  // Wenn eine Taste gedrückt wurde
    Serial.print("Die Taste ");
    Serial.print(Taste);
    Serial.println(" wurde gedrückt");

    if (Taste == '0' && digitalRead(endstop_1) == LOW) {
      maestro.setSpeed(50, 50);
      maestro.setAcceleration(10, 10);

      //StartSchrittMotor;
      stepper.setMaxSpeed(800);
      stepper.runToNewPosition(-3730);

      maestro.setTarget(0, open);
      delay(3000);
      maestro.setTarget(0, close);

      stepper.setMaxSpeed(400);
      stepper.runToNewPosition(-3250);

      maestro.setTarget(0, open);
      delay(3000);
      maestro.setTarget(0, close);


      stepper.setMaxSpeed(400);
      stepper.runToNewPosition(-2680);


      maestro.setTarget(0, open);
      delay(3000);
      maestro.setTarget(0, close);


      stepper.setMaxSpeed(400);
      stepper.runToNewPosition(-1800);
      


      //Mischgetränke
      //StoppSchrittMotor;
      
      //Für die Relais
      startPattern(pattern0, relayIntervals0, sizeof(pattern0) / sizeof(pattern0[0]));
    } else if (Taste == '1') {
      startPattern(pattern1, relayIntervals1, sizeof(pattern1) / sizeof(pattern1[0]));
    } else if (Taste == '2') {
      startPattern(pattern2, relayIntervals2, sizeof(pattern2) / sizeof(pattern2[0]));
    }
  }

  if (patternActive) {
    if (currentMillis - previousMillis >= relayIntervals[currentPatternIndex]) {
      digitalWrite(relayPins[currentPattern[currentPatternIndex]], HIGH);  // Aktuelles Relais ausschalten
      Serial.print("Relais ");
      Serial.print(currentPattern[currentPatternIndex] + 1);
      Serial.println(" ausgeschaltet");

      currentPatternIndex++;

      if (currentPatternIndex < patternLength) {
        digitalWrite(relayPins[currentPattern[currentPatternIndex]], LOW);  // Nächstes Relais einschalten
        Serial.print("Relais ");
        Serial.print(currentPattern[currentPatternIndex] + 1);
        Serial.println(" eingeschaltet");

        previousMillis = currentMillis;
      } else {
        patternActive = false;  // Muster ist beendet
        Serial.println("Muster abgeschlossen");
      }
    }
  }
}

wir wissen nicht was du dir überlegt hast

const int pattern0[] = { 0, 1, 3 };
const unsigned long relayIntervals0[] = { 4000, 4000, 4000 };

was willst du mit deinem Sketch erreichen?
Relay 0 HIGH nach 4000 ms LOW
dann Relay 1 HIGH nach 4000 ms LOW
dann Relay 3 HIGH nach 4000 ms LOW
?

Also wenn die Tast 0 gedrückt wurde, sollen die aufgezählten Relais nach einander für 4s eingeschaltet werden.( Die Relais sollen Pumpen einschalten)

Moin @sorenert,

Deine Vermutung trifft zu:

  • Am Anfang der loop() wird currentMillis gesetzt.
  • In startPattern() wird previousMillis gesetzt.
  • Beim Tastendruck "0" vergehen zwischen beiden Vorgängen aber mehr als 9 s. Damit ist previousMillis um diesen Betrag "jünger" als die ehemals "aktuelle" Zeit.

Verschiebe mal

unsigned long currentMillis = millis();

vor die Zeile "if (patternActive)":


  unsigned long currentMillis = millis();

  if (patternActive) {
    if (currentMillis - previousMillis >= relayIntervals[currentPatternIndex]) {

dann sollte es laufen.

ec2021

P.S.: Da Du "currentMillis" bisher nur an einer Stelle

 if (currentMillis - previousMillis >= relayIntervals[currentPatternIndex]) {

verwendest, spricht m.E. nichts dagegen, hier gleich

 if (millis()- previousMillis >= relayIntervals[currentPatternIndex]) {

zu schreiben , oder?

edit: Vergiss es -> #9

Wenn die Variable Taste den Inhalt '0' hat, bekommst Du für die Bedingungif (Taste) false.

Einspruch!
Das gilt für '\0'. Die ASCII-Null '0' führt zu True.

1 Like

Viele Wege führen nach Rom, so auch (oder gerade) beim Codieren ... :wink:

Ich habe mal eine Version erstellt, die (hoffentlich) auch weiterhin das tut, was Du erwartest, aber z.B.

  • die Möglichkeit nutzt, Relaisnummer und Schaltintervall in einer Struktur zusammenzufassen, so dass nur noch ein Array übergeben werden muss
  • wiederholte Codepassagen in Funktionen umsetzt und
  • statt der "if/else if/else if" eine switch/case Anweisung verwendet und
  • die Berechnung der Pattern-Anzahl mit einem Macro beinhaltet.

Läuft bei Wokwi:
https://wokwi.com/projects/405851025462290433

Gerne mal anschauen/ausprobieren, wenn Du möchtest. Sonst -> Ignorieren :wink:

/*
  Forum: https://forum.arduino.cc/t/millis-mit-if-bedingung/1290488/5
  Wokwi: https://wokwi.com/projects/405851025462290433

*/

#include <Keypad.h>
#include <AccelStepper.h>
#include <PololuMaestro.h>

// Größe des Keypads definieren
const byte COLS = 4;  // 4 Spalten
const byte ROWS = 4;  // 4 Zeilen

// Die Ziffern und Zeichen des Keypads
char hexaKeys[ROWS][COLS] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};

byte colPins[COLS] = { 11, 12, 4, 5 };  // Pins für die 4 Spalten
byte rowPins[ROWS] = { 7, 6, 8, 9 };    // Pins für die 4 Zeilen

char Taste;  // Variable für die jeweils gedrückte Taste
Keypad Tastenfeld = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

const int relayPins[] = { A0, A1, A2, A3, A4, A5, A6 };
const int numRelays = sizeof(relayPins) / sizeof(relayPins[0]);

unsigned long previousMillis = 0;
int currentPatternIndex = 0;
bool patternActive = false;
int patternLength = 0;

// Die folgende Struktur beinhaltet
// die Nummer des zu schaltenden Relais und
// die Dauer des Einschaltens (Schaltintervall) in [ms]
struct relayType {
  int relay;
  unsigned long interval;
};

relayType *currentPattern = nullptr;

// Beispielmuster
// linker Wert = Relaisnummer
// rechter Wert = Schaltintervall
const relayType pattern0[] =
{ {0, 4000},
  {1, 4000},
  {3, 4000}
};

const relayType pattern1[] =
{ {2, 2000},
  {3, 3000}
};

const relayType pattern2[] =
{
  {0, 4000},
  {1, 4000},
  {3, 4000}
};

// Das folgende Macro ergibt die Anzahl der Einträge in den Arrays vom Typ "relayType"
#define ANZAHL(x) sizeof(x)/sizeof(relayType)


#ifdef SERIAL_PORT_HARDWARE_OPEN
#define maestroSerial SERIAL_PORT_HARDWARE_OPEN
#else
#include <SoftwareSerial.h>
SoftwareSerial maestroSerial(18, 19);
#endif

MicroMaestro maestro(maestroSerial);
const int open = 8000;
const int close = 6000;

AccelStepper stepper(1, 2, 3);


int endstop_1 = A14;
int endstop_2 = A15;

void setup() {
  Serial.begin(9600);
  maestroSerial.begin(9600);

  //Endstop
  pinMode(endstop_1, INPUT);
  pinMode(endstop_2, INPUT);

  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(1000);
  stepper.setSpeed(100);

  for (int i = 0; i < numRelays; i++) {
    pinMode(relayPins[i], OUTPUT);
    digitalWrite(relayPins[i], HIGH);  // Relais anfangs ausschalten (HIGH bedeutet ausgeschaltet für ein Relaismodul)
  }
}

void loop() {
  Taste = Tastenfeld.getKey();

  if (Taste) {  // Wenn eine Taste gedrückt wurde
    Serial.print("Die Taste ");
    Serial.print(Taste);
    Serial.println(" wurde gedrückt");
    switch (Taste) {
      case '0': if (digitalRead(endstop_1) != LOW) break;  // Wenn endstop_1 ungleich LOW, geht's nicht weiter
                prepare(); // Hier wird alles abgerufen, was bei der Taste '0' vor dem Schalten der Relais  erfolgt
                startPattern(pattern0, ANZAHL(pattern0));
        break;
      case '1' : startPattern(pattern1, ANZAHL(pattern1));
         break;
      case  '2': startPattern(pattern2, ANZAHL(pattern2));
         break;
    }
  }

  if (patternActive) {
    if (millis() - previousMillis >= currentPattern[currentPatternIndex].interval) {
      switchRelay(HIGH);
      currentPatternIndex++;
      if (currentPatternIndex < patternLength) {
        switchRelay(LOW);
      } else {
        patternActive = false;  // Muster ist beendet
        Serial.println("Muster abgeschlossen");
      }
    }
  }
}

// Vorgeplänkel im Fall der Taste '0'
void prepare() {
  maestro.setSpeed(50, 50);
  maestro.setAcceleration(10, 10);
  setStepperAndMaestro(800, -3730, true);
  setStepperAndMaestro(400, -3250, true);
  setStepperAndMaestro(400, -2680, true);
  setStepperAndMaestro(400, -1800, false);
}


// Diese Funktion wird an mehreren Stellen aufgerufen, um Relais ein- und auszuschalten
void switchRelay (byte state) {
  previousMillis = millis();  // Hier wird die Schaltzeit für das Intervall gesetzt
  digitalWrite(relayPins[currentPattern[currentPatternIndex].relay], LOW);  // Nächstes Relais einschalten
  Serial.print("Relais ");
  Serial.print(currentPattern[currentPatternIndex].relay + 1);
  Serial.println((state == LOW) ? " eingeschaltet" : " ausgeschaltet");
}

void startPattern(const struct relayType pattern[], int length) {
  currentPattern = pattern;
  patternLength = length;
  currentPatternIndex = 0;
  patternActive = true;
  switchRelay(LOW);
}

// Wird bei prepare() mehrfach aufgerufen
void setStepperAndMaestro(int maxSpeed, int newPos, boolean setMaestro) {
  stepper.setMaxSpeed(maxSpeed);
  stepper.runToNewPosition(newPos);
  if (setMaestro) {
    maestro.setTarget(0, open);
    delay(3000);
    maestro.setTarget(0, close);
  }
}

Stimmt.
Ich bin noch nicht ganz da.
Möge es heute der einzige Abweg sein.

Probier ich morgen mal aus. Danke schon mal

Hat funktioniert. Jetzt läuft alles wie es soll. Besten dank

Dann gerne den Thread als gelöst kennzeichnen (bei dem Post, der geholfen hat, "Lösung' anklicken).

Gruß
ec2021