PCF8574 Library by Renzo Mischianti

repository·master·Indexed 42 days ago

https://github.com/xreef/pcf8574_library

A library for controlling the PCF8574 8-bit I2C digital I/O expander on Arduino, ESP32, and ESP8266. It provides standard digital I/O methods like digitalWrite and digitalRead, support for hardware interrupts, and specialized functions for pulse measurement and HC-SR04 ultrasonic sensors, including non-blocking polling variants to optimize I2C traffic.

Tokens
2.5K
Snippets
7
Records
9
Agent score
4%

What's inside PCF8574 library

  1. Enable Rotary Encoder Support

    master

    The library supports rotary encoders, but this feature must be enabled manually in the library header.

    1. Open PCF8574.h and uncomment #define PCF8574_ENCODER_SUPPORT or #define PCF8574_ENCODER_SUPPORT_OPTIMIZED.
    2. Use pcf8574.encoder(pinA, pinB) to initialize the encoder pins.
    3. Use pcf8574.getEncoderValue() to retrieve the current position.
    4. Use pcf8574.setEncoderValue(value) to reset the position.
    // In PCF8574.h, uncomment:
    // #define PCF8574_ENCODER_SUPPORT
    
    PCF8574 pcf8574(0x20);
    const uint8_t ENCODER_A = P0;
    const uint8_t ENCODER_B = P1;
    
    void setup() {
      pcf8574.begin();
      pcf8574.encoder(ENCODER_A, ENCODER_B);
      pcf8574.setEncoderValue(0);
    }
    
    void loop() {
      long val = pcf8574.getEncoderValue();
    }
  2. Use Interrupts to Detect Input Changes

    master

    Instead of polling the I2C bus constantly, you can use the INT pin of the PCF8574 to trigger an interrupt on your microcontroller.

    1. Connect the PCF8574 INT pin to an interrupt-capable pin on your MCU.
    2. Define an Interrupt Service Routine (ISR).
    3. Initialize the PCF8574 object with the interrupt pin and the ISR function pointer.

    When the interrupt triggers, use digitalReadAll() to retrieve the state of all pins at once via the PCF8574::DigitalInput struct.

    volatile bool keyPressed = false;
    
    // ISR
    void ICACHE_RAM_ATTR keyPressedOnPCF8574() {
      keyPressed = true;
    }
    
    // Initialize with Address, Interrupt Pin, and ISR
    PCF8574 pcf8574(0x20, D3, keyPressedOnPCF8574);
    
    void setup() {
      pcf8574.begin();
    }
    
    void loop() {
      if (keyPressed) {
        keyPressed = false;
        // Read all values using the struct
        PCF8574::DigitalInput values = pcf8574.digitalReadAll();
        Serial.println(values.p0);
      }
    }
  3. Install the PCF8574 library

    master

    You can install the library using one of the following three methods:

    Arduino IDE

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

    PlatformIO

    Add the following line to your platformio.ini file:

    lib_deps = xreef/PCF8574 library

    Manual Installation

    1. Download the latest release from the GitHub repository.
    2. Unzip the folder and rename it to PCF8574_library.
    3. Move the folder to your Arduino libraries directory.
    4. Restart the Arduino IDE.
  4. Use HC-SR04 Ultrasonic Sensors via PCF8574

    master

    The library provides specialized methods for HC-SR04 sensors to reduce I2C traffic and simplify distance measurement.

    Note on Accuracy: Measuring pulses via I2C introduces latency and jitter. For high-precision requirements, connect the sensor's ECHO pin directly to the microcontroller instead of the expander.

    To improve I2C bus efficiency, use the _poll variants. These methods use a pollInterval (in microseconds) to reduce the frequency of I2C requests.

    MethodReturnsDescription
    ping_cm_poll(trig, echo, max, interval)CentimetersDistance in cm with polling (recommended)
    ping_in_poll(trig, echo, max, interval)InchesDistance in inches with polling
    ping_median_poll(trig, echo, iter, max, interval)CentimetersMedian of multiple readings with polling

    Polling Interval Guidance:

    • 50-100µs: High precision, higher I2C traffic.
    • 200-500µs: Lower precision, lower I2C traffic.
    • 100µs: Generally recommended balance.
    #include <Wire.h>
    #include <PCF8574.h>
    
    PCF8574 pcf(0x20);
    const uint8_t trigPinPCF = P1;
    const uint8_t echoPinPCF = P0;
    const unsigned long MAX_DISTANCE = 400;
    
    void setup() {
      pcf.pinMode(trigPinPCF, OUTPUT);
      pcf.pinMode(echoPinPCF, INPUT);
      pcf.begin();
    }
    
    void loop() {
      // Recommended: Use polling to reduce I2C traffic
      unsigned long distance = pcf.ping_cm_poll(trigPinPCF, echoPinPCF, MAX_DISTANCE, 100);
      Serial.print("Distance: ");
      Serial.println(distance);
      delay(500);
    }
  5. Enable Low Memory Mode

    master

    For extremely RAM-constrained devices, you can enable Low Memory Mode by uncommenting #define PCF8574_LOW_MEMORY in PCF8574.h.

    This changes the return type of digitalReadAll() from a struct to a single byte. You must then use bitwise operations to extract pin states.

    // After enabling PCF8574_LOW_MEMORY in PCF8574.h
    byte pinValues = pcf8574.digitalReadAll();
    
    bool p0 = (pinValues & bit(0)) > 0;
    bool p1 = (pinValues & bit(1)) > 0;
  6. Basic Usage: Control LEDs and Read Buttons

    master

    To use the PCF8574 library for basic digital I/O, instantiate the PCF8574 class with the I2C address, configure pin modes using pinMode(), and then call begin().

    Important: Always configure pin modes with pinMode() before calling begin(). Calling begin() before pinMode() can lead to unexpected behavior on some platforms.

    Use digitalWrite(pin, level) to set output levels and digitalRead(pin) to read input states.

    #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);
    
      // 1. Set pin modes FIRST
      pcf8574.pinMode(LED_PIN, OUTPUT);
      pcf8574.pinMode(BUTTON_PIN, INPUT);
    
      // 2. Initialize the PCF8574
      if (!pcf8574.begin()) {
        Serial.println("Couldn't find PCF8574");
        while (1);
      }
    }
    
    void loop() {
      uint8_t buttonState = pcf8574.digitalRead(BUTTON_PIN);
      if (buttonState == LOW) {
        pcf8574.digitalWrite(LED_PIN, HIGH);
      } else {
        pcf8574.digitalWrite(LED_PIN, LOW);
      }
      delay(100);
    }
  7. Measure pulses and use ultrasonic sensors

    master

    The library includes specialized methods for timing and ultrasonic sensor integration (HC-SR04 compatible, following a NewPing-style API):

    Pulse Measurement

    • pulseIn(uint8_t pin, uint8_t state, unsigned long timeout): Low-level pulse measurement.
    • pulseInPoll(...): A polling version of pulseIn with a configurable interval.

    Ultrasonic Sensor (HC-SR04)

    These methods take trigPin and echoPin as arguments:

    • ping(uint8_t trigPin, uint8_t echoPin, unsigned long maxDistance_cm): Returns pulse duration in microseconds.
    • ping_cm(...): Returns distance in centimeters.
    • ping_in(...): Returns distance in inches.
    • ping_median(...): Returns a median value from multiple iterations to reduce noise.

    Note: Many of these functions have a _poll variant (e.g., ping_cm_poll) which allows for non-blocking polling with a pollIntervalMicros parameter.

  8. Initialize the PCF8574 object

    master

    The PCF8574 class can be instantiated using several constructor patterns depending on your hardware requirements:

    • Standard: Use only the I2C address.
    • Custom I2C Pins: For ESP8266 or ESP32, specify custom SDA and SCL pins.
    • Interrupts: Specify an interrupt pin and a callback function to handle hardware interrupts.
    // 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)());
  9. Use core PCF8574 functions

    master

    The library provides standard digital I/O methods to control the 8-bit expander:

    • begin(uint8_t defaultVal = 0xFF): Initializes the library. Must be called in setup().
    • pinMode(uint8_t pin, uint8_t mode): Configures a pin as INPUT or OUTPUT.
    • digitalWrite(uint8_t pin, uint8_t value): Writes HIGH or LOW to a specific pin.
    • digitalRead(uint8_t pin): Reads the state (HIGH or LOW) of a specific pin.
    • digitalReadAll(): Reads the state of all 8 pins in a single I2C transaction, returning a PCF8574::DigitalInput object.