Blinking Leds with a multiplexer

I'm using an Arduino Mega with a PCF8575 I2C I/O expander for controlling a relay board from switch inputs. I would also like to use a PCF8575 to flash a Led when the relay is off and turn it on solid when the relay is on. I currently have the Leds connected to digital pins and everything works. I would like to install another I/O expander to run the Leds and free up more of my digital pins. I tried installing another I/O expander but can only get the Leds to be on or off. I have attached a sample code with 4 switches . I'm using many more switches, but the code is all the same. The code I attached works, but it used the digital pins. Any help would be appreciated. The PCF8575 library is by Rob Tillart.


//The power switches 1 to turn on/off relays and turn on/flash corresponding Led's

#include <Bounce2.h>
#include "PinFlasher.h"
#include "PCF8575.h"

//Power swithches
byte pwrSw1State = 0;
byte pwrSw2State = 0;
byte pwrSw3State = 0;
byte pwrSw4State = 0;


const byte pwr1Sw = 0; //set up digital pin 0 for reading power control switch 1 for block 1
const byte pwr2Sw = 1; //set up digital pin 1 for reading power control switch 2 for block 2
const byte pwr3Sw = 2; //set up digital pin 2 for reading power control switch 3 for block 3
const byte pwr4Sw = 3; //set up digital pin 3 for reading power control switch 4 for block 4

PinFlasher pwr1Led = 47;
PinFlasher pwr2Led = 49;
PinFlasher pwr3Led = 51;
PinFlasher pwr4Led = 53;

const byte debouncerInterval = 50;

// Initiate the switch debouncer
Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();
Bounce debouncer3 = Bounce();
Bounce debouncer4 = Bounce();


PCF8575 PCF(0x20);  // sets address for shift register for power control relays

void setup() {

  //sets digital pins as inputs for the block power switches
  pinMode(pwr1Sw, INPUT_PULLUP);
  pinMode(pwr2Sw, INPUT_PULLUP);
  pinMode(pwr3Sw, INPUT_PULLUP);
  pinMode(pwr4Sw, INPUT_PULLUP);

  //Block power switches debouncers
  debouncer1.attach(pwr1Sw);
  debouncer1.interval(debouncerInterval);
  debouncer2.attach(pwr2Sw);
  debouncer2.interval(debouncerInterval);
  debouncer3.attach(pwr3Sw);
  debouncer3.interval(debouncerInterval);
  debouncer4.attach(pwr4Sw);
  debouncer4.interval(debouncerInterval);


  PCF.begin(); //initializes shift register for I2C buss for power control relays


  //sets blocks 1 to 4 off
  for (int i = 0; i < 14; i++)
  {
    PCF.write(i, 1);
  }

  //Turns Led's on flashing
  pwr1Led.setOnOff(400);
  pwr2Led.setOnOff(400);
  pwr3Led.setOnOff(400);
  pwr3Led.setOnOff(400);

}

void loop() {

  // Pushbutton Power Switch #1 for block 1
  pwr1Led.update();
  if (debouncer1.update()) {
    if (debouncer1.read() == 0) {
      if (pwrSw1State == 0) {
        PCF.toggle(1); //Turns relay #1 ON
        pwr1Led.setOnOff(PIN_OFF);// Turns Led #1 ON when relay is ON
        pwrSw1State = 1;
      }
      else {
        PCF.toggle(1);// Turns relay #1 OFF
        pwr1Led.setOnOff(400);//Flashes Led #1 when relay is OFF
        pwrSw1State = 0;
      }
    }
  }


  // Pushbutton Power Switch #2 for block 2
  pwr2Led.update();
  if (debouncer2.update()) {
    if (debouncer2.read() == 0) {
      if (pwrSw2State == 0) {
        PCF.toggle(2);//Turns relay #2 ON
        pwr2Led.setOnOff(PIN_OFF);// Turns Led #2 ON when relay is ON
        pwrSw2State = 1;
      }
      else {
        PCF.toggle(2);// Turns relay #2 OFF
        pwr2Led.setOnOff(400);
        pwrSw2State = 0;//Flashes Led #2 when relay is OFF
      }
    }
  }

  // Pushbutton Power Switch #3 for block 3
  pwr3Led.update();
  if (debouncer3.update()) {
    if (debouncer3.read() == 0) {
      if (pwrSw3State == 0) {
        PCF.toggle(3);
        pwr3Led.setOnOff(PIN_OFF);
        pwrSw3State = 1;
      }
      else {
        PCF.toggle(3);
        pwr3Led.setOnOff(400);
        pwrSw3State = 0;
      }
    }
  }

  //  Pushbutton Power Switch #4 for block 4
  pwr4Led.update();
  if (debouncer4.update()) {
    if (debouncer4.read() == 0) {
      if (pwrSw4State == 0) {
        PCF.toggle(4);
        pwr4Led.setOnOff(PIN_OFF);
        pwrSw4State = 1;
      }
      else {
        PCF.toggle(4);
        pwr4Led.setOnOff(400);
        pwrSw4State = 0;
      }
    }
  }


}

//End

You can install a second PCF with a new I2C address. Just create a second instance like this:

PCF8575 PCF2(new_address);

I have done that, but can't get the Leds to blink. I can just turn them on or off.

Show me the circuit.

Keep in mind that PCF can delivery only 20 mA per output.

AFAIK, some modules of this type can work only with LOW input. Doesn't have 5V output.

The PCF will sink 50ma per output up to a max of 100ma total. The leds are using 5ma each s the chip will handle it. I can get the leds to turn on or off but just cant figure out how to make them blink.

Look this topic. There's an example to blink PCF8575 using another library.

The code should work with pcf8575.h too.

I can't post the code from cellphone now.

You are going to have to write a non blocking blink code similar to the SafeString PinFlasher. You will then call the pcf blink function at the same time as pwrNLed.setOnOff(400).

I prefer to use the Adafruit library for the pcf8574. It is available through the library manager.

Adafruit_PCF8574.h

Here's an example to blink an led attached to pin 7 of the expander.

#include <Adafruit_PCF8574.h>

/* Example for 1 output LED that is connected from power to the GPIO expander pin #7
 * Note the LEDs must be connected with the CATHODES to the expander, to SINK current!
 * The PCF8574 cannot SOURCE current!
 */
Adafruit_PCF8574 pcf;

void setup()
{
  while (!Serial) { delay(10); }
  Serial.begin(115200);
  Serial.println("Adafruit PCF8574 LED blink test");

  if (!pcf.begin(0x20, &Wire))
  {
    Serial.println("Couldn't find PCF8574");
    while (1)
      ;
  }
  pcf.pinMode(7, OUTPUT);
}
void loop()
{
  blinkWithOutDelay(400);
}

void blinkWithOutDelay(const long interval)
{
  static byte ledState = LOW;  // ledState used to set the LED
  static unsigned long previousMillis = 0;

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval)
  {
    previousMillis += interval; 

    if (ledState == LOW)
    {
      ledState = HIGH;
    }
    else
    {
      ledState = LOW;
    }
    pcf.digitalWrite(7, ledState);
  }
}

I'm going to have to give this a try.

Here's the code.

I have used this library previously but I found the function digitalRead doesn't work, so I have moved to mxUnifiedPCF8574.

#include "PCF8575.h"

PCF8575 PCF8575;

void setup() {
  Serial.begin(38400);
  Serial.println("I'm alive!");

  PCF8575.begin(0x20);

  for (int i = 0; i < 16; i++) {
    PCF8575.pinMode(i, OUTPUT);
  }
}

void loop() {
  for (int i = 0; i < 16; i++) {
    PCF8575.digitalWrite(i, HIGH);  // Tun on all pins
    delay(200);
  }
  delay(5000);

  for (int i = 0; i < 16; i++) {
    PCF8575.digitalWrite(i, LOW);  // Turn off all pins
    delay(200);
  }
  delay(5000);
}

Here's the code for mxUnifiedPCF8574.

#include "mxUnifiedPCF8574.h"

mxUnifiedPCF8575 PCF8575 = mxUnifiedPCF8575(0x20); // Endereço em hexadecimal = 0x20

void setup()
{
  Serial.begin(38400);
  Serial.println("I'm alive!");

  PCF8575.begin();

  for(int i = 0; i < 16; i++)
  {
    PCF8575.pinMode(i,OUTPUT);
  }
}

void loop()
{
  for(int i = 0; i < 16; i++)
  {
    PCF8575.digitalWrite(i, HIGH); // Tun on all pins
    delay(200);
  }
  delay(5000);
 
  for(int i = 0; i < 16; i++)
  {
    PCF8575.digitalWrite(i, LOW); // Turn off all pins
    delay(200);
  }
  delay(5000);
}

I can get the led to flash, but I need it to toggle from flashing to steady when a momentary push button is pressed. Initial state "led ON" ,button pressed and released "led flashing", button pressed and released "led ON" , button pressed and released "led flashing" .......

I can get the led to flash

Good progress.

Initial state "led ON" ,button pressed and released "led flashing", button pressed and released "led ON" , button pressed and released "led flashing"

Does the led connected to the pcf8574 follow the same behavior as the pin flasher code, or does it replace that code?

After the pin mode of the pcf 8574 pin is set to OUTPUT and the wiring connected so that the pcf 8574 connects the pin to ground so as to sink current then:
"ledON" is just pcf.digitalWrite(pin, LOW);
"ledOFF" is just pcf.digitalWrite(pin, HIGH);

Do you already know how to read the button states and know what behavior you want to trigger?

If you can't figure out how to make the pcf 8574 pin do what you want on the button status, post the code you have with comments placed in the code where you want something you can't figure out.

I have a small library

https://werner.rothschopf.net/microcontroller/202202_tools_led_en.htm

it can be used to blink leds with discrete Arduino pins or on several kinds of port expanders.

See the example
0402_blink_PCF8574.ino

/*
   Blink LED on a PCF8574
   blinks 3 pixel on a PCF8574 port expander

   by noiasca

   2022-12-19 ok
*/

#include <Wire.h>                      // I2C class for the PCF8574 port expander
#include <Noiasca_led.h>               // download from: https://werner.rothschopf.net/microcontroller/202202_tools_led_en.htm
#include <utility/Noiasca_PCF8574.h>   // needed to control PCF8574 

// create a expander object 
PCF8574expander myPCF8574(0x3F);           // create a PCF8574 instance at a specific I2C address

// create your objects:
BlinkPCF8574 blinkLEDA(myPCF8574, 1);      // a blink LED on a port expander
BlinkPCF8574 blinkLEDB(myPCF8574, 2);      // a blink LED on a port expander
BlinkPCF8574 blinkLEDC(myPCF8574, 3);      // a blink LED on a port expander

void setup() {
  Serial.begin(115200);
  Serial.println(F("LED & PCF8574 Test"));

  Wire.begin();

  //blinkLEDA.setOnInterval(250);    // set the on time of a pixel
  //blinkLEDB.on();                  // you can switch on or off a pixel
  //blinkLEDB.setOffInterval(250);   // set the off time of a pixel
}

void loop() {
  blinkLEDA.update();                // call .update() for your object 
  blinkLEDB.update();
  blinkLEDC.update();
}

I can read the button states and get the PCF to turn on and off the leds from a button press. I can also get the leds to flash or remain on solid from a button press using "pin flasher" on a digital output. I just cant get the leds to flash when I replace the digital pins with the PCF8575. I will post the code later with what I'm trying to do. The code I posted , works but the leds are on digital pins.

I was thinking that you could replace the "pin flasher" output code with the "blinkwithoutdelay" code written for the pcf8574 outputs as shown in reply #8.

Am I misunderstanding your situation?

I tried the "blink without delay "and can get the led to flash , but I can't control it with a pushbutton switch.

It sounds like you can move all the led output (on,off,flashing) to pcf 8574 pins.

but I can't control it with a pushbutton switch.

I thought you said that the pushbuttons and the logic was working correctly.

The code I attached works, but it used the digital pins.

Are you trying to move the input push buttons to pcf8574 pins?

I will post the code later with what I'm trying to do.

Yes, Please do this.

No the input pins are staying on the digital inputs. I just want to move the output pins to the PCF8575. I did move 16 outputs to a PCF8575 to operate relays and they work just fine. The problem I'm having is getting an led to be on when the corresponding relay is on and flash the led when the relay is off. I can get the led to be on or off with the relay, but can't get it to flash. When I use a digital pin for the leds, they work just fine.
I can get an led to flash on the PC8575 , but I can't control the flashing with a switch. I'm using the library from Rob Tillaart. I tried the Adafruit library as well.

Here is the code with 1 switch


//This is a single switch of my code. The actual code uses 32 switches and 48 relays
//The power switches are to turn on/off relays and turn on/flash corresponding Led's

#include <Bounce2.h>
#include "PinFlasher.h"
#include "PCF8575.h"


//Power switches
byte pwrSw1State = 0;

const byte pwr1Sw = 1; //set up digital pin 1 for reading power control switch 1 for block 1
const byte debouncerInterval = 50;
PinFlasher pwr1Led = 53;

// Initiate the switch debouncer
Bounce debouncer1 = Bounce();

PCF8575 PCF(0x21);  // sets address for shift register for the power control relays
PCF8575 pcf(0x20);  // sets address for shift register for the leds

void setup() {

  //sets digital pins as inputs for the block power switches
  pinMode(pwr1Sw, INPUT_PULLUP);

  //Block power switches debouncers
  debouncer1.attach(pwr1Sw);
  debouncer1.interval(debouncerInterval);

  PCF.begin(); //initializes shift register for I2C buss for the power control relays
  pcf.begin();//initializes shift register for I2C buss for the leds

  //sets blocks 1 to 16 off
  for (int i = 0; i < 16; i++)
  {
    PCF.write(i, 1); //turns relays off
    pcf.write(i,1); //turns leds off
  }
}

void loop() {


  /*
    This code  below does work ,but it uses a digital pin for the led and a pcf for the relay
    
    // Pushbutton Power Switch #1 for block 1
    pwr1Led.update();
    if (debouncer1.update()) {
      if (debouncer1.read() == 0) {
        if (pwrSw1State == 0) {
          PCF.toggle(1); //Turns relay #1 ON
          pwr1Led.setOnOff(PIN_OFF);// Turns Led #1 ON when relay is ON
          pwrSw1State = 1;
        }
        else {
          PCF.toggle(1);// Turns relay #1 OFF
          pwr1Led.setOnOff(400);//Flashes Led #1 when relay is OFF
          pwrSw1State = 0;
        }
      }
    }

  */

// I would like to move the leds from the digital pins to a pcf with the following code. 

  // Pushbutton Power Switch #1 for block 1
  pwr1Led.update();
  if (debouncer1.update()) {
    if (debouncer1.read() == 0) {
      if (pwrSw1State == 0) {
        PCF.toggle(1); //Turns relay #1 ON
        pcf.write(1,0);// Turns Led #1 ON when relay is ON
        pwrSw1State = 1;
      }
      else {
        PCF.toggle(1);// Turns relay #1 OFF
        
        // I can get the folling line to work
        pcf.write(1,1);//Turns Led #1 OFF  when relay is OFF 
         //I want to replace the following line  with the previous line to flash the led
        pcf.setOnOff(400) // flashes Led#1 when relay is off
        
        pwrSw1State = 0;
      }
    }
  }

}

//End

What's this?

pcf.setOnOff(400)

src/main.cpp:90:13: error: 'class PCF8575' has no member named 'setOnOff'

This codes are working very well to me.

Imgur