WS2812B Effekte über Taster steuern

Guten Abend,

ich versuche mich zur Zeit an einem Projekt mit den WS2812B.
Im Prinzip nutze ich 2 Taster. Mit dem Haupttaster (button2) soll es möglich sein zwischen verschiedenen "Effekten" zu wechseln. Per default soll der "Effekt" "StaticStripColor" laufen und der Streifen immer gelb leuchten. Der button1 soll hierbei die Farbe der LEDs wechseln. Durch drücken des button2 soll dann der "Effekt" gewechselt.
Nun das Problem. Nach drücken des button2 wechselt der Effekt, doch bleibt dann stecken. Im SerialMonitor wird dann auch nur noch "Modus 1" ausgegeben. Egal wie oft ich den button2 drücke, die Loop bleibt beim Effekt stecken.

Die Effekte funktionieren einzeln. Außerdem habe ich die Effekte einmal auskommentiert und nur im SerialMonitor den aktuellen Status des buttonCounters ausgeben. Das funktioniert auch.

Kann mir bitte jemand dabei helfen meinen Fehler zu finden? Bin für anderweitige Änderungsvorschläge natürlich offen.

LG, Carlos

#include <Adafruit_NeoPixel.h>

#define PIN_LEDs_strip    6    //arduino pin to send data to the LED_strip
#define NUMPIXELS_strip  14   //amount of LEDs on the strip

// initialize the LED strip
Adafruit_NeoPixel pixels1(NUMPIXELS_strip, PIN_LEDs_strip, NEO_GRB + NEO_KHZ800);

// variables to use button1
int button1 = 2;                 // button 1 is connected to pin 2 of the arduino
int pinState1;                   // pin status variable
int buttonState1;                // last button status variable
int buttonCounter1 = 0;          // counts the times how often the button was pressed

// variables to use button2
int button2 = 13;                 // button 2 is connected to pin 13 of the arduino
int pinState2;                   // pin status variable
int buttonState2;                // last button status variable
int buttonCounter2 = 0;          // counts the times how often the button was pressed


void setup() {

  //Setup for LED strip
  pixels1.begin();             // start the LED strip
  pixels1.setBrightness(10);       // set the brightness 0....255

  // Setup for button1: basically to change the color of the strip
  pinMode(button1, INPUT);               // set button1 as input
  buttonState1 = digitalRead(button1);   // read the beginning status of button1

  // Setup for button2: basically to change the effect of the strip
  pinMode(button2, INPUT);               // set button2 as input
  buttonState2 = digitalRead(button2);   // read the beginning status of button2

  Serial.begin(9600);                     // start the serial communication with 9600bps


}



void loop() {


  pinState1 = digitalRead(button1);           // read out the button1 and save the pin state
  pinState2 = digitalRead(button2);           // read out the button2 and save the pin state

  if (pinState2 != buttonState2) { // status of the button has changed

    if (pinState2 == LOW) {          // asks if the is pressed

      buttonCounter2++;              // variable buttonCounter counts up by 1
      Serial.print("Modus: ");
      Serial.println(buttonCounter2);
    }


  }
  buttonState2 = pinState2;      // save the status


  switch (buttonCounter2) {

    case 1: CylonBounce(255, 0, 0, 2, 10, 50);
      delay(100);
      break;
    case 2: RunningLights(255, 0, 0, 50);
      delay(100);
      break;
    case 3: SnowSparkle(0, 255, 0, 20, random(100, 1000));
      delay(100);
      break;
    case 4: RGBLoop();
      delay(100);
      break;
    default: staticStripColor();
      delay(100);
      buttonCounter2 = 0;
      break;



  }

}

void setPixel(int Pixel, byte red, byte green, byte blue) {

  pixels1.setPixelColor(Pixel, pixels1.Color(red, green, blue));

}
void setAll(byte red, byte green, byte blue) {

  pixels1.clear();
  for (int i = 0; i < NUMPIXELS_strip; i++) {

    setPixel(i, red, green, blue);

  }
  pixels1.show();
  delay(100);

}


// ----- Effekte -----

void staticStripColor() {


  if (pinState1 != buttonState1) {   // status of the button has changed

    if (pinState1 == LOW) {          // asks if the is pressed

      buttonCounter1++;              // variable buttonCounter counts up by 1
      Serial.print("Color: ");
      Serial.println(buttonCounter1);
    }

  }
  buttonState1 = pinState1;      // save the status


  switch (buttonCounter1) {

    case 1: setAll(255, 0, 0); //red
      break;
    case 2: setAll(0, 255, 0); //green
      break;
    case 3: setAll(0, 0, 255); //blue
      break;
    case 4: setAll(255, 0, 255); //magenta
      break;
    case 5: setAll(0, 255, 255); //cyan
      break;
    case 6: setAll(255, 255, 255); //whitw
      break;
    default: setAll(255, 255, 0); //yellow
      buttonCounter1 = 0;
      break;

  }
}

void RGBLoop() {
  
  for (int j = 0; j < 3; j++ ) {
    // Fade IN
    for (int k = 0; k < 256; k++) {
      switch (j) {
        case 0: setAll(k, 0, 0); break;
        case 1: setAll(0, k, 0); break;
        case 2: setAll(0, 0, k); break;
      }
      pixels1.show();
      delay(3);
    }
    // Fade OUT
    for (int k = 255; k >= 0; k--) {
      switch (j) {
        case 0: setAll(k, 0, 0); break;
        case 1: setAll(0, k, 0); break;
        case 2: setAll(0, 0, k); break;
      }
      pixels1.show();
      delay(3);
    }
  }
}

void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {

  
  for (int i = 0; i < NUMPIXELS_strip - EyeSize - 2; i++) {
    setAll(0, 0, 0);
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    pixels1.show();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);

  for (int i = NUMPIXELS_strip - EyeSize - 2; i > 0; i--) {
    setAll(0, 0, 0);
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    pixels1.show();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);
}

void SnowSparkle(byte red, byte green, byte blue, int SparkleDelay, int SpeedDelay) {

  
  setAll(red, green, blue);
  int Pixel = random(NUMPIXELS_strip);
  setPixel(Pixel, 0xff, 0xff, 0xff);
  pixels1.show();
  delay(SparkleDelay);
  setPixel(Pixel, red, green, blue);
  pixels1.show();
  delay(SpeedDelay);
}

void RunningLights(byte red, byte green, byte blue, int WaveDelay) {

  
  int Position = 0;

  for (int j = 0; j < NUMPIXELS_strip * 2; j++)
  {
    Position++; // = 0; //Position + Rate;
    for (int i = 0; i < NUMPIXELS_strip; i++) {

      setPixel(i, ((sin(i + Position) * 127 + 128) / 255)*red,
               ((sin(i + Position) * 127 + 128) / 255)*green,
               ((sin(i + Position) * 127 + 128) / 255)*blue);
    }

    pixels1.show();
    delay(WaveDelay);
  }
}

Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden.
Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.
mfg ein Moderator.

Servus, dankeschön. Das wusste ich nicht, aber Danke vielmals!

Setz das mal 2 Zeile höher, zwischen die

   }


  }

Hallo, brachte leider nicht den gewünschten Erfolg.

Ich würde mal vermuten, dass Dir Deine delay(xxx) in den Aktionen auf die Füße fallen.
Setze die Zeitsteuerung besser mit millis() um (verstehe das Beispiel BilinkWithoutDelay in der IDE und lies die Nachtwächtererklärung)

Gruß Tommy

Danke für deine Antwort, werde dem einmal nachgehen. LG Carlos

Aus meiner Sicht ist der irgendwie komplett vermurkst.
Wenn Du den Counterwechsel merkst und dann sofort eine Funktion aufrufst, warum schreibst Du Dir da nicht in die Funktion ne Handvoll debug-Zeilen?
Du musst doch einfach nur raus bekommen, wo es klemmt!?

Hallo, bin leider noch recht unerfahren. Meinst du damit, dass ich innerhalb der Funktion zB. den aktuellen Wert, oder Status in den SerialMonitor schreiben soll?
LG, Carlos

14 Stück WS2812 braucht es weiß, 840mA, zuviel für USB.

Grüße Uwe

Hallo, danke für deine Antwort. Im Aufbau ist der Streifen extra versorgt. Das angehängte Bild ist nur aus TinkerCad und soll den Aufbau skizzieren. LG Carlos

Egal was - hauptsache irgendwas, damit Du erstmal in die Verlegenheit kommst, den Punkt zu finden, wo es hängt.

void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay)
{
  Serial.println(F("CyclonBounce aufgerufen"));
  for (int i = 0; i < NUMPIXELS_strip - EyeSize - 2; i++)
  {
    Serial.println(F("Rufe setAll"));
    setAll(0, 0, 0);
    Serial.println(F("Zurück aus setAll - setze Pixel"));
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++)
    {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    pixels1.show();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
  for (int i = NUMPIXELS_strip - EyeSize - 2; i > 0; i--)
  {
    setAll(0, 0, 0);
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++)
    {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    pixels1.show();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
}
  • Ich glaub Uwe war schneller ... :slight_smile:

Guten Morgen,

habe es jetzt einmal versucht umzusetzen.

void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {

  Serial.println(F("CyclonBounce aufgerufen"));
  for (int i = 0; i < NUMPIXELS_strip - EyeSize - 2; i++) {
    Serial.println(F("Alle Pixel werden gesetzt"));
    setAll(0, 0, 0);
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    Serial.println(F("Pixel werden ausgegeben"));
    pixels1.show();
    delay(SpeedDelay);
  }
Serial.println(F("Halb durch"));
  delay(ReturnDelay);

  for (int i = NUMPIXELS_strip - EyeSize - 2; i > 0; i--) {
    Serial.println(F("Alle Pixel werden erneut gesetzt"));
    setAll(0, 0, 0);
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    Serial.println(F("Pixel werden ausgegeben"));
    pixels1.show();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);
  Serial.println(F("durch"));
}

Das läuft durch, endlos.

Habe dann versucht mit setAll einfach eine andere Farbe auszugeben. Und das funktioniert.

  switch (buttonCounter2) {
 
    case 1: setAll(255, 0, 0); //red //CylonBounce(255, 0, 0, 2, 10, 50);
      delay(100);
      break;
    case 2: setAll(0, 255, 0); //green //RunningLights(0, 0, 255, 50);
      delay(100);
      break;
    case 3: setAll(0, 255, 255); //cyan //SnowSparkle(0, 255, 0, 20, random(100, 1000));
      delay(100);
      break;
    case 4: setAll(255, 0, 255); //magenta //RGBLoop();
      delay(100);
      break;
    default: staticStripColor();
      delay(100);
      buttonCounter2 = 0;
      break;



  }

}

Das Problem liegt dann wohl in den loops der Effekten. Mir ist im SerialMonitor dann aufgefallen, dass ein Tastendruck die loop nicht beendet bzw. der Taster nicht ausgelesen wird.

Könnte darin das Problem?

LG, Carlos

Die LED-Animation Funktionen werden durch For-Schleifen dein Code blockieren. Wie sieht denn der Code der Funktionen aus?

Hallo Plumps, danke für deine Antwort.

Hier sind die Animationen, die for-Schleifen verwenden. Die Animationen an sich habe ich alle einzeln getestet und die haben funktioniert. Der Wechsel der Animation durch den Tastendruck funktioniert nicht.

Diese sollte den ganzen Streifen rot, dann grün und dann blau leuchten lassen

void RGBLoop() {
  
  for (int j = 0; j < 3; j++ ) {
    // Fade IN
    for (int k = 0; k < 256; k++) {
      switch (j) {
        case 0: setAll(k, 0, 0); break;
        case 1: setAll(0, k, 0); break;
        case 2: setAll(0, 0, k); break;
      }
      pixels1.show();
      delay(3);
    }
    // Fade OUT
    for (int k = 255; k >= 0; k--) {
      switch (j) {
        case 0: setAll(k, 0, 0); break;
        case 1: setAll(0, k, 0); break;
        case 2: setAll(0, 0, k); break;
      }
      pixels1.show();
      delay(3);
    }
  }
}

Bei der nächsten Animation sollte ein kleiner Streifen an LEDs (ähnlich wie bei KITT aus Knight Rider) über den gesamten Streifen hin und her laufen.

void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay) {

  Serial.println(F("CyclonBounce aufgerufen"));
  for (int i = 0; i < NUMPIXELS_strip - EyeSize - 2; i++) {
    Serial.println(F("Alle Pixel werden gesetzt"));
    setAll(0, 0, 0);
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    Serial.println(F("Pixel werden ausgegeben"));
    pixels1.show();
    delay(SpeedDelay);
  }
Serial.println(F("Halb durch"));
  delay(ReturnDelay);

  for (int i = NUMPIXELS_strip - EyeSize - 2; i > 0; i--) {
    Serial.println(F("Alle Pixel werden erneut gesetzt"));
    setAll(0, 0, 0);
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    Serial.println(F("Pixel werden ausgegeben"));
    pixels1.show();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);
  Serial.println(F("durch"));
}

Bei dieser Animation sollen alle LEDs weiß leuchten und dann einzelne per Zufall eine heller leuchten.

void SnowSparkle(byte red, byte green, byte blue, int SparkleDelay, int SpeedDelay) {

  
  setAll(red, green, blue);
  int Pixel = random(NUMPIXELS_strip);
  setPixel(Pixel, 0xff, 0xff, 0xff);
  pixels1.show();
  delay(SparkleDelay);
  setPixel(Pixel, red, green, blue);
  pixels1.show();
  delay(SpeedDelay);
}

Beim folgenden Effekt laufen immer mehrere LEDs quasi als Gruppe über den Streifen.

void RunningLights(byte red, byte green, byte blue, int WaveDelay) {

  
  int Position = 0;

  for (int j = 0; j < NUMPIXELS_strip * 2; j++)
  {
    Position++; // = 0; //Position + Rate;
    for (int i = 0; i < NUMPIXELS_strip; i++) {

      setPixel(i, ((sin(i + Position) * 127 + 128) / 255)*red,
               ((sin(i + Position) * 127 + 128) / 255)*green,
               ((sin(i + Position) * 127 + 128) / 255)*blue);
    }

    pixels1.show();
    delay(WaveDelay);
  }
}

Nur als Beispiel:

Diese Schleife blockiert für 3 x 2 x 256 x 3 Millissekunden = ~4,8Sekunden deinen Code. In der Zeit kannst du auf keine Taster oder ähnliches reagieren. Das musst du anders lösen, wenn du auf Taster oder ähnliches reagieren willst.

Hallo,
also denkst du ich sollte de Animationen generell überarbeiten, oder es mal mit dem Vorschlag von Tommy56 mit millis() anstatt der delays versuchen?

Ja, aber beides.

Ein ausbaufähiger Vorschlag (geänderte Pinnummern!):

#include <Adafruit_NeoPixel.h>

#define PIN_LEDs_strip   12   //arduino pin to send data to the LED_strip
#define NUMPIXELS_strip  14   //amount of LEDs on the strip

// initialize the LED strip
Adafruit_NeoPixel pixels1(NUMPIXELS_strip, PIN_LEDs_strip, NEO_GRB + NEO_KHZ800);

// variables to use button1
uint8_t button1 = 2;              // button 1 is connected to pin 2 of the arduino
bool pinState1;                   // pin status variable
bool buttonState1;                // last button status variable
uint8_t buttonCounter1 = -1;      // counts the times how often the button was pressed

// variables to use button2
uint8_t button2 = 4;              // button 2 is connected to pin 13 of the arduino
bool pinState2;                   // pin status variable
bool buttonState2;                // last button status variable
uint8_t buttonCounter2 = -1;      // counts the times how often the button was pressed


void setup() {
  //Setup for LED strip
  pixels1.begin();                 // start the LED strip
  pixels1.setBrightness(255);       // set the brightness 0....255
  pixels1.show();

  // Setup for button1: basically to change the color of the strip
  pinMode(button1, INPUT_PULLUP);               // set button1 as input
  buttonState1 = digitalRead(button1);   // read the beginning status of button1

  // Setup for button2: basically to change the effect of the strip
  pinMode(button2, INPUT_PULLUP);               // set button2 as input
  buttonState2 = digitalRead(button2);   // read the beginning status of button2

  Serial.begin(115200);                     // start the serial communication with 9600bps
  delay(1000);
  Serial.println("\nStart");
}

void loop() {
  buttonState1 = pinState1;
  buttonState2 = pinState2;
  pinState1 = digitalRead(button1);           // read out the button1 and save the pin state
  pinState2 = digitalRead(button2);           // read out the button2 and save the pin state
  bool neu = false;

  if (pinState2 != buttonState2) {   // status of the button has changed
    if (!pinState2) {                // asks if the is pressed
      buttonCounter2++;              // variable buttonCounter counts up by 1
      Serial.print("Modus: ");
      Serial.println(buttonCounter2);
      delay(100);                    // Entprellen
    }
  }

  switch (buttonCounter2) {
    case 1: neu |= CylonBounce(255, 0, 0, 2, 10, 50);
      break;
    /*
      case 2: RunningLights(255, 0, 0, 50);
      break;
      case 3: SnowSparkle(0, 255, 0, 20, random(100, 1000));
      break;
      case 4: RGBLoop();
      break;
    */
    default: neu |= staticStripColor();
      buttonCounter2 = 0;
      break;
  }

  if (neu) pixels1.show();
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
  pixels1.setPixelColor(Pixel, pixels1.Color(red, green, blue));
}

// ----- Effekte -----

bool staticStripColor() {
  if (pinState1 != buttonState1) {   // status of the button has changed
    if (!pinState1) {                // asks if the is pressed
      buttonCounter1++;              // variable buttonCounter counts up by 1
      Serial.print("Color: ");
      Serial.println(buttonCounter1);
    }
  }

  switch (buttonCounter1) {
    case 1: pixels1.fill(pixels1.Color(255, 0, 0)); //red
      break;
    case 2: pixels1.fill(pixels1.Color(0, 255, 0)); //green
      break;
    case 3: pixels1.fill(pixels1.Color(0, 0, 255)); //blue
      break;
    case 4: pixels1.fill(pixels1.Color(255, 0, 255)); //magenta
      break;
    case 5: pixels1.fill(pixels1.Color(0, 255, 255)); //cyan
      break;
    case 6: pixels1.fill(pixels1.Color(255, 255, 255)); //whitw
      break;
    default: pixels1.fill(pixels1.Color(255, 255, 0)); //yellow
      buttonCounter1 = 0;
      break;
  }
  return true;
}


bool CylonBounce(byte red, byte green, byte blue, const byte EyeSize, const uint16_t SpeedDelay, const uint16_t ReturnDelay) {
  uint32_t jetzt = millis();
  static uint32_t vorhin = 0;
  static uint16_t led = 0;
  static uint8_t schritt = 0;
  bool neu = false;

  switch (schritt) {
    case 0:
      if (jetzt - vorhin >= SpeedDelay) {
        vorhin = jetzt;
        pixels1.fill(pixels1.Color(0, 0, 0));
        setPixel(led, red / 10, green / 10, blue / 10);
        for (int j = 1; j <= EyeSize; j++) {
          setPixel(led + j, red, green, blue);
        }
        setPixel(led + EyeSize + 1, red / 10, green / 10, blue / 10);
        neu = true;
        if (led < NUMPIXELS_strip - EyeSize - 2) {
          led++;
        } else {
          schritt++;
        }
      }
      break;
    case 1:
      if (jetzt - vorhin >= ReturnDelay) {
        schritt++;
      }
      break;
    case 2:
      if (jetzt - vorhin >= SpeedDelay) {
        vorhin = jetzt;
        pixels1.fill(pixels1.Color(0, 0, 0));
        setPixel(led, red / 10, green / 10, blue / 10);
        for (int j = 1; j <= EyeSize; j++) {
          setPixel(led + j, red, green, blue);
        }
        setPixel(led + EyeSize + 1, red / 10, green / 10, blue / 10);
        neu = true;
        if (led > 0) {
          led--;
        } else {
          schritt = 0;
        }
      }
      break;
  }
  return neu;
}

Danke @agmue jetzt funktioniert jetzt wie es soll.
Werde die anderen Animationen noch anpassen, aber danke vielmals!

Aber würde noch gerne wissen warum die Pins zu ändern waren?

Bitte gerne!

Meine WS2815 hängen gerade an einem ESP32, deshalb habe ich mit dieser Konstellation getestet. Du kannst das gerne auf Deine Pins zurückändern.