Arduino Programming

2.0 Introduction

Though much of an Arduino project will involve integrating the Arduino board with supporting hardware, you need to be able to tell the board what to do with the rest of your project. This chapter introduces core elements of Arduino programming, shows non-programmers how to use common language constructs, and provides an overview of the language syntax for readers who are not familiar with C or C++, the language that Arduino uses.

Since making the examples interesting requires making Arduino do something, the recipes use physical capabilities of the board that are explained in detail in later chapters. If any of the code in this chapter is not clear, feel free to jump forward, particularly to Chapter 4 for more on serial output and Chapter 5 for more on using digital and analog pins. You don’t need to understand all the code in the examples, though, to see how to perform the specific capabilities that are the focus of the recipes. Here are some of the more common functions used in the examples that are covered in the next few chapters:

Serial.println(value);

Prints the value to the Arduino IDE’s Serial Monitor so you can view Arduino’s output on your computer; see Recipe 4.1.

pinMode(pin, mode);

Configures a digital pin to read (input) or write (output) a digital value; see the introduction to Chapter 5.

digitalRead(pin);

Reads a digital value (HIGH or LOW) on a pin set for input; see Recipe 5.1.

digitalWrite(pin, value);

Writes the digital value (HIGH or LOW) to a pin set for output; see Recipe 5.1.

2.1 A Typical Arduino Sketch

Problem

You want to understand the fundamental structure of an Arduino program. We’ll show this structure in the following sketch, which programs an Arduino to continually flash an LED light.

Solution

Programs for Arduino are usually referred to as sketches; the first users were artists and designers and sketch highlights the quick and easy way to have an idea realized. The terms sketch and program are interchangeable. Sketches contain code—the instructions the board will carry out. Code that needs to run only once (such as to set up the board for your application) must be placed in the setup function. Code to be run continuously after the initial setup has finished goes into the loop function. Here is a typical sketch:

// The setup() method runs once, when the sketch starts
void setup()
{
  pinMode(LED_BUILTIN, OUTPUT); // initialize the onboard LED as an output
}

// the loop() method runs over and over again,
void loop()
{
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on
  delay(1000);                       // wait a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off
  delay(1000);                       // wait a second
}

When the Arduino IDE finishes uploading the code, and every time you power on the board after you’ve uploaded this code, it starts at the top of the sketch and carries out the instructions sequentially. It runs the code in setup once and then goes through the code in loop. When it gets to the end of loop (marked by the closing bracket, }) it calls the loop function again, and does so over and over again until you disconnect power or reset the board.

Discussion

This example continuously flashes an LED by writing HIGH and LOW outputs to a pin. See Chapter 5 to learn more about using Arduino pins. When the sketch begins, the code in setup sets the pin mode (so it’s capable of lighting an LED). After the code in setup is completed, the code in loop is repeatedly called (to flash the LED) for as long as the Arduino board is powered on.

You don’t need to know this to write Arduino sketches, but experienced C/C++ programmers may wonder where the expected main() entry point function has gone. It’s there, but it’s hidden under the covers by the Arduino build environment. The build process creates an intermediate file that includes the sketch code and the following additional statements. Here’s what the main function looks like for 8-bit boards (32-bit boards are similar):

int main( void )
{
  init();

  initVariant();

#if defined(USBCON)
  USBDevice.attach();
#endif

  setup();

  for (;;)
  {
    loop();
    if (serialEventRun) serialEventRun();
  }

  return 0;
}

The first thing that happens is a call to an init() function that initializes the Arduino hardware. After that, initVariant() gets called. This is a rarely-used hook to give makers of Arduino-compatible boards a way to invoke their own custom initialization routines. If the microcontroller on the board has dedicated USB hardware, main will prepare (attach) it for use.

Next, your sketch’s setup() function is called. Finally, your loop() function is called over and over. Because the for loop never terminates, the return statement is never executed.

Note

Right after each call to loop, the main function will call serialEventRun if it’s supported on your board (it’s not available on boards that are based on the ATmega32U4 such as the Leonardo). This allows you to add a special function called serialEvent in your sketch that will be called whenever data is available on the serial port (see Recipe 4.3).

See Also

Recipe 1.4 explains how to upload a sketch to the Arduino board.

Chapter 17 and http://www.arduino.cc/en/Hacking/BuildProcess provide more on the build process.

2.2 Using Simple Primitive Types (Variables)

Problem

Arduino has different types of variables to efficiently represent values. You want to know how to select and use these Arduino data types.

Solution

Although the int (short for integer) data type is the most common choice for the numeric values encountered in Arduino applications, you can use Table 2-1 to determine the data type that fits the range of values your application expects.

Arduino data types for 8-bit boards such as the Uno
Numeric types Bytes Range Use

int

2

–32768 to 32767

Represents positive and negative integer values.

unsigned int

2

0 to 65535

Represents only positive values; otherwise, similar to int.

long

4

–2147483648 to 2147483647

Represents a very large range of positive and negative values.

unsigned long

4

4294967295

Represents a very large range of positive values.

float

4

3.4028235E+38 to –3.4028235E+38

Represents numbers with fractions; use to approximate real-world measurements.

double

4

Same as float

In Arduino, double is just another name for float.

bool

1

false (0) or true (1)

Represents true and false values.

char

1

–128 to 127

Represents a single character. Can also represent a signed numeric value between –128 and 127.

byte

1

0 to 255

Similar to char, but for unsigned values.

Other types Use

String

Represents a sequence of characters typically used to contain text.

void

Used only in function declarations where no value is returned.

Arduino data types for 32-bit boards such as the Zero and 101

Numeric types Bytes Range Use

short int

2

–32768 to 32767

Same as int on 8-bit boards.

unsigned short int

2

0 to 65535

Same as unsigned int on 8-bit boards.

int

4

–2147483648 to  2147483647

Represents positive and negative integer values.

unsigned int

4

0 to 4294967295

Represents only positive values; otherwise, similar to int.

long

4

–2147483648 to 2147483647

Same as int.

unsigned long

4

4294967295

Same as unsigned int.

float

4

±3.4028235E+38

Represents numbers with fractions; use to approximate real-world measurements.

double

8

±1.7976931348623158E+308

32-bit boards have much greater range and preceision than 8-bit boards.

bool

1

false (0) or true (1)

Represents true and false values.

char

1

–128 to 127

Represents a single character. Can also represent a signed value between –128 and 127.

byte

1

0 to 255

Similar to char, but for unsigned values.

Other types Use

String

Represents a sequence of characters typically used to contain text.

void

Used only in function declarations where no value is returned.

Discussion

Except in situations where maximum performance or memory efficiency is required, variables declared using int will be suitable for numeric values if the values do not exceed the range (shown in Table 2-1) and if you don’t need to work with fractional values. Most of the official Arduino example code declares numeric variables as int. But sometimes you do need to choose a type that specifically suits your application. This is specifically important if you are calling library functions that return values other than int. Take, for example the millis function shown in Recipe 2.10 and other recipes. It returns an unsigned long value. If you use an int on an 8-bit board to store the results of that function, you won’t get a warning, but you will get the wrong results because an int is not large enough to hold the maximum value of a long. Instead, after you reach 32767, it will roll over to -32768. If you were to try to stuff a long into an unsigned int, you’ll roll over to zero after you pass the maximum value for an unsigned int (65535).

Sometimes you need negative numbers and sometimes you don’t, so numeric types come in two varieties: signed and unsigned. unsigned values are always positive. Variables without the keyword unsigned in front are signed so that they can represent negative and positive values. One reason to use unsigned values is when the range of signed values will not fit the range of the variable (an unsigned variable has twice the capacity of a signed variable). Another reason programmers choose to use unsigned types is to clearly indicate to people reading the code that the value expected will never be a negative number.

On a 32-bit board an int  requires twice as many bytes as on an 8-bit board, however memory is ample on 32-bit boards so most code for 8-bit will run on 32-bit boards. A rare exception is code that assumes that ints will always be represented in memory using 2 bytes, something well written code and libraries should not do. 

bool (boolean) types have two possible values: true or false. They are commonly used to store values that represent a yes/no condition. You may also see bool types used in place of the built-in constants HIGH and LOW, which are used to modify (with digitalWrite()) or determine (with digitalRead()) the state of a digital I/O pin. For example, the statement digitalWrite(LED_BUILTIN, HIGH); will transmit power to the pin that the built-in LED is connected to. Using LOW instead of HIGH will turn off the power. You can use true or false in place of HIGH or LOW, and you are likely to find examples of this in code you find online. You will also see examples where 1 and 0 are used (1 is equivalent to true and 0 is equivalent to false). However, it is a bad habit to make assumptions about the underlying value of a constant, so you should always use the constants HIGH and LOW. It is extremely unlikely that you would ever come across an Arduino variant where HIGH was equal to false. But there are many other constants you will come across, and most of them do not have such an explicit and obvious relationship to their underlying values.

See Also

The Arduino reference at https://www.arduino.cc/reference provides details on data types.

2.3 Using Floating-Point Numbers

Problem

Floating-point numbers are used for values expressed with decimal points (this is the way to represent fractional values). You want to calculate and compare these values in your sketch.

Solution

The following code shows how to declare floating-point variables, illustrates problems you can encounter when comparing floating-point values, and demonstrates how to overcome them:

/*
 * Floating-point example
 * This sketch initialized a float value to 1.1
 * It repeatedly reduces the value by 0.1 until the value is 0
 */

float value = 1.1;

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

void loop()
{
  value = value - 0.1;   // reduce value by 0.1 each time through the loop
  if( value == 0)
  {
     Serial.println("The value is exactly zero");
  }
  else if(almostEqual(value, 0))
  {
    Serial.print("The value ");
    Serial.print(value,7); // print to 7 decimal places
    Serial.println(" is almost equal to zero, restarting countdown");
    value = 1.1;
  }
  else 
  {
    Serial.println(value);
  }
  delay(250);
}
      
// returns true if the difference between a and b is small
bool almostEqual(float a, float b)
{  
  const float DELTA = .00001; // max difference to be almost equal
  if (a == 0) return fabs(b) <= DELTA;
  if (b == 0) return fabs(a) <= DELTA;
  return fabs((a - b) / max(fabs(a), fabs(b))) <= DELTA;
}

Discussion

Floating-point math is not exact, and values returned can have a small approximation error. The error occurs because floating-point values cover a huge range, so the internal representation of the value can only hold an approximation. Because of this, you need to test if the values are within a range of tolerance rather than exactly equal.

The Serial Monitor output from this sketch is as follows:

1.00
0.90
0.80
0.70
0.60
0.50
0.40
0.30
0.20
0.10
The value -0.0000001 is almost equal to zero, restarting countdown
1.00
0.90

The output starts over from the beginning (1.00) and continues the countdown.

You may expect the code to print "The value is exactly zero" after value is 0.1 and then 0.1 is then subtracted from it. But value never equals exactly zero; it gets very close, but that is not good enough to pass the test: if (value == 0). This is because the only memory-efficient way that floating-point numbers can contain the huge range in values they can represent is by storing an approximation of the number.

The solution to this is to check if a variable is close to the desired value, as shown in this recipe’s Solution.

The almostEqual function tests if the variable value is within a margin of the desired target and returns true if so. The acceptable range is set with the constant DELTA, you can change this to smaller or larger values as required. The function named fabs (short for floating-point absolute value) returns the absolute value of a floating-point variable and this is used to test the difference between the given parameters.

Before the almostEqual function compares the difference between a and b to DELTA, it scales that difference by the maximum value of either a or b. This is necessary to account for the fact that the precision of floating point values varies by their magnitude. In fact, because this code compares a value to 0, this expression is not necessary because the logic in the preceding two lines takes over when either a or b is 0. Table 2-3 shows what would happen at different orders of magnitude for pairs of Start and Comparison values. Equal At shows the value reached by the starting value when they are considered equal. Unscaled Difference shows the difference between a and b when almostEqual determines they are almost equal. Scaled Difference shows the difference that the final line in almostEqual uses to make that determination. As you can see, by the time you get up to 100, the unscaled value exceeds the DELTA of 0.00001.

Counting down in floating point
Start Comparison Equal At Unscaled Difference Scaled Difference
11.1 10 9.9999962 0.0000038 0.0000004
101.1 100 100.0000153 0.0000153 0.0000002
1001.1 1000 1000.0002441 0.0002441 0.0000002
Note

Floating point approximates numbers because it only uses 32 bits to hold all values within a huge range. Eight bits are used for the decimal multiplier (the exponent), and that leaves 24 bits for the sign and value—only enough for seven significant decimal digits.

Warning

Although float and double are exactly the same on Arduino Uno, doubles do have a higher precision on 32-bit boards and many other platforms. If you are importing code that uses float and double from another platform, check that there is sufficient precision for your application.

See Also

The Arduino reference for float: http://www.arduino.cc/en/Reference/Float.

2.4 Working with Groups of Values

Problem

You want to create and use a group of values (called arrays). The arrays may be a simple list or they could have two or more dimensions. You want to know how to determine the size of the array and how to access the elements in the array.

Solution

This sketch creates two arrays: an array of integers for pins connected to switches and an array of pins connected to LEDs, as shown in Figure 2-1:

/*
 array sketch
 an array of switches controls an array of LEDs
 see Chapter 5 for more on using switches
 see Chapter 7 for information on LEDs
 */

int inputPins[] = {2, 3, 4, 5}; // create an array of pins for switch inputs

int ledPins[] = {10, 11, 12, 13}; // create array of output pins for LEDs

void setup()
{
  for (int index = 0; index < 4; index++)
  {
    pinMode(ledPins[index], OUTPUT);         // declare LED as output
    pinMode(inputPins[index], INPUT_PULLUP); // declare as input
  }
}

void loop() {
  for (int index = 0; index < 4; index++)
  {
    int val = digitalRead(inputPins[index]);  // read input value
    if (val == LOW)                           // check if the switch is pressed
    {
      digitalWrite(ledPins[index], HIGH); // LED on if switch is pressed
    }
    else
    {
      digitalWrite(ledPins[index], LOW);  // turn LED off
    }
  }
}
Note

If you’re familiar with Arduino’s INPUT mode, you may be used to wiring the button up with a pulldown resistor that connects the input pin to ground. But with the INPUT_PULLUP mode, you don’t need this resistor in your circuit, because this mode enables Arduino’s internal pullup resistors. The difference with the INPUT_PULLUP mode is that when the button is pressed, digitalRead returns LOW rather than HIGH.

Connections for LEDs and switches

Discussion

Arrays are collections of consecutive variables of the same type. Each variable in the collection is called an element. The number of elements is called the size of the array.

The Solution demonstrates a common use of arrays in Arduino code: storing a collection of pins. Here the pins connect to switches and LEDs (a topic covered in more detail in Chapter 5). The important parts of this example are the declaration of the array and access to the array elements.

The following line of code declares (creates) an array of integers with four elements and initializes each element. The first element is set equal to 2, the second to 3, and so on:

int inputPins[] = {2,3,4,5};

If you don’t initialize values when you declare an array (for example, when the values will only be available when the sketch is running), you must set each element individually. You can declare the array as follows:

int inputPins[4];

If you declare the array outside of a function, this declares an array of four elements with the initial value of each element set to zero. (If you declare it inside of a function, such as setup() or loop(), the elements will be set to seemingly random values). The number within the square brackets ([]) is the size, and this sets the number of elements. This array has a size of four and can hold, at most, four integer values. The size can be omitted if array declaration contains initializers (as shown in the first example) because the compiler figures out how big to make the array by counting the number of initializers.

Note

Because Arduino’s programming environment accepts C or C++ syntax, it is governed by the conventions of those languages. In C and C++, arrays that are declared globally (outside of a function) but are not initialized will have their elements initialized to 0. If they are declared within a function and not initialized, their elements will be undefined, and will probably contain whatever happens to be sitting inside the memory that the array element points to. Uninitialized variables (such as int i;) may often be set to zero, but there is no guarantee of this, so it’s always important to initialize variables before you try to use their values.

The first element of the array is arrayname[0]:

int firstElement = inputPins[0];  // this is the first element

inputPins[0] = 2; // set the value of the first element to 2

The last element is one less than the size, so for a four-element array, the last element is element 3:

int lastElement = inputPins[3]; // this is the last element

It may seem odd that an array with a size of four has the last element accessed using array[3], but because the first element is array[0], the four elements are:

inputPins[0],inputPins[1],inputPins[2],inputPins[3]

In the previous sketch, the four elements are accessed using a for loop:

for (int index = 0; index < 4; index++)
{
  pinMode(ledPins[index], OUTPUT);         // declare LED as output
  pinMode(inputPins[index], INPUT_PULLUP); // declare as input
}

This loop will step through the variable index with values starting at 0 and ending at 3. It is a common mistake to accidentally access an element that is beyond the actual size of the array. This is a bug that can have many different symptoms and care must be taken to avoid it. One way to keep your loops under control is to set the size of an array by using a constant as follows:

const int PIN_COUNT = 4;  // define a constant for the number of elements
int inputPins[PIN_COUNT] = {2,3,4,5};
int ledPins[PIN_COUNT] = {10, 11, 12, 13};

/* ... */

for(int index = 0; index < PIN_COUNT; index++)
{
  pinMode(ledPins[index], OUTPUT);
  pinMode(inputPins[index], INPUT_PULLUP);
}
Warning

The compiler will not report an error if you accidentally try to store or read beyond the size of the array, but it’s likely that your sketch will mysteriously crash if you do. You must be careful that you only access elements that are within the bounds you have set. Using a constant to set the size of an array and in code referring to its elements helps your code stay within the bounds of the array.

Another use of arrays is to hold a string of text characters. In Arduino code, these are called character strings (strings for short). A character string consists of one or more characters, followed by the null character (the value 0) to indicate the end of the string.

Note

The null at the end of a character string is not the same as the character 0. The null has an ASCII value of 0, whereas 0 has an ASCII value of 48.

Methods to use strings are covered in Recipes 2.5 and 2.6.

2.5 Using Arduino String Functionality

Problem

You want to manipulate text. You need to copy it, add bits together, and determine the number of characters.

Solution

The previous recipe mentioned how arrays of characters can be used to store text: these character arrays are usually called strings. Arduino has a String object that adds rich functionality for storing and manipulating text. Note that the ‘S’ in the String object’s name is uppercase.

Note

The word String with an uppercase S refers to the Arduino text capability provided by the Arduino String library. The word string with a lowercase s refers to the group of characters rather than the Arduino String functionality.

This recipe demonstrates how to use Arduino Strings.

Load the following sketch onto your board, and open the Serial Monitor to view the results:

/*
  Basic_Strings sketch
 */

String text1 = "This text";
String text2 = " has more characters";
String text3;  // to be assigned within the sketch

void setup()
{
  Serial.begin(9600);
  while(!Serial); // Wait for serial port (Leonardo, 32-bit boards)

  Serial.print("text1 is ");
  Serial.print(text1.length());
  Serial.println(" characters long.");

  Serial.print("text2 is ");
  Serial.print(text2.length());
  Serial.println(" characters long.");

  text1.concat(text2);
  Serial.println("text1 now contains: ");
  Serial.println(text1);
}

void loop()
{
}

Discussion

This sketch creates three variables of type String, called text1, text2, and text3. Variables of type String have built-in capabilities for manipulating text. The statement text1.length() returns (provides the value of) the length (number of characters) in the string text1.

text1.concat(text2) combines the contents of strings; in this case, it appends the contents of text2 to the end of text1 (concat is short for concatenate).

The Serial Monitor will display the following:

text1 is 9 characters long.
text2 is 20 characters long.
text1 now contains: 
This text has more characters

Another way to combine strings is to use the string addition operator. Add these two lines to the end of the setup code:

  text3 = text1 + " and more";
  Serial.println(text3);

The new code will result in the Serial Monitor adding the following line to the end of the display:

This text has more characters and more

You can use the indexOf and lastIndexOf functions to find an instance of a particular character in a string. Like arrays, Arduino strings are indexed beginning with 0.

Note

You will come across Arduino sketches that use arrays of characters or pointers to a sequence of characters rather than the String type. See Recipe 2.6 for more on using arrays of characters without the help of the Arduino String functionality. See Recipe 17.4 for instructions on storing string literals in flash memory rather than Arduino’s main working RAM memory.

If you see a line such as the following:

char oldString[] = "this is a character array";

the code is using C-style character arrays (see Recipe 2.6). If the declaration looks like this:

String newString = "this is a string object";

the code uses Arduino Strings. To convert a C-style character array to an Arduino String, just assign the contents of the array to the String object:

char oldString[] = "I want this character array in a String object";
String newString = oldString;

To use any of the functions listed in Table 2-4, you need to invoke them upon an existing string object, as in this example:

  • int len = myString.length();
Brief overview of Arduino String functions

charAt(n)

Returns the nth character of the String

compareTo(S2)

Compares the String to the given String S2

concat(S2)

Returns a new String that is the combination of the String and S2

endsWith(S2)

Returns true if the String ends with the characters of S2

equals(S2)

Returns true if the String is an exact match for S2 (case-sensitive)

equalsIgnoreCase(S2)

Same as equals but is not case-sensitive

getBytes(buffer,len)

Copies len(gth) characters into the supplied byte buffer

indexOf(S)

Returns the index of the supplied String (or character) or –1 if not found

lastIndexOf(S)

Same as indexOf but starts from the end of the String

length()

Returns the number of characters in the String

remove(index)

Removes the character in the String at the given index

remove(index, count)

Removes the specified number of characters from the String starting at the given index

replace(A,B)

Replaces all instances of String (or character) A with B

reserve(count)

Sets aside (allocates) the specified number of bytes to make subsequent String operations more efficient

setCharAt(index,c)

Stores the character c in the String at the given index

startsWith(S2)

Returns true if the String starts with the characters of S2

substring(index)

Returns a String with the characters starting from index to the end of the String

substring(index,to)

Same as above, but the substring ends at the character location before the ‘to’ position

toCharArray(buffer,len)

Copies up to len characters of the String to the supplied buffer

toFloat()

Returns the floating point value of the numeric digits in the String

toInt()

Returns the integer value of the numeric digits in the String

toLowerCase()

Returns a String with all characters converted to lowercase

toUpperCase()

Returns a String with all characters converted to uppercase

trim()

Returns a String with all leading and trailing whitespace removed

See the Arduino reference pages for more about the usage and variants for these functions.

Choosing between Arduino Strings and C character arrays

Arduino’s built-in String datatype is easier to use than C character arrays, but this is achieved through complex code in the String library, which makes more demands on your Arduino, and is, by nature, more prone to problems.

The String datatype is so flexible because it makes use of dynamic memory allocation. That is, when you create or modify a String, Arduino requests a new region of memory from the C library, and when you’re done using a String, Arduino needs to release that memory. This usually works smoothly, but 8-bit Arduino boards have so little working RAM (2K on the Arduino Uno), that even small memory leaks can have a big impact on your sketch. A memory leak occurs when, through a bug in a library or incorrect usage of it, memory that you allocate is not released. When this happens, the memory available to Arduino will slowly decrease (until you reboot the Arduino). A related issue is memory fragmentation: as you repeatedly allocate and release memory, Arduino will have successively smaller contiguous blocks of free memory, which could cause a String allocation to fail even if there’s otherwise sufficient RAM.

Even if there are no memory leaks, it’s complicated to write code to check if a String request failed due to insufficient memory (the String functions mimic those in Processing, but unlike that platform, Arduino does not have runtime error exception handling). Running out of dynamic memory is a bug that can be very difficult to track down because the sketch can run without problems for days or weeks before it starts misbehaving through insufficient memory.

If you use C character arrays, you are in control of memory usage: you’re allocating a fixed (static) amount of memory at compile time so you don’t get memory leaks. Your Arduino sketch will have the same amount of memory available to it all the time it’s running. And if you do try to allocate more memory than available, finding the cause is easier because there are tools that tell you how much static memory you have allocated (see the reference to avr-objdump in Recipe 17.1).

However, with C character arrays, it’s easier for you to have another problem: C will not prevent you from modifying memory beyond the bounds of the array. So if you allocate an array as myString[4], and assign myString[4] = 'A' (remember, myString[3] is the end of the array), nothing will stop you from doing this. But who knows what piece of memory myString[4] refers to? And who knows whether assigning 'A' to that memory location will cause you a problem? Most likely, it will cause your sketch to misbehave.

So, Arduino’s built-in String library, by virtue of using dynamic memory, runs the risk of eating up your available memory. C’s character arrays require care on your part to ensure that you do not exceed the bounds of the arrays you use. So use Arduino’s built-in String library if you need rich text handling capability and you won’t be creating and modifying Strings over and over again. If you need to create and modify them in a loop that is constantly repeating, you’re better off allocating a large C character array and writing your code carefully so you don’t write past the bounds of that array.

Another instance where you may prefer C character arrays over Arduino Strings is in large sketches that need most of the available RAM or flash. The Arduino StringToInt example code uses almost 2 KB more flash than equivalent code using a C character array and atoi to convert to an int. The Arduino String version also requires a little more RAM to store allocation information in addition to the actual string.

If you do suspect that the String library, or any other library that makes use of dynamically allocated memory, might be leaking memory, you can determine how much memory is free at any given time; see Recipe 17.2. Check the amount of RAM when your sketch starts, and monitor it to see whether it’s decreasing over time. If you suspect a problem with the String library, search the list of open bugs (https://github.com/arduino/Arduino/issues) for “String.”

See Also

The Arduino distribution provides String example sketches (FileExamplesStrings).

The String reference page can be found at https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/.

Tutorials for the String library are available at http://arduino.cc/en/Tutorial/HomePage

2.6 Using C Character Strings

Problem

You want to understand how to use raw character strings: you want to know how to create a string, find its length, and compare, copy, or append strings. The core C language does not support the Arduino-style String capability, so you want to understand code from other platforms written to operate with primitive character arrays.

Solution

Arrays of characters are sometimes called character strings (or simply strings for short). Recipe 2.4 describes Arduino arrays in general. This recipe describes functions that operate on character strings. If you have done any C or C++ programming, you may be used to adding #include <string.h> to your code in order to get access to these functions. The Arduino IDE does this for you under the hood, so you don’t need the #include.

You declare strings like this:

char stringA[8]; // declare a string of up to 7 chars plus terminating null
char stringB[8]  = "Arduino"; // as above and init(ialize) the string to "Arduino"
char stringC[16] = "Arduino"; // as above, but string has room to grow
char stringD[ ]  = "Arduino"; // the compiler inits the string and calculates size

Use strlen (short for string length) to determine the number of characters before the terminating null:

int length = strlen(string);  // return the number of characters in the string

length will be 0 for stringA and 7 for the other strings shown in the preceding code. The null that indicates the end of the string is not counted by strlen.

Use strcpy (short for string copy) to copy one string to another:

strcpy(destination, source);   // copy string source to destination

Use strncpy to limit the number of characters to copy (useful to prevent writing more characters than the destination string can hold). You can see this used in Recipe 2.7:

// copy up to 6 characters from source to destination
strncpy(destination, source, 6);

Use strcat (short for string concatenate) to append one string to the end of another:

// append source string to the end of the destination string
strcat(destination, source);
Note

Always make sure there is enough room in the destination when copying or concatenating strings. Don’t forget to allow room for the terminating null.

Use strcmp (short for string compare) to compare two strings. You can see this used in Recipe 2.7:

if(strcmp(str, "Arduino") == 0)
{
  // do something if the variable str is equal to "Arduino"
}

Discussion

Text is represented in the Arduino environment using an array of characters called strings. A string consists of a number of characters followed by a null (the value 0). The null is not displayed, but it is needed to indicate the end of the string to the software.

See Also

The str* functions described in this recipe are part of C’s string.h library. See one of the many online C/C++ reference pages, such as http://www.cplusplus.com/reference/clibrary/cstring/ and http://www.cppreference.com/wiki/string/c/start.

2.7 Splitting Comma-Separated Text into Groups

Problem

You have a string that contains two or more pieces of data separated by commas (or any other separator). You want to split the string so that you can use each individual part.

Solution

This sketch prints the text found between each comma:

/*
 * SplitSplit sketch
 * split a comma-separated string
 */

String  text = "Peter,Paul,Mary";  // an example string
String  message = text; // holds text not yet split
int     commaPosition;  // the position of the next comma in the string

void setup()
{
  Serial.begin(9600);
  while(!Serial); // Wait for serial port (Leonardo, 32-bit boards)

  Serial.println(message); // show the source string
  do
  {
    commaPosition = message.indexOf(',');
    if(commaPosition != -1)
    {
      Serial.println( message.substring(0,commaPosition));
      message = message.substring(commaPosition+1, message.length());
    }
    else
    { // here after the last comma is found
      if(message.length() > 0)
        Serial.println(message);  // if there is text after the last comma,
                                  // print it
    }
   }
   while(commaPosition >=0);
}

void loop()
{
}

The Serial Monitor will display the following:

Peter,Paul,Mary
Peter
Paul
Mary

Discussion

This sketch uses String functions to extract text from between commas. The following code:

commaPosition = message.indexOf(',');

sets the variable commaPosition to the position of the first comma in the String named message (it will be set to –1 if no comma is found). If there is a comma, the substring function is used to print the text from the beginning of the string up to, but excluding, the comma. The text that was printed, and its trailing comma, are removed from message in this line:

message = message.substring(commaPosition+1, message.length());

substring returns a string starting from commaPosition+1 (the position just after the first comma) up to the length of the message. This results in that message containing only the text following the first comma. This is repeated until no more commas are found (commaPosition will be equal to –1).

If you are an experienced programmer, you can also use the low-level functions that are part of the standard C library. The following sketch has similar functionality to the preceding one using Arduino strings:

/*
 * strtok sketch
 * split a comma-separated string
 */

const int  MAX_STRING_LEN = 20; // set this to the largest string
                                // you will process
                                
char stringList[] = "Peter,Paul,Mary"; // an example string

char stringBuffer[MAX_STRING_LEN+1]; // a static buffer for computation and output

void setup()
{
  Serial.begin(9600);
  while(!Serial); // Wait for serial port (Leonardo, 32-bit boards)

  char *str;
  char *p;
  strncpy(stringBuffer, stringList, MAX_STRING_LEN); // copy source string
  Serial.println(stringBuffer);                      // show the source string
  
  for( str = strtok_r(stringBuffer, ",", &p);        // split using comma
       str;                                          // loop while str is not null
       str = strtok_r(NULL, ",", &p)                 // get subsequent tokens
     )
  {
    Serial.println(str);
  }
}

void loop()
{
}
Note

Although you can use pointers with Arduino, it’s generally discouraged in sketches because it makes it harder for beginners to understand your code. In practice, you will rarely see pointers or any advanced C functionality in example sketches. For more information on recommended Arduino coding style, see https://www.arduino.cc/en/Reference/StyleGuide.

The core functionality comes from the function named strtok_r (the name of the version of strtok that comes with the Arduino compiler). The first time you call strtok_r, you pass it the string you want to tokenize (separate into individual values). But strtok_r overwrites the characters in this string each time it finds a new token, so it’s best to pass a copy of the string as shown in this example. Each call that follows uses a NULL to tell the function that it should move on to the next token. In this example, each token is printed to the serial port. *p is a pointer that strtok_r uses to keep track of the string it’s working on. You declare it as *p but you pass it into the strtok_r function as &p.

If your tokens consist only of numbers, see Recipe 4.5. This shows how to extract numeric values separated by commas in a stream of serial characters.

See Also

See http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html for more on C string functions such as strtok_r and strcmp.

Recipe 2.5

See http://man7.org/linux/man-pages/man3/strtok.3.html for an online reference to the C/C++ functions strtok_r and strcmp.

2.8 Converting a Number to a String

Problem

You need to convert a number to a string, perhaps to show the number on an LCD or other display.

Solution

The String variable will convert numbers to strings of characters. You can use literal values, or the contents of a variable. For example, the following code will work:

String myNumber = String(1234);

As will this:

int value = 127;
String myReadout = "The reading was ";
myReadout.concat(value);

Or this:

int value = 127;
String myReadout = "The reading was ";
myReadout += value;

Discussion

If you are converting a number to display as text on an LCD or serial device, the simplest solution is to use the conversion capability built in to the LCD and Serial libraries (see Recipe 4.2). But perhaps you are using a device that does not have this built-in support (see Chapter 13) or you want to manipulate the number as a string in your sketch.

The Arduino String class automatically converts numerical values when they are assigned to a String variable. You can combine (concatenate) numeric values at the end of a string using the concat function or the string + operator.

Note

The + operator is used with number types as well as strings, but it behaves differently with each.

The following code results in number having a value of 13:

    int number = 12;
    number += 1;

With a String, as shown here:

    String textNumber = "12";
    textNumber += 1;

textNumber is the text string "121".

Prior to the introduction of the String class, it was common to find Arduino code using the itoa or ltoa function. The names come from “integer to ASCII” (itoa) and “long to ASCII” (ltoa). The String version described earlier is easier to use, but the following can be used if you prefer working with C character arrays as described in Recipe 2.6.

itoa or ltoa take three parameters: the value to convert, the buffer that will hold the output string, and the number base (10 for a decimal number, 16 for hex, and 2 for binary).

The following sketch illustrates how to convert numeric values using ltoa:

/*
 * NumberToString
 * Creates a string from a given number
 */

char buffer[12];  // long data type has 11 characters (including the
                  // minus sign) and a terminating null

void setup()
{
  Serial.begin(9600);
  while(!Serial);

  long value = 12345;
  ltoa(value, buffer, 10);

  Serial.print( value);
  Serial.print(" has  ");
  Serial.print(strlen(buffer));
  Serial.println(" digits");

  value = 123456789;
  ltoa(value, buffer, 10);

  Serial.print( value);
  Serial.print(" has  ");
  Serial.print(strlen(buffer));
  Serial.println(" digits");
}

void loop()
{
}

Your buffer must be large enough to hold the maximum number of characters in the string. For 16-bit base 10 (decimal) integers, that is seven characters (five digits, a possible minus sign, and a terminating 0 that always signifies the end of a string); 32-bit long integers need 12 character buffers (10 digits, the minus sign, and the terminating 0). No warning is given if you exceed the buffer size; this is a bug that can cause all kinds of strange symptoms, because the overflow will corrupt some other part of memory that may be used by your program. The easiest way to handle this is to always use a 12-character buffer and always use ltoa because this will work on both 16-bit and 32-bit values.

2.9 Converting a String to a Number

Problem

You need to convert a string to a number. Perhaps you have received a value as a string over a communication link and you need to use this as an integer or floating-point value.

Solution

There are a number of ways to solve this. If the string is received as serial stream data, it can be converted using the parseInt function. See the discussion section of this recipe  or Recipe 4.3 for examples of how to do this using the serial port.

Another approach to converting text strings representing numbers is to use the C language conversion function called atoi (for int variables) or atol (for long variables).

This sketch terminates the incoming digits on any character that is not a digit (or if the buffer is full). After you upload the sketch, open the Serial Monitor and type some numeric characters, then press Ener or Return. For this to work, though, you’ll need to enable the newline option in the Serial Monitor or type some non-digit characters before you press Enter or Return:

/*
 * StringToNumber
 * Creates a number from a string
 */

int   blinkDelay;     // blink rate determined by this variable
char strValue[6];     // must be big enough to hold all the digits and the
                      // 0 that terminates the string
int index = 0;        // the index into the array storing the received digits

void setup()
{
 Serial.begin(9600); 
 pinMode(LED_BUILTIN, OUTPUT); // enable LED pin as output
}

void loop()
{
  if( Serial.available())
  {
    char ch = Serial.read();
    if(index < 5 && isDigit(ch) ){
      strValue[index++] = ch; // add the ASCII character to the string;
    }
    else
    {
      // here when buffer full or on the first non digit
      strValue[index] = 0;        // terminate the string with a 0
      blinkDelay = atoi(strValue);  // use atoi to convert the string to an int
      index = 0;
    }
  }
  blink();
}  

void blink()
{
   digitalWrite(LED_BUILTIN, HIGH);
   delay(blinkDelay/2);  // wait for half the blink period 
   digitalWrite(LED_BUILTIN, LOW);
   delay(blinkDelay/2);  // wait for the other half 
}

Discussion

The obscurely named atoi (for ASCII to int) and atol (for ASCII to long) functions convert a string into integers or long integers. To use them, you have to receive and store the entire string in a character array before you can call the conversion function. The code creates a character array named strValue that can hold up to five digits (it’s declared as char strValue[6] because there must be room for the terminating null). It fills this array with digits from Serial.read until it gets the first character that is not a valid digit. The array is terminated with a null and the atoi function is called to convert the character array into the variable blinkDelay.

A function called blink is called that uses the value stored in blinkDelay.

As mentioned in the warning in Recipe 2.4, you must be careful not to exceed the bounds of the array. If you are not sure how to do that, see the Discussion section of that recipe.

Arduino also offers the parseInt function that can be used to get integer values from Serial and Ethernet (or any object that derives from the Stream class). The following fragment will convert sequences of numeric digits into numbers. It is similar to the solution but does not need a buffer (and does not limit the number of digits to 5):

void loop()
{
  if( Serial.available())
  {
    int newValue = Serial.parseInt();
    if (newValue != 0) {
        blinkDelay = newValue;
        Serial.print("New delay: ");
        Serial.println(blinkDelay);
    }
  }
  blink();
}
Note

Stream-parsing methods such as parseInt use a timeout to return control to your sketch if data does not arrive within the desired interval. The default timeout is one second but this can be changed by calling the setTimeout method:

Serial.setTimeout(1000 * 60); // wait up to one minute

parseInt (and all other stream methods) will return whatever value was obtained prior to the timeout if no delimiter was received. The return value will consist of whatever values were collected; if no digits were received, the return value will be zero.

See Also

Documentation for atoi can be found at: http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html.

There are many online C/C++ reference pages covering these low-level functions, such as http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/ or http://www.cppreference.com/wiki/string/c/atoi.

See Recipe 4.3 and Recipe 4.5 for more about using parseInt with Serial.

2.10 Structuring Your Code into Functional Blocks

Problem

You want to know how to add functions to a sketch, and understand how to plan the overall structure of a sketch.

Solution

Functions are used to organize the actions performed by your sketch into functional blocks. Functions package functionality into well-defined inputs (information given to a function) and outputs (information provided by a function) that make it easier to structure, maintain, and reuse your code. You are already familiar with the two functions that are in every Arduino sketch: setup and loop. You create a function by declaring its return type (the information it provides), its name, and any optional parameters (values) that the function will receive when it is called.

Note

The terms functions and methods are used to refer to well-defined blocks of code that can be called as a single entity by other parts of a program. The C language refers to these as functions. Object-oriented languages such as C++ that expose functionality through classes tend to use the term method. Arduino uses a mix of styles (the example sketches tend to use C-like style, libraries tend to be written to expose C++ class methods). In this book, the term function is usually used unless the code is exposed through a class. Don’t worry; if that distinction is not clear to you, treat both terms as the same.

Here is a simple function that just blinks an LED. It has no parameters and doesn’t return anything (the void preceding the function indicates that nothing will be returned):

// blink an LED once
void blink1()
{
   digitalWrite(LED_BUILTIN, HIGH); // turn the LED on
   delay(500);                      // wait 500 milliseconds
   digitalWrite(LED_BUILTIN, LOW);  // turn the LED off
   delay(500);                      // wait 500 milliseconds
}

The following version has a parameter (the integer named count) that determines how many times the LED will flash:

// blink an LED the number of times given in the count parameter
void blink2(int count)
{
  while(count > 0 )  // repeat until count is no longer greater than zero
  {
    digitalWrite(LED_BUILTIN, HIGH); // turn the LED on
    delay(500);                      // wait 500 milliseconds
    digitalWrite(LED_BUILTIN, LOW);  // turn the LED off
    delay(500);                      // wait 500 milliseconds
    count = count -1; // decrement count
  }
}
Note

Experienced programmers will note that both functions could be named blink because the compiler will differentiate them by the type of values used for the parameter. This behavior is called function overloading. The Arduino print discussed in Recipe 4.2 is a common example. Another example of overloading is in the discussion of Recipe 4.6.

That version checks to see if the value of count is 0. If not, it blinks the LED and then reduces the value of count by one. This will be repeated until count is no longer greater than 0.

Note

A parameter is sometimes referred to as an argument in some documentation. For practical purposes, you can treat these terms as meaning the same thing.

Here is an example sketch with a function that takes a parameter and returns a value. The parameter determines the length of the LED on and off times (in milliseconds). The function continues to flash the LED until a button is pressed, and the number of times the LED flashed is returned from the function. This sketch uses the same wiring as the pull-up sketch from Recipe 5.2.

/*
  blink3 sketch
  Demonstrates calling a function with a parameter and returning a value.
  
  The LED flashes when the program starts and stops when a switch connected
  to digital pin 2 is pressed.
  The program prints the number of times that the LED flashes.
 */

const int inputPin = 2;         // input pin for the switch

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(inputPin, INPUT);
  digitalWrite(inputPin,HIGH); // use internal pull-up resistor (Recipe 5.2)
  Serial.begin(9600);
}

void loop(){
  Serial.println("Press and hold the switch to stop blinking");
  int count = blink3(250); // blink the LED 250ms on and 250ms off
  Serial.print("The number of times the switch blinked was ");
  Serial.println(count);
  while(digitalRead(inputPin) == LOW)
  {
    // do nothing until they let go of the button
  }
}

// blink an LED using the given delay period
// return the number of times the LED flashed
int blink3(int period)
{
  int blinkCount = 0;

  while(digitalRead(inputPin) == HIGH) // repeat until switch is pressed
                                       // (it will go low when pressed)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(period);
    digitalWrite(LED_BUILTIN, LOW);
    delay(period);
    blinkCount = blinkCount + 1; // increment the count
  }
  // here when inputPin is no longer HIGH (means the switch is pressed)
  return blinkCount;  // this value will be returned
}
Note

A function declaration is a prototype—a specification of the name, the types of values that may be passed to the function, and the function’s return type. The Arduino build process creates the declarations for you under the covers so you do not need to follow the standard C requirement of declaring the function separately.

Discussion

The code in this recipe’s Solution illustrates the three forms of function call that you will come across. blink1 has no parameter and no return value. Its form is:

void blink1()
{
  // implementation code goes here...
}

blink2 takes a single parameter but does not return a value:

void blink2(int count)
{
  // implementation code goes here...
}

blink3 has a single parameter and returns a value:

int blink3(int period)
{
  int result = 0;
  // implementation code goes here...
  return result; // this value will be returned
}

The data type that precedes the function name indicates the return type (or no return type if void). When declaring the function (writing out the code that defines the function and its action), you do not put a semicolon following the parenthesis at the end. When you use (call) the function, you do need a semicolon at the end of the line that calls the function.

Most of the functions you come across will be some variation on these forms.

The data type identifier in front of the declaration tells the compiler (and reminds the programmer) what data type the function returns. In the case of blink1 and blink2, void indicates that it returns no value. In the case of blink3, int indicates that it returns an integer. When creating functions, choose the return type appropriate to the action the function performs.

Note

It is recommended that you give your functions meaningful names, and it is a common practice to combine words by capitalizing the first letter of each word, except for the first word. Use whatever style you prefer, but it helps others who read your code if you keep your naming style consistent.

The blink2 function has a parameter called count (when the function is called, count is given the value that is passed to the function). The blink3 function is different in that it is given a parameter called period.

The body of the function (the code within the curly brackets) performs the action you want—for blink1, it blinks the LED on and then off. For blink2, it iterates through a while loop the number of times specified by count, blinking the LED each time through. For blink3, it flashes the LED until you press a button, and then it returns a value to the calling function: the number of times that the LED blinked before you pressed the button.

See Also

The Arduino function reference page: http://www.arduino.cc/en/Reference/FunctionDeclaration

2.11 Returning More Than One Value from a Function

Problem

You want to return two or more values from a function. Recipe 2.10 provided examples for the most common form of a function, one that returns just one value or none at all. But sometimes you need to modify or return more than one value.

Solution

There are various ways to solve this. The easiest to understand is to have the function change some global variables and not actually return anything from the function:

/*
  swap sketch
  demonstrates changing two values using global variables
 */

int x; // x and y are global variables
int y;

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

void loop(){
  x = random(10); // pick some random numbers
  y = random(10);

  Serial.print("The value of x and y before swapping are: ");
  Serial.print(x); Serial.print(","); Serial.println(y);
  swap();

  Serial.print("The value of x and y after swapping are: ");
  Serial.print(x); Serial.print(","); Serial.println(y);Serial.println();


  delay(1000);
}

// swap the two global values
void swap()
{
  int temp;
  temp = x;
  x = y;
  y = temp;
}

The swap function changes two values by using global variables. Global variables are easy to understand (global variables are values that are accessible everywhere and anything can change them), but they are avoided by experienced programmers because it’s easy to inadvertently modify the value of a variable or to have a function stop working because you changed the name or type of a global variable elsewhere in the sketch.

A safer and more elegant solution is to pass references to the values you want to change and let the function use the references to modify the values. This is done as follows:

/*
  functionReferences sketch
  demonstrates returning more than one value by passing references
 */


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

void loop(){
  int x = random(10); // pick some random numbers
  int y = random(10);

  Serial.print("The value of x and y before swapping are: ");
  Serial.print(x); Serial.print(","); Serial.println(y);
  swapRef(x,y);

  Serial.print("The value of x and y after swapping are: ");
  Serial.print(x); Serial.print(","); Serial.println(y);Serial.println();

  delay(1000);
}

// swap the two given values
void swapRef(int &value1, int &value2)
{
  int temp;
  temp = value1;
  value1 = value2;
  value2 = temp;
}

Finally, another option is to use a C structure, which can contain multiple fields, allowing you to pass and return all kinds of data:

/*
  struct sketch
  demonstrates returning more than one value by using a struct
 */

struct Pair {
  int a, b;
};

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

void loop() {
  int x = random(10); // pick some random numbers
  int y = random(10);
  struct Pair mypair = {random(10), random(10)};

  Serial.print("The value of x and y before swapping are: ");
  Serial.print(mypair.a); Serial.print(","); Serial.println(mypair.b);
  mypair = swap(mypair);

  Serial.print("The value of x and y after swapping are: ");
  Serial.print(mypair.a); Serial.print(","); Serial.println(mypair.b);Serial.println();

  delay(1000);
}

// swap the two given values
Pair swap(Pair pair)
{
  int temp;
  temp = pair.a;
  pair.a = pair.b;
  pair.b = temp;
  return pair;
}

Discussion

The swapRef function is similar to the functions with parameters described in Recipe 2.10, but the ampersand (&) symbol indicates that the parameters are references. This means changes in values within the function will also change the value of the variable that is given when the function is called. You can see how this works by first running the code in this recipe’s Solution and verifying that the parameters are swapped. Then modify the code by removing the two ampersands in the function definition.

The changed line should look like this:

void swapRef(int value1, int value2)

Running the code shows that the values are not swapped—changes made within the function are local to the function and are lost when the function returns.

The swapPair function uses a C language feature called a struct (or structure). A structure contains any number of primitive types or pointers. The amount of memory reserved for a struct is equivalent to the size of its elements (on an 8-bit Arduino, a Pair would take up four bytes, eight on a 32-bit board). If you are familiar with object-oriented programming, it may be tempting to think of structs as similar to classes, but structs are nothing more than the data they contain.

2.12 Taking Actions Based on Conditions

Problem

You want to execute a block of code only if a particular condition is true. For example, you may want to light an LED if a switch is pressed or if an analog value is greater than some threshold.

Solution

The following code uses the wiring shown in Recipe 5.2.

/*
 * Pushbutton sketch
 * a switch connected to digital pin 2 lights the built-in LED
 */

const int inputPin = 2;           // choose the input pin (for a pushbutton)

void setup() 
{
  pinMode(LED_BUILTIN, OUTPUT);     // declare LED pin as output
  pinMode(inputPin, INPUT_PULLUP);  // declare pushbutton pin as input
}

void loop()
{
  int val = digitalRead(inputPin);  // read input value
  if (val == LOW)                   // Input is LOW when the button is pressed
  {
    digitalWrite(LED_BUILTIN, HIGH); // turn LED on if switch is pressed
  }
}

Discussion

The if statement is used to test the value of digitalRead. An if statement must have a test within the parentheses that can only be true or false. In the example in this recipe’s Solution, it’s val == LOW, and the code block following the if statement is only executed if the expression is true. A code block consists of all code within the curly brackets (or if you don’t use curly brackets, the block is just the next executable statement terminated by a semicolon).

If you want to do one thing if a statement is true and another if it is false, use the if...else statement:

/*
 * Pushbutton sketch
 * a switch connected to pin 2 lights the built-in LED
 */

const int inputPin = 2;         // choose the input pin (for a pushbutton)

void setup() 
{
  pinMode(LED_BUILTIN, OUTPUT);    // declare LED pin as output
  pinMode(inputPin, INPUT_PULLUP); // declare pushbutton pin as input
}

void loop()
{
  int val = digitalRead(inputPin);   // read input value
  if (val == LOW)                    // Input is LOW when the button is pressed
  {
    // do this if val is LOW
    digitalWrite(LED_BUILTIN, HIGH); // turn LED on if switch is pressed
  }
  else
  {
    // else do this if val is not LOW
    digitalWrite(LED_BUILTIN, LOW);  // turn LED off
  }
}

See Also

See the discussion on Boolean types in Recipe 2.2.

2.13 Repeating a Sequence of Statements

Problem

You want to repeat a block of statements while an expression is true.

Solution

A while loop repeats one or more instructions while an expression is true:

/*
 * Repeat
 * blinks while a condition is true
 */

const int sensorPin = A0; // analog input 0

void setup()
{
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT); // enable LED pin as output
}

void loop()
{
  while(analogRead(sensorPin) > 100)
  {
    blink();    // call a function to turn an LED on and off
    Serial.print(".");
  }
  Serial.println(analogRead(sensorPin)); // this is not executed until after
                                         // the while loop finishes!!!
}  

void blink()
{
   digitalWrite(LED_BUILTIN, HIGH);
   delay(100);
   digitalWrite(LED_BUILTIN, LOW);
   delay(100);
}

This code will execute the statements in the block within the curly brackets, {}, while the value from analogRead is greater than 100. This could be used to flash an LED as an alarm while some value exceeded a threshold. The LED is off when the sensor value is 100 or less; it flashes continuously when the value is greater than 100.

Discussion

Curly brackets define the extent of the code block to be executed in a loop. If curly brackets are not used, only the first line of code will be repeated in the loop, so you should use this style sparingly (or not at all):

while(analogRead(sensorPin) > 100)
   blink();   // line immediately following the loop expression is executed
   Serial.print("."); // this is not executed until after the while loop finishes!!!

The do...while loop is similar to the while loop, but the instructions in the code block are executed before the condition is checked. Use this form when you must have the code executed at least once, even if the expression is false:

do
{
   blink();  // call a function to turn an LED on and off
   Serial.print(".");
}
while (analogRead(sensorPin) > 100);

The preceding code will flash the LED at least once and will keep flashing as long as the value read from a sensor is greater than 100. If the value is not greater than 100, the LED will only flash once. This code could be used in a battery-charging circuit, if it were called once every 10 seconds or so: a single flash shows that the circuit is active, whereas continuous flashing indicates the battery is charged.

Warning

Only the code within a while or do loop will run until the conditions permit exit. If your sketch needs to break out of a loop in response to some other condition such as a timeout, sensor state, or other input, you can use break:

while(analogRead(sensorPin) > 100)
{            
   blink(); 
   Serial.print(".");
   if(Serial.available()) 
   {
     while(Serial.available())
     {
         // consume any pending serial input
         Serial.read();
     }
     break; // any serial input breaks out of the while loop
   }
}

See Also

Chapters 4 and 5

2.14 Repeating Statements with a Counter

Problem

You want to repeat one or more statements a certain number of times. The for loop is similar to the while loop, but you have more control over the starting and ending conditions.

Solution

This sketch counts from zero to three by printing the value of the variable i in a for loop:

/*
   ForLoop sketch
   demonstrates for loop
*/

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

void loop(){
  Serial.println("for(int i=0; i < 4; i++)");
  for(int i=0; i < 4; i++)
  {
    Serial.println(i);
  }
  delay(1000);
}

The Serial Monitor output from this is as follows (it will be displayed over and over):

for(int i=0; i < 4; i++)
0
1
2
3

Discussion

A for loop consists of three parts: initialization, conditional test, and iteration (a statement that is executed at the end of every pass through the loop). Each part is separated by a semicolon. In the code in this recipe’s Solution, int i=0; initializes the variable i to 0; i < 4; tests the variable to see if it’s less than 4; and i++ increments i.

A for loop can use an existing variable, or it can create a variable for exclusive use inside the loop. This version uses the value of the variable j created earlier in the sketch:

  int j;

  Serial.println("for(j=0; j < 4; j++)");
  for(j=0; j < 4; j++ )
  {
    Serial.println(j);
  }

This is almost the same as the earlier example, but it does not have the int keyword in the initialization part because the variable j was already defined. The output of this version is similar to the output of the earlier version:

for(j=0; j < 4; j++)
0
1
2
3

You control when the loop stops in the conditional test. The previous example tests whether the loop variable is less than 4 and will terminate when the condition is no longer true.

Note

If your loop variable starts at 0 and you want it to repeat four times, your conditional statement should test for a value less than 4. The loop repeats while the condition is true and there are four values that are less than 4 with a loop starting at 0.

The following code tests if the value of the loop variable is less than or equal to 4. It will print the digits from 0 to 4:

  Serial.println("for(int i=0; i <= 4; i++)");
  for(int i=0; i <= 4; i++)
  {
    Serial.println(i);
  }

The third part of a for loop is the iterator statement that gets executed at the end of each pass through the loop. This can be any valid C/C++ statement. The following increases the value of i by two on each pass:

  Serial.println("for(int i=0; i < 4; i+= 2)");
  for(int i=0; i < 4; i+=2)  {
    Serial.println(i);
  }

That expression only prints the values 0 and 2.

The iterator expression can be used to cause the loop to count from high to low, in this case from 3 to 0:

  Serial.println("for(int i=3; i > = 0 ; i--)");
  for(int i=3; i >= 0 ; i--)
  {
    Serial.println(i);
  }

Like the other parts of a for loop, the iterator expression can be left blank (you must always have the two semicolons separating the three parts even if they are blank).

This version only increments i when an input pin is high. The for loop does not change the value of i; it is only changed by the if statement after Serial.print—you’ll need to define inPin and set it to INPUT with pinMode():

  pinMode(2, INPUT_PULLUP); // this goes in setup()

  /* ... */

  Serial.println("for(int i=0; i < 4; )");
  for(int i=0; i < 4; )
  {
    Serial.println(i);
    if(digitalRead(2) == LOW) {
      i++;  // only increment the value if the button is pressed
    }
  }

See Also

Arduino reference for the for statement: https://www.arduino.cc/reference/en/language/structure/control-structure/for/

2.15 Breaking Out of Loops

Problem

You want to terminate a loop early based on some condition you are testing.

Solution

Use the break statement as shown in the following sketch:

/*
 * break sketch
 * Demonstrates the use of the break statement
 */

const int switchPin = 2; // digital input 2

void setup()
{
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT); // enable LED pin as output
  pinMode(switchPin, INPUT_PULLUP); // enable button pin as input
}

void loop()
{
  while(true) // endless loop
  {
    if(digitalRead(switchPin) == LOW)
    {
      break; // exit the loop if the switch is pressed
    }
    blink(); // call a function to turn an LED on and off
  }
}

void blink()
{
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  digitalWrite(LED_BUILTIN, LOW);
  delay(100);
}

Discussion

This code is similar to the one using while loops, but it uses the break statement to exit the loop if a digital pin goes high. For example, if a switch is connected on the pin as shown in Recipe 5.2, the loop will exit and the LED will stop flashing even though the condition in the while loop is true.

See Also

Arduino reference for the break statement: https://www.arduino.cc/reference/en/language/structure/control-structure/break/

An interrupt is a facility built into the microcontroller hardware that allows you to take action more or less immediately when a pin state changes. See Recipe 18.2 for more details.

2.16 Taking a Variety of Actions Based on a Single Variable

Problem

You need to do different things depending on some value. You could use multiple if and else if statements, but the code soon gets complex and difficult to understand or modify. Additionally, you may want to test for a range of values.

Solution

The switch statement provides for selection of a number of alternatives. It is functionally similar to multiple if/else if statements but is more concise:

/*
 * SwitchCase sketch
 * example showing switch statement by switching on chars from the serial port
 *
 * sending the character 1 blinks the LED once, sending 2 blinks twice
 * sending + turns the LED on, sending - turns it off
 * any other character prints a message to the Serial Monitor
 */

void setup()
{
  Serial.begin(9600); // Initialize serial port to send and 
                      // receive at 9600 baud
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  if ( Serial.available()) // Check to see if at least one 
                           // character is available
  {
    char ch = Serial.read();
    switch(ch)
    {
    case '1':
      blink();
      break;
    case '2':
      blink();
      blink();
      break;
    case '+':
      digitalWrite(LED_BUILTIN, HIGH);
      break;
    case '-':
      digitalWrite(LED_BUILTIN, LOW);
      break;
    case '
': // newline, safe to ignore
      break;
    case '
': // carriage return, safe to ignore
      break;
    default:
      Serial.print(ch);
      Serial.println(" was received but not expected");
      break;
    }
  }
}

void blink()
{
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
}

Discussion

The switch statement evaluates the variable ch received from the serial port and branches to the label that matches its value. The labels must be numeric constants. Because the char datatype is represented as a numeric value (see Recipe 2.2), it is permitted. However, you can’t use strings in a case statement, and no two labels can have the same value. If you don’t have a break statement following each expression, the execution will fall through into the statement:

    case '1':
      blink();   // no break statement before the next label
    case '2':
      blink();   // case '1' will continue here
      blink();
      break;     // break statement will exit the switch expression

If the break statement at the end of case '1': was removed (as shown in the preceding code), when ch is equal to the character 1 the blink function will be called three times. Accidentally forgetting the break is a common mistake. Intentionally leaving out the break is sometimes handy; it can be confusing to others reading your code, so it’s a good practice to clearly indicate your intentions with comments in the code.

Note

If your switch statement is misbehaving, check to ensure that you have not forgotten the break statements.

The default: label is used to catch values that don’t match any of the case labels. If there is no default label, the switch expression will not do anything if there is no match.

See Also

Arduino reference for the switch and case statements: https://www.arduino.cc/reference/en/language/structure/control-structure/switchcase/

2.17 Comparing Character and Numeric Values

Problem

You want to determine the relationship between values.

Solution

Compare integer values using the relational operators shown in Table 2-5.

Relational and equality operators
Operator Test for Example

==

Equal to

2 == 3 // evaluates to false

!=

Not equal to

2 != 3 // evaluates to true

>

Greater than

2 > 3 // evaluates to false

<

Less than

2 < 3 // evaluates to true

>=

Greater than or equal to

2 >= 3 // evaluates to false

<=

Less than or equal to

2 <= 3 // evaluates to true

The following sketch demonstrates the results of using the comparison operators:

/*
 * RelationalExpressions sketch
 * demonstrates comparing values
 */

int i = 1;  // some values to start with
int j = 2;

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

void loop(){
  Serial.print("i = ");
  Serial.print(i);
  Serial.print(" and j = ");
  Serial.println(j);

  if(i < j)
    Serial.println(" i is less than j");
  if(i <= j)
    Serial.println(" i is less than or equal to j");
  if(i != j)
    Serial.println(" i is not equal to j");
  if(i == j)
    Serial.println(" i is equal to j");
  if(i >= j)
    Serial.println(" i is greater than or equal to j");
  if(i > j)
    Serial.println(" i is greater than j");

  Serial.println();
  i = i + 1;
  if(i > j + 1)
  {
    delay(10000);  // long delay after i is no longer close to j
  }
  else
  {
    delay(1000);   // short delay
  }
}

Here is the output:

i = 1 and j = 2
 i is less than j
 i is less than or equal to j
 i is not equal to j

i = 2 and j = 2
 i is less than or equal to j
 i is equal to j
 i is greater than or equal to j

i = 3 and j = 2
 i is not equal to j
 i is greater than or equal to j
 i is greater than j

Discussion

Note that the equality operator is the double equals sign, ==. One of the most common programming mistakes is to confuse this with the assignment operator, which uses a single equals sign.

The following expression will compare the value of i to 3. The programmer intended this:

  if(i == 3)  // test if i equals 3

But suppose he put this in the sketch:

  if(i = 3)  // single equals sign used by mistake!!!!

This will always return true, because i will be set to 3, so they will be equal when compared.

You can also perform these sorts of comparisons on character values because they are represented as numeric values (see Recipe 2.2). This will evaluate to true

if ('b' > 'a')

As will this, because the numeric value of ‘a’ is 97 in the ASCII character set that Arduino uses:

if ('a' == 97)

However, strings cannot be directly compared to numeric values:

String word1 = String("Hello");
char word2[] = "World";
if (word1 > 'G') // This will not compile
{ 
  Serial.println("word1 > G");
}
if (word2 >= 'W') // This also will not compile
{
  Serial.println("word2 >= W");
}

But you can always compare a number or char against a single character from a string:

if (word1.charAt(0) > 'G')
{ 
  Serial.println("word1[0] > G");
}
if (word2[0] >= 'W')
{
  Serial.println("word2[0] >= W");
}

See Also

Arduino reference for conditional and comparison operators: https://www.arduino.cc/reference/en/language/structure/control-structure/if/

Arduino ASCII chart reference: https://www.arduino.cc/en/Reference/ASCIIchart

2.18 Comparing Strings

Problem

You want to see if two character strings are identical.

Solution

There is a function to compare strings, called strcmp (short for string compare). Here is a fragment showing its use:

  char string1[ ] = "left";
  char string2[ ] = "right";

  if(strcmp(string1, string2) == 0)
  {
    Serial.println("strings are equal");
  }

Discussion

strcmp returns the value 0 if the strings are equal and a value greater than zero if the first character that does not match has a greater value in the first string than in the second. It returns a value less than zero if the first nonmatching character in the first string is less than in the second. Usually you only want to know if they are equal, and although the test for zero may seem unintuitive at first, you’ll soon get used to it.

Bear in mind that strings of unequal length will not be evaluated as equal even if the shorter string is contained in the longer one. So:

if (strcmp("left", "leftcenter") == 0)  // this will evaluate to false

You can compare strings up to a given number of characters by using the strncmp function. You give strncmp the maximum number of characters to compare and it will stop comparing after that many characters:

if (strncmp("left", "leftcenter", 4) == 0)  // this will evaluate to true

Unlike character strings, Arduino Strings can be directly compared as follows:

String stringOne = String("this");    
if (stringOne == "this")
{
  Serial.println("this will be true");
}
if (stringOne == "that")
{
  Serial.println("this will be false");
}

A tutorial on Arduino String comparison is at http://arduino.cc/en/Tutorial/StringComparisonOperators.

See Also

More information on strcmp is available at http://www.cplusplus.com/reference/clibrary/cstring/strcmp/.

See Recipe 2.5 for an introduction to the Arduino String.

2.19 Performing Logical Comparisons

Problem

You want to evaluate the logical relationship between two or more expressions. For example, you want to take a different action depending on the conditions of an if statement.

Solution

Use the logical operators as outlined in Table 2-6.

Logical operators
Symbol Function Comments

&&

Logical And

Evaluates as true if the conditions on both sides of the && operator are true

||

Logical Or

Evaluates as true if the condition on at least one side of the || operator is true

!

Not

Evaluates as true if the expression is false, and false if the expression is true

Discussion

Logical operators return true or false values based on the logical relationship. The examples that follow assume you have sensors wired to digital pins 2 and 3 as discussed in Chapter 5.

The logical And operator && will return true if both its two operands are true, and false otherwise:

if( digitalRead(2) && digitalRead(3) )
  blink(); // blink if both pins are HIGH

The logical Or operator || will return true if either of its two operands are true, and false if both operands are false:

if( digitalRead(2) || digitalRead(3) )
  blink(); // blink if either pins is HIGH

The Not operator ! has only one operand, whose value is inverted—it results in false if its operand is true and true if its operand is false:

if( !digitalRead(2)  )
  blink(); // blink if the pin is not HIGH

2.20 Performing Bitwise Operations

Problem

You want to set or clear certain bits in a value.

Solution

Use the bit operators as outlined in Table 2-7. The 0b prefix indicates binary representation of numbers and is used to disambiguate between the decimal and binary numbers in the table.

Bit operators
Symbol Function Result Example

&

Bitwise And

Sets bits in each place to 1 if both bits are 1; otherwise, bits are set to 0.

3 & 1 equals 1

(0b11 & 0b01 equals 0b01)

|

Bitwise Or

Sets bits in each place to 1 if either bit is 1.

3 | 1 equals 3

(0b11 | 0b01 equals 0b11)

^

Bitwise Exclusive Or

Sets bits in each place to 1 only if one of the two bits is 1.

3 ^ 1 equals 2

(0b11 ^ 0b01 equals 0b10)

~

Bitwise Negation

Inverts the value of each bit. The result depends on the number of bits in the data type.

~1 equals 254

(~00000001 equals 11111110)

Here is a sketch that demonstrates the example values shown in Table 2-7:

/*
 * bits sketch
 * demonstrates bitwise operators
 */

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

void loop(){
  Serial.print("3 & 1 equals "); // bitwise And 3 and 1
  Serial.print(3 & 1);         // print the result
  Serial.print(" decimal, or in binary: ");
  Serial.println(3 & 1 , BIN);   // print the binary representation of the result

  Serial.print("3 | 1 equals "); // bitwise Or 3 and 1
  Serial.print(3 | 1 );
  Serial.print(" decimal, or in binary: ");
  Serial.println(3 | 1 , BIN);   // print the binary representation of the result

  Serial.print("3 ^ 1 equals "); // bitwise exclusive or 3 and 1
  Serial.print(3 ^ 1);  Serial.print(" decimal, or in binary: ");
  Serial.println(3 ^ 1 , BIN);   // print the binary representation of the result


  byte byteVal = 1;
  int intVal = 1;

  byteVal = ~byteVal;  // do the bitwise negate
  intVal = ~intVal;

  Serial.print("~byteVal (1) equals "); // bitwise negate an 8-bit value
  Serial.println(byteVal, BIN);  // print the binary representation of the result
  Serial.print("~intVal (1) equals "); // bitwise negate a 16-bit value
  Serial.println(intVal, BIN);   // print the binary representation of the result

  delay(10000);
}

This is what is displayed on the Serial Monitor:

3 & 1 equals 1 decimal, or in binary: 1
3 | 1 equals 3 decimal, or in binary: 11
3 ^ 1 equals 2 decimal, or in binary: 10
~byteVal (1) equals 11111110
~intVal (1) equals 11111111111111111111111111111110

Discussion

Bitwise operators are used to set or test bits. When you “And” or “Or” two values, the operator works on each individual bit. It is easier to see how this works by looking at the binary representation of the values.

The decimal integer 3 is binary 11, and the decimal integer 1 is binary 1. Bitwise And operates on each bit. The rightmost bits are both 1, so the result of And-ing these is 1. Moving to the left, the next bits are 1 and 0; And-ing these results in 0. All the remaining bits are 0, so the bitwise result of these will be 0. In other words, for each bit position where there is a 1 in both places, the result will have a 1; otherwise, it will have a 0. So, 11 & 01 equals 1. Binary numbers are often written with leading zeroes because it makes it easier to evaluate the effect of bitwise operations at a glance, but the leading zeroes are not significant.

Tables 2-8, 2-9, and 2-10 should help to clarify the bitwise And, Or, and Exclusive Or values.

Bitwise And
Bit 1 Bit 2 Bit 1 and Bit 2

0

0

0

0

1

0

1

0

0

1

1

1

Bitwise Or
Bit 1 Bit 2 Bit 1 or Bit 2

0

0

0

0

1

1

1

0

1

1

1

1

Bitwise Exclusive Or
Bit 1 Bit 2 Bit 1 ^ Bit 2

0

0

0

0

1

1

1

0

1

1

1

0

All the bitwise expressions operate on two values, except for the negation operator. This simply flips each bit, so 0 becomes 1 and 1 becomes 0. In the example, the byte (8-bit) value 00000001 becomes 11111110. The int value has 16 bits, so when each is flipped, the result is 15 ones followed by a single zero.

See Also

Arduino reference for the bitwise And, Or, and Exclusive Or operators: http://www.arduino.cc/en/Reference/Bitwise

2.21 Combining Operations and Assignment

Problem

You want to understand and use compound operators. It is not uncommon to see published code that uses expressions that do more than one thing in a single statement. You want to understand a += b, a >>= b, and a &= b.

Solution

Table 2-11 shows the compound assignment operators and their equivalent full expression.

Compound operators
Operator Example Equivalent expression

+=

value += 5;

value = value + 5; // add 5 to value

-=

value -= 4;

value = value - 4; // subtract 4 from value

*=

value *= 3;

value = value * 3; // multiply value by 3

/=

value /= 2;

value = value / 2; // divide value by 2

>>=

value >>= 2;

value = value >> 2; // shift value right two places

<<=

value <<= 2;

value = value << 2; // shift value left two places

&=

mask &= 2;

mask = mask & 2; // binary-and mask with 2

|=

mask |= 2;

mask = mask | 2; // binary-or mask with 2

Discussion

These compound statements are no more efficient at runtime than the equivalent full expression, and if you are new to programming, using the full expression is clearer. Experienced coders often use the shorter form, so it is helpful to be able to recognize the expressions when you run across them.

See Also

See http://www.arduino.cc/en/Reference/HomePage for an index to the reference pages for compound operators.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.247.196