Arduino 2560R3: Receiving a stream of data over UART

Hello!

I have a following problem to solve - I would like to receive a constant stream of data from STM32F4Discovery (everything already implemented here) to Arduino 2560R3 via UART. Connection in not a problem, I understand everything.

My stream consists of 20 bytes, each byte from #1 to #19 representing ASCII coded number/letter and byte number #20 representing ASCII coded new line/line feed (0x0A), serving as delimiter.

My question - how to store and update first 19 bytes? How does Arduino UART buffer work? How to actually parse data? I would like to display it on LCD screen as live data, with refresh rate around 10 values per second (value gets calculated from bytes 1 to 19).

I also forgot to ask - what does Arduino do when the receive buffer is full? Does it overwrite it with new data, or does it throw away new data? Is is possible to pick between these two options?

You should describe your application in more details, with this amount of information helping is almost not possible.

how to store and update first 19 bytes?

Probably a character array would be appropriate?

How does Arduino UART buffer work?

It’s organized as a ring buffer. Why do you ask?

How to actually parse data?

That depends a lot on what the data contains. As you haven’t told us we cannot tell you how it may be done.

on LCD screen as live data, with refresh rate around 10 values per second

Most LCDs aren’t that fast in updating their content but maybe your’s is different. You haven’t told us what type you’re using.

Does it overwrite it with new data

Yes.

Is is possible to pick between these two options?

No.

  1. Application sends 20 consecutive bytes over and over again. Each of these bytes represents ASCII coded value character value 0-9 or A-9 (for example - char '0' gets send as 0x30), except byte 20 which is always of value 0x0A (line feed) and serves as delimiter between messages. Messages are sent at "high" speed, let's say 20 messages per second (= 400 bytes per second, including delimiters).

  2. About buffer - I am asking because I always need the newest data possible. I don't mind if the old data gets thrown away - during calculation of value from message and displaying it on LCD, I need old data to be thrown away, so I can use new data in next loop iteration. Also - how long is the buffer? I read somewhere it is 128 bytes long, is that correct?

  3. Assuming the buffer is 128 bytes long, I can put 6 messages in it (in best case). Now, since my data changes fast, it is enough to pick one message from the buffer and discard the others. In other words - I need (any) 19 bytes between two bytes with value 0x0A. I want to store each of these bytes into separate integer / integer table. After I have them stored, I can calculate the value which I want to show it on LCD.

  4. LCD is taken care of, don't need help here.

I read somewhere it is 128 bytes long, is that correct?

With 1.0, and later, the buffer is 64 bytes. Prior to 1.0, it was 128 bytes.

  1. Assuming the buffer is 128 bytes long, I can put 6 messages in it (in best case).

No, you can't. The HardwareSerial instance can, but you can't.

In other words - I need (any) 19 bytes between two bytes with value 0x0A.

You can do that. Read (and discard?) until you get a 0x0A. Then, read and store until you get another 0x0A.

I want to store each of these bytes into separate integer / integer table.

Not sure what you want to do here. The bytes are not ints, so why store them in an int array? You will run put of room quickly if you try to store each set of 19 bytes in another position of a more complex array.

"You can do that. Read (and discard?) until you get a 0x0A. Then, read and store until you get another 0x0A."

Could you tell me how to do that?

"Not sure what you want to do here. The bytes are not ints, so why store them in an int array? You will run put of room quickly if you try to store each set of 19 bytes in another position of a more complex array."

You did not get me right here. I can use short type instead, but this is not the point. Point is I want to update values in this array in each loop iteration, that's all. No way of running out of space here.

Could you tell me how to do that?

This is what I use to receive a whole packet. It is easily modified to use the same start and end marker.

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

Looks simple. So the data gets stored in inData char array? So, after that, I only need to convert chars into integers and that's it.

Thanks, will try!

P.S.: Here:

if(inChar == SOP) {
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}

... is better to do like this:

if(inChar == SOP) {
index = 0;
inData[index] = '\0';
continue;
}

... and then in the last if statement you can just check for EOP (which actually you don't have to).

This code here does not work … :frowning:

char data[19];

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

void loop() {
  while(Serial.available() == 0){
    
  }
  receiveCANData();
  loopbackCANData();
}

void receiveCANData() {
  //char data[19];
  byte index = 0;
  boolean discard = true;
  boolean start = true;
  
  // Start reading data from buffer
  while(Serial.available() > 0) {
    char ASCII = Serial.read();
     
    if (ASCII != '\n' && discard) { // discard all data until first delimiter
      discard = false;
      //Serial.write('H');
      //delay(50);
      continue;
    }
    else if (ASCII == '\n' && start) { // discard first delimiter
      start = false;
      //Serial.write('G');
      //delay(50);
      continue;
    } 
    else if (ASCII == '\n') { // reached second delimiter, end of data, exit loop
      break;
    }
    else {
        data[index] = ASCII;
        index++;
    }
  }
}

void loopbackCANData() {
  for (int i=0; i<19; i++) {
    Serial.write(data[i]);
    delay(50);
  }
  Serial.write('\n');
}

What am I doing wrong?

Simple solutions are always the best …

void receiveCANData() {
  index = 0;
  while(index < 19) {
    while(Serial.available() > 0) {
      char ASCII = Serial.read();
       
      if (ASCII == '\n' && index < 19) {
        index = 0;
      }
      else {
          data[index] = ASCII;
          index++;
          if (index == 19) {
            break;
          }
      }
    }
  }
}