PDA

View Full Version : help: countdown with timer0 interrupt



xnihilo
- 8th August 2008, 12:34
Hello.

I need to start a 5 minutes countdown on a pic16f690.

I have the very simple main program:

Loop
@ sleep
Goto loop

Then I have an int handler for triggerings on porta pins. In fact there are ir receivers on each porta pin and an ir beam triggers an int and specific actions are taken.

I would need to use timer0 overflow interrupt. What I read from the datasheet is that timer0 is a 8 bits timer that can be used as either a counter or a timer, with prescaler.

If I am using:

Define Osc 8

I assume it means clock speed is 8000000 clock cycles per 1000000 microseconds, thus 125ns clock cycles.
Right?
If tmr0 is updated at every clock cycle it takes 256*125ns to set the tmr0 overflow flag in intcon register. If I use a 1:256 prescaler, it will take 256*256*125ns (=8.192 ms) before tmr0 overflows.
Is that correct?

I would need 36621 iterations of a counter variable to get 5 minutes countdown (300000/8.192).
Right?

If I add in my int handler a routine that will increment a word variable at every tmr0 overflow, I can still get porta change interrupts.
Right?

I could have used a loop but during the loop (inside the int handler) no interrupt would occur.

What do you think?

Thanks a lot.

skimask
- 8th August 2008, 13:51
Define Osc 8

I assume it means clock speed is 8000000 clock cycles per 1000000 microseconds, thus 125ns clock cycles.
Right?
If tmr0 is updated at every clock cycle it takes 256*125ns to set the tmr0 overflow flag in intcon register. If I use a 1:256 prescaler, it will take 256*256*125ns (=8.192 ms) before tmr0 overflows.
Is that correct?

Datasheet reference one more time...
The PICs run at F(osc) / 4 , 4 clock cycles per instruction cycle. Therefore, at 4Mhz, the PIC executes 1 million single cycle instructions per second. At 8Mhz, 2 million single cycle instructions per second, 500ns per instruction cycle, which is what the timers are incremented from.

Tmr0 overflows every 256 instruction cycles, 7812.5 timers per second.
5 minutes = 300 seconds = 2,343,750 total overflows to get 5 minutes.
If Tmr0 is capable of 16 bit (as it is in some PICs), then 9155.2734375 overflows to get 5 minutes.

Bruce
- 8th August 2008, 19:32
While the PIC is sleeping Timer0 will be off since on-chip clocks are shut down. You could
use Timer1, but you would need an extermal clock during sleep.

If it will be awake during your 5 minute time period, you could use the compare module set
to reset Timer1 on each match. Load CCPR1L and CCPR1H with 62,500, set a prescaler of
1:16, and it will interrupt every 500mS + automatically reset Timer1 to 0.

Then you can just increment a variable in your int handler until your delay period is reached.
This is a lot easier than reloading a timer in an int handler - or fiddling with adjustments to
reload values compensating for code overhead.

xnihilo
- 8th August 2008, 19:42
8MHz & Fosc/4 = 2MHz = 0.5Us per instruction cycle.
Id 1:256 prescaler, it will count 256 instruction cycle before incrementing TMR0.
With a TMR0 preset to 176 and a prescaler of 256 it will interrupt every 10ms.

Skimask, you say:
"Tmr0 overflows every 256 instruction cycles, 7812.5 timers per second".
I don't get it.
256*0.5ns = 128 ns per overflow if 1:1 prescaler.
1000000000ns / 128 = 7812500 iterations per second

skimask
- 8th August 2008, 19:46
Skimask, you say:
"Tmr0 overflows every 256 instruction cycles, 7812.5 timers per second".
I don't get it.
256*0.5ns = 128 ns per overflow if 1:1 prescaler.
1000000000ns / 128 = 7812500 iterations per second

At 8Mhz, there are 2,000,000 instructions cycles per second.
Assuming a 1:1 prescaler, with an 8 bit counter, you'll get 7812.5 Tmr0 overflow interrupts per second.

256 * .5US = 128 US per overflow!

You're off by 1,000 ! :)

xnihilo
- 8th August 2008, 20:18
While the PIC is sleeping Timer0 will be off since on-chip clocks are shut down. You could
use Timer1, but you would need an extermal clock during sleep.

If it will be awake during your 5 minute time period, you could use the compare module set
to reset Timer1 on each match. Load CCPR1L and CCPR1H with 62,500, set a prescaler of
1:16, and it will interrupt every 500mS + automatically reset Timer1 to 0.

Then you can just increment a variable in your int handler until your delay period is reached.
This is a lot easier than reloading a timer in an int handler - or fiddling with adjustments to
reload values compensating for code overhead.

You pointed out something I just read this afternoon: timer0 is frozen, which is a problem as I use "@ SLEEP" !!
Well, my idea is to use the folowing parameters:
With a TMR0 preset to 176 and a prescaler of 256 it will interrupt every 10ms.
When in my lasergame program player health points drop below 0, it sets a variable (BIT) called CRITICAL to 1 and enable TMR0 interrupts.
The routine handling the TMR0 interrupt would increment a counter variable and then it would go back to my main loop and... uh... go to sleep, disabling the timer...
But, if I write (preseting CRITICAL to 0):

(program starts here)
loop:
if (countdown == 1) THEN
PAUSEus 15 'shortest pause I can use with a 8MHz clock
ELSE
@ SLEEP
ENDIF
Goto loop


Then when my countdown in the INT handler reaches the desired value, I disable the INT for TMR0 and set CRITICAL to 0 so the main loop will behave as it should: have a sleep when the INT handler has been processed.
My question is: when sleeping, the interrupt will be handled then MCU will go back to "goto loop" or will it continue the "@ sleep"?????

xnihilo
- 8th August 2008, 20:18
At 8Mhz, there are 2,000,000 instructions cycles per second.
Assuming a 1:1 prescaler, with an 8 bit counter, you'll get 7812.5 Tmr0 overflow interrupts per second.

256 * .5US = 128 US per overflow!

You're off by 1,000 ! :)

Jeeze! You are right. Sorry, I should have more @ SLEEP myself :p

Bruce
- 8th August 2008, 20:25
It would return to goto loop. The sleep instruction has already been executed.

xnihilo
- 8th August 2008, 21:32
It would return to goto loop. The sleep instruction has already been executed.

FIne, then that's what I need, right.
It would work...
Thank you very much.

xnihilo
- 18th August 2008, 15:47
Well, it does not work as expected.

First I have a problem with the other interrupts (I poster a message today about this) but with my settings I was expecting a TMR0 overflow evey 10ms but it happens every 1ms...

TMR0 starts at 98, and I'm using a 8MHz intosc.
0.5Us per instruction cycle (FOSC/4).

Strange...

skimask
- 18th August 2008, 17:15
Well, it does not work as expected.

First I have a problem with the other interrupts (I poster a message today about this) but with my settings I was expecting a TMR0 overflow evey 10ms but it happens every 1ms...

TMR0 starts at 98, and I'm using a 8MHz intosc.
0.5Us per instruction cycle (FOSC/4).

Strange...

8,000,000 Hz oscillator / 4 = 2,000,000 instructions/second = 2,000,000 increments of TMR0 using a prescale of 1:1 (prescaler assigned to WDT).
TMR0 is an 8 bit timer, max count = 256. You're reloading it with 98, leaves you with 158 counts.
2,000,000 / 158 = 12,658.228 Hz = 79us per interrupt.
2,000,000 / 256 = 7812.5 Hz = 128us per interrupt.
So, you're 10ms theory (since we don't have any better information) isn't going to work.
But this might:
http://www.mister-e.org/pages/picmulticalcpag.html

xnihilo
- 18th August 2008, 21:56
8Mh/4 = 2000000 op per s.
1:128 prescale = 2000000/128 = 15625 per s.
Preload with 98, 158 counts.
15628 / 158 = 98.89 Hz
1000ms/100 = 10ms

What's wrong?

skimask
- 19th August 2008, 14:12
1:128 prescale = 2000000/128 = 15625 per s.
What's wrong?

You left out that vital bit of information (the 1:128 prescale).

So, it's happening every 1ms instead of 10ms?
Are you sure you're correctly clearing/re-enabling the correct interrupt after you are done processing the interrupt...or is the interrupt sequence 'jumping right back into itself' after you are done processing it?