0.4.1 PCF8574

This commit is contained in:
Rob Tillaart 2024-01-08 15:12:06 +01:00
parent 888ee09d82
commit f157f53f4e
22 changed files with 466 additions and 177 deletions

View File

@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.4.1] - 2023-09-23
- Update readme with advanced interrupts insights
- kudos to ddowling for testing.
- add example
- fix URL examples
- add Wire1 example (ESP32 + RP2040)
## [0.4.0] - 2023-09-23
- refactor API, begin()
- update readme.md

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2013-2023 Rob Tillaart
Copyright (c) 2013-2024 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -2,7 +2,7 @@
// FILE: PCF8574.cpp
// AUTHOR: Rob Tillaart
// DATE: 02-febr-2013
// VERSION: 0.4.0
// VERSION: 0.4.1
// PURPOSE: Arduino library for PCF8574 - 8 channel I2C IO expander
// URL: https://github.com/RobTillaart/PCF8574
// http://forum.arduino.cc/index.php?topic=184800

View File

@ -3,7 +3,7 @@
// FILE: PCF8574.h
// AUTHOR: Rob Tillaart
// DATE: 02-febr-2013
// VERSION: 0.4.0
// VERSION: 0.4.1
// PURPOSE: Arduino library for PCF8574 - 8 channel I2C IO expander
// URL: https://github.com/RobTillaart/PCF8574
// http://forum.arduino.cc/index.php?topic=184800
@ -13,7 +13,7 @@
#include "Wire.h"
#define PCF8574_LIB_VERSION (F("0.4.0"))
#define PCF8574_LIB_VERSION (F("0.4.1"))
#ifndef PCF8574_INITIAL_VALUE
#define PCF8574_INITIAL_VALUE 0xFF
@ -50,7 +50,7 @@ public:
// added 0.1.07/08 Septillion
uint8_t readButton8() { return PCF8574::readButton8(_buttonMask); }
uint8_t readButton8() { return PCF8574::readButton8(_buttonMask); }
uint8_t readButton8(const uint8_t mask);
uint8_t readButton(const uint8_t pin);
void setButtonMask(const uint8_t mask) { _buttonMask = mask; };

View File

@ -11,7 +11,7 @@
# PCF8574
Arduino library for PCF8574 - 8 channel I2C IO expander
Arduino library for PCF8574 - 8 channel I2C IO expander.
## Description
@ -36,17 +36,52 @@ The library allows to read and write both single pins or 8 pins at once.
Furthermore some additional functions are implemented that are playful and useful.
#### Interrupts
#### Interrupts intro
The PCF8574 has an interrupt output line (INT) to notify an MCU that one of the input lines has changed.
This can be used to prevent active polling of the PCF8574, which can be more efficient.
The library cannot handle the PCF8574 interrupts as it has no code for it.
The user should catch the interrupt in his own code and can use the library to see which line has changed.
From the datasheet:
There are two examples to show how interrupts can be used:
- PCF8574_interrupt.ino
- PCF8574_rotaryEncoder.ino
_An interrupt is generated by any rising or falling edge of the port inputs in the input mode.
After time, (Tiv), INT is valid. Resetting and reactivating the interrupt circuit is achieved
when data on the port is **changed to the original setting** or data is **read from**, or
**written to**, the port that generated the interrupt.
Resetting occurs in the read mode at the acknowledge bit after the rising edge of the SCL signal,
or in the write mode at the acknowledge bit after the high-to-low transition of the SCL signal._
So there are three scenarios how the INT is reset.
1. pins revert to original state (lesser known).
2. read from the device (well known)
3. write to the device (well known)
This implies that polling the PCF8574 can miss an INT in scenario 1. (see #48)
In practice if you have faster polling than your signals changes this would not
be a problem. E.g. tactile switches and a polling frequency > 100 Hz will work.
#### Interrupts library
The library cannot handle the PCF8574 interrupts as it has no code for it.
The user should catch the interrupt in his own code to set a flag and can use
the library to see which line has changed.
There are two examples to show how interrupts can be handled:
- **PCF8574_interrupt.ino**
- **PCF8574_rotaryEncoder.ino**
A more advanced interrupt handler would not set a boolean flag in the interrupt
routine but increase a counter (uint8_t or larger).
Then it would be possible to see that:
1. an interrupt occurred. (counter > 0)
2. if one or more interrupts are not handled (counter > 1)
A minimal example that shows catching missed interrupts:
- **PCF8574_interrupt_advanced.ino**
#### 0.4.0 Breaking change
@ -194,7 +229,8 @@ It is advised to use pull-up or pull-down resistors so the lines have a defined
#### Must
- keep in sync with PCF8575
- update documentation.
- keep in sync with PCF8575 (as far as meaningful)
#### Should
@ -214,3 +250,4 @@ donate through PayPal or GitHub sponsors.
Thank you,

View File

@ -0,0 +1,27 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
# - uno
# - due
# - zero
# - leonardo
# - m4
- esp32
# - esp8266
# - mega2560
- rpipico

View File

@ -0,0 +1,81 @@
//
// FILE: PCF8574_Wire1.ino
// AUTHOR: Rob Tillaart
// DATE: 2016-04-30
// PURPOSE: demo
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"
// adjust addresses if needed
PCF8574 PCF(0x39, &Wire1);
void doHigh()
{
PCF.write(4, HIGH);
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doLow()
{
PCF.write(4, LOW);
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doToggle()
{
PCF.toggle(4);
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("PCF8574_LIB_VERSION:\t");
Serial.println(PCF8574_LIB_VERSION);
Wire1.begin();
if (!PCF.begin())
{
Serial.println("could not initialize...");
}
if (!PCF.isConnected())
{
Serial.println("=> not connected");
while(1);
}
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
delay(1000);
}
void loop()
{
Serial.println("HLT");
while (Serial.available() == 0);
switch (Serial.read())
{
case 'H': doHigh(); break;
case 'L': doLow(); break;
case 'T': doToggle(); break;
}
}
// -- END OF FILE --

View File

@ -1,9 +1,27 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
# example made for Teensy a.o.
#
# - uno
# - leonardo
# - due
# - zero
# - leonardo
# - m4
# - esp32
# - esp8266
# - mega2560
# - rpipico

View File

@ -1,14 +1,42 @@
//
//
// FILE: PCF8574_Wire2.ino
// AUTHOR: Rob Tillaart
// DATE: 2016-04-30
// PURPOSE: demo
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"
// adjust addresses if needed
PCF8574 PCF(0x39, &Wire2);
PCF8574 PCF(0x39, &Wire2); // Wire2 ==> Teensy
void doHigh()
{
PCF.write(4, HIGH);
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doLow()
{
PCF.write(4, LOW);
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doToggle()
{
PCF.toggle(4);
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void setup()
@ -50,32 +78,4 @@ void loop()
}
void doHigh()
{
PCF.write(4, HIGH);
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doLow()
{
PCF.write(4, LOW);
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doToggle()
{
PCF.toggle(4);
int x = PCF.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
// -- END OF FILE --

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2020-12-07
// PURPOSE: test PCF8574 library
// URL: https://github.com/RobTillaart/PCF8574
//
// TEST SETUP
// Connect INT pin of the PCF8574 to UNO pin 2

View File

@ -0,0 +1,86 @@
//
// FILE: PCF8574_interrupt_advanced.ino
// AUTHOR: Rob Tillaart
// DATE: 2024-01-08
// PURPOSE: test PCF8574 library
// URL: https://github.com/RobTillaart/PCF8574
//
// TEST SETUP
// Connect INT pin of the PCF8574 to UNO pin 2
//
// (from figure 4 datasheet
// Place a pull up resistor 4K7 between pin and 5V
// Place a capacitor 10-400 pF between pin and GND
#include "PCF8574.h"
PCF8574 PCF(0x38);
////////////////////////////////////
//
// INTERRUPT ROUTINE + FLAG
//
const int IRQPIN = 2;
volatile uint8_t interruptCount = 0;
void pcf_irq()
{
interruptCount++;
}
////////////////////////////////////
//
// MAIN CODE
//
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("PCF8574_LIB_VERSION: ");
Serial.println(PCF8574_LIB_VERSION);
Wire.begin();
PCF.begin();
pinMode(IRQPIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(IRQPIN), pcf_irq, FALLING);
}
void loop()
{
uint32_t now = millis();
// make a local copy of the counter.
noInterrupts();
uint8_t irq_count = interruptCount;
interruptCount = 0;
interrupts();
if (irq_count > 0)
{
if (irq_count > 1)
{
Serial.print("IRQ missed: ");
Serial.println(irq_count - 1); // as last will be handled
}
int x = PCF.read8();
Serial.print("READ:\t");
Serial.print('\t');
Serial.print(now);
Serial.print('\t');
Serial.println(x, HEX);
}
// simulate doing other things here.
// uses to a large delay to miss IRQ's on purpose.
delay(1000);
}
// -- END OF FILE --

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2021-01-03
// PURPOSE: demo isConnected function
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2021-01-24
// PURPOSE: test PCF8574 library at different I2C speeds.
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"
@ -11,6 +12,8 @@ PCF8574 PCF(0x38);
uint32_t start, stop;
volatile uint8_t x;
void setup()
{
@ -23,23 +26,31 @@ void setup()
PCF.begin();
Serial.println(PCF.isConnected());
delay(100); // time to flush Serial
for (long clk = 100000; clk < 800000; clk += 100000)
for (long clk = 100000; clk < 800000; clk += 50000)
{
Serial.println(clk);
// setup and measure
Wire.setClock(clk);
start = micros();
int x = PCF.read8();
x = PCF.read8();
stop = micros();
// output results
Serial.println(clk);
Serial.print("Read:\t");
Serial.print(stop - start);
Serial.print("\t");
Serial.println(x); // keep build CI compiler happy
delay(1000);
// measure
start = micros();
PCF.write8(0xFF);
stop = micros();
// output results
Serial.print("Write:\t ");
Serial.println(stop - start);
delay(1000);
@ -53,3 +64,4 @@ void loop()
// -- END OF FILE --

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2021-05-08
// PURPOSE: demo PCF8574 as rotary encoder reader.
// URL: https://github.com/RobTillaart/PCF8574
//
//
// RotaryEncoder PCF8574 UNO
@ -30,13 +31,69 @@ int32_t encoder[4] = {0, 0, 0, 0};
volatile bool flag = false;
////////////////////////////////////////////////
//
// IRQ routine
//
void moved()
{
flag = true;
}
////////////////////////////////////////////////
//
// rotary routines
//
void initRotaryDecoder()
{
uint8_t val = decoder.read8();
for (uint8_t i = 0; i < 4; i++)
{
lastpos[i] = val & 0x03;
val >>= 2;
}
}
// assumes 4 rotary encoders connected to one PCF8574
void updateRotaryDecoder()
{
uint8_t val = decoder.read8();
// check which of 4 has changed
for (uint8_t i = 0; i < 4; i++)
{
uint8_t currentpos = (val & 0x03);
if (lastpos[i] != currentpos) // moved!
{
uint8_t change = (lastpos[i] << 2) | currentpos;
switch (change)
{
case 0b0001: // fall through..
case 0b0111:
case 0b1110:
case 0b1000:
encoder[i]++;
break;
case 0b0010:
case 0b0100:
case 0b1101:
case 0b1011:
encoder[i]--;
break;
}
lastpos[i] = currentpos;
}
val >>= 2;
}
}
////////////////////////////////////////////////
//
// main code
//
void setup()
{
Serial.begin(115200);
@ -86,50 +143,5 @@ void loop()
}
void initRotaryDecoder()
{
uint8_t val = decoder.read8();
for (uint8_t i = 0; i < 4; i++)
{
lastpos[i] = val & 0x03;
val >>= 2;
}
}
// assumes 4 rotary encoders connected to one PCF8574
void updateRotaryDecoder()
{
uint8_t val = decoder.read8();
// check which of 4 has changed
for (uint8_t i = 0; i < 4; i++)
{
uint8_t currentpos = (val & 0x03);
if (lastpos[i] != currentpos) // moved!
{
uint8_t change = (lastpos[i] << 2) | currentpos;
switch (change)
{
case 0b0001: // fall through..
case 0b0111:
case 0b1110:
case 0b1000:
encoder[i]++;
break;
case 0b0010:
case 0b0100:
case 0b1101:
case 0b1011:
encoder[i]--;
break;
}
lastpos[i] = currentpos;
}
val >>= 2;
}
}
// -- END OF FILE --

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2022-06-18
// PURPOSE: demo PCF8574 library select functions
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 7-febr-2013
// PURPOSE: test PCF8574 library
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"
@ -10,6 +11,33 @@
PCF8574 PCF_01(0x38);
void doHigh()
{
PCF_01.write(4, HIGH);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doLow()
{
PCF_01.write(4, LOW);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doToggle()
{
PCF_01.toggle(4);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void setup()
{
Serial.begin(115200);
@ -41,32 +69,5 @@ void loop()
}
void doHigh()
{
PCF_01.write(4, HIGH);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doLow()
{
PCF_01.write(4, LOW);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doToggle()
{
PCF_01.toggle(4);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
// -- END OF FILE --

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 27-08-2013
// PURPOSE: demo
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2016-04-30
// PURPOSE: demo rotateLeft, rotateRight and toggleMask
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 7-febr-2013
// PURPOSE: test PCF8574 library
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"
@ -10,6 +11,33 @@
PCF8574 PCF_01(0x38);
void doHigh()
{
PCF_01.write(4, HIGH);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doLow()
{
PCF_01.write(4, LOW);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doToggle()
{
PCF_01.toggle(4);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void setup()
{
Serial.begin(115200);
@ -42,32 +70,5 @@ void loop()
}
void doHigh()
{
PCF_01.write(4, HIGH);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doLow()
{
PCF_01.write(4, LOW);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doToggle()
{
PCF_01.toggle(4);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
// -- END OF FILE --

View File

@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2023-12-10
// PURPOSE: test PCF8574 library
// URL: https://github.com/RobTillaart/PCF8574
#include "PCF8574.h"
@ -10,6 +11,33 @@
PCF8574 PCF_01(0x38);
void doHigh()
{
PCF_01.write(4, HIGH);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doLow()
{
PCF_01.write(4, LOW);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doToggle()
{
PCF_01.toggle(4);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void setup()
{
Serial.begin(115200);
@ -44,32 +72,5 @@ void loop()
}
void doHigh()
{
PCF_01.write(4, HIGH);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doLow()
{
PCF_01.write(4, LOW);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
void doToggle()
{
PCF_01.toggle(4);
int x = PCF_01.read8();
Serial.print("Read ");
Serial.println(x, HEX);
}
// -- END OF FILE --

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/PCF8574.git"
},
"version": "0.4.0",
"version": "0.4.1",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=PCF8574
version=0.4.0
version=0.4.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for PCF8574 - 8 channel I2C IO expander