From 11e4a24dd5cbf750742c89ea22ef38e47671c929 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Mon, 5 Jul 2021 09:58:48 +0200 Subject: [PATCH] fix #25 add setAddress() (#26) * fix #25 add setAddress() + refactor --- PCF8574.cpp | 30 +++++++++++++++++- PCF8574.h | 16 +++++++--- README.md | 71 +++++++++++++++++++++++------------------- keywords.txt | 7 +++-- library.json | 2 +- library.properties | 2 +- test/unit_test_001.cpp | 14 +++++++++ 7 files changed, 101 insertions(+), 41 deletions(-) diff --git a/PCF8574.cpp b/PCF8574.cpp index 7cdeaac..0a6db6a 100644 --- a/PCF8574.cpp +++ b/PCF8574.cpp @@ -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 @@ -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() @@ -106,6 +120,7 @@ uint8_t PCF8574::read8() return _dataIn; } + void PCF8574::write8(const uint8_t value) { _dataOut = value; @@ -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) @@ -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) @@ -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) @@ -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; @@ -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; @@ -175,6 +196,7 @@ void PCF8574::shiftLeft(const uint8_t n) PCF8574::write8(_dataOut); } + int PCF8574::lastError() { int e = _error; @@ -182,6 +204,7 @@ int PCF8574::lastError() return e; } + void PCF8574::rotateRight(const uint8_t n) { uint8_t r = n & 7; @@ -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; @@ -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) { @@ -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) { @@ -230,4 +257,5 @@ uint8_t PCF8574::readButton(const uint8_t pin) return rtn; } + // -- END OF FILE -- diff --git a/PCF8574.h b/PCF8574.h index f728b4c..1d5e950 100644 --- a/PCF8574.h +++ b/PCF8574.h @@ -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 @@ -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 @@ -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); @@ -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); @@ -72,4 +79,5 @@ class PCF8574 TwoWire* _wire; }; + // -- END OF FILE -- diff --git a/README.md b/README.md index 68b2379..5e1b872 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Arduino library for PCF8574 - 8 channel I2C IO expander + ## Description Related to the PCF8575 16 channel IO expander library https://github.com/RobTillaart/PCF8575 @@ -14,10 +15,10 @@ Related to the PCF8575 16 channel IO expander library https://github.com/RobTil 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 @@ -25,7 +26,7 @@ to 16 x 8 = 128 IO lines. To maximize IO lines combine 8 x PCF8575 + 8 x PCF8574 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 @@ -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 diff --git a/keywords.txt b/keywords.txt index 6ccf681..c8f523c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -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 diff --git a/library.json b/library.json index a405ba3..c25c606 100644 --- a/library.json +++ b/library.json @@ -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": "*" diff --git a/library.properties b/library.properties index 85e5009..d72c2d9 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=PCF8574 -version=0.3.1 +version=0.3.2 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for PCF8574 - 8 channel I2C IO expander diff --git a/test/unit_test_001.cpp b/test/unit_test_001.cpp index 3c0910a..3139a81 100644 --- a/test/unit_test_001.cpp +++ b/test/unit_test_001.cpp @@ -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() // --------