Here it is shown how to expand Arduino's I/O using MCP2307 I/O expander IC with example of a button-controlled LED.
The MCP2307 is a 16-bit input/output (I/O) expansion chip manufactured by Microchip Technology that can be used to add extra input/output pins to a microcontroller or processor or boards like Arduino, Raspberry Pi Pico 2, PIC, AVR microcontroller, ESP32-CAM etc. The MCP2307 is connected to the microcontroller or Arduino like boards using I2C communication interface. That means only two pins of the microcontroller/Arduino like boards are required. It has 16 bidirectional I/O pins and supports interrupt for event driven input handing. Each pin can source/sink upto 25mA. Its operating voltage is 1.8V to 5V and has low power standby current, as low as 1uA.
MCP23017 I/O expander IC Arduino Example Circuit
To illustrate how to use MCP23017, we will use Arduino and connect Arduino with MCP23017 with I2C pins. A push button is connected to MCP23017 GPB0 pin on one side and grounded on the other side. The LED in series with 220Ohm resistor is connected to the GPA7 pin of the MCP23017 expander IC. The circuit diagram is shown below.
Arduino MCP23017 Programming
// MCP23017 Button-to-LED, POLLING version (no interrupt) — for diagnosis
#include <Wire.h>
#define MCP23017 0x20
#define IODIRA 0x00
#define IPOLB 0x03
#define GPPUB 0x0D
#define GPIOB 0x13
#define GPIOA 0x12
uint8_t portA = 0;
void I2Cwrite(uint8_t addr, uint8_t reg, uint8_t val) {
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission(true);
}
uint8_t I2Cread(uint8_t addr, uint8_t reg) {
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(addr, (uint8_t)1);
return Wire.read();
}
void setup() {
Wire.begin();
I2Cwrite(MCP23017, IODIRA, 0x00); // Port A = all outputs (LED)
I2Cwrite(MCP23017, GPPUB, 0xFF); // Port B pull-ups on (button)
I2Cwrite(MCP23017, IPOLB, 0xFF); // Invert polarity: pressed = 1
Serial.begin(9600);
while (!Serial) { ; }
Serial.println("Polling Button-to-LED Ready!");
}
void loop() {
uint8_t portB = I2Cread(MCP23017, GPIOB); // plain poll, no interrupt
if (portB & B00000001) { // B0 pressed
portA |= B10000000;
Serial.println("Button B0 pressed -> LED ON");
} else { // B0 released
portA &= B01111111;
Serial.println("Button B0 released -> LED OFF");
}
I2Cwrite(MCP23017, GPIOA, portA);
delay(100);
}
setup(), it configures Port A as outputs for the LED and Port B as inputs with pull-up resistors for the button, then in loop(), it simply asks the chip "what's the button doing right now?" every tenth of a second, checks if that reading shows the button pressed, and if so flips on a bit for the LED (or off if released) and sends that result back to the chip — so the light just continuously follows whatever the button's current state is, with no waiting or interrupts involved.Note: You can download the proteus project which contains schematic and program code from the link below.
