PCF8574.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  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. #include "PCF8574.h"
  28. #include "Wire.h"
  29. /**
  30. * Constructor
  31. * @param address: i2c address
  32. */
  33. PCF8574::PCF8574(uint8_t address){
  34. _wire = &Wire;
  35. _address = address;
  36. };
  37. /**
  38. * Construcor
  39. * @param address: i2c address
  40. * @param interruptPin: pin to set interrupt
  41. * @param interruptFunction: function to call when interrupt raised
  42. */
  43. PCF8574::PCF8574(uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ){
  44. _wire = &Wire;
  45. _address = address;
  46. _interruptPin = interruptPin;
  47. _interruptFunction = interruptFunction;
  48. _usingInterrupt = true;
  49. };
  50. #if !defined(__AVR) && !defined(ARDUINO_ARCH_SAMD) && !defined(ARDUINO_ARCH_STM32) && !defined(TEENSYDUINO)
  51. /**
  52. * Constructor
  53. * @param address: i2c address
  54. * @param sda: sda pin
  55. * @param scl: scl pin
  56. */
  57. PCF8574::PCF8574(uint8_t address, int sda, int scl){
  58. _wire = &Wire;
  59. _address = address;
  60. _sda = sda;
  61. _scl = scl;
  62. };
  63. /**
  64. * Constructor
  65. * @param address: i2c address
  66. * @param sda: sda pin
  67. * @param scl: scl pin
  68. * @param interruptPin: pin to set interrupt
  69. * @param interruptFunction: function to call when interrupt raised
  70. */
  71. PCF8574::PCF8574(uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)() ){
  72. _wire = &Wire;
  73. _address = address;
  74. _sda = sda;
  75. _scl = scl;
  76. _interruptPin = interruptPin;
  77. _interruptFunction = interruptFunction;
  78. _usingInterrupt = true;
  79. };
  80. #endif
  81. #if defined(ESP32) || defined(ARDUINO_ARCH_SAMD)
  82. /**
  83. * Constructor
  84. * @param address: i2c address
  85. */
  86. PCF8574::PCF8574(TwoWire *pWire, uint8_t address){
  87. _wire = pWire;
  88. _address = address;
  89. };
  90. /**
  91. * Construcor
  92. * @param address: i2c address
  93. * @param interruptPin: pin to set interrupt
  94. * @param interruptFunction: function to call when interrupt raised
  95. */
  96. PCF8574::PCF8574(TwoWire *pWire, uint8_t address, uint8_t interruptPin, void (*interruptFunction)() ){
  97. _wire = pWire;
  98. _address = address;
  99. _interruptPin = interruptPin;
  100. _interruptFunction = interruptFunction;
  101. _usingInterrupt = true;
  102. };
  103. #endif
  104. #if defined(ESP32)
  105. /**
  106. * Constructor
  107. * @param address: i2c address
  108. * @param sda: sda pin
  109. * @param scl: scl pin
  110. */
  111. PCF8574::PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl){
  112. _wire = pWire;
  113. _address = address;
  114. _sda = sda;
  115. _scl = scl;
  116. };
  117. /**
  118. * Constructor
  119. * @param address: i2c address
  120. * @param sda: sda pin
  121. * @param scl: scl pin
  122. * @param interruptPin: pin to set interrupt
  123. * @param interruptFunction: function to call when interrupt raised
  124. */
  125. PCF8574::PCF8574(TwoWire *pWire, uint8_t address, int sda, int scl, uint8_t interruptPin, void (*interruptFunction)() ){
  126. _wire = pWire;
  127. _address = address;
  128. _sda = sda;
  129. _scl = scl;
  130. _interruptPin = interruptPin;
  131. _interruptFunction = interruptFunction;
  132. _usingInterrupt = true;
  133. };
  134. #endif
  135. bool encoderPins[8];
  136. void PCF8574::attachInterrupt(){
  137. // If using interrupt set interrupt value to pin
  138. if (_usingInterrupt){
  139. for (int i = 0; i < 8;i++){
  140. if (encoderPins[i]) PCF8574::digitalRead(i);
  141. }
  142. // PCF8574::digitalReadAll();
  143. // (*_interruptFunction)();
  144. // DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)");
  145. // ::pinMode(_interruptPin, INPUT_PULLUP);
  146. // attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING );
  147. DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)");
  148. ::pinMode(_interruptPin, INPUT_PULLUP);
  149. ::attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING );
  150. }
  151. }
  152. void PCF8574::detachInterrupt(){
  153. // If using interrupt set interrupt value to pin
  154. if (_usingInterrupt){
  155. ::detachInterrupt(digitalPinToInterrupt(_interruptPin));
  156. DEBUG_PRINTLN("Detach interrupt pin");
  157. }
  158. }
  159. /**
  160. * wake up i2c controller
  161. */
  162. bool PCF8574::begin(){
  163. this->transmissionStatus = 4;
  164. #if !defined(__AVR) && !defined(ARDUINO_ARCH_SAMD) && !defined(ARDUINO_ARCH_STM32) && !defined(TEENSYDUINO)
  165. DEBUG_PRINT(F("begin(sda, scl) -> "));DEBUG_PRINT(_sda);DEBUG_PRINT(F(" "));DEBUG_PRINTLN(_scl);
  166. // _wire->begin(_sda, _scl);
  167. #ifdef ARDUINO_ARCH_STM32
  168. _wire->begin((uint32_t)_sda, (uint32_t)_scl);
  169. #else
  170. _wire->begin((int)_sda, (int)_scl);
  171. #endif
  172. #else
  173. // Default pin for AVR some problem on software emulation
  174. // #define SCL_PIN _scl
  175. // #define SDA_PIN _sda
  176. _wire->begin();
  177. #endif
  178. // Check if there are pins to set low
  179. if (writeMode>0 || readMode>0){
  180. DEBUG_PRINTLN("Set write mode");
  181. _wire->beginTransmission(_address);
  182. DEBUG_PRINT("resetInitial pin ");
  183. #ifdef PCF8574_SOFT_INITIALIZATION
  184. resetInitial = writeModeUp | readModePullUp;
  185. #else
  186. resetInitial = writeModeUp | readMode;
  187. #endif
  188. DEBUG_PRINTLN( resetInitial, BIN);
  189. _wire->write(resetInitial);
  190. initialBuffer = writeModeUp | readModePullUp;
  191. byteBuffered = initialBuffer;
  192. writeByteBuffered = writeModeUp;
  193. DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor.");
  194. this->transmissionStatus = _wire->endTransmission();
  195. }
  196. // // If using interrupt set interrupt value to pin
  197. // if (_usingInterrupt){
  198. //// DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)");
  199. //// ::pinMode(_interruptPin, INPUT_PULLUP);
  200. //// attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING );
  201. // DEBUG_PRINTLN("Using interrupt pin (not all pin is interrupted)");
  202. // ::pinMode(_interruptPin, INPUT_PULLUP);
  203. // ::attachInterrupt(digitalPinToInterrupt(_interruptPin), (*_interruptFunction), FALLING );
  204. // }
  205. PCF8574::attachInterrupt();
  206. // inizialize last read
  207. lastReadMillis = millis();
  208. return this->isLastTransmissionSuccess();
  209. }
  210. /**
  211. * Set if fin is OUTPUT or INPUT
  212. * @param pin: pin to set
  213. * @param mode: mode, supported only INPUT or OUTPUT (to simplify)
  214. * @param output_start: output_start, for OUTPUT we can set initial value
  215. */
  216. void PCF8574::pinMode(uint8_t pin, uint8_t mode, uint8_t output_start){
  217. DEBUG_PRINT("Set pin ");
  218. DEBUG_PRINT(pin);
  219. DEBUG_PRINT(" as ");
  220. DEBUG_PRINTLN(mode);
  221. if (mode == OUTPUT){
  222. writeMode = writeMode | bit(pin);
  223. if (output_start==HIGH) {
  224. writeModeUp = writeModeUp | bit(pin);
  225. }
  226. readMode = readMode & ~bit(pin);
  227. readModePullDown = readModePullDown & ~bit(pin);
  228. readModePullUp = readModePullUp & ~bit(pin);
  229. DEBUG_PRINT("W: ");
  230. DEBUG_PRINT(writeMode, BIN);
  231. DEBUG_PRINT(" R ALL: ");
  232. DEBUG_PRINT(readMode, BIN);
  233. DEBUG_PRINT(" R Down: ");
  234. DEBUG_PRINT(readModePullDown, BIN);
  235. DEBUG_PRINT("R Up: ");
  236. DEBUG_PRINTLN(readModePullUp, BIN);
  237. }else if (mode == INPUT){
  238. writeMode = writeMode & ~bit(pin);
  239. readMode = readMode | bit(pin);
  240. readModePullDown = readModePullDown | bit(pin);
  241. readModePullUp = readModePullUp & ~bit(pin);
  242. DEBUG_PRINT("W: ");
  243. DEBUG_PRINT(writeMode, BIN);
  244. DEBUG_PRINT(" R ALL: ");
  245. DEBUG_PRINT(readMode, BIN);
  246. DEBUG_PRINT(" R Down: ");
  247. DEBUG_PRINT(readModePullDown, BIN);
  248. DEBUG_PRINT("R Up: ");
  249. DEBUG_PRINTLN(readModePullUp, BIN);
  250. }else if (mode == INPUT_PULLUP){
  251. writeMode = writeMode & ~bit(pin);
  252. readMode = readMode | bit(pin);
  253. readModePullDown = readModePullDown & ~bit(pin);
  254. readModePullUp = readModePullUp | bit(pin);
  255. DEBUG_PRINT("W: ");
  256. DEBUG_PRINT(writeMode, BIN);
  257. DEBUG_PRINT(" R ALL: ");
  258. DEBUG_PRINT(readMode, BIN);
  259. DEBUG_PRINT(" R Down: ");
  260. DEBUG_PRINT(readModePullDown, BIN);
  261. DEBUG_PRINT("R Up: ");
  262. DEBUG_PRINTLN(readModePullUp, BIN);
  263. }
  264. else{
  265. DEBUG_PRINTLN("Mode non supported by PCF8574")
  266. }
  267. };
  268. void PCF8574::encoder(uint8_t pinA, uint8_t pinB){
  269. PCF8574::pinMode(pinA, INPUT_PULLUP);
  270. PCF8574::pinMode(pinB, INPUT_PULLUP);
  271. encoderPins[pinA] = true;
  272. encoderPins[pinB] = true;
  273. }
  274. byte getBit(byte n, byte position)
  275. {
  276. return (n >> position) & 1;
  277. }
  278. //int8_t PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB){
  279. // bool changed = false;
  280. //
  281. // byte offset = 0;
  282. //
  283. // byte na = PCF8574::digitalRead(pinA);
  284. // byte nb = PCF8574::digitalRead(pinB);
  285. //
  286. // byte encoderPinALast = (encoderValues & bit(pinA));
  287. // byte encoderPinBLast = (encoderValues & bit(pinB));
  288. //
  289. // if ((encoderPinALast!=na || encoderPinBLast!=nb) && (encoderPinALast == LOW) && (na == HIGH)) {
  290. // if (nb == LOW) {
  291. // offset = - 1;
  292. // changed = true;
  293. // } else {
  294. // offset = + 1;
  295. // changed = true;
  296. // }
  297. // }
  298. //
  299. // encoderValues = (encoderPinALast!=na)?encoderValues ^ bit(pinA):encoderValues;
  300. // encoderValues = (encoderPinBLast!=nb)?encoderValues ^ bit(pinB):encoderValues;
  301. //
  302. // return offset;
  303. //}
  304. bool PCF8574::checkProgression(byte oldValA, byte oldValB, byte newValA, byte newValB, byte validProgression){
  305. bool findOldVal = false;
  306. int posFinded = 0;
  307. for (int pos = 0; pos<8; pos = pos + 2){
  308. if ((oldValB == ((validProgression & bit(pos+1))>0?HIGH:LOW)) && (oldValA == ((validProgression & bit(pos+0))>0?HIGH:LOW)) ){
  309. findOldVal = true;
  310. posFinded = pos;
  311. }
  312. }
  313. if (!findOldVal) return false;
  314. posFinded = posFinded + 2;
  315. if (posFinded>8) posFinded = 0;
  316. return ((newValB == ((validProgression & bit(posFinded+1))>0?HIGH:LOW)) && (newValA == ((validProgression & bit(posFinded+0))>0?HIGH:LOW)) );
  317. }
  318. #ifdef BASIC_ENCODER_ALGORITHM
  319. bool PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){
  320. PCF8574::detachInterrupt();
  321. bool changed = false;
  322. byte na = PCF8574::digitalRead(pinA, true);
  323. byte nb = PCF8574::digitalRead(pinB, true);
  324. byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW;
  325. byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW;
  326. DEBUG_PRINT(pinA);
  327. DEBUG_PRINT(" TO --> ");
  328. DEBUG_PRINT(encoderPinALast);
  329. DEBUG_PRINT(encoderPinBLast);
  330. DEBUG_PRINT(" - ");
  331. DEBUG_PRINT(na);
  332. DEBUG_PRINT(nb);
  333. DEBUG_PRINTLN();
  334. if ((encoderPinALast!=na || encoderPinBLast!=nb) && (encoderPinALast == LOW) && (na == HIGH)) {
  335. // bool vCW = checkProgression(encoderPinALast, encoderPinBLast, na, nb, validCW);
  336. // bool vCCW = checkProgression(encoderPinALast, encoderPinBLast, na, nb, validCCW);
  337. if (nb == LOW) {
  338. *encoderValue = *encoderValue + (!reverseRotation?+1:-1);
  339. changed = true;
  340. } else {
  341. *encoderValue = *encoderValue + (!reverseRotation?-1:+1);
  342. changed = true;
  343. }
  344. // if (nb == LOW && vCW) {
  345. // // checkCW(encoderPinALast, encoderPinBLast, na, nb);
  346. // *encoderValue = *encoderValue - 1;
  347. // changed = true;
  348. // } else if (vCCW) {
  349. // *encoderValue = *encoderValue + 1;
  350. // changed = true;
  351. // }
  352. }
  353. this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues;
  354. this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues;
  355. PCF8574::attachInterrupt();
  356. return changed;
  357. }
  358. int8_t PCF8574::readEncoderValue(uint8_t pinA, uint8_t pinB) {
  359. volatile long encoderValue = 0;
  360. PCF8574::readEncoderValue(pinA, pinB, &encoderValue);
  361. return encoderValue;
  362. }
  363. #endif
  364. #ifdef SEQUENCE_ENCODER_ALGORITHM
  365. bool PCF8574::readEncoderValueSequence(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){
  366. PCF8574::detachInterrupt();
  367. bool changed = false;
  368. delay(100);
  369. byte na = PCF8574::digitalRead(pinA, true);
  370. byte nb = PCF8574::digitalRead(pinB, true);
  371. byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW;
  372. byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW;
  373. DEBUG_PRINT(pinA);
  374. DEBUG_PRINT(" TO --> ");
  375. DEBUG_PRINT(encoderPinALast);
  376. DEBUG_PRINT(encoderPinBLast);
  377. DEBUG_PRINT(" - ");
  378. DEBUG_PRINT(na);
  379. DEBUG_PRINT(nb);
  380. DEBUG_PRINT(" -- ");
  381. int encoded = (na << 1) | nb; //converting the 2 pin value to single number
  382. int lastEncoded = (encoderPinALast << 1) | encoderPinBLast;
  383. int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
  384. DEBUG_PRINT("sum - ");
  385. DEBUG_PRINT(sum, BIN);
  386. DEBUG_PRINT(" enc - ");
  387. DEBUG_PRINT( *encoderValue);
  388. if(
  389. sum == 0b1101
  390. || sum == 0b0100
  391. || sum == 0b0010
  392. || sum == 0b1011
  393. ){
  394. // encoderValue ++;
  395. *encoderValue = *encoderValue + (!reverseRotation?+1:-1);
  396. changed = true;
  397. }
  398. if(
  399. sum == 0b1110
  400. || sum == 0b0111
  401. || sum == 0b0001
  402. || sum == 0b1000
  403. ) {
  404. *encoderValue = *encoderValue + (!reverseRotation?-1:+1);
  405. changed = true;
  406. // encoderValue --;
  407. }
  408. DEBUG_PRINT(" enc next - ");
  409. DEBUG_PRINTLN( *encoderValue);
  410. this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues;
  411. this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues;
  412. PCF8574::attachInterrupt();
  413. return changed;
  414. }
  415. int8_t PCF8574::readEncoderValueSequence(uint8_t pinA, uint8_t pinB) {
  416. volatile long encoderValue = 0;
  417. PCF8574::readEncoderValueSequence(pinA, pinB, &encoderValue);
  418. return encoderValue;
  419. }
  420. #endif
  421. #ifdef SEQUENCE_ENCODER_ALGORITHM_REDUCED
  422. bool PCF8574::readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){
  423. PCF8574::detachInterrupt();
  424. bool changed = false;
  425. delay(100);
  426. byte na = PCF8574::digitalRead(pinA, true);
  427. byte nb = PCF8574::digitalRead(pinB, true);
  428. byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW;
  429. byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW;
  430. DEBUG_PRINT(pinA);
  431. DEBUG_PRINT(" TO --> ");
  432. DEBUG_PRINT(encoderPinALast);
  433. DEBUG_PRINT(encoderPinBLast);
  434. DEBUG_PRINT(" - ");
  435. DEBUG_PRINT(na);
  436. DEBUG_PRINT(nb);
  437. DEBUG_PRINT(" -- ");
  438. int encoded = (na << 1) | nb; //converting the 2 pin value to single number
  439. int lastEncoded = (encoderPinALast << 1) | encoderPinBLast;
  440. int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
  441. DEBUG_PRINT("sum - ");
  442. DEBUG_PRINT(sum, BIN);
  443. DEBUG_PRINT(" enc - ");
  444. DEBUG_PRINT( *encoderValue);
  445. if(
  446. sum == 0b1101
  447. // || sum == 0b0100
  448. || sum == 0b0010
  449. // || sum == 0b1011
  450. ){
  451. // encoderValue ++;
  452. *encoderValue = *encoderValue + (!reverseRotation?+1:-1);
  453. changed = true;
  454. }
  455. if(
  456. sum == 0b1110
  457. // || sum == 0b0111
  458. || sum == 0b0001
  459. // || sum == 0b1000
  460. ) {
  461. *encoderValue = *encoderValue + (!reverseRotation?-1:+1);
  462. changed = true;
  463. // encoderValue --;
  464. }
  465. DEBUG_PRINT(" enc next - ");
  466. DEBUG_PRINTLN( *encoderValue);
  467. this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues;
  468. this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues;
  469. PCF8574::attachInterrupt();
  470. return changed;
  471. }
  472. int8_t PCF8574::readEncoderValueSequenceReduced(uint8_t pinA, uint8_t pinB) {
  473. volatile long encoderValue = 0;
  474. PCF8574::readEncoderValueSequenceReduced(pinA, pinB, &encoderValue);
  475. return encoderValue;
  476. }
  477. #endif
  478. #ifdef MISCHIANTI_ENCODER_ALGORITHM
  479. bool PCF8574::readEncoderValueMischianti(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){
  480. PCF8574::detachInterrupt();
  481. bool changed = false;
  482. byte na = PCF8574::digitalRead(pinA, true);
  483. byte nb = PCF8574::digitalRead(pinB, true);
  484. byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW;
  485. byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW;
  486. if ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == LOW) || encoderPinALast==encoderPinBLast) && (na == HIGH)) {
  487. DEBUG_PRINT("TO --> ");
  488. DEBUG_PRINT(encoderPinALast);
  489. DEBUG_PRINT(encoderPinBLast);
  490. DEBUG_PRINT(" - ");
  491. DEBUG_PRINT(na);
  492. DEBUG_PRINT(nb);
  493. DEBUG_PRINTLN();
  494. if (nb == LOW && nb!=na) {
  495. *encoderValue = *encoderValue + (!reverseRotation?+1:-1);
  496. changed = true;
  497. } else if (nb==na && encoderPinALast==encoderPinBLast) {
  498. *encoderValue = *encoderValue + (!reverseRotation?-1:+1);
  499. changed = true;
  500. }
  501. }
  502. // encoderValues = encoderValues & (~(bit(pinA) | bit(pinB)));
  503. // if (na == HIGH){
  504. // encoderValues = encoderValues | bit(pinA);
  505. // }
  506. // if (nb == HIGH){
  507. // encoderValues = encoderValues | bit(pinA);
  508. // }
  509. if (encoderPinALast!=na || encoderPinBLast!=nb){
  510. this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues;
  511. this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues;
  512. }
  513. PCF8574::attachInterrupt();
  514. return changed;
  515. }
  516. int8_t PCF8574::readEncoderValueMischianti(uint8_t pinA, uint8_t pinB) {
  517. volatile long encoderValue = 0;
  518. PCF8574::readEncoderValueMischianti(pinA, pinB, &encoderValue);
  519. return encoderValue;
  520. }
  521. #endif
  522. //#ifdef MISCHIANTI_ENCODER_ALGORITHM_EVOLVED
  523. // bool PCF8574::readEncoderValueEvolved(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){
  524. // PCF8574::detachInterrupt();
  525. // bool changed = false;
  526. //
  527. // byte na = PCF8574::digitalRead(pinA, true);
  528. // byte nb = PCF8574::digitalRead(pinB, true);
  529. //
  530. // byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW;
  531. // byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW;
  532. //
  533. //// Serial.print(pinA);
  534. //// Serial.print(" TO --> ");
  535. //// Serial.print(encoderPinALast);
  536. //// Serial.print(encoderPinBLast);
  537. //// Serial.print(" - ");
  538. //// Serial.print(na);
  539. //// Serial.print(nb);
  540. //
  541. // if (
  542. //
  543. // ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == LOW) || encoderPinALast==encoderPinBLast) && (na == HIGH))
  544. // || ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == HIGH) || encoderPinALast==encoderPinBLast) && (na == LOW))
  545. // ){
  546. // DEBUG_PRINT("TO --> ");
  547. // DEBUG_PRINT(encoderPinALast);
  548. // DEBUG_PRINT(encoderPinBLast);
  549. // DEBUG_PRINT(" - ");
  550. // DEBUG_PRINT(na);
  551. // DEBUG_PRINT(nb);
  552. // DEBUG_PRINTLN();
  553. //
  554. //// Serial.print (" <------ ");
  555. //
  556. // if (nb == LOW && nb!=na) {
  557. // *encoderValue = *encoderValue + (!reverseRotation?+1:-1);
  558. // changed = true;
  559. // } else if (nb==na && encoderPinALast==encoderPinBLast) {
  560. // *encoderValue = *encoderValue + (!reverseRotation?-1:+1);
  561. // changed = true;
  562. // }
  563. // }
  564. //// Serial.println();
  565. //// encoderValues = encoderValues & (~(bit(pinA) | bit(pinB)));
  566. //// if (na == HIGH){
  567. //// encoderValues = encoderValues | bit(pinA);
  568. //// }
  569. //// if (nb == HIGH){
  570. //// encoderValues = encoderValues | bit(pinA);
  571. //// }
  572. //
  573. // if (encoderPinALast!=na || encoderPinBLast!=nb){
  574. // this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):this->encoderValues;
  575. // this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):this->encoderValues;
  576. // }
  577. //
  578. // PCF8574::attachInterrupt();
  579. // return changed;
  580. // }
  581. // int8_t PCF8574::readEncoderValueEvolved(uint8_t pinA, uint8_t pinB) {
  582. // volatile long encoderValue = 0;
  583. // PCF8574::readEncoderValueEvolved(pinA, pinB, &encoderValue);
  584. // return encoderValue;
  585. // }
  586. //
  587. //#endif
  588. #ifdef POKI_ENCODER_ALGORITHM
  589. bool PCF8574::readEncoderValuePoki(uint8_t pinA, uint8_t pinB, volatile long *encoderValue, bool reverseRotation){
  590. PCF8574::detachInterrupt();
  591. bool changed = false;
  592. byte na = PCF8574::digitalRead(pinA, true);
  593. byte nb = PCF8574::digitalRead(pinB, true);
  594. byte encoderPinALast = (this->encoderValues & bit(pinA))>0?HIGH:LOW;
  595. byte encoderPinBLast = (this->encoderValues & bit(pinB))>0?HIGH:LOW;
  596. DEBUG_PRINT("TO --> ");
  597. DEBUG_PRINT(encoderPinALast);
  598. DEBUG_PRINT(encoderPinBLast);
  599. DEBUG_PRINT(" - ");
  600. DEBUG_PRINT(na);
  601. DEBUG_PRINT(nb);
  602. DEBUG_PRINTLN();
  603. if ((encoderPinALast!=na || encoderPinBLast!=nb) && ((encoderPinALast == LOW) || encoderPinALast==encoderPinBLast) && (na == HIGH)) {
  604. DEBUG_PRINT("TO --> ");
  605. DEBUG_PRINT(encoderPinALast);
  606. DEBUG_PRINT(encoderPinBLast);
  607. DEBUG_PRINT(" - ");
  608. DEBUG_PRINT(na);
  609. DEBUG_PRINT(nb);
  610. DEBUG_PRINTLN();
  611. if (na && !nb) {
  612. if (encoderPinBLast) {
  613. *encoderValue = *encoderValue + (!reverseRotation?+1:-1);
  614. } else {
  615. *encoderValue = *encoderValue + (!reverseRotation?-1:+1);
  616. }
  617. changed = true;
  618. }
  619. }
  620. this->encoderValues = (encoderPinALast!=na)?this->encoderValues ^ bit(pinA):encoderValues;
  621. this->encoderValues = (encoderPinBLast!=nb)?this->encoderValues ^ bit(pinB):encoderValues;
  622. PCF8574::attachInterrupt();
  623. return changed;
  624. }
  625. int8_t PCF8574::readEncoderValuePoki(uint8_t pinA, uint8_t pinB) {
  626. volatile long encoderValue = 0;
  627. PCF8574::readEncoderValue(pinA, pinB, &encoderValue);
  628. return encoderValue;
  629. }
  630. #endif
  631. /**
  632. * Read value from i2c and bufferize it
  633. * @param force
  634. */
  635. void PCF8574::readBuffer(bool force){
  636. if (millis() > PCF8574::lastReadMillis+latency || _usingInterrupt || force){
  637. _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons
  638. lastReadMillis = millis();
  639. if(_wire->available()) // If bytes are available to be recieved
  640. {
  641. byte iInput = _wire->read();// Read a byte
  642. if ((iInput & readModePullDown)>0 and (~iInput & readModePullUp)>0){
  643. // if ((iInput & readMode)>0){
  644. byteBuffered = (byteBuffered & ~readMode) | (byte)iInput;
  645. }
  646. }
  647. }
  648. }
  649. #ifndef PCF8574_LOW_MEMORY
  650. /**
  651. * Read value of all INPUT pin
  652. * Debounce read more fast than 10millis, non managed for interrupt mode
  653. * @return
  654. */
  655. PCF8574::DigitalInput PCF8574::digitalReadAll(void){
  656. DEBUG_PRINTLN("Read from buffer");
  657. _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons
  658. lastReadMillis = millis();
  659. if(_wire->available()) // If bytes are available to be recieved
  660. {
  661. DEBUG_PRINTLN("Data ready");
  662. byte iInput = _wire->read();// Read a byte
  663. if ((readModePullDown & iInput)>0 or (readModePullUp & ~iInput)>0){
  664. DEBUG_PRINT(" -------- CHANGE --------- ");
  665. byteBuffered = (byteBuffered & ~readMode) | (byte)iInput;
  666. }
  667. }
  668. DEBUG_PRINT("Buffer value ");
  669. DEBUG_PRINTLN(byteBuffered, BIN);
  670. if ((bit(0) & readMode)>0) digitalInput.p0 = ((byteBuffered & bit(0))>0)?HIGH:LOW;
  671. if ((bit(1) & readMode)>0) digitalInput.p1 = ((byteBuffered & bit(1))>0)?HIGH:LOW;
  672. if ((bit(2) & readMode)>0) digitalInput.p2 = ((byteBuffered & bit(2))>0)?HIGH:LOW;
  673. if ((bit(3) & readMode)>0) digitalInput.p3 = ((byteBuffered & bit(3))>0)?HIGH:LOW;
  674. if ((bit(4) & readMode)>0) digitalInput.p4 = ((byteBuffered & bit(4))>0)?HIGH:LOW;
  675. if ((bit(5) & readMode)>0) digitalInput.p5 = ((byteBuffered & bit(5))>0)?HIGH:LOW;
  676. if ((bit(6) & readMode)>0) digitalInput.p6 = ((byteBuffered & bit(6))>0)?HIGH:LOW;
  677. if ((bit(7) & readMode)>0) digitalInput.p7 = ((byteBuffered & bit(7))>0)?HIGH:LOW;
  678. if ((bit(0) & writeMode)>0) digitalInput.p0 = ((writeByteBuffered & bit(0))>0)?HIGH:LOW;
  679. if ((bit(1) & writeMode)>0) digitalInput.p1 = ((writeByteBuffered & bit(1))>0)?HIGH:LOW;
  680. if ((bit(2) & writeMode)>0) digitalInput.p2 = ((writeByteBuffered & bit(2))>0)?HIGH:LOW;
  681. if ((bit(3) & writeMode)>0) digitalInput.p3 = ((writeByteBuffered & bit(3))>0)?HIGH:LOW;
  682. if ((bit(4) & writeMode)>0) digitalInput.p4 = ((writeByteBuffered & bit(4))>0)?HIGH:LOW;
  683. if ((bit(5) & writeMode)>0) digitalInput.p5 = ((writeByteBuffered & bit(5))>0)?HIGH:LOW;
  684. if ((bit(6) & writeMode)>0) digitalInput.p6 = ((writeByteBuffered & bit(6))>0)?HIGH:LOW;
  685. if ((bit(7) & writeMode)>0) digitalInput.p7 = ((writeByteBuffered & bit(7))>0)?HIGH:LOW;
  686. //if ((byteBuffered & readModePullDown)>0 and (~byteBuffered & readModePullUp)>0){
  687. // byteBuffered = (resetInitial & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered;
  688. byteBuffered = (initialBuffer & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered;
  689. DEBUG_PRINT("Buffer hight value readed set readed ");
  690. DEBUG_PRINTLN(byteBuffered, BIN);
  691. //}
  692. DEBUG_PRINT("Return value ");
  693. return digitalInput;
  694. };
  695. #else
  696. /**
  697. * Read value of all INPUT pin in byte format for low memory usage
  698. * Debounce read more fast than 10millis, non managed for interrupt mode
  699. * @return
  700. */
  701. byte PCF8574::digitalReadAll(void){
  702. DEBUG_PRINTLN("Read from buffer");
  703. _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons
  704. lastReadMillis = millis();
  705. if(_wire->available()) // If bytes are available to be recieved
  706. {
  707. DEBUG_PRINTLN("Data ready");
  708. byte iInput = _wire->read();// Read a byte
  709. if ((readModePullDown & iInput)>0 or (readModePullUp & ~iInput)>0){
  710. DEBUG_PRINT(" -------- CHANGE --------- ");
  711. byteBuffered = (byteBuffered & ~readMode) | (byte)iInput;
  712. }
  713. }
  714. DEBUG_PRINT("Buffer value ");
  715. DEBUG_PRINTLN(byteBuffered, BIN);
  716. byte byteRead = byteBuffered | writeByteBuffered;
  717. //if ((byteBuffered & readModePullDown)>0 and (~byteBuffered & readModePullUp)>0){
  718. // byteBuffered = (resetInitial & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered;
  719. byteBuffered = (initialBuffer & readMode) | (byteBuffered & ~readMode); //~readMode & byteBuffered;
  720. DEBUG_PRINT("Buffer hight value readed set readed ");
  721. DEBUG_PRINTLN(byteBuffered, BIN);
  722. //}
  723. DEBUG_PRINT("Return value ");
  724. return byteRead;
  725. };
  726. #endif
  727. /**
  728. * Read value of specified pin
  729. * Debounce read more fast than 10millis, non managed for interrupt mode
  730. * @param pin
  731. * @return
  732. */
  733. uint8_t PCF8574::digitalRead(uint8_t pin, bool forceReadNow){
  734. uint8_t value = (bit(pin) & readModePullUp)?HIGH:LOW;
  735. DEBUG_PRINT("Read pin ");
  736. DEBUG_PRINT (pin);
  737. // Check if pin already HIGH than read and prevent reread of i2c
  738. // DEBUG_PRINTLN("----------------------------------")
  739. // DEBUG_PRINT("readModePullUp ");
  740. // DEBUG_PRINTLN(readModePullUp, BIN);
  741. // DEBUG_PRINT("readModePullDown ");
  742. // DEBUG_PRINTLN(readModePullDown, BIN);
  743. // DEBUG_PRINT("byteBuffered ");
  744. // DEBUG_PRINTLN(byteBuffered, BIN);
  745. if ((((bit(pin) & (readModePullDown & byteBuffered))>0) or (bit(pin) & (readModePullUp & ~byteBuffered))>0 )){
  746. DEBUG_PRINTLN(" ...Pin already set");
  747. if ((bit(pin) & byteBuffered)>0){
  748. value = HIGH;
  749. }else{
  750. value = LOW;
  751. }
  752. }else if (forceReadNow || (millis() > PCF8574::lastReadMillis+latency)){
  753. DEBUG_PRINT(" ...Read from buffer... ");
  754. _wire->requestFrom(_address,(uint8_t)1);// Begin transmission to PCF8574 with the buttons
  755. lastReadMillis = millis();
  756. if(_wire->available()) // If bytes are available to be recieved
  757. {
  758. DEBUG_PRINTLN(" Data ready");
  759. byte iInput = _wire->read();// Read a byte
  760. DEBUG_PRINT("Input ");
  761. DEBUG_PRINT((byte)iInput, BIN);
  762. if ((readModePullDown & iInput)>0 or (readModePullUp & ~iInput)>0){
  763. DEBUG_PRINT(" -------- CHANGE --------- ");
  764. byteBuffered = (byteBuffered & ~readMode) | (byte)iInput;
  765. if ((bit(pin) & byteBuffered)>0){
  766. value = HIGH;
  767. }else{
  768. value = LOW;
  769. }
  770. // value = (bit(pin) & byteBuffered);
  771. }
  772. }
  773. }
  774. DEBUG_PRINT(" ..Buffer value ");
  775. DEBUG_PRINT(byteBuffered, BIN);
  776. // If HIGH set to low to read buffer only one time
  777. if ((bit(pin) & readModePullDown) and value==HIGH){
  778. byteBuffered = bit(pin) ^ byteBuffered;
  779. DEBUG_PRINT(" ...Buffer hight value readed set readed ");
  780. DEBUG_PRINT (byteBuffered, BIN);
  781. }else if ((bit(pin) & readModePullUp) and value==LOW){
  782. byteBuffered = bit(pin) ^ byteBuffered;
  783. DEBUG_PRINT(" ...Buffer low value readed set readed ");
  784. DEBUG_PRINT(byteBuffered, BIN);
  785. }else if(bit(pin) & writeByteBuffered){
  786. value = HIGH;
  787. }
  788. DEBUG_PRINT(" ...Return value ");
  789. DEBUG_PRINTLN(value);
  790. return value;
  791. };
  792. /**
  793. * Write on pin
  794. * @param pin
  795. * @param value
  796. */
  797. bool PCF8574::digitalWrite(uint8_t pin, uint8_t value){
  798. DEBUG_PRINTLN("Begin trasmission");
  799. _wire->beginTransmission(_address); //Begin the transmission to PCF8574
  800. DEBUG_PRINT("Value ");
  801. DEBUG_PRINT(value);
  802. DEBUG_PRINT(" Write data pre ");
  803. DEBUG_PRINT(writeByteBuffered, BIN);
  804. if (value==HIGH){
  805. writeByteBuffered = writeByteBuffered | bit(pin);
  806. byteBuffered = writeByteBuffered | bit(pin);
  807. }else{
  808. writeByteBuffered = writeByteBuffered & ~bit(pin);
  809. byteBuffered = writeByteBuffered & ~bit(pin);
  810. }
  811. DEBUG_PRINT("Write data ");
  812. DEBUG_PRINT(writeByteBuffered, BIN);
  813. DEBUG_PRINT(" for pin ");
  814. DEBUG_PRINT(pin);
  815. DEBUG_PRINT(" bin value ");
  816. DEBUG_PRINT(bit(pin), BIN);
  817. DEBUG_PRINT(" value ");
  818. DEBUG_PRINT(value);
  819. // writeByteBuffered = writeByteBuffered & (~writeMode & byteBuffered);
  820. byteBuffered = (writeByteBuffered & writeMode) | (resetInitial & readMode);
  821. // byteBuffered = (writeByteBuffered & writeMode) | (byteBuffered & readMode);
  822. DEBUG_PRINT(" byteBuffered ");
  823. DEBUG_PRINTLN(byteBuffered, BIN);
  824. DEBUG_PRINT("Going to write data ");
  825. DEBUG_PRINTLN(writeByteBuffered, BIN);
  826. _wire->write(byteBuffered);
  827. byteBuffered = (writeByteBuffered & writeMode) | (initialBuffer & readMode);
  828. // byteBuffered = (writeByteBuffered & writeMode) & (byteBuffered & readMode);
  829. DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor.");
  830. this->transmissionStatus = _wire->endTransmission();
  831. return this->isLastTransmissionSuccess();
  832. };
  833. #ifndef PCF8574_LOW_MEMORY
  834. /**
  835. * Read value of all INPUT pin
  836. * Debounce read more fast than 10millis, non managed for interrupt mode
  837. * @return
  838. */
  839. void PCF8574::setVal(uint8_t pin, uint8_t value){
  840. if (value==HIGH){
  841. writeByteBuffered = writeByteBuffered | bit(pin);
  842. byteBuffered = writeByteBuffered | bit(pin);
  843. }else{
  844. writeByteBuffered = writeByteBuffered & ~bit(pin);
  845. byteBuffered = writeByteBuffered & ~bit(pin);
  846. }
  847. }
  848. bool PCF8574::digitalWriteAll(PCF8574::DigitalInput digitalInput){
  849. setVal(P0, digitalInput.p0);
  850. setVal(P1, digitalInput.p1);
  851. setVal(P2, digitalInput.p2);
  852. setVal(P3, digitalInput.p3);
  853. setVal(P4, digitalInput.p4);
  854. setVal(P5, digitalInput.p5);
  855. setVal(P6, digitalInput.p6);
  856. setVal(P7, digitalInput.p7);
  857. return digitalWriteAllBytes(writeByteBuffered);
  858. }
  859. #else
  860. bool PCF8574::digitalWriteAll(byte digitalInput){
  861. return digitalWriteAllBytes(digitalInput);
  862. }
  863. #endif
  864. bool PCF8574::digitalWriteAllBytes(byte allpins){
  865. _wire->beginTransmission(_address); //Begin the transmission to PCF8574
  866. // writeByteBuffered = writeByteBuffered & (~writeMode & byteBuffered);
  867. writeByteBuffered = allpins;
  868. byteBuffered = (writeByteBuffered & writeMode) | (resetInitial & readMode);
  869. // byteBuffered = (writeByteBuffered & writeMode) | (byteBuffered & readMode);
  870. DEBUG_PRINT(" byteBuffered ");
  871. DEBUG_PRINTLN(byteBuffered, BIN);
  872. DEBUG_PRINT("Going to write data ");
  873. DEBUG_PRINTLN(writeByteBuffered, BIN);
  874. _wire->write(byteBuffered);
  875. byteBuffered = (writeByteBuffered & writeMode) | (initialBuffer & readMode);
  876. // byteBuffered = (writeByteBuffered & writeMode) & (byteBuffered & readMode);
  877. DEBUG_PRINTLN("Start end trasmission if stop here check pullup resistor.");
  878. this->transmissionStatus = _wire->endTransmission();
  879. return this->isLastTransmissionSuccess();
  880. }