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); } }
Hi, I understand that this is an old post, but I’m trying to incorporate a second switch that will decrement cases, but cannot get it to work. Any idea how to implement?
Thanks!
Hi Petros,I am trying to do the same thing. Did you find a way? Thank you in advance.
Hi Thodoris, the problem is using the default case to go from state 3 to state 1. This only works for incrementing. If you want to decrement, you have to handle that with if statements.
Have 2 versions of val, modePin, butState, like valUp and valDown,etc. Of course you need to make Down versions of lines 15, 16, 17, and 27.
Duplicate line 44 with the valDown version, but make line 45 portion mode–.
Change line 14 to mode = -1, to use mode 0 as a wrap around flag.
Then handle the wrap around with these ifs.
if (mode==4){mode = 1};
if (mode==0){mode = 3};
I may be missing something, but this should get you started. Post your code.
Sorry, typo, mode- should be mode–. Also line 48 needs to be duplicated with a Down version.
Looks like two minus signs can’t be displayed. Each time I post it changes them to a single one, but longer. Ill try it with a space (no space needed in your code). mode – – not mode-