4051 multiplexer not working correctly with teensy 3.1, but works with arduino

Status
Not open for further replies.

zalterman

Well-known member
Hello everyone

I am trying to get 16 buttons into my teensy 3.1 with as little pins as possible. I have been using the 4051 multiplexer

http://www.mouser.com/ProductDetail/Texas-Instruments/CD4051BE/?qs=q2XTDbzbm6DxulBsMcV7tA==

but am coming across some completely unexplainable (to me and a few other tinkerers at least) issues

***I am considering the possibility that the issue is actually with the teensy and not my hardware or software, because when I keep everything exactly the same, but replace the teensy 3.1 with an arduino or chipKit, everything then works smoothly***

I know the multiplexers work, because when I use them as demultiplexers to consecutively power some LEDS, it works as expected.

Here is a picture of my breadboard

teensy_4051multiplexer_withtext.jpg

As you can see, I am currently testing with only 4 buttons. The power for the rails is 5V from the teensy VUSB.
The code functions as follows
___
pin5 of the teensy is connected to the common out/in of the multiplexer and is pulled high with the internal pullup resistor. The 4 buttons, through the multiplexer, are meant to pull this pin low when pressed.

set multiplexer to first address - this should make a connection between the common out/in (pin 3) and channel 0 (pin 13)
read value of common pin and store to variable (b0)
set multiplexer to second address - this should make a connection between the common out/in (pin 3) and channel 1 (pin 14)
read value of common pin and store to variable (b1)
set multiplexer to first address - this should make a connection between the common out/in (pin 3) and channel 2 (pin 15)
read value of common pin and store to variable (b2)
set multiplexer to fourth address - this should make a connection between the common out/in (pin 3) and channel 3 (pin 12)
read value of common pin and store to variable (b3)

print values of stored variables in serial monitor
_____

ISSUE
what is happening is that when I read these variables, am I given a consistent, incorrect, and seemingly unexplainable response.
b0 should read high until I press down button one - which pulls teensypin 5 to ground when the address is set to the first (pin2=LOW, pin3=LOW, pin4=LOW))
this happens, but b0 also reads low when button2 is pressed (meaning that pin15 is connected to common out/in pin when the address doesnt tell it to...)
b1 reads low when button1 is pressed, but also when button0 is pressed
b2 reads low when button0, button1, and button3 are pressed
b3 reads low when button2 is pressed

this makes NO sense to me

at first thought problem was using 3.3v for 4051 that calls for 5v. now using 5v, no help.
thought maybe multiplexer just fried - however when setting pin5 to an output and wiring to LEDs instead of buttons, everything works perfectly
and the main concern - THIS WORKS PERFECTLY WITH ARDUINO WITH THE SAME PIN/WIRING CONFIGURATION

here is my arduino code
____________________________________


int ax = 2; //address pins
int bx = 3; //address pins
int cx = 4; //address pins

int b0 = 0; //button values
int b1 = 0; //button values
int b2 = 0; //button values
int b3 = 0; //button values

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

pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, INPUT_PULLUP);

}

void loop(){
digitalWrite(ax, LOW);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
b0 = digitalRead(5);

digitalWrite(ax, HIGH);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
b1 = digitalRead(5);

digitalWrite(ax, LOW);
digitalWrite(bx, HIGH);
digitalWrite(cx, LOW);
b2 = digitalRead(5);

digitalWrite(ax, HIGH);
digitalWrite(bx, HIGH);
digitalWrite(cx, LOW);
b3 = digitalRead(5);

Serial.println(b0); //i swap b0 with b1, b2, b3 to look at those values

}
________________________________

The problem must be with either something internal to the teensy, or something with a difference with teensyduino code vs the way an arduino reads arduino language...

Any ideas?? this is driving me insane!!!!!
Thanks in advance for your time
Zach
 

Attachments

  • teensy_4051multiplexer.jpg
    teensy_4051multiplexer.jpg
    153.4 KB · Views: 842
Can you check the power voltage with a multimeter?

If the photo, it looks like the red wire is going to AGND. It is really connected to 3.3V or VIN (5V)?
 
yep 4.94 volts

I'm getting power from the VUSB pin

Screen Shot 2014-03-04 at 9.05.58 PM.png

this isnt apparent in my previous photo because my pin header is displaced at that row- you just cant see
 
What I'm not quite understanding is that when I use use my multimeter to check connection between the common out/in pin and the selected input channel, I am not finding connection.
I have a sketch going where I wait one second before each address change, and check for connectivity when it should be there.
Its not...do multiplexers have something more complicated going on inside so that the passage of current from common pin to input pin is not simply a straight connection? Or is this an issue and possibly indicative of the problem I'm having.

Thanks!
 
Per my last comment - I tested with arduino instead of teensy 3.1 and still am not seeing connection between common pin and input on the 4051 with my multimeter (even though the multiplexer is working correctly).
This must mean the multiplexer is more complicated than simply making connections between common pin and input pin when it is addressed.
 
PROBLEM SOLVED. i was using the internal pullup resistor of the teensy for the common in/out pin, but I was powering the multiplexer with the VUSB 5v from the teensy. I stupidly didn't realize until checking with my meter that the pullup resistors pull up to ~3.2V, and this confused the multiplexer.

another huge part of the problem - faulty breadboard. I do not wish this upon my worst enemy...its been an entire week all day every day...overlooking the faulty possibility of breadboards.

Is it possible to have the internal pullups pull up to 5V?
 
Glad you found the problem! Life it definitely too short to mess with flaky breadboards!

The internal pullup resistors are only to 3.3V. However, you can power the 74HC4051 from 3.3V instead of 5V. The on-resistance of the switches will be a little higher with only 3.3V, but otherwise it works fine at 3.3V.
 
hmmm - when i switch the power rail from the 5V to the 3.3V (and not changing anything else) it no longer works - pressing down the buttons doesn't pull the common pin to ground...cant seem to figure this out
when changing the sketch to only open one address at a time and using my meter to check...button pressing DOES bull common to ground. this just isn't registered by teensy?
ideas?
 
The Teensy 3's 5V tolerant pins (not all are) would permit pull-ups to 5V, I'd think. though it seems the 4051 should work OK on 3.3V.
 
PROBLEM SOLVED

for some reason, when running off of 3.3V instead of 5V, the multiplexer needs 100microseconds of delay time between addressing and reading the input of the common pin.

Can anyone explain this?
 
Can anyone explain this?

Without the circuit here to verify with a scope, my guess would slowly charging the pin+breadboard capacitance through the on-resistance of the analog switch.

Look at figure 3 on page 8 of the datasheet. The on-resistance is pretty low when running from 15 or 10 volts, but gets much worse at 5 volts. Even though they claim the chip works from 3 to 20 volts, it's performance is only specified at 5, 10 and 15 volts.

Remember, datasheets are marketing material disguised as technical reference. Their one and only purpose is to sell semiconductors. When a part has terrible performance under some conditions, it's common practice to sweep that under the rug and hope nobody notices. As you can probably guess from that chart in figure 3 (or from an understanding of mosfet threshold voltages and I-V curves), it's probably a lot worse under 5V.

The 74HC version should be much better.
 
I am confused by the use of Vee for this pin. Why is there a negative voltage with DC electronics? (i dont have EE training)
and what is the channel on resistance? is this the resistance between the common out/in pin and the currently selected address input pin? because i was measuring .6k OHMS for this
 
Can someone please help me! :D

Firstly i apologise if i'm posting in the wrong thread but i'm pretty desperate at this point :((

I cannot find any code online for using buttons sending midi notes through a 4051 to a teensy 2.0

Ive borrowed the code in this thread with a teensy 2.0 and 4051 to attempt to get 4 buttons to send midi notes as a test so that i can use the 4051's to connect more buttons to the teensy 2.0 which i need for my midi controllers

My adapted Code:

int ax = 1; //address pins
int bx = 2; //address pins
int cx = 3; //address pins

int b0 = 0; //button values
int b1 = 0; //button values
int b2 = 0; //button values
int b3 = 0; //button values

int const numDigPins = 1 ; // number of digital pins to send note values
int currentDig[numDigPins];
int digitalpin[] = {
5 // which digital pins to use for sending note values
};

int digitalpitch[] = {
48}; // which midi notes to send from the digital pins selected above
int digInput[numDigPins];

const int channel = 1;

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

pinMode(1, OUTPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(5, INPUT_PULLUP);

}

void loop(){


for (int i = 0; i < numDigPins; i++) {
if (digitalRead(digitalpin) == 1 && currentDig == 0) {
usbMIDI.sendNoteOff(digitalpitch, 100, channel);
currentDig = 1;
}
if (digitalRead(digitalpin) == 0 && currentDig == 1) {
usbMIDI.sendNoteOn(digitalpitch, 100, channel);
currentDig = 0;
}
}


digitalWrite(ax, LOW);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
b0 = digitalRead(5);

digitalWrite(ax, HIGH);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
b1 = digitalRead(5);

digitalWrite(ax, LOW);
digitalWrite(bx, HIGH);
digitalWrite(cx, LOW);
b2 = digitalRead(5);

digitalWrite(ax, HIGH);
digitalWrite(bx, HIGH);
digitalWrite(cx, LOW);
b3 = digitalRead(5);


while (usbMIDI.read()); // read and discard any incoming MIDI messages
delay(25);

}


Hardware Wiring:

4051 pin 9 to Teensy pin 3 (B3)
4051 pin 10 to Teensy pin 2 (B2)
4051 pin 11 to Teensy pin 1 (B1)

4051 pins 6,7,8 to GND
4051 pin 16 to V+

4051 pin 3 to Teensy pin 5 (D0)

4 buttons to 4051 pins 12,13,14,15

Issue

Only one button works at a time sending midi note 48 on midi channel 1

When i uncomment like this :

/*
digitalWrite(ax, LOW);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
b0 = digitalRead(5);
*/

Then the next button works sending the same midi note 48 on midi channel 1

When I uncomment like this :
/*
digitalWrite(ax, LOW);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
b0 = digitalRead(5);

digitalWrite(ax, HIGH);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
b1 = digitalRead(5);
*/

Then the next button works sending midi note 48 on midi channel 1

You get the picture ... etc etc

My Question.

How do i adapt the above code for the 4051 and teensy 2.0 so that my buttons send different midi notes on ALL 8 inputs on the 4051?


Thank you very much in advance for your help!!!
 
First, add a delay between setting the control pins and reading the voltage. Like this:

Code:
digitalWrite(ax, LOW);
digitalWrite(bx, HIGH);
digitalWrite(cx, LOW);
delayMicroseconds(50);  // allow a brief time for the signal to charge/discharge the input pin through the 4051's resistance
b2 = digitalRead(5);

Next, you need to store the previous value and detect changes.

Perhaps like this:
Code:
if (b2 == LOW && b2_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOn(68, 100, 1);
}
if (b2 == HIGH && b2_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOff(68, 100, 1);
}
b2_prev = b2; // always update the "prev" variable for next time...

There may be other issues, but those are 2 I can see right away.
 
Thank you for the fast reply .. u seem to be the brains on this forum :D

I put the "delayMicroseconds etc" in

the next bit of code i tried to put in and the teesny loader gave me a"b2_prev" not declared error :?
 
First, add a delay between setting the control pins and reading the voltage. Like this:

Perhaps like this:
Code:
if (b2 == LOW && b2_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOn(68, 100, 1);
}
if (b2 == HIGH && b2_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOff(68, 100, 1);
}
b2_prev = b2; // always update the "prev" variable for next time...

There may be other issues, but those are 2 I can see right away.

Ok :)

I figured it out .. this is my new code.



Code:
int ax = 1; //address pins
int bx = 2; //address pins
int cx = 3; //address pins

int b0 = 0; //button values
int b1 = 0; //button values
int b2 = 0; //button values
int b3 = 0; //button values

int const numDigPins = 1 ; // number of digital pins to send note values
int currentDig[numDigPins];
int digitalpin[] = {
5 // which digital pins to use for sending note values
};

int digitalpitch[] = {
48}; // which midi notes to send from the digital pins selected above
int digInput[numDigPins];

const int channel = 1;

int b0_prev = 0;
int b1_prev = 0;
int b2_prev = 0;
int b3_prev = 0;

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

pinMode(1, OUTPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(5, INPUT_PULLUP);

}

void loop(){


for (int i = 0; i < numDigPins; i++) {
if (digitalRead(digitalpin[i]) == 1 && currentDig[i] == 0) {
usbMIDI.sendNoteOff(digitalpitch[i], 100, channel); 
currentDig[i] = 1;
} 
if (digitalRead(digitalpin[i]) == 0 && currentDig[i] == 1) {
usbMIDI.sendNoteOn(digitalpitch[i], 100, channel);
currentDig[i] = 0;
} 
} 

/*if (b0 == LOW && b0_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOn(68, 100, 1);
}
if (b0 == HIGH && b0_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOff(68, 100, 1);
}
b0_prev = b0; // always update the "prev" variable for next time...
*/
digitalWrite(ax, LOW);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
delayMicroseconds(50);  // allow a brief time for the signal to charge/discharge the input pin through the 4051's resistance
b0 = digitalRead(5);

if (b0 == LOW && b0_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOn(68, 100, 1);
}
if (b0 == HIGH && b0_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOff(68, 100, 1);
}


digitalWrite(ax, HIGH);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
delayMicroseconds(50);  // allow a brief time for the signal to charge/discharge the input pin through the 4051's resistance
b1 = digitalRead(5);

if (b1 == LOW && b1_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOn(68, 100, 1);
}
if (b1 == HIGH && b1_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOff(68, 100, 1);
}


digitalWrite(ax, LOW);
digitalWrite(bx, HIGH);
digitalWrite(cx, LOW);
delayMicroseconds(50);  // allow a brief time for the signal to charge/discharge the input pin through the 4051's resistance
b2 = digitalRead(5);

if (b2 == LOW && b2_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOn(68, 100, 1);
}
if (b2 == HIGH && b2_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOff(68, 100, 1);
}


digitalWrite(ax, HIGH);
digitalWrite(bx, HIGH);
digitalWrite(cx, LOW);
delayMicroseconds(50);  // allow a brief time for the signal to charge/discharge the input pin through the 4051's resistance
b3 = digitalRead(5);

if (b3 == LOW && b3_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOn(68, 100, 1);
}
if (b3 == HIGH && b3_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOff(68, 100, 1);
}



while (usbMIDI.read()); // read and discard any incoming MIDI messages
delay(25); 

}


Now the midi note 68 just continuously streams into my hairless-midiserial program... like really fast ... lol
 
You need to declare your variables...
int b2_prev = 0;
look at how the other variables are declared in your original code.
 
You need to declare your variables...
int b2_prev = 0;
look at how the other variables are declared in your original code.

thank u :D

That now works ..

this is my code now ..

Code:
int ax = 1; //address pins
int bx = 2; //address pins
int cx = 3; //address pins

int b0 = 0; //button values
int b1 = 0; //button values
int b2 = 0; //button values
int b3 = 0; //button values

int const numDigPins = 1 ; // number of digital pins to send note values
int currentDig[numDigPins];
int digitalpin[] = {
5 // which digital pins to use for sending note values
};

int digitalpitch[] = {
48}; // which midi notes to send from the digital pins selected above
int digInput[numDigPins];

const int channel = 1;

int b0_prev = 0;
int b1_prev = 0;
int b2_prev = 0;
int b3_prev = 0;

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

pinMode(1, OUTPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(5, INPUT_PULLUP);

}

void loop(){

digitalWrite(ax, LOW);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
delayMicroseconds(50);  // allow a brief time for the signal to charge/discharge the input pin through the 4051's resistance
b0 = digitalRead(5);

if (b0 == LOW && b0_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOff(60, 100, 1);
  currentDig[numDigPins] = 0;
}
if (b0 == HIGH && b0_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOn(60, 100, 1);
   currentDig[numDigPins] = 1;
}


digitalWrite(ax, HIGH);
digitalWrite(bx, LOW);
digitalWrite(cx, LOW);
delayMicroseconds(50);  // allow a brief time for the signal to charge/discharge the input pin through the 4051's resistance
b1 = digitalRead(5);

if (b1 == LOW && b1_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOff(61, 105, 1);
  currentDig[numDigPins] = 0;
}
if (b1 == HIGH && b1_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOn(61, 105, 1);
  currentDig[numDigPins] = 1;
}


digitalWrite(ax, LOW);
digitalWrite(bx, HIGH);
digitalWrite(cx, LOW);
delayMicroseconds(50);  // allow a brief time for the signal to charge/discharge the input pin through the 4051's resistance
b2 = digitalRead(5);

if (b2 == LOW && b2_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOff(62, 110, 1);
  currentDig[numDigPins] = 0;
}
if (b2 == HIGH && b2_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOn(62, 110, 1);
  currentDig[numDigPins] = 1;
}


digitalWrite(ax, HIGH);
digitalWrite(bx, HIGH);
digitalWrite(cx, LOW);
delayMicroseconds(50);  // allow a brief time for the signal to charge/discharge the input pin through the 4051's resistance
b3 = digitalRead(5);

if (b3 == LOW && b3_prev == HIGH) {
  // signal just went low
  usbMIDI.sendNoteOff(63, 120, 1);
  currentDig[numDigPins] = 0;
}
if (b3 == HIGH && b3_prev == LOW) {
  // signal just went high
  usbMIDI.sendNoteOn(63, 120, 1);
  currentDig[numDigPins] = 1;
}



while (usbMIDI.read()); // read and discard any incoming MIDI messages
delay(25); 

}

Now i can use all four buttons and im sending different midi signals ..

Problem is that its only sending note on messages and not note off



U guys are really helping a lot THANK YOU !! :D
 
Last edited:
You still need to update the "prev" variables after you use them, so they actually have the previous value the next time loop() runs.

now i'm confuddled

How do i do that ? sorry to be a pain ;(

EDIT Never mind i was being an idiot and NOT reading what you wrote above.. apologies *smacks forehead*
 
Last edited:
YAY !!! Got it all working now ..

Just one more problem im afraid ..

i Cant get the buttons to work on pins 1,2,4 and 5 on the 4051 ??
 
Ill reply to me :D

i got the 8 inputs working eventually !


All i cant figure out is the correct 4051 "Channel" order to have all the buttons in proper note order eg button 1 = 60 button 2 = 61 etc etc.

I have the following chart ...

4051tab.jpeg
 
Status
Not open for further replies.
Back
Top