LEDs verschieden flackern lassen

Hallo Community

Ich möchte gerne 3-4 LEDs verschieden flackern lassen.

Fürs flackern nutze ich folgenden sketch

int ledPin = 10;
byte flicker[] = {180, 30, 89, 23, 255, 200, 90, 150, 60, 230, 180, 45, 90};

void setup()
{
pinMode(ledPin, OUTPUT);
}

void loop()
{
for(int i=0; i,7; i++)
{
analogWrite(ledPin, flicker[i]);
delay(2000);
}
}

Nun möchte ich diesen Code so anpassen dass ich auf weiteren Pins LEDs ansteuere jedoch mit anderem Flackermuster.

Ist dies möglich?

Danke Gruss Enzo

Ja, das ist recht einfach. In deinem Sketch sind jedoch 2 Probleme, die das verhindern.

  1. for Schleife
  2. delay

Auch iterierst du nicht mal über alle Helligkeitswerte. Und die Pause bleibt auch immer gleich.

Du solltest dich aufschlauen, wie man blockierungsfrei programmiert. Such mal nach Nachtwächtererklärung. Die Lib INTERVAL.h begeistert mich seht für solche Dinge.

Hi

Dazu habe ich Mal was gebastelt: Allerdings rein digital (nur an/aus)

// #define debugit   //Die Ausgänge im Sekundentakt blinken lassen

/*
//Pins, an Denen die LEDs hängen (später die FETs für die 12V LED-Streifen, wasserdicht)
const byte ledpin1 = 2;
const byte ledpin2 = 3;
const byte ledpin3 = 4;
const byte ledpin4 = 5;

//Blinkmuster Anzahl AN-Zeit AUS-Zeit
const uint16_t blink1[] = {
  3, 5, 80,
  1, 10, 503,
  3, 5, 80,
  1, 10, 500,
  3, 5, 80,
  1, 10, 500,
  2, 100, 200,
  1, 100, 500,
};

const uint16_t blink2[] = {
  5, 5, 91,
  1, 10, 590,
  2, 100, 200,
  1, 100, 500,
};

const uint16_t blink3[] = {
  2, 5, 90,
  1, 10, 590,
  2, 5, 90,
  1, 10, 590,
  1, 10, 597,
  2, 100, 200,
  1, 100, 500,
};

const uint16_t blink4[] = {
  3, 5, 90,
  1, 10, 190,
  1, 10, 590,
  2, 100, 200,
  1, 100, 500,   //<-- das letzte Komma stört nicht, macht ein Anhängen neuer Muster aber einfacher
};

//Adressen der struct's in einem Array zusammen fassen
const uint16_t * blinker[]={blink1,blink2,blink3,blink4};   //Zeiger auf uint16_t Arrays

struct {
  const byte _pin;  //Pin-Nummer der LED
  byte _schritt;  //Schritt der Blink-Sequenz
  byte _muster;   //Muster-Nummer in der Blink-Sequenz
  uint32_t nextset; //wann ist der aktuelle Schritt abgelaufen?
  const byte _maxSequenz;   //Anzahl der vorhandenen Sequenzen
  const uint16_t* blinkarray; //Adresse der Blinkfolge
} led[] {
  {ledpin1, 0, 0, 0, sizeof(blink1) / sizeof(blink1[0]) / 3, blinker[0]},
  {ledpin2, 0, 0, 0, sizeof(blink2) / sizeof(blink2[0]) / 3, blinker[1]},
  {ledpin3, 0, 0, 0, sizeof(blink3) / sizeof(blink3[0]) / 3, blinker[2]},
  {ledpin4, 0, 0, 0, sizeof(blink4) / sizeof(blink4[0]) / 3, blinker[3]},
};

void setup() {
  Serial.begin(9600);
  Serial.println("Start");
  for (auto &element : led)           //ohne das & können die Werte nicht im Struct geändert werden
  { //da mit Kopien geschafft wird - mit & per Referenz auf das Struct
    Serial.print("Ausgangspin ");
    Serial.println(element._pin);
    Serial.print("Sequenzen ");
    Serial.println(element._maxSequenz);
    pinMode(element._pin, OUTPUT);    //Pin auf Ausgang
    digitalWrite(element._pin, HIGH); //und einschalten
    element.nextset = millis() + element.blinkarray[1];   //Endzeit des ersten Hell-Impuls
    Serial.print("Endzeit:");
    Serial.println(element.nextset);
  }
#ifdef debugit
  while (1) {
    for (auto &element : led) {
      digitalWrite(element._pin, HIGH);
    };
    delay(1000);
    for (auto &element : led) {
      digitalWrite(element._pin, LOW);
    };
    delay(1000);
  }
#endif  
}

void loop() {
  for (auto &element : led)
  {
    //hier prüfen, ob die Laufzeit des aktuellen Schritt abgelaufen ist
    if (millis() >= element.nextset) {                    //Es ist unwahrscheinlich, daß die Schaltung >47 Tage am Stück läuft
      uint16_t schritt = element._schritt;                //da das angedachte Ziel, ein E-Quad, wohl nur für 30 Min Saft hat
      byte muster = element._muster;
      digitalWrite(element._pin, schritt & 0x01); //unterste Bit von Schritt bestimmt, ob AN oder AUS geschaltet wird
      //element._schritt Anzahl der Durchläufe
      //element.muster Anzahl der verschiedenen Blink-Rythmen
      schritt ++;
      if (schritt >> 1 >= element.blinkarray[muster * 3]) {
        //Blink-Sequenz oft genug wiederholt
        muster++;   //nächste Muster
        schritt = 0; //Wiederholungen auf 0 zurück setzen
        if (muster >= element._maxSequenz) {
          muster = 0; //von Vorne anfangen
        }
        element._muster = muster;
      }
      element._schritt = schritt;
      element.nextset = millis() + element.blinkarray[muster * 3 + (schritt % 2) + 1];
      //.muster * 3 + .schritt + 1 = nächste Laufzeit
      //.muster * 3 = Anzahl an Wiederholungen
    }
  }
}

Kompiliert ohne Warnungen, sollte der aktuelle Stand sein.
Sketch lässt vier Pins des Arduino unabhängig voneinander blinken/blitzen.
Die einzelnen Blink-Sequenzen können mit

  • Anzahl
  • ON-Time
  • OFF-Time
    in einem Array definiert werden, Diese werden der Reihe nach ‘durchgeblinkt’ - am Ende wird oben wieder angefangen.
    3,10,990 → 3x 10ms an, 990ms aus

Pro LED-Pin einzeln einstellbar, Umfang der Blinkerei nicht vom Sketch begrenzt.

Vll. passt’s ja schon so - versuchen zu verstehen, was ich mir Da wohl bei gedacht habe, schadet aber bestimmt nicht.

MfG

mastrolindo83:
Ich möchte gerne 3-4 LEDs verschieden flackern lassen.

Das erinnert mich an das “belebte Haus” auf Modellbahnanlagen, was mich dann zu den MobaTools und einem zufälligen Flackern führt:

#include <MobaTools.h>      // https://github.com/MicroBahner/MobaTools
const byte randomPin = A5;  // ein freien analoger Pin
class Zimmer {
    const byte ledPin;      // Pin der LED
    const uint32_t minAn;   // minimale Einschaltzeit in ms
    const uint32_t maxAn;   // maximale Einschaltzeit in ms
    const uint32_t minAus;  // minimale Ausschaltzeit in ms
    const uint32_t maxAus;  // maximale Ausschaltzeit in ms
    EggTimer Schaltzeit;
  public:
    Zimmer(const byte ledPin, const uint32_t minAn, const uint32_t maxAn, const uint32_t minAus, const uint32_t maxAus)
      : ledPin(ledPin), minAn(minAn), maxAn(maxAn), minAus(minAus), maxAus(maxAus), Schaltzeit() {}
    void init() {
      pinMode (ledPin, OUTPUT);
    }
    void schalten() {
      if ( !Schaltzeit.running() ) {
        randomSeed(analogRead(randomPin));
        if (digitalRead(ledPin)) {
          Schaltzeit.setTime( random(minAus, maxAus) );
          digitalWrite(ledPin, LOW);
        } else {
          Schaltzeit.setTime( random(minAn, maxAn) );
          digitalWrite(ledPin, HIGH);
        }
      }
    }
};
Zimmer zimmer[] = {
  // ledPin, minAn, maxAn, minAus, maxAus
  {2, 1000, 5000, 1000, 2000},  // erstes Zimmer; jedes weitere Zimmer eine Zeile
  {3, 1000, 2000, 5000, 10000}, // zweites Zimmer
  {4, 10, 500, 10, 100}         // Fernsehen
};

void setup() {
  for (Zimmer &z : zimmer) z.init();
}

void loop() {
  for (Zimmer &z : zimmer) z.schalten();
}

mastrolindo83: Ist dies möglich?

Ja, klar. Du musst dafür allerdings eine andere „Programmier-Strategie“ anwenden - einen „endlichen Automat“. Was mir dazu eingefallen ist, kannst Du hier lesen.

Wenn Du eine „LED-Klasse“ programmierst, kannst Du mehrere Instanzen (Ausprägungen/Exemplare einer Klasse) anlegen und hast dann in loop() z. B. nur noch solche Dinge stehen:

LED1.on();
LED2.off();
LED3.setPulse(30);

Wobei z. B. setPulse() angibt, dass eine LED mit Geschwindigkeit 30 pulsiert.

Gruß

Gregor

Besten Dank für die schnelle Hilfe.

Habe eure Codes getestet. Habe gestern noch lange getüftelt und gesucht.

Verwende nun folgenden Code

// LED Fire Effect

int ledPin1 = 10;
int ledPin2 = 9;
int ledPin3 = 11;

void setup()
{
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);
}

void loop() {
analogWrite(ledPin1, random(120)+135);
analogWrite(ledPin2, random(120)+135);
analogWrite(ledPin3, random(120)+135);
delay(random(100));
}

Dieser entspricht genau meiner Vorstellung und ist relativ einfach gehalten. Wer ein realistisches Kerzenflackern sucht ist hiermit bestens bedient.

Ich danke euch für eure rasche Unterstützung.

Gruss Enzo

mastrolindo83: Dieser entspricht genau meiner Vorstellung und ist relativ einfach gehalten. Wer ein realistisches Kerzenflackern sucht ist hiermit bestens bedient.

Schön, dass es jetzt so aussieht, wie Du es möchtest. Nur noch ein Tipp für künftige Sketches: Bemühe Dich, „hübschen“ Code zu schreiben - einheitliche Einrückungen, Klammersetzung usw.

Siehe hier. Bei der Fehlersuche ist das Gold wert.

Gruß

Gregor

Hallo,

hier mal ein anderer Ansatz mit einem Led-Stripe und FastLED. Der schon erwähnte objektorientierte Ansatz macht die Sache IMHO etwas übersichtlicher!

Als Beispiel 5 Led’s, die im eigenen Rhythmus flackern.

#include "BlinkFireMillis.h"
#include "CandleLight.h"

#define NUM_CANDLELIGHTS 5

CandleLight cl[NUM_CANDLELIGHTS];

void setup() { 
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);  
  
  // Jeder Led eine eigene Position im Stripe zuweisen 
  for(auto i = 0; i < NUM_CANDLELIGHTS; ++i)
    cl[i].number(i);    
  
  // Den Zufallsgenerator mit einem variablen Startwert aus dem immer vorhandenen anlogen 
      Rauschen versorgen. Kann man bei dieser Anwendung auch weglassen.
  randomSeed(analogRead(0)); 
}

void loop() { 
  // Alle Led's im eigenen Rhythmus flackern lassen
  for(auto i = 0; i < NUM_CANDLELIGHTS; ++i)
    cl[i].flickering();
  FastLED.show();
}
#ifndef BlinkFireMillis_h
#define BlinkFireMillis_h

#include <arduino.h>
#include "FastLED.h"

// How many leds in your strip?
#define NUM_LEDS 5

#define DATA_PIN 6

// Define the array of leds
CRGB leds[NUM_LEDS];

#endif
#ifndef CandleLight_h
#define CandleLight_h

#include "BlinkFireMillis.h"

class CandleLight {
 private:

  uint8_t _number;                               // Position in der Stripe, beginnend mit  0               
  unsigned long _beginIntervall = 0;             // Start eines neuen Intervalls in Millisekunden 
  long _lightIntervallLength;                    // die Länge eines aktuellen Intervalls
  uint8_t _newBrightness;                        // die neue Endhelligkeit beim Fading
  CRGB _color;

  public:
  CandleLight() : CandleLight(0, CRGB::OrangeRed) { 
  }  
  
  CandleLight(uint8_t number, CRGB color) {
    _number = number;                      
    _color = color;    
  }

  void number(uint8_t number)
  {
    _number = number;
  }

  // Falls du die Farben der Led's anpassen möchtest  
  void color(CRGB color) 
  {
    _color = color;
  }
  
  void flickering() {   
    if (millis() > _beginIntervall + _lightIntervallLength) {
        _newBrightness = random(30,100);
        _lightIntervallLength = random(200,500);
        leds[_number] = _color;                           // Die Brightness zurücksetzten, sonst geht sie -> 0
        leds[_number] %= _newBrightness*256/100;                
        _beginIntervall = millis();
    }  
  }
};

#endif

LG Thomas

Hi

Ungetestet, sehe aber einen Stolperstein:

void flickering() {   
    if (millis() > _beginIntervall + _lightIntervallLength) {

Was passiert, wenn 'kurz vor Überlauf' mit dem Intervall begonnen wird und millis() bestenfalls den Endzeitpunkt treffen kann? Jupp - diese IF greift NIE WIEDER. Besser

if (millis()-_beginIntervall>_lightIntervallLenght){

Macht scheinbar das Gleiche, überlebt aber auch, wenn der Arduino Mal 'etwas länger an ist'.

MfG

Jupp - diese IF greift NIE WIEDER.

Prinzipiell richtiger Einwand. Man sollte sich einfach die richtige Schreibweise angewöhnen.

“NIE WIEDER” ist allerdings übertrieben. Im Überlauf ist _beginIntervall + _lightIntervallLength nur noch knapp > 0, und das if kommt (einmal alle 49 Tage) etwas zu früh.

Problematischer ist es, wenn der Sketch wegen delay() o.ä. nicht jede MilliSekunde mindestens einmal drankommt. Dann kann millis() schonmal überlaufen, ohne die > - Bedingung erwischt zu haben.

Auch großes Pech hat man, wenn beginIntervall + _lightIntervallLength  == ULONG_MAX wird. Dann wäre das generell richtigere >= sogar mal nötig.

Wenn schon pingelig, dann richtig.

Aber wie eingangs bestätigt, die richtige Schreibweise ist einfach

if ( millis() - _beginInterval >= _intervallLength)

Hi

Wenn millis() bestenfalls den Endzeitpunkt treffen kann, aber auf GRÖSSER abgefragt wird, trifft die IF NIE WIEDER - da größer als 0xFFFFFFFF geht halt nicht.
Ok, fast wie Lotto, aber ab und zu ist mir bewusst, was ich schreibe :wink:
Genau Deine Ausführung, dort mit >=, liegen Dem zugrunde.

Bei der ‘richtigen Schreibweise’ geht auch ein > - es sei, man will ULONG_MAX warten - wir schweifen ab …

MfG