Tuesday, August 25, 2026

PCF8574 / PCF8574A

 

PCF8574 / PCF8574A

Adding 8 GPIO Pins with Two Wires

A Beginner-to-Practical Guide to the I²C 8-Bit I/O Expander

Contents

Contents........................................................................................................................................ 1

1. What Problem Does It Solve?.......................................................................................................... 2

2. What Exactly Is a PCF8574?............................................................................................................. 2

Important characteristics................................................................................................................ 3

3. PCF8574 vs PCF8574A..................................................................................................................... 3

4. Understanding A0, A1 and A2......................................................................................................... 3

Solder jumpers.............................................................................................................................. 4

5. I²C Basics........................................................................................................................................ 4

Terms worth knowing.................................................................................................................... 4

6. The Unusual Part: “Quasi-Bidirectional” GPIO.................................................................................. 5

7. Driving Outputs — Know the Limits................................................................................................. 5

8. Basic Arduino Example.................................................................................................................... 6

9. Reading Inputs............................................................................................................................... 6

10. Address Scanner........................................................................................................................... 7

11. Using Multiple PCF8574 / PCF8574A Devices.................................................................................. 7

12. Common Applications................................................................................................................... 8

13. Common Mistakes........................................................................................................................ 8

14. One Important Distinction: Chip vs. LCD Backpack.......................................................................... 9

Recap................................................................................................................................................ 9

 


 

An Arduino Nano — or most small microcontrollers — has a limited number of GPIO pins. Real projects quickly run out of them. Consider a project that needs:

        8 LEDs

        8 buttons

        An LCD display

        A bank of relays

        A keypad

        Several switches

Wiring all of that directly to the microcontroller would consume nearly every available pin. The PCF8574 solves this by giving you 8 additional digital I/O pins while using only two MCU pins — the I²C bus (SDA and SCL).

 

        Arduino

         

          │ SDA

          │ SCL

         

       PCF8574

        ├── P0

        ├── P1

        ├── P2

        ├── P3

        ├── P4

        ├── P5

        ├── P6

        └── P7

 

Key idea

The PCF8574 doesn't make your microcontroller more powerful. It gives the microcontroller another set of remotely controlled GPIO pins through the I²C bus.

Keep that sentence in mind — it is the single idea that makes every later section make sense.

The PCF8574 is an 8-bit I/O expander with an I²C interface. “I/O expander” simply means a chip whose entire job is to offer more input/output pins, controlled remotely over a serial bus rather than wired directly to the MCU's own pins.

Important characteristics

        8 quasi-bidirectional I/O pins (P0–P7)

        Communicates over I²C — only 2 wires needed, shared with other devices

        Address is configurable using 3 hardware pins: A0, A1, A2

        No dedicated direction register like many modern GPIO expanders (e.g. MCP23017)

        Each pin can be used as an input or an output

        Multiple PCF8574 devices can share the same I²C bus at the same time

This distinction causes a lot of confusion, so it deserves its own section. The PCF8574 and PCF8574A are functionally identical, but they occupy different I²C address ranges:

Device

Address range

PCF8574

0x20 – 0x27

PCF8574A

0x38 – 0x3F

 

The three address pins (A0, A1, A2) still give 8 possible combinations, but the two chip variants occupy different base ranges. For example, with all three address pins tied high (A2 A1 A0 = 1 1 1):

A2 A1 A0 = 1 1 1

 

PCF8574     0x27

PCF8574A    0x3F

Why this matters: two modules that look identical, with identical A0/A1/A2 jumper settings, can end up at completely different I²C addresses simply because one uses a PCF8574 and the other a PCF8574A. If your I²C scanner doesn't find the address you expected, check which variant is actually on the board.

A0, A1 and A2 are hardware address pins. Each one is tied to VCC (logic 1) or GND (logic 0), and together they select where the chip sits within its address range. With 3 pins, there are 2³ = 8 possible combinations:

A2

A1

A0

Result

0

0

0

Lowest address

0

0

1

 

0

1

0

 

0

1

1

 

1

0

0

 

1

0

1

 

1

1

0

 

1

1

1

Highest address

 

Applied to the actual ranges from Section 3, this gives 8 selectable addresses for the PCF8574 (0x20–0x27) and 8 for the PCF8574A (0x38–0x3F).

Solder jumpers

Many breakout modules bring A0/A1/A2 out to solder-bridge jumpers instead of hard-wiring them, so the address can be changed without redesigning the board:

A0 ──●── GND

    

     └── VCC

Bridging the jumper one way ties the pin to GND (0); bridging it the other way ties it to VCC (1). This is exactly how you give several identical modules different addresses so they can coexist on one bus.

This tutorial doesn't assume prior I²C experience, so here's the short version. I²C is a 2-wire serial bus:

        SDA ────────────────┐

                           

MCU     SCL ────────────────┤

                           

                      PCF8574

The real strength of I²C is that many devices can share the same two wires, each distinguished by its own address:

                 ┌── PCF8574

Arduino ── I²C ──┼── RTC

                 ├── EEPROM

                 └── Sensor

Terms worth knowing

        SDA — the data line

        SCL — the clock line

        Pull-up resistors — required on both SDA and SCL for the bus to work reliably (many breakout boards already include them)

        Device address — the 7-bit address that identifies a chip on the bus

        ACK — a bit each device sends back to confirm it received a byte

        Multiple devices on one bus — each device only responds when its own address is sent

That's enough I²C background for this tutorial — a full protocol deep-dive isn't necessary to use the PCF8574 effectively.

This is probably the single most important technical detail to understand about the PCF8574. Its pins are not like an Arduino GPIO. There is no pinMode()-style direction register — instead, every pin behaves as a quasi-bidirectional I/O.

To use a pin as an input, you first write a 1 to it. This releases the pin (weakly pulls it high) so that an external circuit is free to pull it low:

Write 1    release pin    external circuit can pull it LOW

This is exactly why a button can be wired directly to a PCF8574 pin without any extra components:

    VCC

    

  [button]

    

     P0

    

  PCF8574

Pressing the button connects P0 to GND, pulling it LOW — which the PCF8574 reports back over I²C. Because inputs work this way, the PCF8574 is particularly convenient for buttons, keypads, DIP switches and LCD control lines.

It's tempting to treat the PCF8574's 8 pins as “8 more Arduino pins”, but their electrical characteristics are different, so this deserves its own section rather than being glossed over.

MCU GPIO    PCF8574 GPIO

The PCF8574's outputs have asymmetric source/sink current capability, and the chip is not designed to directly drive arbitrary loads such as motors or high-current LEDs.

        For LEDs, always use an appropriate current-limiting resistor

        For relays, motors, or higher-current loads, drive them through a transistor or MOSFET rather than the pin directly

        The PCF8574's architecture makes sinking current (pulling a load to GND) noticeably more capable than sourcing it — which is why many circuits built around this chip are designed as active-low

Start as simply as possible: toggle pin P0 on and off.

#include <Wire.h>

 

#define PCF8574_ADDR 0x20

 

void setup()

{

    Wire.begin();

}

 

void loop()

{

    Wire.beginTransmission(PCF8574_ADDR);

    Wire.write(0b11111110);

    Wire.endTransmission();

 

    delay(500);

 

    Wire.beginTransmission(PCF8574_ADDR);

    Wire.write(0b11111111);

    Wire.endTransmission();

 

    delay(500);

}

Each byte written over I²C maps directly onto the 8 pins:

Bit:    7  6  5  4  3  2  1  0

                     

       P7 P6 P5 P4 P3 P2 P1 P0

0b11111110 clears only bit 0 (P0), driving it LOW while every other pin stays HIGH — that's the whole example.

To read a button wired as shown in Section 6, first release all pins by writing 0xFF, then request one byte back from the chip:

Wire.beginTransmission(PCF8574_ADDR);

Wire.write(0xFF);

Wire.endTransmission();

 

Wire.requestFrom(PCF8574_ADDR, 1);

 

uint8_t value = Wire.read();

Then test the bit for the pin you care about:

if (!(value & (1 << 0))) {

    // P0 is LOW — button is pressed

}

Why the logic looks backwards: 1 means released/HIGH (button not pressed), and 0 means pressed/LOW. It reads as inverted logic at first, but it follows directly from how quasi-bidirectional inputs work (Section 6).

An I²C scanner sketch is one of the most useful tools you can run before touching any PCF8574 code. It sweeps every possible 7-bit address and reports which ones respond:

Scanning...

Device found at 0x27

Device found at 0x3F

This ties directly back to Section 3 — seeing 0x27 tells you it's a PCF8574, while 0x3F tells you it's a PCF8574A, even if the two boards look identical.

This is where the chip becomes far more useful than “8 extra pins”. Because each device is selected by its own address, several can share the same two I²C wires at once:

Arduino

  

   ├── 0x20  PCF8574

   ├── 0x21  PCF8574

   ├── 0x22  PCF8574

   ...

   └── 0x27  PCF8574

...and, on the second address range:

0x38 – 0x3F   (PCF8574A)

Key idea

Combining both variants, you can theoretically fit up to 16 PCF8574/PCF8574A devices on a single I²C bus — 128 extra GPIO pins from just two MCU pins — assuming no address conflicts and staying within the usual I²C electrical limits (bus capacitance, pull-up strength, cable length).

The PCF8574 shows up in far more places than simple LED-blinking demos:

        16×2 and 20×4 character LCDs (via an I²C “backpack” — see Section 14)

        Membrane keypads

        Button panels and control panels

        LED status indicators

        Relay banks

        DIP switch banks for configuration

        Rotary encoder interfaces

        General GPIO expansion for Arduino, ESP8266 and ESP32 projects

The 16×2 LCD backpack is worth calling out specifically — most people have already seen a small blue PCF8574 board soldered to the back of an LCD, often without realizing what chip is actually doing the work.

Problem

Likely cause

Device doesn't appear on the scanner

Wrong I²C wiring (SDA/SCL swapped or not connected)

Found at an unexpected address

PCF8574 vs PCF8574A confusion (Section 3)

Random / unreliable communication

Missing or incorrect pull-up resistors

Input always reads HIGH

Pin never released with a 1 before reading (Section 6)

LED behaves strangely / stays dim

Output polarity or current-sink/source limitation (Section 7)

Two devices seem to conflict

Same I²C address — check A0/A1/A2 jumpers

ESP8266 doesn't work, Arduino does

Wrong SDA/SCL pins for the ESP8266 board variant

LCD doesn't work at all

Wrong PCF8574 address, or wrong pin mapping for that backpack

People frequently search for “PCF8574 LCD”, but there are really several layers stacked on top of each other:

PCF8574 IC

   

I²C I/O expander

   

LCD backpack PCB

   

16×2 / 20×4 LCD

The backpack board that sits between the PCF8574 and the LCD usually adds its own components:

        A potentiometer for LCD contrast

        A backlight-control transistor

        Its own pull-up resistors

        Jumpers (for example, to disable the backlight control)

        A specific P0–P7 → LCD pin mapping, which varies by manufacturer

This is why: different LCD libraries sometimes use different pin mappings even though every one of them says it supports “PCF8574” — the chip is identical, but the backpack wiring around it isn't standardized.

The PCF8574 and PCF8574A turn two I²C wires into 8 extra digital I/O pins, with up to 16 devices shareable on a single bus. The two ideas most worth remembering are: the address-range split between PCF8574 (0x20–0x27) and PCF8574A (0x38–0x3F), and the quasi-bidirectional input behaviour that requires releasing a pin (writing 1) before reading it.

Key idea

The PCF8574 doesn't make your microcontroller more powerful. It gives the microcontroller another set of remotely controlled GPIO pins through the I²C bus.

 


No comments:

Post a Comment