Arduino Serial Read issue

I am sending midi data from Processing to Arduino over serial. The first piece of data is the pitch which is a 2 or 3 digit number associated with the key being pressed on my digital piano. The second piece of data is the velocity which is a 0-100 number associated with how fast the key is pressed. I am using the Midibus library in processing to get these numbers. I am unsure how to separate these these two pieces of data when I use Serial Read on the Arduino, so that I can do something useful with them. In Processing I can separate the values by a comma or put a character in front of them or anything else, but I am unsure how to write Arduino code so that it can read the two pieces of data separately. Any help would be greatly appreciated.

I'm a little bit unsure of what you mean. Do you mean you want a program to print a value to Serial but you want like a word or character to be in front of the number?

Thanks OP! I rarely see someone raising a question would give a tutorial on how things work (you gave a tut on how midi works so thanks!)

Is this what you want?

// Variables outside functions
char midi_text[]="123,50"; //Key 123 is pressed at speed 50
int key,speed;

// code in loop:
sscanf(midi_text,"%d%*c%d",&key,&speed); // This assign 123 to key and 50 to speed. If you have string "123 50" then use "%d %d"
Serial.print("Key pressed is:);
Serial.println(key); // Just showing that the number is correct
Serial.print("Key speed is:);
Serial.println(speed);

My tutorial on sscanf:

I have no problem printing the midi data to serial using processing. The problem is reading the data serially with the Arduino. If I press key 63 at 3/4 speed, processing will print 6375 to serial (depending on how I choose to format it). This works perfectly. I am trying to write Arduino code that reads this data and splits the data up into two separate pieces (63 and 75) so that I can do one thing with the key number data, and something else with the velocity data.

artvandalay113:
I have no problem printing the midi data to serial using processing. The problem is reading the data serially with the Arduino. If I press key 63 at 3/4 speed, processing will print 6375 to serial (depending on how I choose to format it). This works perfectly. I am trying to write Arduino code that reads this data and splits the data up into two separate pieces (63 and 75) so that I can do one thing with the key number data, and something else with the velocity data.

It will be much easier if the numbers are physically separated by a space or comma like in my example code. The code IS for arduino.
If the numbers come connected, then how does one tell if the key is 63 and speed is 75 instead of key is 637 and speed is 5? What exact syntax does the midi stream follow then?

artvandalay113:
I have no problem printing the midi data to serial using processing. The problem is reading the data serially with the Arduino.

I don't know if it will help, but there was a thread posted the other day on a similar problem: http://arduino.cc/forum/index.php/topic,92767.0.html

Might be useful for you as well. I hope this helps,

Brad.

In this project:-
http://www.thebox.myzen.co.uk/Hardware/Glockenspiel.html
MIDI input is split up to fire solenoids if the note number is within a certain range.

All MIDI messages have the most significant bit set, all MIDI data has it clear.

So to start off you want to look for a byte over serial that has the most significant bit set. Then you know what follows is the data with it clear. If you get what you expect to be data with the most significant bit set then you have some sort of error and you should abandon trying to decode that message.

liudr,
Thanks for your explanation. I can make the formatting be whatever I want.
63,75
63 75
A63 B75

I will do some research on sscanf.

artvandalay113:
liudr,
Thanks for your explanation. I can make the formatting be whatever I want.
63,75
63 75
A63 B75

I will do some research on sscanf.

If that is so, then 63 75 is the best for starters since it makes the sscanf easy to extract the numbers. Next to address data corruption questions, you may need more, say A63 75'\n' so you read the whole thing until you get '\n'. If the first character is A, the process the rest, if not, toss and wait for a new one.

I tried the following:
void loop() {
if (Serial.available() > 0) {
char incomingByte = Serial.read();
Serial.print(incomingByte);
sscanf(incomingByte,"%d%*c%d",&key,&press);
Serial.print("Key pressed:");
Serial.println(key);
Serial.print("Key speed:");
Serial.prinln(press);
}
}

I am getting the error: "invalid conversion from char to const char" on the sscanf line

Sscanf's first parameter must be a pointer to a C string, but you're passing it a single character.
You need to assemble your incoming string into a buffer before calling sscanf.
There are plenty of examples of how to do this.

I have tried searching for how to assemble an incoming string into a buffer but cannot find any explanation. Can you explain or point me in the right direction?

I have tried searching for how to assemble an incoming string into a buffer but cannot find any explanation. Can you explain or point me in the right direction?

Point, point, point:

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

Where it says "Process the packet" is where strtok()/atoi() or sscanf() stuff goes.

artvandalay113:
I have tried searching for how to assemble an incoming string into a buffer but cannot find any explanation. Can you explain or point me in the right direction?

Perhaps help is closer than you think? I'd suggest reading all the replies in your own thread.

Searching can be difficult, but sometimes even scanning a few pages of threads will show others have had similar problems or questions just days before you :slight_smile:

Brad (KF7FER)

I decided to try a different approach and just put each incoming character into an array, not using the sscanf function. I cannot figure out where I am going wrong. I am sending the data over as "int1int2," The first int will always be 2 digits and the second int will be 2 or 3 digits. See my code below. I intend for the first piece of data to end up in the variable "key" and the second in "press".
char inChar;

byte key;
byte key0;
byte key1;

byte press;
byte press0;
byte press1;
byte press2;

byte array1[2];
byte array2[3];

void setup() {
Serial.begin(9600);
}

void loop() {
// Read all serial data available, as fast as possible
if(Serial.available() > 0)
{
for(int a = 0; a > 2; a++){
//read first character of int1
inChar = Serial.read();
//place characters into array1
array1[a] = inChar;
}
key0 = array1[0]*10;
key1 = array1[1];
key = key0 + key1;

for(int b = 0; b > 3; b++){
inChar = Serial.read();
if(inChar = ','){
break;
}
array2 = inChar;
** }**
__ press0 = array2[0]100;__
__ press1 = array2[1]10;__
** press2 = array2[2];

** press = press0 + press1 + press2;**
** }**

Can you post code in a box using the #icon

I cannot figure out where I am going wrong.

If you explained what was wrong it would help.

I can think of two things:-

  1. You are treating the bytes that arrive as numbers where as they will normally be in ASCII
  2. You assume you are always going to get two characters for the first one and three for the second, is this true?

If you send the whole MIDI message like I said earlier it would be much easier to extract the tings you want.

also there are some fundamental errors in the code:-

for(int a = 0; a > 2; a++)

will not loop.
You are checking that there is at least one byte in the serial buffer but are then reading lots. The first one might have arrived but have the others?

array2 = inChar;

is wrong.

if(Serial.available() > 0)
  {
    for(int a = 0; a > 2; a++){
//read first character of int1
      inChar = Serial.read();
//place characters into array1
      array1[a] = inChar;
    }

If there is at least one byte of serial data to read, read both of them.

      for(int b = 0; b > 3; b++){
      inChar = Serial.read();
      if(inChar = ','){
        break;
      }

Then read 3 more.

So, one byte shows up and you read all 5 of them. Got it. How's that working for you?

Although, as Mike said, it won't actually try and read any of them, as the for loops won't do anything.

Although, as Mike said, it won't actually try and read any of them, as the for loops won't do anything.

Good thing that there is more than one person reading the code, isn't it? I missed that.

I realized my mistake using a greater than instead of less than sign. The first number will always be two digits and the second number will be 2 or 3 digits. The 3 digit number will always be below 255 which is why I used byte and not int. However, I am sending it as an int from Processing so I should probably keep it as an int on the Arduino. I guess my problem is that I don't understand how Arduino communicates with Processing over serial. If Processing sends int "234" how will that be read on the Arduino? I can't figure it out because I can't use the Arduino serial monitor because Processing is using serial. I was trying to write my code as if it sent "2" then "3" then "4" because the Serial.read reference states that only a byte is read at a time. So if I received "2" I would put that in a variable and multiply it by 100, then put 3 in a separate variable and multiply by 10 and add those two variable to the 4. Am I way off here?