├── LICENSE ├── README.md ├── examples ├── pcf8574_arduinomicro │ └── pcf8574_arduinomicro.ino ├── pcf8574_attiny85_digispark │ └── pcf8574_attiny85_digispark.ino ├── pcf8574_esp8266 │ └── pcf8574_esp8266.ino └── pcf8574_stm32f1 │ └── pcf8574_stm32f1.ino ├── keywords.txt ├── library.properties ├── pcf8574_esp.cpp └── pcf8574_esp.h /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 WereCatf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PCF8574_ESP 2 | 3 | This is a simple library for using the PCF8574/PCF8574A/PCF8575 I/O-expanders over I2C. I took the code by Rob Tillaart from http://playground.arduino.cc/Main/PCF8574Class and modified it. Rob's original code is designed to work only with the first I2C-bus, but many devices now have multiple I2C-buses and on the ESP8266 the I2C is software-based, so you can have as many buses as you have free I/O-pins for and you can use whatever free pin you like for it. I also added support for the PCF8575 16-pin I/O-expander. 4 | 5 | This library does not supply any special functionality for using the interrupt-pin on the PCF8574/PCF8575, you have to do that part yourself. Don't forget to configure the pin on the MCU's end as INPUT_PULLUP! You also have to set up the I2C-bus yourself before calling any library-functions. 6 | 7 | The library also doesn't supply any pinMode()-function for a reason: it'd be confusing. The 8 | PCF857x-devices only support two pin-modes, namely INPUT HIGH and OUTPUT LOW -- no INPUT LOW 9 | or OUTPUT HIGH or anything fancier than that. Use the write()-function instead and remember 10 | that there are only those two modes. 11 | 12 | Despite the library's name, it supports the ESP8266, Attiny85, STM32F1 and should work with any standard Arduino-device at the moment, though, out of the official Arduino-boards, I have only tested it with Arduino Micro as I don't yet own any other ones. 13 | 14 | # Usage 15 | ``` 16 | What arguments the class-constructor accepts depends on the board you use: 17 | Attiny85: PCF857x(uint8_t address, is8575 = false) 18 | STM32F1: PCF857x(uint8_t address, HardWire *Wire, is8575 = false) 19 | ESP8266 and others: PCF857x(uint8_t address, TwoWire *UseWire, is8575 = false) 20 | 21 | void begin() 22 | uint8_t read8() -- Read all 8 pins' status at once as a bitmask with a pin being HIGH if the corresponding bit is set, and vice versa. 23 | uint8_t read(uint8_t pin) -- Returns a single pin's status. 24 | void write8(uint8_t value) -- Set all 8 pins' status at once. 25 | void write(uint8_t pin, uint8_t value) -- Set a single pin's status. 26 | void toggle(uint8_t pin) -- Reverses the corresponding pin's status, HIGH to LOW or vice versa. 27 | void toggleAll() -- Reverses all the pins' statuses, from HIGH to LOW and vice versa. 28 | void shiftLeft(uint8_t n=1) -- Shift the pins' states left, with pin 1's state going into pin 2 and so on. 29 | void shiftRight(uint8_t n=1) -- Like above, but to the right instead. 30 | void rotateLeft(uint8_t n=1) -- Rotate the pins' status instead of just shifting them, with pin 7's status going to pin 0, ie. wrapping around. 31 | void rotateRight(uint8_t n=1) -- Like above. 32 | int lastError() 33 | uint16_t read16() -- Returns all the 16 pins' status at once if you set is8575 as true, otherwise doesn't do anything and returns zero. 34 | void write16() -- Sets all the 16 pins' statuses at once if you set is8575 as true, otherwise doesn't do anything. 35 | ``` 36 | 37 | # Mixing INPUT- and OUTPUT-pins and write8 38 | 39 | Due to the way the PCF8574 works you cannot just use read8() to read the pin-states, then change one pin and write8() the new states out because if you are using some pins as INPUT and the pin is being pulled low the moment you read8() its state you'll then be pulling the pin LOW when issuing write8() and it'll stop working as an INPUT. For this reason the library caches written values instead of relying on reading the pin-states when using write() or toggle(), and if you use write8() in your own code you need to remember to pull HIGH any pin you want to use as INPUT regardless of their current state. 40 | -------------------------------------------------------------------------------- /examples/pcf8574_arduinomicro/pcf8574_arduinomicro.ino: -------------------------------------------------------------------------------- 1 | /* Example sketch for the PCF8574 for the purposes of showing how to use the interrupt-pin. 2 | 3 | Attach the positive lead of an LED to PIN7 on the PCF8574 and the negative lead to GND, 4 | a wire from Arduino-pin 13 to pin 3 on the PCF8474, a wire from the int-pin on the PCF8574 5 | to Arduino-pin 7 and wires for SDA and SCL to Arduino-pins 2 and 3, respectively. 6 | 7 | If all goes well you should see the small blue LED on the ESP-module lighting up and the 8 | LED connected to the PCF going off, and vice versa. */ 9 | 10 | #include 11 | 12 | /* We need to set up the I2C-bus for the library to use */ 13 | #include 14 | 15 | // Initialize a PCF8574 at I2C-address 0x20 16 | PCF857x pcf8574(0x20, &Wire); 17 | 18 | //If you had a PCF8575 instead you'd use the below format 19 | //PCF857x pcf8575(0x20, &Wire, true); 20 | 21 | volatile bool PCFInterruptFlag = false; 22 | 23 | void PCFInterrupt() { 24 | PCFInterruptFlag = true; 25 | } 26 | 27 | void setup() { 28 | Serial.begin(115200); 29 | delay(5000); 30 | Serial.println(F("Firing up...")); 31 | pinMode(13, OUTPUT); 32 | 33 | Wire.begin(); 34 | //Specsheets say PCF8574 is officially rated only for 100KHz I2C-bus 35 | //PCF8575 is rated for 400KHz 36 | Wire.setClock(100000L); 37 | pcf8574.begin(); 38 | // Most ready-made PCF8574-modules seem to lack an internal pullup-resistor, so you have to use the MCU-internal one. 39 | pinMode(7, INPUT_PULLUP); 40 | pcf8574.resetInterruptPin(); 41 | 42 | attachInterrupt(digitalPinToInterrupt(7), PCFInterrupt, FALLING); 43 | } 44 | 45 | void loop() { 46 | if(PCFInterruptFlag){ 47 | Serial.println(F("Got an interrupt: ")); 48 | if(pcf8574.read(3)==1) Serial.println("Pin 3 is HIGH!"); 49 | else Serial.println("Pin 3 is LOW!"); 50 | // DO NOTE: When you write LOW to a pin on a PCF8574 it becomes an OUTPUT. 51 | // It wouldn't generate an interrupt if you were to connect a button to it that pulls it HIGH when you press the button. 52 | // Any pin you wish to use as input must be written HIGH and be pulled LOW to generate an interrupt. 53 | pcf8574.write(7, pcf8574.read(3)); 54 | PCFInterruptFlag=false; 55 | } 56 | Serial.println(F("Blink.")); 57 | if(digitalRead(13)==HIGH) digitalWrite(13, LOW); 58 | else digitalWrite(13, HIGH); 59 | delay(1000); 60 | } 61 | -------------------------------------------------------------------------------- /examples/pcf8574_attiny85_digispark/pcf8574_attiny85_digispark.ino: -------------------------------------------------------------------------------- 1 | /* A simple example-sketch on how to toggle an LED on PIN7 on the PCF8574. 2 | Wire the LED so that the positive lead of the LED goes to PIN7 on the PCF8574, 3 | and the negative lead goes to GND. 4 | 5 | You must install TinyWireM-library (https://github.com/SpenceKonde/TinyWireM) for I2C on Attiny */ 6 | 7 | #include 8 | #include 9 | 10 | //Initialize a PCF8574 at I2C-address 0x20 11 | PCF857x pcf8574(0x20); 12 | //PCF857x pcf8574(0x20, false); //This also works 13 | 14 | //If you had a PCF8575 you'd use the below format 15 | //PCF857x pcf8575(0x20, true); 16 | 17 | void setup() { 18 | TinyWireM.begin(); 19 | pcf8574.begin(); 20 | } 21 | 22 | void loop() { 23 | delay(1000); 24 | pcf8574.toggle(7); 25 | } 26 | -------------------------------------------------------------------------------- /examples/pcf8574_esp8266/pcf8574_esp8266.ino: -------------------------------------------------------------------------------- 1 | /* Example sketch for the PCF8574 for the purposes of showing how to use the interrupt-pin. 2 | 3 | Attach the positive lead of an LED to PIN7 on the PCF8574 and the negative lead to GND, 4 | a wire from GPIO2 (Nodemcu D4) to PIN3 that will be used to trigger the interrupt, 5 | and the INT-pin to GPIO14 (Nodemcu D5) on the ESP8266. 6 | 7 | If all goes well you should see the small blue LED on the ESP-module lighting up and the 8 | LED connected to the PCF going off, and vice versa. */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | /* Wire.h already defines "Wire" which the PCF8574-class would use by default, 15 | but for the sakes of an example let's define our own instance of it and use that instead! 16 | 17 | Also, since I2C is emulated on the ESP8266 let's redefine what pins to use as SDA and SCL 18 | and instead swap them around! 19 | DO NOT FORGET TO WIRE ACCORDINGLY, SDA GOES TO GPIO5, SCL TO GPIO4 (ON NODEMCU GPIO5 IS D1 AND GPIO4 IS D2) */ 20 | TwoWire testWire; 21 | // Initialize a PCF8574 at I2C-address 0x20, using GPIO5, GPIO4 and testWire for the I2C-bus 22 | PCF857x pcf8574(0x20, &testWire); 23 | // Use PCF857x pcf8574(0x20, &Wire); if you don't wish to define your own Wire-instance. 24 | 25 | //If you had a PCF8575 instead you'd use the below format 26 | //PCF857x pcf8575(0x20, &testWire, true); 27 | 28 | volatile bool PCFInterruptFlag = false; 29 | 30 | void ICACHE_RAM_ATTR PCFInterrupt() { 31 | PCFInterruptFlag = true; 32 | } 33 | 34 | void setup() { 35 | WiFi.persistent(false); 36 | WiFi.mode(WIFI_OFF); 37 | WiFi.forceSleepBegin(); 38 | delay(1); 39 | // The above lines turn WiFi off for lower power-consumption, since we're not using it in this sketch. 40 | // Remove them if you want to modify the sketch and use WiFi. 41 | 42 | Serial.begin(115200); 43 | Serial.println("Firing up..."); 44 | pinMode(2, OUTPUT); 45 | 46 | testWire.begin(5, 4); 47 | //Specsheets say PCF8574 is officially rated only for 100KHz I2C-bus 48 | //PCF8575 is rated for 400KHz 49 | testWire.setClock(100000L); 50 | pcf8574.begin(); 51 | // Most ready-made PCF8574-modules seem to lack an internal pullup-resistor, so you have to use the ESP8266-internal one. 52 | pinMode(14, INPUT_PULLUP); 53 | pcf8574.resetInterruptPin(); 54 | attachInterrupt(digitalPinToInterrupt(14), PCFInterrupt, FALLING); 55 | } 56 | 57 | void loop() { 58 | if(PCFInterruptFlag){ 59 | Serial.println("Got an interrupt: "); 60 | if(pcf8574.read(3)==HIGH) Serial.println("Pin 3 is HIGH!"); 61 | else Serial.println("Pin 3 is LOW!"); 62 | // DO NOTE: When you write LOW to a pin on a PCF8574 it becomes an OUTPUT. 63 | // It wouldn't generate an interrupt if you were to connect a button to it that pulls it HIGH when you press the button. 64 | // Any pin you wish to use as input must be written HIGH and be pulled LOW to generate an interrupt. 65 | pcf8574.write(7, pcf8574.read(3)); 66 | PCFInterruptFlag=false; 67 | } 68 | Serial.println("Blink."); 69 | if(digitalRead(2)==HIGH) digitalWrite(2, LOW); 70 | else digitalWrite(2, HIGH); 71 | delay(1000); 72 | } 73 | -------------------------------------------------------------------------------- /examples/pcf8574_stm32f1/pcf8574_stm32f1.ino: -------------------------------------------------------------------------------- 1 | /* Example sketch for the PCF8574 for the purposes of showing how to use the interrupt-pin. 2 | 3 | Attach the positive lead of an LED to PIN7 on the PCF8574 and the negative lead to GND, 4 | a wire from PC13 to pin 3 on the PCF8474, a wire from the int-pin on the PCF8574 to PC15 5 | and wires for SDA and SCL according to your STM32F1-module. 6 | 7 | If all goes well you should see the small blue LED on the ESP-module lighting up and the 8 | LED connected to the PCF going off, and vice versa. */ 9 | 10 | #include 11 | 12 | /* We need to set up the I2C-bus for the library to use */ 13 | #include 14 | /* Use I2C-bus 1 15 | Specsheets say PCF8574 is officially rated only for 100KHz I2C-bus */ 16 | HardWire HWire(1, I2C_BUS_RESET); 17 | /* PCF8575 is rated for 400KHz 18 | HardWire HWire(1, I2C_FAST_MODE | I2C_BUS_RESET); */ 19 | 20 | // Initialize a PCF8574 at I2C-address 0x20, using GPIO5, GPIO4 and testWire for the I2C-bus 21 | PCF857x pcf8574(0x20, &HWire); 22 | //If you had a PCF8575 instead you'd use the below format 23 | //PCF857x pcf8575(0x20, &Hwire, true); 24 | 25 | volatile bool PCFInterruptFlag = false; 26 | 27 | void PCFInterrupt() { 28 | PCFInterruptFlag = true; 29 | } 30 | 31 | void setup() { 32 | Serial.begin(115200); 33 | Serial.println(F("Firing up...")); 34 | pinMode(PC13, OUTPUT); 35 | 36 | HWire.begin(); 37 | pcf8574.begin(); 38 | // Most ready-made PCF8574-modules seem to lack an internal pullup-resistor, so you have to use the MCU-internal one. 39 | pinMode(PC15, INPUT_PULLUP); 40 | pcf8574.resetInterruptPin(); 41 | 42 | attachInterrupt(PC15, PCFInterrupt, FALLING); 43 | } 44 | 45 | void loop() { 46 | if(PCFInterruptFlag){ 47 | Serial.println(F("Got an interrupt: ")); 48 | if(pcf8574.read(3)==1) Serial.println("Pin 3 is HIGH!"); 49 | else Serial.println("Pin 3 is LOW!"); 50 | // DO NOTE: When you write LOW to a pin on a PCF8574 it becomes an OUTPUT. 51 | // It wouldn't generate an interrupt if you were to connect a button to it that pulls it HIGH when you press the button. 52 | // Any pin you wish to use as input must be written HIGH and be pulled LOW to generate an interrupt. 53 | pcf8574.write(7, pcf8574.read(3)); 54 | PCFInterruptFlag=false; 55 | } 56 | Serial.println(F("Blink.")); 57 | if(digitalRead(PC13)==HIGH) digitalWrite(PC13, LOW); 58 | else digitalWrite(PC13, HIGH); 59 | delay(1000); 60 | } 61 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Time 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | PCF8574 KEYWORD1 9 | ####################################### 10 | # Methods and Functions (KEYWORD2) 11 | ####################################### 12 | begin KEYWORD2 13 | read8 KEYWORD2 14 | read KEYWORD2 15 | value KEYWORD2 16 | write8 KEYWORD2 17 | write KEYWORD2 18 | toggle KEYWORD2 19 | toggleAll KEYWORD2 20 | shiftRight KEYWORD2 21 | shiftLeft KEYWORD2 22 | lastError KEYWORD2 23 | resetInterruptPin KEYWORD2 24 | rotateLeft KEYWORD2 25 | rotateRight KEYWORD2 26 | ####################################### 27 | # Instances (KEYWORD2) 28 | ####################################### 29 | 30 | ####################################### 31 | # Constants (LITERAL1) 32 | ####################################### 33 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=PCF8574_ESP 2 | version=1.0.10 3 | author=Rob Tillaart, WereCatf 4 | maintainer=WereCatf 5 | sentence=Library for using the 8- and 16-pin I2C GPIO-expanders PCF8574 and PCF8575 6 | paragraph=The original code by Rob Tillaart does not allow you to specify which I2C-bus to use if there are multiple ones, but this one does. On the ESP8266 this means you can use whichever pins you like, since it uses bitbanged I2C. This library has been tested to work with the Stm32duino, the Attiny-core by Spencekonde, the ESP8266-core and Arduino Micro. 7 | category=Communication 8 | url=https://github.com/WereCatf/PCF8574_ESP 9 | architectures=* 10 | includes=pcf8574_esp.h 11 | -------------------------------------------------------------------------------- /pcf8574_esp.cpp: -------------------------------------------------------------------------------- 1 | /* PCF857x_ESP -- library for using the I2C-driven 8-pin GPIO-expander 2 | ORIGINAL AUTHOR: Rob Tillaart 3 | Library modified by WereCatf */ 4 | 5 | #include "pcf8574_esp.h" 6 | #if defined (ARDUINO_AVR_DIGISPARK) || defined (ARDUINO_AVR_ATTINYX5) 7 | #include 8 | #else 9 | #include 10 | #endif 11 | 12 | #if defined (ARDUINO_AVR_DIGISPARK) || defined (ARDUINO_AVR_ATTINYX5) 13 | PCF857x::PCF857x(uint8_t address, bool is8575) 14 | { 15 | _Wire = &TinyWireM; 16 | _address = address; 17 | _is8575 = is8575; 18 | } 19 | 20 | void PCF857x::begin(uint16_t defaultValues) 21 | { 22 | if(_is8575) PCF857x::write16(defaultValues); 23 | else PCF857x::write8(defaultValues); 24 | } 25 | 26 | #else 27 | PCF857x::PCF857x(uint8_t address, TwoWire *UseWire, bool is8575) 28 | { 29 | _Wire = UseWire; 30 | _address = address; 31 | _is8575 = is8575; 32 | } 33 | 34 | void PCF857x::begin(uint16_t defaultValues) 35 | { 36 | if(_is8575) PCF857x::write16(defaultValues); 37 | else PCF857x::write8(defaultValues); 38 | } 39 | 40 | #endif 41 | 42 | uint8_t PCF857x::read8() 43 | { 44 | if(_is8575) 45 | { 46 | PCF857x::read16(); 47 | return (uint8_t) _data; 48 | } 49 | 50 | _Wire->requestFrom(_address, (uint8_t) 1); 51 | if(_Wire->available() < 1) 52 | { 53 | _error = PCF857x_I2C_ERROR; 54 | return (uint8_t) _data; 55 | } 56 | #if (ARDUINO < 100) 57 | _data = _Wire->receive(); 58 | #else 59 | _data = _Wire->read(); 60 | #endif 61 | return _data; 62 | } 63 | 64 | uint16_t PCF857x::read16() 65 | { 66 | if(!_is8575){ 67 | PCF857x::read8(); 68 | return (uint16_t) _data; 69 | } 70 | 71 | _Wire->requestFrom(_address, (uint8_t) 2); 72 | if(_Wire->available() < 2) 73 | { 74 | _error = PCF857x_I2C_ERROR; 75 | return _data; 76 | } 77 | _data = 0; 78 | #if (ARDUINO < 100) 79 | _data = _Wire->receive(); 80 | _data |= _Wire->receive() << 8; 81 | #else 82 | _data = _Wire->read(); 83 | _data |= _Wire->read() << 8; 84 | #endif 85 | return _data; 86 | } 87 | 88 | void PCF857x::resetInterruptPin() 89 | { 90 | if(_is8575) PCF857x::read16(); 91 | else PCF857x::read8(); 92 | } 93 | 94 | void PCF857x::write8(uint8_t value) 95 | { 96 | _Wire->beginTransmission(_address); 97 | _pinModeMask &=0xff00; 98 | _pinModeMask |= value; 99 | _data = _pinModeMask; 100 | _Wire->write((uint8_t) _data); 101 | if(_is8575) _Wire->write((uint8_t) (_data >> 8)); 102 | _error = _Wire->endTransmission(); 103 | } 104 | 105 | void PCF857x::write16(uint16_t value) 106 | { 107 | if(!_is8575) return; 108 | _Wire->beginTransmission(_address); 109 | _pinModeMask = value; 110 | _data = _pinModeMask; 111 | _Wire->write((uint8_t) _data); 112 | _Wire->write((uint8_t) (_data >> 8)); 113 | _error = _Wire->endTransmission(); 114 | } 115 | 116 | uint8_t PCF857x::read(uint8_t pin) 117 | { 118 | if(_is8575) 119 | { 120 | if(pin > 15) 121 | { 122 | _error = PCF857x_PIN_ERROR; 123 | return 0; 124 | } 125 | PCF857x::read16(); 126 | } 127 | else 128 | { 129 | if(pin > 7) 130 | { 131 | _error = PCF857x_PIN_ERROR; 132 | return 0; 133 | } 134 | PCF857x::read8(); 135 | } 136 | return (_data & (1< 0; 137 | } 138 | 139 | void PCF857x::write(uint8_t pin, uint8_t value) 140 | { 141 | if(_is8575) 142 | { 143 | if(pin > 15) 144 | { 145 | _error = PCF857x_PIN_ERROR; 146 | return; 147 | } 148 | } 149 | else if(pin > 7) 150 | { 151 | _error = PCF857x_PIN_ERROR; 152 | return; 153 | } 154 | uint8_t _val = value & 1; 155 | if(_val) _pinModeMask |= _val << pin; 156 | else _pinModeMask &= ~(1 << pin); 157 | if(_is8575) PCF857x::write16(_pinModeMask); 158 | else PCF857x::write8(_pinModeMask); 159 | } 160 | 161 | void PCF857x::toggle(uint8_t pin) 162 | { 163 | if(_is8575) 164 | { 165 | if(pin > 15) 166 | { 167 | _error = PCF857x_PIN_ERROR; 168 | return; 169 | } 170 | } 171 | else if(pin > 7) 172 | { 173 | _error = PCF857x_PIN_ERROR; 174 | return; 175 | } 176 | _pinModeMask ^= 1 << pin; 177 | if(_is8575) PCF857x::write16(_pinModeMask); 178 | else PCF857x::write8(_pinModeMask); 179 | } 180 | 181 | void PCF857x::toggleAll() 182 | { 183 | _pinModeMask = ~_pinModeMask; 184 | if(_is8575) PCF857x::write16(_pinModeMask); 185 | else PCF857x::write8(_pinModeMask); 186 | } 187 | 188 | void PCF857x::shiftRight(uint8_t n) 189 | { 190 | if(_is8575) 191 | { 192 | if (n == 0 || n > 15 ) return; 193 | } 194 | else if (n == 0 || n > 7 ) return; 195 | _pinModeMask >>= n; 196 | if(_is8575) PCF857x::write16(_pinModeMask); 197 | else PCF857x::write8(_pinModeMask); 198 | } 199 | 200 | void PCF857x::shiftLeft(uint8_t n) 201 | { 202 | if(_is8575) 203 | { 204 | if (n == 0 || n > 15 ) return; 205 | } 206 | else if (n == 0 || n > 7 ) return; 207 | _pinModeMask <<= n; 208 | if(_is8575) PCF857x::write16(_pinModeMask); 209 | else PCF857x::write8(_pinModeMask); 210 | } 211 | 212 | void PCF857x::rotateRight(uint8_t n) 213 | { 214 | if(_is8575){ 215 | uint8_t r = n & 15; 216 | _pinModeMask = (_pinModeMask >> r) | (_pinModeMask << (16-r)); 217 | PCF857x::write16(_pinModeMask); 218 | } else { 219 | uint8_t r = n & 7; 220 | _pinModeMask = (_pinModeMask >> r) | (_pinModeMask << (8-r)); 221 | PCF857x::write8(_pinModeMask); 222 | } 223 | } 224 | 225 | void PCF857x::rotateLeft(uint8_t n) 226 | { 227 | if(_is8575) PCF857x::rotateRight(16- (n & 15)); 228 | else PCF857x::rotateRight(8- (n & 7)); 229 | } 230 | 231 | int PCF857x::lastError() 232 | { 233 | int e = _error; 234 | _error = 0; 235 | return e; 236 | } 237 | -------------------------------------------------------------------------------- /pcf8574_esp.h: -------------------------------------------------------------------------------- 1 | /* PCF8574_ESP -- library for using the I2C-driven 8-pin GPIO-expander 2 | ORIGINAL AUTHOR: Rob Tillaart 3 | Library modified by WereCatf */ 4 | 5 | #ifndef _PCF8574_ESP_H 6 | #define _PCF8574_ESP_H 7 | 8 | #if defined(ARDUINO) && ARDUINO >= 100 9 | #include 10 | #else 11 | #include 12 | #endif 13 | 14 | #if defined (ARDUINO_AVR_DIGISPARK) || defined (ARDUINO_AVR_ATTINYX5) 15 | #include 16 | #else 17 | #include 18 | #endif 19 | 20 | #define PCF857x_OK 0x00 21 | #define PCF857x_PIN_ERROR 0x81 22 | #define PCF857x_I2C_ERROR 0x82 23 | 24 | class PCF857x 25 | { 26 | public: 27 | // Defaults to 8574, set is8575 to true if you have a 8575 instead. 28 | #if defined (ARDUINO_AVR_DIGISPARK) || defined (ARDUINO_AVR_ATTINYX5) 29 | PCF857x(uint8_t address, bool is8575 = false); 30 | #else 31 | PCF857x(uint8_t address, TwoWire *UseWire, bool is8575 = false); 32 | #endif 33 | 34 | void begin(uint16_t defaultValues=0xffff); 35 | uint8_t read8(); 36 | uint16_t read16(); 37 | uint8_t read(uint8_t pin); 38 | 39 | void write8(uint8_t value); 40 | void write16(uint16_t value); 41 | void write(uint8_t pin, uint8_t value); 42 | 43 | void toggle(uint8_t pin); 44 | void toggleAll(); 45 | void shiftRight(uint8_t n=1); 46 | void shiftLeft(uint8_t n=1); 47 | void rotateRight(uint8_t n=1); 48 | void rotateLeft(uint8_t n=1); 49 | void resetInterruptPin(); 50 | 51 | int lastError(); 52 | 53 | protected: 54 | uint16_t _data; 55 | uint16_t _pinModeMask; 56 | bool _is8575; 57 | 58 | private: 59 | #if defined (ARDUINO_AVR_DIGISPARK) || defined (ARDUINO_AVR_ATTINYX5) 60 | USI_TWI *_Wire; 61 | #else 62 | TwoWire *_Wire; 63 | #endif 64 | uint8_t _address; 65 | int _error; 66 | }; 67 | 68 | #endif 69 | --------------------------------------------------------------------------------