NeoPixel Color Fade Problem

Hallo Leute!
Im Prinzip sollte das ja nicht unter Cross-posting fallen, aber ich verweise auch gern nochmal an meinen Beitrag im Programming-Questions Bereich NeoPixel Multi LED Controller

Ursprünglich ging es um das simultane Ansteuern von 2 NeoPixel Strips mit unabhängigen Tastern für jeweils Bewegungsmuster und Farbe.

Da ich dort aber überhaupt nicht weiter komme versuche ich nun erstmal einen Strip mit den gewünschten Funktionen anzusteuern.
Vermutlich sind meine Englischkenntnisse einfach zu schlecht um mein Vorhaben richtig erklären zu können.

Unabhängig davon ist das Problem auf das ich jetzt gestoßen bin:

der erste "Color-Fade Modus" den ich implementieren möchte:
Der ganze Strip (alle LEDs gleich) soll von Rot über Grün zu Blau wieder zu Rot durch alle Farben faden.

Bei mir fadet er nur von Rot nach Grün und fängt dann wieder bei Rot an.

Ich vermute, dass ich die Funktion Wheel() nicht entgültig verstanden habe.

Ich habe mal einen festen wert (170) an Wheel() übergeben.
Eigentlich sollte der 32bit Wert (130560) der von Wheel() zurückgegeben wird Blau sein.
Der Strip zeigt aber Grün an...

Ich habe den Code mal angehängt.
Wäre schön, wenn mir dazu jemand etwas sagen könnte :slight_smile:

#include <Adafruit_NeoPixel.h>

// Digital IO pin connected to the buttons.
#define BTN01_PIN   2  // This will be
#define BTN02_PIN   5  // driven with a pull-up resistor so the switch should
                      // pull the pin to ground momentarily.  On a high -> low
                      // transition the button press logic will execute.

// Digital IO pin connected to the NeoPixels.
#define PIXEL_PIN    6  // BOTTOM STRIP

// LED Anzahl
#define PIXEL_COUNT  8

// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_RGB     Pixels are wired for RGB bitstream
//   NEO_GRB     Pixels are wired for GRB bitstream, correct for neopixel stick
//   NEO_KHZ400  400 KHz bitstream (e.g. FLORA pixels)
//   NEO_KHZ800  800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

int modeType = 0;
int colrType = 0;

int pixelPos = 0;

int ledClock = 0;

bool oldState01 = HIGH;
bool oldState02 = HIGH;

uint32_t pixelColor = strip.Color(0, 0, 0);
byte color = 0;

void colorWipe(int strip, int color[]);
int pickcolor(int c);
uint32_t Wheel(byte WheelPos);

void setup() {

  pinMode(BTN01_PIN, INPUT_PULLUP);
  pinMode(BTN02_PIN, INPUT_PULLUP);
  Serial.begin(9600);
   
  strip.begin();
  strip.show();
}

void loop() {

  ledClock ++;                                                        //Clock to sync different speed rates of the modes

  if (ledClock > 1000)                                                //Clock Loop
    ledClock = 1;
  
  Serial.print("MODE: ");
  Serial.print(modeType);

  Serial.print("  |  COLR: ");
  Serial.print(colrType);

  Serial.print("  |  COLOR: ");
  Serial.print(color);
  
  Serial.print("  |  PIXEL: ");
  Serial.print(pixelPos);

  Serial.print("  |  pixel.Color: ");
  Serial.println(pixelColor);

  if(pixelPos == PIXEL_COUNT)
    pixelPos = 0;

  bool newState01 = digitalRead(BTN01_PIN);
  bool newState02 = digitalRead(BTN02_PIN);

  // Check if state changed from high to low (button press).
  if (newState01 == LOW && oldState01 == HIGH) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState01 = digitalRead(BTN01_PIN);
    if (newState01 == LOW) {
      colrType++;
      pixelPos = 0;
      if (colrType > 6)
        colrType=0;
    }
  }

  // Set the last button state to the old state.
  oldState01 = newState01;
  
  // Check if state changed from high to low (button press).
  if (newState02 == LOW && oldState02 == HIGH) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState02 = digitalRead(BTN02_PIN);
    if (newState02 == LOW) {
      modeType++;
      pixelPos = 0;
      if (modeType > 1)
        modeType=0;
    }
  }
  
  // Set the last button state to the old state.
  oldState02 = newState02;
  
    
  pickColor(colrType);                                               //Get Color for strip
  startShow(modeType);                                            //Start strip with selected Mode

}

void pickColor(int c) {                                   
  switch(c){
    
    case 0: {
      pixelColor = strip.Color(255, 0, 0);                         // RED
    }
      break;
    case 1: {
      pixelColor = strip.Color(0, 255, 0);                         // GREEN
    }
      break;
    case 2: {
      pixelColor = strip.Color(0, 0, 255);                         // BLUE
    }
      break;
    case 3: {
      pixelColor = strip.Color(255, 255, 255);                     // WHITE
    }
      break;
    case 4: {
      pixelColor = strip.Color(15, 04, 87);                       // rainbow      -> LATER
    }
      break;
    case 5: {
      Wheel(color) ;
      //Wheel(color & 255) ;                           // color fade
      color++;
    }
      break;
    case 6: {
      pixelColor = strip.Color(0, 0, 0);                           // Black/off
    }
      break;
  }
} 

void startShow(int mode) {
  switch(mode){
    case 0: {
      colorWipe();
    }
            break;
    case 1: {
      colorWipe();
    }
            break;
    case 2: {
      colorWipe();
    }
            break;
    case 3: {
      colorWipe();
    }
            break;
  }
}

// MODE 01 COLOR WIPE - FILL LEDS ONE AFTER THE OTHER-----------------------------------------------------------------------------------------------------------------
void colorWipe() {
  uint16_t i;
  for(i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, pixelColor);
  }
  strip.show();
}


//RAINBOW COLOR
/*void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}
/*

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

//Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
  for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}
*/
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte wheelPos) {
  wheelPos = 255 - wheelPos;
  if(wheelPos <= 85) {
    Serial.println("TEST bis 85!!!");
    pixelColor = strip.Color(255 - wheelPos * 3, 0, wheelPos * 3);  
  }
  if(wheelPos > 85 && wheelPos <= 170) {
    Serial.println("TEST 86 - 170!!!");
    wheelPos -= 85;
    pixelColor = strip.Color(0, wheelPos * 3, 255 - wheelPos * 3);
  }
  wheelPos -= 170;
  pixelColor = strip.Color(wheelPos * 3, 255 - wheelPos * 3, 0);
}

Was soll Wheel zurückgeben? Gibt es da in der Arduino IDE keine Compilerwarnung, dass der Compiler einen Rückgabewert erwartet, wenn es sich um eine nicht-void Funktion handelt?

P.S: Versuch es mal mit der FastLed. Die hat da schon einiges mit an Board. Weiß sowieso nicht, was alle immer wieder mit den Ada Libs haben.

Oh, sorry, darauf habe ich ja gar nicht geachtet :fearful:
Aber das war nicht der Fehler.

Ich war schon kurz davor FastLED auszuprobieren, aber ich hab jetzt schon so viel geschrieben... :sweat_smile:
Hatte aber auch gelesen, dass sich der Unterschied erst bei einer Anzahl LEDs bemerkbar macht.
Mehr habe ich mich bis dahin noch nicht mit der Bibliothek beschäftigt.

Ich habe die Funktion soweit umgeschreiben, dass es jetzt funktioniert.

void Wheel(byte wheelPos) {
  wheelPos = 255 - wheelPos;
  if(wheelPos <= 85) {
    pixelColor = strip.Color(255 - wheelPos * 3, 0, wheelPos * 3);  
  }
  else if(wheelPos > 85 && wheelPos <= 170) {
    wheelPos -= 85;
    pixelColor = strip.Color(0, wheelPos * 3, 255 - wheelPos * 3);
  }
  else if(wheelPos > 170){
    wheelPos -= 170;
    pixelColor = strip.Color(wheelPos * 3, 255 - wheelPos * 3, 0);
  }
}

mit der umfunktionierten Wheel() funktioniert jetzt aber der nächste Mode nicht :smiley:

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

Muss mich noch mal mit der bitweisen UND Verknüpfung beschäftigen. Die verstehe ich hier noch nicht so ganz.

Vielen Dank für deine Hinweise :slight_smile:

Sp4rtan:
Ich habe die Funktion soweit umgeschreiben, dass es jetzt funktioniert.

Was Du da als "jetzt funktioniert" zusammen hast, ist eine Funktion, die gleich zwei Arten der Programmblockierung in einer Funktion kombiniert:

  for(j=0; j<256; j++) {
...
    delay(wait);
  }

1.) erstens mal ist drin "delay()" als allgemeine Blockierung für eine bestimmte Zeit
2.) und zweitens mal wird das "delay()" bis zum Ende des Effekts 256 mal aufgerufen, das ist "Busy Waiting", nämlich warten darauf, dass der Effekt einmal durchgelaufen ist

Mit so einer Programmlogik kannst Du nichts aufbauen, was im Multitasking läuft.

Weder mit "delay()" noch mit "busy waiting" kannst Du Dein Vorhaben realisieren " 2 NeoPixel Strips mit unabhängigen Tastern für jeweils Bewegungsmuster und Farbe" anzusteuern.

Komplett falsche Programmlogik für den Ablauf!

Deinen Taster zum Umschalten zwischen verschiedenen Effekten kannst Du vielleicht mit Hängen und Würgen noch realisieren: Wenn Du den Schalter in der loop abfragst, mußt Du diesen Schalter nur so lange gedrückt lassen, bis der Effekt mit allen delay() Aufrufen komplett zuende durchgelaufen ist, dann kann der Tastendruck erkannt und auf den nächsten Effekt umgeschaltet werden.

Aber damit zwei oder mehr LED-Streifen gleichzeitig anzusteuern, ist mit dieser blockierenden Programmlogik vollkommen unmöglich. Dafür brauchst Du eine komplett anders aufgebaute, nicht blockierende Programmlogik, ohne delay() und ohne busy waiting auf das Ende des Effekts.

Dank dir Jurs für deine Hilfe.
Das ist mir auch soweit klar, hab mich da gestern wohl falsch ausgedrückt ::slight_smile:

das "funktionierende" ist nur der erste Codeabschnit den ich gepostet habe, bzw. die Wheel() Funktion.
Die Strip Ausgabe sieht bzw. sah so aus:

void colorWipe() {
  uint16_t i;
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, pixelColor);
    }
  strip.show();
}

mit:

case 6: {
      Wheel(color);                                                // COLOR FADE
      color++;
    }

Der Andere Code ist aus dem NeoPixel beispiel Sketch direkt rauskopiert.
Ich weiß, dass delay() absolut fehl am Platz ist :slight_smile:
Ich versuche auch mit möglichst wenig for-Schleifen auszukommen.

meine Ausgabe mit rainbow-Funktion sieht nun erstmal so aus.
Anders bekomme ich es leider nicht hin.
Wenn ich die "normale" Wheel() nehme sieht der Strip genauso aus wie bei Color Fade :neutral_face: :neutral_face:

void colorWipe() {
  uint16_t i;
  if(colrType == 5){
      for(i=0; i< strip.numPixels(); i++) {
        strip.setPixelColor(i, Wheel2(((i * 256 / strip.numPixels()) + j) & 255));
      }
  }
  else{
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, pixelColor);
    }
  }
  strip.show();
}
uint32_t Wheel2(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}