Table of Contents
Overview
In this tutorial, we will learn how to use an External Interrupt in PIC Microcontroller and why/where we will need them. This is a part of the sequence of PIC Tutorials in which we started learning PIC Microcontrollers from scratch; hence this tutorial assumes that you are familiar with how to program a PIC MCU using MPLABX.
Components required table
S.No | Components | Quantity | link |
1 | DSPIC33FJ64GS606 | 1 | https://www.mouser.in/ProductDetail/Microchip-Technology-Atmel/dsPIC33FJ64GS606 |
2 | PICkit4 Programmer | 1 | https://www.amazon.in/MPLAB-PICkit4-in-Circuit-Debugger |
3 | LED’S | 1 | https://www.amazon.in/Traffic-Lights-Signal-Module-Digital |
4 | Push Button | 1 | https://robu.in/product/momentary-tactile-push-button |
5 | Breadboard – 2 | 1 | https://www.amazon.in/Robotbanao-Solderless-MB102-Breadboard1 |
6 | Jumper wires | 1(set) | https://www.amazon.in/YUVS-Jumper-Wires |
Software Requirments
- MPLAB X IDE
- MPLAB X X16 Compailer
Circuit Diagram
Registers Used for Interrupts
- ICxCON: INPUT CAPTURE x CONTROL REGISTER
- IFS0: INTERRUPT FLAG STATUS REGISTER 0
- IEC0: INTERRUPT ENABLE CONTROL REGISTER 0
ICxCON: INPUT CAPTURE x CONTROL REGISTER
IFS0: INTERRUPT FLAG STATUS REGISTER
IEC0: INTERRUPT ENABLE CONTROL REGISTER 0
- PIC I/O Register Configurations
- PIC I/O Register Configurations
Register | Description |
TRISx | Used to configure the respective PORT as output/input |
PORTx | Used to Read/Write the data from/to the Port pins |
LATx | Used to Read/Write the data from/to the Port pins |
Source code
Input and output selection
TRISGbits.TRISG3 = 0; // 0 as a output 1 as a input Led
TRISGbits.TRISG2 = 1; // 0 as a output 1 as a input Pushbutton
- 1st set as input capture register
- 2nd set as Capture mode, every rising edge or falling edge
- 3rd Interrupt flag status for the selected channel
- IC1IF: Input Capture Channel 1 Interrupt Flag Status bit
- 4th Interrupt enables control for the selected channel
- IC1IE: Input Capture Channel 1 Interrupt Enable bit
Example for interrupt Selection
// set RD8 as interrupt pin
IC1CONbits.ICSIDL = 0; // Input Capture Registers
IC1CONbits.ICM = 1; // 001 = Capture mode, every edge (rising and falling)
// 010 = Capture mode, every falling edge
// 011 = Capture mode, every rising edge
IFS0bits.IC1IF = 0; // Interrupt request has not occurred
//INTERRUPT FLAG STATUS
// Input Capture Channel 1 Interrupt Flag Status bit
// 1 = Interrupt request has occurred
// 0 = Interrupt request has not occurred
IEC0bits.IC1IE = 1; // Input Capture Channel 1 Interrupt Enable bit
Final Source Code
/*
* File: main.c
* Author: Admin
*
* Created on 4 March, 2023, 5:59 PM
*/
#include "xc.h"
#include <p33FJ64GS606.h>
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
#include <math.h>
#include <dsp.h>
#include "libpic30.h"
#define Led_High_A LATGbits.LATG3 = 1;
#define Led_Low_A LATGbits.LATG3 = 0;
#define Led_High_B LATGbits.LATG2 = 1;
#define Led_Low_B LATGbits.LATG2 = 0;
#define Led_High_C LATDbits.LATD2 = 1;
#define Led_Low_C LATDbits.LATD2 = 0;
_FOSCSEL(FNOSC_FRC & IESO_OFF); // Internal FRC start-up without PLL,// no Two Speed Start-up
_FOSC(FCKSM_CSECMD & OSCIOFNC_ON & POSCMD_NONE); // POSCMD_XT);// Clock switch enabled,// Primarly Oscillator XT
_FWDT(FWDTEN_OFF); // Watchdog Timer disabled
_FICD(JTAGEN_OFF); // & ICS_PGD3);// Disable JTAG
_FPOR(FPWRT_PWR128); // Power up timer enabled by 128 mS
void initOscFreq(void);
void initInputCapture();
uint32_t Hal_Flag_1=0;
uint32_t Hal_Flag_2=0;
uint32_t Hal_Flag_3=0;
int main(void) {
// -------------- HALL Sensors ------------- //
#define HALL1 PORTDbits.RD8 // Hall sensor one
#define HALL2 PORTDbits.RD9 // Hall sensor two
#define HALL3 PORTDbits.RD10 // Hall sensor three
// Ouputs
TRISGbits.TRISG3 = 0; // Led_1
TRISGbits.TRISG2 = 0; // Led_2
TRISDbits.TRISD2 = 0; // Led
initOscFreq(); // Oscillator Initialization
initInputCapture();
while(1)
{
}
}
void initInputCapture()
{
// set RD8 as external interrupt pin
IC1CONbits.ICSIDL = 0; // Input Capture Registers
IC1CONbits.ICM = 1; // 001 = Capture mode, every edge (rising and falling)
// 010 = Capture mode, every falling edge
// 011 = Capture mode, every rising edge
IFS0bits.IC1IF = 0; // Interrupt request has not occurred
//INTERRUPT FLAG STATUS
// Input Capture Channel 1 Interrupt Flag Status bit
// 1 = Interrupt request has occurred
// 0 = Interrupt request has not occurred
IEC0bits.IC1IE = 1; // Input Capture Channel 1 Interrupt Enable bit
// set RD9 as external interrupt pin
IC2CONbits.ICSIDL = 0;
IC2CONbits.ICM = 1;
IFS0bits.IC2IF = 0;
IEC0bits.IC2IE = 1;
// set RD10 as external interrupt pin
IC3CONbits.ICSIDL = 0;
IC3CONbits.ICM = 1;
IFS2bits.IC3IF = 0;
IEC2bits.IC3IE = 1;
// set RD11 as external interrupt pin
IC4CONbits.ICSIDL = 0;
IC4CONbits.ICM = 1;
IFS2bits.IC4IF = 0;
IEC2bits.IC4IE = 1;
}
//***************Function Definitions starts from here************************************
void initOscFreq(void)
{
// Configure PLL prescaler, PLL postscaler, PLL divisor for FOsc=80Mhz and Fcy=40Mhz
PLLFBD = 63; // M = 65
CLKDIVbits.PLLPOST=0; // N2 = 2
CLKDIVbits.PLLPRE=1; // N1 = 3
// Initiate Clock Switch to Internal FRC with PLL (NOSC = 0b001)
__builtin_write_OSCCONH(0x01);
__builtin_write_OSCCONL(OSCCON | 0x01); //Clock witch Enable
//OSCTUNbits.TUN = 0b111111; //FRC tuning to 7.345Mhz
while (OSCCONbits.COSC != 0b001); // Wait for Clock switch to occur
while (OSCCONbits.LOCK != 1); //wait till PLL is locked
/* Now setup the ADC and PWM clock for 120MHz
** ((FRC * 16) / APSTSCLR ) = (7.37 * 16) / 1 = ~ 120MHz
*/
ACLKCONbits.FRCSEL = 1; // FRC provides input for Auxiliary PLL (x16)
ACLKCONbits.SELACLK = 1; // Auxiliary Ocillator provides clock source for PWM & ADC
ACLKCONbits.APSTSCLR = 7; // Divide Auxiliary clock by 1
ACLKCONbits.ENAPLL = 1; // Enable Auxiliary PLL
while(ACLKCONbits.APLLCK != 1); // Wait for Aux. PLL to Lock {{for Testing}}
// REFOCONbits.ROON = 0; //REF OSC o/p is enabled on REFCLKO pin
// REFOCONbits.RODIV = 0; //Output at REFCLKO pin is Fosc/2 i.e. 40Mz
}
// Hal Sensor External Inputs
// Hall A Interrupt
void _ISR __attribute__((no_auto_psv)) _IC1Interrupt()
{
IFS0bits.IC1IF = 0;
Led_High_A = 1;
Led_Low_B = 1;
Led_Low_C = 1;
}
// Hall B Interrupt
void _ISR __attribute__((no_auto_psv)) _IC2Interrupt()
{
IFS0bits.IC2IF = 0;
Led_High_B = 1;
Led_Low_A = 1;
Led_Low_C = 1;
}
// Hall C Interrupt
void _ISR __attribute__((no_auto_psv)) _IC3Interrupt()
{
IFS2bits.IC3IF = 0;
Led_High_C = 1;
Led_Low_A = 1;
Led_Low_B = 1;
}