Analog 16 channel input mux Sparkfun

Hi all,

I have a Analog 16 channel input mux Sparkfun connetcted to an Uno. Now for some reason he shows value going up to 1023 and then down again to 0 in a wave like form...
Even if the board is not powered its doing this but then values are 200 to 0 ...seems like some kind of interference but dont know where. Or broken ?

cheers ian

This one ? SparkFun Analog/Digital MUX Breakout - CD74HC4067 - BOB-09056 - SparkFun Electronics.
Can you show us a photo so we can check the wiring ?
This is a tutorial for a mux: https://www.gammon.com.au/forum/?id=11976.

It could be reading an open analog input. Perhaps the enable is not used or you are reading the wrong analog pin. Did you apply something to the inputs of the mux ?
Perhaps you are reading electric noise, for example the 50 Hz or 60 Hz from the mains.

Can you tell us why you need more analog channels ? The Arduino Leonardo has more analog input and the Arduino Mega 2560 has 16 analog inputs. Was it not possible to use sensors with a digital interface ?

Well i thought this was the best way to handle lot of servos and sensors...was a guess basicly. I solved the wave thing by connecting the ground together from arduino and a seperate psu and a 10K pull down resistor.

I want to position servo based on sensor value and still there is a lot of distortion in the signal. specially when there is nothing in front of the sensor. Dont know how to fix that....was thinking of something that calculates every 10 values and average them.

tried a IF AND to isolate an area but for some reason that is not working.

these are the sensors am using :

here is my code

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm0 = Adafruit_PWMServoDriver(0x40);
int s0 = 8;
int s1 = 9;
int s2 = 10;
int s3 = 11;
int servomin = 110; //150
int servomax = 500; //600
int readingPin = A0;
int controlPin[] = {s0, s1, s2, s3};
int servo;

void setup() {
  Serial.begin(9600);
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  pwm0.begin();
  pwm0.setPWMFreq(60);
}

void loop() {
 reading();
// patroon();
}

// ------ mux functie
int readMux(int channel){
  int muxChannel[16][4]={{0,0,0,0},{1,0,0,0},{0,1,0,0},{1,1,0,0},{0,0,1,0},{1,0,1,0},{0,1,1,0},
  {1,1,1,0},{0,0,0,1},{1,0,0,1},{0,1,0,1},{1,1,0,1},{0,0,1,1},{1,0,1,1},{0,1,1,1},{1,1,1,1}};

  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
     }
  int val = analogRead(readingPin);
  return val;
  }
  
// ------ uitlezen mux
void reading(){
  for (servo = 0; servo < 1; servo++) {
    if((readMux(servo) > 200) && (readMux(servo) < 400)){
      
    Serial.print("Reading sensor ");
    Serial.print(servo);
    Serial.print(" ");
    Serial.println(readMux(servo));
    delay(100);
    }
  }
}

An Arduino Mega 2560 can drive 48 servo motors and has 16 analog input. That would be easier. But there is nothing wrong with those two modules.

Those IR sensors are indeed analog. I didn't know they were so noisy when there is nothing in front of them.

Your code could be easier. It is possible to transfer the bits one by one to output bits.

int muxControlPins[4] = { 8, 9, 10, 11};     // The first pin number (8) is the LSB bit S0 for the mux.

for(int i = 0; i < 4; i++)
{
  int value = bitRead( channel, i) == 1 ? HIGH : LOW;
  digitalWrite( muxControlPins[i], value);
}

How fast is the mux ? You could add an extra delay between setting the mux and reading the analog value. I think that 1ms is more than enough, so start with 5.

delay( 5);           // wait for mux
int val = analogRead(readingPin);

Using the average of a few samples is normal for an analog signal. About 5 to 10000 times.
Some use a delay between taking the samples, but in most cases a delay has no influence with normal noise.

delay( 5);        // wait for mux

const int n = 5;
int total = 0;
for( int i=0; i<n; i++)
{
  total += analogRead(readingPin);
  // delay( 1);    // no delay needed here, depending on the type of the noise.
}
int val = total / n;    // integer divide

My main concern is the ground currents and ground path and also bad contacts of the breadboard.
The ground current of the servo motors could influence the analog value.
You have to completely seperate the power for the servo motors and the returning ground current from the servo motors from the sensors. Then connect the GND of the servo module with a single wire directly on the Arduino board. When you have a power supply for both the Arduino and servo motors, you could make a single ground point close to the power supply.

When the current from the servo motors is going through the breadboard, it will lift the GND level because of bad contacts. That might lift all the GND levels of all sensors.

Grounding is difficult subject on its own. You should have a plan how to do that.

Could you upgrade to the newest Arduino IDE 1.8.5 ?
There might be problems when upgrading from 1.6.7, perhaps you have to check the installed libraries and perhaps you have to delete the hidden "arduino15" folder.

Ennuh... proost!

Hahah thx :slight_smile:

Well the servo part is not active but will remove wires and try your suggestions tomorrow morning. Maybe it’s good to isolate everything and first focus on the mux and sensors. I will also make a cad wiring diagram. For me the ground thing is new ...never built this advanced.
Also not sure what to let arduino power and what external.

Full pull 10 servos is around 600ma
All 10 sensors is around 270ma

Both at 5v

Thx for the fast replies and help

got some results but still a lot of stutter on the servo. figuring out how the make a smoother function for the analog IR sensor.

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm0 = Adafruit_PWMServoDriver(0x40);
int s0 = 8;
int s1 = 9;
int s2 = 10;
int s3 = 11;
int servomin = 110; //150
int servomax = 500; //600
int readingPin = 0;
int controlPin[] = {s0, s1, s2, s3};
int servo;

void setup() {
  Serial.begin(9600);
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  pwm0.begin();
  pwm0.setPWMFreq(60);
}

void loop() {
 reading();
// patroon();
// midden();
}

// ------ mux functie
int readMux(int channel){
  int muxChannel[16][4]={{0,0,0,0},{1,0,0,0},{0,1,0,0},{1,1,0,0},{0,0,1,0},{1,0,1,0},{0,1,1,0},
  {1,1,1,0},{0,0,0,1},{1,0,0,1},{0,1,0,1},{1,1,0,1},{0,0,1,1},{1,0,1,1},{0,1,1,1},{1,1,1,1}};

  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
     }
const int n = 5;
int total = 0;
for( int i=0; i<n; i++)
{
  total += analogRead(readingPin);
  // delay( 1);    // no delay needed here, depending on the type of the noise.
}

int val = total / n;
// int val = analogRead(readingPin);
  return val;
  }
  
// ------ uitlezen mux
void reading(){
  for (servo = 0; servo < 1; servo++) {
    int newwaarde = readMux(servo);
   // delay(5);
    if((newwaarde > 250) && (newwaarde < 500)){
      
    
   int newservo = map(newwaarde, 250, 500, 120, 450);
    pwm0.setPWM(servo, 0, newservo);
    Serial.print("Reading sensor ");
    Serial.print(servo);
    Serial.print(" ");
    Serial.print(newwaarde);
    Serial.print(" to ");
    Serial.println(newservo);
    delay(10);
    }
  }
}
// ----- programma interactie mensen
//void peopleaction(){
 // if 
 // for (servo = 0; servo < 10; servo++) {
  //  pwm0.setPWM(0, 0, int degreelength);
 // }
//}
  // ----- programma interactie mensen

Try 30 samples. The variable 'total' is a signed integer. That means 'n' can be maximum about 30, because more samples do not fit in the variable 'total'.

The peak current of a servo motor can do nasty things. That peak occurs at the moment the servo starts to move.
You could try a single IR sensor and a single servo motor and make that working without stutter.

With a single power supply the best is to use a star point ground near the power supply.
All the sensor with 270 mA can be powered via the Arduino for less noise or directly from the power supply for less problems.

If you have more sensors and servo motors you could buy a cheap Arduino board and do some test.

Using the average is normal for slow analog signals, but you can also add a simple software low-pass filter.
For example with a float variable, that gets 2% of the new value and 98% of the old value.

float distance;   // global variable

void loop()
{
  val = ...
  float newDistance = val * .. / ...   // calculate the distance

  distance = 0.02 * newDistance + 0.98 * distance;   // software low-pass filter
}

aaa cool will try that....bytheway ..hooked up the sensors on a different lab psu and grounded to arduino with better results.

i dont get your last code :frowning:

A global variable has the updated distance.
When a new distance is measured, only a few percent of it is used to update the global variable.
It can be any percentage as long as both are 100% together.

distance = 0.05 * newDistance + 0.95 * distance;

This is easier with float variables.

Added: a low pass filter in action. The orange line is hard to see, but that is the filtered signal.

aaa thx :slight_smile: