Serial I/O Theory

Theory

The SODAQ Mbili has two hardware serial connections Serial & Serial1. Serial is the USB connection and Serial1 the connection to the Bee module. They are also connected to two of the Grove sockets. See here for details: Grove sockets.

In this tutorial we will discuss sending data over a serial connection (USB) between the SODAQ Mbili and a connected PC. This can be a useful way of displaying debug data (in the Serial Monitor) or for sending commands to the device.

The Serial class inherits from the Stream class and the behaviour is similar to other Stream based classes. Most of the functionality involves reading from and writing to the incoming and outgoing stream buffers. Below is a brief description of some of the methods which you might use for this purpose.

Note: Some of the links here reference the documentation of the parent class Stream.

The Serial Connection

To open the serial connection to the PC a call must be made to Serial.begin(speed). The parameter speed specifies the bits per second or baud rate. This must match the baud rate set in the Serial Monitor or in the terminal emulator program you are using. Similarly a call to Serial.end() will close the connection.

Reading from the Serial Connection (Input)

Data which is received from the PC is stored in the incoming stream buffer. Here are some of the methods available for reading from the incoming stream buffer:

  • read(): Reads and returns a single byte (character) from the incoming stream buffer.
  • readBytes(buffer, length): Copies length number of bytes (characters) from the incoming stream buffer into the parameter buffer.
  • readString(): Reads characters from the incoming stream buffer and returns the data as a String.

Each of these methods read varying amounts of data from the incoming stream buffer and either return that data directly, or in the case of readBytes() writes the data into the supplied parameter buffer. The data which is read is also removed from the incoming stream buffer.

These methods are only able to return data when the incoming stream buffer is not empty. Calling them when the incoming stream buffer is empty will likely result in a timeout (unless new data is received before the timeout duration has elapsed). A call to the method available() returns the number of bytes (characters) currently stored in the incoming stream buffer and can used to determine if any data has been received. Additionally, the timeout duration can be set with a call to the method setTimeout().

Writing to the Serial Connection (Output)

Sending data to the PC involves writing data to the outgoing stream buffer. Here are several of the methods which can be used for writing to the outgoing stream buffer:

  • print(val, base): Writes the data from val into the outgoing stream buffer. If val is a numerical type, the optional second parameter base can be used to specify the formatting.
  • println(val, base): Functions the same as the print() method but also appends the carriage return (ASCII 13, or ‘\r’) and a newline characters (ASCII 10, or ‘\n’).

Example

Required Components

  • SODAQ Mbili Board

Required Libraries

  • none

Hardware Setup

Turn on the SODAQ Mbili board, compile and upload the following sketch from the Arduino IDE onto the SODAQ Mbili board. Leave the USB cable plugged in and open the Serial Monitor (Ctrl-Shift-M) and ensure that it is set to the 9600 baud rate.

If you try sending the command ‘add’ followed by ‘sub’ you should see output similar to this:

Sketch Code

#define INPUT_DELAY 100 //Specifies how often we check for input
int value = 0; //A variable which is modified by commands from the serial connection

void setup()
{
    //Open the port
    Serial.begin(9600);
    Serial.println("Opened serial connection");

    //Print initial message
    Serial.println("Enter the commands <add> or <sub>");
}

void loop()
{
    //Check if any data has been received
    //If so call the method handleInput() to process it
    if (Serial.available() > 0)
    {
        handleInput();
    }

 //This delay dictates how often the device will check for input
    delay(INPUT_DELAY);
}

void handleInput()
{
    //Get the input string
    String input = Serial.readString();

    //Remove any whitespace or CR/LF
    input.trim();

    //Echo the input
    Serial.println("Command: " + input + " received");

    //Process the input
    if (input == "add")
    {
        Serial.println("Adding 1 to the value");
        value++;
    }
    else if (input == "sub")
    {
        Serial.println("Subtracting 1 from the value");
        value--;
    }
    else
    {
        Serial.println("Unknown command: " + input);
    }

    //Echo the changes
    Serial.print("The current value is: ");
    Serial.println(value);
}

Sketch Code Breakdown

Globals

Here we define a delay value which is used to control the effective frequency that the sketch checks for any new incoming data.We also declare a global variable, value, which we will modify via commands sent from the PC.

#define INPUT_DELAY 100 //Specifies how often we check for input
int value = 0; //A variable which is modified by commands from the serial connection

setup()

In the setup() method we first open the serial connection. This is done with a call to Serial.begin() on the hardware serial object Serial. We then use the output method println() to write two strings to the outgoing stream buffer.

void setup()
{
     //Open the port
     Serial.begin(9600);
     Serial.println("Opened serial connection");

     //Print initial message
     Serial.println("Enter the commands <add> or <sub>");
}

loop()

Here we check if there is any data in the incoming stream buffer. This is done with a call to Serial.available() which returns the number of bytes (characters) which have been received and are currently held in the incoming stream buffer. If the returned value is greater than zero then we call the user defined method handleInput() which processes the incoming data. We have also added a small delay by calling the method delay(). This affects how quickly the sketch responds to data received over the serial connection.

Note: An alternative way of handling the data in the incoming stream buffer would be to use the automatically triggered method serialEvent().

void loop()
{
     //Check if any data has been received
     //If so call the method handleInput() to process it
     if (Serial.available() > 0)
     {
          handleInput();
     }

     //This delay dictates how often the device will check for input
     delay(INPUT_DELAY);
}

handleInput()

This user defined method handleInput() is called from loop() if any data is detected in the incoming stream buffer. Here we read the data into the String input using the method readString(). This copies the data from the incoming stream buffer and stores it in input. It also clears the stream buffer of the data it copied. We then use trim() to remove any additional termination characters which might have be added by the terminal program. Using the String comparison operator == we compare the received command against the two specified ones and then modify value accordingly.

void handleInput()
{
    //Get the input string
    String input = Serial.readString();

    //Remove any whitespace or CR/LF
    input.trim();

    //Echo the input
    Serial.println("Command: " + input + " received");

    //Process the input
    if (input == "add")
    {
        Serial.println("Adding 1 to the value");
        value++;
    }
    else if (input == "sub")
    {
        Serial.println("Subtracting 1 from the value");
        value--;
    }
    else
    {
        Serial.println("Unknown command: " + input);
    }

    //Echo the changes
    Serial.print("The current value is: ");
    Serial.println(value);
}