Anfänger!!! Schrittkette ohne ext. Input

Hallo,

ich experimentiere seit ein paar Tagen mit Arduino rum. Leider habe ich von Programmierung keine Ahnung und habe bisher Versucht mir bei Google Hilfe zu holen. Nun bin ich aber an einem Punkt angekommen, wo mir das dort erklärte zu kompliziert wird.

Meine Idee ist es, eine Schrittkette zu programmieren, ohne von außerhalb mit Taster oder anderen Eingabegeräten einzugreifen.
Ich habe bisher 5 LED´s in verschiedenen Frequenzen gleichzeitig zum blinken gebracht. Der Plan ist aber, diese LED´s nicht alle gleichzeitig Blinken zu lassen, sondern in verschiedenen Schritten. In etwa wie folgt:
Schritt 1: LEDGruen für 5s
Schritt 2: LEDGelb und LEDBlau für 3s
Schritt 3: LEDGruen und LEDGelb für 2s
Schritt 4: LEDRot für 2s
Schritt 5: LEDWeis und LEDGruen für 3s
Schritt 6: LEDBlau für 1s

Es sollen halt immer nur die LED´s blinken, die in dem jeweiligen Schritt angegeben sind und auch nur so lange, wie die jeweilige Zeit es vorgibt.

Hier meine bisherige Programmierung:

const int LEDGruen=4;
const int LEDGelb=5;
const int LEDRot=6;
const int LEDWeis=7;
const int LEDBlau=8;

int LEDStateGruen = LOW;
long myTimerGruen =1000;
long myTimeoutGruen =100;

int LEDStateGelb = LOW;
long myTimerGelb =500;
long myTimeoutGelb =200;

int LEDStateRot = LOW;
long myTimerRot =700;
long myTimeoutRot =150;

int LEDStateWeis = LOW;
long myTimerWeis =300;
long myTimeoutWeis =50;

int LEDStateBlau = LOW;
long myTimerBlau =150;
long myTimeoutBlau =80;

void setup() {
pinMode(LEDGruen, OUTPUT);
pinMode(LEDGelb, OUTPUT);
pinMode(LEDRot, OUTPUT);
pinMode(LEDWeis, OUTPUT);
pinMode(LEDBlau, OUTPUT);
}
void loop() {
if (millis() > myTimeoutGruen + myTimerGruen ) {
  myTimerGruen = millis();

  if (LEDStateGruen == LOW) LEDStateGruen = HIGH;
  else LEDStateGruen = LOW;

  digitalWrite(LEDGruen, LEDStateGruen);
}

if (millis() > myTimeoutGelb + myTimerGelb ) {
  myTimerGelb = millis();

  if (LEDStateGelb == LOW) LEDStateGelb = HIGH;
  else LEDStateGelb = LOW;

  digitalWrite(LEDGelb, LEDStateGelb);
}
if (millis() > myTimeoutRot + myTimerRot ) {
  myTimerRot = millis();

  if (LEDStateRot == LOW) LEDStateRot = HIGH;
  else LEDStateRot = LOW;

  digitalWrite(LEDRot, LEDStateRot);
}
if (millis() > myTimeoutWeis + myTimerWeis ) {
  myTimerWeis = millis();

  if (LEDStateWeis == LOW) LEDStateWeis = HIGH;
  else LEDStateWeis = LOW;

  digitalWrite(LEDWeis, LEDStateWeis);
}
if (millis() > myTimeoutBlau + myTimerBlau ) {
  myTimerBlau = millis();

  if (LEDStateBlau == LOW) LEDStateBlau = HIGH;
  else LEDStateBlau = LOW;

  digitalWrite(LEDBlau, LEDStateBlau);
}
}

Das ganze ist schon nett anzuschauen, aber wie gesagt, nicht der eigentliche Plan.

Bis jetzt befindet sich das ganze noch in der Probephase und soll später mit weiteren Ausgängen erweitert werden. Z.B. mit einem Servo, weitere LED´s und Relaiskarten.

Über recht einfach zu verstehende Antworten wäre ich dankbar.

Vielen Dank schonmal im vorraus.

Andre

Setze Deinen Code bitte in Codetags (</>-Button oben links im Forumseditor oder [code] davor und [/code] dahinter ohne *).
Dann ist er auch auf mobilen Geräten besser lesbar.
Das kannst Du auch noch nachträglich ändern.

Schau Dir mal das Beispiel BlinkWithoutDelay in der IDE an.

Gruß Tommy

Nun bin ich aber an einem Punkt angekommen, wo mir das dort erklärte zu kompliziert wird.

Nu, dann zurück einen Schritt und Grundlagen lernen.

Meine Idee ist es, eine Schrittkette zu programmieren, ohne von außerhalb mit Taster oder anderen Eingabegeräten einzugreifen.

Was ist eine "Schrittkette" ?

Hi

Schrittkette - State-Maschine - Endlicher Automat - Ablauf-Steuerung ... Alles das Gleiche

Bei einer Schritt-Kette muß die Bedingung, Die zum Weiterschalten führt, ja nicht Extern kommen - kann ja auch nur eine vergangene Zeit sein - und Die kann der Arduino noch alleine abhandeln.

MfG

Deine millis() Bedingungen sind falsch gewählt. So funktioniert die Zeit beim Overflow nicht richtig.
Richtig ist: if (currentMillis - previousMillis >= interval)

Der Sketch schaltet die LED gleichzeitig.
Du möchtest aber die Sachen nacheinander.

Du solltest aber die Pins und die Zeiten in Arrays speichern.
Da Du 2 LED gleichzeitig leuchten sollen brauchst Du 2 Arrays für die Pins.
Dann kannst Du eine Schrittkette machen

Grüße Uwe

kannst du näher erläutern, was dir Schwierigkeiten bereitet?

  • eine LED blinken lassen
  • mehrere LEDs unabhängig voneinander blinken lassen
  • eine State Machine mit switch case abbilden
  • von einem State in den anderen per Zeitablauf weiterschalten

Alles zusammen wäre dann wohl dein Sketch. Was fehlt dir?

Habe mir mal das Beispiel BlinkWithoutDelay näher angeschaut (@Tommy: danke) und das Blinken meiner Dioden danach programmiert. Zur Zeit zwar nur 2 aber das kommt noch.

unsigned long LEDGruen_timestore;
int LedGruenStatus = LOW;
int LedGruenPin = 4;

unsigned long LEDRot_timestore;
int LEDRotStatus = LOW;
int LEDRotPin = 6;


void setup() {
  pinMode(LedGruenPin, OUTPUT);  
  pinMode(LEDRotPin, OUTPUT);
}

void loop() {
  if (LedGruenStatus == LOW){
    if (millis() - LEDGruen_timestore> 100 ){
      digitalWrite(LedGruenPin, HIGH);
      LEDGruen_timestore = millis();
      LedGruenStatus = HIGH;
      
    }
  } else {
    if (millis() - LEDGruen_timestore> 10) {
      digitalWrite(LedGruenPin, LOW);
      LedGruenStatus = LOW;
    }
 if (LEDRotStatus == LOW){
  if (millis() - LEDRot_timestore> 200 )    {
      digitalWrite(LEDRotPin, HIGH);
      LEDRot_timestore = millis();
      LEDRotStatus = HIGH;
     }
  } else {
    if (millis() - LEDRot_timestore> 10) {
      digitalWrite(LEDRotPin, LOW);
      LEDRotStatus = LOW;
     }
    }
  }
  }

Das mit dem Blinken gefällt mir jetzt besser. Ich weiß aber immer noch nicht, wie das mit der State Machine/ Schrittkette funktioniert.

bei einer Schrittkette hast

  • du eine Variable Status die dir den aktuellen Schritt speichert
  • ein if oder switch case das je nach Status dann in deine Aktionen springt
  • eine Logik, die von einem Status in den nächsten Springt. Bei dir halt per Zeitablauf.

Verständlich?

noiasca:
bei einer Schrittkette hast

  • du eine Variable Status die dir den aktuellen Schritt speichert
  • ein if oder switch case das je nach Status dann in deine Aktionen springt
  • eine Logik, die von einem Status in den nächsten Springt. Bei dir halt per Zeitablauf.

Verständlich?

Von der Logik her klar. Kannst du mir Beispiele geben?

Wurstomat
Da sind sogar Zwei drin enthalten.

MfG

Von der Logik her klar. Kannst du mir Beispiele geben?

schau dir zunächst den Link von Postmaster an, wenns noch weitere Beispiele brauchst melde dich.

Von der Logik her klar. Kannst du mir Beispiele geben?

Beispiele sind nur bedingt hilfreich.

#include <CooperativeTask.h>

enum BlinkMuster : byte
{
  LEDAus   =     0 ,
  LEDGruen = _BV(0),
  LEDGelb  = _BV(1),
  LEDBlau  = _BV(2),
  LEDRot   = _BV(3),
  LEDWeis  = _BV(4)
};

byte muster {LEDAus}; // Uebergabe Merker



class BlinkTask: public Task
{
  protected:
    const byte pin;
    const unsigned long interval;
    const BlinkMuster flag;
  
  public:
    BlinkTask(const byte pin,const unsigned long interval,BlinkMuster flag):
       pin(pin),
       interval(interval),
       flag(flag)
    {}
    
    virtual void init() override
    {
      pinMode(pin,OUTPUT);
    }
    
    virtual void run() override
    {
      TaskBlock
      {
        taskWaitFor(flag & muster);
        digitalWrite(pin,HIGH);
        taskPause(interval);
        digitalWrite(pin,LOW);
        taskPause(interval);
      }
    }

    virtual ~BlinkTask()
    {
      digitalWrite(pin,LOW);
      pinMode(pin,INPUT);
    }
};

class Schrittkette : public Task
{
    public:
    virtual void run() override
    {
      TaskBlock
      {
        //muster = LEDAus;
        //taskPause(3000);
        
        muster = LEDGruen;
        taskPause(5000);
        
        muster = LEDGelb | LEDBlau;
        taskPause(3000);
        
        muster = LEDGelb | LEDGruen;
        taskPause(2000);
        
        muster = LEDRot;
        taskPause(2000);
        
        muster = LEDWeis | LEDGruen;
        taskPause(3000);
        
        muster = LEDBlau;
        taskPause(1000);
      }
    }  
};


Schrittkette schrittkette;

BlinkTask blinker[]{// {pin,interval,farbe} 
                       {4,100,LEDGruen},
                       {5,133,LEDGelb},
                       {6,175,LEDRot},
                       {7,221,LEDWeis},
                       {8,277,LEDBlau},
                   };     

void setup() 
{
  Scheduler::instance().init();
}

void loop() 
{
  Scheduler::instance().run();
}

CooperativeTask.zip (9.92 KB)

Moin,

wenn ich das aus dem Wurstomaten richtig verstehe, dann ist "case..." die Beschreibung des aktuellen Schritts. Mit "if (millis() 3000) {" stell ich die Wartezeit für den aktuellen Schritt ein (kann ich da direkt die Zeit in Millisekunden eintragen?). "schritt++; }" ist der Befehl um einen Schritt weiterzuschalten."break;" hält das Programm solange in dem Schritt, bis die "if" Bedingung erfüllt ist.

Gruß Andre

Moin,

apro1974:
wenn ich das aus dem Wurstomaten richtig verstehe, dann ist "case..." die Beschreibung Auswahl des aktuellen Schritts.

In der Arduino-IDE ist unter Hilfe die Referenz als offline-html hinterlegt.

Ein sehr gutes deutschsprachiges PDF mit Erklärungen der wichtigsten Dinge findest Du unter ArduinoForum.de - Das deutschsprachige Forum rund um den Arduino - Arduino Code-Referenz (deutsch)

das break; bricht aus dem switch aus.

stell dir das eher so vor, du beginnst mit case xxx: einen abschnitt und mit break; beendest ihn.
Oder (was besser hinkommt): auf Grund des switch springt der Controller in den Abschnitt der mit dem passenden Case beginnt und arbeitet diesen durch bis er zu einen break oder zum Ende kommt.

So ein case verwaltet daher einen Status. Du brauchst noch separat etwas um von einen Status in den anderen zu kommen.

ein Leeres gerüst für dich könnte in etwa so aussehen:

void runFsmBlinkled()
{
  static uint32_t previousMillis = 0;
  static byte state = 0;
  static uint32_t interval[] {5000, 3000, 2000, 2000, 3000, 1000};

  switch (state)
  {
    case 0:
      if (millis() - previousMillis < interval[state])
      {
        // was ist in diesem Status zu tun
      }
      else
      {
        // LEDs ausschalten
        // weiterschalten
        state++;
        previousMillis = millis(); // previousMillis resetten
      }
      break;
    case 1:
      if (millis() - previousMillis < interval[state])
      {
        // was ist in diesem Status zu tun
      }
      else
      {
        // LEDs ausschalten
        // weiterschalten
        state++;
        previousMillis = millis(); // previousMillis resetten
      }
      break;
    case 2:
      if (millis() - previousMillis < interval[state])
      {
        // was ist in diesem Status zu tun
      }
      else
      {
        // LEDs ausschalten
        // weiterschalten
        state++;
        previousMillis = millis(); // previousMillis resetten
      }
      break;
    case 3:
      if (millis() - previousMillis < interval[state])
      {
        // was ist in diesem Status zu tun
      }
      else
      {
        // LEDs ausschalten
        // weiterschalten
        state++;
        previousMillis = millis(); // previousMillis resetten
      }
      break;
    case 4:
      if (millis() - previousMillis < interval[state])
      {
        // was ist in diesem Status zu tun
      }
      else
      {
        // LEDs ausschalten
        // weiterschalten
        state++;
        previousMillis = millis(); // previousMillis resetten
      }
      break;
    case 5:
      if (millis() - previousMillis < interval[state])
      {
        // was ist in diesem Status zu tun
      }
      else
      {
        // LEDs ausschalten
        state = 0; // weiterschalten
        previousMillis = millis(); // previousMillis resetten
      }
      break;
  }
}

im loop rufst einfach immer wieder runFsmBlinkled() auf.

Natürlich tut dieses Gerüst noch nichts, aber du kannst ja mal einfach einzelnen LEDs einschalten und ausschalten als erste Übung.

Mach einen funktionierenden Sketch draus, ich hab dann noch drei weitere Teile im petto, weil das geht schon noch einfacher. Aber zum Grundverständnis denke ich das das passen soll.

Moin noiasca,

Das mit dem “void runFsmBlinkled()” habe ich noch nicht verstanden…

Ich habe allerdings deinen Tipp versucht umzusetzen. Die Schrittkette habe ich mal auf 3 Schritte reduziert.

unsigned long LEDGruen_timestore; //Grüne LED
int LedGruenStatus = LOW;
int LedGruenPin = 4;
unsigned long LEDGelb_timestore; //Gelbe LED
int LEDGelbStatus = LOW;
int LEDGelbPin = 5;
unsigned long LEDRot_timestore; //Rote LED
int LEDRotStatus = LOW;
int LEDRotPin = 6;
unsigned long LEDWeis_timestore; //Weise LED
int LEDWeisStatus = LOW;
int LEDWeisPin = 7;
unsigned long LEDBlau_timestore; //Blaue LED
int LEDBlauStatus = LOW;
int LEDBlauPin = 8;


void setup() {
  pinMode(LedGruenPin, OUTPUT);
  pinMode(LEDGelbPin, OUTPUT);  
  pinMode(LEDRotPin, OUTPUT);
  pinMode(LEDWeisPin, OUTPUT);
  pinMode(LEDBlauPin, OUTPUT);
}

void loop() 
{
  {
  static uint32_t previousMillis = 0;
  static byte state = 0;
  static uint32_t interval[] {5000, 3000, 2000};

  switch (state)
    {
      case 0:
        if (millis() - previousMillis < interval[state])
    if (LedGruenStatus == LOW){
    if (millis() - LEDGruen_timestore> 100 ){
      digitalWrite(LedGruenPin, HIGH);
      LEDGruen_timestore = millis();
      LedGruenStatus = HIGH;
      }
  } else {
    if (millis() - LEDGruen_timestore> 10) {
      digitalWrite(LedGruenPin, LOW);
      LedGruenStatus = LOW;
      state++;
      previousMillis = millis();
    }
    break;

    case 1:
    if (millis() - previousMillis < interval[state])
      {
 if (LEDRotStatus == LOW){
  if (millis() - LEDRot_timestore> 200 )    {
      digitalWrite(LEDRotPin, HIGH);
      LEDRot_timestore = millis();
      LEDRotStatus = HIGH;
     }
  } else {
    if (millis() - LEDRot_timestore> 10) {
      digitalWrite(LEDRotPin, LOW);
      LEDRotStatus = LOW;
       state++;
      previousMillis = millis();
    }
    break;

    case 2:
      if (millis() - previousMillis < interval[state])
      {
 if (LEDGelbStatus == LOW){
  if (millis() - LEDGelb_timestore> 300 )    {
      digitalWrite(LEDGelbPin, HIGH);
      LEDGelb_timestore = millis();
      LEDGelbStatus = HIGH;
     }
  } else {
    if (millis() - LEDGelb_timestore> 20) {
      digitalWrite(LEDGelbPin, LOW);
      LEDGelbStatus = LOW;
       state++;
      previousMillis = millis();
    }
    break;

  }
  }
  }
  }
  }
  }
  }
  }

Allerdings passiert bei mir dann folgendes. Die LEDs blinken zwar in der richtigen Reihenfolge, aber leider direkt hintereinander und auch nur genau 1 mal. Egal welche Zahlen ich hier " static uint32_t interval {5000, 3000, 2000};" eingebe…
Außerdem verliere ich bei den ganzen Klammern den Überblick.
Ich vermute mal, das ich versuche mehrere if Schleifen gleichzeitig laufen zu lassen. Dies scheint aber nicht so zu funktionieren.

Gruß

Andre

ich hätte ja gemeint, du lässt mal das blinken weg.

ich schau mal drüber…

edit:

du hast deine Geblinke mit den ifs aus der FSM vermischt.
Außerdem war es absicht, dass du das nicht direkt im loop machst sondern in einer eigenen Funktion.

hier nur mal für die Phase 0

unsigned long LEDGruen_timestore; //Grüne LED
int LedGruenStatus = LOW;
int LedGruenPin = 4;
unsigned long LEDGelb_timestore; //Gelbe LED
int LEDGelbStatus = LOW;
int LEDGelbPin = 5;
unsigned long LEDRot_timestore; //Rote LED
int LEDRotStatus = LOW;
int LEDRotPin = 6;
unsigned long LEDWeis_timestore; //Weise LED
int LEDWeisStatus = LOW;
int LEDWeisPin = 7;
unsigned long LEDBlau_timestore; //Blaue LED
int LEDBlauStatus = LOW;
int LEDBlauPin = 8;



void runFsmBlinkled()
{
  static uint32_t previousMillis = 0;
  static byte state = 0;
  static uint32_t interval[] {5000, 3000, 2000};

  switch (state)
  {
    case 0:
      if (millis() - previousMillis < interval[state])
      {
        // was ist in diesem Status zu tun
        
        // dein geblinke richtig gestellt
        if (LedGruenStatus == LOW) {
          if (millis() - LEDGruen_timestore > 100 ) {
            digitalWrite(LedGruenPin, HIGH);
            LedGruenStatus = HIGH;
            LEDGruen_timestore = millis();
          }
        } else {
          if (millis() - LEDGruen_timestore > 10) {
            digitalWrite(LedGruenPin, LOW);
            LedGruenStatus = LOW;
            LEDGruen_timestore = millis();
          }
        }
        // ende dein geblinke

      }
      else
      {
        // LEDs ausschalten
        digitalWrite(LedGruenPin, LOW);
        // weiterschalten
        state++;
        previousMillis = millis(); // previousMillis resetten
      }
      break;
    case 1:
      if (millis() - previousMillis < interval[state])
      {
        // was ist in diesem Status zu tun
      }
      else
      {
        // LEDs ausschalten
        // weiterschalten
        state++;
        previousMillis = millis(); // previousMillis resetten
      }
      break;
    case 2:
      if (millis() - previousMillis < interval[state])
      {
        // was ist in diesem Status zu tun
      }
      else
      {
        // LEDs ausschalten
        // weiterschalten
        state=0;
        previousMillis = millis(); // previousMillis resetten
      }
      break;
  }
}


void setup() {
  pinMode(LedGruenPin, OUTPUT);
  pinMode(LEDGelbPin, OUTPUT);
  pinMode(LEDRotPin, OUTPUT);
  pinMode(LEDWeisPin, OUTPUT);
  pinMode(LEDBlauPin, OUTPUT);
}

void loop()
{
  runFsmBlinkled();
}

verstanden? wenn ja, dann mach mal die anderen beiden Status und stell dein Ergebnis rein.
bevor du es postest, drücke STRG-T in der IDE damit das ordentlich formatiert wird.

p.s.: du hast die Anzahl der Status reduziert, daher musst du im letzten Status auch das Rücksetzen auf 0 einfügen.

Ich habe es tatsächlich geschafft ohne blinken die Schrittkette ans laufen zu bekommen. Habe es nur zeitlich nicht geschafft es zu posten. Werde mir deinen Post morgen mal in Ruhe anschauen und versuchen es umzusetzen.

Hallo,

mein Plan für den TO wäre folgender, wenn er das programmieren und verstehen lernen möchte, wovon ich ausgehe. Ansonsten kann der TO alle Bsp. hier für sich übernehmen.

Der Plan wäre. Den Umgang mit millis verstehen, falls noch nicht verstanden. Ein Klasse "Blinker" bauen. Die bräuchte erstmal nur 2 Methoden. start und stop für den Blinker. Wäre später noch ausbaubar. Mit dieser Klasse für jede Led ein Objekt erstellen. Dann wird die Steuerung mit den Methoden in switch case einfacher. Es kommen sich keine Zeiten ins Gehege, weil gekapselt. Code Dopplungen werden auch vermieden.

Ohne Objekte mit Blinkerei artet der Steuerungsablauf in Spaghetti-Code aus, zumindestens hätte es die Tendenz und wäre schlecht wartbar. Sollte man sich vorher überlegen. Ich kann nur aus meiner Erfahrung heraus eine Empfehlung geben.

kommt schrittweise doc, einiges davon hätte ich schon vorbereitet. Nur nicht übereilen. Außerdem ist die Antwortgeschwindigkeit des TO auch nicht gerade berauschend...