Unterprogramme nach einander ausführen

Moin, ich möchte für mein Model eine Beleuchtung programmieren.
Als erstes soll ein Lauflicht nach links und rechts mit jeweils 10 Leds laufen.
Im Anschluss sollen alle Leds einmal aufblinken. Zu einem späteren Zeitpunkt soll das eventuell erweitert werden bzw. noch andere Muster eingebunden werden.
Ich habe für das Lauflicht und blinken jeweils eigene Unterprogramme erstellt die dann aufgerufen werden soll.
Mein Problem ist nun wenn ich die Funktion Lauflicht und Blitzer nacheinander ausführe blinken die LEDs nur und das Lauflicht wird nicht ausgeführt (bzw. angezeigt).
Lasse ich starte ich nur das Lauflicht funktioniert es einwandfrei.
Ich habe einige Ansätze probiert um das Problem zu lösen, der letzte Stand ist mit Switch Case zu versuchen die Programme von einander zu trennen.
Anscheinend habe ich allerdings einen generellen Denkfehler und wäre um einen Denkanstoß oder Lösung dankbar.

int n=0;                                                                                 //Variable für Schleifen
int m=0;
int Lauflinks=1; 
int ledPinlinks[8]={2,3,4,5,6,7,8,9};                                            //Ausgänge links  !! Reihenfolge der Pins aufsteigend !!
int ledPinrechts[8]={53,52,51,50,49,48,47,46};                                   //Ausgänge rechts !! Reihenfolgeder Pins absteigen !!
int Status_Lauflicht=0;
int Status_Blitzer=0;
int ProgrammWahl=0;
int counter=0;

unsigned long previousMillis=0;
const long Laufintervall=1000;     //75                                                      //Zeitspanne Lauflicht

class Blink {
private: 
  unsigned long prevtime;
  unsigned int zyklus;
  unsigned int an;
public:
   Blink(unsigned int _an, unsigned int _zyklus) { zyklus=_zyklus; an = _an;}
   boolean currentState () {
     // sollte häufig aufgerufen werden, damit der jeweils aktuelle Zustand zurückgeliefert wird
     if (millis() - prevtime >= zyklus) {
       prevtime = millis();
     }
     if (millis() - prevtime < an) return true;
     else return false;
   } 
};

Blink blitz(20,2000);   //200

void setup() {
  // put your setup code here, to run once:
    Serial.begin(9600);
  
  // auf serielle Verbindung warten
  while(!Serial);
  delay(1000);

  Serial.println("Programmieren ist toll!");
  
  for(int i=0;i<8;i++){
      pinMode(ledPinlinks[i],OUTPUT);
      pinMode(ledPinrechts[i],OUTPUT);
  }
  pinMode(25,OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
switch(ProgrammWahl){
  case 0:
    Lauflicht(5);
    break;
  case 1:
    Blitzer(3);
    break;

}

//  if (Status_Lauflicht=0){Lauflicht(5);}
//  if (Status_Blitzer==0) {Blitzer(3);}
  
}

void Lauflicht(int Durchlauf){
  int i=0;
  unsigned long currentMillis=millis();
  do{
  if(currentMillis-previousMillis>=Laufintervall){                                    
    previousMillis=currentMillis;
      if(Lauflinks==1){
        digitalWrite(ledPinlinks[counter-1],LOW);
        digitalWrite(ledPinlinks[counter],HIGH);
        digitalWrite(ledPinrechts[counter-1],LOW);
        digitalWrite(ledPinrechts[counter],HIGH);

        counter=counter+1;
        if(counter>7){
          counter=7;
          Lauflinks=2;
        }
      }
      if(Lauflinks==2){
        digitalWrite(ledPinlinks[counter+1],LOW);
        digitalWrite(ledPinlinks[counter],HIGH);
        digitalWrite(ledPinrechts[counter+1],LOW);
        digitalWrite(ledPinrechts[counter],HIGH);
        
        counter=counter-1;
        if(counter<0){
          counter=1;
          Lauflinks=1;
         }
      } 
  }
  i++;
  } while (i<32);
   ProgrammWahl=1;
}

void Blitzer(int Durchlauf){
  for (int i=0;i<8;i++){
    digitalWrite(ledPinlinks[i], blitz.currentState() );
    digitalWrite(ledPinrechts[i], blitz.currentState() );
  }
  ProgrammWahl=0;

}

Hallöchen, ich hab mir das mal angeschaut aber nicht ausprobiert aber 2 Sachen in den Schleifen die mir aufgefallen sind:
1.) In der Lauflicht Funktion warum nimmst Du da eine do while Schleife und nicht eine for Schleife ?
2.) die Variable i wird in der Lauflicht Funktion hochgezählt aber vor der Blitz Funktion nicht auf 0 zurück gesetzt. Könnte das die Blitzer Funktion beeinflussen ? Nimm doch zwei Variablen für die Zähler, i und j
Nur so ne Idee, vielleicht ist das auch ein Denkfehler von meiner Seite

Moin, danke für die Antwort.
zu 1: ich hatte eine do while schleife gewählt da das Lauflicht im void loop() funktioniert und habe dann einfach eine Abbruchbedingung eingefügt um den blitzer ausführen zu können.
zu 2: hab ich mal getestet, bringt leider auch keinen Erfolg.

Ich habe mal ein Video gemacht wie das momentan aussieht.
Zwischen dem blitzen der LEDs kann man ein kurzes aufblinken vom Lauflicht erkennen.

https://streamable.com/6cu426

Beides:
Füge Dir serielle Ausgaben ein, damit Du siehst, an welcher Stelle im Code nix passiert, weil Du da nie hin kommst und dann das gleiche um zu sehen, an welcher Stelle Du ein anderes Ergebnis bekommst, als Du erwartest.

Und ja, das geht.
Sogar sehr gut.

Hallo dr_n0b0dy

Willkommen im besten Arduino Forum der Welt :slight_smile:

Ich habe in meiner Sketchkiste für gebrauchte Sketches ein Led-Sequencer für drei Leds gefunden.

In diesem Sketch kannst du einfach die LedPins erweitern und das Timing und Pattern aufbohren.


constexpr int LedPins[] {9, 10, 11};

struct LEDSEQUENCER
{
  uint32_t span;
  int pattern[sizeof(LedPins) / sizeof(LedPins[0])];
  uint32_t now;
  int control;
};
LEDSEQUENCER ledSequencers[]
{
  { 500, 0, 0, 0, 0, HIGH},
  { 1000, 1, 0, 0, 0, LOW},
  { 500, 0, 0, 0, 0, LOW},
  { 1000, 0, 1, 0, 0, LOW},
  { 500, 0, 0, 0, 0, LOW},
  { 1000, 0, 0, 1, 0, LOW},
  { 500, 0, 0, 0, 0, LOW},
  { 1000, 0, 0, 1, 0, LOW},
  // add timing and pattern as needed
};

void setup()
{
  for (auto LedPin : LedPins)
  {
    pinMode ( LedPin, OUTPUT);
    digitalWrite(LedPin, HIGH);
    delay(1000);
    digitalWrite(LedPin, LOW);
    delay(1000);
  }
}
void loop()
{
  uint32_t currentMillis = millis();
  for (auto &ledSequencer : ledSequencers)
  {
    if (currentMillis - ledSequencer.now >= ledSequencer.span && ledSequencer.control)
    {
      static int number = 0;
      int element = 0;
      ledSequencer.control = LOW;
      number = (number + 1) % (sizeof(ledSequencers) / sizeof(ledSequencers[0]));
      ledSequencers[number].control = HIGH;
      ledSequencers[number].now = currentMillis;
      for (auto LedPin : LedPins) digitalWrite(LedPin, ledSequencers[number].pattern[element++]);
    }
  }
}

Viel Spass beim Testen und Basteln.

Hallo,

dein i bleibt auf 32 stehen. Das ist eine Endlosschleife in Zeile 100.

Programmwahl bitte nicht global. Alles was mit der Steuerung zu hat sollte zusammenbleiben. Sonst hat man schnell alles im Sketch verteilt und zu viel Kaos. Die aufgerufenen Funktionen können ein bool als Rückgabe liefern um zu melden das sie fertig sind. Das kann man in der Steuerung nutzen um zum nächsten case zu wechseln. Es helfen auch "sprechende" Steuervariablen des Typs enum. Switch-Case und enum nimmt man gern zusammen.

Ich hab den Anstoß von my_xy_projekt mal aufgegriffen.
Ich lasse mir am Anfang sowie Ende der Funktion Lauflicht einen Wert ausgeben.
Jedes Mal wenn der Counter in Lauflicht geändert wird gibt es eine weitere Ausgabe.
In der Funktion Blitz lasse ich eine Meldung bei starten ausgeben.

Damit fällt auf das im Ablauf der Funktion Lauflicht zwischen den einzelnen Änderungen des Counters die Funktion Blitz aufgerufen wird.

Sieht im Monitor dann so aus:

Blitz
Lauflicht
25
durchlauf
Ende
Blitz
Lauflicht
Ende
Blitz
Lauflicht
Ende
Blitz
Lauflicht
24
durchlauf
Ende
Blitz
Lauflicht
Ende
Blitz
Lauflicht
Ende
Blitz
Lauflicht
23
durchlauf
Ende
Blitz

Das würde dann bedeuten das die Schleife in der Funktion Lauflicht nicht richtig ist.

Mit den Vorschlägen von paulpaulson und Doc_Arduino werde ich mich am Wochenende
mal mit beschäftigen.

Zuerst würde ich den Code einmal formatieren. Dazu kannst du Strg-T in der IDE benutzen.

Du überschreibst einmal alles und bist dann weg. Du darfst ProgrammWahl erst ändern wenn die Animation durch ist.

Überprüfe deine Arrayzugriffe auf Out of bounds.

Die Parameter int Durchlauf in Blitzer bzw. Lauflicht verwendest du gar nicht.
Wäre aber hübsch.

Dass zwei Funktionen sich über gemeinsame globale Variable gegenseitig steuern kann man machen, ist aber unnötig kompliziert und fehleranfällig.
Da sie bei dir sowieso nur nacheinander laufen können (schade eigentlich :wink: ), kannst du das auch einfach weglassen.

Hallo,
ich habe jetzt das bisher geschriebene nur kurz überflogen, also eventuell den Hinweis übersehen.
Wenn Du letztlich weitere Unterprogramme dazu nehmen willst dann würde sich doch eine Statemashine , Ablaufsteuerung / Schrittkette anbieten. Die könnte man zeitgesteuert weiter schalten oder auch mit einem Statusmerker "Unterprogramm beendet". Solange der Schritt aktiv ist wird immer die gleicher Funktion aufgerufen. Wenn man es richtig macht blockiert auch kein Programmteil. Vorlagen zu einer Ablaufsteuerung findest Du z.B. auch reichlich hier im Forum.

Heinz

Ich beziehe mich auf #1. Den Vorteil der Klasse vermag ich nicht zu erkennen. Blockierendes do/while zusammen mit millis() ergibt wieder einen blockiernden Ablauf. Wie Du selbst gemerkt hast, bist Du in eine Sackgasse geraten.

Wenn das Programm nichts weiter tun soll, als die LEDs blinken zu lassen, stört ein blockierendes Programm nicht, dann geht auch delay().

Programm mit delay und 2 * 4 LEDs
const byte ledPinlinks[] = {36, 37, 38, 39};                           //Ausgänge links  !! Reihenfolge der Pins aufsteigend !!
const byte ledPinrechts[] = {49, 48, 47, 46};                          //Ausgänge rechts !! Reihenfolgeder Pins absteigen !!
const byte anzLeds = sizeof(ledPinlinks);

const unsigned long intervall = 75;                                    //Zeitspanne Lauflicht
const unsigned long anZeit = 50;                                       //Zeit Blitzer an
const unsigned long ausZeit = 500;                                     //Zeit Blitzer aus
unsigned long vorhin = 0;

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("\nProgrammieren ist toll!");

  for (byte i = 0; i < anzLeds; i++) {
    pinMode(ledPinlinks[i], OUTPUT);
    pinMode(ledPinrechts[i], OUTPUT);
  }
}

void loop() {
  lauflicht(5);
  blitzer(3);
}

void lauflicht(const byte durchlauf) {
  for (byte d = 0; d < durchlauf; d++) {
    for (byte l = 0; l <= anzLeds; l++) {
      if (l > 0) {
        digitalWrite(ledPinlinks[l - 1], LOW);
        digitalWrite(ledPinrechts[l - 1], LOW);
      }
      if (l < anzLeds) {
        digitalWrite(ledPinlinks[l], HIGH);
        digitalWrite(ledPinrechts[l], HIGH);
      }
      delay(intervall);
    }
  }
}

void blitzer(const byte durchlauf) {
  for (byte d = 0; d < durchlauf; d++) {
    for (byte l = 0; l < anzLeds; l++) {
      digitalWrite(ledPinlinks[l], HIGH);
      digitalWrite(ledPinrechts[l], HIGH);
    }
    delay(anZeit);
    for (byte l = 0; l < anzLeds; l++) {
      digitalWrite(ledPinlinks[l], LOW);
      digitalWrite(ledPinrechts[l], LOW);
    }
    delay(ausZeit);
  }
}

Sollte Dein Programm neben dem Blinken noch andere Dinge tun sollen, kann man diese blockierende Version in eine nicht blockierende umwandeln. Der Herzschlag steht für diese zusätzlichen Aufgaben:

blockadearmes Programm mit Herzschlag
const byte ledPinlinks[] = {36, 37, 38, 39};                           //Ausgänge links  !! Reihenfolge der Pins aufsteigend !!
const byte ledPinrechts[] = {49, 48, 47, 46};                          //Ausgänge rechts !! Reihenfolgeder Pins absteigen !!
const byte anzLeds = sizeof(ledPinlinks);

const unsigned long intervall = 75;                                    //Zeitspanne Lauflicht
const unsigned long anZeit = 50;                                       //Zeit Blitzer an
const unsigned long ausZeit = 500;                                     //Zeit Blitzer aus
unsigned long jetzt = millis();

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("\nProgrammieren ist toll!");

  for (byte i = 0; i < anzLeds; i++) {
    pinMode(ledPinlinks[i], OUTPUT);
    pinMode(ledPinrechts[i], OUTPUT);
  }
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  jetzt = millis();
  static byte schritt = 0;
  switch (schritt) {
    case 0:
      if (lauflicht(5)) schritt++;
      break;
    case 1:
      if (blitzer(3)) schritt--;
      break;
  }
  herzschlag();
}

bool lauflicht(const byte durchlauf) {
  static unsigned long vorhin = 0;
  static byte d = 0;
  static byte l = 0;
  bool fertig = false;

  if (jetzt - vorhin >= intervall) {
    vorhin = jetzt;
    if (l > 0) {
      digitalWrite(ledPinlinks[l - 1], LOW);
      digitalWrite(ledPinrechts[l - 1], LOW);
    }
    if (l < anzLeds) {
      digitalWrite(ledPinlinks[l], HIGH);
      digitalWrite(ledPinrechts[l], HIGH);
    }
    if (l <= anzLeds) {
      l++;
    } else {
      l = 0;
      if ( d < durchlauf ) {
        d++;
      } else {
        d = 0;
        fertig = true;
      }
    }
  }
  return fertig;
}

bool blitzer(const byte durchlauf) {
  static unsigned long vorhin = 0;
  static byte d = 0;
  static bool ein = true;
  bool fertig = false;

  if (ein) {
    if (jetzt - vorhin >= ausZeit) {
      vorhin = jetzt;
      ein = !ein;
      for (byte l = 0; l < anzLeds; l++) {
        digitalWrite(ledPinlinks[l], HIGH);
        digitalWrite(ledPinrechts[l], HIGH);
      }
    }
  } else {
    if (jetzt - vorhin >= anZeit) {
      vorhin = jetzt;
      ein = !ein;
      for (byte l = 0; l < anzLeds; l++) {
        digitalWrite(ledPinlinks[l], LOW);
        digitalWrite(ledPinrechts[l], LOW);
      }
      if ( d < durchlauf ) {
        d++;
      } else {
        d = 0;
        fertig = true;
      }
    }
  }
  return fertig;
}

void herzschlag() {
  static unsigned long vorhin = 0;

  if (jetzt - vorhin >= 111) {
    vorhin = jetzt;
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }
}