Yes, I am seeing this too. You can understand why with this code:
int intcounter = 0;
int intcounterlast = 0;
void setup() {
pinMode(3, INPUT); //pin 3 for interrupt
Serial.begin(9600);
}
void loop() {
if (Serial.available()>0)
{
char tempchar = Serial.read();
// Print out INT1 registers before and after attachInterrupt/detachInterrupt
Serial.print(tempchar);
Serial.println(F(" recieved."));
Serial.print(F("EIMSK before = "));
Serial.println(EIMSK);
Serial.print(F("EIFR before = "));
Serial.println(EIFR);
switch (tempchar)
{
case 'a':
attachInterrupt(1,pulses_in,RISING);
break;
case 'b':
detachInterrupt(1);
break;
}
// Print out INT1 registers before and after attachInterrupt/detachInterrupt
Serial.print(F("EIMSK after = "));
Serial.println(EIMSK);
Serial.print(F("EIFR after = "));
Serial.println(EIFR);
Serial.println(F("===================="));
}
// Look for ISRs and print message when they occur
int intcountertemp;
do
{
intcountertemp = intcounter;
} while(intcountertemp != intcounter);
if(intcounter != intcounterlast)
{
Serial.print(F("AAA:"));
Serial.println(intcounter);
intcounterlast = intcounter;
}
}
void pulses_in()
{
intcounter++;
}
Here are the results of the code after performing the actions you described:
a recieved.
EIMSK before = 0
EIFR before = 0
EIMSK after = 2
EIFR after = 0
AAA:6
AAA:14
AAA:20
AAA:27
b recieved.
EIMSK before = 2
EIFR before = 0
EIMSK after = 0
EIFR after = 0
a recieved.
EIMSK before = 0
EIFR before = 2
EIMSK after = 2
EIFR after = 0
AAA:28
If you look at sections 13.2.2 and 13.2.3 of the ATmega328P datasheet, you'll see that INT1 has both an "enable" bit in EIMSK and a "flag" bit in EIFR. The condition that INT1 has been configured to detect will always set the flag, but will only run your ISR if the enable bit is set.
When you first send 'a', both the flag and enable start at zero. Your code then calls attachInterrupt(), and now you see that EIMSK is 2 indicating INT1 is now enabled. Your flag is still 0, however, since you haven't pushed the button yet.
After you push the button, you likely get a bunch of interrupts unless you have filtering on your circuit you didn't mention.
When you next send 'b' you see that the enable is set before you call detachInterrupt() but 0 afterwards. When you push the button now, your ISR does not run because it's not enabled.
It is still setting the flag, however, as you can see the next time you send 'a'. EIFR is now 2 before you call attachInterrupt(), although it is 0 after. This is because as soon as you enable the interrupt, your ISR immediately fires and clears the flag.
If you think about it, however, it's the safest way for the Arduino to have implemented this. For all they know, the programmer might want to get an interupt for any events that might have occurred while they are turned off.
If this isn't the behavior you want, however, then it seems you need to manually clear the INT1 flag in EIFR before you call attachInterrupt()
Edited to Add:
- A couple other things too. You don't typically want to call Serial.print() in an ISR since it could possibly lock up forever.
- It is unusual to use an INT pin to read a button. One of the reasons is demonstrated by my example, which shows how many times the ISR runs even when I try to push the button quickly. The other reason is that it is usually unnecessary to respond to human input that quickly (with the exception of a Big Red Emergency Power Off button).