Now what if you're out riding around and get tired of the current animation and want to change it. Ride all the way home and reload a different animation? Nah. Let's see how we can have them all loaded and then choose the one we want using the buttons on the Circuit Playground.
Doing Two (or more) Things At Once
As simple as the idea of changing animations with a button press is, it has some surprising complexities. At it's lowest level, the brain on the Circuit Playground can only do one thing at a time. So if it's busy turning NeoPixels on and off, how can it check on button presses?
There are various approaches. For our bike light, we will use the simplest of them. However, for an excellent overview of more complex approaches (including using interrupts), check out this three part series. The ideas discussed in these guides could be used on the Circuit Playground.
What we will do is take advantage of the fact that all of our animation loops run fairly fast. This makes it possible to simply check for any button presses at the beginning (or end) of the animation loop. Then, if a button is pressed, take some action - like move to the next animation. This isn't perfect and has some issues, as you'll see.
To do this, we first take all of the animation code from our previous sketches and move them into functions that have the form:
void animation1() { while (!buttonsPressed()) { // animation code goes here } }
We'll create a function for each animation. The while()
loop will drive the animation and will continue as long as no buttons are pressed.
Then, our main Arduino loop()
will look something like this:
void loop() { animation1(); delay(250); animation2(); delay(250); animation3(); delay(250); // etc }
So the first animation is launched with a call to animation1()
. That will run until a button is pressed. When a button is pressed, the animation function exits and the next animation function animation2()
is called. Which runs until a button is pressed, etc.
The delay()
is needed so that you don't cycle through the animations super fast when you press a button. This is a simple form of debounce.
Here's the final code:
/////////////////////////////////////////////////////////////////////////////// // Circuit Playground Bike Light - The All Of Them // // Author: Carter Nelson // MIT License (https://opensource.org/licenses/MIT) #include <Adafruit_CircuitPlayground.h> // Change these to set speed (lower is faster) #define FLASH_RATE 250 #define SPIN_RATE 100 #define CYLON_RATE 100 #define BEDAZZLE_RATE 100 #define CHASE_RATE 100 // Change these to be whatever color you want // Use color picker to come up with hex values #define FLASH_COLOR 0xFF0000 #define SPIN_COLOR 0xFF0000 #define CYLON_COLOR 0xFF0000 // Define 10 colors here. // Must be 10 entries. // Use 0x000000 if you want a blank space. uint32_t rainbowColors[] = { 0xFF0000, 0xFF5500, 0xFFFF00, 0x00FF00, 0x0000FF, 0xFF00FF, 0x000000, 0x000000, 0x000000, 0x000000 }; /////////////////////////////////////////////////////////////////////////////// bool buttonsPressed() { return CircuitPlayground.leftButton() | CircuitPlayground.rightButton(); } /////////////////////////////////////////////////////////////////////////////// void flasher() { while (!buttonsPressed()) { // Turn on all the pixels to FLASH_COLOR for (int pixel=0; pixel<10; pixel++) { CircuitPlayground.setPixelColor(pixel, FLASH_COLOR); } // Leave them on for a little bit delay(FLASH_RATE); // Turn off all the NeoPixels CircuitPlayground.clearPixels(); // Leave them off for a little bit delay(FLASH_RATE); } } /////////////////////////////////////////////////////////////////////////////// void spinner() { // Can be any two pixels int pixel1 = 0; int pixel2 = 5; while (!buttonsPressed()) { // Turn off all the NeoPixels CircuitPlayground.clearPixels(); // Turn on two pixels to SPIN_COLOR CircuitPlayground.setPixelColor(pixel1, SPIN_COLOR); CircuitPlayground.setPixelColor(pixel2, SPIN_COLOR); // Increment pixels to move them around the board pixel1 = pixel1 + 1; pixel2 = pixel2 + 1; // Check pixel values if (pixel1 > 9) pixel1 = 0; if (pixel2 > 9) pixel2 = 0; // Wait a little bit so we don't spin too fast delay(SPIN_RATE); } } /////////////////////////////////////////////////////////////////////////////// void cylon() { int pixel1 = 0; int pixel2 = 9; while (!buttonsPressed()) { // Scan in one direction for (int step=0; step<4; step++) { CircuitPlayground.clearPixels(); CircuitPlayground.setPixelColor(pixel1, CYLON_COLOR); CircuitPlayground.setPixelColor(pixel2, CYLON_COLOR); pixel1 = pixel1 + 1; pixel2 = pixel2 - 1; delay(CYLON_RATE); } // Scan back the other direction for (int step=0; step<4; step++) { CircuitPlayground.clearPixels(); CircuitPlayground.setPixelColor(pixel1, CYLON_COLOR); CircuitPlayground.setPixelColor(pixel2, CYLON_COLOR); pixel1 = pixel1 - 1; pixel2 = pixel2 + 1; delay(CYLON_RATE); } } } /////////////////////////////////////////////////////////////////////////////// void bedazzler() { while (!buttonsPressed()) { // Turn off all the NeoPixels CircuitPlayground.clearPixels(); // Turn on a random pixel to a random color CircuitPlayground.setPixelColor( random(10), // the pixel random(256), // red random(256), // green random(256) ); // blue // Leave it on for a little bit delay(BEDAZZLE_RATE); } } /////////////////////////////////////////////////////////////////////////////// void rainbow() { // Start at the beginning int startIndex = 0; int colorIndex; while (!buttonsPressed()) { // Turn off all the NeoPixels CircuitPlayground.clearPixels(); // Loop through and set pixels colorIndex = startIndex; for (int pixel=0; pixel<10; pixel++) { CircuitPlayground.setPixelColor(pixel, rainbowColors[colorIndex]); colorIndex++; if (colorIndex > 9) colorIndex = 0; } // Increment start index into color array startIndex++; // Check value and reset if necessary if (startIndex > 9) startIndex = 0; // Wait a little bit so we don't spin too fast delay(CHASE_RATE); } } /////////////////////////////////////////////////////////////////////////////// void setup() { CircuitPlayground.begin(); // Make it bright! CircuitPlayground.setBrightness(255); } /////////////////////////////////////////////////////////////////////////////// void loop() { flasher(); delay(250); spinner(); delay(250); cylon(); delay(250); bedazzler(); delay(250); rainbow(); delay(250); // TODO: add your animation here! }
Issues
With the above code loaded and running on the Circuit Playground, try changing the animations by pressing either of the two buttons. Did it work? If not try pressing it again. Work that time?
So you might notice that the button response is a little sluggish. Sometimes it will change, sometimes it won't. This is the main issue with the simple approach we've taken for checking button presses. The responsiveness is coupled to the speed of the animation. You could make the problem even worse by slowing down an animation. Then the button is checked even less frequently and becomes even more sluggish.
Kind of annoying, isn't it? If you're motivated to try and make it better, read the guides linked above.
Text editor powered by tinymce.