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
r 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
  • 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
  • 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

Follow on Twitter.