How to Blink an Led Using PIC Microcontroller

In this tutorial we will learn How to Blink an LED with PIC Microcontroller using MPAB XC16 Compiler. Recently Microchip released a series of development tools including MPLAB X IDE and MPAB XC Compilers. MPLAB X IDE is a software that runs on a computer intended to develop applications for Microchip’s Microcontrollers and Digital Signal Controllers. It can be used with Windows, Mac and Linux Operating Systems. It is called an Integrated Development Environment as it provides comprehensive facilities to the developers. Unlike previous  versions of MPLAB, MPLAB X IDE is based on open source NetBeans IDE by Oracle.

Components Required:

  • PIC24FJ128GA106/PIC24 – 1
  • LED’S
  • Resistors
  • Pickit3
  • Breadboard – 2
  • Jumper wires

ANSEL and ANSELH

There are several registers that affect the operation of the digital I/O pins. If you look at the pin diagram you will see that pin 3 is called RA4/AN3. This is because it can serve as digital I/O port RA4 or analog input pin AN3. The two registers ANSEL and ANSELH control whether or not AN0 through AN11 are operational. Each bit in the register controls one pin as outlined in the register tables shown below. A ‘0’ sets the pin to digital mode and a ‘1’ sets the pin to analog mode. For example, if you make ANSEL equal to 0b10000001 (binary), then AN7 will be enabled and RC3 will be disabled because they share the same pin (pin 7). AN0 will also be in analogue mode (RA0 disabled). Reading a pin that is set to analog mode will return a ‘0’.

The code to set which pins are in analog mode will look something like the following:

ANSEL = 0b10000001;	//AN7 and AN0 enabled
ANSELH = 0b00000101;	//AN8 and AN10 enabled

Or we could use hex instead:

ANSEL = 0x81;	//AN7 and AN0 enabled
ANSELH = 0x05;	//AN8 and AN10 enabled

Because the pic24 have more than 12 analog inputs, you can write anything you want to the top 4 bits of ANSELH and it will have no effect. These are what the datasheet refers to as “unimplemented bits”. I’ve shown my code writing 0s to those locations.

We can also access individual bits of a register. When you include xc. h at the beginning of your code, that file includes a header file for your device. In our case, it includes pic16f690.h. This file contains all the information for the registers in our device. It also contains unions for each register with each bit (or bit range) named. For example, there is a union called ANSELbits. In ANSELbits you will find ANS0, ANS1, … , ANS7. Therefore, you can set an individual analog port as follows:

ANSELbits.ANS5 = 0;	//disable AN5

PIC I/O Register Configuration

TRISA, TRISB, and TRISC

GPIO Registers

The basic and important feature of any controllers is the number of gpio’s available for connecting the peripherals. PIC16F877A has 33-gpio’s grouped into five ports namely PORTA-PORTE as shown in the below table.

PORTDirection RegisterNumber of PinsAlternative Function
PORTATRISA6 (PA0-PA5)ADC
PORTBTRISB8 (PB0-PB7)Interrupts
PORTCTRISC8 (PC0-PC7)UART,I2C,PWM
PORTDTRISD8 (PD0-PD7)Parallel Slave Port
PORTETRISE3 (PE0-PB2)ADC

As shown in the above table many I/O pins have 2-3 functions. If a pin is used for other function then it may not be used as a gpio.

RegisterDescription
TRISxUsed to configure the respective PORT as output/input
PORTxUsed to Read/Write the data from/to the Port pins

note: Here ‘x’ could be A,B,C,D,E so on depending on the number of ports supported by the controller.

Once again, some bits are unimplemented because those pins do not exist on this device.

Code to set the data direction for the I/O pins might look as follows:

TRISA = 0b00110000;	//RA5 and RA4 are digital inputs, the rest
			//are outputs
			
TRISB = 0b10010000;	//RB7 and RB4 are digital inputs, RB6 and RB5
			//are outputs
			
TRISC = 0b00010001;	//RC4 and RC0 are digital inputs, the rest
			//are outputs

                //are outputs

RISx:TRI-State Register/ Data Direction Register
Before reading or writing the data from the ports, their direction needs to be set. Unless the PORT is configured as output, the data from the registers will not go to controller pins.

This register is used to configure the PORT pins as Input or Output. Writing 1’s to TRISx will make the corresponding PORTx pins as Input. Similarly writing 0’s to TRISx will make the corresponding PORTx pins as Output.

1.	TRISB =0xff;// Configure PORTB as Input.
2.	 
3.	TRISC =0x00;// Configure PORTC as Output.
4.	 
5.	TRISD =0x0F;// Configure lower nibble of PORTD as Input and higher nibble as Output
6.	 
7.	TRISD =(1<<0)|(1<<3)|(1<<6);// Configure PD0,PD3,PD6 as Input and others as Output

PORTx:
This register is used to read/write the data from/to port pins. Writing 1’s to PORTx will make the corresponding PORTx pins as HIGH. Similarly writing 0’s to PORTx will make the corresponding PORTx pins as LOW.
Before reading/writing the data, the port pins should be configured as InputOutput.

1.	PORTB =0xff;// Make all PORTB pins HIGH.
2.	 
3.	PORTC =0x00;// Make all PORTC pins LOW..
4.	 
5.	PORTD =0x0F;// Make lower nibble of PORTD as HIGH and higher nibble as LOW 
6.	 
7.	PORTD =(1<<PD0)|(1<<PD3)|(1<<PD6);// Make PD0,PD3,PD6 HIGH,
8.	 
9.	 
10.	TRISB =0x00;// Configure PORTB as Output
11.	TRISD =0xff;// Configure PORTD as Input
12.	PORTD = PORTB;// Read the data from PORTB and send it to PORTD.

Final code

Methode 1

// PIC24FJ128GA106 Configuration Bit Settings

// 'C' source line config statements

// CONFIG3
#pragma config WPFP = WPFP511           // Write Protection Flash Page Segment Boundary (Highest Page (same as page 85))
#pragma config WPDIS = WPDIS            // Segment Write Protection Disable bit (Segmented code protection disabled)
#pragma config WPCFG = WPCFGDIS         // Configuration Word Code Page Protection Select bit (Last page(at the top of program memory) and Flash configuration words are not protected)
#pragma config WPEND = WPENDMEM         // Segment Write Protection End Page Select bit (Write Protect from WPFP to the last page of memory)

// CONFIG2
#pragma config POSCMOD = HS             // Primary Oscillator Select (HS oscillator mode selected)
#pragma config IOL1WAY = ON             // IOLOCK One-Way Set Enable bit (Write RP Registers Once)
#pragma config OSCIOFNC = ON            // Primary Oscillator Output Function (OSCO functions as port I/O (RC15))
#pragma config FCKSM = CSDCMD           // Clock Switching and Monitor (Both Clock Switching and Fail-safe Clock Monitor are disabled)
#pragma config FNOSC = FRC              // Oscillator Select (Fast RC Oscillator (FRC))
#pragma config IESO = ON                // Internal External Switch Over Mode (IESO mode (Two-speed start-up) enabled)

// CONFIG1
#pragma config WDTPS = PS32768          // Watchdog Timer Postscaler (1:32,768)
#pragma config FWPSA = PR128            // WDT Prescaler (Prescaler ratio of 1:128)
#pragma config WINDIS = OFF             // Watchdog Timer Window (Standard Watchdog Timer is enabled,(Windowed-mode is disabled))
#pragma config FWDTEN = ON              // Watchdog Timer Enable (Watchdog Timer is enabled)
#pragma config ICS = PGx1               // Comm Channel Select (Emulator functions are shared with PGEC1/PGED1)
#pragma config GWRP = OFF               // General Code Segment Write Protect (Writes to program memory are allowed)
#pragma config GCP = OFF                // General Code Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = ON              // JTAG Port Enable (JTAG port is enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#define _XTAL_FREQ 20000000 //Specify the XTAL crystal FREQ
#define FCY 8000000UL
#include <libpic30.h>
#include <xc.h>
int main()
{
    TRISB=0X0000; //Instruct the MCU that the PORTB pins are used as Output.
	PORTB=0X0000; //Make all output of RB3 LOW
    while(1)
    {
        PORTB = 0X0001;
		__delay_ms(500);   //Wait
		PORTB = 0X0000;
		__delay_ms(500);   //Wait
 
    }
}

Methode 2

// PIC24FJ128GA106 Configuration Bit Settings

// 'C' source line config statements

// CONFIG3
#pragma config WPFP = WPFP511           // Write Protection Flash Page Segment Boundary (Highest Page (same as page 85))
#pragma config WPDIS = WPDIS            // Segment Write Protection Disable bit (Segmented code protection disabled)
#pragma config WPCFG = WPCFGDIS         // Configuration Word Code Page Protection Select bit (Last page(at the top of program memory) and Flash configuration words are not protected)
#pragma config WPEND = WPENDMEM         // Segment Write Protection End Page Select bit (Write Protect from WPFP to the last page of memory)

// CONFIG2
#pragma config POSCMOD = HS             // Primary Oscillator Select (HS oscillator mode selected)
#pragma config IOL1WAY = ON             // IOLOCK One-Way Set Enable bit (Write RP Registers Once)
#pragma config OSCIOFNC = ON            // Primary Oscillator Output Function (OSCO functions as port I/O (RC15))
#pragma config FCKSM = CSDCMD           // Clock Switching and Monitor (Both Clock Switching and Fail-safe Clock Monitor are disabled)
#pragma config FNOSC = FRC              // Oscillator Select (Fast RC Oscillator (FRC))
#pragma config IESO = ON                // Internal External Switch Over Mode (IESO mode (Two-speed start-up) enabled)

// CONFIG1
#pragma config WDTPS = PS32768          // Watchdog Timer Postscaler (1:32,768)
#pragma config FWPSA = PR128            // WDT Prescaler (Prescaler ratio of 1:128)
#pragma config WINDIS = OFF             // Watchdog Timer Window (Standard Watchdog Timer is enabled,(Windowed-mode is disabled))
#pragma config FWDTEN = ON              // Watchdog Timer Enable (Watchdog Timer is enabled)
#pragma config ICS = PGx1               // Comm Channel Select (Emulator functions are shared with PGEC1/PGED1)
#pragma config GWRP = OFF               // General Code Segment Write Protect (Writes to program memory are allowed)
#pragma config GCP = OFF                // General Code Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = ON              // JTAG Port Enable (JTAG port is enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#define _XTAL_FREQ 20000000 //Specify the XTAL crystal FREQ
#define FCY 8000000UL
#include <libpic30.h>
#include <xc.h>

#define led_on PORTB = 0X0001
#define led_off PORTB = 0X0000
int main()
{
    TRISB=0X0000; //Instruct the MCU that the PORTB pins are used as Output.
	PORTB=0X0000; //Make all output of RB3 LOW
    while(1)
    {
		led_on;
		__delay_ms(500);   //Wait
		led_off;
		__delay_ms(500);   //Wait
 
    }
}

You may also like...

Leave a Reply

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

%d bloggers like this: