Programming PIC 18 using XC8 (MPLAB X) : Interrupts

Interrupts! You use them to detect the change in pin status, timers, communication and so on. I’m sure if you reached this post in need of using interrupts (or having trouble with interrupts), then I assume you know what interrupts are and what you are trying to use.

With XC8, using interrupts is programmatically simple, since most of the code layout is given to you by <xc.h>. Now setting up interrupts is as simple as using the keyword “interrupt” before the function which should be called when an interrupt happens. I am not going to cover the difference between C18 and XC8 (XC8 makes your life a lot easier), but I’ll show you how to use interrupts in XC8. This post will have only the input from pin change. The timer interrupt will be covered later in the timer chapter.

I encourage you to read the datasheet in order to understand much better about interrupt registers.

Make sure the IO pin you are going to use for interrupt actually has interrupt feature. Because I have seen people using some random pin out of nowhere and say interrupt is not working. Usually PORTB has most of its pins with interrupt capability. As you know I have been using PIC18F4550 here and according to the datasheet (screenshot below), RB0 is INT0. So now I will be connecting a switch pulled up to VCC. When the switch is pressed, the pin voltage becomes zero. So I will be setting the interrupt to work at the falling edge.

interrupt

 

In order to make the pin RB0 to handle interrupt these are the following steps

  • Set RB0 as input pin (set the TRIS as 1)
  • Enable the interrupt bit for RB0
  • Set rising or falling edge interrupt
  • clear the interrupt for the pin (just to make sure)

Follow the 4 steps to enable the interrupt and here is the code snippet for RB0

TRISBbits.RB0 = 1; //set RB0 as Input INTCONbits.INT0E = 1; //enable Interrupt 0 (RB0 as interrupt) INTCON2bits.INTEDG0 = 0; //cause interrupt at falling edge INTCONbits.INT0F = 0; //reset interrupt flag

 

 

Finally you got to just enable the master switch for interrupt

TRISBbits.RB0 = 1; //set RB0 as Input INTCONbits.INT0E = 1; //enable Interrupt 0 (RB0 as interrupt) INTCON2bits.INTEDG0 = 0; //cause interrupt at falling edge INTCONbits.INT0F = 0; //reset interrupt flag ei(); // This is like fliping the master switch to enable interrupt

 

When an interrupt happens, you need a subroutine (fancy word for function) to do something.

Here are is the order you need to handle and interrupt

  • Check if the interrupt flag to make sure the IO pin caused the interrupt (or the peripheral you are looking for)
  • Do your task
  • Reset your interrupt flag

Code snippet for interrupt subroutine

void interrupt low_priority CheckButtonPressed() { //check if the interrupt is caused by the pin RB0 if(INTCONbits.INT0F == 1) { LATB4 = ~LATB4; INTCONbits.INT0F = 0; } }

So, you have to keyword interrupt and then say it’s a low_priority or high priority

Note: Read the datasheet for proper way of setting the high and low priorities. No matter how how many code snippets are out there, without reading and understanding the datasheet, there is now way you can get outputs as expected.

interruptlogic

 

Compare the code snippet and the logic diagram. Will make a lot of sense and you should be able to take from there.

Here is the complete code

#include <xc.h> #include "config.h" #define _XTAL_FREQ 8000000 //What ever speed you set your internal(or)external oscillator int i = 0; void DelayHalfSecond(void); void SetupClock(void); void main(int argc, char** argv) { SetupClock(); TRISBbits.RB4 = 0; //set RB4 as Output TRISBbits.RB0 = 1; //set RB0 as Input INTCONbits.INT0E = 1; //enable Interrupt 0 (RB0 as interrupt) INTCON2bits.INTEDG0 = 0; //cause interrupt at falling edge INTCONbits.INT0F = 0; //reset interrupt flag ei(); // This is like fliping the master switch to enable interrupt while(1) //infinite loop { //actually we have to put the processor in sleep which i will cover // in later tutorials } } void DelayHalfSecond() { for(i=0;i<50;i++) __delay_ms(10); } void SetupClock() { OSCCONbits.IRCF0 = 1; OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF2 = 1; } void interrupt low_priority CheckButtonPressed() { //check if the interrupt is caused by the pin RB0 if(INTCONbits.INT0F == 1) { LATB4 = ~LATB4; DelayHalfSecond(); //like a debounce INTCONbits.INT0F = 0; } }