Reading the byte after the header

I have been trying to use the following switch case, but I can only successfully read case 1 and not case 2.

  if (Serial.available() > 2)  // Wait for serial input (min 3 bytes in buffer)
    // Read the first byte
    startbyte = Serial.read();
    // If it's really the startbyte (253) ...
    if (startbyte == 253) {
      // ... then get the next two bytes
      for (i=0;i<2;i++) {
        userInput[i] = Serial.read();
      }
      // First byte = servo to move?
      servo = userInput[0];
      // Second byte = which position?
      pos = userInput[1];
      // Packet error checking and recovery
      if (pos == 253) { servo = 253; }

      // Assign new position to appropriate servo
      switch (servo) {
        case 1:
          servo7.write(pos);    // move servo7 to 'pos'
          break;
        case 2:
          servo8.write(pos);
          break;}
  delay(10);                           // waits for the servo to get there
  Serial.flush();

So I decided that maybe it’s easier to just create a unique header for each servo and a value instead of a header, servo number and value. That way I can be rid of the switch case issue and it can provide a positive test. The challenge I have is that I can’t figure out an if statement that allows me to read the character after the header. I tried the following but it didn’t work. Can someone provide me with pointers on how to do a simple “if this header then read next character” routine?

      if (Serial.available() > 1)  // Wait for serial input (min 2 bytes in buffer)
    // Read the first byte
    startbyte = Serial.read();
    // If it's really the startbyte (253) ...
    if (startbyte == 253) {
      // ... then get the next byte
      for (i=0;i<1;i++) {
        userInput[i] = Serial.read();
      }
      // First byte = which position?
      pos = userInput[0];
      // Packet error checking and recovery
      if (pos == 253) { servo = 253; }
         servo8.write(pos);    // move servo8 to 'pos'
 
  Serial.flush(); 
    }

icek,

The problem is that your program can call Serial.read() much more quickly than the bytes come in. Remember, at 9600 bits per second, it takes about one millisecond to receive each character.

If there are no bytes to read, Serial.read() returns a value of -1. In some cases, you are calling Serial.read() without using Serial.available() to check if there are any bytes ready.

Regards,

-Mike

Hi Mike:

Thank you for your feedback. I am a bit confused about your comment since in each case I do call out serial available before serial read. I make sure that it reads at least three bytes and then interprets them. I doubt my second set of code is right with looking for just the next byte, but my first set of code is used by many people according to forums.

Icek

icek,

On closer reading of your code, you are correct. There should be enough bytes in the buffer. My apologies.

One way to debug this would be to print out the bytes that are received. I don't know how your hardware is set up, but you could use a pin and SoftSerial to output the debug information.

Regards,

-Mike

The only portion of that code that is dependent on there being 2 or more bytes available is the first Serial.read() statement, since there are no curly braces defining a block.

if (Serial.available() > 2)  // Wait for serial input (min 3 bytes in buffer)
    // Read the first byte
    startbyte = Serial.read();

The next bit of code is executed regardless of whether there was any serial data, or not.

if (startbyte == 253) {
      // ... then get the next byte
      for (i=0;i<1;i++) {
        userInput[i] = Serial.read();
      }
      // First byte = which position?
      pos = userInput[0];
      // Packet error checking and recovery
      if (pos == 253) { servo = 253; }
         servo8.write(pos);    // move servo8 to 'pos'

  Serial.flush();
    }

In this code, you read serial data, regardless of whether there is anything to read, or not.

The loop is going to read one character (possibly getting a -1) into an array. Why are you using a loop to read one character?

Then, if there is any serial data that has been sent, but not yet read, you delete it. Why?

Unless there is compelling reason, you should not be flushing the serial buffer. Is there a good reason for doing so? If the sender is sending information faster than it can be processed, the sender should be modified to slow down the send rate, or the receiver should be improved to process data faster. Discarding, indiscriminately, random amounts of data is not a best practice.

Where is the data being read coming from?

Hi PaulS:

I will check out the braces again to see if that makes a difference. The reason why I had Serial.flush() was that without it I wasn't able to read anything. With it I get at least the case 1 data working.

What I'm doing is using an FSR from one device and sending to the other device which will then read the mapped data to move a servo. I would like to use multiple FSRs and multiple corresponding servos. My thought around the first block of code was that by defining serial.available() > 2 I was consistently getting 3 bytes in the buffer. From your message it doesn't sound like that's the case.

For the second block I decided to break down the switch case and make a more inefficient, though clearer for error checking, code. In the second case I decided to just send a unique header per FSR and then have the other Arduino read the header and the following variable produced by the FSR. So really it's two characters and not one, just that one is always pre-defined as a header.

In the end all I wanted to do was use the switch case which everyone else seems to be using to parse the data that is being received via serial: Fixed header, fixed number for servo and variable value from FSR reading.

You don't want to do anything unless there are at least two bytes to read.

if(Serial.available() > 1)
[glow]{[/glow]
   // EVERYTHING to do with reading, and using, data goes in these braces
[glow]}[/glow]

Another thing to look at:

if (pos == 253) { servo = 253; }
         servo8.write(pos);    // move servo8 to 'pos'

Do you really want to (try to) move the servo to position 253?

Hi PaulS, I will try out that format of using the curly brackets. And you're right, I don't want pos 253 to move the servo to 253. I read somewhere that it was an "error correcting" thing. Ironically I tried removing it and it impacted even the first servo's ability to move when it was gone. I will test it out more and hopefully be able to remove the position 253 statement you pointed out.