newbie : interrupt in arduino (not AVR-C)

Hello World!

I am not able to find an example in arduino that shows how to handle interrupts.

What I wanted to do was mod the melody example to use an interrupt on pin 2 to play the melody. These are the lines I added :

in setup :

attachInterrupt(0,play, LOW);

then, rewrote loop() as :

void loop(){
delay(10000);
}

since loop doesn’t need to do anything now. Then, play is :

void play() {
for (int i = 0; i < length; i++) {
if (notes == ’ ') {
delay(beats * tempo); // rest
* } else {*
playNote(notes, beats * tempo);
* }*

* // pause between notes*
* delay(tempo / 2);*
* }*
}
The result is that, when I press the button, all I get is the first note of the melody. I have to push the reset button on the board to start over and then, again, all I get with the pushbutton on Pin 2 (10k pullup, switch to GND) is the first note.
Any thoughts. Ideally, I want to disable all interrupts as soon as I enter the play function and enable interrupts just before I exit. Anyone know the arduino syntax for that?
Do commands such as
sei
cli
work in Arduino?
Thanks!!

I think the problem is your using a delay function inside the ISR function, when I tried that once it locked up my sketch. Generally you want to do as little as possible inside a ISR function, such as set a global flag variable and test that in your main loop function to determine to take action because of the interrupt and then reset the flag and wait until the ISR sets the flag on the next received interrupt.

The following is from the reference section:

Note Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function.

Obtained here: http://arduino.cc/en/Reference/AttachInterrupt

Lefty

Any chance we can update Arduino's compiler to detect a call to delay() with an ISR and issue a warning? How complex would that be to add?

Nearly impossible. For instance, there is no way that the compiler can tell that "play()" was an ISR routine.

In general, this sort of thing is one of the big differences between programming a microcontroller and programming a "real computer." On a PC, code that is not permitted in an ISR might detect when it was called from an interrupt, throw an error toward the operating system, resulting in a nice error message and perhaps some sort of remedial action. On a small microcontroller it'll just sit there waiting for something that will never change, and it looks dead...

Another curio - noInterrupts doesn't seem to be doing it's job inside the ISR. I rewrote the ISR as :

void blink(){ noInterrupts(); digitalWrite( ledPin, val?HIGH:LOW); val ^= 1; }

So the system should stop responding after the first button press since nothing enables interrupts after the first run of the ISR. But that's not what I see. I can keep pushing the button to toggle the LED. Any thoughts?

Just for completeness, putting the code here that works for playing the melody through an interrupt on pin 2 :

volatile int val = 0;

void loop(){ if( 1 == val) { play(); val = 0; } }

// NOTE: if I straddle the play() call with noInterrupts() and interrupts(), it doesn't work - it only plays the first note of the melody. (Why??)

play() has been described already - it's straight from the Melody example.

void setup() { pinMode(speakerPin, OUTPUT); pinMode( inPin, INPUT); attachInterrupt(0,isr2, FALLING); interrupts(); }

void isr2(){ val = 1; }

noInterrupts doesn't seem to be doing it's job inside the ISR. I rewrote the ISR as :

void blink(){ noInterrupts(); digitalWrite( ledPin, val?HIGH:LOW); val ^= 1; }

So the system should stop responding after the first button press since nothing enables interrupts after the first run of the ISR

It's pretty fundamental to the operation of interrupts on computers in general that when the ISR is done, the processor state (registers, status (including Interrupt Enable status)) is restored to the state that in effect at the time the interrupt occurred. The "return from interrupt" instruction that the AVR compiler will put at the end of the ISR automatically re-enables interrupts, regardless of whether you change that inside the ISR. You'd have to get very tricky indeed to do otherwise.