Skip to content

Commit

Permalink
fix #25 add setAddress() (#26)
Browse files Browse the repository at this point in the history
* fix #25 add setAddress() + refactor
  • Loading branch information
RobTillaart authored Jul 5, 2021
1 parent 174d0c0 commit 11e4a24
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 41 deletions.
30 changes: 29 additions & 1 deletion PCF8574.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// FILE: PCF8574.cpp
// AUTHOR: Rob Tillaart
// DATE: 02-febr-2013
// VERSION: 0.3.1
// VERSION: 0.3.2
// PURPOSE: Arduino library for PCF8574 - 8 channel I2C IO expander
// URL: https://github.com/RobTillaart/PCF8574
// http://forum.arduino.cc/index.php?topic=184800
//
// HISTORY:
// 0.3.2 2021-07-04 fix #25 add setAddress()
// 0.3.1 2021-04-23 Fix for platformIO compatibility
// 0.3.0 2021-01-03 multiWire support - inspirated by mattbue - issue #14
// 0.2.4 2020-12-17 fix #6 tag problem 0.2.3
Expand Down Expand Up @@ -90,6 +91,19 @@ bool PCF8574::isConnected()
}


bool PCF8574::setAddress(const uint8_t deviceAddress)
{
_address = deviceAddress;
return isConnected();
}


uint8_t PCF8574::getAddress()
{
return _address;
}


// removed _wire->beginTransmission(addr);
// with @100KHz -> 265 micros()
// without @100KHz -> 132 micros()
Expand All @@ -106,6 +120,7 @@ uint8_t PCF8574::read8()
return _dataIn;
}


void PCF8574::write8(const uint8_t value)
{
_dataOut = value;
Expand All @@ -114,6 +129,7 @@ void PCF8574::write8(const uint8_t value)
_error = _wire->endTransmission();
}


uint8_t PCF8574::read(const uint8_t pin)
{
if (pin > 7)
Expand All @@ -125,6 +141,7 @@ uint8_t PCF8574::read(const uint8_t pin)
return (_dataIn & (1 << pin)) > 0;
}


void PCF8574::write(const uint8_t pin, const uint8_t value)
{
if (pin > 7)
Expand All @@ -143,6 +160,7 @@ void PCF8574::write(const uint8_t pin, const uint8_t value)
write8(_dataOut);
}


void PCF8574::toggle(const uint8_t pin)
{
if (pin > 7)
Expand All @@ -153,12 +171,14 @@ void PCF8574::toggle(const uint8_t pin)
toggleMask(1 << pin);
}


void PCF8574::toggleMask(const uint8_t mask)
{
_dataOut ^= mask;
PCF8574::write8(_dataOut);
}


void PCF8574::shiftRight(const uint8_t n)
{
if ((n == 0) || (_dataOut == 0)) return;
Expand All @@ -167,6 +187,7 @@ void PCF8574::shiftRight(const uint8_t n)
PCF8574::write8(_dataOut);
}


void PCF8574::shiftLeft(const uint8_t n)
{
if ((n == 0) || (_dataOut == 0)) return;
Expand All @@ -175,13 +196,15 @@ void PCF8574::shiftLeft(const uint8_t n)
PCF8574::write8(_dataOut);
}


int PCF8574::lastError()
{
int e = _error;
_error = PCF8574_OK; // reset error after read, is this wise?
return e;
}


void PCF8574::rotateRight(const uint8_t n)
{
uint8_t r = n & 7;
Expand All @@ -190,11 +213,13 @@ void PCF8574::rotateRight(const uint8_t n)
PCF8574::write8(_dataOut);
}


void PCF8574::rotateLeft(const uint8_t n)
{
rotateRight(8 - (n & 7));
}


void PCF8574::reverse() // quite fast: 14 shifts, 3 or, 3 assignment.
{
uint8_t x = _dataOut;
Expand All @@ -204,6 +229,7 @@ void PCF8574::reverse() // quite fast: 14 shifts, 3 or, 3 assignment.
PCF8574::write8(x);
}


//added 0.1.07/08 Septillion
uint8_t PCF8574::readButton8(const uint8_t mask)
{
Expand All @@ -214,6 +240,7 @@ uint8_t PCF8574::readButton8(const uint8_t mask)
return _dataIn;
}


//added 0.1.07 Septillion
uint8_t PCF8574::readButton(const uint8_t pin)
{
Expand All @@ -230,4 +257,5 @@ uint8_t PCF8574::readButton(const uint8_t pin)
return rtn;
}


// -- END OF FILE --
16 changes: 12 additions & 4 deletions PCF8574.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FILE: PCF8574.H
// AUTHOR: Rob Tillaart
// DATE: 02-febr-2013
// VERSION: 0.3.1
// VERSION: 0.3.2
// PURPOSE: Arduino library for PCF8574 - 8 channel I2C IO expander
// URL: https://github.com/RobTillaart/PCF8574
// http://forum.arduino.cc/index.php?topic=184800
Expand All @@ -12,10 +12,12 @@
// see PCF8574.cpp file
//


#include "Arduino.h"
#include "Wire.h"

#define PCF8574_LIB_VERSION (F("0.3.1"))

#define PCF8574_LIB_VERSION (F("0.3.2"))

#ifndef PCF8574_INITIAL_VALUE
#define PCF8574_INITIAL_VALUE 0xFF
Expand All @@ -37,8 +39,13 @@ class PCF8574
bool begin(uint8_t val = PCF8574_INITIAL_VALUE);
bool isConnected();

// note: setting the address corrupt internal buffer values
// a read8() / write8() call updates them.
bool setAddress(const uint8_t deviceAddress);
uint8_t getAddress();

uint8_t read8();
uint8_t read(uint8_t pin);
uint8_t read(const uint8_t pin);
uint8_t value() const { return _dataIn; };

void write8(const uint8_t value);
Expand All @@ -49,7 +56,7 @@ class PCF8574
inline uint8_t readButton8() { return PCF8574::readButton8(_buttonMask); }
uint8_t readButton8(const uint8_t mask);
uint8_t readButton(const uint8_t pin);
inline void setButtonMask(uint8_t mask) { _buttonMask = mask; };
inline void setButtonMask(const uint8_t mask) { _buttonMask = mask; };

// rotate, shift, toggle, reverse expect all lines are output
void toggle(const uint8_t pin);
Expand All @@ -72,4 +79,5 @@ class PCF8574
TwoWire* _wire;
};


// -- END OF FILE --
71 changes: 39 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,26 @@

Arduino library for PCF8574 - 8 channel I2C IO expander


## Description

Related to the PCF8575 16 channel IO expander library https://github.com/RobTillaart/PCF8575

This library gives easy control over the 8 pins of a PCF8574 and PCF8574A chip.
These chips are identical in behavior although there are two distinct address ranges.

| TYPE | ADDRESS-RANGE | notes |
|:----|:----:|:----:|
|PCF8574 | 0x20 to 0x27 | same range as PCF8575 !! |
|PCF8574A | 0x38 to 0x3F |
| TYPE | ADDRESS-RANGE | notes |
|:---------|:-------------:|:------------------------:|
|PCF8574 | 0x20 to 0x27 | same range as PCF8575 !! |
|PCF8574A | 0x38 to 0x3F | |

So you can connect up to 16 PCF8574 on one I2C bus, giving access
to 16 x 8 = 128 IO lines. To maximize IO lines combine 8 x PCF8575 + 8 x PCF8574A giving
128 + 64 = 192 IO lines. Be sure to have a well dimensioned power supply.

The library allows to read and write both single pins or 8 pins at once.
Furthermore some additional functions are implemented that are
playfull but useful.
playful but useful.


## Interface
Expand All @@ -34,57 +35,63 @@ playfull but useful.
the include of "pcf8574.h" to overrule the default value used with the
**begin()** call.


### Constructor

- **PCF8574(deviceAddress, TwoWire \*wire = &Wire)** Constructor with device address,
and optional the Wire interface as parameter.
- **begin(val = PCF8574_INITIAL_VALUE)** set the initial value for the pins and masks.
- **begin(sda, scl, val = PCF8574_INITIAL_VALUE)** idem, for the ESP32 where one can choose the I2C pins
What needs to be added in the future is a parameter to choose another Wire interface
as some processors have multiple hardware Wire interfaces.
- **isConnected()** checks if the address is visable on the I2C bus
- **bool begin(val = PCF8574_INITIAL_VALUE)** set the initial value for the pins and masks.
- **bool begin(sda, scl, val = PCF8574_INITIAL_VALUE)** idem, for the ESP32 where one can choose the I2C pins.
- **bool isConnected()** checks if the address set in the constructor or by **setAddress()** is visible on the I2C bus.
- **bool setAddress(const uint8_t deviceAddress)** sets the device address after construction. Can be used to switch between PCF8574 modules runtime. Note this corrupts internal buffered values, so one might need to call **read8()** and/or **write8()**. Returns true if address can be found on I2C bus.
- **uint8_t getAddress()** returns the device address.


### Read and Write

- **read8()** reads all 8 pins at once. This one does the actual reading.
- **read(pin)** reads a single pin; pin = 0..7
- **value()** returns the last read inputs again, as this information is buffered
- **uint8_t read8()** reads all 8 pins at once. This one does the actual reading.
- **uint8_t read(uint8_t pin)** reads a single pin; pin = 0..7
- **uint8_t value()** returns the last read inputs again, as this information is buffered
in the class this is faster than reread the pins.
- **write8(value)** writes all 8 pins at once. This one does the actual reading.
- **write(pin, value)** writes a single pin; pin = 0..7; value is HIGH(1) or LOW (0)
- **void write8(const uint8_t value)** writes all 8 pins at once. This one does the actual reading.
- **uint8_t write(const uint8_t pin, const uint8_t value)** writes a single pin; pin = 0..7; value is HIGH(1) or LOW (0)
- **valueOut()** returns the last written data.


### Button

- **setButtonMask(mask)**
- **readButton8()**
- **readButton8(mask)**
- **readButton(pin)**
- **void setButtonMask(const uint8_t mask)**
- **uint8_t readButton8()**
- **uint8_t readButton8(const uint8_t mask)**
- **uint8_t readButton(const uint8_t pin)**


### Special

- **toggle(pin)** toggles a single pin
- **toggleMask(mask)** toggles a selection of pins,
- **void toggle(const uint8_t pin)** toggles a single pin
- **void toggleMask(const uint8_t mask = 0xFF)** toggles a selection of pins,
if you want to invert all pins use 0xFF (default value).
- **shiftRight(n = 1)** shifts output channels n pins (default 1) pins right (e.g. leds ).
- **void shiftRight(const uint8_t n = 1)** shifts output channels n pins (default 1) pins right (e.g. leds ).
Fills the higher lines with zero's.
- **shiftLeft(n = 1)** shifts output channels n pins (default 1) pins left (e.g. leds ).
- **void shiftLeft(const uint8_t n = 1)** shifts output channels n pins (default 1) pins left (e.g. leds ).
Fills the lower lines with zero's.
- **rotateRight(n = 1)** rotates output channels to right, moving lowest line to highest line.
- **rotateLeft(n = 1)** rotates output channels to left, moving highest line to lowest line.
- **reverse()** revers the "bit pattern" of the lines, high to low and vice versa.
- **void rotateRight(const uint8_t n = 1)** rotates output channels to right, moving lowest line to highest line.
- **void rotateLeft(const uint8_t n = 1)** rotates output channels to left, moving highest line to lowest line.
- **void reverse()** revers the "bit pattern" of the lines, high to low and vice versa.


### Misc

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


## Error codes

| name | value | description |
|:------|:----:|:----|
| PCF8574_OK | 0x00 | no error
| PCF8574_PIN_ERROR | 0x81 | pin number out of range |
| PCF8574_I2C_ERROR | 0x82 | I2C communication error |
| name | value | description |
|:-------------------|:-----:|:------------------------|
| PCF8574_OK | 0x00 | no error |
| PCF8574_PIN_ERROR | 0x81 | pin number out of range |
| PCF8574_I2C_ERROR | 0x82 | I2C communication error |


## Operation
Expand Down
7 changes: 5 additions & 2 deletions keywords.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# Syntax Coloring Map for PCF8574
# Syntax Colouring Map for PCF8574


# Datatypes (KEYWORD1)
# Data types (KEYWORD1)
PCF8574 KEYWORD1


# Methods and Functions (KEYWORD2)
begin KEYWORD2
isConnected KEYWORD2
setAddress KEYWORD2
getAddress KEYWORD2

read8 KEYWORD2
read KEYWORD2
value KEYWORD2
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/PCF8574.git"
},
"version":"0.3.1",
"version": "0.3.2",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*"
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=PCF8574
version=0.3.1
version=0.3.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for PCF8574 - 8 channel I2C IO expander
Expand Down
14 changes: 14 additions & 0 deletions test/unit_test_001.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ unittest(test_read)
}


unittest(test_address)
{
PCF8574 PCF(0x38);

// incorrect in test environment.
assertTrue(PCF.begin());
assertTrue(PCF.isConnected());
assertEqual(0x38, PCF.getAddress());

assertTrue(PCF.setAddress(0x20));
assertEqual(0x20, PCF.getAddress());
}


unittest_main()

// --------

0 comments on commit 11e4a24

Please sign in to comment.