FastLED and calling functions within a class

Hello all,

I'm trying to use this library to control a small LED strip without using delay() because I'm doing other stuff at the same time.

So, when I looked up the topic of multi tasking, I came to the understanding that I need to utilize Object Oriented Programming methods to achieve multi tasking.

There are 2 buttons:
btnOrange when pressed will light the strip Orange alternating the LEDs every 50ms and will activate a motor.
btnGreen when pressed will light the strip Green alternating the LEDs every 50ms and will activate a different motor.

My problem is when I press btnGreen, only the first LED will turn green and will flicker as long as I'm pressing. This is not the case with btnOrange because I'm using a for loop and the beautiful delay().

Here's the code in the main sketch:

#include "ledControl.h"


int btnOrange = 2;
int btnGreen = 3;

void setup()
{
  pinMode (btnOrange,INPUT);
  pinMode (btnGreen,INPUT);
}

void loop()
{
  ledControl ledObject;
  
  if (digitalRead(btnOrange) == HIGH)
  {
    ledObject.orangeAlternate();
    theOtherFunction1();
  }
  
  if (digitalRead(btnGreen) == HIGH)
  {
    ledObject.greenAlternate();
    theOtherFunction2();
  }
  
  ledObject.switchOffStrip();
}

void theOtherFunction1()
{
 //stuff goes here 
}

void theOtherFunction2()
{
 //stuff goes here 
}

And here's the rest of the code inside the "ledControl.h" tab:

//FastLED definitions
  #include <FastLED.h>
  #define NUM_LEDS 6
  #define DATA_PIN 5
  CRGB leds[NUM_LEDS];

class ledControl
{
  public:
//class constructor  
  ledControl()
  {
    FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  }
  
// class public variables
  int y = 0;
  unsigned long now;
  unsigned long elapsed;
  unsigned long period = 50;
  
// class functions 
  void orangeAlternate()
  {
    for (int x=0; x < NUM_LEDS; x++)
    {
    leds[x].setRGB(255,69,0);
    FastLED.show();
    delay(50);                //used here for demonstration, I'm trying to substitue it with millis() similar to the greenAlternate function.
    leds[x] = CRGB::Black;
    }
  }

  void greenAlternate()
  {
    now = millis();
    if (now - elapsed >= period)
    {
      elapsed = now;
      leds[y].setRGB(0,255,0);
      FastLED.show();
      leds[y] = CRGB::Black;
      y++;
      if (y >= NUM_LEDS) y = 0;
    }
  }

  void switchOffStrip()
  {
    for (int x = 0; x < NUM_LEDS; x ++)
    {
      leds[x].setRGB(0,0,0);
      FastLED.show();
    }
  }

};

BTW, If moved the code for greenAlternate to the main sketch and outside the class it works fine -providing that I include FastLED stuff in -.

I've spent the last 5 days learning about millis() and classes and I can't figure what am I doing wrong.

Thoughts please ... Thanks a lot,

when I looked up the topic of multi tasking, I came to the understanding that I need to utilize Object Oriented Programming methods to achieve multi tasking.

Not true.

What you need to do is to break down the actions in your program into small steps and execute each step in order. Between each step you can then do something else such as executing a small step in another aspect of the program and/or read in input to determine whether it has changed, for instance. Then you go back and execute another small step and so on.

If you have not already done so then look at Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

UKHeliBob:
Not true.

What you need to do is to break down the actions in your program into small steps and execute each step in order. Between each step you can then do something else such as executing a small step in another aspect of the program and/or read in input to determine whether it has changed, for instance. Then you go back and execute another small step and so on.

If you have not already done so then look at Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

You're right,I was able to achieve the desired result when I put all the code in the main sketch but using classes will also make the code tidier and easier to read.

Maybe my question should be: why my greenAlternate() won't operate properly when I put it inside the class?

P.s. Trust me, in 5 days I read all sorts of things :slight_smile:

aminabudahab:
You're right,I was able to achieve the desired result when I put all the code in the main sketch but using classes will also make the code tidier and easier to read.

Maybe my question should be: why my greenAlternate() won't operate properly when I put it inside the class?

P.s. Trust me, in 5 days I read all sorts of things :slight_smile:

this was done wiht NeoPixel library, but you should be able to do it similarly with FastLed:

#include <Adafruit_NeoPixel.h>

constexpr size_t PIXEL_COUNT = 10;
constexpr uint8_t PIXEL_PIN = 7;

struct LedColor {
  LedColor(){color = 0x00000000;}
  LedColor(uint32_t c) : color(c){}
  LedColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) : b(blue), g(green), r(red), w(white){}
  union {
    uint32_t color;
    struct {
      uint8_t b;
      uint8_t g;
      uint8_t r;
      uint8_t w;
    };
  };
  bool operator==(const LedColor& that) const {
    return this->color == that.color;
  }
};

class NeopixelFader : public  Adafruit_NeoPixel{
  public:
    NeopixelFader(uint16_t num_pixels, uint8_t pixel_pin, uint8_t desc) : Adafruit_NeoPixel(num_pixels, pixel_pin, desc){}
    void update(void) {
      uint32_t currentMillis = millis();
      if (currentMillis - lastUpdateMillis > fadeInterval) {
        if (target == current) {
          return;
        }
        if (target.r > current.r) {
          current.r++;
        } else if (target.r < current.r) {
          current.r--;
        }
        // green
        if (target.g > current.g) {
          current.g++;
        } else if (target.g < current.g) {
          current.g--;
        }
        // blue
        if (target.b > current.b) {
          current.b++;
        } else if (target.b < current.b) {
          current.b--;
        }
        //white
        if (target.w > current.w) {
          current.w++;
        } else if (target.w < current.w) {
          current.w--;
        }
//        Serial.print(F("Curret Color:\t"));
//        Serial.println(current.color, HEX);
        for (size_t i = 0; i < numLEDs; i++) {
          setPixelColor(i, current.color);
        }
        lastUpdateMillis = currentMillis;
        show();
      }
    }
    void fadeStripToColor(LedColor c){
      target = c;
    }
    void fadeStripToColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w){
      target.r = r;
      target.g = g;
      target.b = b;
      target.w = w;
    }
    LedColor getTargetColor(void) {
      return target;
    }
    LedColor getCurrentColor(void) {
      return current;
    }
  private:
    LedColor target;
    LedColor current;
    uint32_t lastUpdateMillis;
    uint32_t fadeInterval = 3;
};

NeopixelFader strip(PIXEL_COUNT, PIXEL_PIN, NEO_RGB + NEO_KHZ800);

LedColor red    (0x00FF0000);  // 0xWWRRGGBB
LedColor green  (0x0000FF00);
LedColor blue   (0x000000FF);
LedColor orange (0x00FF9B00);
LedColor someColor(197, 255, 200);  // alternate construction (r, g, b, w)

void setup() {
  Serial.begin(9600);
  pinMode(3, INPUT_PULLUP);
  Serial.println(someColor.r);
  Serial.println(someColor.g);
  Serial.println(someColor.b);
  Serial.println(someColor.w);
  strip.begin();
  strip.show();
  strip.fadeStripToColor(blue);
}

void loop() {
  strip.update();
  auto checkButton = [](uint8_t pin, uint16_t debounceMillis){
    bool lastState = true;
    static uint32_t lastMillis = 0;
    int currentState = digitalRead(pin);
    if (currentState != lastState and millis() - lastMillis > debounceMillis) {
      lastState = currentState;
      lastMillis = millis();
      Serial.println(F("Pressed"));
      return true;
    }
    return false;
  };
  if(checkButton(3, 100)) {
    if (strip.getTargetColor() == red) {
      strip.fadeStripToColor(green);
    } else if (strip.getTargetColor() == green) {
      strip.fadeStripToColor(blue);
    } else if (strip.getTargetColor() == blue) {
      strip.fadeStripToColor(red);
    }
  }
}

BulldogLowell:
this was done wiht NeoPixel library, but you should be able to do it similarly with FastLed:

#include <Adafruit_NeoPixel.h>

constexpr size_t PIXEL_COUNT = 10;
constexpr uint8_t PIXEL_PIN = 7;

struct LedColor {
  LedColor(){color = 0x00000000;}
  LedColor(uint32_t c) : color(c){}
  LedColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) : b(blue), g(green), r(red), w(white){}
  union {
    uint32_t color;
    struct {
      uint8_t b;
      uint8_t g;
      uint8_t r;
      uint8_t w;
    };
  };
  bool operator==(const LedColor& that) const {
    return this->color == that.color;
  }
};

class NeopixelFader : public  Adafruit_NeoPixel{
  public:
    NeopixelFader(uint16_t num_pixels, uint8_t pixel_pin, uint8_t desc) : Adafruit_NeoPixel(num_pixels, pixel_pin, desc){}
    void update(void) {
      uint32_t currentMillis = millis();
      if (currentMillis - lastUpdateMillis > fadeInterval) {
        if (target == current) {
          return;
        }
        if (target.r > current.r) {
          current.r++;
        } else if (target.r < current.r) {
          current.r--;
        }
        // green
        if (target.g > current.g) {
          current.g++;
        } else if (target.g < current.g) {
          current.g--;
        }
        // blue
        if (target.b > current.b) {
          current.b++;
        } else if (target.b < current.b) {
          current.b--;
        }
        //white
        if (target.w > current.w) {
          current.w++;
        } else if (target.w < current.w) {
          current.w--;
        }
//        Serial.print(F("Curret Color:\t"));
//        Serial.println(current.color, HEX);
        for (size_t i = 0; i < numLEDs; i++) {
          setPixelColor(i, current.color);
        }
        lastUpdateMillis = currentMillis;
        show();
      }
    }
    void fadeStripToColor(LedColor c){
      target = c;
    }
    void fadeStripToColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w){
      target.r = r;
      target.g = g;
      target.b = b;
      target.w = w;
    }
    LedColor getTargetColor(void) {
      return target;
    }
    LedColor getCurrentColor(void) {
      return current;
    }
  private:
    LedColor target;
    LedColor current;
    uint32_t lastUpdateMillis;
    uint32_t fadeInterval = 3;
};

NeopixelFader strip(PIXEL_COUNT, PIXEL_PIN, NEO_RGB + NEO_KHZ800);

LedColor red    (0x00FF0000);  // 0xWWRRGGBB
LedColor green  (0x0000FF00);
LedColor blue  (0x000000FF);
LedColor orange (0x00FF9B00);
LedColor someColor(197, 255, 200);  // alternate construction (r, g, b, w)

void setup() {
  Serial.begin(9600);
  pinMode(3, INPUT_PULLUP);
  Serial.println(someColor.r);
  Serial.println(someColor.g);
  Serial.println(someColor.b);
  Serial.println(someColor.w);
  strip.begin();
  strip.show();
  strip.fadeStripToColor(blue);
}

void loop() {
  strip.update();
  auto checkButton = [](uint8_t pin, uint16_t debounceMillis){
    bool lastState = true;
    static uint32_t lastMillis = 0;
    int currentState = digitalRead(pin);
    if (currentState != lastState and millis() - lastMillis > debounceMillis) {
      lastState = currentState;
      lastMillis = millis();
      Serial.println(F("Pressed"));
      return true;
    }
    return false;
  };
  if(checkButton(3, 100)) {
    if (strip.getTargetColor() == red) {
      strip.fadeStripToColor(green);
    } else if (strip.getTargetColor() == green) {
      strip.fadeStripToColor(blue);
    } else if (strip.getTargetColor() == blue) {
      strip.fadeStripToColor(red);
    }
  }
}

Appreciate it, will try it tommorrow