Multiple interrupts with MsTimer2?

Hi all,

I want to write a sketch that does a few different things at timed intervals. I found the MsTimer2 library and have made it work (simple!) but I get the impression it can only maintain one interrupt at a time, so I can't do something like this:

setup() {
  MsTimer2::set(5, readSomeStuff);
  MsTimer2::set(18, writeSomeStuff);
  MsTimer2::start();
}

void readSomeStuff() {
  // read from an analog pin, do some calcs and write to a shared array
}

void writeSomeStuff() {
 // write current values in shared array out to display
}

Is there another library which lets me set multiple interrupts at different intervals, or how simple would it be to modify MsTimer2 to do so?

Cheers, Robert.

You can probably do what you want using just one timer interrupt. Then just have the ISR routine check for elapsed time via millis() for the time intervals for your functions and set global byte flags that the main loop can test for and then call your different time based functions from the main loop and then reset the flags when the functions return. Timers are a limited resource on your chip and have to be shared with functions like servo and pwm, so if you get by using just one then it might be worth the effort.

Keep the ISR routine lean and mean and you should be able to do what you wish.

Lefty

Well, sure I could do that, but it'd be much neater to just be able to say, "run this ISR 60 times a second, and run that ISR 500 times a second".

I apologise, I'm a software engineer—just because you can hack it in, doesn't mean you should ;).

Cheers, Robert.

Oh wait, I think I just worked something out: you can’t have multiple interrupts on one timer (however you set the prescaler, it can only “overflow” once) so you have to set your interrupt to trigger on the smallest common multiple of the desired intervals; you then increment a global counter inside your main ISR and do this routine every interupt and that routine every “n” interrupts.

Have I got the right idea?

Cheers, Robert.

Have I got the right idea?

Yes, you do. But again a good rule is to just do the minimum possible steps inside the ISR as all other interrupts are disable until your ISR returns, so this can effect other things going on in the hardware and software functions. Global variables are generally shunned in the PC world, but are a necessary 'evil' in the microcontroller world and are often the best choice.

And I wasn't questioning your qualifications or experience. However if you are new to microcontrollers you soon find out how limited some of the resources are, such as the small SRAM space for variables, arrays, and stack space. Lots of tricks and workarounds are often used to cope with resource limits not experienced with PC systems.

Good luck with your projects. Lefty

But again a good rule is to just do the minimum possible steps inside the ISR as all other interrupts are disable until your ISR returns, so this can effect other things going on in the hardware and software functions.

I was under the impression that only other interrupts on the same timer were affected—I didn't think the call to milis() would be off by the time taken executing an ISR set on a different timer.

So what you're saying is my ISR should set a global "doReadSomeStuff = true" and "doWriteSomeStuff = true", which my main loop checks for and calls the appropriate method, resetting the flag when done?

Hmm. I haven't been this close to the hardware in some time :-?.

Cheers, Robert.

ratkins:

I am not sure if this would fit your needs, but did you check out this thread:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1279464696

I found it quite interesting when it was first posted; there are also more than a few libraries and other schemes out there to do what you want (admittedly not in the "elegant" fashion you are looking for, but as others have noted, this is microcontroller-land)...

:)

So what you're saying is my ISR should set a global "doReadSomeStuff = true" and "doWriteSomeStuff = true", which my main loop checks for and calls the appropriate method, resetting the flag when done?

Yes, that is the generally recommended best practice on using interrupts in the AVR world. Also keep in mind that one also has to keep 'atomic' problems in mind. A reference to a int (or larger) variable in the main loop can be corrupted because an interrupt can happen and change the global variable between the two (or more) memory reads required in the main loop. To combat this one can limit globals used inside ISR to byte size only or bracket loop variable references with nointerrupt() and interrupt() statements in the main loop. http://arduino.cc/en/Reference/NoInterrupts

Lefty

You can have what you want, but it takes some more thought.

First, determine the cycle time of all your desired tasks, in hertz. Then determine the least common multiple; this is how fast your interrupt needs to fire in order for the number of interrupt firings between execution of each task to be an integer. This integer delay is what you use in the code.

Second, have a static variable in the ISR that increments each time the timer fires. When the counter modulo the integer delay for a task is 0, call that task. Reset the counter to zero when you get to the least common multiple of all the integer delays.

Third, there are two ways to handle calling the code. One is to set some flags that cause the functions that implement the tasks to get called from the main loop. I am not fond of this, because it can lead to timing jitter and uneven execution of tasks (imagine a setup where you have half a dozen tasks, and the timer interrupt fires when you're part way through checking the flags for all of them).

I'd rather just set the ISR to block all other interrupts, make sure my task code is fast and tight enough that all tasks can execute between one timer interrupt and the next, and limit my use of other interrupts. I tend to be a bit grumpy about rigidly correct timing, however, so YMMV.