4067 Multiplexer code question

Thanks you very much for this help.

You said no time to do anything. Is it because more then 100ms has passed before we got the chance to read the second and third iteration? In other circumstances such as higher value then 100ms could work?

the other question I have is regarding the filter of the value we read each time.
the filter is defined as a global variable at the beginning of the code:

byte filter               = 10; //whatever is needed

it seems that in the above function you made void otherAnalogInputs() the filter not doing is job, meaning I get printed numbers that are also lower by the filter (which is equal to 10)

for example I got this printing:

Screen Shot 2022-08-22 at 20.42.31

value at channel 6 is: 42

then it printed:

value at channel 6 is: 43

it should not print either we got a number that is less then 32 or bigger then 52 isn't it?

I said "not time to do anything"… the timing variable readSigMilkis was updated at the first iteration, the second and third iterations happen very extremely soon thereafter, effectively instantly, certainly nowhere near what would be required for the timing logic to allow the if statement to run its block of code!

So no, a longer value woukd not solve the logical problem.

As for what your filter does and doesn't do here

    //has analog value changed more than the filter amount ?
    if (abs(lastValue_other[i] - sigValue) > filter) {
... 
... 
    }

I did not alter that, or it was not my intent to do. I'll look at it L8R, sitting under an umbrella just now watching the rain and drinking.

Ah, retirement.

OK, I think maybe the filter value is being applied to the raw readings, and I bet that if you looked at the raw readings, you woukd see that the mapping is changing the effective size of the filter. A guess for now.

a7

The filter method is applied the same way to the main multiplexer code checkSettlingTIMER() in which the filter seems to work also on the mapping values.

this is not happening in the otherAnalogInputs() function :confused:

edit: the filter indeed those it job to filter out the input data in both function.. you were (obviously) right

Everything is obvious, even intuitively so, sooner later. :expressionless:

I didna notice before, but now I see you have duplicated some code, code significant enough to merit placing it in one place for all to use. The below compiles, but I cannot test it. It's not meant to run at all, just to illustrate the point.

# define N_MUX_INPUTS 5
# define N_OTHER_INPUTS 3
# define N_INPUTS	(N_MUX_INPUTS + N_OTHER_INPUTS)

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

//Others analog pin inputs
const byte otherSIG_pin[N_OTHER_INPUTS] = {A1, A2, A3};

// all  previous values
int lastValue[N_INPUTS];

// all mapping values  ch0  ch1 ch2   ch3  ch4   extras   0    1    2
const int lowEnd[] = { -70,  10, 500,   0,   0,         -70,  10, 500};
const int highEnd[] = { 6, 100, -50, 1000, 10,         236, 100, -50};

byte filter  = 10; //whatever is needed - could be an array if channels need personalized filter values

void demo()
{
  int muxValue, sigValue;
  unsigned char indexI;   // i is a bad name for a variable

  // in two places, decide how to call the filterMap function

  // 1. when you use the multiplxer - indexI ranges from 0 to N_MUX_INPUTS - 1:

  muxValue = analogRead(SIG_pin);
  muxValue = filterMap(indexI, muxValue);

  // ...

  // 2. when you are going direct - indexI runs from 0 to N_OTHER_INPUTS - 1:

  sigValue = analogRead(otherSIG_pin[indexI]);
  sigValue = filterMap(indexI + N_MUX_INPUTS, sigValue); // skip over multiplexed entries
}

// so all your map and filter logic is expressed once, modified in only one place, like

// input index runs from 0 to N_INPUTS - 1 as hybrid channel number
// filters and maps a raw value and returns that new value

int filterMap(unsigned char inputIndex, int rawValue)
{
  int filteredValue;
  //has analog value changed more than the filter amount ?
  if (abs(lastValue[inputIndex] - rawValue) > filter)
  {
    //update to the new value
    lastValue[inputIndex] = rawValue;

    //log the new value of the selected analog
    filteredValue = map(rawValue, 0, 1023, lowEnd[inputIndex], highEnd[inputIndex]);

    Serial.print("Value at channel ");
    Serial.print(inputIndex);
    Serial.print(" is : ");
    Serial.println(filteredValue);
  }

  return filteredValue;
}

void setup() {
}

void loop() {
}


Essentially I rolled up the arrays that were used in the same way and made them one where they were two. And wrote demonstration code showing how the one function is to be called depending on whether you dealing with the multiplexer or the direct analog pins,

I'll just have to ask you to read this code caefully. You will see that I have tinkered a bit to strongarm all your uses of filter and map into one place.

When there is duplicate code (or triplicate and believe me, we see cut and paste code where the essentially identical doxen lines of code is cut/paste/edited 10s of times) it means a world of pain fixing an error you discover, as a writer, and as readers, it leaves us to wonder if the code is indeed identical or might have some things that justify their (almost) identity.

K&R put it best:

...the reader doesn't have to check painstakingly that two long [code sequences] are indeed the same, or wonder why they're not.

They were talking about expressions in the context of using assignment operators, but the idea fits for lines of code.

a7

I tried to add another array of boolean to store whenever an analog sensor is pressed, if the value of that sensor is above 5 then the array should store 1. If it is less then 5 (not pressed) the array should store 1.

here is the function with that change:

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

    //read the stabilized analog
    muxValue = 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;
      {
      if(lastValue[muxAddress] >=5)
      {
        muxIsOn[muxAddress] = 1;
        if(muxIsOn[muxAddress] != muxIsOnPre[muxAddress])
        {
        Serial.print("channel ");
        Serial.print(muxAddress);
        Serial.print(" Is: ");
        Serial.println(muxIsOn[muxAddress]);
        muxIsOnPre[muxAddress] = muxIsOn[muxAddress];
        }
      }
      else
      {
        muxIsOn[muxAddress] = 0;
        if(muxIsOn[muxAddress] != muxIsOnPre[muxAddress])
         Serial.print("channel ");
        Serial.print(muxAddress);
        Serial.print(" Is: ");
        Serial.println(muxIsOn[muxAddress]);
        muxIsOnPre[muxAddress] = muxIsOn[muxAddress];
      }

      //log the new value of the selected analog
      muxValue = map(muxValue, 0, 1023, lowEnd[muxAddress], highEnd[muxAddress]);

       Serial.print("Value at channel ");
       Serial.print(muxAddress);
       Serial.print(" is : ");
       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()

it is not working as intended. Can someone spot my mistake?

Full updated code is here:

#define ENABLED                        true
#define DISABLED                       false

#define NUM_INPUTS                     2

//                                     s0 s1  s2  s3
const byte addressPin[]              = {8, 9, 10, 11};

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
};

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

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

boolean sampleFlag            = DISABLED;

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

int muxValue;
int lastValue[NUM_INPUTS];


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

//mapping values      ch0  ch1 ch2  ch3 ch4
const int lowEnd[] = {0, 10, 500, 0, 0};
const int highEnd[] = {1023, 100, -50, 1000, 1023};

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

//********************************************^************************************************
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 >= 100ul)
  {
    //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 >= 10ul)
  {
    //we are now finished with this analog settling TIMER
    sampleFlag = DISABLED;

    //read the stabilized analog
    muxValue = 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;
      {
      if(lastValue[muxAddress] >=5)
      {
        muxIsOn[muxAddress] = 1;
        if(muxIsOn[muxAddress] != muxIsOnPre[muxAddress])
        {
        Serial.print("channel ");
        Serial.print(muxAddress);
        Serial.print(" Is: ");
        Serial.println(muxIsOn[muxAddress]);
        muxIsOnPre[muxAddress] = muxIsOn[muxAddress];
        }
      }
      else
      {
        muxIsOn[muxAddress] = 0;
        if(muxIsOn[muxAddress] != muxIsOnPre[muxAddress])
         Serial.print("channel ");
        Serial.print(muxAddress);
        Serial.print(" Is: ");
        Serial.println(muxIsOn[muxAddress]);
        muxIsOnPre[muxAddress] = muxIsOn[muxAddress];
      }

      //log the new value of the selected analog
      muxValue = map(muxValue, 0, 1023, lowEnd[muxAddress], highEnd[muxAddress]);

       Serial.print("Value at channel ");
       Serial.print(muxAddress);
       Serial.print(" is : ");
       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()


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

The opening brace in the middle here is odd and most likely superfluous or unmatched.

Auto Format your code and see if you can eliminate that brace or pair of braces.

No idea if that is any problem. Just a distraction.

Does the code compile? Do you ever see the statements that should issue when the value goes above or below 5?

Best I can do with the little window.

Also, that logic only gets executed within the

      if (abs(lastValue[muxAddress] - muxValue) > filter)

protectd section… why not move it out on its own and give it a full crack at the analog value, not just when it has passed the threshold filter reset?

a7

Yes, the code compile.

What do you mean by that?

He is referring to these statements...

obviously there is an issue with those statement (and in general with my latest update trying to store 0 or 1 if a sensor is pressed)

I just can't understand the issue

What is the issue?

for the example now I have only two pressure sensors.
When I first run the code and pressing the first sensor this is what is printed to the Serial

Screen Shot 2022-08-30 at 19.46.30

When I release the sensor I expect it to print "channel 0 Is: 0" and "Value at channel 0 is : 'any number less then 802'"

there is no printing what's so ever when pressing sensor 1.
Only when I press sensor 2 I get a new reading. My serial then looks like this:

Screen Shot 2022-08-30 at 19.49.28

from that picture I can see that only after I press sensor 2 I get the new reading at channel 1 (sensor 2) and only after that I got a print saying "channel 0 Is: 0" meaning the sensor is not pressed. That reading should happen immediately after releasing the sensor in the first screenshot and not only after pressing the other sensor.

So if To be more precise what I would like it to do is the following:
When pressing sensor 1 it should print "channel 0 Is: 1" (indicate the sensor is pressed)
and imidiatly after that as long the sensor is pressed to print changing values of that sensor "Value at channel 0 is : 802"
"Value at channel 0 is : 756"
"Value at channel 0 is : 744"
etc etc

when the sensor is released it should print " "channel 0 Is: 0" indicated there is no pressed.

This should be apply to all sensor in a non blocking manner meaning multiple sensors could be pressed at the same time

Scrolling back I don't see that you ever posted code that works, and works to your satisfaction before you are adding a new feature, that is printing

Channel 0 is 1

channel 0 is 0

Can you point it out if I am missing the full code before the new feature?

Or post it if you haven't?

I hope that it was working perfectly before you are adding a new feature. There is enough to be confusing about the full code with new feature what isnt working yet.

Still looking through a little window. L8R I can take a closer.

And I agree with myself that the new logic should have its own chance to print or not independent of whether the filter condition is met.

But first the next to latest code, if it is doing everything right w/o the new latest feature added.

a7

I did not post a code that works because I did not manage to make one.
The idea before the new feature that is printing
"
Channel 0 is 1
channel 0 is 0

"
was to add another analog inputs to read from apart of the Maximus 16 inputs of the Mux. So be able to read 19 analog sensors in a non blocking manner.

As I did not manage to do so, I thought that for the moment is more important for me to store fore each input the value 0 or 1 (press or not press) rather then have more then 16 inputs.

As I said above - I did not manage making it work as perfect as I wish

OK, I don't think there is anyone who would find this a good path. It doesn't make fixing the new feature impossible, but it means we looking all over for what is wrong with your code.

If you can't/don't wanna take a step by step approach where progress builds on previous success, please at least say with as much detail as possible why the sketch is unsatisfactory with respect to the old feature set.

The new feature seems like it would be easy to add, and it looks like a plausible stab you have taken, so.

It is actually too hot on the beach to do any drinking at all. :frowning:

a7

Well, it doesn't.

Not until you fix this line:

  digitalWrite(addressPin[i], muxChannel[muxAddress][I]);

with plausible guess...

Should we assume that is the only thing different to the code you are working with?

What is the roll of the settling timer? What do you think is "settling" between, it look like, setting the multiplexer address pins and the analogRead() of the mux output?

a7

Imma guess you have some missing braces - maybe they are in that code that compiles.

In this section:

          if (muxIsOn[muxAddress] != muxIsOnPre[muxAddress])
            Serial.print("channel ");
          Serial.print(muxAddress);
          Serial.print(" Is: ");
          Serial.println(muxIsOn[muxAddress]);
          muxIsOnPre[muxAddress] = muxIsOn[muxAddress];

Anyway, your logic for the whole ON / OFF section is needlessly complex. I am reasonably confidant that the below will perform the identical function. Well, identical except it will work.
      if (lastValue[muxAddress] >= 5)     // 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("channel ");
          Serial.print(muxAddress);
          Serial.println(" Is: ON (1)"); // and say so
        }
      }
      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("channel ");
          Serial.print(muxAddress);
          Serial.print(" Is: OFF (0)");  // and say so
        }
      }


HTH and I blame my headache on the Sun, not you. :expressionless:

a7

True indeed

Same problem I stated in my post #71 is happening.

I'm expect to see a continue flow of numbers when pressing the sensor and only at the first press to see "channel 0 Is: ON (1)" and when releasing the sensor to see: "channel 0 Is: OFF (0)"

right now' something' which I don't know why but I'm assuming it is in the new feature is blocking the code and therefore not printing continue data from the sensor rather stuck at only printing the first value of pressing.

Edit: I fixed original errors in the code I used to make the sketch posted below.

Edit: Also, you never answered, or I missed your answer : What is the roll of the settling timer? What do you think is "settling" between, it look like, setting the multiplexer address pins and the analogRead () of the mux output?

The entire "new feature" section can be commented out easily. Use /* before and */ after the big if statement that is the new feature.

Then see if your code does what you want, which you have asserted is not the case, so fix it or tell us more about what, with the new feature removed, the code at that point wasn't working.

I do not see a way where adding the new feature would break the old code. As you have said, the old code was already broken, so you need to say more about that and fix it.

#define ENABLED                        true
#define DISABLED                       false

#define NUM_INPUTS                     2

//                                     s0 s1  s2  s3
const byte addressPin[]              = {8, 9, 10, 11};

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
};

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

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

boolean sampleFlag            = DISABLED;

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

int muxValue;
int lastValue[NUM_INPUTS];


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

//mapping values      ch0  ch1 ch2  ch3 ch4
const int lowEnd[] = {0, 10, 500, 0, 0};
const int highEnd[] = {1023, 100, -50, 1000, 1023};

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

//********************************************^************************************************
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 >= 100ul)
  {
    //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 >= 10ul)
  {
    //we are now finished with this analog settling TIMER
    sampleFlag = DISABLED;

    //read the stabilized analog
    muxValue = 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] >= 5)     // 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("channel ");
          Serial.print(muxAddress);
          Serial.println(" Is: ON (1)"); // and say so
        }
      }
      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("channel ");
          Serial.print(muxAddress);
          Serial.print(" Is: OFF (0)");  // and say so
        }
      }
new feature removed for now */

      //log the new value of the selected analog
      muxValue = map(muxValue, 0, 1023, lowEnd[muxAddress], highEnd[muxAddress]);

      Serial.print("Value at channel ");
      Serial.print(muxAddress);
      Serial.print(" is : ");
      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()

a7

Hi a7.
Thank you very much for your help. I'm not sure what was my issue before but your new version is working as intended! Thanks for that.

Now my wish is adding the previous feature which was the ability to read more inputs in a non-blocking manners, not via the multiplexer (A0), rather from the other available analog inputs..