Example Code for Arduino-IO Interrupt
Last revision 2025/12/13
This article provides an example code for setting up IO interrupts on Arduino using the MCP23017 library, covering hardware and software preparations, wiring diagrams, and demonstrating the interrupt service functions to detect changes and execute actions via serial port.
Hardware Preparation
- DFR0216-2 DFRduino UNO R3 with IO Expansion Shield and USB Cable A-B x 1
- DFR0626 MCP23017 IIC to 16 Digital IO Expansion Module x1
- DFR0029 Gravity: Digital Push Button x1
- Gravity: Bright LED Module x1
Software Preparation
- Download Arduino IDE: Click to download Arduino IDE
- Download the DFRobot_MCP23017 Library: DFRobot_MCP23017 Library
- About how to install the library?
Wiring Diagram

Other Preparation Work
Connect 2 buttons to IO expansion board, one to a pin of port eGPA(eg: eGPA0), the other to a pin of port eGPB(eg: eGPB0). Connect INTA to the external interrupt pin0 of UNO, INTB to external interrupt pin1 of UNO.
Sample Code
/*!
* @file ioInterrupt.ino
* @brief IO interrupt, set a pin of a port group(A or B) IO to interrupt mode. When an interrupt occurs on the related port group, pin INTA(group A) or INTB(group B) will output a High level.
* INTA and INTB are used to detect if an interrupt occurs on the pin of port eGPA and eGPB respectively; connect pin INTA and INTB to main-controller's external interrupt 0 and 1 respectively.
* @n Experiment phenomenon: when the signal change of pin INTA or INTB is detected by main-board, the related interrupt service function will be executed to print out which pin was interrupted on serial port.
*
* @copyright Copyright (c) 2010 DFRobot Co.Ltd (https://www.dfrobot.com)
* @licence The MIT License (MIT)
* @author [Arya]([email protected])
* @version V1.0
* @eGPAte 2019-07-18
* @get from https://www.dfrobot.com
* @url https://github.com/DFRobot/DFRobot_MCP23017
*/
#include <DFRobot_MCP23017.h>
DFRobot_MCP23017 mcp(Wire, /*addr =*/0x27);//constructor, change the Level of A2, A1, A0 via DIP switch to revise I2C address within 0x20~0x27.
//DFRobot_MCP23017 mcp;//use default parameter, Wire 0x27(default I2C address)
//Connect 2 buttons to IO expansion board, one to a pin of port eGPA(eg: eGPA0), the other to a pin of port eGPB(eg: eGPB0)
//Connect INTA to the external interrupt pin0 of UNO, INTB to external interrupt pin1 of UNO.
bool intFlagA = false;//INTA interrupt sign
bool intFlagB = false;//INTB interrupt sign
/*Interrupt service function, prototype void func(int index), index represents the pin which is interrupted*/
void gpa0CB(int index){
String description = mcp.pinDescription(index);
Serial.print(description);Serial.println(" Interruption occurs!");
}
void gpb7CB(int index){
String description = mcp.pinDescription(index);
Serial.print(description);Serial.println(" Interruption occurs!");
}
void setup() {
Serial.begin(115200);
#ifdef ARDUINO_ARCH_MPYTHON
pinMode(P0, INPUT);//use mPython external interrupt, connect INTA to pin 0 of mPython.
pinMode(P1, INPUT);//use mPython external interrupt, connect INTB to pin 1 of mPython.
#else
pinMode(2, INPUT);//use UNO external interrupt 0
pinMode(3, INPUT);//use UNO external interrupt 1
#endif
/*wait for the chip to be initialized completely, and then exit*/
while(mcp.begin() != 0){
Serial.println("Initialization of the chip failed, please confirm that the chip connection is correct!");
delay(1000);
}
/*Parameter mode, the available parameter is shown below:
eLowLevel eHighLevel eRising eFalling eChangeLevel
Low-level interrupt High-level interrupt Rising edge interrupt Falling edge interrupt Double edge interrupts
Parameter cb interrupt service function(with parameter)
Prototype void func(int)
*/
mcp.pinModeInterrupt(/*pin = */mcp.eGPA0, /*mode = */mcp.eHighLevel, /*cb = */gpa0CB);//digital pin 0(eGPA0), interrupt in High level. Generate an interrupt when pin 0 is in High level state.INTA output High level.
mcp.pinModeInterrupt(/*pin = */mcp.eGPB7, /*mode = */mcp.eChangeLevel, /*cb = */gpb7CB);//digital pin 15(eGPB7), double edge interrupts. Generate an interrupt when the status of Pin 15 changes. INTB output High level.
#ifdef ARDUINO_ARCH_MPYTHON //
/* mPython Interrupt Pin vs Interrupt NO
* -------------------------------------------------------------------------------------
* | | DigitalPin | P0~P20 can be used as external interrupt|
* | mPython |--------------------------------------------------------------|
* | | Interrupt No | use digitalPinToInterrupt(Pn) to query interrupt number |
* |-----------------------------------------------------------------------------------|
*/
attachInterrupt(digitalPinToInterrupt(P0)/*query Interrupt NO of P0*/,notifyA,RISING);//Enable the external interrupt of mPython P0; rising edge trigger; connect INTA to P0
attachInterrupt(digitalPinToInterrupt(P1)/*query Interrupt NO of P1*/,notifyB,RISING);//Enable the external interrupt of mPython P1; rising edge trigger; connect INTB to P1
#else
/* Main-board of AVR series Interrupt Pin vs Interrupt NO
* ---------------------------------------------------------------------------------------
* | | DigitalPin | 2 | 3 | |
* | Uno, Nano, Mini, other 328-based |--------------------------------------------|
* | | Interrupt No | 0 | 1 | |
* |-------------------------------------------------------------------------------------|
* | | Pin | 2 | 3 | 21 | 20 | 19 | 18 |
* | Mega2560 |--------------------------------------------|
* | | Interrupt No | 0 | 1 | 2 | 3 | 4 | 5 |
* |-------------------------------------------------------------------------------------|
* | | Pin | 3 | 2 | 0 | 1 | 7 | |
* | Leonardo, other 32u4-based |--------------------------------------------|
* | | Interrupt No | 0 | 1 | 2 | 3 | 4 | |
* |--------------------------------------------------------------------------------------
*/
/* microbit Interrupt Pin vs Interrupt NO
* ---------------------------------------------------------------------------------------------------------------
* | | DigitalPin | P0~P20 can be used as external interrupt |
* | microbit |---------------------------------------------------------|
* |(when used as external interrupt, do not need to set it to input mode via pinMode) | Interrupt No | Interrupt NO is pin value, for instance, the Interrupt NO of P0 is 0, P1 is 1. |
* |-------------------------------------------------------------------------------------------------------------|
*/
attachInterrupt(/*Interrupt NO*/0,notifyA,RISING);//Enable external interrupt 0, connect INTA to the main-controller's digital pin: UNO(2),Mega2560(2),Leonardo(3),microbit(P0)
attachInterrupt(/*Interrupt NO*/1,notifyB,RISING);//Enable external interrupt 1, connect INTB to the main-controller's digital pin: UNO(3),Mega2560(3),Leonardo(2),microbit(P1)
#endif
}
/*Interrupt service function*/
void notifyA(){
intFlagA = true;
}
void notifyB(){
intFlagB = true;
}
void loop() {
if(intFlagA){
intFlagA = false;
/*pollInterrupts function is used to poll if an interrupt occurs on a port group
parameter group, the available parameter is shown below: (default value: eGPIOALL):
eGPIOA eGPIOB eGPIOALL
Port groupA Port groupB Port groupA+B
*/
mcp.pollInterrupts(/*group = */mcp.eGPIOA);
}
if(intFlagB){
intFlagB = false;
mcp.pollInterrupts(/*group = */mcp.eGPIOB);
}
}
Result
Press the button on PA0 or PB7, the following result will be printed on the serial port.

Was this article helpful?
