I have a sensor which is outputting data at a high rate (200 Hz). The data always starts with a value of 222 followed by the information and then it repeats.
I would appreciate example code showing how to correctly and efficiently parse this data then display EACH value before reading the next value ...? I am using the code below but it is not efficient as I am throwing away the remainder of the buffer as you can see below ....
float takeReading()
{
digitalWrite(rs485Pin, LOW); // Disable RS485 Transmit
len = Serial1.readBytes((char *)buf, 8); //Process after 8 Bytes
if (len > 0)
{
for (int i = 0; i <= len - 2; i++)
{
if (buf[i] == 222)
{
measure = (int(buf[i + 1]) + (buf[i + 2]));
i = i + 2;
break; //Leave for
}
}
}
Serial1.flush();
return measure;
}
Why does takeReading() return a global variable? Why is the return type float, when the value being returned is an int (regardless of the type that measure is).
For more info on parsing input, google "LALR(1) parser"
enum ReadingState {
WAITING_FOR_222,
WAITING_FOR_FIRST_BYTE,
WAITING_OR_SECOND_BYTE,
GOT_READING
} reading_state = WAITING_FOR_222;
int measure;
void loop() {
take_reading();
if(reading_state == GOT_READING) {
// do something with the reading
reading_state = WAITING_FOR_222;
}
}
void take_reading() {
static byte first_byte;
static byte second_byte;
if(!Serial1.available()) return;
// the outer loop has not consumed the reading, so don't read the serial
// This may or may not be the right thing to do here
if(state == GOT_READING) return;
byte input = Serial1.read();
switch(reading_state) {
case WAITING_FOR_222:
if(input == 222) {
reading_state = WAITING_FOR_FIRST_BYTE;
}
break;
case WAITING_FOR_FIRST_BYTE:
first_byte = input;
reading_state = WAITING_FOR_SECOND_BYTE;
break;
case WAITING_FOR_SECOND_BYTE:
second_byte = input;
// I'm surprised that the original code just adds these without bit-shifting them
// also, it's important to use unsigned because of possible sign-extension
measure = (unsigned int) first_byte + (unsigned int) second_byte;
reading_state = GOT_READING;
break;
case GOT_READING:
// discard the byte we just read. This may or may not be the right thing to do here
break;
}
}
Several ways to do it, of course. 'Take reading' could return a boolean rather than using a GOT_READING state, or it could return a -1 if there was no reading (which the loop would have to check for). Or you could bury it all in a class and have a "yep_we_got_a_reading" and a "I_have_consumed_the_reading" method in the class.
enum ReadingState {
WAITING_FOR_222,
WAITING_FOR_FIRST_BYTE,
WAITING_OR_SECOND_BYTE
} reading_state = WAITING_FOR_222;
int measure;
void loop() {
if(take_reading()) {
// do something with the reading
}
}
boolean take_reading() {
static byte first_byte;
static byte second_byte;
if(!Serial1.available()) return false;
byte input = Serial1.read();
switch(reading_state) {
case WAITING_FOR_222:
if(input == 222) {
reading_state = WAITING_FOR_FIRST_BYTE;
}
return false;
case WAITING_FOR_FIRST_BYTE:
first_byte = input;
reading_state = WAITING_FOR_SECOND_BYTE;
return false;
case WAITING_FOR_SECOND_BYTE:
second_byte = input;
reading_state = WAITING_FOR_222;
// I'm surprised that the original code just adds these without bit-shifting them
// also, it's important to use unsigned because of possible sign-extension
measure = (unsigned int) first_byte + (unsigned int) second_byte;
return true;
}
}