«

»

Jan 26

Getting Started with PIC Microcontrollers – The Header File

This time we’ll have an in depth look at a specific area which can present problems for the beginner. Using the simple code presented in Getting Started with Microcontrollers as our example. we will talk a bit about the main xc.h header file, how it works, and how important it is. Understanding this file, and how the registers are mapped to the names we use in the code is very important, will help you form a clearer picture of what is happening behind the scenes, and can save you a lot of debugging time later on. 

Okay, let’s jump right in, here is the previous code for reference:

/* 
 * File:   led_blink.c
 * Author: Oli Glaser
 *
 * Created on 02 January 2013, 06:59
 */

// main include file - this contains all the "friendly names"
// for the pins and peripherals
#include <xc.h>
// Turn the Watchdog Timer off
#pragma config WDTE = OFF 

void delay(int d); // This is the prototype declaration for the Delay function

int main(int argc, char** argv) {
   
    TRISBbits.TRISB6 = 0; // This sets pin RB6 to output
    
    while(1) // Infinite loop
    {
        PORTBbits.RB6 = 1;  // Set RB6 pin to logic high (5V)
        delay(500);         // Delay for roughly 500ms
        PORTBbits.RB6 = 0;  // Set RB6 pin to logic low (0V)
        delay(500);         // Delay for roughly 500ms
    }
    
}

// Delay routine
void delay(int d)
{
    int i;  // Declare variable to be used in the loop

    while(d)    // While d > 0
    {
        i = 100;    // set i to 100 for inner loop
        while(i)    // while i > 0
        {
            i--;    // decrement i (e.g. i will equal 99, 98, 97,...)
        }

        d--;    // decrement d
    }
}

 

Some of you may wonder why the main routine has a return value and argument options, since they are never used in firmware such as this (i.e. the code is executed automatically on power up and never exits) This is simply the default template MPLABX starts you off with when you begin a new project, and conforms to the standard ANSI C entry point. You could also use for example: int main(void) if you wish, but I just leave it as it is.

The main header file

Now for a very important issue, and one which causes many beginners much frustration – the main header file <xc.h>. This header file is a global header that will point to another header file in turn, and eventually point to the header file for the particular part you are using. This contains the friendly names for all the registers (e.g. Ports, Peripherals, etc) in your device, and allows you to type things such as PORTB = 0;

Let’s examine this in detail, and follow the header file “trail” to find out how it does this. To do this, highlight  <xc.h> right click and select Navigate->Go to Declaration as shown below:

MPLABX_GotoImp 

Now, the xc.h file should open in your editor:

#ifndef _XC_H_
#define _XC_H_

#ifdef __XC8
#include <htc.h>
#endif

#endif        //_XC_H

You will notice there is not a lot there, apart from a couple of preprocessor commands, one makes sure that _XC_H_ is defined, and the other includes <htc.h> if __XC8  is defined, which it will be since we are using the XC8 compiler. So let’s follow <htc.h> and see where that leads; use exactly the same method as described above, and you should find this code:

#ifndef _HTC_H_
#define _HTC_H_

#if defined(__CCI__) && !defined(_XC_H_)
#warning "CCI projects should use the top-level support file xc.h\nIncluding xc.h instead"
#include <xc.h>
#endif

/* Definitions for _HTC_EDITION_ values */
#define __LITE__ 0
#define __STD__ 1
#define __PRO__ 2

/* common definitions */

#define    ___mkstr1(x)    #x
#define    ___mkstr(x)    ___mkstr1(x)



/* HI-TECH PICC / PICC-Lite compiler */
#if    defined(__PICC__) || defined(__PICCLITE__)
#include <pic.h>
#endif

/* HI-TECH PICC-18 compiler */
#if    defined(__PICC18__)
#include <pic18.h>
#endif

/* MPLAB C18 Compatibility Header */
#ifdef __18CXX
#include <pic18.h>
#endif

/* HI-TECH dsPICC compiler */
#if    defined(__DSPICC__)
#include <dspic.h>
#endif

/* HI-TECH C for PIC32 */
#if defined(__PICC32__)
#include <pic32.h>
#endif

#endif

Okay, there’s a bit more here, but it still is not the header file we are looking for. Essentially, it is checking to see which compiler is being used and including yet another header based on what it finds. In our case, it is the __PICC__ or __PICC_LITE__ compiler which has already been defined, so we follow <pic.h> (you can tell which code is being used as the unused code will be greyed out, whilst the <pic.h> should be highlighted). Now we get to another file which includes <pic_chip_select.h> and <eeprom_routines.h>. Follow the <pic_chip_select.h>  header, and we are finally getting somewhere – this is a huge file that checks for the particular part you are using (defined automatically when you select the part during project setup) and includes the header that contains all the important definitions mentioned at the start. Depending on your part, you will see one of the related sections highlighted. I used the PIC16F690 for the first tutorial, so scanning the file, about halfway down I come across this highlighted code:

PIC_Include  

Now if we look in pic16f690.h (or whatever the header file for you part is), we will see a very long list of defintions which map the addresses of the registers to the “friendly names” we use in our code. Since we used PORTB in our code, lets take a look at the definition for this in the file:

// Register: PORTB
extern volatile unsigned char           PORTB               @ 0x006;
#ifndef _LIB_BUILD
asm("PORTB equ 06h");
#endif
// bitfield definitions
typedef union {
    struct {
        unsigned                        :4;
        unsigned RB4                    :1;
        unsigned RB5                    :1;
        unsigned RB6                    :1;
        unsigned RB7                    :1;
    };
} PORTBbits_t;
extern volatile PORTBbits_t PORTBbits @ 0x006;
// bitfield macros
#define _PORTB_RB4_POSN                                     0x4
#define _PORTB_RB4_POSITION                                 0x4
#define _PORTB_RB4_SIZE                                     0x1
#define _PORTB_RB4_LENGTH                                   0x1
#define _PORTB_RB4_MASK                                     0x10
#define _PORTB_RB5_POSN                                     0x5
#define _PORTB_RB5_POSITION                                 0x5
#define _PORTB_RB5_SIZE                                     0x1
#define _PORTB_RB5_LENGTH                                   0x1
#define _PORTB_RB5_MASK                                     0x20
#define _PORTB_RB6_POSN                                     0x6
#define _PORTB_RB6_POSITION                                 0x6
#define _PORTB_RB6_SIZE                                     0x1
#define _PORTB_RB6_LENGTH                                   0x1
#define _PORTB_RB6_MASK                                     0x40
#define _PORTB_RB7_POSN                                     0x7
#define _PORTB_RB7_POSITION                                 0x7
#define _PORTB_RB7_SIZE                                     0x1
#define _PORTB_RB7_LENGTH                                   0x1
#define _PORTB_RB7_MASK                                     0x80

Now we can see how it works. Don’t worry if you don’t fully understand it, you don’t need to in order to use it, but it helps to know where these definitions are and why the compiler will complain if it can’t find them. For further reading check the XC8 Compiler User’s Guide (this will also be on your computer under the Microchip->MPLAB XC8 folder). We won’t fully cover all the above code (General C books, PIC specific C books, and the users guide mentioned cover all this), apart from the most important part of it:

// Register: PORTB
extern volatile unsigned char           PORTB               @ 0x006;

Note the @ 0x006; part of this code. This points the PORTB declaration to a specific address in the microcontrollers memory. If we check the PIC16F690 datasheet and look at page 31, we will see a table of the Special Function Registers and their addresses:

PIC16F690Registers

Note that PORTB is at address 06h, as defined in the header file. If you check the other registers you will see they will all correspond with the datasheet table.

Hopefully the above has helped to show how important the main header file is, and how the code connects with the hardware. This brings us on to the last part of this tutorial; making sure your tools know where to look for the header file. Firstly, click on the spanner icon in the “Dashboard” at the bottom left hand of your screen. This brings up the Project Properties dialog box. Select compiler properties, pre-processing and messages in the dropdown and in the include directories box, you need to point to the folder which contains the compiler include files:

IncludeDir

Usually it’s under something like C:\Program Files\Microchip\xc8\v1.12\include as shown in the clip, but it may be different if for example, you chose another install directory or Microchip decides to rearrange things in the near future.

13 comments

1 ping

Skip to comment form

  1. jayanath

    dear sir request provide c code for 12 led chaser with comet tail effect i mean followed led to be faded and off for any suitable pic. jaya19995@gmail.com

    1. Oli G

      Hi Jaya – hopefully I will be able to commit a lot more time to the blog shortly, so I will try and post something that you (and others) should find useful.
      If you can be a bit more specific about the pattern and timing for the LEDs it would help me get as close as possible to the effect you seek.

  2. Afiq

    can this header use for pic16f1455?

    1. Oli G

      Yes, provided you are using the XC8 compiler, it should work fine.

      1. Anonymous

        what are the header files used for pic16f690?

        1. Oli G

          It depends on the compiler, though they are all pretty similar just with different syntax.
          For the XC8 compiler, the header file is as explained in the text. Let me know if you still have trouble finding it
          and I’ll link a copy here.

  3. sunil kumar nk

    hi,
    sir nice information… I am interested in using XC8 compiler. But I didn’t get how we can manually highlight the grayed codes inside a specific Library file? for example: in relation with i2c.h file the library file i2c_open.c shows like below.

    #include
    #include

    /********************************************************************
    * Function Name: ReadI2C *
    * Return Value: contents of SSPBUF register *
    * Parameters: void *
    * Description: Read single byte from I2C bus. *
    ********************************************************************/
    #if defined (I2C_V1)
    unsigned char ReadI2C( void )
    {
    if( ((SSPCON1&0x0F)==0x08) || ((SSPCON1&0x0F)==0x0B) ) //master mode only
    SSPCON2bits.RCEN = 1; // enable master for 1 byte reception
    while ( !SSPSTATbits.BF ); // wait until byte received
    return ( SSPBUF ); // return with read byte
    }
    #endif
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    But the function unsigned char ReadI2C( void ) is always in gray… How can I enable this?by this reason I can’t write a code using library functions. I’m using PIC18f4550. will you Please replay any solution?

    Thanks
    sunil
    India

    1. Oli G

      Hi Sunil,

      I’m very sorry for the late reply.

      The reason the code is greyed out is because it is enclosed by an #if defined section. This means that unless (in this case) I2C_V1 is not defined, then the preprocessor will ignore this section of code up to the #endif point.
      If you wish to use this and other routines enclosed with this define, then you need to add:
      #define I2C_V1
      somewhere in your code, e.g. at the top of your main.c or configuration header file.
      For more info, check the XC8 compiler manual (or indeed any decent C book) and see the preprocessor section.
      If you have any more questions on this or I2C in general, just let me know (I will be doing pages on I2C, SPI and other protocols as I go along)
      Best Regards,
      Oli

  4. Ahmad Tahir

    Can we use this header file for pic18f452?

    1. Oli G

      Yes, as long as you are using the XC8 compiler (downloadable from Microchip’s website) the xc.h header file will cover all Microchips 8-bit range (there may possibly be some old/obsolete parts not covered, but there is a list on their website and also the pic.h file (as mentioned above) will list all the parts covered.
      For the PIC18F452, it’s definitely yes.

  5. raja

    hi i am new to PIC. i am using pic18f26k80 with xc8 compiler….

    i want to connect HCSR04 ultrsonic sensor .

    please tell me code for above sensor….
    thanking you…

  6. Luke

    Thanks for this tutorial Mplabx was doing my head in with the xc8 compiler not finding the header file.

  7. Andrew Wilkes

    Your post helped me figure out what was going wrong with the latest MPLAB X with the C compiler – thanks. It seems that the IDE thinks that the header file xc.h that includes all the chip defines cannot be found and the tokens cannot be resolved, but this is not the case. The build succeeds ok. Just the IDE has this bug that has been known for a few years but not yet/ever fixed.

Leave a Reply

Your email address will not be published.

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>