Weird interrupt behaviour. Randomly choosing ISR?

Hey everyone.

I have been troubleshooting the same problem now for what seems like forever, so I finally call on the Arduino forums to hopefully shed some light on the situation.

I am using the two hardware interrupts to trigger two different interrupt service routines (ISRs) that change the system state, but it seems like it picks either one at random despite what button is pressed!

So, here’s what I’ve done.

To start with, I attach the two interrupts in the setup.

 attachInterrupt(0, press_up, RISING);
 attachInterrupt(1, press_down, RISING);

Then, theres the two functions that the interrupts call:

void press_up(){
  if(millis() - last_btn_press > debounce){
    remote_inuse = false;
    state_inc();
    last_btn_press = millis();
  }
}

void press_down(){
  if(millis() - last_btn_press > debounce){
    remote_inuse = false;
    state_dec();
    last_btn_press = millis();
  }
}

Then, the actual (only) functions that do the state work:

void state_inc(){
    if (state < max_state){
      state++;
      state_changed = true;
      kill_effects();
    }
  state_beep();
  lcd_print();
}

void state_dec(){
    if (state > 0){
      state--;
      state_changed = true;
      kill_effects();
    }
  state_beep();
  lcd_print();
}

Stuff I’ve tried:

If I press one button repeatedly, I should end up in either the highest (4) or lowest (0) state. But instead, it tends to jump around. pressing up, up, up, up, up i might go 0, 1, 0, 1, 2, 1.

Interestingly, if i comment out one of the attachinterrupts, both buttons still register! Clearly, only one should work after that, right?

I also tried setting both attach interrupt functions to the same thing, like press_up, and the system stepped happily from 0 to 4.

This is driving me crazy!
If anyone can help at all, I would be greatly appreciative!

Thanks in advance,
Gavin

Quick Update:

I inserted a serial print in each of the interrupt handlers inside the debounce code (alongside state_inc etc.) to see what I get.

This is the serial output from pressing the up button repeatedly:

down down up up down up up down down down down down down up up down up up up up down

Crazy, huh?

http://www.arduino.cc/en/Reference/AttachInterrupt

Inside the attached function, delay() won't work and the value returned by millis() will not increment.

:)

[edit]Are you sure you need to use interrupts?[/edit]

Thanks for the quick reply AlphaBeta!

I know millis() wont increment in an interrupt, but thats ok, so long as it still returns a value. It will increment after the interrupt finishes and is just there for debounce (which works).

I'm not 100% sure I want to use interrupts, but its a lighting controller so my code has a lot of big for loops, which make it a pain to interlace with other code.

I would use some kind of timer overflow to check every couple of milliseconds for a button press (i.e. poll the buttons) but I'm already using all 3 timers! (2 for PWM and an Infared handler)

I feel like the attachinterrupt is doing something dodgey and not setting things up correctly. But chances are, thats not the case, or someone would have picked up on it and fixed it by now...

:(

I saw the word state being used in your source, so I'll take a leap of faith and guess you're implementing your project as a finite state machine. If this is the case, using an interrupt is maybe not the best idea, because then you can change state while in a loop that may act upon the presumption that the FSM was in a certain state, which suddenly, no longer is true.

Sorry for a poorly written sentence.

This is just a guess, and if you do not use a FSM architecture, excause me :) [edit]However, on topic: I think the ISR behaviour is strange.

May we see all the code?[/edit]

Once again, thanks for the reply! I really love these forums…

Well, you’re mostly right. The idea is for a FSM, more or less, just less strict. There is basically a state variable that is used in the main loop to decide which part of the code to branch to which then kicks back to the main loop after its done its bit. Reasonably simple.

I copied out all the relevant code, and while I have no problem with sharing my code with everyone (I know I’ve learnt so much reading everyone elses) there is a lot of it and It would take multiple posts, so if you must, I have put it up on rapidshare.

http://rapidshare.com/files/258732354/RGB_controller.zip.html

I wrote all this code a few months ago and since then, I have learnt a lot and would probably do things differently, but as it is, it works (aside from the funky interrupts). That said, I’m always open to new things, so any advice is also great!

It looks like you have put all the functions that do a delay in the module called functions.pde. If this is the case then you could put your code to service the buttons in your delay routine and avoid interrupts.

For example, in your pro_delay() and pro_delay_adj2() functons you could call a function to check if any buttons are pressed and service the button state accordingly

Hey, thanks mem! You read through that that fast? You're a machine.

Thats actually not a bad idea, and I'm embarrased by the numerous dirty hacks in my code like pro_delay_adj2 :-[.

I feel better now that if all else fails, I can hack away some more and get the result I'm after. Thanks!

Still, this interrupt problem should be fixable, right? I don't want it to beat me like this...

I think life is too short to spend time solving problems that don't matter ;) Save the interrupt issue for when you really need it.

Its been my experience that with Arduino, there is almost always an easier way to do something without using interrupts

Well, in an effort to make things work, I implemented mem's idea and it worked great. The buttons work perfectly now without having to really modify my previous functions.

Firstly, thats great because all my stuff works! :) However, that also only further reaffirms that the interrupts are insane.

I worry now though because I have an upcoming project soon that I will need to use the interrupts for wheel encoders. So I wish I knew what was going on...

If ANYONE has any idea of things I can try or what might be the problem, let me know!

That aside, thanks heaps to mem and AlphaBeta for helping me out ;D (And fast too!)

Reading rotary encoders are the kind of thing that is well suited to using interrupts. In your handler you check the encoder state and increment and decrement a counter that you can use in the main body of your code. See: http://www.arduino.cc/playground/Main/RotaryEncoders