Zweite IF-Abfrage kollidiert mit State Machine

Moin Jungs, ich schon wieder mit einem Problem.
Ich versuche in meiner Programmierung 4 Zustände zu messen un wenn diese in der richtigen reinfolge aktiviert werden soll eine LED angehen, das funktioniert grundsätzlich auch und ich habe es erfolgreich testen können.

Das Problem ist dann die IF Abfrage am Ende, schalte ich alle vier gemeseenen LEDs in der falschen Reihenfolge ab, geht natürlich oben genannte LED nicht an.. Also soll er einmal den Strom über powerctrl abschalten.
Füge ich die IF Abfrage aber an, schaltet er auch bei der richtigen Reihenfolge nicht die LED an.

ICh hoffe ich konnte das irgendwie verständlich machen.

const int buttonA = A0;
const int buttonB = A1;
const int buttonC = A2;
const int buttonD = A3;
const int ledPin = 7;
const int powerctrl = 8;

enum AutomatenZustand {START,WaitForA,WaitForB,WaitForC,WaitForD,ACTIVE};
AutomatenZustand zustand = START;

int ledState = LOW;
int aktiverZustand = 0;
int powerState = HIGH;
unsigned long previousMillis = 0;
const long interval = 2000;

void setup() {
pinMode(ledPin,OUTPUT);
pinMode(buttonA , INPUT);
pinMode(buttonB, INPUT);
pinMode(buttonC, INPUT);
pinMode(buttonD, INPUT);
pinMode(powerctrl, OUTPUT);

}

void loop() {
automat();
}

void automat() {
int buttonStateA = analogRead(buttonA);
int buttonStateB = analogRead(buttonB);
int buttonStateC = analogRead(buttonC);
int buttonStateD = analogRead(buttonD);

unsigned long currentMillis = millis();

switch(zustand){
case START:
ledState = LOW;
digitalWrite(ledPin,ledState);
powerState = HIGH;
digitalWrite(powerctrl,powerState);
delay(1000);
if(buttonStateA < 160 && buttonStateB < 160 && buttonStateC < 160 && buttonStateD < 160){
zustand = WaitForA;
}

break;
case WaitForA:
if(buttonStateA > 160 && buttonStateB < 160 && buttonStateC < 160 && buttonStateD < 160){
zustand = WaitForB;
}
break;

case WaitForB:
if(buttonStateA > 160 && buttonStateB > 200 && buttonStateC < 160 && buttonStateD < 160){
zustand = WaitForC;
}
break;

case WaitForC:
if(buttonStateA > 160 && buttonStateB > 200 && buttonStateC > 240 && buttonStateD < 250){
zustand = WaitForD;
}
break;

case WaitForD:
if(buttonStateA > 160 && buttonStateB > 200 && buttonStateC > 240 && buttonStateD > 260){
ledState = HIGH;
digitalWrite(ledPin,ledState);
zustand = ACTIVE;
}
break;

case ACTIVE:
delay(10000);
powerState = LOW;
digitalWrite(powerctrl,powerState);
{
if(currentMillis - previousMillis >= interval){
previousMillis = currentMillis;
zustand = START;
}
}
break;

}

if(buttonStateA > 350 && buttonStateB > 350 && buttonStateC > 350 && buttonStateD > 350 && ledState == LOW){
powerState = LOW;
digitalWrite(powerctrl,powerState);
delay(3000);
powerState = HIGH;
digitalWrite(powerctrl,powerState);
delay(3000);
} }

Nein, konntest du nicht!

Ich finde, die If Bedingungen zu komplex.
Es ist mir auch ein Rätsel, warum du Buttons analog ausliest.

Auch etwas mehr Sorgfalt, bei den Daten Typen, wäre angebracht.

Es sind keine Buttons die ich auslese, sondern leuchtende LED Kerzen. WEnn man diese in der richtigen Reihenfolge auspustet geht die LED an (später öffnet dann ein Schloss). Das ganze ist für ein Spiel.

Da die LEDs der kerzen nur kleine Spannungen führen lese ich diese Analog aus.

Die Beschreibung ist etwas dürftig, daher ist nicht klar, wann wie lange welcher Ausgang geschaltet werden soll. Kannst ja mal dies probieren und an Deine Wünsche anpassen:

const int buttonA = A0;
const int buttonB = A1;
const int buttonC = A2;
const int buttonD = A3;
const int ledPin = 7;
const int powerctrl = 8;

enum AutomatenZustand {START, WaitForA, WaitForB, WaitForC, WaitForD, ACTIVE, PWOFF};
AutomatenZustand zustand = START;

int ledState = LOW;
int aktiverZustand = 0;
int powerState = HIGH;
unsigned long previousMillis, intervall;

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode(ledPin, OUTPUT);
  pinMode(buttonA, INPUT);
  pinMode(buttonB, INPUT);
  pinMode(buttonC, INPUT);
  pinMode(buttonD, INPUT);
  pinMode(powerctrl, OUTPUT);
}

void loop() {
  automat();
}

void automat() {
  int buttonStateA = analogRead(buttonA);
  int buttonStateB = analogRead(buttonB);
  int buttonStateC = analogRead(buttonC);
  int buttonStateD = analogRead(buttonD);

  unsigned long currentMillis = millis();
  // nur zur Veranschaulichung
  if (currentMillis % 1000 == 0)
  {
    Serial.println(zustand);
    delay(1);
  }
  
  switch (zustand) {
    case START:
      ledState = LOW;
      digitalWrite(ledPin, ledState);
      powerState = HIGH;
      digitalWrite(powerctrl, powerState);
      if (buttonStateA < 160 && buttonStateB < 160 && buttonStateC < 160 && buttonStateD < 160) {
        zustand = WaitForA;
      }
      break;

    case WaitForA:
      if (buttonStateA > 160 && buttonStateB < 160 && buttonStateC < 160 && buttonStateD < 160) {
        zustand = WaitForB;
      }
      break;

    case WaitForB:
      if (buttonStateA > 160 && buttonStateB > 200 && buttonStateC < 160 && buttonStateD < 160) {
        zustand = WaitForC;
      }
      break;

    case WaitForC:
      if (buttonStateA > 160 && buttonStateB > 200 && buttonStateC > 240 && buttonStateD < 250) {
        zustand = WaitForD;
      }
      break;

    case WaitForD:
      if (buttonStateA > 160 && buttonStateB > 200 && buttonStateC > 240 && buttonStateD > 260) {
        ledState = HIGH;
        digitalWrite(ledPin, ledState);
        previousMillis = currentMillis;
        intervall = 10000;
        zustand = ACTIVE;
      }
      break;

    case ACTIVE:
      if (currentMillis - previousMillis >= intervall) {
        previousMillis = currentMillis;
        powerState = LOW;
        digitalWrite(powerctrl, powerState);
        intervall = 3000;
        zustand = PWOFF;
      }
      break;

    case PWOFF:
      if (currentMillis - previousMillis >= intervall) {
        zustand = START;
      }
      break;
  }
}

Die Ausgabe am seriellen Monitor kann ganz hilfreich sein.

Vielen dank schon mal.

Wie aktiviere ich den seriellen Ausgang? Reicht es einmal oben den Print Befehl gebe?

WhyNot2K:
Wie aktiviere ich den seriellen Ausgang?

Du kannst die Standardprogrammbibliothek Serial mittels Serial.begin(Übertragungsgeschwindigkeit) aktivieren. Den seriellen Monitor öffnest Du in der IDE unter Werkzeuge, was beim UNO zum Reset führt. Wird nur Datensalat angezeigt, mußt Du die Übertragungsgeschwindigkeit anpassen.

Obwohl ich Serial.begin drin habe zeigt mir der Monitor nix an-

Obwohl ich Serial.begin drin habe zeigt mir der Monitor nix an-

-->Code?
Passt die Übertragungsgeschwindigkeit mit der Eingestellten im seriellen Monitor überein?
Hast überhaupt Ausgaben eingefügt?

Und agmue hat dir das doch schon in Post #3 vorgeschrieben.
Einfach nur abtippen, Copy&Paste, geht doch, oder ?

Hallo,

unsigned long currentMillis = millis();
  // nur zur Veranschaulichung
  if (currentMillis % 1000 == 0)
  {
    Serial.println(zustand);
    delay(1);
  }

Eine Anmerkung zur Modulo Verwendung für zeitliche Wiederholungen. Das funktioniert nur in der Theorie. Die loop hat eine bestimmte Laufzeit die nicht konstant sein muss. Das bedeutet für diese Abfrage, es ist Zufall dass diese Bedingung gültig wird. Das Programm müßte genau zu dem Zeitpunkt bei der Abfrage vorbeikommen wenn millis ein Vielfaches von 1000 ist.

@Doc_Arduino: Ein beknacktes Stück Programm, leider war mir kein besserer Code eingefallen. Aber jurs hatte da mal was mit modulo in dieser Richtung gemacht, nur wahrscheinlich besser. Ach wenn ich mich doch erinnern könnte :-[

Sachdienliche Hinweise sind willkommen!

Hallo,

keine Sorge, manchmal entwickelt sich daraus etwas ... :wink:

Mit meinen Programmierkenntnissen kann ich mir aktuell schwer vorstellen das diese Art der zeitlichen Abfrage mit modulo überhaupt irgendwie funktioniert. Von jurs kenne ich nur noch diese Variante.

static unsigned long last_ms = 0;
const unsigned int interval = 1000;
		
if (millis() - last_ms < interval) return;
	
last_ms += interval;
...
...

Hi

Wenn die loop() >= 1000 Durchläufe die Sekunde macht, dürfte Das sogar teilweise öfter, als gewünscht passen.

Man muß ja nicht überall mit delay() um sich werfen, damit die loop auch schön lange braucht :wink:
(aber ok, wenn Mal etwas Mehr auf's Display getextet wird, der DS18B20 für die Messzeit die Kontrolle über den µC übernimmt oder sonst recht zeitintensive Tätigkeiten vorkommen, daß auch eine ms übersprungen werden wird - DANN ist man vll. mit Lotto besser dran).

Allerdings favorisiere ich ebenfalls die vom Doc gepostete Variante von Jurs, wo nach einem abgelaufenem Intervall die Abarbeitung gestartet wird und der Zeitpunkt des letzten Intervall um die Intervallzeit angehoben wird - so ergibt sich kein Verschleppen der Zeit.

MfG

Der DS18B20 kann auch im nichtblockierenden Modus betrieben werden. Da ist halt der Programmierer für die Einhaltung der Wartezeit verantwortlich. Das kann man prima mit millis() erschlagen.

Gruß Tommy

Wieso nicht einfach

If (buttonStateA >= 350){
a = millis();
}

If (buttonStateB >= 350){
b = millis();
}

If (buttonStateC >= 350){
c = millis();
}

if ((a >= b) && (b >= c))

wäre das für die abfrage nicht einfacher ? zusätzlich wenn die kerzen nach der falschen Reihenfolge wieder ausgehen sollen bzw an könnte man ja ne variable bei jeder if button mit hochzählen.

Und natürlich noch ne variable die kontrolliert ob die kerze schon aus ist damit die jewalige if button nicht innerhalb von ner halben Sekunde allein die Variable hochzählt.

Ansonnsten wäre noch mal ne genaue Beschreibung nicht schlecht.

Mfg Marcus