WS2812 per FastLED: Keine PinMode- Deklarierung möglich?

Hallo!

Ich bin Moritz, neu hier mit Uno R3, und gleich eine Frage:

Ich möchte eine LED- Animation mittels WS2812- Clone (PL9823) realisieren, die sich an einem Eingangs- Tastsignal orientieren soll (Signal am Taster -> LEDs leuchten auf). Die WS2811- Ansteuerung mittels FastLED- Library sowie die Abfrage eines Eingangspins mit Pullup funktionieren jede für sich, und seit neuestem auch zusammen.
Die gewünschte Tastendruck- confirm- Funktion per Onboard- LED an Pin 13 funktioniert prinzipiell auch, aber nur, wenn ich im Code alles FastLED- Betreffende auskommentiere. Mit den Zeilen
void setup() {

  • FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);*
  • FastLED.addLeds(leds, NUM_LEDS); *
    }
    scheint die Tasterdruckbestätigung wie ausgeschaltet; dafür funktioniert die Ansteuerung des WS2811.

Wer kennt sich mit der FastLED- Library aus? Eliminiert diese die Ausgabe per Digitalpin? Findet jemand den Fehler?

Würde mich sehr über Hilfestellungen freuen.
Gruß,
Moritz

Folgend mein kompletter Code:

#include <Bounce2.h>
#include <FastLED.h>

#define NUM_LEDS 61                             // definiert globalen Platzhalter(?) NUM_LEDS für FastLED
#define DATA_PIN 7                              // definiert globalen Platzhalter(?) DATA_PIN für FastLED
#define BUTTON_PIN 8                            // definiert globalen Platzhalter(?) BUTTON_PIN für Bounce2
#define LED_PIN 13                              // definiert globalen Platzhalter(?) LED_PIN für Bounce2

CRGB leds[NUM_LEDS];
Bounce debouncer = Bounce();


void setup() {

  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  FastLED.addLeds<APA102>(leds, NUM_LEDS); 
 
  pinMode(LED_PIN, OUTPUT);                      // LED- Pin als Output definiert (LED an Pin13)
  pinMode(BUTTON_PIN, INPUT);                    // Button- Pin als Input definiert
  pinMode(BUTTON_PIN, INPUT_PULLUP);             // aktiviert Pullup- Widerstand an Pin7, genauso wie "digitalWrite(8, HIGH);"
}

void loop() {

// Variablen- Initialisierung
  int count;
  int del = 10;
  static int nr_Led;

  debouncer.update();
  int tast = digitalRead(BUTTON_PIN);
 
  if ( tast == LOW ) {
    digitalWrite(LED_PIN, HIGH);            // LED an Pin13 ON als confirm, das funktioniert NICHT
    delay(50);
    digitalWrite(LED_PIN, LOW);

    nr_Led++;
  }
  else {
    digitalWrite(LED_PIN, LOW);
  }

// Einzel- LED- RGB- Durchlauf
  for (count; count < nr_Led; count++){

// lokale Variablen- Initialisierung, nur in dieser for- Schleife
    int r = 0;
    int g = 0;
    int b = 0;
    int steps = 10;
  
//Auf- Dimmen
    for(r; r < 255; r=r+steps){
      leds[nr_Led].setRGB(r, g, b);
      FastLED.show();
      delay(del);
    }
    for(g; g < 255; g=g+steps){
      leds[nr_Led].setRGB(r, g, b);
      FastLED.show();
      delay(del);
    }
    for(b; b < 255; b=b+steps){
      leds[nr_Led].setRGB(r, g, b);
      FastLED.show();
      delay(del);
    }

//Ab- Dimmen  
    for(r; r > 0; r=r-steps){
      leds[nr_Led].setRGB(r, g, b);
      FastLED.show();
      delay(del);
    }
    for(g; g > 0; g=g-steps){
      leds[nr_Led].setRGB(r, g, b);
      FastLED.show();
      delay(del);
    } 
    for(b; b >= 0; b=b-steps){
      leds[nr_Led].setRGB(r, g, b);
      FastLED.show();
      delay(del);
    }
  }
}

Schreibe nicht blockierenden Code. Die Abfrage deines Tasters erfolgt nur alle ~15 Sekunden

Das delay() ist wie gesagt dein Hauptproblem.

Aber du verwendest auch die Bounce Library falsch. Schau dir mal die Beispiele dazu an:
https://github.com/thomasfredericks/Bounce2/blob/master/examples/bounce/bounce.ino

Du musst schon nach dem Update den Zustand auch aus dem bouncer Objekt lesen. Nicht von digitalRead():

int value = debouncer.read();

Außerdem fehlt auch das attach() wo dem Objekt überhaupt sagst mit welchem Pin es verbunden ist

Das merkst du nur nicht weil du den Taster im Moment über das delay() entprellst

Man kann mit der FastLED Lib "normales" Pinmode nutzen du darfst nur keine delays nutzen die blockiern dir den ganzen Code. Bei meiner (Code bzw Thread hier im Forum) läuft es auch wunderbar also liegt der Hund eher in deinem Code begraben. Ich weiß nicht wie die Debounce Lib evtl dir die Timer versaut keine Ahnung nutzte ich auch nicht.
Hier findest du am Ende (unten) auch meinen Code zusammen mit 114 WS2812B LED. Dort habe ich auch 4 Taster (Reeds) genommen mit der Flanken erkennung kannst du auch sehr gut arbeiten dann braucht man keinen Debounce mehr. Das sich steigende Flanken zusammen mit dem Prellen treffen habe ich bisher nicht oder wenn dann nur in extrem seltenen Fällen gehabt, die dann auch nicht sichtbar waren.

Gruß
DerDani

Hallo!

Man dankt für die Unterstützung.
Ich habe versucht, mich an die Vorlage "bounce.ino" zu halten, aber die Zeilen mit "attach" und "interval" sind wohl verlorengegangen. Und dass der Debouncer auch eine eingebaute Read- Funktion hat, macht die Lage schon besser.
Kein delay(), soweit habe ich das jetzt verstanden. Wobei ich noch forschen muss, was denn als Alternative in Frage kommt.

Ich habe die LED- Ansteuerung nun einfach auf

leds[nr_Led].setRGB(0, 255, 0);
FastLED.show();

zusammengestrichen, allerdings ist auch hierbei keine Beträtigung durch Aufleuchten der integrierten LED an Pin13 zu erkennen. Das kann doch nicht allein an der Delay- Funktion liegen?!

Danke, Gruß

ein LED 50mS aufleuchten Lassen ist schon wenig.
Verlängere mal probeweise auf 1000

Grüße Uwe

Hi,

ein Verlängern des LED-Leucht- Delays ist weniger, was ich will. Es verlängert jedoch auch nur das Tastenabfrage- Intervall. Der Code bleibt spürbar länger hängen, aber trotzdem leuchtet die Pin13- LED während dieser Zeit nicht.
Beim Blinky blinkt sie aber nach wie vor, ist also nicht defekt. Auch eine parallele Breadboard- LED leuchtet nur, wenn das Onboard- Pendant es tut, also nicht in Verwendung mit FastLED.

Jetzt habe ich auf ein LED- Blinken durch Mitzählen mittels millis() umgestellt: Keine Veränderung.
Wenn ich die bekannten FastLED-Zeilen auskommentiere, blinkt die LED, wenn ich sie reinnehme, funktionieren die WS2811, die confirm- LED bleibt dunkel.
Ich wage zu behaupte, es liegt nicht an der delay()- Funktion, sondern die FastLED-Library lässt dieses nicht zu.

Wie denn sonst? Per ISR? Hält diese, wenn sie ausgeführt wird (d.h. wenn die LED blinkt), den Hauptcode nicht genauso auf?

Freue mich, wenn mich wer vom Gegenteil überzeugt.

Gruß,
Moritz

#include <Bounce2.h>
#include <FastLED.h>

#define NUM_LEDS 61                             // definiert globalen Platzhalter NUM_LEDS für FastLED
#define DATA_PIN 7                              // definiert globalen Platzhalter DATA_PIN für FastLED
#define BUTTON_PIN 8                            // definiert globalen Platzhalter BUTTON_PIN für Bounce2
#define LED_PIN 13                              // definiert globalen Platzhalter LED_PIN für Bounce2

bool ledState = LOW;
long previousMillis = 0;   
long blink_interval = 100; 

CRGB leds[NUM_LEDS];
Bounce debouncer = Bounce();


void setup() {

  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  FastLED.addLeds<APA102>(leds, NUM_LEDS); 

  debouncer.attach(BUTTON_PIN);
  debouncer.interval(15);                        // Entprell- Intervall in ms
 
  pinMode(LED_PIN, OUTPUT);                      // LED- Pin als Output definiert (LED an Pin13)
  pinMode(BUTTON_PIN, INPUT);                    // Button- Pin als Input definiert
  pinMode(BUTTON_PIN, INPUT_PULLUP);             // aktiviert Pullup- Widerstand an Pin7
}

void loop() {

// Variablen- Initialisierung
  int count;
  int del = 10;
  static int nr_Led;
  unsigned long currentMillis = millis();

  debouncer.update();
  bool tast = debouncer.read();
 
  if(tast == LOW){                               //falls Taster gedrückt (active- low):
    nr_Led++;                                   // zählt nr_LED einen rauf
    
    if(currentMillis - previousMillis > blink_interval) {
      previousMillis = currentMillis;            // Übertrag speichern

      if (ledState == LOW)                       // invertiert LED- Status
        ledState = HIGH;
      else
        ledState = LOW;

      digitalWrite(LED_PIN, ledState);            // stellt LED- Status dar
    }
  }
  else digitalWrite(LED_PIN, LOW);                // schaltet LED aus, falls Taster nicht gedrückt
  
// Einzel- LED- Durchlauf
  for (count; count < nr_Led; count++){       //alle LEDs bis inkl. der aktuellen

      leds[(nr_Led-1)].setRGB(0, 255, 0);       //auf grün setzen
      FastLED.show();                                 //und anzeigen
  }
}

Das Sperren der Interrupts durch die FastLED Lib kann da wieder mal Ärger machen

Benutzt die Bounce Lib Interrupts?

FastLED sperrt selbige - allerdings nur während FastLED.show();

Beim zuletzt geposteten Code fällt mir auf, dass FastLED.show(); nach dem Setzen jeder einzelnen LED aufgerufen wird. Das ist Quatsch, man pusht die Daten einmal, nachdem man das komplette Frame - also alle LEDs geschrieben hat.

FastLED.show(); nur einmal NACH der Schleife aufrufen.

Und eventuell mal Alterativen zum Entprellen überdenken bzw. selber schreiben.

Und warum

FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);

UND

FastLED.addLeds<APA102>(leds, NUM_LEDS);

?

Wenn WS2811, dann ist die zweite Zeile Unsinn.

Helmuth:
Benutzt die Bounce Lib Interrupts?

Indirekt über millis(). Dadurch sollte es eigentlich nur Probleme machen wenn mehr als 1ms vergeht.

Aber ich denke es ist eher wie du sagst, dass show() in der for-Schleife ständig aufgerufen wird und dadurch vielleicht zu lange dran ist.

Und der doppelte addLeds Aufruf sorgt zusätzlich dafür, dass ein einzelnes show doppelt so lange wie nötig dauert, weil alle Daten 2 Mal nacheinander (wir reden über AVR, richtig?) und eben nicht parallel gesendet werden: einmal an Pin 7 und dann nocheinmal an die Hardware-SPI Pins...

Das einzige "Problem", welches ich mit millis() plus FastLED kenne, ist, dass die Zeit langsam wegdriftet bzw. dass eine ms keine exakte ms mehr ist. War sie aber vorher auch nicht wirklich. :wink:

Helmuth:
Das einzige "Problem", welches ich mit millis() plus FastLED kenne, ist, dass die Zeit langsam wegdriftet bzw. dass eine ms keine exakte ms mehr ist.

Das kann daher kommen dass der Timer zwar das Overflow Interrupt Flag setzt, aber es durch das deaktivierte globale Interrupt Enable Flag nicht gleich abgearbeitet wird wenn gerade show() aktiv ist. Wenn die Interrupts dann wieder aktiviert werden werden anstehende Interrupts bearbeitet, aber eben später als sie eigentlich ausgelöst wurden.

Und eventuell mal Alterativen zum Entprellen überdenken bzw. selber schreiben.

Einen Hardwarepullup mit 10k und parallel dazu einen 100nF - und du braucht keine Bounce Lib mehr.

Keine verkehrte alternative Möglichkeit mit dem 10kR + 100nF. Es funktioniert, ist im großen Maßstab unwirtschaftlich, was hier ja wohl nicht der Fall ist.

Wenn dir die Pins ausgehen, kann man auch über einen alternativen Controller nachdenken. Der Atmega644P/1284P/ .... ist auch als Dip Variante verfügbar. Quarz, 4 Kerkos und ein 10k PullUp reichen in der Minimalbeschaltung.

Hallo!

Danke an alle. Ich bin schon ein ganzes Stück weiter, und es hat sich einiges geklärt.

Das mit
FastLED.addLeds(leds, NUM_LEDS);
war natürlich Blödsinn. Ich hatte es bei der ersten Beschäftigung mit FastLib so übernommen, weil ich dachte, es gehört dazu...

Mittlerweile funktioniert die Tastenbestätigung per LED. Mit der Millis()- Alternative zu delay bin ich noch nicht so richtig warm geworden, aber mal schauen...

Die Idee mit dem Hardwarepullup mit 10k und parallel dazu einen 100nF ist gut. Es geht um ein Einzelstück, und so kann ich den Code angenehm klein halten.

Weitere Fragen kommen bestimmt noch.

Gruß,
Moritz

Das mit dem Fade und Millis kann man recht einfach lösen. Hier mal aus einem aktuellen Projekt.

/* Rueckgabewerte :
0 = Vorgang nicht abgeschlossen
1 = Wert 255 erreicht
2 = Wert 0 erreicht
uint8_t fade(uint8_t *value, int8_t *reverse)
{
  if (*reverse == 0)
  {
    if (*value < 255) (*value)++;
    else
    {
      *reverse = 1;
      (*value)--;
      return 1;
    }
  }
  else
  {
    if (*value > 0) (*value)--;
    else
    {
      *reverse = 0;
      (*value)++;
      return 2;
    }
  }
  return 0;
}

Die Funktion einfach je nach Fadedauer alle x ms aufrufen.