EEVblog Electronics Community Forum

EEVblog => EEVblog Specific => Topic started by: EEVblog on December 28, 2016, 02:41:54 am

Title: EEVblog #961 - Monkey Debouncing
Post by: EEVblog on December 28, 2016, 02:41:54 am
How do you debounce a clapping monkey?
Probes The Monkey makes his return.
All about contact debouncing, setting up a universal counter as an event counter, and other issues that can arise on a seemingly simple test setup.

https://www.youtube.com/watch?v=Nj-Q8FQxHhU (https://www.youtube.com/watch?v=Nj-Q8FQxHhU)
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: joeqsmith on December 28, 2016, 03:57:57 am
Interesting.  I would have used a hall sensor or optics and filtered it in the digital domain.  Looking forward to seeing the actual testing of that little boost converter.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: ECEdesign on December 28, 2016, 04:19:03 am
We were taught to use a latch to debounce a switch at Uni
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: rob77 on December 28, 2016, 04:30:15 am
"how many times it claps" in a chinese or japanese accent would be much more funny   :-DD
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: rrinker on December 28, 2016, 05:06:22 am
 Or German. "Ve haf veys of making you clap, monkey!"
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: MartinX on December 28, 2016, 09:03:34 am
Worth mentioning is also that constantly shorting a capacitor will over time seriously corrode the contact surfaces, so the circuit will appear to work in the beginning but may stop counting after a while.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Fungus on December 28, 2016, 10:34:29 am
Use an Arduino!

It's two minutes' work to write a sketch that waits a minimum time between claps.

It can output pulses to your counter for display.

Code: [Select]
pinMode(counterOut,OUTPUT);
pinMode(clap,INPUT_PULLUP);

if (digitalRead(clap)==0) {
  // This creates 20ms of delay before it will recognize another clap
  // Adjust timing as needed
  digitalWrite(counterOut,LOW);
  delay(10);
  digitalWrite(counterOut,HIGH);
  delay(10);
}
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: kalleboo on December 28, 2016, 11:06:21 am
It's two minutes' work to write a sketch that waits a minimum time between claps.
Will that be reliable if there's noise on the line when it's making the squeaking noises?
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: max_torque on December 28, 2016, 11:10:08 am
Whilst the 330uF cap across the inputs of the counter is, frankly, at least 10x too large for this job, it does suggest the false counting from the head nodding motor noise has to be common mode noise, because that massive cap creates a low impedance AC "short" across the input of the counter.  Putting the two leads from Probes hands together a couple of turns round a large ferrite (as a common mode choke) would probably have fixed the issue without requiring the pass filter device used!
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: strangersound on December 28, 2016, 11:13:22 am
This was great lesson. What appears on the surface to be a pointless and silly exercise turns out to be a good lesson in setting up a test and some basic functions of multiple pieces of test gear, and even various signal issues such as noise, shape, etc.  :-+
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Fungus on December 28, 2016, 11:19:04 am
It's two minutes' work to write a sketch that waits a minimum time between claps.
Will that be reliable if there's noise on the line when it's making the squeaking noises?

If there's that much noise on the line then the entire setup won't work anyway, doesn't matter what you do.

I think Dave's choice of components in the video isn't great - the capacitor/resistor values are much too large and will leave it very susceptible to noise. Maybe he chose those values to make a pretty video (see the capacitor charge!). In real life the capacitor should recharge in much less than a second.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Fungus on December 28, 2016, 11:26:04 am
Just saw this while surfing...

(https://www.eevblog.com/forum/blog/eevblog-961-monkey-debouncing/?action=dlattach;attach=281296;image)
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: amspire on December 28, 2016, 11:35:44 am
Most top-end counters have a gate hold-off or delay so that once it triggers, it will not trigger again for the delay/hold-off time you set.

With this method, the noise becomes irrelevant because the counter trigger is disabled for the duration of the noise.

Doesn't this counter have a delay->time setting?

Edit: had a quick look at the manual and it looks like it does have a delay function but it may be it only works with the external gate input. Not sure about that.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Faith on December 28, 2016, 01:02:56 pm
Mm, not sure if it's a good idea to measure number of "cycles" versus exact numbers of claps.

If I recall correctly from previous videos Probes The Monkey does slow down in clapping quite significantly at lower voltage levels.

Thus you'll reach a point where it becomes a little trickier in determining exactly what one cycle is.

Since one clap at low voltage could be as long as one entire cycle at nominal voltage.

Other than that, super interesting video!~ Thanks much :D
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: PeterL on December 28, 2016, 03:56:19 pm
Whilst the 330uF cap across the inputs of the counter is, frankly, at least 10x too large for this job, it does suggest the false counting from the head nodding motor noise has to be common mode noise, because that massive cap creates a low impedance AC "short" across the input of the counter.  Putting the two leads from Probes hands together a couple of turns round a large ferrite (as a common mode choke) would probably have fixed the issue without requiring the pass filter device used!

I agree on this one, in fact I would say it's at least 1000x to large for a normal design. For a simple one-time solution like Dave needs here a quick-and-dirty solution is more acceptable, but I was hoping for a 555 solution right from the start.

This circuit is also a bit high on the load of the batteries that feed the switch. At each (1st)clap 1mC is thrown away. So I expect the batteries are starting to drain after a couple of thousand claps.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: joeqsmith on December 28, 2016, 05:53:47 pm
It's two minutes' work to write a sketch that waits a minimum time between claps.
Will that be reliable if there's noise on the line when it's making the squeaking noises?

If there's that much noise on the line then the entire setup won't work anyway, doesn't matter what you do.

I think Dave's choice of components in the video isn't great - the capacitor/resistor values are much too large and will leave it very susceptible to noise. Maybe he chose those values to make a pretty video (see the capacitor charge!). In real life the capacitor should recharge in much less than a second.

I think the micro is fine but not use a simple delay.  You really want a counter running at some rate faster than the cycle time that is reading the input and waiting for it to settle.  Any change in the input state resets the counter.  So you want what ever your debounce time to be a number of consecutive reads of the input with no state change.



if clear = '1' then
  state <= S_INIT;
  cnt <= (others => '0');               -- Reset filter timer
  filt_out <= '0';                      -- Force output low
elsif (clock'event and clock = '1') then
  case state is
    when S_INIT    =>
      nt <= (others => '0');           -- Reset filter timer
      if input /= filt_out then         -- Test input state change
        state <= S_SETTLE;              -- Wait for input to settle
      end if;
    when S_SETTLE  =>
      cnt <= cnt + 1;                   -- Increment the filter timer
      if input = filt_out then          -- Check if input glitched
        state <= S_INIT;                -- Glitched, reset filter
      elsif cnt > FILTPERIOD then       -- Check filter timeout
        state <= S_DEBNCED;             -- We have a clean signal
      end if;
    when S_DEBNCED =>
      filt_out <= input;                -- Change output state
      state <= S_INIT;                  -- Reset filter and search for next edge
    when others=>
      state <= s0;                      -- We are lost, reset filter
  end case;
end if;




Title: Re: EEVblog #961 - Monkey Debouncing
Post by: lpickup on December 28, 2016, 06:38:52 pm
This circuit is also a bit high on the load of the batteries that feed the switch. At each (1st)clap 1mC is thrown away. So I expect the batteries are starting to drain after a couple of thousand claps.
No worries, mate!  Just slap a batteriser on it, and she'll be right!

In all seriousness though, the batteries driving the switch detector circuitry should last an order of magnitude or so longer than the batteries driving Probes, no?

Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Dave on December 29, 2016, 04:26:29 pm
Use an Arduino!

It's two minutes' work to write a sketch that waits a minimum time between claps.

It can output pulses to your counter for display.
You keep the switch pressed and have a 50Hz signal generator. Great solution there, buddy.
Kudos on the blocking code.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: rrinker on December 29, 2016, 04:51:48 pm
 Yet after ALL that work, I see the monkey STILL bounces after he claps....  :-DD
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Yansi on December 29, 2016, 04:57:36 pm
Worth mentioning is also that constantly shorting a capacitor will over time seriously corrode the contact surfaces, so the circuit will appear to work in the beginning but may stop counting after a while.

Good point there. I always yell pissed, where someone puts a pair of 100n caps directly accross a mechanical rotary encoder, as a means of debouncing the contacts.  >:D  ;D
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Fungus on December 29, 2016, 05:03:03 pm
It's two minutes' work to write a sketch that waits a minimum time between claps.
You keep the switch pressed and have a 50Hz signal generator. Great solution there, buddy.
Kudos on the blocking code.
It's only for the monkey so who cares about the blocking, etc.

Off topic: Shameless plug for some non-blocking, fully debounced Arduino code I'm working on:

https://www.facebook.com/official.arduino/videos/1604466669579646/ (https://www.facebook.com/official.arduino/videos/1604466669579646/)

 :)
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Yansi on December 29, 2016, 05:04:17 pm
[quote author=PeterL link=topic=80536.msg1100856#msg1100856 date=1482940579}
This circuit is also a bit high on the load of the batteries that feed the switch. At each (1st)clap 1mC is thrown away. So I expect the batteries are starting to drain after a couple of thousand claps.
[/quote]

How did you get to 1mC?   I thought he used 330uF and 3V. That is 3mC per each clap.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: PeterL on December 29, 2016, 05:20:01 pm
[quote author=PeterL link=topic=80536.msg1100856#msg1100856 date=1482940579}
This circuit is also a bit high on the load of the batteries that feed the switch. At each (1st)clap 1mC is thrown away. So I expect the batteries are starting to drain after a couple of thousand claps.

How did you get to 1mC?   I thought he used 330uF and 3V. That is 3mC per each clap.
[/quote]

To my best knowledge it's: Q=C x U
3 times 330u gives 990u...
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: FrankBuss on December 29, 2016, 05:25:50 pm

if clear = '1' then
  state <= S_INIT;
  cnt <= (others => '0');               -- Reset filter timer
  filt_out <= '0';                      -- Force output low
elsif (clock'event and clock = '1') then
...


Hmm, asynchronous reset, this can have metastability problems. And we are in 2016, you can write "elsif rising_edge(clock) then" (and parentheses are not needed). Every synthesis tool should understand this by now.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Kalvin on December 29, 2016, 07:04:02 pm
Arduino pseudo-code:

#define SAMPLE_TIME_ms 1
#define THRESHOLD 100
state = input_pin_state
count = THRESHOLD / 2
loop forever:
  if input_pin_state == 0:
    /* switch closed, react fast */
    count = 0
    state = 0
  else
    /* switch opened, debounce */
    if count < THRESHOLD:
      count = count + 1
    endif
    if count >= THRESHOLD:
      state = 1
    endif
  endif
  output_pin_state = state
  delay SAMPLE_TIME_ms
endloop
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Harrkev on December 29, 2016, 08:06:41 pm
OK.  I am confused.  At around the 14 minute mark, there is a circuit shown with a diode bypassing R2 so that, when charging, R2 does not matter.  In that case, only R2 is used for discharging, and only R1 is used for charging.

Ummmm, given that R2 is going to be much smaller than R1, couldn't we just choose a new R1 that is found by R1 - R2?  That saves us having to put a diode in there at all!  One fewer part is a good thing.

I could see needing the diode if, for some reason, R2 > R1.  However, that does not seem to be the case here.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Yansi on December 29, 2016, 09:10:36 pm
[quote author=PeterL link=topic=80536.msg1100856#msg1100856 date=1482940579}
This circuit is also a bit high on the load of the batteries that feed the switch. At each (1st)clap 1mC is thrown away. So I expect the batteries are starting to drain after a couple of thousand claps.

How did you get to 1mC?   I thought he used 330uF and 3V. That is 3mC per each clap.

To my best knowledge it's: Q=C x U
3 times 330u gives 990u...
[/quote]

Oh, sorry, I wasn't reading right. I read Joules instead of Coulombs. Doh.  :palm:
0,5*C*U^2 per discharge lost in the ESR when switch closes, the same 0,5CU^2 lost on charge in the pullup resistor. ... if I am not mistaken.
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: joeqsmith on December 30, 2016, 01:48:05 am

if clear = '1' then
  state <= S_INIT;
  cnt <= (others => '0');               -- Reset filter timer
  filt_out <= '0';                      -- Force output low
elsif (clock'event and clock = '1') then
...


Hmm, asynchronous reset, this can have metastability problems. And we are in 2016, you can write "elsif rising_edge(clock) then" (and parentheses are not needed). Every synthesis tool should understand this by now.

Hmm, I guess S0 state should have been S_INIT.  Codes there just to give readers another way to look at the simple debounce problem.       
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Fungus on December 30, 2016, 09:53:31 am

if clear = '1' then
  state <= S_INIT;
  cnt <= (others => '0');               -- Reset filter timer
  filt_out <= '0';                      -- Force output low
elsif (clock'event and clock = '1') then
...


Hmm, asynchronous reset, this can have metastability problems. And we are in 2016, you can write "elsif rising_edge(clock) then" (and parentheses are not needed). Every synthesis tool should understand this by now.

Hmm, I guess S0 state should have been S_INIT.  Codes there just to give readers another way to look at the simple debounce problem.     

I liked my code better, even if it did block. KISS  :)
Title: Re: EEVblog #961 - Monkey Debouncing
Post by: Kalvin on December 30, 2016, 01:03:30 pm
Modified the original pseudocode to allow dynamically adjustable debounce time using the A/D-converter and a trimpot connected toe ADC-input and between VCC and GND:
 

#define ADC_THRESHOLD_RANGE 255
function Get_Threshold() : int
begin
  return ADC value between 0 ...  ADC_THRESHOLD_RANGE
end
#define SAMPLE_TIME_ms 1
state = input_pin_state
count = Get_Threshold() / 2
loop forever:
  threshold = Get_Threshold()
  if input_pin_state == 0:
    /* switch closed, react fast */
    count = 0
    state = 0
  else
    /* switch opened, debounce */
    if count < threshold:
      count = count + 1
    endif
    if count >= threshold:
      state = 1
      count = threshold
    endif
  endif
  output_pin_state = state
  delay SAMPLE_TIME_ms
endloop