Multiple HT16K33 Devices

please come up with a clear schematic of all your modules and how they are connected to which line!

for example if you have ex2 (@0x21) not behind a TCA it will interfere with any communication you do to sx2(@0x21).

But I don't want to do any guessing any more.
Provide a clear schematic and real pictures how you have connected what.






It is likely that I'll need to move ex2 behind the TCA, as it currently isn't as you'll see by my drawings - I daren't use the term schematic.

Hopefully this gives an idea of what I'm doing, even if it does look like a spiders web.
I am tidying up as I get something working. Or at least that is the theory.

Certain. You can't have any two devices with the same address visible on the bus at the same time. The "bus" means the combination of every device on the main bus (ie. attached direct to the arduino) plus any devices on whichever auxiliary bus is selected by the TCA at that moment. Anything on the main bus is visible 100% of the time, so nothing on the auxiliary buses can have the same address as anything on the main bus. The only way you can have two devices with the same address is when they are on different auxiliary buses, and so are never visible at the same time.

It's probably too late to suggest this now, but for your relays, I may have gone a different direction. I suspect they are only switching low voltages like 12V or 24V? I also imagine the current is not very high either, like a few tens or hundreds of milliamps? If so, these can be switched in much more compact, efficient and cheaper ways.

So.... this is the current state of affairs.
I've now connected the original PCFs via the TCA as well, on number 2.
I tcaselect(2); to the code, as I thought the 2 referred to the number on the TCA, however, that doesn't seem to be the case. I changed the tcaselect(1) to (0) and the switch still worked exactly the same on TCA output 1.

This is my code (abridged for relevance)

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
#include <FastLED.h>
#include <pcf8574.h>

#define NUM_LEDS 30
#define DATA_PIN1 46
#define DATA_PIN2 47

#define TCAADDR 0x71

CRGB leda[NUM_LEDS];
CRGB ledb[NUM_LEDS];

Adafruit_AlphaNum4 alpha4 = Adafruit_AlphaNum4();

LiquidCrystal_I2C lcd(0x27, 20, 4);

Adafruit_PWMServoDriver pwm0 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x41);
Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x42);
// Dunderby Junction
Adafruit_PWMServoDriver pwm3 = Adafruit_PWMServoDriver(0x43);
// lighting
Adafruit_PWMServoDriver pwm4 = Adafruit_PWMServoDriver(0x44);

PCF8574 ex1(0x20);
PCF8574 ex2(0x21);
PCF8574 ex3(0x22);
PCF8574 ex4(0x23);
PCF8574 ex5(0x24);
// via TCA channel
PCF8574 sx1(0x20);
PCF8574 sx2(0x21);

#define SERVOMIN1 265 // Servo 1 min
#define SERVOMAX1 370 //
#define SERVOMIN2 340 // Servo 2
#define SERVOMAX2 440 // 

// points into TCA controlled
#define pushButton1 0

int angle1 = 0;
int angle2 = 0;

int angleStep1 = 5;
int angleStep2 = 5;

int buttonPushed1 = 0;
int buttonPushed2 = 0;

void tcaselect(uint8_t i) {
  if (i > 7) return;

  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

// activate a specific TCA channel, choose a specific PCF instance, read one pin)
int read(int tcaChannel, PCF8574 &pcf, int pcfPin )
{
  tcaselect(tcaChannel);
  int state = digitalRead(pcf, pcfPin);
  if (state == -1) Serial.println("PCF8574 not detected");
  return state;
}

void setup() {
  Serial.begin(9600);

  Wire.begin();

  tcaselect(1);
  tcaselect(2);

  pinMode(sx1, 0, INPUT_PULLUP);
  pinMode(sx1, 1, INPUT_PULLUP);
  pinMode(sx1, 2, INPUT_PULLUP);
  pinMode(sx1, 3, INPUT_PULLUP);
  pinMode(sx1, 4, INPUT_PULLUP);
  pinMode(sx1, 5, INPUT_PULLUP);
  pinMode(sx1, 6, INPUT_PULLUP);
  pinMode(sx1, 7, INPUT_PULLUP);
  
  pinMode(ex1, 0, OUTPUT);
  pinMode(ex1, 1, OUTPUT);
  pinMode(ex1, 2, OUTPUT);
  pinMode(ex1, 3, OUTPUT);
  pinMode(ex1, 4, OUTPUT);
  pinMode(ex1, 5, OUTPUT);
  pinMode(ex1, 6, OUTPUT);
  pinMode(ex1, 7, OUTPUT);

//  lcd.init();
  lcd.clear();
  lcd.setBacklight(32);
  lcd.print("Start up...");

  pwm0.begin();
  pwm1.begin();
  pwm2.begin();

  pwm0.setPWMFreq(60);
  pwm1.setPWMFreq(60);
  pwm2.setPWMFreq(60);


  pwm0.setPWM(0, 0, 265);
  leda[0].setRGB(8, 8, 16);
  ledb[0].setRGB(0, 0, 0);
  digitalWrite(ex1, 0, HIGH);

  pwm0.setPWM(1, 0, 340);
  leda[1].setRGB(8, 8, 16);
  ledb[1].setRGB(0, 0, 0);
  digitalWrite(ex1, 1, HIGH);

  yield();

}

void loop() {
tcaselect(1);
tcaselect(2);

 int state1 = read(1, sx1, 0);
  if (state1 == LOW)
  {
    buttonPushed1 = 1;
  }
  if (buttonPushed1) {
    angle1 = angle1 + angleStep1;
    if (angle1 <= 0 || angle1 >= 180) {
      angleStep1 = -angleStep1;
      buttonPushed1 = 0;
      if (angle1 <= 0) {
        lcd.setCursor(0, 0);
        lcd.print("Point 01 is set     ");
        Serial.println("Point 01 is set");
        leda[0].setRGB(16, 16, 8);
        ledb[0].setRGB(0, 0, 0);
        digitalToggle(ex1, 0);
      }
      else if (angle1 >= 180) {
        lcd.setCursor(0, 0);
        lcd.print("Point 01 is thrown ");
        Serial.println("Point 01 is back");
        leda[0].setRGB(0, 0, 0);
        ledb[0].setRGB(16, 16, 8);
        digitalToggle(ex1, 0);
      }
    }
    pwm0.setPWM(0, 0, angleToPulse(angle1) );
  }
  if (analogRead(sw1) > 510 && analogRead(sw1) < 520 )
  {
    buttonPushed2 = 1;
  }
  if (buttonPushed2) {
    angle2 = angle2 + angleStep2;
    if (angle2 <= 0 || angle2 >= 180) {
      angleStep2 = -angleStep2;
      buttonPushed2 = 0;
      if (angle2 <= 0) {
        lcd.setCursor(0, 0);
        lcd.print("Point 02 is set     ");
        leda[1].setRGB(32, 16, 32);
        ledb[1].setRGB(0, 0, 0);
        digitalToggle(ex1, 1);
      }
      else if (angle2 >= 180) {
        lcd.setCursor(0, 0);
        lcd.print("Point 02 is thrown ");
        leda[1].setRGB(0, 0, 0);
        ledb[1].setRGB(32, 16, 0);
        digitalToggle(ex1, 1);
      }
    }
    pwm0.setPWM(1, 0, angleToPulse2(angle2) );
  }

  if (angle1 > 0 && angle1 < 180) {
    leda[0].setRGB(0, 0, 0);
    ledb[0].setRGB(0, 0, 0);
  }
  if (angle2 > 0 && angle2 < 180) {
    leda[1].setRGB(0, 0, 0);
    ledb[1].setRGB(0, 0, 0);
  }
  FastLED.show();
  delay(30);

int angleToPulse(int ang) {
  int pulse = map(ang, 0, 180, SERVOMIN1, SERVOMAX1);
  return pulse;
}
int angleToPulse2(int ang2) {
  int pulse2 = map(ang2, 0, 180, SERVOMIN2, SERVOMAX2);
  return pulse2;
}

There are many more switches in there, 36 in total, but for keeping the code shorter I'm showing only 2. Number one simply bounces between thrown and set, not locking. Number 2 works fine. If I blank out digitalToggle(ex1,0); on button1, it works and latches. So I know there is a conflict, but I don't know why as I have now connected the original batch of 4 PCFs through the TCA as you can see from the photograph below. Also, the relays no longer work since I have connected it through the TCA, even though I added the additional line of tcaselect(2).

So I'm confused basically - shocking eh?

When you have changed your wiring - please update the schematic so we can follow it.
I should be able to read exactly, which pcf is on which channel

it doesn't make sense to switch to channel 1 in one line - do nothing with the pcf on that channel and than switch to channel 2.

the same story in loop

void loop() {
tcaselect(1);
tcaselect(2);

you activate channel 1 - but you don't do nothing on channel 1
you activate channel 2 - and than you do several things in the rest of the sketch.

I expect, your PCF on channel 1 will not work.

Ahhh, so when I use the tcaselect(#), I'm activating that channel to talk to it??
Like below?

  tcaselect(1);
  pinMode(sx1, 0, INPUT_PULLUP);
  pinMode(sx1, 1, INPUT_PULLUP);
  pinMode(sx1, 2, INPUT_PULLUP);
  pinMode(sx1, 3, INPUT_PULLUP);
  pinMode(sx1, 4, INPUT_PULLUP);
  pinMode(sx1, 5, INPUT_PULLUP);
  pinMode(sx1, 6, INPUT_PULLUP);
  pinMode(sx1, 7, INPUT_PULLUP);
  
  tcaselect(2); 
  pinMode(ex1, 0, OUTPUT);
  pinMode(ex1, 1, OUTPUT);
  pinMode(ex1, 2, OUTPUT);
  pinMode(ex1, 3, OUTPUT);
  pinMode(ex1, 4, OUTPUT);
  pinMode(ex1, 5, OUTPUT);
  pinMode(ex1, 6, OUTPUT);
  pinMode(ex1, 7, OUTPUT);

Then again below?:

  tcaselect(1);
  int state1 = read(1, sx1, 0);
  if (state1 == LOW)
  {
    buttonPushed1 = 1;
  }
  if (buttonPushed1) {
    angle1 = angle1 + angleStep1;
    if (angle1 <= 0 || angle1 >= 180) {
      angleStep1 = -angleStep1;
      buttonPushed1 = 0;
      if (angle1 <= 0) {
        lcd.setCursor(0, 0);
        lcd.print("Point 01 is set     ");
        Serial.println("Point 01 is set");
        leda[0].setRGB(16, 16, 8);
        ledb[0].setRGB(0, 0, 0);
        tcaselect(2);
        digitalToggle(ex1, 0);
      }
      else if (angle1 >= 180) {
        lcd.setCursor(0, 0);
        lcd.print("Point 01 is thrown ");
        Serial.println("Point 01 is back");
        leda[0].setRGB(0, 0, 0);
        ledb[0].setRGB(16, 16, 8);
        tcaselect(2);
        digitalToggle(ex1, 0);
      }
    }
    pwm0.setPWM(0, 0, angleToPulse(angle1) );
  }

Sorry, absolutely right.
I was excited as I felt like I might understand something lol

So, the one for switches is on number 1, and the one for relays is on number 2 now.
I hope that makes sense?

Is it a case, that each time I use tcaselect(#), then that channel is activated until I change it to the next tcaselect(#) number?

if you connect your modules according to the schematic it might / should work.
Does it work?

yes, that's the basic idea of the TCA.

1 Like

Thanks again, I gained some understanding of it all this time... which I don't think I did before.

I just got home and tested it, it works!!!!
I shall change some more over to make sure it continues to work - but thank you very much for the help (again)

fine.

now check again the examples I provided in #75, #77 and write functions which provides you a combined TCA and PCF access so you can't never forget to set the proper TCA channel.

if you have some experience you could also consider a wrapper around the PCF class including the proper TCA channel...

Don't forget to change the function name to tcaselect() instead of TCA9548A() since that's what you are using now.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.