Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/* Anmimation speed test program for FastLED.
*
* By: Andrew Tuline
*
* Date: October, 2017
*
* Problem:
*
* When you write a display routine, the performance of that routine may change as you add other elements to your program. How do we keep that display consistent?
*
* The ideal situation would be for the animation to not change as the frame rate decreases (or the program overhead increases). Also note that the lower the frame rate, the less reliable button or other inputs will be. Therefore, you want the frame rate
* to be as high as possible.
*
*
* This Program:
*
* This program demonstrates the problem by using a potentiometer (connected to pin A4) to vary the amount of 'overhead' or delay in the program. There are 4 different animation routines included, 3 of which attempt to provide solutions to this issue.
*
*
* Demonstration
*
* This program has 4 animation routines that march a single pixel across a strip of LED's. Enable one of those routines at a time and then dial the potentiometer from end to end and observe the results.
*
* animationA() - Uses a standard counter and a blocking delay.
* animationB() - Uses a standard counter and a FastLED.delay.
* animationC() - Uses a standard counter and FastLED's EVERY_N_MILLISECONDS function.
* animationD() - Just uses millis() as the counter.
*
* delaypot() - Reads a potentiometer on pin A4 and adds a blocking delay to increase overhead/lower the frame rate of the program.
*
* showfps() - Shows the frame rate of the program. With FastLED, this can reach about 400 frames (or loops) per second for a standard Arduino UNO/Nano.
*
*
* Instructions
*
* Enable one of the animations as a time and compile the program for your Arduino/LED strip. Turn on the serial monitor and observe the frames per second as well as the LED's as you adjust the potentiometer.
*
* As we dial the potentiometer, the speed of the animation changes, dependinmg on the animation routine used.
*
* Ideally, the animation speed should be fixed no matter what the frame rate is.
*
*
* Results:
*
* animationA() - As the frame rate decreases signficantly, the animation speed also decreases. The animation continues to be smooth.
*
* animationB() - Doesn't seem to be as bright as animation A, which must be a function of FastLED.delay(). Otherwise the behaviour is similar to animation A.
*
* animationC() - At full speed, the brightness is similar to animationB, however it gets brighter as the frame rate decreases. In additon, the animation rate changes inconsistently as the frame rate decreases signficantly.
*
* animationD() - As the frame rate decreases, the animation speed remains fixed. At a low enough frame rate, the animation starts to skip the occasional LED because the change in millis values are significant.
*
*
* Conclusion:
*
* The animationD provides the most consistent animation appearance and consistent speed over a wide range of frame rates. At extremely low frame rates, you would need to increase the complexity of animatonD in order for the animation
* to remain stable.
*
*/
#include "FastLED.h" // FastLED library.
#if FASTLED_VERSION < 3001000
#error "Requires FastLED 3.1 or later; check github for latest code."
#endif
// Fixed definitions cannot change on the fly.
#define LED_DT 12 // Data pin to connect to the strip.
#define LED_CK 11 // Clock pin for WS2801 or APA102.
#define COLOR_ORDER BGR // It's GRB for WS2812 and BGR for APA102.
#define LED_TYPE APA102 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit.
#define NUM_LEDS 60 // Number of LED's.
#define POT_PIN A4 // Here's our potentiometer.
uint8_t max_bright = 255; // Overall brightness.
struct CRGB leds[NUM_LEDS]; // Initialize our LED array.
uint8_t counter = 0; // A counter variable used by the animation routines.
long currentMillis = 0; // Variables used by our fps counter.
long lastMillis = 0;
long loops = 0;
void setup() {
Serial.begin(57600); // Initialize serial port for debugging.
delay(1000); // Soft startup to ease the flow of electrons.
pinMode(POT_PIN, INPUT); // Set pin to input.
digitalWrite(POT_PIN, HIGH); // Turn on pullup resistor.
LEDS.addLeds<LED_TYPE, LED_DT, LED_CK, COLOR_ORDER>(leds, NUM_LEDS); // Use this for WS2801 or APA102
// LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS); // Use this for WS2812
FastLED.setBrightness(max_bright);
set_max_power_in_volts_and_milliamps(5, 500); // FastLED Power management set at 5V, 500mA.
} // setup()
void loop () {
delaypot(); // Add more 'overhead' with this routine. It changes with the movement of the potentiometer.
fadeToBlackBy(leds, NUM_LEDS, 255); // Use a fader, so that we appear to be just moving a single dot across the length of the strip. 1 = slow fade, 255 = fast fade.
// Enable ONLY ONE Animation at a time!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// animationA();
// animationB();
/* EVERY_N_MILLISECONDS(30) { // FastLED based non-blocking delay to update/display the sequence.
animationC();
}
*/
// animationD();
FastLED.show();
showfps(); // Show our Frames per second.
} // loop()
void animationA() {
delay(25);
counter = (counter + 1) % (NUM_LEDS);
leds[counter] = CRGB::White;
} // animationA()
void animationB() { // This routine has a regular counter with a delay
FastLED.delay(25);
counter = (counter + 1) % (NUM_LEDS);
leds[counter] = CRGB::White;
} // animationB()
void animationC() { // This routine relies on FastLED's EVERY_N_MILLISECONDS function.
counter = (counter + 1) % (NUM_LEDS);
leds[counter] = CRGB::White;
} // animationC()
void animationD() { // This routine animates with millis() as a counter.
counter = (millis()>>5) % (NUM_LEDS); // Slow the animation down with '>>5'.
leds[counter] = CRGB::White;
} // animationD()
void delaypot() { // This routine allows me to change the 'overhead' in the overall program by adding more delay
int potval = analogRead(POT_PIN);
// Serial.println(potval);
delay(potval>>5); // Here's where we add overhead/reduce the frame rate.
} // delaypot()
void showfps() { // Show our frames per seocond on the serial monitor
currentMillis=millis();
loops++;
if(currentMillis - lastMillis >1000) {
Serial.println(loops); // Print it once a second.
lastMillis = currentMillis;
loops = 0;
}
} // showfps()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment