Char array with Serial.Read: It works - but why?

Hi!

I'm new to Arduino and C++ programming. One of my first small projects is to send data back and forth between my computer and the arduino over serial. After some research and some playing around I created a small project for the Arduino that receives a string over serial and simply returns the whole serial data back. Strange thing is: It works and I wonder why... Here is the code:

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

void loop() {
  
  char received[3];
  int i = 0;
  while (Serial.available() > 0)
  {
    received[i] = Serial.read();
    i++;
  }
  
  if (i != 0)
  {    
      Serial.print(received[0]); 
  }  
}

The part that is really confusing me is the char array 'received' that I initialized with [3]. I expected it to only take up to three chars, but when I test the program with the serial monitor then I can send whatever I want - I always receive the whole string back, no matter if it is three char long, longer or shorter - it is simply working !?!?! Even if I change the capacity of the char array to a different number - its still the same behavior... Can someone please explain that to me?

Another question: I'm initializing the serial communication with 9600 baudrate and it works - with all other rates I'm receiving a mess back. Why is it exactly 9600 and not something different?

Kind regards

Ralf

That is because loop() starts over and over again ... It will just receive one char at the time:

modded your code a bit to illustrate it

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

void loop()
{
  char received[3];
  int i = 0;
  while (Serial.available() > 0)
  {
    received[i] = Serial.read();
    i++;
  }
  
  if (i != 0)
  {   
    Serial.print("i= ");
    Serial.print(i);
    Serial.print("\t\t"); 
    Serial.println(received[0]); 
  }  
}

This variation will echo one char or none at all..

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

void loop()
{
  char received[3];
  int i = 0;
  while (Serial.available() > 0)
  {
    received[i] = Serial.read();
    i++;
  }
  
  if (i != 0)
  {   
    Serial.print("i= ");
    Serial.print(i);
    Serial.print("\t\t"); 
    Serial.println(received[0]); 
  }  
  while(1);  // "stop the sketch" 
}

Why is it exactly 9600 and not something different?

Because that is the baud rate set at the sending end and the recieving end. You set it in the setup() function and it is the default value of the monitor on the PC. To change it use the drop down menu at the bottom right hand corner of the serial monitor. It will work at any speed as long as it is the same in the sketch and the monitor window.

Hi robtillaart,

I guess you are right, but then I wonder about the "while (Serial.available() > 0)" ...I expected it to get the whole data that the Arduino receives at a time, so I can process it in one piece.

Regards

Ralf

Hi Grumpy_Mike,

you are right - I just never noticed that drop down box in the serial monitor window... D'Oh!

Thanks

Ralf

but then I wonder about the “while (Serial.available() > 0)” …I expected it to get the whole data that the Arduino receives at a time, so I can process it in one piece.

It does get all the data that has arrived. It just hasn’t all arrived yet.

Serial data is sent like I type. Sssslllloooowwwwllllyyyy.

There are ways to correct all the data that constitutes a packet, but you have to define what constitutes a packet, and write appropriate code to get it.

If you send data using < and > as start and end markers, this code will collect all of it in an array, no matter how slowly it arrives.

#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';
  }
}

You can use other start and end markers, if you do not like < and >.

Hi PaulS,

I really have to take a closer look at your code there, at least I have a better understanding on what is going on there.

Thanks!

Just for fun:

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

int  count = 0;

void loop() {
  
  char received[3];
  int i = 0;

  while (Serial.available() > 0)
  {
    received[i] = Serial.read();
    i++;
  }

  if (i != 0)
  {    
      Serial.print(received[0]);
      Serial.print(" .. ");
      Serial.println(count); 
  }  
  else
  {
    count++;
  }
}