CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Timer0 false triggering on enable:

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
mng000



Joined: 06 Jun 2006
Posts: 3

View user's profile Send private message

Timer0 false triggering on enable:
PostPosted: Tue Jun 06, 2006 11:30 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jun 06, 2006 12:01 pm     Reply with quote

You need to clear the timer0 interrupt flag before you enable the interrupt.
_________________
David
mng000



Joined: 06 Jun 2006
Posts: 3

View user's profile Send private message

PostPosted: Tue Jun 06, 2006 12:21 pm     Reply with quote

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







PostPosted: Tue Jun 06, 2006 3:00 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jun 06, 2006 3:12 pm     Reply with quote

Thank you very much Ttelmah for the helpful explanation and general pointers - most appreciated!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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