Wednesday, September 4, 2013

Using PIC18 Timer Module for delay – C Code with Proteus Simulation

title_image
In our LED Blinking tutorial we used the PIC18 library function for delay which doesn’t use timer for delay. The built-in function we used for delay just insert’s NOP instruction to obtain the required delay. Today we will use the PIC18’s Timer Module to obtain the delay for  LED Blinking Example.

Introduction to PIC18 Timers

The number of timers a PIC18 has depends on its family. They ranges from 2 to 5 in PIC18. PIC18 Timers can be used as timers to generate delays or as counters. In the counter mode it is used to count events which occur outside of the Microcontroller. PIC18 Timers are referred by the names Timer0, Timer1, Timer3, and so on. In our Example Program we will be using Timer0 in timer mode to obtain the required delay. Timer can be 8-bit, 16-bit or even 32-bit on some newest PICs. In the PIC18F8722 Timer0 can be used in 8-bit or 16-bit mode selectable via software. In the 8-bit mode the timer increments an 8-bit register on each clock cycle and ranges from 0 – 255 while in 16-bit mode the range is 0 – 65535.

Timer Clock Source

A Timer or any other Microcontroller peripheral requires clock source for its operation referred to as the Peripheral Clock. The clock can be internal or external. In the internal clock mode Timer0 operates as timer and uses the internal(FCPU) clock with or without pre-scalar. Pre-Scalar is an integer value which divides the CPU clock to give Timer Clock i.e Timer Clock = FCPU/pre-scalar.  When the Pre-scalar is set to one or bypassed then the timer runs on the same clock as the CPU is running. In the external clock mode Timer0 operates as counter and counts on every rising or falling edge of the clock connected to the Timer's clock pin. In this example we will be using Timer0 with the internal clock(timer mode) configuration and pre-scalar bypassed or 1. T0CON – Timer0 Control Register is used to control all these settings, details can be found in the Timer0 Module section of the datasheet.

Difference Between FOSC and FCPU

Oscillator Frequency (FOSC) is the frequency of the crystal we have connected to the PIC. in our case we are using 20MHz crystal so FOSC = 20MHz. The PIC internally divides FOSC by 4 to get FCPU. Based on this we have clock cycle and instruction cycle. the clock cycle is simply 1/FOSC while instruction cycle is 1/FCPU. An instruction cycle is the time required for the PIC to execute a single assembly language instruction( excluding jump and loop instructions which requires more than on instruction cycles).

Delay Calculation

After initializing Timer0 in 8-bit mode with internal clock by setting the relevant bits in T0CON Register we turn on the Timer. As the Timer is turned on it increments the TMR0 register every clock cycle starting from 0. What happens when it reaches 255? glad you asked. PIC18 has the ability to generate interrupt on overflow – meaning that a  bit called Timer0 Interrupt Flag(TMR0IF) which is set when TMR0 makes  transition from 255 to 0. We can check TMR0IF either by polling or using Interrupt Service Routine(ISR). In this example we will used polling method and will cover Interrupts in another post. 
Assuming the PIC is operating with FOSC = 20MHz or FCPU = 5MHz, a single overflow of Timer0 will give us 256 * 1/5MHz = 51.2usec delay. So if we need delay more than 51.2usec we maintain a counter and increment it each time Timer0 overflows.
For a delay of 1sec
1sec = 10^6usec the timer overflows after 51.2usec So number of TImer0 overflows required to get a 1sec delay can be calculated as 10^6/51.2 = 19531.25 rounded to 19531 will give approximately 1sec delay.
So after starting Timer0 we poll for TMR0IF if set a variable called counter is incremented. The counter value is compared to 19531 if equal it means approximately 1sec is elapsed and an LED toggles to indicate this.

C Code

Below is the C code for this example with comments, copy it and generate the hex file for Proteus simulation.
/* 

   ################################################################################ 

   **** PIC18 Timer Example

   **** IDE      : MPLAB Ver 8.91

   **** Compiler : Microchip C18 Ver 3.43

   ################################################################################

*/

 

// Includes

#include <p18cxxx.h>

#include <delays.h>

 

// Configurations

#pragma config WDT = OFF                // Watchdog Timer Disabled

#pragma config OSC = HS                // OSC Mode - High Speed Crystal/Resonator

#pragma config XINST = OFF            // Extended Instructions Disabled

 

// LEDs

#define LED1    LATCbits.LATC0

 

// main

void main(void)

{   

    unsigned int counter = 0;    // variable that holds timer overflow count

 

    // Initialize Timer0

    // T0CON bits

    //   7    |   6    |   5  |   4   |  3  |   2   |   1   |   0 

    // TMR0ON | T08BIT | T0CS |  T0SE | PSA | T0PS2 | T0PS1 | T0PS0

    // See datasheet for details

    // 8-bit timer mode 

    // internal clock, pre-scaler = 1

    // TMR0ON = 0 at this point we don't start the timer

    T0CON = 0b01001000;

 

    TRISCbits.TRISC0 = 0;     // Set as output for LED

 

    // infinite loop    

    while(1)

    {

        T0CONbits.TMR0ON = 1;           // Start Timer

        while(!INTCONbits.TMR0IF)      // wait until Timer0 overflows - polling

            INTCONbits.TMR0IF = 0;    // clear interrupt flag

        if(counter != 19531)

            counter++;

        else

        {

            counter = 0;              // reset counter

            LED1 = ~LED1;            // toggle LED

            T0CONbits.TMR0ON = 0;   // Stop Timer0      

        }

    }

}

unsigned int counter = 0;    // variable that holds timer overflow count

this line of code declares the counter as unsigned int which ranges from 0 – 65535. So if you want delay other than 19531(calculated for 1sec) and greater than 65535 then you may declare the counter as unsigned long int instead.

Simulation

Here is the gif animation of the Proteus simulation

Timer_Ex_animation

Conclusion


In this post we used PIC18F8722’s Timer0 in 8-bit timer mode to obtain a delay of approximately 1sec. Besides this the timer can also be used to find the execution time of a function – for example. In which case we have to use Timer Interrupt to take care of the timer overflow. In the beginning of the function Timer is started and after the function finishes it is stopped. To calculate the time we use our counter variable value as well as TMR0 value as
time taken = (counter * 0.0000512) + (TMR0 * 1/5MHz) sec or more generally

time taken = ((counter * 256) + TMR0) *  1/FCPU in seconds.

Please comment you questions and suggestions and subscribe for updates.

Share This!



7 comments:

  1. Hi;
    how can I calculate time difference between two signals by using timer?(not phase difference)they are undependent sittuations

    ReplyDelete
    Replies
    1. Are the signals coming on I/O pins? If yes then you can simply start a timer when the first signals arrives and stop the timer when the other arrives, the difference is the time difference between the two signals. Hope it helps.

      Delete
  2. Very sincere work hafeezulla khan this blog is packed with lot of information. Thanks for sharing.

    sell used Laptop, Desktop here.

    ReplyDelete
  3. What should be the value of TMR0 in the Formula??

    ReplyDelete
  4. Brilliant Tutorial....Very well explained

    ReplyDelete
  5. I learn some new stuff from it too, thanks for sharing your information. predelay calculator

    ReplyDelete
  6. Your Blog is very nice. Wish to see much more like this. Thanks for sharing your information fixed resistor

    ReplyDelete

Popular Posts

Followers

Like Us

Follow me on Twitter