16 pots MIDI controller

Hello everyone

I’m trying to make a simple Midi controller with 16 potentiometers. I’m using a teensy 3.1 and a 16 channel mux from Sparkfun SparkFun Analog/Digital MUX Breakout - CD74HC4067 - BOB-09056 - SparkFun Electronics (that is in fact the CD74HC4067 on a breadboard).

I think my wiring is good here is a schematic of it

My real problem is in the coding part, I’m really bad at it. I lost a lot of time searching for examples and messing with them but couldn’t make my controller work. Here is the code I made it’s probably awful and if somebody has a simpler way of reading a pot from the mux and sending it in a MIDI signal to my computer he’s going to be my best friend :slight_smile:

#include <Bounce.h>

const int channel = 1;


int s0 = 10;
int s1 =11;
int s2 = 14;
int s3 = 13; //Mux control pins

int controlpin = A0;

int previouspot0 = 0;
int previouspot1 = 0;
int previouspot2 = 0;
int previouspot3 = 0;
int previouspot4 = 0;
int previouspot5 = 0;
int previouspot6 = 0;
int previouspot7 = 0;
int previouspot8 = 0;
int previouspot9 = 0;
int previouspot10 = 0;
int previouspot11 = 0;
int previouspot12 = 0;
int previouspot13 = 0;
int previouspot14 = 0;
int previouspot15 = 0; // store previous values


int MUX_read = 0;

elapsedMillis msec = 0;


void setup(){

  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT); 
  
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  
}

void loop(){
  
  if (msec >= 20) {
    msec = 0;
    int pot0 = readMux(0) / 8;
    int pot1 = readMux(1) / 8;
    int pot2 = readMux(2) / 8;
    int pot3 = readMux(3) / 8;
    int pot4 = readMux(4) / 8;
    int pot5 = readMux(5) / 8;
    int pot6 = readMux(6) / 8;
    int pot7 = readMux(7) / 8;
    int pot8 = readMux(8) / 8;
    int pot9 = readMux(9) / 8;
    int pot10 = readMux(10) / 8;
    int pot11 = readMux(11) / 8;
    int pot12 = readMux(12) / 8;
    int pot13 = readMux(13) / 8;
    int pot14 = readMux(14) / 8;
    int pot15 = readMux(15) / 8; //read values and write them in variables
    
    // transmit only if control change
   if (pot0 != previouspot0) {
      usbMIDI.sendControlChange(controlpin, pot0, channel);
      previouspot0 = pot0;
    }
    if (pot1 != previouspot1) {
      usbMIDI.sendControlChange(controlpin, pot1, channel);
      previouspot1 = pot1;
    }
    if (pot2 != previouspot2) {
      usbMIDI.sendControlChange(controlpin, pot2, channel);
      previouspot2 = pot2;
    }
    if (pot3 != previouspot3) {
      usbMIDI.sendControlChange(controlpin, pot3, channel);
      previouspot3 = pot3;
    }
    if (pot4 != previouspot4) {
      usbMIDI.sendControlChange(controlpin, pot4, channel);
      previouspot4 = pot4;
    }
    if (pot5 != previouspot5) {
      usbMIDI.sendControlChange(controlpin, pot5, channel);
      previouspot5 = pot5;
    }
    if (pot6 != previouspot6) {
      usbMIDI.sendControlChange(controlpin, pot6, channel);
      previouspot6 = pot6;
    }
    if (pot7 != previouspot7) {
      usbMIDI.sendControlChange(controlpin, pot7, channel);
      previouspot7 = pot7;
    }
    if (pot8 != previouspot8) {
      usbMIDI.sendControlChange(controlpin, pot8, channel);
      previouspot8 = pot8;
    }
    if (pot9 != previouspot9) {
      usbMIDI.sendControlChange(controlpin, pot9, channel);
      previouspot9 = pot9;
    }
    if (pot10 != previouspot10) {
      usbMIDI.sendControlChange(controlpin, pot10, channel);
      previouspot10 = pot10;
    }
    if (pot11 != previouspot11) {
      usbMIDI.sendControlChange(controlpin, pot11, channel);
      previouspot11 = pot11;
    }
    if (pot12 != previouspot12) {
      usbMIDI.sendControlChange(controlpin, pot12, channel);
      previouspot12 = pot12;
    }
    if (pot13 != previouspot13) {
      usbMIDI.sendControlChange(controlpin, pot13, channel);
      previouspot13 = pot13;
    }
    if (pot14 != previouspot14) {
      usbMIDI.sendControlChange(controlpin, pot14, channel);
      previouspot14 = pot14;
    }
     if (pot15 != previouspot15) {
      usbMIDI.sendControlChange(controlpin, pot15, channel);
      previouspot15 = pot15;
    }
    
  }
   
  // MIDI Controllers should discard incoming MIDI messages.
   while (usbMIDI.read()) {
    // ignore incoming messages
  }
}

int readMux(int channel){
  int controlPin[] = {s0, s1, s2, s3};

  int muxChannel[16][4]={
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10
    {1,1,0,1}, //channel 11
    {0,0,1,1}, //channel 12
    {1,0,1,1}, //channel 13
    {0,1,1,1}, //channel 14
    {1,1,1,1}  //channel 15
  };

  //loop through the 4 sig
  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
  delayMicroseconds(25);
  
  int n;
  n = analogRead (A0);
  return n;
}

Thanks for your help

Step one is to learn about arrays, and replace the 16 pot's and 16 previous pot's with arrays

Something like this ?

#include <Bounce.h>

const int channel = 1;

int s0 = 10;
int s1 =11;
int s2 = 14;
int s3 = 13; //Mux control pins

int controlpin = A0;

int pot[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // store values
int previouspot[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // store previous values

int MUX_read = 0;

elapsedMillis msec = 0;


void setup(){

  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT); 
  
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  
}

void loop(){
  
//read values and write them in variables
    for (int h = 0; h < 15; h++){
    pot[h] = readMux(h) / 8;
   }
    
     
// transmit only if control change
for (int g = 0; g < 15; g++){
   if (pot[g] != previouspot[g]) {
      usbMIDI.sendControlChange(controlpin, pot[g], channel);
      previouspot[g] = pot[g];
    }
  }
  
// ignore incoming messages
   while (usbMIDI.read()) {
     }
  }

//
int readMux(int channel){
  int controlPin[] = {s0, s1, s2, s3};

  int muxChannel[16][4]={
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10
    {1,1,0,1}, //channel 11
    {0,0,1,1}, //channel 12
    {1,0,1,1}, //channel 13
    {0,1,1,1}, //channel 14
    {1,1,1,1}  //channel 15
  };

//loop through the 4 sig
  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
  delayMicroseconds(25);
  
  int n;
  n = analogRead (A0);
  return n;
}

Indeed :slight_smile: But your next task is to replace muxChannel with some bit-manipulation,
since the 4 select lines are just a 4-bit integer.

  digitalWrite (s0, channel & 0b0001) ;
  digitalWrite (s1, channel & 0b0010) ;
  digitalWrite (s2, channel & 0b0100) ;
  digitalWrite (s3, channel & 0b1000) ;

Although you can use a loop and an array here too if you want.

Your s0..s3 pin numbers appear to be CD4067 pin numbers, not Arduino pin
numbers (which they need to be). s0 is the least significant bit, note (I've
corrected that above)

#define s0 8
#define s1 9
#define s2 10
#define s3 11

Thanks for your help :smiley:

First I don’t know if it really changes something in this case but I’m using a Teensy 3.1

I replaced the muxread with what you suggested and think I understood your correction.
For the second thing I’m not sure if I’m getting it correctly. I realized I declared the wrong pins for s0, s1, s2 & s3. Is it what you meant or is it more ? Is it okay if I declare them with int or do I need to use a #define ? To be honest I don’t get the difference :blush:

I repost my code with the things you gave me and thanks you again for helping me :wink:

#include <Bounce.h>

const int channel = 1;


int s0 = 8;
int s1 = 9;
int s2 = 10;
int s3 = 11;

int controlpin = A0;

int pot[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // store values

int previouspot[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // store previous values

int MUX_read = 0;

elapsedMillis msec = 0;


void setup(){

  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT); 
  
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  
}

void loop(){
  
//read values and write them in variables
    for (int h = 0; h < 15; h++)
    pot[h] = readMux(h) / 8;
   
     
// transmit only if control change
for (int g = 0; g < 15; g++){
   if (pot[g] != previouspot[g]) {
      usbMIDI.sendControlChange(controlpin, pot[g], channel);
      previouspot[g] = pot[g];
    }
  }
  
// ignore incoming messages
   while (usbMIDI.read()) {
     }
  }

//
int readMux(int channel){
  int controlPin[] = {s0, s1, s2, s3};

  int muxChannel[16][4]={
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10
    {1,1,0,1}, //channel 11
    {0,0,1,1}, //channel 12
    {1,0,1,1}, //channel 13
    {0,1,1,1}, //channel 14
    {1,1,1,1}  //channel 15
  };

//loop through the 4 sig
    digitalWrite (s0, channel & 0b0001) ;
    digitalWrite (s1, channel & 0b0010) ;
    digitalWrite (s2, channel & 0b0100) ;
    digitalWrite (s3, channel & 0b1000) ;
  
  int n;
  n = analogRead (A0);
  return n;
}

Good keep going.
Read this to see how to use an array to get the mux address lines out in a simple manner.
http://www.thebox.myzen.co.uk/Tutorial/Arrays.html