/* * PCF8574 GPIO Port Expand * * AUTHOR: Renzo Mischianti * VERSION: 2.3.4 * * 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. * * You may copy, alter and reuse this code in any way you like, but please leave * reference to www.mischianti.org in your comments if you redistribute this code. * * 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. */ #ifndef PCF8574_h #define PCF8574_h #include "Wire.h" #if ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h" #endif #define DEFAULT_SDA SDA; #define DEFAULT_SCL SCL; // Uncomment to enable printing out nice debug messages. // #define PCF8574_DEBUG // Uncomment for low memory usage this prevent use of complex DigitalInput structure and free 7byte of memory // #define PCF8574_LOW_MEMORY // Uncomment for low latency to get realtime data every time. // #define PCF8574_LOW_LATENCY //#define PCF8574_SOFT_INITIALIZATION // Select an algorithm to manage encoder progression #define BASIC_ENCODER_ALGORITHM // #define MISCHIANTI_ENCODER_ALGORITHM // #define SEQUENCE_ENCODER_ALGORITHM_REDUCED // #define SEQUENCE_ENCODER_ALGORITHM // #define POKI_ENCODER_ALGORITHM // Define where debug output will be printed. #define DEBUG_PRINTER Serial // Setup debug printing macros. #ifdef PCF8574_DEBUG #define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); } #define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); } #else #define DEBUG_PRINT(...) {} #define DEBUG_PRINTLN(...) {} #endif #ifdef PCF8574_LOW_LATENCY #define READ_ELAPSED_TIME 0 #else #define READ_ELAPSED_TIME 10 #endif //#define P0 B00000001 //#define P1 B00000010 //#define P2 B00000100 //#define P3 B00001000 //#define P4 B00010000 //#define P5 B00100000 //#define P6 B01000000 //#define P7 B10000000 // #define P0 0 #define P1 1 #define P2 2 #define P3 3 #define P4 4 #define P5 5 #define P6 6 #define P7 7 #include class PCF8574 { public: PCF8574(uint8_t address); PCF8574(uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ); #if !defined(__AVR) && !defined(ARDUINO_ARCH_SAMD) && !defined(ARDUINO_ARCH_STM32) && !defined(TEENSYDUINO) PCF8574(uint8_t address, int sda, int scl); PCF8574(uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)()); #endif #if defined(ESP32) || defined(ARDUINO_ARCH_SAMD) ///// changes for second i2c bus PCF8574(TwoWire *pWire, uint8_t address); PCF8574(TwoWire *pWire, uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ); #endif #if defined(ESP32) PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl); PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)()); #endif bool begin(); void pinMode(uint8_t pin, uint8_t mode, uint8_t output_start = HIGH); void encoder(uint8_t pinA, uint8_t pinB); void attachInterrupt(); void detachInterrupt(); void readBuffer(bool force = true); uint8_t digitalRead(uint8_t pin, bool forceReadNow = false); #ifndef PCF8574_LOW_MEMORY struct DigitalInput { uint8_t p0; uint8_t p1; uint8_t p2; uint8_t p3; uint8_t p4; uint8_t p5; uint8_t p6; uint8_t p7; } digitalInput; DigitalInput digitalReadAll(void); bool digitalWriteAll(PCF8574::DigitalInput digitalInput); #else byte digitalReadAll(void); bool digitalWriteAll(byte digitalInput); #endif bool digitalWrite(uint8_t pin, uint8_t value); #ifdef MISCHIANTI_ENCODER_ALGORITHM bool readEncoderValueMischianti(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); int8_t readEncoderValueMischianti(uint8_t pinA, uint8_t pinB); #endif #ifdef POKI_ENCODER_ALGORITHM bool readEncoderValuePoki(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); int8_t readEncoderValuePoki(uint8_t pinA, uint8_t pinB); #endif // bool readEncoderValueEvolved(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); // int8_t readEncoderValueEvolved(uint8_t pinA, uint8_t pinB); #ifdef SEQUENCE_ENCODER_ALGORITHM bool readEncoderValueSequence(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); int8_t readEncoderValueSequence(uint8_t pinA, uint8_t pinB); #endif #ifdef SEQUENCE_ENCODER_ALGORITHM_REDUCED bool readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); int8_t readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB); #endif #ifdef BASIC_ENCODER_ALGORITHM bool readEncoderValue(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false); int8_t readEncoderValue(uint8_t pinA, uint8_t pinB); #endif int getLatency() const { return latency; } void setLatency(int latency = READ_ELAPSED_TIME) { this->latency = latency; } uint8_t getTransmissionStatusCode() const { return transmissionStatus; } bool isLastTransmissionSuccess(){ DEBUG_PRINT(F("STATUS --> ")); DEBUG_PRINTLN(transmissionStatus); return transmissionStatus==0; } private: uint8_t _address; #if !defined(DEFAULT_SDA) # if defined(ARDUINO_ARCH_STM32) # define DEFAULT_SDA PB7 # elif defined(ESP8266) # define DEFAULT_SDA 4 # elif defined(SDA) # define DEFAULT_SDA SDA # else # error "Error define DEFAULT_SDA, SDA not declared, if you have this error contact the mantainer" # endif #endif #if !defined(DEFAULT_SCL) # if defined(ARDUINO_ARCH_STM32) # define DEFAULT_SCL PB6 # elif defined(ESP8266) # define DEFAULT_SCL 5 # elif defined(SDA) # define DEFAULT_SCL SCL # else # error "Error define DEFAULT_SCL, SCL not declared, if you have this error contact the mantainer" # endif #endif int _sda = DEFAULT_SDA; int _scl = DEFAULT_SCL; TwoWire *_wire; bool _usingInterrupt = false; uint8_t _interruptPin = 2; void (*_interruptFunction)(){}; byte writeMode = 0b00000000; byte writeModeUp = 0b00000000; byte readMode = 0b00000000; byte readModePullUp = 0b00000000; byte readModePullDown = 0b00000000; byte byteBuffered = 0b00000000; byte resetInitial = 0b00000000; byte initialBuffer = 0b00000000; unsigned long lastReadMillis = 0; byte writeByteBuffered = 0b00000000; volatile byte encoderValues = 0b00000000; uint8_t prevNextCode = 0; uint16_t store=0; int latency = READ_ELAPSED_TIME; bool checkProgression(byte oldValA, byte newValA, byte oldValB, byte newValB, byte validProgression); // byte validCW = B11100001; // byte validCCW = B01001011; byte validCW = 0b01001011; byte validCCW = 0b11100001; uint8_t transmissionStatus = 0; void setVal(uint8_t pin, uint8_t value); bool digitalWriteAllBytes(byte allpins); }; #endif