|
|
View previous topic :: View next topic |
Author |
Message |
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
Timer2 easy question |
Posted: Fri May 19, 2006 5:45 am |
|
|
Hello,
I want to interrupt every 10ms using timer2. Now I've used the search function of the forum. That brought me to this implementation:
Using a 4 Mhz ceramic resonator:
#fuses XT, PUT, NOWDT, NOPROTECT, NOLVP, NOCPD, NOWRT, NOBROWNOUT, NODEBUG
#use delay(clock=4000000)
start the timer:
Code: | setup_timer_2 (T2_DIV_BY_4, 249 , 10); // Timer2 Interrupt |
Timer2 isr:
Code: | #int_Timer2
Timer2_isr()
{
TIMER2_ITR = TRUE;
}// TIMER2 |
in main: check flag and do the required
Code: | //******************** TIMER2 interrupt vlag afhandelen **********************//
if (TIMER2_ITR)
{
TIMER2_ITR = FALSE;
// De batterijspanning wordt gemeten elke minuut en zowieso doorgestuurd.
teller++;
if (teller == 1000) // 1000 * 10ms = 10s
{
Meet_Vbat(&Vbat); // Vbat meten
if (!E3_SLEEP) // Stuur de batterijspanning door naar E3 als deze
{ // niet in sleep staat
Send_Vbat(Vbat);
}
teller = 0;
}
} |
So what _should_ happen is that battery voltage is sent to the serial port every 10 seconds. Now it does send it but every 21 a 22 seconds and I don't understand why. Who helps me with this timing?
Timing is not critical. Has to be approximately 10 seconds.
|
|
|
drh
Joined: 12 Jul 2004 Posts: 192 Location: Hemet, California USA
|
|
Posted: Fri May 19, 2006 8:15 am |
|
|
According to your code, there are 2 conditions that determine when you send the battery voltage. One of them is if "teller" is equal to zero. The other is if "E3_SLEEP" is false. If you are sure that the timer is functioning correctly, what's connected to E3_SLEEP? And is it in the correct state? _________________ David |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Fri May 19, 2006 8:21 am |
|
|
Drh
E3_SLEEP is set to FALSE; always.
There's something wrong with the timer. I want it to send at 10 seconds |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Fri May 19, 2006 8:26 am |
|
|
Try this:
Code: | setup_timer_2 (T2_DIV_BY_16, 249 , 10); // Timer2 Interrupt |
This will have the timer ISR being entered 25 times a second.
Code: | #int_Timer2
Timer2_isr()
{
if(++counter > 24)// when the counter reaches 25
{
counter = 0;
if(++counter2 > 9)// this will enter every ten seconds
{
counter2 = 0;
TIMER2_ITR = TRUE;
}
}
}// TIMER2 |
This ISR will make TIMER2_ITR go true every ten seconds. Then, in your main body, you can evaluate that and do whatever you need to do.
I do this quite a bit when I need to have something happen at a certain frequency.
Ronald |
|
|
Ttelmah Guest
|
|
Posted: Fri May 19, 2006 8:46 am |
|
|
I'd actually do this a slightly different way.
Though I am always preaching 'keep the interrupt handler short', the work involved in a simple test and/or subtraction, is only a couple of machine cycles. So:
Code: |
int16 tick;
#int_Timer2
Timer2_isr() {
if (tick) --tick;
} // TIMER2
|
Then in main:
Code: |
if (tick==0) {
tick=1000;
Meet_Vbat(&Vbat);
if (!E3_SLEEP)
Send_Vbat(Vbat);
}
|
The advantage of this, is that it makes it impossible for main to 'miss' the countdown. Testing for a value 'equal to', has the problem that if something occurs and the main code doesn't get to the test on that loop, it can be skipped...
Note also that resetting the tick, is the first thing done. Otherwise if the printout takes any significant time, a count may be missed.
If your main loop is taking more than 10mSec to go 'round', then this may be the cause of the problem, with the count only updating at half the interrupt frequency.
If this doesn't fix it, then I have to agree with the possibility that it is 'E3_SLEEP' causing the problem. Try with this removed.
Best Wishes |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Fri May 19, 2006 9:22 am |
|
|
At first thanks for the input.
Quote: | If your main loop is taking more than 10mSec to go 'round', then this may be the cause of the problem, with the count only updating at half the interrupt frequency. |
I'm sure this is the problem.
Here 's my new implementation:
Timer2 isr:
Code: | #int_Timer2
Timer2_isr()
{
teller++;
if (teller == 6000)
{
ONE_MINUTE = TRUE;
teller = 0;
} // 6000 * 10ms = 01m00s
if (Debounce_counter == 0)
{
if (On_off_State == input(AAN_UIT))
{
BUTTON_DEBOUNCED = TRUE;
}
Debounce_Counter = 255; // 255 is a special value that means that no debouncing is happening
} // If debounce nodig
else if (Debounce_Counter < 255)
{
--Debounce_Counter;
}
}// TIMER2 |
in main flag resetter and handler:
Code: | //***************************** ONE MINUTE Teller ****************************//
// De batterijspanning wordt gemeten elke minuut en zowieso doorgestuurd.
If ( ONE_MINUTE )
{
ONE_MINUTE = FALSE;
Meet_Vbat(); // Vbat meten
if (!E3_SLEEP) // Stuur de batterijspanning door naar E3 als deze
{ // niet in sleep staat
Send_Vbat(Vbat);
}
} |
Off course I'll try the 'tick' implementation. But that will be on monday. Have a nice weekend. |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Thu Jun 22, 2006 3:39 am |
|
|
About
Code: | setup_timer_2 (T2_DIV_BY_4, 0xF9 , 10); // Timer2 Interrupt elke 10mS |
How can I adapt that code in order to interrupt every 20 ms ?
Is that:
Code: | setup_timer_2 (T2_DIV_BY_4, 0xF9 , 20); // Timer2 Interrupt elke 20mS |
? |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Thu Jun 22, 2006 6:14 am |
|
|
Quote: | Depends whether your chip has it!. You don't mention what the chip is. Data sheet...
MicroChip, have an application note about the various timers.
The 'point' about timer2, is that it has a hardware circuit to 'reset' it at a specified count. It can also interrupt on every 'n' counts (where 'n' is a 4 bit counter). So if your chip has it:
setup_timer2(T2_DIV_BY_4,249,10);
Will for a 4MHz clock, divide this by 16 (/4, then /4 in the prescaler), count from 0...249, and interrupt every tenth time through the count, giving an interrupt every 10mSec. Rather nice for timing. :-)
Be careful about the counter value. The 'wizard', gets this wrong, as does the help file. the chip counts from zero _to_ the value specified, and resets on the _next_ cycle. Hence for 250 counts, you need 249, yet the wizard insists on using 250. The MicroChip notes have this right As you'd - hopefully - expect!).
Best Wishes |
I found this as an explanation, but don't really understand that in order to get a 20 mS interrupt..
I think:
Code: | setup_timer2 (T2_DIV_BY_8,249,10); //20 MS itr |
|
|
|
Ttelmah Guest
|
|
Posted: Thu Jun 22, 2006 8:43 am |
|
|
Yes.
The formula, is:
(((Clock/4)/prescaler)/(max count +1))/postscaler
counts per second.
So for 20mSec = 50 counts per second, you need:
prescaler * (max count+1) * postscaler = (4000000/4)/50
8 * (249+1) * 10 = 20000
Spot on.
Best Wishes |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jun 22, 2006 8:47 am |
|
|
You didn't mention the processor you are using, but Timer2 operates similar in most PIC models. For the next explanation I suggest you study the diagram for Timer2 in your datasheet.
Your processor has a clock crystal of 4MHz. By design the PIC processors are executing instructions at a frequency that is a factor 4 slower than the clock frequency, in the datasheets this is named Fosc/4. This same clock is also the base frequency for the timers, in your situation this means 1 million counts per second.
You want to get an interrupt every 20ms, i.e.:
= every 0.02 seconds * 1 million counts
= every 20,000 counts
20,000 is too large to fit in the 8 bits counter of Timer2. Now you can decide to use either one of the larger 16-bit timers or you can use the post- and prescalers to make it fit in an 8-bit counter.
Since you decided on using Timer2 you will have to find a combination of post- and prescalers settings that equals 20,000.
Assuming you have a PIC18F458 you have the following possible settings:
Prescaler: 1, 4 or 16
Postscaler: 1 to 16
Period register (PR2): 0 to 255
Now with some simple arithmetic you can find combinations that work, for example:
prescaler 16 * postscaler 5 * PR 250 = 20,000
prescaler 16 * postscaler 10 * PR 125 = 20,000
Quote: | I found this as an explanation, but don't really understand that in order to get a 20 mS interrupt..
I think:
Code: |
setup_timer2 (T2_DIV_BY_8,249,10); //20 MS itr |
| 8 * (249 + 1) * 10 = 20,000
This would be a valid setup, only too bad that T2_DIV_BY_8 is not supported for Timer2.
Always have the datasheet of your PIC processor at hand. Programming a microcontroller is 'close' to the hardware, so please study the datasheets carefully. |
|
|
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Thu Jun 22, 2006 9:13 am |
|
|
Thks for the input, guys. |
|
|
|
|
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
|