Hi! Hope you're enjoying this blog. I have a new home at www.goldsborough.me. Be sure to also check by there for new posts <3
Showing posts with label arduino. Show all posts
Showing posts with label arduino. Show all posts

Monday, February 3, 2014

The Mini Midi

Finished, at last. I finally completed my project of building a mini midi controller, a Teensy based controller for interfacing with DJ/Music production software via MIDI signals. I had finished the electronics last December, and also the programming was not a big problem. What did prove difficult, though was building the case, as this project was DIY all the way. Anyway, here some pictures:



Once upon a time on a breadboard...


The secret to getting ahead is getting started - Mark Twain



The electronics: front


From the side. Note: I removed one row of LEDs in the end.


And there was light!


Screw buying buttons



The finished Mini MIDI






Ta.Da.

A video in which I describe the electronic components:





Dry/Wet control of the effects means controlling how much of a certain effect “reaches” the audio signal. Dry means no effect, Wet means the audio signal is affected 100% percent by the effect. 

A video in which I talk about the hardware I used (have a look at how I made the buttons):



A video in which I show the Mini Midi in action:



Note: The first song is not off, it's just not loud enough to really hear in the video. 

So, there it is. Some comments:

What electronic components did I use?

The Teensy++ as a micro controller. Why not an Arduino? The main reason is that Arduinos cannot act as native MIDI/HID devices, meaning that, without flashing the MIDI firmware onto the Arduino, Arduinos cannot send MIDI signals. Teensys, on the other hand, can do so very easily and have a nice built in library. There's no extra software required really so the programming can still happen over the Arduino IDE. 

8 Rotary potentiometers. Two for the Dry/Wet control of the effects and 6 for the high, mid and low sound levels of the two decks. 

1 Slide potentiometer, for crossfading between the two decks. 

1 Rotary encoder for the browser.

6 Buttons, 2 for Play/Pause, 2 for loading songs from the browser and 2 for turning on effects. 

All the potentiometers are controlled over a multiplexer. The two LED bars on each side are controlled by two shift registers.  

What hardware did I use?

I went the DIY path all the way, meaning, whereas most people would buy cases or get them CNCd online, I built the case from scratch. It was very, very hard and the result is not the best it could be, especially in comparison to something machine-made, but it does feel nice to have done it all alone.

The method of pressing the buttons via the plastic sheets works as follows:

The top line in this picture is the plastic sheet with, say, Play/Pause on it. It is glued to the ground by that vertical rod on the left, which is nothing else than a clipped-off pin of an LED. Additionally, underneath the plastic sheet you can see that big light-grey box which lies right on the pushbutton (the dark grey/black boxes) and which is glued to the plastic sheet. So now, if you press down on the plastic sheet, the big grey box also goes down and pushes the button. Because the plastic sheet is glued to the ground, though, the whole system will spring back into it's original position. Worked great. 

That being said, I'm not sure I'll never again build a case on my own again, it's just to inefficient. 

How long did it take me? 


What did I enjoy the most? Doing the electronics and programming it.
What did I enjoy the least? Building the case/hardware.

Lastly, I'll talk about my source code. Since releasing something under no license means releasing it copyrighted, it is released under the MIT license:
/*

The MIT License (MIT)

Copyright (c) <year> <copyright holders>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/


#include 
#include 

//SHIFT REGISTERS A

const int latchPin_a = 9; //Latch pin of first shift register
const int clockPin_a = 8; //Clock pin of first shift register
const int dataPin_a = 7; //Data pin of first shift register

//SHIFT REGISTERS B

const int latchPin_b = 13; //Latch pin of second shift register
const int clockPin_b = 12; //Clock pin of second shift register
const int dataPin_b = 11; //Data pin of second shift register

// SHIFT REGISTER BUTTON

const int shift_reg_button = 21; // Button to control whether the LED bars are on or off
boolean shift_reg_state = false;

//BUTTONS A

const int fx_a = 1; //fx button left side
const int load_a = 4; //load song on left side from browser
const int play_a = 5; //play left side

// LEDS A

const int fx_a_led = 27; //it's led
const int play_a_led = 0; //it's led

//BUTTONS B

const int fx_b = 24; //fx button right side
const int load_b = 23; //load song on right side from browser
const int play_b = 22; //play right side

// LEDS B

const int fx_b_led = 26; //it's led
const int play_b_led = 25; //it's led

//ENCODER

const int encoderPin1 = 18; //Pin one of the encoder
const int encoderPin2 = 19; //Pin two of the encoder

// volatile means it can change within a loop, special type for ISR (interupt service routine)
volatile int lastEncoded = 0; //last value
volatile long encoderValue = 0; //sum of values

long lastencoderValue = 0;
int last_val = 0;

int lastMSB = 0; //Most Significant Bit -> 100000, the first 1 is meant
int lastLSB = 0; //Least Significant Bit -> the right most 0 is meant

// MUX

const int mux_0 = 17; //s0
const int mux_1 = 16; //s1
const int mux_2 = 15; //s2

int s0 = 0; // value of s0
int s1 = 0; // value of s1
int s2 = 0; // value of s2

const int mux_pin = 7; // multiplexer analog output pin
 
int  mux_bin [] = {0b000, 0b001, 0b010, 0b011, 0b100, 0b101, 0b110, 0b111}; //list of binary values

// OTHER POTENTIOMETERS

const int slide_pot = 6; //Slide pot analog pin

/* The below pot_vals are stored at one point in the loop and later on compared with a 
// second reading, if the values in that very vey short period of time has changed (basically)
// if a potentiometer has turned, a signal is sent and these values are reset to those, thus
// readings are a lot more efficient because signals are only sent when a change has actually
// occured, opposed to constant sending of signals! 
// Check out my blog at http://goo.gl/0yaVBo for more info on that. 
*/ 

int pot_vals[9] = {0}; //9th value is for the slide pot
int pot_notes[9] = {60,61,62,63,64,65,66,67,68};

int bs[6] = {fx_a,play_a,fx_b,play_b,load_a,load_b}; //all the buttons
int notes[6] = {50,51,52,53,54,55};

int leds[4] = {fx_a_led,play_a_led,fx_b_led,play_b_led};

// SHIFT REGISTER PATTERNS + VARIABLES FOR FUNCTION

byte stages [] = {
                    0b00000000,0b11111111,                                                                                 // on off
                    0b00000000,0b10000000,0b01000000,0b00100000,0b00010000,0b00001000,0b00000100,0b00000010,0b00000001,    // left to right 1 by 1
                    0b00000000,0b00000001,0b00000010,0b00000100,0b00001000,0b00010000,0b00100000,0b01000000,0b10000000,    // right to left 1 by 1
                    0b00000000,0b00011000,0b00100100,0b01000010,0b10000001,                                                // streaming out from middle
                    0b00000000,0b10000001,0b01000010,0b00100100,0b00011000,                                                // streaming in from outside
                    0b00000000,0b00011000,0b00111100,0b01111110,0b11111111,                                                // streaming out from middle, leaving previous ones on
                    0b00000000,0b11111111,0b01111110,0b00111100,0b00011000,                                                // streaming in from outside, leaving previous ones on
                    0b00000000,0b11000000,0b01100000,0b00110000,0b00011000,0b00001100,0b00000110,0b00000011,               // left to right 2 by 2
                    0b00000000,0b00000011,0b00000110,0b00001100,0b00011000,0b00110000,0b01100000,0b11000000,               // right to left 2 by 2
                    0b00000000,0b11110000,0b00001111,                                                                      // left to right 4 by 4
                    0b00000000,0b00001111,0b11110000,                                                                      // right to left 4 by 4
                    0b00000000,0b00011000,0b00100100,0b01011010,0b10100101,                                                // streaming out from middle, leaving previous ones blinking
                    0b00000000,0b10000001,0b01000010,0b10100101,0b01011010,                                                // streaming in from outside, leaving previous ones blinking
                    0b00000000,0b10000000,0b01000010,0b00100100,0b00010000,0b00000001,0b00000010,0b00000100,0b00001000,    // right to middle, left to middle
                  };

int patterns [14] = {2,9,9,5,5,5,5,8,8,3,3,5,5,9}; //how many stages each pattern has, I keep the number in the brackets just to know how many are in there
                      
int intervs [7] = {10,25,50,75,100,150,250};
int reps [5] = {2,5,10,15,20};

int r_p; //random pattern
int r_i; //random interval
int r_r; //random repitition number

int index; //index from which the pattern starts
int interv; //it's interval
int rep; //how many times do you want the pattern´?
int num_stages; //how many stages it is, so we know how much to subtract if repitions are left over, if you don't care for clarity, this is basically tot_ind - index

int tot_ind; //the last index of the pattern

// Debouncing

long t; //for debouncing the buttons without delay or Bounce library
long last_t[9] = {millis()}; //initialize a list of 8 last_ts each at current millis() // 4 toggle buttons, 2 normal buttons, 1 shift_reg_button, 1 for pattern

// Channel 1:  Pushbuttons
// Channel 2: Potentiometers

// SET TRUE IF YOU WANT SERIAL OUTPUT

boolean SER = true;

// ----------------------- SETUP ------------------------------- \\

void setup() {
  
  // Shift Registers
  
  pinMode(latchPin_a, OUTPUT);
  pinMode(dataPin_a, OUTPUT);  
  pinMode(clockPin_a, OUTPUT);
  
  pinMode(latchPin_b, OUTPUT);
  pinMode(dataPin_b, OUTPUT);  
  pinMode(clockPin_b, OUTPUT);
  
  pinMode(shift_reg_button,INPUT);
    
  //Encoder
  
  pinMode(encoderPin1, INPUT); 
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3) 
  attachInterrupt(6, updateEncoder, CHANGE); 
  attachInterrupt(7, updateEncoder, CHANGE);
  
  //Mux
  
  pinMode(mux_0, OUTPUT);    // s0
  pinMode(mux_1, OUTPUT);    // s1
  pinMode(mux_2, OUTPUT);    // s2
  
  //Buttons
  
  for (int i = 0; i < 7; i++) pinMode(bs[i],INPUT); //deck buttons

  //Leds
  
  for (int i = 0; i < 4; i++) pinMode(leds[i],OUTPUT); 
  
  if (SER) Serial.begin(57600); //set serial if wanted
  
  randomSeed(analogRead(0)); //seed random
  
  shift(0b00000000);
  get_patt();
  
}

void loop() {
  
  t = millis(); // get elapsed time
  
  check_pots();
  check_buttons();
  
  if (shift_reg_state) shift_reg();
   
}

void check_buttons() //check buttons for HIGH signal
{
  for (int i = 0; i < 6; i++) //for every fx and play button
  {
    if (digitalRead(bs[i]) == HIGH && t >= last_t[i] + 250) 
    {
      usbMIDI.sendNoteOn(notes[i],100,1);
      
      if (i < 4)
      {
        if (digitalRead(leds[i]) == HIGH) digitalWrite(leds[i],LOW);
        else digitalWrite(leds[i],HIGH);
      }
      
      last_t[i] = t;

    }
    
    
  }
 
 if (digitalRead(shift_reg_button) && t >= last_t[6] + 200) //if shift_reg_button is HIGH
 {
   
   if (shift_reg_state == false) shift_reg_state = true; //if previous state is false, switch to false, this then triggers the if clause in the led_bars() function
   else 
   {
     shift_reg_state = false; //if previous state was on, so true, switch to false
     shift(0b00000000); //make all shift_reg pins go low here because I don't want this to happen everytime during the loop
   }

   last_t[6] = t;   
 }  

}

void shift(byte b)
{
  digitalWrite(latchPin_a, LOW);
  shiftOut(dataPin_a,clockPin_a,MSBFIRST,b);
  digitalWrite(latchPin_a, HIGH);
  
  digitalWrite(latchPin_b, LOW);
  shiftOut(dataPin_b,clockPin_b,MSBFIRST,b);
  digitalWrite(latchPin_b, HIGH);
}

void get_patt()
{
  r_p = random() % 14; //pattern
  r_i = random() % 7;  //interval
  r_r = random() % 5;  //repetitions
  
  interv = intervs[r_i];
  rep = reps[r_r];
  num_stages = patterns [r_p];
  
  tot_ind = 0;
  index = 0;
 
  for (int i = 0; i < r_p; i++)  tot_ind += patterns[i];//add all indexes until the last index of the pattern before
  
  index = tot_ind; //since tot_ind stores the index + 1, this is exactly the first index of the pattern
  
  tot_ind += num_stages; //then add the total stages of this pattern to get the last pattern, now we have a beginning and an end
  
  if (SER)
  {
    Serial.print("NEW: ");
    Serial.println(r_p);
    Serial.print("Interval: ");
    Serial.println(interv);
    Serial.print("Repetitions: ");
    Serial.println(rep);
    Serial.print("Number of stages: ");
    Serial.println(num_stages);
    Serial.print("First index: ");
    Serial.println(index);
    Serial.print("Last index: ");
    Serial.println(tot_ind-1);
  } 
  
}

void shift_reg()
{ 
  shift(stages[index]);
  
  if (t >= (last_t[7] + interv))
  {
     Serial.println("pushed");
     
  digitalWrite(latchPin_a, LOW);
  shiftOut(dataPin_a,clockPin_a,MSBFIRST,stages[index]);
  digitalWrite(latchPin_a, HIGH);
  
  digitalWrite(latchPin_b, LOW);
  shiftOut(dataPin_b,clockPin_b,MSBFIRST,stages[index]);
  digitalWrite(latchPin_b, HIGH);
  
  if (index == tot_ind-1) //if the pattern is over
  {
    if (rep == 0) get_patt(); //if no more repetitions, get new pattern
    
    else//if repetitions left, go back to first stage
    {
      index -= num_stages; 
      rep--;
    }
    
  }
  
  index++;
  
   last_t[7] = t; //next time the last millis() is the current millis()
  }
  
}


void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;
  
  
  if(t >= (last_t[8] + 20))
  {
    Serial.print("encoder: ");
    Serial.println(encoderValue/4);
    
    if (encoderValue > last_val) usbMIDI.sendControlChange(75,70,1);
    
    else usbMIDI.sendControlChange(75,60,1);
    
    last_val = encoderValue;
    
    last_t[8] = t;
  }
  

  lastEncoded = encoded; //store this value for next time
}

void check_pots()
{
  int val; //analogRead value
  
  //MULTIPLEXER
  
  for (int i = 0; i < 8; i++) { //loop through each channel, checking for a signal

   int row = mux_bin[i]; //channel 5 = 5th element in the bin list -> 101 etc. 
    
   s0 = bitRead(row,0); //bitRead() -> parameter 1 = binary sequence, parameter 2 = which bit to read, starting from the right most bit
   s1 = bitRead(row,1); //channel 7 = 111, 1 = 2nd bit (starting at 0, 0 = 1st element)
   s2 = bitRead(row,2); // third bit
 
   digitalWrite(mux_0, s0); // send the bits to the digital inputs 
   digitalWrite(mux_1, s1);
   digitalWrite(mux_2, s2);
   
   val = analogRead(mux_pin)/8;
   
   if (i == 0 || i == 7) val = 127 - val;
   
   if (val != pot_vals[i] && val != pot_vals[i] + 1 && val != pot_vals[i] -1)
  {
       Serial.print("Channel: ");
       Serial.print(i+1);
       Serial.print(" ==== ");
       Serial.println(val); // after sending the binary sequence, the mux determines which channel to read from and sends it to this analog input
       
       usbMIDI.sendControlChange(pot_notes[i],val,1);
       
       pot_vals[i] = val;
  } 
}
  
  //SLIDE POT
  
  val = analogRead(slide_pot)/8;
  
  if (val != pot_vals[8])
  {
       Serial.print("Slide pot ");
       Serial.print(" ==== ");
       Serial.println(val); // after sending the binary sequence, the mux determines which channel to read from and sends it to this analog input
       
       usbMIDI.sendControlChange(pot_notes[8],val,1);
       
       pot_vals[8] = val;
  } 
  
}

Lots of this code are just functions for handling the checking of the potentiometers/buttons and sending the MIDI signals. I wrote everything myself except for the encoder function, which, despite me knowing how to write the code for an encoder, is just a really nice and efficient way that I wanted to use. All credit goes to the author. 

Something I tinkered with for a little longer was how I would devise a system for displaying many patterns on my LED bars. The led bars are controlled via shift registers, microchips that pulse a bit through 8 channels, making the current for that individual LED either go high or low, on or off. This happens so fast, though, that you can even make it look like all LEDS were on at the same time. 

Here a video that shows some of the patterns:





The function that sends a byte (one bit for each of the 8 channels) to the shift register is called shiftOut(), which takes, besides the pin numbers of the different pins of the shift register, the byte that you want to send to it as a parameter. That’s why there’s that huge array of bytes up there. Each pattern has a certain amount of bytes. E.g. turning the LEDs all off and on would be:

0b00000000, 0b11111111

0b is the prefix for a binary number. As you can see, when the shiftOut function sends the first byte to the shift register, it will go through each channel and set it to the corresponding value of the byte, in this case 0, or LOW, for very LED. Then, it will send out the next byte, with all 1s, so all HIGH, and turn each LED on. 

Instead of using a multidimensional array for the patterns, which is impossible since not all patterns have the same amount of bytes/states, I store the indexes in a separate array. 

There are to more variables that are relevant, for one the interval between each individual state of a pattern, which basically determines how fast an entire pattern goes by. Also, the number of repetitions of each pattern. It is noteworthy to say at this point that the entire program does not use the delay() function that stops the whole processor, as this could interrupt a MIDI signal. Everything is done via interval debouncing and the millis() function, meaning the code rather checks whether a certain period of time has passed. 

The array index, the interval and the repetitions variable are all generated randomly, so the following situation is an example of how the whole code works for one pattern:

The index i is randomly generated. At position i, the pattern:

0b00000000, 0b11000000, 0b00110000, 0b00001111, 0b00000011

is found. This would show two leds “streaming” through the bar. 

Next, the interval interv and the repetitions rep are randomly generated. 

Whenever interv has passed, the index is incremented by one, so the next state of the pattern is shown. If the index has reached the maximum index for this pattern, stored in the second array I mentioned above, it will check whether rep > 0. If so, the index is decreased by the maximum index. Thus, the whole pattern is “reset” and the pattern will repeat again. This will continue so long until rep = 0. If rep = 0, the index is increased to the start of the next  pattern. 



This was the only non-standard part in that code. Feel free to use/modify it and comment if you have any questions/issues regarding the code or anything else. 

Monday, October 14, 2013

Reading potentiometers more efficiently

It recently occured to me when sending MIDI Control Changes with my Microcontroller that having a potentiometer spew out values continuously is quite impractical when you don't want it to interfere with other potentiometers. I came up with a swift solution that could be packed in a function or so.


int nstate;
int state;

void setup()
{
  //For demonstration I'll just use Serial
  Serial.begin(9600);
}

void loop()
{
  nstate = analogRead(0)/8; //Read - Divide by at least 2 to prevent floating
  
  if (nstate != state)
  {
    Serial.println(nstate);
  }
  
  state = analogRead(0)/8; //Read again

  delay(10); //Only to stabilize Serial printing
}


So what I did here is I just created two variables into which I read the potentiometer's state at two different times (I don't know how fast the processor is but the time difference is probably in the microseconds) and if in that time the potentiometer was changed, the second reading will not match the first one anymore and the message is sent/ the action is executed. In my opinion an awesome way to:


  1. Keep delay() out of the game (Delay shuts down the entire system, not so practical)
  2. Get values only when the potentiometer is actually used, this is a huge advantage to just reading the values continously and changing something in "real time" (I hope you understand what I mean). E.g. when sending MIDI signals, you don't have the knob in your MIDI software always getting signals, rather only when a change actually occured. 

Attention! I recommend dividing the range of the potentiometer (0-1023) by at least 2 (you do so anyway when sending MIDI, because it only ranges from 0-127). Why? Even when the potentiometer is at rest, the values "float" a little (I hope it's the right term), meaning it might jump + or - 1 even when you're not touching it. I guess that's common for cheaper pots, so to prevent that, you need to divide it by at least 2 (= 0 - 512). Since the values are rounded and aren't as easily moved, the little inaccuracy never really changes the value. So the fewer the steps, the less fluctuation. 

I'm not really good with the words yet, but to give you an example: If a flight of stairs has 1023 steps each 20cm high and you then divide that by two, leaving you with only 512 steps, the steps need to be twice as high to make you complete the same distance. Thus, if you have Parkinson disease and shiver a lot, it's not as easy for you to move up a 40cm step than it is a 20cm one. There you go. The best metaphor in the history of the english language. 

Anyway, I'm probably waffeling already too much for the small piece of code, I'm so thankful for any comments, so please :)

Sunday, October 6, 2013

Arduino and Multiplexing

So you have, say, 7 or more potentiometers but your Arduino only has 6 analog inputs. Now what? Well, you're screwed .. or not? Welcome to multiplexing. A multiplexer, or simply mux, is a small electronic device that converts multiple analog or digital signals into a binary sequence and then sends this value to only one, common, pin.

There are a couple of different multiplexers around, some are better for digital signals, some for analog, some for input (potentiometers), some for output (leds), nevertheless, the principle is the same for all of these. I will be using the M74HC4051B1 (no I did not headbang my keyboard).

Firstly, if you do not understand binary, have a look at this explanation. Next, let me explain what a mux actually does. Let's assume you have an 8 channel multiplexer, meaning you can hook up 8 different analog signals to your multiplexer. Instead of having to read each signal individually, we can send a number, in binary, to the multiplexer over 3 digital pins (3 bit binary number, depending on the high/low state of these three pins), then, the multiplexer will redirect the signals it gets from the potentiometer we want to the common pin, where we can finally read it.

Say we want to read channel 5 of our mux, given three digital pins p1, p2, p3. We would set p1 high, p2 low and p3 high, so the mux would read HIGH, LOW, HIGH - or 101, which is 5 in binary. Then it will direct the signal from channel 5 to our common analog pin.

 Here the schematic of a mux:


y = individual channels
z = common output/input pin
E = enable (connected to ground)
Vee = negative voltage (connected to ground)
Gnd = Ground 0V
s0, s1 and s2 = digital pins that send the bits


I will be using only two potentiometers, just to keep it simple. Connect it up, Scotty!

How to connect the mux:



You see, the analog output pins are connected to channel 5 and 7 (y5 and y7 in the above schem.), these are then replaced by the single output from the mux (cyan cable), connected to the Arduino's A0 analog input pin, and three digital pins for the three bits.

Here is what it looked like when I did it with only one pot:



Right. Assuming you connected everything properly, let's move on to the code. It is partly taken from an Arduino playground post, although modified quite a bit.


int r0 = 0;      
int r1 = 0;  // the three digital pins for the bits     
int r2 = 0;         

int  bin [] = {000, 1, 10, 11, 100, 101, 110, 111};//list of binary values

void setup(){

  pinMode(2, OUTPUT);    // r0
  pinMode(3, OUTPUT);    // r1
  pinMode(4, OUTPUT);    // r2

  Serial.begin(9600); // fire up the serial 
}

 
void loop () {
  
 for (int count=0; count < 8; count++) { //loop through each channel, checking for a signal
   
   int row = bin[count]; //channel 5 = 5th element in the bin list -> 101 etc. 
   
   r0 = bitRead(row,0); //bitRead() -> parameter 1 = binary sequence, parameter 2 = which bit to read, starting from the right most bit
   r1 = bitRead(row,1); //channel 7 = 111, 1 = 2nd bit 
   r2 = bitRead(row,2); // third bit

   digitalWrite(2, r0); // send the bits to the digital pins 
   digitalWrite(3, r1);
   digitalWrite(4, r2);
      
   Serial.print(count);
   Serial.print(" ==== ");
   Serial.println(analogRead(0)); // after sending the binary sequence, the mux determines which channel to read from and sends it to this analog input

   delay (1000); // time to read the values
   
 }

 } 


I hope the comments help you figuring out what does what. Once you upload your code, open the serial monitor. You'll notice that despite only connecting 2 (or how many connected) signals to the mux, the other channels are spewing out arbitrary values. This is because they are not connected to anything and thus float. Nevertheless, the values for the channels you connected should change depending on the state of your potentiometer.

I hope I cleared things up a bit. I wrote this tutorial because I had quite a hard time pulling together the information from the various sources there are online when I first used multiplexers. It's not so difficult once you grasp the concept of the three bits being sent over the three digital pins to let the analog pin know which channel to read from, and what the different pins do. If you do have any problems, or I made a mistake somewhere, or you disagree with some of my explanations (I'm only learning this stuff myself), feel free to comment.