Go Down

Topic: Mux Shield (Read 11773 times) previous topic - next topic

edward11

Hi there,

While working on a midicontroller, i'm using a mux shield (/1/]http://mayhewlabs.com/products/arduino-mux-shield#!prettyPhoto[gallery]/1/)to increase the number of (analog) inputs i can use on the arduino uno. Now, i've got a little midicontroller with just 2 analogs and 1 digital working and everythings seems to work just fine. I used this setup: http://starfiretech.wordpress.com/2009/12/08/simple-arduino-midi-controler/

As i said, i want to use the mux shield to increase the number of inputs. When i use the code given on the mux shield site (the analog input example) the midi monitor gives all kinds of weird stuff, i added a screenshot of the midi monitor.

It says something about a timing clock, but as far is i know it isn''t supposed to do that... Anyone knows why it does that? And if you know how to use the mux shield, any ideas on how i can read analog pins and print the result of a potmeter change over midi?

Grtz

Grumpy_Mike

I can only think you have wired it up wrong.
The example code does not use the serial port so you must have added code to get an output, either that or you left the MIDI connected when you uploaded the code and you got rubbish.

So post the code you are actually using.

edward11

I pretty sure I did disconnect the MIDI device when uploading the example code, but I just tried it again and as one would expect the midi monitor showed nothing :).

I''m using this code to send midi data to the computer when the potmeters value is changed:
Code: [Select]
void setup()
{
   Serial.begin(31250);        // Default speed of MIDI serial port
   pinMode(13, OUTPUT);        // Light LED on pin 13 to notify of readynes
   digitalWrite(13, HIGH);
}

int iAn0Val, iAn1Val;

void loop()
{
   //Slider X
   int iAn0ValPrev = iAn0Val; //Get the previous value of slider X
   iAn0Val = analogRead(0)/8;
   analogPinMidiTX(1,iAn0Val,iAn0ValPrev); //TX the value of slider X
   
   //Slider Y
   int iAn1ValPrev = iAn1Val; //Get the previous value of slider Y
   iAn1Val = analogRead(1)/8;
   analogPinMidiTX(2,iAn1Val,iAn1ValPrev); //TX the value of slider Y
}

void analogPinMidiTX(int iChan, int iVal, int iValPrev)

  //only TX the value over midi if it is changed, as to prevent spamming the midi port and thus confusing the receiving application in learning mode
  if(iValPrev != iVal)
  {
    MidiTX(176,iChan,iVal);
  }
}

void MidiTX(unsigned char MESSAGE, unsigned char CONTROL, unsigned char VALUE) //pass values out through standard Midi Command
{
   Serial.write(MESSAGE);
   Serial.write(CONTROL);
   Serial.write(VALUE);
}


How do i get the arduino via the muxshield to read a lot of analog inputs? I assume there must be a way to alter the example code and implement the code written above to achieve this...

Grtz

Grumpy_Mike

Quote
How do i get the arduino via the muxshield to read a lot of analog inputs?

Just before you read the analogue input you write out to the multiplex select lines the bit pattern of the channel you want to read.
If you had a variable i that holds the channel number of the input you want to read then:-
Code: [Select]

   // select multiplexer channel
   digitalWrite(s0Pin, i & 0x1);
   digitalWrite(s1Pin, (i>>1) & 0x1);
   digitalWrite(s2Pin, (i>>2) & 0x1);

With s0Pin etc. being the pin numbers of the multiplex select lines.

This is an extract from my project:-
http://www.thebox.myzen.co.uk/Hardware/MIDI_Footsteps.html
Which reads in 16 analogue sensors. see the project for the schematic, it will be the same idea as your shield but will probably use different select pins. 

edward11

I have not been able to work on my project for a while due to exams, but i have finished them now..

What i don't understand is how i can integrate the code i was using to read analog inputs in the example code for reading the multiplexer. Where do i need to write the lines to select the multiplexer channel, where does my own code fit in the example code and should the example code be altered or just stay the same?

I've been trying everything that would seem logic to me, but it seems i'm really stuck on this one. Any help would be greatly appreciated :).

Greets,

Grumpy_Mike

So post what you think is right.
Basically you set up your multiplexer select pins, then read the analogue pin it is connected to.

edward11

This is what i ended with, which is obviously not right :).

Code: [Select]
//Give convenient names to the control pins
#define CONTROL0 5   
#define CONTROL1 4
#define CONTROL2 3
#define CONTROL3 2

//Create arrays for data from the the MUXs
int mux0array[16];
int mux1array[16];
int mux2array[16];

void setup()
{
  //Set MUX control pins to output
  pinMode(CONTROL0, OUTPUT);
  pinMode(CONTROL1, OUTPUT);
  pinMode(CONTROL2, OUTPUT);
  pinMode(CONTROL3, OUTPUT);
 
//Default speed of MIDI serial port
  Serial.begin(31250);
}

void loop()
{
  //This for loop is used to scroll through and store the 16 inputs on the FIRST multiplexer
  for (int i=0; i<16; i++)
  {
    //The following 4 commands set the correct logic for the control pins to select the desired input
    digitalWrite(CONTROL1, (i&7)>>2); 
    digitalWrite(CONTROL2, (i&3)>>1); 
    digitalWrite(CONTROL3, (i&1));     
   
    int s0Pin = 0
    digitalWrite(s0Pin, i & 0x1);
    //Read and store the input value at a location in the array
    mux0array[i] = analogRead(0);
  }  
   //Slider X
   int iAn0ValPrev = iAn0Val; //Get the previous value of slider X
   iAn0Val = analogRead(0)/8;
   analogPinMidiTX(1,iAn0Val,iAn0ValPrev);

 
//The following lines are for printing out results of array0
  Serial.print("mux0array: ");
  for (int i=0; i<16; i++)
  {
    Serial.print(mux0array[i]);
    Serial.print("-");
  }
  Serial.println();  //line feed
 
void analogPinMidiTX(int iChan, int iVal, int iValPrev)

  //only TX the value over midi if it is changed, as to prevent spamming the midi port and thus confusing the receiving application in learning mode
  if(iValPrev != iVal)
  {
    MidiTX(176,iChan,iVal);
  }
}
}
 
void MidiTX(unsigned char MESSAGE, unsigned char CONTROL, unsigned char VALUE) //pass values out through standard Midi Command
{
   Serial.write(MESSAGE);
   Serial.write(CONTROL);
   Serial.write(VALUE);
}


First of all, this is the error log i get when i try to upload the programm:

sketch_jun25a.cpp: In function 'void loop()':
sketch_jun25a:37: error: expected ',' or ';' before 'digitalWrite'
sketch_jun25a:39: error: 'iAn0Val' was not declared in this scope
sketch_jun25a:41: error: 'analogPinMidiTX' was not declared in this scope
sketch_jun25a:54: error: a function-definition is not allowed here before '{' token
sketch_jun25a:68: error: expected `}' at end of input

As i said before, i'm not sure how the two parts of code (example code and what i was using before) should fit together.
Furthermore, i left out the parts where the second and third multiplexer are scrolled trough and printed as to make the whole thing a little more clear.

I'm not sure whether there should be a digitalWrite(CONTROL2, ...) and a digitalWrite(s0Pin, ...) or that both are used to accomplish the same thing.
I'm not sure how to use the analogPinMidiTX and analogRead() to read the values off the multiplexer and i'm not sure whether the results should be printed  of the arrays...

Grumpy_Mike

Quote
First of all, this is the error log i get when i try to upload the programm:

These are syntax errors, that means you made a mistake in writing the code so the compiler could not understand it.
Basically you missed out a ; you put a } in the wrong place and you did not declare a variable before you used it.
This is the "corrected" version.

Code: [Select]
//Give convenient names to the control pins
#define CONTROL0 5   
#define CONTROL1 4
#define CONTROL2 3
#define CONTROL3 2

//Create arrays for data from the the MUXs
int mux0array[16];
int mux1array[16];
int mux2array[16];
int iAn0Val;

void setup()
{
  //Set MUX control pins to output
  pinMode(CONTROL0, OUTPUT);
  pinMode(CONTROL1, OUTPUT);
  pinMode(CONTROL2, OUTPUT);
  pinMode(CONTROL3, OUTPUT);
 
//Default speed of MIDI serial port
  Serial.begin(31250);
}

void loop()
{
  //This for loop is used to scroll through and store the 16 inputs on the FIRST multiplexer
  for (int i=0; i<16; i++)
  {
    //The following 4 commands set the correct logic for the control pins to select the desired input
    digitalWrite(CONTROL1, (i&7)>>2); 
    digitalWrite(CONTROL2, (i&3)>>1); 
    digitalWrite(CONTROL3, (i&1));     
   
    int s0Pin = 0;
    digitalWrite(s0Pin, i & 0x1);
    //Read and store the input value at a location in the array
    mux0array[i] = analogRead(0);
  }  
   //Slider X
   int iAn0ValPrev = iAn0Val; //Get the previous value of slider X
   iAn0Val = analogRead(0)/8;
   analogPinMidiTX(1,iAn0Val,iAn0ValPrev);

 
//The following lines are for printing out results of array0
  Serial.print("mux0array: ");
  for (int i=0; i<16; i++)
  {
    Serial.print(mux0array[i]);
    Serial.print("-");
  }
  Serial.println();  //line feed
}
void analogPinMidiTX(int iChan, int iVal, int iValPrev)

  //only TX the value over midi if it is changed, as to prevent spamming the midi port and thus confusing the receiving application in learning mode
  if(iValPrev != iVal)
  {
    MidiTX(176,iChan,iVal);
  }
}
 
void MidiTX(unsigned char MESSAGE, unsigned char CONTROL, unsigned char VALUE) //pass values out through standard Midi Command
{
   Serial.write(MESSAGE);
   Serial.write(CONTROL);
   Serial.write(VALUE);
}


I say "corrected" because although it now compiles I suspect there are still logical errors in it.

Take this line:-
Code: [Select]
//Slider X
   int iAn0ValPrev = iAn0Val;

iAn0Val has not been previously defined.
Also the line before it:-
Code: [Select]
int iAn0ValPrev = iAn0Val;
Is creating a new variable each time that line is executed. You want to define this outside of the loop() function so that it is a global variable and it's value is preserved from one iteration of the loop to another.
So that line should just read:-
Code: [Select]
iAn0ValPrev = iAn0Val;
and you should have a line saying:
Code: [Select]
int iAn0ValPrev = 0;
At the start of your code outside any function.

The line:-
Code: [Select]
    int s0Pin = 0;
    digitalWrite(s0Pin, i & 0x1);

Will define a new variable called s0Pin 16 times and each time it will assign the value of 0 to it. So you write to pin 0 which is one of the serial lines, so that is wrong. What are you trying to do here?
You also seem to have missed out writing to CONTROL0 pin, so you are not setting all 4 select lines.

I know this sounds a lot but you are very close to getting it going.

edward11

i defined s0Pin, iAn0Val and iAn0ValPrev at the beginning of the programm and added the CONTROL0 line. I think i accidently deleted it when i deleted some comments written above it. The programm loads now, but i still don't get exactly how it works. Anyways this is what i have now:

Code: [Select]
//Give convenient names to the control pins
#define CONTROL0 5   
#define CONTROL1 4
#define CONTROL2 3
#define CONTROL3 2

int s0Pin = 0;
int iAn0Val;
int iAn0ValPrev = 0;

//Create arrays for data from the the MUXs
int mux0array[16];
int mux1array[16];
int mux2array[16];


void setup()
{
  //Set MUX control pins to output
  pinMode(CONTROL0, OUTPUT);
  pinMode(CONTROL1, OUTPUT);
  pinMode(CONTROL2, OUTPUT);
  pinMode(CONTROL3, OUTPUT);
 
//Default speed of MIDI serial port
  Serial.begin(31250);
}

void loop()
{
  //This for loop is used to scroll through and store the 16 inputs on the FIRST multiplexer
  for (int i=0; i<16; i++)
  {
    //The following 4 commands set the correct logic for the control pins to select the desired input
    digitalWrite(CONTROL0, (i&15)>>3);
    digitalWrite(CONTROL1, (i&7)>>2); 
    digitalWrite(CONTROL2, (i&3)>>1); 
    digitalWrite(CONTROL3, (i&1));     
     
    digitalWrite(s0Pin, i & 0x1);
    //Read and store the input value at a location in the array
    mux0array[i] = analogRead(0);
  }  
   //Slider X
   iAn0ValPrev = iAn0Val; //Get the previous value of slider X
   iAn0Val = analogRead(0)/8;
   analogPinMidiTX(1,iAn0Val,iAn0ValPrev);

 
//The following lines are for printing out results of array0
  Serial.print("mux0array: ");
  for (int i=0; i<16; i++)
  {
    Serial.print(mux0array[i]);
    Serial.print("-");
  }
  Serial.println();  //line feed
}
void analogPinMidiTX(int iChan, int iVal, int iValPrev)

  //only TX the value over midi if it is changed, as to prevent spamming the midi port and thus confusing the receiving application in learning mode
  if(iValPrev != iVal)
  {
    MidiTX(176,iChan,iVal);
  }
}
 
void MidiTX(unsigned char MESSAGE, unsigned char CONTROL, unsigned char VALUE) //pass values out through standard Midi Command
{
   Serial.write(MESSAGE);
   Serial.write(CONTROL);
   Serial.write(VALUE);
}


what about the arrays, i don't understand how i use them in the part where they are printed. For example, what exactly does this do:

Code: [Select]
Serial.print("mux0array: ");
Do i really need this part?

And where do i read the value of the mux channels; is that here
Code: [Select]
mux0array[i] = analogRead(0);
, here
Code: [Select]
  Serial.print("mux0array: ");
  for (int i=0; i<16; i++)
  {
    Serial.print(mux0array[i]);
    Serial.print("-");
  }

, another line or do i need to add a few lines (i suspect it's the mux0array = analogRead(0))?

Grumpy_Mike

For a start the control pins look to be the wrong way round. You normally have 0 as the least significant bit, so your code should look like:-
Code: [Select]
digitalWrite(CONTROL3, (i&15)>>3);
    digitalWrite(CONTROL2, (i&7)>>2); 
    digitalWrite(CONTROL1, (i&3)>>1); 
    digitalWrite(CONTROL0, (i&1));


This line
Code: [Select]
Serial.print("mux0array: ");
Just prints the message mux0array:, it doesn't do anything with the value, anything between quotes is simply sent out to the display.
When you do
Code: [Select]
mux0array[i] = analogRead(0);
You put the value of what is on the analogue port into a variable, the actual one depends on the value of i. It is like saying put this letter into the door number i in the street called mux0array, so as the value of i changes so you change the door where you post ( store ) the value.

Code: [Select]
for (int i=0; i<16; i++)
  {
    Serial.print(mux0array[i]);
    Serial.print("-");
  }

That bit is a loop which prints out the contents of every door in the street.



edward11

But since i want to send a midi signal and not a serial signal and at the end of the sketch i have
Code: [Select]
void MidiTX(unsigned char MESSAGE, unsigned char CONTROL, unsigned char VALUE) //pass values out through standard Midi Command
{
   Serial.write(MESSAGE);
   Serial.write(CONTROL);
   Serial.write(VALUE);
}


,doesn't this mean i can get rid of the whole serial.print part? I don't see the need for
Code: [Select]
  for (int i=0; i<16; i++)
  {
    Serial.print(mux0array[i]);
  }
  Serial.println();  //line feed
}

when i want to send midi.

Then to select the pins i would use
Code: [Select]
digitalWrite(s0Pin, i & 0x1);
and so on. Then i would want to store the values of those pins in the array, so that would be
Code: [Select]
mux0array[i] = analogRead(s0Pin)/8  //divide by 8 to get in the range of 1-127

Finally i would use something like to get the values from the array.
Code: [Select]
iAn0Val = mux0array[i]

Is this in the direction of how i'm supposed to use the shield??

Grumpy_Mike

Quote
doesn't this mean i can get rid of the whole serial.print part?

Yes, you only have it in at the moment for testing.

Quote
Then i would want to store the values of those pins in the array

What you want to do is to store the values you send in the array and only send a value when what you read is not what is in the array. Otherwise you will swamp the MIDI receiver with duplicate values.
Code: [Select]
temp = analogRead(s0Pin)/8  //divide by 8 to get in the range of 1-127
if( abs(mux0array[i] - temp) > 2) {
    mux0array[i] = temp;
    MidiTX(char(0xB0), control[i], char(mux0array[i]) ); // control[i] is a char look up table for the controller number to change
   }


edward11

I tried to fit the code into the sketch i already had. This is what I came up with:

Code: [Select]
//Give convenient names to the control pins
#define CONTROL0 5   
#define CONTROL1 4
#define CONTROL2 3
#define CONTROL3 2

int s0Pin = 0;
int iAn0Val;
int iAn0ValPrev = 0;
int temp;
int control[4];

//Create arrays for data from the the MUXs
int mux0array[16];
int mux1array[16];
int mux2array[16];


void setup()
{
  //Set MUX control pins to output
  pinMode(CONTROL0, OUTPUT);
  pinMode(CONTROL1, OUTPUT);
  pinMode(CONTROL2, OUTPUT);
  pinMode(CONTROL3, OUTPUT);
 
//Default speed of MIDI serial port
  Serial.begin(31250);
}

void loop()
{
  //This for loop is used to scroll through and store the 16 inputs on the FIRST multiplexer
  for (int i=0; i<16; i++)
  {
    //The following 4 commands set the correct logic for the control pins to select the desired input
    digitalWrite(CONTROL3, (i&15)>>3);
    digitalWrite(CONTROL2, (i&7)>>2); 
    digitalWrite(CONTROL1, (i&3)>>1); 
    digitalWrite(CONTROL0, (i&1));     
     
    digitalWrite(s0Pin, i & 0x1);
    temp = analogRead(s0Pin)/8;  //divide by 8 to get in the range of 1-127
    if( abs(mux0array[i] - temp) > 2) {
        mux0array[i] = temp;
        MidiTX(char(0xB0), control[i], char(mux0array[i]) );   //control[i] is a char look up table for the controller number to change
        }
  }
}

void MidiTX(unsigned char MESSAGE, unsigned char CONTROL, unsigned char VALUE) //pass values out through standard Midi Command
{
   Serial.write(MESSAGE);
   Serial.write(CONTROL);
   Serial.write(VALUE);
}


The error log gives nothing when I upload the programm and I'm pretty confident that this - or something like it - should work. One question though: I thought the size of control should be 4, because of the 4 control select pins. Is that right?

I'm not receiving midi yet, but I suspect that I didn't wire up the shield the right way. Working on that!

Grumpy_Mike

I don't understand what this is doing:-
Code: [Select]
digitalWrite(s0Pin, i & 0x1);
It might be stopping it working. What do you think it does?

Quote
One question though: I thought the size of control should be 4, because of the 4 control select pins.

No it should be 16 because you have 16 MIDI control channels you want to control.
This should be initialised with values you want to use, like this:-
Code: [Select]
int control[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };

or any set of values you want to use.

edward11

Code: [Select]
digitalWrite(s0Pin, i & 0x1);
I thought this part wrote a value from the mux to the variable s0Pin, which could later be used in the array.
I figured that
Code: [Select]
    //The following 4 commands set the correct logic for the control pins to select the desired input
    digitalWrite(CONTROL3, (i&15)>>3);
    digitalWrite(CONTROL2, (i&7)>>2); 
    digitalWrite(CONTROL1, (i&3)>>1); 
    digitalWrite(CONTROL0, (i&1));

'sets the correct logic for the controlpins to select the desired input' and that s0Pin was used to actually write the desired input to a variable.
But since you say you don't understand why it's there, I suppose it's unnecessary?

What then, should the analogRead funtion read?
Code: [Select]
temp = analogRead(XXX)/8;

As for the control[] array, I understand how to initialise it, but what values do i want in it? I mean, which values should be in it. I suppose it would be something like control pin numbers or so.

Go Up