Timer Delay Implementation in PIC18F4550

Timer Delay Implementation in PIC18F4550

In PIC18F4550 delay is implemented with general counting loops or with timers. Looping delays have their downsides such as inaccurate delay duration and blocking precious processor time. Thus delays of the order of milliseconds are preferred to be implemented with timers. PIC18F4550 has 4 timers, each of which could be used to provide delays of a few seconds. The delay required is configured with the help of timer control registers and preload value, in accordance with the Oscillator frequency, as explained in our previous chapter Timer and Counter with PIC18F4550. Here we will learn more about how to implement a required delay with Timers.

Delay Calculation

The oscillator in our PIC18F4550 development board is a 20Mhz crystal oscillator. Here we will be using the Timer 0 in 16-bit mode. The maximum value or resolution of a 16-bit timer will be 0xFFFF H or 65535 ( 2^16 ). Thus the timer value, by default, increments from the value 0000 H to FFFF H. We can also load the TMR0 register with a preload value such that the timer counts from that value to the maximum value before it overflows, giving us a required delay.

The present timer value is stored in the register TMR0L in 8-bit mode and TMR0H, TMR0L in 16-bit mode. The TMR0H and TMR0L 8 bit registers could be accessed together as a 16 bit TMR0 register. The timer value is incremented after each timer cycles. A single timer cycle in the PIC18F family is given by ( Fosc/4 ) since a single timer cycle uses 4 instruction cycles. Thus the time delay used for a single timer cycle is ( 4/Fosc ).

A prescaler could be used to increase the maximum delay length. The prescaler, if assigned, will first increment the prescale value with every timer cycle. The timer value is incremented only when the prescale value overflows the assigned maximum limit. The prescale value is selected with the T0PS2: T0PS0 bits ( T0CON <2:0> ) and can have the values 256, 128, 64, 32, 16, 8, 4, 2 and 1.

The time delay in seconds for timer overflow is given by the equation,

 

Timer Delay Implementation in PIC18F4550

Where,

  • T – is the delay time in seconds
  • Fosc – is the oscillator frequency (20 MHz)
  • Prescale – is the maximum prescale value ( T0CON<2:0> )
  • Resolution – is the maximum value of the timer ( 0xFFFF H )
  • TMR0 – is the timer preload value ( TMR0H, TMR0L )

Thus to obtain a particular delay, the TMR0 timer/preload register should be updated with an appropriate value after each timer overflow.

The maximum delay that can be obtained with the 16-bit timer is when the prescale value is maximum and the TMR0 preload value is minimum. Thus for PIC18F4550 with a 20Mhz crystal oscillator, the maximum delay that can be obtained is

Tmax = (4/20000000)*256*(65535-0) 
     = 3.35 sec

Designing a 1-millisecond timer delay

To design a timer delay, we have to first choose the prescale value. The prescale value must be large enough to provide the required delay but small enough to provide it accurately. Here we will be choosing the value 8.

The TMR0 value is calculated with this formula.

TMR0 = Resolution - (( T * Fosc ) / (4 * Prescale))
     = 65535 - (((1/1000) * 20000000) / (4 * 8))
     = 65535 - 625
     = 64910
     = 0xFD8E H

After turning on Timer 0 with prescale value 8 using T0CON register and loading the preload timer value, the timer interrupt flag bit T0IF is used to check the timer overflow. When the timer overflows, the TMR0 register should again be loaded with the preload value to again obtain the 1millisecond delay. This could be repeated ‘n’ times to obtain an ‘n’ millisecond delay, after which the timer is disabled.

Firmware Example:

#ifndef _XTAL_FREQ
#define _XTAL_FREQ 20000000UL                           //Defining the oscillator frequency
#endif

void timer_ms(unsigned int n)
{
    unsigned int i;
    T0CON = 0x82;                                       //Enable timer with prescale value 8
    for(i=0;i<n;i++)
    {
        TMR0 = 65535 - (_XTAL_FREQ/(4*8*1000));         //Preload value for 1 ms
        while(!TMR0IF);                                 //Check for timer overflow
        TMR0IF=0;                                       //Clear timer flag
    }
    T0CON = 0x00;                                       //Disable Timer 0
}