Step 6: Programming

At this point, we'll be working exclusively with the MPLAB X IDE. To get started, notice the panel titled Projects on the left side of the MPLAB IDE window. From this panel, create a code:

Right-click on the 'Source Files' folder listed below your project>New>C Main File

Feel free to name it as you wish ('Main' is fine) You'll now see that MPLAB X has created a main file, visible in the center panel.

Code: For the purposes of this tutorial I will provide the necessary code, which you can copy and paste into that center window (after deleting all other text in the file) To give you an idea of what the code is doing, I've included a brief overview below as well as comments within the actual code itself (pasted below)

Overview: There are a couple of distinct portions of code for programming a PIC microcontroller, which are outlined below.

Define Statements: Define statements allow programmers to use words that may mean something else to the computer. For example, we could define the word OFF to mean a binary '0'. Thus while we see the word off, making the code easier to understand, the computer reads a binary '0'.

Include Statements: Include statements tell the compiler to include various header files. These external files may consist of files that define input/output functions (stdlib.h), or a variety of standard C functions (stdio.h), etc.

Pragmas: Pragmas are used to set the configuration bits on the microcontroller which control aspects such as oscillator selection, code protection, etc. Feel free to check out the configuration bits be selecting Window>PIC Memory Views>Configuration Bits

Functions: Functions are sections of the program that perform specific tasks. The main function is where the program starts execution.



How to program a PIC & read an encoder program

Last Revised: 1/3/14
Authors: Carson Miller
Written for: PIC18F4525 (Current Version)


#define INPUT 1
#define OUTPUT 0

#define _XTAL_FREQ 4000000 //Used by the XC8 delay_ms(x) macro

// PIC18F25K22 Configuration Bit Settings

#include <xc.h> //Includes PIC hardware mapping
#include "GenericTypeDefs.h" //Includes standard variable types

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#pragma config OSC = INTIO7 // Oscillator Selection bits (Internal oscillator block, CLKOUT function on RA6, port function on RA7)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

#pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3 // Brown Out Reset Voltage bits (Minimum setting)

#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT enabled)
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)

#pragma config CCP2MX = PORTC // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

#pragma config CP0 = OFF // Code Protection bit (Block 0 (000800-003FFFh) not code-protected)
#pragma config CP1 = OFF // Code Protection bit (Block 1 (004000-007FFFh) not code-protected)
#pragma config CP2 = OFF // Code Protection bit (Block 2 (008000-00BFFFh) not code-protected)

#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

#pragma config WRT0 = OFF // Write Protection bit (Block 0 (000800-003FFFh) not write-protected)
#pragma config WRT1 = OFF // Write Protection bit (Block 1 (004000-007FFFh) not write-protected)
#pragma config WRT2 = OFF // Write Protection bit (Block 2 (008000-00BFFFh) not write-protected)

#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

#pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 (000800-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 (004000-007FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection bit (Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks)

#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)

//Dummy variable setup

UINT distance = 0;
CHAR direction = 0;
CHAR error = 0;

void configure(void)

//ADC Setup

ADCON1bits.PCFG = 1111; //Turns off all analog inputs (See datasheet p. 224)

//Oscillator Setup

OSCCONbits.IRCF = 110; //Sets oscillator to 4MHz

//Interrupt Setup

INTCONbits.GIE = 1; //Enables all unmasked or high priority interrupts (Depending on IPEN)
INTCONbits.PEIE = 1; //Enables all unmasked peripheral interrupts or low- priority interrupts (Depending on IPEN)
INTCONbits.INT0IF = 0; //Clears interrupt 0 flag bit (Must occur before enabling interrupt)
INTCONbits.INT0IE = 1; //Enables the INT0 external interrupt

INTCON2bits.INTEDG0 = 1; //Sets external interrupt 0 to interrupt on rising edge

RCONbits.IPEN = 0; //Disables priority levels on interrupts

TRISBbits.TRISB0 = INPUT; //Sets INT0 as input
TRISBbits.TRISB1 = INPUT; //Sets INT1 as input


void main()


//Program Loop

//Main interrupt service routine (ISR)
void interrupt ISR()
//Check to see if it is interrupt 0
if (INTCONbits.INT0IF == 1)
INTCONbits.INT0IF = 0; //Clears interrupt flag
error = 1;

<p>Hello,</p><p>I ran across your excellent project. I wondered if you ever had a chance to implement code to decrement the count value? I am attempting to output values of direction and distance to an LCD display, however I am new to PIC programming and not sure how to make this work. If you have time to post the code I would be very grateful.</p>
<p>Hi! Thank you for your comment - it has been a while since I worked with this project. I believe that the other phase from the encoder would be used to determine the direction the motor is travelling. The interrupt routine would have to be modified to read the other phase and adjust your counting variable appropriately based on the direction sensed.</p>
Can you share your project me ? I need to , cause i make a project like yours. But dont stabile
<p>Hi and thank-you for publishing this project, I followed your instructions for the code and used MPLAB X IDE and complier XC8 and it came with several errors when I attempted to build it, </p><p>BUILD FAILED (exit value 2, total time: 1s).</p><p> I am a newbie any help appreciated.</p>
<p>Hi constructionjohn,</p><p>I believe that you've identified a typo in my code. </p><p>Where it previously said &quot;#include //Includes PIC hardware mapping&quot; it should have said &quot;#include &lt;xc.h&gt; //Includes PIC hardware mapping&quot;</p><p>I've updated the code included in step 6 to reflect this change. Don't hesitate to write if you have any other questions. Thank you!</p>
<p>Hello, I need to build a motor controller for a brushless motor to be used for my quadcopter. do you have any idea whether I can use an encoder to determine the position of the rotor and do the job for me?</p>
Hi,<br><br>The encoder used in this project had a resolution of 48 counts per revolution. If that is precise enough for your application, the encoders could certainly track the number of revolutions per rotor to 1/48 precision. <br><br>Did that answer your question?
I see where you increment your counter for going forward, but where do you decrement it when the encoder is turned backwards?
Thank you for your comment. As soon as I have working code that supports a decreasing count during backward movement I will update the Instructable.

About This Instructable



More by CarsonMiller:How to Program a PIC Microcontroller & Read an Encoder 
Add instructable to: