[SOLVED]: Analog values through multiplexer are very inconsistent!

Hi all,

I need to read 4 analog accelerometers. I thought of using a multiplexer for this (i took the CD74HC4067E for this). I wired everything up the way it should but my values are very inconsistent in comparison to reading the values directly.

These values come from the same sensor, the left ones come trough the multiplexer, the right ones are read directly.

x: 309 | y: 320 | z: 317	 x: 331 | y: 329 | z: 273
x: 367 | y: 259 | z: 373	 x: 331 | y: 329 | z: 273
x: 332 | y: 285 | z: 332	 x: 331 | y: 329 | z: 273
x: 259 | y: 348 | z: 262	 x: 331 | y: 329 | z: 273
x: 267 | y: 353 | z: 275	 x: 331 | y: 329 | z: 273
x: 332 | y: 290 | z: 344	 x: 331 | y: 329 | z: 273
x: 364 | y: 260 | z: 367	 x: 331 | y: 329 | z: 273
x: 313 | y: 299 | z: 313	 x: 331 | y: 329 | z: 273
x: 251 | y: 358 | z: 253	 x: 331 | y: 329 | z: 273
x: 282 | y: 341 | z: 291	 x: 331 | y: 329 | z: 273

I tried using delays in between reads from the multiplexer channels but no luck.

I'm in the dark here, please help!

i use the 4067, 2...
and i dont c such big variations...
the capacitance and resistance introduced by the 4067 r quite small...

can u show us the program and cabling u use?

r u possibly reading from a wrong mux line?

what if u dont change the mux line and read again and again?
does it get stable then?

How fast do you scan mux inputs? Is analogRead and scan function synchronous?

Have you got decoupling on the multiplexer chips?
http://www.thebox.myzen.co.uk/Tutorial/De-coupling.html

Are you suffering from cross talk, that is one channel affecting the other?
To test:-
Start off with only one channel connected, connect it also through another chip analogue input look at the readings are they similar.
Then add more channels but don't look at them in the software. Do they now behave differently?

EDIT: I removed all references to any analog read and my program is just reading channel 0 at the mux and still a lot of deviation.....

EDIT 2: the chip was left unpowered, i'll run another test sorry about this.

Thanks to all for the quick replies!

Ok these values come out when using only one channel:

x: 330	 x: 330 | y: 330 | z: 273
x: 91	 x: 330 | y: 330 | z: 273
x: 100	 x: 330 | y: 330 | z: 272
x: 330	 x: 330 | y: 330 | z: 273
x: 143	 x: 331 | y: 330 | z: 273
x: 325	 x: 330 | y: 330 | z: 273
x: 48	 x: 330 | y: 330 | z: 273
x: 119	 x: 330 | y: 330 | z: 273
x: 330	 x: 330 | y: 330 | z: 273
x: 133	 x: 330 | y: 330 | z: 273
x: 60	         x: 330 | y: 330 | z: 273
x: 330	 x: 330 | y: 330 | z: 273
x: 133	 x: 330 | y: 330 | z: 273
x: 330	 x: 330 | y: 330 | z: 273
x: 121	 x: 331 | y: 330 | z: 273
x: 47	         x: 330 | y: 330 | z: 273
x: 330	 x: 330 | y: 330 | z: 273

still all over the place.

So try to decouple the power source of the multiplexer. I put a capacitator from 0.047 uF from the power pin of the multiplexer to ground.

these are the values i get:

x: 331	 x: 331 | y: 330 | z: 273
x: 135	 x: 331 | y: 330 | z: 273
x: 68	 x: 331 | y: 330 | z: 273
x: 331	 x: 331 | y: 330 | z: 273
x: 163	 x: 331 | y: 330 | z: 273
x: 331	 x: 331 | y: 329 | z: 273
x: 121	 x: 331 | y: 330 | z: 273
x: 91	 x: 331 | y: 330 | z: 273
x: 331	 x: 331 | y: 330 | z: 273
x: 158	 x: 331 | y: 330 | z: 273
x: 331	 x: 331 | y: 330 | z: 272
x: 97	 x: 331 | y: 330 | z: 273

not much difference.

The wiring is in the attachment, hope it's clear.

Thanks again!

This is the code i'm using:

//////////////////////////////////////////////////////////////////
//©2011 bildr
//Released under the MIT License - Please reuse change and share
//Simple code for the ADXL335, prints calculated orientation via serial
//////////////////////////////////////////////////////////////////

//mux pins
int s0 = 8;
int s1 = 9;
int s2 = 10;
int s3 = 11;

//Mux in "SIG" pin
int SIG_pin = 0;

//Analog read pins
const int xPin = A8;
const int yPin = A9;
const int zPin = A10;

void setup(){
  Serial.begin(57600); //does the speed matter?
}

void loop(){

  //read the analog values from the accelerometer
  int xRead = readMux(0);
  int xReadDirect = analogRead(xPin);
  //int yRead = readMux(1);
  int yReadDirect = analogRead(yPin);  
  //int zRead = readMux(2);
  int zReadDirect = analogRead(zPin);

  //Output the caculations
  Serial.print("x: ");
  Serial.print(xRead);  
  Serial.print("\t x: ");
  Serial.print(xReadDirect);
  Serial.print(" | y: ");
  Serial.print(yReadDirect);
  Serial.print(" | z: ");
  Serial.println(zReadDirect);
  
  delay(10);//just here to slow down the serial output - Easier to read
}


int readMux(int channel){

  int controlPin[] = {s0, s1, s2, s3};
  int muxChannel[16][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}, //channel 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
  };
  delay(40);//maybe it helps??
  //loop through the 4 sig
  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
  //read the value at the SIG pin
  int val = analogRead(SIG_pin);

  //return the value
  return val;
}

It is hard to tell what is going on because the output you post is not from the code you post.
The wiring is not much help, better would be a schematic of what you are trying to do.

It is not immediately clear you are doing what I said. Is the first X through the multiplexer and the second one direct? It would imply that you are not getting correct power to the multiplexer or you have something like a floating enable pin or some such.

The code for setting the multiplexer's select line is rather verbose.
You can do it like this:-

for(int i=0; i<16; i++){
   // select multiplexer channel
   digitalWrite(s0Pin, i & 0x1);
   digitalWrite(s1Pin, (i>>1) & 0x1);
   digitalWrite(s2Pin, (i>>2) & 0x1);
  digitalWrite(s3Pin, (i>>3) & 0x1);
 // now read the multiplexer
 }

In general the output from an accelerometer is not the most stable of signals.

I put a capacitator from 0.047 uF from the power pin of the multiplexer to ground.

A bit low normally you would use a 0.1uF, don't remove it you need it even if you do not see an immediate change. I would also add some on the supply to your accelerometer boards.

where do u set the pinMode of the MUX control lines?
or is it not necessary anymore...?
i still use those old arduinos duemil...

i have another suggestion (in case u like loops):

for (int8_t i=3; i>=0; i--) digitalWrite(cl[i],channel&(1<<i));

:slight_smile:

From the photo I can't be sure that pins 13 and 14 are both low - address inputs A3 and A2 respectively, these need to be low to select the correct set of inputs (in particular pin 14 has a red wire not a blue one, which implies you are selecting channels 4/5/6 rather than 0/1/2. The signal wires are going into pins 9,8,7 (channels 0,1,2).

The leakage current specification is upto 0.8uA for switches in the off state, plenty large enough to explain your readings.

The leakage current specification is upto 0.8uA for switches in the off state, plenty large enough to explain your readings.

only if the source impedance was as high as the input impedance of the processor. what does the spec sheet say about output impedance or available load current? since you didn't see fit to post the sensor information anything beyond power supply bypassing is a waste of time... My Crystal Ball has been broken since it told me I was ugly...

Doc

Hello again!

I have put a capacitor on the output of the mux and the readings are much more consistent. However, it seems that the capacitor just holds the voltage to long, so that for the next read the output is too high. My readings:

Through the Mux x: 274	 y: 310	 z: 333		 Direct analog readings x: 332 | y: 333 | z: 277
Through the Mux x: 274	 y: 332	 z: 333		 Direct analog readings x: 332 | y: 334 | z: 276
Through the Mux x: 274	 y: 306	 z: 329		 Direct analog readings x: 332 | y: 333 | z: 277
Through the Mux x: 277	 y: 310	 z: 331		 Direct analog readings x: 332 | y: 333 | z: 277
Through the Mux x: 274	 y: 305	 z: 331		 Direct analog readings x: 333 | y: 335 | z: 277
Through the Mux x: 274	 y: 314	 z: 325		 Direct analog readings x: 332 | y: 332 | z: 276
Through the Mux x: 310	 y: 310	 z: 331		 Direct analog readings x: 332 | y: 334 | z: 277

It seems that the readings on the channel 0 are actually from the z pin on the sensor. when i position the sensor vertically the readings become:

Through the Mux x: 349	 y: 295	 z: 332		 Direct analog readings x: 264 | y: 296 | z: 349
Through the Mux x: 350	 y: 268	 z: 334		 Direct analog readings x: 266 | y: 334 | z: 350
Through the Mux x: 352	 y: 271	 z: 336		 Direct analog readings x: 266 | y: 334 | z: 350

the readings from x pin on the sensor are now visible on the y channel (channel 1 in the code) of the multiplexer. How is this delay introduced.

I have drawn the schematics, see the attachment. When I keep the accelerometer flat the readings on from the analog pins are correct. I have used a delay of even 1000 ms to let the capacitor discharge but no luck. I also have connected GND to channel 15 on the mux and have this channel read in order to "clear" the output pin. But all output became 0.

About crosstalking: if read only one channel in the software but leave all the wires in place then the readings are correct, even if delays are set to 1ms.

What else can i do to prevent and test?

The datasheet of the mux is found here http://datasheet.octopart.com/CD74HC4067E-Texas-Instruments-datasheet-151719.pdf

and my code:

//to hold direct read from the analog output of the ADXL335
int xAnaRead;
int yAnaRead;
int zAnaRead;

//to hold readings from the mux:
int xMuxRead;
int yMuxRead;
int zMuxRead;

//mux pins
int s0 = 8;
int s1 = 9;
int s2 = 10;
int s3 = 11;

//The pin on which the Mux outputs
int SIG_pin = A0;

//Analog read pins
const int xPin = A8;
const int yPin = A9;
const int zPin = A10;

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

void loop(){

  //read value on channel 0 of Mux
  xMuxRead = readMux(0);  
  //read analog value
  int xAnaRead = analogRead(xPin);
  delay(100); //to let the capacitator discharge

  //read value on channel 1 of Mux
  yMuxRead = readMux(1);  
  //read analog value
  int yAnaRead = analogRead(yPin);
  delay(100); //to let the capacitator discharge

  //read value on channel 2 of Mux
  zMuxRead = readMux(2);  
  //read analog value
  int zAnaRead = analogRead(zPin);
  delay(100); //to let the capacitator discharge


  //Output the readings
  Serial.print("Through the Mux x: ");
  Serial.print(xMuxRead);  
  Serial.print("\t y: ");
  Serial.print(yMuxRead);  
  Serial.print("\t z: ");
  Serial.print(zMuxRead);  

  Serial.print("\t\t Direct analog readings x: ");
  Serial.print(xAnaRead);
  Serial.print(" | y: ");
  Serial.print(yAnaRead);
  Serial.print(" | z: ");
  Serial.print(zAnaRead);
  Serial.println("");
  delay(100);//just here to slow down the serial output - Easier to read
}


//this is verbose but it works, and is more readable (i need that :)
int readMux(int channel){

  int controlPin[] = {
    s0, s1, s2, s3        };
  int muxChannel[16][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                }
    , //channel 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
  };

  //loop through the 4 sig
  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
  //read the value at the SIG pin
  int val = analogRead(SIG_pin);

  //return the value
  return val;
}

still not pinMode() call?

i mean code like this in setup():

pinMode(s0,OUTPUT);
pinMode(s1,OUTPUT);
pinMode(s2,OUTPUT);
pinMode(s3,OUTPUT);

so that the mux-config-arduino-pins r low-impedance pins...

What value of capacitor? Make it smaller.

int xAnaRead = analogRead(xPin);
  delay(100); //to let the capacitator discharge

  //read value on channel 1 of Mux
  yMuxRead = readMux(1);

This delay is doing nothing because it is while the input is switched through you need to do this:-

int xAnaRead = analogRead(xPin);
  delay(100); //to let the capacitator discharge
  xAnaRead = analogRead(xPin); // now read the value once it has discharged
  //read value on channel 1 of Mux
  yMuxRead = readMux(1); 
  delay(100); //to let the capacitator discharge
    yMuxRead = readMux(1);

RIDDICK:
still not pinMode() call?

i mean code like this in setup():

pinMode(s0,OUTPUT);

pinMode(s1,OUTPUT);
pinMode(s2,OUTPUT);
pinMode(s3,OUTPUT);



so that the mux-config-arduino-pins r low-impedance pins...

hmm according to the tutorial in bildr its not neccessary, nut i'll give it try!

hmm according to the tutorial in bildr its not neccessary,

No you misread that.

nut i'll give it try!

yup - give it a try... wag tail :wink:

Grumpy_Mike:
What value of capacitor? Make it smaller.

I did but the readings became less consistent.

Grumpy_Mike:

hmm according to the tutorial in bildr its not neccessary,

No you misread that.

hmmm i did indeed, will throw myself from the balcony later cos this was indeed the problem (3 days i was banging my head over this grrr).

Guess the output pins always give something so there random channels on the mux where selected?

this was indeed the problem

good to read that...

Guess the output pins always give something so there random channels on the mux where selected?

the wires between the arduino and the MUX pick up some voltage, so that they swing between 0 and 1...

i wouldnt use a cap on the MUX output... together with the resistance of the MUX path... it works like a low pass... do u need to suppress any noise on the output of ur sensor?

btw: it is normal to miss a little detail sometimes... :wink:

RIDDICK:

nut i'll give it try!

yup - give it a try... wag tail :wink:

shame on me, shame on me.......

thanks for all the efforts!

Guess the output pins always give something so there random channels on the mux where selected?

No what it was that those pins were defined as inputs. Then your attempts to drive them high and low simply had the effect of switching on and off the weak 30K pull up resistor on and off. So the pins went between just a logic one and floating. This is enough of an effect to see something happening but just not the right thing.