/* * PCF8574 GPIO Port Expand * https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/ * * The MIT License (MIT) * * Copyright (c) 2017 Renzo Mischianti www.mischianti.org All right reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "PCF8574.h" #include "Wire.h" /** * Constructor * @param address: i2c address */ PCF8574::PCF8574(uint8_t address){ _wire = &Wire; _address = address; }; /** * Construcor * @param address: i2c address * @param interruptPin: pin to set interrupt * @param interruptFunction: function to call when interrupt raised */ PCF8574::PCF8574(uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ){ _wire = &Wire; _address = address; _interruptPin = interruptPin; _interruptFunction = interruptFunction; _usingInterrupt = true; }; #if !defined(__AVR) && !defined(ARDUINO_ARCH_SAMD) && !defined(ARDUINO_ARCH_STM32) && !defined(TEENSYDUINO) /** * Constructor * @param address: i2c address * @param sda: sda pin * @param scl: scl pin */ PCF8574::PCF8574(uint8_t address, int sda, int scl){ _wire = &Wire; _address = address; _sda = sda; _scl = scl; }; /** * Constructor * @param address: i2c address * @param sda: sda pin * @param scl: scl pin * @param interruptPin: pin to set interrupt * @param interruptFunction: function to call when interrupt raised */ PCF8574::PCF8574(uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)() ){ _wire = &Wire; _address = address; _sda = sda; _scl = scl; _interruptPin = interruptPin; _interruptFunction = interruptFunction; _usingInterrupt = true; }; #endif #if defined(ESP32) || defined(ARDUINO_ARCH_SAMD) /** * Constructor * @param address: i2c address */ PCF8574::PCF8574(TwoWire *pWire, uint8_t address){ _wire = pWire; _address = address; }; /** * Construcor * @param address: i2c address * @param interruptPin: pin to set interrupt * @param interruptFunction: function to call when interrupt raised */ PCF8574::PCF8574(TwoWire *pWire, uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ){ _wire = pWire; _address = address; _interruptPin = interruptPin; _interruptFunction = interruptFunction; _usingInterrupt = true; }; #endif #if defined(ESP32) /** * Constructor * @param address: i2c address * @param sda: sda pin * @param scl: scl pin */ PCF8574::PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl){ _wire = pWire; _address = address; _sda = sda; _scl = scl; }; /** * Constructor * @param address: i2c address * @param sda: sda pin * @param scl: scl pin * @param interruptPin: pin to set interrupt * @param interruptFunction: function to call when interrupt raised */ PCF8574::PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)() ){ _wire = pWire; _address = address; _sda = sda; _scl = scl; _interruptPin = interruptPin; _interruptFunction = interruptFunction; _usingInterrupt = true; }; #endif bool encoderPins[8]; void PCF8574::attachInterrupt(){ // If using interrupt set interrupt value to pin if (_usingInterrupt){ for (int i = 0; i < 8;i++){ if (encoderPins[i]) PCF8574::digitalRead(i); } // PCF8574::digitalReadAll(); // (*_interruptFunction)(); // DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)"); // ::pinMode(_interruptPin, INPUT_PULLUP); // attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING ); DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)"); ::pinMode(_interruptPin, INPUT_PULLUP); ::attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING ); } } void PCF8574::detachInterrupt(){ // If using interrupt set interrupt value to pin if (_usingInterrupt){ ::detachInterrupt(digitalPinToInterrupt(_interruptPin)); DEBUG_PRINTLN("Detach interrupt pin"); } } /** * wake up i2c controller */ bool PCF8574::begin(){ this->transmissionStatus = 4; #if !defined(__AVR) && !defined(ARDUINO_ARCH_SAMD) && !defined(ARDUINO_ARCH_STM32) && !defined(TEENSYDUINO) DEBUG_PRINT(F("begin(sda, scl) -> "));DEBUG_PRINT(_sda);DEBUG_PRINT(F(" "));DEBUG_PRINTLN(_scl); // _wire->begin(_sda, _scl); #ifdef ARDUINO_ARCH_STM32 _wire->begin((uint32_t)_sda, (uint32_t)_scl); #else _wire->begin((int)_sda, (int)_scl); #endif #else // Default pin for AVR some problem on software emulation // #define SCL_PIN _scl // #define SDA_PIN _sda _wire->begin(); #endif // Check if there are pins to set low if (writeMode>0 || readMode>0){ DEBUG_PRINTLN("Set write mode"); _wire->beginTransmission(_address); DEBUG_PRINT("resetInitial pin "); #ifdef PCF8574_SOFT_INITIALIZATION resetInitial = writeModeUp | readModePullUp; #else resetInitial = writeModeUp | readMode; #endif DEBUG_PRINTLN( resetInitial, BIN); _wire->write(resetInitial); initialBuffer = writeModeUp | readModePullUp; byteBuffered = initialBuffer; writeByteBuffered = writeModeUp; DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor."); this->transmissionStatus = _wire->endTransmission(); } // // If using interrupt set interrupt value to pin // if (_usingInterrupt){ //// DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)"); //// ::pinMode(_interruptPin, INPUT_PULLUP); //// attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING ); // DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)"); // ::pinMode(_interruptPin, INPUT_PULLUP); // ::attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING ); // } PCF8574::attachInterrupt(); // inizialize last read lastReadMillis = millis(); return this->isLastTransmissionSuccess(); } /** * Set if fin is OUTPUT or INPUT * @param pin: pin to set * @param mode: mode, supported only INPUT or OUTPUT (to simplify) * @param output_start: output_start, for OUTPUT we can set initial value */ void PCF8574::pinMode(uint8_t pin, uint8_t mode, uint8_t output_start){ DEBUG_PRINT("Set pin "); DEBUG_PRINT(pin); DEBUG_PRINT(" as "); DEBUG_PRINTLN(mode); if (mode == OUTPUT){ writeMode = writeMode | bit(pin); if (output_start==HIGH) { writeModeUp = writeModeUp | bit(pin); } readMode = readMode & ~bit(pin); readModePullDown = readModePullDown & ~bit(pin); readModePullUp = readModePullUp & ~bit(pin); DEBUG_PRINT("W: "); DEBUG_PRINT(writeMode, BIN); DEBUG_PRINT(" R ALL: "); DEBUG_PRINT(readMode, BIN); DEBUG_PRINT(" R Down: "); DEBUG_PRINT(readModePullDown, BIN); DEBUG_PRINT("R Up: "); DEBUG_PRINTLN(readModePullUp, BIN); }else if (mode == INPUT){ writeMode = writeMode & ~bit(pin); readMode = readMode | bit(pin); readModePullDown = readModePullDown | bit(pin); readModePullUp = readModePullUp & ~bit(pin); DEBUG_PRINT("W: "); DEBUG_PRINT(writeMode, BIN); DEBUG_PRINT(" R ALL: "); DEBUG_PRINT(readMode, BIN); DEBUG_PRINT(" R Down: "); DEBUG_PRINT(readModePullDown, BIN); DEBUG_PRINT("R Up: "); DEBUG_PRINTLN(readModePullUp, BIN); }else if (mode == INPUT_PULLUP){ writeMode = writeMode & ~bit(pin); readMode = readMode | bit(pin); readModePullDown = readModePullDown & ~bit(pin); readModePullUp = readModePullUp | bit(pin); DEBUG_PRINT("W: "); DEBUG_PRINT(writeMode, BIN); DEBUG_PRINT(" R ALL: "); DEBUG_PRINT(readMode, BIN); DEBUG_PRINT(" R Down: "); DEBUG_PRINT(readModePullDown, BIN); DEBUG_PRINT("R Up: "); DEBUG_PRINTLN(readModePullUp, BIN); } else{ DEBUG_PRINTLN("Mode non supported by PCF8574") } }; void PCF8574::encoder(uint8_t pinA, uint8_t pinB){ PCF8574::pinMode(pinA, INPUT_PULLUP); PCF8574::pinMode(pinB, INPUT_PULLUP); encoderPins[pinA] = true; encoderPins[pinB] = true; } byte getBit(byte n, byte position) { return (n >> position) & 1; } //int8_t PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB){ // bool changed = false; // // byte offset = 0; // // byte na = PCF8574::digitalRead(pinA); // byte nb = PCF8574::digitalRead(pinB); // // byte encoderPinALast = (encoderValues & bit(pinA)); // byte encoderPinBLast = (encoderValues & bit(pinB)); // // if ((encoderPinALast!=na || encoderPinBLast!=nb) && (encoderPinALast == LOW) && (na == HIGH)) { // if (nb == LOW) { // offset = - 1; // changed = true; // } else { // offset = + 1; // changed = true; // } // } // // encoderValues = (encoderPinALast!=na)?encoderValues ^ bit(pinA):encoderValues; // encoderValues = (encoderPinBLast!=nb)?encoderValues ^ bit(pinB):encoderValues; // // return offset; //} bool PCF8574::checkProgression(byte oldValA, byte oldValB, byte newValA, byte newValB, byte validProgression){ bool findOldVal = false; int posFinded = 0; for (int pos = 0; pos<8; pos = pos + 2){ if ((oldValB == ((validProgression & bit(pos+1))>0?HIGH:LOW)) && (oldValA == ((validProgression & bit(pos+0))>0?HIGH:LOW)) ){ findOldVal = true; posFinded = pos; } } if (!findOldVal) return false; posFinded = posFinded + 2; if (posFinded>8) posFinded = 0; return ((newValB == ((validProgression & bit(posFinded+1))>0?HIGH:LOW)) && (newValA == ((validProgression & bit(posFinded+0))>0?HIGH:LOW)) ); } #ifdef BASIC_ENCODER_ALGORITHM bool PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ PCF8574::detachInterrupt(); bool changed = false; byte na = PCF8574::digitalRead(pinA, true); byte nb = PCF8574::digitalRead(pinB, true); byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; DEBUG_PRINT(pinA); DEBUG_PRINT(" TO --> "); DEBUG_PRINT(encoderPinALast); DEBUG_PRINT(encoderPinBLast); DEBUG_PRINT(" - "); DEBUG_PRINT(na); DEBUG_PRINT(nb); DEBUG_PRINTLN(); if ((encoderPinALast!=na || encoderPinBLast!=nb) && (encoderPinALast == LOW) && (na == HIGH)) { // bool vCW = checkProgression(encoderPinALast, encoderPinBLast, na, nb, validCW); // bool vCCW = checkProgression(encoderPinALast, encoderPinBLast, na, nb, validCCW); if (nb == LOW) { *encoderValue = *encoderValue + (!reverseRotation?+1:-1); changed = true; } else { *encoderValue = *encoderValue + (!reverseRotation?-1:+1); changed = true; } // if (nb == LOW && vCW) { // // checkCW(encoderPinALast, encoderPinBLast, na, nb); // *encoderValue = *encoderValue - 1; // changed = true; // } else if (vCCW) { // *encoderValue = *encoderValue + 1; // changed = true; // } } this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; PCF8574::attachInterrupt(); return changed; } int8_t PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB) { volatile long encoderValue = 0; PCF8574::readEncoderValue(pinA, pinB, &encoderValue); return encoderValue; } #endif #ifdef SEQUENCE_ENCODER_ALGORITHM bool PCF8574::readEncoderValueSequence(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ PCF8574::detachInterrupt(); bool changed = false; delay(100); byte na = PCF8574::digitalRead(pinA, true); byte nb = PCF8574::digitalRead(pinB, true); byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; DEBUG_PRINT(pinA); DEBUG_PRINT(" TO --> "); DEBUG_PRINT(encoderPinALast); DEBUG_PRINT(encoderPinBLast); DEBUG_PRINT(" - "); DEBUG_PRINT(na); DEBUG_PRINT(nb); DEBUG_PRINT(" -- "); int encoded = (na << 1) | nb; //converting the 2 pin value to single number int lastEncoded = (encoderPinALast << 1) | encoderPinBLast; int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value DEBUG_PRINT("sum - "); DEBUG_PRINT(sum, BIN); DEBUG_PRINT(" enc - "); DEBUG_PRINT( *encoderValue); if( sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011 ){ // encoderValue ++; *encoderValue = *encoderValue + (!reverseRotation?+1:-1); changed = true; } if( sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000 ) { *encoderValue = *encoderValue + (!reverseRotation?-1:+1); changed = true; // encoderValue --; } DEBUG_PRINT(" enc next - "); DEBUG_PRINTLN( *encoderValue); this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; PCF8574::attachInterrupt(); return changed; } int8_t PCF8574::readEncoderValueSequence(uint8_t pinA, uint8_t pinB) { volatile long encoderValue = 0; PCF8574::readEncoderValueSequence(pinA, pinB, &encoderValue); return encoderValue; } #endif #ifdef SEQUENCE_ENCODER_ALGORITHM_REDUCED bool PCF8574::readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ PCF8574::detachInterrupt(); bool changed = false; delay(100); byte na = PCF8574::digitalRead(pinA, true); byte nb = PCF8574::digitalRead(pinB, true); byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; DEBUG_PRINT(pinA); DEBUG_PRINT(" TO --> "); DEBUG_PRINT(encoderPinALast); DEBUG_PRINT(encoderPinBLast); DEBUG_PRINT(" - "); DEBUG_PRINT(na); DEBUG_PRINT(nb); DEBUG_PRINT(" -- "); int encoded = (na << 1) | nb; //converting the 2 pin value to single number int lastEncoded = (encoderPinALast << 1) | encoderPinBLast; int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value DEBUG_PRINT("sum - "); DEBUG_PRINT(sum, BIN); DEBUG_PRINT(" enc - "); DEBUG_PRINT( *encoderValue); if( sum == 0b1101 // || sum == 0b0100 || sum == 0b0010 // || sum == 0b1011 ){ // encoderValue ++; *encoderValue = *encoderValue + (!reverseRotation?+1:-1); changed = true; } if( sum == 0b1110 // || sum == 0b0111 || sum == 0b0001 // || sum == 0b1000 ) { *encoderValue = *encoderValue + (!reverseRotation?-1:+1); changed = true; // encoderValue --; } DEBUG_PRINT(" enc next - "); DEBUG_PRINTLN( *encoderValue); this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; PCF8574::attachInterrupt(); return changed; } int8_t PCF8574::readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB) { volatile long encoderValue = 0; PCF8574::readEncoderValueSequenceReduced(pinA, pinB, &encoderValue); return encoderValue; } #endif #ifdef MISCHIANTI_ENCODER_ALGORITHM bool PCF8574::readEncoderValueMischianti(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ PCF8574::detachInterrupt(); bool changed = false; byte na = PCF8574::digitalRead(pinA, true); byte nb = PCF8574::digitalRead(pinB, true); byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; if ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == LOW) || encoderPinALast==encoderPinBLast) && (na == HIGH)) { DEBUG_PRINT("TO --> "); DEBUG_PRINT(encoderPinALast); DEBUG_PRINT(encoderPinBLast); DEBUG_PRINT(" - "); DEBUG_PRINT(na); DEBUG_PRINT(nb); DEBUG_PRINTLN(); if (nb == LOW && nb!=na) { *encoderValue = *encoderValue + (!reverseRotation?+1:-1); changed = true; } else if (nb==na && encoderPinALast==encoderPinBLast) { *encoderValue = *encoderValue + (!reverseRotation?-1:+1); changed = true; } } // encoderValues = encoderValues & (~(bit(pinA) | bit(pinB))); // if (na == HIGH){ // encoderValues = encoderValues | bit(pinA); // } // if (nb == HIGH){ // encoderValues = encoderValues | bit(pinA); // } if (encoderPinALast!=na || encoderPinBLast!=nb){ this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; } PCF8574::attachInterrupt(); return changed; } int8_t PCF8574::readEncoderValueMischianti(uint8_t pinA, uint8_t pinB) { volatile long encoderValue = 0; PCF8574::readEncoderValueMischianti(pinA, pinB, &encoderValue); return encoderValue; } #endif //#ifdef MISCHIANTI_ENCODER_ALGORITHM_EVOLVED // bool PCF8574::readEncoderValueEvolved(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ // PCF8574::detachInterrupt(); // bool changed = false; // // byte na = PCF8574::digitalRead(pinA, true); // byte nb = PCF8574::digitalRead(pinB, true); // // byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; // byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; // //// Serial.print(pinA); //// Serial.print(" TO --> "); //// Serial.print(encoderPinALast); //// Serial.print(encoderPinBLast); //// Serial.print(" - "); //// Serial.print(na); //// Serial.print(nb); // // if ( // // ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == LOW) || encoderPinALast==encoderPinBLast) && (na == HIGH)) // || ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == HIGH) || encoderPinALast==encoderPinBLast) && (na == LOW)) // ){ // DEBUG_PRINT("TO --> "); // DEBUG_PRINT(encoderPinALast); // DEBUG_PRINT(encoderPinBLast); // DEBUG_PRINT(" - "); // DEBUG_PRINT(na); // DEBUG_PRINT(nb); // DEBUG_PRINTLN(); // //// Serial.print (" <------ "); // // if (nb == LOW && nb!=na) { // *encoderValue = *encoderValue + (!reverseRotation?+1:-1); // changed = true; // } else if (nb==na && encoderPinALast==encoderPinBLast) { // *encoderValue = *encoderValue + (!reverseRotation?-1:+1); // changed = true; // } // } //// Serial.println(); //// encoderValues = encoderValues & (~(bit(pinA) | bit(pinB))); //// if (na == HIGH){ //// encoderValues = encoderValues | bit(pinA); //// } //// if (nb == HIGH){ //// encoderValues = encoderValues | bit(pinA); //// } // // if (encoderPinALast!=na || encoderPinBLast!=nb){ // this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues; // this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues; // } // // PCF8574::attachInterrupt(); // return changed; // } // int8_t PCF8574::readEncoderValueEvolved(uint8_t pinA, uint8_t pinB) { // volatile long encoderValue = 0; // PCF8574::readEncoderValueEvolved(pinA, pinB, &encoderValue); // return encoderValue; // } // //#endif #ifdef POKI_ENCODER_ALGORITHM bool PCF8574::readEncoderValuePoki(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){ PCF8574::detachInterrupt(); bool changed = false; byte na = PCF8574::digitalRead(pinA, true); byte nb = PCF8574::digitalRead(pinB, true); byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW; byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW; DEBUG_PRINT("TO --> "); DEBUG_PRINT(encoderPinALast); DEBUG_PRINT(encoderPinBLast); DEBUG_PRINT(" - "); DEBUG_PRINT(na); DEBUG_PRINT(nb); DEBUG_PRINTLN(); if ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == LOW) || encoderPinALast==encoderPinBLast) && (na == HIGH)) { DEBUG_PRINT("TO --> "); DEBUG_PRINT(encoderPinALast); DEBUG_PRINT(encoderPinBLast); DEBUG_PRINT(" - "); DEBUG_PRINT(na); DEBUG_PRINT(nb); DEBUG_PRINTLN(); if (na && !nb) { if (encoderPinBLast) { *encoderValue = *encoderValue + (!reverseRotation?+1:-1); } else { *encoderValue = *encoderValue + (!reverseRotation?-1:+1); } changed = true; } } this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):encoderValues; this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):encoderValues; PCF8574::attachInterrupt(); return changed; } int8_t PCF8574::readEncoderValuePoki(uint8_t pinA, uint8_t pinB) { volatile long encoderValue = 0; PCF8574::readEncoderValue(pinA, pinB, &encoderValue); return encoderValue; } #endif /** * Read value from i2c and bufferize it * @param force */ void PCF8574::readBuffer(bool force){ if (millis() > PCF8574::lastReadMillis+latency || _usingInterrupt || force){ _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons lastReadMillis = millis(); if(_wire->available()) // If bytes are available to be recieved { byte iInput = _wire->read();// Read a byte if ((iInput & readModePullDown)>0 and (~iInput & readModePullUp)>0){ // if ((iInput & readMode)>0){ byteBuffered = (byteBuffered & ~readMode) | (byte)iInput; } } } } #ifndef PCF8574_LOW_MEMORY /** * Read value of all INPUT pin * Debounce read more fast than 10millis, non managed for interrupt mode * @return */ PCF8574::DigitalInput PCF8574::digitalReadAll(void){ DEBUG_PRINTLN("Read from buffer"); _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons lastReadMillis = millis(); if(_wire->available()) // If bytes are available to be recieved { DEBUG_PRINTLN("Data ready"); byte iInput = _wire->read();// Read a byte if ((readModePullDown & iInput)>0 or (readModePullUp & ~iInput)>0){ DEBUG_PRINT(" -------- CHANGE --------- "); byteBuffered = (byteBuffered & ~readMode) | (byte)iInput; } } DEBUG_PRINT("Buffer value "); DEBUG_PRINTLN(byteBuffered, BIN); if ((bit(0) & readMode)>0) digitalInput.p0 = ((byteBuffered & bit(0))>0)?HIGH:LOW; if ((bit(1) & readMode)>0) digitalInput.p1 = ((byteBuffered & bit(1))>0)?HIGH:LOW; if ((bit(2) & readMode)>0) digitalInput.p2 = ((byteBuffered & bit(2))>0)?HIGH:LOW; if ((bit(3) & readMode)>0) digitalInput.p3 = ((byteBuffered & bit(3))>0)?HIGH:LOW; if ((bit(4) & readMode)>0) digitalInput.p4 = ((byteBuffered & bit(4))>0)?HIGH:LOW; if ((bit(5) & readMode)>0) digitalInput.p5 = ((byteBuffered & bit(5))>0)?HIGH:LOW; if ((bit(6) & readMode)>0) digitalInput.p6 = ((byteBuffered & bit(6))>0)?HIGH:LOW; if ((bit(7) & readMode)>0) digitalInput.p7 = ((byteBuffered & bit(7))>0)?HIGH:LOW; if ((bit(0) & writeMode)>0) digitalInput.p0 = ((writeByteBuffered & bit(0))>0)?HIGH:LOW; if ((bit(1) & writeMode)>0) digitalInput.p1 = ((writeByteBuffered & bit(1))>0)?HIGH:LOW; if ((bit(2) & writeMode)>0) digitalInput.p2 = ((writeByteBuffered & bit(2))>0)?HIGH:LOW; if ((bit(3) & writeMode)>0) digitalInput.p3 = ((writeByteBuffered & bit(3))>0)?HIGH:LOW; if ((bit(4) & writeMode)>0) digitalInput.p4 = ((writeByteBuffered & bit(4))>0)?HIGH:LOW; if ((bit(5) & writeMode)>0) digitalInput.p5 = ((writeByteBuffered & bit(5))>0)?HIGH:LOW; if ((bit(6) & writeMode)>0) digitalInput.p6 = ((writeByteBuffered & bit(6))>0)?HIGH:LOW; if ((bit(7) & writeMode)>0) digitalInput.p7 = ((writeByteBuffered & bit(7))>0)?HIGH:LOW; //if ((byteBuffered & readModePullDown)>0 and (~byteBuffered & readModePullUp)>0){ // byteBuffered = (resetInitial & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered; byteBuffered = (initialBuffer & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered; DEBUG_PRINT("Buffer hight value readed set readed "); DEBUG_PRINTLN(byteBuffered, BIN); //} DEBUG_PRINT("Return value "); return digitalInput; }; #else /** * Read value of all INPUT pin in byte format for low memory usage * Debounce read more fast than 10millis, non managed for interrupt mode * @return */ byte PCF8574::digitalReadAll(void){ DEBUG_PRINTLN("Read from buffer"); _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons lastReadMillis = millis(); if(_wire->available()) // If bytes are available to be recieved { DEBUG_PRINTLN("Data ready"); byte iInput = _wire->read();// Read a byte if ((readModePullDown & iInput)>0 or (readModePullUp & ~iInput)>0){ DEBUG_PRINT(" -------- CHANGE --------- "); byteBuffered = (byteBuffered & ~readMode) | (byte)iInput; } } DEBUG_PRINT("Buffer value "); DEBUG_PRINTLN(byteBuffered, BIN); byte byteRead = byteBuffered | writeByteBuffered; //if ((byteBuffered & readModePullDown)>0 and (~byteBuffered & readModePullUp)>0){ // byteBuffered = (resetInitial & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered; byteBuffered = (initialBuffer & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered; DEBUG_PRINT("Buffer hight value readed set readed "); DEBUG_PRINTLN(byteBuffered, BIN); //} DEBUG_PRINT("Return value "); return byteRead; }; #endif /** * Read value of specified pin * Debounce read more fast than 10millis, non managed for interrupt mode * @param pin * @return */ uint8_t PCF8574::digitalRead(uint8_t pin, bool forceReadNow){ uint8_t value = (bit(pin) & readModePullUp)?HIGH:LOW; DEBUG_PRINT("Read pin "); DEBUG_PRINT (pin); // Check if pin already HIGH than read and prevent reread of i2c // DEBUG_PRINTLN("----------------------------------") // DEBUG_PRINT("readModePullUp "); // DEBUG_PRINTLN(readModePullUp, BIN); // DEBUG_PRINT("readModePullDown "); // DEBUG_PRINTLN(readModePullDown, BIN); // DEBUG_PRINT("byteBuffered "); // DEBUG_PRINTLN(byteBuffered, BIN); if ((((bit(pin) & (readModePullDown & byteBuffered))>0) or (bit(pin) & (readModePullUp & ~byteBuffered))>0 )){ DEBUG_PRINTLN(" ...Pin already set"); if ((bit(pin) & byteBuffered)>0){ value = HIGH; }else{ value = LOW; } }else if (forceReadNow || (millis() > PCF8574::lastReadMillis+latency)){ DEBUG_PRINT(" ...Read from buffer... "); _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons lastReadMillis = millis(); if(_wire->available()) // If bytes are available to be recieved { DEBUG_PRINTLN(" Data ready"); byte iInput = _wire->read();// Read a byte DEBUG_PRINT("Input "); DEBUG_PRINT((byte)iInput, BIN); if ((readModePullDown & iInput)>0 or (readModePullUp & ~iInput)>0){ DEBUG_PRINT(" -------- CHANGE --------- "); byteBuffered = (byteBuffered & ~readMode) | (byte)iInput; if ((bit(pin) & byteBuffered)>0){ value = HIGH; }else{ value = LOW; } // value = (bit(pin) & byteBuffered); } } } DEBUG_PRINT(" ..Buffer value "); DEBUG_PRINT(byteBuffered, BIN); // If HIGH set to low to read buffer only one time if ((bit(pin) & readModePullDown) and value==HIGH){ byteBuffered = bit(pin) ^ byteBuffered; DEBUG_PRINT(" ...Buffer hight value readed set readed "); DEBUG_PRINT (byteBuffered, BIN); }else if ((bit(pin) & readModePullUp) and value==LOW){ byteBuffered = bit(pin) ^ byteBuffered; DEBUG_PRINT(" ...Buffer low value readed set readed "); DEBUG_PRINT(byteBuffered, BIN); }else if(bit(pin) & writeByteBuffered){ value = HIGH; } DEBUG_PRINT(" ...Return value "); DEBUG_PRINTLN(value); return value; }; /** * Write on pin * @param pin * @param value */ bool PCF8574::digitalWrite(uint8_t pin, uint8_t value){ DEBUG_PRINTLN("Begin trasmission"); _wire->beginTransmission(_address); //Begin the transmission to PCF8574 DEBUG_PRINT("Value "); DEBUG_PRINT(value); DEBUG_PRINT(" Write data pre "); DEBUG_PRINT(writeByteBuffered, BIN); if (value==HIGH){ writeByteBuffered = writeByteBuffered | bit(pin); byteBuffered = writeByteBuffered | bit(pin); }else{ writeByteBuffered = writeByteBuffered & ~bit(pin); byteBuffered = writeByteBuffered & ~bit(pin); } DEBUG_PRINT("Write data "); DEBUG_PRINT(writeByteBuffered, BIN); DEBUG_PRINT(" for pin "); DEBUG_PRINT(pin); DEBUG_PRINT(" bin value "); DEBUG_PRINT(bit(pin), BIN); DEBUG_PRINT(" value "); DEBUG_PRINT(value); // writeByteBuffered = writeByteBuffered & (~writeMode & byteBuffered); byteBuffered = (writeByteBuffered & writeMode) | (resetInitial & readMode); // byteBuffered = (writeByteBuffered & writeMode) | (byteBuffered & readMode); DEBUG_PRINT(" byteBuffered "); DEBUG_PRINTLN(byteBuffered, BIN); DEBUG_PRINT("Going to write data "); DEBUG_PRINTLN(writeByteBuffered, BIN); _wire->write(byteBuffered); byteBuffered = (writeByteBuffered & writeMode) | (initialBuffer & readMode); // byteBuffered = (writeByteBuffered & writeMode) & (byteBuffered & readMode); DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor."); this->transmissionStatus = _wire->endTransmission(); return this->isLastTransmissionSuccess(); }; #ifndef PCF8574_LOW_MEMORY /** * Read value of all INPUT pin * Debounce read more fast than 10millis, non managed for interrupt mode * @return */ void PCF8574::setVal(uint8_t pin, uint8_t value){ if (value==HIGH){ writeByteBuffered = writeByteBuffered | bit(pin); byteBuffered = writeByteBuffered | bit(pin); }else{ writeByteBuffered = writeByteBuffered & ~bit(pin); byteBuffered = writeByteBuffered & ~bit(pin); } } bool PCF8574::digitalWriteAll(PCF8574::DigitalInput digitalInput){ setVal(P0, digitalInput.p0); setVal(P1, digitalInput.p1); setVal(P2, digitalInput.p2); setVal(P3, digitalInput.p3); setVal(P4, digitalInput.p4); setVal(P5, digitalInput.p5); setVal(P6, digitalInput.p6); setVal(P7, digitalInput.p7); return digitalWriteAllBytes(writeByteBuffered); } #else bool PCF8574::digitalWriteAll(byte digitalInput){ return digitalWriteAllBytes(digitalInput); } #endif bool PCF8574::digitalWriteAllBytes(byte allpins){ _wire->beginTransmission(_address); //Begin the transmission to PCF8574 // writeByteBuffered = writeByteBuffered & (~writeMode & byteBuffered); writeByteBuffered = allpins; byteBuffered = (writeByteBuffered & writeMode) | (resetInitial & readMode); // byteBuffered = (writeByteBuffered & writeMode) | (byteBuffered & readMode); DEBUG_PRINT(" byteBuffered "); DEBUG_PRINTLN(byteBuffered, BIN); DEBUG_PRINT("Going to write data "); DEBUG_PRINTLN(writeByteBuffered, BIN); _wire->write(byteBuffered); byteBuffered = (writeByteBuffered & writeMode) | (initialBuffer & readMode); // byteBuffered = (writeByteBuffered & writeMode) & (byteBuffered & readMode); DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor."); this->transmissionStatus = _wire->endTransmission(); return this->isLastTransmissionSuccess(); }