|
|
View previous topic :: View next topic |
Author |
Message |
Sam_40
Joined: 07 Jan 2015 Posts: 127
|
How to accurately set timer? [SOLVED] |
Posted: Fri Nov 06, 2015 8:18 am |
|
|
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: 19553
|
|
Posted: Fri Nov 06, 2015 8:33 am |
|
|
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.
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
|
|
Posted: Fri Nov 06, 2015 9:13 am |
|
|
Ttelmah,
Thanks a lot for the detailed information. You have a great weekend! |
|
|
Sam_40
Joined: 07 Jan 2015 Posts: 127
|
|
Posted: Wed Nov 11, 2015 9:09 am |
|
|
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: 19553
|
|
Posted: Wed Nov 11, 2015 10:11 am |
|
|
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
|
|
Posted: Wed Nov 11, 2015 11:25 am |
|
|
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, |
|
|
|
|
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
|