|For novel ideas about building embedded systems (both hardware and firmware), join the 25,000+ engineers who subscribe to The Embedded Muse, a free biweekly newsletter. The Muse has no hype, no vendor PR. It takes just a few seconds (just enter your email, which is shared with absolutely no one) to subscribe.|
A Guide to Debouncing, or, How to Debounce a Contact in Two Easy Pages
By Jack Ganssle
Rev 1: April, 2006
Rev 2: April, 2007
Rev 3: June, 2008
Rev 4: March, 2014 (Added link to Trent Cleghorn's code)
The beer warms a bit as you pound the remote control. Again and again, temper fraying, you click the "channel up" key until the TV finally rewards your efforts. But it turns out channel 345 is playing Jeopardy so you again wave the remote in the general direction of the set and continue fiddling with the buttons.
Some remotes work astonishingly well, even when you bounce the beam off three walls before it impinges on the TV's IR detector. Others don't. One vendor told me reliability simply isn't important as users will subconsciously hit the button again and again till the channel changes.
When a single remote press causes the tube to jump two channels, we developers know lousy debounce code is at fault. The FM radio on my sailboat has a tuning button that advances too far when I hit it hard. The usual suspect: bounce.
When the contacts of any mechanical switch bang together they rebound a bit before settling, causing bounce. Debouncing, of course, is the process of removing the bounces, of converting the brutish realities of the analog world into pristine ones and zeros. Both hardware and software solutions exist, though by far the most common are those done in a snippet of code.
Surf the net to sample various approaches to debouncing. Most are pretty lame. Few are based on experimental bounce parameters. A medley of anecdotal tales passed around the newsgroups substitute for empirical evidence.
Ask most developers about the characteristics of a bounce and they'll toss out a guess at a max bounce time. But there's an awful lot going on during the bounce. How can we build an effective bounce filter, in hardware or software, unless we understand the entire event? During that time a long and complex string of binary bits is hitting our code. What are the characteristics of that data?
We're writing functions that process an utterly mysterious and unknown input string. That's hardly the right way to build reliable code.
|Suggestion: Subscribe to my free newsletter which often coversdebouncing and related subjects.|
So I ran some experiments.
I pulled some old switches out of my junk box. 20 bucks at the ever-annoying local Radio Shack yielded more (have you noticed that Radio Shack has fewer and fewer components? It's getting hard to buy a lousy NPN transistor there). Baynesville Electronics (http://www.baynesvilleelectronics.com), Baltimore's best electronics store, proved a switch treasure trove. Eventually I had 18 very different kinds of switches.
My desktop PC always has a little $49 MSP430 (TI's greatly underrated 16 bit microprocessor) development board attached, with IAR's toolchain installed. It's a matter of seconds to pop a little code into the board and run experiments. Initially I'd planned to connect each switch to an MSP430 input and have firmware read and report bounce parameters. A bit of playing around with the mixed signal scope (MSO) showed this to be an unwise approach.
I gave up on regular oscilloscopes. Now my Agilent MSO-X 3054A MSO is my go-to scope. An MSO is a mixed-signal oscilloscope; it combines a logic analyzer and a scope. Trigger from either an analog channel or a digital pattern to start the trace, and see how the digital and analog interact.
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.
I tested the trigger switches from an old cheap game-playing joystick (the three yellow ones in the picture), the left mouse button from an ancient Compaq computer (on PCB in upper left corner), toggle switches, pushbuttons, and slide switches. Some were chassis mount, others were to be soldered directly onto circuit boards.
Switches tested. The upper left is switch A, with B to its right, working to E (in red), and then F below A, etc.
I pressed each switch 300 times, logging the min and max amount of bouncing for both closing and opening of the contacts. Talk about mind-numbingly boring! I logged every individual bounce time for each actuation into a spreadsheet for half the switches till my eyes glazed over and gentle wife wondered aloud if I was getting some sort of Pavlovian reward.
The results were interesting.
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.
Years ago a pal and I installed a system for the Secret Service that had thousands of very expensive switches on panels in a control room. We battled with a unique set of bounce challenges because the uniformed officers were too lazy to stand up and press a button. They tossed rulers at the panels from across the room. Different impacts created (and sometimes destroyed, but hey, it's only taxpayer money after all) quite an array of bouncing. So in these experiments I tried to actuate each device with a variety of techniques. Pushing hard or soft, fast or slow, releasing gently or with a snap, looking for different responses. F, a slide switch, was indeed very sensitive to the rate of actuation. Toggle switch G showed a 3 to 1 difference in bounce times depending on how fast I bonked its lever. A few others showed similar results but there was little discernable pattern.
I was fascinated with the switches' analog behavior. A few operated as expected, yielding a solid zero or 5 volts. But most gave much more complicated responses.
The MSO responded to digital inputs assuming TTL signal levels. That means 0 to .8 volts is a zero, 0.8 to 2.0 is unknown, and above 2 a one. The instrument displayed both digital and analog signals to see how a logic device would interpret the real-world's grittiness.
Switch A was typical. When opened the signal moved just a bit above ground and wandered in the hundreds of millivolts range for up to 8 msec. Then it suddenly snapped to a one. As the signal meandered up to near a volt the scope interpreted it as a one, but the analog's continued uneasy rambles took it in and out of "one" territory. The MSO showered the screen with hash as it tried to interpret the data.
It was if the contacts didn't bounce so much as wiped, dragging across each other for a time, acting like a variable resistor.
Looking into this more deeply I expanded the traces for switch C and, with the help of Ohm's Law, found the resistance when the device opened crawled pretty uniformly over 150 µsec from zero to 6 ohms, before suddenly hitting infinity. There was no bouncing per se; just an uneasy ramp up from 0 to 300 mV before it suddenly zapped to a solid +5.
Another artifact of this wiping action was erratic analog signals treading in the dreaded no-man's land of TTL uncertainty (0.8 to 2.0 volts), causing the MSO to dither, tossing out ones or zeroes almost randomly, just as your microprocessor would if connected to the same switch.
The two from the el cheapo game joystick were nothing more than gold contacts plated onto a PCB; a rubber cover, when depressed, dropped some sort of conductive elastomer onto the board. Interestingly, the analog result was a slow ramp from zero to five volts, with no noise, wiping or other uncertainty. Not a trace of bounce. And yet.. . . the logic channel showed a msec or so of wild oscillations! What's going on?
With TTL logic, signals in the range of 0.8 to 2.0 volts are illegal. Anything goes, and everything did. Tie this seemingly bounce-free input to your CPU and prepare to deal with tons of oscillation - virtual bounces.
My assessment, then, is that there's much less whacking of contacts going on than we realize. A lot of the apparent logic hash is from analog signals treading in illegal logic regions. Regardless, the effect on our system is the same and the treatment identical. But the erratic nature of the logic warns us to avoid simple sampling algorithms, like assuming two successive reads of a one means a one.
Anatomy of a Bounce
So we know how long the contacts bounce and that lots of digital zaniness - ultra short pulses in particular - can appear.
But what happens during the bounce? Quite a lot, and every bounce of every switch was different. Many produced only high speed hash till a solid one or zero appeared. Others generated a serious pulse train of discernable logic levels like one might expect. I was especially interested in results that would give typical debounce routines heartburn.
Consider switch E again, that one with the pretty face that hides a vicious 157 msec bouncing heart. One test showed the switch going to a solid one for 81 msec, after which it dropped to a perfect zero for 42 msec before finally assuming its correct high state. Think what that would do to pretty much any debounce code!
Switch G was pretty well behaved, except that a couple of times it gave a few microsecond one before falling to zero for over 2 msec. Then it assumed its correct final one. The initial narrow pulse might escape your polled I/O, but would surely fire off an interrupt, had you dared wire the system so. The poor ISR would be left puzzled as it contemplates 2 msec of nothingness. "Me? Why did it invoke me? Ain't nuthin' there!"
O is a very nice, high quality microswitch which never showed more than 1.18 msec of bouncing. But digging deeper I found it usually generated a pulse train guaranteed to play havoc with simple filter code. There's no high speed hash, just hard-to-eliminate solid ones and zeroes. One actuation yielded 7 clean zeroes levels ranging in time from 12 to 86 µsec, and 7 logic ones varying from 6 to 95 µsec. Easy to filter? Sure. But not by code that just looks for a couple of identical reads.
What happens if we press the buttons really, really fast? Does that alter the bouncing in a significant way? It's awfully hard for these aging fingers to do anything particularly quickly, so I set up a modified experiment, connecting my MSP430 board to a sizeable 3 amp four pole relay. Downloading code into the CPU's flash let me toggle the relay at different rates.
Bounce times ranged from 410 to 2920 µsec, quite similar to those of the switches, presumably validating the experiment. The relay had no noticeable analog effects, banging cleanly between 0 and 5 volts.
The raucous clacking of contacts overwhelmed our usual classical fare for a few hours as the MSO accumulated bounce times in storage mode. When the relay opened it always had a max bounce time of 2.3 to 2.9 msec, at speeds from 2.5 to 30 Hz. More variation appeared on contact closure: at 2.5 Hz bounces never exceeded 410 µsec, which climbed to 1080 µsec at 30 Hz. Why? I have no idea. But it's clear there is some correlation between fast actuations and more bounce. These numbers suggest a tractable factor of two increase, though, not a scary order of magnitude or more.
In the bad old days we used a lot of leaf switches which typically bounced forever. Weeks, it seemed. Curious I disassembled a number of cheap consumer products expecting to find these sort of inexpensive devices. None found! Now that everything is mounted on a PCB vendors use board-mounted switches, which are pretty darn good little devices.
I admit these experiments aren't terribly scientific. No doubt someone with a better education and more initials following his name could do a more reputable study for one of those journals no one reads. But as far as I know there's no data on the subject available anywhere, and we working engineers need some empirical information.
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.
Go to Page Two of This report which has hardware and software debounce solutions.