Blinking an LED with a PIC Microcontroller – XC8Bitahwa Bindu
Watch the Video Tutorial
A Light Emitting Diode (LED) is a semiconductor light source, when forward biased, it emits light.
LEDs are used mainly to indicate the status of electronic circuits, for example to indicate that power is on or off but nowadays they are used in many applications including lighting and beam detection.
Early LEDs emitted low-intensity red light, but today high brightness and many colour LEDs are available (white, blue, red, green, yellow or even infrared).
LEDs have many advantages over the traditional lights (the incandescent and neon light bulbs) such as: low voltage of operation, very low energy consumption, smaller size, longer lifetime, available in many colours etc. In many energy efficient applications, the LEDs are tending to replace the traditional light source.
In this article we will learn how to connect and switch on and off various LEDs to a microcontroller using the Microchip XC8 Compiler.
This is the simplest project a beginner in embedded programming can start with before attempting any complex projects as we have learned from the Introduction to XC8 Compiler article.
An LED is similar to a diode, it has two legs: the longer leg is the anode (+) and the shorter leg the cathode (-). The cathode is also identified by a flat side on the body.
The intensity of the light emitted by an LED depends on the amount of forward current passed through the device but we must take attention not to exceed the maximum allowable forward current or draw more current than the PIC output pin can handle. A PIC can source or sink 25mA of current per Input/Output pin.
When designing an LED circuit, we have to know the typical voltage drop, table 1 below lists some few characteristics of some LEDs.
|Colour||Typical Voltage Drop||Typical Forward Current|
Table 1: Typical LEDs Characteristics
Most LEDs have a typical forward voltage drop of about 2V, with a typical operating current of around 10 mA (it is always good not to operate a device at its high end current), it’s important to read the datasheet to get the correct values.
An LED can be connected to a microcontroller in two different ways: in current sourcing mode (figure 2) or current sinking mode (figure 1).
Figure 1: LED connected in current sinking mode Figure 2: LED connected in current sourcing mode
In current sinking mode, a logic LOW (output 0) has to be applied to the connected pin for the LED to switch on while in current sourcing mode a logic HIGH (output 1) has to be applied to the pin for the LED to switch on.
The port output voltage can be assumed to be +5V when the port is at logic HIGH. Assuming that the LED is to be operated with 10mA forward current, and that it has a forward voltage drop of 2V, we can easily calculate the value of the current limiting resistor as:
As the PIC can supply up to 25mA, the current can be increased for more brightness. We are going to choose a resistance of 220Ω (forward current of about 13.6mA) in our example but a resistance of 330Ω could be also do the job very well.
To switch ON and OFF an LED all we need is:
1. Set The PORT bit Direction with the TRIS Register. 1 will make it an input and 0 an output.
TRISB = 0; //Set the whole PORTB as Output
TRISCbits.RC1 = 0; //Set PORTC.1 as Output
2. Output a LOW (to switch off) or a HIGH (switch on) to the PORT with the LAT Register.
Note that you can use the PORT Register as well it is going to work but it is not a reliable way to write to a PORT, the best way is to use the LAT. Always use the LAT if the microcontroller has it (note that the PIC 16F series don’t have the LAT register) to write to a PORT (Output a value) and the PORT to read from the PORT.
LATB = 0xFF; //Switch ON the whole PORTB
LATBbits.LATB0 = 1; //Switch ON PORTB.0
A delay function is used to create a delay in the program, if let say you need a 1 second delay between the ON and OFF of the LED, it’s easier to use a delay function to generate a 1 second.
Table 2 gives a list of the available XC8 delay functions. In MPLAB X environment, press F1 to open the help file document, search for delay to lean more. The header file “delays.h” must be included at the beginning of the program when any of these functions are used. The arguments of the functions must be an 8-bit unsigned character, i.e., the maximum allowed number in an argument is 255.
The delays are specified in terms of instruction cycle times which depend on the frequency of the clock used.
For example, when using a 4-MHz clock, the instruction cycle time is 1 µs.
In PIC microcontrollers, an instruction cycle takes four clock periods, the microcontroller actually operates at a clock rate, which is a quarter of the actual oscillator frequency. For example, in a PIC microcontroller operating at 4-MHz clock, the instruction cycle time is only 1 μs (frequency of 1 MHz).
The PIC18F series of microcontrollers can operate with clock frequencies up to 40 MHz.
|Delay1TCY||Delay in one instruction cycle|
|Delay10TCYx||Delay in multiples of 10 instruction cycles|
|Delay100TCYx||Delay in multiples of 100 instruction cycles|
|Delay1KTCYx||Delay in multiples of 1000 instruction cycles|
|Delay10KTCYx||Delay in multiples of 10 000 instruction cycles|
Table 2: XC8 delay functions
If a clock of 4MHz is used and the function Delay100TCYx(6) is called,
This will cause: 100 X 1μ X 6 = 600μS delay in the program.
To generate a 1 second delay when using a 4-MHz clock, we can call the function Delay10KTCYx(100).
With an 8-MHz clock, the required function to generate a 1 Second delay is Delay10KTCYx(200)
__Delay_ms and __Delay_us
As it is often more convenient request a delay in time-based terms rather than in cycle counts, the macros __delay_ms(x) is used to generate a delay in millisecond and __delay_us(x) is used to generate a delay in microsecond.
These macros simply convert the time based request into instruction cycles based on the system frequency.
In order to achieve this, these macros require the prior definition of preprocessor symbol _XTAL_FREQ for the oscillator frequency (in Hertz). An error will result if these macros are used without defining oscillator frequency symbol or if the delay period requested is too large. For very large delays, call this function multiple times.
Example: Using an oscillator frequency of 8MHz, generate a 1 second delay:
#define _XTAL_FREQ 8000000 // Define an oscillator frequency of 8MHz
__delay_ms(1000); //Generate 1 second delay
Example: Light Chaser
Figure 1: A typical Connection of LEDs to a PIC microcontroller
Figure 3 above shows 8 LEDs connected to PORTB, in this code the LEDs switch ON one after the other and make an impression of a light chaser:
OSCCON = 0x76; //Configure OSCON Register to use Internal Oscillator. Please check the datasheet
TRISB=0x00; // Set PORT B as Output
unsigned char Chasing_LED =1; //Declare a char variable
while (1) //Endless Loop
LATB=Chasing_LED; // Send Chasing_LED to PORT B
for (int x=0; x<=20; x++) __delay_ms(50); //Generate 1 second delay
Chasing_LED = Chasing_LED << 1; // Shift left Chasing_LED
if (Chasing_LED == 0) Chasing_LED =1;
You can download the full project files (MPLAB XC8 source code and Proteus Schematic design) below here.
Note: All the files are zipped, you will need to unzip them (Download a free version of the Winzip utility to unzip files).
Download MPLAB XC8 Project: Connecting-LEDs.X
Download Connecting-LEDs Proteus