If a newcomer to the electronics engineering community were to ask me to pick a topic that would follow them around throughout their career -- popping up when they least expect it like a surreal version of Whac-A-Mole -- the subject I would select would be that of switch bounce.
Switch bounce is a relatively easy concept to wrap your brain around, but it can be a trickly little scamp to address with a high degree of confidence. Actually, that’s not strictly true because many an engineer has been extremely confident in their switch bounce solution, right up until the time when an unanticipated bounce triggered an unwanted event.
The underlying idea is that the moving contacts in switches bounce. That’s what they do. This is true of toggle switches, pushbutton switches, micro switches, limit switches... in fact, just about every switch other than devices like mercury tilt switches, with which most engineers never come into contact (no pun intended) anyway.
To the uninitiated, a switch is either Off or On. When someone activates or deactivates a light switch on a wall, for example, the associated light appears to react immediately. In reality, for some period of time, the switch will be bouncing (turning on and off) like a ping pong ball dropped onto a hardwood floor. However, this bouncing -- and the corresponding flickering of the light -- occurs too quickly to be perceived by our biological sensory systems. (There’s also the thermal inertia of the filament in an incandescent bulb coupled with the persistence of vision, but let’s not wander off into the weeds.)
By comparison, in the case of a microcontroller unit (MCU) with a clock running at millions of times a second, the bouncing associated with every activation and deactivation may be perceived as tens or hundreds of events.
Consider the normally open (NO) terminal associated with a single-pole, single-throw (SPST) toggle switch, for example (Figure 1) (SPSTs with normally closed (NC) terminals are also available). Observe that bouncing can occur on both the active and inactive “edges.” Also, that the bouncing may extend all the way between logic 0 and logic 1 levels (which I think of as “clean bounces”) and/or between a good logic level and some intermediate voltage level (which I think of as “dirty bounces”).
Similarly, in the case of a single-pole, double-throw (SPDT) switch, bouncing may occur on both the active and inactive edges of both the NO and NC terminals (Figure 2).
Observe that only clean bounces are shown in this image for the sake of simplicity. Also, we are assuming that this is the most common form of SPDT -- a break-before-make (BBM) -- which means the moving contact breaks the existing connection with the current throw before making a new connection with the new throw (although they are less commonly used, make-before-break (MBB) implementations are also available).
So, how long might switch bounce persist? The problem here is that a lot of “established wisdom” is conveyed by word-of-mouth. When I was starting out as a newly minted bright-eyed bushy-tailed engineer, for example, a senior engineer told me that bouncing would certainly have ceased within 1 millisecond (ms), so I’d be fully covered if I assumed a worst-case scenario of 2 ms. I took him at his word. I have no idea why I never thought to actually verify this for myself using simple test rigs (like the circuits shown above) and an oscilloscope.
By comparison, embedded systems guru Jack Ganssle is cut from a different piece of cloth because he took a bunch of different switches, subjected them to exhaustive analysis (it exhausted me just reading about it), and wrote his Guide to Debouncing. Jack determined that the switches bounced for an average of 1.6 ms with a maximum value of 6.2 ms. Wow! That was way more than I was expecting.
As one final point of data, one of my friends, who used to be a technician in the US Air Force, told me that they assumed a worst-case bouncing scenario of 20 ms and -- since this is a nice round number -- I’m happy to go with the flow. Hey, if it’s good enough for the US Air Force, it’s certainly good enough for me.
So, how should we set about debouncing the signals coming out of our switches? In fact, we have two main options because we can opt for hardware or software solutions. To be honest, there are almost as many hardware techniques as there are hardware designers, and there are almost as many software solutions as there are software developers, so we will touch on only a few here.
Traditional Hardware Debounce Techniques
Let’s start with some traditional hardware-based approaches. In the case of an SPST switch, a very common option is to use an RC delay coupled with a Schmitt inverter (Figure 3).
Note that the diode is optional, but its presence simplifies the timing calculations, which can be especially useful if we wish to trigger actions both when the switch is activated and when it’s deactivated. With the diode in place, the capacitor charges via R1 and discharges via R2. If we omit the diode, then the capacitor still discharges via R2, but it charges via (R1 + R2).
By comparison, in the case of an SPDT switch, the crème de la crème solution is to use an SR latch formed from two back-to-back NAND gates (two back-to-back NOR gates can also be employed) (Figure 4).
To be honest, we could talk about these traditional hardware solutions for hours, but there’s not much point because relatively few designers employ these techniques these days. Also, there is a more modern hardware solution, but first...
Software Debounce Techniques
Today’s embedded systems developers tend to debounce signals from their switches using software techniques. The big problem here is that the majority of software developers have little idea as to how switch bounce works in the real world, so oftentimes they employ snippets of code provided by their peers, where this code may or may not be as robust as one might hope.
There are all sorts of software techniques available. A common approach is to use a counter. Also, to loop around checking the state of things (like the switches) and performing any associated actions once each millisecond, for example. Let’s suppose we are waiting for the output of the switch to transition from a 0 to a 1. Let’s also suppose we have decided to wait for 20 ms following the final bounce before we do anything.
We start with our counter containing zero. After we detect our first 1, every time we cycle round our loop, we check to see if the signal is still 1. If so, we increment our counter; if not, we reset our counter to zero. It’s only when the counter contains 20 that we know the signal has been a steady logic 1 for the past 20 ms, at which point we can perform any desired actions, after which we start waiting for the output of the switch to transition from a 1 to a 0.
Now, remember that I’m a hardware designer by trade, so you rely on any software advice I give at your peril. Bearing this in mind, I favor another software approach that I find easier to wrap my brain around. The idea here is to have a 20-bit shift register, which we can implement using an unsigned 32-bit integer variable.
Every time we go round our main loop, which we are assuming is once every millisecond in this example, we shift the contents of our shift register one bit to the left, read the state of the switch, and load its 0 or 1 value into the least-significant bit (LSB) of the register. When all 20 LSBs are 0, then we know that the signal from the switch has been 0 for at least 20 ms. Similarly, when all 20 LSBs are 1, then we know that the signal from the switch has been 1 for at least 20 ms. Deciding how we subsequently employ this information is easy-peasy lemon squeezy. For example, we could create a simple state machine with six states: CurrentlyZero, TransitioningToOne, JustBecameOne, CurrentlyOne, TransitioningToZero, and JustBecameZero.
I’m afraid to admit that, as the years go by, I’m starting to become a little lazy. I no longer wish to spend my valuable time on this planet slogging away on mundane tasks like debouncing the signals from switches when there are so many other fun things to do.
Also, while debouncing a single switch is no problem, things become more painful as the number of switches mounts. In the case of my Prognostication Engine (don’t ask), for example, there are eight toggle switches, ten push-button switches, and two knife switches.
Thus, the switch debouncing in all of my recent hobby projects has been achieved using dedicated ICs from LogiSwitch (in the spirit of full disclosure, I should point out that I’m a member of their Technical Advisory Board). These little beauties are available in 3-, 6-, and 9-channel versions. Also, they are available in dual-in-line (DIL) lead through-hole (LTH) packages suitable for prototyping on breadboards, and as surface-mount devices (SMDs) for those who prefer them. For example, consider a 3-channel LS18 device (Figure 5) (the “SW0” vs. “SW1” nomenclature is unfortunate, but that’s the way the cookie crumbles and the switch bounces, I’m afraid).
The first thing to note is that we don’t need to use a pull-up resistor on the switch because this function is included in the chip itself. Also of interest is that any noise spikes are rejected, which gives me a warm fuzzy feeling of happiness. The debounced output follows the input 20 ms after the final bounce, which is negligible when it comes to human-machine-interface (HMI) applications.
If you do demand “instant” response (within a couple of nanoseconds) for an automation application, for example, then LogiSwitch provides another family of chips that do just that. This other family also provides a unique 1-wire handshake interface on each channel that can be used to “clear” the switch event, but those chips will form a story for another day.
How About You?
So, how about you? Have you run into any problems related to switch bounce that you would care to share with the rest of us? Also, what debouncing solution(s) do you tend to favor?