MCP23017 Port Expander Library?

Does anyone know of an MCP23017 library which can support chip(s) configured as outputs plus other chips configured as inputs that give interupts for both 'Offs' and 'Ons'?

It doesn't necessarily have to be a library, a stand-alone sketch giving that sort of functionality would be very welcome.

Basically I wish to monitor more than 20 door switches for being triggered when opened or closed, and be able to control several things in response.

There seem to be plenty of examples which can do one thing or another, but I haven't yet been able to find anything that can offer rising and falling interupts AND manage multiple chips. The Adafruit library seems professional, but I can't find an arduino tutorial for it (only for their Ras Pi/ Beaglebone version), and in the arduino examples there is no mention of using multiple expanders, plus the interupt example suggests interupts are generated only when input buttons are pressed and not when they are released. The Centipede library can handle multiple chips as inputs and outputs, and mentions a forthcoming interupt version, but it was promised long ago, and I can't find it.

Does anyone know of anything suitable, please?

Basically you need to read the data sheet of the chip. To use multiple chips just change the I2C address you are using and talk to the registers in the other chip. The three least significant bits of the address are given by the logic levels of the A0 to A2 pins on the chip.

I normally add a .h file with the register names to the Arduino Sketch:-

// hash defines
// Port expander registers
#define IODIR (byte) 0x00
#define IPOL (byte) 0x02
#define GPINTEN (byte) 0x04
#define DEFVAL (byte) 0x06
#define INTCON (byte) 0x08
#define IOCON (byte) 0x0A
#define GPPU (byte) 0x0C
#define INTF (byte) 0x0E
#define INTCAP (byte) 0x10
#define GPIO (byte) 0x12
#define OLAT (byte) 0x14

// Bits in the IOCON register
#define BANK (byte) 0x80
#define MIRROR (byte) 0x40
#define SEQOP (byte) 0x20
#define DISSLW (byte) 0x10
#define HAEN (byte) 0x08
#define ODR (byte) 0x04
#define INTPOL (byte) 0x02

Then I use these two functions to read and write 16 bit values to the registers:-

void gpio_write(int address, int data, int reg) {
  //  Send output register address
  //  Connect to device and send two bytes
  Wire.write(0xff & data);  //  low byte
  Wire.write(data >> 8);    //  high byte

int gpio_read(int address) {
  int data = 0;
 //  Send input register address
  //  Connect to device and request two bytes
  Wire.requestFrom(address, 2);
 if (!Wire.available()) { } // do nothing until data arrives
    data =;

 if (!Wire.available()) { } // do nothing until data arrives
    data |= << 8;
  return data;

Then in the setup function I initialise them like this:-

// Setup I2C devices
   Wire.begin();                      // start the I2C interface
   // initialise port expanders INT internal connected + open drain int
   gpio_write(chip1Address, (MIRROR | ODR)<<8, IOCON);
   gpio_write(chip2Address, (MIRROR | ODR)<<8, IOCON); 
   gpio_write(chip3Address, (MIRROR | ODR)<<8, IOCON);
   gpio_write(chip4Address, (MIRROR | ODR)<<8, IOCON);

Jay98: Hello Electroguard, have you found a solution for this?

Have you read this thread? It contains the solution you require.

I don't understand what that code does.

Then you need to read the data sheet of the MCP23017.

How have you wired up your encoders? Do you have external pull up resistors on them because you have not enabled the internal ones?

I am a bit cross with you because you have not followed the rules and you have hijacked this thread. How to use this forum

Please start another thread.

Grumpy_Mike: I am a bit cross with you because you have not followed the rules and you have hijacked this thread. How to use this forum

Sorry about that.

Let's get back on topic:

Hello Electroguard, have you found a library for what you were looking for?