Lauflicht ohne delay mit Unterbrechung

Hallo Programmierfreunde,
ich habe folgendes Problem.

Zunächst bin ich hier im Forum neu und als Programmierer bin ich Anfänger. Falls ich den Beitrag in flasche Rubrik gestellt habe, entschuldige ich mich schon mal dafür!

Nun zum Problem:
Ich möchte mit einem Taster (oder einfach spannunseingang 5v) ein Lauflicht auslösen. Jede der 14 LED soll dazwischen 0,5s Pause haben. Wenn alle LED’s an sind, dann bleiben für 10s alle an und dann sollen im selben Muster auch alle ausgehen mit 0,5 sek Verzögerung. Eingentlich einfach!

Ich habe schon ein Programm mit delay erstellt und es funktioniert auch alles. Doch ein Problem gibt es!:
Wenn die LED’s im “Ausgeh-Modus” sind, kann ich die Schleife nicht vorzeitig starten, weil jedes mal im delay muss der mC warten und nichts tun!

Natürlich habe ich mir schon andere Lösungen angeguckt, wie z.B. currentMillis, oder Interrupt.
Aber ich bekommen nicht mal einen Plan wie ich das realisieren soll.

Ich brauche nicht unbediengt den kompletten Code für mein Problem, aber Leitfaden wäre nicht schlecht wie man so was realisieren kann.

ich hoffe ihr könnt mir helfen, danke
gruß

Schau Dir BlinkWitoutDelay und die Nachtwächtererklärung (kein Witz) an.

Gruß Tommy

Natürlich habe ich mir schon andere Lösungen angeguckt, wie z.B. currentMillis

Da bist du vermutlich schon richtig.

Damit es geht, brauchst du Variable, in der (denen) du dir merkst, wo du grade bist.
z.B. (als Vorschlag) An / Aus Phase, LED-Nummer .

Ich verstehe dich so, dass der Taster die Sequenz sofort wieder neu starten soll, egal ob sie schon fertig war oder noch nicht.

Das ist die klassische Aufgabe, wo delay() versagt.
Und wo das Schlagwort "BlinkWithoutDelay" nicht ganz ausreicht, wenn du nicht komplett verstehst, worin der wesentliche Unterschied besteht.

loop() braucht keine Zeit und kommt dafür sofort wieder dran, und du hast Variable, die dir sagen wo "Das Programm" grade ist. Bei BlinkWithoutDelay ist das previousMillis, bei dir wären wohl andere Merker interessant.

Obwohl: das geht auch nur mit

   unsigned long previousMillis; // Zeit des letzten Tasterdrucks

und etwas, das die ganze Lauflichtshow relativ dazu abdeckt.

Deine loop hätte dann eine ganze Serie von

  • Wenn es x millis nach Show-Start ist, muss diese LED gerade an oder ausgeschaltet werden.
    Anweisungen, und eine Tasterabfrage, die alles auf einen Anfangszustand setzt.

Zwei Hinweise, such dir einen davon aus und berichte. Viel Spass :wink:

Ich brauche nicht unbediengt den kompletten Code für mein Problem, aber Leitfaden wäre nicht schlecht wie man so was realisieren kann.

Einen Leitfaden…?

Baue einen endlichen Automaten.

TimeLed1 = millis ();
If ((StartZeit - TimeLed1) >= deine zeit)
{
Led1 einschalten
}

Als code schnippsel wie sowas aussehen könnte.
Natürlich musst du in StartZeit die millis speichern damit es ein Vergleich gibt.

Würde zwar gerne ein besseres Bsp geben aber vom smartphone aus ist das einfach nix.

If ((StartZeit - TimeLed1) >= deine zeit)

If ((millis() - StartZeit) >= deine zeit)

dimix100:
Ich brauche nicht unbediengt den kompletten Code für mein Problem, aber Leitfaden wäre nicht schlecht wie man so was realisieren kann.

Dafür bietet sich eine Finite State Machine (SFM) mit vier Betriebszuständen an:
AUS,HOCHFAHREN,EIN,RUNTERFAHREN

Für jeden Betriebszustand brauchst Du eine "State Funktion" zum Agieren in diesem Zustand.
Dazu eine buttonPressed() Funktion mit boolschem Rückgabewert zum Feststellen eines Tastendrucks.

Ein Tastendruck würde dann jeweils den Betriebszustand HOCHFAHREN setzen.

Und alles andere würde zeitgesteuert bzw nach Anzahl der geschalteten LEDs ablaufen, im wesentlichen über die "vergangene Zeit seit ein Betriebszustand gesetzt wurde.

Den gewünschten Programmablauf hast Du ja sehr detailliert und verständlich beschrieben.

Wenn Du nicht weißt, wie Du eine FSM dafür programmtechnisch umsetzen kannst, verrate mir noch, an welchem Pin der Tastschalter und an welchen 14 Pins die LEDs hängen sollen, dann kann ich Dir ggf. ein Beispielprogramm machen.

Bei den LEDs mußt Du aufpassen, dass der Mikrocontroller vom Strombedarf her nicht überlastet wird. Also 14x 5mA wäre vermutlich OK, aber 14x20mA wäre vermutlich außerhalb der Spezifikation des Controllers, wenn Du die ganzen Milliamperes direkt aus OUTPUT-Pins ziehen möchtest.

Hallo,
danke für die Antwort.

Meine Ausgangspin sind von 24...38 und Eingang ist auf Pin 50.

Ich muss alles noch verarbeiten. Ich hatte Nachtschicht und muss mich noch mal alles durchlesen.
Danke
Gruß

Meine Ausgangspin sind von 24...38 und Eingang ist auf Pin 50.

Und?
Willst du andeuten, dass du einen Arduino MEGA (Nachbau) hast? Schön für dich :wink:

Udo BlinkenLight hätte den Reset-Knopf verwendet und 20 LED an einem Uno betrieben. Ohne delay natürlich ...

Ich bin neu in dem Bereich.
Hab einfach ein Biard genommen der viele ein/Ausgänge hat. Für alle Fälle.
Ich wollte nicht angeben, falls du das meinst...
Gruß

falls du das meinst

nein, eher nicht. Angeben geht hier andersrum: je kleiner bei gleicher Funktion, desto toller.

Ich fürchtete eher, dass du annimmst, jemand könnte diese Information benötigen, um dir den Sketch gebrauchsfertig zu liefern. :wink:

dimix100:
Hallo,
danke für die Antwort.

Meine Ausgangspin sind von 24…38 und Eingang ist auf Pin 50.

Pins 24 bis 38 einschließlich? Das wären insgesamt 15 Pins.

15 Ausgangspins zum Schalten von 14 LEDs?
Das klingt ein wenig verschwenderisch.
Irrtum Deinerseits?
Oder soll das so und eine von den 14 LEDs soll über zwei Pins steuerbar sein?

Pins 24 bis 38 einschließlich? Das wären insgesamt 15 Pins.

Ne Sorry hab mich vertan...
24 bis 37 sind led, 38 ist belegt als Reserve.

dimix100:
Pins 24 bis 38 einschließlich? Das wären insgesamt 15 Pins.

Ne Sorry hab mich vertan...
24 bis 37 sind led, 38 ist belegt als Reserve.

OK, also 14 LEDs von 24 bis 37.

So ein Programm besteht im Prinzip aus zwei Elementen:

  • Datenstrukturen und Algorithmen

Als Datenstruktur für die LED-Pins schlage ich dann mal ein Array aus byte-Konstanten vor:

const byte ledPins={24,25,26,27,28,29,30,31,32,33,34,35,36,37};

So lassen sich die Pins aus einem Programm leicht über einen Array-Index von 0 bis 13 ansprechen
, etwa um in der setup() Funktion mit einer for-Schleife alle Pins auf pinMode OUTPUT zu setzen.

Ich glaube, im englischsprachigen Teil des Forums hatte icherst vor ein bis zwei Wochen ein ähnliches Programm zur Demonstration einer Finite State Machine (FSM/Zustandsautomat) gepostet. Das Beispielprogramm behandelte zwar nur 6 LEDs. aber dafür sollten alle 6 LEDs auch an PWM Ausgängen in der Helligkeit geregelt werden, erst hochdimmen, dann nach einer Weile wieder runterdimmen. Soll ich das hier bei mir vorhandeneFSM-Beispielprogramm mal auf Deine Schaltlogik für 14 LEDs ändern und dann hier den Code posten?

Was verwendest Du für LED?s Und was für Vorwiderstände? Weiße 5mm low-Power LEDs mit 330 Ohm Vorwiderstand, oder was?

Mit der Taste habe ich es mir einfach gemacht und die Library Bounce2 benutzt.
Den momentanen Zustand repräsentiere ich in einem Byte,
0 alles aus, 1 die erste LED leuchtet… … 14 die ersten 14 LEDs leuchten … 27 die erste leuchtet.
Die Dauer aller Schritte ist 0,5 Sekunden, nur im Schritt 14 sollen es 10 Sekunden sein.
Ein Tastendruck (re)startet die Sequenz in Schritt 1.
Die Anzahl der anzuschaltenden LEDs wird aus der Schrittnummer berechnet.

#include <Bounce2.h>

const byte ledPin[] = { 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37};
const byte tastenPin = 50;
const byte ledPins = sizeof(ledPin) / sizeof(ledPin[0]);

Bounce Taste;

void setup() {
  Taste.attach(tastenPin, INPUT_PULLUP);
  for (byte i = 0; i < ledPins; i++) {
    pinMode(ledPin[i], OUTPUT);
  }
}

void loop() {
  static unsigned long letzteAktion;
  static unsigned long dauerDiesesSchritts;
  static byte zustand;
  unsigned long topLoop = millis();
  if (Taste.update() && Taste.fell()) {
    zustand = 1;
    dauerDiesesSchritts = 1;
  }
  if (dauerDiesesSchritts && topLoop - letzteAktion >= dauerDiesesSchritts) {
    letzteAktion = topLoop;
    byte anzahlVonLeuchtendenLeds = zustand <= ledPins ? zustand : 2 * ledPins - zustand;
    for (byte i = 0; i < ledPins; i++) {
      digitalWrite(ledPin[i], i < anzahlVonLeuchtendenLeds);
    }
    dauerDiesesSchritts = zustand == ledPins ? 10000 : 500;
    if (++zustand > 2 * ledPins) {
      dauerDiesesSchritts = 0;
    }
  }
}

Hi,
ich verwende einen Arduino Relais Board mit 16 Kanälen. Einer Ausgang schaltet über das Relais ein LED Band.
Das Arduino mega kann 40mA pro Ausgang. Die Ansteuerung der Relais benötigt 10mA den Rest übernimmt externe Spannungsversorgung.
Gruß

Ach, noch was.
Aus oben beschrieben Grund brauche ich keine PMW Ansteuerung.
Die wäre Contra produktiv!

Whandall:
0 alles aus, 1 die erste LED leuchtet.... .... 14 die ersten 14 LEDs leuchten ... 27 die erste leuchtet.
Die Dauer aller Schritte ist 0,5 Sekunden, nur im Schritt 14 sollen es 10 Sekunden sein.
Ein Tastendruck (re)startet die Sequenz in Schritt 1.

Habe ich jetzt die vom Themenstarter beschriebene Programmlogik falsch verstanden oder Du?

Ich hatte es so verstanden:

  • 14 LEDs sollen nacheinander von der ersten bis zur vierzehnten angehen
  • wenn alle 14 an sind, soll sich 10 Sekunden lang nichts ändern
  • danach sollen die LEDs in derselben Reihenfolge, von der ersten bis zur vierzehnten wieder ausgehen.
    Nach meinem Verständnis wäre die zuletzt leuchtende einzelne LED dann die vierzehnte, bevor wieder alles aus ist.

Aber Du scheinst die LEDs in umgekehrter Reihenfolge ausuischalten wie einzuschalten. so dass die zuletzt leuchtende einzelne LED die erste LED ist und nicht die vierzehnte.
Das habe ich irgendwie anders verstanden.

Ich habe “im selben Muster wieder ausgehen” als “das Ganze rückwärts” verstanden.

Aber Ausgehenlassen geht fast genauso

#include <Bounce2.h>

const byte ledPin[] = { 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37};
const byte tastenPin = 50;
const byte ledPins = sizeof(ledPin) / sizeof(ledPin[0]);

Bounce Taste;

void setup() {
  Taste.attach(tastenPin, INPUT_PULLUP);
  for (byte i = 0; i < ledPins; i++) {
    pinMode(ledPin[i], OUTPUT);
  }
}

void loop() {
  static unsigned long letzteAktion;
  static unsigned long dauerDiesesSchritts;
  static byte zustand;
  unsigned long topLoop = millis();
  if (Taste.update() && Taste.fell()) {
    zustand = 1;
    dauerDiesesSchritts = 1;
  }
  if (dauerDiesesSchritts && topLoop - letzteAktion >= dauerDiesesSchritts) {
    letzteAktion = topLoop;
    bool zweitePhase = zustand > ledPins;
    byte anzahlAusgewaehlterLeds = zweitePhase ?  zustand - ledPins : zustand ;
    for (byte i = 0; i < ledPins; i++) {
      digitalWrite(ledPin[i], zweitePhase ^ (i < anzahlAusgewaehlterLeds));
    }
    dauerDiesesSchritts = zustand == ledPins ? 10000 : 500;
    if (++zustand > 2 * ledPins) {
      dauerDiesesSchritts = 0;
    }
  }
}

Ich hatte es so verstanden:

  • 14 LEDs sollen nacheinander von der ersten bis zur vierzehnten angehen
  • wenn alle 14 an sind, soll sich 10 Sekunden lang nichts ändern
  • danach sollen die LEDs in derselben Reihenfolge, von der ersten bis zur vierzehnten wieder ausgehen.
    Nach meinem Verständnis wäre die zuletzt leuchtende einzelne LED dann die vierzehnte, bevor wieder alles aus ist.

So habe ich es auch gemeint!
Alles richtig verstanden!