Help with debouncing a "debounced" switch

I have a setup as in the attached image. I am getting a bounce somewhere that I don't believe I should. I have a tried both 22 and 100uF capacitor. The attached code should cause an led to light as a button is pressed and dim as the button is released (or the opposite as the bounce occurs). I'm scratching my head and not knowing what I'm doing wrong. Can you help me figure this thing out?

// http://leaflabs.com/docs/lang/api/attachinterrupt.html

volatile int state = LOW; // must declare volatile, since it's // modified within the blink() handler int ledPin = 13; void setup() { pinMode(ledPin, OUTPUT); pinMode(0, INPUT); attachInterrupt(0, blink, CHANGE); }

void loop() { digitalWrite(ledPin, state); }

void blink() { if (state == HIGH) { state = LOW; } else { // state must be LOW state = HIGH; } }

WP_20140420_008[1].jpg|1955x1326

Some issues:

  1. It looks like the filter for “INT0” has built-in “hysteresis” which works when the pushbutton is released. However, when it’s pressed, it shorts the capacitor creating a small interval of noise until it is discharged.
  2. The iteration speed of your loop is extremely fast … it will detect this noise and toggle the output (led).
  3. The blink() function only toggles the output based on input change. Rising, falling, or input level is disregarded. So the final status of the led is random.

sl33k3r: I'm scratching my head and not knowing what I'm doing wrong.

Just about everything, I am inclined to say!

Specifically, using an interrupt to sense a pushbutton, and using a hardware debounce circuit.

Actually, the problem with the hardware debounce, is that (as dlloyd has pointed out,) you are directly discharging the capacitor. This will among other things, over time destroy the pushbutton. The circuit will work if you put a resistor in series with the pushbutton of the order of one fifth of the pull-up value.

But there is simply no need for any hardware debounce because you have a microcontroller which is perfect for this very job. Interrupts are completely inappropriate for "Human Interface" functions and particularly pushbuttons because of their immediate response (so they respond to every individual element of the bounce) whilst you have over a million clock cycles in which to respond to the fastest possible human-generated event. There are some things for which interrupts are useful; this simply is not one of them.

The "loop" code is where you poll your inputs and make decisions based on those inputs. This is important - if you use interrupts to handle events, the interrupt cannot directly affect the execution of the main loop, you then have to introduce the complication of "semaphores" which the main code will detect only as it passes the sections where it examines such semaphores. This indirection is rarely appropriate.

Polling a pushbutton is a two-step process; the first is to determine the polling interval, generally one millisecond (by examining the "millis()" count) and then to detect when the button is stable in a new state for - say - ten successive intervals at which point you can consider it "de-bounced". I have attempted to detail the logic here.

Thank you for your replies. I am familiar with software debounce while polling, but thought I would try hardware debouncing. I had a LM339 laying around so I thought I might try to see how well debouncing would work with hardware since I had seen others using it with apparent success.

As suggested, I did place a 2.2k resistor in series with the push button switch. I end up with the same results. Inconsistent switching with polling and with interrupt when no software debounce was utilized. Curious, (and lacking an oscilloscope) I wrote a script to count the number of bounces on the switch as it was pressed or released and track the amount of time that the switch actually bounced. The hardware as set up (including Paul__B’s resistor suggestion) would bounce an average of 2 times in 12-16 us upon press and 5 to 7 times in 34-80 us when released. So I decided to try a very basic circuit. Leaving one side of the switch grounded, I pulled the other side high with a 2.2k resistor and connected my interrupt between the resistor and the switch. The bounces were reduced to 2 or less in under 16 us. The other parts of the circuit were introducing many bounces.

I used the capacitor to smooth the switching, but apparently it is hindering. I decided to test the circuit as Paul__B stated it would work (with the 1/5 value of the pull-up resistor in series with the switch) but with the capacitor removed, to see how much it was affecting performance. Bounces were “nearly” non-existent. Software debouncing will be required for this type of circuit. The capacitor was, as I find now in this circuit configuration, an error in judgement. Add this to my experiences.

Also, if you can use the included code to count switch bounces or other interrupt activations…please do. If you see a flaw that I can improve fix, please let me know.

// Constants
const unsigned int mode = FALLING; // Mode of interrupt [ LOW/CHANGE/RISING/FALLING/HIGH ] (HIGH is for Arduino Due only)
const unsigned int interrupt = 1; // Which interrupt will be used
const unsigned int baud = 38400; // Speed (Baud) of the serial connection [ 300/1200/2400/4800/9600/19600/38400/57600/115200 ]
const unsigned long waitTime = 5000; // Default timeout of the process to display bounces…if any
const unsigned long gracePeriodMs = 100; // Number of milliseconds to wait after last button action recorded before posting results
// Too short of time may not get all interrupt calls for the current switch activation
// Too long will only make you wait until “waitTime” expires

// Non-Constants
unsigned long inputExpiryTime; // When time runs out and bounce results will be displayed

// Variables modified within ISR (Interrupt Service Routine) must be declared “volatile”
volatile unsigned int count; // Number of interrupt calls
volatile unsigned long countStartTime; // Time of first interrupt in microseconds
volatile unsigned long countEndTime; // Time of last interrupt in microseconds

void setup()
{
Serial.begin( baud );
}

void loop()
{
count = 0; // Reset interrupt call count
inputExpiryTime = millis() + waitTime; // set input expiration time
attachInterrupt( interrupt , recordBounce , FALLING ); // attach the interrupt
while( millis() < inputExpiryTime ) // Wait for interrupt input
{
if( count && ( micros() - countEndTime > gracePeriodMs * 1000 ) ) // once interrupt has been called, don’t wait until the timeout expires…// only wait until grace period expires
{
inputExpiryTime = millis() - 1; // Force the display of the interrupt call count
}
}
detachInterrupt( interrupt ); // detach the interrupt to keep from receiving signals while printing
switch (count) {
case 0: // Time ran out for operating switch
Serial.println( “Time expired! No input detected.” );
break;
case 1: // No bounce detected
Serial.println( “No bounce detected! Is the grace period long enough?” );
break;
default:
Serial.print( "Start Time: ");
Serial.print( “\t” );
Serial.print( countStartTime ); // First interrupt call of this iteration
Serial.print( “\t” );
Serial.print( "End Time: " );
Serial.print( “\t” );
Serial.print( countEndTime ); // Last interrupt call of this iteration
Serial.println( “\t” );
Serial.print( "Total Time: " );
Serial.print( “\t” );
Serial.print( countEndTime - countStartTime ); // Time that switch bounced in this iteration
Serial.println( "us " );
Serial.print( "Count: " );
Serial.print( “\t” );
Serial.print( count ); // How many times the switch actuated interrupt mode
Serial.print( “:\t” );
Serial.print( "Initial activation and " );
Serial.print( count - 1 ); // Number of measured bounces per interrupt mode
if( count == 2 )
{
Serial.print( " bounce. " );
}
else
{
Serial.print( " bounces. " );
}
Serial.println( “\t” );
break;
}
}

void recordBounce()
{ // ISR to count actuation and subsequent bounces
count += 1;
if( count == 1 ) countStartTime = micros(); // first interrupt, start counter
countEndTime = micros(); // current time
}

Are you sure you've got it hooked up correctly? 10k and 100uF should have a time constant of 1 second, so there should be no bouncing on that end. It may be transition glitching, which would probably be worse for a slower circuit since your comparator circuit has no hysteresis.

Actually, on second read through your last post, that;s probably it. You mention that the bouncing is worse on release. This is consistent with a slow signal curve causing the comparator to glitch around the transition point due to noise.

I say unless you add some hysteresis to your comparator, ditch it. It's an unnecessary complication, and is probably the cause of your glitches.

Finally, use code tags to post code, not quotes.

Try this.
Only one jumper wire - one end connected to pin 2, then keep touching the other end to ground.
Serial monitor will display running count of “touches” without skipping or missing any values.

// constants
const byte button = 2, led = 13;

// variables
byte buttonState, buttonRead;
unsigned long microsStart = 20000, buttonCount = 0;

void setup() {
  Serial.begin(115200);
  pinMode(led, OUTPUT);
  pinMode(button, INPUT_PULLUP);
  buttonState = 0xFF;
  buttonRead = 1;
}

void loop() {
  buttonFilter();
  // your code starts here
  digitalWrite(led, buttonRead); // debounced and filtered
}

void buttonFilter(void) {
  if (micros() - microsStart >= 10000) // min interval between bounces
  {
    buttonState = (buttonState << 1) | digitalRead(button); // shift and read
    if ((buttonState & B11111) == B01111) // if rising and high for 3 stable reads
    {
      buttonRead = 1;
    }
    if ((buttonState & B11111) == B10000) // if falling and low for 3 stable reads
    {
      buttonRead = 0;
      buttonCount =  buttonCount ++;
      Serial.println(buttonCount);
    }
    microsStart = micros();
  }
}

For pushbutton input, only one 10K pull-up resistor required.
Reference

Jiggy-Ninja:
Actually, on second read through your last post, that;s probably it. You mention that the bouncing is worse on release. This is consistent with a slow signal curve causing the comparator to glitch around the transition point due to noise.

Precisely.

Jiggy-Ninja:
I say unless you add some hysteresis to your comparator, ditch it. It’s an unnecessary complication, and is probably the cause of your glitches.

Aakkk! I misread his circuit, was thinking that it did incorporate hysteresis. Which it could with slight rearrangement.

If you must use hardware debounce - if you really must - then you use a pushhbutton to ground, a 2k2 resistor to 5V, take that point through a 10k resistor to the input of a 74HC14 with a capacitor of some value (2µF) to ground on that input.

sl33k3r: Thank you for your replies. I am familiar with software debounce while polling, but thought I would try hardware debouncing.

Hardware debouncing should only be used for inputs to counters/flipflops where every single change needs to be recorded and there's no microcontroller around to do software debouncing.

None of those conditions apply here.