I am trying to use different buttons to activate different methods for an LED strip. However, when one button is pressed after another has been pressed, I want it to interrupt the first buttons method and begin the second. For example: one button sends a rainbow pattern through the LED strip when pressed, however, while it is cycling through the rainbow, the second button is pressed which sends a white cycle through the LED strip. There will be 24 buttons total. I have gotten this to work with 2 buttons but am having trouble getting it to work for a third. The code is below:
void loop(){
if (digitalRead(inPin(1)) == HIGH && lastState == LOW){//if button has just been pressed
stopCycle();
theaterChaseRainbow(50);
}
if (digitalRead(inPin(2)) == HIGH){
stopCycle();
theaterChase(strip.Color(127, 127, 127), 50); // White
}
if (digitalRead(inPin(3)) == HIGH){
stopCycle();
rainbowCycle(0);
}
}
//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<100; j++) { //do 100 cycles of chasing
if (digitalRead (inPin(1)) == LOW) { //checks that other button(s) have not been pressed
if (digitalRead (inPin(3) == LOW)){
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, c); //turn every third pixel on
}
strip.show();
delay(wait);
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
}
}
void rainbow(uint8_t wait) {
int i, j;
for (j=0; j < 384; j++) {
if (digitalRead (inPin(2)) == LOW) { // 3 cycles of all 384 colors in the wheel
if (digitalRead (inPin(3) == LOW)){
for (i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel( (i + j) % 384));
}
strip.show(); // write all the pixels out
delay(wait);
}
}
}
}
uint32_t Wheel(uint16_t WheelPos)
{
byte r, g, b;
switch(WheelPos / 128)
{
case 0:
r = 127 - WheelPos % 128; //Red down
g = WheelPos % 128; // Green up
b = 0; //blue off
break;
case 1:
g = 127 - WheelPos % 128; //green down
b = WheelPos % 128; //blue up
r = 0; //red off
break;
case 2:
b = 127 - WheelPos % 128; //blue down
r = WheelPos % 128; //red up
g = 0; //green off
break;
}
return(strip.Color(r,g,b));
}
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
for (j=0; j < 384 * 5; j++) { // 5 cycles of all 384 colors in the wheel
if (inPin(1) == LOW) {
if (inPin(2) == LOW) {
for (i=0; i < strip.numPixels(); i++) {
// tricky math! we use each pixel as a fraction of the full 384-color wheel
// (thats the i / strip.numPixels() part)
// Then add in j which makes the colors go around per pixel
// the % 384 is to make the wheel cycle around
strip.setPixelColor(i, Wheel( ((i * 384 / strip.numPixels()) + j) % 384) );
}
strip.show(); // write all the pixels out
delay(wait);
}
}
}
}
void stopCycle(){
int i;
for (i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, 0);
}
strip.show(); // write all the pixels out
}
2 Answers 2
Inside each inner loop, just test the switches and return
if they are pressed.
eg.
//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<100; j++) { //do 100 cycles of chasing
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3)
{
strip.setPixelColor(i+q, c); //turn every third pixel on
}
strip.show();
delay(wait);
// give up if switches pressed
if (digitalRead (inPin(1)) == HIGH ||
digitalRead (inPin(2)) == HIGH ||
digitalRead (inPin(3)) == HIGH )
return;
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
am having trouble getting it to work for a third
If that doesn't help please explain the nature of this "trouble".
You may need to debounce the switch presses. And you may need to wait for them to release the switch, eg.
if (digitalRead(inPin(1)) == HIGH && lastState == LOW){//if button has just been pressed
stopCycle();
while (digitalRead(inPin(1)) == HIGH)
{ } // wait for switch release
delay (10); // debounce
theaterChaseRainbow(50);
}
-
This is an excellent solution but is there a way to move the return statement to the loop? This way, I could call theatreChase multiple times with different buttons at different paramenters.Jet Propelled Insectivore– Jet Propelled Insectivore2015年08月19日 05:30:54 +00:00Commented Aug 19, 2015 at 5:30
-
I'm not sure what you mean by "move the return statement to the loop". Can you elaborate?2015年08月19日 09:11:57 +00:00Commented Aug 19, 2015 at 9:11
I would normally do this (pseudocode):
void loop() {
static state=state_off;
if (button_1_pushed) {
state=state_1;
} elseif (button_2_pushed) {
state=state_2;
}
if (state==state_off) {
turn_all_leds_off();
} elseif (state==state_2) {
shownextframe_rainbow();
} elseif (state==state_2) {
shownextframe_chaser();
}
delay(1);
}
In shownextframe_chaser/shownextframe_rainbow, I would probably work out what should be shown based on the current millis() - e.g. if your chaser has 10 lights, and you want it to pulse over 1 second, then each led should be on for 100 millis, so at any instant, the led that should be on is (millis()/100)%10
(assuming the led's are numbered for 0 to 9).