diff --git a/PCF8575.cpp b/PCF8575.cpp index 734d88e..69b38ea 100644 --- a/PCF8575.cpp +++ b/PCF8575.cpp @@ -2,13 +2,14 @@ // FILE: PCF8575.cpp // AUTHOR: Rob Tillaart // DATE: 2020-07-20 -// VERSION: 0.0.2 +// VERSION: 0.0.3 // PURPOSE: Arduino library for PCF8575 - 16 channel I2C IO expander // URL: https://github.com/RobTillaart/PCF8575 // // HISTORY: // 0.0.1 2020-07-20 initial version // 0.0.2 2020-07-21 fix reverse(); refactor; +// 0.0.3 2020-07-29 fix #5 reverse() + refactor. #include "PCF8575.h" @@ -36,6 +37,12 @@ void PCF8575::begin(uint16_t val) PCF8575::write16(val); } +bool PCF8575::isConnected() +{ + Wire.beginTransmission(_address); + return Wire.endTransmission() == 0; +} + uint16_t PCF8575::read16() { if (Wire.requestFrom(_address, (uint8_t)2) != 2) @@ -98,53 +105,52 @@ void PCF8575::toggle(const uint8_t pin) void PCF8575::toggleMask(const uint16_t mask) { - _dataOut ^= mask; - PCF8575::write16(_dataOut); + PCF8575::write16(_dataOut ^ mask); } void PCF8575::shiftRight(const uint8_t n) { if ((n == 0) || (_dataOut == 0)) return; - if (n > 15) _dataOut = 0; // shift 8++ clears all, valid... - if (_dataOut != 0) _dataOut >>= n; // only shift if there are bits set + if (n > 15) _dataOut = 0; // shift 8++ clears all, valid... + else _dataOut >>= n; // only shift if there are bits set PCF8575::write16(_dataOut); } void PCF8575::shiftLeft(const uint8_t n) { if ((n == 0) || (_dataOut == 0)) return; - if (n > 15) _dataOut = 0; // shift 8++ clears all, valid... - if (_dataOut != 0) _dataOut <<= n; // only shift if there are bits set + if (n > 15) _dataOut = 0; // shift 8++ clears all, valid... + else _dataOut <<= n; // only shift if there are bits set PCF8575::write16(_dataOut); } int PCF8575::lastError() { int e = _error; - _error = PCF8575_OK; + _error = PCF8575_OK; // reset error after read, is this wise? return e; } void PCF8575::rotateRight(const uint8_t n) { - if ((n % 16) == 0) return; uint8_t r = n & 15; + if (r == 0) return; _dataOut = (_dataOut >> r) | (_dataOut << (15 - r)); PCF8575::write16(_dataOut); } void PCF8575::rotateLeft(const uint8_t n) { - rotateRight(16- (n & 15)); + rotateRight(16 - (n & 15)); } -void PCF8575::reverse() // quite fast -{ - uint8_t x = _dataOut; - x = (((x & 0xAAAA) >> 1) | ((x & 0x5555) << 1)); - x = (((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2)); - x = (((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4)); - x = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)); +void PCF8575::reverse() // quite fast +{ // 1 char === 1 bit + uint16_t x = _dataOut; // x = 0123456789ABCDEF + x = (((x & 0xAAAA) >> 1) | ((x & 0x5555) << 1)); // x = 1032547698BADCFE + x = (((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2)); // x = 32107654BA98FEDC + x = (((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4)); // x = 76543210FEDCBA98 + x = (x >> 8) | ( x << 8); // x = FEDCBA9876543210 PCF8575::write16(x); } @@ -152,9 +158,9 @@ void PCF8575::reverse() // quite fast uint16_t PCF8575::readButton16(const uint16_t mask) { uint16_t temp = _dataOut; - PCF8575::write16(mask | _dataOut); + PCF8575::write16(mask | _dataOut); // read only selected lines PCF8575::read16(); - PCF8575::write16(temp); + PCF8575::write16(temp); // restore return _dataIn; } diff --git a/PCF8575.h b/PCF8575.h index 8378357..f36495e 100644 --- a/PCF8575.h +++ b/PCF8575.h @@ -3,20 +3,23 @@ // FILE: PCF8575.h // AUTHOR: Rob Tillaart // DATE: 2020-07-20 -// VERSION: 0.0.2 +// VERSION: 0.0.3 // PURPOSE: Arduino library for PCF8575 - 16 channel I2C IO expander // URL: https://github.com/RobTillaart/PCF8575 // // HISTORY: -// based upon PCF8574 library -// // see PCF8575.cpp file // #include "Arduino.h" #include "Wire.h" -#define PCF8575_LIB_VERSION "0.0.2" +#define PCF8575_LIB_VERSION "0.0.3" + +#ifndef PCF8575_INITIAL_VALUE +#define PCF8575_INITIAL_VALUE 0xFFFF +#endif + #define PCF8575_OK 0x00 #define PCF8575_PIN_ERROR 0x81 @@ -30,9 +33,10 @@ class PCF8575 explicit PCF8575(const uint8_t deviceAddress); #if defined (ESP8266) || defined(ESP32) - void begin(uint8_t sda, uint8_t scl, uint16_t val = 0xFFFF); + void begin(uint8_t sda, uint8_t scl, uint16_t val = PCF8575_INITIAL_VALUE); #endif - void begin(uint16_t val = 0xFFFF); + void begin(uint16_t val = PCF8575_INITIAL_VALUE); + bool isConnected(); uint16_t read16(); uint8_t read(uint8_t pin); @@ -48,7 +52,7 @@ class PCF8575 uint8_t readButton(const uint8_t pin); void setButtonMask(uint16_t mask) { _buttonMask = mask; }; - // rotate, shift, toggle, reverse expect all lines are output + // rotate, shift, toggle, reverse expect all lines are output void toggle(const uint8_t pin); void toggleMask(const uint16_t mask = 0xFFFF); // default invertAll() void shiftRight(const uint8_t n = 1); diff --git a/README.md b/README.md index 52a2b8d..ffd43ec 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,21 @@ The library allows to read and write both single pins or 16 pins at once. Furthermore some additional functions are implemented that are a little more playfull but still are useful. +## I2C Clock + +Testing showed that the PCF8575 still works at 600 KHz and failed at 800 KHz. +These values are outside the specs of the datasheet so they are not recommendend. +However when performance is neede you can try to overclock the chip. ## Interface -- **PCF8575(deviceAddress)** Constructor with device address as parameter. -- **begin(val = 0xFF)** set the initial value for the pins and masks. -- **begin(sda, scl, val = 0xFFFF)** idem, for the ESP32 where one can choose the I2C pins +**PCF8575_INITIAL_VALUE** is a define that can be set compile time or before +the include of "pcf8575.h" to overrule the default value used with the +**begin()** call. + +- **PCF8575(deviceAddress)** Constructor with I2C device address as parameter. +- **begin(val = PCF8575_INITIAL_VALUE)** set the initial value for the pins and masks. +- **begin(sda, scl, val = PCF8575_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. - **read16()** reads all 16 pins at once. This one does the actual reading. @@ -52,6 +61,12 @@ Fills the lower lines with zero's. - **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. +## Testing + +Testing the initial library is done by Colin Mackay (thanks!). + +Platforms used for testing include: Nano, ESP32 and Seeed Xiao + ## Operation diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..8223b8b --- /dev/null +++ b/keywords.txt @@ -0,0 +1,32 @@ +# Syntax Coloring Map For PCF8575 + +# Datatypes (KEYWORD1) +PCF8575 KEYWORD1 + +# Methods and Functions (KEYWORD2) +begin KEYWORD2 +isConnected KEYWORD2 + +read16 KEYWORD2 +read KEYWORD2 +value KEYWORD2 + +write16 KEYWORD2 +write KEYWORD2 +valueOut KEYWORD2 + +readButton16 KEYWORD2 +readButton KEYWORD2 +setButtonMask KEYWORD2 + +toggle KEYWORD2 +toggleMask KEYWORD2 +shiftRight KEYWORD2 +shiftLeft KEYWORD2 +rotateRight KEYWORD2 +rotateLeft KEYWORD2 +reverse KEYWORD2 +lastError KEYWORD2 + +# Constants (LITERAL1) + diff --git a/library.json b/library.json index b22e605..0a31542 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "PCF8575", - "keywords": "I2C, PCF8575, 16 channel, IO, I/O, shift, rotate", + "keywords": "I2C, PCF8575, 16 channel, IO, I/O, shift, rotate, readButton, toggle, reverse", "description": "Arduino library for PCF8575 - 16 channel I2C IO expander, implements shift rotate.", "authors": [ @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/PCF8575.git" }, - "version":"0.0.2", + "version":"0.0.3", "frameworks": "arduino", "platforms": "*" } diff --git a/library.properties b/library.properties index 71b3da9..0bcf33e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=PCF8575 -version=0.0.2 +version=0.0.3 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for PCF8575 - 16 channel I2C IO expander