Introduction to PIC18’s Timers – PIC Microcontroller Tutorial

Timers are common features of most microcontroller. In simplified terms a timer is just a register whose value keeps increasing (or decreasing) by a constant rate without the help of the CPU. The CPU can read or write this register any time. It reads it find out how much time has elapsed. The Timer register can have the following bit length

  • 8 bit timers – These can count between between 0-255
  • 16 bit timers – These can count between 0-65536
  • 32 bit timers – These can count between 0-4294967296

A timer has a clock source, for example of the clock source of 10KHz is input to a timer then one increment will take 100uS (micro second). This clock source can be obtained from the CPU clock. The CPU clock of popular MCU ranges from 1 MHz to 20Mhz, this can be sometimes too fast. To help us out their is a thing called prescaler in the MCU. The job of prescaler is to divide the CPU clock to obtain a smaller frequency. The PIC Micro that we will use in this example has the following prescaler division factors available.

  1. 256
  2. 128
  3. 64
  4. 32
  5. 16
  6. 8
  7. 4
  8. 2
  9. 1 (Prescaler by-passed)

Timers are also called Counters this is because they can be used to count external events. The following example illustrate the fact.

timer used as counter in pic

Counter Operation.

The above setup can be used to measure the RPM (speed in revolution per minute) of the rotating wheel. A small magnet is attached in the edge of the wheel. Whenever this magnet is exactly below the Magnetic sensor its output becomes high. This output is connected to the T0CKI pin of the MCU. The T0CKI stands for Timer0 Clock Input Pin. So each time the magnet passes by the sensor the timer register inside the MCU is incremented. You can note one this that all this happens without the help of CPU. CPU can do other task and read the Timer register only when required.

Overflow

An overflow occurs when a timer register has already counted the maximum value it can count. At overflow the counter value become 0 again. For example when an 8 bit timer has the value 255 and receive another clock that will set it to 0 and generate an overflow. An overflow can trigger an interrupt and the ISR can handle it.

Using TIMER0 of PIC18F4520

PIC18F4520 has four different timers. The simplest is the TIMER0 so we will learn how to use it first. In this example the TIMER0 is configured as follows.

  • 8 Bit Mode
  • Clock Source from Prescaler
  • Prescaler = FCPU/256 (Note: FCPU= Fosc/4)
  • Over flow INT enabled

Our FCPU=20MHz/4 (We are running from 20MHz XTAL)

=5MHz

Time Period = 0.2uS
Prescaler Period = 0.2 x 256 = 51.2uS (Prescaler is set to divide frequency by 256)
Overflow Period = 51.2 x 256 = 13107.2 uS (Each over flow takes 256 counts)
= 0.0131072 sec

So we need 1/0.0131072 Overflows to count for 1 sec
= 76.2939 Overflows

For that we maintain a counter to keep track of overflows.

When an over flow occurs the PIC jumps to ISR, where we increment the counter. And when counter becomes 76 we toggle RB1 pin. This pin is connected to LED. Therefore we have a LED which is ON for 1 sec and Off for 1sec.

Simple Program to Learn Operation of PIC TIMER0 in HI-TECH C and MPLAB


/*****************************************************************

A simple example to demonstrate the use of PIC Timers. In this 

example the TIMER0 is configured as follows.

*8 Bit Mode
*Clock Source from Prescaler
*Prescaler = FCPU/256 (Note: FCPU= Fosc/4)
*Over flow INT enabled

As our FCPU=20MHz/4 (We are running from 20MHz XTAL)
=5MHz

Time Period = 0.2uS
Prescaller Period = 0.2 x 256 = 51.2uS
Overflow Period   = 51.2 x 256 = 13107.2 uS
                  = 0.0131072 sec

So we need 1/0.0131072 Over Flows to count for 1 sec
= 76.2939 Overflows

So we keep a counter to keep track of overflows.

When an over flow occurs the PIC jumps to ISR where we
increment counter. And when counter becomes 76 we toggle
RB1 pin. This pin is connected to LED. Therefore we
have a LED which is ON for 1 sec and Off for 1sec.


Target Chip: PIC18F4520
Target Compiler: HI-TECH C For PIC18 (http://www.htsoft.com/)
Project: MPLAP Project File

Author: Avinash Gupta
Copyright (c) 2008-2010
eXtreme Electronics, India
www.eXtremeElectronics.co.in

                     NOTICE
                  -------------
NO PART OF THIS WORK CAN BE COPIED, DISTRIBUTED OR PUBLISHED WITHOUT A

WRITTEN PERMISSION FROM EXTREME ELECTRONICS INDIA. THE LIBRARY, NOR ANY PART
OF IT CAN BE USED IN COMMERCIAL APPLICATIONS. IT IS INTENDED TO BE USED FOR
HOBBY, LEARNING AND EDUCATIONAL PURPOSE ONLY. IF YOU WANT TO USE THEM IN 
COMMERCIAL APPLICATION PLEASE WRITE TO THE AUTHOR.

*****************************************************************/

#include <htc.h>


//Chip Settings
__CONFIG(1,0x0200);
__CONFIG(2,0X1E1F);
__CONFIG(3,0X8100);
__CONFIG(4,0X00C1);
__CONFIG(5,0XC00F);


unsigned char counter=0;//Overflow counter

void main()
{
   //Setup Timer0
   T0PS0=1; //Prescaler is divide by 256

   T0PS1=1;
   T0PS2=1;

   PSA=0;      //Timer Clock Source is from Prescaler

   T0CS=0;     //Prescaler gets clock from FCPU (5MHz)

   T08BIT=1;   //8 BIT MODE

   TMR0IE=1;   //Enable TIMER0 Interrupt
   PEIE=1;     //Enable Peripheral Interrupt

   GIE=1;      //Enable INTs globally

   TMR0ON=1;      //Now start the timer!

   //Set RB1 as output because we have LED on it

   TRISB&=0B11111101;

   while(1);   //Sit Idle Timer will do every thing!
}

//Main Interrupt Service Routine (ISR)
void interrupt ISR()
{
   //Check if it is TMR0 Overflow ISR

   if(TMR0IE && TMR0IF)
   {
      //TMR0 Overflow ISR
      counter++;  //Increment Over Flow Counter

      if(counter==76)
      {
         //Toggle RB1 (LED)

         if(RB1==0)
            RB1=1;
         else
            RB1=0;

         counter=0;  //Reset Counter

      }

      //Clear Flag
      TMR0IF=0;
   }
}

The program begins by Setting up TIMER0. The TIMER0 can be configured using a single register called T0CON which stands for TIMER0 control register. The details of each bit is given below.

Name TMR0ON T08BIT T0CS T0SE PSA PS2 PS1 PS0
Initial Value
1
1
1
1
1
1
1
1
BIT
7
6
5
4
3
2
1
0

BIT7 – TMR0ON: Timer0 On, set this to 1 to start the timer.

BIT6 – T08BIT: =1 for 8 bit mode and =0 for 16 bit mode.

BIT5 – T0CS: Timer0 clock source. =1 for T0CLK pin input i.e. counter mode. Set to 0 for internal instruction clock.

BIT4 – T0SE: Used in counter mode only. Please see datasheet for details.

BIT3 – PSA: Prescaler Assignment. Set this to 0 to assign prescaler or 1 to by pass it.

BIT2 to BIT0 – PS2 to PS0: Prescaler Division factor select

PS2 PS1 PS0  
0 0 0 Divide by 2
0 0 1 Divide by 4
0 1 0 Divide by 8
0 1 1 Divide by 16
1 0 0 Divide by 32
1 0 1 Divide by 64
1 1 0 Divide by 128
1 1 1 Divide by 256

So as per our requirement we have set the bits of T0CON register on program startup. This configures the TIMER0 as we require. Lets have a look at the code that initializes the TIMER0

//Setup Timer0
T0PS0=1; //Prescaler is divide by 256
T0PS1=1;
T0PS2=1;
PSA=0; //Timer Clock Source is from Prescaler
T0CS=0; //Prescaler gets clock from FCPU (5MHz)
T08BIT=1; //8 BIT MODE
TMR0IE=1; //Enable TIMER0 Interrupt
PEIE=1;   //Enable Peripheral Interrupt
GIE=1;    //Enable INTs globally
TMR0ON=1; //Now start the timer!
//Set RB1 as output because we have LED on it
TRISB&=0B11111101;
while(1); //Sit Idle Timer will do every thing!

As you can see in the above code, first we set up the bits of T0CON then we enable Timer Overflow interrupt, after that peripheral interrupt and finally enable interrupt globally. PEIE i.e. Peripheral Interrupt bit can enable or disable all peripheral interrupt. GIE or Global Interrupt bit is the master bit that can disable all interrupts.

Then when set PB1 i/o pins as output so that it can control a LED. The LED is connected to MCU by using series resistor to GND. Finally we enter an infinite loop that does nothing. As our timer is set up and running each times it overflows we increment counter by one. When counter becomes 76 we toggle the RB1 pin and reset the counter variable.

In HI-TECH C you can create an ISR (that is Interrupt service routine) by using the keyword interrupt. The ISR function can have any valid C function name. Its argument should be void and the return type should also be void. In our example we have named it "ISR".

void interrupt ISR()

Whenever TIMER0 overflow the CPU stops it current operation and jumps to the ISR. This is called interrupt(or exception) condition. As soon as it enters the ISR we check if it is the TIMER0 overflow interrupt by checking the TMR0IF (Timer0 interrupt flag). We also check if the interrupt is enabled (by checking TMR0IE i.e. Timer0 interrupt enable bit). If both the conditions are met we execute the TIMER0 Overflow ISR Code.

Schematic for Testing TIMER0 of PIC18F4520

pic18f4520 timer0 test schematic

Schematic For Testing TIMER0 of PIC18

The circuit is described in this article.

Running Demo On 40 PIN PIC Development Board

The PIC development board from eXtreme Electronics has all core circuit required in most PIC projects. So we can use it to easily test the above demo program. All you need to do is to short jumper J5, this will connect the LED to RB1 that’s it!

PIC18 Sample Code Downloads

By
Avinash Gupta

May 13, 2010

Facing problem with your embedded, electronics or robotics project? We are here to help!
Post a help request.

Avinash

Avinash Gupta is solely focused on free and high quality tutorial to make learning embedded system fun !

More Posts - Website

Follow Me:
FacebookLinkedInGoogle Plus

47 thoughts on “Introduction to PIC18’s Timers – PIC Microcontroller Tutorial

  • By donnovan - Reply

    he, i just looked at you’re tutorial, and it helped me thanks, i’m am a student computer technology in the Netherlands, what i really liked to know is, in you’re example you had time period 0,2 us, did you divide 1 by 5MHZ(1/5=0,2)
    great totorial…
    Donnovan

    • By Avinash - Reply

      @Donnovan

      Everyone knows Time Period = 1/Frequency !!! Nothing new here, I think even a 8th standard student know that !

  • By donnovan - Reply

    @Avinash
    i just like to be sure

  • By Nagaraj.P.R - Reply

    Hi Avinash,
    Good work… Keep it up.

    I want you to update the below
    16 bit timers – These can count between 0-65536
    32 bit timers – These can count between 0-4294967296
    to
    16 bit timers – These can count between 0-65535
    32 bit timers – These can count between 0-4294967295,
    as the maximum value a 16-bit timer can count is 0xFFFF which is equal to 65535.
    Similarly 0xFFFFFFFF = 4294967295.

  • By George - Reply

    Hi, I run your program on a PICDEM Plus 2 board but the LED stays constantly on. Any ideas why? Thnx.

    Very good site guys, well done.

    • By Avinash - Reply

      @George,

      What MCU was installed on PICDEM 2 Plus?
      Which programmer did you used ?
      Did you also programmed the config area?

  • By George - Reply

    I use PIC18F4525 40pin. I use MPLAB with ICD2 and HITECH compiler. The XTAL is 16MHz but I changed the values accordingly.No I didn’t use the config part of your progra,. I assume that it affects the configuration bits that I control through MPLAB (HS and wachtdog off). thnx.

  • By Avinash - Reply

    @George,

    You have to write config area too. Try that and inform.

  • By George - Reply

    I added the config lines and it works fine. I’ll try to find on the net what those lines do. A kind suggestion would be to add comment to those lines. Thank you very much for your help.

  • Pingback: Introduction to PIC Interrupts and their Handling in C | eXtreme Electronics

  • By PIC Beginner - Reply

    This article is awesome and comprehensible. I can fully understand the concept of the article even I am just a beginner. Please carry on…I am looking forward to your subsequent articles (relevant to PIC)…best regards

  • By georgetwo - Reply

    Thank You Very mush for that special lecture. can I use this code on pic18f4550 by just changing the chip setting to my type of pic?

  • Pingback: PIC18F452 Timers/Counters Interrupts,...

  • By Bahman - Reply

    Dear Mr.Gupta,
    Hello.Thanks for your very interesting and usefull site.
    I want to write a program using PIC18F452&XTAL=20MHZ in C to do the followings;

    1.Simultaneously turn a timer on[timer1 or 2] to count for 1 sec. and
    also count the number of High[transition from H to L] state of the
    input signal.

    2.Turn a timer on[timer1 or2] for 1 sec. and as soon as a input signal injected or entered to a PIC pin the timer[timer0 or…]immediately turned off and calculate the time of passed by that timer.

    Would you please help and give me some example codes to write those programs?How can I modify that above program example to do the 2 above cases?

    Thanks,

  • Pingback: Using Multiplexed 7 Segment Displays – PIC Microcontroller Tutorial | eXtreme Electronics

  • By Will - Reply

    I used to be good at programming this puppies. But I have not touched them for three years now. I am having a big issue with the timer as a counter and as a timer. My question is I program in MPlAB IDE. I hated C in college. Is there a way you can post this execellent code in assembly. Thank you.

    • By Avinash - Reply

      @Will,

      Sorry but I don’t like programming in ASM.

  • By Arlen - Reply

    Mr. Gupta:

    The counter variable should be defined as type volatile.

    This is a hint to the compiler that its value can change at any time, in this case due to the ISR routine.

    Not doing so can lead to sections of code being optimized out since the compiler can think that section of code is unreachable.

    -Arlen

    • By Avinash - Reply

      @Arlen,

      NOT all variable used in ISRs need to be volatile type.
      Only those variable that are also referred (mainly read) in other parts of the code too, needs to be volatile.

  • By aredhel_vlsi - Reply

    Hello there, thank you for the useful information, I finally got what is the prescaler cause datasheet doesn’t refer to it. Well I work with PIC 18F4331 but this code does not work for me. They are different devices but the TMR0 is the same as I ve checked.
    I made some changes , please have a look and advise since I am a beginner and I desperately need help!

    I have a 10MHz oscillator, and set 1:4 prescaler.So according to the above
    FCPU=10/4=2.5 MHz
    time period=0.4 us
    prescaler period=1.6 us
    overflow period=6.4 us
    thus we need 156250 overflows to reset the timer, right? I ve tried different prescalings but nothing changed..
    I m not sure how we decide which prescaling to choose!! :64 or :256

    The only changes I ‘ve made to the code are ;

    T0PS0=1; //Prescaler is divide by 4
    T0PS1=0;
    T0PS2=0;
    T016BIT=1; //8 BIT MODE

    TRISC=0b11111111;

    if(counter==156250)
    {
    //Toggle RC3 (LED)

    if(RC3==0)
    RC3=1;
    else
    RC3=0;

    counter=0; //Reset Counter
    }

    • By aredhel_vlsi - Reply

      Xcuse me I meant the counter has to reach 2441 to overflow, my mistake, but it doesn’t work again!

    • By Avinash - Reply

      @aredhel_vlsi

      One thing you should make sure is the CONFIG bytes are written correctly.

      You should first consult the datasheet that describes the CONFIG bytes.
      Other one is the part that deals with the oscillator configuration, since you are a beginner your should read this section throughly and find out how to configure the oscillator then you need to set the CONFIG bytes accordingly. Only then you may proceed to other tutorials.

      I are done all this work but it applies to PIC18F4520 only.

      The TIMER part may then be easily ported.

      • By aredhel_vlsi -

        ok, can I ask, the configuration bits are standard for the device an Oscillator I use, right? I ve set them and my program works correctly for another code with simple delays. Its just it doesn’t work with the interrupt.
        Are my calculations right ? because the difference is not big to 18f4331 acoording to the datasheet.
        How will I choose the proper prescaler?
        Thank you

    • By Tonbra - Reply

      Friend your OVERFLOW PERIOD is wrong in that it is a product of PRESCALER PERIOD AND COUNT. i.e 1.6 x 256(8bit count) = 409.6uS.
      thus, we have
      2441 overflows in 1second

  • By cartiss - Reply

    thank alots..b4 this..im stuck at the “timer”
    now u give me clear about this timer..

  • By Panos - Reply

    Your tutorial was quite interesting and helpful,but I have a question about the timer.Can u pls tell me one practical use of timer with example??Because I am not sure if have fully understood the concept.Thank you 🙂

  • By OzzySAfrica - Reply

    Okay if any one could please help with my project,
    my limits is that i use PIC C compiler and Proteus design software for the project.
    Farmers’ Tank

    -Tank need to be filled up everyday at specific time adjustable by farmer

    -Tank level % must be displayed on the 1st line of an lcd

    -time to fill tank must be displayed on second line time to be logged for up to 40 days downloadable via rs232 port and clearing data after download

    -Use LEDs to indicate pump running , tank full, tank empty.

    -include a relay and motor to represent pump

  • Pingback: Timer0 interrupts on PIC18F4620

  • Pingback: pic timers and prescal of timers in it

  • By Avinash - Reply

    Follow the instructions properly !

  • By Kenza - Reply

    I want to use PIC 18f452 for all the things in your tutorials that is ADC, Sensor interface, LCD expansion board, timers, serial communication etc

    please tell me that what changes i have to make for running these codes (that are for PIC 18f4520) to make them run for PIC 18f452???

  • By Patrick - Reply

    Hi !

    Thanks for this tutorial. It was VERY helpfull for me to understand how these timer work. I didn’t find another tutorial as clear as yours !
    I could write my own interrupt routine and it works perfectly.
    If i understand it right, you can’t set precise timings, as it is always a combination of clock fequency and prescaler value, so approximative timer value?
    It is not possible to flag the interrupt for a precise internal counter value.

    Thanks again,

    • By Avinash - Reply

      @Patrick,

      Yes it is possible. But this is only the simplest explanation.

  • By noufal - Reply

    is this “void interrupt ISR()” only specific to hitech c. I am using micro c,
    can I use as follows?

    if(counter==76)
    myISR();

    what is the advantages/disadvantages of these two methods?

  • By noufal - Reply

    Please let me know one more thing….
    what does the following code mean? what does the function __CONFIG(a,b); actually do?

    __CONFIG(1,0×0200);
    __CONFIG(2,0X1E1F);
    __CONFIG(3,0X8100);
    __CONFIG(4,0X00C1);
    __CONFIG(5,0XC00F);

    Your work is appreciated …

  • By Tom - Reply

    Hello and thank you from France!

    Thanks to you, I understand how to use timers and implement in my project.

    I imagined that the task was daunting, but no.

    Thank you again and good luck for your future projects. 🙂

    • By Avinash - Reply

      @Tom,

      Thanks a lot !

  • By Anand raut - Reply

    thanx for valuable information………………………….

    • By Avinash - Reply

      @Anand Raut, welcome

  • By shweta - Reply

    Hello sir,

    How to use TIMER1 in PIC18f4520 for external frequency counting up to 5MHz

    • By Avinash - Reply

      @Shweta,

      There can be two different methods by which frequency can be measured.

      In first method we can count the number of peaks and wait for one second. The number of peeks counted in one second will be the frequency.

      The drawback is that this is slow(because we get data only after one whole second) and only gives us average frequency.

      But is good if the user want to display this data to humans.

      But if the data is to be used to control other parts of system. Then it may require that frequency can be calculated much faster. Like in case of a vehical fuel injection system

      In this case we need to timers. One is used as a counter for peaks and other keep tracks of time and notify us when 1 second has elapsed.

      On second method we measure the time between peaks.

  • By SUJIN C - Reply

    hello,
    In the above program why peripheral interrupts are enabled??
    PEIE=1; //Enable Peripheral Interrupt

    • By Avinash - Reply

      @Sujin, Because TIMER is a peripheral!

  • By Manu - Reply

    Hi i was adopting the same code for pic18f45k50 but i am unable to execute pls share the exact files in mplab or microc

    • By Avinash - Reply

      “pls share the exact files”

      which exact files?

  • By Rox - Reply

    I thought pic18 microcontrollers has 16 Bit Timer 0, why not use the option so that you have less interruptions in your programs.

Leave a Reply

Your email address will not be published. Required fields are marked *


× 1 = five

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>