I'm just testing out interrupt handling to better understand it. Somehow, it does not look right to me. I have an external pullup connected to Pin2, and a push button switch to pull it low. If an interrupt occurs, the count will increase by one. Every time I push the button, I got increment of 2 or sometimes 3 counts. I have a 100mS debounce also, doesn't seem to help. I hooked Pin2 to the scope, I don't see any bounce after 10mS. So, I'm confused and need some guidance. My code is below:
/*
*External 51K pullup on Pin2
*Pin2 is pulled down with a push button switch
*/
int interruptPin = 2;
volatile unsigned int count = 0;
void myISR() {
noInterrupts(); //disable further interrupts
for (int i=0;i<100;i++) //software debounce, 100mS
{
delayMicroseconds(1000); //delay() does not work in ISR. Have to use delayMicroseconds().
}
count += 1;
interrupts();
}
Thanks for your reply. I was trying to figure out why the interrupt doesn't work as expected, thus these extra precaution in the code. I'm coming from the Microchip PIC world, so Arduino is a little new to me.
Interrupts events (that is, noticing the event) can occur at any time, and most are remembered by setting an "interrupt event" flag inside the processor. If interrupts are disabled, then that interrupt will be handled when they are enabled again, in priority order.
The interrupt flag is in the que while i'm waiting for the debounce to expire. As posted by Delta_G, I have to ignore the extra interrupts during that time frame of the debounce. Once I understood this, I got it to work as I intend it to.
Never delay in an ISR, that defeats the whole idea of interrupts to handle an urgent hardware
event. And of course delay() itself will hang, delayMicroseconds() won't and delaying a few us isn't
so bad, but long delays (100's of us) are bad news in an ISR.
To debounce in an ISR you have to compare times to decide if the current transition is a bounce or not.
ExFisherman:
Thanks for your reply. I was trying to figure out why the interrupt doesn't work as expected, thus these extra precaution in the code. I'm coming from the Microchip PIC world, so Arduino is a little new to me.
What might be tripping you up is that AVRs automatically clear the interrupt flag at the beginning of the ISR, while PICs require you to manually clear it. If you clear the flag at the end of the ISR this "debouncing" scheme will work. Unfortunately, you don't have that control with an AVR so when a bounce happens during the ISR delay, the flag is set again and queued up for execution, which gives you the double count.
Also as mentioned, the noInterrupts()/interrupts() is redundant. Interrupts are disabled by default during an ISR.
More to the point, interrupts should not be needed for buttons. delay is a terrible, horrible, no good, very bad function to sprinkle around your code.
void myISR() {
static unsigned long lastIntMicros = 0;
unsigned long currentMicros = micros();
if (currentMicros - lastIntMicros > 10000UL) {
// It's been more than 10 milliseconds since the last button push
count++;
lastIntMicros = currentMicros; // Start debounce timer now
}
}
I ended up using the code like johnwasser posted above for myISR.
The lock out on interrupt response can fail when the button is released.
Your interrupt mode is FALLING, and you have have an external pullup. Switch bounce on the lead falling edge when the button is pressed will be locked out.
But, a human is going to hold the switch down for longer than the lockout time. If there is bounce on the release, the last FALLING edge time used in the debounce routine will be from when the button was pressed and the lockout will not occur and and the conditional statement will execute and you'll get an unwanted count.
Interrupts with noisy, human operated switches are problematic. That's why polling is usually recommended. Hardware debounce may be more reliable if interrupts are used.