Hardware debounce

Ciao!

I have a question regarding hardware debounce.

My project has 19 push buttons (tactile switch) + 7 rotary encoders. To make it as solid as possible, I want to hardware debounce them. I learned how to do it using the resistor/capacitor combo but all the examples I found shows how to do it to only 1 switch. Considering I have 33 switches, do I need to use 1 resistor + 1 capacitor for EACH switch!?

Also, what's the correct capacity for both resistor and capacitor? Some places says to use 1uF capacitor, others says 100nF. The resistor, some says to use 10k resistor, others 50k. Any advice on that?

Thank you so much for all your help!

Gabriel

BielMB:
My project has 19 push buttons (tactile switch) + 7 rotary encoders. To make it as solid as possible, I want to hardware debounce them.

Very bad idea!

Particularly for the rotary encoders!

Software de-bounce is much more "solid", doing things that would take quite complex hardware.

Are your 19 pushbuttons wired in a matrix? That would be nine I/O pins (and a diode for each button) and software de-bounce will manage the entire matrix with a single piece of code (which is to say it will recognise one or more keypresses only when all buttons have ceased bouncing).

But you need to understand what proper software de-bouncing is. It is not merely waiting a certain time after a change is observed and seeing whether it is still the same.

I have a page here that discusses debouncing in both hardware and software

Debouncing a LOT of inputs will be complicated either way.

I'd look at your requirements to see if its needed at all.

Eg you press a button and a process is activated. Does it matter if the switch bounces? If the same switch STOPS the process then of course it does, but a simple time out debounce would take care of that.

Please provide a link to the rotary encoders you are using. Bounce should not be an issue.

Considering I have 33 switches, do I need to use 1 resistor + 1 capacitor for EACH switch!?

I think you probably know the answer to that already, and I'm not going to say otherwise.

Also, what's the correct capacity for both resistor and capacitor?

10k Ohms and 0μ1 should be fine.

However,
I agree with the other comments, using hardware debuncing is daft in my opinion.

Lots of people have written tutorials on this, here's mine:

How are the 19 switches wired up? I'd suggest a 4x5 matrix and use the Keypad.h library to read them.

Rotary Encoders need a pair of pins each, I've had good results with this Bourns filtering.

RotaryEncoderFilter.JPG

RotaryEncoderFilter.JPG

CrossRoads,

You don’t need to filter inputs from rotary encoders, you just need a state based way of reading them, debouncing is then inherent in the code.

This was written for a PIC and reads 4 encoders on the port specified as p (8 inputs). It has to be called once per millisecond to be reliable. Debounce is inherent in the way it works.

void RPE_read(unsigned char p) {
    const char p_mask[4] = {0xfc, 0xf3, 0xcf, 0x3f};
    const char RPE_input_mask[4][4] = {{0xfe, 0xfd, 0xfc, 0xff}, {0xfb, 0xf7, 0xf3, 0xff}, {0xef, 0xdf, 0xcf, 0xff}, {0xbf, 0x7f, 0x3f, 0xff}};
    char p_masked; static char p_last; char i;
    if (p != p_last) {
        p_last = p;
        for (i = 0; i < zone_count; i++) {
            p_masked = p | p_mask[i];
            if (p_masked == 0xff) {
                RPE[i].index = 0;
            }
            switch (RPE[i].index) {
                case 0:
                    if (p_masked == RPE_input_mask [i][0]) {
                        RPE[i].index = 1;
                    }
                    if (p_masked == RPE_input_mask [i][1]) {
                        RPE[i].index = 4;
                    }
                    break;
                case 1:
                    if (p_masked == RPE_input_mask [i][2]) {
                        RPE[i].index = 2;
                    }
                    break;
                case 2:
                    if (p_masked == RPE_input_mask [i][1]) {
                        RPE[i].index = 3;
                        RPE[i].RPE_input_delta++;
                    }
                    break;
                case 3:
                    if (p_masked == RPE_input_mask [i][3]) {
                        RPE[i].index =0;
                    }
                    break;
                case 4:
                    if (p_masked == RPE_input_mask [i][2]) {
                        RPE[i].index = 5;
                    }
                    break;
                case 5:
                    if (p_masked == RPE_input_mask [i][0]) {
                        RPE[i].index = 6;
                        RPE[i].RPE_input_delta--;
                    }
                    break;
                case 6:
                    if (p_masked == RPE_input_mask [i][3]) {
                        RPE[i].index = 0;
                    }
            }
        }
    }
}

Good morning, y'all and thank you so much for the help and guidance you guys gave me already.

Paul__B:
Very bad idea!

Particularly for the rotary encoders!

Software de-bounce is much more "solid", doing things that would take quite complex hardware.

Are your 19 pushbuttons wired in a matrix? That would be nine I/O pins (and a diode for each button) and software de-bounce will manage the entire matrix with a single piece of code (which is to say it will recognise one or more keypresses only when all buttons have ceased bouncing).

But you need to understand what proper software de-bouncing is. It is not merely waiting a certain time after a change is observed and seeing whether it is still the same.

Yes, I'm wiring the tact switches in a 4x5 matrix. I will dig more into software debounce then, when I was researching online everyone was advising to hardware debounce though.

johnerrington:
I have a page here that discusses debouncing in both hardware and software

Debouncing a LOT of inputs will be complicated either way.

I'd look at your requirements to see if its needed at all.

Eg you press a button and a process is activated. Does it matter if the switch bounces? If the same switch STOPS the process then of course it does, but a simple time out debounce would take care of that.

Please provide a link to the rotary encoders you are using. Bounce should not be an issue.

Yeah, it does look complicated lol. I'm not sure if it's "necessary", the intention is just to avoid ghosting and multiple clicks when a button is pressed just once.

This is the encoder I got:

PerryBebbington:
I think you probably know the answer to that already, and I'm not going to say otherwise.
10k Ohms and 0μ1 should be fine.

However,
I agree with the other comments, using hardware debuncing is daft in my opinion.

Lots of people have written tutorials on this, here's mine:
https://forum.arduino.cc/index.php?topic=719995.0
https://forum.arduino.cc/index.php?topic=720016.0

Thank you so much for your insight, sir. I will consider those options!

CrossRoads:
How are the 19 switches wired up? I'd suggest a 4x5 matrix and use the Keypad.h library to read them.

Rotary Encoders need a pair of pins each, I've had good results with this Bourns filtering.

Yes, it's wired in a 4x5 matrix. Thanks for the sketch!

PerryBebbington:
CrossRoads,

You don't need to filter inputs from rotary encoders, you just need a state based way of reading them, debouncing is then inherent in the code.

This was written for a PIC and reads 4 encoders on the port specified as p (8 inputs). It has to be called once per millisecond to be reliable. Debounce is inherent in the way it works.

Very interesting! I will check on that!


I'm attaching below the sketch for my project. Two things about it:

  1. I'm not sure sure if I wired everything correctly, since I based my project on other people's projects I found here / Google.

  2. I'm having issues on where to place the capacitors for he matrix. Since all examples were for single switches, I'm not sure where they should be.

Thank you again for the time answering and helping me, you guys are awesome!

  1. I'm having issues on where to place the capacitors for he matrix. Since all examples were for single switches, I'm not sure where they should be.

Perhaps someone will correct me but I can't imagine how you could use hardware denouncing with a matrix.

That explains why I couldn't find anything about it. Thank you!

Your resistors don't look right. Groups of 5 are wired in parallel.

aarg:
Your resistors don't look right. Groups of 5 are wired in parallel.

And generally unnecessary if you are using INPUT_PULLUP to read them.

But - will you want more than one button to be pressed at any one time? If so, you need a diode in series with each button. If no more than one button to be pressed at any one time the diodes do not matter.

PerryBebbington:
Perhaps someone will correct me but I can't imagine how you could use hardware denouncing with a matrix.

I trust we have denounced that point adequately. :sunglasses:

Does the Keypad.h library facilitate debouncing? If so, how effective is it? As I originally commented, there are both crude and actually serious ways to do it. :astonished:

Yes, the Keypad library performs switch debouncing.

But you need to understand what proper software de-bouncing is. It is not merely waiting a certain time after a change is observed and seeing whether it is still the same.

The latter is perfectly adequate for a switch or switch matrix that isn't subject to any electrical interference and the only issue is contact bounce. In fact, the "lockout" method works just fine, and it is LESS stringent than the latter (register a key event whenever a change is observed and prohibit any further reads until the debounce interval has expired).

Are that resistors? I think you used the wrong symbol for diodes... those are needed for a button matrix (to allow you to press more than one at a time), resistors not.

See How to debounce for multiple buttons

aarg:
Your resistors don't look right. Groups of 5 are wired in parallel.

So, I don't need one resistor for each switch, only one per row!? That's good to know, thank you!

aarg:
Yes, the Keypad library performs switch debouncing.

The latter is perfectly adequate for a switch or switch matrix that isn't subject to any electrical interference and the only issue is contact bounce. In fact, the "lockout" method works just fine, and it is LESS stringent than the latter (register a key event whenever a change is observed and prohibit any further reads until the debounce interval has expired).

Thank you for the info!

wvmarle:
Are that resistors? I think you used the wrong symbol for diodes... those are needed for a button matrix (to allow you to press more than one at a time), resistors not.

Those are resistors. And yes, I will need to press more than one button at a time. Should I just replace resistors with diodes and keep it wired exactly as it is or the wiring is incorrect to be used with diodes?

IoT_hobbyist:
See How to debounce for multiple buttons

Thank you for the link!

BielMB:
So, I don't need one resistor for each switch, only one per row!? That's good to know, thank you!

You don't need resistors, you need 1 diode per button/switch/light-sensor-for-all-it-matters.

And you need to know that Arduino pins can be in one of four states.

OUTPUT HIGH or LOW
INPUT HIGH or LOW

-- where INPUT HIGH is INPUT_PULLUP, it sources weak 5V through 20K-50k resistance, can't burn the pin.
I put a jumper in pin 2, set mode pin 2 to INPUT_PULLUP and read pin 2 in a fast loop, until the other end of the jumper touches ground it will read HIGH. Ground the pin, it reads LOW. The resistor is built into the chip, INPUT_PULLUP saves you one.

-- where INPUT LOW when the pin is read once it drains about 1 microamp of current (at least with AVR) but when not read is electrically neutral. It makes the array simpler when only the 1 read pin sources current and one other ground pin can pull it LOW only if the right button is down.

Before and between row pin reads, make all the pins OUTPUT LOW briefly to drain the array down to ground, then set all INPUT/neutral zero-state.

For each row pin set INPUT_PULLUP, one at a time set each column pin OUTPUT LOW and read the row pin then set the column pin back to INPUT before next. That read if LOW, you know both row and column of a pressed button.

You need to write non-blocking code to pull this off smoothly. Just read one button per loop rather than every button every time, your code can react to a press before all of the buttons have been read. You can achieve > 50k reads per second if you do not load your void loop() down!

http://www.gammon.com.au/switches

Here is 1 cap hardware debounce.

I have a debounce that reads the pin twice a millisecond and put the reads into a history byte.
8 bits in the byte, each one is a half millisecond, the byte 8 reads covers 4ms read history.

Before each new read, the history byte is doubled. That moves all the bits up 1. 1->2->4...->128.
Add the read which is 0 or 1 to that and history is updated.

Reading bits is like reading decimals,
Decimal 1234 is 1000 + 200 + 30 + 4
Binary 10101001 is Decimal 128 + 32 + 8 + 1

But I want the history bits to be a picture.
10000000 shows 7 LOW reads since the last HIGH read, value==128, this button has been stable pressed for 3ms.
01111111 shows the stable release, value=127.
Fun part, everything else is unstable.

All required is update reads as one task and read the history in any other. The biggest load is the 500us read interval timer check and it's 16 bit instead of 32... this way is cycle-light on the CPU. This way, RAM takes 1 int start_time and 1 byte history per button.

If you process 1 button and history per loop(), you will get the quickest response.
Set up a variable for which button to do and change it to which to do next before the loop() ends.

This forum and the web is replete with beginner level lessons on "Do many things at the same time.".

http://www.gammon.com.au/switches

Here is 1 cap hardware debounce.

I have a debounce that reads the pin twice a millisecond and put the reads into a history byte.
8 bits in the byte, each one is a half millisecond, the byte 8 reads covers 4ms read history.

Before each new read, the history byte is doubled. That moves all the bits up 1. 1->2->4...->128.
Add the read which is 0 or 1 to that and history is updated.

Reading bits is like reading decimals,
Decimal 1234 is 1000 + 200 + 30 + 4
Binary 10101001 is Decimal 128 + 32 + 8 + 1

But I want the history bits to be a picture.
10000000 shows 7 LOW reads since the last HIGH read, value==128, this button has been stable pressed for 3ms.
01111111 shows the stable release, value=127.
Fun part, 0 is button held down, 255 is button up, everything else is unstable.

All required is update reads as one task and read the history in any other. The biggest load is the 500us read interval timer check and it's 16 bit instead of 32... this way is cycle-light on the CPU. This way, RAM takes 1 int start_time and 1 byte history per button.

If you process 1 button and history per loop(), you will get the quickest response.
Set up a variable for which button to do and change it to which to do next before the loop() ends.

This forum and the web is replete with beginner level lessons on "Do many things at the same time.".

I'm a fan of hardware debouncing as you will see here

The simple "cap across the switch" can cause massive current spikes when the switch is closed as the cap discharges "instantaneoously" through the switch and cap resisitance.

When it opens the cap charges through the pullup so for c=0.1uf, R pullup =30k CR = 2.5msec

which is long enough to kill bounce on opening.

But again, look at your requirements to see if bounce on the switch matrix will matter.
You dont say what your project is.

If pressing A starts a sequence that will take some time to process then a second press (or bounce) should be ignored anyway? Or a simple millis() delay would prevent reactivation.
Input from a key matrix is not THAT fast.

Reading the matrix only once every 20 ms or so should do away with any bounce, and still be an instant reaction for a human of typical slowness. No special debounce needed.

Cap across switch (a few nF should be enough already) is easy to debounce; if you’re worried about the current spikes - which I can imagine may damage a button over time, especailly when used a lot - add a small resistor in series with that cap. 100Ω or so is enough and won’t result in a noticeable delay. That’s of course yet another component in the mix…