I've found a tricky application for which the Arduino platform may be appropriate, but before I proceed I'd like to ask a couple questions I couldn't seem to find clear answers for in my research.
Without going into many details, let's say I'm using some switches to activate interrupts and I want to make certain that my ISRs don't run twice or at inappropriate times. I can't incorporate debounce delays without compromising the tasks performed by my hardware. To solve this, I could detach the interrupt and then reattach it when I need to use it again. Is it possible to detach an interrupt within that same interrupt's ISR? If so, I'm confident I could accomplish what I hope to.
For further control, I'd also like the interrupt to receive its HIGH signal from a digital output pin with a physical switch in between. This would act as a software safety so that an accidental button press won't set off the ["rising"] interrupt unless the digital pin is set HIGH. I see no reason this can't be done, but to be clear I have my circuitry right, I'd wire the DO pin to the interrupt with a switch in between; and a 10k resistor between the interrupt and ground. Is that correct? Or should the resistor be between the DO pin and ground? The difference is whether the circuit is tied to ground before or after the physical switch. I'm not sure which works.
I see no reason this can't be done, but to be clear I have my circuitry right, I'd wire the DO pin to the interrupt with a switch in between; and a 10k resistor between the interrupt and ground. Is that correct?
Yes, between the interrupt pin and ground, so as to prevent a 'floating' input condition when the switch is in the open position. Not sure about the detachinterrupt when inside a ISR, but I think it should work. The trick is when do you reattach it such that you won't miss a future interrupt when you need to?
Ah, that wiring makes sense. I appreciate the swift replies.
For safety's sake I think it would be best to detach the interrupt so there's no risk of running an ISR when I shouldn't. (robtillaart- would your example provide this kind of protection? I don't fully understand.) And reattaching shouldn't cause and trouble unless the process takes long, but even a few ms wouldn't hurt.
The code I presented allows interrupts to happen, but the first thing the IRQ does is check if the IRQ is allowed by checking the volatile booean disableIRQ. If this flag is set the IRQ will be finished (return statement) so no further code will be executed. It is volatile so the compiler will not optiimize it and every change of it will directly be visible in the IRQ.
When the disableIRQ flag will be set is up to you(r programs logic)
can be in the IRQ itself
can be in void loop()
can be in void setup()
can be in another function
can be in another IRQ routine.
"disabling" IRQ's this way has an advantage above detachInterrupt shown in code below. This sample IRQ updates counter2 if enabled, and updates counter1 if disabled. The advantage is that you can easily see how often the IRQ is called while disabled. The disadvantage is that the IRQ still will steal CPU cycles while disabled.
volatile unsigned long counter1 = 0;
volatile unsigned long counter2 = 0;
volatile boolean disableIRQ =false;
void IRQ()
{
if (disableIRQ)
{
counter1++;
return;
}
counter2++;
// rest of the IRQ code
}
Another question- I was told that sometimes with microcontrollers, tripping a disabled interrupt will result in the ISR being run as soon as that interrupt is re-enabled because the flag is set when the interrupt is tripped regardless of whether it is enabled. Will I need to clear the flag before re-enabling the interrupt or does the Arduino utility do this automatically?
Will I need to clear the flag before re-enabling the interrupt or does the Arduino utility do this automatically?
It's your choice really and is application dependent. The 'memory' of a pending interrupt happening while your were detatched can be useful to not miss that event while in the detached mode as it will be 'serviced' when you reattach. However that 'event' memory is only one event long and it doesn't mean you haven't missed multible events while detached. So again it's nice to have the option either way and use it to best fit your application requirements. Interrupts can be tricky and takes some study and experiance to learn all their traps.
When bit 0 is set in EIFR and and the I bit is set in SREG, you jump to the isr for external interrupt 0, you can clear this bit by writing a one to it, as you did in that code.
Bit 1 in EiFR has the same functionality for external interrupt 1, so to clear it,
EIFR = 2; or
EIFR = 0x2; hex is easier to convert to bytes, or
EIFR = 1<<1;
all those do the same thing, but you are better off with;
Thanks so much for the help, guys. My project works perfectly now. It now "debounces" by detaching the interrupts, running the important code, clearing the interrupt flags, and then resetting them. I really appreciate it.
BTW, not trying to be snide about the datasheet comment. Its just when you get to the level of programming these things where you are worried about say, resetting the external interrupt flag, the datasheet has the answers and I have never yet had to wait for it to get back to me. The trick was convincing myself that i could actually understand it, even if it is more than 500 pages long
When bit 0 is set in EIFR and and the I bit is set in SREG, you jump to the isr for external interrupt 0,...
What about EIMSK?
You might want to take a look at the Reference Diagrams for the ATmega External Interrupts at http://web.alfredstate.edu/weimandn. Scroll down to the 'Atmel ATmega Subsystem Diagrams' and click on the Reference Diagrams link.
Well, certainly the correct bit must be set in EIMSK to get your externals firing at all, didn't think that was part of the problem here so I didn't mention it, he had that part going already.