Calculate Prescaler value for PIC16F877

I am trying to figure out if there's a way to calculate the prescaler value for Timer 0 on the PIC16F877. I've looked at both parts of Microchip's tutorial on timer 0 and some other tutorials:

These tutorials just mention that it's using a certain prescaler but don't specify why. I know what the prescaler is and how to calculate everything else since I just always used the maximum prescaler available. However, for my current studies I need to know how to calculate it or justify the choice of prescaler.

The prescaler divides the Timer input by the prescaler value. For Timer 0, the input can be either T0CKI (RA4) or CKLOUT (Fosc/4) [page 47 of the datasheet]. If the input of the timer is CLKOUT, you need to divide the oscillator frequency by 4, to get the Timer input frequency. Let's assume you use a 16MHz external crystal oscillator (HS mode) [page 121]. That means the input of the Timer is:

Fosc/4 = 16MHz/4 = 4MHz

Then you can calculate the time needed to execute 1 instruction:

Which is the same as the time needed to increase Timer 0 by 1:

T0inc = 1/CLKOUT = 1/4MHz = 250ns

Timer 0 is an 8-bit timer, so it counts from 0 to 255. When it's at 255, and another increase happpens, it would reach 256 - but it cant't with only 8 bits - so it rolls over to 0, and creates an interrupt (T0IF becomes high).

If you'd run this code:

TMR0 = 0;  //reset the timer to 0;
T0IF = 0;  //reset the Interupt Flag
T0IE = 1;  //turn on the Timer 0 Interrupt Enable

It would take this time to create an interrupt on T0IF from the moment you've written to the TMR0 register:

(256-TMR0)*T0inc = 256*250ns = 64us

This is the maximum time you can achieve without prescaler. I read in the comments you need a time of 5 minutes (!). That is a long time @Fosc=16MHz. Now you can do a few things:

• Don't use Fosc as timer input, but an external signal. E.g. you might have an RTC on board that has an output signal of 1Hz. Hook that up to T0CKI and you're making your life very easy! You'd have to count to 5min*60s=300. That's more then 256, but less than 256*2, so prescaler of 1:2. Count to 150 (TMR0 = ~150;) and you're done.
• Lower the Fosc. You might use a crystal oscillator with a lower frequency. In HS mode you could choose 4MHz. That would increase the time to 256us. Still not even close to 1 second. And you need 5 minutes. So you could lower it even more and use LP mode, or use RC mode instead. What you choose depends on the other needs your application has. If you need precision, you might want to stay with the crystal oscillators, and not use RC mode. If you need a long delay, but you need a fast processing speed once that long delay is done, you'd want to keep the Fosc high, to keep the CLKOUT high.
• You could increase the prescaler. If you use the prescaler, you divide the input of Timer 0 by the prescaler:

T0inc = (1/CLKOUT)*PS

You need a T0inc of 5minutes/256 (max. 8-bit timer value) = 5*60sec/256 = 1.17seconds

At Fosc=16MHz, that gives you a prescaler of:

PS = T0inc/(1/CLKOUT) = 4687500

That's more then the maximum of 256, so let's set the prescaler to the maximum value:

T0CS = 0;    //Internal instruction cycle clock (CLKOUT)
PSA = 0;     //Prescaler is assigned to the Timer0 module [page 48]
PS = 0b111;  //256bit prescaler

That gives us:

T0inc = (1/CLKOUT)*PS = 64us
(256-TMR0)*T0inc = 256*64us = 16.384ms interrupt time

To get to 5 minutes, the timer would have to create an interrupt 300s*16.384ms = about 18310 times. You could use a 16-bit variable inside the ISR to count, and do what you have to do when the counter reaches 18310.

Whether this will work, depends on how much accuracy you need. If you need to be really exact, you'll have to take into account the time the PIC needs to reach the ISR and that sort of things. But if you're creating a cooking timer, this would be precise enough... It all depends on your application.

Your question was specifically about Timer 0, but in this case I would use Timer 1 on the PIC16F877. It's a 16-bit timer with an 8-bit prescaler :-). That would give me an interrupt time @16MHz of 0.131 seconds at a prescaler of 8! For 5 minutes, I'd only have to count to 2288 inside the ISR. That saves quite some interrupt time, that I can use to do something else.

What you could also do, is choose a prescaler that makes your live easier. When Fosc is 16MHz, CLKOUT is 4MHz, you could use a prescaler of 4, and have a 1MHz Timer input. That's easy to count with as a human; T0inc = 1us. Set TMR1 to count to 25000 (TMR1 = ~25000;) to get 25ms interrupt time. Count to 12000 in your ISR to get to 5min. That's how I often work, since I usually end up using the same timer for different things. It helps to have a simple time base.

I think in that sense, programming is quite a creative process :-)

• Thank you for your thorough explanation! This is exactly what I wanted – Simeon R Apr 28 at 18:01