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);           
        
    }
}

 Sample window

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

 

  • 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

11 Feb 2014
Hi Chris
Please explain more on first experiment,
why set "int samples = 0xf;" ?
why "samples |= 0x80;" ?
why "samples = samples >> 1;"
Thanks

----------------------------------------------------------------------

#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);           
        
    }
}

You need to log in to post a comment