Digital Multiplexing: Best 16x mux, can i use 4067

Hi guys! I've a question about multiplexing I'm building a custom midi controller and i'm looking at the best way to add many buttons. What is the best 16 x Digital Multiplexer i can use? I've been testing the 4021 but it's 8x, is there the possibility to use a 16x? Which model?

I also have a HEF4067BP, that's analogue... can i use this for digital as well??

One last question... Is there a way to avoid using a resistor for each button? Is there a way to "compress" the circuit layout? ....mmm this might be a not very expert question

anyway, thanks in advance for any help g

You can create a matrix of buttons... 16 switches with 8 IO pins, 64 switches with 16 IO pins, and so on

thanks!

i went to have a look at the documentation while i was doing some testings on the arduino and found this:

... how to use two 4051 (one as demultiplexer and one as multiplexer) in a 8x8 Matrix to check 64 buttons or other digital Inputs just with one digital-In-Pin on the arduino (with the second setup you can just have two buttons on at the same time...

Unfortunately i need to press more than two buttons at the same time. I've been trying with the 4021 mux (without matrix).... i'll probably need to use 20 mux (!) i hope it will not explode :) I'll post the code i prepared to control the buttons/mux later.

Even if you use the example to the left on the 4051 page you can only push one button for each 4051.

The 4051 can only select one of it' 8 inputs at a time. The same is true for 4067.

So 4021 is probably a beter solution.

http://www.arduino.cc/en/Tutorial/ShiftIn

Yes!
In fact i’m using the shif-in with 4021.

Here’s the code i made:

#include <MIDI.h>


// ******************************************
// Variables definitions
// ******************************************

// *********************
// Buttons Multiplexing Variables
// Definition of pins
int buttonsMuxClockPin = 7;
int buttonsMuxLatchPin = 8;
int buttonsMuxDataPin = 9;
// Define variables to hold the data 
// for each shift register.
byte muxButtons1 = 0;
byte muxButtons2 = 0;
// byte muxButtons3 = 0;
// byte muxButtons4 = 0;
// ...
// General midi notes
char buttonsMuxNotes1[] = {0, 1, 2, 3, 4, 5, 6, 7};
char buttonsMuxNotes2[] = {67, 68, 69, 70, 71, 72, 73, 74};
// char buttonsMuxNotes3[] = {75, 76, 77, 78, 79, 90, 91, 92};
// char buttonsMuxNotes4[] = {93, 94, 95, 96, 97, 98, 99, 100};
// ...
// Status of each button of the mux
boolean buttonsMuxStatus1[] = {0,0,0,0,0,0,0,0};
boolean buttonsMuxStatus2[] = {0,0,0,0,0,0,0,0};
// boolean buttonsMuxStatus3[] = {0,0,0,0,0,0,0,0};
// boolean buttonsMuxStatus4[] = {0,0,0,0,0,0,0,0};
// ...
// Midi channel where to send notes for each mux
int buttonsMuxMidiChannel1 = 1;
int buttonsMuxMidiChannel2 = 2;
// int buttonsMuxMidiChannel3 = 8;
// int buttonsMuxMidiChannel4 = 16;
// ...
// Debounce settings
long muxButtonsTime = 0;         // the last time the output pin was toggled
long muxButtonsDebounce = 100;   // the debounce time, increase if the output flickers



// *********************
// Set up application
// *********************
void setup() {
  // Standard serial begin
  // Serial.begin(9600);
  // Midi serial begin
  Serial.begin(31250); 

 // Buttons Mux
  // Define pin modes
  pinMode(buttonsMuxLatchPin, OUTPUT);
  pinMode(buttonsMuxClockPin, OUTPUT); 
  pinMode(buttonsMuxDataPin, INPUT);
}



// ******************************************
// Main Loop
// ******************************************
void loop() {
  // Butons Mux
  // Function that handles digital mux for buttons
  startReadingButtonMux();
  
  // Serial.println("-------------------");
  //delay so all these print satements can keep up. 
  // delay(500);
}

// ******************************************
// Buttons Mux
// ******************************************
// Activate Digital Mux for Buttons
void startReadingButtonMux() {
  //  Pulse the latch pin:
  //  Set it to 1 to collect parallel data
  digitalWrite(buttonsMuxLatchPin, 1);
  // .... collecting data from digital inputs of MUX ... wait ...
  delayMicroseconds(20);
  // Set it to 0 to transmit data serially  
  digitalWrite(buttonsMuxLatchPin, 0);

  // While the shift register is in serial mode
  //collect each shift register into a byte
  //the register attached to the chip comes in first 
  muxButtons1 = shiftIn(buttonsMuxDataPin, buttonsMuxClockPin);
  muxButtons2 = shiftIn(buttonsMuxDataPin, buttonsMuxClockPin);
  // Add more mux here...

  analyzeButtonsMux(muxButtons1, buttonsMuxNotes1, buttonsMuxStatus1, buttonsMuxMidiChannel1);
  analyzeButtonsMux(muxButtons2, buttonsMuxNotes2, buttonsMuxStatus2, buttonsMuxMidiChannel2);
  // Add more mux here...
}

// ShiftIn function
// Just needs the location of the data pin and the clock pin
// it returns a byte with each bit in the byte corresponding
// to a pin on the shift register. leftBit 7 = Pin 7 / Bit 0= Pin 0
byte shiftIn(int myDataPin, int myClockPin) { 
  int i;
  int temp = 0;
   // int pinState;
  byte myDataIn = 0;

  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, INPUT);

  // we will be holding the clock pin high 8 times (0,..,7) at the
  // end of each time through the for loop

  // at the begining of each loop when we set the clock low, it will
  // be doing the necessary low to high drop to cause the shift
  // register's DataPin to change state based on the value
  // of the next bit in its serial information flow.
  // The register transmits the information about the pins from pin 7 to pin 0
  // so that is why our function counts down
  
  // Loop for all the pins of the shift reg.
  for (i=7; i>=0; i--)
  {
    digitalWrite(myClockPin, 0);
    delayMicroseconds(2);
    temp = digitalRead(myDataPin);
    if (temp) {
      // pinState = 1;
      // Set the bit to 1 no matter what
      myDataIn = myDataIn | (1 << i);
    }
    else {
      //turn it off -- only necessary for debuging
      //print statement since myDataIn starts as 0
      // pinState = 0;
    }

    //Debuging print statements
    // Serial.print("Valore Pin: ");
    // Serial.print(pinState);
    // Serial.print(" - ");
    //Serial.println (dataIn, BIN);
    digitalWrite(myClockPin, 1);
  }
  //debuging print statements whitespace
  //Serial.println();
  //Serial.println(myDataIn, BIN);
  return myDataIn;
}

// Function that analiyzes the data from the Mux
// Parameters:
// 1. Byte with the state of the 8 pins
// 2. Array of notes corresponfding to the 8 pins
// 3. Array off boolean values indicates the actual status of each not/pin
// 4. Midi channel to send the midi data for the 8 notes of the mux
void analyzeButtonsMux(byte incomingData, char* muxNotes, boolean* muxStatus, int midiChannel) {
  // Loop thru the Byte
  for (int n=0; n<=7; n++)
  {
    // if 'n' value equals 1
    if (incomingData & (1 << n) ){
      //print the value of the array location
      // Pin "i" has value 1! 
      // If that note was not playing.....
      if(muxStatus[n] == 0 && (millis() - muxButtonsTime > muxButtonsDebounce) ) { // Some debouncing here
        // playMuxOnNotes(n, muxNotes, midiChannel);
        sendMidi(NoteOn, muxNotes[n], 120, midiChannel);
        muxStatus[n] = 1;
        muxButtonsTime = millis(); // Reset debouncing variables
      }
    } else { 
      if(muxStatus[n] == 1 && (millis() - muxButtonsTime > muxButtonsDebounce) ) { // If that note was already playing .... Some debouncing here
        // playMuxOffNotes(n, muxNotes, midiChannel);
        sendMidi(NoteOff, muxNotes[n], 120, midiChannel);
        muxStatus[n] = 0;
        muxButtonsTime = millis(); // Reset debouncing variables
      }
    }
  }
}

// ******************************************
// MIDI Functions
// ******************************************
// Send a MIDI note-on/off message.  
void sendMidi(char cmd, char data1, char data2, int midiChannel) {
  // Based on midi library
  MIDI.send(cmd, data1, data2, midiChannel);
}

It retrieve the data from the 4021 and send it via MIDI.
At the beginning i set some arrays that indicate which Midi Note corresponds to each button:

buttonsMuxNotes1, buttonsMuxNotes2…

I have also some variables that set the midi channel:

buttonsMuxMidiChannel1, buttonsMuxMidiChannel2, buttonsMuxMidiChannel3…

Do you think there’s a way to make this program better? Any way to improve it?

g

Do you think there's a way to make this program better? Any way to improve it?

I think your program looks fine, but I would recommand changing all hardcoded constants into its variable / define name, such as HIGH LOW etc.

You could also save a bit of ram / increase speed by changing some datatypes.

My 2cHz. ::)

Ciao AlphaBeta! so you mean changing

digitalWrite(buttonsMuxLatchPin, 0);
digitalWrite(buttonsMuxLatchPin, 1);
digitalWrite(myClockPin, 0);
digitalWrite(myClockPin, 1);

to

digitalWrite(buttonsMuxLatchPin, LOW);
digitalWrite(buttonsMuxLatchPin, HIGH);
digitalWrite(myClockPin, LOW);
digitalWrite(myClockPin, HIGH);

??

For datatypes... what do you mean?? Which datatypes can i modify to make it better??

Thanks in advance :) g

what do you mean?? Which data types can i modify to make it better

Change int into byte, less space to store and faster to do stuff with (although I am not convinced that the compiler takes notice of this)

shall i change

// Definition of pins int buttonsMuxClockPin = 7; int buttonsMuxLatchPin = 8; int buttonsMuxDataPin = 9;

and

// Midi channel where to send notes for each mux int buttonsMuxMidiChannel1 = 1; int buttonsMuxMidiChannel2 = 1; int buttonsMuxMidiChannel3 = 2; int buttonsMuxMidiChannel4 = 2; int buttonsMuxMidiChannel5 = 8; int buttonsMuxMidiChannel6 = 8; int buttonsMuxMidiChannel7 = 16;

into byte type?

(thanks for helping)

ps. i'll move this thread to software forum section

g

Yes change them as they will never go above 255.

In fact I don't suppose you ever change those :- buttonsMuxMidiChannel variables so why not make them # defines. Like this:-

define buttonsMuxMidiChannel4 2

It makes the code easer to read without requiring any storage.

That's clear! thanks, i'll change it!