├── .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 |

5 |
6 |
7 |

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 | 
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 | 
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
--------------------------------------------------------------------------------