I'm trying to understand the EVERY_N_SECONDS() method.
I am using the FASTLed NOISE functions to invoke random moving color patterns.
I want to use a specific palette for a set period of time (60 seconds), followed by a second palette for a set period of time (5 seconds) and then start over.
The EVERY_N_SECONDS macro is useful for simple "metronome" timing of changes, but your requirement is slightly more complex.
I would use millis(), and some variables to remember which was the last palette to be set, and when, and use an if or switch statement to decide what to do based on those variables. This technique is called a "state machine" which sounds advanced and scary, but is actually really easy and obvious to grasp, especially once you have seen it once.
#include <FastLED.h>
// How many leds in your strip?
#define NUM_LEDS 60
// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN
#define LED_PIN 11
#define CLK_PIN 13
#define LED_TYPE APA102
#define COLOR_ORDER BGR
#define NUM_LEDS 60
#define BRIGHTNESS 10
#define FRAMES_PER_SECOND 10
// Define the array of leds
CRGB leds[NUM_LEDS];
CRGBPalette16 currentPalette(CRGB::Black); //initialize to BLACK for fade on affect
CRGBPalette16 targetPalette(LavaColors_p); //initialize target palette to LAVA colors
//CRGBPalette16 targetPalette(HeatColors_p);
//CRGBPalette16 targetPalette(ForestColors_p);
String palette = "Lava"; //used for debuging
const unsigned long lavaDur = 60000; //show lava for 60 seconds
const unsigned long forestDur = 5000; //show forest for 5 seconds
unsigned long currentTime = 0; //initilize current timer
unsigned long previousTime = 0; //initialize previous timer
unsigned int x = 0; //used for debugging
void setup() {
/* used for debugging */
Serial.begin(9600);
Serial.println("resetting");
delay(3000);
LEDS.addLeds<LED_TYPE, LED_PIN, CLK_PIN, COLOR_ORDER>(leds, NUM_LEDS); // APA102, WS8201
LEDS.setBrightness( BRIGHTNESS );
}
void loop() {
currentTime = millis(); //start timer
/* debugging, curious what is going on under the hood */
EVERY_N_SECONDS(1){
x++;
Serial.print(x);
Serial.print(": ");
Serial.print(" palette: ");
Serial.println(palette);
}
/* After 60 seconds, set color palette to Forest */
if(currentTime - previousTime >= lavaDur){
targetPalette=CRGBPalette16(ForestColors_p);
palette = "Forest";
}
/* After 5 seconds, set color palette to Lava */
if(currentTime - previousTime >= lavaDur + forestDur){
targetPalette=CRGBPalette16(LavaColors_p);
palette = "Lava";
previousTime = currentTime;
}
/* Fill LEDS with noise colors */
fillnoise8();
/* fade colors from current palette to target palette */
EVERY_N_MILLIS(10) {
nblendPaletteTowardPalette(currentPalette, targetPalette, 48); // Blend towards the target palette over 48 iterations.
}
/* show LEDs */
LEDS.show(); // Display the LED's at every loop cycle.
}
void fillnoise8() {
#define scale 30 // Don't change this programmatically or everything shakes.
for (int i = 0; i < NUM_LEDS; i++) { // Just ONE loop to fill up the LED array as all of the pixels change.
uint8_t index = inoise8(i * scale, millis() / 10 + i * scale); // Get a value from the noise function. I'm using both x and y axis.
leds[i] = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
}
} // fillnoise8()
Is that because of the space limitations imposed by the device and the space requirements for the String data type?
I'm not used to working with limited space constraints. I can see where a bit level approach would be better in this case. i'm not used to working within that framework. I am still figuring things out.
The 'extra' code was removed for final implementation.
Is that because of the space limitations imposed by the device and the space requirements for the String data type?
Not quite. It is because the memory for old strings is not cleaned up.
In applications running on larger machines there is a "garbage collection" that frees up memory once used by strings but no longer needed because they have been changed or are no longer in scope. Embedded system do not have this feature because it would cause random delays while the garbage is being collected which is what you don't want on an embedded system. The lack of this causes, over time, a stack / heap collision and so the whole program falls over or can do strange things.
@Grumpy_Mike
That makes perfect sense. Maybe that should have been obvious but its been a bit since I have written production level code and I've never had to function within those types of constraints.