The attachInterrupt() sets a function to be called when an external interrupt occurs.
The external interrupt is triggered by one of INT0, INT1, and PCINT0 to PCINT23. On the Arduino Uno, INT0(pin 2) and INT1(pin 3) can be used.
Controling interrupt
The registers EICRA and EIMSK controls the external interrupt.
EICRA
EICRA contrls how the interrupt is detected.
EICRA
Bit
7
6
5
4
3
2
1
0
Name
-
-
-
-
ISC11
ISC10
ISC01
ISC00
The combination of ISC11 and ISC10 controls the condition of INT1(pin 3), and ISC01 and ISC00 controls that of INT0(pin2).
ISC11/ISC01
ISC10/ISC00
Condition
0
0
Low level
0
1
Any bitwise change
1
0
The falling edge
1
1
The rising edge
EIMSK
The EIMSK(External Interrupt Mask Register) enables and disables external interrupt.
EIMSK
Bit
7
6
5
4
3
2
1
0
Name
-
-
-
-
-
-
INT1
INT0
When the bit is 1, it enables interrupt. Also I bit of the status register need to be 1.
Source Code
The attachInterrupt() is defined in hardware/arduino/avr/cores/arduino/WInterrupts.c as below. Only the souce code for Arduino UNO is quoted. The original source code supports many tips using #if’s.
staticvoidnothing(void){}staticvolatilevoidFuncPtrintFunc[EXTERNAL_NUM_INTERRUPTS]={nothing,nothing,};voidattachInterrupt(uint8_tinterruptNum,void(*userFunc)(void),intmode){if(interruptNum<EXTERNAL_NUM_INTERRUPTS){intFunc[interruptNum]=userFunc;// Configure the interrupt mode (trigger on low input, any change, rising
// edge, or falling edge). The mode constants were chosen to correspond
// to the configuration bits in the hardware register, so we simply shift
// the mode into place.
// Enable the interrupt.
switch(interruptNum){case0:EICRA=(EICRA&~((1<<ISC00)|(1<<ISC01)))|(mode<<ISC00);EIMSK|=(1<<INT0);break;case1:EICRA=(EICRA&~((1<<ISC10)|(1<<ISC11)))|(mode<<ISC10);EIMSK|=(1<<INT1);break;case2:break;}}}
The intFuc[] is an array to store functions when external interrupt occurs. The type of the function is defined as below in hardware/arduino/cores/arduino/wiring_private.h.
The voidFuncPtr is a pointer to function which has no argument and returns void. As EXTERNAL_NUM_INTERRUPTS is defined as 2, the array can hold 2 functions. Initial value is noghint() which dose nothing.
The input is interruptNum, userFunc and mode. The types are uint8_t, void(*)(void) and int. It has no output.
// Configure the interrupt mode (trigger on low input, any change, rising
// edge, or falling edge). The mode constants were chosen to correspond
// to the configuration bits in the hardware register, so we simply shift
// the mode into place.
// Enable the interrupt.
switch(interruptNum){case0:EICRA=(EICRA&~((1<<ISC00)|(1<<ISC01)))|(mode<<ISC00);EIMSK|=(1<<INT0);break;case1:EICRA=(EICRA&~((1<<ISC10)|(1<<ISC11)))|(mode<<ISC10);EIMSK|=(1<<INT1);break;case2:break;}}}
The operation is a little bit difficult( to me), I will dissect them.
22
(1<<ISC00)|(1<<ISC01)
ISC00 and ISC01 are 0 and 1 respectively. 1 « ISC00 is 1(0b00000001) and 1«ISC01 is 2(0b00000010).
Bitwise OR of them is 0b00000011(=3).
22
(EICRA&~((1<<ISC00)|(1<<ISC01)))
Next calculate the bitwise AND of EICRA and ~((1 « ISC00) | (1 « ISC01))).
As ((1 « ISC00) | (1 « ISC01))) is 0b00000011, the bitwise NOT is 0b11111100.
Then calculating bitwise AND of EICRA and 0b11111100 would clear lower 2 bits of EICRA.
Next calculate bitwise OR of mode « ISC00. As ISC00 is 0, it is same as calculate bitwise OR with mode.
22
(EICRA&~((1<<ISC00)|(1<<ISC01)))|(mode<<ISC00)
The mode is one of the LOW, CHANGE, RISING and FALLING and they are 0, 1, 2, 3 respectively.
The value of mode is not checked, if we specify invalid value, it may do something bad.
/*
Copyright (c) 2019 garretlab.
Added source code explanation by garretlab.
*//*
Part of the Wiring project - http://wiring.uniandes.edu.co
Copyright (c) 2004-05 Hernando Barragan
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 24 November 2006 by David A. Mellis
Modified 1 August 2010 by Mark Sproul
*/