Go Down

Topic: Debouncing multiple buttons using schmitt trigger (Read 828 times) previous topic - next topic

Kuusou

#45
Sep 10, 2019, 07:27 am Last Edit: Sep 10, 2019, 07:28 am by Kuusou
@OP: In your last schematic you removed the WRONG set of resistors. Pressing a button will short Vcc to GND. Not a good design.
Thanks for catching that. Luckily it looks like I'll be able to avoid the need for the hardware debounce altogether!

Thanks to everyone for the help on this issue, you guys are great!

septillion

So how does this look?
Way clearer! 8)

[edit]But indeed, as I typed/read on, Smajdalf is right, you left R1, R3 and R5 and removed the others :p[/edit]

where i'm pressing the button and on release its registering multiple presses, these circuit are suppose to debounce at 1ms but is that enough?
So you still have bounce with this circuit?

It seems to me that I should make the caps larger so as to increase the debounce time to avoid this issue.
Or the resistor for that matter.

Does anyone have any thoughts on this? In programming it seems the normal is 50ms debounce but does follow over to hardware debounce?
Why not? Bounce is bounce. I once saw an article about it and I think most switches where below 1ms.  And only one or so passes the 10ms mark. Bounce2 for example uses 10ms (by default) which should cover most switches. But you might have that unlucky type which can bounce >10ms.

I've tried to debounce them in software but nothing seems to work.
Then you must be doing something wrong.... 14 led functions sounds pretty easy. I would say, just grab a library like Bounce2.

My first PCB I just covered both sides of the PCB in copper as the grounding layer and that seemed to work just fine. I didn't have any ground traces.
Depends on the signal, but usually fine. But it's better to do use separated traces for high current tracks. That way they don't influence other components (by shifting their voltage a bit).

NOTE: at this point I noticed it's not just 2 - 3 replies I missed but 2 pages.... So hold on, it's going to be a write as I read kind of post!

@runaway_pancake: Like I said, is the first thing you do when the interrupt fires to check which pin caused it? Because if that's the case you will indeed not get any random inc/dec but the interrupt is probably firing away quite a lot.

@ Kuusou  Wait, what? Now you're even dragging the watch dog in? :o

Code: [Select]
asm volatile ("jmp 0"); // force reset of micro controller at line 0
What the.... Must say, seeing the must ugly code at the start of the day is refreshing... Even didn't finish my coffee yet! :D

Let me guess, the rest of your code is full of delay()'s? If so, that's where you went wrong ;)

For beginners, interrupts create many more problems than they solve.
AMEN!

Luckily it looks like I'll be able to avoid the need for the hardware debounce altogether!
But please please please, don't use interrupts or the WDT for that! That's just different lipstick on a pig!

The real fix is pretty simple, remove all delay()s! ;) And see it as a lesson learned, NEVER EVER use delay() (in a real program) ;)
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

GolamMostafa

#47
Sep 10, 2019, 11:21 am Last Edit: Sep 10, 2019, 05:10 pm by GolamMostafa
I have assumed that that you are triggering INT0/INT1 interrupt at the falling edge of the incoming interrupting signal. I would think to employ the following hardware non-retriggerable one shot circuit instead of time delay to over come the bouncing times of the interrupting device. For more details, see this post.


Functional Description: When K1 is closed at time t1, the signal-A goes LOW and then after a while the bouncing of the button begins which lasts for about 25 ms before the button makes the final sit. At the very first low-going edge of signal-A (at time t1), the signal-B assumes HIGH state and remains HIGH during the whole bouncing times of K1 (because 74LS221 is a non-retriggering one shot, it does not  respond to the bouncing transitions of K1). At time t2, the signal-B makes a transition from HIGH to LOW; as a result, the MCU is interrupted only once. The pulse width of signal-B (tw) is about: 0.7*R1*C1 = 0.7*4.7x103*10*10-6 ~= 33 ms (>25 ms).

septillion

Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

GolamMostafa

#49
Sep 10, 2019, 11:58 am Last Edit: Sep 10, 2019, 12:05 pm by GolamMostafa
Or, just do it all in software ::)
It is definitely possible. There is a Debounce.h library; but, there are relative merits and demerits as to the use of hardware or software to overcome the bouncing times of the button -- a mechanical switch.

wvmarle

I for one can't see any advantage to the hardware solution - especially not one as convulated as proposed in #47 - except when using interrupts (required if you want a button press to wake from sleep). And then a small capacitor is usually enough.

Another place I needed hardware debounce is with an encoder, as the library apparently doesn't handle bounce at all. A small cap was all that's needed to make the encoder behave properly.

Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

GolamMostafa

#51
Sep 10, 2019, 03:08 pm Last Edit: Sep 10, 2019, 03:11 pm by GolamMostafa
If the following one is a typical behavior of a mechanical switch, then you want to claim that the small capacitor (usually 0.1 uF) is going to absorb all those jitters and keep the line at HIGH (or LOW) state at least for 20 ms?


There are some cases (especially in the firing fields) one demands that the firing pulse should be only for once and guaranteed; the Engineer does not go for any risk; he straight uses the non-retriggerable one-shot circuit that guarantees only one firing pulse in spite of hundreds of to-and-fro movements of the triggering switch.

wvmarle

If the following one is a typical behavior of a mechanical switch, then you want to claim that the small capacitor (usually 0.1 uF) is going to absorb all those jitters and keep the line at HIGH (or LOW) state at least for 20 ms?
Taking care of the bounce, easy. The button press discharges the cap very fast (it basically shorts it out); the pull-up resistor takes almost 1xRC to reach a logic "high" level (guaranteed at 0.6 * Vcc on an ATmega - in 1x RC the cap charges to about 0.7 * Vcc). RC is 3 ms for a 100nF cap and the typical 30 kΩ value for the internal pull-ups, 5-6 times longer than the total time you mention, while the cap gets discharged every time the contacts make during that bounce period. In fact I found that to debounce a mechanical encoder 100 nF is too big, if you rotate it fast (by hand!) you miss pulses simply because the cap doesn't allow the voltage to go up enough.
For a human pressed button, it'd be quite hard to ask that human to produce a press shorter than 20 ms. No need for external circuits for that. Sure for some very specific applications you may want to guarantee that you record a press even if you have a superhuman pressing the button super short, and you care less about the added cost in hardware & PCB space.
Even so if you have so short button presses (i.e. pulses) to worry about and your code is too slow (20 ms is a very long time for a single iteration of loop()), add that cap to debounce your button and guarantee a single pulse, and then connect an interrupt to your button to guarantee you don't miss the pulse. That's what interrupts are for.
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

GolamMostafa

#53
Sep 10, 2019, 03:31 pm Last Edit: Sep 10, 2019, 05:20 pm by GolamMostafa
Cool reading. (+).

(The natural behavior of a mechanical switch/button is such that when pressed, it makes a contact for a while and then starts bouncing which lasts for about 20 ms before it makes the final sit at the closing position. If the button is connected with an interrupt pin, it has to be ensured that the interrupt-pin receives only one active pulse out of these bouncing.)  

6v6gt

Cool reading. (+).

(The natural behavior of a mechanical switch/button is such that when pressed, it makes a contact for a while and then starts bouncing which lasts for about 20 ms before it makes the final sit at the closing position. If the button is connected with an interrupt pin, it has to be ensured that the interrupt-pin receives only one active pulse out of these bouncing.)  
Of course the filtering of these bounces could also happen later. That is in the interrupt service routine.

GolamMostafa

#55
Sep 11, 2019, 03:45 am Last Edit: Sep 11, 2019, 04:32 am by GolamMostafa
Of course the filtering of these bounces could also happen later. That is in the interrupt service routine.
You wanted to say that let the MCU be interrupted at the very first falling edge that happens at time t1 (Fig-1) following the closure of the interrupting device (the button).

Figure-1:

The ISR is very very short, and it usually contains only one line to set a flag like:
Code: [Select]
void ISRINT0()
{
    flag1 = true;
}


My intuition is this: before we start the process of filtering out the bounce pulses (by software delay or whatever may be) after arriving at the ISR, the ISR is done; the MCU returns to the main line program; the MCU is again interrupted by the next bounce pulse. There are multiple interrupts which we don't want to happen. The solution is to make an arrangement (either by software or by hardware) in such a way so that the MCU receives only one falling edge (the interrupting signal) at time t2 (Fig-1) from the button out of many bounces. That means that we have to crate a fence to block the 20 ms bouncing time , which is effectively built using oneshot circuit (Fig-2) by the Electronics Enthusiasts.  

Figure-2:

wvmarle

There are multiple interrupts which we don't want to happen.
That's one of the key reasons we don't want to use interrupts for button presses.

The next problem, if you just set a flag to true: in your main loop() you then have to check for the flag, clear it, and still subsequently ignore the flag being set for some time due to possible button bounce! So all you do is ADD the complexity of an interrupt while you STILL have to do software debouncing.

Quote
The solution is to make an arrangement (either by software or by hardware) in such a way so that the MCU receives only one falling edge (the interrupting signal) at time t2
The capacitor solution gives a single falling edge at t1, which is the only guaranteed one (how do you know which of the bounces is the last one? Buttons are not even guaranteed to bounce), after which you simply ignore new triggers for some time - 20-50 ms typically, a time that's long for a button's bouncing but short for a human operator.
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

Smajdalf

If an interrupt and SW debounce is needed simply disable it in the ISR and enable it after the button is released again. You may use the enable bit instead of the SW flag.
How to insert images: https://forum.arduino.cc/index.php?topic=519037.0

Go Up