As a first step I always like to code the basic 'blinking LED' in a new PIC project. I use interrupts instead of delays because in addition to having a visual indication that the PIC is alive, I also use the same interrupt routine to handle any delays I may need down the road. XC8 does have built-in delay functions however, XC8 delay functions actually inserts NOP instructions into the code and you can't pass a variable into the XC8 delay function. You need to know all your static only delays ahead of time! Not very robust or efficient, so I use an interrupt routine to handle all delays instead of the built in XC8 functions. In addition to this basic 'heartbeat' I also configured two CCP peripherals as PWM channels for the control of the two drive motors.
First we configure the PIC 16F1829 fuses:
/* configuration_bits.c */
#include <xc.h> /* XC8 General Include File */
#include <xc.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)
/* system.h */
#define SYS_FREQ 1600000L
#define FCY SYS_FREQ/4
/******************************************************************************/
/* System Function Prototypes */
/******************************************************************************/
void ConfigureOscillator(void); /* Handles clock switching/osc initialization */
...and
#include <xc.h> /* XC8 General Include File */
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include "system.h"
void ConfigureOscillator(void)
{
OSCCON=0b01111010;
while (!HFIOFS) continue;// wait for stable osc
}
/* user.c */
#include <xc.h> /* XC8 General Include File */
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include "user.h"
void InitApp(void)
{
/* Heartbeat config */
TRISAbits.TRISA5 = 0; // Heartbeat LED
TMR2=0;// clear TMR2
T2CON = 0b00000110;//post 0, timer on, pre 16
PR2=0xF9; // sets up timer2 for 1ms interrupts
/* PWM Left config */
TRISCbits.TRISC6 = 0; // Left PWM output
T4CON = 0b00000110;//post 0, timer on, pre 16
PR4 = 0xF9; // 1000 Hz PWM freq
CCP4CON = 0x3C;// PWM mode
CCPR4H = 0;
CCPR4L = 0x3E; // Duty cycle count 1% = 0x9 to 100% = 0xF9
CCPTMRS = 0x40; // use Timer 4
/* PWM Right config */
TRISAbits.TRISA2 = 0; // Right PWM output
T6CON = 0b00000110;//post 0, timer on, pre 16
PR6 = 0xF9; // 1000 Hz PWM freq
CCP3CON = 0x1C; // PWM mode
CCPR3H = 0;
CCPR3L = 0x7C; // Duty cycle count 1% = 0x9 to 100% = 0xF9
CCPTMRS = 0x20; // use Timer 6
/* Enable interrupts */
PIR1bits.TMR2IF=0; // clear TMR2 interrupt flag
PIE1bits.TMR2IE=1;//enable TMR2 interrupts
INTCONbits.PEIE=1;//enable Peripheral interrupts
INTCONbits.GIE=1;// enable global interrupts
}
void msDelay(unsigned int d){
// load up the msec delay variable
ms_delay=d;
// loop execution here until msec delay completes via 1 ms interrupts
while(ms_delay)continue;
}
The O'scope shot below shows the two outputs from the PIC with the top trace being the Left and the bottom trace being the Right.
The interrupt routine:
/* interrupts.c */
#include <xc.h> /* XC8 General Include File */
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include "user.h"
void interrupt isr(void)
{
INTCONbits.GIE=0;// disable all interrupts
/* Determine which flag generated the interrupt */
if(PIR1bits.TMR2IF)// 1ms interrupt via Timer 2
{
if(hb_count++>500)// if counted 500ms
{
LED = ~LED; // toggle the 'heartbeat' LED
hb_count=0; // and reset the count to 0
}
if (ms_delay){ // if msec delay variable is not zero
ms_delay--; // decrement the delay
}
PIR1bits.TMR2IF=0; // clear Timer 2 interrupt flag
}
else
{
/* Unhandled interrupts */
}
INTCONbits.GIE=1;// enable global interrupts
}
General definitions:
/* user.h */
#define _XTAL_FREQ 16000000 // Fosc frequency for _delay() library
#define LED LATAbits.LATA5
/******************************************************************************/
/* User Function Prototypes */
/******************************************************************************/
void msDelay(unsigned int d);
void InitApp(void); /* I/O and Peripheral Initialization */
/* global variables */
unsigned int hb_count=0;// Heartbeat counter
unsigned long ms_delay=0;
/* main.c */
#include <xc.h> /* XC8 General Include File */
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include "system.h" /* System funct/params, like osc/peripheral config */
#include "user.h" /* User funct/params, such as InitApp */
void main(void)
{
/* Configure the oscillator for the device */
ConfigureOscillator();
/* Initialize I/O and Peripherals for application */
InitApp();
while(1)
{
}
}