Does this mechanical switch really have no bounce?

I'm prototyping with a bunch of no name mechanical button mini-switches and SAM D21 microcontroller (Adafruit Feather M0). The switch is connected directly between the ground and the input pin #19 (PB02 of ATSAMD21G18) without any debouncing circuitry #19. This Arduino test program:

constexpr int BUTTON = 19;

void setup()
{
pinMode(BUTTON,  INPUT_PULLUP);
}

void loop()
{
Serial << digitalRead(BUTTON) << ", " << micros() << "\n";
}


produces a log of clean transitions without a single bounce, e.g.

1, 8891998
1, 8892101
1, 8892197
1, 8892362
0, 8892468
0, 8892569
0, 8892668
0, 8892764
....
0, 9063951
0, 9064048
0, 9064145
0, 9064305
1, 9064401
1, 9064507
1, 9064610
1, 9064706


Pin PB02 is read more often than every 0.1ms, which seems sufficient to catch mechanical switch bounce. Is there some hardware filtering involved here? Unfortunately, I don't have a scope handy to capture the signal.

Here is a picture of the switch:

EDIT

There are several answers blaming serial port latency for missing the bounce. This is incorrect. I'm logging timestamps of each measurement, which are better than 4μs accurate. See https://www.arduino.cc/en/pmwiki.php%3Fn%3DReference/Micros for description of micros() function, specifically: "On 16 MHz Arduino boards (e.g. Duemilanove and Nano), this function has a resolution of four microseconds".

EDIT'

Picture of the test setup, as requested (tiny switch on the left):

• @mkeith I think it is better than 4us accurate. I don't see any truncation of the returned value. "On 16 MHz Arduino boards (e.g. Duemilanove and Nano), this function has a resolution of four microseconds" (arduino.cc/en/pmwiki.php%3Fn%3DReference/Micros) – Paul Jurczak Jun 21 at 6:50
• @danmcb No scope at hand, as I mentioned in my question, but see my answer below. – Paul Jurczak Jun 21 at 7:23
• @danmcb The behavior is consistent both on close and open. I tried about a dozen times. You are right that much finer time resolution could be achieved with buffered measurement. You just motivated me to do it. I will post the results as an edit to my answer below. – Paul Jurczak Jun 21 at 8:43
• Egads. Protoboard! Okay. So there is definitely capacitance. I'm no longer curious. Best wishes to all. – jonk Jun 21 at 9:10
• @PaulJurczak note the Jack Gannsle info before about how variable the timing of bounce can be. JG is a pretty reliable source. What you are doing is an interesting exercise, but there is no test you can do with an arduino that will let you conclude "there is no bounce on this switch". You need a scope to do that. – danmcb Jun 21 at 9:29

5 Answers

Not every electromechanical contact exhibits bounces, and if it does, not always every single time you activate it. Moreover, some switches bounce only on one "edge" of the signal, i.e. only when closed or open. And other switches' bounces are so quick that they are not detectable by common MCUs. You need a scope to capture that behavior.

The variations could be astounding.

An interesting article about debouncing from embedded guru Jack Ganssle shows you some empirical data.

Excerpts (emphasis mine):

Many of the switches exhibited quite wild and unexpected behavior. Bounces of under 100 nsec were common (more on this later). No reasonable micro could reliably capture these sorts of transitions, so I abandoned that plan and instead used the scope, connecting both analog and digital channels to the switch. This let me see what was going on in the analog domain, and how a computer would interpret the data. A 5 volt supply and 1k pull-up completed the test jig.

If a sub-100 nsec transition won't be captured by a computer why worry about it? Unfortunately, even a very short signal will toggle the logic once in a while. Tie it to an interrupt and the likelihood increases. Those transitions, though very short, will occasionally pervert the debounce routine. For the sake of the experiment we need to see them.

[...]

So how long do switches bounce for? The short answer: sometimes a lot, sometimes not at all.

Only two switches exhibited bounces exceeding 6200 µsec. Switch E, what seemed like a nice red pushbutton, had a worst case bounce when it opened of 157 msec - almost a 1/6 of a second! Yuk. Yet it never exceeded a 20 µsec bounce when closed. Go figure.

Another switch took 11.3 msec to completely close one time; other actuations were all under 10 msec.

Toss out those two samples and the other 16 switches exhibited an average 1557 µsec of bouncing, with, as I said, a max of 6200 µsec. Not bad at all.

Seven of the switches consistently bounced much longer when closed than when opened. I was amazed to find that for most of the switches many bounces on opening lasted for less than 1 µsec - that's right, less than a millionth of a second. Yet the very next experiment on the same switch could yield a reading in the hundreds of microseconds.

Identical switches were not particularly identical. Two matching pairs were tested; each twin differed from its brother by a factor of two.

[...]

Use a grain of salt when playing with these numbers. Civil engineers don't really know the exact strength of a concrete beam poured by indolent laborers, so they beef things up a bit. They add margin. Do the same here. Assume things are worse than shown.

Bottom line: always assume switches will bounce and implement a conservative debouncing strategy (HW, SW or even both for maximum reliability).

If you really need to optimize things, you have to characterize your switch with sound statistical methods (never trust the manufacturer, unless you have a legal guarantee), so that you can choose the optimum debouncing strategy/parameters.

• JG is so good. Very interesting, thanks. – danmcb Jun 21 at 8:35
• Many cheap buttons, if pressed slowly after a long period of disuse, may appear to open and close continuously during the first push or two, if read by conventional input circuitry, but may be debounced with circuitry which will require the resistance to fall below 1000 ohms to register a closure, but rise to over 100,000 ohms to register an open. Otherwise, robust software debouncing without such hysteresis will only be possible if there's a limit to how slowly the button will be pushed. – supercat Jun 21 at 18:48
• @supercat Another interesting data point. Thanks! Since I read that article of Jack Ganssle ~6y ago I was enlightened about the "truth" of the "absurd" world of switch bouncing and it continues to "amaze" me almost "every day". I can't count the times when, in every day's life, I found something working flukey and I can recognize now the trademarks of bad debouncing implementations! – Lorenzo Donati -- Codidact.com Jun 23 at 8:27
• @LorenzoDonati--Codidact.com: I helped troubleshoot a design which where a button was supposed to toggle a device on and off, and it would fairly routinely sit for months without being pressed. It wasn't until after the device was fielded that customers complained about never working right the first time, and it took awhile to figure out what was going on because the "defective" devices always worked perfectly during testing. – supercat Jun 23 at 14:50
• @LorenzoDonati--Codidact.com: What makes me most happy are designs that use a double-throw switch. Those designs simply work 100%, first time, every time, with never any bounce ever, and have zero quiescent current in either switch position. Not sure all electronics designers have seen those, though. – supercat Jun 23 at 14:53

Your buttons aren't magical, though they are good.

I tested some push button switches for one of my projects a few months ago.

Surprisingly (at least to me,) the bounce is asymmetric.

Transition from high to low:

That's about 1.4 milliseconds.

Transition from low to high:

That's about 60 microseconds.

With a minimal debouncing circuit, the high to low transition is shortened to about 90 microseconds:

The "debounce" circuit for that was very simple:

With better buttons, there will be less bounce. Depending on the resistance and impedance of the wires and the button, the capacitances on the PCB and between the wires could well reduce the bounce to the nearly undetectable levels you found.

• The asymmetry of bounce is not surprising at all. In general, the bounce has to be longer on close. A springy metal piece hits a stationary surface and starts dampened oscillations - long bounce on close. Spring tension is released and contact is broken without major oscillations - short bounce on open. – Paul Jurczak Jun 21 at 8:28
• @PaulJurczak "In general, the bounce has to be longer on close". I disagree about the "generality" of that statement. It strongly depends on the mechanical construction of the switch. If your switch has some kind of "shock absorption" mechanism (intended or not) on close, it could not bounce at all. However, for example, if there is some kind of arcing on open (or contact stickyness), it could bounce quite a lot on open. ... – Lorenzo Donati -- Codidact.com Jun 21 at 14:44
• @PaulJurczak ... This also heavily depends on the activation mechanism: if it is built so that the operator has to juggle it more on open, there could be more bounce then. Have you ever found a switch which is easily closed but you have to force it a lot to open (some kinds of lever switch come to my mind)? Really, the situation is pretty wild out there, giving the metric ton of different kinds of switches (and electromechanical contacts in general) and the technologies employed. – Lorenzo Donati -- Codidact.com Jun 21 at 14:46
• @LorenzoDonati--Codidact.com You are right. My generalization doesn't hold across the whole range of electromechanical switch designs. I had a simple, low power, leaf spring design in mind, which is what you would use for a simple user interface. – Paul Jurczak Jun 21 at 23:05
• In power switching, this asymmetry is not surprising. Top priority especially for higher voltage DC is to throw the contacts apart quickly and positively so as to avoid sustaining an arc. Far less important on close, since the arc will self-extinguish when the contacts mate. – Harper - Reinstate Monica Jun 22 at 19:26

Well, the simplest Plan B was to test a different switch and see the results. I took a limit switch, which has a switching mechanism an order of magnitude larger:

and the bounce is now detectable (about 1.3ms) with the same software and connections, but much longer switch leads:

1, 7195437
1, 7195516
1, 7195658
1, 7195750
0, 7195840
1, 7195917
1, 7196010
1, 7196084
1, 7196157
0, 7196235
1, 7196318
0, 7196397
1, 7196491
1, 7196624
0, 7196699
0, 7196780
0, 7196853
1, 7196952
0, 7197029
0, 7197113
0, 7197213
0, 7197287


So the tiny switch is really "magical": no bouncing longer than about 0.1ms, given the capacitance of short hookup wires and PCB traces.

EDIT

I was motivated by danmcb to make finer resolution measurements and I got down to about 6μs resolution. Still no detectable bounce! Perhaps capacitance of the breadboard helps a lot here as suggested by jonk. Here is the data log:

1, 8604568
0, 8604573
0, 8604579
0, 8604585
0, 8604591
0, 8604597
0, 8604603
0, 8604609
0, 8604615
0, 8604621
....
0, 8605142
0, 8605148
0, 8605154
0, 8605160
0, 8605166

• The test for internal cap is to put > 1M in series a series and test with an DMM for rise time . (Or ADC). But an edge triggered counter will easily detect . Expect to get bounces with aging. A good mechanical bounce less design means well damped (less springy). Larger mechanical switches have bounce due to spring. Mass discontinuity from no tension to loaded spring. (Step response) Good buttons are bounce less as the spring constant k is constant during travel to the end stop without hysteresis. – Tony Stewart EE75 Jun 21 at 11:09

The test for internal cap is to put > 1M in series a series and test with an DMM for rise time . (Or ADC). But an edge triggered counter will easily detect . Expect to get bounces with aging. A good mechanical bounceless momentary switch design means well damped (less springy on contact).

Larger mechanical switches have bounce due to spring flip flop to pretension the closed contact to arm it for reopening.

The force discontinuity from no tension to loaded spring to over travel with contact then less force is felt as pushing the switch is like an electrical Step response.

Good buttons are bounceless as the spring constant k is constant during travel to the end stop without hysteresis. The force feeling is linear until contact then gets stiffer after in an exponential way but without hysteresis or backlash.

The louder the click sound the more hysteresis force and thus more bounce time.

This hysteresis is necessary to reduce arc time on opening for high rated voltages and inductive loads with a the preloaded spring, in order to quickly transition open in order to quench the inductively loaded arc and protect the contacts from thermal damage.

Since dry contacts can make transition times even faster than some semiconductors, it can create higher voltages from close to open times limited by the tiny contact capacitance. V=LdI/dt and as dt goes towards zero, V goes past the gap arc voltage of 3kV/mm in an approximate air ionization time of 1 us.

A snubber circuit is then used to provide additional protection and provide debouncing the electrical contact by bypassing the arc current and preventing discontinuity in voltage with an RC load across the contact. This then creates a current surge on closure but safely current limited by the chosen series resistor.

A good “toggle” switch is rated for 1 million mechanical contacts but if loaded with rated arc current is reduced in life span by several orders of magnitude, which is why they are derated for non-resistive loads. But as the metal ages and gets brittle the spring constant changes over time and may become nonlinear which then can cause hysteresis which then may cause bouncing.

So depending on the voltage and current rating, it is possible for button switches to be bounceless when new. But if you rely on not doing aging tests on a large sample and hope no debouncing cct or logic works forever, then you may be making false assumptions for future reliability issues.

The Arduino code is very likely busy-waiting for the debug message to be sent. At 115200 baud that will take of the order of a millisecond.

• Yeah. But how do you explain the microsecond timestamps? – mkeith Jun 21 at 6:36
• As @mkeith mentioned, look at the timestamps. Each message takes less than 0.1ms to get buffered and finally send over the USB bus. – Paul Jurczak Jun 21 at 6:40
• After perusing a search engine, I discovered that the arduino has a serial buffer. The documentation for micros() says that it returns the number of microseconds since program execution began. So it is probably not busy waiting, and there is no reason to think that micros() is wrong. So I think you have to start from the assumption that the timestamps are correct. – mkeith Jun 21 at 7:13
• At 115k2 each message will unavoidably take about a millisecond to transmit, so unless there’s an infinitely large buffer somewhere the Arduino will have to wait. I’m not sure of the implementation of micros() but conceivably it stalls if the transmit busy-waits. – Frog Jun 21 at 8:43
• @Frog You are wrongly assuming 115Kbps bandwidth and no buffering. This microcontroller has "One full-speed (12Mbps) Universal Serial Bus (USB) 2.0 interface", so the bandwidth is 12Mbps with hardware buffering. The delay is negligible. – Paul Jurczak Jun 21 at 9:17