Serial printing is lagging when adding more inputs

Hi there,

I have a code that is reading 15 sensor using 4067 multiplexer.

When I read only 1 sensor or 2 sensor the data printed into the serial seems smooth and fast. the moment I added more input it seems that the data printed to the serial is lagged and not smooth.

can someone see a problem with the code itself? what can cause it and how can I fix it?

#define ENABLED                        true
#define DISABLED                       false

#define NUM_INPUTS                     15

//                                     s0 s1  s2  s3
const byte addressPin[]              = {2, 3, 4, 5};

const byte muxChannel[NUM_INPUTS][4] =
{
  {0, 0, 0, 0}, //channel 0
  {1, 0, 0, 0}, //channel 1
  {0, 1, 0, 0}, //channel 2
  {1, 1, 0, 0}, //channel 3
  {0, 0, 1, 0}, //channel 4
  {1, 0, 1, 0}, //channel 5
  {0, 1, 1, 0}, //channel 6
  {1, 1, 1, 0}, //channel 7
  {0, 0, 0, 1}, //channel 8
  {1, 0, 0, 1}, //channel 9
  {0, 1, 0, 1}, //cahennl 10
  {1, 1, 0, 1}, //channel 11
  {0, 0, 1, 1}, //channel 12
  {1, 0, 1, 1}, //channel 13
  {0, 1, 1, 1}, //channel 14
  //{1, 1, 1, 1}  //channel 15
};

// verify non blocking code//
const byte heartbeatLED       = 13;

//Mux in "SIG" pin
const byte  SIG_pin           = A0;


int sigValue;


boolean sampleFlag            = DISABLED;

byte muxAddress;
byte filter               = 10; //whatever is needed

//sensor is pressed threshold //

const byte pressThreshold = 30;


int muxValue;
int lastValue[NUM_INPUTS];

bool muxIsOn[NUM_INPUTS];
bool muxIsOnPre[NUM_INPUTS];


//timing stuff//
unsigned long heartbeatMillis;
unsigned long readMuxMillis;
unsigned long settlingMillis;
unsigned long readSigMillis;






//********************************************^************************************************
void setup()
{
  Serial.begin(115200);

  pinMode(heartbeatLED, OUTPUT);

  for (byte x = 0; x <= 3; x++)
  {
    pinMode(addressPin[x], OUTPUT);
    digitalWrite(addressPin[x], LOW);
  }

}

void loop()
{
  checkHeartbeatTIMER();

  checkReadMuxTIMER();

  checkSettlingTIMER();




}


//// functions ////
void checkHeartbeatTIMER()
{
  //*********************************                                heartbeat TIMER
  //is it time to toggle the heartbeatLED ?
  if (millis() - heartbeatMillis >= 500ul)
  {
    //restart this TIMER
    heartbeatMillis = millis();

    //toggle the heartbeatLED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

} //END of   checkHeartbeatTIMER()




void checkReadMuxTIMER()
{
  //*********************************                                readMux TIMER
  //is it time to read the next mux analog ?
  if (millis() - readMuxMillis >= 5ul)
  {
    //restart this TIMER
    readMuxMillis = millis();

    //send the new address to the CD4067 mux
    for (byte i = 0; i < 4; i ++)
    {
      digitalWrite(addressPin[i], muxChannel[muxAddress][i]);
    }

    //enable the analog settling TIMER
    sampleFlag = ENABLED;

    //restart the analog settling TIMER
    settlingMillis = millis();
  }

} //END of   checkReadMuxTIMER()



void checkSettlingTIMER()
{
  //*********************************                                settling TIMER
  //if this TIMER is enabled, has this it expired ?
  if (sampleFlag == ENABLED && millis() - settlingMillis >= 5ul)
  {
    //we are now finished with this analog settling TIMER
    sampleFlag = DISABLED;

    //read the stabilized analog
    muxValue = 1023 -  analogRead(SIG_pin);

    //has analog value changed more than the filter amount ?
    if (abs(lastValue[muxAddress] - muxValue) > filter)
    {
      //update to the new value
      lastValue[muxAddress] = muxValue;
      //      /* new feature removed for now
      if (lastValue[muxAddress] >= pressThreshold)     // should mux channel be on?
      {
        if (muxIsOn[muxAddress] == 0)    // was it off? tell us it went on
        {
          muxIsOn[muxAddress] = 1;       // remember it went on
          Serial.print("ch");
          Serial.print(muxAddress);
          Serial.print("on "); // and say so
          Serial.println(muxIsOn[muxAddress]);
        }
      }
      else                               // mux channel should be off
      {
        if (muxIsOn[muxAddress] == 1)    // was it on? tell us it went off
        {
          muxIsOn[muxAddress] = 0;       // remember it is off
          Serial.print("ch");
          Serial.print(muxAddress);
          Serial.print("on "); // and say so
          Serial.println(muxIsOn[muxAddress]);
        }
      }


      Serial.print("value_ch");
      Serial.print(muxAddress);
      Serial.print(" ");
      Serial.println(muxValue);
    }

    //prepare for the new/next mux address
    muxAddress++;

    //have we read all the inputs ?
    if (muxAddress > NUM_INPUTS - 1)
    {
      //back to the first address
      muxAddress = 0;
    }
  }

} //END of   checkSettlingTIMER()


//********************************************^************************************************

here is the schematics:

OK, I have noticed something interesting. When I'm reading 15 sensors - When only pressing 1 or 2 or 3 sensor the data seems to lag. The moment I'm pressing more and more sensors it seems the data is transferred faster.

if I enable only 1 input and reading only one sensor the data is not lagged at all.

here is some videos examples: link

first video:

Enabled 1 input and reading only 1 input via mux. data is smooth and fast

second video:

enabled all 15 inputs but pressing only 1 sensor. data lagging

third video:

enabled all 5 inputs and pressing few sensors. data seems to be less lagging

Do you really need the millis timer there ? Your flag should be enough to tell you to sample (and it could be done probably where you set the flag and get rid of the flag)

so shall I just delete the millis() - settlingMillis >= 5ul

and just write:

if (sampleFlag == ENABLED)

edit:
It seems to be less lagging when only writing:

if (sampleFlag == ENABLED)

why is that?

You might have Conflict with timing

what you suggesting in order to solve it?

please. what shall I do in order to make it work?

with the help of GPT Chat this what I've got:

unsigned long previousMillis = 0;

int s0 = 2;
int s1 = 3;
int s2 = 4;
int s3 = 5;

int sig = A0;
int previousValue[15] = {0};
bool isOn[15] = {false};
int numSensors = 2; // change this variable to set the number of sensors
unsigned long interval = 10;
int threshold = 5; // Change this variable to set the threshold value
int bufferSize = 10; // Change this variable to set the buffer size
int readings[15][10]; // buffer array to store the readings
int index[15]; // counter variable to keep track of how many readings have been taken

byte filter = 5; //whatever is needed

void setup() {
  Serial.begin(115200);
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    readSensors();
  }
}

void readSensors() {
  for (int i = 0; i < numSensors; i++) {
    // Set the multiplexer to select the correct channel
    digitalWrite(s0, (i & 1));
    digitalWrite(s1, (i & 2) >> 1);
    digitalWrite(s2, (i & 4) >> 2);
    digitalWrite(s3, (i & 8) >> 3);
    int sensorValue = 1023 -  analogRead(sig);
    readings[i][index[i] % bufferSize] = sensorValue;
    int sum = 0;
    for (int j = 0; j < bufferSize; j++) {
      sum += readings[i][j];
    }
    int filteredValue = sum / bufferSize;
    index[i]++;
    if (filteredValue != previousValue[i]) {
      if (abs(previousValue[i] - filteredValue) > filter)
      {
        previousValue[i] = filteredValue;
        Serial.print("value_ch");
        Serial.print(i);
        Serial.print(" ");
        Serial.println(filteredValue);
        if (filteredValue > threshold) {
          if (!isOn[i]) {
            isOn[i] = true;
            Serial.print("ch");
            Serial.print(i);
            Serial.print("on ");
            Serial.println(isOn[i]);
          }
        }
        else {
          if (isOn[i]) {
            isOn[i] = false;
            Serial.print("ch");
            Serial.print(i);
            Serial.print("on ");
            Serial.println(isOn[i]);
          }
        }
      }
    }
  }
}

That is the only thing I can see that might be causing a problem. The timers for checkReadMuxTimer and checkSettlingTimer are both testing for 5mS, but the value of millis() for checkReadMuxTImer is stored slightly before the timer for checkSettlingTImer, which can potentially result in repeatedly setting the mux before taking a reading. The compiler will likely optimize the single-input code a bit more, since all the array references can be reduces to fixed addresses, resulting in slightly faster code execution.

so what can I do to avoid that conflict?
eliminate completely checkReadMuxTimer and checkSettlingTimer ?

There is really no need to have a timer in the function that sets the mux channel. Change the function to unconditionally set the mux channel outputs, then only call the function when you need to, either in setup to set the initial channel, or after you change the mux channel number.

Something else that will affect the output rate, you are only printing to Serial when the change in value exceeds the filter amount, so a steady input will result in nothing being printed.

thanks. I have change the code for the following and it seems to work just fine!

#define ENABLED                        true
#define DISABLED                       false

#define NUM_INPUTS                     15

//                                     s0 s1  s2  s3
const byte addressPin[]              = {2, 3, 4, 5};

const byte muxChannel[NUM_INPUTS][4] =
{
  {0, 0, 0, 0}, //channel 0
  {1, 0, 0, 0}, //channel 1
  {0, 1, 0, 0}, //channel 2
  {1, 1, 0, 0}, //channel 3
  {0, 0, 1, 0}, //channel 4
  {1, 0, 1, 0}, //channel 5
  {0, 1, 1, 0}, //channel 6
  {1, 1, 1, 0}, //channel 7
  {0, 0, 0, 1}, //channel 8
  {1, 0, 0, 1}, //channel 9
  {0, 1, 0, 1}, //cahennl 10
  {1, 1, 0, 1}, //channel 11
  {0, 0, 1, 1}, //channel 12
  {1, 0, 1, 1}, //channel 13
  {0, 1, 1, 1}, //channel 14
  //  {1, 1, 1, 1}  //channel 15
};

// verify non blocking code//
const byte heartbeatLED       = 13;

//Mux in "SIG" pin
const byte  SIG_pin           = A0;
int sigValue;
byte muxAddress;
byte filter               = 5; //whatever is needed

//sensor is pressed threshold //
const byte pressThreshold = 5;

int muxValue;
int lastValue[NUM_INPUTS];

bool muxIsOn[NUM_INPUTS];
bool muxIsOnPre[NUM_INPUTS];


//timing stuff//
unsigned long heartbeatMillis;






//********************************************^************************************************
void setup()
{
  Serial.begin(115200);

  pinMode(heartbeatLED, OUTPUT);

  for (byte x = 0; x <= 3; x++)
  {
    pinMode(addressPin[x], OUTPUT);
    digitalWrite(addressPin[x], LOW);
  }

}

void loop()
{
  checkHeartbeatTIMER();

  muxValues();




}


//// functions ////
void checkHeartbeatTIMER()
{
  //*********************************                                heartbeat TIMER
  //is it time to toggle the heartbeatLED ?
  if (millis() - heartbeatMillis >= 500ul)
  {
    //restart this TIMER
    heartbeatMillis = millis();

    //toggle the heartbeatLED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

} //END of   checkHeartbeatTIMER()



void muxValues()
{
  //send the new address to the CD4067 mux
  for (byte i = 0; i < 4; i ++)
  {
    digitalWrite(addressPin[i], muxChannel[muxAddress][i]);
  }
  //read the stabilized analog
  muxValue = 1023 -  analogRead(SIG_pin);

  //has analog value changed more than the filter amount ?
  if (abs(lastValue[muxAddress] - muxValue) > filter)
  {
    //update to the new value
    lastValue[muxAddress] = muxValue;
    //      /* new feature removed for now
    if (lastValue[muxAddress] >= pressThreshold)     // should mux channel be on?
    {
      if (muxIsOn[muxAddress] == 0)    // was it off? tell us it went on
      {
        muxIsOn[muxAddress] = 1;       // remember it went on
        Serial.print("ch");
        Serial.print(muxAddress);
        Serial.print("on "); // and say so
        Serial.println(muxIsOn[muxAddress]);
      }
    }
    else                               // mux channel should be off
    {
      if (muxIsOn[muxAddress] == 1)    // was it on? tell us it went off
      {
        muxIsOn[muxAddress] = 0;       // remember it is off
        Serial.print("ch");
        Serial.print(muxAddress);
        Serial.print("on "); // and say so
        Serial.println(muxIsOn[muxAddress]);
      }
    }


    Serial.print("value_ch");
    Serial.print(muxAddress);
    Serial.print(" ");
    Serial.println(muxValue);
  }

  //prepare for the new/next mux address
  muxAddress++;

  //have we read all the inputs ?
  if (muxAddress > NUM_INPUTS - 1)
  {
    //back to the first address
    muxAddress = 0;
  }
}


Do you see a need for adding a reading interval? or constantly reading the value is just fine?

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    muxValues();
    checkHeartbeatTIMER();
  }
}

How often do you need to update the data ?

the data will be a continuous pressure of a sensor, so I guess it should be updated fast. is there anything wrong without interval of reading at all? in that case the loop is running at the speed of the arduino clock?

Nothing wrong if you can use the data, have unlimited power supply and you don’t have better things to do in the code.

Just because the sensor output update is fast does not mean you have to read it fast.

Read it at a rate that suits your code and application.

Tom... :smiley: :+1: :coffee: :australia:

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