Hi all,
I have a single push button and an led shield. I have the following code which works but not as smoothly as it should. I would like the cases specified in the loop to happen in a cycle each time the button is pressed it should move to the next case. Case 1 and 3 are a steady color while case 2 and 4 require a loop to alternate between a color and nothing. Is there a better way to do this with an interrupt? I know I can't use the delay function in an interrupt function so I am not sure how I would perform the alternating writes in case 2 and 4. Any ideas?
Thank you XD!
#include <Wire.h>
#include <HPRGB.h>
#include <Bounce.h>
HPRGB ledShield; //initialize
#define BUTTON 2 //button
//debouncer
Bounce bouncer = Bounce( BUTTON,5 );
int count = 0; //need a counter
void setup()
{
pinMode(BUTTON,INPUT); //initialize
Serial.begin(9600); //used for debugging
ledShield.begin(); //mA of each output
ledShield.setCurrent(350,350,350);
ledShield.setFreq(600); //set freq
ledShield.stopScript(); //stop check sequence
ledShield.eepromWrite(); //writes settings
delay(100); //needs this per spec
}
void loop()
{
bouncer.update ( ); //check and read
int value = bouncer.read();
if (value == HIGH) {
Serial.println("HIGH");
delay(500);
count = count + 1; //increment
int valuein = LOW; //used for c2 and c4
switch (count) {
case 1:
Serial.println("Pressed 1");
ledShield.goToRGB(0,0,255);
delay(1000);
break;
case 2:
Serial.println("Pressed 2");
while(valuein == LOW){
ledShield.goToRGB(0,0,255);
delay(1000);
ledShield.goToRGB(0,0,0);
delay(1000);
bouncer.update ( );
valuein = bouncer.read();
}
break;
case 3:
Serial.println("Pressed 3");
ledShield.goToRGB(255,0,0);
delay(1000);
break;
case 4:
Serial.println("Pressed 4");
while(valuein == LOW){
ledShield.goToRGB(255,0,0);
delay(1000);
ledShield.goToRGB(0,0,0);
delay(1000);
bouncer.update ( );
valuein = bouncer.read();
}
break;
}
if (count == 4) {
count = 0;
}
}
}
The interrupt is only used to raise a flag. Inside loop(), you check this flag on every iteration - if it has been set, "count" advances to the next mode. Otherwise, "count" remains unchanged and the current mode is executed again. Note that you don't need any pin reads with this approach. All input is handled by the interrupt.
Based-on your code sample I have integrated it as shown below. I am seeing a couple oddities. On first press it cycles through case 1 and case 2 together. Then it keeps cycling through case 3 repeatedly. It won't go to case 4 and jumps back to case 1. Any ideas?
#include <Wire.h>
#include <HPRGB.h>
#include <Bounce.h>
HPRGB ledShield; //initialize
//interrupt
volatile boolean interrupted = false;
int count = 0; //need a counter
void setup()
{ //interrupt for button
attachInterrupt(0, handler, RISING);
Serial.begin(9600); //used for debugging
ledShield.begin(); //mA of each output
ledShield.setCurrent(350,350,350);
ledShield.setFreq(600); //set freq
ledShield.stopScript(); //stop check sequence
ledShield.eepromWrite(); //writes settings
delay(100); //needs this per spec
}
void loop()
{
if (interrupted)
{
Serial.println("HIGH");
count = (count + 1) % 4;
interrupted = false;
delay(500);
}
switch (count)
{
case 1:
Serial.println("Pressed 1");
ledShield.goToRGB(0,0,255);
delay(500);
break;
case 2:
Serial.println("Pressed 2");
while(interrupted == false){
ledShield.goToRGB(0,0,255);
delay(1000);
ledShield.goToRGB(0,0,0);
delay(1000);
}
break;
case 3:
Serial.println("Pressed 3");
ledShield.goToRGB(255,0,0);
delay(500);
break;
case 4:
Serial.println("Pressed 4");
while(interrupted == false){
ledShield.goToRGB(255,0,0);
delay(1000);
ledShield.goToRGB(0,0,0);
delay(1000);
}
break;
}
}
void handler()
{
interrupted = true;
}
"count" changes 0 -> 1 -> 2 -> 3 -> 0. The switch labels should be 0 ~ 3, instead of 1 ~ 4
Having curly brackets in each case is always helpful (see below)
Finally, you should not need the two "while(interrupted == false){" loops. If there's been no interrupt, the main loop() will always repeat the same switch branch.
switch (count)
{
case 0:
{
Serial.println("Pressed 1");
ledShield.goToRGB(0,0,255);
delay(500);
break;
}
case 1:
{
...
I do notice on case 1 and case 3 it doesn't always get the interrupt on the first button press. I am assuming this is due to the delay? Is there a better was to do this so that it works every time regardless of when the button is pressed?
Indeed, the code does not react immediately. This also happens on the other two cases - 0 and 2, but they are shorter in duration (0.5s) and it's hardly noticeable.
Technically, the interrupts do happen and interrupted becomes true on the very first button press. But it won't switch to the next mode, until the current one completes.
You are right - it's all due to the delays. I'm not aware of a way to "stop" in the middle of a delay() and skip to the next instruction. You can work around this by replacing a delay(1000) with a loop of 100x delay(10). Check for interrupted and break the loop if true. This way the response time will be 0.01s instead of a 1s. However, you may start running into button bouncing issues...