Skip to content

Instantly share code, notes, and snippets.

  • Star 13 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save NormalUniverse/5b3a8a8d909b56b58b67bd3ec2808f4b to your computer and use it in GitHub Desktop.
//Title: Button Debouncing using a State Machine, Complex Version
//Author: Chris Guichet
//Date: Jan 15, 2018
//
//Description:
// -A State Machine is a useful tool to organize complex code
// -Think of it like the next step beyone "If Else" statements
// -This example code uses a State Machine to handle tac switch debouncing
// -It also has a "Hold" function to enable interaction with long button presses
//
//Wiring Instructions:
// -Wire a SPST momentary switch between a Digital I/O pin and Ground. (I use pin 12)
// (we will use an internal pullup resistor, so no need to worry about wiring a resistor)
//
//Code Reading Tip:
// -Before mentally digesting this code, collapse all folds to get a bird's eye view.
// -Ctrl-a (to select all) -> Right Click -> Folding -> Collapse All Folds
//Top Level Variables:
int DEBUG = 1; //Set to 1 to enable serial monitor debugging info
//Switch Variables:
int state_s1 = 0;
int state_prev_s1 = 0;
int pin_s1 = 12;
int val_s1 = 0;
unsigned long t_s1 = 0;
unsigned long t_0_s1 = 0;
unsigned long bounce_delay_s1 = 10;
unsigned long hold_delay_s1 = 1000;
void setup() {
// initialize digital pins
pinMode(12,INPUT_PULLUP); //INPUT_PULLUP will use the Arduino's internal pullup resistor
//if DEBUG is turned on, intiialize serial connection
if(DEBUG) {Serial.begin(115200);Serial.println("Debugging is ON");}
}
void loop() {
// put your main code here, to run repeatedly:
SM_s1();
//If debug is enabled, do some printing of messages
//Let the world know when the state changes
if(DEBUG) {
if(state_prev_s1 != state_s1) {Serial.print("Switch State: "); Serial.println(state_s1);}
};
//Let the world know when the button is held or pressed
if (DEBUG) {Serial.println("HOLDED!!");}
if (DEBUG) {Serial.println("TRIGGERED!!");}
}
void SM_s1() {
//Almost every state needs these lines, so I'll put it outside the State Machine
val_s1 = digitalRead(pin_s1);
state_prev_s1 = state_s1;
//State Machine Section
switch (state_s1) {
case 0: //RESET!
//Catch all "home base" for the State MAchine
state_s1 = 1;
break;
case 1: //WAIT
//Wait for the switch to go low
if (val_s1 == LOW) {state_s1 = 2;}
break;
case 2: //ARMING!
//Record the time and proceed to ARMED
t_0_s1 = millis();
state_s1 = 3;
break;
case 3: //ARMED
//Check to see if the proper has delay has passed. If a bounce occures then RESET
t_s1 = millis();
if (t_s1 - t_0_s1 > bounce_delay_s1) {state_s1 = 4;}
if (val_s1 == HIGH) {state_s1 = 0;}
break;
case 4: //DRAWN
//If switch goes HIGH, then TRIGGER. Also check timer for a "Long Pess"
t_s1 = millis();
if (val_s1 == HIGH) {state_s1 = 5;}
if (t_s1 - t_0_s1 > hold_delay_s1) {state_s1 = 6;}
break;
case 5: //TRIGGERED!
//reset the State Machine
state_s1 = 0;
break;
case 6: //HOLD!
//proceed to LOW WAIT
state_s1 = 7;
break;
case 7: //LOW WAIT
//wait for switch to go back HIGH, then reset
if (val_s1 == HIGH) {state_s1 = 0;}
break;
}
}
@tbair8
Copy link

tbair8 commented Feb 4, 2019

Awesome!! Thanks for sharing.

@redalrt
Copy link

redalrt commented Jul 30, 2019

Very cool, Thank you!

@yhde-oliveira-falcao
Copy link

The "if (DEBUG) {Serial.println("HOLDED!!");}" part is, by this logic, being called whenever DEBUG is 1 (always), so I put a report of the trigger or hold in their respective functions.
But this logic is very good, thank you very much for sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment