Wednesday, March 1, 2017

Getting and Using Arduino Serial Input

This part of the Arduino programming course shows how to get data into an Arduino sketch from the serial port. Data can be sent to the Arduino from the Serial Monitor window in the Arduino IDE.
A user can enter data in the input field in the serial monitor window to send values and data to the Arduino. Any serial program, or even a custom serial application can be used to send data to the Arduino instead of using the Serial Monitor window.
Except for part 13 of this course, the Serial Monitor window has only been used for output purposes. It was used to display the results or outputs from various example sketches in each part of the course. Let's now look at how to handle both serial input and output.

Getting Serial Input

The following sketch shows how to get a single character from the Serial Monitor window and determine if the character is a number or not.
void setup() {
  Serial.begin(9600);
}

char rx_byte = 0;

void loop() {
  if (Serial.available() > 0) {    // is a character available?
    rx_byte = Serial.read();       // get the character
  
    // check if a number was received
    if ((rx_byte >= '0') && (rx_byte <= '9')) {
      Serial.print("Number received: ");
      Serial.println(rx_byte);
    }
    else {
      Serial.println("Not a number.");
    }
  } // end: if (Serial.available() > 0)
}

How the Sketch Works

Checking for a Character

In the Arduino main loop (loop() function), an if statement is used to check if a character is available on the serial port – i.e. if a character has been sent from the Serial Monitor window and received by the Arduino.
This if statement is run as fast as it takes to run the if statement and get back to the top of the loop to run it again.
if (Serial.available() > 0) {    // is a character available?
}
Nothing in the body of the if statement is run until a character is received.

Getting a Character

When a character is received on the serial port, it is stored in a character variable (of type char) called rx_byte.
rx_byte = Serial.read();       // get the character
A copy of the received character is now stored in the rx_byte variable and we can use the received character in our sketch.

Check if the Received Character is a Number

The sketch tests whether the received character is a number or not by checking if the character is greater than or equal to '0' and less than or equal to '9'.
if ((rx_byte >= '0') && (rx_byte <= '9')) {
}
We are actually checking for the character numbers '0' to '9' and not the actual integer numbers 0 to 9. This is because the data received from the Serial Monitor window is in ASCII format.
From the table that shows the printable ASCII characters, we can see that the ASCII character '0' has the integer value of 48 decimal and the ASCII character '9' has the decimal value of 57. In other words when '0' is typed on the keyboard in the Serial Monitor window "send" field and the Send button is clicked, the integer value of 48 is sent to the Arduino. In the sketch, we can refer to this character as '0' or 48.
The same if statement could be written using decimal integers as follows:
if ((rx_byte >= 48) && (rx_byte <= 57)) {
}
This code would do exactly the same as the version that checks for the characters.
If the character received is one of the number characters, the number character will be printed out. The else statement takes care of any character that is not a number character.

Getting String Input

The previous sketch was used to get and process a single character at a time. It will be more useful if we could get a whole string at a time, then we could get a name as input, or a number that is more than one digit long.

Finding the End of a String

A string is a series of characters. To be able to read a string from the serial port in the Arduino, we will need to know when the string ends. One way to do this is to insert a newline character at the end of the string. A newline character is a non-printable ASCII character that is called "line feed" in the ASCII control code table.
The linefeed character has a value of 10 decimal but can be written as an escape code in an Arduino sketch as: '\n'.
The following sketch is a modified version of the previous sketch. In addition to checking whether a number or non-number is received, it also checks whether the newline character is received.
When the sketch is run and a character is sent from the Serial Monitor window, a setting at the bottom of the Serial Monitor window must be changed so that a newline character is appended to the character sent as shown in the image below the sketch.
x_byte <= '9')) {
      Serial.print("Number received: ");
      Serial.println(rx_byte);
    }
    else if (rx_byte == '\n') {
      Serial.println("Newline");
    }
    else {
      Serial.println("Not a number.");
}
  } // end: if (Serial.available() > 0)
}

How the Sketch Works

Checking for a Character

In the Arduino main loop (loop() function), an if statement is used to check if a character is available on the serial port – i.e. if a character has been sent from the Serial Monitor window and received by the Arduino.
This if statement is run as fast as it takes to run the if statement and get back to the top of the loop to run it again.
if (Serial.available() > 0) {    // is a character available?
}
Nothing in the body of the if statement is run until a character is received.

Getting a Character

When a character is received on the serial port, it is stored in a character variable (of type char) called rx_byte.
rx_byte = Serial.read();       // get the character
A copy of the received character is now stored in the rx_byte variable and we can use the received character in our sketch.

Check if the Received Character is a Number

The sketch tests whether the received character is a number or not by checking if the character is greater than or equal to '0' and less than or equal to '9'.
if ((rx_byte >= '0') && (rx_byte <= '9')) {
}
We are actually checking for the character numbers '0' to '9' and not the actual integer numbers 0 to 9. This is because the data received from the Serial Monitor window is in ASCII format.
From the table that shows the printable ASCII characters, we can see that the ASCII character '0' has the integer value of 48 decimal and the ASCII character '9' has the decimal value of 57. In other words when '0' is typed on the keyboard in the Serial Monitor window "send" field and the Send button is clicked, the integer value of 48 is sent to the Arduino. In the sketch, we can refer to this character as '0' or 48.
The same if statement could be written using decimal integers as follows:
if ((rx_byte >= 48) && (rx_byte <= 57)) {
}
This code would do exactly the same as the version that checks for the characters.
If the character received is one of the number characters, the number character will be printed out. The else statement takes care of any character that is not a number character.

Getting String Input

The previous sketch was used to get and process a single character at a time. It will be more useful if we could get a whole string at a time, then we could get a name as input, or a number that is more than one digit long.

Finding the End of a String

A string is a series of characters. To be able to read a string from the serial port in the Arduino, we will need to know when the string ends. One way to do this is to insert a newline character at the end of the string. A newline character is a non-printable ASCII character that is called "line feed" in the ASCII control code table.
The linefeed character has a value of 10 decimal but can be written as an escape code in an Arduino sketch as: '\n'.
The following sketch is a modified version of the previous sketch. In addition to checking whether a number or non-number is received, it also checks whether the newline character is received.
When the sketch is run and a character is sent from the Serial Monitor window, a setting at the bottom of the Serial Monitor window must be changed so that a newline character is appended to the character sent as shown in the image below the sketch.
void setup() {
  Serial.begin(9600);
}

char rx_byte = 0;

void loop() {
  if (Serial.available() > 0) {    // is a character available?
    rx_byte = Serial.read();       // get the character
  
    // check if a number was received
    if ((rx_byte >= '0') && (rx_byte <= '9')) {
      Serial.print("Number received: ");
      Serial.println(rx_byte);
    }
    else if (rx_byte == '\n') {
      Serial.println("Newline");
    }
    else {
      Serial.println("Not a number.");
    }
// end: if (Serial.available() > 0)
}
Before running the sketch, make sure that the Arduino Serial Monitor window is set to "Newline" as shown in this image.
Setting the newline character in the Arduino Serial Monitor window
When "Newline" is set in the Serial Monitor window, whatever is typed into the "send" field of the Serial Monitor window, will be followed by a newline character.
An else if is used to test if a newline character has been received as shown in this line of code.
else if (rx_byte == '\n') {
This code checks for the newline character which is represented by '\n' and prints "Newline" to the Serial Monitor window if found.

Reading a String

The sketch below reads a string into the Arduino and uses the newline character to determine when the string ends.
void setup() {
  Serial.begin(9600);
  Serial.println("Enter your name.");
}

char rx_byte = 0;
String rx_str = "";

void loop() {
  if (Serial.available() > 0) {    // is a character available?
    rx_byte = Serial.read();       // get the character
    
    if (rx_byte != '\n') {
      // a character of the string was received
      rx_str += rx_byte;
    }
    else {
      // end of string
      Serial.print("Welcome ");
      Serial.println(rx_str);
      rx_str = "";                // clear the string for reuse
// end: if (Serial.available() > 0)
Each individual character of the string is obtained in the same way as the previous sketches and stored in the rx_byte variable.
If the character is not equal to the newline character, then it is added to the String object rx_str.
if (rx_byte != '\n') {
  // a character of the string was received
  rx_str += rx_byte;
}
The line of code rx_str += rx_byte; is the same as:
rx_str = rx_str + rx_byte;
It simply puts each character onto the end of the string to build up the string from received characters.
After the string has been assembled, the newline character will be received which will then trigger the else statement and the received string is printed out to the Serial Monitor window as part of a welcome message.

Getting a Number

When a number is received from the Serial Monitor window, it is a string of number characters and must be converted into a number that can be stored in a number variable such as an integer or int.
The following sketch checks to see that the received characters are number characters and then converts the number to an integer.
oid setup() {
  Serial.begin(9600);
  Serial.println("Enter a number to multiply by 2.");
}

char rx_byte = 0;
String rx_str = "";
boolean not_number = false;
int result;

void loop() {
  if (Serial.available() > 0) {    // is a character available?
    rx_byte = Serial.read();       // get the character
    
    if ((rx_byte >= '0') && (rx_byte <= '9')) {
      rx_str += rx_byte;
    }
    else if (rx_byte == '\n') {
      // end of string
      if (not_number) {
        Serial.println("Not a number");
      }
 else {
        // multiply the number by 2
        result = rx_str.toInt() * 2;
        // print the result
        Serial.print(rx_str);
        Serial.print(" x 2 = ");
        Serial.print(result);
        Serial.println("");
        Serial.println("Enter a number to multiply by 2.");
      }
      not_number = false;         // reset flag
      rx_str = "";                // clear the string for reuse
    }
    else {
      // non-number character received
      not_number = true;    // flag a non-number
    }
  } // end: if (Serial.available() > 0)
}

Building the String

A string is built up of received characters as done in the previous sketch. If any character received is not a character number, the variable not_number is set to true to "flag" that a non-number character was received.

Using a Boolean Flag

The not_number variable is of type boolean which can only have a value of true or false. In the sketch, this variable is used as a flag which is checked later to see if any non-number characters were received.
After receiving the full string, which occurs when the newline character is received, the not_number flag is checked and a message is displayed if any character received was not a number.

Processing the String

If all the received characters were numbers, the string is converted to an integer using rx_str.toInt(), multiplied by 2 and the result stored in the result variable. The result of the calculation in then printed to the Serial Monitor Window.

Sketch Limitations

There are some limitations with this sketch. We cannot get a result when a negative number is sent to the Arduino because the minus sign will trigger the not_number flag. The size of the number that can be multiplied is also limited by the size of a positive integer on the Arduino.

No comments: