Hello,
I'm struggling with a test card using a PCF8574A chip. The problem is that one input pin seem to be frozen to 0. All the other input pins work as expected. I have tried several chips with the same result.
I have connected a multi-meter (as shown in the KiCad diagram) and it read 0.02 volt all the time.
If I disconnect the wire between pin 4 on the PC817 and pin 6 PCF8574, the output from the PC817 is as expected - high when the heating power is not connected and low when it is connected.
I have used hours debugging this but cannot find anything wrong with the code or the test card so I need some feedback on this
The controller is a Mega2560.
Below is a KiCad diagram of the board. The problem is input pin P6. I also include an image from the datasheet for the PCF8574(A).
The test code for pin 6 on the PCF8574A:
#include "PowerBoard.h"
const uint8_t i2cMuxAddr = 0x70;
Board_tca954xa_i2c_mux mux(i2cMuxAddr, tca9546);
PowerBoard pb(&mux, 0);
void setup()
{
Serial.begin(9600);
// Initialize the unit.
pb.setup();
}
void loop()
{
byte stat;
// Turn on and then off the relays, one at a time.
Serial.println(F("Testing relays"));
for (uint8_t ch = 0; powerBoardChannelCount > ch; ch++) {
Serial.print(ch);
Serial.print(F(":"));
pb.setRelayState((wireUnitNumber)ch, true);
delay(100);
stat = pb.getHeatingWireState((wireUnitNumber)ch);
Serial.print(F(" On state="));
Serial.print(stat ? F("true") : F("false"));
delay(6000);
pb.setRelayState((wireUnitNumber)ch, false);
delay(100);
stat = pb.getHeatingWireState((wireUnitNumber)ch);
Serial.print(F(" Off state="));
Serial.print(stat ? F("true") : F("false"));
delay(2000);
Serial.println();
}
Serial.print(F("Power state: "));
stat = pb.getPowerState();
Serial.println(stat ? F("true") : F("false"));
delay(1000);
Serial.print(F("Fan state: "));
stat = pb.getFanState();
Serial.println(stat ? F("true") : F("false"));
delay(1000);
}
The output from the code when the heating power is connected:
07:26:36.412 -> Testing relays
07:26:36.452 -> 0: On state=true Off state=false
07:26:44.572 -> 1: On state=true Off state=false
07:26:52.773 -> 2: On state=true Off state=false
07:27:00.973 -> Power state: true
07:27:01.973 -> Fan state: false
and when not connected:
07:25:43.132 -> Testing relays
07:25:43.132 -> 0: On state=false Off state=false
07:25:51.292 -> 1: On state=false Off state=false
07:25:59.492 -> 2: On state=false Off state=false
07:26:07.692 -> Power state: true
07:26:08.692 -> Fan state: false
and the Power state is always "true" even if the heating power supply is not turned on (expected "false" if it is not turned on).
PowerBoard.h:
#ifndef POWERBOARD_H_INCLUDED
#define POWERBOARD_H_INCLUDED
#include <PCF8574.h>
#include <Board_tca954xa_i2c_mux.h>
#include <I2Cmux.h>
const uint8_t powerBoardChannelCount = 3;
const uint8_t relay1pin = 0;
const uint8_t relay2pin = 1;
const uint8_t relay3pin = 2;
const uint8_t sense1Pin = 3;
const uint8_t sense2Pin = 4;
const uint8_t sense3Pin = 5;
const uint8_t powerSensePin = 6;
const uint8_t fanSensePin = 7;
const uint8_t unitAddr = 0x38;
typedef enum {
wireUnit1 = 0,
wireUnit2,
wireUnit3
} wireUnitNumber;
class PowerBoard : public I2CMux
{
private:
PCF8574 *m_unit;
public:
PowerBoard(Board_tca954xa_i2c_mux *mux, const uint8_t tcaChannel);
bool setup();
bool setRelayState(const wireUnitNumber n, const bool on);
bool getHeatingWireState(const wireUnitNumber n);
bool getPowerState();
bool getFanState();
};
#endif
PowerBoard.cpp:
#include "PowerBoard.h"
PowerBoard::PowerBoard(Board_tca954xa_i2c_mux *mux, const uint8_t tcaChannel) : I2CMux(mux, tcaChannel)
{
m_unit = new PCF8574(unitAddr);
}
bool PowerBoard::setup()
{
bool stat = tcaSelect();
if (!stat) {
Serial.println(F("tcaSelect failed!"));
return false;
}
// Initialize the unit.
m_unit->begin();
// Configurate output pins.
m_unit->pinMode(relay1pin, OUTPUT);
m_unit->pinMode(relay2pin, OUTPUT);
m_unit->pinMode(relay3pin, OUTPUT);
m_unit->pinMode(sense1Pin, INPUT);
m_unit->pinMode(sense2Pin, INPUT);
m_unit->pinMode(sense3Pin, INPUT);
m_unit->pinMode(powerSensePin, INPUT);
m_unit->pinMode(fanSensePin, INPUT);
return true;
}
bool PowerBoard::setRelayState(const wireUnitNumber wNo, const bool on)
{
tcaSelect();
m_unit->digitalWrite(wNo, on ? HIGH : LOW);
return true;
}
bool PowerBoard::getHeatingWireState(const wireUnitNumber wNo)
{
byte stat;
tcaSelect();
stat = m_unit->digitalRead(wNo + 3);
return (HIGH == stat) ? true : false;
}
bool PowerBoard::getPowerState()
{
byte stat;
tcaSelect();
stat = m_unit->digitalRead(powerSensePin);
return (LOW == stat) ? true : false;
}
bool PowerBoard::getFanState()
{
byte stat;
tcaSelect();
stat = m_unit->digitalRead(fanSensePin);
return (HIGH == stat) ? true : false;
}
The Board_tca854xa_i2c_mux.h:
#ifndef BOARD_TCA954XA_H_INCLUDED
#define BOARD_TCA954XA_H_INCLUDED
#include <Arduino.h>
enum tca_chip_type {
tca9546 = 0,
tca9548
};
const uint8_t tca9546channelCount = 4;
const uint8_t tca9548channelCount = 8;
class Board_tca954xa_i2c_mux
{
private:
uint8_t m_adr;
uint8_t m_curChannel;
uint8_t m_maxChannel;
byte m_status;
public:
Board_tca954xa_i2c_mux(const uint8_t adr, const tca_chip_type chiptype);
virtual ~Board_tca954xa_i2c_mux();
bool tcaSelect(const uint8_t channel);
byte getStatus() {return m_status;}
};
#endif
The Board_tca854xa_i2c_mux.cpp:
#include <Wire.h>
#include <Board_tca954xa_i2c_mux.h>
Board_tca954xa_i2c_mux::Board_tca954xa_i2c_mux(const uint8_t adr, const tca_chip_type chiptype)
{
m_adr = adr;
m_curChannel = tca9546channelCount;
m_status = 0;
switch (chiptype) {
case tca9546:
m_maxChannel = 4;
break;
case tca9548:
m_maxChannel = 8;
break;
}
}
Board_tca954xa_i2c_mux::~Board_tca954xa_i2c_mux()
{
}
bool Board_tca954xa_i2c_mux::tcaSelect(const uint8_t channel)
{
if (channel >= m_maxChannel) {
return false;
}
if (channel == m_curChannel) {
return true;
}
Wire.beginTransmission(m_adr);
Wire.write(1 << channel);
m_status = Wire.endTransmission();
if (0 == m_status) {
m_curChannel = channel;
return true;
}
return false;
}
The I2Cmux.h:
#ifndef I2C_MUX_H_INCLUDED
#define I2C_MUX_H_INCLUDED
#include <Board_tca954xa_i2c_mux.h>
class I2CMux
{
private:
Board_tca954xa_i2c_mux *m_pMux;
uint8_t m_tcaChannel;
protected:
bool m_muxStatus;
public:
I2CMux(Board_tca954xa_i2c_mux *mux, const uint8_t channel);
virtual ~I2CMux();
const bool getStatus() const {return m_muxStatus;}
uint8_t getChannel () const {return m_tcaChannel;}
protected:
bool tcaSelect();
};
#endif
The I2Cmux.cpp:
#include <Arduino.h>
#include <I2Cmux.h>
I2CMux::I2CMux(Board_tca954xa_i2c_mux *mux, const uint8_t channel)
{
m_pMux = mux;
m_tcaChannel = channel;
m_muxStatus = false;
}
I2CMux::~I2CMux()
{
}
bool I2CMux::tcaSelect()
{
if (NULL != m_pMux) {
m_muxStatus = m_pMux->tcaSelect(m_tcaChannel);
}
return m_muxStatus;
}
The library I'm using is:
name=PCF8574 library
version=2.2.2
author=Renzo Mischianti <renzo.mischianti@gmail.com>
maintainer=Renzo Mischianti <renzo.mischianti@gmail.com>
sentence=Arduino/ESP8266 library for PCF8574
paragraph=Use i2c digital expander with Arduino, esp32 and ESP8266. Can read write digital values with only 2 wire. Very simple and encoder support.
category=Sensors
url=https://www.mischianti.org/category/my-libraries/pcf8574/
repository=https://github.com/xreef/PCF8574_library
architectures=*
includes=PCF8574.h
The test card is "emulating" a heating controller and I have made it to be able to develop the code for the controller.