What is Interrupt : 8051 Interrupt Programming | Hardware Interrupts
Close or Esc Key

Arduino Projects   |   Raspberry Pi   |   Electronic Circuits   |   AVR   |   PIC   |   8051   |   Electronic Projects

Interrupts & Programming 8051 Hardware Interrupts

Written By: 

Himanshu Choudhary
 
Interrupt is one of the most important and powerful concepts and features in microcontroller/processor applications. Almost all the real world and real time systems built around microcontrollers and microprocessors make use of interrupts.
 
What is Interrupt
The interrupts refer to a notification, communicated to the controller, by a hardware device or software, on receipt of which controller momentarily stops and responds to the interrupt. Whenever an interrupt occurs the controller completes the execution of the current instruction and starts the execution of an Interrupt Service Routine (ISR) or Interrupt Handler. ISR is a piece of code that tells the processor or controller what to do when the interrupt occurs. After the execution of ISR, controller returns back to the instruction it has jumped from (before the interrupt was received). The interrupts can be either hardware interrupts or software interrupts.
 
Why need interrupts
An application built around microcontrollers generally has the following structure. It takes input from devices like keypad, ADC etc; processes the input using certain algorithm; and generates an output which is either displayed using devices like seven segment, LCD or used further to operate other devices like motors etc. In such designs, controllers interact with the inbuilt devices like timers and other interfaced peripherals like sensors, serial port etc. The programmer needs to monitor their status regularly like whether the sensor is giving output, whether a signal has been received or transmitted, whether timer has finished counting, or if an interfaced device needs service from the controller, and so on. This state of continuous monitoring is known as polling.
 
In polling, the microcontroller keeps checking the status of other devices; and while doing so it does no other operation and consumes all its processing time for monitoring. This problem can be addressed by using interrupts. In interrupt method, the controller responds to only when an interruption occurs. Thus in interrupt method, controller is not required to regularly monitor the status (flags, signals etc.) of interfaced and inbuilt devices.
 
To understand the difference better, consider the following. The polling method is very much similar to a salesperson. The salesman goes door-to-door requesting to buy its product or service. Like controller keeps monitoring the flags or signals one by one for all devices and caters to whichever needs its service. Interrupt, on the other hand, is very similar to a shopkeeper. Whosoever needs a service or product goes to him and apprises him of his/her needs. In our case, when the flags or signals are received, they notify the controller that they need its service.
 

Hardware & Software Interrupt

Hardware and Software interrupt
The interrupts in a controller can be either hardware or software. If the interrupts are generated by the controller’s inbuilt devices, like timer interrupts; or by the interfaced devices, they are called the hardware interrupts. If the interrupts are generated by a piece of code, they are termed as software interrupts.
 
Multiple interrupts
What would happen if multiple interrupts are received by a microcontroller at the same instant? In such a case, the controller assigns priorities to the interrupts. Thus the interrupt with the highest priority is served first. However the priority of interrupts can be changed configuring the appropriate registers in the code.
 
8051 Interrupts
The 8051 controller has six hardware interrupts of which five are available to the programmer. These are as follows:
 
1. RESET interrupt - This is also known as Power on Reset (POR). When the RESET interrupt is received, the controller restarts executing code from 0000H location. This is an interrupt which is not available to or, better to say, need not be available to the programmer.
 
2. Timer interrupts - Each Timer is associated with a Timer interrupt. A timer interrupt notifies the microcontroller that the corresponding Timer has finished counting.
 
3. External interrupts - There are two external interrupts EX0 and EX1 to serve external devices. Both these interrupts are active low. In AT89C51, P3.2 (INT0) and P3.3 (INT1) pins are available for external interrupts 0 and 1 respectively. An external interrupt notifies the microcontroller that an external device needs its service.
 
4. Serial interrupt - This interrupt is used for serial communication. When enabled, it notifies the controller whether a byte has been received or transmitted.
 

How is an interrupt serviced?

How is an interrupt serviced?
Every interrupt is assigned a fixed memory area inside the processor/controller. The Interrupt Vector Table (IVT) holds the starting address of the memory area assigned to it (corresponding to every interrupt).
 
The interrupt vector table (IVT) for AT89C51 interrupts is as follows :
Interrupt
ROM Location (Hex)
Pin
Flag clearing
Reset
0000
9
Auto
External interrupt 0
0003
12
Auto
Timer interrupt 0
000B
-
Auto
External interrupt 1
0013
13
Auto
Timer interrupt 1
001B
-
Auto
Serial COM interrupt
0023
-
Programmer clears it
 
When an interrupt is received, the controller stops after executing the current instruction. It transfers the content of program counter into stack. It also stores the current status of the interrupts internally but not on stack. After this, it jumps to the memory location specified by Interrupt Vector Table (IVT). After that the code written on that memory area gets executed. This code is known as the Interrupt Service Routine (ISR) or interrupt handler. ISR is a code written by the programmer to handle or service the interrupt.
 

Programming Interrupts

Programming Interrupts
While programming interrupts, first thing to do is to specify the microcontroller which interrupts must be served. This is done by configuring the Interrupt Enable (IE) register which enables or disables the various available interrupts. The Interrupt Enable register has following bits to enable/disable the hardware interrupts of the 8051 controller.
 
 
To enable any of the interrupts, first the EA bit must be set to 1. After that the bits corresponding to the desired interrupts are enabled. ET0, ET1 and ET2 bits are used to enable the Timer Interrupts 0, 1 and 2, respectively. In AT89C51, there are only two timers, so ET2 is not used. EX0 and EX1 are used to enable the external interrupts 0 and 1. ES is used for serial interrupt.
 
EA bit acts as a lock bit. If any of the interrupt bits are enabled but EA bit is not set, the interrupt will not function. By default all the interrupts are in disabled mode.
 
Note that the IE register is bit addressable and individual interrupt bits can also be accessed.
For example –
IE = 0x81; enables External Interrupt0 (EX0)
IE = 0x88; enables Serial Interrupt
 
Setting the bits of IE register is necessary and sufficient to enable the interrupts. Next step is to specify the controller what to do when an interrupt occurs. This is done by writing a subroutine or function for the interrupt. This is the ISR and gets automatically called when an interrupt occurs. It is not required to call the Interrupt Subroutine explicitly in the code.
 
An important thing is that the definition of a subroutine must have the keyword interrupt followed by the interrupt number. A subroutine for a particular interrupt is identified by this number. These subroutine numbers corresponding to different interrupts are tabulated below.
 
Number
Interrupt
Symbol
0
External0
EX0
1
Timer0
IT0
2
External1
EX1
3
Timer1
IT1
4
Serial
ES
5
Timer2
ET2
 
For example : Interrupt routine for Timer1
void ISR_timer1(void) interrupt 3
{
	<Body of ISR>
}
For example : Interrupt routine for External Interrupt0 (EX0)
void ISR_ex0(void) interrupt 0
{
	<Body of ISR>
}
Note that the interrupt subroutines always have void return type. They never return a value.
 

Programming Timer Interrupts


1. Programming Timer Interrupts
The timer interrupts IT0 and IT1 are related to Timers 0 and 1, respectively. (Please refer 8051 Timers for details on Timer registers and modes.) The interrupt programming for timers involves following steps :
 
1.                  Configure TMOD register to select timer(s) and its/their mode.
2.                  Load initial values in THx and TLx for mode 0 and 1; or in THx only for mode 2.
3.                  Enable Timer Interrupt by configuring bits of IE register.
4.                  Start timer by setting timer run bit TRx.
5.                  Write subroutine for Timer Interrupt. The interrupt number is 1 for Timer0 and 3 for Timer1.
       Note that it is not required to clear timer flag TFx.
6.                 To stop the timer, clear TRx in the end of subroutine. Otherwise it will restart from 0000H in case of modes 0 or 1 and from initial values in case of mode 2.
7.                 If the Timer has to run again and again, it is required to reload initial values within the routine itself (in case of mode 0 and 1). Otherwise after one cycle timer will start counting from 0000H.
 
Example code
Timer interrupt to blink an LED; Time delay in mode1 using interrupt method
// Use of Timer mode0 for blinking LED using interrupt method
// XTAL frequency 11.0592MHz 
#include<reg51.h>
sbit LED = P1^0; 		//LED connected to D0 of port 1

void timer(void) interrupt 1 		//interrupt no. 1 for Timer 0
{
	led=~led; 		//toggle LED on interrupt
	TH0=0xFC;		// initial values loaded to timer
	TL0=0x66;
}
main()
{
	TMOD = 0x01; 		// mode1 of Timer0
	TH0 = 0xFC;		// initial values loaded to timer
	TL0 = 0x66;
	IE = 0x82;		// enable interrupt
	TR0 = 1;		//start timer
	while(1);		// do nothing  
}
 

Programming External Interrupts

2. Programming External Interrupts
The external interrupts are the interrupts received from the (external) devices interfaced with the microcontroller. They are received at INTx pins of the controller. These can be level triggered or edge triggered. In level triggered, interrupt is enabled for a low at INTx pin; while in case of edge triggering, interrupt is enabled for a high to low transition at INTx pin. The edge or level trigger is decided by the TCON register. The TCON register has following bits:
 
 
Setting the IT0 and IT1 bits make the external interrupt 0 and 1 edge triggered respectively. By default these bits are cleared and so external interrupt is level triggered.
 
Note : For a level trigger interrupt, the INTx pin must remain low until the start of the ISR and should return to high before the end of ISR. If the low at INTx pin goes high before the start of ISR, interrupt will not be generated. Also if the INTx pin remains low even after the end of ISR, the interrupt will be generated once again. This is the reason why level trigger interrupt (low) at INTx pin must be four machine cycles long and not greater than or smaller than this.
 
Following are the steps for using external interrupt :
1.        Enable external interrupt by configuring IE register.
2.        Write routine for external interrupt. The interrupt number is 0 for EX0 and 2 for EX1 respectively.
 
Example code
//Level trigger external interrupt
void main()
{
	IE = 0x81;
	while(1);
}
void ISR_ex0(void) interrupt 0
{
	<body of interrupt>
}
Example code
//Edge trigger external interrupt
void main()
{
	IE = 0x84;
	IT1 = 1;
	while(1);
}
void ISR_ex1(void) interrupt 2
{
	<body of interrupt>
}
 

Programming Serial Interrupt

3. Programming Serial Interrupt
To use the serial interrupt the ES bit along with the EA bit is set. Whenever one byte of data is sent or received, the serial interrupt is generated and the TI or RI flag goes high. Here, the TI or RI flag needs to be cleared explicitly in the interrupt routine (written for the Serial Interrupt).
 
The programming of the Serial Interrupt involves the following steps:
1.        Enable the Serial Interrupt (configure the IE register).
2.        Configure SCON register.
3.        Write routine or function for the Serial Interrupt. The interrupt number is 4.
4.        Clear the RI or TI flag within the routine.
 
Example code
Send ‘A’ from serial port with the use of interrupt
// Sending ‘A’ through serial port with interrupt
// XTAL frequency 11.0592MHz 
void main()
{
	TMOD = 0x20;
	TH1 = -1;
	SCON = 0x50;
	TR1 = 1;
	IE = 0x90;
	while(1);
}
void ISR_sc(void) interrupt 4
{
	if(TI==1)
	{
		SBUF = ‘A’;
		TI = 0;
	}
	else
		RI = 0;
}
Example code
// Receive data from serial port through interrupt
// XTAL frequency 11.0592MHz 
void main()
{
	TMOD = 0x20;
	TH1 = -1;
	SCON = 0x50;
	TR1 = 1;
	IE = 0x90;
	while(1);
}
void ISR_sc(void) interrupt 4
{
	unsigned char val;
	if(TI==1)
	{
		TI = 0;
	}
	else
	{
		val = SBUF;
		RI = 0;
	}
}

 Programming Multiple Interrupts

Programming multiple interrupts
Multiple interrupts can be enabled by setting more than one interrupts in the IE register. If more than one interrupts occur at the same time, the interrupts will be serviced in order of their priority. By default the interrupts have the following priorities in descending order:
 
Default priority order of Interrupts
Interrupt
Symbol
External0
EX0
Timer0
ET0
External1
EX1
Timer1
ET1
Serial
ES
Timer2
ET2
 
The priority of the interrupts can be changed by programming the bits of Interrupt Priority (IP) register. The IP register has the following bit configuration:
 
 
First two MSBs are reserved. The remaining bits are the priority bits for the available interrupts.
Bit
Interrupt
Symbol
PX0
External0
EX0
PT0
Timer0
ET0
PX1
External1
EX1
PT1
Timer1
ET1
PS
Serial
ES
PT2
Timer2
ET2
 
Setting a particular bit in IP register makes the corresponding interrupt of the higher priority.
For example, IP = 0x08; will make Timer1 priority higher. So the interrupt priority order will change as follows (in descending order):
 
IP = 0x08
Default Priority
Changed Priority
EX0
ET1
ET0
EX0
EX1
ET0
ET1
EX1
ES
ES
ET2
ET2
 
More than one bit in IP register can also be set. In such a case, the higher priority interrupts will follow the sequence as they follow in default case.
For example, IP = 0x0A; will make Timer0 and Timer1 priorities higher. So the interrupt priority order will change as follows (in descending order):
 
IP = 0x0A
Default Priority
Changed Priority
EX0
ET0
ET0
ET1
EX1
EX0
ET1
EX1
ES
ES
ET2
ET2
 
Note that the Timer 0 and 1 have been assigned higher priorities in the same sequence as they follow in default case.
Example code
// Toggle LEDs by Timer and External Interrupt
#include<reg51.h>
sbit led_timercontrol = P1^0;
sbit led_externalcontrol = P1^0;
void external(void) interrupt 0
{
	led_externalcontrol = ~ led_externalcontrol;
}

void timer(void) interrupt 1
{
	led_timercontrol = ~ led_timercontrol; 
}
main()
{
	TMOD = 0x01;
	TH0 = 0x00;
	TL0 = 0x00;
	IE = 0x83;
	TR0 = 1;	
	while(1);
}

]]>]]>