Thursday, November 08, 2007

Pots and switches to midi data

This schematic and program has been tested and found working.

I am sure that the code can be optimised quite a bit further.

This post is in response to a number of comments by an anonymous user in regards to an earlier example of using the Arduino to output continuous controller MIDI data (see here).

In this example, eight pots and eight switches are read and sent as various MIDI controller numbers.


Schematic
This circuit uses a 4051 to multiplex the pots and a 4021 to shift in the switch states.
Notes:
  • The value of R17 should be 220Ω
  • The value of R1 - R8 should be somewhere between 4kΩ and 20kΩ. I have used 20kΩ 0.25W 5% resistors in the photo examples.
  • Jumpers JP1 represent Arduino digital pins 11, 10 and 12
  • Jumpers JP2 represent Arduino digital pins 4, 3 and 2
  • Jumpers JP3 represent Arduino 5V and TX pins (see here for an example of connecting the Arduino to a MIDI connection).
  • Jumpers JP5 represent the MIDI connection (see here for an example of connecting the Arduino to a MIDI connection)
  • Jumper JP4 represents Arduino analog input pin 0
Breadboard Example

The breadboard with the Arduino.


The pots and the 4051.


The 8 x SPST DIP switch and the 4021.

Arduino Code
The sketch will only send data for a given pot / switch if that controllers state has changed since the last loop. This saves any unnecessary MIDI data from being sent.

Important Variables:
  • status_byte (default: 176)
    This sets the fact that it is controller data that is being sent. Values from 176 to 191 sets the channel from 1 to 16. Each control shares the same status byte (and therefore is sent using the same channel).

  • cc_on_byte (default: 127)
    This sets the value of a switch when that switch is high / pressed. This value is the same for all eight switches.

  • cc_off_byte (default: 0)
    This sets the value of a switch when that switch is low / depressed. This value is the same for all eight switches.

  • ana_cc[] (default: {20, 21, 22, 23, 24, 25, 26, 27})
    This array sets the controller numbers for the pots 1 to 8

  • dig_cc[] (default: {28, 29, 30, 31, 32, 33, 34, 35})
    This array sets the controller numbers for the switches 1 to 8


/*
Digital and Analog Data to MIDI Output
by Sebastian Tomczak


*/

byte status_byte = 176;
// control change on channel 1

byte cc_on_byte = 127;
// data to send if button is pressed

byte cc_off_byte = 0;
// data to send if button is depressed

byte ana_cc[] = {
20, 21, 22, 23, 24, 25, 26, 27}
; // set controller numbers for the pots

byte dig_cc[] = {
28, 29, 30, 31, 32, 33, 34, 35}
; // set controller numbers for the switches

byte data_ana_cc[] = {
255, 255, 255, 255, 255, 255, 255, 255}
;

byte data_dig_cc[] = {
0, 0, 0, 0, 0, 0, 0, 0}
;


byte data = 0;

int latchPin = 10; // set the latch pin
int clockPin = 11; // set the clock pin
int dataPin = 12;// set the data in pin

byte digital_data = 0;

int state = 0;

void setup() {
Serial.begin(31250);
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);

pinMode(latchPin,OUTPUT);
pinMode(clockPin,OUTPUT);
pinMode(dataPin,INPUT);

digitalWrite(latchPin,HIGH);
digitalWrite(clockPin,HIGH);
}

void loop() {
delayMicroseconds(20);
digitalWrite(latchPin,0);

byte myDataIn = 0;
for (int j=7; j>=0; j--)
{
digitalWrite(clockPin, 0);
delayMicroseconds(20);
state = digitalRead(dataPin);
if (state) {
if(data_dig_cc[j] != 1) {
Serial.print(status_byte);
Serial.print(dig_cc[j]);
Serial.print(cc_on_byte);
data_dig_cc[j] = 1;
}
}
else {
if(data_dig_cc[j] != 0) {
Serial.print(status_byte);
Serial.print(dig_cc[j]);
Serial.print(cc_off_byte);
data_dig_cc[j] = 0;
}
}
digitalWrite(clockPin, 1);
}
digitalWrite(latchPin, 1);

for(byte i = 0; i <= 7; i++) { PORTD = i * 4; data = analogRead(0) >> 3;
if(data_ana_cc[i] != data) {
Serial.print(status_byte);
Serial.print(ana_cc[i]);
Serial.print(data);
data_ana_cc[i] = data;
}
}
}

13 comments:

Anonymous said...

Anonymous would like to thank you...:)

thanks seb, great stuff.
Hopefuly I'll find some time tomorrow to test it on my circuit. thanks again

Sebastian Tomczak said...

yeah okay good luck... let me know how it all goes!

who is this by the way???

Sebastian Tomczak said...

Anonymous user, i have updated the code a little. It allows for more functions to be set initially for each controller...

http://little-scale.blogspot.com/2007/11/more-pots-and-switches-to-midi-data.html

Anonymous said...

hi seb, your example seems to work ok in my circuit.

However, my 4021 is faulty so I had to modify your code in order to use 3 digital pins as inputs (for 3 switches).

just a couple of questions though:

i) workPort = (i / 2) * 4;
PORTD = workPort;

I'm not sure I understand what these 2 lines do

ii) byte data_send = 0; // stores outgoing byte for spi bus

is this referred to the communocation between the atmeg and the multiplexers?

Finally, I noticed that this example sends MIDI data
continuously, even when I don't rotate any pot or press any switch. Is this normal?

thanks for your help.

Sebastian Tomczak said...

Hey Warpie,
Can't seem to find either of the lines you are talking about in the code in this example.

Could you point out where abouts they are? Are you using this code from *this* post?

Also... in regards to sending MIDI data all of the time... see the newer version at:

http://little-scale.blogspot.com/2007/11/more-pots-and-switches-to-midi-data.html

byte data_send looks like it is a hangover from an SPI protocol i might have been working on.

workPort = i ...

looks like it might have something to do with the multiplexers but not in this context... hmmm... strange...


regards,
sebastian tomczak

warpie said...

ehh sorry seb,

these 2 lines are in your original MIDI out example. The one with the 2 4051s.

warpie

Sebastian Tomczak said...

ahh, thought so.

Victor495 said...

Is there any difference in the sketch if I put a 4051 and 8 SPDT where is the 4021

nathan said...

Thanks for posting this, i'd be a little lost without it.

I have one question though-

I have one 10k pot wired to a 4051 and it only partially works- it will turn a virtual midi knob half way and that's it. Also, the arduino is sending non-stop random midi messages that can't be stopped.

do i need more than one pot wired to test it or should it work with just one pot?

Any ideas?

Vik said...

Hi, I'm a beginner in electronics and I have built this project. On Arduino I get this error message:



sketch_sep04c:0: error: expected constructor, destructor, or type conversion before '&&' token
sketch_sep04c.cpp: In function 'void loop()':
sketch_sep04c:68: error: 'status_byte' was not declared in this scope
sketch_sep04c:76: error: 'status_byte' was not declared in this scope
sketch_sep04c:88: error: 'status_byte' was not declared in this scope

(I have replaced the switch with buttons...)

Besides, in the monitor view's baudrate menu 31250 does not show.

Is there anybody out there to help?

Vik said...

Sorry but now it's compiled the error is:

Binary sketch size: 3 164 bytes (of a 14 336 byte maximum)
avrdude: stk500_getsync(): not in sync: resp=0x44
What does it mean?

I hope someone can help. Thanks.

HANKENSTIEN said...

I too am having issues with some pots only working partially, and sometimes, I get the constant random sending of all sorts of messages?
One of my thoughts is that it needs a sort of denounce, but not sure if it can simply be done with a pull-down resistor to ground and if so whats a good size resistor, or can it be done in the code? I think Id rather add a resistor it would seem to be more stable, not sure where to start on the ohm-age though.

BAW said...

I used
if( cc >= ( lastAnalogValue[i] + 2 ) || cc <= ( lastAnalogValue[i] - 2 ) )

for the input change check.

It effectively halves the resolution of the pots but solved the random number issues I was getting. Obviously not great for applications where exact values are required but otherwise works well.