Here is a quick explanation of all the standard instructions supported by the Arduino language.
For a more detailed reference, see the Arduino “Language Reference” page.
An Arduino sketch runs in two parts:
void
setup
()
This is where you set things up that have to be done once before the loop starts running, and then don’t need to happen again.
void
loop
()
This contains the main code of your sketch. It contains a set of instructions that get repeated over and over until the board is switched off.
Arduino includes a number of symbols to delineate lines of code, comments, and blocks of code.
Every instruction (line of code) is terminated by a semicolon. This syntax lets you format the code freely. You could even put two instructions on the same line, as long as you separate them with a semicolon. (However, this would make the code harder to read.)
Example:
delay
(
100
);
These are used to mark blocks of code. For example, when you write code for the loop()
function, you have to use a curly brace before and after the code.
Example:
void
loop
()
{
Serial
.
println
(
"ciao"
);
}
These are portions of text ignored by the Arduino microcontroller, but are extremely useful to explain to others (and to remind yourself) what a piece of code does.
There are two styles of comments in Arduino:
// single-line: this text is ignored until the end of the line
/* multiple-line:
you can write
a whole poem in here
*/
Arduino includes a set of predefined keywords with special values.
HIGH
and LOW
are used, for example, when you want to turn on or off an Arduino pin. INPUT
and OUTPUT
are used to set a specific pin to be either an input or an output.
true
and false
are used to test whether a condition or expression is true or false. They are used primarily with comparison operators.
Variables are named areas of the Arduino’s memory where you can store data. Your sketch can use and manipulate this data by referring to it by the variable name. As the word variable suggests, variables can be changed as many times as you like.
Because Arduino is a very simple microcontroller, when you declare a variable, you have to specify its type. This means telling the microcontroller the size of the value you want to store.
Following are the datatypes that are available.
Can have one of two values: true
or false
.
Holds a single character, such as the letter A. Like any computer, Arduino stores it as a number, even though you see text. When chars are used to store numbers, they can hold values from –128 to 127. A char occupies 1 byte of memory.
There are two major sets of characters available on computer systems: ASCII and UNICODE. ASCII is a set of 127 characters that was used for, among other things, transmitting text between serial terminals and time-shared computer systems such as mainframes and minicomputers. UNICODE is a much larger set of values used by modern computer operating systems to represent characters in a wide range of languages. ASCII is still useful for exchanging short bits of information in languages such as Italian or English that use Latin characters, Arabic numerals, and common typewriter symbols for punctuation and the like.
Holds a number between 0 and 255. Like a char, a byte uses only 1 byte of memory. Unlike chars, a byte can store only positive numbers.
Uses 2 bytes of memory to represent a number between –32,768 and 32,767. The int
is the most common datatype used in Arduino. If you are unsure of what datatype to use, try an int.
Like int, uses 2 bytes of memory, but the unsigned prefix means that it can’t store negative numbers, so its range goes from 0 to 65,535.
This is twice the size of an int and holds numbers from –2,147,483,648 to 2,147,483,647.
Unsigned version of long; it goes from 0 to 4,294,967,295.
This is quite big and can hold floating-point values, which is a fancy way of saying that you can use a float to store numbers with a decimal point. A float will eat up 4 bytes of your precious RAM, and the functions that can handle them use up a lot of code memory as well, so use floats only when you need to.
Double-precision floating-point number, with a maximum value of 1.7976931348623157 x 10308. Wow, that’s huge!
A set of ASCII characters used to store textual information (you might use a string to send a message via a serial port, or to display on an LCD display). For storage, they use 1 byte for each character in the string, plus a null character (1 byte) at the end to tell Arduino that it’s the end of the string. The following are equivalent:
char
string1
[]
=
"Arduino"
;
// 7 chars + 1 null char
char
string2
[
8
]
=
"Arduino"
;
// Same as above
A list of variables that can be accessed via an index. They are used to build tables of values that can easily be accessed. For example, if you want to store different levels of brightness to be used when fading an LED, you could create six variables called light01
, light02
, and so on. Better yet, you could use a simple array like this:
int
light
[
6
]
=
{
0
,
20
,
50
,
75
,
100
};
The word array is not actually used in the variable declaration: the symbols [] and {} do the job.
Arrays are ideal when you want to do the same thing to a whole lot of pieces of data, because you can write what you need to do once and then perform it on each variable in the array simply by changing the index—for example, using a for
loop.
Variables in Arduino have a property called scope. Variables can be local or global, depending on where they are declared.
A global variable is one that can be seen (and used) by every function in a program. Local variables are visible only to the function in which they are declared.
When programs start to get larger and more complex, local variables are a useful way to ensure that each function has access to its own variables. This prevents programming errors when one function inadvertently modifies variables used by another function. Variables that must be used by multiple functions can be global.
In the Arduino environment, any variable declared outside of a function (e.g., setup()
, loop()
, or your own functions), is a global variable. Any variable declared within a function is local (and accessible) only within that function.
It is also sometimes handy to declare and initialize a variable inside a for
loop. This creates a variable that can only be accessed from inside the for
loop braces. In fact, any time a variable is declared within curly braces, it is local only within that block of code.
Arduino includes keywords for controlling the logical flow of your sketch.
This structure makes decisions in your program. if
must be followed by a question specified as an expression contained in parentheses. If the expression is true, whatever follows will be executed. If it’s false, the block of code following else
will be executed. The else
clause is optional.
Example:
if
(
val
==
1
)
{
digitalWrite
(
LED
,
HIGH
);
}
Lets you repeat a block of code a specified number of times.
Example:
for
(
int
i
=
0
;
i
<
10
;
i
++
)
{
Serial
.
(
"ciao"
);
}
The if
statement is like a fork in the road for your program. switch case is like a massive roundabout. It lets your program take a variety of directions depending on the value of a variable. It’s quite useful to keep your code tidy as it replaces long lists of if
statements.
It’s important to remember the break
statement at the end of each case
, or else Arduino will execute the instructions of the following cases, until it reaches a break
or the end of the switch case.
Example:
switch
(
sensorValue
)
{
case
23
:
digitalWrite
(
13
,
HIGH
);
break
;
case
46
:
digitalWrite
(
12
,
HIGH
);
break
;
default
:
// if nothing matches this is executed
digitalWrite
(
12
,
LOW
);
digitalWrite
(
13
,
LOW
);
}
Similar to if
, this executes a block of code if a certain condition is true. However, if
executes the block only once, whereas while
keeps on executing the block as long as the condition is true.
Example:
// blink LED while sensor is below 512
sensorValue
=
analogRead
(
1
);
while
(
sensorValue
<
512
)
{
digitalWrite
(
13
,
HIGH
);
delay
(
100
);
digitalWrite
(
13
,
HIGH
);
delay
(
100
);
sensorValue
=
analogRead
(
1
);
}
Just like while
, except that the code is run before the condition is evaluated. This structure is used when you want the code inside your block to run at least once before you check the condition.
Example:
do
{
digitalWrite
(
13
,
HIGH
);
delay
(
100
);
digitalWrite
(
13
,
HIGH
);
delay
(
100
);
sensorValue
=
analogRead
(
1
);
}
while
(
sensorValue
<
512
);
This term lets you break out of a while
or for
loop even if the loop condition says to go on looping. It’s also used to separate the different sections of a switch case statement.
Example:
// blink LED while sensor is below 512
do
{
// Leaves the loop if a button is pressed
if
(
digitalRead
(
7
)
==
HIGH
)
break
;
digitalWrite
(
13
,
HIGH
);
delay
(
100
);
digitalWrite
(
13
,
LOW
);
delay
(
100
);
sensorValue
=
analogRead
(
1
);
}
while
(
sensorValue
<
512
);
When used inside a loop, continue
lets you skip the rest of the code inside it and force the condition to be tested again.
Example:
for
(
light
=
0
;
light
<
255
;
light
++
)
{
// skip intensities between 140 and 200
if
((
x
>
140
)
&&
(
x
<
200
))
continue
;
analogWrite
(
PWM
pin
,
light
);
delay
(
10
);
}
continue
is similar to break
, but break
leaves the loop, while continue
goes on with the next repetition of the loop.
Stops running a function and returns to whatever called the function. You can also use this to return a value from inside a function.
For example, if you have a function called computeTemperature()
and you want to return the result to the part of your code that invoked the function, you would write something like this:
int
computeTemperature
()
{
int
temperature
=
0
;
temperature
=
(
analogRead
(
0
)
+
45
)
/
100
;
return
temperature
;
}
You can use Arduino to make complex calculations using a special syntax. + and – work just like you’ve learned in school; multiplication is represented with an *, and division with a /.
There is an additional operator called modulo (%), which returns the remainder of an integer division.
Just as you learned in algebra, you can use as many levels of parentheses as you wish to to group expressions the proper way. Contrary to what you might have learned in school, square brackets and curly braces are not used for arithmetic forumulas because they are reserved for other purposes (array indexes and blocks, respectively).
Example:
a
=
2
+
2
;
light
=
((
12
*
sensorValue
)
-
5
)
/
2
;
remainder
=
7
%
2
;
// returns 1
When you specify conditions or tests for if
, while
, and for
statements, these are the operators you can use:
== |
Equal to |
!= |
Not equal to |
< |
Less than |
> |
Greater than |
<= |
Less than or equal to |
>= |
Greater than or equal to |
When testing for equality, be very careful to use the == comparison operator and not the = assignment operator, or your program will not behave the way you expect.
These are used when you want to combine multiple conditions. For example, if you want to check whether the value coming from a sensor is between 5 and 10, you would write this:
if ( (sensor => 5) && (sensor <=10) )
There are three Boolean operators: and, represented with &&
; or, represented with ||
; and finally not, represented with !
.
These are special operators used to make code more concise for some very common operations like incrementing a value.
For example, to increment value
by 1, you would write:
value
=
value
+
1
;
but using a compound operator, this becomes:
value
++
;
It’s perfectly fine not to use these compound operators, but they are so common that, as a beginner, you will have a hard time learning from examples if you don’t understand these operators.
––
and ++
)These operators increment or decrement a value by 1. Be careful—they work both in front of or behind a variable, but they have a very subtle difference: if you write i
++, this first increments i
by 1 and then evaluates to the equivalent of i + 1
, while ++i
first evaluates to the value of i
and then increments i
. The same applies to ––.
Similar to ++ and ––, but these allow you to increment and decrement by values other than 1, and also allow multiplication and division. The following two expressions are equivalent:
a
=
a
+
5
;
a
+=
5
;
One of the main jobs of Arduino is to input information from sensors and to output values to actuators. You’ve already seen some of these in the example programs throughout the book.
(Re)configure a digital pin to behave either as an input or an output.
Example:
pinMode
(
7
,
INPUT
);
// turns pin 7 into an input
Forgetting to set pins to outputs using pinMode()
is a common cause of faulty or nonfunctioning output.
Although typically used in setup()
, pinMode()
can be used in a loop as well if you need to change the pin’s behaviour.
(When a function name is used in text, it is often written with empty parentheses at the end to indicate that a function is being discussed.)
Turns a digital pin either HIGH or LOW. Pins must be explicitly made into an output using pinMode()
before digitalWrite()
will have the expected effect.
Example:
digitalWrite
(
8
,
HIGH
);
// sets digital pin 8 to 5 V
Note that while HIGH or LOW usually correspond to on and off, respectively, this depends on how the pin is used. For example, an LED connected between 5V and a pin will turn on when that pin is LOW and turn off when the pin is HIGH.
Reads the state of an input pin, and returns HIGH if the pin senses some voltage or LOW if there is no voltage applied.
Example:
val
=
digitalRead
(
7
);
// reads pin 7 into val
Reads the voltage applied to an analogue input pin and returns a number between 0 and 1023 that represents the voltages between 0 and 5 V.
Example:
val
=
analogRead
(
0
);
// reads analog input 0 into val
Changes the PWM rate on one of the PWM pins. pin
can only be a pin that supports PWM, that is, pins 3, 5, 6, 9, 10, or 11 on the Arduino Uno (different Arduino boards may support PWM on different pins). value
must be a number between 0 and 255. You can think of value
to represent the average amount of power Arduino will deliver, where a value
of zero corresponds to fully off, while a value
of 255 corresponds to fully on.
Example:
analogWrite
(
9
,
128
);
// Dim an LED on pin 9 to 50%
A value
of 0 sets the output fully LOW, while a value
of 255 sets an output fully HIGH.
Sends data to a shift register, devices that are used to expand the number of digital outputs. This protocol uses one pin for data and one for clock. bitOrder
indicates the ordering of bytes (least significant or most significant) and value
is the actual data to be sent out.
Example:
shiftOut
(
dataPin
,
clockPin
,
LSBFIRST
,
255
);
Measures the duration of a pulse coming in on one of the digital inputs. This is useful, for example, to read some infrared sensors or accelerometers that output their value as pulses of changing duration.
Example:
time
=
pulsein
(
7
,
HIGH
);
// measures the time the next
// pulse stays high
Arduino includes functions for measuring elapsed time and also for pausing the sketch.
Returns the number of milliseconds that have passed since the sketch started.
Example:
duration
=
millis
()
-
lastTime
;
// computes time elapsed since "lastTime"
Pauses the program for the amount of milliseconds specified.
Example:
delay
(
500
);
// stops the program for half a second
Pauses the program for the given amount of microseconds.
Example:
delayMicroseconds
(
1000
);
// waits for 1 millisecond
Arduino includes many common mathematical and trigonometric functions:
Returns the smaller of x
and y
.
Example:
val
=
min
(
10
,
20
);
// val is now 10
Returns the larger of x
and y
.
Example:
val
=
max
(
10
,
20
);
// val is now 20
Returns the absolute value of x
, which turns negative numbers into positive. If x
is 5, it will return 5, but if x
is –5, it will still return 5.
Example:
val
=
abs
(
-
5
);
// val is now 5
Returns the value of x
, constrained between a
and b
. If x
is less than a
, it will just return a
, and if x
is greater than b
, it will just return b
.
Example:
val
=
constrain
(
analogRead
(
0
),
0
,
255
);
// reject values bigger than 255
Maps a value in the range fromLow
and maxLow
to the range toLow
and toHigh
. Very useful to process values from analogue sensors.
Example:
val
=
map
(
analogRead
(
0
),
0
,
1023
,
100
,
200
);
// maps the value of
// analog 0 to a value
// between 100 and 200
Returns the result of raising a number (base
) to a value (exponent
).
Example:
double
x
=
pow
(
y
,
32
);
// sets x to y raised to the 32nd power
Returns the square root of a number.
Example:
double
a
=
sqrt
(
1138
);
// approximately 33.73425674438
Returns the sine of an angle specified in radians.
Example:
double
sine
=
sin
(
2
);
// approximately 0.90929737091
Returns the cosine of an angle specified in radians.
Example:
double
cosine
=
cos
(
2
);
// approximately -0.41614685058
Returns the tangent of an angle specified in radians.
Example:
double
tangent
=
tan
(
2
);
// approximately -2.18503975868
If you need to generate random numbers, you can use Arduino’s pseudorandom number generator. Random numbers are useful if you want your project to behave differently each time it’s used.
Resets Arduino’s pseudorandom number generator. Although the distribution of the numbers returned by random()
is essentially random, the sequence is predictable. So, you should reset the generator to some random value. A good seed is a value read from an unconnected analogue input, as an unconnected pin will pick up random noise from the surrounding environment (radio waves, cosmic rays, electromagnetic interference from cell phones and fluorescent lights, etc.) and so will be unpredictable.
Example:
randomSeed
(
analogRead
(
5
));
// randomize using noise from pin 5
Returns a pseudorandom long
integer value between min
and max – 1
. If min
is not specified, the lower bound is 0.
long
randnum
=
random
(
0
,
100
);
// a number between 0 and 99
long
randnum
=
random
(
11
);
// a number between 0 and 10
As you saw in Chapter 5, you can communicate with devices over the USB port using a serial communication protocol. Following are the serial functions.
Prepares Arduino to begin sending and receiving serial data. You’ll generally use 9600 baud (bits per second) with the Arduino IDE serial monitor, but other speeds are available, usually no more than 115,200 bps. The specific baud rate doesn’t matter much, as long as both sides agree and use the same rate.
Example:
Serial
.
begin
(
9600
);
Sends some data to the serial port. The encoding is optional; if not supplied, the data is treated as much like plain text as possible.
Examples (note that the final example uses Serial.write
):
Serial
.
(
75
);
// Prints "75"
Serial
.
(
75
,
DEC
);
// The same as above.
Serial
.
(
75
,
HEX
);
// "4B" (75 in hexadecimal)
Serial
.
(
75
,
OCT
);
// "113" (75 in octal)
Serial
.
(
75
,
BIN
);
// "1001011" (75 in binary)
Serial
.
write
(
75
);
// "K" (the letter K happens
// to be 75 in the ASCII set)
Same as Serial.print()
, except that it adds a carriage return and linefeed (
) as if you had typed the data and then pressed Return or Enter.
Examples:
Serial
.
println
(
75
);
// Prints "75 "
Serial
.
println
(
75
,
DEC
);
// The same as above.
Serial
.
println
(
75
,
HEX
);
// "4B "
Serial
.
println
(
75
,
OCT
);
// "113 "
Serial
.
println
(
75
,
BIN
);
// "1001011 "
Returns how many unread bytes are available on the serial port for reading via the read()
function. After you have read()
everything available, Serial.available()
returns 0 until new data arrives on the serial port.
Example:
int
count
=
Serial
.
available
();
Fetches 1 byte of incoming serial data.
Example:
int
data
=
Serial
.
read
();
Because data may arrive at the serial port faster than your program can process it, Arduino keeps all the incoming data in a buffer. If you need to clear the buffer and let it fill up with fresh data, use the flush()
function.
Serial
.
flush
();
When somebody thinks about Arduino, the first board that comes to mind is the Arduino UNO, but over the years we have created a whole family of boards of different shapes and functionality. Let’s look at the main family members and their features.
The Arduino UNO is the timeless classic; it’s very robust and it’s ideal for learning and prototyping. We still recommend it for beginners and learners. It’s hard to break it, and there are a ton of shields and libraries compatible with it. The main drawbacks are the limitations of the 8-bit processor with very little RAM and inability to run on battery for a long time.
Right after the introduction of the UNO, people started to request boards with more inputs and outputs, and the Arduino Mega was born. It became quite popular as the “motherboard” for 3D printers and other devices where you need a lot of I/O and more memory than the UNO.
As people progress in their prototyping effort, they often need to go smaller, and this is where the Arduino Nano comes in. The first Nano was designed to “shrink” the original UNO format into something you could put in a breadboard and use to build small, portable devices. The classic Nano suffers from some of the limitations of the original UNO, so for newer projects we recommend you take a look at the Arduino Nano Every. It’s powered by a much more powerful 8 bit processor (the latest generation of AVR processors) with more RAM, program memory and computing power while still being compatible with almost all of the 8-bit code. One further advantage of the Every is that all the parts are mounted on top of the PCB so you can solder it directly on another PCB without using extra pin-header connectors. It’s also the cheaper member of the Nano family, so it’s a good way to get started on a budget.
The Nano family has also recently branched out to 32-bit arm processors: the Nano 33 IoT provides a fast arm processor coupled with a WiFi/Bluetooth module that makes it easy to build connected projects, and the Arduino 33 Nano BLE Sense, a powerful Bluetooth board packed with sensors that has become quite popular with people who run Artificial Intelligence algorithms on Microcontrollers (TinyML).
The Internet of Things is a very popular topic, and to make it simpler for makers to build robust connected devices, we introduced the MKR Family, a series of 32-bit arm boards with the same footprint but available with all the most popular types of connectivity. They range from WiFi to GSM, from LoRA to Narrowband IOT and more. These boards are designed to run on battery and provide a LiPO battery charger along with software libraries to take advantage of the “Low Power” modes of the processor. Finally one interesting feature of the MKRs is the presence of a “Crypto Chip”, a small IC which is used to make authentication and connection to the cloud very robust to increase the security of the devices people build.
Finally the latest family we introduced is the Portenta family, designed for professional users looking to build industrial grade projects. It’s the most powerful Arduino board out there with a Dual-Core processor, a Cortex M7 coupled with a Cortex M4. ( Note: “Cortex” is the way ARM indicates the class of their processors, going from Cortex M0 to Cortex M7. As the number after the M grows, so does the complexity and technical capabilities of the processor.) This dual processor architecture running at 480Mhz allows running complex software including computer vision and other tasks which require a lot of computing power coupled with the robustness and power efficiency of microcontrollers. If you’re a beginner, the Portenta might be a bit difficult to approach, but if you’re trying to build a sophisticated project that needs to be useable in an industrial setting, the Portenta will give all the power you need.
A final note: Over 90% of the hardware that is designed and sold directly from Arduino (and its distributors) is still manufactured in Italy at very high standard of quality and reliability. If you want to support Arduino and want a product that won’t let you down, buy an original. It’s also much cooler to have an original.
The family we just described is made of the “official” boards but, due to the open source nature of Arduino, there are other types of compatible boards that are divided in these broad categories:
18.218.15.205