Debounce Time Code Explanation

I really need someone to explain the Debounce code example to me line by line. I am getting lost in the loop and when it is kicking out of the if statements. I have posted the code I am using. I have everything set up correctly and the circuit is behaving as expected. LED light is on when the code is loaded and turns off and stays off when I press the button until I press it again. It's really the code I am struggling with understanding. Any help is appreciated.

//Debounce

/* Each time the input pin goes from LOW to high (e.g. because of a push-button press),
   the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a minimum delay
   between toggles to debounce the circuit (i.e to ignore noise)

   The Circuit:
   LED attached from PIN 8 to ground through 220 ohm resistor.
   Push button attached to pin 2 from +5V
   10K resistor attached to pin 2 from ground
*/

//Constants won't change. They're used here to set pin numbers:
const int buttonPin = 2; //The number of the pushbutton pin.
const int ledPin = 8; //The number of the LED pin.

//Variables will change:
int ledState = HIGH; //The current state of the output pin.
int buttonState; //The current reading from the input pin.
int lastButtonState = LOW; // The previous reading from the input pin.

//The following variables are unsigned longs because the time, measured in
//milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; //The last time the output pin was toggled.
unsigned long debounceDelay = 50; //The debounce time; increase if the output flickers

void setup() 
{
  pinMode(ledPin, OUTPUT); //Initialize the LED pin as an output.

  pinMode(buttonPin, INPUT); //Initialize the pushbutton pin as an input.

  digitalWrite(ledPin, ledState); //Set initial LED state
}

void loop() 
{
 int reading = digitalRead(buttonPin); //Read the state of the switch into a local variable:

 //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 (reading != lastButtonState)
 {
  lastDebounceTime = millis(); //Reset the debouncing timer
 }

 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 (reading != buttonState) //If the button state has changed:
  {
    buttonState = reading;

    if (buttonState == HIGH) //Only toggle the LED if the new button state is high
    {
      ledState = !ledState;
    }
  }
 }

digitalWrite(ledPin, ledState); //Set the LED:

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

You can learn what the code is doing by adding the ability to use your serial.Print() to display a line identifier and the variable values for each variable in the line of code.
Then after the line, display the results if there is a compare or function call, etc.

1 Like

What part of the sketch are you having trouble understanding ?

1 Like

I tried doing that for one line of code to check it and got a result I did not understand. I assume I would need to start the serial monitor in the setup code. Would you be willing to provide a short example in the loop code to describe what you mean. In the mean time I am going to play around with the code in the manner I think you are suggesting to see what I get.

here's the project in a sim..
Uno Button Led

well, documented code..

have fun.. ~q

1 Like

I was getting lost really bad in the if statements. I am applying Paul_KD7HB suggested methodology by using the serial monitor and I am adding delays to slow the serial monitor down so I can read it. A little clunky but getting the job done to help me understand a little better.

1 Like

In most situations, you can simply sample your switches every 50ms and look for a change in input state.

No other de-bouncing of the switch is needed.

2 Likes

Yeah when I was taking a look at it ignoring the whole debounce code I felt like the code would still accomplish turning the LED on and off by pressing the button as long as I wait long enough between presses. Which I really would not have to wait that long. Correct me if I am wrong.

Bouncy switches settle out around 10-15ms.

The need behind de-bouncing is the Arduino is so fast it catches noisy switch contact changes.

i.e. loop( ) runs very fast, let’s say 100us.

With loop( ) running at 100us and if we get 50 switch bounces in 15ms the Arduino catches each transition :face_with_spiral_eyes:

When we only sample our switches at 50ms, and switches settle in less than 15ms, switch bounces are not caught.

1 Like

I kind of sort of figured it now. Yep I get the need for debounce code when it is looping so fast. Still trying to understand the debounce code. I know what it is doing just not sure how. However I will say that when I took the debounce code out and properly spaced all of the if statements I was able to follow the code a lot better. So I save the example with and without the debounce code for future reference. I really appreciate everyone's input. I am still learning and following the examples built into the IDE but for some reason I feel like the code to turn the LED on/off with the button could have been done in way fewer lines of code. Maybe I am wrong though.

Maybe this will help.



#define PRESSED                     LOW   //+5V---[Internal 50k]---PIN---[Switch]---GND
#define RELEASED                    HIGH

#define LEDon                       HIGH
#define LEDoff                      LOW

const byte toggleSwitch           = 2;
const byte testLED                = 12;
const byte heartbeatLED           = 13;

byte lastToggleSwitch             = RELEASED;

unsigned long heartbeatTIME;
unsigned long checkSwitchesTime;


//********************************************^************************************************
void setup()
{
  pinMode(toggleSwitch, INPUT_PULLUP);

  digitalWrite(testLED, LEDoff);
  pinMode(testLED, OUTPUT);
  
  pinMode(heartbeatLED, OUTPUT);

} //END of   setup()


//********************************************^************************************************
void loop()
{
  //********************************************
  //time to toggle the heartbeat LED ?
  if (millis() - heartbeatTIME >= 500ul)
  {
    //restart this TIMER
    heartbeatTIME = millis();

    //toggle the heartbeat LED
    if (digitalRead(heartbeatLED) == HIGH) digitalWrite(heartbeatLED, LOW);
    else digitalWrite(heartbeatLED, HIGH);
  }

  //********************************************
  //time to check our switches ?
  if (millis() - checkSwitchesTime >= 50ul)
  {
    //restart this TIMER
    checkSwitchesTime = millis();

    checkSwitches();
  }

} //END of   loop()


//********************************************^************************************************
void checkSwitches()
{
  byte state;

  //************************************************              toggleSwitch
  state = digitalRead(toggleSwitch);

  //************************
  //has there been a change in state ?
  if (lastToggleSwitch != state)
  {
    //update to the new state
    lastToggleSwitch = state;

    //is the switch pressed ?
    if (state == PRESSED)
    {
      if (digitalRead(testLED) == HIGH) digitalWrite(testLED, LOW);
      else digitalWrite(testLED, HIGH);
    }
  }

} //END of   checkSwitches()


//********************************************^************************************************





1 Like
void loop()
{
    int reading = digitalRead(buttonPin);

    if (reading != lastButtonState)
        lastDebounceTime = millis();

    if ((millis() - lastDebounceTime) > debounceDelay) {
        if (reading != buttonState) {
            buttonState = reading;

            if (buttonState == HIGH)
                ledState = !ledState;
        }
    }

    digitalWrite(ledPin, ledState);

    lastButtonState = reading;
}

this code seems unnecessarily complicated and may not work reliably

  • after recognizing a state change, a timestamp is captured
  • when the timer expires, it attempts to toggle ledState when the button is released. the additional check that the button state has changed, seems unnecessary

the other issue is what the button state is when pressed. buttons are typically connected between the pin and ground, the pin configured as INPUT_PULLUP to use the internal pullup resistor which pulls the pin HIGH and when pressed, the button pulls the pin LOW.

this seems a bit clearer

    int reading = digitalRead(buttonPin);

    if (reading != lastButtonState)  {
        lastButtonState = reading;
        lastDebounceTime = millis();
    }

    if ((millis() - lastDebounceTime) > debounceDelay) {
        if (buttonState == LOW)
            ledState = !ledState;
            digitalWrite(ledPin, ledState);
        }
    }

but unless there's some severe real-time restriction where the code can't tolerate a 20 msec delay, why not simply

    int reading = digitalRead(buttonPin);

    if (reading != lastButtonState)  {
        lastButtonState = reading;
        delay (20);                 // debounce

        if (buttonState == LOW)
            ledState = !ledState;
            digitalWrite(ledPin, ledState);
        }
    }
1 Like

This is exactly why variable names are so important.
The sketch in the OP has 3 variables tracking the various button states.
They are: reading, buttonState and lastButtonState.
I just changed them to: newButtonState, currentButtonState and previousButtonState.
I think that makes it a whole lot easier to understand whats happening. YMMV

//Debounce

/* Each time the input pin goes from LOW to high (e.g. because of a push-button press),
   the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a minimum delay
   between toggles to debounce the circuit (i.e to ignore noise)

   The Circuit:
   LED attached from PIN 8 to ground through 220 ohm resistor.
   Push button attached to pin 2 from +5V
   10K resistor attached to pin 2 from ground
*/

//Constants won't change. They're used here to set pin numbers:
const int buttonPin = 2; //The number of the pushbutton pin.
const int ledPin = 8; //The number of the LED pin.

//Variables will change:
int ledState = HIGH; //The current state of the output pin.
int currentButtonState; //The current reading from the input pin.
int previousButtonState = LOW; // The previous reading from the input pin.

//The following variables are unsigned longs because the time, measured in
//milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; //The last time the output pin was toggled.
unsigned long debounceDelay = 50; //The debounce time; increase if the output flickers

void setup() 
{
  pinMode(ledPin, OUTPUT); //Initialize the LED pin as an output.

  pinMode(buttonPin, INPUT); //Initialize the pushbutton pin as an input.

  digitalWrite(ledPin, ledState); //Set initial LED state
}

void loop() 
{
 int newButtonState = digitalRead(buttonPin); //Read the state of the switch into a local variable:

 //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 (newButtonState != previousButtonState)
 {
  lastDebounceTime = millis(); //Reset the debouncing timer
 }

 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 (newButtonState != currentButtonState) //If the button state has changed:
  {
    currentButtonState = newButtonState;

    if (currentButtonState == HIGH) //Only toggle the LED if the new button state is high
    {
      ledState = !ledState;
    }
  }
 }

digitalWrite(ledPin, ledState); //Set the LED:

previousButtonState = newButtonState; //Save the reading. Next time through the loop, it'll be the previousButtonState:
}
1 Like

i just realized that buttonState is not set in the code i posted can either be lastButtonState or reading.

        if (astButtonState == LOW)
            ledState = !ledState;
            digitalWrite(ledPin, ledState);
        }
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.