Reading serial bytes from MIDI, unexpected values

I've tried with two different MIDI pedal board/processors. When you
change preset on the pedal board, it is supposed to send MIDI program
change messages, if enabled. I've confirmed MIDI channel is set to 1.
The values are supposed to correspond with the numbering scheme of the pedal board,
so bank 1 preset 1 should send a command byte of 192 for channel 1 program change,
and the next byte would be 0 for preset 1.

However, when I use the serial monitor in the Arduino IDE, instead I get a command byte of 128
which is channel 1 Note Off. Also program numbers are not in order.
Bank 1 presets 1, 2, 3 and 4 send values of 0,1,6 and 7 respectively.
The manual for the pedal boards (Vox Tonelab LE and Line 6 POD HD500) do not mention
being able to edit or map these values.

Here are the important bits from the sketch:

I declared two variables...
byte cmdByte; // 1st byte is command or "status" byte
byte progNum; // 2nd byte is program change number

In setup, I've included...
//start serial with midi baudrate 31250 or 38400 for debugging
Serial.begin(38400);

In the main loop, I have...

if (Serial.available() > 0) {
// read the incoming bytes:
cmdByte = Serial.read();
progNum = Serial.read();

// debugging
Serial.println("COMMAND BYTE: ");
Serial.println(cmdByte);
Serial.println("PROGRAM NUMBER: ");
Serial.println(progNum);

if (cmdByte == 192){ // channel 1 program change command
//do stuff
}
}

MIDI baudrate is 31250, but I have to set it in the sketch to 38400 to get
the values in the serial monitor.

Any ideas or thoughts would be appreciated!

if (Serial.available() > 0) {   
   // read the incoming bytes: 
   cmdByte = Serial.read();
   progNum = Serial.read();

If there is at least one byte to be read, read both of them. No, I don't think so.

According to my understanding of I what I've read, Serial.available() returns the number of bytes available to read. There are 2 bytes in a MIDI program change message, and the above method is giving me two different numbers in the serial monitor that change as I send different program changes.
The first Serial.read() returns the first byte. I thought you could call Serial.read() again to retrieve the next byte.
Or does it have to be nested in a while Serial.available() loop?

The code is executing way faster than the midi rate.
You need to do something to differentiate one byte from another. You can read when you got 2 bytes, store them in an array, and read pos 0 and pos 1 of the array.
Or you could use switch, if the command byte arrived(byte == 192(PC status byte if i remember correctly)) go to next case, if the new byte is between 0 - 127, that's your program change value

ArtieJ:
According to my understanding of I what I've read, Serial.available() returns the number of bytes available to read.

Yes, it does, but Serial.available() does not return the bytes themselves; but only how many bytes there are available.

See the comments in the code. Assume you receive two bytes, with values of 14 and 20.

if (Serial.available() > 0) {   
// There is at least one byte available now. You don't know how many because
// you throw away the return from Serial.available

   // read the incoming bytes:    // Incoming byte, not bytes. 
   cmdByte = Serial.read();
 // you now have the first bte the first byte
   progNum = Serial.read();
 // you put something into progNum, but it likely isn't the second byte, because
 // you sre zipping through this routine atthe rate of 62.5 nanoseconds per insctuction,
  // and your thing that's sending the data is still busy sending out the first bit of the second byte
 // it will arrive eventually, just not yet.

The first Serial.read() returns the first byte. I thought you could call Serial.read() again to retrieve the next byte.

You can, and you do. BUt it will, with the above code, be placed in cmdByte, and again you'll put junk into progNum.

You can wait until Serial.available() returns 2, or you can collect bytes until you have the right number, or you can grab each byte, one at a time, and put them in different variables, but you'll need to know which byte it is.

OK, thanks for some clarification.
The 1st byte value I'm getting is consistently 128, not 192. I've checked with a Windows utility to capture the data and it is what it is supposed to be, 192. So I'm not even getting the first byte right!
So, you're saying the function "if (Serial.available() > 0)" evaluates TRUE when there is a complete byte. But the byte from Serial.read() is incorrect. Any thought why that might be? It's called immediately, shouldn't it be the first complete byte?
I'm also going to try a different hardware interface to see if that helps.

Ah, re-read you're info, cmdByte value is going to change with the 2nd Serial.read().
OK, closer to getting by brain around it, haha. I guess I need to figure out how to make a while loop
create an array of the bytes?

RE-read again. Look at the switch pseudo example I wrote.
The good thing is that you know what and how many bytes you'll receive. That simplifies things. The first byte will be above or equal to 192, the second data byte will be under 128. So when you receive the first byte, store it in a variable, then go to the next case, and if the new byte is below 128, store it in another variable corresponding to the byte function. Then when you received that 2nd byte, execute your programchange function.
Here's a nice tutorial for serial.read and etc
http://hacking.majenko.co.uk/reading-serial-on-the-arduino

I incorporated the second example from that site. Here's my complete code:

//variables setup

int cmdByte;         // 1st byte is command or "status" byte
int progNum;         // 2nd byte is program change number
int theBytes[2];
int statusLed = 13;   // select the pin for the LED

// setup: declaring iputs and outputs and begin serial 

void setup() {
// declare the LED pin as output
   pinMode(statusLed,OUTPUT);   
  
// declare the relay pins as outputs
   pinMode(2,OUTPUT); 
   pinMode(3,OUTPUT);
   pinMode(4,OUTPUT);
   pinMode(5,OUTPUT);

// mute everything on startup 
   digitalWrite(2, LOW);
   digitalWrite(3, LOW);
   digitalWrite(4, LOW);
   digitalWrite(5, LOW);
  
  //start serial with midi baudrate 31250 or 38400 for debugging
  Serial.begin(38400);        
  digitalWrite(statusLed,HIGH);  
}

//loop: wait for serial data, and interpret the message 
void loop () {
  
if (Serial.available() >= 2) {
   for (int i=0; i<2; i++) {
   theBytes[i] = Serial.read();
   }

   cmdByte = theBytes[0];
   progNum = theBytes[1];

 // debugging
    Serial.println("===========================================");
    Serial.println("COMMAND BYTE: ");
    Serial.println(cmdByte);   
    Serial.println("PROGRAM NUMBER: ");
    Serial.println(progNum);
    Serial.println("===========================================");
 
}	
      
       if (cmdByte == 144){ // channel 1 program change command	

             if (progNum <= 16){ // unmute relay 1 
                 digitalWrite(2, HIGH);
		 digitalWrite(3, LOW);
		 digitalWrite(4, LOW);
		 digitalWrite(5, LOW);
             }
	
	     if (progNum == 17){ // unmute relay 2
                 digitalWrite(2, LOW);
		 digitalWrite(3, HIGH);
		 digitalWrite(4, LOW);
		 digitalWrite(5, LOW);
             }
	
	     if (progNum == 18){ // unmute relay 3
                 digitalWrite(2, LOW);
		 digitalWrite(3, LOW);
		 digitalWrite(4, HIGH);
		 digitalWrite(5, LOW);
             }
	
	     if (progNum == 19){ // unmute relay 4
                 digitalWrite(2, LOW);
		 digitalWrite(3, LOW);
		 digitalWrite(4, LOW);
		 digitalWrite(5, HIGH);
              }
	
              if (progNum > 19){ // mute all relays
                 digitalWrite(2, LOW);
		 digitalWrite(3, LOW);
		 digitalWrite(4, LOW);
		 digitalWrite(5, LOW);
              }
       }  // end if (cmdByte == 144)	
}  // end void loop

Does this look right? Serial monitor still prints out cmdByte as 128 and the funky progNum sequence.

What are you using to send the bytes? How do you know what values they are?

What are you using to send the bytes?

And, why do you send text data back to that MIDI device?

I would do it with switch cases like I said earlier; look at this example from grumpy mike MIDI Shield
And by the way, 144 is the byte for Note On.

144 was a late hour brain fart. I had changed it to 128 just to see the relays work. Actually, it worked reliably after dozens of MIDI messages sent.
But my question stands, is there anything procedurally wrong with the method? It waits until there are two bytes, stuffs them in an array.
One more important thing, I changed the hardware interface. The original circuit was based on a 4N28 opto, used by others with success. I built another one based on the 6N138. I'm getting different values now, 0 for cmdByte. So, hardware appears to be mangling bits. I'll find a way to capture MIDI messages and inspect the waveform before continuing with code work.
To answer questions, I have used 3 different MIDI processors that send standard MIDI program changes. This is interfaced with the circuit I built. I've been in electronics for over 35 years, I'm confident of the hardware build.
Also, what text am I sending back? The only MIDI connection is an input.
Thanks all, I'll report back when I know the MIDI bits are correct.

It's working. All I had to do was be smarter than the code. Which is a challenge for me. :grin:

I forgot to change the baud rate back to 31250 for hardware test. Scrambled bits I guess.
Anyway, from the original code when I started, if I had just made 2 changes, the baud rate and
changing the 1st if() statement from if(Serial.available() > 0) to if(Serial.available() > 1) or
if(Serial.available() ==2) then all would have been fine. I tested both of those repeatedly and had not one glitch.

So my final questions would be is if(Serial.available() ==2) the best test? Also it didn't matter if I used an array or just did Serial.read() twice consecutively. I've tested both repeatedly, and again, not a glitch. But would one method be preferable?

As an aside, I found the 4N28 worked more reliably and uses less external components.
Thanks again, all, I hang my head in shame! :blush:

changing the 1st if() statement from if(Serial.available() > 0) to if(Serial.available() > 1) or
if(Serial.available() ==2) then all would have been fine.

Until there was some hiccup, and a third byte arrived before you checked. Then, Serial.available() == 2 would never have been true again. >= 2 is the proper test.

ok, just for reference since this is a topic i found, when i searched for an arduino midi in implementation (other then via the midi-library).

grumpy mike's example at: MIDI Shield is only partially "right", it handles only 3 byte messages (and running status) correctly. however channel pressure and program change are two byte messages that the example fails to read in. here is an updated code snippet, that reads those messages as well and safely ignores sysex... i don't know if it is the best way to do it, but it works very well so i thought i post it here:

//some random cc numbers:
#define SAVE_CC 120
#define CHANNELMODE_CC 119
#define FULLLEGATO_CC 118
#define OCTAVE_CC 117
#define STICK_CC 116

//midi in variables
byte state = 0;
byte statusByte;
byte dataByte1;
byte dataByte2;



void setup() {
  //start serial with MIDI baud rate 31250 or another standard speed for debugging
  Serial.begin(31250);   
}

void loop() {
  // put your main code here, to run repeatedly:
MidiIn();
}

void MidiIn(){
  if (Serial.available() > 0) {
    // read the incoming byte:
   byte incomingByte = Serial.read();
  
   switch (state){
      case 0:
      if (incomingByte > 0x7F && incomingByte < 0xF0 ){    // this reads all statusbytes, realtime stuff is ignored
         statusByte = incomingByte;
         state=1;
        }
        if (incomingByte == 0xF0) state=3;
       case 1:
       // get first databyte
       if(incomingByte < 0x80) {
        dataByte1 = incomingByte;
        //check for two byte messages...
       if ((statusByte & 0xF0) == 0xC0 | (statusByte & 0xF0) == 0xD0) {
        midiParser();
        state = 0; //reset state machine 
       } else state = 2;
       } else{
      state = 0;  // reset state machine as this should be a note number
      }
       break;
       
       case 2:
       // get second databyte
       if(incomingByte < 128) {
       dataByte2 = incomingByte;
       }
       midiParser();
         state = 0;  // reset state machine to start
         break;
          //stay here for sysex, wait for it to end...
         case 3:
         if (incomingByte == 0xF7) state=0;
         if(incomingByte > 0x7F && incomingByte < 0xF0) {
              statusByte = incomingByte;
              state=1;   
         }
         break;
  }
}
}
void midiParser(){
  switch (statusByte){
    
    case 0xC0: //program change
    //do something when a program change arrives, prg nr is dataByte1
    break;
    case 0xB0: //cc messages 
    switch (dataByte1) {
      case SAVE_CC:
      //do something here
      break;
      case CHANNELMODE_CC:
      //do something else
      case STICK_CC:
      //again something on this cc
      break;
      case FULLLEGATO_CC:
      //you get the idea
      break;
      case OCTAVE_CC:
     //octaves!!!
    break;
  }
}
}

please don't use the other code (not grumpy mikes) posted in this thread, it does not work correctly, or only for very special use cases