Tutorial 4 – “Hello World” Program in C
Since the assembly tutorials went up, I’ve had a large number of requests for PIC18F tutorials in C. In this tutorial, I will explain the basics of PIC18F C programming and provide simple sample code for a blinking LED, similar to tutorial 2. If I receive positive feedback, more tutorials will follow. This tutorial assumes minimal understanding of C programming.
I will be working with the following until further notice:
- PIC18F4550
- PicKit 2
- MPLAB IDE V8.40
- MPLAB C for PIC18 v3.34 in LITE mode – A free compiler for the 18 series PIC microcontrollers
The installation procedure is as follows:
- Install MPLAB IDE. The default settings should be fine. Hi-Tech C may or may not be covered in future tutorials, but installing it does not take much space.
- Install MPLAB C compiler (C18).Most of the default settings should be fine, but make sure to select the “Update MPLAB IDE to use this MPLAB C18″ installer option.
- Start MPLAB IDE (Start -> All Programs -> Microchip -> MPLAB IDE v8.40 -> MPLAB IDE).
- Make sure the project and output windows are open in the IDE by going to the view menu and clicking the appropriate options.
- Select your microcontroller in the Configure -> Select Device menu. This area will also show you all the compatible programmers for that device.
- Select the programmer by clicking Programmer -> Select Programmer.
- If your programmer is plugged in, it should display an initialization routine in the output console.
- You may also need to upgrade the firmware on it.
Your overall setup should look like this:

Now it’s time to start a new Project:
- Click Project -> Project Wizard
- Select your device on page 2, if it isn’t already selected
- On page 3, select Microchip C18 Toolsuite. If any items in Toolsuite Contents have a red X, select them and click Browse. The default locations for the files are:
- MPASM Assembler – C:\MCC18\mpasm\mpasmwin.exe
- MPLINK Object Linker – C:\MCC18\bin\mplink.exe (Make sure you do not select _mplink.exe)
- MPLAB C18 Compiler – C:\MCC18\bin\mcc18.exe
- MPLIB Librarian – C:\MCC18\bin\mplib.exe
- On page 4, click Browse and select the name and location of your new project (example: My Documents\PIC\tutorial4\tutorial4.mcp)
- Do not add any existing files to the project since this project will be made from scratch
- Once the project is created, you should be able to see the empty project folders in the project window
Open a file, add the header file for your PIC and save it: Click File -> New.
Add the line
Type
#include <p18f4550.h>
with the appropriate include file for your microcontroller.
The C18 compiler provides a header file with definitions for ports and pins for each microcontroller it supports. The default directory for these files is C:\MCC18\h . For example, the 18F4550 file includes the following code:
extern volatile near unsigned char PORTB;
extern volatile near union {
struct {
unsigned RB0:1;
unsigned RB1:1;
unsigned RB2:1;
unsigned RB3:1;
unsigned RB4:1;
unsigned RB5:1;
unsigned RB6:1;
unsigned RB7:1;
};
struct {
unsigned INT0:1;
unsigned INT1:1;
unsigned INT2:1;
};
struct {
unsigned :5;
unsigned PGM:1;
unsigned PGC:1;
unsigned PGD:1;
};
} PORTBbits;
This code shows the various ways of addressing PORT B pins. For example, they can be addressed as a byte by PORTB, or as individual pins by the union PORTBbits using PORTBbits.RB0 through PORTBbits.RB7. When set up as interrupts, pins 0-2 should be accessed as PORTBbits.INT0 through PORTBbits.INT2.
After adding the include line to the new file, it is time to save it. Click File -> Save and save it in the project folder (it will be saved as main.c for this tutorial). Then, either check “Add File to Project” at the bottom of the save screen or add this file to your project by right clicking Source Files in the Project window and clicking Add Files.
Add an empty main function to your project to make main.c look like this:
#include <p18f4550.h>
void main()
{
}
Now is a good time to try to build the project. Click Project -> Build All. In the Output window, it will say BUILD FAILED. If you scroll up, you will see that the reason for the error is:
main.c:1:Error [1027] unable to locate 'p18f4550.h'
To fix this error, the include directory for the project must be specified. To do this, click Project -> Build Options -> Project. Click the Directories tab and select “Include Search Path” from the drop-down menu. Add the include directory by clicking New, then the ellipsis. The default directory for the header files, as mentioned above, is C:\MCC18\h. Also, make sure to specify the Library Search Path (default: C:\MCC18\lib) and the Linker-Script Search Path (default: C:\MCC18\bin\LKR). Now, building should return BUILD SUCCEEDED.
Next, we will configure the microcontroller. Several very useful documents are included with C18 to facilitate the learning process. By default, these files can be found in C:\MCC18\doc. The following files are included with C18 V3.34:
- hlpC18Lib – An overview of the MPLAB C18 library files and functions that can be included in an application. These files can be divided into 3 sections:
- Peripherals
- Character LCDs
- CAN bus
- I2C
- SPI
- UART
- General
- Character Classification (ex: isalpha(), isupper(), isprint())
- Data Conversion (ex: atoi(), itoa(), rand())
- Memory and String Manupulation (ex: memset(), strcpy(), memcpyram2pgm())
- Delay (ex: Delay1TCY() – 1 cycle delay, Delay10KTCYx() – delay for multiples of 10K cycles)
- Reset (ex: isBOR(), isMCLR() – find out cause of reset)
- Character Output (ex: sprintf(), usart_putc())
- Math Libraries (ex: sin(), cos(), log())
- hlpC18ug – The technical details of the C18 compiler, including data types, pragmas, memory models, etc. This is very useful to really understand what you are doing.
- hlpCOFFfile – Describes the format of the executable file created by the compiler
- hlpPIC18ConfigSet – Describes the configuration settings (using #pragma config) for all supported microcontrollers. We will be looking at this file.
- MPLAB-C18-Getting-Started_51295f – A guide to getting started with C18. A highly recommended read.
- PIC18F Peripheral Library Help Document – Describes the peripheral library for all supported microcontrollers. To view the library details, select the appropriate family and device, then click “CLICK HERE for the Peripheral Library Support Details for this Device”
Open hlpPIC18ConfigSet.chm and find PIC18F4550 (or your respective microcontroller). This document lists all the configuration settings available for it. Right now, we will only configure the ones necessary for this tutorial to work. First and most important are the Oscillator Selection bits. Without this, the microcontroller will do nothing. To set the microcontroller to use the internal oscillator (1MHz or 250,000 instructions/second since each instruction takes 4 cycles), add the following code directly after the include directives:
#pragma config FOSC = INTOSCIO_EC //Internal oscillator, port function on RA6, EC used by USB
The watchdog timer also needs to be disabled. Config values can be written one per line or separated by commas. For the sake of clarity, they will be listed on separate lines in this tutorial. To disable the WDT, add the following line:
#pragma config WDT = OFF //Disable watchdog timer
The physical setup is similar to the one in Tutorial 2:

5V — 1KOhm — LED — (20)
According to the 18F4550 Datasheet, pin 20 is PORT D Pin 1.
The datasheet states that each port has three registers for its operation. These registers are:
- TRIS register (data direction register 0 – output, 1 – input)
- PORT register(reads the levels on the pins of the device)
- LAT register(output latch)
In other words, use the PORT register for input operations, the LAT register for output operations and the TRIS register to select between input and ouput on each individual pin. To control an LED using PORT D Pin 1, it will first be set to output using the TRIS register and then be toggled on and off using the LAT register.
A #define statement can make the code much more readable. Add these lines after the #pragma config statements:
#define LEDPin LATDbits.LATD1 //Define LEDPin as PORT D Pin 1
#define LEDTris TRISDbits.TRISD1 //Define LEDTris as TRISD Pin 1
In main, make PORT D Pin 1 an output and set it HIGH:
LEDTris = 0;//Set LED Pin data direction to OUTPUT
LEDPin = 1;//Set LED Pin
The last step is to add a loop that toggles the pin at an interval:
while(1)
{
LEDPin = ~LEDPin;//Toggle LED Pin
Delay10KTCYx(25);//Delay 250K cycles (1 second at 1MHz since each instruction takes 4 cycles)
}
The Delay10KTCx() function and other delay functions are documented in hlpC18Lib.chm in the C18 documentation directory (see above). You will need to add the following line to the top of your file:
#include <delays.h>
Now, you should be able to test it on the microcontroller:
- Click Project -> Build All
- Click Programmer -> Program
- If the above two steps were successful, Click Programmer -> Release From Reset
You should now see your LED blinking on and off about once per second. Congratulations, you have completed this tutorial!

Please provide feedback in the form below!
Files:
C file:main.c
Project:tutorial4.zip