2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
[![Arduino CI](https://github.com/RobTillaart/PCF8574/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
2021-12-23 06:51:26 -05:00
|
|
|
[![Arduino-lint](https://github.com/RobTillaart/PCF8574/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/PCF8574/actions/workflows/arduino-lint.yml)
|
|
|
|
[![JSON check](https://github.com/RobTillaart/PCF8574/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/PCF8574/actions/workflows/jsoncheck.yml)
|
2023-09-23 11:22:26 -04:00
|
|
|
[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/PCF8574.svg)](https://github.com/RobTillaart/PCF8574/issues)
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/PCF8574/blob/master/LICENSE)
|
|
|
|
[![GitHub release](https://img.shields.io/github/release/RobTillaart/PCF8574.svg?maxAge=3600)](https://github.com/RobTillaart/PCF8574/releases)
|
2023-09-23 11:22:26 -04:00
|
|
|
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/PCF8574.svg)](https://registry.platformio.org/libraries/robtillaart/PCF8574)
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2021-12-23 06:51:26 -05:00
|
|
|
|
2020-05-23 07:33:43 -04:00
|
|
|
# PCF8574
|
|
|
|
|
2024-01-08 09:12:06 -05:00
|
|
|
Arduino library for PCF8574 - 8 channel I2C IO expander.
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2021-07-05 04:01:35 -04:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
## Description
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
Related to the PCF8575 16 channel IO expander library https://github.com/RobTillaart/PCF8575
|
2020-05-23 07:33:43 -04:00
|
|
|
|
|
|
|
This library gives easy control over the 8 pins of a PCF8574 and PCF8574A chip.
|
2021-12-23 06:51:26 -05:00
|
|
|
These chips are identical in behaviour although there are two distinct address ranges.
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2023-02-04 10:53:26 -05:00
|
|
|
| type | address-range | notes |
|
|
|
|
|:-----------|:---------------:|:-------------------------:|
|
|
|
|
| PCF8574 | 0x20 to 0x27 | same range as PCF8575 ! |
|
|
|
|
| PCF8574A | 0x38 to 0x3F |
|
|
|
|
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
So you can connect up to 16 PCF8574 on one I2C bus, giving access
|
|
|
|
to 16 x 8 = 128 IO lines. To maximize IO lines combine 8 x PCF8575 + 8 x PCF8574A giving
|
2022-06-18 03:44:19 -04:00
|
|
|
128 + 64 = 192 IO lines.
|
|
|
|
Be sure to have a well dimensioned power supply.
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
The library allows to read and write both single pins or 8 pins at once.
|
2022-06-18 03:44:19 -04:00
|
|
|
Furthermore some additional functions are implemented that are playful and useful.
|
|
|
|
|
|
|
|
|
2024-01-08 09:12:06 -05:00
|
|
|
#### Interrupts intro
|
2022-11-16 06:26:14 -05:00
|
|
|
|
2023-02-04 10:53:26 -05:00
|
|
|
The PCF8574 has an interrupt output line (INT) to notify an MCU that one of the input lines has changed.
|
2022-11-16 06:26:14 -05:00
|
|
|
This can be used to prevent active polling of the PCF8574, which can be more efficient.
|
2023-02-04 10:53:26 -05:00
|
|
|
|
2024-01-08 09:12:06 -05:00
|
|
|
From the datasheet:
|
|
|
|
|
|
|
|
_An interrupt is generated by any rising or falling edge of the port inputs in the input mode.
|
|
|
|
After time, (Tiv), INT is valid. Resetting and reactivating the interrupt circuit is achieved
|
|
|
|
when data on the port is **changed to the original setting** or data is **read from**, or
|
|
|
|
**written to**, the port that generated the interrupt.
|
|
|
|
Resetting occurs in the read mode at the acknowledge bit after the rising edge of the SCL signal,
|
|
|
|
or in the write mode at the acknowledge bit after the high-to-low transition of the SCL signal._
|
|
|
|
|
|
|
|
So there are three scenarios how the INT is reset.
|
|
|
|
|
|
|
|
1. pins revert to original state (lesser known).
|
|
|
|
2. read from the device (well known)
|
|
|
|
3. write to the device (well known)
|
|
|
|
|
|
|
|
This implies that polling the PCF8574 can miss an INT in scenario 1. (see #48)
|
|
|
|
In practice if you have faster polling than your signals changes this would not
|
|
|
|
be a problem. E.g. tactile switches and a polling frequency > 100 Hz will work.
|
|
|
|
|
|
|
|
|
|
|
|
#### Interrupts library
|
|
|
|
|
2023-02-04 10:53:26 -05:00
|
|
|
The library cannot handle the PCF8574 interrupts as it has no code for it.
|
2024-01-08 09:12:06 -05:00
|
|
|
The user should catch the interrupt in his own code to set a flag and can use
|
|
|
|
the library to see which line has changed.
|
2022-11-16 06:26:14 -05:00
|
|
|
|
2024-01-08 09:12:06 -05:00
|
|
|
There are two examples to show how interrupts can be handled:
|
|
|
|
|
|
|
|
- **PCF8574_interrupt.ino**
|
|
|
|
- **PCF8574_rotaryEncoder.ino**
|
|
|
|
|
|
|
|
A more advanced interrupt handler would not set a boolean flag in the interrupt
|
|
|
|
routine but increase a counter (uint8_t or larger).
|
|
|
|
Then it would be possible to see that:
|
|
|
|
|
|
|
|
1. an interrupt occurred. (counter > 0)
|
|
|
|
2. if one or more interrupts are not handled (counter > 1)
|
|
|
|
|
|
|
|
A minimal example that shows catching missed interrupts:
|
|
|
|
|
|
|
|
- **PCF8574_interrupt_advanced.ino**
|
2022-11-16 06:26:14 -05:00
|
|
|
|
|
|
|
|
2023-12-11 03:17:06 -05:00
|
|
|
#### 0.4.0 Breaking change
|
|
|
|
|
|
|
|
Version 0.4.0 introduced a breaking change.
|
|
|
|
You cannot set the pins in **begin()** any more.
|
|
|
|
This reduces the dependency of processor dependent Wire implementations.
|
|
|
|
The user has to call **Wire.begin()** and can optionally set the Wire pins
|
|
|
|
before calling **begin()**.
|
|
|
|
|
|
|
|
|
2023-02-04 10:53:26 -05:00
|
|
|
#### Related
|
|
|
|
|
|
|
|
16 bit port expanders
|
|
|
|
|
|
|
|
- https://github.com/RobTillaart/MCP23017_RT
|
|
|
|
- https://github.com/RobTillaart/MCP23S17
|
|
|
|
- https://github.com/RobTillaart/PCF8575
|
|
|
|
|
|
|
|
|
|
|
|
8 bit port expanders
|
|
|
|
|
|
|
|
- https://github.com/RobTillaart/MCP23008
|
|
|
|
- https://github.com/RobTillaart/MCP23S08
|
|
|
|
- https://github.com/RobTillaart/PCF8574
|
|
|
|
|
|
|
|
|
2022-06-18 03:44:19 -04:00
|
|
|
## I2C Clock
|
|
|
|
|
|
|
|
Tested on UNO with **PCF8574_performance** showed that the PCF8574 still works at 500 KHz and failed at 600 KHz.
|
|
|
|
These values are outside the specs of the datasheet so they are not recommended.
|
|
|
|
However when performance is needed you can try to overclock the chip.
|
|
|
|
|
2023-02-04 10:53:26 -05:00
|
|
|
| clock speed | Read | Write | Notes |
|
|
|
|
|:-----------:|:------:|:-------:|:--------------------|
|
|
|
|
| 100000 | 236 | 240 | spec datasheet |
|
2022-06-18 03:44:19 -04:00
|
|
|
| 200000 | 132 | 140 |
|
|
|
|
| 300000 | 104 | 108 |
|
2023-02-04 10:53:26 -05:00
|
|
|
| 400000 | 96 | 96 | max advised speed |
|
|
|
|
| 500000 | 92 | 92 | not recommended |
|
2022-06-18 03:44:19 -04:00
|
|
|
| 600000 | crash | crash |
|
2020-05-23 07:33:43 -04:00
|
|
|
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
## Interface
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2023-02-04 10:53:26 -05:00
|
|
|
```cpp
|
|
|
|
#include "PCF8574.h"
|
|
|
|
```
|
|
|
|
|
2023-12-11 03:17:06 -05:00
|
|
|
**PCF8574_INITIAL_VALUE** is a define 0xFF that can be set compile time or before
|
2021-12-23 06:51:26 -05:00
|
|
|
the include of "pcf8574.h" to overrule the default value used with the **begin()** call.
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2021-07-05 04:01:35 -04:00
|
|
|
|
2023-12-11 03:17:06 -05:00
|
|
|
#### Constructor
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2023-12-11 03:17:06 -05:00
|
|
|
- **PCF8574(uint8_t deviceAddress = 0x20, TwoWire \*wire = &Wire)** Constructor with optional address, default 0x20,
|
2021-12-23 06:51:26 -05:00
|
|
|
and the optional Wire interface as parameter.
|
2023-12-11 03:17:06 -05:00
|
|
|
- **bool begin(uint8_t value = PCF8574_INITIAL_VALUE)** set the initial value (default 0xFF) for the pins and masks.
|
2021-07-05 04:01:35 -04:00
|
|
|
- **bool isConnected()** checks if the address set in the constructor or by **setAddress()** is visible on the I2C bus.
|
2021-12-23 06:51:26 -05:00
|
|
|
- **bool setAddress(const uint8_t deviceAddress)** sets the device address after construction.
|
|
|
|
Can be used to switch between PCF8574 modules runtime. Note this corrupts internal buffered values,
|
|
|
|
so one might need to call **read8()** and/or **write8()**. Returns true if address can be found on I2C bus.
|
2023-12-11 03:17:06 -05:00
|
|
|
- **uint8_t getAddress()** Returns the device address.
|
2021-07-05 04:01:35 -04:00
|
|
|
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2023-12-11 03:17:06 -05:00
|
|
|
#### Read and Write
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2021-07-05 04:01:35 -04:00
|
|
|
- **uint8_t read8()** reads all 8 pins at once. This one does the actual reading.
|
|
|
|
- **uint8_t read(uint8_t pin)** reads a single pin; pin = 0..7
|
|
|
|
- **uint8_t value()** returns the last read inputs again, as this information is buffered
|
2020-05-23 07:33:43 -04:00
|
|
|
in the class this is faster than reread the pins.
|
2021-12-23 06:51:26 -05:00
|
|
|
- **void write8(const uint8_t value)** writes all 8 pins at once. This one does the actual writing.
|
|
|
|
- **uint8_t write(const uint8_t pin, const uint8_t value)** writes a single pin; pin = 0..7;
|
|
|
|
value is HIGH(1) or LOW (0)
|
2022-06-18 03:44:19 -04:00
|
|
|
- **uint8_t valueOut()** returns the last written data.
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2021-07-05 04:01:35 -04:00
|
|
|
|
2023-12-11 03:17:06 -05:00
|
|
|
#### Button
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2021-12-23 06:51:26 -05:00
|
|
|
The **"button"** functions are to be used when you mix input and output on one IC.
|
|
|
|
It does not change / affect the pins used for output by masking these.
|
|
|
|
Typical usage is to call **setButtonMask()** once in setup as pins do not (often) change
|
|
|
|
during program execution.
|
|
|
|
|
|
|
|
- **void setButtonMask(const uint8_t mask)** sets the (bit) mask which lines are input.
|
|
|
|
- **uint8_t getButtonMask()** returns the set buttonMask.
|
|
|
|
- **uint8_t readButton8()** use the mask set by setButtonMask to select specific input pins.
|
|
|
|
- **uint8_t readButton8(const uint8_t mask)** use a specific mask to select specific input pins.
|
|
|
|
Note this can be a subset of the pins set with **setButtonMask()** if one wants to process not all.
|
|
|
|
- **uint8_t readButton(const uint8_t pin)** read a singe input pin.
|
|
|
|
|
|
|
|
Background - https://github.com/RobTillaart/Arduino/issues/38
|
2021-07-05 04:01:35 -04:00
|
|
|
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2023-12-11 03:17:06 -05:00
|
|
|
#### Special
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2021-07-05 04:01:35 -04:00
|
|
|
- **void toggle(const uint8_t pin)** toggles a single pin
|
|
|
|
- **void toggleMask(const uint8_t mask = 0xFF)** toggles a selection of pins,
|
2021-01-29 06:31:58 -05:00
|
|
|
if you want to invert all pins use 0xFF (default value).
|
2021-12-23 06:51:26 -05:00
|
|
|
- **void shiftRight(const uint8_t n = 1)** shifts output channels n pins (default 1) pins right (e.g. LEDs ).
|
2020-05-23 07:33:43 -04:00
|
|
|
Fills the higher lines with zero's.
|
2021-12-23 06:51:26 -05:00
|
|
|
- **void shiftLeft(const uint8_t n = 1)** shifts output channels n pins (default 1) pins left (e.g. LEDs ).
|
2020-05-23 07:33:43 -04:00
|
|
|
Fills the lower lines with zero's.
|
2021-07-05 04:01:35 -04:00
|
|
|
- **void rotateRight(const uint8_t n = 1)** rotates output channels to right, moving lowest line to highest line.
|
|
|
|
- **void rotateLeft(const uint8_t n = 1)** rotates output channels to left, moving highest line to lowest line.
|
2022-06-18 03:44:19 -04:00
|
|
|
- **void reverse()** reverse the "bit pattern" of the lines, swapping pin 7 with 0, 6 with 1, 5 with 2 etc.
|
|
|
|
|
|
|
|
|
2023-12-11 03:17:06 -05:00
|
|
|
#### Select
|
2022-06-18 03:44:19 -04:00
|
|
|
|
|
|
|
Some convenience wrappers.
|
|
|
|
|
|
|
|
- **void select(const uint8_t pin)** sets a single pin to HIGH, all others are set to LOW.
|
|
|
|
If pin > 7 all pins are set to LOW.
|
|
|
|
Can be used to select one of n devices.
|
|
|
|
- **void selectN(const uint8_t pin)** sets pins 0..pin to HIGH, all others are set to LOW.
|
|
|
|
If pin > 7 all pins are set to LOW.
|
|
|
|
This can typical be used to implement a VU meter.
|
|
|
|
- **void selectNone()** sets all pins to LOW.
|
|
|
|
- **void selectAll()** sets all pins to HIGH.
|
2021-07-05 04:01:35 -04:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2023-12-11 03:17:06 -05:00
|
|
|
#### Miscellaneous
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2022-06-18 03:44:19 -04:00
|
|
|
- **int lastError()** returns the last error from the lib. (see .h file).
|
2021-07-05 04:01:35 -04:00
|
|
|
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
## Error codes
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2023-02-04 10:53:26 -05:00
|
|
|
| name | value | description |
|
|
|
|
|:--------------------|:-------:|:--------------------------|
|
|
|
|
| PCF8574_OK | 0x00 | no error |
|
|
|
|
| PCF8574_PIN_ERROR | 0x81 | pin number out of range |
|
|
|
|
| PCF8574_I2C_ERROR | 0x82 | I2C communication error |
|
2020-05-23 07:33:43 -04:00
|
|
|
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
## Operation
|
2020-05-23 07:33:43 -04:00
|
|
|
|
2022-06-18 03:44:19 -04:00
|
|
|
See examples.
|
2021-12-23 06:51:26 -05:00
|
|
|
|
|
|
|
It is advised to use pull-up or pull-down resistors so the lines have a defined state at startup.
|
|
|
|
|
|
|
|
|
|
|
|
## Future
|
|
|
|
|
2023-02-04 10:53:26 -05:00
|
|
|
#### Must
|
|
|
|
|
2024-01-08 09:12:06 -05:00
|
|
|
- update documentation.
|
|
|
|
- keep in sync with PCF8575 (as far as meaningful)
|
2023-02-04 10:53:26 -05:00
|
|
|
|
|
|
|
#### Should
|
|
|
|
|
|
|
|
|
|
|
|
#### Could
|
|
|
|
|
|
|
|
- move code to .cpp
|
|
|
|
|
|
|
|
#### Wont
|
2022-04-11 04:50:17 -04:00
|
|
|
|
2021-12-23 06:51:26 -05:00
|
|
|
|
2023-09-23 11:22:26 -04:00
|
|
|
## Support
|
|
|
|
|
|
|
|
If you appreciate my libraries, you can support the development and maintenance.
|
|
|
|
Improve the quality of the libraries by providing issues and Pull Requests, or
|
|
|
|
donate through PayPal or GitHub sponsors.
|
|
|
|
|
|
|
|
Thank you,
|
|
|
|
|
2024-01-08 09:12:06 -05:00
|
|
|
|