Building a Debounce Function for use in a different Loop

Hi all,

I am tying to use the debounce example as a function to toggle switch state. As i will have a few switch inputs in my Loop I though having 1 function to manage this would be better.

This is the code as it sits right now...

// constants won't change. They're used here to
// set pin numbers:

const int upMotor = 8;     
const int dnMotor = 9;
const int button1 = 2;   
const int button2 = 3;



void setup() {

  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(upMotor, OUTPUT);
  pinMode(dnMotor, OUTPUT);  



  // set initial Motor state

  
  Serial.begin(9600);
 
  
}

void loop(){
  int upButtonState = LOW;
  int dnButtonState = LOW;
  int upButton;
  int dnButton;
  int upMotorState;
  

  
  upButton = digitalRead(button1);
  dnButton = digitalRead(button2);
  
  digitalWrite(upMotor, upMotorState);

upButtonState = debounce(upButton);

Serial.print(upButton);
Serial.print(upButtonState);
Serial.print(upMotorState);





}

int debounce(int button) {

  
  
 // the current state of the output pin
int outputState = LOW;
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

 


long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers


  // read the state of the switch into a local variable:
  int reading = digitalRead(button);

  Serial.print(" buttonState ");
Serial.print(buttonState);
Serial.print(" lastButtonState ");
Serial.print(lastButtonState);
Serial.print(" lastDebounceTime ");
Serial.print(lastDebounceTime);  
Serial.println(reading);
 
  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the output if the new button state is HIGH
      if (buttonState == HIGH) {
        outputState = !outputState;
       
      }
    }
  }

  // set the output:

  return outputState;



  // save the reading.  Next time through,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

Some notable behavior:
"upButton" and "reading" Both change state on the button press. Which is to be expected. However, "lastbuttonState" and "lastDebounceTime" do not change at all.

SO what I am assuming is that there is a breakdown somewhere around line 89 of this code "if (reading != lastButtonState)".

any ideas or suggestions what what to do next to see why this is getting stuck would be appreciated.

long lastDebounceTime = 0; // the last time the output pin was toggled
Since the above is a local variable it vaporizes when you leave the function.
Also make it 'unsigned long' if you want to store millis()
lastDebounceTime = millis();

int lastButtonState = LOW; // the previous reading from the input pin
Same as above.
Better look into what 'global, local, static' means.
lastButtonState = reading;

Cool, I take a look at those and see what happens next.

BTW
I use Nick Gammon's switch monitor to deal with switches.
http://gammon.com.au/Arduino/SwitchManager.zip
You may want to examine this example:

/*SwitchManager skeleton 
 
 This sketch is to introduce new people to the SwitchManager library written by Nick Gammon
 
 The library handles switch de-bouncing and provides timing and state change information in your sketch.
 The SwitchManager.h file should be placed in your libraries folder, i.e.
 C:\Users\YourName\Documents\Arduino\libraries\SwitchManager\SwitchManager.h
 You can download the library at:
 http://gammon.com.au/Arduino/SwitchManager.zip    Thank you Nick!
 
 In this example we have 2 normally open (N.O.) switches connected to the Arduino - increment and decrement.
 The increment switch will also be used as a "Reset" switch if pressed for more than two seconds.
 The two switches are connected between GND (0 volts) and an Arduino input pin.
 The library enables pull-up resistors for your switch inputs.
 Pushing a switch makes its pin LOW. Releasing a switch makes its pin HIGH.
 
 The SwitchManager library provides 10ms de-bounce for switches. 
 i.e. enum { debounceTime = 10, noSwitch = -1 };
 If you need more time, edit the SwitchManager.h file
 i.e. enum { debounceTime = 50, noSwitch = -1 }; //here it is changed to 50ms
 */

#include <SwitchManager.h>             
//object instantiations
SwitchManager myIncSwitch;
SwitchManager myDecSwitch;

unsigned long currentMillis;
unsigned long heartBeatMillis;
unsigned long heartFlashRate  = 500UL; // time the led will change state       
unsigned long incShortPress   = 500UL; // 1/2 second
unsigned long incLongPress    = 2000UL;// 2 seconds 
unsigned long decShortPress   = 500UL; // 1/2 second

const byte heartBeatLED       = 13;
const byte incSwitch          = 4; //increment switch is on Arduino pin 4
const byte decSwitch          = 5; //decrement switch is on Arduino pin 5

int myCounter;

//======================================================================

void setup()
{
  Serial.begin(9600);

  //gives a visual indication if the sketch is blocking
  pinMode(heartBeatLED, OUTPUT);  

  myIncSwitch.begin (incSwitch, handleSwitchPresses); 
  myDecSwitch.begin (decSwitch, handleSwitchPresses);
  //the handleSwitchPresses() function is called when a switch changes state

} //                   E N D  O F  s e t u p ( )

//======================================================================

void loop()
{
  //leave this line of code at the top of loop()
  currentMillis = millis();

  //***************************
  //some code to see if the sketch is blocking
  if (CheckTime(heartBeatMillis, heartFlashRate, true))
  {
    //toggle the heartBeatLED
    digitalWrite(heartBeatLED,!digitalRead(heartBeatLED));
  }

  //***************************
  //check to see what's happening with the switches
  //"Do not use delay()s" in your sketch as it will make switch changes unresponsive 
  //Use BlinkWithoutDelay (BWD) techniques instead.
  myIncSwitch.check ();  
  myDecSwitch.check (); 

  //***************************
  //put other non-blocking stuff here


} //                      E N D  O F  l o o p ( )


//======================================================================
//                          F U N C T I O N S
//======================================================================


//                        C h e c k T i m e ( ) 
//**********************************************************************
//Delay time expired function
//parameters:
//lastMillis = time we started
//wait = delay in ms
//restart = do we start again  

boolean CheckTime(unsigned long  & lastMillis, unsigned long wait, boolean restart) 
{
  //has time expired for this task?
  if (currentMillis - lastMillis >= wait) 
  {
    //should this start again? 
    if(restart)
    {
      //yes, get ready for the next iteration
      lastMillis = millis();  
    }
    return true;
  }
  return false;

} //                 E N D   o f   C h e c k T i m e ( )


//                h a n d l e S w i t c h P r e s s e s( )
//**********************************************************************

void handleSwitchPresses(const byte newState, const unsigned long interval, const byte whichPin)
{
  //  You get here "ONLY" if there has been a change in a switches state.

  //When a switch has changed state, SwitchManager passes this function 3 arguments:
  //"newState" this will be HIGH or LOW. This is the state the switch is in now.
  //"interval" the number of milliseconds the switch stayed in the previous state
  //"whichPin" is the switch pin that we are examining  

  switch (whichPin)
  {
    //***************************
    //are we dealing with this switch?
  case incSwitch: 

    //has this switch gone from LOW to HIGH (gone from pressed to not pressed)
    //this happens with normally open switches wired as mentioned at the top of this sketch
    if (newState == HIGH)
    {
      //The incSwitch was just released
      //was this a short press followed by a switch release
      if(interval <= incShortPress) 
      {
        Serial.print("My counter value is = ");
        myCounter++;
        if(myCounter > 1000)
        {
          //limit the counter to a maximum of 1000
          myCounter = 1000; 
        }
        Serial.println(myCounter);
      }

      //was this a long press followed by a switch release
      else if(interval >= incLongPress) 
        //we could also have an upper limit
        //if incLongMillis was 2000UL; we could then have a window between 2-3 seconds
        //else if(interval >= incLongMillis && interval <= incLongMillis + 1000UL) 
      {
        //this could be used to change states in a StateMachine
        //in this example however, we will just reset myCounter
        myCounter = 0;
        Serial.print("My counter value is = ");
        Serial.println(myCounter);
      }

    }

    //if the switch is a normally closed (N.C.) and opens on a press this section would be used
    //the switch must have gone from HIGH to LOW 
    else 
    {
      Serial.println("The incSwitch was just pushed");
    } 

    break; //End of case incSwitch

    //*************************** 
    //are we dealing with this switch?
  case decSwitch: 

    //has this switch gone from LOW to HIGH (gone from pressed to not pressed)
    //this happens with normally open switches wired as mentioned at the top of this sketch
    if (newState == HIGH)
    {
      //The decSwitch was just released
      //was this a short press followed by a switch release
      if(interval <= decShortPress) 
      {
        Serial.print("My counter value is = ");
        myCounter--;
        if(myCounter < 0) 
        {
          //don't go below zero
          myCounter = 0;
        }
        Serial.println(myCounter);
      }

    }

    //if the switch is a normally closed (N.C.) and opens on a press this section would be used
    //the switch must have gone from HIGH to LOW
    else 
    {
      Serial.println("The decSwitch switch was just pushed");
    } 

    break; //End of case decSwitch

    //*************************** 
    //Put default stuff here
    //default:
    //break; //END of default

  } //End switch (whichPin)

} //      E n d   o f   h a n d l e S w i t c h P r e s s e s ( )


//======================================================================
//                      E N D  O F  C O D E
//======================================================================

.

Again thank you. The learning curve has been like trying to drink from the end of a fire hose.

Just took a look at that library. And it kind of what I am after, its still not quite what I am trying to do.

Really what I am trying to accomplish is turning a physical momentary switch into a latched switch for later use in the code.

The example debounce code is close because i can toggle an output. But I want that "output" to be something i can use as a HIGH/LOW state and then further use in an argument. I hope that makes sense.

In its simplest form, what do you want the switch to do?

I want a momentary switch to turn an output on.
I want a second switch to turn a different output on.
I cannot have both outputs on at the same time.

This is for an H-bridge motor control.

What I THOUGHT I could do was:
have 1 function that would handle the inputs and outputs. i.e. switch 1 would change a status that I could then use to turn the motor on.

Using that same bit of code for the "status changing" I could use button 2.

So to reword that: 2 inputs make 2 separate "status" outputs using the same lines of code.

EDIT:
Resources for learning are what i am looking for not an out right answer.

Cheers.

Let us assume the first switch is pushed and output 1 is turned on.
If the second switch is then pushed what do you want to happen?

.

Ah, this is where it gets interesting for me.

what i would like is for it stop the first output OR if the first output is already not running THEN i would like it to turn on the second output.

First output spins the motor in 1 direction
Second output spins motor in opposite direction.

Let's use the same language.
Don't say 'stop' or 'running'.

At the start both outputs are low.
If you press the first button the first output goes high.
If you press the second button you want the first output to go low and then second output to go high.
If you press the first button again 1st output goes high again and the 2nd goes low.

How will you ever make both outputs go low?

All this has to be written down before coding.

.

Ok no more stop and start. Let's see if this clears things up a bit.

inputs:
Button1
Button 2

Outputs:
motorForward (Forward)
motorReverse (Reverse)

Both button inputs are internally pulled up. so if we can, for arguments sake, HIGH is released, LOW is pressed.
And for clarity on the outputs, HIGH is active, LOW is inactive.

On startup:
both inputs are are HIGH and both outputs are LOW.

I would like the flow to go like this

Button1 = LOW and Forward = HIGH, Reverse = LOW
Button1 = HIGH and still Forward = HIGH, Reverse = LOW
(Forward output effectively toggled)

This is where I thought I could make toggled HIGH/LOW state from a momentary input.

Button2 = LOW, Forward = LOW, Reverse = LOW
Button2 = HIGH, Forward = LOW, Reverse = LOW
(again just toggling the Forward output but with a second input source)

Button2 = LOW, Reverse = HIGH, Forward = LOW
Button2 = HIGH, still Reverse = HIGH, Forward = LOW
Button 1 =LOW, Reverse = LOW, Forward = LOW
Button 1 = HIGH, Reverse = LOW, Forward = LOW

(same as the first operation but in reverse direction)

and since its an H-bridge, as I understand, both outputs cannot be HIGH at the same time.

I'm not following.

Button1 = LOW and Forward = HIGH, Reverse = LOW
Button1 = HIGH and still Forward = HIGH, Reverse = LOW
(Forward output effectively toggled)
OR
Button1 = LOW and motorForward = HIGH, motorReverse = LOW
Button1 = HIGH and still motorForward = HIGH, motorReverse = LOW
(Forward output effectively toggled)

I don't see that there is any changing on your outputs.

.

Ok I'll try this a different way.

Pressing button 1
Button 1 = FALLING EDGE and Reverse = LOW. then Forward = HIGH,
Pressing Button 2
Button 2 = FALLING EDGE and Reverse = LOW. then Forward = LOW,

Button 2 = FALLING EDGE and Forward =LOW. then Reverse = HIGH,
Button 1 = FALLING EDGE and Forward = LOW. then Reverse = LOW

That sounds doable with Mr. Gammon's library.

  1. When you say falling edge do you mean releasing the switch?

  2. Your switch is is wired as S3?

When I say falling edge I mean going from 5v-0v.

Yes its wired per S3.

Ok, let's see what you can do with Nick's library.
How would you start?

.

Look at this.
Before you try it out on the hardware let's discuss.

//Version 2

/*SwitchManager skeleton
 LarryD
 
 This sketch is to introduce new people to the SwitchManager library written by Nick Gammon
 
 The library handles switch de-bouncing and provides timing and state change information in your sketch.
 The SwitchManager.h file should be placed in your libraries folder, i.e.
 C:\Users\YourName\Documents\Arduino\libraries\SwitchManager\SwitchManager.h
 You can download the library at:
 http://gammon.com.au/Arduino/SwitchManager.zip    Thank you Nick!

 The SwitchManager library provides 10ms de-bounce for switches. 
 i.e. enum { debounceTime = 10, noSwitch = -1 };
 If you need more time, edit the SwitchManager.h file
 i.e. enum { debounceTime = 50, noSwitch = -1 }; //here it is changed to 50ms
 */

#include <SwitchManager.h>             
//object instantiations
SwitchManager Button1Switch;
SwitchManager Button2Switch;

unsigned long heartBeatMillis;
unsigned long heartFlashRate  = 500UL; // time the led will change state       

const byte heartBeatLED = 13;
const byte Button1      =  4;  //Switch wired to GND, N.O.
const byte Button2      =  5;  //Switch wired to GND, N.O
const byte motorForward =  8;
const byte motorReverse =  9;

//======================================================================

void setup()
{
  Serial.begin(9600);

  //gives a visual indication if the sketch is blocking
  pinMode(heartBeatLED, OUTPUT); 
 
  digitalWrite(motorForward, LOW);
  pinMode(motorForward, OUTPUT);

  digitalWrite(motorReverse, LOW);  
  pinMode(motorReverse, OUTPUT);

  Button1Switch.begin (Button1, handleSwitchPresses); 
  Button2Switch.begin (Button2, handleSwitchPresses);
  //the handleSwitchPresses() function is called when a switch changes state

} //                   E N D  o f  s e t u p ( )

//======================================================================

void loop()
{
  //***************************
  //some code to see if the sketch is blocking
  if (CheckTime(heartBeatMillis, heartFlashRate, true))
  {
    //toggle the heartBeatLED
    digitalWrite(heartBeatLED,!digitalRead(heartBeatLED));
  }

  //***************************
  //check to see what's happening with the switches
  //"Do not use delay()s" in your sketch as it will make switch changes unresponsive 
  //Use BlinkWithoutDelay (BWD) techniques instead.
  Button1Switch.check ();  
  Button2Switch.check (); 

  //*********************************
  //put other non-blocking stuff here
  //*********************************

} //                      E N D  o f  l o o p ( )


//======================================================================
//                          F U N C T I O N S
//======================================================================


//                        C h e c k T i m e ( ) 
//**********************************************************************
//Delay time expired function
//parameters:
//lastMillis = time we started
//wait       = delay in ms
//restart    = do we start timing again  

boolean CheckTime(unsigned long  & lastMillis, unsigned long wait, boolean restart) 
{
  //has time expired for this task?
  if (millis() - lastMillis >= wait) 
  {
    //should this start again? 
    if(restart)
    {
      //yes, get ready for the next iteration
      lastMillis = millis();  
    }
    return true; //the timer has timed out
  }
  return false;  //the timer has not timed out

} //                 E N D   o f   C h e c k T i m e ( )


//                h a n d l e S w i t c h P r e s s e s( )
//**********************************************************************

void handleSwitchPresses(const byte newState, const unsigned long interval, const byte whichPin)
{
  //You get here 'ONLY' if there has been a change in a switches state.

  //when a switch has changed state, SwitchManager passes this function 3 arguments:
  //"newState" this will be HIGH or LOW. This is the state the switch is in now.
  //"interval" the number of milliseconds the switch stayed in the previous state
  //"whichPin" is the switch pin that we are examining  

  switch (whichPin)
  {
    //********************************
    //are we dealing with this switch?
  case Button1: 

    //has this switch gone from LOW to HIGH (gone from pressed to not pressed)
    //this happens with normally open switches wired as mentioned at the top of this sketch
    if (newState == HIGH)
    {
      //Button1 was just released
    }

    else 
    {
      //Button1 was just pushed
      if(digitalRead(motorReverse) == LOW)
      {
        digitalWrite(motorForward, HIGH);
      }

      else if(digitalRead(motorForward) == LOW)
      {
        digitalWrite(motorReverse, LOW);
      }      
    } 

    break; //End of case Button1

    //******************************** 
    //are we dealing with this switch?
  case Button2: 

    //has this switch gone from LOW to HIGH (gone from pressed to not pressed)
    //this happens with normally open switches wired as mentioned at the top of this sketch
    if (newState == HIGH)
    {
      //Button2 was just released
    }

    else 
    {
      //Button2 was just pushed
      if(digitalRead(motorForward) == LOW)
      {
        digitalWrite(motorReverse, HIGH);
      }

      else if(digitalRead(motorReverse) == LOW)
      {
        digitalWrite(motorForward, LOW);        
      }
      
    } 

    break; //End of case Button2Switch

    //*************************** 
    //Put default stuff here
    //default:
    //break; //END of default

  } //End of switch (whichPin)

} //      E n d   o f   h a n d l e S w i t c h P r e s s e s ( )


//======================================================================
//                      E N D  O F  C O D E
//======================================================================

.

So, you have three states: STOPPED, FORWARD, and REVERSE.

You have two inputs: SWITCH1 and SWITCH2. These are momentary buttons, and we won't worry for the moment about debouncing, etc. We will also ignore for the moment what heappens if they are pressed simultaneously (perhaps this should unconditionally stop?)

Can we stop calling these SWITCH1 and SWITCH2? It's lazy. Let's call 'em FORWARD_BUTTON and REVESE_BUTTON.

Let us assume the first switch is pushed and output 1 is turned on.
If the second switch is then pushed what do you want to happen?

Ah, this is where it gets interesting for me.

what i would like is for it stop the first output OR if the first output is already not running THEN i would like it to turn on the second output.

So the state transitions are:
STOPPED + FORWARD_BUTTON -> FORWARD
STOPPED + REVERSE_BUTTON -> REVERSE

FORWARD + FORWARD_BUTTON -> STOPPED
REVERSE + FORWARD_BUTTON -> STOPPED
FORWARD + REVERSE_BUTTON -> STOPPED
REVERSE + REVERSE_BUTTON -> STOPPED

Well, that's pretty straightforward. With respect to debouncing, ideally we'd like a separate debounce delay for each switch. Easy way to do this is to use a class.

enum State {
  STOPPED = 0,
  FORWARD = 1,
  REVERSE = 2
} state;

struct Button {
  const byte pin;
  unsigned long debounce_start_ms;
  int state;
  boolean just_been_pressed = false;
  boolean just_been_released = false;

  Button(const byte pin) : pin(pin) {}

  void setup() {
    pinMode(pin, INPUT_PULLUP);
    state = digitalRead(pin);
    debounce_start_ms = millis();
  }

  void check() {
    just_been_pressed = false;
    just_been_released = false;

    if (millis() - debounce_start_ms < 50) {
      // do nothing;
    }
    else {
      int newState = digitalRead(pin);
      if (newState == state) {
        // do nothing
      }
      else {
        debounce_start_ms = millis();
        if (newState == LOW) {
          just_been_pressed = true;
        }
        else {
          just_been_released = true;
        }
        state = newState;
      }
    }
  }
};

// PINOUT - usually I like to use enums, but this is simple enough.

Button forwardButton = Button(3);
Button reverseButton = Button(4);

// and you will also need pinout for the motor.

void setup() {
  forwardButton.setup();
  reverseButton.setup();

  // set up your H-bridge

  stopMotor();
  state = STOPPED;
}

void loop() {
  forwardButton.check();
  reverseButton.check();

  if (forwardButton.state == LOW && reverseButton.state == LOW) {
    if (state != STOPPED) {
      // unconditional emergency stop!
      stopMotor();
      state = STOPPED;
    }
  }
  else {
    if (state == STOPPED) {
      // if we are stopped, ether button will start the motor
      if (forwardButton.just_been_pressed) {
        startMotorForward();
        state = FORWARD;
      }
      else if (reverseButton.just_been_pressed) {
        startMotorReverse();
        state = REVERSE;
      }
    }
    else {
      // if we are not stopped, ether button will stop the motor
      if (forwardButton.just_been_pressed || reverseButton.just_been_pressed) {
        stopMotor();
        state = STOPPED;
      }
    }
  }
}

void stopMotor() {}

void startMotorForward() {}

void startMotorReverse() {}

Wow! Thanks guys. I will wrap my head around each bit of code you've provided and let you know what questions I have.