PCF8574.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. * PCF8574 GPIO Port Expand
  3. *
  4. * AUTHOR: Renzo Mischianti
  5. * VERSION: 2.3.4
  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. #ifndef PCF8574_h
  35. #define PCF8574_h
  36. #include "Wire.h"
  37. #if ARDUINO >= 100
  38. #include "Arduino.h"
  39. #else
  40. #include "WProgram.h"
  41. #endif
  42. #define DEFAULT_SDA SDA;
  43. #define DEFAULT_SCL SCL;
  44. // Uncomment to enable printing out nice debug messages.
  45. // #define PCF8574_DEBUG
  46. // Uncomment for low memory usage this prevent use of complex DigitalInput structure and free 7byte of memory
  47. // #define PCF8574_LOW_MEMORY
  48. // Uncomment for low latency to get realtime data every time.
  49. // #define PCF8574_LOW_LATENCY
  50. //#define PCF8574_SOFT_INITIALIZATION
  51. // Select an algorithm to manage encoder progression
  52. #define BASIC_ENCODER_ALGORITHM
  53. // #define MISCHIANTI_ENCODER_ALGORITHM
  54. // #define SEQUENCE_ENCODER_ALGORITHM_REDUCED
  55. // #define SEQUENCE_ENCODER_ALGORITHM
  56. // #define POKI_ENCODER_ALGORITHM
  57. // Define where debug output will be printed.
  58. #define DEBUG_PRINTER Serial
  59. // Setup debug printing macros.
  60. #ifdef PCF8574_DEBUG
  61. #define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); }
  62. #define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); }
  63. #else
  64. #define DEBUG_PRINT(...) {}
  65. #define DEBUG_PRINTLN(...) {}
  66. #endif
  67. #ifdef PCF8574_LOW_LATENCY
  68. #define READ_ELAPSED_TIME 0
  69. #else
  70. #define READ_ELAPSED_TIME 10
  71. #endif
  72. //#define P0 B00000001
  73. //#define P1 B00000010
  74. //#define P2 B00000100
  75. //#define P3 B00001000
  76. //#define P4 B00010000
  77. //#define P5 B00100000
  78. //#define P6 B01000000
  79. //#define P7 B10000000
  80. //
  81. #define P0 0
  82. #define P1 1
  83. #define P2 2
  84. #define P3 3
  85. #define P4 4
  86. #define P5 5
  87. #define P6 6
  88. #define P7 7
  89. #include <math.h>
  90. class PCF8574 {
  91. public:
  92. PCF8574(uint8_t address);
  93. PCF8574(uint8_t address, uint8_t interruptPin, void (*interruptFunction)() );
  94. #if !defined(__AVR) && !defined(ARDUINO_ARCH_SAMD) && !defined(ARDUINO_ARCH_STM32) && !defined(TEENSYDUINO)
  95. PCF8574(uint8_t address, int sda, int scl);
  96. PCF8574(uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)());
  97. #endif
  98. #if defined(ESP32) || defined(ARDUINO_ARCH_SAMD)
  99. ///// changes for second i2c bus
  100. PCF8574(TwoWire *pWire, uint8_t address);
  101. PCF8574(TwoWire *pWire, uint8_t address, uint8_t interruptPin, void (*interruptFunction)() );
  102. #endif
  103. #if defined(ESP32)
  104. PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl);
  105. PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)());
  106. #endif
  107. bool begin();
  108. void pinMode(uint8_t pin, uint8_t mode, uint8_t output_start = HIGH);
  109. void encoder(uint8_t pinA, uint8_t pinB);
  110. void attachInterrupt();
  111. void detachInterrupt();
  112. void readBuffer(bool force = true);
  113. uint8_t digitalRead(uint8_t pin, bool forceReadNow = false);
  114. #ifndef PCF8574_LOW_MEMORY
  115. struct DigitalInput {
  116. uint8_t p0;
  117. uint8_t p1;
  118. uint8_t p2;
  119. uint8_t p3;
  120. uint8_t p4;
  121. uint8_t p5;
  122. uint8_t p6;
  123. uint8_t p7;
  124. } digitalInput;
  125. DigitalInput digitalReadAll(void);
  126. bool digitalWriteAll(PCF8574::DigitalInput digitalInput);
  127. #else
  128. byte digitalReadAll(void);
  129. bool digitalWriteAll(byte digitalInput);
  130. #endif
  131. bool digitalWrite(uint8_t pin, uint8_t value);
  132. #ifdef MISCHIANTI_ENCODER_ALGORITHM
  133. bool readEncoderValueMischianti(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false);
  134. int8_t readEncoderValueMischianti(uint8_t pinA, uint8_t pinB);
  135. #endif
  136. #ifdef POKI_ENCODER_ALGORITHM
  137. bool readEncoderValuePoki(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false);
  138. int8_t readEncoderValuePoki(uint8_t pinA, uint8_t pinB);
  139. #endif
  140. // bool readEncoderValueEvolved(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false);
  141. // int8_t readEncoderValueEvolved(uint8_t pinA, uint8_t pinB);
  142. #ifdef SEQUENCE_ENCODER_ALGORITHM
  143. bool readEncoderValueSequence(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false);
  144. int8_t readEncoderValueSequence(uint8_t pinA, uint8_t pinB);
  145. #endif
  146. #ifdef SEQUENCE_ENCODER_ALGORITHM_REDUCED
  147. bool readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false);
  148. int8_t readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB);
  149. #endif
  150. #ifdef BASIC_ENCODER_ALGORITHM
  151. bool readEncoderValue(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation = false);
  152. int8_t readEncoderValue(uint8_t pinA, uint8_t pinB);
  153. #endif
  154. int getLatency() const {
  155. return latency;
  156. }
  157. void setLatency(int latency = READ_ELAPSED_TIME) {
  158. this->latency = latency;
  159. }
  160. uint8_t getTransmissionStatusCode() const {
  161. return transmissionStatus;
  162. }
  163. bool isLastTransmissionSuccess(){
  164. DEBUG_PRINT(F("STATUS --> "));
  165. DEBUG_PRINTLN(transmissionStatus);
  166. return transmissionStatus==0;
  167. }
  168. private:
  169. uint8_t _address;
  170. #if !defined(DEFAULT_SDA)
  171. # if defined(ARDUINO_ARCH_STM32)
  172. # define DEFAULT_SDA PB7
  173. # elif defined(ESP8266)
  174. # define DEFAULT_SDA 4
  175. # elif defined(SDA)
  176. # define DEFAULT_SDA SDA
  177. # else
  178. # error "Error define DEFAULT_SDA, SDA not declared, if you have this error contact the mantainer"
  179. # endif
  180. #endif
  181. #if !defined(DEFAULT_SCL)
  182. # if defined(ARDUINO_ARCH_STM32)
  183. # define DEFAULT_SCL PB6
  184. # elif defined(ESP8266)
  185. # define DEFAULT_SCL 5
  186. # elif defined(SDA)
  187. # define DEFAULT_SCL SCL
  188. # else
  189. # error "Error define DEFAULT_SCL, SCL not declared, if you have this error contact the mantainer"
  190. # endif
  191. #endif
  192. int _sda = DEFAULT_SDA;
  193. int _scl = DEFAULT_SCL;
  194. TwoWire *_wire;
  195. bool _usingInterrupt = false;
  196. uint8_t _interruptPin = 2;
  197. void (*_interruptFunction)(){};
  198. byte writeMode = 0b00000000;
  199. byte writeModeUp = 0b00000000;
  200. byte readMode = 0b00000000;
  201. byte readModePullUp = 0b00000000;
  202. byte readModePullDown = 0b00000000;
  203. byte byteBuffered = 0b00000000;
  204. byte resetInitial = 0b00000000;
  205. byte initialBuffer = 0b00000000;
  206. unsigned long lastReadMillis = 0;
  207. byte writeByteBuffered = 0b00000000;
  208. volatile byte encoderValues = 0b00000000;
  209. uint8_t prevNextCode = 0;
  210. uint16_t store=0;
  211. int latency = READ_ELAPSED_TIME;
  212. bool checkProgression(byte oldValA, byte newValA, byte oldValB, byte newValB, byte validProgression);
  213. // byte validCW = B11100001;
  214. // byte validCCW = B01001011;
  215. byte validCW = 0b01001011;
  216. byte validCCW = 0b11100001;
  217. uint8_t transmissionStatus = 0;
  218. void setVal(uint8_t pin, uint8_t value);
  219. bool digitalWriteAllBytes(byte allpins);
  220. };
  221. #endif