|
|
View previous topic :: View next topic |
Author |
Message |
hadeelqasaimeh
Joined: 05 Jan 2006 Posts: 105
|
Timer1 help |
Posted: Sun Jul 27, 2008 12:44 pm |
|
|
hello every body
i need timer1 to overflow every 1 second, how can i do that? i search but i cant find clear way to decide the value in set_Timer1(0xvalue)
any body can help me and explain, please?
note that i use 16f877a with 4Mhz osc
here is my code:
Code: |
#include<16f877A.h>
#fuses NOWDT, XT, NOPROTECT
#use delay (clock=4000000)
#priority timer1,ext
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
long x;
#INT_EXT
void ext_isr() {
x++;
}
#INT_TIMER1
void timer1_isr() {
delay_us(1);
printf("X:%lu\r\n",x);
}
int main()
{
x=0;
set_timer1(0x0000); // this must changed to match overflow every //1000ms
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT);
enable_interrupts(INT_TIMER1);
ext_int_edge( H_TO_L );
while (1) {}
}//main
|
thank you |
|
|
Ttelmah Guest
|
|
Posted: Mon Jul 28, 2008 10:37 am |
|
|
What you show, won't work.
Think of the timer, a bit like a strange game of 'snakes and ladders'. The height of the ladder, is set by the size of the timer (256 rungs, or 65536 rungs, for 8bit, or 16bit timers). You step 'up' the ladder, at the programmed clock rate. Normally the master oscillator/4, over any 'prescaler' value, available to the timer. So, for timer1, with a 4MHz clock, you can climb at 1 rung every uSec, or 2uSec, 4uSec, or 8uSec.
Then when you get to the top of the ladder, the interrupt occurs,and you fall straight back to the bottom of the ladder.
'Setting' the timer to a value, jumps you _once_, to a particular rung. However when you get to the top, you again fall back to the bottom of the whole ladder.
One 'solution', then is to set the 'rung' in the interrupt. Unfortunately, the counter is running all the time, and it takes _time_ to get into the interrupt code. If you set a particular count, and one or more counts has already occurred, these get lost, and the accuracy vanishes. Even if you set the rung, to the current count + the required 'jump', there will be errors if the count increments between reading, and writing...
Now, look at values. Work in uSec. There are 1000000 in one second. The counter counts up to 65536. Multiply 65536, by the largest prescaler (8). 524288. Less than the million you need. So, this timer, _cannot_ count one second.
In fact, none of the timers on your chip, can go this long on the standard clock. You either have to use a lower frequency clock feeding the chip/timer, or use a faster timer 'tick', and count these.
Now, the one timer that is different in this, is timer2. This is a bit like an 'extension ladder', and you can actually change it's effective 'length', allowing it to automatically count to particular numbers and reset.
If (for instance), you set this up with:
setup_timer2(10,249,10);
Then it will run off the master oscillator/40 (/4 /10 - the first 'prescaler'), divide this by 250 (second number+1), and then only interrupt on the tenth time round (third number). 40 times per second.
Then in the timer interrupt, have:
Code: |
#INT_TIMER2
void tick(void) {
static int counts=39;
if (counts) --counts;
else {
counts=39;
//do your 1/second job here
}
}
|
This gives a system 'tick', running 40*per second, which you then use to generate the one second counter.
Best Wishes |
|
|
hadeelqasaimeh
Joined: 05 Jan 2006 Posts: 105
|
|
Posted: Tue Jul 29, 2008 6:20 am |
|
|
hi Ttelmah
i think i got the idea,and i use Timer2 as you post,but still not working!
maybe there is some misunderstanding, here is the code:
Code: |
#include<16f877A.h>
#fuses NOWDT, XT, NOPROTECT
#use delay (clock=4000000)
#priority timer2,ext
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
int1 flag;
long x;
#INT_EXT
void ext_isr() {
x++;
}
#INT_TIMER2
void tick(void) {
static int counts=39;
if (counts) --counts;
else {
counts=39;
//do your 1/second job here
printf("X:%lu",x);
}
}
int main()
{
x=0;
setup_timer_2(10,249,10);
set_timer2(0);
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT);
enable_interrupts(INT_TIMER2);
ext_int_edge( L_TO_H );
while (1) {
}
}//main
|
i wonder what this line do:
thank you very much |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jul 31, 2008 6:29 pm |
|
|
hadeelqasaimeh wrote: | i wonder what this line do:
| If you don't know what the line does, why did you put it in?
This line sets the value of timer2 to a known start-up value. Good coding practice but pointless because the time of your application start-up is unknown so who cares if the first timer interrupt occurs a few milliseconds sooner or later.
Keep the line if you like a strict programming style. Or remove the line if you want to save a few bytes memory (my preference).
Code: | setup_timer_2(10,249,10); | The calculation is correct but doesn't match the hardware capabilities. Check the datasheet for the prescaler options of this chip and you will find: 1, 4 or 16.
Many possible setup combinations can be used to create a 1s counter but for optimal performance you want to minimize the interrupt overhead. Configure timer 2 to generate as few interrupts as possible and still get a nice integer value for the counter in the interrupt handler.
For example: setup_timer_2(T2_DIV_BY_16, 249, 10) and in the interrupt count to 25.
16 * (249+1) * 10 * 25 = 1,000,000
1MHz * 4 clocks per count (always) = 4MHz
Edit 4-Aug-2008: fixed a stupid bug in the prescaler setting. Now use the defined value T2_DIV_BY_16 instead of a hardcoded value. |
|
|
|
|
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
|