Adding pins to your Arduino using I2C and a PCF8574P chip

You are working on a project built around an Arduino and you realize you won’t have enough I/O pins to do everything? There are different ways of working around that limitation. One of them is to use an Inter-Integrated Circuit (I2C) bus and a PCF8574P chip. That chip will provide you with an additional 8 I/O pins at the cost of 2 pins from your Arduino!



– There is a 100nF ceramic capacitor between pin 16 and ground.
– There is a 2.2K Ohms pull-up resistor on SDA and SCL pins, so pins 14 & 15. This is because the way that I2C works is that the lines are pulled low to communicate and have to be pulled high the reminder of the time.
– As explained later, pins A0, A1 & A2 (pin #1, 2 & 3) are simply connected to ground so the chip’s address is 20h.
– The 4 red LED are in series with a 470 Ohms resistor. Pay attention to the LEDs orientation. The long lead is connected to the VCC (5V) line and the short lead is connected to the resistor. So, to turn on a LED, what we will do is pull its corresponding pin to ground (on the PCF8574) so the current can flow through the LED. To turn off a LED, we will pull its corresponding pin to high.

Note: On an Arduino UNO, SDA is on pin A4 and SCL is on pin A5. This may be different if you use another Arduino board. The Wire library page contains the information (location of SDA and SCL pins) for some other Arduino boards.

PCF8574P Pinout

Source: Official NXP Datasheet

That chip is pretty simple to use.


Pin 16 (VDD): Connect to your 5V or 3.3V power source. Ideally, you should also put a 100nF ceramic capacitor between the VDD pin and ground.
Pin 8 (VSS): Connect to Arduino’s ground.

I2C chip address:

No, even if they are named A0, A1 & A2, these are not analog pins like the ones your have on your Arduino! 🙂 These pins are used to tell the chip what will be his address (see it as his name) on the I2C bus. This is useful if you want to use many PCF8574P chips, on the same I2C bus, because it will allow you to give each of them a unique addresses.

A0 = Adress input 0
A1 = Adress input 1
A2 = Adress input 2

Source: Another official NXP Datasheet

Use the information from the 3 columns, in the “Pin connectivity” section, to see how to configure your chip address. Again, VDD means that pin must to be connected to 3.3V or 5V and VSS means that pin must be connected to ground.

You will see that, in this example, I simply connected A0, A1 & A2 to ground. So, to talk to the chip, I will use 0x20 (C language notation for 20 in hexadecimal) as the chip address.

I2C bus:

The I2C bus requires 2 wires, so 2 pins on the Arduino and 2 pins on each device attached to the bus. On the PCF8574P, the 2 pins are:

– SCL (pin #14): Serial Clock Line that is used to synchronize all communications on the bus.
– SDA (pin #15): Serial Data Line that is used to carry data between the devices on the bus.

As mentionned in the wiring section, the 2 pins have to be pulled high with a pull-up resistor. I used a 2.2K resistor in this case.

I/O Pins

The 8 I/O pins are simply named P0..P7.
When we will send information, to the chip, we will simply tell it if each pin is on (VDD) or off (GND).

Example Code

#include < Wire.h >

#define PCF8574_I2C_ADDR 0x20

#define P0 0
#define P1 1
#define P2 2
#define P3 3
#define P4 4
#define P5 5
#define P6 6
#define P7 7

void setup() {
  Wire.begin();        // initialize the I2C/TWI interface

void loop() {
  // send the data to the LEDs
  turnPinLowOnPCF8574P(PCF8574_I2C_ADDR, P4);
  turnPinLowOnPCF8574P(PCF8574_I2C_ADDR, P5);
  turnPinLowOnPCF8574P(PCF8574_I2C_ADDR, P6);
  turnPinLowOnPCF8574P(PCF8574_I2C_ADDR, P7);

void turnPinLowOnPCF8574P(int chipI2CAddress, int pinNumber) {
  Wire.write(~(1 << pinNumber));

I defined a constant for the chip name: PCF8574_I2C_ADDR. Simply change that constant value is you configured the chip with a different address.

Essentially, what the code does is using the Wire library. In the setup() function, all it does is initializing the Wire library. Then, in the loop() function, it turns each LED on for 200 milliseconds one at the time.

The turnPinLowOnPCF8574P() function contains the most interesting code. The Arduino starts by initiating a communication with our PCF8574 chip by doing a call to Wire.beginTransmisson(). Then, it tells the PCF8574 chip what is the new state of all his 8 output pins. The message payload is made of 8 bits, one per output pin. If the value of the bit corresponding to a pin is a 0, then that pin will be turned low (to ground). If the value of the bit for that pin is a 1, then it will be pulled high (5V in this case). My goal, here, is to turn on only one LED at the time. So, there should be only one pin that's pulled to ground.

Example of the value returned by ~(1 << pinNumber):

If pinNumber = P5, then we have:

  ~(1 << 5) 
= ~(0b00100000) 
=   0b11011111

So, the PCF8574 chip will pull high all of his I/O pins except pin P5.
This will allow the current to flow through the LED connected to P5.

The last thing done, in turnPinLowOnPCF8574P(), is to complete the transmission with a call to Wire.endTransmission().

Using many PCF8574 chips

If you need more than 6 extra pins for your project, you can use more than one PCF8574 on the same I2C bus (blue & yellow wires). All you have to do is to give then their own address (unless you want many chips to do the same thing) and use that address to talk to the chip in your code. If you do like this example, you now have an extra 14 pins to play with (2 X 8 pins - 2 pins on the Arduino for I2C bus).

Since a PCF8574P chip can be configured with 8 different I2C bus addresses, that means you can have a maximum of 8 distinct chips on your I2C bus. This gives you a total of 8 chips X 8 pins - 2 pins on Arduino = 62 extra I/O pins that can be individually addressed. I never faced situations where I needed that many pins! 🙂


Leave a Reply

Your email address will not be published. Required fields are marked *

Comments Protected by WP-SpamShield Spam Plugin