A fellow Arduino guy from Texas asked about how to set up a multi-mode selector switch using a single pushbutton and 3 states (not including the boot up state). What follows is this discussion that we had becoming a back and forth collaboration of ideas until I got off work and decided to see if I could make it more robust and simpler at the same time.
Lets talk about the original code… it essentially worked… with some quirks.
The original code would continuously set all the pins… every loop, even though it didn’t need to…
It also tried to process the loop even if the mode was equal to zero (IE; No button presses have occurred yet and in that case, all LED’s should be off)
Lastly, it got weird when mode was incremented to 4 and set back to 1 and in here is the behavior that I wanted to eliminate. It would change to mode 1 and 2 and 3 when the key was PRESSED but would only go back to mode 1 when button was released when in mode 3. This is just not the way to make all the button presses seem similar. All the other buttons react on the button press, not the release.
So it was SWITCH/CASE to the rescue. With switch case statements I could handle all the mode switching and deal with mode 1 and any other mode that was not 2 or 3 with the default statement. This allowed it to have all button mode migration to appear to behave the same.
The code also makes sure that pins do not get changed when they don’t need to be… IE; every loop traversal.
On to the final code example…
/*
Using a single switch to select between 3 modes
*/
// Schematic: http://www.pwillard.com/files/mode4.jpg
//===============================================================
// Global Variables & Constants
//===============================================================
const int ledPinOne = 2; // LED1 ANODE
const int ledPinTwo = 4; // LED2 ANODE
const int ledPinThree = 7; // LED3 ANODE
const int modePin = 13; // Active HIGH, held low by 4.7K
int mode = 0; // Selector State (Initial state = ALL OFF)
int val = 0; // Pin 13 HIGH/LOW Status
int butState = 0; // Last Button State
int modeState = 0; // Last Mode State
boolean debug = 1; // 1 = Print Serial Enabled / 0 = disabled
//===============================================================
// SETUP
//===============================================================
void setup () {
pinMode(ledPinOne, OUTPUT);
pinMode(ledPinTwo, OUTPUT);
pinMode(ledPinThree, OUTPUT);
pinMode(modePin, INPUT);
if (debug){
Serial.begin(9600);
Serial.print("Initial Mode: ");
Serial.println(mode);
Serial.print("Setup Complete\n");
}
}
//===============================================================
// Main Loop
//===============================================================
void loop() {
val = digitalRead(modePin);
// If we see a change in button state, increment mode value
if (val != butState && val == HIGH){
mode++;
}
butState = val; // Keep track of most recent button state
// No need to keep setting pins *every* loop
if (modeState != mode){
// If no keys have been pressed yet don't execute
// the switch code below
// if (mode != 0) {
switch ( mode ) {
//case 1 is actually handled below as default
case 2:
digitalWrite(ledPinOne, LOW);
digitalWrite(ledPinTwo, HIGH);
showState();
break;
case 3:
digitalWrite(ledPinTwo, LOW);
digitalWrite(ledPinThree, HIGH);
showState();
break;
default:
mode = 1;
// loop back to 1 by default, seems redundant but
// it also handles the "mode is > 3" problem
digitalWrite(ledPinThree, LOW);
digitalWrite(ledPinOne, HIGH);
showState();
break;
} // end switch
// } // end of "if mode = 0" check
} // end of ModeState check
modeState = mode; // Keep track of mode recent mode value
delay(10); // slow the loop just a bit for debounce
}
//===============================================================
// Subroutine
//===============================================================
void showState() {
if (debug){
Serial.print("Mode: ");
Serial.println(mode);
}
}