Blink an LED with PIC18F452

13 minute read

In this post, we’ll design and build a circuit which will blink an LED controlled by a PIC18F452 microcontroller. We’ll use a power supply, 5V voltage regulator, some safety elements, signalization LED and the microcontroller with an LED we’re going to blink. After building the circuit, we’re going to program the PIC to blink the LED in regular intervals. I’ll be using the programming environment MPLABX and the PICkit3 programmer.

The hardware

What you’ll need

  • PIC18F452 microcontroller (or similar if has the same functionality)
  • PICkit3 programmer (or similar, if you know how to operate it)
  • solder-less breadboard on which the circuit will be built
  • wires for connecting
  • some tools to cut and strip the wires
  • 9V battery OR 5 or more AA batteries as a power supply
  • switch to turn the circuit on/off
  • around 100mA fuse not to fry the microcontroller in case of a short circuit.
  • diode not to fry the microcontroller in case the power supply is connected backwards
  • signalization LED to know if the circuit gets power
  • 200Ω – 1kΩ Ohm resistor in series with the signalization LED
  • 5V voltage regulator so that the PIC receives a steady 5V voltage
  • 330nF and 100nF capacitors for the voltage regulator (check this in the datasheet for your regulator)
  • 10µF capacitor to have a steady 5V supply (optional)
  • pushbutton for resetting the microcontroller
  • 10kΩ resistor for the reset mechanism
  • 20MHz crystal for timing the PIC
  • 2x 22pF capacitors for the crystal (check this in the datasheet for your crystal)
  • LED for blinking
  • 220Ω – 1kΩ resistor in series with the blinking LED

Don’t get discouraged by that long list of required parts — most of them, except the programmer and the tools are very cheap and quite easy to get from various electronics stores. I’ll explain what each of them is for when we get there. So, lets start by looking at the voltage regulator.

Parts used

Voltage regulator is needed in our circuit to control the voltage the PIC receives. If you look into the PIC18f452 datasheet, you’ll notice that it’s a 5V microcontroller, meaning that if the voltage it receives is higher or lower than 5V, it may not function properly. And since our power supply is 9V, we must use a voltage regulator to get it to 5V. You may ask why not use a 5V supply directly, and it’s because 1. it’s hard to come by a portable 5V supply and 2. its voltage would decrease over time and would soon have to be replaced. We can solve both of these problems using, say, a 9V battery connected to a 5V power supply and even if the battery’s voltage would decrease to, say, 8V, the microcontroller would still receive the 5V. And why don’t we use a 6V battery (4xAA) instead of the 9V one? Well, one of the drawback of voltage regulators is that they also have a large (around 1V) voltage drop and when we account also for voltage drops on other parts, such as the diode, we find that the total voltage drop can reach 1.5V to 2V. So, to get a steady 5V supply, we need to use at least around 7V battery. Also, when you’re going to use a voltage regulator, be sure to check the values of capacitors it needs in its datasheet. In the datasheet, there’s often a circuit of how the regulator should be wired up in a circuit. For my voltage regulator, the capacitor values are 330nF which is placed before the regulator, 100nF which is placed after it and another 10µF one which is also placed after the regulator (for the values of capacitors used with a popular “7805” voltage regulator, see page 7, Figure 1 in its datasheet.) See the schematic under the article.

Next come the safety elements, namely a switch to turn the circuit on and off; a 100mA fuse to protect the microcontroller from getting burned when there’s a short circuit; and a diode, which is another protection if you accidentally connected the power supply the opposite way. They are placed in series.

This is optional, but I’ve also chosen to use a signalization LED to see if the circuit is powered on or off. This is easily wired after the voltage has been regulated to 5V with a resistor in series so that the LED doesn’t fry. I’ve chosen a 1.6kΩ resistor so that the current will be low enough for the LED to be lit all the time but high enough for me to see it.

Now we get to the microcontroller itself. PIC18f452 is an 8bit microcontroller and has 40 pins, each having one or more functions. You can see the position and function of the pins in the PIC18f452 datasheet (section Pin Diagrams, page 3.) It’s often useful to have this pinout in front of you when making connections on the breadboard. For now, we’re only interested in pins Vdd and Vss, since these two are the power for the microcontroller and are connected to +5V and GND respectively. Don’t forget to wire up the Vdd and Vss pins on the other side of the PIC as well, otherwise the PIC will not work.

Next, we look at the pins CLKI and CLKO which are used for connecting an external oscillator, which is used for timing in the microcontroller. In my case, it’s a 20MHz crystal. When wiring the oscillator, also wire the two 22pF capacitors, each on one side of the crystal, used to remove noise. You’ll have to check the exact values of the capacitors for your crystal in the crystal’s datasheet (the tested values for capacitors are also shown in the datasheet for PIC18f452, page 18, table 2-2), but values around 11-33pF should be okay.

Now we’re going to add a reset button, which will, well … reset the execution of the program in the microcontroller. For resetting the PIC, there’s a pin called MCLR (annotated \overline{MCLR} ) which needs to be connected to +5V. If it’s is connected to GND, the execution of instructions will stop and the PIC will pause until the MCLR pin is again connected to +5V, when the execution of instructions will start from the beginning. To utilize this, I connected the MCLR to +5V through a 10kΩ resistor and also used a pushbutton, which will after it’s pressed connect MCLR to GND and the PIC will pause. During this time, +5V is connected to GND through the 10kΩ resistor, which has such a great value so that there’ll be just a small current flowing, namely I=\frac{U}{R}=\frac{5V}{10k\Omega}=0.5mA. When the pushbutton is released, the MCLR is again connected to +5V and the program is executed from the beginning.

And we come to our blinking LED, which we’ll connect to the pin RD0. Now if a pin is labeled RA, for example, the pin is a part of an 8-bit long register with pins ranging from RA0 to RA7. PIC18f452 has 4 of these registers: RA, RB, RC and RD. The pins in these registers can be used either as digital inputs or outputs and the RA pins also as analog inputs/outputs. Later on, when we’re going to program the microcontroller, we’ll set the pin RD0 to digital output, which means that it will have a +5V voltage. To this pin, we now connect the cathode of the LED we want to blink and connect the LED’s anode through a, say, 220Ω resistor to GND.

Finally, we need to make a pinout on the solder-less breadboard to correspond with the pinout for the PICkit3 (it can be found in the PICkit3’s datasheet; figure 1.2, page 11.) So, from right to left, we connect the 6 pins as follows: 1-MCLR, 2-Vdd, 3-Vss, 4-PGD, 5-PGC, 6-nothing. We’ve talked about the first 3 pins, the 4th pin PGD is used for data transfer, the 5th pin PGC is used for clock and we don’t connect the 6th pin to anything (according to the datasheet, it’s used for low-voltage programming which we’re not going to use.) Later on when we’ll be programming the PIC, the PICkit3 programmer will be connected to these pins and will be used to connect the microcontroller to the computer.


Schematic for a circuit to blink an LED

The software

First, we’re going to install the environment in which we’ll be programming. I’ve chosen MPLABX since its from the same company which develops the microcontrollers, so there should be no compatibility issues. So, head to Microchip’s website and download MPLABX IDE for your platform and install it. We also need to install the compiler for the type of microcontrollers we’re going to program, so from the same website download and install the MPLAB XC8 compiler, which is used for 8-bit PICs. The last thing needed is a tool called programmer which we’ll use to program the microcontroller from the MPLABX environment. I’ve chosen the PICkit3 programmer, since, again, it’s from the same company that makes the PICs so there should be no compatibility issues.

Create project

Now we can open MPLABX and create a simple project which will contain the program for blinking the LED. From menu, select “File > New Project…”. In the 1st step, “Choose Project”, from “Categories” select “Microchip Embedded” and from “Project” choose “Standalone Project”. In the 2nd step, “Select Device”, in “Family” select “Advanced 8-bit MCUs (PIC18)” and from “Device” select the microcontroller you’re going to program — “PIC18F452”. In the 4th step (the 3rd was skipped), “Select Tool”, choose the compiler you want to use — I’ve chosen “Hardware Tools > PICkit3”. In the 6th step (5th was skipped), “Select Compiler”, choose the XC8 compiler you have installed — “Compiler Toolchains > XC8 > XC8”. Finally, in the 7th step, “Select Project Name and Folder”, choose the name for the project, such as “HelloWorld” and leave the project location as is. After you click “Finish”, the project is now created.

Next, create a main C file where we’ll write the code by right-clicking on the project “HelloWorld” in the left project explorer and selecting “New > C Main File…”. As “File Name” type “main” or whatever you wish, leave the rest as is and click “Finish”. Now you should see a new C file added to the project explorer under “HelloWorld” project.


When you open the file, you can see that some content has been auto-generated. The stdio.h and stdlib.h libraries are already included but we need also to include the XC8 compiler library using

#include <xc.h>

We also need to tell the program how fast is the crystal in Hz — so my 20MHz crystal will have a value of 20000000:

#define _XTAL_FREQ  20000000

And now we need to define some processor directives, which are used to modify the behavior of the PIC. First, we set the speed of the crystal (oscillator) to high-speed (“HS” value). Depending on the frequency of your crystal, there are also other possible values like “LP” or “XT”. You can find which speeds of crystal correspond to which OSC setting (again) in the PIC’s datasheet (page 17, table 2-2.)

#pragma config OSC = HS

We also turn off the watchdog timer, which is a “feature” used in more complicated programs to prevent the program from getting stuck. When it’s turned on, every few milliseconds we have to report to the program that we’re still running otherwise the program will automatically reset itself. But for our purposes it would just complicate the work so we turn it off.

#pragma config WDT = OFF

And finally, we’re also going to turn off the “low voltage programming” feature. (I’m not sure if this is true, but I’ve read somewhere that LVP is used when we want to have low voltage (~5V) on the ISCP pin instead of the default high voltage (~13V) generated by the programmer; but since the higher voltage on ISCP pin doesn’t damage anything, it’s more beneficial to turn it off and be able to use the PGM pin which would be used when LVP is turned on.)

#pragma config LVP = OFF

Write program

With these directives out of the way, we can proceed to writing the program itself. To blink an LED, we’ll first need some function which will wait between the on and off states of the LED. The supplied __delay_ms() function is, for some strange reasons, only restricted to some small values around hundreds of milliseconds and if it’s used with higher values, it will produce a compiler error. So, we’ll create our own function called delay_ms() (without the initial underscores) which we’ll supply with the number of milliseconds to wait and it will call that many times the supplied __delay_ms() function with a parameter of 1. Since the __delay_ms() function will be called in the cycle always with a parameter of 1, no compiler error will be produced and we will be able to use times larger than some hundreds of milliseconds. Here’s the function:

void delay_ms(int ms) {
    for(int i = 0; i &lt; ms; i++) __delay_ms(1);

Now we will write the code for blinking the LED into the generated main() function. When we look at our diagram, we can see that the LED is connected to pin RD0, which is part of the 8-bit D register. So, in the program we first need to tell the microcontroller that the RD0 pin will be an output and not an input pin. This is done by writing into the TRIS — if the value written is 0, the pin is an output pin and if it’s a 1, it’s an input pin. To set our RD0 pin to output, we write the following:

TRISDbits.TRISD0 = 0;

or by writing the following, which is the same instruction:

TRISDbits.RD0 = 0;

Now, to continually blink an LED we’ll have an infinite for loop which will turn the LED on, wait some time, turn it off and again wait some time. To turn the LED on, we need to set the value of the RD0 pin to 1, which will cause it to have a voltage of +5V and to turn it off, we set it to 0 which will cause 0V. We can set these values by writing into the LAT register, which is used for setting the values for pins. To set the pin to +5V, we write:

LATDbits.LATD0 = 1;

or the following, which has the same effect:

LATDbits.LD0 = 1;

After the LED is turned on, we need to wait some time, let’s say half a second, using our new delay_ms() function, where we’ll supply as argument 500ms:


Then, we turn the LED off by writing 0 to the LAT register:

LATDbits.LATD0 = 0;

And again we wait half a second:


And that’s it! The final program should look like the one below:

#include <xc.h>

#pragma config  OSC = HS     // High-Speed oscillator
#pragma config  WDT = OFF    // Watchdog timer OFF
#pragma config  LVP = OFF    // Low-voltage programming OFF

#define _XTAL_FREQ  20000000 // 20MHz crystal

void delay_ms(int ms){
    for(int i = 0; i < ms; i++) __delay_ms(1);

int main() {

    TRISDbits.TRISD0 = 0;

    while(1) {
        LATDbits.LATD0 = 1;
        LATDbits.LATD0 = 0;

    return 0;

Program the PIC

Now, we first build the program by clicking the hammer icon in the top of MPLABX and if all went well, somewhere at the end of the output you should see a line “BUILD SUCCESSFUL”. If this is the case, we can proceed to the programming of the microcontroller. Now you can power the circuit and connect your PICkit3 programmer to your computer and the other side to the prepared 6 pins as seen in the schematic. If there’s no smell from burning, you may continue and hit the “make and program device” icon in shape of an arrow over a microcontroller, positioned next to the build icon. During the programming of the microcontroller, you’ll be asked to confirm whether the device you’re about to program is the same one which is in the circuit. If it is, click the button and wait till the programming process is over. If you see a success message, you can remove the programmer from the circuit and should see an LED blinking in half-second intervals. Congratulations!

In the next post, I’ll show you how to connect a 7-segment LED display and make it to show numbers from 0 to 9 which will later be used for calibrating an IR sensor.

Finally, I would like to thank my former classmate Martin Holicky who introduced me to the basics of PIC microcontrollers. Many of the ideas in this post come from him.


Leave a comment