├── .gitattributes ├── .project ├── .travis.yml ├── LICENSE ├── LICENSE.md ├── PCF8574.cpp ├── PCF8574.h ├── PCF8574_library.h ├── README.md ├── examples ├── Arduino4Leds4ButtonsWithInterrupt │ └── Arduino4Leds4ButtonsWithInterrupt.ino ├── ArduinoSAMDSercom3keyPressedPin1 │ └── ArduinoSAMDSercom3keyPressedPin1.ino ├── blinkOnPin0 │ └── blinkOnPin0.ino ├── encoderWithBasicLibraryFunction │ └── encoderWithBasicLibraryFunction.ino ├── encoderWithFullLibraryFunction │ └── encoderWithFullLibraryFunction.ino ├── interruptWemos │ └── interruptWemos.ino ├── keyPressedPin1 │ └── keyPressedPin1.ino ├── keyPressedPin1_storedOnBuffer_async │ └── keyPressedPin1_storedOnBuffer_async.ino ├── keyPressed_withInterrupt │ └── keyPressed_withInterrupt.ino ├── ledEsp32OnTheSecondI2C │ ├── ledEsp32OnTheSecondI2C.ino │ └── testLedESP32_bb.jpg ├── ledWemos │ ├── ledWemos.ino │ └── testLedWemosEsp8266_bb.jpg ├── readAll_Interrupt │ └── readAll_Interrupt.ino ├── readAll_Interrupt_lowMemory │ └── readAll_Interrupt_lowMemory.ino └── writeAllEsp8266 │ └── writeAllEsp8266.ino ├── keywords.txt ├── library.json └── library.properties /.gitattributes: -------------------------------------------------------------------------------- 1 | resources export-ignore 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | PCF8574_library 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.make.core.makeBuilder 10 | clean,full,incremental, 11 | 12 | 13 | org.eclipse.cdt.core.errorOutputParser 14 | org.eclipse.cdt.autotools.core.ErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GmakeErrorParser;org.eclipse.cdt.core.VCErrorParser;org.eclipse.cdt.core.CWDLocator;org.eclipse.cdt.core.MakeErrorParser; 15 | 16 | 17 | org.eclipse.cdt.make.core.append_environment 18 | true 19 | 20 | 21 | org.eclipse.cdt.make.core.build.arguments 22 | 23 | 24 | 25 | org.eclipse.cdt.make.core.build.command 26 | make 27 | 28 | 29 | org.eclipse.cdt.make.core.build.target.auto 30 | all 31 | 32 | 33 | org.eclipse.cdt.make.core.build.target.clean 34 | clean 35 | 36 | 37 | org.eclipse.cdt.make.core.build.target.inc 38 | all 39 | 40 | 41 | org.eclipse.cdt.make.core.enableAutoBuild 42 | false 43 | 44 | 45 | org.eclipse.cdt.make.core.enableCleanBuild 46 | true 47 | 48 | 49 | org.eclipse.cdt.make.core.enableFullBuild 50 | true 51 | 52 | 53 | org.eclipse.cdt.make.core.enabledIncrementalBuild 54 | true 55 | 56 | 57 | org.eclipse.cdt.make.core.environment 58 | 59 | 60 | 61 | org.eclipse.cdt.make.core.stopOnError 62 | false 63 | 64 | 65 | org.eclipse.cdt.make.core.useDefaultBuildCmd 66 | true 67 | 68 | 69 | 70 | 71 | org.eclipse.cdt.autotools.core.genmakebuilderV2 72 | 73 | 74 | 75 | 76 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 77 | 78 | 79 | 80 | 81 | io.sloeber.core.inoToCpp 82 | 83 | 84 | 85 | 86 | org.eclipse.cdt.codan.core.codanBuilder 87 | 88 | 89 | 90 | 91 | 92 | io.sloeber.arduinonature 93 | org.eclipse.cdt.core.cnature 94 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 95 | org.eclipse.cdt.core.ccnature 96 | org.eclipse.cdt.autotools.core.autotoolsNatureV2 97 | org.eclipse.cdt.make.core.makeNature 98 | org.eclipse.cdt.codan.core.codanNature 99 | org.eclipse.cdt.make.core.cfgSupportNature 100 | 101 | 102 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | language: python 23 | python: 24 | - "3.7" 25 | 26 | # Cache PlatformIO packages using Travis CI container-based infrastructure 27 | sudo: false 28 | cache: 29 | directories: 30 | - "~/.platformio" 31 | - $HOME/.cache/pip 32 | 33 | env: 34 | - PLATFORMIO_CI_SRC=examples/Arduino4Leds4ButtonsWithInterrupt/Arduino4Leds4ButtonsWithInterrupt.ino 35 | - PLATFORMIO_CI_SRC=examples/readAll_Interrupt/readAll_Interrupt.ino 36 | 37 | install: 38 | - pip install -U platformio pip setuptools 39 | - platformio update 40 | 41 | script: 42 | - platformio ci --lib="." --board=uno --board=esp-wrover-kit 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Renzo Mischianti 4 | 5 | You may copy, alter and reuse this code in any way you like, but please leave 6 | reference to www.mischianti.org in your comments if you redistribute this code. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Renzo Mischianti www.mischianti.org All right reserved. 4 | 5 | You may copy, alter and reuse this code in any way you like, but please leave 6 | reference to www.mischianti.org in your comments if you redistribute this code. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /PCF8574.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PCF8574 GPIO Port Expand 3 | * https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 4 | * 5 | * The MIT License (MIT) 6 | * 7 | * Copyright (c) 2017 Renzo Mischianti www.mischianti.org All right reserved. 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #include "PCF8574.h" 29 | #include "Wire.h" 30 | 31 | /** 32 | * Constructor 33 | * @param address: i2c address 34 | */ 35 | PCF8574::PCF8574(uint8_t address){ 36 | _wire = &Wire; 37 | 38 | _address = address; 39 | }; 40 | 41 | /** 42 | * Construcor 43 | * @param address: i2c address 44 | * @param interruptPin: pin to set interrupt 45 | * @param interruptFunction: function to call when interrupt raised 46 | */ 47 | PCF8574::PCF8574(uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ){ 48 | _wire = &Wire; 49 | 50 | _address = address; 51 | _interruptPin = interruptPin; 52 | _interruptFunction = interruptFunction; 53 | _usingInterrupt = true; 54 | }; 55 | 56 | #if !defined(__AVR) && !defined(ARDUINO_ARCH_SAMD) && !defined(TEENSYDUINO) && !defined(ARDUINO_ARCH_RENESAS) 57 | /** 58 | * Constructor 59 | * @param address: i2c address 60 | * @param sda: sda pin 61 | * @param scl: scl pin 62 | */ 63 | PCF8574::PCF8574(uint8_t address, int sda, int scl){ 64 | _wire = &Wire; 65 | 66 | _address = address; 67 | _sda = sda; 68 | _scl = scl; 69 | }; 70 | 71 | /** 72 | * Constructor 73 | * @param address: i2c address 74 | * @param sda: sda pin 75 | * @param scl: scl pin 76 | * @param interruptPin: pin to set interrupt 77 | * @param interruptFunction: function to call when interrupt raised 78 | */ 79 | PCF8574::PCF8574(uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)() ){ 80 | _wire = &Wire; 81 | 82 | _address = address; 83 | _sda = sda; 84 | _scl = scl; 85 | 86 | _interruptPin = interruptPin; 87 | _interruptFunction = interruptFunction; 88 | 89 | _usingInterrupt = true; 90 | }; 91 | #endif 92 | 93 | #if defined(ESP32) || defined(ARDUINO_ARCH_SAMD)|| defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_RENESAS) 94 | /** 95 | * Constructor 96 | * @param address: i2c address 97 | */ 98 | PCF8574::PCF8574(TwoWire *pWire, uint8_t address){ 99 | _wire = pWire; 100 | 101 | _address = address; 102 | }; 103 | 104 | /** 105 | * Construcor 106 | * @param address: i2c address 107 | * @param interruptPin: pin to set interrupt 108 | * @param interruptFunction: function to call when interrupt raised 109 | */ 110 | PCF8574::PCF8574(TwoWire *pWire, uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ){ 111 | _wire = pWire; 112 | 113 | _address = address; 114 | _interruptPin = interruptPin; 115 | _interruptFunction = interruptFunction; 116 | _usingInterrupt = true; 117 | }; 118 | #endif 119 | #if defined(ESP32) 120 | /** 121 | * Constructor 122 | * @param address: i2c address 123 | * @param sda: sda pin 124 | * @param scl: scl pin 125 | */ 126 | PCF8574::PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl){ 127 | _wire = pWire; 128 | 129 | _address = address; 130 | _sda = sda; 131 | _scl = scl; 132 | }; 133 | 134 | /** 135 | * Constructor 136 | * @param address: i2c address 137 | * @param sda: sda pin 138 | * @param scl: scl pin 139 | * @param interruptPin: pin to set interrupt 140 | * @param interruptFunction: function to call when interrupt raised 141 | */ 142 | PCF8574::PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)() ){ 143 | _wire = pWire; 144 | 145 | _address = address; 146 | _sda = sda; 147 | _scl = scl; 148 | 149 | _interruptPin = interruptPin; 150 | _interruptFunction = interruptFunction; 151 | 152 | _usingInterrupt = true; 153 | }; 154 | #endif 155 | bool encoderPins[8]; 156 | 157 | void PCF8574::attachInterrupt(){ 158 | // If using interrupt set interrupt value to pin 159 | if (_usingInterrupt){ 160 | for (int i = 0; i < 8;i++){ 161 | if (encoderPins[i]) PCF8574::digitalRead(i); 162 | } 163 | // PCF8574::digitalReadAll(); 164 | // (*_interruptFunction)(); 165 | 166 | // DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)"); 167 | // ::pinMode(_interruptPin, INPUT_PULLUP); 168 | // attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING ); 169 | DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)"); 170 | ::pinMode(_interruptPin, INPUT_PULLUP); 171 | ::attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING ); 172 | } 173 | 174 | } 175 | void PCF8574::detachInterrupt(){ 176 | // If using interrupt set interrupt value to pin 177 | if (_usingInterrupt){ 178 | ::detachInterrupt(digitalPinToInterrupt(_interruptPin)); 179 | DEBUG_PRINTLN("Detach interrupt pin"); 180 | } 181 | 182 | } 183 | 184 | bool PCF8574::begin(uint8_t address){ 185 | _address = address; 186 | return PCF8574::begin(); 187 | } 188 | 189 | 190 | /** 191 | * wake up i2c controller 192 | */ 193 | bool PCF8574::begin(){ 194 | this->transmissionStatus = 4; 195 | #if !defined(__AVR) && !defined(ARDUINO_ARCH_SAMD) && !defined(TEENSYDUINO) && !defined(ARDUINO_ARCH_RENESAS) 196 | DEBUG_PRINT(F("begin(sda, scl) -> "));DEBUG_PRINT(_sda);DEBUG_PRINT(F(" "));DEBUG_PRINTLN(_scl); 197 | // _wire->begin(_sda, _scl); 198 | #ifdef ARDUINO_ARCH_STM32 199 | _wire->begin((uint32_t)_sda, (uint32_t)_scl); 200 | #elif defined(ARDUINO_ARCH_RP2040) 201 | _wire->setSCL(_scl); 202 | _wire->setSDA(_sda); 203 | _wire->begin(); 204 | #else 205 | _wire->begin((int)_sda, (int)_scl); 206 | #endif 207 | #else 208 | // Default pin for AVR some problem on software emulation 209 | // #define SCL_PIN _scl 210 | // #define SDA_PIN _sda 211 | _wire->begin(); 212 | #endif 213 | 214 | // Check if there are pins to set low 215 | if (writeMode>0 || readMode>0){ 216 | DEBUG_PRINTLN("Set write mode"); 217 | _wire->beginTransmission(_address); 218 | 219 | 220 | DEBUG_PRINT("resetInitial pin "); 221 | #ifdef PCF8574_SOFT_INITIALIZATION 222 | resetInitial = writeModeUp | readModePullUp; 223 | #else 224 | resetInitial = writeModeUp | readMode; 225 | #endif 226 | DEBUG_PRINTLN( resetInitial, BIN); 227 | 228 | _wire->write(resetInitial); 229 | 230 | initialBuffer = writeModeUp | readModePullUp; 231 | byteBuffered = initialBuffer; 232 | writeByteBuffered = writeModeUp; 233 | 234 | DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor."); 235 | this->transmissionStatus = _wire->endTransmission(); 236 | } 237 | 238 | // // If using interrupt set interrupt value to pin 239 | // if (_usingInterrupt){ 240 | //// DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)"); 241 | //// ::pinMode(_interruptPin, INPUT_PULLUP); 242 | //// attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING ); 243 | // DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)"); 244 | // ::pinMode(_interruptPin, INPUT_PULLUP); 245 | // ::attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING ); 246 | // } 247 | 248 | PCF8574::attachInterrupt(); 249 | 250 | // inizialize last read 251 | lastReadMillis = millis(); 252 | 253 | return this->isLastTransmissionSuccess(); 254 | } 255 | 256 | /** 257 | * Set if fin is OUTPUT or INPUT 258 | * @param pin: pin to set 259 | * @param mode: mode, supported only INPUT or OUTPUT (to simplify) 260 | * @param output_start: output_start, for OUTPUT we can set initial value 261 | */ 262 | void PCF8574::pinMode(uint8_t pin, uint8_t mode, uint8_t output_start){ 263 | DEBUG_PRINT("Set pin "); 264 | DEBUG_PRINT(pin); 265 | DEBUG_PRINT(" as "); 266 | DEBUG_PRINTLN(mode); 267 | 268 | if (mode == OUTPUT){ 269 | writeMode = writeMode | bit(pin); 270 | if (output_start==HIGH) { 271 | writeModeUp = writeModeUp | bit(pin); 272 | } 273 | 274 | readMode = readMode & ~bit(pin); 275 | readModePullDown = readModePullDown & ~bit(pin); 276 | readModePullUp = readModePullUp & ~bit(pin); 277 | 278 | DEBUG_PRINT("W: "); 279 | DEBUG_PRINT(writeMode, BIN); 280 | DEBUG_PRINT(" R ALL: "); 281 | DEBUG_PRINT(readMode, BIN); 282 | 283 | DEBUG_PRINT(" R Down: "); 284 | DEBUG_PRINT(readModePullDown, BIN); 285 | DEBUG_PRINT("R Up: "); 286 | DEBUG_PRINTLN(readModePullUp, BIN); 287 | 288 | }else if (mode == INPUT){ 289 | writeMode = writeMode & ~bit(pin); 290 | 291 | readMode = readMode | bit(pin); 292 | readModePullDown = readModePullDown | bit(pin); 293 | readModePullUp = readModePullUp & ~bit(pin); 294 | 295 | DEBUG_PRINT("W: "); 296 | DEBUG_PRINT(writeMode, BIN); 297 | DEBUG_PRINT(" R ALL: "); 298 | DEBUG_PRINT(readMode, BIN); 299 | 300 | DEBUG_PRINT(" R Down: "); 301 | DEBUG_PRINT(readModePullDown, BIN); 302 | DEBUG_PRINT("R Up: "); 303 | DEBUG_PRINTLN(readModePullUp, BIN); 304 | }else if (mode == INPUT_PULLUP){ 305 | writeMode = writeMode & ~bit(pin); 306 | 307 | readMode = readMode | bit(pin); 308 | readModePullDown = readModePullDown & ~bit(pin); 309 | readModePullUp = readModePullUp | bit(pin); 310 | 311 | DEBUG_PRINT("W: "); 312 | DEBUG_PRINT(writeMode, BIN); 313 | DEBUG_PRINT(" R ALL: "); 314 | DEBUG_PRINT(readMode, BIN); 315 | 316 | DEBUG_PRINT(" R Down: "); 317 | DEBUG_PRINT(readModePullDown, BIN); 318 | DEBUG_PRINT("R Up: "); 319 | DEBUG_PRINTLN(readModePullUp, BIN); 320 | } 321 | else{ 322 | DEBUG_PRINTLN("Mode non supported by PCF8574") 323 | } 324 | }; 325 | 326 | 327 | void PCF8574::encoder(uint8_t pinA, uint8_t pinB){ 328 | PCF8574::pinMode(pinA, INPUT_PULLUP); 329 | PCF8574::pinMode(pinB, INPUT_PULLUP); 330 | 331 | encoderPins[pinA] = true; 332 | encoderPins[pinB] = true; 333 | } 334 | 335 | byte getBit(byte n, byte position) 336 | { 337 | return (n >> position) & 1; 338 | } 339 | 340 | 341 | //int8_t PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB){ 342 | // bool changed = false; 343 | // 344 | // byte offset = 0; 345 | // 346 | // byte na = PCF8574::digitalRead(pinA); 347 | // byte nb = PCF8574::digitalRead(pinB); 348 | // 349 | // byte encoderPinALast = (encoderValues & bit(pinA)); 350 | // byte encoderPinBLast = (encoderValues & bit(pinB)); 351 | // 352 | // if ((encoderPinALast!=na || encoderPinBLast!=nb) && (encoderPinALast == LOW) && (na == HIGH)) { 353 | // if (nb == LOW) { 354 | // offset = - 1; 355 | // changed = true; 356 | // } else { 357 | // offset = + 1; 358 | // changed = true; 359 | // } 360 | // } 361 | // 362 | // encoderValues = (encoderPinALast!=na)?encoderValues ^ bit(pinA):encoderValues; 363 | // encoderValues = (encoderPinBLast!=nb)?encoderValues ^ bit(pinB):encoderValues; 364 | // 365 | // return offset; 366 | //} 367 | 368 | bool PCF8574::checkProgression(byte oldValA, byte oldValB, byte newValA, byte newValB, byte validProgression){ 369 | bool findOldVal = false; 370 | int posFinded = 0; 371 | for (int pos = 0; pos<8; pos = pos + 2){ 372 | if ((oldValB == ((validProgression & bit(pos+1))>0?HIGH:LOW)) && (oldValA == ((validProgression & bit(pos+0))>0?HIGH:LOW)) ){ 373 | findOldVal = true; 374 | posFinded = pos; 375 | } 376 | } 377 | if (!findOldVal) return false; 378 | 379 | posFinded = posFinded + 2; 380 | if (posFinded>8) posFinded = 0; 381 | 382 | return ((newValB == ((validProgression & bit(posFinded+1))>0?HIGH:LOW)) && (newValA == ((validProgression & bit(posFinded+0))>0?HIGH:LOW)) ); 383 | } 384 | 385 | #ifdef BASIC_ENCODER_ALGORITHM 386 | bool PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ 387 | PCF8574::detachInterrupt(); 388 | 389 | bool changed = false; 390 | 391 | byte na = PCF8574::digitalRead(pinA, true); 392 | byte nb = PCF8574::digitalRead(pinB, true); 393 | 394 | byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; 395 | byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; 396 | 397 | DEBUG_PRINT(pinA); 398 | DEBUG_PRINT(" TO --> "); 399 | DEBUG_PRINT(encoderPinALast); 400 | DEBUG_PRINT(encoderPinBLast); 401 | DEBUG_PRINT(" - "); 402 | DEBUG_PRINT(na); 403 | DEBUG_PRINT(nb); 404 | DEBUG_PRINTLN(); 405 | 406 | if ((encoderPinALast!=na || encoderPinBLast!=nb) && (encoderPinALast == LOW) && (na == HIGH)) { 407 | // bool vCW = checkProgression(encoderPinALast, encoderPinBLast, na, nb, validCW); 408 | // bool vCCW = checkProgression(encoderPinALast, encoderPinBLast, na, nb, validCCW); 409 | 410 | if (nb == LOW) { 411 | *encoderValue = *encoderValue + (!reverseRotation?+1:-1); 412 | changed = true; 413 | } else { 414 | *encoderValue = *encoderValue + (!reverseRotation?-1:+1); 415 | changed = true; 416 | } 417 | 418 | // if (nb == LOW && vCW) { 419 | // // checkCW(encoderPinALast, encoderPinBLast, na, nb); 420 | // *encoderValue = *encoderValue - 1; 421 | // changed = true; 422 | // } else if (vCCW) { 423 | // *encoderValue = *encoderValue + 1; 424 | // changed = true; 425 | // } 426 | 427 | } 428 | 429 | this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; 430 | this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; 431 | PCF8574::attachInterrupt(); 432 | 433 | return changed; 434 | } 435 | int8_t PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB) { 436 | volatile long encoderValue = 0; 437 | PCF8574::readEncoderValue(pinA, pinB, &encoderValue); 438 | return encoderValue; 439 | } 440 | 441 | #endif 442 | 443 | #ifdef SEQUENCE_ENCODER_ALGORITHM 444 | bool PCF8574::readEncoderValueSequence(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ 445 | 446 | PCF8574::detachInterrupt(); 447 | bool changed = false; 448 | 449 | delay(100); 450 | byte na = PCF8574::digitalRead(pinA, true); 451 | byte nb = PCF8574::digitalRead(pinB, true); 452 | 453 | byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; 454 | byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; 455 | 456 | DEBUG_PRINT(pinA); 457 | DEBUG_PRINT(" TO --> "); 458 | DEBUG_PRINT(encoderPinALast); 459 | DEBUG_PRINT(encoderPinBLast); 460 | DEBUG_PRINT(" - "); 461 | DEBUG_PRINT(na); 462 | DEBUG_PRINT(nb); 463 | DEBUG_PRINT(" -- "); 464 | 465 | int encoded = (na << 1) | nb; //converting the 2 pin value to single number 466 | int lastEncoded = (encoderPinALast << 1) | encoderPinBLast; 467 | int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value 468 | 469 | DEBUG_PRINT("sum - "); 470 | DEBUG_PRINT(sum, BIN); 471 | 472 | DEBUG_PRINT(" enc - "); 473 | DEBUG_PRINT( *encoderValue); 474 | 475 | if( 476 | sum == 0b1101 477 | || sum == 0b0100 478 | || sum == 0b0010 479 | || sum == 0b1011 480 | ){ 481 | // encoderValue ++; 482 | *encoderValue = *encoderValue + (!reverseRotation?+1:-1); 483 | changed = true; 484 | } 485 | if( 486 | sum == 0b1110 487 | || sum == 0b0111 488 | || sum == 0b0001 489 | || sum == 0b1000 490 | ) { 491 | *encoderValue = *encoderValue + (!reverseRotation?-1:+1); 492 | changed = true; 493 | // encoderValue --; 494 | } 495 | 496 | DEBUG_PRINT(" enc next - "); 497 | DEBUG_PRINTLN( *encoderValue); 498 | 499 | this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; 500 | this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; 501 | PCF8574::attachInterrupt(); 502 | return changed; 503 | } 504 | int8_t PCF8574::readEncoderValueSequence(uint8_t pinA, uint8_t pinB) { 505 | volatile long encoderValue = 0; 506 | PCF8574::readEncoderValueSequence(pinA, pinB, &encoderValue); 507 | return encoderValue; 508 | } 509 | 510 | #endif 511 | #ifdef SEQUENCE_ENCODER_ALGORITHM_REDUCED 512 | bool PCF8574::readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ 513 | 514 | PCF8574::detachInterrupt(); 515 | bool changed = false; 516 | 517 | delay(100); 518 | byte na = PCF8574::digitalRead(pinA, true); 519 | byte nb = PCF8574::digitalRead(pinB, true); 520 | 521 | byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; 522 | byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; 523 | 524 | DEBUG_PRINT(pinA); 525 | DEBUG_PRINT(" TO --> "); 526 | DEBUG_PRINT(encoderPinALast); 527 | DEBUG_PRINT(encoderPinBLast); 528 | DEBUG_PRINT(" - "); 529 | DEBUG_PRINT(na); 530 | DEBUG_PRINT(nb); 531 | DEBUG_PRINT(" -- "); 532 | 533 | int encoded = (na << 1) | nb; //converting the 2 pin value to single number 534 | int lastEncoded = (encoderPinALast << 1) | encoderPinBLast; 535 | int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value 536 | 537 | DEBUG_PRINT("sum - "); 538 | DEBUG_PRINT(sum, BIN); 539 | 540 | DEBUG_PRINT(" enc - "); 541 | DEBUG_PRINT( *encoderValue); 542 | 543 | if( 544 | sum == 0b1101 545 | // || sum == 0b0100 546 | || sum == 0b0010 547 | // || sum == 0b1011 548 | ){ 549 | // encoderValue ++; 550 | *encoderValue = *encoderValue + (!reverseRotation?+1:-1); 551 | changed = true; 552 | } 553 | if( 554 | sum == 0b1110 555 | // || sum == 0b0111 556 | || sum == 0b0001 557 | // || sum == 0b1000 558 | ) { 559 | *encoderValue = *encoderValue + (!reverseRotation?-1:+1); 560 | changed = true; 561 | // encoderValue --; 562 | } 563 | 564 | DEBUG_PRINT(" enc next - "); 565 | DEBUG_PRINTLN( *encoderValue); 566 | 567 | this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; 568 | this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; 569 | PCF8574::attachInterrupt(); 570 | return changed; 571 | } 572 | int8_t PCF8574::readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB) { 573 | volatile long encoderValue = 0; 574 | PCF8574::readEncoderValueSequenceReduced(pinA, pinB, &encoderValue); 575 | return encoderValue; 576 | } 577 | 578 | #endif 579 | #ifdef MISCHIANTI_ENCODER_ALGORITHM 580 | bool PCF8574::readEncoderValueMischianti(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ 581 | PCF8574::detachInterrupt(); 582 | bool changed = false; 583 | 584 | byte na = PCF8574::digitalRead(pinA, true); 585 | byte nb = PCF8574::digitalRead(pinB, true); 586 | 587 | byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; 588 | byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; 589 | 590 | if ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == LOW) || encoderPinALast==encoderPinBLast) && (na == HIGH)) { 591 | DEBUG_PRINT("TO --> "); 592 | DEBUG_PRINT(encoderPinALast); 593 | DEBUG_PRINT(encoderPinBLast); 594 | DEBUG_PRINT(" - "); 595 | DEBUG_PRINT(na); 596 | DEBUG_PRINT(nb); 597 | DEBUG_PRINTLN(); 598 | 599 | if (nb == LOW && nb!=na) { 600 | *encoderValue = *encoderValue + (!reverseRotation?+1:-1); 601 | changed = true; 602 | } else if (nb==na && encoderPinALast==encoderPinBLast) { 603 | *encoderValue = *encoderValue + (!reverseRotation?-1:+1); 604 | changed = true; 605 | } 606 | } 607 | // encoderValues = encoderValues & (~(bit(pinA) | bit(pinB))); 608 | // if (na == HIGH){ 609 | // encoderValues = encoderValues | bit(pinA); 610 | // } 611 | // if (nb == HIGH){ 612 | // encoderValues = encoderValues | bit(pinA); 613 | // } 614 | 615 | if (encoderPinALast!=na || encoderPinBLast!=nb){ 616 | this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; 617 | this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; 618 | } 619 | 620 | PCF8574::attachInterrupt(); 621 | return changed; 622 | } 623 | int8_t PCF8574::readEncoderValueMischianti(uint8_t pinA, uint8_t pinB) { 624 | volatile long encoderValue = 0; 625 | PCF8574::readEncoderValueMischianti(pinA, pinB, &encoderValue); 626 | return encoderValue; 627 | } 628 | 629 | #endif 630 | //#ifdef MISCHIANTI_ENCODER_ALGORITHM_EVOLVED 631 | // bool PCF8574::readEncoderValueEvolved(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ 632 | // PCF8574::detachInterrupt(); 633 | // bool changed = false; 634 | // 635 | // byte na = PCF8574::digitalRead(pinA, true); 636 | // byte nb = PCF8574::digitalRead(pinB, true); 637 | // 638 | // byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; 639 | // byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; 640 | // 641 | //// Serial.print(pinA); 642 | //// Serial.print(" TO --> "); 643 | //// Serial.print(encoderPinALast); 644 | //// Serial.print(encoderPinBLast); 645 | //// Serial.print(" - "); 646 | //// Serial.print(na); 647 | //// Serial.print(nb); 648 | // 649 | // if ( 650 | // 651 | // ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == LOW) || encoderPinALast==encoderPinBLast) && (na == HIGH)) 652 | // || ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == HIGH) || encoderPinALast==encoderPinBLast) && (na == LOW)) 653 | // ){ 654 | // DEBUG_PRINT("TO --> "); 655 | // DEBUG_PRINT(encoderPinALast); 656 | // DEBUG_PRINT(encoderPinBLast); 657 | // DEBUG_PRINT(" - "); 658 | // DEBUG_PRINT(na); 659 | // DEBUG_PRINT(nb); 660 | // DEBUG_PRINTLN(); 661 | // 662 | //// Serial.print (" <------ "); 663 | // 664 | // if (nb == LOW && nb!=na) { 665 | // *encoderValue = *encoderValue + (!reverseRotation?+1:-1); 666 | // changed = true; 667 | // } else if (nb==na && encoderPinALast==encoderPinBLast) { 668 | // *encoderValue = *encoderValue + (!reverseRotation?-1:+1); 669 | // changed = true; 670 | // } 671 | // } 672 | //// Serial.println(); 673 | //// encoderValues = encoderValues & (~(bit(pinA) | bit(pinB))); 674 | //// if (na == HIGH){ 675 | //// encoderValues = encoderValues | bit(pinA); 676 | //// } 677 | //// if (nb == HIGH){ 678 | //// encoderValues = encoderValues | bit(pinA); 679 | //// } 680 | // 681 | // if (encoderPinALast!=na || encoderPinBLast!=nb){ 682 | // this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; 683 | // this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; 684 | // } 685 | // 686 | // PCF8574::attachInterrupt(); 687 | // return changed; 688 | // } 689 | // int8_t PCF8574::readEncoderValueEvolved(uint8_t pinA, uint8_t pinB) { 690 | // volatile long encoderValue = 0; 691 | // PCF8574::readEncoderValueEvolved(pinA, pinB, &encoderValue); 692 | // return encoderValue; 693 | // } 694 | // 695 | //#endif 696 | 697 | #ifdef POKI_ENCODER_ALGORITHM 698 | bool PCF8574::readEncoderValuePoki(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ 699 | PCF8574::detachInterrupt(); 700 | 701 | bool changed = false; 702 | 703 | byte na = PCF8574::digitalRead(pinA, true); 704 | byte nb = PCF8574::digitalRead(pinB, true); 705 | 706 | byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; 707 | byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; 708 | 709 | DEBUG_PRINT("TO --> "); 710 | DEBUG_PRINT(encoderPinALast); 711 | DEBUG_PRINT(encoderPinBLast); 712 | DEBUG_PRINT(" - "); 713 | DEBUG_PRINT(na); 714 | DEBUG_PRINT(nb); 715 | DEBUG_PRINTLN(); 716 | 717 | if ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == LOW) || encoderPinALast==encoderPinBLast) && (na == HIGH)) { 718 | DEBUG_PRINT("TO --> "); 719 | DEBUG_PRINT(encoderPinALast); 720 | DEBUG_PRINT(encoderPinBLast); 721 | DEBUG_PRINT(" - "); 722 | DEBUG_PRINT(na); 723 | DEBUG_PRINT(nb); 724 | DEBUG_PRINTLN(); 725 | 726 | if (na && !nb) { 727 | if (encoderPinBLast) { 728 | *encoderValue = *encoderValue + (!reverseRotation?+1:-1); 729 | } else { 730 | *encoderValue = *encoderValue + (!reverseRotation?-1:+1); 731 | } 732 | changed = true; 733 | } 734 | } 735 | 736 | this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):encoderValues; 737 | this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):encoderValues; 738 | PCF8574::attachInterrupt(); 739 | 740 | return changed; 741 | } 742 | int8_t PCF8574::readEncoderValuePoki(uint8_t pinA, uint8_t pinB) { 743 | volatile long encoderValue = 0; 744 | PCF8574::readEncoderValue(pinA, pinB, &encoderValue); 745 | return encoderValue; 746 | } 747 | 748 | #endif 749 | 750 | 751 | /** 752 | * Read value from i2c and bufferize it 753 | * @param force 754 | */ 755 | void PCF8574::readBuffer(bool force){ 756 | // if (millis() > PCF8574::lastReadMillis+latency || _usingInterrupt || force){ 757 | if (millis() - PCF8574::lastReadMillis > latency || _usingInterrupt || force){ 758 | _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons 759 | lastReadMillis = millis(); 760 | if(_wire->available()) // If bytes are available to be recieved 761 | { 762 | byte iInput = _wire->read();// Read a byte 763 | if ((iInput & readModePullDown)>0 and (~iInput & readModePullUp)>0){ 764 | // if ((iInput & readMode)>0){ 765 | byteBuffered = (byteBuffered & ~readMode) | (byte)iInput; 766 | } 767 | } 768 | } 769 | } 770 | 771 | #ifndef PCF8574_LOW_MEMORY 772 | /** 773 | * Read value of all INPUT pin 774 | * Debounce read more fast than 10millis, non managed for interrupt mode 775 | * @return 776 | */ 777 | PCF8574::DigitalInput PCF8574::digitalReadAll(void){ 778 | DEBUG_PRINTLN("Read from buffer"); 779 | _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons 780 | lastReadMillis = millis(); 781 | if(_wire->available()) // If bytes are available to be recieved 782 | { 783 | DEBUG_PRINTLN("Data ready"); 784 | byte iInput = _wire->read();// Read a byte 785 | 786 | if ((readModePullDown & iInput)>0 or (readModePullUp & ~iInput)>0){ 787 | DEBUG_PRINT(" -------- CHANGE --------- "); 788 | byteBuffered = (byteBuffered & ~readMode) | (byte)iInput; 789 | } 790 | } 791 | 792 | DEBUG_PRINT("Buffer value "); 793 | DEBUG_PRINTLN(byteBuffered, BIN); 794 | 795 | if ((bit(0) & readMode)>0) digitalInput.p0 = ((byteBuffered & bit(0))>0)?HIGH:LOW; 796 | if ((bit(1) & readMode)>0) digitalInput.p1 = ((byteBuffered & bit(1))>0)?HIGH:LOW; 797 | if ((bit(2) & readMode)>0) digitalInput.p2 = ((byteBuffered & bit(2))>0)?HIGH:LOW; 798 | if ((bit(3) & readMode)>0) digitalInput.p3 = ((byteBuffered & bit(3))>0)?HIGH:LOW; 799 | if ((bit(4) & readMode)>0) digitalInput.p4 = ((byteBuffered & bit(4))>0)?HIGH:LOW; 800 | if ((bit(5) & readMode)>0) digitalInput.p5 = ((byteBuffered & bit(5))>0)?HIGH:LOW; 801 | if ((bit(6) & readMode)>0) digitalInput.p6 = ((byteBuffered & bit(6))>0)?HIGH:LOW; 802 | if ((bit(7) & readMode)>0) digitalInput.p7 = ((byteBuffered & bit(7))>0)?HIGH:LOW; 803 | 804 | if ((bit(0) & writeMode)>0) digitalInput.p0 = ((writeByteBuffered & bit(0))>0)?HIGH:LOW; 805 | if ((bit(1) & writeMode)>0) digitalInput.p1 = ((writeByteBuffered & bit(1))>0)?HIGH:LOW; 806 | if ((bit(2) & writeMode)>0) digitalInput.p2 = ((writeByteBuffered & bit(2))>0)?HIGH:LOW; 807 | if ((bit(3) & writeMode)>0) digitalInput.p3 = ((writeByteBuffered & bit(3))>0)?HIGH:LOW; 808 | if ((bit(4) & writeMode)>0) digitalInput.p4 = ((writeByteBuffered & bit(4))>0)?HIGH:LOW; 809 | if ((bit(5) & writeMode)>0) digitalInput.p5 = ((writeByteBuffered & bit(5))>0)?HIGH:LOW; 810 | if ((bit(6) & writeMode)>0) digitalInput.p6 = ((writeByteBuffered & bit(6))>0)?HIGH:LOW; 811 | if ((bit(7) & writeMode)>0) digitalInput.p7 = ((writeByteBuffered & bit(7))>0)?HIGH:LOW; 812 | 813 | //if ((byteBuffered & readModePullDown)>0 and (~byteBuffered & readModePullUp)>0){ 814 | 815 | // byteBuffered = (resetInitial & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered; 816 | 817 | byteBuffered = (initialBuffer & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered; 818 | 819 | DEBUG_PRINT("Buffer hight value readed set readed "); 820 | DEBUG_PRINTLN(byteBuffered, BIN); 821 | //} 822 | DEBUG_PRINT("Return value "); 823 | return digitalInput; 824 | }; 825 | #else 826 | /** 827 | * Read value of all INPUT pin in byte format for low memory usage 828 | * Debounce read more fast than 10millis, non managed for interrupt mode 829 | * @return 830 | */ 831 | byte PCF8574::digitalReadAll(void){ 832 | DEBUG_PRINTLN("Read from buffer"); 833 | _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons 834 | lastReadMillis = millis(); 835 | if(_wire->available()) // If bytes are available to be recieved 836 | { 837 | DEBUG_PRINTLN("Data ready"); 838 | byte iInput = _wire->read();// Read a byte 839 | 840 | if ((readModePullDown & iInput)>0 or (readModePullUp & ~iInput)>0){ 841 | DEBUG_PRINT(" -------- CHANGE --------- "); 842 | byteBuffered = (byteBuffered & ~readMode) | (byte)iInput; 843 | 844 | } 845 | } 846 | 847 | DEBUG_PRINT("Buffer value "); 848 | DEBUG_PRINTLN(byteBuffered, BIN); 849 | 850 | byte byteRead = byteBuffered | writeByteBuffered; 851 | 852 | //if ((byteBuffered & readModePullDown)>0 and (~byteBuffered & readModePullUp)>0){ 853 | // byteBuffered = (resetInitial & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered; 854 | byteBuffered = (initialBuffer & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered; 855 | DEBUG_PRINT("Buffer hight value readed set readed "); 856 | DEBUG_PRINTLN(byteBuffered, BIN); 857 | //} 858 | DEBUG_PRINT("Return value "); 859 | return byteRead; 860 | }; 861 | #endif 862 | 863 | /** 864 | * Read value of specified pin 865 | * Debounce read more fast than 10millis, non managed for interrupt mode 866 | * @param pin 867 | * @return 868 | */ 869 | uint8_t PCF8574::digitalRead(uint8_t pin, bool forceReadNow){ 870 | uint8_t value = (bit(pin) & readModePullUp)?HIGH:LOW; 871 | DEBUG_PRINT("Read pin "); 872 | DEBUG_PRINT (pin); 873 | // Check if pin already HIGH than read and prevent reread of i2c 874 | // DEBUG_PRINTLN("----------------------------------") 875 | // DEBUG_PRINT("readModePullUp "); 876 | // DEBUG_PRINTLN(readModePullUp, BIN); 877 | // DEBUG_PRINT("readModePullDown "); 878 | // DEBUG_PRINTLN(readModePullDown, BIN); 879 | // DEBUG_PRINT("byteBuffered "); 880 | // DEBUG_PRINTLN(byteBuffered, BIN); 881 | 882 | 883 | if ((((bit(pin) & (readModePullDown & byteBuffered))>0) or (bit(pin) & (readModePullUp & ~byteBuffered))>0 )){ 884 | DEBUG_PRINTLN(" ...Pin already set"); 885 | if ((bit(pin) & byteBuffered)>0){ 886 | value = HIGH; 887 | }else{ 888 | value = LOW; 889 | } 890 | // }else if (forceReadNow || (millis() > PCF8574::lastReadMillis+latency)){ 891 | }else if (forceReadNow || (millis() - PCF8574::lastReadMillis > latency)){ 892 | DEBUG_PRINT(" ...Read from buffer... "); 893 | _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons 894 | lastReadMillis = millis(); 895 | if(_wire->available()) // If bytes are available to be recieved 896 | { 897 | DEBUG_PRINTLN(" Data ready"); 898 | byte iInput = _wire->read();// Read a byte 899 | DEBUG_PRINT("Input "); 900 | DEBUG_PRINT((byte)iInput, BIN); 901 | 902 | if ((readModePullDown & iInput)>0 or (readModePullUp & ~iInput)>0){ 903 | DEBUG_PRINT(" -------- CHANGE --------- "); 904 | byteBuffered = (byteBuffered & ~readMode) | (byte)iInput; 905 | if ((bit(pin) & byteBuffered)>0){ 906 | value = HIGH; 907 | }else{ 908 | value = LOW; 909 | } 910 | // value = (bit(pin) & byteBuffered); 911 | } 912 | } 913 | } 914 | DEBUG_PRINT(" ..Buffer value "); 915 | DEBUG_PRINT(byteBuffered, BIN); 916 | // If HIGH set to low to read buffer only one time 917 | if ((bit(pin) & readModePullDown) and value==HIGH){ 918 | byteBuffered = bit(pin) ^ byteBuffered; 919 | DEBUG_PRINT(" ...Buffer hight value readed set readed "); 920 | DEBUG_PRINT (byteBuffered, BIN); 921 | }else if ((bit(pin) & readModePullUp) and value==LOW){ 922 | byteBuffered = bit(pin) ^ byteBuffered; 923 | DEBUG_PRINT(" ...Buffer low value readed set readed "); 924 | DEBUG_PRINT(byteBuffered, BIN); 925 | }else if(bit(pin) & writeByteBuffered){ 926 | value = HIGH; 927 | } 928 | DEBUG_PRINT(" ...Return value "); 929 | DEBUG_PRINTLN(value); 930 | return value; 931 | }; 932 | 933 | /** 934 | * Write on pin 935 | * @param pin 936 | * @param value 937 | */ 938 | bool PCF8574::digitalWrite(uint8_t pin, uint8_t value){ 939 | DEBUG_PRINTLN("Begin trasmission"); 940 | _wire->beginTransmission(_address); //Begin the transmission to PCF8574 941 | DEBUG_PRINT("Value "); 942 | DEBUG_PRINT(value); 943 | DEBUG_PRINT(" Write data pre "); 944 | DEBUG_PRINT(writeByteBuffered, BIN); 945 | 946 | if (value==HIGH){ 947 | writeByteBuffered = writeByteBuffered | bit(pin); 948 | byteBuffered = writeByteBuffered | bit(pin); 949 | }else{ 950 | writeByteBuffered = writeByteBuffered & ~bit(pin); 951 | byteBuffered = writeByteBuffered & ~bit(pin); 952 | } 953 | DEBUG_PRINT("Write data "); 954 | DEBUG_PRINT(writeByteBuffered, BIN); 955 | DEBUG_PRINT(" for pin "); 956 | DEBUG_PRINT(pin); 957 | DEBUG_PRINT(" bin value "); 958 | DEBUG_PRINT(bit(pin), BIN); 959 | DEBUG_PRINT(" value "); 960 | DEBUG_PRINT(value); 961 | 962 | // writeByteBuffered = writeByteBuffered & (~writeMode & byteBuffered); 963 | byteBuffered = (writeByteBuffered & writeMode) | (resetInitial & readMode); 964 | 965 | // byteBuffered = (writeByteBuffered & writeMode) | (byteBuffered & readMode); 966 | DEBUG_PRINT(" byteBuffered "); 967 | DEBUG_PRINTLN(byteBuffered, BIN); 968 | 969 | DEBUG_PRINT("Going to write data "); 970 | DEBUG_PRINTLN(writeByteBuffered, BIN); 971 | 972 | _wire->write(byteBuffered); 973 | 974 | byteBuffered = (writeByteBuffered & writeMode) | (initialBuffer & readMode); 975 | 976 | // byteBuffered = (writeByteBuffered & writeMode) & (byteBuffered & readMode); 977 | DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor."); 978 | 979 | this->transmissionStatus = _wire->endTransmission(); 980 | 981 | return this->isLastTransmissionSuccess(); 982 | }; 983 | 984 | #ifndef PCF8574_LOW_MEMORY 985 | /** 986 | * Read value of all INPUT pin 987 | * Debounce read more fast than 10millis, non managed for interrupt mode 988 | * @return 989 | */ 990 | void PCF8574::setVal(uint8_t pin, uint8_t value){ 991 | if (value==HIGH){ 992 | writeByteBuffered = writeByteBuffered | bit(pin); 993 | byteBuffered = writeByteBuffered | bit(pin); 994 | }else{ 995 | writeByteBuffered = writeByteBuffered & ~bit(pin); 996 | byteBuffered = writeByteBuffered & ~bit(pin); 997 | } 998 | 999 | } 1000 | bool PCF8574::digitalWriteAll(PCF8574::DigitalInput digitalInput){ 1001 | 1002 | setVal(P0, digitalInput.p0); 1003 | setVal(P1, digitalInput.p1); 1004 | setVal(P2, digitalInput.p2); 1005 | setVal(P3, digitalInput.p3); 1006 | setVal(P4, digitalInput.p4); 1007 | setVal(P5, digitalInput.p5); 1008 | setVal(P6, digitalInput.p6); 1009 | setVal(P7, digitalInput.p7); 1010 | 1011 | return digitalWriteAllBytes(writeByteBuffered); 1012 | } 1013 | #else 1014 | bool PCF8574::digitalWriteAll(byte digitalInput){ 1015 | return digitalWriteAllBytes(digitalInput); 1016 | } 1017 | #endif 1018 | 1019 | 1020 | bool PCF8574::digitalWriteAllBytes(byte allpins){ 1021 | _wire->beginTransmission(_address); //Begin the transmission to PCF8574 1022 | 1023 | // writeByteBuffered = writeByteBuffered & (~writeMode & byteBuffered); 1024 | writeByteBuffered = allpins; 1025 | byteBuffered = (writeByteBuffered & writeMode) | (resetInitial & readMode); 1026 | 1027 | // byteBuffered = (writeByteBuffered & writeMode) | (byteBuffered & readMode); 1028 | DEBUG_PRINT(" byteBuffered "); 1029 | DEBUG_PRINTLN(byteBuffered, BIN); 1030 | 1031 | DEBUG_PRINT("Going to write data "); 1032 | DEBUG_PRINTLN(writeByteBuffered, BIN); 1033 | 1034 | _wire->write(byteBuffered); 1035 | 1036 | byteBuffered = (writeByteBuffered & writeMode) | (initialBuffer & readMode); 1037 | 1038 | // byteBuffered = (writeByteBuffered & writeMode) & (byteBuffered & readMode); 1039 | DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor."); 1040 | 1041 | this->transmissionStatus = _wire->endTransmission(); 1042 | 1043 | return this->isLastTransmissionSuccess(); 1044 | 1045 | } 1046 | -------------------------------------------------------------------------------- /PCF8574.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PCF8574 GPIO Port Expand 3 | * 4 | * AUTHOR: Renzo Mischianti 5 | * VERSION: 2.3.7 6 | * 7 | * https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 8 | * 9 | * The MIT License (MIT) 10 | * 11 | * Copyright (c) 2017 Renzo Mischianti www.mischianti.org All right reserved. 12 | * 13 | * You may copy, alter and reuse this code in any way you like, but please leave 14 | * reference to www.mischianti.org in your comments if you redistribute this code. 15 | * 16 | * Permission is hereby granted, free of charge, to any person obtaining a copy 17 | * of this software and associated documentation files (the "Software"), to deal 18 | * in the Software without restriction, including without limitation the rights 19 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | * copies of the Software, and to permit persons to whom the Software is 21 | * furnished to do so, subject to the following conditions: 22 | * 23 | * The above copyright notice and this permission notice shall be included in 24 | * all copies or substantial portions of the Software. 25 | * 26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 | * THE SOFTWARE. 33 | */ 34 | 35 | #ifndef PCF8574_h 36 | #define PCF8574_h 37 | 38 | #include "Wire.h" 39 | 40 | #if ARDUINO >= 100 41 | #include "Arduino.h" 42 | #else 43 | #include "WProgram.h" 44 | #endif 45 | 46 | #define DEFAULT_SDA SDA; 47 | #define DEFAULT_SCL SCL; 48 | 49 | // Uncomment to enable printing out nice debug messages. 50 | // #define PCF8574_DEBUG 51 | 52 | // Uncomment for low memory usage this prevent use of complex DigitalInput structure and free 7byte of memory 53 | // #define PCF8574_LOW_MEMORY 54 | 55 | // Uncomment for low latency to get realtime data every time. 56 | // #define PCF8574_LOW_LATENCY 57 | 58 | //#define PCF8574_SOFT_INITIALIZATION 59 | 60 | // Select an algorithm to manage encoder progression 61 | #define BASIC_ENCODER_ALGORITHM 62 | // #define MISCHIANTI_ENCODER_ALGORITHM 63 | // #define SEQUENCE_ENCODER_ALGORITHM_REDUCED 64 | // #define SEQUENCE_ENCODER_ALGORITHM 65 | // #define POKI_ENCODER_ALGORITHM 66 | 67 | // Define where debug output will be printed. 68 | #define DEBUG_PRINTER Serial 69 | 70 | // Setup debug printing macros. 71 | #ifdef PCF8574_DEBUG 72 | #define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); } 73 | #define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); } 74 | #else 75 | #define DEBUG_PRINT(...) {} 76 | #define DEBUG_PRINTLN(...) {} 77 | #endif 78 | 79 | #ifdef PCF8574_LOW_LATENCY 80 | #define READ_ELAPSED_TIME 0 81 | #else 82 | #define READ_ELAPSED_TIME 10 83 | #endif 84 | 85 | //#define P0 B00000001 86 | //#define P1 B00000010 87 | //#define P2 B00000100 88 | //#define P3 B00001000 89 | //#define P4 B00010000 90 | //#define P5 B00100000 91 | //#define P6 B01000000 92 | //#define P7 B10000000 93 | // 94 | #define P0 0 95 | #define P1 1 96 | #define P2 2 97 | #define P3 3 98 | #define P4 4 99 | #define P5 5 100 | #define P6 6 101 | #define P7 7 102 | 103 | #include 104 | 105 | 106 | class PCF8574 { 107 | public: 108 | 109 | PCF8574(uint8_t address); 110 | PCF8574(uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ); 111 | 112 | #if !defined(__AVR) && !defined(ARDUINO_ARCH_SAMD) && !defined(TEENSYDUINO) && !defined(ARDUINO_ARCH_RENESAS) 113 | PCF8574(uint8_t address, int sda, int scl); 114 | PCF8574(uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)()); 115 | #endif 116 | 117 | #if defined(ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_RENESAS) 118 | ///// changes for second i2c bus 119 | PCF8574(TwoWire *pWire, uint8_t address); 120 | PCF8574(TwoWire *pWire, uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ); 121 | #endif 122 | #if defined(ESP32) 123 | PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl); 124 | PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)()); 125 | #endif 126 | 127 | bool begin(); 128 | bool begin(uint8_t address); 129 | void pinMode(uint8_t pin, uint8_t mode, uint8_t output_start = HIGH); 130 | 131 | void encoder(uint8_t pinA, uint8_t pinB); 132 | 133 | void attachInterrupt(); 134 | void detachInterrupt(); 135 | 136 | void readBuffer(bool force = true); 137 | uint8_t digitalRead(uint8_t pin, bool forceReadNow = false); 138 | #ifndef PCF8574_LOW_MEMORY 139 | struct DigitalInput { 140 | uint8_t p0; 141 | uint8_t p1; 142 | uint8_t p2; 143 | uint8_t p3; 144 | uint8_t p4; 145 | uint8_t p5; 146 | uint8_t p6; 147 | uint8_t p7; 148 | } digitalInput; 149 | 150 | 151 | DigitalInput digitalReadAll(void); 152 | 153 | bool digitalWriteAll(PCF8574::DigitalInput digitalInput); 154 | #else 155 | byte digitalReadAll(void); 156 | bool digitalWriteAll(byte digitalInput); 157 | #endif 158 | bool digitalWrite(uint8_t pin, uint8_t value); 159 | 160 | #ifdef MISCHIANTI_ENCODER_ALGORITHM 161 | bool readEncoderValueMischianti(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); 162 | int8_t readEncoderValueMischianti(uint8_t pinA, uint8_t pinB); 163 | #endif 164 | #ifdef POKI_ENCODER_ALGORITHM 165 | bool readEncoderValuePoki(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); 166 | int8_t readEncoderValuePoki(uint8_t pinA, uint8_t pinB); 167 | #endif 168 | 169 | // bool readEncoderValueEvolved(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); 170 | // int8_t readEncoderValueEvolved(uint8_t pinA, uint8_t pinB); 171 | 172 | #ifdef SEQUENCE_ENCODER_ALGORITHM 173 | bool readEncoderValueSequence(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); 174 | int8_t readEncoderValueSequence(uint8_t pinA, uint8_t pinB); 175 | #endif 176 | #ifdef SEQUENCE_ENCODER_ALGORITHM_REDUCED 177 | bool readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); 178 | int8_t readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB); 179 | #endif 180 | #ifdef BASIC_ENCODER_ALGORITHM 181 | bool readEncoderValue(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); 182 | int8_t readEncoderValue(uint8_t pinA, uint8_t pinB); 183 | #endif 184 | 185 | int getLatency() const { 186 | return latency; 187 | } 188 | 189 | void setLatency(int latency = READ_ELAPSED_TIME) { 190 | this->latency = latency; 191 | } 192 | 193 | uint8_t getTransmissionStatusCode() const { 194 | return transmissionStatus; 195 | } 196 | 197 | bool isLastTransmissionSuccess(){ 198 | DEBUG_PRINT(F("STATUS --> ")); 199 | DEBUG_PRINTLN(transmissionStatus); 200 | return transmissionStatus==0; 201 | } 202 | private: 203 | uint8_t _address; 204 | 205 | #if !defined(DEFAULT_SDA) 206 | # if defined(ARDUINO_ARCH_STM32) 207 | # define DEFAULT_SDA PB7 208 | # elif defined(ESP8266) 209 | # define DEFAULT_SDA 4 210 | # elif defined(SDA) 211 | # define DEFAULT_SDA SDA 212 | # else 213 | # error "Error define DEFAULT_SDA, SDA not declared, if you have this error contact the mantainer" 214 | # endif 215 | #endif 216 | #if !defined(DEFAULT_SCL) 217 | # if defined(ARDUINO_ARCH_STM32) 218 | # define DEFAULT_SCL PB6 219 | # elif defined(ESP8266) 220 | # define DEFAULT_SCL 5 221 | # elif defined(SDA) 222 | # define DEFAULT_SCL SCL 223 | # else 224 | # error "Error define DEFAULT_SCL, SCL not declared, if you have this error contact the mantainer" 225 | # endif 226 | #endif 227 | 228 | int _sda = DEFAULT_SDA; 229 | int _scl = DEFAULT_SCL; 230 | 231 | TwoWire *_wire; 232 | 233 | bool _usingInterrupt = false; 234 | uint8_t _interruptPin = 2; 235 | void (*_interruptFunction)(){}; 236 | 237 | byte writeMode = 0b00000000; 238 | byte writeModeUp = 0b00000000; 239 | byte readMode = 0b00000000; 240 | byte readModePullUp = 0b00000000; 241 | byte readModePullDown = 0b00000000; 242 | byte byteBuffered = 0b00000000; 243 | byte resetInitial = 0b00000000; 244 | byte initialBuffer = 0b00000000; 245 | unsigned long lastReadMillis = 0; 246 | 247 | byte writeByteBuffered = 0b00000000; 248 | 249 | volatile byte encoderValues = 0b00000000; 250 | 251 | uint8_t prevNextCode = 0; 252 | uint16_t store=0; 253 | 254 | int latency = READ_ELAPSED_TIME; 255 | 256 | bool checkProgression(byte oldValA, byte newValA, byte oldValB, byte newValB, byte validProgression); 257 | 258 | // byte validCW = B11100001; 259 | // byte validCCW = B01001011; 260 | byte validCW = 0b01001011; 261 | byte validCCW = 0b11100001; 262 | 263 | uint8_t transmissionStatus = 0; 264 | 265 | void setVal(uint8_t pin, uint8_t value); 266 | bool digitalWriteAllBytes(byte allpins); 267 | }; 268 | 269 | #endif 270 | 271 | -------------------------------------------------------------------------------- /PCF8574_library.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PCF8574 GPIO Port Expand 3 | * 4 | * AUTHOR: Renzo Mischianti 5 | * VERSION: 2.3.7 6 | * 7 | * https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 8 | * 9 | * The MIT License (MIT) 10 | * 11 | * Copyright (c) 2017 Renzo Mischianti www.mischianti.org All right reserved. 12 | * 13 | * You may copy, alter and reuse this code in any way you like, but please leave 14 | * reference to www.mischianti.org in your comments if you redistribute this code. 15 | * 16 | * Permission is hereby granted, free of charge, to any person obtaining a copy 17 | * of this software and associated documentation files (the "Software"), to deal 18 | * in the Software without restriction, including without limitation the rights 19 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | * copies of the Software, and to permit persons to whom the Software is 21 | * furnished to do so, subject to the following conditions: 22 | * 23 | * The above copyright notice and this permission notice shall be included in 24 | * all copies or substantial portions of the Software. 25 | * 26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 | * THE SOFTWARE. 33 | */ 34 | 35 | #ifndef PCF8574_LIBRARY_H 36 | #define PCF8574_LIBRARY_H 37 | 38 | #include "PCF8574.h" 39 | 40 | #endif 41 | 42 | #pragma once 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Support forum pcf8574 English 5 |
6 |
7 | Forum supporto pcf8574 italiano 10 |
11 | 12 | # 13 | 14 | 15 | # PCF8574 PCF8574AP digital input and output expander with i2c bus. 16 | #### Complete documentation on my site: [pcf8574 Article](https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/). 17 | 18 | #### If you need more pins [here](https://www.mischianti.org/2019/07/22/pcf8575-i2c-16-bit-digital-i-o-expander/) you can find the pcf8575 16bit version of the IC. 19 | 20 | ## Changelog 21 | - 01/02/2024: v2.3.7 Add the possibility to insert address at begin() 22 | - 10/07/2023: v2.3.6 Support for Arduino UNO R4 23 | - 08/02/2023: v2.3.5 Fix STM32 support and add support for Raspberry Pi Pico and other rp2040 boards 24 | - 10/08/2022: v2.3.4 Add support for custom SERCOM interface of Arduino SAMD devices. Force SDA SCL to use GPIO numeration for STM32 bug (https://www.mischianti.org/forums/topic/compatible-with-stm32duino/). 25 | - 28/07/2022: v2.3.3 Force SDA SCL to use GPIO numeration (https://www.mischianti.org/forums/topic/cannot-set-sda-clk-on-esp8266/). 26 | - 28/07/2022: v2.3.2 Fix the SDA SCL type #58 and add basic support for SAMD device. 27 | - 26/04/2022: v2.3.1 Fix example for esp32 and double begin issue #56. 28 | - 06/04/2022: v2.3.0 Fix package size 29 | - 30/12/2021: v2.2.4 Minor fix and remove deprecated declaration 30 | - 23/11/2020: v2.2.2 Add multiple implementation for encoder management (you can enable by uncomment relative define) 31 | 32 | I try to simplify the use of this IC, with a minimal set of operations. 33 | 34 | Tested with esp8266, esp32, Arduino, Arduino SAMD (Nano 33 IoT, MKR etc.), STM32 and rp2040 (Raspberry Pi Pico and similar) 35 | 36 | PCF8574P address map 0x20-0x27 37 | PCF8574AP address map 0x38-0x3f 38 | 39 | **Constructor:** 40 | Pass the address of I2C (to check the address use this guide [I2cScanner](https://playground.arduino.cc/Main/I2cScanner)) 41 | ```cpp 42 | PCF8574(uint8_t address); 43 | ``` 44 | For ESP8266 if you want to specify SDA and SCL pins use this: 45 | 46 | ```cpp 47 | PCF8574(uint8_t address, uint8_t sda, uint8_t scl); 48 | ``` 49 | You must set input/output mode: 50 | ```cpp 51 | pcf8574.pinMode(P0, OUTPUT); 52 | pcf8574.pinMode(P1, INPUT); 53 | pcf8574.pinMode(P2, INPUT); 54 | ``` 55 | 56 | then IC as you can see in the image has 8 digital input/output ports: 57 | 58 | ![PCF8574 schema](https://github.com/xreef/PCF8574_library/blob/master/resources/PCF8574-pins.gif) 59 | 60 | To read all analog input in one trasmission you can do (even if I use a 10millis debounce time to prevent too much read from i2c): 61 | ```cpp 62 | PCF8574::DigitalInput di = PCF8574.digitalReadAll(); 63 | Serial.print(di.p0); 64 | Serial.print(" - "); 65 | Serial.print(di.p1); 66 | Serial.print(" - "); 67 | Serial.print(di.p2); 68 | Serial.print(" - "); 69 | Serial.println(di.p3); 70 | ``` 71 | 72 | To follow a request (you can see It on [issue #5](https://github.com/xreef/PCF8574_library/issues/5)) I create a define variable to work with low memory devices, if you uncomment this line in the .h file of the library: 73 | 74 | ```cpp 75 | // #define PCF8574_LOW_MEMORY 76 | ``` 77 | 78 | Enable low memory props and gain about 7 bytes of memory, and you must use the method to read all like so: 79 | 80 | ```cpp 81 | byte di = pcf8574.digitalReadAll(); 82 | Serial.print("READ VALUE FROM PCF: "); 83 | Serial.println(di, BIN); 84 | ``` 85 | 86 | where `di` is a byte like 1110001, so you must do a bitwise operation to get the data, operation that I already do in the "normal" mode. For example: 87 | 88 | ```cpp 89 | p0 = ((di & bit(0))>0)?HIGH:LOW; 90 | p1 = ((di & bit(1))>0)?HIGH:LOW; 91 | p2 = ((di & bit(2))>0)?HIGH:LOW; 92 | p3 = ((di & bit(3))>0)?HIGH:LOW; 93 | p4 = ((di & bit(4))>0)?HIGH:LOW; 94 | p5 = ((di & bit(5))>0)?HIGH:LOW; 95 | p6 = ((di & bit(6))>0)?HIGH:LOW; 96 | p7 = ((di & bit(7))>0)?HIGH:LOW; 97 | ``` 98 | 99 | 100 | if you want to read a single input: 101 | 102 | ```cpp 103 | int p1Digital = PCF8574.digitalRead(P1); // read P1 104 | ``` 105 | 106 | If you want to write a digital value: 107 | ```cpp 108 | PCF8574.digitalWrite(P1, HIGH); 109 | ``` 110 | or: 111 | ```cpp 112 | PCF8574.digitalWrite(P1, LOW); 113 | ``` 114 | 115 | You can also use an interrupt pin: 116 | You must initialize the pin and the function to call when interrupt raised from PCF8574 117 | ```cpp 118 | // Function interrupt 119 | void keyPressedOnPCF8574(); 120 | 121 | // Set i2c address 122 | PCF8574 pcf8574(0x39, ARDUINO_UNO_INTERRUPT_PIN, keyPressedOnPCF8574); 123 | ``` 124 | Remember you can't use Serial or Wire on an interrupt function. 125 | 126 | It's better to only set a variable to read on loop: 127 | ```cpp 128 | void keyPressedOnPCF8574(){ 129 | // Interrupt called (No Serial no read no wire in this function, and DEBUG disabled on PCF library) 130 | keyPressed = true; 131 | } 132 | ``` 133 | 134 | For the examples I use this wire schema on breadboard: 135 | ![Breadboard](https://github.com/xreef/PCF8574_library/raw/master/resources/testReadWriteLedButton_bb.png) 136 | 137 | https://downloads.arduino.cc/libraries/logs/github.com/xreef/PCF8574_library/ 138 | -------------------------------------------------------------------------------- /examples/Arduino4Leds4ButtonsWithInterrupt/Arduino4Leds4ButtonsWithInterrupt.ino: -------------------------------------------------------------------------------- 1 | /* 2 | KeyPressed and leds with interrupt 3 | by Mischianti Renzo 4 | 5 | https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "PCF8574.h" 10 | 11 | // For arduino uno only pin 1 and 2 are interrupted 12 | #define ARDUINO_UNO_INTERRUPTED_PIN 2 13 | 14 | // Function interrupt 15 | void keyPressedOnPCF8574(); 16 | 17 | // Set i2c address 18 | PCF8574 pcf8574(0x38, ARDUINO_UNO_INTERRUPTED_PIN, keyPressedOnPCF8574); 19 | unsigned long timeElapsed; 20 | void setup() 21 | { 22 | Serial.begin(115200); 23 | 24 | pcf8574.pinMode(P0, INPUT_PULLUP); 25 | pcf8574.pinMode(P1, INPUT_PULLUP); 26 | pcf8574.pinMode(P2, INPUT); 27 | pcf8574.pinMode(P3, INPUT); 28 | 29 | pcf8574.pinMode(P7, OUTPUT); 30 | pcf8574.pinMode(P6, OUTPUT, HIGH); 31 | pcf8574.pinMode(P5, OUTPUT); 32 | pcf8574.pinMode(P4, OUTPUT, LOW); 33 | 34 | Serial.print("Init pcf8574..."); 35 | if (pcf8574.begin()){ 36 | Serial.println("OK"); 37 | }else{ 38 | Serial.println("KO"); 39 | } 40 | 41 | timeElapsed = millis(); 42 | } 43 | unsigned long lastSendTime = 0; // last send time 44 | unsigned long interval = 4000; // interval between sends 45 | 46 | bool startVal = HIGH; 47 | 48 | bool keyPressed = false; 49 | void loop() 50 | { 51 | if (keyPressed){ 52 | uint8_t val0 = pcf8574.digitalRead(P0); 53 | uint8_t val1 = pcf8574.digitalRead(P1); 54 | uint8_t val2 = pcf8574.digitalRead(P2); 55 | uint8_t val3 = pcf8574.digitalRead(P3); 56 | Serial.print("P0 "); 57 | Serial.print(val0); 58 | Serial.print(" P1 "); 59 | Serial.print(val1); 60 | Serial.print(" P2 "); 61 | Serial.print(val2); 62 | Serial.print(" P3 "); 63 | Serial.println(val3); 64 | keyPressed= false; 65 | } 66 | 67 | if (millis() - lastSendTime > interval) { 68 | pcf8574.digitalWrite(P7, startVal); 69 | if (startVal==HIGH) { 70 | startVal = LOW; 71 | }else{ 72 | startVal = HIGH; 73 | } 74 | lastSendTime = millis(); 75 | 76 | Serial.print("P7 "); 77 | Serial.println(startVal); 78 | } 79 | } 80 | 81 | void keyPressedOnPCF8574(){ 82 | // Interrupt called (No Serial no read no wire in this function, and DEBUG disabled on PCF library) 83 | keyPressed = true; 84 | 85 | } 86 | -------------------------------------------------------------------------------- /examples/ArduinoSAMDSercom3keyPressedPin1/ArduinoSAMDSercom3keyPressedPin1.ino: -------------------------------------------------------------------------------- 1 | /* 2 | KeyPressed on PIN1 3 | by Mischianti Renzo 4 | 5 | https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "PCF8574.h" 10 | 11 | TwoWire aWire(&sercom3, 20, 21); 12 | // Set i2c address 13 | PCF8574 pcf8574(&aWire, 0x38); 14 | 15 | unsigned long timeElapsed; 16 | void setup() 17 | { 18 | Serial.begin(115200); 19 | delay(1000); 20 | 21 | pcf8574.pinMode(P0, OUTPUT); 22 | pcf8574.pinMode(P1, INPUT); 23 | 24 | Serial.print("Init pcf8574..."); 25 | if (pcf8574.begin()){ 26 | Serial.println("OK"); 27 | }else{ 28 | Serial.println("KO"); 29 | } 30 | } 31 | 32 | void loop() 33 | { 34 | uint8_t val = pcf8574.digitalRead(P1); 35 | if (val==HIGH) Serial.println("KEY PRESSED"); 36 | delay(50); 37 | } 38 | -------------------------------------------------------------------------------- /examples/blinkOnPin0/blinkOnPin0.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Blink led on PIN0 3 | by Mischianti Renzo 4 | 5 | https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "PCF8574.h" 10 | 11 | // Set i2c address 12 | PCF8574 pcf8574(0x39); 13 | 14 | void setup() 15 | { 16 | Serial.begin(115200); 17 | delay(1000); 18 | 19 | // Set pinMode to OUTPUT 20 | pcf8574.pinMode(P0, OUTPUT); 21 | pcf8574.pinMode(P1, INPUT); 22 | 23 | Serial.print("Init pcf8574..."); 24 | if (pcf8574.begin()){ 25 | Serial.println("OK"); 26 | }else{ 27 | Serial.println("KO"); 28 | } 29 | } 30 | 31 | void loop() 32 | { 33 | pcf8574.digitalWrite(P0, HIGH); 34 | delay(1000); 35 | pcf8574.digitalWrite(P0, LOW); 36 | delay(1000); 37 | } 38 | -------------------------------------------------------------------------------- /examples/encoderWithBasicLibraryFunction/encoderWithBasicLibraryFunction.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * PCF8574 GPIO Port Expand 3 | * https://www.mischianti.org/2020/03/13/pcf8574-i2c-digital-i-o-expander-rotary-encoder-part-2/ 4 | * 5 | * PCF8574 ----- WeMos 6 | * A0 ----- GRD 7 | * A1 ----- GRD 8 | * A2 ----- GRD 9 | * VSS ----- GRD 10 | * VDD ----- 5V/3.3V 11 | * SDA ----- D1(PullUp) 12 | * SCL ----- D2(PullUp) 13 | * INT ----- INT(PullUp) 14 | * 15 | * P0 ----------------- ENCODER PIN A 16 | * P1 ----------------- ENCODER PIN B 17 | * P2 ----------------- ENCODER BUTTON 18 | * 19 | */ 20 | #include "Arduino.h" 21 | #include "PCF8574.h" 22 | 23 | int encoderPinA = P0; 24 | int encoderPinB = P1; 25 | 26 | #define INTERRUPTED_PIN D7 27 | 28 | void ICACHE_RAM_ATTR updateEncoder(); 29 | 30 | // initialize library 31 | PCF8574 pcf8574(0x38, INTERRUPTED_PIN, updateEncoder); 32 | 33 | volatile long encoderValue = 0; 34 | uint8_t encoderButtonVal = HIGH; 35 | 36 | void setup() 37 | { 38 | Serial.begin (9600); 39 | delay(500); 40 | 41 | // encoder pins 42 | pcf8574.pinMode(encoderPinA, INPUT_PULLUP); 43 | pcf8574.pinMode(encoderPinB, INPUT_PULLUP); 44 | // encoder button 45 | pcf8574.pinMode(P2, INPUT_PULLUP); 46 | 47 | // Set low latency with this method or uncomment LOW_LATENCY define in the library 48 | // Needed for encoder 49 | pcf8574.setLatency(0); 50 | 51 | // Start library 52 | Serial.print("Init pcf8574..."); 53 | if (pcf8574.begin()){ 54 | Serial.println("OK"); 55 | }else{ 56 | Serial.println("KO"); 57 | } 58 | } 59 | 60 | bool changed = false; 61 | 62 | void loop() 63 | { 64 | if (changed){ 65 | Serial.print("ENCODER --> "); 66 | Serial.print(encoderValue); 67 | Serial.print(" - BUTTON --> "); 68 | Serial.println(encoderButtonVal?"HIGH":"LOW"); 69 | changed = false; 70 | } 71 | } 72 | 73 | uint8_t encoderPinALast = LOW; 74 | uint8_t valPrecEncoderButton = LOW; 75 | 76 | void updateEncoder(){ 77 | // Encoder management 78 | uint8_t n = pcf8574.digitalRead(encoderPinA); 79 | if ((encoderPinALast == LOW) && (n == HIGH)) { 80 | if (pcf8574.digitalRead(encoderPinB) == LOW) { 81 | encoderValue--; 82 | changed = true; // Chnged the value 83 | } else { 84 | encoderValue++; 85 | changed = true; // Chnged the value 86 | } 87 | } 88 | encoderPinALast = n; 89 | 90 | // Button management 91 | encoderButtonVal = pcf8574.digitalRead(P2); 92 | if (encoderButtonVal!=valPrecEncoderButton){ 93 | changed = true; // Chnged the value of button 94 | valPrecEncoderButton = encoderButtonVal; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /examples/encoderWithFullLibraryFunction/encoderWithFullLibraryFunction.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * PCF8574 GPIO Port Expand 3 | * https://www.mischianti.org/2020/03/13/pcf8574-i2c-digital-i-o-expander-rotary-encoder-part-2/ 4 | * 5 | * PCF8574 ----- WeMos 6 | * A0 ----- GRD 7 | * A1 ----- GRD 8 | * A2 ----- GRD 9 | * VSS ----- GRD 10 | * VDD ----- 5V/3.3V 11 | * SDA ----- D1(PullUp) 12 | * SCL ----- D2(PullUp) 13 | * INT ----- INT(PullUp) 14 | * 15 | * P0 ----------------- ENCODER PIN A 16 | * P1 ----------------- ENCODER PIN B 17 | * P2 ----------------- ENCODER BUTTON 18 | * 19 | */ 20 | #include "Arduino.h" 21 | #include "PCF8574.h" 22 | 23 | int encoderPinA = P0; 24 | int encoderPinB = P1; 25 | 26 | #define INTERRUPTED_PIN D7 27 | 28 | void ICACHE_RAM_ATTR updateEncoder(); 29 | 30 | // initialize library 31 | PCF8574 pcf8574(0x38, INTERRUPTED_PIN, updateEncoder); 32 | 33 | volatile long encoderValue = 0; 34 | uint8_t encoderButtonVal = HIGH; 35 | 36 | void setup() 37 | { 38 | Serial.begin (9600); 39 | delay(500); 40 | 41 | // encoder pins 42 | pcf8574.encoder(encoderPinA, encoderPinB); 43 | // encoder button 44 | pcf8574.pinMode(P2, INPUT); 45 | 46 | // Start library 47 | Serial.print("Init pcf8574..."); 48 | if (pcf8574.begin()){ 49 | Serial.println("OK"); 50 | }else{ 51 | Serial.println("KO"); 52 | } 53 | 54 | } 55 | 56 | bool changed = false; 57 | 58 | // The loop function is called in an endless loop 59 | void loop() 60 | { 61 | if (changed){ 62 | Serial.print("ENCODER --> "); 63 | Serial.print(encoderValue); 64 | Serial.print(" - BUTTON --> "); 65 | Serial.println(encoderButtonVal?"HIGH":"LOW"); 66 | changed = false; 67 | } 68 | } 69 | 70 | bool valPrecEncoderButton = LOW; 71 | void updateEncoder(){ 72 | changed = pcf8574.readEncoderValue(encoderPinA, encoderPinB, &encoderValue); 73 | 74 | // int vale = pcf8574.readEncoderValue(encoderPinA, encoderPinB); 75 | // if (vale!=0){ 76 | // changed = true; 77 | // } 78 | // encoderValue = encoderValue + vale; 79 | 80 | // Button management 81 | encoderButtonVal = pcf8574.digitalRead(P2); 82 | if (encoderButtonVal!=valPrecEncoderButton){ 83 | changed = true; // Chnged the value of button 84 | valPrecEncoderButton = encoderButtonVal; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /examples/interruptWemos/interruptWemos.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * PCF8574 GPIO Port Expand 3 | * http://nopnop2002.webcrow.jp/WeMos/WeMos-25.html 4 | * 5 | * PCF8574 ----- WeMos 6 | * A0 ----- GRD 7 | * A1 ----- GRD 8 | * A2 ----- GRD 9 | * VSS ----- GRD 10 | * VDD ----- 5V/3.3V 11 | * SDA ----- GPIO_4 12 | * SCL ----- GPIO_5 13 | * INT ----- GPIO_13 14 | * 15 | * P0 ----------------- BUTTON0 16 | * P1 ----------------- BUTTON1 17 | * P2 ----------------- BUTTON2 18 | * P3 ----------------- BUTTON3 19 | * P4 ----------------- BUTTON4 20 | * P5 ----------------- BUTTON5 21 | * P6 ----------------- BUTTON6 22 | * P7 ----------------- BUTTON7 23 | * 24 | */ 25 | 26 | #include "Arduino.h" 27 | #include "PCF8574.h" // https://github.com/xreef/PCF8574_library 28 | 29 | #define ESP8266_INTERRUPTED_PIN 13 30 | 31 | // Set i2c address 32 | PCF8574 pcf8574(0x20); 33 | 34 | // Function interrupt 35 | bool keyPressed = false; 36 | 37 | void ICACHE_RAM_ATTR keyPressedOnPCF8574(){ 38 | // Serial.println("keyPressedOnPCF8574"); 39 | keyPressed = true; 40 | } 41 | 42 | void setup() 43 | { 44 | Serial.begin(9600); 45 | delay(1000); 46 | 47 | pinMode(ESP8266_INTERRUPTED_PIN, INPUT_PULLUP); 48 | attachInterrupt(digitalPinToInterrupt(ESP8266_INTERRUPTED_PIN), keyPressedOnPCF8574, FALLING); 49 | 50 | for(int i=0;i<8;i++) { 51 | pcf8574.pinMode(i, INPUT); 52 | } 53 | Serial.print("Init pcf8574..."); 54 | if (pcf8574.begin()){ 55 | Serial.println("OK"); 56 | }else{ 57 | Serial.println("KO"); 58 | } 59 | } 60 | 61 | void loop() 62 | { 63 | if (keyPressed){ 64 | PCF8574::DigitalInput val = pcf8574.digitalReadAll(); 65 | if (val.p0==HIGH) Serial.println("KEY0 PRESSED"); 66 | if (val.p1==HIGH) Serial.println("KEY1 PRESSED"); 67 | if (val.p2==HIGH) Serial.println("KEY2 PRESSED"); 68 | if (val.p3==HIGH) Serial.println("KEY3 PRESSED"); 69 | if (val.p4==HIGH) Serial.println("KEY4 PRESSED"); 70 | if (val.p5==HIGH) Serial.println("KEY5 PRESSED"); 71 | if (val.p6==HIGH) Serial.println("KEY6 PRESSED"); 72 | if (val.p7==HIGH) Serial.println("KEY7 PRESSED"); 73 | keyPressed= false; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/keyPressedPin1/keyPressedPin1.ino: -------------------------------------------------------------------------------- 1 | /* 2 | KeyPressed on PIN1 3 | by Mischianti Renzo 4 | 5 | https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "PCF8574.h" 10 | 11 | // Set i2c address 12 | PCF8574 pcf8574(0x39); 13 | unsigned long timeElapsed; 14 | void setup() 15 | { 16 | Serial.begin(115200); 17 | delay(1000); 18 | 19 | pcf8574.pinMode(P0, OUTPUT); 20 | pcf8574.pinMode(P1, INPUT); 21 | 22 | Serial.print("Init pcf8574..."); 23 | if (pcf8574.begin()){ 24 | Serial.println("OK"); 25 | }else{ 26 | Serial.println("KO"); 27 | } 28 | } 29 | 30 | void loop() 31 | { 32 | uint8_t val = pcf8574.digitalRead(P1); 33 | if (val==HIGH) Serial.println("KEY PRESSED"); 34 | delay(50); 35 | } 36 | -------------------------------------------------------------------------------- /examples/keyPressedPin1_storedOnBuffer_async/keyPressedPin1_storedOnBuffer_async.ino: -------------------------------------------------------------------------------- 1 | /* 2 | KeyPressed async 3 | by Mischianti Renzo 4 | 5 | https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "PCF8574.h" 10 | 11 | // Set i2c address 12 | PCF8574 pcf8574(0x39); 13 | unsigned long timeElapsed; 14 | void setup() 15 | { 16 | Serial.begin(115200); 17 | delay(1000); 18 | 19 | pcf8574.pinMode(P0, OUTPUT); 20 | pcf8574.pinMode(P1, INPUT); 21 | 22 | Serial.print("Init pcf8574..."); 23 | if (pcf8574.begin()){ 24 | Serial.println("OK"); 25 | }else{ 26 | Serial.println("KO"); 27 | } 28 | 29 | timeElapsed = millis(); 30 | } 31 | 32 | void loop() 33 | { 34 | // Read and store on buffer all input (pinMode) that are going HIGHT 35 | pcf8574.readBuffer(); 36 | if (millis()>timeElapsed+2000){ 37 | // read value on buffer than reset value for that pin 38 | uint8_t val = pcf8574.digitalRead(P1); 39 | if (val==HIGH) Serial.println("KEY PRESSED STORED ON BUFFER, NOW READED AND RESETTED."); 40 | timeElapsed = millis(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/keyPressed_withInterrupt/keyPressed_withInterrupt.ino: -------------------------------------------------------------------------------- 1 | /* 2 | KeyPressed with interrupt 3 | by Mischianti Renzo 4 | 5 | https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "PCF8574.h" 10 | 11 | // For arduino uno only pin 1 and 2 are interrupted 12 | #define ARDUINO_UNO_INTERRUPTED_PIN 2 13 | 14 | // Function interrupt 15 | void keyPressedOnPCF8574(); 16 | 17 | // Set i2c address 18 | PCF8574 pcf8574(0x39, ARDUINO_UNO_INTERRUPTED_PIN, keyPressedOnPCF8574); 19 | unsigned long timeElapsed; 20 | void setup() 21 | { 22 | Serial.begin(115200); 23 | delay(1000); 24 | 25 | pcf8574.pinMode(P0, OUTPUT); 26 | pcf8574.pinMode(P1, INPUT); 27 | Serial.print("Init pcf8574..."); 28 | if (pcf8574.begin()){ 29 | Serial.println("OK"); 30 | }else{ 31 | Serial.println("KO"); 32 | } 33 | 34 | 35 | timeElapsed = millis(); 36 | } 37 | 38 | bool keyPressed = false; 39 | void loop() 40 | { 41 | if (keyPressed){ 42 | uint8_t val = pcf8574.digitalRead(P1); 43 | Serial.print("READ VALUE FROM PCF "); 44 | Serial.println(val); 45 | keyPressed= false; 46 | } 47 | } 48 | 49 | void keyPressedOnPCF8574(){ 50 | // Interrupt called (No Serial no read no wire in this function, and DEBUG disabled on PCF library) 51 | keyPressed = true; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /examples/ledEsp32OnTheSecondI2C/ledEsp32OnTheSecondI2C.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * PCF8574 GPIO Port Expand 3 | * Blink all led 4 | * by Mischianti Renzo 5 | * 6 | * https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 7 | * 8 | * 9 | * PCF8574 ----- Esp32 10 | * A0 ----- GRD 11 | * A1 ----- GRD 12 | * A2 ----- GRD 13 | * VSS ----- GRD 14 | * VDD ----- 5V/3.3V 15 | * SDA ----- 21 16 | * SCL ----- 22 17 | * 18 | * P0 ----------------- LED0 19 | * P1 ----------------- LED1 20 | * P2 ----------------- LED2 21 | * P3 ----------------- LED3 22 | * P4 ----------------- LED4 23 | * P5 ----------------- LED5 24 | * P6 ----------------- LED6 25 | * P7 ----------------- LED7 26 | * 27 | */ 28 | 29 | #include "Arduino.h" 30 | #include "PCF8574.h" // https://github.com/xreef/PCF8574_library 31 | 32 | // Instantiate Wire for generic use at 400kHz 33 | TwoWire I2Cone = TwoWire(0); 34 | // Instantiate Wire for generic use at 100kHz 35 | TwoWire I2Ctwo = TwoWire(1); 36 | 37 | // Set i2c address 38 | PCF8574 pcf8574(&I2Ctwo, 0x20); 39 | // PCF8574 pcf8574(&I2Ctwo, 0x20, 21, 22); 40 | // PCF8574(TwoWire *pWire, uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ); 41 | // PCF8574(TwoWire *pWire, uint8_t address, uint8_t sda, uint8_t scl, uint8_t interruptPin, void (*interruptFunction)()); 42 | 43 | void setup() 44 | { 45 | Serial.begin(112560); 46 | 47 | I2Cone.begin(16,17,400000U); // SDA pin 16, SCL pin 17, 400kHz frequency 48 | delay(1000); 49 | 50 | // Set pinMode to OUTPUT 51 | for(int i=0;i<8;i++) { 52 | pcf8574.pinMode(i, OUTPUT); 53 | } 54 | 55 | Serial.print("Init pcf8574..."); 56 | if (pcf8574.begin()){ 57 | Serial.println("OK"); 58 | } else { 59 | Serial.println("KO"); 60 | } 61 | } 62 | 63 | void loop() 64 | { 65 | static int pin = 0; 66 | pcf8574.digitalWrite(pin, HIGH); 67 | delay(400); 68 | pcf8574.digitalWrite(pin, LOW); 69 | delay(400); 70 | pin++; 71 | if (pin > 7) pin = 0; 72 | } 73 | -------------------------------------------------------------------------------- /examples/ledEsp32OnTheSecondI2C/testLedESP32_bb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xreef/PCF8574_library/7314395ac147b34ec1d8ff29408eba1332772382/examples/ledEsp32OnTheSecondI2C/testLedESP32_bb.jpg -------------------------------------------------------------------------------- /examples/ledWemos/ledWemos.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * PCF8574 GPIO Port Expand 3 | * http://nopnop2002.webcrow.jp/WeMos/WeMos-25.html 4 | * 5 | * PCF8574 ----- WeMos 6 | * A0 ----- GRD 7 | * A1 ----- GRD 8 | * A2 ----- GRD 9 | * VSS ----- GRD 10 | * VDD ----- 5V/3.3V 11 | * SDA ----- GPIO_4(PullUp) 12 | * SCL ----- GPIO_5(PullUp) 13 | * 14 | * P0 ----------------- LED0 15 | * P1 ----------------- LED1 16 | * P2 ----------------- LED2 17 | * P3 ----------------- LED3 18 | * P4 ----------------- LED4 19 | * P5 ----------------- LED5 20 | * P6 ----------------- LED6 21 | * P7 ----------------- LED7 22 | * 23 | */ 24 | 25 | #include "Arduino.h" 26 | #include "PCF8574.h" // https://github.com/xreef/PCF8574_library 27 | 28 | // Set i2c address 29 | PCF8574 pcf8574(0x20); 30 | 31 | void setup() 32 | { 33 | Serial.begin(9600); 34 | delay(1000); 35 | 36 | // Set pinMode to OUTPUT 37 | for(int i=0;i<8;i++) { 38 | pcf8574.pinMode(i, OUTPUT); 39 | } 40 | Serial.print("Init pcf8574..."); 41 | if (pcf8574.begin()){ 42 | Serial.println("OK"); 43 | }else{ 44 | Serial.println("KO"); 45 | } 46 | } 47 | 48 | void loop() 49 | { 50 | static int pin = 0; 51 | pcf8574.digitalWrite(pin, HIGH); 52 | delay(1000); 53 | pcf8574.digitalWrite(pin, LOW); 54 | delay(1000); 55 | pin++; 56 | if (pin > 7) pin = 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/ledWemos/testLedWemosEsp8266_bb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xreef/PCF8574_library/7314395ac147b34ec1d8ff29408eba1332772382/examples/ledWemos/testLedWemosEsp8266_bb.jpg -------------------------------------------------------------------------------- /examples/readAll_Interrupt/readAll_Interrupt.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Read all data after interrupt 3 | by Mischianti Renzo 4 | 5 | https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "PCF8574.h" 10 | 11 | // For arduino uno only pin 1 and 2 are interrupted 12 | #define ARDUINO_UNO_INTERRUPTED_PIN 2 13 | 14 | // Function interrupt 15 | void keyChangedOnPCF8574(); 16 | 17 | // Set i2c address 18 | PCF8574 pcf8574(0x39, ARDUINO_UNO_INTERRUPTED_PIN, keyChangedOnPCF8574); 19 | unsigned long timeElapsed; 20 | void setup() 21 | { 22 | Serial.begin(115200); 23 | delay(1000); 24 | 25 | pcf8574.pinMode(P0, OUTPUT); 26 | pcf8574.pinMode(P1, INPUT); 27 | pcf8574.pinMode(P2, INPUT); 28 | Serial.print("Init pcf8574..."); 29 | if (pcf8574.begin()){ 30 | Serial.println("OK"); 31 | }else{ 32 | Serial.println("KO"); 33 | } 34 | 35 | 36 | Serial.println("START"); 37 | 38 | timeElapsed = millis(); 39 | } 40 | 41 | bool keyChanged = false; 42 | void loop() 43 | { 44 | if (keyChanged){ 45 | PCF8574::DigitalInput di = pcf8574.digitalReadAll(); 46 | Serial.print("READ VALUE FROM PCF P1: "); 47 | Serial.print(di.p0); 48 | Serial.print(" - "); 49 | Serial.print(di.p1); 50 | Serial.print(" - "); 51 | Serial.print(di.p2); 52 | Serial.print(" - "); 53 | Serial.println(di.p3); 54 | // delay(5); 55 | keyChanged= false; 56 | } 57 | } 58 | 59 | void keyChangedOnPCF8574(){ 60 | // Interrupt called (No Serial no read no wire in this function, and DEBUG disabled on PCF library) 61 | keyChanged = true; 62 | } 63 | -------------------------------------------------------------------------------- /examples/readAll_Interrupt_lowMemory/readAll_Interrupt_lowMemory.ino: -------------------------------------------------------------------------------- 1 | /* 2 | KeyPressed with interrupt in LOW_MEMORY mode 3 | by Mischianti Renzo 4 | 5 | https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "PCF8574.h" 10 | 11 | // To use in low memory mode and prevent use of 7byte you must decomment the line 12 | // #define PCF8574_LOW_MEMORY 13 | // in the library 14 | 15 | // For arduino uno only pin 1 and 2 are interrupted 16 | #define ARDUINO_UNO_INTERRUPTED_PIN 2 17 | 18 | // Function interrupt 19 | void keyChangedOnPCF8574(); 20 | 21 | // Set i2c address 22 | PCF8574 pcf8574(0x39, ARDUINO_UNO_INTERRUPTED_PIN, keyChangedOnPCF8574); 23 | unsigned long timeElapsed; 24 | void setup() 25 | { 26 | Serial.begin(115200); 27 | delay(1000); 28 | 29 | pcf8574.pinMode(P0, INPUT); 30 | pcf8574.pinMode(P1, INPUT); 31 | pcf8574.pinMode(P2, INPUT); 32 | Serial.print("Init pcf8574..."); 33 | if (pcf8574.begin()){ 34 | Serial.println("OK"); 35 | }else{ 36 | Serial.println("KO"); 37 | } 38 | 39 | Serial.println("START"); 40 | 41 | timeElapsed = millis(); 42 | } 43 | 44 | bool keyChanged = false; 45 | void loop() 46 | { 47 | if (keyChanged){ 48 | byte di = pcf8574.digitalReadAll(); 49 | Serial.print("READ VALUE FROM PCF: "); 50 | Serial.println(di, BIN); 51 | // delay(5); 52 | keyChanged= false; 53 | } 54 | } 55 | 56 | void keyChangedOnPCF8574(){ 57 | // Interrupt called (No Serial no read no wire in this function, and DEBUG disabled on PCF library) 58 | keyChanged = true; 59 | } 60 | -------------------------------------------------------------------------------- /examples/writeAllEsp8266/writeAllEsp8266.ino: -------------------------------------------------------------------------------- 1 | /* 2 | KeyPressed with interrupt and digital write all 3 | from P4 to P7 4 | by Mischianti Renzo 5 | 6 | https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ 7 | */ 8 | 9 | #include "Arduino.h" 10 | #include "PCF8574.h" 11 | 12 | // For arduino uno only pin 1 and 2 are interrupted 13 | #define ARDUINO_UNO_INTERRUPTED_PIN D3 14 | 15 | // Function interrupt 16 | void ICACHE_RAM_ATTR keyPressedOnPCF8574(); 17 | 18 | // Set i2c address 19 | PCF8574 pcf8574(0x38, ARDUINO_UNO_INTERRUPTED_PIN, keyPressedOnPCF8574); 20 | unsigned long timeElapsed; 21 | void setup() 22 | { 23 | Serial.begin(115200); 24 | delay(1000); 25 | Serial.println("INIT"); 26 | 27 | pcf8574.pinMode(P0, INPUT); 28 | pcf8574.pinMode(P1, INPUT_PULLUP); 29 | pcf8574.pinMode(P2, INPUT); 30 | pcf8574.pinMode(P3, INPUT); 31 | 32 | pcf8574.pinMode(P7, OUTPUT); 33 | pcf8574.pinMode(P6, OUTPUT, HIGH); 34 | pcf8574.pinMode(P5, OUTPUT, LOW); 35 | pcf8574.pinMode(P4, OUTPUT, LOW); 36 | 37 | Serial.print("Init pcf8574..."); 38 | if (pcf8574.begin()){ 39 | Serial.println("OK"); 40 | }else{ 41 | Serial.println("KO"); 42 | } 43 | 44 | Serial.println("START"); 45 | timeElapsed = millis(); 46 | } 47 | unsigned long lastSendTime = 0; // last send time 48 | unsigned long interval = 3000; // interval between sends 49 | 50 | bool startVal = HIGH; 51 | 52 | bool keyPressed = false; 53 | void loop() 54 | { 55 | if (keyPressed){ 56 | uint8_t val0 = pcf8574.digitalRead(P0); 57 | uint8_t val1 = pcf8574.digitalRead(P1); 58 | uint8_t val2 = pcf8574.digitalRead(P2); 59 | uint8_t val3 = pcf8574.digitalRead(P3); 60 | Serial.print("P0 "); 61 | Serial.print(val0); 62 | Serial.print(" P1 "); 63 | Serial.println(val1); 64 | Serial.print("P2 "); 65 | Serial.print(val2); 66 | Serial.print(" P3 "); 67 | Serial.println(val3); 68 | keyPressed= false; 69 | 70 | 71 | } 72 | 73 | if (millis() - lastSendTime > interval) { 74 | Serial.print("WRITE ALL VALUE FROM P4 TO P7 "); 75 | Serial.println(startVal); 76 | 77 | // pcf8574.digitalWrite(P7, startVal); 78 | bool startVal2 = LOW; 79 | if (startVal==HIGH) { 80 | startVal = LOW; 81 | startVal2 = HIGH; 82 | }else{ 83 | startVal = HIGH; 84 | startVal2 = LOW; 85 | } 86 | PCF8574::DigitalInput digitalInput; 87 | digitalInput.p4 = startVal2; 88 | digitalInput.p5 = startVal; 89 | digitalInput.p6 = startVal2; 90 | digitalInput.p7 = startVal; 91 | 92 | pcf8574.digitalWriteAll(digitalInput); 93 | lastSendTime = millis(); 94 | } 95 | } 96 | 97 | void keyPressedOnPCF8574(){ 98 | // Interrupt called (No Serial no read no wire in this function, and DEBUG disabled on PCF library) 99 | keyPressed = true; 100 | 101 | } 102 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Syntax Coloring Map For PCF8574-library 3 | ########################################### 4 | 5 | ########################################### 6 | # Datatypes (KEYWORD1) 7 | ########################################### 8 | 9 | PCF8574 KEYWORD1 10 | 11 | ########################################### 12 | # Methods and Functions (KEYWORD2) 13 | ########################################### 14 | 15 | begin KEYWORD2 16 | pinMode KEYWORD2 17 | encoder KEYWORD2 18 | 19 | attachInterrupt KEYWORD2 20 | detachInterrupt KEYWORD2 21 | 22 | readBuffer KEYWORD2 23 | digitalRead KEYWORD2 24 | digitalReadAll KEYWORD2 25 | digitalWrite KEYWORD2 26 | digitalWriteAll KEYWORD2 27 | 28 | readEncoderValue KEYWORD2 29 | getLatency KEYWORD2 30 | setLatency KEYWORD2 -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PCF8574 library", 3 | "version": "2.3.7", 4 | "keywords": "digital, i2c, encoder, expander, pcf8574, pcf8574a, esp32, esp8266, stm32, SAMD, Arduino, wire, rp2040, Raspberry", 5 | "description": "Most starred PCF8574 library. i2c digital expander for Arduino, Raspberry Pi Pico and rp2040 boards, esp32, SMT32 and ESP8266. Can read write digital values with only 2 wire. Very simple to use and encoder support.", 6 | "homepage": "https://www.mischianti.org/category/my-libraries/pcf8574/", 7 | "authors": 8 | [ 9 | { 10 | "name": "Renzo Mischianti", 11 | "email": "renzo.mischianti@gmail.com", 12 | "maintainer": true, 13 | "url": "https://www.mischianti.org" 14 | } 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/xreef/PCF8574_library" 19 | }, 20 | "license": "MIT", 21 | "frameworks": "arduino", 22 | "platforms": "*", 23 | "headers": ["PCF8574.h, PCF8574_library.h"] 24 | } -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=PCF8574 library 2 | version=2.3.7 3 | author=Renzo Mischianti 4 | maintainer=Renzo Mischianti 5 | sentence=Most starred PCF8574 library for Arduino (standard and SAMD), Raspberry Pi Pico and rp2040 boards, ESP8266, smt32 and esp32 6 | paragraph=Most starred PCF8574 library. i2c digital expander for Arduino (standard and SAMD), esp32, Raspberry Pi Pico and rp2040 boards, SMT32 and ESP8266. Can read write digital values with only 2 wire. Very simple to use and encoder support. 7 | category=Signal Input/Output 8 | url=https://www.mischianti.org/category/my-libraries/pcf8574/ 9 | repository=https://github.com/xreef/PCF8574_library 10 | architectures=* 11 | includes=PCF8574.h --------------------------------------------------------------------------------