Programming PIC 18 using XC8 (MPLAB X) : Timers

Remember the first GPIO post where we used the function __delay_ms() function? That’s a bad way to use delay. It will get the job done, but in a not so effective way. What happens when you call __delay_ms() function is, the controller will execute NOP() (which means No OPeration). But still NOP is an instruction, which means your controller is doing something, but nothing useful. If you can use that time to do some other operations, that will be awesome. If there are no operations to be done, at least put the controller to sleep, so that you will save some battery life.

With XC (and with pervious C18) compiler, we have a header file called “timers.h”. The header timers.h gives us the functions to reduce the number of lines of code. I strongly suggest read the datasheet and compiler documentation.

Since I am using PIC18F4550, there are 4 timers according the datasheet (from 0 – 3). I will be using Timer0 to blink a LED at 1Hz (on/off a second).

I have the following functions to configure and run the timer using timers.h

void OpenTimer0 ( unsigned char config); void CloseTimer0 (void); unsigned int ReadTimer0 (void); void WriteTimer0 ( unsigned int timer0);

 

Step 1: Configure Timer0 (fill the config variable with settings)

Step 2: Enable interrupts (yes, we like to create an interrupt when timer reaches the limit)

Step 3: Configure the interrupt and start running the program.

timmer

The picture from the screenshot will give you an insight of our configuration setup.

An interrupt will happen when the timer overflows. So, when I say open timer, the timer will start counting from 0,1,2……….0xFF (for 8 bit timer) or 0xFFFF (for 16 bit timer). So an interrupt happens at 0xFF for 8 bit and 0xFFFF for 16 bit timer.

Please read the peripheral library documentation. Haven’t heard of it? (Its really bad of not reading documentation of a device or its development tools) well, when you install the compiler XC8 (or C18) you will find it in your C:\Program Files (x86)\Microchip\xc8\<compiler version>\docs. Also go through C:\Program Files (x86)\Microchip\xc8\<compiler version>\include\plib to find the available peripheral libraries and their code.

 

Note : When you use WriteTimer0(); function, please use HEX values as arguments. Like WriteTimer0(0xE17B); The program I’m going to show down is a 1 second timer based on timer0 and using interrupts.

for 8MHz oscillator and 256 prescalar, the effective instruction execution speed is (4*256)/8×106 which will give you 128uS (micro second) per instruction. So for 1 second 7812.5 (it is 1/128uS). Since we know interrupt happens only when the timer buffer overflows, for a 16 bit timer the preset value to achieve 1 second for overflow will be 65535 – 7813(roundup 7812.5)  =  57723 which in HEX will be 0xE17B.

Now here is the code

#define _XTAL_FREQ 8000000 //The speed of your internal(or)external oscillator #define USE_AND_MASKS #include <xc.h> #include "config.h" #include <plib/timers.h> int i = 0; unsigned char Timer0Config; void SetupClock(void); void main(int argc, char** argv) { SetupClock(); // Internal Clock to 8MHz TRISBbits.RB4 = 0; //set RB4 as output LATB4 = 1; //Make RB4 high when the program starts Timer0Config = TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_256 ; OpenTimer0(Timer0Config); WriteTimer0(0xE17B); //Please use HEX. Decimal don't work INTCONbits.TMR0IF = 0; //reset Interrupt Flag ei(); // This is like fliping the master switch to enable interrupt while(1) //infinite loop { } } void SetupClock() { OSCCONbits.IRCF0 = 1; OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF2 = 1; } void interrupt TimerOverflow() { if(INTCONbits.TMR0IF == 1) { LATB4 = ~LATB4; INTCONbits.TMR0IF = 0; WriteTimer0(0xE17B); //Please use HEX. Decimal don't work } }

Author: singularengineer

12 thoughts on “Programming PIC 18 using XC8 (MPLAB X) : Timers

    1. In peripheral library document located at C:\Program Files (x86)\Microchip\xc8\\docs\pic18_plib.pdf, you will see that you can use either AND_MASK or OR_MASK to set your configuration for your peripherals like USART, Timer etc.

      Using AND_MASK = UART1Config = USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_BRGH_HIGH ;
      Using OR_MASK = UART1Config = USART_TX_INT_OFF | USART_RX_INT_OFF | USART_ASYNCH_MODE & USART_EIGHT_BIT | USART_BRGH_HIGH

      Please read the documents. Also open your usart.h file and look into it. You can clearly see how the AND OR mask’s are being implemented.

      ~SE

  1. Dear Boss,
    There is my code.I want to make delay of 1 second in RB4.But it cant…..I ve found this code in PIC Microcontoller by M Ali Mazidi.I also read the docs….but it seems to me difficult to unnderstand.

    #include
    #include “config.h”
    //#include

    #define _XTAL_FREQ 20000000 //The speed of your internal(or)external oscillator
    //#define USE_AND_MASKS
    #define mybit PORTBbits.RB4
    void T0Delay(void);

    void main(void)
    {
    TRISBbits.TRISB4 = 0;
    while(1)
    {
    mybit = ~mybit;
    T0Delay();
    T0Delay();
    }
    }
    void T0Delay(void)
    {
    T0CON = 0x07;
    TMR0H = 0xB3;
    TMR0L = 0xB3;
    T0CONbits.TMR0ON = 1;
    while(INTCONbits.TMR0IF == 0);
    T0CONbits.TMR0ON = 0;
    INTCONbits.TMR0IF == 0;

    }

    1. T0CON, he sets the timmer 0 control register (what he’s setting – read the datasheet)
      TMR0H, TMR0L = setting the register values
      T0CONbits.TMR0ON = 1; – turn on the timer
      while(INTCONbits.TMR0IF == 0); – wait till overflow happens and the interrupt flag is set (this is were the 1 second delay happens)
      T0CONbits.TMR0ON = 0; – turn off the timer
      INTCONbits.TMR0IF == 0; – clear the interrupt flag

      Datasheet teaches you everything. read, read, read.

    1. The keyword interrupt before the function TimerOverflow tells the compiler that this is the function that has to be called when an interrupt happens (timer, uart or any interrupt). You can rename the TimerOverflow to any name and still it will be called because of the keyword interrupt before the function name.

      “interrupt” is a keyword. Read page no 189 http://ww1.microchip.com/downloads/en/DeviceDoc/52053B.pdf (compiler documentation).

      I think you might be working for a class or something. If you don’t read documentations you ain’t going any further bro. Just read, read and read.

  2. I am having the same doubt as SJK. I was trying to understand AND_MASK and OR_MASK by reading the peripheral library docs. One thing I am not understanding is If we are using bitwise “&” and “|” operators in the program what is the use of defining the macros? and it is also mentioned in the peripheral library docs that we have to use the OR_MASK macro at the beginning of the application prior to inclusion of library. But here we used the macro after inclusion of library. Is it only applicable for OR_MASK?

  3. You’re a legend – thanks for these great tutorials! 😀 I’m finally making the move from Arduino and I’ve been getting a little lost so your site has been very helpful! 🙂

Leave a Reply

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