At any given instant, multiple processes can be running in the 8051. Additionally, a number of external devices can also be connected to it at the same time. So it’s safe to say that multiple peripherals or processes could require the CPU at any given moment. As the 8051 has a single-core CPU it can tend to only one task at a given instant of time. It’s natural for a question to arise as to what happens when two resources need the CPU at the same time? Well, this is the scenario where interrupts come to our rescue.
An interrupt is a signal sent by hardware or software processes calling for the immediate attention of the CPU. Once the CPU receives this signal it stops whatever it is doing and takes care of that particular resource. So if you look at it, an interrupt is similar to an urgent phone call you might get while you are watching the telly and you have to make a decision to answer the call depending on who’s calling.
How many types of interrupts can 8051 handle?
The 8051 has a total of six interrupts and each interrupt has a designated interrupt service routine (ISR)/interrupt handler assigned to it. The ISR is a predefined code that is stored at a particular memory location in the ROM that the microcontroller executes when the designated interrupt arises. A table known as the “interrupts vector table” is responsible for storing the address of the ISR. Check out the interrupt vector table for 8051 below. (Topmost interrupt has the highest priority).
|Interrupt||ROM location of its ISR||Pin||Flag clearing|
|External hardware interrupt 0(INT0)||0003H||P3.2(12)||Auto|
|Timer 0 interrupt(TF0)||000BH||Auto|
|External hardware interrupt 1(INT1)||0013H||P3.3(13)||Auto|
|Timer 1 interrupt(TF1)||001BH||Auto|
|Serial communication interrupt(RI and TI)||0023H||Programmer clears it|
If you look closely at the table you will realize that except the Reset interrupt’s ISR, all other ISRs occupy 8 bytes of space. The Reset interrupt’s ISR, however, occupies only 3 bytes. This is a very important observation and you should keep in mind the sizes of each ISR.
What happens when an interrupt occurs and you have a code larger than 8-bytes to run?
In 8051 you can nest jumps in an ISR to increase this memory space. We will talk in detail about this feature below.
Interrupts in modern 8051 variants
In the case of a few modern microcontrollers with 8051 IP cores, the number of interrupts is higher. For example, in the case of C8051F96x by Silabs the number of interrupts is 16. These include an advance AES encryption interrupt, battery supply monitor interrupt, and an ADC conversion interrupt. Whenever you pick up an 8051 variant, make sure to go through its datasheet to understand any upgrades that the manufacturer might have made.
What happens inside the microcontroller when an interrupt occurs?
To get a better understanding of what happens when an interrupt occurs, let us take a peek at what happens inside the microcontroller. We will run the earlier used analogy parallel to the explanation.
- The CPU of the microcontroller is busy performing a task (like you binge-watching a show) when it receives an interrupt from a certain resource (Call on your phone). At this moment the CPU stops whatever it is doing and takes care of the resource which causes the interrupt. (You decided that you’d like to pause the show and take the call.)
- Hang on though. You’ve paused your show. Once the call ends, you will continue watching from where you left off. Similarly, the microcontroller will take a moment, finish the current execution, store the address of the next instruction that it has to come back to on the stack and then service the interrupt by branching to the address of the ISR.
- How does it branch to the ISR? Simple, it stores the addresses of all the interrupt service routines in the memory in an interrupt vector table.
- It retrieves the address, stores it in the program counter, and branches to the ISR.
- Meanwhile, when the interrupt is being executed, all the remaining lower and equal priority interrupts are latched and waiting for the current ISR to end.
- The ISR executes until it reaches the RETI instruction.
- Once it encounters the RETI keyword, the latched interrupts (if available) are now active and execute their respective ISRs. Else, the address of the next instruction that would have been executed had an interrupt not arisen is fetched from the stack into the PC and normal execution resumes. (Your call is over and you can resume your show! Yay!)
This whole process is quite similar to how the CALL instruction transfers control in case of branching operations. Now that you have a basic understanding of how an interrupt works, let’s have a look at how to set it up for the 8051 microcontroller.
Two registers which help manage interrupts
By default, all the interrupts on the 8051 microcontroller are disabled. Hence, you need to use the Interrupt Enable register to enable them. We had studied about the IE register in our post on the Special Function Registers in 8051. The location of this register is A8H in the SFR memory space and it is bit addressable. Let’s recap.
Interrupt Enable register
The structure of the IE register is given below and all the bits are described thereafter.
- EA: Enables the interrupts in 8051. By default, it is set to zero. You need to place a 1 here to enable all interrupts. This bit is the Master Control.
- ES: Serial communication interrupt. Write 1 to enable, 0 to disable.
- ET1: Interrupt for timer 1. Write 1 to enable, 0 to disable.
- EX1: External interrupt 1 (p3.3). Write 1 to enable, 0 to disable.
- ET0: Interrupt for timer 0. Write 1 to enable, 0 to disable.
- EX0: External interrupt 0 (p3.2). Write 1 to enable, 0 to disable.
- The rest of the bits can’t be used by the programmer.
Now comes the question of what happens when two interrupts occur at the same time? Or to continue our analogy, what happens when you have two phones and both of them ring at the same time while you are watching the telly. Which one do you answer?
Interrupt priorities in 8051
The interrupts in the 8051 microcontrollers have certain priorities assigned to them. This helps the microcontroller decide which interrupt to service first if two of them occur at the same time. The priorities of the interrupts are as follows:
- External interrupt 0
- Timer interrupt 0
- External interrupt 1
- Timer interrupt 1
- Serial interrupt
To change the priorities of these five interrupts, the Interrupt Priority register is used. This is another register that we studied in our post on SFRs in 8051. Just like the IE register, this register is bit addressable and placed at B8H in the SFR memory space.
If any of the bits in the IP register has a value one its priority of that interrupt is increased
- PT2: Increases the priority of timer 2 (for 8052 only)
- PS: Increases the priority of the serial interrupt
- PT1: Increases the priority of timer 1
- PX1: Increases the priority of external interrupt 1
- PT0: Increases the priority of timer 0
- PX1: Increases the priority of external interrupt 0
Programming and understanding each interrupt
Now that we have a basic understanding of interrupts in general, let us look at how the different types of interrupts are programmed to get a more thorough understanding of the concept.
Interrupts in timers
We would advise you to go through our post on timers/counters in 8051 to understand how they work and then return to this section. If you are already well acquainted with that topic, let’s begin!
In this case, we are going to generate an internal interrupt that interrupts the processor in the case of an internal event. The internal event, in this case, is the timer register overflowing and setting the TF flag.
When we use timers without interrupts we use a method called polling. In the case of polling, the microcontroller continuously checks the TF1/TF0 flag bit till the timer overflows. During this time it cant perform any other task, which if you ponder over, is a waste of the CPU’s resources. I mean it’s just waiting for something to happen and can’t do anything till that event occurs. Using interrupts with timers solves this problem.
When we use interrupts with timers the CPU doesn’t continuously check the TF1/TF0 flag instead it performs other tasks and comes back to the timer only when the TF1/TF0 flag is raised. Once the flag is raised the CPU stops whatever it’s doing and executes the ISR for a particular timer. Look at the diagram given below to get a better understanding of the same (the diagram is for timer 1).
Note: Once the RETI instruction executes it sets TF1/TF0 flag to 0.
Program to execute internal interrupt
ORG 0000H; starting address for the microcontroller LJMP MAIN; used to bypass the memory which store the interrupt service routine ORG 001BH; memory location which holds the interrupt service routine for TF1 MOV R3,P1.3; stoes data in R3 which comes from port 1.3 RETI; used to exit the interrupt subroutine ORG 0030H; Memory location where the program code (i.e MAIN) is kept MAIN: MOV TMOD,# 10H; selects timer 1 mode 1 MOV TL1, #00H; loads 00H into the TL1 register of timer 1 MOV TH1, #00H; loads 00H into the TH1 register of timer 1 MOV IE, #1000 1000B; enables interrupt for timer 1 SETB TR1; starts the timer MOV R2,#130; moves 100 into r2 which acts as a counter AGAIN: ADD A,#02; adds 2 into the accumulator till r2!=0 DJNZ R2,AGAIN; decrements value in r2 and jumps to again label till value !=0 MOV R5,A; Moves the result into R5
In the example mentioned above the CPU keeps adding 2 to the accumulator 130 times but once the timer overflows it stores the data at port 1.3 to R3.
Two ports on the 8051 microcontroller; pins 12 (INT0) and 13 (INT1) in port 3 can be used as external interrupts. Once the microcontroller gets a signal from an external device on these ports, it interrupts its operation and starts executing the ISR meant for the external interrupt. The microcontroller can be interrupted by two different signals. These include an edge-triggered (falling edge) signal or a level-triggered signal.
By default, the external interrupts are level triggered. When the pins 12/13 receive a low-level signal for a minimum duration of four machine cycles an interrupt occurs. This low-level signal must be transferred to a high level before the microcontroller reaches the RETI instruction in the ISR. If the signal remains low after the RETI instruction, it will interrupt the microcontroller again. Due to this, the microcontroller can get stuck in a loop of interrupts.
To configure ports 12/13 as edge-triggered interrupts the TCON register is used. The TCON register is bit addressable. Setting IT0/IT1 bits of the TCON register configures these ports as edge-triggered interrupts. A falling edge on the ports during this mode interrupts the microcontroller. This signal should be kept high for 1 machine cycle and then low for another 1 machine cycle. This enables the microcontroller to identify the signal easily.
IE0 and IE1 in the TCON register are used to tackle the problem of looping inside interrupts, which occurs during external edge-triggered interrupts. The CPU sets IE1(P3.3)/IE0(P3.2) as 1 when it encounters an edge-triggered signal at any of the two ports. When either of this bit is 1, the CPU ignores any other falling edge signal on the port, preventing reoccurring interrupts.
Program to execute the external interrupt with falling edge
ORG 0000H; starting address for the microcontroller LJMP MAIN; used to bypass the memory which store the interrupt service routine ORG 0013H; memory location which holds the interrupt service routine for INT1 MOV R3,P3.3; stores data in R3 which comes from the port 3.3 RETI; used to exit the interrupt subroutine ORG 0030H; Memory location where the program code (i.e MAIN) is kept MAIN: MOV TMOD,# 10H; selects timer 1 mode 1 MOV TL1, #00H; loads 00H into the TL1 register of timer 1 MOV TH1, #00H; loads 00H into the TH1 register of timer 1 MOV IE, #1000 1000B; enables interrupt for timer 1 SETB TR1; starts the timer SETB IE1; makes p3.3 edge triggered MOV R2,#130; moves 130 into r2 which acts as a counter AGAIN:ADD A,#02; adds 2 into the accumulator till r2!=0 DJNZ R2,AGAIN; decrements value in r2 and jumps to again label till value !=0 MOV R5,A; Moves the result into R5
In the example mentioned above the CPU keeps adding 2 to the accumulator 130 times but once an external interrupt occurs at port 3.3 it stores the data at that port in R3
Interrupts in serial communication
Interrupts are widely used in serial communication and we will talk about them in great detail in the next article on UART in 8051. The serial interrupt mentioned in the list of the five interrupt types in 8051 will also be covered in that post.
Interrupt inside an interrupt
Another question you might have is what happens when an interrupt occurs when the microcontroller is servicing another interrupt? Or to extend our analogy one last time, what happens when you receive a call on the second phone while you are answering the call on the first phone?
In the 8051 microcontroller a higher priority interrupt can interrupt a lower priority interrupt in execution. But if a lower priority interrupt occurs it is serviced only once the higher priority interrupt is serviced.
So if it’s your mom’s call while you are speaking to your friend, you are going to keep the friend’s call on hold and answer your mom’s. IF it was the other way around, you will finish your conversation with your mom and then attend your friend’s call on the second phone.
Jumps in interrupts
As mentioned earlier, each ISR has a memory space of 8 bytes (except reset which has a space of 3 bytes). To increase the memory space in an interrupt service routine, jumps are used.
Let us look at an example in which we generate a square wave that has a high portion of 1085 microseconds and a low portion of 15 microseconds at port 2.1 and transfer data from port 0 to port 1 simultaneously.
ORG 0000H; Starting address when the microcontroller starts LJMP MAIN; Used to bypass the Interrupt service routine ORG 001BH; Location for ISR of timer 1 LJMP ISR_T1; Jumps to another memory location for more memory requirement of code ORG 0030H; location where program code is stored MAIN: MOV TMOD,#10H; Selects timer 1 mode 1 MOV P0,#0FFH; Sets port 0 as input port MOV TL1,#018H; Loads value 18H into TL1 MOV TH1,#0FCH; Loads value FCH into TH1 MOV IE, #88H; Enables interrupt for timer 1 SETB TR1; starts the timer BACK: MOV A, P0; Moves data from Port0 to the accumulator MOV P1, A; Moves data from the accumulator to Port1 SJMP BACK ISR_T1: CLR TR1; Stops the timer CLR P2.1; Makes port 2.1 low MOV R2,#4 Moves 4 into R2(2 machine cycles) HERE: DJNZ R2, HERE; Loop to continue looping(instruction take 4x2=8 clock cycles) MOV TL1,#18H; Loads value 18H into TL1(2 machine cycles) MOV TH1,#FCH; Loads value FCH into TH1(2 machine cycles) SETB TR1; Starts a timer again SETB 2.1; Makes port 2.1 high again RETI; Returns control to main
We hope that reading this article has made the concept of interrupts in the 8051 crystal clear. But if you have any doubts feel free to contact us through the comments section and we will get back to use in a jiffy.