statechangedetection and debounce

Hi,

When a button is pressed 3 times within 2 seconds, a led light up.
I’ve done this with the arranged sketch of StateChangeDetection.

Now I want to debounce the button.
But in the Debounce example there look likes a StateChangeDetection too.
When I try to combine this, i think a few statements are double, but I’m not sure of it.

How can i combine these two examples?

This is the my first code (sorry for dutch comment)

const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

unsigned long starttime;
unsigned long stoptime;
int time;

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  
  buttonState = digitalRead(buttonPin);                //uitlezen knop

  if (buttonState != lastButtonState) {                // vergelijken met vorige staat van de knop
    if (buttonState == HIGH) {                        // als de status nu HIGH is, is hij dus van LOW naar HIGH gegaan en is de knop dus INgedrukt.
      buttonPushCounter++;                            // we tellen nu +1
      if (buttonPushCounter < 2){                     //als de teller kleiner is dan 2
        starttime = millis();                         //noemen we dit de starttime (gevuld met de functie millis(), die te tijd in millisec. aangeeft vanaf de start van de sketch)
        Serial.print("starttime: ");
        Serial.println(starttime);
      }
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    } 
  }
  lastButtonState = buttonState;                      //nu is deze status (HIGH) dus de vorige status geworden

  if (buttonPushCounter == 3) {                        //als de teller op waarde 3 staat, dus de knop 3 keer HIGH geweest is
    stoptime = millis();                                // noemen we dat de stoptime, ook weer gevuld met millis()
    Serial.print("stoptime: ");
    Serial.println(stoptime);

    time = stoptime-starttime;                          //we trekken stop- en starttijd van elkaar af en noemen dit 'time'

    Serial.print("time between pushes ");
    Serial.println(time);

    buttonPushCounter = 0;                              //dan zetten we de teller weer op 0, klaar voor de volgende ronde

    if (time < 2000){                                  //nu controleren we op de het optellen van 0 tot 3 binnen de 2 seconden is gebeurt
      digitalWrite(ledPin, HIGH);                      //zo ja, ledje aan of wat dan ook...
    } 
    else {
      digitalWrite(ledPin, LOW);                      //en anders niks
    }
  }
}

Gr.
Johan

Most of the examples that come with the Arduino are pretty good. The state change detection example is one.

The debounce example is crap, in my opinion. They use three variables with completely unrelated names to keep track of three things.

Since you are already using the state change detection example, and know how to record when something happens, it would be trivial to determine if two events are too close together to be considered unique events.

Use a name like thisTime to record each time that the switch is pressed. Copy the current value to a name like lastTime each time the switch is pressed, before updating thisTime.

If thisTime - lastTime is smaller than some interval (maybe 10 milliseconds) consider that the switch bounced, and ignore the transition.

Indeed! In fact I coded a 'debounce'-system, only with a debouncetime of 2 seconds.

The only thing i have to do is: If the second push is within 20 ms, the push isn't a push but a jitter.

Thanks for this eyeopener.

J.

Hmm… not as simple as I thought.

When I pushed the button the first time I started millis() to measure the 2 seconds (wherein the 3 pushes must be done).
Evenso I started millis() for debounce.

But the same statements reads the buttonstate for push 1, 2 or 3.

if (buttonState != lastButtonState) {                // vergelijken met vorige staat van de knop
    if (buttonState == HIGH) {                        // als de status nu HIGH is, is hij dus van LOW naar HIGH gegaan en is de knop dus INgedrukt.
      buttonPushCounter++;                            // we tellen nu +1
      if (buttonPushCounter < 2){                     //als de teller kleiner is dan 2
        starttime = millis();

I have the measure the time between the first two pushes.

What can I do?

J.

Evenso I started millis() for debounce.

No, you didn't. The timer that millis() returns the value of was already running.

Here's an outline of what I think you are trying to accomplish: Each time that a transition happens, and is the right kind, Determine if it is the first one (the event time is 0) If so, record the time as the start of the 2 second interval AND as the last time that a transition occurred. If not, record the event time temporarily. If the interval between the temporary time and the last time is large, Increment the counter Else Ignore the transition Else Record the event time temporarily. If the interval between the temporary time and the last time is large, Increment the counter Else Ignore the transition If it has been two seconds since the first transition Perform the happy dance (whatever that means).

Thanks for explanation. I, or my students, will try this later. There are other deadlines at the moment.

(I coach a group of students who do projects by Physics, including some with arduino. And their projecttime is nearly ended. It's all very basic for them and for me, but I hope to enthousiasm them to choose for Arduino.)

I have upgraded and published my DebouncedInput class. It abstracts most common operations you do on a button with nice functions:

The one that may appeal to you is the .changedTo(level) function - it reports “true” if the button, after being debounced, has changed to the specified level.

#include <DebouncedInput.h>

DebouncedInput myButton(6, 20, true); // Pin 6, 20ms debounce, and enable the internal pullup

myButton.begin(); // set the pin mode and get the initial state
...
if (myButton.changedTo(LOW)) { // If it has been pressed ...
  .. do whatever you want to do
}

Edit:
I have just added transition time-stamp logging to my DebouncedInput class. It can now keep a record of the time of the last X transitions. There’s even a PressTime.ino example in there now to demonstrate it.

You could use that to record the last 3 presses, and if the oldest is less than 2 seconds ago then you trigger your code. Couldn’t be simpler:

DebouncedButton button(3, 20, true, 3);
...
button.begin();
...
if (button.changedTo(LOW)) {
  if ((button.getLowTime(2) > 0) && (millis() - button.getLowTime(2) < 2000)) {
    // ... do your stuff ...
    button.clearTimes();
  }
}

… I have even created an example in there too now.

http://www.gammon.com.au/switches

Thanks for last two replies. I saw a hardware solution (capacitor) was possible too. Thats a great idea, i think.

jmnijsse: Thanks for last two replies. I saw a hardware solution (capacitor) was possible too. Thats a great idea, i think.

Proper hardware debouncing is more than just a capacitor. 100% perfect debouncing is 2 resistors, a capacitor, and a diode. I never bother with the diode though.

You should arrange it so the capacitor charges up through the pull-up resistor (internal or external - external is best as the internal may be too slow to charge), then when you push the button the capacitor discharges through a smaller discharge resistor. Without that second resistor the capacitor discharges too fast to be properly useful.

This is a very good write-up on debouncing with analysis of different buttons and switches, and the different types of debouncing. A great resource: http://www.ganssle.com/debouncing.htm