Introduction to PIC Interrupts and their Handling in C

Interrupts are common features in almost all processor family, be it old 8051, AVR, PIC, ARM or the x86 used in desktops. So their in depth and clear knowledge is required for successful system software engineers. This guide will explain the interrupt system in general and their application using PIC18 architecture. We will also learn about handling of interrupts in HI-TECH C for PIC18.

What are Interrupts?

Interrupts, as the name suggests interrupts the normal execution and Requests and urgent attention of CPU. Interrupts are situations that the CPU can’t predict when they will happen, they can happen any time, so the CPU does not wait for them. So the CPU keeps on doing its normal job unless and interrupt occurs. For example when the USART (Serial Communication Hardware) will receive data is unknown, it can receive data any time. So the CPU keeps on doing its normal job, which may be for example read temperature using LM35 sensor and display on LCD. The CPU keeps on doing the "normal" job, but as soon as the USART receive data it informs the CPU using an interrupt. The CPU save its current state (so that it can resume), and jumps to the ISR (interrupt service routine) immediately. Where we can process the command or put it in a FIFO queue (to process latter). The ISR is generally kept very small and fast. As soon as the ISR ends, the CPU restores its saved state and resumes where it left. In this way CPU does not missed any data byte.

Example of sources of Interrupts in PIC18 (also common in other MCUs)

  • External interrupts – they are named INTx (like INT0, INT1 etc), they provide a means for external hardware to generate interrupts. Like if you connect a touchscreen controller to your PIC MCU. Then the touchscreens PENINT (pen interrupt) can be connected to INT0 (or any other INTx). Then when ever the pen (or stylus) touches the screen it will interrupt the CPU. This interrupt will be explained in details in its own tutorial.
  • TIMER interrupts – They are also very common in MCUs. Today’s MCUs comes with very sophisticated timers that can do lots of magic for you. They have they related interrupts. In most simple situation they can act like alarm clocks that can interrupt the CPU at predefined intervals. If you toggle a i/o pin in response to these alarms (interrupts), what you have is a frequency generator! For more info on timers on PIC18, read this article.
  • Analog to Digital Converter Interrupts – A/D Converter takes some time to complete its operation. So the CPU can either wait for it to complete or set up an AD conversion complete interrupt. In the latter case CPU can do other tasks while A/D converter converts the input. As soon as A/D converter completes its job it will inform CPU to read the value from its buffer. For more info on A/D Converter of PIC18, read this article.
  • Data Interrupts – MCUs have many different types of data i/o engines, like USART, SPI, I2C, Parallel etc. They can also interrupt the CPU when data transmission is complete or data arrives from external source. Like an RFID reader send a packet because a user just brought his or her card near the reader. Or the GSM module detected an incoming call.

How interrupts are managed?

In general each interrupt source have following related bits.

  • Enable Bit – The are suffixed with IE (Interrupt Enable) example TMR0IE stands for TIMER0 Interrupt Enable. It can be used to enable/disable the related interrupt. When set to ’1′ it enables the interrupt.
  • Flag Bit – It is set automatically by the related hardware when the interrupt condition occurs. It is generally suffixed with IF (Interrupt Fag). When it is set to ’1′ we know that interrupt has occurred. For example when TMR0IF is set by TIMER0, it indicates that TIMER0 has overflowed.
  • Priority Bit - We can leave this for now to keep things simple. We won’t be using interrupt priority feature of PIC18.

In global level their are following bits to control the interrupts globally.

  • GIE – Global Interrupt Enable, enables/disables interrupts globally.
  • PEIE – Enable/disable all peripheral interrupts.

Interrupt Vector

It is the address where the CPU jumps when an interrupt occurs. In PIC18 this address is 0008(hex). CPU jumps to this address for any interrupt. The ISR or Interrupt service routine is placed in this address. The ISR must determine the source of interrupt from the flag bit(described above).

1     //Main Interrupt Service Routine (ISR)
2     void interrupt ISR()
3     {
4        //Check if it is TMR0 Overflow ISR
5        if(TMR0IE && TMR0IF)
6        {
7           //TMR0 Overflow ISR
9           counter++;//Increment Over Flow Counter
11          if(counter==76)
12          {
13             //Toggle RB1 (LED)
14             if(RB1==0)
15                RB1=1;
16             else
17                RB1=0;
19             counter=0;  //Reset Counter
20          }
22          //Clear Flag
23          TMR0IF=0;
24       }
25    }

For example in above code snipped. void interrupt ISR() is the main service routine where the CPU jumps for any interrupt (TIMER,A/D, INTx etc). As soon as we enter the ISR we check for the source of interrupt. This done using the line


the above line check is the source of interrupt was TIMER0 (so it checks if TMR0IF is set or not). It also checks TMR0IE (TIMER0 interrupt enable bit) to make sure this interrupt is enabled or not. It execute the TIMER0 ISR only of both the condition are true. One more line on interest is line 23 where we clear the flag, this is necessary otherwise the interrupt is triggered again.

You should note one more point the GIE (explained above) is cleared automatically when PIC18 enters ISR, this make sure that interrupts cannot be interrupted them self. It also automatically sets GIE on return from interrupt, which re enable interrupts.

In the above code (from line 9 to 20), you can see that for each overflow of timer (like alarm from an alarm clock) we increment a counter and as soon as this counter reaches 76 we toggle an LED. And also clear the counter (line 19). This gives us a LED that is toggled ever 1sec. So you see that LED is controlled fully by the TIMER while CPU can keep on doing other jobs but LED will always blink at its predefined rate. This example give a kind of illustration of multitasking, the LED take care of itself. You don’t have to write anything on the main() function to control the LED. Your main function could go on normally, for example control a line follower robot. The TIMER will take care of the LED and toggle it every second. The LED could be used for decoration of the robot.

Handling interrupt in C

Here I will show you how we can write programs in HI-TECH C that utilizes interrupt feature of PIC MCU. The interrupt handling is very clean and straightforward in HI-TECH C (as compare to Microchip C18 Compiler). Please note that interrupt handling is not a standard feature of C language, so their is significant diffenence between different compiler in handling interrupts.

Please note that to simplify the situtation, we are not using interrupt priority feature of PIC18(because this is a guide for first time user of interrput). In HI-TECH C for PIC18 an ISR (interrupt service routine, that is called when interrupt condition occur) is defined like this

void interrupt FunctionName(void)

as you can see in above code line the "interrupt" function qualifier is used to mark a function as ISR. The following point must be kept in mind while defining an ISR :-

  1. The return type of ISR must always be void.
  2. It must not take any parameters. That’s why argument list is set to void.
  3. The name of function can be any valid C function name. But I generally use the name ISR for ISRs.
  4. Their can be at most one ISR function. (Two if using interrupt priority).

For more information refer to the HI-TECH C user manual.

HI-TECH C Program for TIMER0 Interrupt.

The following is a simple program that demonstrate use of interrupts. The program is very simple so does not do any magic but only teaches use of interrupt. Please go through the program very carefully to check out how every feature described above are used. To understand the program you also need some knowledge of TIMER0 which is described in detail in the following article.

1     /*****************************************************************
3     A simple example to demonstrate the use of PIC Timers. In this 
4     example the TIMER0 is configured as follows.
6     *8 Bit Mode
7     *Clock Source from Prescaler
8     *Prescaler = FCPU/256 (Note: FCPU= Fosc/4)
9     *Over flow INT enabled
11    As our FCPU=20MHz/4 (We are running from 20MHz XTAL)
12    =5MHz
14    Time Period = 0.2uS
15    Prescaller Period = 0.2 x 256 = 51.2uS
16    Overflow Period   = 51.2 x 256 = 13107.2 uS
17                      = 0.0131072 sec
19    So we need 1/0.0131072 Over Flows to count for 1 sec
20    = 76.2939 Overflows
22    So we keep a counter to keep track of overflows.
24    When an over flow occurs the PIC jumps to ISR where we
25    increment counter. And when counter becomes 76 we toggle
26    RB1 pin. This pin is connected to LED. Therefore we
27    have a LED which is ON for 1 sec and Off for 1sec.
30    Target Chip: PIC18F4520
31    Target Compiler: HI-TECH C For PIC18 (
32    Project: MPLAP Project File
34    Author: Avinash Gupta
35    Copyright (c) 2008-2010
36    eXtreme Electronics, India
39                         NOTICE
40                      -------------
47    *****************************************************************/
49    #include <htc.h>
52    //Chip Settings
53    __CONFIG(1,0x0200);
54    __CONFIG(2,0X1E1F);
55    __CONFIG(3,0X8100);
56    __CONFIG(4,0X00C1);
57    __CONFIG(5,0XC00F);
59    unsigned char counter=0;//Overflow counter
61    void main()
62    {
63       //Setup Timer0
64       T0PS0=1; //Prescaler is divide by 256
65       T0PS1=1;
66       T0PS2=1;
68       PSA=0;      //Timer Clock Source is from Prescaler
70       T0CS=0;     //Prescaler gets clock from FCPU (5MHz)
72       T08BIT=1;   //8 BIT MODE
74       TMR0IE=1;   //Enable TIMER0 Interrupt
75       PEIE=1;     //Enable Peripheral Interrupt
76       GIE=1;      //Enable INTs globally
78       TMR0ON=1;      //Now start the timer!
80       //Set RB1 as output because we have LED on it
81       TRISB&=0B11111101;
83       while(1);   //Sit Idle Timer will do every thing!
84    }
86    //Main Interrupt Service Routine (ISR)
87    void interrupt ISR()
88    {
89       //Check if it is TMR0 Overflow ISR
90       if(TMR0IE && TMR0IF)
91       {
92          //TMR0 Overflow ISR
93          counter++;  //Increment Over Flow Counter
95          if(counter==76)
96          {
97             //Toggle RB1 (LED)
98             if(RB1==0)
99                RB1=1;
100            else
101               RB1=0;
103            counter=0;  //Reset Counter
104         }
105         //Clear Flag
106         TMR0IF=0;
107      }
108   }

Program Walk through

  • Line 64 to 72 : Configure the TIMER0. See tutorial on timer for more info.
  • Line 74 to 76 : Enables Timer0 interrupt (TMR0IE=1), peripheral interrupt (PEIE=1) and finally sets GIE=1 to enable interrupts.
  • Line 83: The program has noting to do, so we enter an infinite loop and burn CPU cycles. Your program is free to to any tasks after interrupts are set up and enabled. We required ISR will automatically called by the hardware to service the situation. As as soon as service is complete, normal execution will be resumed.
  • Line 87: define the ISR.
  • Line 90: Checks if it is the timer interrupt (by checking the flag bit TMR0IF) and if the timer interrupts are enabled (by checking TMR0IE).
  • Line 91 to 104: is the service routine of TIMER0 interrupt.
  • Line 106: clears the timer interrupt flag, this step is very important before exiting the ISR or it will be called again!

A Word from the author

Interrupt handling is a vital for any successful and quality embedded code, so their clear knowledge is very important. The above article described interrupt handling in details. The same code framework and techniques are applicable for any interrupt enabled program howsoever complex it is. So I recommend that you go though the article until you are clear with every concept. They will be very helpful for you to write your own interrupt enabled programs and understand other programs provided in our website.

Help Us!

We try to publish beginner friendly tutorials for latest subjects in embedded system as fast as we can. If you like these tutorials and they have helped you solve problems, please help us in return. You can donate any amount as you like securely using a Credit or Debit Card or Paypal.

We would be very thankful for your kind help.

Avinash Gupta
Facebook, Follow on Twitter.


Avinash Gupta is solely focused on free and high quality tutorial to make learning embedded system fun !

More Posts - Website

Follow Me:
FacebookLinkedInGoogle Plus

About Avinash

Avinash Gupta is solely focused on free and high quality tutorial to make learning embedded system fun !

21 thoughts on “Introduction to PIC Interrupts and their Handling in C

  • By PIC Beginner - Reply

    Hi Mr Avinash,

    Your webside has a lot of great articles and valuable knowledge…thanks…as a fresh learner of PIC mcu, your informations are really paramount to me. By the way, I have a queston in response to the article above…that is, is all the information above including the register and its bits name applicable to other PIC MCU series, like 16F or 24F. I will further study your other masterpieces if everything are applicable, as I will be using 16F PIC in my project…best regards.

    • By rishi - Reply

      Please reply.I have the same query.

  • By Nahian Rahman - Reply

    Great works as usual from you. Where I can get details about the “_cofig(argument1,argument2)” macro? thanks.

  • By Mash_rishi - Reply

    Hi Avinash, your lessons have a lot of simple but very important information. Could you give some information on how to out two different freq. using interrupts independtly using PIC18F4520. For example 1Hz at RA0 and 3Hz at RA1 at the same time with both starting at the same clock edge.
    Thanks Mash

  • Pingback: Using Multiplexed 7 Segment Displays – PIC Microcontroller Tutorial | eXtreme Electronics

  • By Gowtham - Reply


    iam very happy to see this article.Iam working with pic18f6520 (iam new to this),can u suggest some more points to start writing the code in hitech c about interrupts with example program or flowchart for sample program

  • By Jaggu - Reply


    How to handle, two hardware interrupts??

    • By Vijay Kishore - Reply

      There is no issue in handling two hardware interrupts.
      Write an ISR for each and enable the two interrupts.
      Based on the priority they are executed.

  • By joshua - Reply

    Thank you for putting up this site and uploading this information.This is a very important website to students and other people deaing with projects in embedded systems
    I am working on a project involving PIC18F4550.Please help me with the code for USB interfacing with PIC18

  • By aredhel_vlsi - Reply

    Hello this is a great tutorial but I have a serious problem in PIC18F43331. I have created an interrupt using the Input Capture of the Motion Feedback Module. When the RC3 led blinks, (with TMR5) the RC0 blinks too. I want also to make a motor run with different speed ( to change the PWM) when the RC3 blinks. Would you suggest to me something please? Have you encountered anything similar?

  • By Emmanuel.I - Reply

    Enjoyed your tutorial, but what i don’t know is whether this code will work in Mikroc compiler.


  • By Emmanuel - Reply

    thanks again for the wonderful material you put here on this site, would really like to send my little donation in appreciation of this free and easy to understand tutorial not minding whether how small it is but my country(Nigeria) is not on the list.

    If there is any other means which i can use my credit card please send it to my e-mail.


    • By Avinash - Reply


      Yes I think Nigeria is not available in PayPal. But we appropriate your will to help. If you are facing problem donating then their is no need to do, your kind words are just enough !!!

  • By Suneth (Sri Lanka) - Reply

    Absolutely Great…..!
    No wordz 2 thank…..!!

  • By Sujith - Reply

    can you post the link that explains the intialization of the external interrupts

  • By vino - Reply

    nice and easy to understand

  • By VJ - Reply

    Hi how will I translate a switch pressed into a interrupt ? will it be interrupt on change ?

    • By Avinash - Reply


      Switches being a physical contact device cannot be connected to interrupt.

      Because when you press a switch from your perspective the level changes from one to another.

      But actually when you view the signal in high speed. It actually bounces several times to make a contact. So actually at the point of contact their will be several spikes when a contact is made. This will lead to multiple interrupts.

      • By VJ -

        so how can you translate a switch turning off an LED into a certain logic ? can you give me some idea ..

  • By VJ - Reply

    Can we define an array of PORTS as say
    Is this valid ?

  • By shrikant - Reply

    i am using interrupt for a switch to control LED, after five sec of key pressed LED will turn off, it is fine, working normally, but when i want to display seven segment display for an analog input that time led concept not working,
    please let me know the solution for this.

Leave a Reply

Your email address will not be published. Required fields are marked *

6 × nine =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>