Short story. I am making an led hula hoop. I have programmed several different sketches that make the hoop do different things such as chasing leds or the entire led strip on. My question is how do I program to add a push button to switch between the programs? I am having a hard time finding examples of this. Thanks in advance.
When I want to setup a list of pre-sets, I use a switch case statement. Wire your button up using this http://www.arduino.cc/en/tutorial/button, then in your code do something like this:
int mode = 0;
//this will control which case to use
void loop() {
switch(mode) {
case 1:
buttonDetail();
ledProgram();
break; }
}
void buttonDetail(){
int button1State = digitalRead(your button pin);
if (button1State == LOW) {
mode = mode + 1;
}
}
void ledProgram() {
//insert your LED programming here
}
I’d read the button outside of the case switch, put it in the main loop in case any of the patterns has some odd delay in it. Same idea, debounce the button, change mode based on its counter. Loop ad infinitum …
The code I snipped from had a counter that would flop over to zero after a certain number of button presses.
While on the subject, would it be best practice to incorporate a hardware debounce option onboard because the library will interfere with the millis() function?
I haven’t noticed any issues with it. I debounce a button for 200ms, no issues.
And yes, a simple if (mode > MAX_PATTERNS) mode = 0; will get it to loop back to 0.
The funkboxing demo code allows you to change patterns virtually instantly. It’s a matter of coding your patterns so they do one “frame” of animation per loop, then check for signals to change the pattern at the start of every loop. This requires making your counting variables global.
@Jon_Burroughs So i need to add?
int modePin = 1
leds doing nothing. I am sure i am just missing something silly. anyone see the problem?
#include “FastSPI_LED2.h”
#define NUM_LEDS 70
#define DATA_PIN 0
#define MODE_UP 1
CRGB leds[NUM_LEDS];
int hue;
int mode = 0;
void setup() {
pinMode(MODE_UP, OUTPUT);
FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
}
void loop() {
switch(mode) {
case 1:
buttonDetail();
ledProgram();
break; }
}
void buttonDetail(){
int button1State = digitalRead(MODE_UP);
if (button1State == LOW) {
mode = mode + 1;
}
}
void ledProgram() {
for(int ledIndex = 0; ledIndex < NUM_LEDS; ledIndex = ledIndex + 1) {
leds[ledIndex].setHSV(hue,255,255);
FastLED.show();
delay(1);
leds[ledIndex] = CRGB::Black;
hue = hue + 1;
if(hue > 255) {
hue = 0;
}
}
}
haha changed pinMode(MODE_UP, OUTPUT); from output to input that was just silly but still not working
ah i must be missing a digitalread command
bah have a digitalread line. so lost
A see a few issues here, but before I dive into it, it helps to see how you have the button wired up. Your code is expecting it to go LOW when you press it, which tells me you have it pulled up, is that correct? Also, try running it without the call to buttonDetail() in the case switch. Put // in front of that line. As a rule of thumb, always make sure the very basic part of your code works before you start adding other pieces.
Also, you have a blocking delay in your routine, means the loop will not get called till the entire for loop in the ledProgram() finishes running. It also means that your button presses have to be at the very exact moment it finishes that for loop but before it starts the next one. This needs to be code without any delays and loops, so that your main loop() is constantly running. And the buttonDetail() function needs to be in the main loop as well.
One of the issues I ran into originally when I was figuring this stuff out too, I would wire my buttons incorrectly. Be sure to crawl before you try to run.
void ledProgram() {
for(int ledIndex = 0; ledIndex < NUM_LEDS; ledIndex++) {
leds[ledIndex] = HSV(hue,255,255);
FastLED.show();
// I think this is your faulty code
delay(1);
leds[ledIndex] = CRGB::Black;
hue = hue + 1;
if(hue > 255) {
hue = 0;
}
}
}
From what it looks like to me, is that you are setting the hue to a specified color, then you show the hue to the leds for 1 millisecond, then show the color black immediately after that. Your eyes never have a chance to see the color because you are only showing it for 1 milli sec. Try increasing the delay to over 100 to experiment.
Actually, that’s more than 1ms because he doesn’t immediately call another .show(). Granted, it is still too fast, but you should notice the whole thing light up very dim because it’s cycling through the whole string within 100ms, fast enough to make it appear as if it’s dimly lit. Either way, having a delay inside of the routine is a bad idea as the buttonDetail() won’t ever run unless exactly timed. A better solution is something like this pseudo code:
loop() {
// check button
// if state changed, increase mode
// call display(mode) routine
}
void display(int mode) {
switch (mode) {
case 1:
displayMode1();
break;
case 2:
displayMode2();
break;
case N:
displayModeN();
breakl
default:
// shut the string off
LEDS.showColor(CRGB(0,0,0));
breakl
}
}
void displayMode1() {
if (millis() - lastRun > pause) { // here ‘pause’ determines how often the string changes*.
// run ONE step of the sequence
lastRun = millis();
}
}
- Usually I set ‘pause’ to a default value of 1000, then divide it per mode, some mode run at pause/10 (100ms), others run at pause/40 (25ms), etc., etc.
The above code will insure that the loop() is constantly running and checking the button state, while the actual string display only runs whenever it reaches the ‘pause’ interval.
I see what you’re saying Ashley. thanks i’ll try and work that out
i thought arduino programming was less robust i guess. I may have to find a college kid who knows this locally and just pay him to do it
“Converting” what you’re doing, which is running a single pixel down the line, store the current pixel in a global variable and use that, instead of a for loop. Something like:
volatile uint8_t currPx = 0;
volatile long lastRun;
void displayMode1() {
if (millis() - lastRun > pause) {
leds[currPx].setHSV(hue, 255, 255);
LEDS.show();
// increase hue
hue++;
if (hue > 255) hue = 0;
// increase LED counter
currPx++;
if (currPx > NUM_LEDS) currPx = 0;
lastRun = millis();
}
}
Note that I did not turn the LED off. You need to figure that part out. One easy way is to not turn it off till the next cycle so it remains on for the full duration of ‘pause’. But I will leave that exercise for you.
It’s as “robust” as you’d like it to be.
You can get down to the bare metal if you’d like …