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