Skip to content

Commit

Permalink
update readme.md (interrupts) + examples
Browse files Browse the repository at this point in the history
  • Loading branch information
RobTillaart committed Jan 8, 2024
1 parent 98ffc54 commit 1e1ef39
Show file tree
Hide file tree
Showing 17 changed files with 193 additions and 63 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).


## [0.2.2] - 2024-01-08
- Update readme with advanced interrupts insights
- add example
- Fix URL in examples
- minor edits


## [0.2.1] - 2023-12-29
- Fix #34 change addresses in examples.
- add range check to **setAddress()**.
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020-2023 Rob Tillaart
Copyright (c) 2020-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
Expand Down
2 changes: 1 addition & 1 deletion PCF8575.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// FILE: PCF8575.cpp
// AUTHOR: Rob Tillaart
// DATE: 2020-07-20
// VERSION: 0.2.1
// VERSION: 0.2.2
// PURPOSE: Arduino library for PCF8575 - 16 channel I2C IO expander
// URL: https://github.com/RobTillaart/PCF8575

Expand Down
4 changes: 2 additions & 2 deletions PCF8575.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FILE: PCF8575.h
// AUTHOR: Rob Tillaart
// DATE: 2020-07-20
// VERSION: 0.2.1
// VERSION: 0.2.2
// PURPOSE: Arduino library for PCF8575 - 16 channel I2C IO expander
// URL: https://github.com/RobTillaart/PCF8575

Expand All @@ -12,7 +12,7 @@
#include "Wire.h"


#define PCF8575_LIB_VERSION (F("0.2.1"))
#define PCF8575_LIB_VERSION (F("0.2.2"))


#ifndef PCF8575_INITIAL_VALUE
Expand Down
81 changes: 56 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ Arduino library for PCF8575 - 16 channel I2C IO expander.

## Description

Related to the PCF8574 8 channel IO expander library https://github.com/RobTillaart/PCF8574.

The library gives easy control over the 16 pins of the PCF8575 chips.

Base address = 0x20 + 0..7 depending on address pins A0..A2.
Expand All @@ -37,27 +35,63 @@ Be sure to have a well dimensioned power supply.
The library allows to read and write both single pins or 16 pins at once.
Furthermore some additional functions are implemented that are playful and useful.

Related to the PCF8574 8 channel IO expander library https://github.com/RobTillaart/PCF8574.

#### 0.2.0 Breaking change

Version 0.2.0 introduced a breaking change.
You cannot set the pins in **begin()** any more.
This reduces the dependency of processor dependent Wire implementations.
The user has to call **Wire.begin()** and can optionally set the Wire pins
before calling **begin()**.
#### Interrupts intro

The PCF8575 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.

#### Interrupts
From the datasheet:

The PCF8575 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 PCF8575, which can be more efficient.
_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 PCF8575 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.
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 is one example to show how interrupts can be used:
There is one example to show how interrupts can be handled:
- PCF8575_interrupt.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:

- **PCF8575_interrupt_advanced.ino**


#### 0.2.0 Breaking change

Version 0.2.0 introduced a breaking change.
You cannot set the pins in **begin()** any more.
This reduces the dependency of processor dependent Wire implementations.
The user has to call **Wire.begin()** and can optionally set the Wire pins
before calling **begin()**.


#### Related

Expand Down Expand Up @@ -106,13 +140,11 @@ the include of "pcf8575.h" to overrule the default value used with the
**begin()** call.


### Constructor
#### Constructor

- **PCF8575(uint8_t deviceAddress = 0x20, TwoWire \*wire = &Wire)** Constructor with the optional
I2C device address, default 0x20, and the optional Wire interface as parameter.
- **bool begin(uint8_t value = PCF8575_INITIAL_VALUE)** set the initial value for the pins and masks.
- **bool begin(int dataPin, int clockPin, uint8_t value = PCF8575_INITIAL_VALUE)** idem,
for the ESP32 where one can choose the I2C pins.
- **bool isConnected()** checks if the address is visible on the I2C bus.
- **bool setAddress(const uint8_t deviceAddress)** sets the device address after construction.
Can be used to switch between PCF8575 modules runtime. Note this corrupts internal buffered values,
Expand All @@ -122,7 +154,7 @@ Returns true if address can be found on I2C bus.
- **uint8_t getAddress()** returns the device address.


### Read and Write
#### Read and Write

- **uint16_t read16()** reads all 16 pins at once. This one does the actual reading.
- **uint8_t read(uint8_t pin)** reads a single pin; pin = 0..15.
Expand All @@ -133,7 +165,7 @@ in the class this is faster than reread the pins.
- **uint16_t valueOut()** returns the last written data.


### Button
#### Button

The **"button"** functions are to be used when you mix input and output on one IC.
It does not change / affect the pins used for output by masking these.
Expand All @@ -150,7 +182,7 @@ Note this can be a subset of the pins set with **setButtonMask()** if one wants
Background - https://github.com/RobTillaart/Arduino/issues/38


### Special
#### Special

- **void toggle(uint8_t pin)** toggles a single pin.
- **void toggleMask(uint16_t mask)** toggles a selection of pins,
Expand All @@ -164,7 +196,7 @@ Fills the lower lines with zero's.
- **void reverse()** reverse the "bit pattern" of the lines, swapping pin 15 with 0, 14 with 1, 13 with 2 etc..


### Select
#### Select

Some convenience wrappers.

Expand All @@ -178,7 +210,7 @@ This can typical be used to implement a VU meter.
- **void selectAll()** sets all pins to HIGH.


### Miscellaneous
#### Miscellaneous

- **int lastError()** returns the last error from the lib. (see .h file).

Expand Down Expand Up @@ -210,20 +242,19 @@ It is advised to use pull-up or pull-down resistors so the lines have a defined
#### Must

- update documentation.

- keep in sync with pcf8574 (as far as meaningful)

#### Should

- keep in sync with pcf8574 (as far as meaningful)
- verify difference between PCF8575 and PCF8575C version- see #39

#### Could

- **value()** => **lastRead16()** ??

- move code to .cpp

#### Wont

- **value()** => **lastRead16()**

## Support

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
//
// FILE: PCF8575_Wire2.ino
// FILE: PCF8575_Wire1.ino
// AUTHOR: Rob Tillaart
// DATE: 2021-01-03
// PURPOSE: demo
// URL: https://github.com/RobTillaart/PCF8575


#include "PCF8575.h"

// adjust addresses if needed
PCF8575 PCF(0x21, &Wire1); // or Wire2 if supported



void doHigh()
{
PCF.write(4, HIGH);
int x = PCF.read16();
Serial.print("Read ");
Serial.println(x, HEX);
}


void doLow()
{
PCF.write(4, LOW);
int x = PCF.read16();
Serial.print("Read ");
Serial.println(x, HEX);
}


void doToggle()
{
PCF.toggle(4);
int x = PCF.read16();
Serial.print("Read ");
Serial.println(x, HEX);
}


void setup()
{
Expand Down Expand Up @@ -50,32 +78,5 @@ void loop()
}


void doHigh()
{
PCF.write(4, HIGH);
int x = PCF.read16();
Serial.print("Read ");
Serial.println(x, HEX);
}


void doLow()
{
PCF.write(4, LOW);
int x = PCF.read16();
Serial.print("Read ");
Serial.println(x, HEX);
}


void doToggle()
{
PCF.toggle(4);
int x = PCF.read16();
Serial.print("Read ");
Serial.println(x, HEX);
}


// -- END OF FILE --

1 change: 1 addition & 0 deletions examples/PCF8575_array/PCF8575_array.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2021-12-13
// PURPOSE: demo array of PCF - not tested
// URL: https://github.com/RobTillaart/PCF8575


#include "PCF8575.h"
Expand Down
1 change: 1 addition & 0 deletions examples/PCF8575_interrupt/PCF8575_interrupt.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2021-01-03
// PURPOSE: test PCF8575 library
// URL: https://github.com/RobTillaart/PCF8575
//
// TEST SETUP
// Connect INT pin of the PCF8575 to UNO pin 2
Expand Down
74 changes: 74 additions & 0 deletions examples/PCF8575_interrupt_advanced/PCF8575_interrupt_advanced.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// FILE: PCF8575_interrupt_advanced.ino
// AUTHOR: Rob Tillaart
// DATE: 2021-01-03
// PURPOSE: test PCF8575 library
// URL: https://github.com/RobTillaart/PCF8575
//
// TEST SETUP
// Connect INT pin of the PCF8575 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 "PCF8575.h"

PCF8575 PCF(0x20);


////////////////////////////////////
//
// INTERRUPT ROUTINE + FLAG
//
const int IRQPIN = 2;

volatile bool flag = false;

void pcf_irq()
{
flag = true;
}


////////////////////////////////////
//
// MAIN CODE
//
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("PCF8575_LIB_VERSION:\t");
Serial.println(PCF8575_LIB_VERSION);

Wire.begin();

PCF.begin();

pinMode(IRQPIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(IRQPIN), pcf_irq, FALLING);
}


void loop()
{
uint32_t now = millis();
if (flag)
{
flag = false;
uint16_t x = PCF.read16();
Serial.print("READ:\t");
Serial.print('\t');
Serial.print(now);
Serial.print('\t');
Serial.println(x, HEX);
}
// do other things here
delay(10);
}


// -- END OF FILE --

1 change: 1 addition & 0 deletions examples/PCF8575_isConnected/PCF8575_isConnected.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// AUTHOR: Rob Tillaart
// DATE: 2021-01-03
// PURPOSE: demo device detection
// URL: https://github.com/RobTillaart/PCF8575


#include "PCF8575.h"
Expand Down
Loading

0 comments on commit 1e1ef39

Please sign in to comment.