Learn to code

Arduino Home

Lessons 1
Arduino - Getting Started
Lessons 2
Arduino - Basics
Lessons 3
Arduino - Serial Communication
Lessons 4
Arduino - Digital / Analog
Lessons 5
Arduino - Visual Output
Lessons 6
Arduino - Motor Control
Lessons 7
Arduino -LCD Displays
Lessons 8
Arduino -LCD Displays

Receiving and Sending multiple characters with serial communication

in Arduino Serial Communication

In lesson 3.3, we send and receive single characters to control a LED. Sometimes, single characters are not enough, and we need to apply some more complex commands or send data that consists of more than one character.

In this tutorial, we discuss a couple of methods for receiving and sending multiple characters, starting with the functions that are build-in the Arduino Language and moving to a function made by the community.

Multiple Characters

A common mistake that a lot of beginners make when they send data from the serial monitor to an Arduino Board or from board to board is that the data arrives at the same time. IT DOES NOT.

When you use serial communication and send the characters string “HELLO” to another board, the characters are received one character at a time.

If you would like to check “HELLO”,  for instance, you need to check each character on the receiving Arduino Board and put them in order. There are a number of ways to solve this problem. Let’s start with the command Serial.readBytesUntil().

Serial.readBytesUntil()

Serial.readBytesUntil() reads characters from the serial buffer into an array. If the determined length is reached. The function terminates if it times out or if the terminator character is detected.

Serial.readBytesUntil(character, buffer, length)

Parts you will need

Arduino Uno Rev3 Arduino Uno Rev3 × 1
Arduinoplatform is a participant in several affiliate programs. This means that I will earn a commission if you buy a product from the affiliated websites by clicking on the links provided above.

Example code with the serial monitor

The above example is very basic and sets the buffer to a maximum length of 30 characters. You could enter more than 30 characters which will lead that the sketch will misbehave.

Give the above a try. It should work quite well as long as you remember the limitations.

// Arduino serial communication sketch
// example of Serial.readBytesUntil() function
 
int length = 30;
char buffer [31];
char termChar = 'n';
 
void setup()
{
Serial.begin(9600);
Serial.println("Set line endings Newline");
Serial.println("");
Serial.println("Please enter your name and click Send");
}
 
void loop()
{    
  if (Serial.available())
  {
int numChars=Serial.readBytesUntil(termChar,buffer,length);
buffer[numChars]='';
Serial.print("Hello ");  Serial.println(buffer); 
  }
}

 

If you select the “no-line ending” in the serial monitor and enter a new name it will work, but there is a delay before the Arduino Responds.

This is because the function reads until it times out. The default timeout is 1000ms or 1 second. In other words, the function could timeout even if not all the data is received

Alternative function for multiple characters

So there is an alternative function derived from Martyn Currey, which allows us to solve the negative issues surrounding the serial.readByteUntil(). It allows us to set a length of the buffer size and solves the problem with the blocking. When serial.readByteUntil() is executed the function blocks while waiting. This means that the Arduino Board cannot do anything else.

To solve these two problems, the following sketch can be used as a guideline.

// Arduino Sketch: alternative to Serial.readBytesUntil()


char c = ' ';
int length = 30;
char buffer [31];
char termChar = 10;

byte index = 0;
boolean haveNewData = false;

void setup()
{
  Serial.begin(9600);
  Serial.println("Set EOL to Newline");
  Serial.println("Please enter your name and click Send");
}

void loop()
{
  readSerial();
  if ( haveNewData ) {
    processNewData();
  }
}

void readSerial()
{
  if (Serial.available())
  {
    c = Serial.read();
    if (c != termChar)
    {
      if (index < length)
      {
        buffer[index] = c;
        index = index + 1;
      }
    }
    else
    {
      buffer[index] = '';
      index = 0;
      haveNewData = true;
    }
  }

}


void processNewData()
{
  Serial.print("Hello ");  Serial.println(buffer);
  haveNewData = false;
}

Code Explanation

Variable c is used to store the latest character read from the serial input.

The integer variable length defines the maximum length of the buffer.

The char variable buffer is used to store incoming data.

Termchar is a char variable that is used for the terminating character.

The index variable is for determining the position of the buffer, where the next character is copied to. T

he Boolean variable haveNewData is used in the sketch to determine if there is new data to process.

char c = ' ';
int length = 30;
char buffer [31];
char termChar = 10;
 
byte index = 0;
boolean haveNewData = false;

Since we need a place for storing the terminating character, the length of the data put into the buffer should always be one space smaller than the buffer.

Void setup()

In the setup part of the sketch we begin serial communication and print some text to the Serial monitor.

void setup()
{
  Serial.begin(9600);
  Serial.println("Set EOL to Newline");
  Serial.println("Please enter your name and click Send");
}

Void loop()

 readSerial: this function checks whether or not there is data to read, and inside the function is a limitation for the length of the data.

haveNewData: this is the condition in the if statement that checks to see if there is a terminating character. It means that there is new data available. If there is not a terminating character, the character that is read is added to a char variable called buffer, and the process continues. If the last character that is read is a terminating character, we will “process” the received data.

processNewData: this part prints a “Hello” message and the content of the buffer to the serial monitor.

Void readSerial()

If serial data is available, we read one character into c. We then check to see if c is not the terminating character and if it is not we copy c to the buffer char array at the position specified by index. Then index is incremented, ready for the next character.

To limit the size, all we need to do is check the current index position against the maximum size of the buffer. If we have reached the end of the buffer, do not increase the index. This does mean the end of the data will be missing, but at least the sketch will function properly.

void readSerial()
{
  if (Serial.available())
  {
    c = Serial.read();
    if (c != termChar)
    {
      if (index < length)
      {
        buffer[index] = c;
        index = index + 1;
      }
    }
    

If c is the terminating character there is no need to copy it to the buffer we simply close the buffer (add ‘’ to the end of the buffer) set index to 0 ready for next time and set haveNewData = true to show we have new data.

else
    {
      buffer[index] = '';
      index = 0;
      haveNewData = true;
    }
  }

}

Void processNewData()

in this part of the sketch, we print a message to the serial monitor with the buffer. After the data is printed, we set the Boolean to be false. It is important to set the Boolean haveNewData to false in order to receive a new message.

void processNewData()
{
  Serial.print("Hello ");  Serial.println(buffer);
  haveNewData = false;
}

If c is the terminating character there is no need to copy it to the buffer we simply close the buffer (add ‘’ to the end of the buffer) set index to 0 ready for next time and set haveNewData = true to show we have new data.

Why is this better than using Serial.readBytesUntil()?

As mentioned above, Serial.readBytesUntil() has a timeout. This will not be an issue when using the serial Monitor but can become an issue when you receive data from other devices. The new method/function does not have a timeout.

The new method will receive characters one by one. You can test this by using the Serial monitor yourself. Set the EOL to “no line ending” enter A and click send, enter B click send, enter C and click send. Now, change it back to “Newline” and enter D and click send. ABCD should now appear on the serial monitor.

Previous Post
Serial communication between two Arduino Boards
You must be logged in to post a comment.
Menu