I'm working on an interface that reads serial data from a single wire bus on a car (BMW IBUS). I'm using an Microchip MCP2025 LIN bus transceiver chip to convert the single line bus to regular Rx/Tx to feed into the hardware serial pins (0 & 1) of an Arduino (Nano V3).
BMW's IBUS protocol uses Serial 8E1 at 9600 baud. Messages are variable length (between 5 and 37 bytes) Bus messages are separated by a pause of around 11 milliseconds (considerably longer than the bus high time when receiving) and I need to use this gap to detect the end of one message and the beginning of the next.
1st byte is the Source ID,
2nd byte is length of the packet excluding the first two bytes (source & length),
3rd byte is the destination ID,
4th byte onwards is the actual data,
Last byte is the checksum
Checksum is generated by XOR of the entire packet excluding the checksum itself.
My problem is that I don't know how to measure the bus idle time between messages. I think I can use bitRead(PIND,0) to tell when the bus is idle (high), but I'm not sure how to time this and go and process the message after a suitable time has passed.
I'm currently using the following code to read messages from the IBUS. It works for the most part, but gets out of sync when connected to the car. It's doesn't really know when messages have finished, but relies on the second byte of each message (the length byte) to know how many bytes to read in. As long as it reads the length byte correctly, it's fine, but if it gets out of sync, and the length byte is wrong, it reads in the wrong number of bytes and eventually overruns the array and the Arduino resets. If I can detect the idle time between messages I will know for sure that I have a complete message.
void ReadIBUS()
{
boolean inSTATE = 0;
byte IBUSbyte[40];
while(Serial.available() > 0 && inSTATE == 0 )
{
IBUSbyte[0] = Serial.read(); //read source byte
while (inSTATE == 0)
{
if(Serial.available() > 0)
{
IBUSbyte[1] = Serial.read(); //read length byte
inSTATE = 1;
}
delay(10);
}
inSTATE == 0;
LENGTH = IBUSbyte[1];
int i = 2;
while(i <= LENGTH + 1)
{
if(Serial.available() > 0)
{
IBUSbyte[i] = Serial.read();
i++;
delay(10);
}
}
checksumBYTE = 0;
byteSTATE = 0;
for (int i = 0; i < LENGTH + 1; i++){
checksumBYTE ^= IBUSbyte[i];
}
if (IBUSbyte[LENGTH + 1] == checksumBYTE){
for(int i = 0; i <= LENGTH + 1; i++)
{
mySerial.print(IBUSbyte[i], HEX);
mySerial.print(" ");
}
mySerial.println();
}
else {
debug();
inSTATE = 0;
byteSTATE = 0;
}
}
}
First off, delay is rarely a good thing to use. In this case, you can use millis to measure how long it is between characters, but only if you lose the delay:
void ReadIBUS()
{
byte IBUSbyte[40];
do {
// First, make sure we're between frames, in the quiet interval
uint32_t last_rx = millis();
while (millis() - last_rx < 5) {
// Hasn't been long enough, see if more chars are coming
if (Serial.available()) {
Serial.read(); // throw away partial frame chars
last_rx = millis();
}
}
// Haven't received any chars for a while, we must be
// between frames. Now wait for a frame.
while (!Serial.available())
; // waiting...
IBUSbyte[0] = Serial.read(); //read source byte
while (!Serial.available())
; // waiting...
IBUSbyte[1] = Serial.read(); //read length byte
LENGTH = IBUSbyte[1];
// Check the LENGTH to make sure it's not bogus. If it is, try again.
} while (LENGTH > sizeof(IBUSbyte)-1);
// LENGTH is reasonable, wait for the payload
uint8_t bytes_received = 2;
while (bytes_received <= LENGTH + 1) {
if (Serial.available()) {
IBUSbyte[ bytes_received++ ] = Serial.read(); // read frame payload byte
}
}
// All here, verify the checksum
checksumBYTE = 0;
for (int i = 0; i < LENGTH + 1; i++) {
checksumBYTE ^= IBUSbyte[i];
}
if (IBUSbyte[LENGTH + 1] == checksumBYTE) {
for(int i = 0; i <= LENGTH + 1; i++) {
mySerial.print(IBUSbyte[i], HEX);
mySerial.print(" ");
}
mySerial.println();
} else {
debug();
}
}
And the state variables are no longer needed.
BTW, this routine "blocks" the rest of the program from doing anything until a complete frame is received. It should probably be rewritten so that it is called frequently (like from loop), and last_rx and bytes_received are remembered across calls. It could return true when a complete frame has been received. This'll work, it's just sub-optimal because it blocks anything else from happening, except interrupts.
Related
I'm trying to get an MCU to read data from a LIDAR via UART, but for some reason the checksum isn't correct. I'm using an ESP32-WROOM dev chip (using Arduino) and a Cygbot D1 LIDAR with this datasheet. I am able to read the 2D data packets, but not the 3D data packets, which are much longer.
After receiving a packet, I use a sequence of Serial.read() calls to read in data, byte by byte. The packet header, packet length bytes, and payload header are read correctly. The payload is 14,401 bytes long.
When I finish reading the data, the checksum doesn't match, and there are ~300 bytes left in the Serial buffer. After a lot of debugging I'm stuck and would appreciate any pointers or ideas for how to get un-stuck.
The relevant portions of my code:
bool readPacket() {
/*
* Call when we're expecting a packet. The top of the buffer
* must be the correct packet header.
*/
if (Serial2.available()) {
//Check the header, return false if it's wrong
if (not checkHeader()) {
return false;
}
//Next 2 bytes are the packet length
byte b0 = Serial2.read();
byte b1 = Serial2.read();
unsigned int payloadLen = combineBytesIntoInt(b0, b1);
//Read in the data based on the payload header.
byte payloadHeader = Serial2.read();
byte sum = b0 ^ b1 ^ payloadHeader; //Start computing checksum
if (payloadHeader == 0x08) {
sum ^= parse3D();
}
byte packetChecksum = Serial2.read();
if (packetChecksum != sum) {
Serial.println("Checksum error");
return false;
}
return true;
} else {
return false;
}
}
byte parse3D() {
/*
* Parse a 3D dataset, reading directly from the serial.
* Reading in batches of 3 due to the way data is formatted in the packet.
* Returns checksum.
*/
byte checksum = 0;
for (int i=0; i<N_MEASURES_3D; i+=2) {
int msb0 = -1;
//If data hasn't been sent, Serial2.read will return -1. Wait until we receive valid data before proceeding.
while (msb0 < 0) {
msb0 = Serial2.read();
}
int split = -1;
while (split < 0) {
split = Serial2.read();
}
int lsb1 = -1;
while (lsb1 < 0) {
lsb1 = Serial2.read();
}
checksum ^= byte(msb0) ^ byte(split) ^ byte(lsb1);
}
return checksum
}
void loop() {
//When the button is clicked, send a packet.
if (buttonState == 1) {
ct += 1;
if (ct % 2 == 0) {
Serial.println("Write packet: start 3d");
lidarStart3DMode();
}
}
bool readSuccess = readPacket();
if (readSuccess) {
lidarStop();
}
//This code just updates the button
if ((digitalRead(BUTTON_PIN) == 1) and (millis() - lastTime > BUTTON_DEBOUNCE_TIME)) {
lastTime = millis();
buttonState = 1;
} else {
buttonState = 0;
}
}
All the reads in your code here:
byte b0 = Serial2.read();
byte b1 = Serial2.read();
unsigned int payloadLen = combineBytesIntoInt(b0, b1);
//Read in the data based on the payload header.
byte payloadHeader = Serial2.read();
and here
byte packetChecksum = Serial2.read();
and possibly in checkHeader() (which you didn't provide), should be safe-guarded against buffer under-run, ie., reading bytes when none are available.
You could add
while (!Serial.available());
before each read().
The base of the problem: I have an Arduino Due and a MPU6050 accelerometer and an 23lcv512. MPU gives me 16bit signed integer. I would like to save the datas to the SRAM and after the measurement read them back and via Serial send it to PC. Sending to PC is not a problem. The problem is that this SRAM has 128k pcs 8bit address. My numbers are 16 bit. I can't write them directly. Here is my code. I tested the RAM with this code:
`
void loop() {
int i = 0;
Serial.print("Write Byte: ");
for (i = 0; i < 70000; i++) {
//Serial.print("Write Byte: ");
//Serial.print(i);
//Serial.println();
SRAM.writeByte(START_ADDRESS, i);
START_ADDRESS = START_ADDRESS + 1;
}
Serial.print("Write End");
i = 0;
START_ADDRESS = 0;
for (i = 0; i < 300; i++) {
Serial.print("Read Byte: ");
Serial.print(SRAM.readByte(START_ADDRESS));
Serial.println();
Serial.println();
START_ADDRESS = START_ADDRESS + 1;
delay(100);
}
}`
I added the 23LC library. If it's run reads back the numbers from the RAM but after 255 it starts to read 0 again. I know why does it happen. But I don't know howto solve the problem.
I tried to use the writeBlock command but it only works for me with char variables. Char variable requires more space than integers. I have not too much.
Is there anyone who can write a sample code which can write 16 bit signed integer to sram?
I've commented the most obvious problems in your original code below:
void loop() {
int i = 0;
Serial.print("Write Byte: ");
for (i = 0; i < 70000; i++) { // since i is a 16bit int, 70,000 is out of range.
SRAM.writeByte(START_ADDRESS, i); // cool you wrote 1 byte, where is the other write?
START_ADDRESS = START_ADDRESS + 1; // try to keep all caps names for constants.
// this will make your code easier to read, trust me!
}
Serial.print("Write End");
i = 0;
START_ADDRESS = 0;
for (i = 0; i < 300; i++) {
Serial.print("Read Byte: ");
Serial.print(SRAM.readByte(START_ADDRESS)); // you read 1 byte, you can't expect a 16 bit
// value out of that.
Serial.println();
Serial.println();
START_ADDRESS = START_ADDRESS + 1;
delay(100);
}
}
Here's a more sound approach, it stores unsigned ints, but that can easily be changed to signed ints.
#define SRAM_SIZE (128UL << 10) // we have 128K of SRAM available.
// The U and L make this value an unsigned long.
// ALWAYS use unsigned values for addresses.
void loop()
{
Serial.print(F("Writing sequential numbers into SRAM...")); // _always_ store string constants in flash.
// save your RAM for more interesting stuff.
for (unsigned long i = 0; i < SRAM_SIZE; i += 2) // filling SRAM
{
// this is the (truncated from 0-65535) value we'll write.
unsigned int value = static_cast<unsigned int>(i & 0xFFFF);
SRAM.writeByte(i, value & 0xFF); // write lowest 8 bits
SRAM.writeByte(i + 1, (value >> 8) & 0xFF); // write next 8 bits.
}
Serial.println(F("done."));
// read back
Serial.println(F("SRAM contents (16-bits unsigned values):"));
for (unsigned long i = 0; i < SRAM_SIZE; i += 2) // reading all SRAM in 16-bit chunks.
{
Serial.print(i, HEX);
Serial.print(F(": "));
// read two consecutive bytes and pack them into a 16-bit integer.
unsigned int value = SRAM.readByte(i) + (static_cast<unsigned int>(SRAM.readByte(i+1)) << 8); // the cast is necessary.
Serial.println(value);
}
delay(100);
}
I'm very new to the Microchip line and I'm currently using the Pic32 Ethernet Starter Kit 2. I've been playing and testing all aspects of this product and I'm currently working with the Generic TCPIP Servo demo from Harmony. I can load the app on the Chip and log into it with Telnet. I can also see it working if I type in say "h" it will echo back "hH" as it should. Because in this demo it runs a ToUpper line on it. What I'm looking to try is to type "hello" in telnet then have it send back "World" Just something simple to get me rolling with this. Below is the current section of code that reads the incoming data converts it to Upper and sends back out.
case APP_TCPIP_SERVING_CONNECTION:
{
if (!TCPIP_TCP_IsConnected(appData.socket))
{
appData.state = APP_TCPIP_CLOSING_CONNECTION;
SYS_CONSOLE_MESSAGE("Connection was closed\r\n");
break;
}
int16_t wMaxGet, wMaxPut, wCurrentChunk;
uint16_t w, w2;
uint8_t AppBuffer[32];
//uint8_t AppBuffer2[] = "This is a Test";
// Figure out how many bytes have been received and how many we can transmit.
wMaxGet = TCPIP_TCP_GetIsReady(appData.socket); // Get TCP RX FIFO byte count
wMaxPut = TCPIP_TCP_PutIsReady(appData.socket); // Get TCP TX FIFO free space
// Make sure we don't take more bytes out of the RX FIFO than we can put into the TX FIFO
if(wMaxPut < wMaxGet)
wMaxGet = wMaxPut;
// Process all bytes that we can
// This is implemented as a loop, processing up to sizeof(AppBuffer) bytes at a time.
// This limits memory usage while maximizing performance. Single byte Gets and Puts are a lot slower than multibyte GetArrays and PutArrays.
wCurrentChunk = sizeof(AppBuffer);
for(w = 0; w < wMaxGet; w += sizeof(AppBuffer))
{
// Make sure the last chunk, which will likely be smaller than sizeof(AppBuffer), is treated correctly.
if(w + sizeof(AppBuffer) > wMaxGet)
wCurrentChunk = wMaxGet - w;
// Transfer the data out of the TCP RX FIFO and into our local processing buffer.
TCPIP_TCP_ArrayGet(appData.socket, AppBuffer, wCurrentChunk);
// Perform the "ToUpper" operation on each data byte
for(w2 = 0; w2 < wCurrentChunk; w2++)
{
i = AppBuffer[w2];
if(i >= 'a' && i <= 'z')
{
i -= ('a' - 'A');
AppBuffer[w2] = i;
}
else if(i == '\e') //escape
{
appData.state = APP_TCPIP_CLOSING_CONNECTION;
SYS_CONSOLE_MESSAGE("Connection was closed\r\n");
}
}
// Transfer the data out of our local processing buffer and into the TCP TX FIFO.
SYS_CONSOLE_PRINT("Server Sending %s\r\n", AppBuffer);
TCPIP_TCP_ArrayPut(appData.socket, AppBuffer, wCurrentChunk);
// No need to perform any flush. TCP data in TX FIFO will automatically transmit itself after it accumulates for a while. If you want to decrease latency (at the expense of wasting network bandwidth on TCP overhead), perform and explicit flush via the TCPFlush() API.
}
}
break;
Thanks in advance.
PBSnake
case APP_TCPIP_SERVING_CONNECTION:
{
static uint8_t message[] = "Hello";
static uint16_t pos = 0;
if (!TCPIP_TCP_IsConnected(appData.socket))
{
pos = 0;
appData.state = APP_TCPIP_CLOSING_CONNECTION;
SYS_CONSOLE_MESSAGE("Connection was closed\r\n");
break;
}
int16_t wMaxGet, wMaxPut, wCurrentChunk;
uint16_t w, w2;
uint8_t AppBuffer[32];
//uint8_t AppBuffer2[] = "This is a Test";
// Figure out how many bytes have been received and how many we can transmit.
wMaxGet = TCPIP_TCP_GetIsReady(appData.socket); // Get TCP RX FIFO byte count
wMaxPut = TCPIP_TCP_PutIsReady(appData.socket); // Get TCP TX FIFO free space
// Make sure we don't take more bytes out of the RX FIFO than we can put into the TX FIFO
if(wMaxPut < wMaxGet)
wMaxGet = wMaxPut;
// Process all bytes that we can
// This is implemented as a loop, processing up to sizeof(AppBuffer) bytes at a time.
// This limits memory usage while maximizing performance. Single byte Gets and Puts are a lot slower than multibyte GetArrays and PutArrays.
wCurrentChunk = sizeof(AppBuffer);
for(w2 = 0; w2 < wCurrentChunk; w2++)
{
i = AppBuffer[w2];
if (i == message[pos])
{
pos++;
if (pos == strlen(message))
{
pos = 0;
strcpy(AppBuffer, "World");
SYS_CONSOLE_PRINT("Server Sending %s\r\n", AppBuffer);
TCPPutArray(MySocket, AppBuffer, strlen(AppBuffer));
}
}
else
{
pos = 0;
}
if(i == '\e') //escape
{
TCPServerState = SM_CLOSING;
}
}
}
break;
I have the following code which I need to execute quickly, yet its taking a lot of time to change the value, anyway over way of making this task quicker?
I am using indexOf() and substring() to accomplish this task.
This is for changing the strip LED colors.
// declare LED Series A Pins R-G-B (PWM Pins)
int const AledRedPin = 6;
int const AledGreenPin = 5;
int const AledBluePin = 3;
// declare LED Series B Pins R-G-B (PWM Pins)
int const BledRedPin = 10;
int const BledGreenPin = 11;
int const BledBluePin = 9;
// serial input variable & string
// initialise LED Series A Pins R-G-B (PWN Value: 0 to 255)
// initial value = 255
int AledRed = 255;
int AledGreen = 255;
int AledBlue = 255;
// initialise LED Series A Pins R-G-B (PWN Value: 0 to 255)
// initial value = 255
int BledRed = 255;
int BledGreen = 255;
int BledBlue = 255;
//serial input
String Command = "";
//string manipulation
int cmdindexval = 0;
String CommandType = "";
int CommandValue = 0;
String Series = "";
void setup() {
// put your setup code here, to run once:
// start serial
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB
}
// set LED Series A Pins as Output R-G-B
pinMode(AledRedPin, OUTPUT);
pinMode(AledGreenPin, OUTPUT);
pinMode(AledBluePin, OUTPUT);
// set LED Series B Pins as Output R-G-B
pinMode(BledRedPin, OUTPUT);
pinMode(BledGreenPin, OUTPUT);
pinMode(BledBluePin, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
// read from serial if it's available
if (Serial.available() > 0) {
Command = Serial.readString(); //read string from serial monitor
cmdindexval = Command.indexOf('='); //read characters until '=' then assign the value
CommandType = Command.substring(0, cmdindexval); //assign the value from 0 to cmdindexval
//Series = Command.substring(0, 1); //read first character
CommandValue = Command.substring(cmdindexval + 1).toInt(); //assign the value after '=' and convert string to Int
Serial.println(CommandType + " ,is equal to " + CommandValue + " ,Series: " + Series);
//if (Series == "A") {
if (CommandType == "ACledRed"){
AledRed = CommandValue;
}
else if (CommandType == "ACledGreen"){
AledGreen = CommandValue;
}
else if (CommandType == "ACledRedBlue") {
AledBlue = CommandValue;
}
//}
//else if (Series == "B") {
if (CommandType == "BCledRed") {
BledRed = CommandValue;
}
else if (CommandType == "BCledGreen") {
BledGreen = CommandValue;
}
else if (CommandType == "BCledBlue") {
BledBlue = CommandValue;
}
//}
} //end serial
analogWrite(AledRedPin, AledRed);
analogWrite(AledGreenPin, AledGreen);
analogWrite(AledBluePin, AledBlue);
analogWrite(BledRedPin, BledRed);
analogWrite(BledGreenPin, BledGreen);
analogWrite(BledBluePin, BledBlue);
}
From the Arduino docs on readString:
Serial.readString() reads characters from the serial buffer into a string. The function terminates if it times out (see setTimeout()).
and the docs on setTimeout:
Serial.setTimeout() sets the maximum milliseconds to wait for serial data when using Serial.readBytesUntil(), Serial.readBytes(), Serial.parseInt() or Serial.parseFloat(). It defaults to 1000 milliseconds.
This means that the readString is always waiting 1 sec to make sure that the sending of the string is finished and has the complete string.
Unfortunately that means it's slow to respond. You could lower the timeout with the setTimeout, but you would still have some delay, or if you set it too low you could potentially get incomplete stings.
The best solution would be to use readStringUntil, so you know you have a complete string when you get a terminator character (like a newline).
Replace
Command = Serial.readString();
with
Command = Serial.readStringUntil('\n');
and make sure you set the Serial monitor so send the newline character.
Edit: see important update at the end.
This can be made significantly faster, but first let's have a look at the work that has to be done in every loop iteration with the current code:
As #gre_gor already explained, you could be losing some time in readString().
for each value, between 15 and 20 bytes have to be sent, read, parsed and converted to int.
for each received value (R, G or B), analogWrite() is called 6 times (and analogWrite() isn't really fast). This means that in order to change the two series, analogWrite() is called 36 times (and this is probably where most time is lost). And if no serial data is available, analogWrite() is still called 6 times.
and also, Serial.println() is called each time in the example - so it would be best to turn this off.
To speed this up, the RGB values could be sent in a small buffer (assuming you have control over the sending side as well), and read with Serial.readBytesUntil().
If the values for both A and B are sent together, the 6 RGB values can be sent as 6 bytes:
byte rcvBuffer[7];
void loop() {
if (Serial.available() > 0) {
// message: RGBRGBx - but see update below
int numRead = Serial.readBytesUntil(0x78, rcvBuffer, 7); // 0x78 is 'x'
if (numRead == 7) { // or 6, see below
analogWrite(AledRedPin, rcvBuffer[0]);
analogWrite(AledGreenPin, rcvBuffer[1]);
analogWrite(AledBluePin, rcvBuffer[2]);
analogWrite(BledRedPin, rcvBuffer[3]);
analogWrite(BledGreenPin, rcvBuffer[4]);
analogWrite(BledBluePin, rcvBuffer[5]);
}
// else ignore this read - could be a first unaligned read
}
}
If only the values for A or B are sent together:
byte rcvBuffer[5];
void loop() {
// You could probably even remove the Serial.available() check
if (Serial.available() > 0) {
// message: TRGBx where T is Type ('A' or 'B')
int numRead = Serial.readBytesUntil(0x78, rcvBuffer, 5); // 0x78 is 'x'
if (numRead == 5) { // or 4, see below
switch (rcvBuffer[0]) {
case 'A':
analogWrite(AledRedPin, rcvBuffer[1]);
analogWrite(AledGreenPin, rcvBuffer[2]);
analogWrite(AledBluePin, rcvBuffer[3]);
break;
case 'B':
analogWrite(BledRedPin, rcvBuffer[1]);
analogWrite(BledGreenPin, rcvBuffer[2]);
analogWrite(BledBluePin, rcvBuffer[3]);
break;
default :
// do nothing, or send error message
}
}
}
}
I used 'x' as the stop byte to make it visible, but you could as well use a zero byte.
Now, I'm not really sure if readBytesUntil() also reads the terminating byte into the buffer or skips it, and can't test this right now. But I would think only the RGB values are read into the buffer. In this case you'll have to change those values to the ones I put in the comments.
To save even more time, you could check each value and only call analogWrite() if that value did change since the last call (for each R, G and B).
Update: Obviously we can't just use 'x' or a zero byte as the stop byte, because each of the RGB values could also be an 'x' or zero byte (it's getting late here :). And while ReadBytes() could be used instead, it's better to have a stop byte to keep the buffers aligned. So I would suggest to use 0xff (255) as the stop byte and make sure none of the RGB values can be 0xff.
And just in case there could be other message types in the future, each message could also be prepended with a message code (1 or 2 bytes).
I always use readBytesUntil()whenever I use the serial port for communication.
It gets the job done, it always gets the entire string, but the same problem as readString()takes at least 1000ms to complete.
Using both Serial.setTimeout() and Serial.readBytesUntil() worked fine for me, by reducing the delay.
Something like:
Serial.setTimeout(250);
inData = Serial.readStringUntil('\n');
Having issues with the Serial.read() command on my Arduino code. I have it connected to two 74HC595's shift registers connected to LED's.
I check if there is Serial data, then read two bytes. Then pass these bytes to a method that shifts them both out. When I check the bytes with Serial.print to print them out to the serial moniter I get for example
49
255
50
255
Why am I getting the two 255's I have read the documentation on arduino.cc and it says it reads a single byte only. Any ideas?
The end goal is to read two bytes on the serial line and shift them out to the shift reg's IE is the byte values of decimal 5 & 6 were passed the 1st 3rd LED's would light on one shift register then the 2nd and 3rd would on the other shift register
const int dataPin = 8;
const int latchPin = 9;
const int clockPin = 10;
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
byte low = Serial.read();
byte high = Serial.read();
Serial.println(low);
Serial.println(high);
sendBytes(low,high);
}
}
void sendBytes(byte l, byte h) {
digitalWrite(latchPin,LOW);
shiftOut(dataPin,clockPin,MSBFIRST,l);
shiftOut(dataPin,clockPin,MSBFIRST,h);
digitalWrite(latchPin,HIGH);
}
if (Serial.available() > 0) {
byte low = Serial.read();
byte high = Serial.read();
//...
This is a bug in your code. Very likely to trip, serial ports are not that fast. So high odds that Serial.available() only returns 1. You'll read the low byte okay but Serial.read() will then return -1 if there is no data to read. Which makes high equal to 0xff. The simple fix is:
if (Serial.available() >= 2)
I had the same problem reading from a program...
I had luck both letting the code loop until filled...
and before taking on new Serial data I flush the serial to get the latest bytes
While(Serial.read() != -1); //clears data in the PC Serial Port
Here's what it looks like all put together
int i = 0;
byte bytes[3];
interval = 150; //allows for this amount of time to read from serial
long previousMillis = 0;
void loop() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis < interval && i < 2) {
if(Serial.available() > 0) {
bytes[i] = Serial.read();
i++; }
}
if(currentMillis - previousMillis > 1000) { //waits 1 second to get new serial data
previousMillis = currentMillis; //resets the timer
i = 0;
While(Serial.read() != -1); //clears data in the PC Serial Port
}