Reading Serial on the Arduino

I see many many questions on the Arduino forums from people trying to read data from a serial connection and not fully understanding how it works – and hence failing.

So, how should you read from serial?

Well, what a lot of new users don’t realise is that serial data arrives one character at a time, and you have little or no control over just when that data arrives.

The Arduino has a handy function: Serial.available(), which tells you how many characters are in the serial device’s receive buffer. If you know beforehand how many characters you are going to be receiving this can be a very handy and simple way of managing your receiving. However, it has to be done right.

Too many times I have seen the following:

if (Serial.available() > 0) {
  for (int i=0; i<8; i++) {
    buffer[i] = Serial.read();
  }
}

What that is intended to do is wait for the message to arrive, then read all 8 characters of it into a buffer. What it actually does, is wait for the first character of the message to arrive and then try and read in 8 characters into the buffer, whether or not they have actually arrived.

What you should be doing is waiting for the internal serial buffer to have all 8 characters in it, and only then do you read them in:

if (Serial.available() >= 8) {
  for (int i=0; i<8; i++) {
    buffer[i] = Serial.read();
  }
}

See the subtle difference there?

Another problem is what to do if you don’t know how many characters you will be receiving. A common misconception seems to be that if you send 5 characters from one end of the serial link you will instantly receive 5 characters at the other end, and that those 5 characters will form a single coherent lump that the receiver somehow knows are one transmission. That is not the case. The receiver just receives the characters one at a time and adds them to its internal buffer. It has no concept at all about how many characters were sent, and how long the message is meant to be.

For that you need to have some marker that tells the receiver when the whole message has arrived. The normal marker to use is character 13, or the carriage return character. This is what your keyboard sends when you press the RETURN or ENTER key, so it’s a logical choice.

The receiver needs to just keep receiving characters and adding them to its buffer up until it receives this terminatingcharacter. Only then can you actually do anything with the message.

Remember – Serial.read() just returns one character (if it is available). So you will need to keep calling it over and over again until the whole message has arrived.

Take the following little sketch for example:

int readline(int readch, char *buffer, int len)
{
  static int pos = 0;
  int rpos;

  if (readch > 0) {
    switch (readch) {
      case '\n': // Ignore new-lines
        break;
      case '\r': // Return on CR
        rpos = pos;
        pos = 0;  // Reset position index ready for next time
        return rpos;
      default:
        if (pos < len-1) {
          buffer[pos++] = readch;
          buffer[pos] = 0;
        }
    }
  }
  // No end of line has been found, so return -1.
  return -1;
}

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

void loop()
{
  static char buffer[80];
  if (readline(Serial.read(), buffer, 80) > 0) {
    Serial.print("You entered: >");
    Serial.print(buffer);
    Serial.println("<");
  }
}

So, what are we doing here? Well, we have a little function called readline(). This takes an incoming character (provided by Serial.read()), and decides what to do with it. If it’s a new line character (‘\n’) then it gets ignored and thrown away. This is to make it handle “CRLF” terminated lines properly without leaving a mess. If it’s a carriage return, then we decide that the message is complete and return the number of characters in the message. If it’s none of those, then just add the character to the buffer (if there’s room).

Only when the message has been received (the return value > 0) will we actually look at the contents of the buffer and do something with it – in this case just print it back to the serial device. you’ll notice that this method has several advantages:

  • You’re not blocking while waiting for a character to arrive, so you can continue doing other things at the same time as receiving your message.
  • The terminating carriage return (and possible line-feed) characters are automatically discarded, which makes string comparisons simpler.
  • Your program can continue doing other things while the message is being received – it’s very simple to know if it’s all there or not.
  • The buffer will always be properly null-character terminated.

So as soon as the return value of readline() is greater than 0 you know you have a full message of more that 0 characters in length. Now you can go and do whatever you want with that message – be it convert it to an integer withatoi(), compare it with other strings with strcmp(), etc.

3 thoughts on “Reading Serial on the Arduino

  1. Josh

    I’m working on a serial communication protocol for the Arduino and I knew most of the example code I was seeing on forums wasn’t designed well. Your code illustrates proper design principles and understanding of serial buffers. Thank you for taking the time to share it, I can now code in confidence!

    Like

    Reply
  2. The Waz

    I really appreciate your taking time to share this post. I have recently built some projects that require communication with several serial devices. An adaptation of this scheme allows me to build up buffers for each in parallel instead of putting the rest of the sketch on hold while listening to a one device.

    Like

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s