# Leading edge debouncing

**URL:** <https://forum.arduino.cc/t/leading-edge-debouncing/964407>\
**Category:** Programming\
**Created:** [February 28, 2022, 5:43pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407 "2022-02-28T17:43:48Z")\
**Posts on this page:** 17\
**Page:** 2

<div class="post-metadata">

**Author:** ![dlloyd](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/dlloyd/32/751911_2.png) [@dlloyd](https://forum.arduino.cc/u/dlloyd)\
**Post date:** [March 27, 2022, 10:39pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/21 "2022-03-27T22:39:27Z")

</div>

I like to test for a stable input. No need to guess at an ideal bounce period. Debounces on press or release of button. Here, I check for 40ms of stability representing 8 consecutive identical readings ...

```cpp
const byte buttonPin = 8;
const byte readPeriod = 5;
byte buttonHistory = 0x55;
unsigned long lastTime, timeChange;

void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  timeChange = (millis() - lastTime);
  if (timeChange >= readPeriod) {
    buttonHistory <<= 1;
    buttonHistory |= digitalRead(buttonPin);
    if (buttonHistory == 255) Serial.println("OFF");
    else if (buttonHistory == 0) Serial.println("ON");
    lastTime = millis();
  }
}

```

---

<div class="post-metadata">

**Author:** ![alto777](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/alto777/32/317385_2.png) [@alto777](https://forum.arduino.cc/u/alto777)\
**Post date:** [March 28, 2022, 3:05am UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/22 "2022-03-28T03:05:13Z")

</div>

> [@dlloyd](#):
>
> I like to test for a stable input.

Pushbuttons do not capriciously close their contacts unless going down, nor open them unless on the way up. Same with slide switches &c.

So there is no reason to delay 40 ms the recognition of either transition looking for stability.

If the switches and pushbuttons you use do misbehave in this way, I recommend getting better switches (!) or addressing what must be some other issue in the circuitry.

Unless you are looking to disallow a human input consisting of (in your view) too brief a press.

Like you want someone to really mean it. Which to me is odd. Buttons should work when you press them.

a7

---

<div class="post-metadata">

**Author:** ![DaveX](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/davex/32/751443_2.png) [@DaveX](https://forum.arduino.cc/u/DaveX)\
**Post date:** [March 28, 2022, 3:28am UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/23 "2022-03-28T03:28:41Z")

</div>

> [@alto777](#):
>
> I have asked the wokwi boys to implement bouncing for switches beyond _does_ or _doesn't_, so far it seems it is a low priority. I'd like to see something like _bounce for_ N _micro (or milli)seconds_.

I have another Wokwi demonstrating it's simulated pushbutton contact noise:

> **[ButtonBounceDemo.ino - Wokwi ESP32, STM32, Arduino Simulator](https://wokwi.com/projects/327202747064517203)**
>
> Run IoT and embedded projects in your browser: ESP32, STM32, Arduino, Pi Pico, and more. No installation required!

The Wokwi encoder is perfect, with no noise on its contacts.

Here's some of the button output:

```arduino
ButtonBounceDemo.ino -- Wokwi simulation of bouncing
If you push the button, the sketch will report the
microsecond times of the signal on Digital Pin 2.
This is good for checking for noisy buttons.
1228+ 4269756- 360+ 168- 160+ 188- 168+ 168- 176+ 
168- 156+ 160- 160+ 13498032- 380+ 164- 160+ 156- 
200+ 192- 156+ 184- 164+ 160- 156+ 160- 14432+ 252- 
220+ 232- 212+ 160- 172+ 172- 160+ 216- 160+ 156- 
168+ 3714376- 336+ 160- 156+ 168- 220+ 168- 216+ 160- 
180+ 160- 160+ 160- 847740+ 300- 160+ 164- 180+ 160- 
176+ 180- 168+ 192- 176+ 164- 160+ 

```

---

<div class="post-metadata">

**Author:** ![dlloyd](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/dlloyd/32/751911_2.png) [@dlloyd](https://forum.arduino.cc/u/dlloyd)\
**Post date:** [March 28, 2022, 4:01am UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/24 "2022-03-28T04:01:03Z")

</div>

> [@alto777](#):
>
> Pushbuttons do not capriciously close their contacts unless going down, nor open them unless on the way up. Same with slide switches &c.

Meant to be _all-purpose_. Relay contacts, knife switch, touching GND with a jumper wire connected to input with internal pullup, [other switching devices](https://my.eng.utah.edu/~cs5780/debouncing.pdf). P.S. [Normally closed push buttons](https://www.google.com/search?client=firefox-b-d&q=normally+closed+push+button+switch).

> [@alto777](#):
>
> So there is no reason to delay 40 ms the recognition of either transition looking for stability.

- Sure, could easily use a shorter interval, but the interval is non-blocking, and a human just cannot react (or press a button) faster than ??? ms ([try the test](https://humanbenchmark.com/tests/reactiontime)).
- P.S. I wonder what interval the Arduino "debounce" example uses?
- Having said all this, the code checks for stability ... the bounce time could be 100ms and as long as there's no stable period of 40 ms (5ms x 8 readings) while the contacts are bouncing, then the code return value will remain clean.

> [@alto777](#):
>
> Unless you are looking to disallow a human input consisting of (in your view) too brief a press.
> 
> Like you want someone to really mean it. Which to me is odd. Buttons should work when you press them.

See above (or try the code). Very responsive, just please don't repeatedly press the button at a rate greater than 12.5Hz. Disclaimer: code is untested as I didn't have the time.

---

<div class="post-metadata">

**Author:** ![alto777](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/alto777/32/317385_2.png) [@alto777](https://forum.arduino.cc/u/alto777)\
**Post date:** [March 28, 2022, 2:21pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/25 "2022-03-28T14:21:13Z")

</div>

@DaveX again, nice demo.

I noticed their encoder is perfect and have no bounce attribute. Of course we all know that there is no need to debounce a rotary encoder, so. Nevertheless, it would be nice if the encoder allowed s l o w l y t u r n i n g so all four phases of the quadrature signal would not fly by \<click!\> at once.

I suppose your trick could be used to examine the actual behaviour of the simukated encoder, or use the handy digital logic analyser that is available in wokwi that doesn't cost even $13. 😑

> [@dlloyd](#):
>
> Meant to be _all-purpose_.

Yes. Although we could wonder 'bout those knife switches that capriciously open and close by themselves... and I have no sympathy for anyone too lazy to use a real switch poking around with jumper wires! I think if the button was to launch the nuclear tipped misile, there'd probably be an argument for stability. Normally closed switches of some kinds have to be handled better, as you point out.

But it's software. No where in life is a general purpose anything the bast at all deployments, and no where else but software is the opportunity provided to easily supply the best solution on a use case by use case basis.

I've been abnormal all my life. One size fits all does not fit. Me. Libraries that have options up the wazoo (technical term there) can be hard to understand, often suck and take too much code space.

As for human reaction time, why add 40 ms to what is already an eternity of dozens if not hundreds? Besides noting that there is no reaction time involved when I go to press a button.

I see that this time I failed to mention that it was when working with musicians that I became very sensitive to how fast systems do (or do not) take action when requested.

If by

```
 See above (or try the code).

```

you mean your clever "waiting for stability" code, I have used the technique and sure enough, it takes a predictable and excruciating N milliseconds to see a button go down. _An eternity._ 😉

> …please don't repeatedly press the button at a rate greater than 12.5Hz.

said the note on some thing I bought recently… not.

BTW thanks for linking this great paper, which I first saw on his website

> **[debouncing.pdf](https://my.eng.utah.edu/~cs5780/debouncing.pdf)**
>
> 333.26 KB

[http://www.ganssle.com](http://www.ganssle.com) is worth all the time spent there.

a7

---

<div class="post-metadata">

**Author:** ![anon57585045](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@anon57585045](https://forum.arduino.cc/u/anon57585045)\
**Post date:** [March 28, 2022, 2:40pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/26 "2022-03-28T14:40:08Z")

</div>

Yes. I did some testing with both methods. I belong to the school that says you should register a switch closure immediately. When it is necessary to have a long debounce period, it's noticeable enough to be frustrating to a user, if the registration doesn't happen until after the time out. It's experienced as "sluggishness". Often the repetition rate will never be high, but this delay would still be noticeable if it's handled in that way. So you can have a really long debounce and nobody will think it's slow if the key press is reported immediately.

I once worked for a company, that had a lot of repair returns with bad keypads. The real problem was, the debounce was like that, the users became frustrated and pounded the membrane keys with pens, fingernails, and really hard, hoping to make it respond faster.

Also this whole thing about noise seems specious to me. Switches should not be producing noise when they are not active. If they are, there are some serious design problems that should be addressed before considering masking it with a debounce delay.

---

<div class="post-metadata">

**Author:** ![dlloyd](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/dlloyd/32/751911_2.png) [@dlloyd](https://forum.arduino.cc/u/dlloyd)\
**Post date:** [March 28, 2022, 3:23pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/27 "2022-03-28T15:23:25Z")

</div>

Yeah, I see the value of instant response (stopwatch, etc). Using the following code:

- instant response (0 ms)
- actual switch bounce time can be anything from 0 - 4294967295 ms with each contact "hit" or release (bounce) period lasting no longer than 40 ms.
- example test: On an UNO, take a m/m jumper wire from pin 8 and rapidly touch the USB casing. There'll be no glitches in the printout (OFF-ON-OFF or ON-OFF-ON) sequences.

```cpp
const byte buttonPin = 8;
const byte readPeriod = 5;
byte buttonHistory = 0xFF;
unsigned long lastTime, timeChange;

void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  timeChange = (millis() - lastTime);
  if (timeChange >= readPeriod) {
    buttonHistory <<= 1;
    buttonHistory |= digitalRead(buttonPin);
    if (buttonHistory == 0xFF) Serial.println("OFF");
    else if (buttonHistory) Serial.println("ON");
    lastTime = millis();
  }
}

```

---

<div class="post-metadata">

**Author:** ![alto777](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/alto777/32/317385_2.png) [@alto777](https://forum.arduino.cc/u/alto777)\
**Post date:** [March 28, 2022, 3:34pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/28 "2022-03-28T15:34:03Z")

</div>

I'm waiting for I believe it is @groundFungus to remind us that a 0.1 uF ceramic cap across switch terminals can often do the entire job.

At least with the microprocessors that have Schmitt trigger input pin hysteresis. At the very least this does include the '328p. I would check

a7

---

<div class="post-metadata">

**Author:** ![anon57585045](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@anon57585045](https://forum.arduino.cc/u/anon57585045)\
**Post date:** [March 28, 2022, 4:35pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/29 "2022-03-28T16:35:44Z")

</div>

Sure, you can. But why? Debouncing is not rocket science. Even when written as non-blocking.

---

<div class="post-metadata">

**Author:** ![DaveX](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/davex/32/751443_2.png) [@DaveX](https://forum.arduino.cc/u/DaveX)\
**Post date:** [March 28, 2022, 9:36pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/30 "2022-03-28T21:36:02Z")

</div>

> [@DaveX](#):
>
> I updated the Wokwi simulation to repeatedly and noisily press the button and raised an issue at [Does #define BOUNCE\_LOCK\_OUT work? · Issue #85 · thomasfredericks/Bounce2 · GitHub](https://github.com/thomasfredericks/Bounce2/issues/85) over the `#define BOUNCE_LOCK_OUT` not appearing to have an effect.

Ah: [Need mechanism to pass defines to library cpp files](https://forum.arduino.cc/t/need-mechanism-to-pass-defines-to-library-cpp-files/227179)  
-- you can't use `#define LIBRARY_CONDITIONAL` in your sketches to control the compilation of the library referenced with the `#include <library.h>`. If you muck with the Bounce2.h file, you could enable the BOUNCE\_LOCK\_OUT behavior of Bounce2, but you can't control it from the sketch.

The Bounce2 library documentation is modified to reflect the need to modify the global Bounce2.h file with:

> **[Release Bounce V2.71 · thomasfredericks/Bounce2](https://github.com/thomasfredericks/Bounce2/releases/tag/v2.71)**
>
> duration() was added back but marked as deprecated
> documentation was updated

Also, look at the [Bounce2 README](https://github.com/thomasfredericks/Bounce2?tab=readme-ov-file#bounce2) and the references with

- [John Errington's Experiments with an Arduino - Using digital inputs: Switch bounce and solutions to it](http://www.skillbank.co.uk/arduino/switchbounce.htm)
- [Wikipedia article on contact Debouncing](http://en.wikipedia.org/wiki/Debounce#Contact_bounce)

and @anon14381181's illustration of the difference between the different BOUNCE2 schemes:

 ![](https://europe1.discourse-cdn.com/arduino/original/4X/9/4/a/94a4694e66ba62501fe76c30ee93750c8e3379bd.png)

---

<div class="post-metadata">

**Author:** ![zmemw16](https://avatars.discourse-cdn.com/v4/letter/z/e5b9ba/32.png) [@zmemw16](https://forum.arduino.cc/u/zmemw16)\
**Post date:** [March 28, 2022, 10:50pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/31 "2022-03-28T22:50:36Z")

</div>

Debounce all of them. Takes their issues out of it.  
Then look at the resulting states.  
Srp

---

<div class="post-metadata">

**Author:** ![groundFungus](https://avatars.discourse-cdn.com/v4/letter/g/73ab20/32.png) [@groundFungus](https://forum.arduino.cc/u/groundFungus)\
**Post date:** [March 28, 2022, 11:55pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/32 "2022-03-28T23:55:30Z")

</div>

@RayLivingston beat me to it in reply #12.

---

<div class="post-metadata">

**Author:** ![alto777](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/alto777/32/317385_2.png) [@alto777](https://forum.arduino.cc/u/alto777)\
**Post date:** [March 29, 2022, 1:14pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/33 "2022-03-29T13:14:40Z")

</div>

> [@dlloyd](#):
>
> Using the following code:
> 
> - instant response (0 ms)

Your algorithm is asymmetrical. Fast switch down, delayed switch up.

Replace readPeriod with something long enough to see it.

But the odd way this handles time

```arduino
  if (timeChange >= readPeriod) {

// other code here

    lastTime = millis();
  }

```

means the average response to a button down event will take readPeriod / 2 ms. You are locking out the examination of the button every time you loop.

So this is not an edge catcher, it does not respond in minimal time.

I hope I did not damage your code when I added a few things to it.

Play with it here:

> **[anotherDebounceThing.ino - Wokwi ESP32, STM32, Arduino Simulator](https://wokwi.com/projects/327470513802707540)**
>
> Run IoT and embedded projects in your browser: ESP32, STM32, Arduino, Pi Pico, and more. No installation required!

```arduino
// https://forum.arduino.cc/t/leading-edge-debouncing/964407/28

const byte buttonPin = 8;
const byte lookingLED = 9;

const int readPeriod = 1000; // absurd. human scale so we can see what really goes on

byte buttonHistory = 0xFF;

unsigned long lastTime, timeChange;

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

  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(lookingLED, OUTPUT);
}

void loop() {

  timeChange = (millis() - lastTime);

  digitalWrite(lookingLED, (timeChange >= readPeriod) ? HIGH : LOW); // locked out on time?

  if (timeChange >= readPeriod) {

    buttonHistory <<= 1;
    buttonHistory |= digitalRead(buttonPin);
    if (buttonHistory == 0xFF) tracePrint("OFF");
    else if (buttonHistory) tracePrint("ON");

    lastTime = millis();
  }
}

// print a new message, and how many times you didn't print the last new message. or don't.
void tracePrint(char *s)
{
  static unsigned long tCount;
  static char traced[32];

  if (strcmp(s, traced)) {
    Serial.print(tCount);
    Serial.print(" now ");
    Serial.println(s);
    strcpy(traced,s);
  }
  else tCount++;
}

```

  
a7

---

<div class="post-metadata">

**Author:** ![dlloyd](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/dlloyd/32/751911_2.png) [@dlloyd](https://forum.arduino.cc/u/dlloyd)\
**Post date:** [March 29, 2022, 2:41pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/34 "2022-03-29T14:41:14Z")

</div>

> [@alto777](#):
>
> Your algorithm is asymmetrical. Fast switch down, delayed switch up.

Yes, ideal for a pushbutton circuit that connects the input to GND when pressed (normally high signal with button released).

Delayed switch up will vary. If monitoring a dry relay contact with bounce time on operate = 15 ms, then the switch up delay = 15 + 40 = 55 ms. If monitoring a push button with 2 ms bounce, then the switch up delay = 2 + 40 = 42 ms. Therefore the switch up delay is the time it takes for the signal to be stable HIGH for a 40 ms period + contact bounce period + ½ loop iteration period.

> [@alto777](#):
>
> So this is not an edge catcher, it does not respond in minimal time.

Not meant to be an edge catcher as with using an interrupt. Just basic polling where actual response is determined by the user's sketch that avoids any significant blocking code.

> [@alto777](#):
>
> But the odd way this handles time

With both this and your example, millis() is on the left side of the operator, so there's no rollover problem, but yeah, it adds on avg ½ read period to the initial response which (to me) isn't concerning since we don't really need instantaneous.

> [@alto777](#):
>
> I hope I did not damage your code when I added a few things to it.

Uh-oh, its uninsured! 😳

**EDIT:**

Since the most common push button circuit would use INPUT\_PULLUP which offers low drive current which is usually below the minimum specified level for switch contacts (some specifiy 10 mA min), this makes the input suseptible to noise, glitches, EMI, etc and adds to the "bounce" time.

In this case, a software improvement could be a small compromise, where there's 1-bit delay on press, 7-bit delay on release.

---

<div class="post-metadata">

**Author:** ![alto777](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/alto777/32/317385_2.png) [@alto777](https://forum.arduino.cc/u/alto777)\
**Post date:** [March 29, 2022, 3:03pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/35 "2022-03-29T15:03:48Z")

</div>

> [@dlloyd](#):
>
> Not meant to be an edge catcher as with using an interrupt. Just basic polling where actual response is determined by the user's sketch that avoids any significant blocking code.

The "actual response" in the plain one where you just catch the edges then begin a timed blockout period reacts as fast as possible to both edges.

No need to mention interrupts. Polling is polling, and will always suffer when it can.

Simpler algorithm, symmetrical response. Not general purpose. 😉

a7

---

<div class="post-metadata">

**Author:** ![DaveX](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/davex/32/751443_2.png) [@DaveX](https://forum.arduino.cc/u/DaveX)\
**Post date:** [March 29, 2022, 3:25pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/36 "2022-03-29T15:25:21Z")

</div>

> [@DaveX](#):
>
> Of the multitude of debouncing libraries available, can you recommend ones that trigger at the leading edge?

So the recommendations are:

> [@johnwasser](#):
>
> I like to debounce on both edges:

> [@RayLivingston](#):
>
> The hardware solution to switch bounce is to add a simple capacitor to ground the switch output. That will absorb the bounce on BOTH edges, so you get a clean open and close signals. The exact same thing can be accomplished with a digital low-pass filter with an appropriate time constant. The simplicity of this approach is hard to beat.

> [@alto777](#):
>
> If you find them doing, get better switches or take other measures to eliminate whatever is causing the spurious opening or closing what isn’t due to being pressed or released.

> [@dlloyd](#):
>
> I like to test for a stable input. No need to guess at an ideal bounce period. Debounces on press or release of button. Here, I check for 40ms of stability representing 8 consecutive identical readings ...

> [@alto777](#):
>
> this great paper, which I first saw on his website
> 
> [https://my.eng.utah.edu/~cs5780/debouncing.pdf](https://my.eng.utah.edu/~cs5780/debouncing.pdf)

And hacking `#define BOUNCE\_LOCK\_OUT" into the Bounce2 library code.

I did like my Wokwi sims for comparing debouncing schemes and simulating noise (I don't like the hacking on Bounce2 I had to do to make its fast mode work):

> [@DaveX](#):
>
> [LeadingEdgeDebounce.ino - Wokwi ESP32, STM32, Arduino Simulator](https://wokwi.com/projects/324855073217708626)

and for simple code for reporting un-debounced buttons.

> [@DaveX](#):
>
> [ButtonBounceDemo.ino - Wokwi ESP32, STM32, Arduino Simulator](https://wokwi.com/projects/327202747064517203)

But to the original Q, the only popular library that catches the leading edge of a transition is Bounce2's BOUNCE\_LOCK\_OUT mode or BOUNCE\_WITH\_PROMPT\_DETECTION, but that only works if you edit the installed library code to define the flag.

Besides having quality buttons, and good hardware filtering, another thought is that if you write good state-machine code, you don't need the debouncing because the states should take care of themselves. Like an industrial start-stop motor contactor, or a period of lockout on HVAC systems.

---

<div class="post-metadata">

**Author:** ![system](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/system/32/1140315_2.png) [@system](https://forum.arduino.cc/u/system)\
**Post date:** [September 25, 2022, 3:25pm UTC](https://forum.arduino.cc/t/leading-edge-debouncing/964407/37 "2022-09-25T15:25:32Z")

</div>

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

[Previous page](https://forum.arduino.cc/t/leading-edge-debouncing/964407.md?page=1)
