How to Connect an MCP23017 I/O Port Expander to an Arduino


MCP23017 I/O port expander


In this project, we will show how to connect an MCP23017 I/O port expander chip to an Arduino microcontroller.

This is a very useful thing to do if we need additional I/O ports for a microcontroller.

I/O ports are input/output ports.

If we need more inputs or outputs to a microcontroller, we can expand the number of I/O ports with an I/O port expander chip.

The MCP23017 chip will let us have an additional 16 I/O ports simply by just using 2 pins on the microcontroller.

The MCP23017 chip uses the I2C bus and protocol. So only 2 digital pins on the arduino need to be used. So it uses a very minimal number of I/O pins for communication.

The 2 pins that it uses are for the clock line and data line.

Each of the I/O ports are bidirectional. So the device attached to one of the ports can both receive and send information to the microcontroller. Each of the ports can sink up to 25mA of current, so this is enough to drive certain devices like LEDs, which we use in this circuit. If you need more current you can always use a transistor to get more, but for this circuit, the IC is capable of driving LEDs.

Being that an MCP23017 contains 16 outputs, we can drive 16 LEDs with it.

Components

  • MCP23017 I/O Port Expander
  • A few 220Ω resistors
  • A few LEDs
  • Arduino microcontroller


The MCP23017 I/O port expander can be obtained for a little over $2.

It is a perfect addition to a microcontroller where more I/O ports are needed.

It is a 28-pin chip.

The datasheet for this chip can be found at the following link: MCP23017 Datasheet.

The pinout of the MCP23017 is shown below.

MCP23017 I/O port expander pinout

The MCP23017 can be powered with +5V. Therefore, we can connect VDD to the 5V terminal of the arduino. We connect VSS to ground. This completes the powering that's necessary for the MCP23017.

The GPB0-GPB7 and the GPA0-GPA7 are the 16 I/O ports.

NC is Not Connected so we leave that unconnected (or floating).

SCL is the serial clock line. It connects to analog pin 5 on the arduino, which is the analog clock pin.

SDA is the serial data line. It connects to analog pin 4 on the arduino, which is the analog data line.

INTA and INTB are interrupt pins for the outputs. Being that we are not going to use them here, we just leave them unconnected.

The RESET pin is if you want the outputs all reset to 0. Being that we aren't going to use this pin, we connect it permanently to +5V.

A0, A1, and A2 are the address pins. You only need be concerned about these pins if you are using multiple MCP23017 chips. These pins are externally biased, meaning you provide voltages to them to create different addresses. Since there are 3 pins, you can create a total of 8 different addresses (23=8). This is only necessary if you are connecting multiple ICs, so that we can distinguish between them. For example, if I grounded A2 and A1 and held A0 HIGH, this would create the address 001. Being that we are grounding all 3 pins, the address will for the address pins will be 000. But if you are connecting up to 8 MCP23017s, you will need to configure these pins so that each has a unique address: 000, 001, 010, 011, 100, 101, 110, 111. This way, you will be able to uniquely address each of them.


MCP23017 I/O Port Expander Circuit with an Arduino Microcontroller

The MCP23017 I/O port expander circuit we will build with an Arduino microcontroller is shown below.

MCP23017 I/O port expander circuit with arduino


In this circuit, the hardware connections are very simple.

To each of the I/O pins, we attach a 220Ω resistor and an LED.

To power the pin, we attach +5V to VDD and connect VSS to GND. This establishes power to the MCP23017 chip.

We leave the 2 NC (Not Connect) pins unconnected (or floating).

We connect pin 12 of the MCP23017, which is SCL (serial clock line) to analog pin 5 of the arduino. This allows the clock synchrony from the arduino to the I/O port expander chip.

We connect pin 13 of the MCP23017, which is the SDA (serial data line) to analog pin 4 of the arduino. This allows data transfer between the arduino and the I/O port expander chip.

Being that we're not working with interrupts, we leave INTA and INTB unconnected.

Being that we don't want to use the RESET pin, we connect it to +5V, since it's active LOW. However, if you want to use this pin, you simply connect it to a digital pin on the arduino. If you want to reset all the outputs, then you draw this pin LOW in code.

And we connect the address pins, pins A0, A1, and A2, to ground. This makes the address of these 3 pins 000. Later on in our code, this will be important for addressing this MCP23017 chip.


Code

The code so that we can connect an MCP23017 I/O port expander to an arduino microcontroller to turn on LEDs is shown below.

Arduino's I2C communication library is called the Wire library. With this library, you can easily write to and read from I2C devices.

#include <Wire.h>

void setup() { Wire.begin(); //creates a Wire object

// set I/O pins to outputs
Wire.beginTransmission(0x20); //begins talking to the slave device
Wire.write(0x00); //selects the IODIRA register
Wire.write(0x00); //this sets all port A pins to outputs
Wire.endTransmission(); //stops talking to device
Wire.beginTransmission(0x20);//begins talking again to slave device
Wire.write(0x01); //selects the IODIRB register
Wire.write(0x00); // sets all port B pins to outputs
Wire.endTransmission(); //ends communication with slave device
}

void loop()
{
Wire.beginTransmission(0x20); //starts talking to slave device
Wire.write(0x12); //selects the GPIOA pins
Wire.write(00000011); // turns on pins 0 and 1 of GPIOA
Wire.endTransmission(); //ends communication with the device
Wire.beginTransmission(0x20); //starts talking to slave device
Wire.write(0x13); //selects the GPIOB pins
Wire.write(00000001); //turns on pin 0 of GPIOA
Wire.endTransmission();//ends communication with the device
}


First, we import the Wire library, which is the library for communicating with I2C devices.

In our setup() function, we create a Wire object to initiate the process of communication. Without this, we can't communicate with the target device. We then begin transmission by the line, Wire.beginTransmission(0x20). The MCP230xx line of I/O port expanders have a base address of 0x20 + A address. In our case, since we grounded all the address pins, our address pins had the value 000. So 0x20 + 000= 0x20. This is why our final address is 0x20. However, if our address pins had a different value, our address would be different. If we connected all the address pins (A0, A1, A2) to +5V, then the address pins would have a value of 111, which in decimal or hexadecimal is 7. Then, our address would have been 0x27 (since 0x20 + 7 = 0x27). So this is an important concept to know, because without the correct address, you won't be able to initiate communication with the target MCP230xx devie.

Then we select the IODIRA register. This is the register of all the 8 pins in port A. The next line then sets all the pins to 0, which makes them outputs.

Then we end communication and begin it again. We now select the IODIRB register, which is the PORTB pins. We makes these all outputs and end communication.

So the setup for which pins of the ports are outputs and which are inputs are done. These are the IODIRA and IODIRB registers.

Next is our loop function which repeats over and over again. Here we will write which pins are on and which are off.

First, we begin communication with the MCP23017 chip, which always must be done. Then we write the line, Wire.write(0x12). This selects the GPIOA pins, the pins of register A. The difference between IODIRA and GPIOA is that IODIRA only can control whether a pin of PORTA is input or output. GPIOA doesn't control that but now controls whether that pin turns on or off. Writing a 1 to the pin turns it on, while writing a 0 turns it off. Here, we select the GPIOA register and then write the value in binary so you can see the exact bits. Here, we turn on pins 0 and 1 and leave all the other pins off.

We go next to the GPIOB register. We select it through the address, 0x13. We then turn only pin 0 on, while the rest are off. We then end communication with the MCP23017.

There are several variations you can do to this circuit. If you want to blink LEDs, then you would turn the LED on, delay for a certain time period, and then turn it off. For example, if you wanted to blink an LED on pin 0, you would write, Wire.write(00000001), then maybe wait a half of second, so you would write, delay(500), then you would turn off the LED by the line, Wire.write(00000000). So there are so many variations that can be done with this circuit. And it can really function just like a regular microcontroller, just with extended I/O port capability.

You just have to get used to the physical wiring and code involved with extending the I/O ports on a given microcontroller. Once you do this and get the hang of it, then it's pretty straightforward.


Related Resources

How to Connect an MCP23008 I/O Port Expander to an Arduino Microcontroller




HTML Comment Box is loading comments...