Understanding the 4051Multiplexer code

Hi.
i'm having a bit of a hard time understanding the code for the 4051 Multiplexer given on the Arduino Playground.

here it is:

/*
 * code example for useing a 4051 * analog multiplexer / demultiplexer
 * by david c. and tomek n.* for k3 / malm? h?gskola
 *
 * edited by Ross R.
 */  

int r0 = 0;      //value of select pin at the 4051 (s0)
int r1 = 0;      //value of select pin at the 4051 (s1)
int r2 = 0;      //value of select pin at the 4051 (s2)
int count = 0;   //which y pin we are selecting

void setup(){
  pinMode(2, OUTPUT);    // s0
  pinMode(3, OUTPUT);    // s1
  pinMode(4, OUTPUT);    // s2
}

void loop () {
  for (count=0; count<=7; count++) {

    // select the bit  
    r0 = bitRead(count,0);    // use this with arduino 0013 (and newer versions)     
    r1 = bitRead(count,1);    // use this with arduino 0013 (and newer versions)     
    r2 = bitRead(count,2);    // use this with arduino 0013 (and newer versions)     

    //r0 = count & 0x01;      // old version of setting the bits
    //r1 = (count>>1) & 0x01;      // old version of setting the bits
    //r2 = (count>>2) & 0x01;      // old version of setting the bits

    digitalWrite(2, r0);
    digitalWrite(3, r1);
    digitalWrite(4, r2);

    //Either read or write the multiplexed pin here

  }  
}

So, here is what i think i understand:

  • connecting it to the arduino and the pins payout i think is ok.
  • i understand the basic functionality of reading 8 Analog Pins using only 4 pins on the Arduino Board.
  • i understand that in order to select which pin of the Multiplexer we want to Read/Write we have to set a different value to r0, r1 and r2. right?
  • r0 HIGH + r1 LOW + r2 LOW would select one InputPin ; r0 HIGH + r1 LOW + r2 HIGH another InputPin ; and so forth. Right?

But now here is my question.
If i have, lets say, a button connected to InputPin0 (y0/pin 13 of the 4051. that would be r0 LOW, r1 LOW, r2 LOW ? ).
How can i say something like "if button is pressed, please turn on my beautiful LED".

can i still use something like a normal

 int buttonRead = AnalogRead(what would go here?);
if (buttonRead == HIGH) {
  digitalWrite(ledPin,HIGH);
}

i would really appreciate any help with understanding this. i feel i am missing how it works and i am hoping you can point me in the right direction.
Thank you!
=)

You always read from the analog pin that the multiplexer is connected to. So, if it's wired to A0, then you always read from A0.

1. Switch MUX to input 0
2. Read from A0
3. Compare with threshold value (NOT "HIGH")
4. Do something
5. Switch MUX to input 4
6. Read from A0
7. Compare with threshold value
8. Do something
... etc ...

ok, in theory i think i understand what you mean.

so if in the end of that code i add something like:

 multiplex1[count] == digitalRead(A0);

 if (multiplex1[1] == HIGH) { // CAN I WRITE THIS to just read pin1? or always multiplex[count] ?
   digitalWrite(led1,HIGH);
}

would this light the LED when the button connected to the y1 of the 4051 is HIGH?
Or should i also put the leds in an array and make something like

if (multiplex1[count] == HIGH) {
   digitalWrite(leds[count],HIGH);
}

and that would for the first button light the first led, second button the second led,... ?

You can read multipex[count] quite happily should you want to. Putting the LEDs in an array will make the whole thing more efficient. However, you could short-cut it:

for (count = 0; count < 8; count++) {
  selectMultiplex(count); // do whatever you need here
  digitalWrite(led[count], digitalRead(A0));
}

The LEDs and the MUX have no connection with each other, you cannot normally use a MUX for outputs.

So having filled multiplex[] (crap name BTW) with data from your MUXed inputs you would then use another array to set the LEDs. eg

byte led_pins [] = {1,4,6,7,9,10};

for (int i = 0; i < number_of_leds; i++)
     digitalWrite (led_pins[i], multiplex[i]);

But using the multiplex[] array is an unnecessary step unless you need the data for another reason.


Rob

what would then be the right way to have 8 buttons connect to 8 leds, using the minimum pins possible on the Arduino?

what would then be the right way to have 8 buttons connect to 8 leds

8 wires, and forget the Arduino :slight_smile:

You have the input MUX sorted I guess, try using a 74HC595 shift register for the outputs, that will need 3 pins for as many outputs as you like in multiples of 8.

Instead of saving the input values into seperate 8 bytes you accumulate the digitalRead() results into a single byte then use shiftOut() to send that byte to the shift register and hence the LEDs.

byte val = 0;
for (int i = 0; i < 8; i++) {
    set_input_mux(i);
    val <<= 1;
    val |= digitalRead(input_pin);
}

shiftOut (..., val); // can't remember the exact syntax, look it up in the reference

EDIT: Code fixed.


Rob

... except you want to shift before the or, not after, or the last bit will always be 0 and you'll lose your first bit off the end.

Note that

 multiplex1[count] == digitalRead(A0);

should be:-

 multiplex1[count] = digitalRead(A0);

only use == in if statements.

you want to shift before the or, not after,

oops. Correct Majenko, fixed.


Rob

Graynomad:
8 wires, and forget the Arduino :slight_smile:

Hmmm, nice idea. Maybe i can even spare 7 of the wires and try to do it with only wire that runs through all of the buttons and LEDs! 8)

Grumpy_Mike:
only use == in if statements.

Ah yes, you're right. sorry! :wink:

Well, about this multiplexer and shift register thing...
i'm still not sure i understand it so well. I will sit today or tomorrow when i have a little time (and peace and quiet) and try to figure it out.
I think you guys have pointed me in the right direction, now maybe my fingers can also learn something for me with some Hands-on experimenting.

== == ==
Something else...
Wouldn't it be cool to make some very basic videos explaining all this kind of things?
i have seen many videos about Arduinos, but honestly most of them were too complicated for the begginer to understand and the others were not so interesting (in a learning kind of way).
Maybe something like going through the Arduino examples and explain a little bit the theory behind them, how it works, what the code is doing...

I think Arduino is a great tool for people like me (people without ANY knowlege of electronics but with lots of motivation) to start doing something, actually building something and bringing ideas to life.
But sometimes i find it hard to find simple and clear "instructions" on how to use this or that.
Like the instructions for using the multiplexer. I can understand that for most people they are good. Enough, precise and with the right information. But for someone like me, they just make me more confused.

Like we say in my country "Please teach me slowly like if I were Stupid!"
:wink:

Maybe this drawing will help and be clearer than looking though the data sheets (which you will have to do eventually because I've only drawn the pins actively involved and there are many more you have to deal with to make it work.)

Note that you could combine some pins to really reduce the number required, but let's not complicate things at this point. Also the signal names I've used on the 595 and 4051 may vary depending on the manufacturer of the chip.

It's probably hard to get good teaching material, in many ways it should be done by the novice shortly after he/she learns a particular technique because it's fresh in their mind and they will probably talk at the same level as other novices, but of course they would rather just move on.

By the time you are experienced you are in many ways not the best person to do it because you will take too much for granted.

There must be exceptions and I guess they are the guys that write the books of which there must be a few around. Certainly I've seen many referenced on this forum over the years.


Rob

thanks, that drawing is great!! It actually helps me understanding what is going around.

i just came home, let's see if today i'll have time to sit a bit with this.
:wink:

So, i did have some time to take a look at this.

I put some pots on a breadboard with a CD4051BF and fiddled with some code to try to output the values of the Pots into MIDI messages (i'm a musician, what can i say...).
Right now i have this:

const int PotsPin = A1;

int r0 = 0;
int r1 = 0;
int r2 = 0;
int count = 0;

unsigned char PotVal[8] = {0,0,0,0,0,0,0,0};
unsigned char CurrentPotVal[8] = {0,0,0,0,0,0,0,0};
unsigned char MappedPotVal[8] = {0,0,0,0,0,0,0,0};
int threshold = 2;

void setup() {
  pinMode(10, OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(8,OUTPUT);
  Serial.begin(115200);
}

void loop() {
  for (count=0; count<8; count++) {
    r0 = bitRead(count,0);
    r1 = bitRead(count,1);
    r2 = bitRead(count,2);
    
    digitalWrite(10,r0);
    digitalWrite(9,r1);
    digitalWrite(8,r2);
    
    PotVal[count] = analogRead(PotsPin);
    MappedPotVal[count] = map(PotVal[count], 0, 1023, 0, 127);
    
    if (abs(PotVal[count] - CurrentPotVal[count]) >= 2) {
      potsMIDI(0xB0, 1, MappedPotVal[count]);
      CurrentPotVal[count] = MappedPotVal[count];
    } 
  } //end of count
}

void potsMIDI (unsigned char cmd, unsigned char pitch, unsigned char vel) {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(vel);
}

I am using the Serial to Midi Converter from SpikenzieLabs.
i think it is kind of working, but not 100%.
I am reading values only between 0 and 31, instead of the 0-127 that i was going for.

Overall, is this the way to read from a multiplexer?
What about this code, 8 Pots in a Multiplexer to MIDI, what is wrong?

Thanks!
=)

I think the code is OK.

What's the raw values read from the pots.

Do you have the E pin pulled low on the 4051?

And how have you connected the pots and the 4051? Got a schematic?


Rob

Look at the code in this project of mine, it is very similar to what you are trying to do:-
http://www.thebox.myzen.co.uk/Hardware/MIDI_Footsteps.html

I noticed now something strange.
The values from the pots don't increase steadilly from 0 to 31. They do it several times (3 or 4) through the whole expanse of each pot.
So i turn the pot completly down and i read 0.
Then i start increasing it and the values go slowly up until 31, then they go back to 0 and again slowly up until 31,...

Graynomad:
What's the raw values read from the pots.

I tried taking away the mapping part of the code.
I then read values between 0 and 127, but also it happen several times for each pot, like i explained before for the 0-31.

Do you have the E pin pulled low on the 4051?

Yes, i think i do.

And how have you connected the pots and the 4051? Got a schematic?

I am using 10k Ohm pots. All the purple wires go to pots connected in the same way.

Grumpy_Mike:
Look at the code in this project of mine, it is very similar to what you are trying to do:-

Thanks, i will sure try to understand it. It looks like an interesting project... (like all projects from you that i know!!) :wink:

boguz:
So, i did have some time to take a look at this.

I put some pots on a breadboard with a CD4051BF and fiddled with some code to try to output the values of the Pots into MIDI messages (i'm a musician, what can i say...).
Right now i have this:

const int PotsPin = A1;

int r0 = 0;
int r1 = 0;
int r2 = 0;
int count = 0;

unsigned char PotVal[8] = {0,0,0,0,0,0,0,0};
unsigned char CurrentPotVal[8] = {0,0,0,0,0,0,0,0};
unsigned char MappedPotVal[8] = {0,0,0,0,0,0,0,0};
int threshold = 2;

void setup() {
 pinMode(10, OUTPUT);
 pinMode(9,OUTPUT);
 pinMode(8,OUTPUT);
 Serial.begin(115200);
}

void loop() {
 for (count=0; count<8; count++) {
   r0 = bitRead(count,0);
   r1 = bitRead(count,1);
   r2 = bitRead(count,2);
   
   digitalWrite(10,r0);
   digitalWrite(9,r1);
   digitalWrite(8,r2);
   
   PotVal[count] = analogRead(PotsPin);
   MappedPotVal[count] = map(PotVal[count], 0, 1023, 0, 127);
   
   if (abs(PotVal[count] - CurrentPotVal[count]) >= 2) {
     potsMIDI(0xB0, 1, MappedPotVal[count]);
     CurrentPotVal[count] = MappedPotVal[count];
   }
 } //end of count
}

void potsMIDI (unsigned char cmd, unsigned char pitch, unsigned char vel) {
 Serial.write(cmd);
 Serial.write(pitch);
 Serial.write(vel);
}




I am using the Serial to Midi Converter from SpikenzieLabs.
i think it is kind of working, but not 100%.
I am reading values only between 0 and 31, instead of the 0-127 that i was going for.

Overall, is this the way to read from a multiplexer?
What about this code, 8 Pots in a Multiplexer to MIDI, what is wrong?

Thanks!
=)

You are using char values to store your int data.

A char can store between -128 and +127. The analogRead returns a value between 0 ans 1023. That won't fit. Then you go and map that char value using the wrong range to another char value, and guess what? The number's don't match up.

Change your char arrays to int arrays and see what magically happens.

majenko:
Change your char arrays to int arrays and see what magically happens.

Thanks, that was it! :wink:

I also changed this line of code:

CurrentPotVal[count] = MappedPotVal[count];

into this:

CurrentPotVal[count] = PotVal[count];

So now it seems to be working ok! Sometimes there are still some little fluctuation, but i think that is to be expected and doesn't really compromise my use of it!

Next step:
Try to make an array of buttons (on a 4051 multiplexer) work with an array of LEDs (on a 74HC595N shift register).
Let's see what happens.

Thank you all for your help!!
=)