'''# PCF8574 I2C Digital I/O Expander Library
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
Complete documentation, tutorials, and examples are available on mischianti.org.
- 🌐 PCF8574 Main Article: The primary guide for this library with wiring diagrams and detailed explanations.
- 📖 PCF8574 and rotary encoder: A guide to using a rotary encoder with the PCF8574.
- 📖 PCF8575 16-bit I/O Expander: A guide for the 16-bit version of this IC.
- 🛠️ I2C Scanner: A utility to find the I2C address of your device.
- 💬 Support Forum (English): Get help and discuss the library.
- 💬 Forum di Supporto (Italiano): Ottieni supporto e discuti della libreria.
- Features
- Supported Platforms
- Installation
- API Overview
- Basic Usage
- Interrupts
- Rotary Encoder Support
- Low Memory Mode
- HC-SR04 Ultrasonic Sensor Example
- Changelog
- License
- Contributing
- Support & Contact
- 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
INPUTorOUTPUT. - 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()andpulseInPoll()for reading pulse widths.
| 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 |
- Open Arduino IDE.
- Go to
Sketch>Include Library>Manage Libraries.... - Search for "PCF8574_library" by Renzo Mischianti.
- Click
Install.
Add the library to your platformio.ini file:
lib_deps = xreef/PCF8574 library- Download the latest release from GitHub.
- Unzip the folder and rename it to
PCF8574_library. - Move it to your Arduino
librariesfolder. - Restart the Arduino IDE.
// 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)());// 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();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);
}You can use an interrupt to detect input changes without constantly polling the device.
- Connect the
INTpin of the PCF8574 to an interrupt-capable pin on your microcontroller. - Define an interrupt handler function (ISR).
- 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 ...
}
}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);
}For devices with very limited RAM, you can enable a low-memory mode.
- Uncomment
#define PCF8574_LOW_MEMORYinPCF8574.h. - 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 pinsThe 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'sECHOpin 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);
}- 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
This library is released under the MIT License. See the LICENSE file for more details.
Copyright (c) 2017-2025 Renzo Mischianti
Contributions are welcome! Please fork the repository, create a feature branch, and submit a pull request.
- Documentation: https://www.mischianti.org/category/my-libraries/pcf8574-i2c-digital-i-o-expander/
- GitHub Issues: https://github.com/xreef/PCF8574_library/issues
- Author: Renzo Mischianti (@xreef)
⭐ If this library helped your project, please give it a star on GitHub! ''
