There’s a lot to get excited about when programming stuff. Tough challenges, wily algorithms, and the feeling of success when it all comes together. When adding electro-mechanical aspects, this also brings a rather theoretical concept, and makes it a physical reality…
But like everything in life, there are chores. You have to wash the dishes. You have to wash your underwear. You have to tie your shoelaces. And you have to debounce.
For those who don’t know what debouncing is, well simply it’s compensating for bouncing. And bouncing is the world being imperfect, practical, and not cleanly theoretical. When you close your switch, there is never a perfect electrical connection.. It takes time to settle. Us humans aren’t fast enough to see what happens, but your microcontroller is. They are very sensitive to this, and will think you have pressed the button a few times really quickly…
And it looks like this:
You can see in this graph at least 4 falling edges before the signal settles. You see one button press, Arduino sees 4.
This manifests in many ways… An ammo counter counting extra darts. A pusher firing less darts. And the bane of all existence – a rotary encoder that skips and does other weird shit.
And so there are as many ways to combat this (i.e. debounce) as tying your shoes. There are quick and dirty knots, I tie fresh double knots every time I wear shoes. Other people have them loose and just slide their heathen feet in and out. And some people don’t tie their shoes at all….
Ultimately it doesn’t matter how you debounce, as long as you do (*). However, if you don’t debounce, like the idiot who walks around with untied shoes, you will eventually fall flat on your face.
(*) Fine print: Of course there are circumstances where it’s not necessary. Sometimes just merely detecting an edge is good enough. Other times you’re not worried about the edge, but rather the logic level at a particular point in time. But in general, things like trigger’s, pusher return switches, UI buttons, etc will benefit from it.
What are some ways of doing it?
- Software using a library (like bounce2.h)
- Software using your own algorithms (e.g. watching for interrupts and waiting a few milliseconds… Or shifting the pin register bit values through a serial buffer)
- Hardware by using your ADC (i.e. analogRead)… Please don’t do this, you heathens.
- Hardware by monitoring both your switch’s NO and NC position, and considering the input true when both lines agree
- Hardware by using a series of resistors and/or capacitors. I have actually released a board that encapsulates this for 4 channels.
Each way has their advantages and disadvantages. You can get away with any of the above techniques on a simple switch or a button, but if you are using rotary encoders, your options are rather limited. I have had luck with both hardware solutions and attaching the encoder to an interrupt, and I have also had luck with a pure software solution.
The only thing I would say about the solutions is that using an ADC to sample the average pin voltage, as opposed to using something to watch for a rising / falling edge is barely better than not debouncing at all. ADC in an Arduino is slow. When you perform an analogRead, the function sets up the *single* ADC to sample your pin through the onboard multiplexer. It then waits a period of time, while the ADC gets about collecting and averaging these readings. An register flag is used to indicate when the reading is complete, and your execution then resumes. If you are constantly polling a pin using analogRead, your code will be slow.
The only time that you should be using the ADC to read a digital switch is if you are multiplexing a number of switches on a single pin using a voltage divider network… There are other ways to do this (such as using a shift register), but given the additional complexity, this is a reasonable compromise. However this is another story for another time.