Programming Atmega328P External Interrupt

 The ATMega328 microcontroller, which is commonly used in Arduino boards, has two external interrupts: INT0 and INT1. These external interrupts allow the microcontroller to respond to external events or signals asynchronously, without the need for continuous polling of input pins. It is similar to  Programming ATMega328 Pin Change Interrupt but the main difference is external interrupt has higher(actually highest) priority than pin-change interrupt.

Here's a brief overview of INT0 and INT1 interrupts on ATmega328P:

External Interrupt INT0

  1. Associated with PD2 (pin 2) on the ATmega328P.
  2. Triggered by any logical change (rising edge, falling edge, or level change) on the INT0 pin, depending on the configuration in the EICRA register.
  3. Can be used to trigger an interrupt service routine (ISR) that responds to events such as button presses, sensor readings, or other external signals.

External Interrupt INT1

  1. Associated with PD3 (pin 3) on the ATmega328P.
  2. Triggered by any logical change (rising edge, falling edge, or level change) on the INT1 pin, depending on the configuration in the EICRA register.
  3. Can be used as a second external interrupt to trigger another ISR for handling additional external events or signals.

Both INT0 and INT1 interrupts can be configured to trigger on either rising edge, falling edge, or level change using the EICRA register. Additionally, they can be enabled or disabled individually using the EIMSK register. When an interrupt occurs, the microcontroller will automatically jump to the ISR associated with that interrupt and execute the code inside the ISR. It's important to keep the ISR code short and efficient, as interrupts can disrupt the normal flow of program execution.

External interrupts are a powerful feature of the ATmega328P microcontroller, as they allow for efficient and timely handling of external events or signals without the need for continuous polling of input pins. They are commonly used in applications where real-time responsiveness is required, such as in robotics, automation, and sensor-based systems. Proper configuration and use of external interrupts can greatly enhance the functionality and performance of your ATmega328P-based projects. 

External Interrupt INT0 Program Code

The following program is a basic code that sets up the ATmega328P microcontroller to respond to external interrupts on INT0, and toggles an LED when the interrupt is triggered. It demonstrates the basic steps for configuring and using external interrupts in AVR microcontrollers.

#include <avr/io.h>
#include <avr/interrupt.h>

// Function prototype for the interrupt service routine (ISR)
ISR(INT0_vect);

int main(void){

	DDRD |= (1<<PD7);	//set PD7 as output for LED
    // Set PD2 (INT0 pin) as input
    DDRD &= ~(1 << PD2);

    // Enable internal pull-up resistor for PD2
    PORTD |= (1 << PD2);

    // Configure external interrupt INT0
    EICRA |= (1 << ISC00);  // Trigger interrupt on any logical change
    EIMSK |= (1 << INT0);  // Enable external interrupt INT0

    // Enable global interrupts
    sei();

    while (1)
    {
        // Main program loop
    }

    return 0;
}

// Interrupt service routine (ISR) for INT0
ISR(INT0_vect){
    PORTD ^= (1<<PD7);
}

 This code demonstrates the use of external interrupt INT0 on the ATmega328P microcontroller. Let's go through the code step by step:

1. Including Header Files:

#include <avr/io.h> #include <avr/interrupt.h>

The code includes two header files, "avr/io.h" for AVR I/O operations and "avr/interrupt.h" for handling interrupts in AVR microcontrollers.

 2. ISR Function Prototype:

ISR(INT0_vect);

This declares the Interrupt Service Routine (ISR) for the INT0 interrupt. The ISR is a function that will be executed automatically when the INT0 interrupt is triggered.

3. Main Function:

int main(void){
    // Code for setting up I/O and interrupts
}

The main function is the entry point of the program. It sets up the I/O and interrupts for the microcontroller.

4. I/O Configuration:

DDRD |= (1<<PD7);	//set PD7 as output for LED
DDRD &= ~(1 << PD2); // Set PD2 as input

This configures PD7 (pin 7) as an output for an LED, and PD2 (pin 2) as an input for the INT0 interrupt.

5. Pull-up Resistor Configuration:

PORTD |= (1 << PD2); // Enable internal pull-up resistor for PD2

This enables the internal pull-up resistor for PD2, which ensures that the pin is pulled to a logic high level when not connected to any external signal.

6. External Interrupt Configuration:

EICRA |= (1 << ISC00); // Trigger interrupt on any logical change
EIMSK |= (1 << INT0); // Enable external interrupt INT0

This configures the external interrupt INT0 to trigger on any logical change (rising edge, falling edge, or level change) on PD2, and enables the INT0 interrupt.

7. Global Interrupt Enable:

sei(); // Enable global interrupts

This enables global interrupts, allowing the microcontroller to respond to interrupts.

8. Infinite Loop:

while (1) {
    // Main program loop
}

The program enters an infinite loop, where the main program logic can be placed.

9. ISR Implementation:

ISR(INT0_vect){
    PORTD ^= (1<<PD7);
}

This is the implementation of the ISR for the INT0 interrupt. When the interrupt is triggered, the ISR is executed, which toggles the state of PD7 (pin 7), causing an LED connected to that pin to toggle on and off.

 Atmega328P External Interrupt INT0 Hardware Connection

Following shows the circuit diagram that uses INT0 interrupt, that is a push button switch is connected to the interrupt 0 pin which is PD2 pin. When the push button is pressed, external interrupt is triggered and the LED connected to PD7 is turned on.

External Interrupt INT0

External Interrupt INT1 Program Code

 The programming of external interrupt INT1 is similar to programming the INT0 external interrupt. The following is code that uses external interrupt INT1 instead of INT0.

#include <avr/io.h>
#include <avr/interrupt.h>

// Function prototype for the interrupt service routine (ISR)
ISR(INT1_vect);

int main(void){

	DDRD |= (1<<PD7);	//set PD7 as output for LED
    // Set PD3 (INT1 pin) as input
    DDRD &= ~(1 << PD3);

    // Enable internal pull-up resistor for PD3
    PORTD |= (1 << PD3);

    // Configure external interrupt INT1
    EICRA |= (1 << ISC10);  // Trigger interrupt on any logical change
    EIMSK |= (1 << INT1);  // Enable external interrupt INT1

    // Enable global interrupts
    sei();

    while (1)
    {
        // Main program loop
    }

    return 0;
}

// Interrupt service routine (ISR) for INT1
ISR(INT1_vect){
    PORTD ^= (1<<PD7);
}

The main differences in this external interrupt INT1 code compared to the previous INT0 are:

  • DDRD and PORTD registers are used to configure and control PD3 (pin 3) which corresponds to INT1.
  • EICRA and EIMSK registers are used to configure and enable external interrupt INT1.
  • The ISR is defined as ISR(INT1_vect) instead of ISR(INT0_vect) to correspond to the INT1 interrupt vector.
  • PD3 (pin 3) is used as the input for the INT1 interrupt, and the internal pull-up resistor is enabled for PD3 using PORTD |= (1 << PD3).

 Important Registers for External Interrupt

The following are important registers for configuring ATmega328p external interrupts.

EICRA – External Interrupt Control Register A

 

EICRA – External Interrupt Control Register A

interrupt sense control

 EIMSK – External Interrupt Mask Register

EIMSK – External Interrupt Mask Register
EIFR – External Interrupt Flag Register

EIFR – External Interrupt Flag Register
 

References and Further Readings

[1] Programming ATmega328P ADC Interrupt

[2] Programming ATmega328P Input Capture with Interrupt

[3] ATmega328p LED Blink Programming Tutorial 

 

Post a Comment

Previous Post Next Post