Switch Debouncing
.
The problem
Switches used as input devices to electronic circuits are mechanical devices, and one of the consequence of this is that they suffer from "bouncing". This means that when you close a switch, it does not simply close and remain closed, but instead bounces several times before staying closed. Think of how when you drop a tennis ball it will bounce several times before coming to a rest on the floor.
The problem is that when the state of a switch is read by a microcontroller, it could easily register the switch as being pressed many times.
There is a simple piece of code running on the mbed that samples the button, regularly, and does edge detection looking for a change in state.
You'll see that the button is being pressed regularly, and the LED should toggle with each press.
Because of swich bounce, sometimes the LED toggles more than once, leaving its state unchanged, although multiple edges have been detected and acted upon.
Before setting about working out a clean way to debounce inputs in software, I spent some time reading around articles on the internet. My favourite was this one :
It seems that there are lots of different schools of thought, and ways to fix the problem both in hardware and in software.
I am not going to write much more about the problems, and the theory, it is all in that article!
Goal
Having read the paper, and understood what is easily possible in the mbed environment, I propose to build the "Alternative Software Debouncer", that is outlined in the article.
This uses a regular shedulded event to read the status of the switch, and detect when the last N samples have been in a steady state. When they are steady, the output is set to the steady state, otherwise it is left unchanged. This means that both bounce and EMI noise is rejected, and the output does not transistion until a switch has been sampled in a consistent state.
Method
My chosen method is to continually sample a DigitalIn, using a ticker to create a sample window. For now I have chosen 8 samples, and the ticker will run every 5ms, giving a worst case 40ms debounce latency. The number of samples and sampling rate will be easy to change later.
First experiment
Sample an input in a loop, create the sample window, print the sample window to sanity check.
#include "mbed.h" DigitalIn button(p20); DigitalOut led1(LED1); int main() { int samples = 0xf; while(1) { samples = samples >> 1; led1 = button; if (button) { samples |= 0x80; } printf("0x%x\n",samples); wait (1); } }
This is the result of the code above when the program is started with the button pushed down and then released when the LED comes on. The output shows the value in the variable "samples"
Second experiment
As the sampling window works as expected, i'll add the logic to set the output.
#include "mbed.h" DigitalIn button(p20); DigitalOut led1(LED1); int main() { int samples = 0xf; int output = 0x0; while(1) { samples = samples >> 1; if (button) { samples |= 0x80; } if (samples == 0x00) { output = 0; } else if (samples == 0xFF) { output = 1; } led1 = output; wait (1); } }
This works exactly the same as the first experiment, but I've now added the logic to do detect when then sample windows is all '1's and all '0's and transitiion as necessary. The logic is working as expect.
Third experiment
As the fundamentals are working, there are a few steps.
- Build a class that takes a single PinName argument - DebounceIn will look like DigitalIn
- Run a ticker inside the class to take care of the sampling
- Add edge detection in the ticker
- Counters and methods for detecting and reading both rising and falling edges
- Add a state counter, counting how long the button has been in the current (debounced) state
- Wrap this all up in a class "DebouncedIn"
As the SRF05 class has internal tickers, I'll reuse this code as a guide.
Before I start hacking around, have a bit of a think about the API to expose :
DebouncedIn(PinName in); // Constructor int read (void); // read the debounced state of the pin operator int(); // Short hand for the read function int rising(void); // How many debounced rising edges int falling(void); // How many debounced falling edges int steady(void); // How many debounce tick has the output been *steady* for
Results
The class came together quite quickly, with just a few typos and syntax errors, rather than any logical bugs to fix.
The results are
- DebouncedIn_HelloWorld - Example program, and the class.
- A video to prove it works :-)
Conclusion
While it might not be the ideal solution for everyone, it works well, and is good for quickly prototyping something where you need to use buttons as inputs but are sensitive to bounce issues
As ever, any comments, feedback and suggestions are welcome!
1 comment
You need to log in to post a comment