I am sorry for the noob question here. Here goes... Do you have to "declare" the pin of the interrupt ?
So Do I add pinMode or no pinMode ?
Ex:
// My variable stuff
void setup()
{
pinMode(2, INPUT); // <-- The interrupt pin
/*
Do I put that line there if I need an interrupt ? YES or NO
*/
attachInterrupt(0, myinterrupt, RISING);
// other init stuffs
}
void loop()
{
// my main program
}
void myinterrupt()
{
// interrupt stuff // No delay() please !!!
}
When the pin goes low (as from a normally open switch being closed to ground, or some external device (output of an optocoupler for example) taking the pin to a low) an interrupt will be created.
Otherwise, the pullup resistor keeps it at a nice clean high level.
attachInterrupt(0, myinterrupt, FALLING); // would work also I guess.
attachInterrupt(0, myinterrupt, CHANGE); // would work also I guess.
Depends on usage, like all things.
For my RF remote control, the program would start from the same spot after getting interrupted from sleep.
This function is called after determining that we're going to sleep:
void enterSleep()
{
/* Setup pin2 as an interrupt and attach handler. */
attachInterrupt(0, pin2Interrupt, LOW);
/* the sleep modes
SLEEP_MODE_IDLE - the least power savings
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_STANDBY
SLEEP_MODE_PWR_DOWN - the most power savings
*/
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // setting up for sleep ...
sleep_enable(); // setting up for sleep ...
// Disable ADC
ADCSRA &= ~(1 << ADEN);
// Power down functions
PRR = 0xFF;
sleep_mode(); // now goes to Sleep and waits for the interrupt
this for the ISR:
void pin2Interrupt()
{
/* This brings us back from sleep. */
}
and then this runs after waking up;
/* The program will continue from here after the interrupt. */
detachInterrupt(0); //disable interrupts while we get ready to read the keypad
// Power up functions
PRR = 0x00;
/* First thing to do is disable sleep. */
sleep_disable();
void pin2Interrupt()
{
detachInterrupt(0); //disable interrupts while we get ready to read the keypad
}
The interrupt might be entered again before the detachInterrupt is done. And indeed getting into the detachInterrupt function (pushing stuff etc.) is likely to take a few instructions. You might not notice it (as the ISR doesn't do much) but I bet the interrupt count is higher than you are expecting, if you were to measure it.
This is detaching the interrupt the moment you return from sleep:
#include <avr/sleep.h>
volatile int counter;
void isr ()
{
counter++;
} // end of isr
void setup ()
{
digitalWrite (2, HIGH); // enable pull-up
attachInterrupt (0, isr, LOW);
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable(); // enables the sleep bit in the mcucr register
sleep_mode(); // now goes to Sleep and waits for the interrupt
detachInterrupt (0);
Serial.begin (115200);
Serial.println ();
Serial.println (counter);
} // end of setup
void loop () {}
Now I start the serial monitor, and then ground pin 2. I see this:
11
Now detach the interrupt in the ISR:
#include <avr/sleep.h>
volatile int counter;
void isr ()
{
counter++;
detachInterrupt (0);
} // end of isr
void setup ()
{
digitalWrite (2, HIGH); // enable pull-up
attachInterrupt (0, isr, LOW);
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable(); // enables the sleep bit in the mcucr register
sleep_mode(); // now goes to Sleep and waits for the interrupt
Serial.begin (115200);
Serial.println ();
Serial.println (counter);
} // end of setup
void loop () {}
Now when testing I see this:
1
So moving the detachInterrupt actually saved an extra 10 interrupts from firing! If the interrupt routine was doing anything else important, it is doing it 11 times rather than 1. Plus there is the overhead of servicing 11 interrupts rather than one.
That is an interresting use of an interrupt, "interrupt and detach" ... Interesting. Can be usefull in some projects design, but to use the interrupt again you just simply re-activated the interrupt. In your example, the first program, you got 11, sound like bouncing, but the other version, it only one, some kind of "debounce" or "latch". .... Interesting
No it's not a bounce. It's expected behaviour from using the LOW interrupt.
The LOW interrupt keeps firing (while interrupts are enabled) after every instruction (and while the signal is low).
According to the datasheet:
When the AVR exits from an interrupt, it will always return to the main program and execute one more instruction before any pending interrupt is served.
So it limps along, executing the ISR for every single machine instruction until you detach the interrupt. I'm guessing from the number 11 being returned, that calling detachInterrupt, and it actually doing something useful, takes 10 instructions (we expected the count of 1 after all).
After the sleep it calls sleep_disable() which takes 3 instructions.
Then it takes two instructions to load a register with 0 and call detachInterrupt.
Then (inside detachInterrupt) this takes two instructions:
if(interruptNum < EXTERNAL_NUM_INTERRUPTS)
Then this takes two instructions:
switch (interruptNum) {
Finally turning the interrupt off takes another.
That's a total of 10 instructions.
For detecting a pin going low you are better off using FALLING interrupt. That only fires once (ie. from HIGH to LOW transition). Handling debounces is another story.
Just to explain a bit, the LOW interrupt is the only one that wakes the processor from sleep, so you need to use it in this particular case. See the manual page 70:
Low level interrupt on INT0 and INT1 is detected asynchronously. This implies that this interrupt can be used for waking the part also from sleep modes other than Idle mode.
It can't detect FALLING, RISING, or CHANGE interrupts because the clock is stopped in sleep mode, thus it can't notice level transitions.
However as I pointed out, if you don't want a "sleepy" wake-up, detach the interrupt immediately in the ISR, to save having severely degraded performance after getting the interrupt.
Sorry I mis-understood you. In one of my project, I did use attachInterrupt(1,myint,LOW); and the display when crazy ( display a counting data ) , so I use FALLING and it's stable. Still, your idea "interrupt & detach" is interesting, it will be usefull in some projects design.