Receive Serial, Transmit Serial1

Hey Arduinoids.

I'm hoping someone could guide me in the right direction regarding the correct coding to send and receive data between the 'Serial' and 'Serial1' pins. Actually an example would really help me understand the process. :-/

So, I have my MEGA2560 receiving MIDI messages in via USB, and transmitting another MIDI message out each time it receives that first message (ping). I have this set up using Callbacks and MIDI.sendNoteOn. It is functioning properly.

I have the Tx of 'Serial1' connected to the Rx of an RS232 converter, and the converters Tx to the Arduinos Rx on 'Serial1'.

OK, so here's what I am having trouble figuring out. I am receiving MIDI messages from my PC into the Arduino, I assume they are coming in on the 'Serial' Rx pin based on the Rx LED activity. I then want to convert that message to another message my RS232 device wants to see to function. However, the RS232 converter is connected to the 'Serial1' pins. So I need to shift the incoming messages from the 'Serial', translate the message, and out to 'Serial1'.

Then, vice versa. Any RS232 messages transmitting from my controller back into the Arduino via the 'Serial1' pins, those MIDI messages translated back to what my PC program wants to see, transmitting back on 'Serial'.

I hope I am clear enough on what I hope to achieve here, any guidance it greatly appreiated!

Could you provide an example of what comes in and what needs to go out?

Yes sure.

So in my audio recording program, I want to press the Mute button on Track Channel 1. If I click that button, the corresponding LED will light up on my external controller next to the controllers Mute button. And then the opposite, pressing Mute on my controller will activate Mute in the recording program.

So, set up the way I am now, pressing Mute (Track Channel 1) in the program sends the message 'B0 0C 00 B0 2C 02' to the Arduino. Now as soon as I receive that message I need to send message 'B0 46 7F', then 'B0 46 00' immediately following, out 'Serial1' to my external controller, turning on its LED.

The opposite, pressing Mute on my external controller sends 'B0 46 7F' from the controller, to the Arduino via 'Serial1'. Then message 'B0 0F 00 B0 2F 42' back to my recording program via 'Serial'.

Does everything contain B0?

You could try a look up table of the bytes combined together as a word or just the last two bytes as an int. Then have one part scan the incoming bytes (after converted) and the other send out appropriate response.

I would need to know more to give you a better answer. Some links to these commands would be helpful
.

There is no link to the commands per se. I had to find out what data was being sent from my controllers and convert those to the HUI protocol, custom. I've been using Bome Midi Translator to translate the midi messages, and it all works, I am just now looking for a way to eliminate the need for software running in the background to use these controllers. I will post some images showing the midi messages that need to be sent/received for a better idea. But basically, I've described everything needed to make the conversion happen above, I just don't know the proper code to use to make it happen :confused:

If it's any help, attached is a sketch I wrote a while back that reads MIDI and decodes it, sending the results to Serial (on a Uno). Therefore it reads MIDI on one serial port, and sends results on another.

Video of it in operation

MIDI_decoder.txt (13.7 KB)

Well you can still use the lookup table. If you have multiple commands, then you can use 2 lookup tables, one for the receiving side and the other for the transmitting side.

What you need to do is convert the 3 incoming bytes to a unsigned long (4 bytes) variable, then compare that variable to one that is in the lookup table and if it matches, see what that index is and send out the response.

Here is an example. (Added comments)

unsigned long Receiver[4] = {0x414141, 0x424242, 0x434343, 0x444444};
unsigned long Transmiter[4] = {0x616161, 0x626262, 0x636363, 0x646464};
unsigned long temp = 0;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop()
{
  // put your main code here, to run repeatedly:
  static byte j = 0;
  temp = 0;

  if (Serial.available() > 2) // or (... == 3) for exactly 3 bytes
  {
    for (byte i = 0; i < 3; i++) // 3, for the 3 bytes you are looking for
    {
      char myData = Serial.read();// collect the incoming byte
      //Serial.println(myData, HEX);
      temp = (temp << 8) | myData; // store them into a 4 byte variable + bit shifting
    }

    for (j = 0; j < 4; j++) // 4 = the number of commands in your array
    {
      if (temp == Receiver[j]) // if your bitShifted bytes are equal to one of the commands, then this condition is true
      {
        Serial.print("We have a match at index: ");
        Serial.println(j);
        delay(1000); // just for effect
        Serial.print("Sending response: ");
        Serial.println(Transmiter[j], HEX); // Send out on Serial1
        break;
      }
    }
    if (j == 4) // self explanatory 
      Serial.println("No match found");
  }
}

Ok... for being a novice just trying to get my bearings, I still find the code a bit confusing, even though you comment well. I'll get there. I hoped there would be more straight forward coding using decimal or hex, without having too many variables. I forgot to mention that my Arduino is flashed with HIDUINO, and I am programming the 2560 via ISP.

Here are some screen shots showing the exact MIDI messages that are being sent and received between my audio recording program and my external controllers:

Here, the "incoming" messages are in HEX, these are the messages being sent from my audio recording program. Bome's MIDI translates that message and shows the "outgoing" code to the external controller, which is what it wants to see to function properly.

This image shows "incoming" messages from the controller, and Bome's MIDI translates that message and shows the "outgoing" code to the audio recording program, which is what it wants to see to function properly.

Here is the code I've started for that PING I mentioned earlier, which is "pinging" properly, but also my attempt at sending this data the way I thought it needed to be sent. Comments are welcome:

#include <MIDI.h>
#include <stdlib.h>
#include "Arduino.h"
#include "HardwareSerial.h"
#define LED 13

MIDI_CREATE_DEFAULT_INSTANCE();

// -----------------------------------------------------------------------------
//This sketch programs the MEGA2560 to receive a HUI ping and return that ping
//back to HUI to allow external controller conversion to occur. Arduino is bootloaded
//with HIDUINO firmware on the Atmel8u2 as a class-compliant driverless MIDI device,
//passing MIDI messages through it. Programmed via ISP as the HIDUINO firmware does not 
//allow for USB<>Arduino sketch programming.

void Ping(byte channel, byte pitch, byte velocity)//channel 1, pitch 0, velocity 0
{
     if (velocity==0);
     digitalWrite(LED, LOW);
     delay(400);                //LED flash for 1/2 second to confirm Ping Return
     digitalWrite(LED, HIGH);   
     MIDI.sendNoteOn(0, 127, 1);//note, velocity, channel
     delay(5);
     MIDI.sendNoteOff(0, 127, 1);
  // Notice that NoteOn messages with 0 velocity are interpreted as NoteOffs.
}
void Channel_1(byte channel, byte pitch, byte velocity){
      
  //Mute Press On Track Channel 1 from Pro Tools to Controller 
      if(channel==176, pitch==12, velocity==0, channel==176, pitch==44, velocity==2);
      byte Mute_1[] = {176,70,127,176,70,0};
      Serial1.write(Mute_1,6);
      delay(50);
      if(channel==176, pitch==12, velocity==0, channel==176, pitch==44, velocity==66);
      byte Mute_1_1[] = {176,70,127};
      Serial1.write(Mute_1_1,3);
}


// -----------------------------------------------------------------------------

void setup()
{
    Serial1.begin(38400);//Serial 1 pin 19(Rx) pin 18(Tx)
    MIDI.setHandleNoteOff(Ping);
    MIDI.setHandleNoteOn(Channel_1);

    // Initiate MIDI communications, listen to all channels
    MIDI.begin(MIDI_CHANNEL_OMNI);
    

}

void loop()
{
    // Call MIDI.read the fastest you can for real-time performance.
    MIDI.read();


}
     if (velocity==0);

?

Trap 13

My audio recording program sends a Ping (90 00 00), so the velocity of that is 0. Once receiving that "message" with a zero velocity, it needs to send back (90 00 7F);

MIDI.sendNoteOn(0, 127, 1);//note, velocity, channel
delay(5);
MIDI.sendNoteOff(0, 127, 1);

Im sure there's a better way to do it...

He was reffering to the semicolon at the end of that If statement.

I'm sorry, I am having severe difficulty getting this working properly, and I really feel like it shouldn't be this hard... I guess baby steps are in order.

Based on the info I gave above, I'd like to at least get one button press on my controller to transmit (0xB0, 0x46, 0x7F) from my controller, in through Serial1 on my MEGA2560, then send (0xB0, 0X0F, 0X0, 0XB0, 0X27, 0X42) transmitting back out through USB to my CPU.

If I can get the Arduino to pass the "Serial1" data from my controller to "Serial" and out, then we are in business.

I just can't wrap my head around this. Thanks for any additional help, I'm just really new at this, I have a basic understanding but I get lost easily (with the code given above)

I'd also add that some midi devices send note on with zero velocity to mean note off.

KenF:
I'd also add that some midi devices send note on with zero velocity to mean note off.

You are certainly correct about that. The Ping I have setup in the sketch above realizes that it is receiving a NoteOff message and sends a NoteOn message successfully. The difficult part here is that due to the fact that the 8u2 is bootloaded with Hiduino firmware, I can't debug over the USB. I only have the Rx and Tx LED's on the Arduino and my RS-232 TTL converter chip to verify that data is being sent.

When I push a button on the controller, the RS-232 chip shows activity on the Rx line, that line being sent out to the 2560's "Serial1" Rx. It seems backwards but that's the direction it's actually going, you can see in the photo that the Rx has an arrow outputting to the Arduino.

I just need to send that data out of the USB, heck, even since I am using "MIDI.h", if I could somehow take the incoming RS-232 data and output a MIDI message back to the computer would work too. As you can see, I am utilizing the MIDI message I am receiving from the CPU and turning it around back out...

void Ping(byte channel, byte pitch, byte velocity)//channel 1, pitch 0, velocity 0
{
     if (channel==144, pitch==0, velocity==0)
     digitalWrite(LED, LOW);
     delay(400);                //LED flash for 1/2 second to confirm Ping Return
     digitalWrite(LED, HIGH);   
     MIDI.sendNoteOn(0, 127, 1);//note, velocity, channel
     delay(5);
     MIDI.sendNoteOff(0, 127, 1);
  // Notice that NoteOn messages with 0 velocity are interpreted as NoteOffs.
}

So in theory, I would want to receive (0xB0, 0x46, 0x7F) from my RS-232, and trigger a MIDI.sendNoteOn (0xB0, 0X0F, 0X0, 0XB0, 0X27, 0X42)or decimal. That would work best since my Arduino is acting as a class-compliant driverless MIDI device.

Comments??! HELP!!!

UPDATE:

So I've got communication from my controller to the Arduino, and sending a message back to my audio recording program and seeing some action. Here is the updated code...

#include <MIDI.h>
#include <stdlib.h>
#include "Arduino.h"
#include "HardwareSerial.h"

uint8_t Mute1Press[3]={0xb0,0x46,0x7f};
uint8_t Mute1Send[6]={0xb0,0x0f,0x0,0xb0,0x2f,0x42};

MIDI_CREATE_DEFAULT_INSTANCE();

// -----------------------------------------------------------------------------
//This sketch programs the MEGA2560 to receive a HUI ping and return that ping
//back to HUI to allow external controller conversion to occur. Arduino is bootloaded
//with HIDUINO firmware on the Atmel8u2 as a class-compliant driverless MIDI device,
//passing MIDI messages through it. Programmed via ISP as the HIDUINO firmware does not 
//allow for USB<>Arduino sketch programming.

void Ping(byte channel, byte pitch, byte velocity)//channel 1, pitch 0, velocity 0
{
     if (channel==144, pitch==0, velocity==0);
     MIDI.sendNoteOn(0, 127, 1);//note, velocity, channel
     delay(5);
     MIDI.sendNoteOff(0, 127, 1);
  
    // Note that NoteOn messages with 0 velocity are interpreted as NoteOffs.
}


// -----------------------------------------------------------------------------

void setup()
{
    Serial.begin(38400);
    Serial3.begin(38400);
    MIDI.setHandleNoteOff(Ping);

    // Initiate MIDI communications, listen to all channels
    MIDI.begin(MIDI_CHANNEL_OMNI);
}

void loop()
{
    // Call MIDI.read the fastest you can for real-time performance.
    MIDI.read();
    
     // read from port 3, send to port 0:
  if (Serial3.available()) {
    uint8_t Mute1Press = Serial3.read();
    Serial.write(Mute1Send,6);


  // read from port 0, send to port 3:
  if (Serial.available()) {
    int inByte = Serial.read();
    Serial3.write(inByte);
    // There is no need to check if there are messages incoming
    // if they are bound to a Callback function.
    // The attached method will be called automatically
    // when the corresponding message has been received.
  }

  }
}

I am sending the 6 byte message to control the Mute button in my program. When I press the Mute button on my controller it is momentarily turning it on and off. However, any button press on the controller is activating the Mute button in my program...

What am I missing here? I would only like this message to be transmitted to the CPU:
uint8_t Mute1Send[6]={0xb0,0x0f,0x0,0xb0,0x2f,0x42};

When this message is received into the Arduino from the controller:
uint8_t Mute1Press[3]={0xb0,0x46,0x7f};

???

Near the beginning of your code you have

uint8_t Mute1Press[3]={0xb0,0x46,0x7f};

So a global variable called Mute1Press

Then in your loop you have

uint8_t Mute1Press = Serial3.read();

So you're now creating a separate local variable with exactly the same name.

Are you creating some conflict here?

Edit: Oh and on the very next line you have

Serial.write(Mute1Send,6);

So was it perhaps Mute1Send that you wanted to use to read Serial3

I want to read this specific HEX string

(Mute1Press[3]={0xb0,0x46,0x7f}:wink:

when the button that transmits that message is pressed, to transmit this specific HEX

(Mute1Send[6]={0xb0,0x0f,0x0,0xb0,0x2f,0x42};

to my program to activate the Mute.

The 6 digit HEX code is "writing" out of the Arduino and activating the proper mute button in the CPU...
Being new at this, I only know part of what I'm doing :-/

Could you help me understand how I can read this specific 3 digit HEX only when it's button is pressed? Thanks for the hints...

OK I'll have a look at it for you, but I'm not familiar with the midi.h library. But before I set about it could you just confirm some of my preconceptions. (I'm just guessing here)

  1. MIDI.read() will read an entire midi message into some sort of buffer on the midi adapter
  2. After a MIDI.read, Serial.read() will read out of that buffer on a byte by byte basis

Am I right so far?

KenF:
OK I'll have a look at it for you, but I'm not familiar with the midi.h library. But before I set about it could you just confirm some of my preconceptions. (I'm just guessing here)

  1. MIDI.read() will read an entire midi message into some sort of buffer on the midi adapter

Yes.

KenF:
2) After a MIDI.read, Serial.read() will read out of that buffer on a byte by byte basis

Am I right so far?

This I am not entirely sure about either. I would assume yes, since MIDI.read is essentially just reading the incoming 3 bytes of data from USB, and assuming Serial.read() basically does the same thing. My guess is as good as yours here. I've been learning by trial and error.