Here's an OOP solution. (It seems a lot of Arduino programmers shy away from C++ classes, but I use them all the time).
Since you don't want to block loop()
, you need to create a function that will set the pixel (if time has expired) and return immediately. I would create a class to encapsulate the pixel strip.
The way this works is the class has a loop()
function that needs to be called every time in the main program's loop()
function. The class's loop()
will either return (almost) immediately or it will update the pixel. Which will also be very quick. This allows you to do other things in the main loop()
.
Disclaimer: I just whipped this up, there may be bugs.
// A class to encapsulate the neo pixel strip.
class color_strip {
protected:
Adafruit_NeoPixel pixels;
uint32_t last_ms;
uint32_t color;
uint32_t duration = 0;
int current_pixel;
bool first_time;
public:
// Constructor
color_strip(int num_pixels, int pin) {
strip = Adafruit_NeoPixel(num_pixels, pin, NEO_GRB + NEO_KHZ800);
}
// Call this from setup()
void setup() {
strip.begin();
}
// Call this to start a wipe
// param duration_ms is how long the entire wipe should take
void wipe(RGB color, uint32_t duration_ms) {
// Calculate how long to light each pixel
duration = duration_ms / strip.numPixels()
// Initialize this data for loop()
last_ms = millis();
first_time = true;
this->color = strip.Color(color.red, color.green, color.blue);
current_pixel = 0;
}
void loop() {
// Is there something to do? Only if duration != 0
if (0 != duration) {
// Time to change pixel?
uint32_t current_ms = millis();
if (current_ms - last_ms >= duration || first_time) {
first_time = false;
// Finished the entire wipe?
if (current_pixel == strip.numPixels()) {
duration = 0;
}
else {
// Set the pixel
strip.setPixelColor(current_pixel++, color);
strip.show();
// Save
last_ms = ms;
}
}
}
}
// Returns true if doing a wipe, else false
bool working() {return duration != 0;}
};
Usage: you can create an array of colors. You then cycle through all these colors. If you want to add more colors, simply add to the array.
// Helper struct to store rgb
struct RGB {
byte red, green, blue;
};
RGB all_colors[] = {
{255, 0, 0},
{0, 255, 0},
{0, 0, 255},
{0, 0, 0}
// Add more colors here, if needed
};
// Need to keep track of the current color being displayed
byte current_color = 0;
const byte num_colors = sizeof(all_colors) / sizeof(all_colors[0]);
// Here's the actual object
// Change the parameters to whatever they need to be in your setup
color_strip strip(number_of_pixels, pin_number);
void setup()
// Call the class setup function
strip.setup();
}
void loop()
{
// If the strip has completed its wipe, set it to next color
if (!strip.working()) {
current_color = (current_color + 1) % num_colors;
strip.wipe(all_colors[current_color], 1000);
}
// Call the class loop(). It will return quickly so won't block
// the rest of the program
strip.loop();
// Do other stuff here...
}