Multiplexed buttons giving the wrong reading

Hi all,
I’m working on multiplexing with a CD74HC4051E chip in order to read buttons. I am using the 4051 because after I get this circuit down I will use the concept to read analog values from piezo sensors for MIDI drum triggers.

The problem I’m having is that my buttons are sending unexpected messages. I know this because I only have one pin on the 4051 hooked up to a single button, the rest of the 7 pins are tied to ground. So when I press this one button it gives me a different value every time even though it should only be giving me HIGH from pin 0.

Output:
Pressed: 6
Pressed: 1
Pressed: 3
Pressed: 2
Pressed: 1
Pressed: 1

Code:

// Kerl Mera //
// Multiplexing button to serial monitor

const int s0 = 2; // Digital select pins
const int s1 = 3;
const int s2 = 4;
const int a0 = A0; // Analog read pin

boolean buttonActive[] = {false, false, false, false, false, false, false, false};

int buttonState[] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW};
int lastButtonState[] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW};   // the previous reading from the input pin

long lastDebounceTime[] = {0, 0, 0, 0, 0, 0, 0, 0};  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time;

void setup() {
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);

  Serial.begin(9600);
}

void loop() {

  for(int i = 0; i < 7; i++) {
    buttonState[i] = cdRead(i); 

    if (buttonState[i] == 1 && lastButtonState[i] == 0) {
      lastDebounceTime[i] = millis();
    } 

    if((millis() - lastDebounceTime[i]) > debounceDelay) {
      if(buttonState[i] == HIGH && buttonActive[i] == false) {
        Serial.print("Pressed: ");
        Serial.println((int) i);
        buttonActive[i] = true;
      } 
      else if(buttonState[i] == LOW) {
        buttonActive[i] = false; 
      }
    }

    lastButtonState[i] = buttonState[i];
  }
}

void cdSelect(unsigned int ch) {

  switch (ch) {
  case 0: 
    digitalWrite(s0, LOW); 
    digitalWrite(s1, LOW); 
    digitalWrite(s2, LOW); 
    break;
  case 1: 
    digitalWrite(s0, HIGH); 
    digitalWrite(s1, LOW); 
    digitalWrite(s2, LOW); 
    break;
  case 2: 
    digitalWrite(s0, LOW); 
    digitalWrite(s1, HIGH); 
    digitalWrite(s2, LOW); 
    break;
  case 3: 
    digitalWrite(s0, HIGH); 
    digitalWrite(s1, HIGH); 
    digitalWrite(s2, LOW); 
    break;
  case 4: 
    digitalWrite(s0, LOW); 
    digitalWrite(s1, LOW); 
    digitalWrite(s2, HIGH); 
    break;
  case 5: 
    digitalWrite(s0, HIGH); 
    digitalWrite(s1, LOW); 
    digitalWrite(s2, HIGH); 
    break;
  case 6: 
    digitalWrite(s0, LOW); 
    digitalWrite(s1, HIGH); 
    digitalWrite(s2, HIGH); 
    break;
  case 7: 
    digitalWrite(s0, HIGH); 
    digitalWrite(s1, HIGH); 
    digitalWrite(s2, HIGH); 
    break;
  default: 
    break;
  } 

}

unsigned short cdRead(unsigned int ch) {
  cdSelect(ch);

  return analogRead(a0); // Read the analog pin 
}

To go over the circuit:

Digital pins 2,3,4 TO 4051 select pins 0, 1, 2
Analog pin 0 TO 4051 Z pin
y0 on 4051 TO button
VCC on 4051 TO 5V
Everything else TO GROUND

Does this single button have a pull-up or is it floating?

I set up the button as in this tutorial except that the button goes to the 4051 input not the arduino input http://arduino.cc/en/Tutorial/Button

legs: 1:2 3:4

Leg 2: to input on 4051 Leg 3: to 5V bus Leg 4: to 10k resistor to ground

Also to note that when I hold down the button for a few seconds the resistor starts to get very hot

If your 10K resistor is getting hot and you are only supplying 5V to the circuit, then it isn’t a 10K resistor, it has a much lower value - probably 100 ohms or less.

You might have the switch rotated 90 degrees. I would get out your multimeter and make sure that the connections occur the way you expect.

Thank you dc42, I was actually using a 10 ohm resistor :relaxed:

My multimeter is broken so I have to wait for my paycheck to get a new one.
This is the way I have the button set up in other projects and the button works fine in those projects (besides the wrong resistor value);

One other thing I forgot to mention:
I had my code written a little different earlier and when I held down the button it would read all the 8 4051 pins as high one at a time until each of them was read once and then it would stop until I released the button and pressed it again. I know that isn’t super helpful since I am not supplying the code for that particular case but it may help show why all of the pins are being read high when only one pin is getting 5v supplied to it.

I’ve just been playing with a 74HC4051 and got reasonable results from it.

http://www.gammon.com.au/forum/?id=11976

You may want to have a look at the code I used. You can select the correct channel with a lot less lines of code than you used.

Wow Nick that is actually the most helpful multiplexing tutorial I have read on the internet thus far!

Hey y'all, newbie here trying to figure out how to work with the 4051, and this forum seemed like the place to grasp all that I require.

Nick seems to have written up a very useful tutorial on the whole scheme of multi/de muxing, and the specific nature of the 4051 chip. Very cool and helpful.

But something I still need help on grasping is how to light up leds through the chip. like nick says, " However you could conceivably connect up LEDs to some of the pins and flash them from time to time, interleaving with taking analog readings." And, most important, if one lights up an LED on a pin, can one keep that on, while deciding to light another on a pin?

So if I hooked up an led to the i/o pins on the 4051, what does the code look like to light it up?

my possible answer (I am at work right now and cannot try it out) using the example from Nick's 'output' schem.: digitalWrite(addressA, HIGH); //select pin 7 on 4051 digitalWrite(addressB, HIGH); digitalWrite(addressC, HIGH); digitalWrite(sensor, HIGH); // send voltage from pin 3 to 4051

is that it?

Also, how can one use the 4051 i/os to read the states of buttons (let's use pin 7 again...) digitalWrite(addressA, HIGH); //select pin 7 on 4051 digitalWrite(addressB, HIGH); digitalWrite(addressC, HIGH); int readSevenButton= digitalRead(sensor);

is that right?

The end result for my questioning will be a foot controller with more buttons, and leds, then my teensy has. the hardware is within reach for me, but the coding is bogging me down....

thanks!

daviddec: And, most important, if one lights up an LED on a pin, can one keep that on, while deciding to light another on a pin?

No, because it is the nature of it that only one pin is connected to the common pin at once.

If you are doing digital writes, and digital reads, you are probably better off with a 595 shift register (for output):

http://www.gammon.com.au/forum/?id=11518

And a 165 for input.

Although a 16-pin port expander could do both (input and output) in a fairly easy-to-use way.

http://www.gammon.com.au/forum/?id=10945

Nick,

I have an application and was perplexed by the 4051.

I posted this topic: http://forum.arduino.cc/index.php?topic=207895.0

But then I found this thread – and was hoping you might be able to help me adapt your code?

I tried to adapt your code here:

// Example of using the 74HC4051 multiplexer/demultiplexer

// Author: Nick Gammon (edited by David Hunt)
// Date: 04 Jan 2014

const byte sensor = A0; // where the multiplexer in/out port is connected

const byte addressA = 2; // the multiplexer address select lines (A/B/C)
const byte addressB = 3;
const byte addressC = 4;

void setup ()
{
// Serial.begin (115200);
Serial.begin (9600);

Serial.println (“Starting multiplexer test …”);
pinMode (addressA, OUTPUT);
pinMode (addressB, OUTPUT);
pinMode (addressC, OUTPUT);
} // end of setup

int readSensor (const byte which)
{
// select correct MUX channel
digitalWrite (addressA, (which & 1) ? HIGH : LOW);
digitalWrite (addressB, (which & 2) ? HIGH : LOW);
digitalWrite (addressC, (which & 4) ? HIGH : LOW);
// now read the sensor
return digitalRead (sensor);
} // end of readSensor

void loop ()
{
// show all 6 sensor readings
for (byte i = 0; i < 7; i++)
//for (byte i = 0; i < 7; i++)
{
Serial.print (“Sensor “);
Serial.print (i);
Serial.print (” reads: “);
Serial.print (readSensor (i));
Serial.print (” | “);
}
Serial.println(””);
delay (1000);
} // end of loop

I want to read a digital input from these sensors… The trouble I am having is if I press any of the buttons it turns all the sensor values from 0 to 1.

So I can’t seem to get individual values for the button presses?

Anything you can see I am doing wrong?

4051_test_3.fzz (10.6 KB)