2

Edit 2 I made a function that works, but I'm still confused about just one thing...

I'm very confused about how variables work in C++.

In this program...

  boolean debounce(void)
{
  static boolean buttonState=LOW;
  static boolean lastButtonState;
  boolean currentState = digitalRead(4);
  static unsigned long lastDebounceTime;
  if (currentState != lastButtonState){ //if the button state has changed
    lastDebounceTime=millis();  //reset timer
    }

  if ((millis()-lastDebounceTime) > 50)  //if 50 milliseconds has passed since last bounce
  {  
    buttonState = currentState;  //read value again now that bouncing is over

    }
  lastButtonState = currentState;
  return buttonState;
} 

Why does changing this

lastButtonState = currentState;

To this

lastButtonState = buttonState;

Make any difference in the program?

When I try the latter line of code, the whole function stops working and I don't understand why.

migrated from electronics.stackexchange.com Jan 13 '16 at 22:49

This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.

  • What happens if 50ms haven't passed? – Ignacio Vazquez-Abrams Jan 13 '16 at 22:19
  • 4
    Using the same name for globals, locals & function parameters is just begging for confusion. – brhans Jan 13 '16 at 22:21
  • 1
    Your debounce() function is only being called every 500ms. That is probably not what you intended. – uint128_t Jan 13 '16 at 22:29
  • @uint128_t - Why do you say: "debounce() function is only being called every 500ms" ? I don't see that, what have I missed? – gbulmer Jan 13 '16 at 22:53
  • @gbulmer he edited his question – d3L Jan 13 '16 at 22:53
4

This probably won't answer your question completely, but here are some notes from me:

buttonState = current ;  //read value again now that bouncing is over

This won't read the value again, it just copies current into buttonValue.

What you wanted is:

buttonState = digitalRead(BUTTON); // read value again now that bouncing is over

You have multiple issues with your debounce call:

  • lastTimeDebounce is never used by your code, so it is always zero.
  • lastButtonState will be always buttonVal making the debounce function useless.

Some other tips:

  • Don't use the same names for parameters as for global variables:

    boolean debounce(boolean lastButton, long lastDebounce, int BUTTON)

    The global variable BUTTON will be shadowed by int BUTTON, essentially overriding it.

  • Don't use global variables (unless you have a very good reason)

EDIT

I would strongly recommend writing a function that debounces only one pin.

Because if you want a function which can debounce any pin you would need a state variable for each pin (which needs arrays hence a lot of space).

EDIT2:

Here is a debounce function that should work:

const uint8_t PIN = 13;

/*
 * Returns debounced value for `PIN`
 */
boolean debounce(void)
{
    // Current state of the pin
    boolean currentState;
    // Last state of the pin, initial value is zero
    static boolean lastCurrentState = 0;
    // Timer
    static unsigned long debounceTimer = millis();
    // Debounced value, initial value is zero
    static boolean debouncedValue = 0;

    // We first read the current state of the pin
    currentState = digitalRead(PIN);

    // Then we look if the state has changed
    if (currentState != lastCurrentState) {
        // If it has, we need to reset the debounce timer
        debounceTimer = millis();
    }

    // Then we check if the timer has expired
    if ((millis() - 50) > debounceTimer) {
        // The timer expired so we update the value
        debouncedValue = currentState;
    }

    // Save the latest state
    lastCurrentState = currentState;

    // We always return a debounced value:
    return debouncedValue;
}

But always test such things with an oscilloscope, no guarantee. FYI: this is not an ideal debounce function, but it should make the idea clear.

  • "buttonState = current ; This won't read the value again, it just copies current into buttonValue." I'm not questioning that your right, but I actually copied the official arduino website when I did this. arduino.cc/en/Tutorial/Debounce – Dallin Jan 14 '16 at 2:23
  • The Arduino site does not make the statement that it is actually reading the pin again. – d3L Jan 15 '16 at 20:43
  • Ok I understand now. I made my code look like yours, and my function works now. Thanks for the help. Quick question though, why does "lastCurrentState = currentState" have to go outside of the if statement? – Dallin Jan 15 '16 at 22:19
  • You could add an else and add it there and it won't affect the debouncing. I just put it there for convience. – d3L Jan 16 '16 at 0:18
  • Sorry maybe I'm still a little confused... The second if statement will be executed no matter what right? ( because the program can't exit the function unless 50 millis have passed). If this is true, why can't I put "lastCurrentState = currentState" within the second if statement? – Dallin Jan 16 '16 at 6:49
2

"It worked perfectly" is probably an overstatement. Yes, you saw the LED change when you pressed the button, but that doesn't mean it was getting debounced.

The problem is that you are trying to use global variables to remember the internal state of the debouncer function, and you're passing those variables into the function as parameters. In C (or C++, which is the underlying language that you're using), an assignment to a function parameter does NOT update the corresponding variable in the caller's environment. Therefore, lastDebounceTime never gets updated, and your debounce() function always just returns the current state of the button.

  • Beat me to it! +1 for "It worked perfectly" is probably an overstatement. Yes, you saw the LED change when you pressed the button, but that doesn't mean it was getting debounced.. A quick (possible) fix is to remove the parameters to debounce() and keep the state in global variables. A bit messy, but more useful than broken. – gbulmer Jan 13 '16 at 23:06
  • Thank you for your answer @Dave, I think I'm starting to understand. But quick question, what do you mean by "an assignment to a function parameter does NOT update the corresponding variable in the callers environment"? Does this mean assigning a variable to a function parameter is pointless? – Dallin Jan 14 '16 at 2:18
  • No, it isn't entirely pointless, because you can use it as an additional local variable inside the function. You can think of it as the caller initializing that variable for you, but then you can update it as needed while the function executes. – Dave Tweed Jan 14 '16 at 2:34
  • @gbulmer or use static variables private to debounce() – Jasen Jan 14 '16 at 9:27
  • @Jasen - Yes, that would be better. C++ classes are a bit verbose (I like to write Go) but a simple class would do, or a struct if there were several buttons to handle. – gbulmer Jan 14 '16 at 16:51
1

Im not an expert of C programming, but I can see lot of troubles in your programming, because you do call a function debounce(), but it is not a function that does a complete task, so you set additional variables outside of it. This is a bad practice, because you can't call the same function to compute multiple keys, that's what functons are for - make one function and call multiple times with different parameters. You should switch to pointer orented parameters for lastButtonState.

    boolean LastButton_1; // global or static variable
    long LastDebounce_1;
    int BUTTON_1;
        ... and so on



    boolean debounce(boolean *LastButton, long *LastDebounce, int BUTTON)
        {
          //your code here, where you read and write to variables located at pointer
           boolean something, new_value;
           something = *LastButton; //read value at pointer address
           *LastButton = new_value; //store the value at pointer address
        } 
//now you call this
debounce(&LastButton_1, &LastDebounce_1, BUTTON_1)

Perhaps it is not correct, since I know only very basic C, but the way is the right one

1

If you only have one button to debounce, you can store it's state as static variables in the debounce() function itself, like:

bool debounce()
{
    const int pin = 4;
    static bool last_state;
    static unsigned long last_change;
    unsigned long now = millis();

    if (now - last_change > 50) {
        bool state = digitalRead(pin);
        if (state != last_state) {
            last_change = now;
            last_state = state;
        }
    }
    return last_state;
}

If you may have to debounce more than one button, the cleaner way would be to store the state inside an object, and have the debounce function be one of its methods. That's what the Bounce library does.

  • Strictly speaking, digitalRead() returns an int not a bool. – Nick Gammon Jan 15 '16 at 3:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.