Arduino Interrupt Microcontroller
Basic Arduino Interrupt Microcontroller Explanation – Almost all types of microcontrollers, there is a feature called interrupts.
Example of Interrupt:
The teacher is explaining a lesson in front of. Suddenly a student raised his hand to ask.
The teacher stopped her explanation, then answered the student’s question.
After finishing answering, the teacher continued to explain the lesson again.
Well, these students are said to have interrupted when the teacher explained their lesson.
It is the same as a microcontroller.
The microcontroller by default will read the program lines one by one to the end, then loop to read the program from the beginning again and so on.
The process of reading this program line is called Polling, the flow is Setup and Looping.
When there is an interrupt from a pin, the microcontroller will stop the reading process and do what the pin asks (see the picture in the interrupt flow below).
Why We Need Interrupts?
We take this example:
We have a program to turn On the LED and turn Off for 3 second.
In the program, we add a button reading function.
Approximately the flow is like this:
Read the button -> LED ON -> wait 3 seconds -> LED OFF -> wait 3 seconds (loop)
If we press the button to coincide with a delay of 500ms when the LED is ON, then the microcontroller will read the button after the 5500ms delay, because it is waiting for the delay from the LED to OFF.
Of course this will make the microcontroller have a delay giving answers when the button is pressed.
Therefore, we must use Interrupt.
When the button has used an interrupt system and the button is pressed to coincide with a delay of 500ms when the LED is ON, the microcontroller will stop reading the program immediately and immediately give an answer from the button pressed.
Interrupt Flow on Microcontroller
This interrupt system is in the ISR (Interrupt Status Register) register. If you don’t know what a register is, please read the explanation of the microcontroller register.
To create an interrupt program, we must understand what an Interrupt Service Routine (ISR) is.
Interrupt Service Routine (ISR) is not the same as Interrupt Status Register (ISR)!
Interrupt Service Routine is a special function that contains a specific program.
We can illustrate the Interrupt flow as in the following image:
Based on the image of the interrupt register address above, the interrupt source on the ATMega328 microcontroller itself is divided into 2, namely:
- External Interrupt.
This interrupt uses the microcontroller pins. On the ATmega328 microcontroller, there are 3 interrupts or 3 interrupt pins.
1 is RESET, 2 again is the interrupt named INT0 and INT1. - Internal Interrupts
Internal interrupt is a type of interrupt that can be manipulated through programs such as WatchDog Interrupt, Timer / Counter Interrupt, SPI Communication, Serial Communication, ADC, EEPROM, and Analog Comparator.
a. Interrupt Pin On ATMega328
The pins used for interrupts are PD2 (INT0) and PD3 (INT1) pins. Pay attention to the following ATMega328 pinout:
b. Interrupt Terms In order to work
However, there must be 3 conditions that must be met for the interrupt to work, including:
- Global Interrupt is Enabled
By default, Arduino has automatically activated Global Interrupt. If you don’t use Interrupt, then you have to activate it manually. - Individual Interrupt is Activated
This means that we have to activate an interrupt by setting the register bits via the interrupt address itself. Suppose we want to use INT0, then we have to set the registers corresponding to INT0. - Interrupt condition met
This is a program state, such as “If the interrupt on pin INT0 occurs in the” Falling “state, then do something” “.
Program Basic Interrupt Access Register
We already know the conditions for an interrupt to be used, a global interrupt is active, an individual interrupt is active and the conditions are met.
On the ATmega328, the Global Interrupt Settings are located in the “Status Register” register (see datasheet, page 27), pay attention to the following picture:
How to activate a global interrupt is:
>> sei ();
If you need to turn off the global interrupt, then the command is:
>> cli ();
After the Global Interrupt is activated, then we will then activate the Individual Interrupt.
So, we have to determine when the pulse condition is what the interrupt is detected.
There are 4 pulse conditions, namely LOW, HIGH, RISING and FALLING. Look at the following picture:
After we determine the condition of the pulse that we want to use, then we must set the pulse condition to an “Interrupt Control Register A”.
In Individual Interrupt, there are 2 more registers that we use, the first register to detect the trigger Interrupt and the second register to activate the interrupt itself.
The trigger interrupt register will read the pulse conditions on the Interrupt Pin. This register has the name EICRA (see datasheet, page 89).
Meanwhile, the register to activate the Interrupt has the name Register EIMSK (see datasheet on page 90).
Let’s look at the EICRA register first to find out the settings in its use. Look at the following picture:
Bit 1 & 0 for INT0.
Bit 3 & 2 for INT1.
Bit 0 is named ISC00
Bit 1 is named ISC01
Bit 2 is named ISC10
Bit 3 is named ISC11
Conditions of Bit 1 & 0 for INT0:
If 00 means low INT0 generates an interrupt request.
If 01 means Any logical change on INT0 results in an interrupt request.
If 10 means “Falling Edge” Condition of INT0 generates an interrupt request
If 11 means “Rising Edge” Condition of INT0 generates an interrupt request.
Conditions of Bit 3 & 2 for INT1:
00 means a low INT1 Level resulting in an interrupt request.
If 01 means Any logical change on INT1 results in an interrupt request.
If 10 means “Falling Edge” State of INT1 generates an interrupt request
If 11 means “Rising Edge” Condition of INT1 generates an interrupt request.
In the example program in this tutorial we will use Interrupt INT0 with a Falling Edge pulse condition.
Therefore, we must set the 1st & 0th bits in the EICRA register with the values:
Bit 1 (ISC01) has a value of 1
Bit 0 (ISC00) has a value of 0.
The way to set the bit value is:
>> EICRA | = (1 << ISC01); // set 1st bit as value 1
>> EICRA & = ~ (1 << ISC00); // set bit 0 with value 0
Then, after we determine the pulse condition, the final step is to activate the Indiviual Interrupt itself.
To activate it, we use the EIMSK Register.
To activate INT0 is to use the command:
>> EIMSK | = (1 << INT0);
After all the 2 conditions above are met, the 3rd condition is to determine the Interrupt condition.
In a typical Arduino program, the compiler will perform certain tasks using a function, such as:
void loop()
{
}
or
void deteksi_tombol()
{
}
However, when you use an Interrupt, the function of the interrupt is written as:
ISR(INT0_vect)
{
}
The ISR () {} function will tell the compiler that it should run the Interrupt Service Routine if there is an interrupt on the INT0 pin.
Okay, here we will demonstrate in a real program. We will make the LED program live for 3 seconds and the LED to turn off for 3 seconds. This we assume the name is LED Blink and connected to pin 0 on PORTD.
Then, we add an LED to pin 1 of the PORTD. We name it LED Interrupt.
Also we will connect a button to pin INT0, to be precise to pin 2 on portd.
When the interrupt button is pressed, the microcontroller will turn off the Blink LED and turn on the Interrupt LED. After that the program will turn on the Blink LED again.
void setup()
{
//set pin 1 and 3 of PORTD to OUTPUT
DDRD = B00000011;
//Falling Edge INT0 Generate
EICRA |= (1 << ISC01);
EICRA |= (1 << ISC00);
//Enable Interrupt for INT0
EIMSK |= (1 << INT0);
//Enable global interrupt
sei();
}
void loop()
{
PORTD = B00000001; //led blink turn On
delay(3000);
PORTD = B00000000; //led blink turn Off
delay(3000);
}
ISR(INT0_vect)
{
PORTD = B00000010; //led interrupt Turn On
}
That is all. I hope this article is useful.