Chapter 4
Structuring and Arduino Programming
This chapter will focus a bit more on Arduino programming and structuring the sketches we build.
Structuring and Arduino Program
Arduino programs are normally alluded to as sketches, to underline the agile nature of advancement. The words program and sketch are compatible. Sketches have code – the guidelines the board will complete. Code required to run just a single time (for example, to set up the board for your application) should be kept in the setup function. While the code which has to be run consistently after the first step has completed goes into the loop function. Below shown is a regular sketch:
const int ledPin = 13; // LED connected to digital pin 13
// The setup() method runs once when the sketch starts
void setup()
{ pinMode(ledPin, OUTPUT); // initialize the digital pin as an output
}
// the loop() method runs over and over again,
void loop()
{
digitalWrite(ledPin, HIGH); // turn the LED on
delay(1000); // wait a second
digitalWrite(ledPin, LOW); // turn the LED off
delay(1000); // wait a second
}
Once the sketch program's transfer from the PC to the Arduino board is completed, the board begins from the start of the sketch and
completes the directions consecutively. It also does the same when the board has the code and is turned on. It executes the code once in the setup function and afterward executes it in a loop. When it gets to the end limit of the loop (set apart by the closing bracket,}) it returns to the start of the loop.
This example persistently flashes a LED by composing HIGH and LOW yields to a pin. Refer to Chapter 5 to become familiar with utilizing Arduino pins. When the sketch starts, the code in setup sets the pin mode (so it’s equipped for lighting a LED). When the code's execution in setup is finished, the code in the loop is consistently executed to flash the LED until the Arduino board is switched on.
You don’t have to realize this to compose Arduino sketches, yet expert C and C++ developers may ponder where the expected main ( ) function (which is the entry point) has gone. Actually, it's present there, yet it's covered under the covers by the Arduino build environment. A halfway document is made by the build process that has the sketch code along with some other explanations:
int main(void)
{
init();
setup();
for (;;)
loop();
return 0;
}
In the above sketch we see that the Arduino Hardware is initialized as at the start of the code the function init ( ) is called. After the init ( ) function the next function called is the setup ( ). After both these functions the last and final function is called, that is the loop ( ). It is called repeatedly. And at last we see that the statement ‘return’ does not run. The reason behind this is that the for loop does not end.
Using Standard Variable Types
Arduino has various kinds of variables to represent the values more efficiently. You need to understand how to choose and utilize these data types of Arduino.
In the Arduino applications we see that the most basic data type used is int. int is an abbreviation for integer and is a 16- bit value. The following table highlights the numerous data types used in Arduino and their explanations, originally given by Michael Margolis in his book ‘Arduino Cookbook
’ which is a very good read.
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.
|
boolean
|
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
|
string
|
Represents arrays of chars (characters) typically used to contain text.
|
void
|
Used only in function declarations where no value is returned.
|
|
|
|
|
(Reference: Arduino Cookbook by Michael Margolis)
If the values do not surpass the range and you do not have to deal with fractional numbers, then the variables proclaimed utilizing int will be appropriate. This is only possible for circumstances in which efficient memory or most of execution is not required. In the official example codes of Arduino, we can see that int data type is preferred for numeric values. But in some cases, you are required to select a different data type.
One might encounter different scenarios where they might either require a positive value or a negative value. So, signed and unsigned are the two numeric types that can be used to represent both positive and negative values respectively, variables are used without the keyword ‘unsigned’ in front of them. Positive values are always considered as unsigned. A signed variable has half the range of an unsigned variable so one main cause to utilize unsigned variables is the point at which the range of signed values won’t be in
the limit of the variable. One other cause is that the developers prefer unsigned values because they want to show the individuals that they will not get a negative value.
True or false are the two potential outcomes of a Boolean data type. These kinds of data types are normally utilized to see the switch’s condition. Instead of using the words true or false, you can also utilize the words HIGH or LOW, respectively. For example, instead of using digitalWrite (pin, true) or digitalWrite (pin, 1), you can write digitalWrite (pin, HIGH) as it feels like a more suitable approach to turn on a LED. However, these all are considered identical when the code really performs the execution.
Floating- Point Numbers
The numbers having decimal points are represented with the help of Floating-point values. Fractional numbers can also be expressed using this approach. Now you are required to write a code that will help you to compute and analyze these numbers.
The code shown below tells you how to express floating-point variables, demonstrates issues you can come across while the comparison floating-point values, and also explains how to solve these issues:
/*
* 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(fabs(value) < .0001) // function to take the absolute value of a float
Serial.println("The value is close enough to zero");
else
Serial.println(value);
delay(100);
}
The calculation performed by the Floating-point numbers isn’t precise. We can face some errors in these calculations. As we know that the numbers expressed internally just hold estimation so these mistakes happen in the light of the fact that a vast range of numbers falls in the category of floating-point numbers. These mistakes bound you to check whether the values are in a ‘range of resilience’
or not.
The following is the output from this sketch:
1.00
0.90
0.80
0.70
0.60
0.50
0.40
0.30
0.20
0.10
The value is close enough to zero
-0.10
-0.20
The output keeps on giving negative numbers.
This might be possible that you assume the loop to terminate as its value becomes equal to ‘0.1.’ Afterward, from this value ‘0.1’ is deducted. In any case, this value never becomes sufficient enough to hold true for the if statement i.e., value == 0. This is because the only approach is that floating-point numbers can accommodate the vast range by saving an estimation of that respective value.
This problem can be solved by checking if a variable is near to the ideal value, as appeared in the code in the current solution
else if(fabs(value) < .0001) // function to take the absolute value of a float
Serial.println("The value is close enough to zero");
This code checks if the variable's value is within 0.0001 of the ideal value and if the case is true, it prints a message. The function known as ‘fabs,’ an abbreviation for floating-point absolute value, gives the absolute value of a floating-point variable. The magnitude of the value is returned through this function, if the value is within 0.0001 of 0, then the code will print a message that ‘the value is close enough to zero.’
Working with Groups of Values
Arrays are called the group of values. Basically, you are required to understand their creation and utilization. These arrays can have more than one dimension. Learn to access the array’s elements and find its size..
The following piece of codes shows the creation of 2 arrays. The first array in the following code consists of integers that denote the pins joined to switches. Similarly, the second array consists of integers that denote the pins joined to LEDs.
/*
array sketch
an array of switches controls an array of 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); // declare pushbutton as input
digitalWrite(inputPins[index],HIGH); // enable pull-up resistors
//(see Recipe 5.2)
}
}
void loop(){
for(int index = 0; index < 4; index++)
{
int val = digitalRead(inputPins[i]); // read input value
if (val == LOW) // check if the switch is pressed
{
digitalWrite(ledPins[index], HIGH); // turn LED on if switch is pressed
}
else
{
digitalWrite(ledPins[i], LOW); // turn LED off
}
}
}
The assortments of successive variables having the similar data types are called arrays. An independent variable in that assortment
is called an element and the quantity of these independent variables determines the array’s dimension.
In the example mentioned above we see how to store an assortment of pins. This is a basic utilization of array in the Arduino code. It shows that the pins are joined to LEDs and switches. The most significant things we learn here are that how an array is created and how its elements are accessed.
Below given is a code that creates an array of data type integer. It has four elements and the values are initialized. The value of the first element is 2, the next element has value 3, etc:
int inputPins[] = {2,3,4,5};
You can create an array as shown below if you do not want the arrays' values to be initialized. Maybe these values will be accessible only when the code is being executed.
int array[4];
This declares an array having 4 elements and the value of each element is initially set to 0 (zero). The number written inside the square [] bracket shows the array's dimension and sets that number of elements of an array. The above array cannot have more than four integer values as its dimension is four. If the array declaration has initializers, then the array's dimension can be excluded as shown in the primary example. This is because the compiler sorts out how huge to make the array by getting the total number of initializers.
element [0] is the first element of the array:
int firstElement = inputPin[0]; // this is the first element
If we look at the previous demonstration, we can find that the array's concluding component is 3 although we are working with a four-dimensional array. This is because it is a common trend that whatever the array's dimension is, the value of its last component will always be ‘n-1’ where ‘n’ is the total dimensions of the array.
int lastElement = inputPin[3]; // this is the last element
It might appear to be odd that the last element of an array having dimension four is accessed through array [3], but since the first element of the array is array [0], the four elements will be:
array[0],array[1],array[2],array[3]
In the preceding sketch, for is used to access the four elements of the array:
for(int index = 0; index < 4; index++)
{
//get the pin number by accessing each element in the pin arrays
pinMode(ledPins[index], OUTPUT); // declare LED as output
pinMode(inputPins[index], INPUT); // declare pushbutton as input
}
With values beginning at ‘0’ and finishing at ‘3,’ the loop will journey over the index variable. This is arguably one of the most common mistakes where sometimes an element that does not lie in the array’s dimension is sent an access request by the user. This is an error that can have various side effects. An approach to avoid such errors is to use a constant to set the array’s dimension. Consider the code written below:
const int PIN_COUNT = 4; // define a constant for the number of elements
int inputPins[PIN_COUNT] = {2,3,4,5};
for(int index = 0; index < PIN_COUNT; index++)
pinMode(inputPins[index], INPUT);
Arrays are also utilized to store text characters that are basically known as strings. These are known as strings or character strings in the Arduino code. At least one character is required to make character string. This is then followed by the null character i.e., 0, to
demonstrate that the string ends here.
Using Strings in Arduino
You need to manage text. You have to copy the text, add bits together, and find the number of characters.
Character arrays are used to store text. They are normally known as strings. Arduino has an additional ability for utilizing a character array known as String that can store and manage text strings.
This topic explains how to use Arduino strings.
First load the sketch was written below and then to view the results open your Serial Monitor:
/*
Basic_Strings sketch
*/
String text1 = "This string";
String text2 = " has more text";
String text3; // to be assigned within the sketch
void setup()
{
Serial.begin(9600);
Serial.print( text1);
Serial.print(" 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()
{
}
The above sketch makes two variables of type String. One is called message and the other is called ‘anotherMessage.’ Type String variables have built-in abilities that allow them to manipulate text. Message.length ( ) provides (returns) the value of the number of characters (length) in the string message.
To combine the contents of a string message.concat (anotherMessage) will be used; in this situation, it will combine the contents of anotherMessage to the end of the message. Here, concat is an abbreviation for concatenation.
The following will be shown on the Serial Monitor:
This string is 11 characters long.
text2 is 14 characters long.
text1 now contains:
This string has more text
There is another way to combine the strings i.e., by using the string addition operator. Write the following two lines of code at the end of setup code:
text3 = text1 + " and more";
Serial.println(text3);
The new code will bring about the Serial Monitor adding the line shown below to the end of the display:
This is a string with more text and more
To find the instance of a specific character in a string, the two functions indexOf and lastIndexOf can be used.
On the off chance that you see a line as shown below:
char oldString[] = "this is a character array";
C-style character arrays are used in the code. And if you see a line of code like the following:
String newString = "this is a string object";
then Arduino Strings are used in the code. If you want a C-style character array to be converted into Arduino String, then assign its contents to the String object:
char oldString[] = "I want this character array in a String object";
String newsString = oldString;
The Arduino distribution provides string example sketches.
Using Strings of C Programming Language
You need to learn that how you can use raw character strings: you need to understand how to declare or create a string, how to find its length, and how to copy, compare, or append strings. The C language does not support the Arduino style String ability, that’s why you need to get code written to work with primitive character arrays.
Character arrays are at times known as character strings or basically strings for short. This topic explains the functions that work on character strings.
String declaration is done as follows:
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
To find the number of characters in an array before the null, use strlen i.e., abbreviation for sting length.
int length = strlen(string); // return the number of characters in the string
StringA will have length ‘0’ and other strings shown in the above code will have length 7. Strlen does not count the null that shows the end of the string.
Now, to copy one string to another string strcpy i.e., abbreviation for string copy is used.
strcpy(destination, source); // copy string source to destination
To restrict the number of characters to copy use strncpy. This is useful as it prevents copying more characters than the destination strings range.
strncpy(destination, source, 6); // copy up to 6 characters from source to destination
To append one string to the end of another string use strcat i.e., abbreviation for string concatenation:
strcat(destination, source); // append source string to the end of the destination string
To compare two strings use strcmp i.e., abbreviation for string compare.
if(strcmp(str, "Arduino") == 0)
// do something if the variable str is equal to "Arduino"
An array of characters is used to display the text in the Arduino environment. A string comprises of various characters followed by a null (it has a value equal to ‘0’). The null isn’t shown, however it is expected to show the end of a string.
Splitting Comma- Separated Text into Groups
You are given a string with at least two bits of data separated by commas or any other separator. You have to divide (split) the string so you can utilize each part of the string individually.
The following sketch displays the text present between ever comma:
/*
* SplitSplit sketch
* split a comma-separated string
*/
String message= "Peter,Paul,Mary"; // an example string
int commaPosition; // the position of the next comma in the string
void setup()
{
Serial.begin(9600);
}
void loop()
{
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);
delay(5000);
}
The Serial Monitor will display the following text:
Peter,Paul,Mary
Peter
Paul
This above sketch utilizes String functions to get the text from between the commas. The line of code written below:
commaPosition = message.indexOf(,’');
finds the position (index) of the first comma used in the String named message and sets the value of the variable commaPosition equivalent to it. If there is no comma found in the string, the value of commaPosition will be set to -1. If a comma is found in the string then to display the text from the start of the string to the comma's position, the substring function is used. The text that was displayed is taken out from the string message with the following code:
message = message.substring(commaPosition+1, message.length());
substring results in a string having text beginning from commaPosition + 1 i.e., the next position after the comma up to the end of the string message. This outcomes in that message having only the text after the first comma. This is done repeatedly until no more commas are left in the string i.e., commaIndex will become – 1.
The low-level functions that belong to the standard C library can also be used if you are an expert programmer. The sketch written below has the same functionality as the previous one using Arduino strings:
/*
* SplitSplit sketch
* split a comma-separated string
*/
const int MAX_STRING_LEN = 20; // set this to the largest string you'll 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);
}
void loop()
{
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);
if(strcmp(str, "Paul") == 0)
Serial.println("found Paul");
}
delay(5000);
}
The fundamental functionality originates from the function known as strtok_r i.e., the version’s name of strtok that accompanies the Arduino compiler. You pass the string you need to tokenize i.e., separate into individual pieces, to the function strtok_r when you call it for the first time. However, whenever the function strtok_r finds a new token it overwrites the characters in this string, so as shown in the example above it's ideal to pass a copy of the string. Every call that follows utilizes a NULL to inform the function that it should go to the following token. In the above example, every token is compared to a target string i.e., (“Paul”), and is printed to the
serial port.
Converting a Number to a String
You have to convert a given number to a string, possibly to represent the number on an LCD or some other display.
The variable String will change numbers to character strings spontaneously. You can utilize the contents of the variable or literal values. For instance, the code written below will work:
String myNumber = 1234;
So will this code:
int value = 127
String myReadout = "The reading was ";
myReadout.concat(value);
Or the following code:
int value = 127;
String myReadout = "The reading was ";
myReadout += value;
If and only if you are changing a number to show on a serial device or an LCD as a text, the easiest approach is to utilize Serial libraries and LCD's built-in conversion ability. However, maybe you are utilizing a device that does not have built-in assistance or want to change the number to a string.
When the numerical values are assigned to a String variable they are automatically converted by the class called Arduino String class. You can use the addition (+) operator or the concat function if you want to join the numeric values at the end of some string.
The piece of code written below gives a number having a value equal to 13:
int number = 12;
number += 1;
When we use the data type String, we get the following result:
String textNumber = 12
textNumber += 1;
In the above code textNumber is a string having text “121”.
When the String class was not introduced, the function itoa or ltoa was usually used to determine the Arduino code. The name ‘itoa’ originates from “integer to ASCII” and the name ‘ltoa’ originates from “long to ASCII”. The String version explained before is simpler to use, however, if you need to know the code that uses ltoa or itoa, the following will help you understand it:
The following functions require three parameters. First, the value to be converted. Second, the buffer that will store the resultant string. And third, the number base i.e., 2 for binary, 10 for decimal, and 16 for hex.
The conversion of numeric values using ltoa is explained in the code written below:
/*
* NumberToString
* Creates a string from a given number
*/
void setup()
{
Serial.begin(9600);
}
char buffer[12]; // long data type has 11 characters (including the
// minus sign) and a terminating null
void loop()
{
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");
delay(1000);
}
It is very important for the buffer being used in the sketch program to be big enough such that it’s capable of handling every character which is being used in the string. Seven character buffer i.e., five digits, a ‘-’ sign, and an ending zero, for a 16 – bit integer. Twelve character buffer i.e., ten digits, a ‘-’ sign, and an ending zero, for a 32 – bit long integer. If you exceed the limit of buffer no warning is given; and this is such a bug that can cause a wide range of abnormal indications, as the overflow will manipulate some other pieces of memory that might be utilized by your program. So the least demanding approach to deal with this is to use a twelve character buffer and always prefer to in light of the fact that it can handle both 16 – bit and 32 – bit values.
Converting a String to a Number
You have to change a string to a number. Maybe you have got a value in the form of a string over a communication connection and you have to utilize this as a floating-point or integer value.
There are various approaches to understand and solve this. As each character is received it can be converted on the fly if the string is received as serial data. Refer to the preceding topics for an example of the most effective method to do this utilizing the serial port.
One more way to convert the text strings that represent numbers is to utilize C language's conversion functions. For int variable use the
function atoi and for long variable use the function atol.
The following piece of code ends the approaching digits on any character that isn’t a digit or if there is no space left in the buffer:
int blinkRate; // blink rate stored in 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 loop()
{
if( Serial.available())
{
char ch = Serial.read();
if(index < 5 && ch >= '0' && ch <= '9'){
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
blinkRate = atoi(strValue); // use atoi to convert the string to an int
index = 0;
}
}
blink();
}
The indistinctly named functions atoi i.e., for ASCII to int and atoll i.e., for ASCII to long are used to change a string into integer or long. If you want to use them then before calling the conversion function, you have to get and then store the whole string in a character array.
The above code will make a character array i.e., strValue that can store five digits. As there must be space to store the terminating NULL, so it is declared as char strValue [6]. Digits are stored in the array from Serial.read till it receives a character that is an invalid digit. The array is ended with a NULL and the character array is converted into the variable blinkRate by calling the atoi function.
The value stored in blinkRate is used by a function named blink. The previous sections show the function of ‘blink.’
This example creates a character array, as opposed to utilizing the class String. At the time of this composition, the Arduino String library didn’t serve the purpose of converting strings into numbers.
Transforming the Lines of Code into Blocks
You should understand how you will be able to write more functions in your code. And also understand the right measure of functionality that you need to go into your functions. Additionally, you should be aware of designing the general structure of a code.
The activities performed by your sketch are sort out by functions into the functional blocks. Functions pack features into clearly described inputs i.e., data provided to a function and outputs i.e., data given as a result by a function that keeps it simpler to maintain, structure, and reuse the code. setup and loop are two functions in every Arduino sketch that are already well known by you. To create a function you declare its return type i.e., the data it gives as a result, the name of the function, and any parameters i.e., values that will be passed in the function when it is called. However, parameters are optional. Below given is a basic function that causes the LED to blink. The following code has no parameters and it returns nothing. The keyword void, which was written before the function, shows that it will not return anything.
// blink an LED once
void blink1()
{
digitalWrite(13,HIGH); // turn the LED on
delay(500); // wait 500 milliseconds
digitalWrite(13,LOW); // turn the LED off
delay(500); // wait 500 milliseconds
}
The piece of code written below has a parameter i.e., int count that shows how frequently the LED will blink:
// 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(13,HIGH);
delay(500);
digitalWrite(13,LOW);
delay(500);
count = count -1; // decrement count
}
}
This block of code's main function is to double-check the counter’s value to see if it’s ‘0’ or some other value and take appropriate actions. For instance, in the scenario where the value is something other than ‘0,’ the program blinks the LED on the Arduino board and, consequently, reduces the value on the counter by ‘1.’ This process is repeated until the counter’s value is brought to ‘0.’
The following is a code that accepts a parameter. It also gives some value as a result. How many times the LED blinks i.e., it is turned on and off is determined by this parameter. The LED keeps on blinking till we press a button. This value is then returned:
/*
As soon as the program starts executing, the LED begins blinking.
When a ‘switch’ is paired with ‘pin 2,’ the blinking will immediately stop after this switch is triggered.
The final result is that the program prints out the total number of blinks the LED went through until the switch was pressed.
*/
const int ledPin = 13;
// This is the LED’s output pin
const int inputPin = 2;
// This is the Input pin which is connected to the switch
void setup()
{
pinMode(ledPin, 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);
}
// blink an LED using the given delay period
// return the number of times the LED flashed
int blink3(int period)
{
int result = 0;
int switchVal = HIGH; //with pull-ups, this will be high when switch is up
while(switchVal == HIGH) // repeat this loop until switch is
pressed
// (it will go low when pressed)
{
digitalWrite(13,HIGH);
delay(period);
digitalWrite(13,LOW);
delay(period);
result = result + 1; // increment the count
switchVal = digitalRead(inputPin); // read input value
}
// here when switchVal is no longer HIGH because the switch is pressed
return result; // this value will be returned
}
Discussion:
The code in this problem’s solution shows the three types of a function call that you’ll encounter.
The following function blink1 does not have any parameter or return value.
void blink1()
{
// implementation code goes here...
}
The next function blink2 has one parameter yet does not have any return value:
void blink2(int count)
{
// implementation code goes here...
}
The third function blink3 has both i.e., a parameter and a return value as shown below:
int blink3(int period)
{
// implementation code goes here...
}
If void is written before the name of a function it shows that the respective function has no return type. Other than this all the functions have some return types that they mentioned before their name. When you declare a function a semicolon is not required at the end of the parenthesis. However, the semicolon plays an important role when you call a specific function.
Most of the functions that we demonstrate are of similar datatypes. For instance, consider the following example;
int sensorPercent(int pin)
{
int percent;
val = analogRead(pin); // read the sensor (ranges from 0 to 1023)
percent = map(val,0,1023,0,100); // percent will range from 0 to 100.
return percent;
}
The name of the function is sensorPercent. A pin number is passed as a parameter in this function and then returns a value i.e., percent. The int written before the name of the function indicates that the function will return an integer. While declaring functions keep in mind to select the proper return type according to what action the function has to perform. For the above-mentioned function, int data type is appropriate as it returns a number between 0 and 100.
The pin is a parameter of sensorPercent. The value that is passed to the function is assigned to the pin when the function is called.
The code that is written inside the parenthesis (the body of the
function) executes the task you need, it reads the value from an analog input pin and afterward depicts the value to a percentage. In the previous example, the variable named percent temporarily holds the percentage. The value stored in the temporary variable i.e., percent is returned to the calling function using the following statement:
return percent;
We can also get similar functionality without the utilization of a temporary variable:
int sensorPercent(int pin)
{
val = analogRead(pin); // read the sensor (ranges from 0 to 1023)
return map(val,0,1023,0,100); // percent will ranges from 0 to 100.
}
The following code shows that how to call a function:
// print the percent value of 6 analog pins
for(int sensorPin = 0; sensorPin < 6; sensorPin++)
{
Serial.print("Percent of sensor on pin ");
Serial.print(sensorPin);
Serial.print(" is ");
int val = sensorPercent(sensorPin);
Serial.print(val);
}
Returning More Than One Value from a Function
You have to return at least two values from a given function. One of these forms of the function returns just one value or no value at all. However, at times you are required to alter or return more values.
There are different approaches to solve this problem. The simplest to comprehend is to have the function alter some global variables
and to not really return any value 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;
}
By utilizing the global variables, the swap function changes the two values. Global variables are available throughout the program and can be changed by anything. Moreover, they are very easy to
understand. However, they are not used by expert programmers since it's very easy to modify the value of these variables or have a function quit working because you altered the type or name of this variable somewhere else in the sketch.
A more secure and more exquisite approach is to pass a reference to those values that you want to change and let the function modify the values by using the references. As shown below:
/*
functionReferences sketch
demonstrates returning more than one value by passing references
*/
void swap(int &value1, int &value2); // functions with references must be
declared before use
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);
swap(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 swap(int &value1, int &value2)
{
int temp;
temp = value1;
value1 = value2;
value2 = temp;
}
The functions having parameters that are described in the preceding sections and the swap function both are similar. However, the symbol ‘&’ (ampersand) shows that the parameters are references. This means that the value of the variable that is given when the function is called is changed when the values inside the function change. This happens by first executing the code given in the above Solution and then checking that the parameters are swapped. Afterward, the code is modified by eliminating all the four ampersands. Two of them are present at the top of the declaration and the other two at the end.
The two lines that are changed should be as follows:
void swap(int value1, int value2); // functions with references must be declared
before use
...
void swap(int value1, int value2)
By running the code, we see that the values are not swapped. The modifications that are done inside the function are local and when the function returns, these changes are lost.
Problem
You need to execute a piece of code if and only if a specific condition is valid. For instance, if a switch is pressed you might need to turn on a LED or if the value of analog is larger than the threshold.
Solution
The piece of code written below utilizes the wiring shown in the preceding sections:
/*
Pushbutton sketch
a switch connected to pin 2 lights the LED on pin 13
*/
const int ledPin = 13; // choose the pin for the LED
const int inputPin = 2; // choose the input pin (for a pushbutton)
void setup() {
pinMode(ledPin, OUTPUT); // declare LED pin as output
pinMode(inputPin, INPUT); // declare pushbutton pin as input
}
void loop(){
int val = digitalRead(inputPin); // read input value
if (val == HIGH) // check if the input is HIGH
{
digitalWrite(ledPin, HIGH); // turn LED on if switch is pressed
}
}
Discussion
To test the value of digitalRead, the if statement is used. The if statement should have a test written between the parenthesis that must be true or false. In this given problem’s Solution, its val == High, and if the expression is true only then the if statement is executed. A block of code comprises of all the code written inside the parenthesis and if the parenthesis is not used, then the block comprises of the following executable statement ended by a semicolon.
Use the if… else statement, if you have to do a certain thing if the statement is true and another if the statement is false:
/*
Pushbutton sketch
a switch connected to pin 2 lights the LED on pin 13
*/
const int ledPin = 13; // choose the pin for the LED
const int inputPin = 2; // choose the input pin (for a
pushbutton)
void setup() {
pinMode(ledPin, OUTPUT); // declare LED pin as output
pinMode(inputPin, INPUT); // declare pushbutton pin as input
}
void loop(){
int val = digitalRead(inputPin); // read input value
if (val == HIGH) // check if the input is HIGH
{
// do this if val is HIGH
digitalWrite(ledPin, HIGH); // turn LED on if switch is pressed
}
else
{
// else do this if val is not HIGH
digitalWrite(ledPin, LOW); // turn LED off
}
}
Problem
You want a piece of code to run until a given condition is true.
Solution
Until a condition is true, a while loops execute the code repeatedly.
while(analogRead(sensorPin) > 100)
{
flashLED(); // call a function to turn an LED on and off
}
The above code is written within the parenthesis of while the loop will execute until the given condition is true i.e., value of analogRead is greater than 100. When a value surpasses a threshold, it could blink a LED as an obvious warning. When the analogRead is greater
than 100, the led blinks continuously. Otherwise, the LED is off if the value is less or equal to 100.
Parentheses fix the limit of a code block that is to be executed within a loop. Only the first line of the code in executed repeatedly if the parenthesis are not used.
while(analogRead(sensorPin) > 100)
flashLED(); // line immediately following the loop expression is executed Serial.print(analogRead(sensorPin)); // this is not executed until after
// the while loop finishes!!!
The ‘do… while’ loop is just like the while loop, however, the statements of the code are run once before checking the condition. You can use do… while loop when you want at least a single execution of the code, regardless of whether the condition is false:
do
{
flashLED(); // call a function to turn an LED on and off
}
while (analogRead(sensorPin) > 100);
The above code will cause the LED to blink at least a single time even if the condition is false. And the LED will keep blinking until the value from analogRead is greater than 100. The LED will blink only once if the value is not greater than 100. A battery – circuit could be made using this code. The LED's persistent blinking will show that the battery is fully charged and if it blinks every other second, this will show that the circuit is active.
You need to execute at least one statement a specific number of times. The ‘while’ loop and ‘for’ loop are almost the same. However, in the ‘for’ loop, you have more command over the beginning and terminating conditions.
In the code lines demonstrated below, the program tells the user the
‘i’ variable’s value as it went through the ‘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);
}
}
We get the following result from the above sketch:
for(int i=0; i < 4; i++)
0
1
2
3
Discussion
Generally, the ‘for’
loop consists of three portions. First is the initialization, second is the conditional test and third is iteration i.e., an expression that is executed toward the finish of each pass through the loop. A semicolon distinguishes all these three parts. In the above solution's code, variable i is initialized to ‘0’ i.e., int i = 0. The condition i.e., i < 4 checks if the variable i is less than 4. And the iteration i.e., i ++ increments the value of the variable i by 1 after a single iteration.
A for loop can either create a new variable that is restricted within the for loop or it can use an existing variable. The following sketch shows the use of an already created variable:
int j;
Serial.println("for(j=0; j < 4; j++ )");
for(j=0; j < 4; j++ )
{
Serial.println(j);
}
This code is nearly similar to the previous code. However, the only difference is in the initialization part i.e., the variable j does not have int keyword written before it, because it is already defined outside the loop. Bothe these codes get the same outputs as shown below:
for(j=0; i < 4; i++)
0
1
2
3
If you want to eliminate the initialization part totally you can just utilize a variable defined before. The following code begins the loop where j has a value equal to 1.
int j = 1;
Serial.println("for( ; j < 4; j++ )");
for( ; j < 4; j++ )
{
Serial.println(j);
}
The above code displays the following output:
for( ; j < 4; j++)
1
2
3
You control the loop termination in the conditional test. In the preceding example, when the variable's value exceeds 4 the loop ends because the condition is no longer true.
The code written below checks the value of the variable whether it is equal to 4 or less than 4. It displays the numbers from 0 to 4:
Serial.println("for(int i=0; i <= 4; i++)");
for(int i=0; i <= 4; i++)
{
Serial.println(i);
}
The iteration statement that is the third part of the for loop gets executed toward the finish of each pass through the loop. This can be any legitimate statement of C or C++. The below given code increments the value of variable i by 2 after each iteration:
Serial.println("for(int i=0; i < 4; i+= 2)");
for(int i=0; i < 4; i+=2)
{
Serial.println(i);
}
This code prints only two values i.e., 0 and 2.
The iteration statement can be utilized to get the values from high to low, for example in the following code, from 3 to 0:
Serial.println("for(int i=3; i > = 0 ; i--)");
for(int i=3; i > = 0 ; i--)
{
Serial.println(i);
}
Just like the other parts, the iteration statement can also be left empty. But in mind to put the semicolons in between to separate the three parts of a ‘for’ loop.
The following piece of code shows that the for loop does not increment or decrement the value of variable i until an input pin is high and this is dine in the if statement after Serial.print:
Serial.println("for(int i=0; i < 4; )");
for(int i=0; i < 4; )
{
Serial.println(i);
if(digitalRead(inPin) == HIGH);
i++; // only increment the value if the input is high
}
Problem
Based on some conditions that you are testing you need to end a loop early.
You will use the code written below:
while(analogRead(sensorPin) > 100)
{
if(digitalRead(switchPin) == HIGH)
{
break; //exit the loop if the switch is pressed
}
flashLED(); // call a function to turn an LED on and off
}
Discussion
This code is like the one that uses while loops, however, this code uses a break statement if the loop needs to be terminated if the digital pin is high. For instance, the LED will stop blinking and the loop will terminate regardless of whether the condition in the while loop is true, if the switch is connected to the pins.