Arduino library 路 Input

Adafruit MCP23017: sixteen extra pins on two I2C wires

The MCP23017 is Microchip鈥檚 16-bit I/O expander: two eight-pin ports, GPA and GPB, controlled over I2C. Each pin can be an input, with an optional internal pull-up, or an output that sources or sinks up to 25 mA, so a board with two spare pins can run a keypad, a row of LEDs and a set of switches.

Built in on Mokxi: #include <Adafruit_MCP23X17.h> and it builds, with nothing to install. Free, and no account needed.

What Adafruit MCP23017 Arduino Library does

Adafruit鈥檚 library makes the pins feel like the board鈥檚 own: mcp.pinMode(), mcp.digitalWrite() and mcp.digitalRead() with pin numbers 0 to 15, where 0 to 7 are GPA0 to GPA7 and 8 to 15 are GPB0 to GPB7. Each call is a read-modify-write over I2C, so for speed write a whole port at once with writeGPIOA() or writeGPIOAB().

The chip鈥檚 own pins are what trip people up. RESET must be tied high, and A0, A1 and A2 must be tied to GND or 3.3 to 5 V, never left floating; together they set the address, 0x20 to 0x27. Version 2 of the library renamed the class to Adafruit_MCP23X17 and begin() to begin_I2C(), so old tutorials no longer compile as written.

Library Manager nameAdafruit MCP23017 Arduino Library
AuthorAdafruit
Include#include <Adafruit_MCP23X17.h>
#include <Adafruit_MCP23X08.h>
Boardsevery board Mokxi compiles for but ATtiny85
In the simulatorSimulated: it runs against the part the way it does on the bench.
Parts it drivesI/O expander, MCP23017

Install it

It builds on every board Mokxi compiles for but ATtiny85.

In Mokxi it is built in: #include <Adafruit_MCP23X17.h> and the sketch compiles, with no download, no zip and no Library Manager.

On a real board, install "Adafruit MCP23017 Arduino Library" by Adafruit from the Arduino IDE鈥檚 Library Manager (Sketch, Include Library, Manage Libraries), or add Adafruit MCP23017 Arduino Library to lib_deps in PlatformIO. Mokxi follows the calls of release 2.3.2, so a sketch written here builds there too.

What to know in the simulator: Mokxi has the MCP23017 part only: Adafruit_MCP23X08 builds, with no chip to drive (run its sketches with Adafruit_MCP23X17, pins 0 to 7), and the SPI chips (begin_SPI) say they are not simulated.

ESP32-C3 路 Arduino Uno 路 Arduino Nano 路 Arduino Mega 2560 路 Arduino Leonardo 路 SparkFun Pro Micro 路 Arduino Micro 路 ESP32-C6 路 Raspberry Pi Pico 路 Raspberry Pi Pico W 路 Seeed XIAO SAMD21 路 STM32 路 STM32 Nucleo-F411RE 路 STM32 Blue Pill 路 micro:bit V2 路 Arduino Uno R4 路 ESP32 DevKit 路 ESP32-S3-DevKitC-1 路 ESP8266 NodeMCU 路 Arduino Pro Mini 3.3 V 路 Seeed XIAO ESP32-C3 路 ESP32-C3 SuperMini 路 Seeed XIAO ESP32-C6 路 ESP32-DevKitC V4 路 LOLIN32 Lite 路 Wemos D1 R32 路 Cheap Yellow Display 路 TTGO T-Display 路 Seeed XIAO ESP32-S3 路 Arduino Nano ESP32 路 Arduino Nano RP2040 Connect 路 Seeed XIAO RP2040 路 Waveshare RP2040-Zero 路 Arduino Uno R4 WiFi

The calls you will use

In the order a sketch meets them.

Adafruit_MCP23X17 mcp

The expander object. Adafruit_MCP23X08 is the eight-pin MCP23008.

mcp.begin_I2C()

Finds the chip at 0x20, or at the address you pass, such as begin_I2C(0x21). Returns false when nothing answers.

if (!mcp.begin_I2C()) {
  Serial.println("MCP23017 not found");
  while (1);
}

mcp.pinMode(8, INPUT_PULLUP)

Makes GPB0 an input with the internal 100 k惟 pull-up. OUTPUT and INPUT work as on the board.

mcp.digitalWrite(0, HIGH)

Drives GPA0 high.

mcp.digitalRead(8)

Reads GPB0, HIGH or LOW. With INPUT_PULLUP a pressed button to GND reads LOW.

mcp.writeGPIOA(0b10101010)

Sets all eight GPA outputs in one I2C transfer. readGPIOAB() reads all sixteen pins at once.

mcp.setupInterrupts(true, false, LOW)

Configures the INTA and INTB outputs: mirrored, push-pull, active low. Then setupInterruptPin(pin, CHANGE) arms a pin.

mcp.getLastInterruptPin()

Which pin caused the interrupt. clearInterrupts() releases the INT line for the next one.

Example: More pins

On the Arduino Uno R3. It runs in the browser exactly as printed.

sketch.ino 路 Arduino Uno R3
// Two port expanders on one I2C bus: a PCF8574 at 0x20 and an MCP23017 at 0x27.
//
// The PCF8574 has no registers at all. Every byte written is its eight pins,
// and a pin written 1 is only weakly high, so the LEDs on it run from 5 V
// through a resistor *into* the pin and light when their bit is 0. The sketch
// walks a single dark bit along four of them.
//
// The MCP23017 is a proper pair of ports: a direction register, pull-ups and
// push-pull outputs. GPB0 is an input with its pull-up on and a button to
// ground; GPA0 drives an LED to ground, lit while the button is held. Its
// RESET is tied high and A0 to A2 high too, which is address 0x27: none of the
// four pins is pulled inside the chip, and left floating the chip is simply
// not on the bus.

#include <Wire.h>
#include <Adafruit_MCP23X17.h>

const uint8_t PCF8574 = 0x20;
Adafruit_MCP23X17 mcp;
uint8_t step = 0;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  Wire.beginTransmission(PCF8574);
  Serial.println(Wire.endTransmission() == 0 ? "PCF8574 at 0x20" : "no PCF8574 at 0x20");
  if (!mcp.begin_I2C(0x27)) {
    Serial.println("no MCP23017 at 0x27");
  } else {
    Serial.println("MCP23017 at 0x27");
  }
  mcp.pinMode(0, OUTPUT);        // GPA0: the LED
  mcp.pinMode(8, INPUT_PULLUP);  // GPB0: the button
}

void loop() {
  // One dark bit walking along P0..P3; the other four stay high, which is
  // also how they would be read as inputs.
  Wire.beginTransmission(PCF8574);
  Wire.write((uint8_t)~(1 << step));
  Wire.endTransmission();
  step = (step + 1) % 4;

  bool pressed = mcp.digitalRead(8) == LOW;
  mcp.digitalWrite(0, pressed ? HIGH : LOW);
  Serial.println(pressed ? "button held" : "button up");
  delay(250);
}

Open it in the editor, wired and ready to run 路 More pins: the project page

Common errors and how to fix them

begin_I2C() returns false

Tie RESET high and A0 to A2 to GND (address 0x20) or to VCC, never floating. Then run an I2C scanner to confirm the address, and check SDA and SCL have pull-up resistors.

'class Adafruit_MCP23017' has no member named 'begin_I2C'

The sketch mixes the old and new libraries. Library version 2 and later use #include <Adafruit_MCP23X17.h>, the Adafruit_MCP23X17 class and begin_I2C(); the old begin(0) took 0 to 7 instead of the full address.

An input pin reads random values

The pin is floating. Use INPUT_PULLUP and wire the button to GND, or add an external resistor, so the pin has a defined level when nothing drives it.

Try Adafruit MCP23017 Arduino Library without installing anything

Open the example, change the sketch, and keep your version in a free account.