Esp32 c3 supermini + 4067 Multiplexer troubles

Hello everybody. To introduce myself, i am Marinko, 38y graphic designer, father, and apsolute newbie in fields of electronics. However, lack of time and knowledge did not stop me to try to bring a project to life.
To keep it short, last 6 months i've put every bit of my time to try and build this. I've came to roadblock which i hope will be skipped with some of your help.

Onto the project!
I would love to make grid of 16 force sensitive resistors (4x4) and read their values via Esp32 c3 supermini. This module is my choice due to its
size and it has just enough pins for project including lcd and rotary encoder.
To get 16 sensors to work together (and use limited number of pins) , ive created flex pcb with exposed copper and velostat over it to make a fsrs. All fsrs are conected to a 10k resistors and i have 100uf capacitor to stabilise readings. For software i use Arduino IDE and so far i've managed to stabilise and get pretty nice readings in serial plotter, but all of my reading lines are moving like one - no matter which sensor is pressed. You can imagine how useless that would be.
I will provide simple code that i am using, as well as connection chart (added some resistors on top of it which helped lower the noise, nothing important for main quest.)
Did i do something terribly wrong in planing, code or it is imposible to read 16 fsrs simultaneously? I would appreciate any help. Thank you.

Code:

// Define MUX control pins
#define S0 2 // GPIO 0
#define S1 10 // GPIO 1
#define S2 21 // GPIO 2
#define S3 4 // GPIO 3

// MUX signal pin connected to the ESP32 analog input
#define MUX_SIGNAL_PIN 0 // GPIO 4

// Define the number of MUX channels (4x4 grid, i.e., 16 FSRs)
#define NUM_CHANNELS 16

// Define array to store FSR readings and initial readings
int fsrValues[NUM_CHANNELS];
int initialReadings[NUM_CHANNELS]; // For calibration

// Function to select MUX channel
void selectMuxChannel(int channel) {
digitalWrite(S0, (channel >> 0) & 0x01); // Set S0
digitalWrite(S1, (channel >> 1) & 0x01); // Set S1
digitalWrite(S2, (channel >> 2) & 0x01); // Set S2
digitalWrite(S3, (channel >> 3) & 0x01); // Set S3
delayMicroseconds(10); // Small delay to allow the MUX to switch channels
}

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

// Initialize MUX control pins
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);

// Initialize the signal pin for analog reading
pinMode(MUX_SIGNAL_PIN, INPUT);

// Record initial readings for each FSR sensor
for (int i = 0; i < NUM_CHANNELS; i++) {
selectMuxChannel(i);
initialReadings <em>= analogRead(MUX_SIGNAL_PIN); // Store initial reading
delay(20); // Allow time for reading
}
}

void loop() {
// Read all FSR values from the MUX and calibrate to start from 0
for (int i = 0; i < NUM_CHANNELS; i++) {
selectMuxChannel(i);
int rawValue = analogRead(MUX_SIGNAL_PIN);
fsrValues <em>= rawValue - initialReadings<em>; // Adjust to start from 0

// Print the calibrated reading for Serial Plotter
Serial.print(fsrValues<em>);
if (i < NUM_CHANNELS - 1) {
Serial.print(","); // Separate values with commas for Serial Plotter
}
}

Serial.println(); // New line for Serial Plotter
delay(100); // Adjust as needed for data refresh rate
}

IMAGES:

Instead of this:

I'd probably have done something like this:

// Function to select MUX channel
void selectMuxChannel(uint8_t channel) {
  digitalWrite(S0, (channel & 0b00000001 ); // Set S0
  digitalWrite(S1, (channel & 0b00000010 ); // Set S1
  digitalWrite(S2, (channel & 0b00000100 ); // Set S2
  digitalWrite(S3, (channel & 0b00001000 ); // Set S3
  delayMicroseconds(10); // Small delay to allow the MUX to switch channels
}

Although, it is probably the same. However, shifting signed numbers is unhealthy.

EDIT

Maybe its just the way you have drawn the diagrams but I would have thought that each of the force sensitive resistors would be connected to its own 10k resistor. The middle point, where the two resistors are connected together, would be connected to a multiplexer input and the other ends connected between the power rails.

EDIT 2
It is becoming clearer. The 16 resistors on the diagram are the 10k resistors you mentioned in the text and the force sensitive resistors are not shown but are intended to be connected between pins 1 and 2 of the connectors J1 through to J16.
I suppose you could have got away with one 10k resistor connected between SIG and ground. The ESP32 has a 3.3 volt voltage reference. An analog pin should not be set with pinMode().
Where is the 100uF capacitor you mentioned? Across the power rails ?

EDIT 3
The pin numbering on the ESP32 Super Mini silk screen is the GPIO pin number so GPIO 0 is marked 0 (at least on the ones I have used) so it is not clear to me what say the 2 refers to on the first line here.

I haven't seen this array subscript notation before. Is it some copy/paste artifact ?

Try this (untested).
Leo..

// 74HC4067 mux board
// 16*FSR between mux inputs and mux ground, 16 pull up resistors to vcc.
// optional 16*100n ceramic cap between mux inputs and mux ground
const byte controlPin[] {0, 1, 2, 3}; // control pins s0-s3
const byte muxCommon = 4;
byte FSRvalue[16]; // holds 16 channels

void setup() {
  Serial.begin(115200);
  pinMode(muxCommon, INPUT_PULLUP);
  for (byte i = 0; i < 4; i++) pinMode(controlPin[i], OUTPUT); // four control pins
}

void loop() {
  // read the FSR
  for (byte i = 0; i < 16; i++) { // 16 channels
    for (byte s = 0; s < 4; s++) digitalWrite (controlPin[s], bitRead(i, s)); // set four control pins
    //FSRvalue[i] = analogRead(muxCommon); // dummy read, if needed
    FSRvalue[i] = analogRead(muxCommon); // 0-15
  }
  // print
  for (byte i = 0; i < 16; i++) {
    Serial.print(FSRvalue[i]);
    Serial.print(",");
  }
  Serial.println();
}

As i've mentioned, maybe i've bit more than i could chew. you are correct. 16 fsrs are connected to resistors and then processed thorough mux. capacitor is across power rail, before mux power supply and fsrs supply.

regarding EDIT 3, i've did not update comments as i've changed location of control pins over esp32 supermini. i've did that in hope that there is noise produced by closeness of pins 0-4. Did not help.

I guess i've skipped steps in my learning process (as usual) and went to pcb design before geting my stuff straight. Now i see it would be better approach to get bigger esp32 board with at least 16 or more gpios ( that support analog reading) and redesign pcb without mux. This is way over my head from the programing side as well as electronic.

but i have 2 more clean, unsoldered flex pcbs- i would love to give it all to make it work! is there a chance that my faulty readings are due to my faulty soldering? :slight_smile:

Thank you so much for providing this code. I've tried it and it gives me lots of noise. I am providing you with screenshot of readings.

Here is how my readings look with this code:

// Define multiplexer control pins and signal pin
const int MUX_PIN_SIG = 4;  // The analog pin on ESP32 connected to the MUX signal pin
const int MUX_PIN_S0 = 0;   // MUX control pins
const int MUX_PIN_S1 = 1;
const int MUX_PIN_S2 = 2;
const int MUX_PIN_S3 = 3;

// Total number of channels in the 16-channel multiplexer
const int NUM_CHANNELS = 16;

// Array to hold readings from each MUX channel
int sensorValues[NUM_CHANNELS];

// Set up multiplexer channel selection (binary control)
void selectMuxChannel(uint8_t channel) {
  digitalWrite(MUX_PIN_S0, (channel & 0b00000001)); // Set S0
  digitalWrite(MUX_PIN_S1, (channel & 0b00000010)); // Set S1
  digitalWrite(MUX_PIN_S2, (channel & 0b00000100)); // Set S2
  digitalWrite(MUX_PIN_S3, (channel & 0b00001000)); // Set S3
  delayMicroseconds(10); // Small delay to allow the MUX to switch channels
}

void setup() {
    Serial.begin(115200);  // Start serial communication

    // Set MUX control pins to output mode
    pinMode(MUX_PIN_S0, OUTPUT);
    pinMode(MUX_PIN_S1, OUTPUT);
    pinMode(MUX_PIN_S2, OUTPUT);
    pinMode(MUX_PIN_S3, OUTPUT);

    Serial.println("Starting MUX Readings...");
}

void loop() {
    // Read each channel on the multiplexer
    for (int channel = 0; channel < NUM_CHANNELS; channel++) {
        selectMuxChannel(channel);          // Select MUX channel
        delay(10);                          // Small delay for stable reading
        sensorValues[channel] = analogRead(MUX_PIN_SIG);  // Read analog value
    }

    // Display all readings in a single line for the Serial Plotter
    for (int i = 0; i < NUM_CHANNELS; i++) {
        Serial.print("Channel ");
        Serial.print(i);
        Serial.print(": ");
        Serial.print(sensorValues[i]);
        Serial.print("\t");  // Tab space for better alignment
    }
    Serial.println();  // Newline for next set of readings

    delay(50);  // Adjust delay as needed for smoother serial plotting
}

@iamloudness210

I would remove the delay(10) and use that time to average multiple analog reads. This should stabilize your readings a bit.

Just replace the snippet

    // Read each channel on the multiplexer
    for (int channel = 0; channel < NUM_CHANNELS; channel++) 
    {
        selectMuxChannel(channel);          // Select MUX channel

        uint32_t sum = 0;
        for (int i = 0; i < 8; i++)
        {
          sum += analogRead(MUX_PIN_SIG);  // Read analog value
        }
        sensorValues[channel] = sum / 8;
    }

Would add one selectMuxChannel(0) call in setup() to have a defined start channel.

void setup() {
    Serial.begin(115200);  // Start serial communication

    // Set MUX control pins to output mode
    pinMode(MUX_PIN_S0, OUTPUT);
    pinMode(MUX_PIN_S1, OUTPUT);
    pinMode(MUX_PIN_S2, OUTPUT);
    pinMode(MUX_PIN_S3, OUTPUT);

    selectMuxChannel(0);  //  to have an explicit defined start channel

    Serial.println("Starting MUX Readings...");
}

Thanks for code! doesn't do much at the moment for me. I will inspect and update here if i get somewhere!

I guess because of the faster code.
Did you try with uncommented dummy read.
Try that, and a small delay between the dummy read and the real read.
16 10k resistors and capacitors on the FSR might also help.
Leo..

Your code looks like it could do it, but somehow it doesnt. Code is probably not an issue, as I saw video on youtube where guy connected 64 analog inputs through 4 mux with very small board - and it worked. He provides code for arduino uno ( i have leonardo by the side, it did not work)
his code is here:
https://www.notesandvolts.com/2016/07/arduino-midi-controller-multiplexers.html

I will test my connections with line continuity buzzer or whatever is called.
Should Signal pins from mux give sound if connections are good, or mux should be powered? it may be a dumb question.

EDIT
Holly mother of bad soldering.
Lets start from the beginning.