Interfacing the Arduino to the MCP23016 IO Expander
by Lewis Loflin
The MCP23016 is available in a DIP package from www.mouser.com.
Mfr. Part # MCP23016-I/SP, Mouser Part # 579-MCP23016-I/SP, Cost: Qty. 1: $2.37 as of March 2023.
The MCP23016 is a popular I/O expander integrated circuit manufactured by Microchip. It provides 16 individually programmable I/O pins that can source/sink 25 milliamps per pin up to about 250 milliamps total. Here we will explore how to use the MCP23016 with the ATMEGA168/Arduino.
Note that in this discussion I'll use hex numbers, a digital "1" is five volts and a digital "0" is zero volts. In binary a byte as individual bits (MSB) B00000000 (LSB). The "B' means this is a binary number to the compiler. All zeros is a decimal values of zero, all ones is a decimal value of 255. The MCP23016 can only handle bytes. (8 bits = 1 byte.) All the ports and registers in the MCP23016 use bytes. The programming examples will use the Wire.h library. For more examples of this see:
Also MCP23016 I2C I/O Expander spec sheet.
Download the Arduino code arduino_mcp23016.txt.
Basics of the MCP23016
Two separate 8-bit I/O ports bit programmable.
Three hardware address pins (A0-A2 pins 16-18) can address up to eight devices at one time.
High-current drive capability per I/O: source/sink 25 milliamps.
- Maximum current sink 300 mA max.
- Maximum current source 250 mA max.
- Total power: 1 watt.
Open-drain interrupt output pin (6) on input change and interrupt port capture register. (Doesn't work very well.)
Internal Power-On Reset.
Polarity inversion register to configure the polarity of the input port data.
The MCP23016 has 12 general purpose registers as follows:
0x00 Port0; can be directly written/read.
0x01 Port1; can be directly written/read.
Defaults to input.
0x02 Output latch 0; write changes output Port0.
0x03 Output latch 1; write changes output Port1.
Write won't work if bit/port set for input.
0x04 Invert input polarity Port0 bit addressable. 1 invert bit, 0 no invert.
0x05 Invert input polarity Port1 bit addressable. 1 invert bit, 0 no invert.
All bits default to 0.
0x06 I/O direction register Port0 bit addressable. 1 = output, 0 = input.
0x07 I/O direction register Port1 bit addressable. 1 = output, 0 = input.
Defaults to all 0 for inputs.
0x08 Interrupt capture register Port0.
0x09 Interrupt capture register Port1.
These are read only, shows state of port during an interrupt.
Connect an LED/resistor to VCC (+5 volts) and to pin 6 of
MCP23016 and LED will blink. Can be used to signal IRQ on
on the ATMEGA168.
See Using Hardware Interrupts ATMEGA168/Arduino
0x0A I/O control register 1
0x0B I/O control register 1 (same thing as 0x0A)
A one-bit register that controls the sampling frequency of the 2 I/O ports.
A "0" results in a 32 millisecond sample rate.
A "1" results in a 200 microsecond sample rate, but uses more power in standby.
Basic I2C setup.
The MCP23016 I/O expander is an I2C slave device with a base address of 0x20. It has additional three-bit address pins A0, A1, A2 on pins 16, 17, and 18 respectively. This allows eight individual devices to be connected at one time with individual addresses of 0x20 through 0x27. (Hex numbers!)
Example 1. In the setup sections of the two sample programs the MCP23016 is setup as follows to make Port0 all output and Port1 all inputs by writing to the two I/O direction registers:
Wire.begin(); // connect the Arduino as a master
Wire.beginTransmission(0x20); // setup out direction registers
Wire.send(0x06); // pointer
Wire.send(0x00); // DDR Port0 all output
Wire.send(0xFF); // DDR Port1 all input 0xFF = B11111111
Wire.endTransmission();
Example 2. What if I wanted both ports to be inputs, but invert the input polarity (a 1 becomes a 0) on Port1 where my switches are connected?
Wire.begin(); // connect the Arduino as a master, setup data direction
Wire.beginTransmission(0x20); // setup out direction registers
Wire.send(0x04); // pointer
Wire.send(0x00); // DDR Port0 no invert Port0
Wire.send(0xFF); // DDR invert input polarity port1 0xFF = B11111111
Wire.send(0xFF); // DDR Port0 all input 0xFF = B11111111
Wire.send(0xFF); // DDR Port1 all input 0xFF = B11111111
Wire.endTransmission();
When the eight switches are open (see schematic) the normal input to Port1 pins are all "0". In program two below all the LEDs on Port0 will be on, will go off when switch is closed. As it is below all LEDs on Port0 will come on only when corresponding switch on Port1 is closed.
Download the Arduino code arduino_mcp23016.txt.
- Interfacing the Arduino to the MCP23016 I/O Expander
- Connecting the Arduino to MCP23016 and LCD Display
- Arduino with a DS1307 Real Time Clock and MCP23016
- Quick navigation of this website:
- Basic Electronics Learning and Projects
- Basic Solid State Component Projects
- Arduino Microcontroller Projects
- Raspberry Pi Electronics, Programming
Stepper Motors
- Easy Driver Micro-Stepper Controller to Arduino
- Unipolar Stepper Motor with a Arduino
- Considerations for Using Stepper Motors
- Connecting the Arduino to a L298N H-Bridge
- L298N Motor Controller Theory and Projects
- TA8050 H-Bridge Motor Controller
- Battery Charger related:
- Solar Panel Charge Controller Using Arduino
- Solar Panel Battery Charge Controller Using Arduino
- Solar Panel Battery Charge Controller Switching Circuit
- Arduino AC Power Control Tutorial
- Rotary Encoder Using Arduino Hardware Interrupts
- Arduino Controlling 74C164 Shift Register
- Arduino Interface MC3479 Stepper Motor Controller
Serial LCD Display and assorted Sensors
- Arduino LCD Display using 74164 Shift Register
- Arduino LCD Display with DS18B20
- Arduino LCD Display with DHT11 Sensor
- Arduino with MM5451 LED Display Driver
- Arduino MAX7219 Operates 8X8 LED Matrix
- Arduino RTC Clock MAX7219 LED Display
- BCD Conversion with MAX7219
- Hatching Chicken Eggs with Arduino
- Arduino TMP37 Temperature Sensor
- Arduino TMP37 Temperature Sensor Tutorial
- The following use obsolete parts and are kept as a reference.
- Testing the Keyes IR Sensor Module with Arduino
- Arduino to MCP23016, LCD Display
- Time-Date with Arduino, LCD Display, DS1307 RTC
- Controlling Driveway Lights with the Arduino
- TSL230R Light to Frequency Converter
- Arduino with MCP23016 I/O Expander
- Arduino DS1307 Real Time Clock
- Arduino with 24LC08 Serial EEPROM
- MC3479 Stepper Motor Controller with Arduino
Web site Copyright Lewis Loflin, All rights reserved.
If using this material on another site, please provide a link back to my site.