Hi all.
I'm building a MIDI-operated reed organ. It has 88 keys and I'm using solenoids + custom 16-channel MOSFET drivers to drive the solenoids. I'm using 3 Mega's to control the whole thing: pins 22-53 on each Mega simply going on and off as the MIDI tells them to.
The whole setup looks like this:
(Note: the small PCB on the right is that Mega's USB port. I desoldered it and put it on breadboard and connected it back up with some short wires so that I can mount it well once the action is back in the case).
I'm using Hairless Midi, which is a MIDI-over-serial program that simply sends out MIDI data at whatever baud you need over a serial port. Using a single Mega, this works great. The following is an example of my code that is running perfectly:
//variables setup
byte incomingByte;
byte note;
byte velocity;
int statusLed = 13; // select the pin for the LED
int action = 2; //0 =note off ; 1=note on ; 2= nada
//setup: declaring iputs and outputs and begin serial
void setup() {
pinMode(statusLed, OUTPUT); // declare the LED's pin as output
int inMin = 22; // Lowest input pin
int inMax = 53; // Highest input pin
for (int i = inMin; i <= inMax; i++) {
pinMode(i, OUTPUT);
}
Serial.begin(38400);
digitalWrite(statusLed, HIGH);
}
//loop: wait for serial data, and interpret the message
void loop () {
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// wait for as status-byte, channel 1, note on or off
if (incomingByte == 144) { // note on message starting starting
action = 1;
} else if (incomingByte == 128) { // note off message starting
action = 0;
} else if (incomingByte == 208) { // aftertouch message starting
//not implemented yet
} else if (incomingByte == 160) { // polypressure message starting
//not implemented yet
} else if ( (action == 0) && (note == 0) ) { // if we received a "note off", we wait for which note (databyte)
note = incomingByte;
playNote(note, 0);
note = 0;
velocity = 0;
action = 2;
} else if ( (action == 1) && (note == 0) ) { // if we received a "note on", we wait for the note (databyte)
note = incomingByte;
} else if ( (action == 1) && (note != 0) ) { // ...and then the velocity
velocity = incomingByte;
playNote(note, velocity);
note = 0;
velocity = 0;
action = 0;
} else {
//nada
}
}
}
void blink() {
digitalWrite(statusLed, HIGH);
delay(100);
digitalWrite(statusLed, LOW);
delay(100);
}
void playNote(byte note, byte velocity) {
int value = LOW;
if (velocity > 10) {
value = HIGH;
} else {
value = LOW;
}
//Basic, always runs whether doubling is enabled or not. Numbers for 3 SHOULD be 84, 109, -63
if (note > 84 && note < 109) {
digitalWrite((note - 63), value);
}
}
What also works perfectly is connecting another Mega running the exact same code (albeit code that responds to a different range of MIDI because its controlling different keys). I connect them by connecting their grounds together and RX0. Both respond to the serial data I'm sending them from my computer, which is going through one of their USB>serial adapters before going out to both of them.
In fact, it works perfectly using either the middle Mega and the right-side Mega, or the middle Mega and the left-side Mega, but as soon as I connect all three up to my serial "bus" (a cable that's running between all three) it simply does not work. Nothing happens.
So I figured either I was having noise issues (there are 88 solenoids close to the cable and power coming out of slightly-sketchy power supplies that may not be very noise-free) or maybe the built-in USB>serial adapter couldn't drive that many inputs. So I modified my code and had the middle Arduino copy every byte it recieved on Serial0 to Serial1, and had the left-side Arduino listen to Serial1 instead.
Middle Arduino code for this:
//variables setup
byte incomingByte;
byte note;
byte velocity;
int statusLed = 13; // select the pin for the LED
int action = 2; //0 =note off ; 1=note on ; 2= nada
//setup: declaring iputs and outputs and begin serial
void setup() {
pinMode(statusLed, OUTPUT); // declare the LED's pin as output
int inMin = 22; // Lowest input pin
int inMax = 53; // Highest input pin
for (int i = inMin; i <= inMax; i++) {
pinMode(i, OUTPUT);
}
//start serial with midi baudrate 31250 or 38400 for debugging
Serial.begin(38400);
Serial1.begin(38400);
digitalWrite(statusLed, HIGH);
}
//loop: wait for serial data, and interpret the message
void loop () {
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
Serial1.write(incomingByte);
// wait for as status-byte, channel 1, note on or off
if (incomingByte == 144) { // note on message starting starting
action = 1;
} else if (incomingByte == 128) { // note off message starting
action = 0;
} else if (incomingByte == 208) { // aftertouch message starting
//not implemented yet
} else if (incomingByte == 160) { // polypressure message starting
//not implemented yet
} else if ( (action == 0) && (note == 0) ) { // if we received a "note off", we wait for which note (databyte)
note = incomingByte;
playNote(note, 0);
note = 0;
velocity = 0;
action = 2;
} else if ( (action == 1) && (note == 0) ) { // if we received a "note on", we wait for the note (databyte)
note = incomingByte;
} else if ( (action == 1) && (note != 0) ) { // ...and then the velocity
velocity = incomingByte;
playNote(note, velocity);
note = 0;
velocity = 0;
action = 0;
} else {
//nada
}
}
}
void blink() {
digitalWrite(statusLed, HIGH);
delay(100);
digitalWrite(statusLed, LOW);
delay(100);
}
void playNote(byte note, byte velocity) {
int value = LOW;
if (velocity > 10) {
value = HIGH;
} else {
value = LOW;
}
//Basic, always runs whether doubling is enabled or not
if (note > 52 && note < 85) {
digitalWrite((note - 31), value);
}
}
And the left-most Arduino was running identical code except Serial was swapped out for Serial1.
This setup mostly worked, except data was clearly getting corrupted or some bytes were being skipped or something: random notes were not going down, or weren't coming back up.
Any general help on what to do now or why the serial "copying" setup was corrupting data is highly appreciated.
Thank you.