Interrupts are one of the most powerful features of PIC Microcontrollers, interrupts make it possible to create applications that can respond to external stimulus in real time. An interrupt is basically an event that requires the microcontroller to stop normal program execution and then to jump to execute a program code related to the event causing the interrupt. An interrupt requires immediate attention, only once the microcontroller will finish executing the interrupt code, then it can go back to continue with the main program. The interrupt code is called Interrupt Service Routine (ISR) or Interrupt Handler. Here is a simple example to understand interrupts, let say you are playing a game with your phone and Suddenly your mobile phone rings somebody is calling you. Your phone will immediately leave the game and start ringing. Only once you are done with the call, then the phone will jump back to the game. This process is similar to ISR execution. You can think the main service routine in this case as playing the game and the ringing of the mobile phone as causing an interrupt. This initiates your mobile phone conversation which is similar to executing Interrupt Service Routine (ISR).

If there were no interrupt, while playing the game, the microcontroller would time to time pause the game and monitor if there is no one trying to call you. As you can see, this is not an efficient way of programming as it consumes all its processing time for monitoring and they can be a possibility of missing a short process that can require immediate attention. The best way is to leave the microcontroller do its normal main program, and if there is nothing to do, let the microcontroller go into sleep mode and be awaken only to respond to an interrupt that occurs. This can save power and much needed processor power especially if the application if battery powered.  The processes of continuous monitoring is known as POLLING.

Interrupts can be very useful in many applications such as:

  • Fail safe applications: Applications which require the immediate attention of the microcontroller when there is a fault in the system can use interrupts. For example, in an emergency such as a power failure in an hazardous environment where a the microcontroller has to take some precise coordinated actions like switching off the system immediately in an orderly manner. In such applications an external interrupt can force the microcontroller to stop whatever it is doing and take immediate action.
  • Performing routine tasks: If an application requires the microcontroller to perform routine tasks at precise times, such as blinking a status LED, reading inputs of sensors connected to the microcontroller exactly every few millisecond. A timer interrupt scheduled with the required timing can divert the microcontroller from normal program execution to accomplish the task at the precise time required.
  • To check if a certain tasks have been completed: Some applications may need to know when a task, such as an A/D conversion, is completed, or instead of keep on listening (polling) for an incoming data from an UART or USB port for example, an interrupt could be raise immediately when an A/D conversion is done or when there is an incoming data instead of keeping the microcontroller doing nothing but waiting for this to happen.

Interrupts in PIC18F Series

Different PIC Microcontrollers have different interrupts, but most have both the core and peripheral interrupt sources. Always check your device datasheet to find out more about the interrupts. Figure 1 below shows the diagram of the PIC18F452.


Figure 1: PIC18F452

Like most PIC18F series PIC Microcontrollers, the PIC18F452 has the following interrupts:

  • External: External edge-triggered interrupt on INT0, INT1, and INT2 pins (RB0, RB1 and RB2).
  • PORTB pins change interrupts (any one of the RB4–RB7 pins changing state)
  • Timer 0 overflow interrupt
  • Timer 1 overflow interrupt
  • Timer 2 overflow interrupt
  • Timer 3 overflow interrupt
  • Parallel slave port read/write interrupt
  • A/D conversion complete interrupt
  • USART receive interrupt
  • USART transmit interrupt
  • Synchronous serial port interrupt
  • CCP1 interrupt
  • CCP2 interrupt
  • Comparator interrupt
  • EEPROM/FLASH write interrupt
  • Bus collision interrupt
  • Low-voltage detect interrupt

There are ten registers in the PIC18F452 microcontroller that control interrupt operations:

  • RCON
  • PIR1, PIR2
  • PIE1, PIE2
  • IPR1, IPR2

Interrupts in the PIC18F family can be divided into two groups: high priority and low priority. Applications that require more attention can be placed in the higher priority group. A high-priority interrupt can stop a low-priority interrupt that is in progress and gain access to the CPU. However, high-priority interrupts cannot be stopped by low-priority interrupts. If the application does not need to set priorities for interrupts, the user can choose to disable the priority scheme so all interrupts are at the same priority level.

Every interrupt source (except INT0) has three bits to control its operation:

  • A flag bit to indicate whether an interrupt has occurred regardless of whether it is enabled or not. This bit has a name ending inIF
  • An interrupt enable bit to enable or disable the interrupt source. This bit has the name ending inIE
  • A priority bit to select high or low priority. This bit has a name ending in IP.

For an interrupt to work the following conditions must be satisfied:

  • The interrupt enable bit of the interrupt source must be enabled. For example, if the interrupt source is external interrupt pin INT0, then bit INT0IE of register INTCON must be set to 1.
  • The interrupt flag of the interrupt source must be cleared. For example, if the interrupt source is external interrupt pin INT0, then bit INT0IF of register INTCON must be cleared to 0.
  • The peripheral interrupt enable/disable bit PEIE of INTCON must be set to 1 if the interrupt source is a peripheral.
  • The global interrupt enable/disable bit GIE of INTCON must be set to 1.

RCON Register

The RCON register contains the bit which is used to enable interrupt priority (IPEN). When IPEN = 0, interrupt priority levels are disabled and the microcontroller interrupt structure is similar to that of the PIC16 series which does not have priorities. When IPEN = 1, interrupt priority levels are enabled. Figure 2 below shows the bits of register RCON.

Figure 2: PIC18F452 RCON Register

INTCON Registers

The INTCON Registers are readable and writable registers, which contain various enable, priority and flag bits.

Figure 3: PIC18F452 INTON Register

For more information on other registers, please check your PIC Datasheet from Microchip website. The PIC18F452 Datasheet can be downloaded from this link.

 External INT0 interrupt on PORTB.0 pin Example

In this simple External INT0 interrupt on PORTB.0 pin Example using the PIC18F4520. Make sure the IO pin you are going to use for interrupt actually has an interrupt feature. You can’t just use any pin because it is convenient for you, check your datasheet to make sure it has interrupt. In our case, we are going to use pin RB0 of PIC18F4520 which is INT0 (External Interrupt 0 Input). A switch will be connected to this pin and 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. Two LEDs are connected one to PORTB.4, this will flash normally at an interval of 1 second  until interrupt occurs (RB0 is pressed with a push button). Then the interrupt routine will be executed, the second LED on RB5 will flash rapidly 5 times at an interval of 300ms.

Watch The Video Tutorial: External Interrupt

With XC8, using interrupts is programmatically simple, since most of the code is given to you by <xc.h>. By just using the keyword “interrupt” before the function which should be called when an interrupt happens to setup the interrupt.

In order to make the pin RB0 to handle interrupt these are the only few steps to follow:

  • Set RB0 as input pin (set the TRIS as 1): TRISBbits.RB0 = 1;    //set RB0 as Input
  • Enable the interrupt bit for RB0: INTCONbits.INT0E = 1;   //enable Interrupt 0 (RB0 as interrupt)
  • Set rising or falling edge interrupt:  INTCON2bits.INTEDG0 = 0;   //cause interrupt at falling edge
  • Clear the interrupt for the pin (just to make sure):  INTCONbits.INT0F = 0;   //reset interrupt flag
  • Finally you got to enable the master switch for interrupt:  ei();     // This is like flipping the master switch to enable interrupt

When an interrupt occurs, you need a subroutine to do something. You’ll need to handle the interrupt in the following order:

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

Here is the full code, the circuit diagram is shown on figure 4. In normal operation, the LED on RB4 will be flashing at an interval of 1 second. When there is an interrupt, the main program will jump to this subroutine and Flash fast the LED connected to PORTB5.

Figure 4: External Interrupt on pin RB0

Watch The Video Tutorial: Peripheral Interrupt

You can download the full project files (MPLAB XC8 source code and Proteus Schematic design) below here.
All the files are zipped, you will need to unzip them (Download a free version of the Winzip utility to unzip files).

MPLAB XC8 Code: Interrupt MPLAB XC8 Project

Proteus Schematic: Interrupt RB0 Proteus Schematic