|
|
View previous topic :: View next topic |
Author |
Message |
mng000
Joined: 06 Jun 2006 Posts: 3
|
Timer0 false triggering on enable: |
Posted: Tue Jun 06, 2006 11:30 am |
|
|
Hi all,
I am looking for a bit of advise - I have been having trouble with timer interrrupts, and have stripped my code down to the bare-essentials to work out what is going wrong.
Basically, i am using a pic16f873A (and tested with a 16f876 to see if the problem persists, which it does). I have setup the timer0 to overflow every few msecs, but after the first enable instruction, it appears to overflow after ~38usec, after which it overflows as expected. I have made sure I have set the timer to 0 before enabling it, so I am not sure what is going wrong.
Code below - am using the test_pin to debug - currently i see it go:
high - delay 100usec - low - delay 100usec - high - delay 38usec - low - then toggle every few msec as expected.
any help most appreciated! Compiler version 3.228.
Cheers!
Code: |
#include <16F873A.H>
#fuses hs,put,nowdt,noprotect,nobrownout,nolvp,nowrt
#use delay(clock=4000000)
#byte a_port=0x05
#byte a_tris=0x85
#byte b_port=0x06
#byte b_tris=0x86
#byte c_port=0x07
#byte c_tris=0x87
#bit test_pin=a_port.0
#int_timer0
void timer0_isr(){
test_pin=!test_pin;
}
void main() {
a_tris=0b11111110;
b_tris=0b11111111;
c_tris=0b11111111;
a_port=0b00000000;
delay_ms(250);
delay_ms(250);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);
enable_interrupts(global);
test_pin=1;
delay_us(100);
test_pin=0;
delay_us(100);
test_pin=1;
set_timer0(0);
enable_interrupts ( int_timer0 );
do {
#asm nop #endasm;
} while (TRUE);
}
|
|
|
|
drh
Joined: 12 Jul 2004 Posts: 192 Location: Hemet, California USA
|
|
Posted: Tue Jun 06, 2006 12:01 pm |
|
|
You need to clear the timer0 interrupt flag before you enable the interrupt. _________________ David |
|
|
mng000
Joined: 06 Jun 2006 Posts: 3
|
|
Posted: Tue Jun 06, 2006 12:21 pm |
|
|
I had tried using:
#bit T0IF=0xB.2
with
do{T0IF=0;}while(T0IF!=0);
at the start of the main function, but now after some playing around, it seems that it works ONLY if I put it after the set_timer0(0) call and not before. Why does it need to be there? Surely setting the timer to zero doesn't trigger the overflow??
drh wrote: | You need to clear the timer0 interrupt flag before you enable the interrupt. |
|
|
|
Ttelmah Guest
|
|
Posted: Tue Jun 06, 2006 3:00 pm |
|
|
First comment, you do not need any of the assembler code or direct accesses you are using. There is a 'clear_interrupt(INT_TIMER0)' instruction which will clear the timer, and a 'delay_cycles(1)' instruction to give the single nop. While the direct accesses don't 'matter', they make things much harder if you latter decide to upgrade to a different chip...
Now when the chip starts, the timer begins counting in instructions, as soon as the code begins. It only 'slows' to 16 instruction steps, when you reprogram the prescaler. Hence it has already wrapped several times, and the interrupt flag is set when you arrive at your enable interrupt. The '38uSec' delay at this point, is the time taken to actually enter the interrupt handler, when the event occurs. A good demonstration of just how major the overhead here is...
I have re-written the demo, in C, and this runs, setting the test pin high at 500.25mSec, and then toggling the pin at 504.38mSec, and next at 508.48mSec.
Code: |
#include <16F873A.H>
#fuses hs,put,nowdt,noprotect,nobrownout,nolvp,nowrt
#use delay(clock=4000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#define test_pin PIN_A0
#int_timer0
void timer0_isr(){
output_toggle(test_pin);
}
void main() {
set_tris_a(0b11111110);
set_tris_b(0b11111111);
set_tris_c(0b11111111);
output_a(0b00000000);
delay_ms(250);
delay_ms(250);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);
enable_interrupts(global);
output_high(test_pin);
delay_us(100);
output_low(test_pin);
delay_us(100);
output_high(test_pin);
set_timer0(0);
clear_interrupt(int_timer0);
enable_interrupts ( int_timer0 );
do {
delay_cycles(1);
} while (TRUE);
}
|
In general, you should be able to clear the interrupt either 'side' of the counter reset, but doing it before hand, does leave the possibility, that the counter could wrap on the same instruction, in which case the interrupt would then reset.
Best Wishes |
|
|
mng000
Joined: 06 Jun 2006 Posts: 3
|
|
Posted: Tue Jun 06, 2006 3:12 pm |
|
|
Thank you very much Ttelmah for the helpful explanation and general pointers - most appreciated! |
|
|
|
|
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
|