Interrupt Structure of ATmega328

6.4 Development of Program for Functional Check of INT0-interrupt

Refer to Fig-6.5 shown below; MLP program is designed to blink LED (L) continuously. The ISRINT0 program will blink LED2 only for 5 times. The K1 is the interrupting device. The LCD panel is added to monitor MCU-registers’ values at different phases of the executing interrupt process.

Figure-6.5: Arduino UNO based set up for functional check of INTO interrupt

(1) Text/Pseudo/Mixed Codes

Void setup()
{
    L11: Establish link between Interrupt Vector Address (0x0002) of INT0 
           with its corresponding interrupt sub routine (ISRINT0)
    IRQ  INT0  INTF0  0x0002  ISRINT0 
          
         .org   0x0002
          rjmp ISRINT0
            
(a) The codes of the ISRINT0 routine come after the codes of setup() and loop() functions. 
The assembler can always compute the numerical value for the offset of ISR subroutine. 
During final phase of assembly, the symbolic name ISRINT0 is replaced by the numerical 
value of this offset. Upon interruption, the MCU finds the interrupt sub routine at a 
distance given by the operand of the [i]rjmp[/i]instruction. 

(b) In HL Programming, the above task of L11 is carried out by declaring the ISRINT0 as a function with a pre-defined name (ISR) and argument (INT0_vect): ISR(INT0_vect). During compilation time, the compiler understands that the stated subroutine (ISR) will be called upon when there is an interrupt on the INT0-pin whose interrupt vector is 0x0002. 

(c) In HL Programming, the task L11 can also be carried out by declaring another kind of function whose three arguments are passed as symbolic names. These symbolic names have pre-defined meanings; the meanings are transformed into executable binary numbers during compilation time. 

The function: attachInterrupt (arg1, arg2, arg3);

(i) arg1 is a function: [i]digitalPinToInterrupt(2)[/i]. The function says that the ‘Digital Pin 2’ of Arduino, which is solidly connected with INT0(PD2/Pin-4)-line of the ATmega328 will work as interrupt line for Interrupt Type 0. And accordingly, the PD2-line will work as input-line with internal pull-up resistor connected.

(ii) arg2 : ISRINT0. It is a name (any valid identifier is acceptable) which the user must use as a name for the function of his interrupt sub routine like ISRINT0(). There is no argument for this function. The 'INT0' can be deleted; however, it is given for easy remembering that this ISR is due to INT0 interrupt. The arg2 links itself to the correct inetrrupt vector (0x0002) from the 'digitalPin' of the previous argument. 

(iii) arg3 : Trigger level of IRQ-signal (AL< RE, AH, FE, CH). The compiler knows the meanings of these symbolic names and assigned appropriate values into the registers of the MCU.   

//-----------------------------------------------------------------------------------------------------
L12: Initialize LCD as needed (LCD type and Cursor Position)
//---------------------------------------------------------------------------------- 
L13: Configure PD2-line (with internal pull-up) to work as interrupt line for INT0 interrupt
L14: Select trigger level of IRQ-signal (Falling Edge)
L15: Close local INT0-switch for auto vectoring to ISRINT0
L16: Close global I-switch for auto vectoring to ISRINT0
//--------------------------------------------------------------------------------------
L17: Set direction of PB5-line as output to drive L of MLP
L18: Set direction of PD4-line as output to drive LED2 of ISR(INT0_vect)
//----------------------------------------------------------------------------------------------

} 

Void loop()
{
     L21: ON LED (L)
     L22: Insert 1-sec Time Delay
     L23: OFF LED (L)
     L24: Insert 1-sec Time Delay
} 

ISRI(INT0_vect)
{
    L31: Enable global interrupt via I-switch // with this delay() function will not work here
    
    L32: ON LED2
    L33: Insert 1-sec Time Delay
    L34: OFF LED2
    L35: Insert 1-sec Time Delay
    L36: Repeat Step-L32 to L35 for 4 times more.
    
    L37: Return to Main Line Program (MLP)
}

P642 (2) Arduino Coding-A for the program codes of Step-1

#include <LiquidCrystal.h>
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7); //declaration of LCD wiring function
LiquidCrystal lcd (5, A0, A1, A2, A3, A4); //definition of LCD wiring function

Void setup()
{
   //Task of L11 is done by declaring ISR(INT0_vect) function at the end of loop() function

   lcd.begin(16, 2); //L12: 16x2 LCD ; 2-line; each line has 
   lcd.setCursor(1, 0); //L12: DP1 postion of TopLine

    //----- the following six lines connects internal pull-up with PD2-line------------------
    DDRD = B11111011; //L13:  PD2 as input; value has come from data sheet
    bitSet(PORTD, 2); //L13: 
    bitClear(MCUCR, 4); //L13
    //---------------------------------------------------
    EICRA = B00000010; //L14: falling edge trigger level for of INT0; value comes from data sheet
    EIMSK = B00000001; //L15: local INT0-switch is closed; value has come from data sheet
    bitSet(SREG, 7); //L16: Global I-switch is closed; alternate code : sei() ; opposite : cli()

    //---------------------------------------------------
    pinMode(13, OUTPUT); //L17:
    pinMode(4, OUTPUT); //L18:

    lcd.print(EIMSK, 16); //check INT0-bit for 1 before the MLP is interrupted
    lcd.setCursor(5, 0); //
    lcd.print)SREG, 16); // check I-bit for 1 before MLP is interrupted

}

Void loop()
{
    digitalWtite(13, HIGH); //L21:
    delay(1000); //L22:
    digitalWrite(13, LOW); //L23:
    delay(1000); //L24
}

ISR(INT0_vect)
{
    lcd.setCursor(1, 1); //cursor at DP1 bottomLine
    lcd.print(EIMSK, 16); //check INT0-bit for 1 after interruption
    lcd.setCursor(5, 1); 
    lcd.print(SREG, 16); //check I-bit for 0 after interruption

    interrupts(); //L31: Set I-bit of SREG-register; global I-switch is closed

    for (int n=0; n<=4; n++)
   {
      digitalWrite(4, HIGH); //L32:
      delay(1000); //L33:
      digitalWrite(4, LOW); //L34:
      delay(1000); //L35; 
      //--------------------------------------
      reti(); //L37: Return to MLP from ISR
}

(3) Compile and upload P642 of Step-2. Press the interrupting device K1. Check that the interrupt process works as expected. Also, monitor the values of EIMSK- and SREG-registers in the LCD. Decode their contents looking at the data sheet and observe that the I-bit becomes LL after interruption; but, the INT0-bit remains unaffected.

(4) Arduino Instruction Set Summary for Interrupts

P645 (5) Arduino Coding-B for the program codes of Step-1

#include <LiquidCrystal.h>
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7); //declaration of LCD wiring function
LiquidCrystal lcd (5, A0, A1, A2, A3, A4); //definition of LCD wiring function

Void setup()
{
    //Task of L11 is done by declaring ISRINT0() function at the end of loop() function

    lcd.begin(16, 2); //L12: 16x2 LCD ; 2-line; each line has 
    lcd.setCursor(1, 0); //L12: DP1 postion of TopLine

    //----- the following single function does all tasks of----------------------------
    attachInterrupt(digitalPinToInterrupt(2), ISRINT0, FALLING); //L13-L16 

    //---------------------------------------------------
    pinMode(13, OUTPUT); //L17:
    pinMode(4, OUTPUT); //L18:
    lcd.print(EIMSK, 16); //check INT0-bit for 1 before the MLP is interrupted
    lcd.setCursor(5, 0); //
    lcd.print)SREG, 16); // check I-bit for 1 before MLP is interrupted

}

Void loop()

{
    digitalWtite(13, HIGH); //L21:
    delay(1000); //L22:
    digitalWrite(13, LOW); //L23:
    delay(1000); //L24
}

Void ISRINT0()
{
    EIMSK = 0x00;
    lcd.setCursor(1, 1); //cursor at DP1 bottomLine
    lcd.print(EIMSK, 16); //check INT0-bit for 1 after interruption
    lcd.setCursor(5, 1); 
    lcd.print(SREG, 16); //check I-bit for 0 after interruption
    //--------------------------------------------------
    interrupts();; //L31: Set I-bit of SREG-register; global I-switch is closed

    lcd.setCursor (9, 1);
    lcd.print(EIMSK, 16);
   
    for (int n=0; n<=4; n++)
    {
        digitalWrite(4, HIGH); //L32:
        delay(1000); //L33:
        digitalWrite(4, LOW); //L34:
        delay(1000); //L35; 
    }

    reti(); // must be here for the MCU to return to MLP properly
}

(6) Compile and upload P645 program. Press the interrupting switch K1 and check that the interrupt process works as scheduled.

(7) Insert suitable commands at the chosen points of the program P645 in order to verify the validity of the instructions of Step-4.

L64.doc (682 KB)

P642.ino (2.1 KB)

P645.ino (1.84 KB)