This article is written in support of the interrupt tool I wrote for the MCS-51 series. Most of the MCS-51 (8051)
derivatives have a similar architecture when it comes to external interrupt processing, so this article should be
applicable to most of them.
What is an Interrupt?
An interrupt is a signal to the processor that the current code execution should be paused to handle a more urgent task.
Usually this is signalled by a peripheral device that needs immediate attention, such as a timer overflow, data received
on a serial port, or an external event like a button press. This event sets the interrupt request flag in the
microcontroller’s interrupt system.
If the EA (Enable All) bit in corresponding IE (Interrupt Enable) register is set, and the specific interrupt is
enabled, the processor will pause its current task and jump to a predefined memory location called the interrupt vector.
The blog image shows all possible interrupt sources for a typical MCS-51 microcontroller. In modern variants there may be
more interrupt sources, but the basic principles remain the same.
Many MCS-51 derivatives have programmable interrupt priorities, which allow
the user to define which interrupt has precedence over another. If all interrupt priorities are the same the MCS-51
architecture uses a polling scheme to determine which interrupt to service first. By adjusting the priority levels, more critical
interrupts can be serviced before less critical ones, and interrupts of the same priority are handled serially. The MCS-51
supports preemptive interrupt handling, meaning that a higher priority interrupt can interrupt the processing of a lower priority
interrupt.
In instruction processing the following happens if an interrupt is serviced (meaning EA and the specific interrupt enable bit are set):
- The current instruction finishes executing.
- The Program Counter (PC) is pushed onto the stack to save the return address. The interrupt state of all other sources is preserved internally.
- The PC is loaded with the address of the interrupt service routine (ISR) corresponding to the interrupt source.
- The ISR executes, handling the interrupt.
- At the end of the ISR, a
RETI (Return from Interrupt) instruction is executed, which pops the return address from the stack back into the PC. - The processor resumes execution from where it left off before the interrupt occurred.
In addition to the above your compiler may perform additional context saving and restoring for registers that are used
within the ISR. This is to ensure that the main program’s state is preserved correctly.
What makes the MCS-51 architecture interesting is that there is not much that needs to be preserved, as there are only a few
registers. This leads to a practical exceptional low interrupt latency compared to more modern architectures. In an essence
you give up processing speed (i.e. more efficient register use on most modern architectures) for latency. While other
architectures, especially DSPs, use windowing to get around this problem, this also introduces consistency issues if the
windowing runs out. A good example for this are Cadence DSPs
One thing to keep in mind is that the address of the interrupt service routine is fixed and that the interrupt vector
itself does not contain any address mappings. As such the typical pattern is to have a small stub at the interrupt vector
that jumps to the actual ISR, which can be located anywhere in memory. The following example is the address map of the
STC89C52 microcontroller, which is a popular MCS-51 derivative.
As seen above the interrupt vectors are located at fixed memory addresses, this also includes the reset vector at 0000H.
The common way to populate these (your compiler does this for you automatically) is to have a small jump instruction at the vector address
that jumps to the actual ISR. Example,
ORG 0
LJMP MAIN ; 3-byte instruction
LJMP INT0INT ; EXT 0 vector address
ORG 000BH ;Timer 0 vector
LJMP T0INT
ORG 001BH ;Timer 1 vector
LJMP T1INT
ORG 0030H
...
External Interrupts
Leaving aside the internal interrupts (timers, serial ports, etc.) for now, which get covered in other blog posts, let’s look
at the external interrupts. The MCS-51 architecture supports two external interrupts, INT0 and INT1, which are
mapped to pins on the microcontroller. These interrupts can be configured to trigger on either a low-level signal or a falling edge,
depending on the settings in the TCON (Timer Control) register. Modern derivatives such as the STC89C5x series support
up to 4 external interrupts (INT2 and INT3), but the principles remain the same. Some other implementations take this
as far as providing interrupts on a per-port-pin basis, which can be useful in certain applications.
On most classic implementations these external interrupts are active low, meaning that they are triggered when the signal
goes from high to low. A typical implementation is shown as follows.
Pressing the switch causes a negative edge transition as the voltage switches down from logic high (Vcc) to logic low (GND), which
triggers the interrupt. Note that a pull-up resistor is used to ensure that the input pin is at a defined logic high level when the switch is not pressed.
This interrupt can be configured to be either level-triggered or edge-triggered using the IT0 and IT1 bits in the TCON register.
When set to level-triggered, the interrupt is activated as long as the input pin remains low. When set to edge-triggered, the interrupt
is activated only on the transition from high to low.
The button press is one example an external interrupt source, other examples include sensors, communication signals, or
any other external event that requires immediate attention from the microcontroller.
In the Tools section of this blog I have created an interrupt configuration tool that allows you to
easily configure external interrupts for MCS-51 derivatives, using the STC89C5x as a baseline case and generate
code for SDCC.
So conceptually the external interrupt is like your significant other half pulling you away from your work to attend to something
more urgent, like taking out the trash or answering the doorbell. You stop what you’re doing, handle the urgent task, and then return to your previous activity.
Who would not stop for this:
I plan to post more on peripheral interrupts (timers, serial ports, etc.) in future articles.
Good references for further reading:
Published: 2025-10-26
Updated : 2025-10-26