View previous topic :: View next topic |
Author |
Message |
TekTrixter
Joined: 10 Apr 2006 Posts: 3 Location: North Carolina, USA
|
Exit from long loop with interrupt? |
Posted: Mon Apr 10, 2006 5:40 pm |
|
|
Currently the program starts / stops the blinking pattern of the LEDs attached to the output pins. However, as written it can't stop within the loop, only between loops. How can I cause the loop to end after the interrupt? I know that I could set a flag in the interrupt and then check it between LED changes, but that doesn't seem to be an elegant method.
Code: |
#include "D:\Data files\robot\BlinkLED\BlinkLED.h"
void setup();
boolean btnToggle = false;
#int_EXT
void EXT_isr() {
output_low(PIN_A2); // indicate that program is within ISR
disable_interrupts(GLOBAL);
if (btnToggle){
btnToggle = false;
}else{
btnToggle = true;
}
delay_ms(50);
clear_interrupt(INT_EXT);
enable_interrupts(GLOBAL);
output_high(PIN_A2);
}
void main() {
setup();
while(true){
if(btnToggle){ //change LED pattern
output_toggle(PIN_B3);
delay_ms(500);
output_toggle(PIN_B3);
output_toggle(PIN_B2);
delay_ms(500);
output_toggle(PIN_B2);
output_toggle(PIN_B1);
delay_ms(500);
output_toggle(PIN_B1);
output_toggle(PIN_B5);
delay_ms(500);
output_toggle(PIN_B5);
delay_ms(500);
}
}
}
void setup(){
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(VREF_LOW|-2);
ext_int_edge(H_TO_L);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
setup_oscillator(OSC_4MHZ);
output_float(PIN_B0);
output_high(PIN_B3);
output_high(PIN_B2);
output_high(PIN_B1);
output_high(PIN_B5);
output_high(PIN_A2);
}
|
|
|
|
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
|
Posted: Mon Apr 10, 2006 8:00 pm |
|
|
Add more places where you test the flag, which you set in the ISR. For example:
Code: |
while(true){
if(btnToggle) goto endloop; //change LED pattern
output_toggle(PIN_B3);
delay_ms(500);
if(btnToggle) goto endloop;
output_toggle(PIN_B3);
output_toggle(PIN_B2);
delay_ms(500);
if(btnToggle) goto endloop;
output_toggle(PIN_B2);
output_toggle(PIN_B1);
delay_ms(500);
if(btnToggle) goto endloop;
output_toggle(PIN_B1);
output_toggle(PIN_B5);
delay_ms(500);
if(btnToggle) goto endloop;
output_toggle(PIN_B5);
delay_ms(500);
// or you can also split up your delay routines like this
// instead of delay_ms(500);
for (i = 0; i < 5; ++i)
{
delay_ms(100);
if(btnToggle) goto endloop;
}
endloop:
}
|
|
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1634 Location: Perth, Australia
|
Re: Exit from long loop with interrupt? |
Posted: Mon Apr 10, 2006 11:03 pm |
|
|
TekTrixter wrote: | Currently the program starts / stops the blinking pattern of the LEDs attached to the output pins. However, as written it can't stop within the loop, only between loops. How can I cause the loop to end after the interrupt? I know that I could set a flag in the interrupt and then check it between LED changes, but that doesn't seem to be an elegant method. |
Using a flag is in the interrupt handler is elegant. I suggest the following:
get rid of the disable interrupts in the interrupt handler unless there are other interrupt sources that you specifically want disabled.
get rid of the enable_interrupts(global) in your interrupt handler - it is a sure way to crash the PIC.
get rid of the clear_interrupt(INT_EXT) from the interrupt handler . It is not required the compiler does it automatically for you.
get rid of the delay_ms from the interrupt handler. By putting this in the handler the compiler will add a disable interrupts into the mainline code whenever delay_ms is invoked which means you may lose interrupts.
A method I use is to enable a timer in the interrupt handler - in your case one with 50ms timeout. You can then sit in the handler until the timeout expires - alternatively (the method I use) you can return immediately from the handler and in the mainline you can test if the timer is running (means an interrupt has occured and you are waiting for a timeout) then loop until the timer IF is set. You can then stop the timer, clear the flag and clear the output.
Alternatively (or in addition) use a timer instead of delay_ms() in the mainline. In this case you would clear the TF flag and start the timer. You you then sit in a while loop such as
Code: |
Ext_Intr_Processed_by_handler = false;
while (!Some_Timer_TF & !Ext_Intr_Processed_by_handler)
// do nothing
;
// here if the timer expired or an interrupt was processed
// do something else ....
|
_________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
Last edited by asmallri on Tue Apr 11, 2006 5:55 pm; edited 2 times in total |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Tue Apr 11, 2006 7:33 am |
|
|
Code: |
//----------------------------------
#INT_EXT
void EXT_isr()
{
if( btnToggle)
{ btnToggle = false; }
else
{ btnToggle = true; }
}
//-----------------------------------
void my_wait_loop(int times)
{
do
{
delay_ms(10);
}while((--times) && (btnToggle));
}
//-----------------------------------
|
In main replace delay_ms(500) for my_wait_loop(n);
Code: |
output_toggle(PIN_B3);
output_toggle(PIN_B2);
my_wait_loop(50);
output_toggle(PIN_B2);
output_toggle(PIN_B1);
my_wait_loop(50);
|
Humberto |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Apr 11, 2006 8:58 am |
|
|
Just to add upon what's already been posted
Code: |
void my_wait_loop(int times)
{
do
{
delay_ms(10);
}while((--times) && (btnToggle));
}
void main()
{
int state;
setup();
while(true)
{
state = 0;
while (btnToggle)
{
switch (state)
{
case 0:
output_toggle(PIN_B3);
break;
case 1:
output_toggle(PIN_B3);
output_toggle(PIN_B2);
break;
case 3:
output_toggle(PIN_B2);
output_toggle(PIN_B1);
break;
case 4:
output_toggle(PIN_B1);
output_toggle(PIN_B5);
break;
case 5:
output_toggle(PIN_B5);
break;
case 6:
state = 0;
continue;
}
state++
my_wait_loop(50);
}
}
}
|
|
|
|
TekTrixter
Joined: 10 Apr 2006 Posts: 3 Location: North Carolina, USA
|
|
Posted: Wed Apr 19, 2006 10:26 am |
|
|
Thank you to everyone that replied. Mark's suggestion of a CASE is what I was origionally looking for (it avoids cut and pasting code). I also needed the interruptable delay as well (and didn't even know it!). I'd like to specificly thank asmallri for the list of corrections and hints.
I'm now working on a function for an interruptable delay using a timer interrupt and a break_delay flag.
Again, thank you to everyone that helped out. |
|
|
|