Go Down

Topic: Zweite IF-Abfrage kollidiert mit State Machine (Read 1 time) previous topic - next topic

WhyNot2K

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);
                        }  }

 

combie

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.
Alle sagen: Das geht nicht!
Einer wusste das nicht und probierte es aus.
Und: Es ging nicht.

WhyNot2K

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.

agmue

#3
Dec 16, 2017, 02:11 pm Last Edit: Dec 16, 2017, 02:12 pm by agmue
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:

Code: [Select]
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.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

WhyNot2K

Vielen dank schon mal.

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

agmue

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.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

WhyNot2K

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

DerLehmi

Quote
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?

HotSystems

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

I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

Doc_Arduino

Hallo,

Code: [Select]
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.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

agmue

#10
Dec 18, 2017, 06:27 pm Last Edit: Dec 18, 2017, 06:27 pm by agmue
@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!
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

Doc_Arduino

Hallo,

keine Sorge, manchmal entwickelt sich daraus etwas ...   ;)

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.
Code: [Select]
static unsigned long last_ms = 0;
const unsigned int interval = 1000;

if (millis() - last_ms < interval) return;

last_ms += interval;
...
...
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

postmaster-ino

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 ;)
(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
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

Tommy56

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
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Mars018

#14
Dec 19, 2017, 11:12 pm Last Edit: Dec 19, 2017, 11:20 pm by Mars018
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


Go Up