![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
are the interrupt disable during printf()? |
Posted: Wed Jul 27, 2011 8:29 am |
|
|
I have a led which is flashing quickly (5-10 Hz) thanks to interrupt from TIMER0.
I have a printf which is writing on rs232 every second (TIMER1) 4 lines of 40-50 characters each.
This causes the led to stop flashing for a moment....it looks very bad!
So, the question is, does the rs232 writing operation disable the interrupt?
How can I do? (16F876A) |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Wed Jul 27, 2011 2:57 pm |
|
|
No, RS232 writing doesn't disable the interrupt, but - if your timer interrupt is directly performing the printf, then the code will stay inside the interrupt handler for the entire time needed to perform the printf (you don't tell us the baud rate, but assuming 9600bps, 40*4*1.04mSec = 166mSec), less the couple of characters of buffering in the chip. Inside an interrupt handler, other interrupts have to wait, so your LED will stop.
Solutions:
1) Set a flag in timer1. Perform the 4*40 character printf, in the main code loop, if this flag is set, then clear the flag. With the RS232 'outside' the interrupt handler, other interrupts can then work.
2) Buffer the RS232 transmission. Look at STISR.c. Just write the data to the buffer in the interrupt, and let the hardware RS232 interrupt send the data.
This is the old adage _get out of interrupt handlers quickly_. Anything that takes more than a few uSec of time, should not be in an interrupt handler.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Fri Jul 29, 2011 1:41 pm |
|
|
I changed the code as you suggested, now it is something like this:
Code: |
#int_TIMER0
void TIMER0_isr(void){ //overflow every 256 us
t0++;
if (t0>300){
t0=0;
sm01=!sm01; //0.1536 s period flashing
}
}
//--------------------------------------------------------------------------
#int_TIMER1
void TIMER1_isr(void){ //overflow every (4/f)*prescaler*(65536-3036)=0.5 s
set_timer1(0x0BDC); //3036 in hex is 0BDC
sm05=!sm05; //1 s period flashing
if (sm05) {
clock=1;
}
}
//--------------------------------------------------------------------------
void main() {
init();
while(1){
restart_wdt();
if (clock) sec();
read_input();
statemachine();
write_output();
}
} |
Inside the function sec() there is also the RS232 printf().
printf() is not in the interrupt routine but the led which is flashing as the bit sm01 stops (sometime on, sometime off) when there is the RS232 writing.
If I comment (//) all the printf() the led flashes correctly at constant frequency.
Now I am getting crazy looking at that led flashing and I can't say if it's flashing at constant frequency or not
Anyway, Ttelmah, is my code what you meant? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Fri Jul 29, 2011 3:21 pm |
|
|
Several further comments:
1) I am assuming you are using the hardware UART?. If not, then interrupts must be disabled when characters are output, or the timings will go wrong.
2) I don't see you clearing the clock flag.
3) Do a search on the form, on why setting a timer 'to' a value is likely to not give good accuracy....
4) What is your CPU clock rate?. Do you really need an interrupt every 256uSec?. It takes typically 60+ instructions to get into, and out of an interrupt handler. Add your code in the handler, and if you are running off 4MHz, something like 1/3rd your _total_ processor time is already being used handling timer0. You could reduce this, by halving the frequency of the interrupt, and reducing t0 to only being an 8bit integer. immediate halving of the number of calls per second, and each is quicker....
Further, if you already have an interrupt happening this fast, why have another?. Just have a second counter, and when this reaches the count for 0.5 seconds, trigger your events. Two interrupts means two sets of interrupt overhead.
Personally, I'd use timer2, since this allows nice 'decimal' count numbers. Set this to trigger (say) every 50th second. Then every 25 counts trigger your 'half second' even, and perhaps every eight counts trigger the LED flash.
Unless you have another interrupt that is using a printf, what you show should not give a problem with the flashing though.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Sat Jul 30, 2011 1:12 am |
|
|
1) yes it is harware UART (#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7))
2) I clear the bit "clock" at the end of the function "sec()".
4) 4 MHz
I changed the program. Now I only have 10 interrupt/s, variables are 8 bit, main() is unchanged.
Code: | #int_TIMER1
void TIMER1_isr(void){ // 0.1s interrupt
//set_timer1(0x0BDC); //3036 in hex is 0BDC
set_timer1(15536);
sm01=!sm01; //0.2 speriod
t0++;
if (t0>4){
t0=0;
sm05=!sm05; //1s period
}
t1++;
if (t1>9){
t1=0;
clock=1; //1s
}
} |
Inside the function sec() there are the rs232 instruction (5 printf()).
If I comment the printf() everything is fine, but if I leave it, when the led is flashing (sm01) it stops every second (during rs232 operation). |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Sat Jul 30, 2011 2:16 am |
|
|
Same comments:
Do a search on why setting a timer 'to' a value is never going to be accurate.
Have you any _other_ interrupts?. Even a single 'putc' in _any_ interrupt?.
As a general comment clear 'clock' at the start rather than the end of the routine.
You'd better show us 'sec'.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Sat Jul 30, 2011 8:12 am |
|
|
I wrote a program to show the problem. The problem is that when I write the UART the red led (bit sm01) stops flashing. Commenting the printf(...) lines the red led flashes correctly.
Timer1 is used to generate an interrupt every 0.5 seconds, which sets a bit (clock) every second to perform the UART (function sec()). Even if I am writing in its register, it is only 2 times in a second, therfore I think that the error in the interrupt frequency is quite small.
Timer2 is used only to quickly flash a red led (bit sm01).
Code: | #include <16F876A.h>
#fuses XT, PUT, WDT, NOLVP
#use delay(clock = 4000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#define green PIN_C5
#define red PIN_B1
int1 sm01, sm05, clock;
#int_TIMER1
void TIMER1_isr(void){ // 500ms
set_timer1(0x0BDC); //(4/f)*prescaler*(65536-3036)=500000 us =0.5 s
sm05=!sm05; //1 s period flashing
if (sm05&&!clock) {
clock=1;
}
}
#int_TIMER2
void TIMER2_isr(void){ // 65.28ms
sm01=!sm01; //130.56 ms period (7-8 flashes/s)
}
void sec(void){
clock=0;
printf("abcdefghijklmnopqrtuvwxyz \n\r");
printf("abcdefghijklmnopqrtuvwxyz \n\r");
printf("abcdefghijklmnopqrtuvwxyz \n\r");
printf("abcdefghijklmnopqrtuvwxyz \n\r");
printf("abcdefghijklmnopqrtuvwxyz \n\r");
}
void main() {
set_tris_a(0x3F);
set_tris_b(0xC8);
set_tris_c(0x84);
setup_wdt(WDT_2304MS); //usa il prescaler del timer0
restart_wdt();
setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8);
setup_timer_2 (T2_DIV_BY_16,255, 16);
enable_interrupts(int_TIMER1);
enable_interrupts(int_TIMER2);
enable_interrupts(global);
output_bit(green,0);
output_bit(red,0);
while(1){
restart_wdt();
if (clock) sec();
output_bit(green,sm05);
output_bit(red,sm01);
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Sat Jul 30, 2011 2:48 pm |
|
|
Now becomes clear. Nothing to do with interrupts at all.....
Think about it for a moment. When you execute 'sec', the code sits printing for about 0.2 sec. Your interrupt doesn't flash the LED, your _main_ loop does. When you are doing the printing, the main loop slows down, while the print's execute. result the flashing changes.
Change your flash interrupt to:
Code: |
#int_TIMER2
void TIMER2_isr(void){ // 65.28ms
output_toggle(red);
}
|
Now the flash is done in the interrupt, not the main, and it'll keep going while the printing takes place.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Mon Aug 01, 2011 2:24 am |
|
|
Now it make sense
Thank you for your help! |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|