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

How to accurately set timer? [SOLVED]

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



Joined: 07 Jan 2015
Posts: 127

View user's profile Send private message

How to accurately set timer? [SOLVED]
PostPosted: Fri Nov 06, 2015 8:18 am     Reply with quote

Hello guys,
I am trying to understand how to set the timer tick event. I have the PIC18F2685 mounted on PCB. I got TIMER1 using external 32768 crystal to generate a very accurate 1Hz (thanks to PCM Programmer for the TIMER1 code). I also got the RBs interrupt, the 7 segment display to work and now I can but the PIC to sleep.
However, I think I can improve my project by using a timer to handle the display instead of using the delay function.
I have been trying to use TIMER0 to generate a 1mS tick with no luck. Would you please help me with this? I want to know how to calculate the tick in case I want to use more or less than 1mS.

FYI; I did search the forum, google, The compiler manual, the examples and the PIC header file. I also tried to change the PIC clock to other than 8M and the T0_DIV_128 to other values in the header file. However the information I have is for trial and error :( I need to understand it so I can use it correctly.

This is a simple test code:
Code:
#include <18F4520.h>
#fuses INTRC_IO, NOWDT, BROWNOUT
#use delay(clock=8M)

#int_timer0
void timer0_isr(void)
{
   output_high(A7);
   output_high(C2);
   output_low(A7);
   output_low(C2);      
}   


void main()
{
   setup_timer_0(T0_INTERNAL|T0_DIV_128||T0_8_BIT);

   delay_ms(500);

   set_timer0(0x00);
   clear_interrupt(INT_TIMER0);
   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);

   while(TRUE);
}


I want it to do what this code does inside the main():

Code:
while(TRUE);
{
   output_high(A7);
   delay_ms(1);
   output_high(C2);
   delay_ms(1);
   output_low(A7);
   delay_ms(1);
   output_low(C2);   
   delay_ms(1);
}


Thanks in advance,


Last edited by Sam_40 on Wed Nov 11, 2015 11:29 am; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19485

View user's profile Send private message

PostPosted: Fri Nov 06, 2015 8:33 am     Reply with quote

The easiest timer to use to actually develop 1mSec, is timer2. Timer2 offers a programmable count, so can give an exact tick. Timer0 does not.

All the timers are fed at the start from Fosc/4. So for 1mSec (1000* per second), you need a count of 2000000/1000 = 2000.

So for timer2:

setup_timer_2(T2_DIV_BY_16,124,1);

This gives /16, and then /125 (the actual count is one greater than the 'PR2' value (second number - read the data sheet), so gives 2000 exactly. Smile

For timer0, the timer always divides intrinsically by either 65536, or 256 (16bit or 8bit). 2000/256, gives /7.8 required, and the nearest prescaler to this is /8. So:

setup_timer_0(T0_INTERNAL|T0_DIV_8||T0_8_BIT);

Will give 2000000/(8*256) = 976.5625/second (1.024mSec) which should be close enough.
Sam_40



Joined: 07 Jan 2015
Posts: 127

View user's profile Send private message

PostPosted: Fri Nov 06, 2015 9:13 am     Reply with quote

Ttelmah,
Thanks a lot for the detailed information. You have a great weekend!
Sam_40



Joined: 07 Jan 2015
Posts: 127

View user's profile Send private message

PostPosted: Wed Nov 11, 2015 9:09 am     Reply with quote

Ttelmah,
I am so confused in regards to timer2 set up to generate the 1mS. This is what I got:

For 1ms at 8Mhz internal osc and 1/16 prescaler for timer2 should be:

The math to calculate the period register
PR2 = (second * Fosc/4 ) / Prescaler
PR2 = (0.001 * 2000000)/16
PR2 = 125 (Why did you use 124?) the datasheet shows the PR2 should match TMR2?

/* Timer 2 Prototype */
/* void setup_timer_2(int8 mode, int8 period, int8 postscale); */

So:
1:16 Prescaler
125 PR2 Register I also tried your value of 124
1:1 Postscaler


Should yield 1000Hz per second or 1mS.

However I am not getting that?

the output result does not match:
Code:
while(TRUE);
{
   output_high(A7);
   delay_ms(1);
   output_high(C2);
   delay_ms(1);
   output_low(A7);
   delay_ms(1);
   output_low(C2);   
   delay_ms(1);
}


It seems as timer2 ticks faster than 1mS. The LEDs are very dim which suggest that the LEDs ON/OFF for less than 1mS?

would you please edit my test code to make timer2 tick for 1mS. I edited the #use delay(clock=8M) to #use delay(internal=8M). I also tried to setup the osc inside the main without any luck. I am also aware that the internal osc is not accurate, However it is working fine if use the above code! I want to see how would you do it for this processor to setup and use timer2.


Regards,
Ttelmah



Joined: 11 Mar 2010
Posts: 19485

View user's profile Send private message

PostPosted: Wed Nov 11, 2015 10:11 am     Reply with quote

The timer counts from 0.....

0 to 124 = 125 counts.

This is common with PIC timers.

Think about it. You are waiting 1mSec for each change, not doing all the changes just 1mSec apart....
Code:

#INT_TIMER2
void t2_tick(void)
{
   static unsigned int8 state=0;
   switch (state)
   {
   case 0:
       output_high(A7);
       state++;
       break;
   case 1:
       output_high(C2);
       state++;
       break;
   case 3:
       output low(A7); //2ticks from when A7 went high.....
       state++;
       break;
   case 4:
       output_low(C2);//2 ticks from when C2 went high.
       state=0;
       break;
   }
}


This takes 4 interrupts to perform the four changes.
Sam_40



Joined: 07 Jan 2015
Posts: 127

View user's profile Send private message

PostPosted: Wed Nov 11, 2015 11:25 am     Reply with quote

Ttelmah,
Thanks a lot. Problem is solved.

My test program without using delay to help others:



Code:
#include <18F2685.h>
#fuses INTRC_IO, NOWDT, BROWNOUT


#INT_TIMER2
void t2_tick(void)
{
   static unsigned int8 state=0;
   switch (state)
   {
   case 0:
       output_high(A7);
       state++;
       break;
   case 1:
       output_high(C2);
       state++;
       break;
   case 3:
       output low(A7); //2ticks from when A7 went high.....
       state++;
       break;
   case 4:
       output_low(C2);//2 ticks from when C2 went high.
       state=0;
       break;
   }
}


void main()
{
   
   setup_oscillator(OSC_8MHZ);
   setup_timer_2(T2_DIV_BY_16,124,1);
   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);
   while(true)
   {
   }
     
}


it also works great with my 7 segments project.

Thanks,
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