I'm using the hardware UART on an Uno (software 0022) in order to read in MIDI note on/off messages and convert them into a different form for another MIDI device. This mostly works, but there's one bug I can't seem to find.
If I send in the following MIDI message:
0x94 0x28 0x7F (MIDI note on, channel 4, note is 0x28, velocity is 0x7F)
I end up spitting out the following two messages after conversion:
The seventh byte (between the 0x06 and 0xF7) is missing (should be 0x28 in the first message and 0x7F in the second). Here's what I've tried to narrow the problem down:
Swapped the "channel" and "note/velocity" bytes in the array before I call Serial.write. No difference in the output (meaning the problem isn't with the position of the vars)
Set up the serial writes to send individual bytes instead of the whole array. No change.
Hardcoded the note/velocity. This works fine, but I obviously need different values in there.
I get all three bytes at the same time from the device I'm reading the data from. Reading has been flawless since day 1, it's the output that's not right.
In any event, I modified that portion to actually spin the processor until I get data:
Reading has been flawless since day 1, it's the output that's not right.
The output depends on the input. If the output is not right, one must assume that there is either a problem with the input or with the mapping of the input to the output. Since there is clearly a problem with collecting the input, and you don't seem inclined to properly fix it, I don't seem inclined to look at the mapping. Sorry about that.
I have to read other messages, too, including a couple that are single bytes. If I get a 0x90-0x9F byte, I know that the next two immediately following it are the two that I'm looking for.
Again, this doesn't answer the question why writing 8 bytes (whether they're valid data or not) to a serial port results in only 7 bytes coming out the other side.
I know that the next two immediately following it are the two that I'm looking for.
But you don't know that the serial hardware has actually received the next two characters and placed them into the receive buffer ready for your next two serial reads. You are making an assumption that based on timing may or may not be true. Hardware and software serial transactions on an Arduino are a byte by byte proposition. So either test that three characters are waiting (not the best method IMHO) or test for 1 or more available right before you do each serial read statement. To not heed that message is either folly or stubbornness on your part.
I changed the bitrate to 9600 and manually fed the system the bytes I'm receiving, as I only have the one serial port and can't use SoftwareSerial without a MAX232 chip or equivalent (can I?). Here's how I'm calling it:
//---
void loop()
{
int channel = 0;
sendNoteOn(0x06, 0x28, 0x7F);
// everything else, since the serial port is physically disconnected and I'm not sending anything, it'll just be skipped)
and can't use SoftwareSerial without a MAX232 chip or equivalent (can I?).
Yes, you can. The same rules about voltage levels, etc. apply to software serial pins as apply to hardware serial pins. If your device can send data safely to the hardware port, it can send it safely to a software port. Use NewSoftSerial, though. SoftwareSerial is obsolete (until 0023, when SoftwareSerial will be replaced by NewSoftSerial).
In order to connect a softserial port to a PC, though, I'd need the level converter, right? I have plenty of experience with programming for serial ports, but still not quite up to par with the electrical part of it.
I'd prefer to use the UART for data transmission, but if I have to use the softserial for that and reserve the UART for debugging until I get this problem figured out, that's not a big deal.
Okay. I just wrote a quick program for a Netduino I had lying around to read in bytes and display them on the Debug output (so I can see what's going on).
When I plug the input device directly into the ND to see what the input is, I'm getting this:
Note on:
0x94
0x28
0x7F
Note on:
0x94
0x28
0x00
This is what I expect. When I look at the output of the Arduino, though, here's what it's reading in:
Note on:
0x94
0xFF
0xFF
Note on:
0x94
0xFF
0xFF
So it looks like the system is actually returning -1 for "no data available." That shouldn't be possible, though, since I'm using this to pull the data:
recvBuffer[1] = blockSerialRead();
recvBuffer[2] = blockSerialRead();
byte blockSerialRead()
{
byte data = -1;
while (data == -1) data = Serial.read();
return data;
}
Am I being an idiot and missing something obvious?
The data type returned by Serial.read() is int, to allow it to return a non-valid value, when there is no data to read. In your previous, you could change the type of data to int, while still having the function return a byte. After getting a valid value from Serial.read(), return data, which will cause only the low byte to be returned, which is the byte that contains the bits of interest.
-1 as an unsigned char should underflow to 0xFF, though.
Yes, but an unsigned char doesn't cast to -1 when promoted.
Since C specifies promotion to integers in expressions, if "foo" is an unsigned char with value 0xFF, then for
if (foo == -1)
foo promotes to 0x00FF and -1 is 0xFFFF, and they're NOT equal.