Difference between revisions of "Interrupts"

From Mech
Jump to navigationJump to search
 
(12 intermediate revisions by the same user not shown)
Line 19: Line 19:




== WARNING ABOUT USING THE SAME VARIABLE IN BOTH THE INTERRUPT AND THE MAIN CODE ==


----
If a variable, X, is being updated in your interrupt routine, you cannot reliably use that variable in your main code. Not even for seeming benign operations such as conditionals (i.e. if (X<CONSTANT){...} ). You can work around this problem by disabling interrupts before referencing the variable and re-enabling them after using it.
WARNING:


USING THE SAME VARIABLE IN BOTH THE INTERRUPT AND THE MAIN CODE WILL GENERATE ELUSIVE BUGS

If a variable, X, is being updated in your interrupt routine, you cannot reliably use that variable in your main code. Not even for seemingly benign operations such as conditionals (i.e. if (X<3){...} ). You can work around this problem by disabling interrupts before referencing the variable and then re-enabling them afterwards.

//INTERRUPT ROUTINE
#INT_TIMER2
#INT_TIMER2
void Timer2isr() {
void Timer2isr() {
//find the change in phase after the 1 ms has passed
u16_X += 3; //add 3 to X every time the interrupt is tripped
u16_X += 3;
...
...
}
}
//MAIN ROUTINE
void main(void) {
void main(void) {
while(TRUE){
while(TRUE){
Line 34: Line 39:
u16_X_MAIN = u16_X; //access the interrupt variable only when interrupts are disabled
u16_X_MAIN = u16_X; //access the interrupt variable only when interrupts are disabled
enable_interrupts(GLOBAL);
enable_interrupts(GLOBAL);
...

if (u16_X_MAIN>20) //access the copy of the variable whenever you'd like
if (u16_X_MAIN>20) //the copy of the variable for the main code can be accessed at any time
{u8_y = 1;}
{u8_y = 1;}
end
end
...
}
}
}
}


The disadvantage is that sometimes a interrupt will be missed because the timer trips while interrupts are disabled. The seriousness of this depends on your application.
One disadvantage is that sometimes an interrupt will be missed because the timer trips while interrupts are disabled.

Latest revision as of 16:02, 25 July 2008

The PIC allows interrupts to occur on the basis of a lot of different triggering events. I've only tried out a few of them.

The most useful is a timed interrupt which can be used as a servo routine to control motors and read sensors on a regular schedule, independent of the logic of your program.

Any of the four timers can be used to create regular interrupts, but we'll use Timer 2 which is the most flexible. We'll set up Timer 2 to overflow/restart at 16KHz (which is used for PWM timing) and to call an interrupt every 16th overflow, so that we have repeating interrupts at 1mS intervals:

setup_timer_2(T2_DIV_BY_4, 78, 16);

To enable interrupts we need these two statements:

enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);

Then, at 1mS intervals, the interrupt service routine (ISR) labeled #INT_TIMER2 will be invoked. As shown in the sample code all that happens in the interrupt service routine is that pin D7 is flashed high for 10uS (to watch it on a scope) and the 32-bit integer msecs is incremented to keep track of time.

We could do a lot more in the ISR, but it's a good idea to keep it as brief as possible, especially for a rapidly repeating ISR like this one. Keep in mind that an interrupt may occur between any two instructions in your main program. So, a variable like msecs that is written by the ISR can change unexpectedly.

You can also trigger an interrupt on a high-to-low or low-to-high transition of a digital input pin (INT0, INT1, or INT2). See InterruptExternal.c



WARNING:

USING THE SAME VARIABLE IN BOTH THE INTERRUPT AND THE MAIN CODE WILL GENERATE ELUSIVE BUGS

If a variable, X, is being updated in your interrupt routine, you cannot reliably use that variable in your main code. Not even for seemingly benign operations such as conditionals (i.e. if (X<3){...} ). You can work around this problem by disabling interrupts before referencing the variable and then re-enabling them afterwards.

//INTERRUPT ROUTINE
#INT_TIMER2
void Timer2isr() {
  u16_X += 3; //add 3 to X every time the interrupt is tripped
  ...
  }
//MAIN ROUTINE
void main(void) {
 while(TRUE){
 disable_interrupts(GLOBAL); 
 u16_X_MAIN = u16_X;        //access the interrupt variable only when interrupts are disabled
 enable_interrupts(GLOBAL);
 ...
 if (u16_X_MAIN>20)         //the copy of the variable for the main code can be accessed at any time
    {u8_y = 1;}
 end
 ...
 }
}
       

One disadvantage is that sometimes an interrupt will be missed because the timer trips while interrupts are disabled.