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.

Arduino Strings

Strings are used to store text. They can be used to display text on an LCD or in the Arduino IDE Serial Monitor window.
Strings are also useful for storing user input – for example the characters that a user types on a keypad connected to the Arduino.
There are two types of strings in Arduino programming:
1) Arrays of characters which are the same as the strings used in C programming
2) The Arduino String which lets us use a string object in a sketch
Strings, objects and how to use strings in Arduino sketches are fully explained in this part of the Arduino programming course. The question of which type of sting to use in a sketch is answered at the end of this article.

String Character Arrays

The first type of string that we will look at is the string that is a series of characters of type char. The previous part of this course showed what an array is – a consecutive series of the same type of variable stored in memory. A string is an array of char variables.
A string is a special array that has one extra element at the end of the string which always has the value of 0 (zero). This is known as a "null terminated string".

String Character Array Example Sketch

This sketch will show how to make a string and print it to the serial monitor window.
void setup() {
  char my_str[6];    // an array big enough for a 5 character string
  
  Serial.begin(9600);
  
  my_str[0] = 'H';  // the string consists of 5 characters
  my_str[1] = 'e';
  my_str[2] = 'l';
  my_str[3] = 'l';
  my_str[4] = 'o';
  my_str[5] = 0;    // 6th array element is a null terminator
  
  Serial.println(my_str);
}

void loop() {
}

The sketch shows what a string is made up of – it consists of a character array with printable characters and a 0 in the last element of the array to show that this is where the string ends.
The string can be printed out to the Arduino IDE Serial Monitor window by using Serial.println() and passing it the name of the string.
This same sketch can be written more conveniently this way:
void setup() {
  char my_str[] = "Hello";
  
  Serial.begin(9600);
  
  Serial.println(my_str);
}

void loop() {
}

In this sketch, the compiler calculates the size of the string array and also automatically null terminates the string with a zero. An array that is six elements long and consists of five characters followed by a zero is created exactly the same way as in the previous sketch.

Strings and Characters

Characters are written between single quotes like this:
'w'
Strings are written between double quotes like this:
"This is a string"

Manipulating String Arrays

We can alter a string array within a sketch as the following sketch shows.

oid setup() {
  char like[] = "I like coffee and cake";  // create a string
  
  Serial.begin(9600);
  
  // (1) print the string
  Serial.println(like);
  
  // (2) delete part of the string
  like[13] = 0;
  Serial.println(like);
  
  // (3) substitute a word into the string
  like[13] = ' ';  // replace the null terminator with a space
  like[18] = 't';  // insert the new word
  like[19] = 'e';
  like[20] = 'a';
  like[21] = 0;    // terminate the string
  Serial.println(like);
}

void loop() {
}

Creating and Printing the String

In this sketch, a new string is created and then printed for display in the Serial Monitor window (1).

Shortening the String

The string is shortened by replacing the 14th character in the string with a null terminating zero (2). This is element number 13 in the string array counting from 0.
When the string is printed out, all the characters are printed up to the new null terminating zero. The other characters do not disappear – they still exist in memory and the string array is still the same size. The only difference is that any function that works with strings will only see the string up to the first null terminator.

Changing a Word in the String

Finally the sketch replaces the word "cake" with "tea" (3). It first has to replace the null terminator at like[13] with a space so that the string is restored to how it was originally created.
New characters overwrite "cak" of the work "cake" with the word "tea". This is done by overwriting individual characters. The 'e' of "cake" is replaced with a new null terminating character. The result is that the string is actually terminated with two null characters – the original one at the end of the string and the new one that replaces the 'e' in "cake". This makes no difference when the new string is printed out because the function that prints the string stops printing string characters when it encounters the first null terminator.

Functions to Manipulate String Arrays

The previous sketch manipulated the string in a very manual way by accessing individual characters in the string. To make it easier to manipulate string arrays, you could write your own functions to do so, or use some of the string functions from the C language library.
The next sketch uses some C string functions.
void setup() {
  char str[] = "This is my string";  // create a string
  char out_str[40];                  // output from string functions placed here
  int num;                           // general purpose integer
  
  Serial.begin(9600);
  
  // (1) print the string
  Serial.println(str);
  
  // (2) get the length of the string (excludes null terminator)
  num = strlen(str);
  Serial.print("String length is: ");
  Serial.println(num);
  
  // (3) get the length of the array (includes null terminator)
  num = sizeof(str);  // sizeof() is not a C string function
  Serial.print("Size of the array: ");
  Serial.println(num);
  
  // (4) copy a string
  strcpy(out_str, str);
 Serial.println(out_str);
  
  // (5) add a string to the end of a string (append)
  strcat(out_str, " sketch.");
  Serial.println(out_str);
  num = strlen(out_str);
  Serial.print("String length is: ");
  Serial.println(num);
  num = sizeof(out_str);
  Serial.print("Size of the array out_str[]: ");
  Serial.println(num);
}

void loop() {
}
The sketch works in the following way.

(1) Print the String

The newly created string is printed to the Serial Monitor window as done in previous sketches.

(2) Get the Length of the String

The strlen() function is used to get the length of the string. The length of the string is for the printable characters only and does not include the null terminator.
The string contains 17 characters, so we see 17 printed in the Serial Monitor window.

(3) Get the Length of the Array

The operator sizeof() is used to get the length of the array that contains the string. The length includes the null terminator, so the length is one more than the length of the string.
sizeof() looks like a function, but technically is an operator. It is not part of the C string library, but was used in the sketch to show the difference between the size of the array and the size of the string (or string length).

(4) Copy a String

The strcpy() function is used to copy the str[] string to the out_num[] array. The strcpy() function copies the second string passed to it into the first string. A copy of the string now exists in the out_num[] array, but only takes up 18 elements of the array, so we still have 22 free char elements in the array. These free elements are found after the string in memory.
The string was copied to the array so that we would have some extra space in the array to use in the next part of the sketch which is adding a string to the end of a string.

(5) Append a String to a String (Concatenate)

The sketch joins one string to another, which is known as concatenation. This is done using the strcat() function. The strcat() function puts the second string passed to it onto the end of the first string passed to it.
After concatenation, the length of the string is printed to show the new string length. The length of the array is then printed to show that we have a 25 character long string in a 40 element long array.
Remember that the 25 character long string actually takes up 26 characters of the array because of the null terminating zero.

Array Bounds

When working with strings and arrays, it is very important to work within the bounds of the string or array. In the example sketch an array was created that was 40 characters long in order to allocate memory that could be used to manipulate strings.
If the array was made too small and we tried to copy a string that is bigger than the array to it, the string would be copied over the end of the array. The memory beyond the end of the array could contain other important data used in the sketch which would then be overwritten by our string. If the memory beyond the end of the string is overrun, it could crash the sketch or cause unexpected behaviour.

The Arduino String Object

The second type of string used in Arduino programming is the String object.

What is an Object?

An object is a construct that contains both data and functions. A String object can be created just like a variable and assigned a value or string. The String object contains functions (which are called "methods" in object oriented programming (OOP)) which operate on the string data contained in the String object.
The following sketch and explanation will make it clearer what an object is and how the String object is used.
void setup() {
  String my_str = "This is my string.";
  
  Serial.begin(9600);
  
  // (1) print the string
  Serial.println(my_str);
  
  // (2) change the string to upper-case
  my_str.toUpperCase();
  Serial.println(my_str);
  
  // (3) overwrite the string
  my_str = "My new string.";
  Serial.println(my_str);
  
  // (4) replace a word in the string
  my_str.replace("string", "Arduino sketch");
  Serial.println(my_str);
  
  // (5) get the length of the string
Serial.print("String length is: ");
  Serial.println(my_str.length());
}

void loop() {
}
A string object is created and assigned a value (or string) at the top of the sketch.
String my_str = "This is my string.";
This creates a String object with the name my_str and gives it a value of "This is my string.".
This can be compared to creating a variable and assigning a value to it such as an integer:
int my_var = 102;

(1) Printing the String

The string can be printed to the Serial Monitor window just like a character array string.

(2) Convert the String to Upper-case

The string object my_str that was created has a number of functions or methods that can operated on it. These methods are invoked by using the objects name followed by the dot operator (.) and then the name of the function to use.
my_str.toUpperCase();
The toUpperCase() function operates on the string contained in the my_str object which is of type String and converts the string data (or text) that the object contains to upper-case characters.
A list of the functions that the String class contains can be found in the Arduino String reference.
Technically String is called a class and is used to create String objects.

(3) Overwrite a String

The assignment operator is used to assign a new string to the my_str object that replaces the old string.
my_str = "My new string.";
The assignment operator can not be used on character array strings, but works on String objects only.

(4) Replacing a Word in the String

The replace() function is used to replace the first string passed to it by the second string passed to it. replace() is another function that is built into the String class and so is available to use on the String object my_str.

(5) Getting the Length of the String

Getting the length of the string is easily done by using length(). In the example sketch, the result returned by length() is passed directly to Serial.println() without using an intermediate variable.

When to use a String Object or String Character Array

String object is much easier to use than a string character array. The object has built-in functions that can perform a number of operations on strings which are fully documented in the reference section on the Arduino website.
The main disadvantage of using the String object is that it uses a lot of memory and can quickly use up the Arduinos RAM memory which may cause the Arduino to hang, crash or produce unexpected behaviour.
If a sketch on an Arduino is small and limits the use of objects, then there should be no problems.
Character array strings are more difficult to use and you may need to write your own functions to operate on these types of strings. The advantage is that you have control of the size of the string arrays that you make, so you can keep the arrays small to save memory.
You need to make sure that you do not write over the end of the array bounds with string arrays. The String object does not have this problem and will take care of the string bounds for you, provided that there is enough memory for it to operate on. The String object can try to write to memory that does not exist when it runs out of memory, but will never write over the end of the string that it is operating on.

Where Strings are Used

This part of the Arduino programming course has looked at what strings are, how they look in memory and some operations that can be done on strings.
Actual practical uses of strings will be covered in the next part of this course when we look at how to get user input from the Serial Monitor window and save the input in a string