NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Basic Electronics » Debouncing and External Interrupts

February 17, 2010
by ecornwell
ecornwell's Avatar

Hello,

I've run into a little problem I can't quite wrap my head around. I've got a little project setup where I use the servo squirter code to move a servo. I added another mode that has timed movements for the servo. I added another "crazy" mode where the servo moves to random positions and waits a random amount of time between the movements. This is pretty cool and helped me get a better understanding of some concepts. (I still don't fully understand how the PWM signal is generated and works but I'll get there.)

What I wanted to do is be able to use all 3 modes and have the included button allow me to cycle through them. I'm having a little problem with the debouncing. I've got the external interrupt setup but I noticed when I hit it, it would go through all 3 modes. (The interrupt handler increments a counter.) I tried using the debounce function from the motors tutorial but it doesn't seem to be working correctly. Sometimes I get a response and other times I don't. I can get it to cycle through if I press the button enough times but I want it to change once when I press the button. I would also like it to break out of whatever its doing as well but I'm really unsure on that one. It is either in a delay_ms() step or a uart_read() which the latter forces me to give uart input in order for the program to move along.

So what's the best way to debounce a button when you're using external interrupts?

Thanks!

February 17, 2010
by pbfy0
pbfy0's Avatar

Well, I din;t know if you're doing this, but in your external interrupt you should at least wait for the end of the button press (while(PINx & (1<<Px?)). If it says &lt;, that means <. &amp; is &

February 18, 2010
by Noter
Noter's Avatar

Basically you need to ignore button input for a short period after the 1st interrupt. Using a timer to control the button disabled period works well ...

volatile int button_disable;

ISR(PCINT1_vect){
  if (button_disable==0) {  // only handle if zero, otherwise in debounce period
    button_disable=102;  // start debounce period ~ .2 sec
    if(!(PINC & (1<<PC5))){ // pin goes low on push
      <button processing code>
      }
    }
  }
}

SIGNAL(SIG_OVERFLOW0) {
  // decrement the push button debounce countdown
  if (button_disable>0) {
    button_disable--;
    }
}

in your init routine...
 // set timer for button debounce
 // Timer0 internal 14745600/256/256 =  225mhz interrupts
 TCCR0B = (1<<CS02);
 TIMSK0 = (1<<TOIE0);
February 18, 2010
by johnh
johnh's Avatar

For more on PWM, refer to the Timer/Counter0 documentation. ATMega 168 data sheet Pg 90. specifically PWM, Pg 97+.

Noter's code is very detailed. It looks to be very effective. An alternative, albeit possibly less effective, solution is something like the following:

if(PINC & (1<<PC5)) {
            count = (count + 1);
            delay_ms(200);
        }

The big advantage of that particular code is that it frees up Timer0 for other uses. The big disadvantage is that it will cause your interrupt to hold for 200 ms, as opposed to Noter's code, which will not. This could be problematic if you have a lot of interrupts or events happening at the same time, as they will queue behind this interrupt as opposed to firing immediately. However, this should not impact your PWM adversely.

October 24, 2010
by Gordito
Gordito's Avatar

I found this great link on Hack a Day, so I hopt this helps with your project.

http://www.ganssle.com/debouncing.htm

G-

January 29, 2011
by leedawg
leedawg's Avatar

This was exactly what I was looking for trying to just make a simple on and off switch using an PCINT1 interrupt. I had mine structured in a similar fashion using a variable that was incremented each time the pin interrupt was called however I found it would increment up by 2 sometimes 7 which was probably due to me not being able to push the button on and off fast enough and several interrupts fired for each button push. This has solved that problem however I find that if I depress the button a moderate speed it will sometimes toggle right back off again.

My question is if you hold the button down with the code provided by Noter what stops the "button processing code" after the if(!PINC & (1<<PC5) function from being executed over and over while the button is depressed or does the code not leave the if statement until the button is released?

Thanks again Im a total Noob to both C and micro-controllers but learning slowly

Thanks.

Lee

January 29, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi leedawg,

What keeps the code from executing over and over is that the whole thing is in a pin change interrupt handler, so only when there is a pin change on the proper pin will that code execute. The timer keeps it from executing twice if two pin transitions happen really close to each other (debouncing), but a sustained press will only generate one pin transition.

Humberto

March 26, 2011
by hariharan
hariharan's Avatar

hey! i want to know how to set interrupts . like do something for the first interrupt. do something for the second interrupt. do something for the third interrupt. if there is no third interrupt, do something

March 27, 2011
by Mujda
Mujda's Avatar

Hi,

I've also been trying to sort out debouncing issues on reed switches. Using the Timers in the software to create a pause before incrementing the pulse count worked fine, but it used up timers. My issue now is I need the mcu to run at 32kHz to save power - too slow to run an interrupt driven increment. I've reverted to using a hardware low-pass filter. All you need is 2 resistors and 1 capacitor. 1 resistor (22k) between input pin and Vcc, 1 resistor (3.6k)in-line with the input, and the capacitor (500nF)between the input pin and 0V. You need to turn off the input pin pull-up resistor, as the 22k now does this job. The problem with using the internal pull-up resistors is they vary between 20-50k, which is too much uncertainty - hence using an external one.

Post a Reply

Please log in to post a reply.

Did you know that NerdKits make a great gift? Learn more...