I want to chain 16 CD74HC4067 MUX together and have one master CD74HC4067 MUX so that I can get a total of 256 analog inputs. I've read that this can be done, however, I'm finding it difficult to read the analog values from the child MUX.
To explain the setup a bit, the master MUX has a SIG connected to A0 of the Arduino board and 4 communication lines connected to pins 3 to 6. I then connected the C0 of the master MUX to the SIG pin of the child MUX. When I change the master MUX channel to C0, I can read the C0 for the child MUX, however, I'm unable to read the read of the channels in the child MUX.
I've tried to use ChatGPT to help but I'm at a loss. Would someone be able to guide me in the right direction, please?
This is the code I'm currently using but I know it's not correct.
const int mainMuxSig = A0; // Main MUX SIG connected to A0
const int mainMuxS0 = 3;
const int mainMuxS1 = 4;
const int mainMuxS2 = 5;
const int mainMuxS3 = 6;
const int numMainMuxes = 16;
const int channelsPerMainMux = 16;
const int totalChannels = numMainMuxes * channelsPerMainMux;
void setup() {
pinMode(mainMuxSig, OUTPUT);
pinMode(mainMuxS0, OUTPUT);
pinMode(mainMuxS1, OUTPUT);
pinMode(mainMuxS2, OUTPUT);
pinMode(mainMuxS3, OUTPUT);
Serial.begin(9600);
}
void loop() {
for (int mainMuxIndex = 0; mainMuxIndex < numMainMuxes; mainMuxIndex++) {
// Select the current main MUX
selectMainMux(mainMuxIndex);
// Delay to allow the main MUX to settle (adjust as needed)
delay(10);
// Read values from all channels of the current main MUX
for (int channelIndex = 0; channelIndex < channelsPerMainMux; channelIndex++) {
// Set the address lines of the main MUX to select the current channel
// selectChannelInMainMux(channelIndex);
digitalWrite(mainMuxS0, (channelIndex & B0001) ? HIGH : LOW);
digitalWrite(mainMuxS1, (channelIndex & B0010) ? HIGH : LOW);
digitalWrite(mainMuxS2, (channelIndex & B0100) ? HIGH : LOW);
digitalWrite(mainMuxS3, (channelIndex & B1000) ? HIGH : LOW);
// Delay to allow the main MUX to settle (adjust as needed)
delay(10);
// Read analog value from the selected input channel
int value = analogRead(mainMuxSig);
// Calculate the overall channel number (across all main MUXes)
int channelNumber = mainMuxIndex * channelsPerMainMux + channelIndex;
if (value > 1) {
// Print channel and value for debugging
Serial.print("Channel: C");
Serial.print(channelNumber);
Serial.print(" | Value: ");
Serial.println(value);
}
// Optional delay between channel readings
delay(100);
}
}
}
void selectMainMux(int muxIndex) {
// Set address lines (S0-S3) of the main MUX to select the desired main MUX
digitalWrite(mainMuxS0, (muxIndex & B0001) ? HIGH : LOW);
digitalWrite(mainMuxS1, (muxIndex & B0010) ? HIGH : LOW);
digitalWrite(mainMuxS2, (muxIndex & B0100) ? HIGH : LOW);
digitalWrite(mainMuxS3, (muxIndex & B1000) ? HIGH : LOW);
}
void selectChannelInMainMux(int channelIndex) {
// Set the address lines (S0-S3) of the main MUX to select the desired channel within the main MUX
digitalWrite(mainMuxS0, (channelIndex & B0001) ? HIGH : LOW);
digitalWrite(mainMuxS1, (channelIndex & B0010) ? HIGH : LOW);
digitalWrite(mainMuxS2, (channelIndex & B0100) ? HIGH : LOW);
digitalWrite(mainMuxS3, (channelIndex & B1000) ? HIGH : LOW);
}
Have ChatGPT forward a copy of the schematic so you can post it showing exactly how you have wired it. Be sure it shows all connections, power sources etc. Also it will take the Arduino time to read all of the ports, and you will have to allow time for the A/D circuits etc to settle each time you change channels.
Thanks @flashko and @gilshultz for your answers. I was trying to use the same communication line for both the main MUX and the child MUX which of course would never work. I now have separate communication lines and worked like a charm.
@gilshultz You mentioned that I would need to let it settle each time I change a channel. Why is that, please, and what happens if I don't let it settle?
Below is the working code in case it's of help to anyone.
const int mainMuxSigPin = A0; // Main MUX SIG pin connected to A0
const int mainMuxS0Pin = 13; // Main MUX S0 pin
const int mainMuxS1Pin = 12; // Main MUX S1 pin
const int mainMuxS2Pin = 11; // Main MUX S2 pin
const int mainMuxS3Pin = 10; // Main MUX S3 pin
const int numChildMuxes = 16; // Total number of child MUXes
const int childMuxS0Pin = 3; // Shared S0 pin for child MUXes
const int childMuxS1Pin = 4; // Shared S1 pin for child MUXes
const int childMuxS2Pin = 5; // Shared S2 pin for child MUXes
const int childMuxS3Pin = 6; // Shared S3 pin for child MUXes
const int channelsPerChildMux = 16;
const int totalChannels = numChildMuxes * channelsPerChildMux;
void setup() {
pinMode(mainMuxSigPin, OUTPUT); // Main MUX SIG pin as input (for analog read)
pinMode(mainMuxS0Pin, OUTPUT); // Main MUX S0 pin as output for address line
pinMode(mainMuxS1Pin, OUTPUT); // Main MUX S1 pin as output for address line
pinMode(mainMuxS2Pin, OUTPUT); // Main MUX S2 pin as output for address line
pinMode(mainMuxS3Pin, OUTPUT); // Main MUX S3 pin as output for address line
pinMode(childMuxS0Pin, OUTPUT); // Shared S0 pin for child MUXes as output for address line
pinMode(childMuxS1Pin, OUTPUT); // Shared S1 pin for child MUXes as output for address line
pinMode(childMuxS2Pin, OUTPUT); // Shared S2 pin for child MUXes as output for address line
pinMode(childMuxS3Pin, OUTPUT); // Shared S3 pin for child MUXes as output for address line
Serial.begin(9600);
}
void loop() {
for (int childMuxIndex = 0; childMuxIndex < numChildMuxes; childMuxIndex++) {
// Select the current child MUX
setAddressLines(mainMuxS0Pin, mainMuxS1Pin, mainMuxS2Pin, mainMuxS3Pin, childMuxIndex);
// Delay to allow the child MUX to settle (adjust as needed)
// delay(10);
for (int channel = 0; channel < channelsPerChildMux; channel++) {
setAddressLines(childMuxS0Pin, childMuxS1Pin, childMuxS2Pin, childMuxS3Pin, channel);
// Read analog value from the selected input channel of the child MUX
int value = analogRead(mainMuxSigPin);
if (value > 0) {
Serial.println(value);
}
// Optional delay between channel readings
// delay(100);
}
}
delay(100);
}
void setAddressLines(int s0Pin, int s1Pin, int s2Pin, int s3Pin, int muxIndex) {
// Set the address lines (S0-S3) based on the muxIndex using bit manipulation
digitalWrite(s0Pin, (muxIndex & B0001) ? HIGH : LOW);
digitalWrite(s1Pin, (muxIndex & B0010) ? HIGH : LOW);
digitalWrite(s2Pin, (muxIndex & B0100) ? HIGH : LOW);
digitalWrite(s3Pin, (muxIndex & B1000) ? HIGH : LOW);
}
That is inherent in the processor. Because of the internal A/D it has its MUX to switch and its internal nodes need to match your input signal, this is not instant. Check this link for more information: analogRead() - Arduino Reference If you read to fast you will get something but it will be undefined. The value of the previous channel will also affect this.