Software Debouncing Multiple Latching Switches With Arduino

This last week I have been working on making the operation of my MIDI controller prototype more robust. One of my tasks has been to debounce and latch the states of my pushbutton toggle switches. Though you could use hardware for debouncing and latching I chose to do it with software. Doing it this way is cheaper, requires less space on a PCB and is fairly easily accomplished with todays microcontrollers.

3763763709 400e22d74e Software Debouncing Multiple Latching Switches With Arduino

A lone pushbutton switch

Before setting out to debounce my pushbuttons I did some searching on Google and discovered an excellent article on debouncing called simply, A Guide To Debouncing. It covers multiple techniques for both hardware and software debouncing.

After reading the article, I decided to go with a software counting algorithm. I did some more research but I wasn’t happy with the examples that I found. All of them involved debouncing a single switch. I wanted to debounce an entire port of switches. To do this you could just repeat the debouncing code for each switch but I decided to write a single piece of code to handle an entire port.

Below is my solution using PORTB on an Arduino. PORTB is a six pin port. This could easily be ported to be used on any AVR microcontroller or indeed any other microcontroller that can be programmed in C.

3763762659 6df9ff15c7 Software Debouncing Multiple Latching Switches With Arduino

My Arduino NG

All the pushbuttons in my example are active high with pull down resistors. The code could easily be adapted for active low. (Note that my prototype actually only has two buttons connected to it. I set up wires with pull downs to act as switches for the remaining pins)

First we define the number of switches on our port (in this case six), then the debounce depth. Debounce depth is the number of consecutive times that a switch must be read to have a certain value (HIGH or LOW, 1 or 0) before a press of that switch is validated.

#define numButtons 6
#define debounceDepth 10

Next we set up the variables we will need. The first one is used to read the PORTB value into. The second is to keep a memory of the last debounceDepth number of reads. The next keeps tabs on whether the pushbutton switch has been released after pressing. This variable provides a form of hysterisis so that we don’t get multiple toggles on one button press. The buttonPressFilter is a bitwise ANDed sum of all of the debounceDepth number of memories. The result in the buttonPressFilter is what determines if a pushbutton switch has been validly pressed.

char buttonRead;
char buttonMemory[debounceDepth] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int buttonHasReleased[numButtons] = {true,true,true,true,true,true};
char buttonPressFilter = 0xFF;
int buttonState[numButtons] = {0,0,0,0,0,0};

So that is the end of initialization. Now onto the code that you would put in your loop. The buttonPressFilter is an 8-bit variable with each of the lower 6 bits representing the state of a pushbutton switch, pressed or not-pressed. (Remember, PORTB on Arduino only has 6 pins) Each time we loop through here, we reset the buttonPressFilter to start as all 1′s. As it is bitwise ANDed with the previous button memories, any button read of a zero value will fall through as a zero, the rest will be left as 1′s. It basically ‘filters’ out any button presses that are not yet stable.

buttonPressFilter = 0xFF;

Here we shift all the memory by one, dumping the oldest reading to make room for the new reading. Then we AND all the old memories together.

for(i=(debounceDepth-1); i>0; i--) {
    buttonMemory[i] = buttonMemory[i-1];
    buttonPressFilter &= buttonMemory[i];
}

Here we read the current status of the switches on PORTB.

buttonRead = PINB;

Now for each pushbutton switch we check if the current read indicates a press. If it does, then we set its memory bit, otherwise we clear it.

for(i=0; i<numButtons; i++) {
    if((buttonRead & bitMask[i]) != 0) { // if current read shows button is pressed
        buttonMemory[0] |= bitMask[i];     // set the memory bit for that button
    } else {
        buttonMemory[0] &= ~(bitMask[i]); // otherwise clear the memory bit for that button
    }
}

Take account of the newest read into memory.

buttonPressFilter &= buttonMemory[0]; // AND the final memory bits into the buttonPressFilter

Now the buttonPressFilter contains the current pressed or non-pressed state of the switches. If any switch has had a consistent value for debounceDepth number of times, then toggle the state in the buttonState array and do whatever it is you want your button to do.

for(i=0; i<numButtons; i++) {
    if((buttonPressFilter & bitMask[i]) != 0) {
        if(buttonHasReleased[i] == true) {
            if(buttonState[i] == 0) {
                // ENTER CODE HERE FOR WHAT YOU WANT TO HAPPEN WHEN BUTTON IS ON
                buttonState[i] = 1;
            } else {
                // ENTER CODE HERE FOR WHAT YOU WANT TO HAPPEN WHEN BUTTON IS OFF
                buttonState[i] = 0;
            }
        }
        buttonHasReleased[i] = false;
    } else {
        buttonHasReleased[i] = true;
    }
}

One final thing to mention is that the debounceDepth value is something that you need to experiment with for the specific switches in your project. Currently with my cheap pushbuttons sitting in a cardboard chassis and wired to a breadboard, I need a value of 10 to get stable results. Using better switches, a stable chassis and a PCB I expect this number to drop.

Share and Enjoy:
  • printfriendly Software Debouncing Multiple Latching Switches With Arduino
  • digg Software Debouncing Multiple Latching Switches With Arduino
  • stumbleupon Software Debouncing Multiple Latching Switches With Arduino
  • delicious Software Debouncing Multiple Latching Switches With Arduino
  • facebook Software Debouncing Multiple Latching Switches With Arduino
  • yahoobuzz Software Debouncing Multiple Latching Switches With Arduino
  • twitter Software Debouncing Multiple Latching Switches With Arduino
  • googlebookmark Software Debouncing Multiple Latching Switches With Arduino
  • reddit Software Debouncing Multiple Latching Switches With Arduino

About jjob

I'm a technologist and a music producer. I make sound, write code and build things with electronics and microcontrollers.
This entry was posted in arduino, code, make, MIDI, prototyping. Bookmark the permalink.

4 Responses to Software Debouncing Multiple Latching Switches With Arduino

  1. brian says:

    I had to do something similar recently. I had to watch several pins for changes in an electrically noisy environment, so I couldn’t immediately believe what a pin was telling me. The solution I came up with was to make a struct containing pin number, pin value, number of votes, and number of votes required. To update the struct, I read the appropriate pin. If the reading agreed with the current value, I considered it a vote to keep the current value and decremented the number of votes, if it wasn’t already 0. If the reading disagreed with the current value, I considered it a vote to toggle and incremented the number of votes. If the number of votes reached the number of votes required, I toggled the value. The electrical noise never reaches the required threshhold. Sounds pretty similar to what you did.

  2. Ray Pasco says:

    All debouncing, whether done in hardware or software, is dependent on time. You have completely ignored this, which makes your software a “point solution” good for only this uC and its particular crystal frequency, not even to mention the compiler you used and whatever optimization level you chose.

    It’s simply not portable. The algorithm does not account for time passing.

    • Jason Job says:

      I am sorry that my blog post did not meet your expectations. It was not meant to be a treatise on de-bouncing, I merely wanted to share with the world the solution that I came up with for my Arduino project and that worked for me.

  3. kuo says:

    nice informative article. thanks for sharing!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>