Uno + 2x 4051 multiplexers

Hey folks -

I've been making some significant headway on my car-sensor input system, combining the arduino, the rPi, some 3d printing, and automotive wiring. For more on that, read here:

Anyhow, I'm running into some issues w/ my perf-board arduino, and I hope that the problem is in the code so it can be easily fixed.

With the two 4051 multiplexers, I'm simply looping through the channels, creating a name:value set, concatenating it all together, and then sending the combined string across the serial communication into the rPi.

It works. But as I'm testing this out with a single sensor at a time before wiring it all up, I'm running into some issues. Namely, I would expect that all of the sensors to read at "0" value when they are grounded w/ a 10k pull-down resistor. So if I just hook up a single sensor (let's say the Turbo boost sensor, which should provide a voltage of 0.5v+ to 4.5v+) while grounding all the other input wires, every sensor value ends up being 0, including the Turbo boost sensor. But if I unground everything and let it all float, every input goes kind of haywire, floating around and chasing whatever value I put into the Turbo boost sensor wire.

Does that make sense?

Anyhow, here's the code. Maybe the problem is in here. But maybe it's with the way the multiplexers are wired up? I currently have the power source of the arduino coming from the rPi USB, if that helps explain anything. Some of the sensors are labeled, and some are just labeled "sensor" until I figure out what's going to be sensed.

Thoughts?

int r0 = 0; // registers.
int r1 = 0;
int r2 = 0;
int count = 0;
int mplexes = 0;  // 0 and 1; the number of multiplexers. Currently, there are 2.
float multiplexOutput = 0;
int incomingByte = 0;
int clientKeepAlive = 0;

float init_X;  // X, Y, Z for the accelerometer
float init_Y;
float init_Z;

String label;

void setup() {

  //4051 multiplexer digital control pins
  pinMode(8, OUTPUT);    // s0
  pinMode(9, OUTPUT);    // s1
  pinMode(10, OUTPUT);   // s2
  
  Serial.begin(19200);
}

void loop() {
  if (Serial.available() > 0) {
    incomingByte = Serial.read();
    if (incomingByte == 'y') {
      clientKeepAlive = 1;      
    }
  }
  
  if (clientKeepAlive) {
    // cycle through both multiplexers

    for (mplexes = 0; mplexes <= 1; mplexes++) {
      
      for (count = 0; count <= 7; count++) {
        r0 = bitRead(count,0);
        r1 = bitRead(count,1);
        r2 = bitRead(count,2);
        
        digitalWrite(8,  r0);
        digitalWrite(9,  r1);
        digitalWrite(10, r2);
  
        multiplexOutput = analogRead(mplexes);


	// GROUP 1
        // 0: Fuel_Level
        if (count == 0 && mplexes == 0) {
		label="Fuel_Level: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
        // 1: WaterTemp
        if (count == 1 && mplexes == 0) {
		label="WaterTemp: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
        // 2: Oil_Pressure
        if (count == 2 && mplexes == 0) {
		label="Oil_Pressure: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
        // 3: Boost
        if (count == 3 && mplexes == 0) {
          label= "Boost: "; 
          float newValue = multiplexOutput * (5.00/1023.00) * 100;
          multiplexOutput = newValue;          
        }

	// GROUP 2
        // 4: Fuel_Pressure
        if (count == 4 && mplexes == 0) {
		label="Fuel_Pressure: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
        // 5: Throttle Position Sensor
        if (count == 5 && mplexes == 0) {
		label="TPS: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
        // 6: Tachometer
        if (count == 6 && mplexes == 0) {
		label="Tachometer: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
        // 7: Speedometer
        if (count == 7 && mplexes == 0) {
		label="Speedometer: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
  
	// GROUP 3
        // Accelerometer (8, 9, 10):
        if (count == 0 && mplexes == 1) {
		label="Accel_X: ";  
	}
        if (count == 1 && mplexes == 1) {
		label="Accel_Y: ";  
	}
        if (count == 2 && mplexes == 1) {
		label="Accel_Z: ";  
	}
        // 11: 
        if (count == 3 && mplexes == 1) {
		label="Sensor13: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}

	// GROUP 4
        // 12: 
        if (count == 4 && mplexes == 1) {
		label="Sensor14: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
        // 13: 
        if (count == 5 && mplexes == 1) {
		label="Sensor15: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
        // 14: 
        if (count == 6 && mplexes == 1) {
		label="Sensor16: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}
        // 15:
        if (count == 7 && mplexes == 1) {
		label="Sensor17: "; 
		multiplexOutput = map(multiplexOutput,1,1023,0,100); 
	}


  
        Serial.print(label); Serial.println(multiplexOutput,0); 
      }
      
    }
    Serial.println("*");  
    clientKeepAlive = 0;
  }
}

Please post complete circuit diagram as well (no Fritzings please, that's just unreadable).

Well, it's Fritzing, but I cleaned it up. (right-click, open image in new tab to enlarge)

Not too bad a schematic indeed.

A few things I notice (I don't know the mux chips themselves well):
You apparently use barebones ICs, no Arduino modules.
Missing filter caps on all ICs (need 100 nF between Vcc and GND, one cap for each).
RESET needs to be pulled up by a resistor (10k is common), not a cap.
LED1 won't do much, it's the wrong way around.
VEE and INH (enable) pins are not connected. That's not good. VEE appears to be normally connected to GND, INH connects to an MCU output.
All communication of the two ICs is shared, but you have to connect the enable pin to an output to be able to select the IC you're reading (leave it floating and you don't know what you're trying to read: either one, both, or none - all is possible).

I'm pretty pedantic about my schematics.

Yes, barebones ICs, but all of the arduino test codes work correctly. What Arduino modules are you referring to?

Can you tell me more about filter caps?

For the reset... I read somewhere else that it's a cap. Interesting. It doesn't work properly, so I wired in a reset-button; I'll replace the cap w/ a resistor and see if it works!

The LED is only incorrect on the schematic. I have it wired correctly, and it works. :slight_smile:

As for the two 4051s, the communication is shared, but I'm only reading from one at a time; accessing the bits concurrently while only reading one seems to limit the amount of code I need to write. If I send 0-0-0 to both chips, the sensor values for both chips will stream through, but I only care about what's being pulled in to input A0 or A1 at a given time on the arduino chip. I'll have to take a closer look at the logic of the code while it's looping through the two chips and the eight channels... but I think I've got that part working correctly.

INH... interesting. I went back to my 4051 documentation, and there's no INH. Just "E," which apparently needs to be grounded. The Fritzing model replaced "E" with "INH" for some reason. I'll go back and ground the E and VEE and see if that helps.

INH = inhibit, E = enable. It is different name of different manufacturer for the same thing.
You NEED to connect all 3 pins (Vee, E and GND) to common ground for the chip to work. (Vee may be connected to negative supply if you need multiplex negative voltages - not your case).

jovial_cynic:
I'm pretty pedantic about my schematics.

For even better schematics: use a proper CAD program like KiCAD or EagleCAD.

Yes, barebones ICs, but all of the arduino test codes work correctly. What Arduino modules are you referring to?

Like the Pro Mini.

Can you tell me more about filter caps?

You need them to keep the input stable (and the IC happy and working stably). You'll see this mentioned in the data sheets of the respective ICs - if you want to go barebones, do read the data sheets on how to connect them!

For the reset... I read somewhere else that it's a cap. Interesting. It doesn't work properly, so I wired in a reset-button; I'll replace the cap w/ a resistor and see if it works!

Again this you'll find in the data sheet.

INH... interesting. I went back to my 4051 documentation, and there's no INH. Just "E," which apparently needs to be grounded. The Fritzing model replaced "E" with "INH" for some reason. I'll go back and ground the E and VEE and see if that helps.

Inhibit is the opposite of enable. You'll see the E written with a bar above it (indeed pronounced "E-bar"), the bar is a kind of logic negative, meaning it's active low: enabled when low. Likewise, inhibit is when the pin is high.

Figured it out!

I noticed that I was getting a little bit of a reading out of a different sensor input than I intended, so I copied the voltage-mapping code from the boost sensor input (#3) to the tachometer input (#6), and I started getting my expected results... but on the wrong sensor.

I looked over the code more closely, and it looks like I forgot that for bitRead(x,n), n reads right to left, and not left to right, so I was sending my signal down 110 instead of 011.

Problem solved, thanks for playing.

Well done. And don't forget to add those capacitors :slight_smile:

wvmarle:
Well done. And don't forget to add those capacitors :slight_smile:

So, I'm looking over the datasheet here, and I'm not familiar enough with all of the terminology to know where to look to find out more about the filter-cap requirements.

Can you tell me what page I should be looking at to learn more?

Indeed not in the data sheet.
As a rule, all ICs need one to stabilise input voltage and filter out noise. Definitely the ATmega does. Caps are very cheap (you can get a bag of 100 of ceramic 100nF ones for <USD 1), and adding them will definitely not hurt anything.

Oh, I've got thousands of them. I inherited boxes and boxes of components from an old radio shack manager!

But I don't understand exactly where the caps are going. Between the IC and the power supply? Or between the IC and ground?

... or are they run directly between power and ground, parallel to the circuit?

EDIT: Figured it out. Nevermind!

Between Vcc and gnd, as physically close as possible to the IC. One for each IC. Big ICs with multiple Vcc pins may need more than one cap - one for each pin.