Receiving Byte Array over serial

Hi all!
I am currently struggling to receive a 4 byte array, containing 3 values and a sync byte (S, or 0x53). All values stay at 0, even though it is receiving serial data... I'm sending this byte array every 10ms.
Here below is my code:

byte RGB[3] = {0, 0, 0};

boolean newData = false;

void setup() {
    Serial.begin(9600);
    Serial.println("<Arduino is ready>");
}

void loop() {
    if (Serial.available() > 0) {
    byte val = Serial.read();  

    if (val == 'S') { 
      while (!Serial.available())
      RGB[0] = Serial.read(); 

      while (!Serial.available()) 
      RGB[1] = Serial.read();

      while (!Serial.available())
      RGB[2] = Serial.read(); 
     }

    Serial.println(RGB[0]);
     
  }
}

What do you think happens here?

There it waits until it receives the next byte, the time between the first and second byte it's stuck in that while loop

Are you expecting the 0x53 byte first?

If you want it to stop at the while statements then you need to terminate them with ;

Otherwise if not true it will just continually execute the next statement.

It certainly does not

Okay... I'm still trying to figure this out, i can't get my head around this serial receiving stuff... What approach would you take to this?

Can start with removing all whiles

I already figured that, doesn't seem like the best approach to this, I'm experimenting with the Serial.readBytes() function, but no results so far, will post the code i have once i get better results

So I made a new program from scratch... But with, so far, no good results.
The data being sent to is is as following:
0x52, [R value], 0x47, [G value], 0x42, [B value]

And here's the code i have come up with:

byte RGB[3];

void setup() {
  Serial.begin(9600);
  }

void loop() {
  byte d = 0;
  int state = 0;

  while (state == 0){
    if (Serial.available() > 0){
      d = Serial.read();

      //"R" found
      if (d == 0x52){
        state = 1;
      }

      //"G" found
      if (d == 0x47){
        state = 2;
      }

      //"B" found
      if (d == 0x42){
        state = 3;
      }

    Serial.println(state);
      
    }

    while (Serial.available() < 0){    // keep looping until data available
    }
  }

  //"R" Found!
  while (state == 1){
    d = Serial.read();

    if ((d != 0x52) && (d != 47) && (d != 42)){
      RGB[0] = d;     
    }
    
    if (d == 0x52){
        state = 1;
      }

      if (d == 0x47){
        state = 2;
      }

      if (d == 0x42){
        state = 3;
      }

      Serial.println(RGB[0]);
  }

  //"G" Found!
  while (state == 2){
    d = Serial.read();

    if ((d != 0x52) && (d != 47) && (d != 42)){
      RGB[1] = d;     
    }
    
    if (d == 0x52){
        state = 1;
      }

      if (d == 0x47){
        state = 2;
      }

      if (d == 0x42){
        state = 3;
      }
  }

    //"B" Found!
  while (state == 3){
    d = Serial.read();

    if ((d != 0x52) && (d != 47) && (d != 42)){
      RGB[2] = d;     
    }
    
    if (d == 0x52){
        state = 1;
      }

      if (d == 0x47){
        state = 2;
      }

      if (d == 0x42){
        state = 3;
      }
  }
}

Where is the serial data coming from?

It appears you are connected to the serial monitor as you have Serial.print statements... so is the input coming from the monitor? or are you expecting it from somewhere else?

Your code is WAY more complicated than it needs to be.

I suggest to read through the Serial Input Basics tutorial on the forum.

1 Like

And the link to Robin's tutorial is Serial Input Basics - updated

1 Like

Thanks for the reply!
It's coming from a C# program, using a usb to serial (5V) adapter. I already checked using a serial port monitor program, and the bytes are being sent correctly.

But you are also connected to the serial monitor? ... do you have 2 serial connections?

You have only opened one

   Serial.begin(9600);

What Arduino board are you using?

1 Like

I'm using an Uno, it has only one serial port, and i just thought about it as well, if i send any text using "Serial.writeln" it will probably mess up the entire system, if my thinking is correct

Thanks! I'll have a good look at that!

Okay so, after reading through the link @sterretje gave, i came accross a similar program to what i want to achive. I based myself off that to understand the workings of this serial stuff... And as a huge surprise the test program i made almost intstantly worked!!
I can now receive the R, G, B and sync bytes and display them on their respective led (except for the sync one of course)!
Below here is the code i got, so far i don't see any room for significant improvement, feel free to prove me wrong!

//Define led pins
#define Rpin 3
#define Gpin 5
#define Bpin 6

//The end marker is 255, the max value of the received R, G and B byte has been reduced to 254!!
//A single bit lower than maximum is barely noticable
#define EndMarker 255

//Define received and temp buffer, and the amount of received bytes
byte dataRec[4];
byte tempBuffer[4];
byte bytesRec = 0;

void setup() {
  //Start serial monitor
  Serial.begin(57600);
  //Set the pins for the R, G and B led as output (PWM)
  pinMode(Rpin, OUTPUT);
  pinMode(Gpin, OUTPUT);
  pinMode(Bpin, OUTPUT);

}

void loop() {
  getData();
}

//Method to read the incoming data
void getData() {
  if (Serial.available() > 0) {
    byte x = Serial.read();

    //If the end marker has been received
    if (x == EndMarker) {
      //Put all temp bytes in the received buffer
      for (byte n = 1; n < bytesRec; n++) {
        dataRec[n] = tempBuffer[n];
      }
      //Executed method to use received data as pwm
      SendToLeds();
    }

    //Put received bytes into temp buffer
    tempBuffer[bytesRec] = x;
    bytesRec ++;
  }
}

//If data has been put in the received buffer, set them on the correct led, and reset received bytes
void SendToLeds() {
  analogWrite(Rpin, dataRec[1]);
  analogWrite(Gpin, dataRec[2]);
  analogWrite(Bpin, dataRec[3]);
  bytesRec = 0;
}

The very first time that you receive a 'packet', data will be in tempBuffer[0..2] and tempBuffer[3] will contain the end marker. All successive times, the data will be in tempBuffer[1..3] and tempBuffer[0] will contain the end marker.

Possible improvements

  1. Fix above :wink:
  2. Hardening; what happens if you send more than 4 bytes accidentally or on purpose? Your application might show undefined behaviour.
  3. Full separation of receive and led control (don't call SendToLeds() in getData(), don't reset bytesRec in SendToLeds()).

Thanks for the feedback!
I don't really get how the end marker can be last in the tempBuffer , but first in the dataRec buffer, since the tempBuffer gets compied exactly as it is into the dataRec buffer in the for loop.

After a call to SendToLeds(), bytesRec is set to 0. Next you do tempBuffer[bytesRec] = x; So where is the end marker.

There must be a reason why you start with 1 in for (byte n = 1; n < bytesRec; n++) and why you use elements 1, 2 and 3 in the SendToLeds() function and not 0, 1 and 2 which would be more usual.