Skip to content

PCF8574 library. i2c digital expander for Arduino, Raspberry Pi Pico and rp2040 boards, esp32, SMT32 and ESP8266. Can read write digital values with only 2 wire. Very simple to use and encoder support.

License

Unknown, Unknown licenses found

Licenses found

Unknown
LICENSE
Unknown
LICENSE.md
Notifications You must be signed in to change notification settings

xreef/PCF8574_library

Repository files navigation

'''# PCF8574 I2C Digital I/O Expander Library

PCF8574 Library Logo

arduino-library-badge

A simple and efficient library to use the PCF8574 I2C 8-bit digital I/O expander with Arduino, ESP8266, ESP32, and other platforms.

Author: Renzo Mischianti
Website: www.mischianti.org
GitHub: xreef/PCF8574_library


📚 Documentation & Articles

Complete documentation, tutorials, and examples are available on mischianti.org.


📋 Table of Contents

✨ Features

  • 8 Digital I/O Pins: Expand your microcontroller's I/O capabilities over I2C.
  • Input & Output Modes: Each pin can be individually configured as an INPUT or OUTPUT.
  • Interrupt Support: Use the PCF8574's interrupt pin to detect input changes without polling.
  • Rotary Encoder Support: Built-in functions to simplify reading rotary encoders.
  • Flexible I2C Configuration:
    • Supports all PCF8574 and PCF8574A I2C addresses (0x20-0x27 and 0x38-0x3F).
    • Custom I2C pins (SDA, SCL) can be specified for platforms like ESP8266/ESP32.
  • Efficient Reading: Read all 8 pin states in a single I2C transaction with digitalReadAll().
  • Low Memory Mode: An optional mode to reduce RAM footprint on memory-constrained devices.
  • Specialized Functions: Includes pulseIn() and pulseInPoll() for reading pulse widths.

🎯 Supported Platforms

Platform Support Notes
ESP32 Full support
ESP8266 Full support
Raspberry Pi Pico (RP2040) Full support
Arduino (AVR, Uno, Mega) Full support
Arduino SAMD (Nano 33 IoT, etc.) Full support
STM32 Full support

📦 Installation

Arduino IDE (Library Manager)

  1. Open Arduino IDE.
  2. Go to Sketch > Include Library > Manage Libraries....
  3. Search for "PCF8574_library" by Renzo Mischianti.
  4. Click Install.

PlatformIO

Add the library to your platformio.ini file:

lib_deps = xreef/PCF8574 library

Manual Installation

  1. Download the latest release from GitHub.
  2. Unzip the folder and rename it to PCF8574_library.
  3. Move it to your Arduino libraries folder.
  4. Restart the Arduino IDE.

🚀 API Overview

Constructor

// Basic constructor with I2C address
PCF8574(uint8_t address);

// For ESP8266/ESP32 with custom SDA/SCL pins
PCF8574(uint8_t address, uint8_t sda, uint8_t scl);

// Constructor with interrupt pin
PCF8574(uint8_t address, uint8_t interruptPin, void (*interruptFunction)());

Core Functions

// Initialize the library (must be called in setup())
bool begin(uint8_t defaultVal = 0xFF);

// Set a pin as INPUT or OUTPUT
void pinMode(uint8_t pin, uint8_t mode);

// Write a value (HIGH/LOW) to a pin
void digitalWrite(uint8_t pin, uint8_t value);

// Read a value (HIGH/LOW) from a pin
uint8_t digitalRead(uint8_t pin);

// Read all 8 pins at once
PCF8574::DigitalInput digitalReadAll();

💡 Basic Usage

Here is a simple example of how to use the library to control an LED and read a button.

#include <Wire.h>
#include <PCF8574.h>

// Set I2C address (e.g., 0x20)
PCF8574 pcf8574(0x20);

const uint8_t LED_PIN = P0;
const uint8_t BUTTON_PIN = P1;

void setup() {
  Serial.begin(115200);

  // Initialize the PCF8574
  if (!pcf8574.begin()) {
    Serial.println("Couldn't find PCF8574");
    while (1);
  }

  // Set pin modes
  pcf8574.pinMode(LED_PIN, OUTPUT);
  pcf8574.pinMode(BUTTON_PIN, INPUT);

  Serial.println("PCF8574 initialized!");
}

void loop() {
  // Read the button state
  uint8_t buttonState = pcf8574.digitalRead(BUTTON_PIN);

  // If button is pressed (assuming active-low), turn on the LED
  if (buttonState == LOW) {
    pcf8574.digitalWrite(LED_PIN, HIGH);
  } else {
    pcf8574.digitalWrite(LED_PIN, LOW);
  }

  delay(100);
}

⚡ Interrupts

You can use an interrupt to detect input changes without constantly polling the device.

  1. Connect the INT pin of the PCF8574 to an interrupt-capable pin on your microcontroller.
  2. Define an interrupt handler function (ISR).
  3. Initialize the library with the interrupt pin and handler.
// Global flag to be set by the ISR
volatile bool keyPressed = false;

// Interrupt Service Routine (ISR)
// NOTE: Keep this function as short and fast as possible.
void ICACHE_RAM_ATTR keyPressedOnPCF8574() {
  keyPressed = true;
}

// Initialize with interrupt pin and ISR
PCF8574 pcf8574(0x20, D3, keyPressedOnPCF8574); // Address, Interrupt Pin, ISR

void setup() {
  // ... setup code ...
  pcf8574.begin();
}

void loop() {
  if (keyPressed) {
    // Reset the flag
    keyPressed = false;

    // An input on the PCF8574 has changed, read all values
    PCF8574::DigitalInput values = pcf8574.digitalReadAll();
    Serial.print("Pin P0 is: ");
    Serial.println(values.p0);
    // ... check other pins ...
  }
}

🔄 Rotary Encoder Support

The library offers built-in support for rotary encoders. To use it, enable one of the encoder implementations in the PCF8574.h file by uncommenting the corresponding #define.

Example implementation:

// In PCF8574.h, uncomment one of these:
// #define PCF8574_ENCODER_SUPPORT
// #define PCF8574_ENCODER_SUPPORT_OPTIMIZED

#include <Wire.h>
#include <PCF8574.h>

PCF8574 pcf8574(0x20);

// Define encoder pins
const uint8_t ENCODER_A = P0;
const uint8_t ENCODER_B = P1;

volatile long encoderValue = 0;

void setup() {
  Serial.begin(115200);
  pcf8574.begin();

  // Initialize the encoder
  pcf8574.encoder(ENCODER_A, ENCODER_B);
  pcf8574.setEncoderValue(0);
}

void loop() {
  long newEncoderValue = pcf8574.getEncoderValue();

  if (newEncoderValue != encoderValue) {
    Serial.print("Encoder value: ");
    Serial.println(newEncoderValue);
    encoderValue = newEncoderValue;
  }

  delay(10);
}

🧠 Low Memory Mode

For devices with very limited RAM, you can enable a low-memory mode.

  1. Uncomment #define PCF8574_LOW_MEMORY in PCF8574.h.
  2. This saves ~7 bytes of RAM by changing how digitalReadAll() works.

Instead of returning a struct, digitalReadAll() will return a single byte. You must then use bitwise operations to get the value of each pin.

// In your sketch, after enabling low memory mode:
byte pinValues = pcf8574.digitalReadAll();

bool p0 = (pinValues & bit(0)) > 0;
bool p1 = (pinValues & bit(1)) > 0;
// ... and so on for all 8 pins

Example: Using an HC-SR04 Ultrasonic Sensor

The library includes pulseIn() and pulseInPoll() to measure pulse durations on PCF8574 pins. This is useful for sensors like the HC-SR04, but be aware of the limitations.

⚠️ Accuracy Warning: Measuring pulses via an I2C expander is less precise than using a direct microcontroller pin. I2C communication adds latency and jitter. For high-accuracy needs, connect the sensor's ECHO pin directly to your microcontroller.

#include <Wire.h>
#include <PCF8574.h>

PCF8574 pcf(0x20);

const int trigPin = 9;          // A standard digital pin on your Arduino/ESP
const uint8_t echoPinPCF = P0;  // A pin on the PCF8574

void setup() {
  Serial.begin(115200);
  pcf.begin();
  pcf.pinMode(echoPinPCF, INPUT);
  pinMode(trigPin, OUTPUT);
}

void loop() {
  // Trigger the sensor
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // Measure the echo pulse duration on the PCF8574 pin
  // Timeout is 30000 microseconds (30ms)
  unsigned long duration = pcf.pulseIn(echoPinPCF, HIGH, 30000UL);

  // Calculate distance
  unsigned long distanceCm = duration / 29 / 2;

  Serial.print("Distance: ");
  Serial.print(distanceCm);
  Serial.println(" cm");

  delay(500);
}

📝 Changelog

  • 30/10/2025: v2.3.8 Add beginResult() to help users find their wrong code
  • 01/02/2024: v2.3.7 Add the possibility to insert address at begin()
  • 10/07/2023: v2.3.6 Support for Arduino UNO R4
  • 08/02/2023: v2.3.5 Fix STM32 support and add support for Raspberry Pi Pico and other rp2040 boards
  • 10/08/2022: v2.3.4 Add support for custom SERCOM interface of Arduino SAMD devices. Force SDA SCL to use GPIO numeration for STM32 bug.
  • 28/07/2022: v2.3.3 Force SDA SCL to use GPIO numeration.
  • 28/07/2022: v2.3.2 Fix the SDA SCL type #58 and add basic support for SAMD device.
  • 26/04/2022: v2.3.1 Fix example for esp32 and double begin issue #56.
  • 06/04/2022: v2.3.0 Fix package size
  • 30/12/2021: v2.2.4 Minor fix and remove deprecated declaration
  • 23/11/2020: v2.2.2 Add multiple implementation for encoder management

📄 License

This library is released under the MIT License. See the LICENSE file for more details.

Copyright (c) 2017-2025 Renzo Mischianti

🤝 Contributing

Contributions are welcome! Please fork the repository, create a feature branch, and submit a pull request.

📞 Support & Contact


⭐ If this library helped your project, please give it a star on GitHub! ''

About

PCF8574 library. i2c digital expander for Arduino, Raspberry Pi Pico and rp2040 boards, esp32, SMT32 and ESP8266. Can read write digital values with only 2 wire. Very simple to use and encoder support.

Topics

Resources

License

Unknown, Unknown licenses found

Licenses found

Unknown
LICENSE
Unknown
LICENSE.md

Stars

Watchers

Forks

Packages

No packages published

Contributors 6