Skip to content

Commit

Permalink
Merge pull request #7 from RobTillaart/arduino-ci
Browse files Browse the repository at this point in the history
* add Arduino-CI
* add unit test
* add examples
* update readme.md
  • Loading branch information
RobTillaart authored Jan 4, 2021
2 parents 42140b0 + 7d17e88 commit 688e807
Show file tree
Hide file tree
Showing 16 changed files with 551 additions and 57 deletions.
7 changes: 7 additions & 0 deletions .arduino-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
- due
- zero
13 changes: 13 additions & 0 deletions .github/workflows/arduino_test_runner.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: Arduino CI

on: [push, pull_request]

jobs:
arduino_ci:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: Arduino-CI/action@master
# Arduino-CI/action@v0.1.1
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020 Rob Tillaart
Copyright (c) 2020-2021 Rob Tillaart

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
71 changes: 43 additions & 28 deletions PCF8575.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,62 +6,76 @@
// PURPOSE: Arduino library for PCF8575 - 16 channel I2C IO expander
// URL: https://github.com/RobTillaart/PCF8575
//
// HISTORY:
// 0.0.1 2020-07-20 initial version
// 0.0.2 2020-07-21 fix reverse(); refactor;
// 0.0.3 2020-07-29 fix #5 reverse() + refactor.
// HISTORY:
// 0.0.1 2020-07-20 initial version
// 0.0.2 2020-07-21 fix reverse(); refactor;
// 0.0.3 2020-07-29 fix #5 reverse() + refactor.
// 0.1.0 2021-01-03 add Arduino-CI + unit tests


#include "PCF8575.h"


PCF8575::PCF8575(const uint8_t deviceAddress)
PCF8575::PCF8575(const uint8_t deviceAddress, TwoWire *wire)
{
_address = deviceAddress;
_dataIn = 0;
_dataOut = 0xFFFF;
_address = deviceAddress;
_wire = wire;
_dataIn = 0;
_dataOut = 0xFFFF;
_buttonMask = 0xFFFF;
_error = PCF8575_OK;
_error = PCF8575_OK;
}

#if defined (ESP8266) || defined(ESP32)
void PCF8575::begin(uint8_t sda, uint8_t scl, uint16_t val)
bool PCF8575::begin(uint8_t dataPin, uint8_t clockPin, uint16_t val)
{
Wire.begin(sda, scl);
_wire = &Wire;
if ((dataPin < 255) && (clockPin < 255))
{
_wire->begin(dataPin, clockPin);
} else {
_wire->begin();
}
if (! isConnected()) return false;
PCF8575::write16(val);
return true;
}
#endif

void PCF8575::begin(uint16_t val)

bool PCF8575::begin(uint16_t val)
{
Wire.begin();
_wire->begin();
if (! isConnected()) return false;
PCF8575::write16(val);
return true;
}

bool PCF8575::isConnected()
{
Wire.beginTransmission(_address);
return Wire.endTransmission() == 0;
_wire->beginTransmission(_address);
return ( _wire->endTransmission() == 0);
}

uint16_t PCF8575::read16()
{
if (Wire.requestFrom(_address, (uint8_t)2) != 2)
if (_wire->requestFrom(_address, (uint8_t)2) != 2)
{
_error = PCF8575_I2C_ERROR;
return _dataIn; // last value
return _dataIn; // last value
}
_dataIn = Wire.read(); // low 8 bits
_dataIn |= (Wire.read() << 8); // high 8 bits
_dataIn = _wire->read(); // low 8 bits
_dataIn |= (_wire->read() << 8); // high 8 bits
return _dataIn;
}

void PCF8575::write16(const uint16_t value)
{
_dataOut = value;
Wire.beginTransmission(_address);
Wire.write(_dataOut & 0xFF); // low 8 bits
Wire.write(_dataOut >> 8); // high 8 bits
_error = Wire.endTransmission();
_wire->beginTransmission(_address);
_wire->write(_dataOut & 0xFF); // low 8 bits
_wire->write(_dataOut >> 8); // high 8 bits
_error = _wire->endTransmission();
}

uint8_t PCF8575::read(const uint8_t pin)
Expand Down Expand Up @@ -105,22 +119,23 @@ void PCF8575::toggle(const uint8_t pin)

void PCF8575::toggleMask(const uint16_t mask)
{
PCF8575::write16(_dataOut ^ mask);
_dataOut ^= mask;
PCF8575::write16(_dataOut);
}

void PCF8575::shiftRight(const uint8_t n)
{
if ((n == 0) || (_dataOut == 0)) return;
if (n > 15) _dataOut = 0; // shift 8++ clears all, valid...
else _dataOut >>= n; // only shift if there are bits set
if (n > 15) _dataOut = 0; // shift 8++ clears all, valid...
if (_dataOut != 0) _dataOut >>= n; // only shift if there are bits set
PCF8575::write16(_dataOut);
}

void PCF8575::shiftLeft(const uint8_t n)
{
if ((n == 0) || (_dataOut == 0)) return;
if (n > 15) _dataOut = 0; // shift 8++ clears all, valid...
else _dataOut <<= n; // only shift if there are bits set
if (n > 15) _dataOut = 0; // shift 8++ clears all, valid...
if (_dataOut != 0) _dataOut <<= n; // only shift if there are bits set
PCF8575::write16(_dataOut);
}

Expand Down
15 changes: 8 additions & 7 deletions PCF8575.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// FILE: PCF8575.h
// AUTHOR: Rob Tillaart
// DATE: 2020-07-20
// VERSION: 0.0.3
// VERSION: 0.1.0
// PURPOSE: Arduino library for PCF8575 - 16 channel I2C IO expander
// URL: https://github.com/RobTillaart/PCF8575
//
Expand All @@ -14,13 +14,12 @@
#include "Arduino.h"
#include "Wire.h"

#define PCF8575_LIB_VERSION "0.0.3"
#define PCF8575_LIB_VERSION (F("0.1.0"))

#ifndef PCF8575_INITIAL_VALUE
#define PCF8575_INITIAL_VALUE 0xFFFF
#endif


#define PCF8575_OK 0x00
#define PCF8575_PIN_ERROR 0x81
#define PCF8575_I2C_ERROR 0x82
Expand All @@ -30,12 +29,12 @@ class PCF8575
{
public:
// deviceAddress base = 0x20 + depends on address bits
explicit PCF8575(const uint8_t deviceAddress);
explicit PCF8575(const uint8_t deviceAddress, TwoWire *wire = &Wire);

#if defined (ESP8266) || defined(ESP32)
void begin(uint8_t sda, uint8_t scl, uint16_t val = PCF8575_INITIAL_VALUE);
bool begin(uint8_t sda, uint8_t scl, uint16_t val = PCF8575_INITIAL_VALUE);
#endif
void begin(uint16_t val = PCF8575_INITIAL_VALUE);
bool begin(uint16_t val = PCF8575_INITIAL_VALUE);
bool isConnected();

uint16_t read16();
Expand All @@ -48,7 +47,7 @@ class PCF8575

// added 0.1.07/08 Septillion
uint16_t readButton16() { return readButton16(_buttonMask); }
uint16_t readButton16(const uint16_t mask = 0xFFFF);
uint16_t readButton16(const uint16_t mask);
uint8_t readButton(const uint8_t pin);
void setButtonMask(uint16_t mask) { _buttonMask = mask; };

Expand All @@ -69,6 +68,8 @@ class PCF8575
uint16_t _dataOut;
uint16_t _buttonMask;
int _error;

TwoWire* _wire;
};

// -- END OF FILE --
53 changes: 43 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@

[![Arduino CI](https://github.com/RobTillaart/PCF8575/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/PCF8575/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/PCF8575.svg?maxAge=3600)](https://github.com/RobTillaart/PCF8575/releases)


# PCF8575

Arduino library for PCF8575 - 16 channel I2C IO expander

## Description

The library is based upon the PCF8574 library https://github.com/RobTillaart/PCF8574
Related to the PCF8574 8 channel IO expander library https://github.com/RobTillaart/PCF8574

The library gives easy control over the 16 pins of the PCF8575 chips.

Expand All @@ -16,42 +22,58 @@ Base address = 0x20 + 0..7 depending on address pins A0..A2
| | | |

So you can connect up to 8 PCF8575 on one I2C bus, giving access
to 8 x 16 = 128 IO lines. Be sure to have a well dimensioned power supply.
to 8 x 16 = 128 IO lines.
To maximize IO lines combine 8 x PCF8575 + 8 x PCF8574A giving
128 + 64 = 192 IO lines.
Be sure to have a well dimensioned power supply.

The library allows to read and write both single pins or 16 pins at once.
Furthermore some additional functions are implemented that are a little more
playfull but still are useful.
Furthermore some additional functions are implemented that are
playfull but useful.

## I2C Clock

Testing showed that the PCF8575 still works at 600 KHz and failed at 800 KHz.
These values are outside the specs of the datasheet so they are not recommendend.
However when performance is neede you can try to overclock the chip.
However when performance is needed you can try to overclock the chip.

## Interface

**PCF8575_INITIAL_VALUE** is a define that can be set compile time or before
the include of "pcf8575.h" to overrule the default value used with the
**begin()** call.

- **PCF8575(deviceAddress)** Constructor with I2C device address as parameter.
### Constructor

- **PCF8575(deviceAddress, TwoWire \*wire = &Wire)** Constructor with I2C device address,
and optional the Wire interface as parameter.
- **begin(val = PCF8575_INITIAL_VALUE)** set the initial value for the pins and masks.
- **begin(sda, scl, val = PCF8575_INITIAL_VALUE)** idem, for the ESP32 where one can choose the I2C pins
What needs to be added in the future is a parameter to choose another Wire interface
as some processors have multiple hardware Wire interfaces.
- **isConnected()** checks if the address is visable on the I2C bus

### Read and Write

- **read16()** reads all 16 pins at once. This one does the actual reading.
- **read(pin)** reads a single pin; pin = 0..15
- **value()** returns the last read inputs again, as this information is buffered
in the class this is faster than reread the pins.
- **write16(value)** writes all 16 pins at once. This one does the actual reading.
- **write(pin, value)** writes a single pin; pin = 0..15; value is HIGH(1) or LOW (0)
- **valueOut()** returns the last written data.
- **valueOut()** returns the last written data.

### Button

- **setButtonMask(mask)**
- **readButton16()**
- **readButton16(mask = 0xFFFF)**
- **readButton16(mask)**
- **readButton(pin)**

### Special

- **toggle(pin)** toggles a single pin
- **toggleMask(mask = 0xFFFF)** toggles a selection of pins,
- **toggleMask(mask)** toggles a selection of pins,
if you want to invert all pins use 0xFFFF (default value)
- **shiftRight(n = 1)** shifts output channels n pins (default 1) pins right (e.g. leds ).
Fills the higher lines with zero's.
Expand All @@ -61,10 +83,21 @@ Fills the lower lines with zero's.
- **rotateLeft(n = 1)** rotates output channels to left, moving highest line to lowest line.
- **reverse()** revers the "bit pattern" of the lines, high to low and vice versa.

### Misc

- **lastError()** returns the last error from the lib. (see .h file)

## Error codes

| name | value | description |
|:------|:----:|:----|
| PCF8574_OK | 0x00 | no error
| PCF8574_PIN_ERROR | 0x81 | pin number out of range |
| PCF8574_I2C_ERROR | 0x82 | I2C communication error |

## Testing

Testing the initial library is done by Colin Mackay (thanks!).

Platforms used for testing include: Nano, ESP32 and Seeed Xiao


Expand Down
9 changes: 9 additions & 0 deletions examples/PCF8575_Wire2/.arduino-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
# example made for Teensy a.o.
#
# - uno
# - leonardo
# - due
# - zero
Loading

0 comments on commit 688e807

Please sign in to comment.