Skip to content

Commit a2c770a

Browse files
authored
add writeArray() and readArray() (#61)
- add **writeArray(array, size)** and **readArray(array, size)**. - add PCF8574_writeArray.ino - update readme.md - minor edits
1 parent 8ab7e28 commit a2c770a

25 files changed

Lines changed: 236 additions & 31 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

88

9+
## [0.4.4] - 2025-09-01
10+
- add **writeArray(array, size)** and **readArray(array, size)**.
11+
- add PCF8574_writeArray.ino
12+
- update readme.md
13+
- minor edits
14+
915
## [0.4.3] - 2025-08-21
10-
- update github actions
16+
- update GitHub actions
1117
- minor edits
1218

1319
## [0.4.2] - 2025-04-18

PCF8574.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22
// FILE: PCF8574.cpp
33
// AUTHOR: Rob Tillaart
44
// DATE: 02-febr-2013
5-
// VERSION: 0.4.3
5+
// VERSION: 0.4.4
66
// PURPOSE: Arduino library for PCF8574 - 8 channel I2C IO expander
77
// URL: https://github.com/RobTillaart/PCF8574
88
// http://forum.arduino.cc/index.php?topic=184800
99

1010

1111
#include "PCF8574.h"
1212

13+
#ifndef I2C_BUFFER_LENGTH
14+
#define I2C_BUFFER_LENGTH (32)
15+
#endif
16+
1317

1418
PCF8574::PCF8574(const uint8_t deviceAddress, TwoWire *wire)
1519
: _address {deviceAddress}, _wire {wire}
@@ -93,6 +97,48 @@ void PCF8574::write(const uint8_t pin, const uint8_t value)
9397
}
9498

9599

100+
// experimental 0.4.4
101+
bool PCF8574::writeArray(uint8_t *array, uint8_t size)
102+
{
103+
if (size > (I2C_BUFFER_LENGTH - 1))
104+
{
105+
_error = PCF8574_BUFFER_LENGTH_ERROR;
106+
return false;
107+
}
108+
yield();
109+
_wire->beginTransmission(_address);
110+
for (uint8_t i = 0; i < size; i++)
111+
{
112+
_wire->write(array[i]);
113+
}
114+
_error = _wire->endTransmission();
115+
_dataOut = array[size - 1];
116+
return true;
117+
}
118+
119+
120+
bool PCF8574::readArray(uint8_t *array, uint8_t size)
121+
{
122+
if (size > (I2C_BUFFER_LENGTH - 1))
123+
{
124+
_error = PCF8574_BUFFER_LENGTH_ERROR;
125+
return false;
126+
}
127+
yield();
128+
if (_wire->requestFrom(_address, size) != size)
129+
{
130+
_error = PCF8574_I2C_ERROR;
131+
return false;
132+
}
133+
for (uint8_t i = 0; i < size; i++)
134+
{
135+
array[i] = _wire->read();
136+
}
137+
_dataIn = array[size - 1];
138+
return true;
139+
}
140+
141+
96142
void PCF8574::toggle(const uint8_t pin)
97143
{
98144
if (pin > 7)

PCF8574.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// FILE: PCF8574.h
44
// AUTHOR: Rob Tillaart
55
// DATE: 02-febr-2013
6-
// VERSION: 0.4.3
6+
// VERSION: 0.4.4
77
// PURPOSE: Arduino library for PCF8574 - 8 channel I2C IO expander
88
// URL: https://github.com/RobTillaart/PCF8574
99
// http://forum.arduino.cc/index.php?topic=184800
@@ -13,15 +13,16 @@
1313
#include "Wire.h"
1414

1515

16-
#define PCF8574_LIB_VERSION (F("0.4.3"))
16+
#define PCF8574_LIB_VERSION (F("0.4.4"))
1717

1818
#ifndef PCF8574_INITIAL_VALUE
19-
#define PCF8574_INITIAL_VALUE 0xFF
19+
#define PCF8574_INITIAL_VALUE 0xFF
2020
#endif
2121

22-
#define PCF8574_OK 0x00
23-
#define PCF8574_PIN_ERROR 0x81
24-
#define PCF8574_I2C_ERROR 0x82
22+
#define PCF8574_OK 0x00
23+
#define PCF8574_PIN_ERROR 0x81
24+
#define PCF8574_I2C_ERROR 0x82
25+
#define PCF8574_BUFFER_LENGTH_ERROR 0x83
2526

2627

2728
class PCF8574
@@ -32,21 +33,25 @@ class PCF8574
3233
bool begin(uint8_t value = PCF8574_INITIAL_VALUE);
3334
bool isConnected();
3435

35-
3636
// note: setting the address corrupt internal buffer values
3737
// a read8() / write8() call updates them.
3838
bool setAddress(const uint8_t deviceAddress);
3939
uint8_t getAddress() const { return _address; }
4040

41+
42+
// read write
4143
uint8_t read8();
4244
uint8_t read(const uint8_t pin);
4345
uint8_t value() const { return _dataIn; };
4446

45-
4647
void write8(const uint8_t value);
4748
void write(const uint8_t pin, const uint8_t value);
4849
uint8_t valueOut() const { return _dataOut; }
4950

51+
// experimental 0.4.4
52+
bool writeArray(uint8_t *array, uint8_t size);
53+
bool readArray(uint8_t *array, uint8_t size);
54+
5055

5156
// added 0.1.07/08 Septillion
5257
uint8_t readButton8() { return PCF8574::readButton8(_buttonMask); }

README.md

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,21 +99,29 @@ before calling **begin()**.
9999
- https://github.com/RobTillaart/MCP23S17 SPI 16 IO lines.
100100
- https://github.com/RobTillaart/PCF8575 I2C 16 IO lines.
101101
- https://github.com/RobTillaart/PCA9671 I2C 16 IO lines. - successor PCF8575
102-
102+
- https://github.com/RobTillaart/TCA9555 I2C 16 IO lines.
103103

104104
8 bit port expanders
105105

106106
- https://github.com/RobTillaart/MCP23008 I2C 8 IO lines.
107107
- https://github.com/RobTillaart/MCP23S08 SPI 8 IO lines.
108108
- https://github.com/RobTillaart/PCF8574 I2C 8 IO lines.
109+
- https://github.com/RobTillaart/TCA9554 I2C 8 IO lines.
110+
111+
Other libs based upon PCF8574
112+
113+
- https://github.com/RobTillaart/I2CKeyPad
114+
- https://github.com/RobTillaart/rotaryDecoder
115+
- https://github.com/RobTillaart/rotaryDecoderSwitch
109116

110117

111118
## I2C
112119

113120

114121
### Performance
115122

116-
Tested on UNO with **PCF8574_performance** showed that the PCF8574 still works at 500 KHz and failed at 600 KHz.
123+
Tested on UNO with **PCF8574_performance** showed that the PCF8574 still works
124+
at 500 kHz and failed at 600 kHz.
117125
These values are outside the specs of the datasheet so they are not recommended.
118126
However when performance is needed you can try to overclock the chip.
119127

@@ -122,7 +130,7 @@ However when performance is needed you can try to overclock the chip.
122130
| 100000 | 236 | 240 | spec datasheet |
123131
| 200000 | 132 | 140 |
124132
| 300000 | 104 | 108 |
125-
| 400000 | 96 | 96 | max advised speed |
133+
| 400000 | 96 | 96 | max speed advised |
126134
| 500000 | 92 | 92 | not recommended |
127135
| 600000 | crash | crash |
128136

@@ -179,6 +187,63 @@ value is HIGH(1) or LOW (0)
179187
- **uint8_t valueOut()** returns the last written data.
180188

181189

190+
### ReadArray and WriteArray
191+
192+
**Experimental (0.4.4)**
193+
194+
Needs testing and verification with scope.
195+
See issue #60 and datasheet, 7.4 Device Functional Modes
196+
197+
These array functions read / write up to 30 bytes in one I2C transaction.
198+
30 bytes is the maximum length of an AVR I2C buffer.
199+
Other lengths are possible by patching the PCF8574.cpp file.
200+
201+
- **bool writeArray(uint8_t \*array, uint8_t size)** writes size bytes in one **blocking** call.
202+
Blocking time depends on the I2C bus speed.
203+
ValueOut() is set to the last byte send.
204+
- **bool readArray(uint8_t \*array, uint8_t size)** reads size bytes in one **blocking** call.
205+
Value() is set to the last byte received.
206+
207+
With **writeArray()** one can implement short pulses on the output pins.
208+
The duration of those pulses are 9 I2C clock pulses.
209+
So the duration of the pulse depends on (1) in how many bytes the pin
210+
is HIGH, (2) the I2C clock speed, and (3) the precision of the I2C clock.
211+
212+
```cpp
213+
uint8_t arr[10] = { 0, 1, 0, 1, 1, 0, 1, 1, 1, 0 };
214+
Wire.setClock(300000);
215+
PCF.writeArray(arr, 10);
216+
Wire.setClock(100000);
217+
```
218+
219+
Indicative pulse duration, depends also on the precision of the I2C clock.
220+
By varying the clock speed one can adjust pulse length.
221+
(e.g. a pulse of 50 us needs about 9000/50 = 180 kHz, with len = 1)
222+
223+
| I2C CLK | len = 1 | len = 2 | len = 3 | notes |
224+
|:---------:|:---------:|:----------:|:----------:|:--------|
225+
| 45 kHz | 200.0 us | 400.0 us | 600.0 us |
226+
| 90 kHz | 100.0 us | 200.0 us | 300.0 us |
227+
| 100 kHz | 90.0 us | 180.0 us | 270.0 us |
228+
| 200 kHz | 45.0 us | 90.0 us | 135.0 us |
229+
| 300 kHz | 30.0 us | 60.0 us | 90.0 us |
230+
| 400 kHz | 22.5 us | 45.0 us | 67.5 us | max speed advised
231+
| 450 kHz | 20.0 us | 40.0 us | 60.0 us | could work.
232+
233+
Note 1: that one writes to all pins so one might need a **read8()** to get the
234+
status of the pins that should not be affected.
235+
236+
Note 2: I2C clocks might not be able to be set to all possible frequencies.
237+
238+
239+
With **readArray()** one can implement a parallel sampling of up to
240+
32 bytes of up to 8 input lines at a sub millisecond range.
241+
This is not enough data for a full logical analyser, however it
242+
might be useful in other applications.
243+
244+
As stated, these function needs testing, so feedback is welcome.
245+
246+
182247
### Button
183248
184249
The **"button"** functions are to be used when you mix input and output on one IC.

docs/pcf8574a_aug_2021.pdf

2.73 MB
Binary file not shown.

examples/PCF8574_Wire1/PCF8574_Wire1.ino

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ void doToggle()
4242
void setup()
4343
{
4444
Serial.begin(115200);
45+
Serial.println();
4546
Serial.println(__FILE__);
46-
Serial.print("PCF8574_LIB_VERSION:\t");
47+
Serial.print("PCF8574_LIB_VERSION: ");
4748
Serial.println(PCF8574_LIB_VERSION);
49+
Serial.println();
4850

4951
Wire1.begin();
5052

examples/PCF8574_Wire2/PCF8574_Wire2.ino

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include "PCF8574.h"
1010

1111
// adjust addresses if needed
12-
PCF8574 PCF(0x39, &Wire2); // Wire2 ==> Teensy
12+
PCF8574 PCF(0x39, &Wire2); // Wire2 ==> Teensy
1313

1414

1515
void doHigh()
@@ -42,9 +42,11 @@ void doToggle()
4242
void setup()
4343
{
4444
Serial.begin(115200);
45+
Serial.println();
4546
Serial.println(__FILE__);
46-
Serial.print("PCF8574_LIB_VERSION:\t");
47+
Serial.print("PCF8574_LIB_VERSION: ");
4748
Serial.println(PCF8574_LIB_VERSION);
49+
Serial.println();
4850

4951
Wire2.begin();
5052

examples/PCF8574_interrupt/PCF8574_interrupt.ino

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ void pcf_irq()
3939
void setup()
4040
{
4141
Serial.begin(115200);
42+
Serial.println();
4243
Serial.println(__FILE__);
4344
Serial.print("PCF8574_LIB_VERSION: ");
4445
Serial.println(PCF8574_LIB_VERSION);
45-
46+
Serial.println();
47+
4648
Wire.begin();
4749
PCF.begin();
4850

0 commit comments

Comments
 (0)