View previous topic :: View next topic |
Author |
Message |
joshkeys
Joined: 16 Aug 2005 Posts: 37 Location: Fredericton,NB
|
Enabling interrupts during a delay_ms() or while() loop |
Posted: Sun Jan 21, 2007 1:33 pm |
|
|
Hi all,
Compiler: 3.239
PIC: 18F4320
I am implementing code in which I have external interrupts on int0 and int1. These interrupts are a on/off button and a reset button on my project. The problem arises in a case where In my code I want to wait a random length of time before turning on an LED. So to do this I am using
Code: |
set_timer0(rand());
while(get_timer0() != 0){}
output_bit(LED,1);
|
The problem is if i hit the on/off button while it is in the while loop, the unit does not turn off until the loop is satisfied. I read a few posts from PCM_Programmer concerning interrupts being disabled while using delay_ms() and other routines.. so how do i get around this. I need to have a random delay for the LED to turn on, but if at any time the user wishes to turn off the unit, I want the interrupt to be working.
Thx |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Sun Jan 21, 2007 3:32 pm |
|
|
Instead of waiting in a loop for timer 0 to roll over, simply set timer 0 to whatever you want, then enable the timer 0 interrupt. When it rolls over, the timer 0 interrupt will fire. In the timer 0 isr, turn on your LED and disable the timer 0 interrupt. If you set up your program in this manner, it will react instantaneously (well, as close to instantaneous as you can get) to user input or other stimulii. |
|
|
joshkeys
Joined: 16 Aug 2005 Posts: 37 Location: Fredericton,NB
|
|
Posted: Sun Jan 21, 2007 3:38 pm |
|
|
Fair enough. That should work for this case.. but for the sake of being more flexible, do you know of anyway to use the delay_ms() command and still have interrupts active? Also, what is a list of commands that will disable interrupts? If you do any sort of loop, they do not seem to work, but for some reason, when I do my while(1) loop in my main program the interrupts will work fine, but if I use a while(!variable){} it does not seem to work. any ideas there?
Thx,
Josh |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
joshkeys
Joined: 16 Aug 2005 Posts: 37 Location: Fredericton,NB
|
|
Posted: Sun Jan 21, 2007 5:18 pm |
|
|
Yah, I read that thread earlier and tried that with no luck. It still waited until my delay_ms() was comlplete.. I exaggerated the time and made it 10 seconds, and it did not go to the interrupt until it was done with that.. I made sure my first #use delay was above the ISR and the second above the main.
Thx,
Josh |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jan 21, 2007 5:39 pm |
|
|
Can you post a very short, but complete program that shows the problem ?
Maybe just use one interrupt in this program. The shorter the program,
the better. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Sun Jan 21, 2007 6:05 pm |
|
|
joshkeys wrote: | Fair enough. That should work for this case.. but for the sake of being more flexible, do you know of anyway to use the delay_ms() command and still have interrupts active? Also, what is a list of commands that will disable interrupts? If you do any sort of loop, they do not seem to work, but for some reason, when I do my while(1) loop in my main program the interrupts will work fine, but if I use a while(!variable){} it does not seem to work. any ideas there?
Thx,
Josh |
Think about what the processor is doing. Your program will have a main loop, like this:
Code: | while (TRUE) {
if (eventa) {
eventa = FALSE;
service_eventa();
}
if (eventb) {
eventb = FALSE;
service_eventb();
}
} |
If you have some sort of while() loop in service_eventa(), the processor will sit in that loop as long as the test condition is true. Let's say that an interrupt occurs while it is sitting in this while loop - the processor will drop what it is doing (sitting in the loop), and run the interrupt service routine. That interrupt service routine will typically set a flag (eventb) to let the main loop know that something must be now be done.
Now the ISR is done, and code jumps back to where it was before the interrupt occured - which is sitting in the while loop.
Make sense now? If you want to be able to break out of a while loop, you'll have to add extra tests that indicate whether it should sit in the loop in the first place.
My personal advice is to avoid this type of coding style (while loops) as they unnecessarily tie up the processor and make it do, essentially, nothing while waiting for some event to occur. It's far better practice to code in such a way that the processor can react to events as quickly as possible. While() loops are bad practice using this type of coding style. |
|
|
joshkeys
Joined: 16 Aug 2005 Posts: 37 Location: Fredericton,NB
|
Problem solved |
Posted: Sun Jan 21, 2007 10:52 pm |
|
|
I enabled the interrupts in the function that the main program called and it worked fine.. My program has a while(1) loop that waits for a variable to be set from the ISR, which always worked, it was my "on" button. so when I pressed "on" the device came on.. with this variable set, the main called a function, and it was while in this function the interrupts would not work. So I added the enable interruptsxxxx to the function the main called and it worked.. weird.
Thx,
Josh |
|
|
horkesley
Joined: 20 Feb 2007 Posts: 48 Location: Essex UK
|
int_rda during a while loop with delay |
Posted: Tue Feb 20, 2007 9:43 am |
|
|
Hi,
I have a 'while loop' including a delay_ms(100)
I have a int_rda looking at the hardware comms.
When chars are received the global interrupt flag is reset and I only receive two chars.
If I remove the delay_ms it works fine.
Why cant I use int_rda when in a while loop?
Regards _________________ Horkesley Electronics Limited |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
Re: int_rda during a while loop with delay |
Posted: Tue Feb 20, 2007 10:06 am |
|
|
horkesley wrote: | Hi,
I have a 'while loop' including a delay_ms(100)
I have a int_rda looking at the hardware comms.
When chars are received the global interrupt flag is reset and I only receive two chars.
If I remove the delay_ms it works fine.
Why cant I use int_rda when in a while loop?
Regards |
You can receive characters anytime. If you don't 'fetch' them from the USART, then you run into trouble. The USART can fetch & store two characters - that's it.
An interrupt (any interrupt) will cause the program to break out from a delay_ms() statement or a while() loop. It's what you do in the interrupt that determines how the program/processor behaves.
Alter your RDA interrupt to store each received character in an array and set a flag to let your main program know that something was received. If the program is 'twiddling its thumbs' in a delay_ms(100) (an eternity by the way), it will still successfully receive and store every serial character that comes its way. When the delay is done and program flow returns to the main while(true) {} loop of the main program, it will branch into the 'if (character_received) {} loop and your program can then analyze the received data and do whatever it is supposed to do with no missed characters. |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Tue Feb 20, 2007 10:08 am |
|
|
If you only get 2 chars. I would say that it is your hardware usart filling up and you not reading the char to clear them out. This causes a error on the usart.
Do a search on uart and error for more info. |
|
|
Tom Jetland
Joined: 23 Jun 2011 Posts: 31 Location: UK
|
Re: int_rda during a while loop with delay |
Posted: Thu Aug 25, 2011 11:53 am |
|
|
Quote: |
You can receive characters anytime. If you don't 'fetch' them from the USART, then you run into trouble. The USART can fetch & store two characters - that's it.
An interrupt (any interrupt) will cause the program to break out from a delay_ms() statement or a while() loop. It's what you do in the interrupt that determines how the program/processor behaves.
|
I don't think you are correct in saying this newguy. When my code is in a delay (which I try to avoid doing) the RDA_INT does not fire when data comes in.
Does anyone know why this is?? |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Thu Aug 25, 2011 12:04 pm |
|
|
Do you see any "interrupts disabled during calls to ... to prevent re-entrancy" warnings when you compile? If you're using delay_ms() functions inside and outside of ISRs, that would explain what you're seeing. |
|
|
Tom Jetland
Joined: 23 Jun 2011 Posts: 31 Location: UK
|
|
Posted: Thu Aug 25, 2011 1:17 pm |
|
|
So are you saying that if a delay_ms is inside an interrupt (and compiler makes ints disabled to avoid re entrancy) that interrupts will be disabled even when it's not in an interrupt when using delay_ms?? That's bizarre! |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Thu Aug 25, 2011 1:36 pm |
|
|
It's not bizarre. There is a delay_ms() function. If it is called both inside an ISR and outside of it, the compiler will disable interrupts during calls to it because there is only one function called delay_ms(). Imagine your code finds its way to the delay_ms() call that is outside of an ISR and while it is executing, the ISR with a call to delay_ms() is executed. What will happen? It's called re-entrancy and it's bad.
Alter your code to eliminate the delay call in your ISR - it's bad practice and is unnecessary. Failing that, you can fool the compiler into separating the two delay calls into separate bits of code by creating a my_delay_ms() function which calls delay_ms() inside of it. |
|
|
|