Arduino Introduction and Advanced Resour
Arduino Introduction and Advanced Resour
AUTHOR
Nuno Pessanha Santos
nuno.pessanha.santos@gmail.com
Personal Website
Google Scholar
Open Researcher and Contributor IDentifier (ORCID)
ResearchGate
Academia
Scopus
Ciência Vitae
Web of Science
MARCH 6, 2023
You cannot teach a man anything,
you can only help him find it within
himself.
Galileo Galilei
CONTENTS
i
CHAPTER 3 INSTRUCTION INDEX PAGE 18
3.1 Base functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.1 Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1.2 Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2 Cycles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.2.1 If/Else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.2.2 For . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.2.3 Switch/Case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.2.4 While . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.2.5 Do/While . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3 Types of available variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.3.1 Boolean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.3.2 Char vs. Unsigned char . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.3.3 Byte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.3.4 Int vs. Unsigned int . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.3.5 Long vs. Unsigned long . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3.6 Float vs. Double . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3.7 Array vs. String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.4 Digital Input/Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.4.1 pinMode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.4.2 digitalWrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.4.3 digitalRead . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.5 Analog Input/Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.5.1 analogRead . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.5.2 analogWrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.6 Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.6.1 millis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.6.2 micros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.6.3 delay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
ii
3.6.4 delayMicroseconds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.7 Mathematical Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.7.1 min . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.7.2 max . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.7.3 abs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.7.4 constrain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.7.5 map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.7.6 pow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.7.7 sqrt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.8 Trigonometric Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.8.1 sen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.8.2 cos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.8.3 tan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.9 Random numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.9.1 randomSeed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.9.2 random . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.10 Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.10.1 attachInterrupt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.10.2 detachInterrupt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.10.3 interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.10.4 noInterrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.11 Serial communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.11.1 Serial.available . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.11.2 Serial.begin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.11.3 Serial.read . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.11.4 Serial.flush . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.11.5 Serial.print vs Serial.println . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.11.6 Serial.write . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
iii
CHAPTER 4 ADVANCED RESOURCES PAGE 59
4.1 Flash memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
4.1.1 Writing data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
4.1.2 Reading data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4.2 EEPROM memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.2.1 Writing data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.2.2 Reading data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.3 Servo motor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.3.1 Conőguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4.3.2 Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.3.3 Angle read . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.4 Serial communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
4.4.1 Conőguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.4.2 Read data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4.4.3 Transmit data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.5 Introduction to visual design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.6 Signal acquisition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.6.1 Theoretical Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.6.2 Arduino analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
BIBLIOGRAPHY PAGE 82
iv
1 INTRODUCTION
This tutorial was created to be an understandable reference for using the Arduino
development board [1], not only for those taking their őrst steps in this őeld but also
for those looking for more advanced knowledge. The initial version of this tutorial
(in Portuguese) dates back to 2009 [2] when the Arduino applications were evolving
quickly, being essential to develop an English language version (better late. . . ).
Arduino is an open-source development tool that emerged from an academic
project that rapidly became a worldwide success [3]. Arduino is usually associated
with the philosophy of physical computing [4] as a tool for rapid prototyping and
simple system development. Physical computing contemplates creating physical
systems capable of responding to inputs from the real world using a combination
of hardware and software, allowing the complete development of a system [5, 6].
We can describe Arduino simply as a piece of hardware with associated
development software (Figure 1.1), but it is much more than that. Due to its success
over time, there is currently a vast community of users/followers worldwide [7],
and it is commonly used as a teaching tool in schools and universities [8]. The
main reasons for this success are primarily its low cost considering its potential,
simplicity of use, and the possibility of being cross-platform since the development
software can run on multiple computing platforms - Windows, Linux, and macOS.
1
Figure 1.1: System Prototyping & Development - Simpliőed illustration.
Using Arduino, we can develop an entire system from scratch with low effort while
increasing our programming skills [9]. This simplicity opens the door to a complete
range of applications since we can create almost everything simply by having
imagination, from robots to home automation, among many others [10].
Due to its vast őeld of application, as stated before, Arduino has become almost a
mandatory subject to be addressed by electronic lovers and enthusiasts [11]. Thus,
this tutorial is expected to help you achieve the necessary expertise to develop your
prototypes and applications. This tutorial is organized into őve chapters, including
this introduction, having the following content:
2
2 HARDWARE VS. SOFTWARE
• Software (Section 2.2) - This section describes the Arduino IDE installation
and utilization, the commonly used sketch (program) development cycle,
and brieŕy introduces the possibility of interaction with other software. By
combining hardware with the appropriate software, we have a complete
development tool capable of rapid prototyping and system development.
3
2.1 Hardware
In this section, we will focus our approach on the Arduino Uno Revision (Rev) 3,
which is very similar in terms of use to the Arduino Mega 2560 Rev 3 (Figure 2.1).
However, minor differences exist, such as their storage capacity according to the
different memory types, the number of analogic and digital pins available, and
their dimensions [1, 2, 12, 13, 14].
Figure 2.1: Arduino Uno Rev 3 (left) & Arduino Mega 2560 Rev 3 (right) [1, 12, 13].
After the prototyping phase, we must choose the hardware that best őts the
desired application. Ideally, we do not want to use hardware with functions and
capabilities that we do not intend to use since the őnal system cost will increase.
When we use hardware with more capabilities than needed, we will typically have
a higher electrical energy demand and the need to ensure more available space
(higher dimensions). With this in mind, we must choose the Arduino board that
better suits our őnal application during the system development. As initially
described before, and to better understand the used hardware, this section is
organized into the following subsections:
4
• Available Memory Types and Amounts (Subsection 2.1.3) - This
subsection describes the available memory types on the Arduino Uno, and
Mega boards [12, 13], also explaining how this could limit their performance
when developing some types of applications (design constraints);
2.1.1 Microprocessor
5
With the continuous development of integrated circuits, we can use
microcontrollers (Subsection 2.1.2) that combine microprocessors with the
needed components (peripherals) in a single integrated circuit. Combining
all the components in a single chip has simpliőed the implementation of this
technology, which is now available in commercial-of-the-shelf solutions like
Arduino (Figure 2.1).
2.1.2 Microcontroller
The Arduino Uno Rev 3 has an ATMega328P [15] microcontroller, while the Arduino
Mega Rev 3 has an ATMega2560 [20] microcontroller (Figure 2.1). In Figure 2.4,
the block diagram of an ATMega328P microcontroller is presented (similar to the
ATMega2560 microcontroller), where it is possible to identify its main components.
By comparing Figure 2.3 and Figure 2.4, we can see that most of the standard
components are present in the ATMega328P. The main ATMega328P components
can be brieŕy described as (Figure 2.4) [15]:
6
• Oscillator Circuits/Clock Generation - Signal (clock) that is used to
synchronize the microprocessor operations (synchronous operation) [21];
• Flash - It stores the Arduino bootloader and sketch or program to run (non-
volatile memory). The bootloader is the software used to manage the sketch
upload to the Arduino board [25, 26];
7
Figure 2.4: ATMega328P microcontroller - Block diagram [15].
8
2.1.3 Available Memory Types and Amounts
One of the main differences between the various Arduino boards is their distinct
memory capacities. It is essential to analyze this difference because it can represent
a crucial performance factor in the őnal developed system (design constraints).
The available memory types are described in Table 2.1, and the available memory
amounts in Table 2.2.
Table 2.1: ATMEGA328P vs. ATMEGA2560 - Memory types description [12, 13].
Table 2.2: ATMEGA328P vs. ATMEGA2560 - Available memory [12, 13, 15, 20].
ATMEGA328P ATMEGA2560
32 kilobytes 256 kilobytes
Flash
(0.5 kilobytes bootloader) (8 kilobytes bootloader)
SRAM 2 kilobytes 8 kilobytes
EEPROM 1 kilobyte 4 kilobytes
After analyzing Table 2.2, it is possible to verify that ATMEGA2560 has a clear
advantage in terms of memory capacity. One of the essential types of memory
apart from Flash, where we store the sketch (program to run) and the bootloader
(software that manages the sketch upload), is SRAM, where the program creates
and modiőes all the necessary variables during its execution. This type of memory
only maintains data while it is powered (volatile), unlike EEPROM and Flash
(non-volatile). Sometimes, we must manage and store large variables during
the program execution. To save SRAM, we can store these constants in Flash or
EEPROM. To access these constants, we can easily use external libraries that allow
fast and safe access, as described in Chapter 4.
9
2.1.4 Available Pinout
Most Arduino Uno Rev 3 digital pins (Figure 2.5) allow Pulse Width Modulation
(PWM) [35, 36]. Using PWM, we can obtain an equivalent analogic voltage from a
digital signal that can only assume the logic state 0 (0 V) or 1 (5 V). A PWM signal is
characterized by having a constant frequency and a variable duty cycle (Figure 2.6).
10
Figure 2.6: PWM signal representation.
The obtained equivalent Direct Current (DC) voltage Vdc of a PWM signal is given
by:
żT
1
Vdc “ V ptq dt (2.1)
T 0
where T represents the period and V ptq represents the signal voltage as a function
of time. By analyzing Figure 2.7, we can simplify Equation 2.1 obtaining:
$
&Vpulse 0 ď t ď tp
’
V ptq “ (2.2)
%0 tp ă t ď T
’
where tp represents the pulse time duration (variable duty cycle) and Vpulse
represents the PWM signal pulse voltage (5 V when using Arduino).
Applying the concepts described before (Figure 2.7) and combining Equation 2.1
and Equation 2.2, we obtain:
˜ż ¸
tp żT
tp
Vdc “ Vpulse dt ` 0 dt “ Vpulse (2.3)
0 tp T
11
Analyzing Equation 2.3, we can conclude that the obtained equivalent DC voltage
is directly proportional to the PWM signal duty cycle (tp ). This feature allows us to
easily change the average tension value between 0 V and 5 V when using Arduino.
After brieŕy describing a PWM signal functioning, we will also explore the analogic-
to-digital conversion. Understanding this conversion is essential to interpreting
the values obtained from analog pins’ readings. The ATMEGA328P analogic-to-
digital converter has 10 bits of resolution (res) [2, 14, 15], and when using 5 V as
analogic reference (Aref ), we obtain the following resolution in voltage (Vres ) [2,
14, 37]:
When analyzing Equation 2.4, we can see that we will only detect voltage variations
(a change in the input obtained value) higher than 5 mV. When using analogic
sensors, it is possible in some applications that 5 mV is not an acceptable resolution
in voltage since the sensor output variation can be lower than that value. A possible
solution without external electronics is to change the analogic reference using the
board AREF pin (Figure 2.5). The AREF pin allows the change of the analogic
reference (Aref ) to its input voltage, originating a different resolution in voltage.
If we use 2 V as Aref , we obtain the following resolution in voltage (Vres ):
It is important to remember that when using a different Aref , all analog pins will
have this reference, being also necessary to declare its use in the Arduino IDE
(Example 2.1). After conőguring the Arduino to use the AREF pin as a reference,
the 3.3 V and 5 V pins become unavailable.
12
When selecting the analogic reference using the Arduino IDE (Example 2.1), we
are changing the Analogue to Digital Converter Multiplexer Selection (ADMUX)
register content [15, 20]. Connecting the high-level language used by the Arduino
IDE with the low-level operations is essential. We can enhance our system
performance in the design phase when making this connection.
The Arduino board can be powered using the Universal Serial Bus (USB) port, the
power jack input, or the voltage input pin Vin . When using an external power
supply for a standalone operation, it is recommended to have an input value
between 7 and 12 volts [12]. The voltage input pin Vin (Figure 2.5) has a dual
function since you can use it as an input or output power supply. The input voltage
supply will be available in this pin when using the USB or the power jack input to
power up the board. More conőguration details are described in Chapter 4.
2.2 Software
This section describes the Arduino IDE installation and use (Subsection 2.2.1),
the application development cycle (Subsection 2.2.2), and brieŕy introduces the
possibility of interaction with other software (Subsection 2.2.3).
This subsection will brieŕy describe the installation and use of the Arduino IDE.
The Arduino IDE is straightforward and intuitive to install and use. Nowadays, the
vast existing Arduino community can quickly help in the learning process [7].
The őrst step is downloading the Arduino IDE (Figure 2.8) from the official website
[1]. The latest available version will appear at the top of the page (Figure 2.9), and
it is only necessary to choose and download the correct version according to the
used operating system - cross-platform (Windows, Linux, and macOS).
13
Figure 2.9: Arduino website - Software tab available download options [1].
After downloading, decompress the őles to the desired destination folder. The next
step involves connecting the Arduino development board to the computer through
USB. This will allow the installation of the Future Technology Devices International
Limited (FTDI) driver, responsible for implementing the conversion between USB
and serial communication [38]. This driver can be installed from the Arduino
software folder or the FTDI official website [39] to use the latest available version.
The standard FTDI pinout is shown in Figure 2.10.
14
To start using the Arduino IDE, we must ensure that the selected model
corresponds to the Arduino board and that the communication port is well-
deőned. To perform this conőguration, we must choose the suitable options in
the Arduino IDE Tools tab, as shown in Figure 2.11. After this conőguration, we
are now ready to implement and complete the development cycle, being able to
compile the sketch and upload it, as described in Subsection 2.2.2.
• Edit - In this stage, we develop our sketch, or in other words, we write our
program. We can use additional tools like ŕowcharts or state machines to
organize the program ŕow better [40, 41, 42];
15
• Upload - When we upload the sketch (our program) through the USB cable
(using the bootloader) to the Arduino board [44];
• Run - When we power up or click the Arduino board reset button to run the
uploaded sketch (program) from the beginning.
If you want to use the Arduino development platform with other software, you
can explore the playground tab on the Arduino official website (Figure 2.14).
There you can őnd several references that perform Arduino interaction with
other development software, for example, Mathematica or Matlab (Figure 2.15).
Any software that can receive, send, and use data from a USB port (serial
communication using the FTDI chip as described in Subsection 2.2.1) can be used
to develop new applications following a physical computing philosophy creating
physical systems capable of interacting with the world around us.
16
Figure 2.14: Arduino website - Playground tab [1].
17
3 INSTRUCTION INDEX
This chapter will describe the high-level language instructions used in the Arduino
IDE without resorting to external libraries. Before describing the instructions, we
will brieŕy explore one of the possible microcontroller classiőcations based on
their instruction set characteristics. Based on their instruction set characteristics,
we can classify the microprocessors types into two main groups [45, 46, 47]:
18
Typically, the RISC microprocessors, in their simplest version, have the following
types of instructions [45, 46, 47]: (i) logical and arithmetic instructions on registers,
(ii) instructions for data transfer between memory and registers, and (iii) control
instructions. The microcontroller models used in the Arduino boards are based
on an advanced RISC architecture [20, 15] developed by Microprocessor Without
Interlocked Pipeline Stages (MIPS) Technologies [48]. Since we are using the
Arduino IDE, which uses a high-level language similar to the general-purpose
programming language C, the microprocessor classiőcation will not directly
concern the programmer. This chapter is divided into the following sections:
• Base functions (Section 3.1) - This section describes the main functions
that need to be implemented in an Arduino sketch (program);
• Cycles (Section 3.2) - This section describes the cycles (loops) that can be
used to adjust the sketch ŕow according to some predeőned conditions;
• Time (Section 3.6) - This section describes the functions that can be used to
count time and perform speciőc time delays during the program workŕow;
19
• Random numbers (Section 3.9) - This section describes the functions that
can be used to generate random (actually pseudo-random) numbers that can
be useful in some applications;
This chapter will brieŕy describe each one of the functions that can be used
to develop our sketch and perform system development. For each one of the
functions, it will be provided a short description and an illustrative example that
will be useful to understand its use and working mode better.
20
3.1.1 Setup
The setup function is only executed once during the board startup (system start),
being only executed again when a reset occurs or when a new startup is veriőed
(power off/power on). This function initializes system parameters such as input
or output pins and serial communication (Example 3.2). As described before, this
function is from the void type since it cannot return any value after execution.
3.1.2 Loop
21
int sensor=3; //Integer variable "sensor" initialized with value "3"
int val; //Initialization of the integer variable "val"
int f[10]; //Integer array initialization with 11 memory positions
float test; //Initialization of the float variable "test"
float analog_read; //Initialization of the float variable "analog_read"
(.....) //Global variables initialization
3.2 Cycles
This section will describe the commonly used cycles (loops) that can be used
to execute speciőc instructions according to predeőned conditions. As will be
described, we can use the if/else cycle to test a speciőc condition (Subsection 3.2.1),
the for cycle to execute a speciőc set of instructions a certain number of times
(Subsection 3.2.2), the switch/case cycle to test a variable value taking into account
22
a certain amount of conditions (Subsection 3.2.3), the while cycle to perform a
speciőc set of instructions until a certain condition is met (Subsection 3.2.4), and
the do/while cycle that is similar to the while cycle but the condition is only tested
at the end after an iteration (Subsection 3.2.5).
3.2.1 If/Else
This cycle describes and tests speciőc conditions (Example 3.4). We can use
multiple chained if/else cycles to test several conditions successively.
X == Y X equals Y
X != Y X not equal to Y
X >Y X greater than Y
X >= Y X greater than or equal to Y
X <Y X less than Y
X <= Y X less than or equal to Y
An example of the if cycle implementation can be seen in Example 3.5, where the
integer variable val is continuously tested. If that variable reaches a value greater
23
than or equal to 500, the digital pin 13 changes to a HIGH value (5 V). On the other
hand, if that variable has a value less than 500, the digital pin 13 changes to a LOW
value (0 V). As described in Example 3.4, using the else statement is optional.
void setup(){
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(12,OUTPUT); //Allows the set of pin 12 as "OUTPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
val=analogRead(sensor); //Analog pin 3 reading is assigned to "val"
if(val>=500){ //Test if "val" is greater than or equal to 500
digitalWrite(13,HIGH); //If true, the digital pin 13 turns "HIGH" (5V)
} else{
digitalWrite(13,LOW); //If false, the digital pin 13 turns "LOW" (0V)
}
if(val>=800){ //Test if "val" is greater than or equal to 800
digitalWrite(12,HIGH); //If true, the digital pin 12 turns "HIGH" (5V)
(.....) //Program code
}
3.2.2 For
This cycle is used when we want to execute a speciőc instruction set several
times. To use this cycle, we have to perform variable initialization, deőne the test
condition, and deőne the increment to be made to the variable (Example 3.6). For
example, we can use this cycle type to őll an integer array with data obtained from
an analog sensor.
24
for(Variable initialization; Condition; Define variable increment){
(.....) //Program code
}
//Example 1
for(int i=10; i==0; i--) //Decrement operator "i--"
//Example 2
for(int i=0; i>10; i++) //Increment operator "i++"
An illustration of the for cycle implementation can be seen in Example 3.7. The
integer variable i is only initialized once at the beginning of the cycle. Each time
the cycle is performed, the condition is tested. If the condition is not met (false),
the increment is performed, and if the condition is met (true), the cycle ends.
int sensor=3; //Integer variable "sensor" initialized with value "3"
int val; //Initialization of the integer variable "val"
int f[10]; //Integer array initialization with 11 memory positions
(.....) //Global variables initialization
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(12,OUTPUT); //Allows the set of pin 12 as "OUTPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
for(int i=0;i<=10;i++){ //Executed until "i" less than or equal to 10
val=analogRead(sensor); //Analog pin 3 reading is assigned to "val"
f[i]=val; //Assign the "val" value to the array "f" in position "i"
}
(.....) //Program code
}
25
3.2.3 Switch/Case
This cycle is used when we want to declare and test a list of possible conditions
(cases) for a speciőc variable (Example 3.8). Each condition is checked (tested)
and executed only when the variable meets the declared condition. The break
condition will ensure that the cycle ends after the condition is met (true).
Otherwise, the cycle will continue to run from the veriőed condition.
switch(variable){
case 1:
//Instructions to be executed when "variable" is 1 (variable == 1)
break;
case 2:
//Instructions to be executed when "variable" is 2 (variable == 2)
break;
(.....) //Program code
default:
//Executed if none of the previous conditions are met (true)
//This condition is optional
}
26
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
val=analogRead(sensor); //Analog pin 3 reading is assigned to "val"
switch(val){
case 500: //Test if "val" is equal to 500
digitalWrite(13,HIGH); //If true, the digital pin 13 turns "HIGH" (5V)
break; //Instruction that allows ending the cycle
default: //If none of the conditions are met (its use is optional)
digitalWrite(13,LOW); //The digital pin 13 turns "LOW" (0V)
}
(.....) //Program code
}
3.2.4 While
This cycle is typically used to execute a speciőc set of instructions (Example 3.10)
until a certain condition is met (true). If the condition is met (true), the cycle
ends. In cases where the condition is not met (false), we get stuck in an inőnite
loop similar to the one described for the loop function (Subsection 3.1.2). We must
consider this in the design phase, guaranteeing that this situation does not happen.
while(condition){
Instruction 1;
Instruction 2;
Instruction 3;
Instruction 4;
(.....) //Program code
}
27
An illustration of implementing the while cycle can be seen in Example 3.11. The
cycle is continuously executed until the integer variable i is less than or equal to
10, assigning the analogic reading from pin 13 to the integer array f[i] in position
i. The cycle ends when the condition is met (true), and the remaining instructions
included in the loop function are executed. As described before, the loop function
is continuously executed, and the cycle is repeated on each iteration.
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
while(i<=10) //Cycle executed until i<=10
val=analogRead(sensor); //Analog pin 3 reading is assigned to "val"
f[i]=val; //Assign the "val" value to the array "f" in position "i"
i++; //Increment the value of "i" (i = i + 1)
}
(.....) //Program code
}
3.2.5 Do/While
This cycle is very similar to the while cycle described in Subsection 3.2.4, being the
main difference in the condition test time. In this cycle, the condition is only tested
28
at the end, not at the beginning (Example 3.12). This means the cycle will always
be executed once (a cycle iteration), even if the condition is already met (true).
do{
Instruction 1;
(.....) //Program code
}
while(condition);
void setup(){
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
do{ //Cycle initialization
val=analogRead(sensor); //Analog pin 3 reading is assigned to "val"
f[i]=val; //Assign the "val" value to the array "f" in position "i"
i++; //Increment the value of "i" (i = i + 1)
}
while(i<=10); //Cycle executed until "i" less than or equal to 10
(.....) //Program code
}
29
3.3 Types of available variables
This section will describe the variables that can be used to develop our sketch.
The difference between them and how we can perform their declaration will
be the main objective of this section. We must use the proper variable type
according to the desired behavior - what we want to store and process. As will be
described, we can use boolean variables (Subsection 3.3.1), char and unsigned char
variables (Subsection 3.3.2), byte variables (Subsection 3.3.3), int and unsigned int
variables (Subsection 3.3.4), long and unsigned long variables (Subsection 3.3.5),
float and double variables (Subsection 3.3.6), and array and string variables
(Subsection 3.3.7).
3.3.1 Boolean
A boolean variable reserves one byte of memory and can only take two distinct
values - true or false (Example 3.14).
An example of using a boolean variable can be seen in Example 3.15. The boolean
variable test is initialized with false, being changed (true or false) inside the do cycle
execution. For example, this variable can store the state of a speciőc condition
during the program execution.
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
pinMode(3,INPUT); //Allows the set of pin 3 as "INPUT"
(.....) //Program code
}
30
void loop(){
do{ //Cycle initialization
test = !test; //Change the "test" boolean variable value
i++; //Increment the value of "i" (i = i + 1)
}
while(i<=10); //Cycle executed until "i" less than or equal to 10
(.....) //Program code
}
A char variable reserves one byte of memory and can store a single character.
This character can also be stored using a decimal value between ´128 and
127, as represented in the American Standard Code for Information Interchange
(ASCII) table [49]. If we use an unsigned char variable, we cannot represent the
negative part being able to store decimal values (characters) between 0 and 255
(Example 3.16).
char v = character //Variable initialized with a character
char v = dec //Variable initialized with a decimal value
unsigned char v = character //Variable initialized with a character
unsigned char v = dec //Variable initialized with a decimal value
An example of using char and unsigned char variables can be seen in Example 3.17.
According to the ASCII table [49], and as described before, the characters N and P
can also be assigned to different variables using their decimal value.
char example_variable = ’N’; //"N" is assigned to "example_variable"
char example_variable_1 = 78; //"N" is assigned to "example_variable_1"
unsigned char ex = ’P’; //"P" is assigned to "ex"
unsigned char ex_2 = 80; //"P" is assigned to "ex_2"
31
3.3.3 Byte
A byte variable reserves one byte of memory and can store an unsigned number
between 0 and 255 (28 ´ 1), as described in Example 3.18.
byte test = value; //Variable "test" initialized with "value"
An example of using a byte variable can be seen in Example 3.19. The byte variable
value can be assigned using decimal or binary numbers representation.
byte example = B00000001; //Binary value is assigned to "example"
byte example_1 = B00000011; //Binary value is assigned to "example_1"
byte example_2 = 1; //Decimal "1" is assigned to "example_2"
An integer variable reserves two bytes of memory and can store an integer value
between ´32768 and 32767. If we declare this variable as unsigned integer, we no
longer have the negative part allowing us to store values between 0 and 65535 (216 ´
1), as described in Example 3.20.
int test = value; //Variable "test" initialized with "value"
unsigned int test_2 = val; //Variable "test_2" initialized with "val"
32
3.3.5 Long vs. Unsigned long
A long variable reserves four bytes of memory and can store a numerical value
between ´2147483648 and 2147483647. If we declare this variable as unsigned
long, we no longer have the negative part allowing us to store values between 0
and 4294967295 (232 ´ 1), as described in Example 3.22.
long test = value; //Variable "test" initialized with "value"
unsigned long test_2 = val; //Variable "test_2" initialized with "val"
A float variable reserves four bytes of memory and can store a decimal value
between ´3.4028235ˆ1038 and 3.4028235ˆ1038 . On the other hand, when we use
a double variable, we should obtain a higher precision variable. However, when
using Arduino, both variables present the same resolution and occupy the same
memory space Example 3.24.
float test = value; //Variable "test" initialized with "value"
double test_2 = val; //Variable "test_2" initialized with "val"
An example of using float and double variables can be seen in Example 3.25. As
described before, both variable types have the same resolution and occupy the
same memory space when using Arduino.
33
float example = 1.589; //Decimal "1.589" is assigned to "example"
double example_1 = 1.589; //Decimal "1.589" is assigned to "example_1"
An example of using array and string variables can be seen in Example 3.27. When
we declare an index value of ten, we reserve eleven memory spaces since we must
consider the zero index.
float ex[10]; //Float array initialization
int ex_2[] = {1,2,3,4,5}; //Integer array with an assigned number set
char ex_3[11] = "Hello"; //Char array with an assigned character set
char ex_4[] = "Pessanha"; //Char array with an assigned character set
34
digitalRead() function (Subsection 3.4.3) to read the value (input voltage) arriving
to a digital pin - 0 V (LOW ) or 5 V (HIGH ).
3.4.1 pinMode
Using the pinMode() function, it is possible to conőgure the digital pins as input or
output (Example 3.28). This deőnition should be made inside the setup function.
pinMode(Pin number, Mode); //"Mode" can be "INPUT" or "OUTPUT"
void setup(){
pinMode(3,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
(.....) //Program code
}
3.4.2 digitalWrite
Using the digitalWrite() function, it is possible to set the output of the digital pins
as 0 V (LOW ) or 5 V (HIGH ), as described in Example 3.30.
digitalWrite(Pin number, Mode); //"Mode" can be "HIGH" or "LOW"
35
An example of using the digitalWrite() function can be seen in Example 3.31. This
function is useful for acting in the surrounding world according to the desired
system behavior.
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(12,OUTPUT); //Allows the set of pin 12 as "OUTPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
val=analogRead(sensor); //Analog pin 3 reading is assigned to "val"
if(val>=500){ //Test if "val" is greater than or equal to 500
digitalWrite(13,HIGH); //If true, the digital pin 13 turns "HIGH" (5V)
digitalWrite(12,LOW); //If true, the digital pin 12 turns "LOW" (0V)
}
(.....) //Program code
}
3.4.3 digitalRead
36
An example of using the digitalRead() function can be seen in Example 3.33. This
function allows reading a speciőc input in real-time, performing processing, and
understanding changes in the surrounding world.
void setup(){
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
val=analogRead(sensor); //Analog pin 3 reading is assigned to "val"
if(val==1){ //Test if "val" is equal to 1 ("HIGH")
digitalWrite(13,HIGH); //If true, the digital pin 13 turns "HIGH" (5V)
}
else{
digitalWrite(13,LOW); //If false, the digital pin 13 turns "LOW" (0V)
}
(.....) //Program code
}
37
an analogic pin and the analogWrite() function (Subsection 3.5.2) that can be used
to emulate a PWM signal, as described in Subsection 2.1.4.
3.5.1 analogRead
An example of using the analogRead() function can be seen in Example 3.35. This
function can be useful to read an analogic input from the surrounding world, such
as a sensor, to perform processing and have the desired system behavior.
int sensor=3; //Integer variable "sensor" initialized with value "3"
int val; //Initialization of the integer variable "val"
(.....) //Global variables initialization
void setup(){
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
val=analogRead(sensor); //Analog pin 3 reading is assigned to "val"
if(val>=500){ //Test if "val" is greater than or equal to 500
digitalWrite(13,HIGH); //If true, the digital pin 13 turns "HIGH" (5V)
}
(.....) //Program code
}
38
3.5.2 analogWrite
An example of using the analogWrite() function can be seen in Example 3.37. This
function allows changing the output voltage using a PWM signal and can be used in
multiple applications, such as providing a voltage proportional to a speciőc input.
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
val=analogRead(sensor); //Analog pin 3 reading is assigned to "val"
if(val>=500){ //Test if "val" is greater than or equal to 500
analogWrite(out,255); //If true, the analog pin 9 turns "HIGH" (5V)
}
else{
analogWrite(out,0); //If false, the analog pin 9 turns "LOW" (0V)
}
(.....) //Program code
}
39
3.6 Time
This section will describe the functions that can be used to count time or to
perform time delays. As will be described, we can use the millis() function
(Subsection 3.6.1) to return the amount of time in milliseconds since the program
started running, the micros() function (Subsection 3.6.2) to return the amount
of time in microseconds since the program started running, the delay() function
(Subsection 3.6.3) that can be used to perform a milliseconds time delay in the
running program, and the delayMicroseconds() function (Subsection 3.6.4) that
can be used to perform a microseconds time delay in the running program.
3.6.1 millis
An example of using the millis() function can be seen in Example 3.39. As stated
before, this function will return the time in milliseconds since the program started.
unsigned long time; //Unsigned long variable "time"
(.....) //Global variables initialization
void setup(){
(.....) //Program code
}
void loop(){
time = millis(); //Time in milliseconds since the program started
(.....) //Program code
}
40
3.6.2 micros
void setup(){
(.....) //Program code
}
void loop(){
time = micros(); //Time in microseconds since the program started
(.....) //Program code
}
3.6.3 delay
41
An example of using the delay() function can be seen in Example 3.43. This can be
useful to suspend the running program for a predeőned time interval according to
the desired system behavior.
void setup(){
pinMode(led,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
digitalWrite(led,HIGH); //The digital pin 13 turns "HIGH" (5V)
delay(200); //A delay of 200 milliseconds
digitalWrite(led,LOW); //The digital pin 13 turns "LOW" (0V)
delay(600); //A delay of 600 milliseconds
(.....) //Program code
}
3.6.4 delayMicroseconds
42
(.....) //Global variables initialization
void setup(){
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}
void loop(){
digitalWrite(13,HIGH); //The digital pin 13 turns "HIGH" (5V)
delayMicroseconds(200); //A delay of 200 microseconds
digitalWrite(13,LOW); //The digital pin 13 turns "LOW" (0V)
delayMicroseconds(600); //A delay of 600 microseconds
(.....) //Program code
}
43
3.7.1 min
Using the min() function, it is possible to compare two values and calculate the
smallest one, as described in Example 3.46.
An example of using the min() function can be seen in Example 3.47. As stated,
this function will compare two values and return the smallest one.
3.7.2 max
Using the max() function, it is possible to compare two values and calculate the
highest one, as described in Example 3.48.
An example of using the max() function can be seen in Example 3.49. As stated,
this function will compare two values and return the highest one.
3.7.3 abs
Using the abs() function, it is possible to calculate the modulus of a given number,
as described in Example 3.50.
44
Module = abs(value);
//"Module" equal to "value" if "value" is greater or equal to zero
//"Module" equal to -1 x "value" if "value" is less than zero
An example of using the abs() function can be seen in Example 3.51. As stated
before, this function will return the modulus of a given number for processing.
3.7.4 constrain
Using the constrain() function, it is possible to compare a value with a speciőc user-
deőned range, as described in Example 3.52.
45
3.7.5 map
Using the map() function, we can modify the range of values expected by a given
application (Example 3.54). This function can adjust the used scale, which can be
helpful, for example, for generating PWM signals between 0 and 255 from analogic
input signals between 0 and 1023.
An example of using the map() function can be seen in Example 3.55. As stated
before, this function can help establish a relationship between two different value
intervals.
void setup(){
pinMode(3,INPUT); //Allows the set of pin 3 as "INPUT"
(.....) //Program code
}
void loop(){
for(int i=0;i<=10;i++){ //Executed until "i" less than or equal to 10
val=analogRead(3); //Analog pin 3 reading is assigned to "val"
map(val,0,1023,0,500); //Map the "val" variable to the range [0,500]
f[i]=val; //Assign the "val" value to the array "f" in position "i"
}
(.....) //Program code
}
46
3.7.6 pow
Using the pow() function, it is possible to calculate the power of a given number,
as described in Example 3.56.
An example of using the pow() function can be seen in Example 3.57. As stated
before, this function calculates a number’s power according to a speciőc exponent.
3.7.7 sqrt
Using the sqrt() function, it is possible to calculate the square root of a given
number, as described in Example 3.58.
Obtained_value = sqrt(value);
An example of using the sqrt() function can be seen in Example 3.59. As stated
before, this function calculates a number’s square root.
47
3.8 Trigonometric Functions
This section will describe the functions used to perform trigonometric operations
in the program variables. As will be described, we can use the sen() function
(Subsection 3.8.1) to calculate the sine of a given value in radians, the cos() function
(Subsection 3.8.2) to calculate the cosine of a given value in radians, and the tan()
function (Subsection 3.8.3) to calculate the tangent of a given value in radians.
3.8.1 sen
Using the sen() function, it is possible to calculate the sine of a given value in
radians, as described in Example 3.60.
Result = sen(angle); //"angle" is in radians
3.8.2 cos
Using the cos() function, it is possible to calculate the cosine of a given value in
radians, as described in Example 3.61.
Result = cos(angle); //"angle" is in radians
3.8.3 tan
Using the tan() function, it is possible to calculate the tangent of a given value in
radians, as described in Example 3.62.
Result = tan(angle); //"angle" is in radians
48
3.9 Random numbers
This section will describe the functions used to generate random numbers. As will
be described, we can use the randomSeed() function (Subsection 3.9.1) that can
be used to change where the random sequence algorithm starts and the random()
function (Subsection 3.9.2) that can be used to generate a random number.
3.9.1 randomSeed
Using the randomSeed() function, it is possible to change the point (seed) where
the pseudo-random sequence algorithm starts (Example 3.63). When changing
this value, we can decrease the probability of repeating a speciőc sequence.
void setup(){
randomSeed(seed) //Change the point where the sequence starts
(.....) //Program code
}
void loop(){
(.....) //Program code
}
49
3.9.2 random
void setup(){
randomSeed(seed) //Change the point where the sequence starts
(.....) //Program code
}
void loop(){
random_value = random(10, 20); //"random_value" between "10" and "19"
(.....) //Program code
}
3.10 Interrupts
This section will describe the functions that can be used to execute interrupts.
Interrupts can change the program ŕow when a speciőc event occurs
50
without checking for a particular condition (polling ). As will be described,
we can use the attachInterrupt() function (Subsection 3.10.1) to make the
deőnition and operation of external interrupts, the detachInterrupt() function
(Subsection 3.10.2) to disable a previously deőned interrupt, the interrupts()
function (Subsection 3.10.3) to enable the use of interrupts, and the noInterrupts()
function (Subsection 3.10.4) to disable the use of interrupts.
3.10.1 attachInterrupt
//Notes:
//The defined "function" should be from the void type
//"mode" defines how an external interrupt is recognized
As described in Example 3.67, the deőned function must be from the void type. The
parameter mode deőnes how an external interrupt is recognized, as described in
Table 3.2.
51
Table 3.2: Possible attachInterrupt() function identify conditions.
3.10.2 detachInterrupt
detachInterrupt(interrupt);
//Arduino Uno Rev. 3
//interrupt == 0 corresponds to digital pin "2"
//interrupt == 1 corresponds to digital pin "3"
3.10.3 interrupts
Using the interrupts() function (Example 3.69), it is possible to reactivate the use
of interrupts after this functionality has been disabled. Interrupts are enabled by
default.
52
interrupts(); //Instruction that enables the use of interrupts
An example of using the interrupts() function can be seen in Example 3.70. We can
use it to enable interrupts during the program execution easily.
void setup(){
(.....) //Program code
}
void loop(){
noInterrupts(); //Instruction that disables the use of interrupts
(.....) //Program code
interrupts(); //Instruction that enables the use of interrupts
(.....) //Program code
}
3.10.4 noInterrupts
Using the noInterrupts() function (Example 3.71), it is possible to disable the use
of interrupts. Interrupts are enabled by default.
noInterrupts(); //Instruction that disables the use of interrupts
void loop(){
noInterrupts(); //Instruction that disables the use of interrupts
53
(.....) //Program code
interrupts(); //Instruction that enables the use of interrupts
(.....) //Program code
}
3.11.1 Serial.available
54
int read=0; //Integer variable "read" initialized with value "0"
(.....) //Global variables initialization
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
(.....) //Program code
}
void loop(){
if(Serial.available()>0) //Check if we are receiving data
read=Serial.read(); //If true, the value is stored in "read"
(.....) //Program code
}
3.11.2 Serial.begin
Using the Serial.begin() function (Example 3.75), it is possible to start the serial
communication and deőne the used baud rate. The most commonly used baud
rates are 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, and
115200. However, other values can be deőned.
An example of using the Serial.begin() function can be seen in Example 3.76. The
serial communication’s deőnition and baud rate are performed inside the setup
function.
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
(.....) //Program code
55
}
void loop(){
(.....) //Program code
}
3.11.3 Serial.read
An example of using the Serial.read() function can be seen in Example 3.78. Using
this function, the obtained data can be stored and processed to use the information
received via serial port to interact with the developed system.
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
(.....) //Program code
}
void loop(){
if(Serial.available()>0) //Check if we are receiving data
read=Serial.read(); //If true, the value is stored in "read"
(.....) //Program code
}
56
3.11.4 Serial.flush
Using the Serial.flush() function (Example 3.79), it is possible to ŕush (erase) all the
existing data in the input buffer. The input buffer has a storage capacity of 64 bytes.
An example of using the Serial.flush() function can be seen in Example 3.80. This
function can ensure that the buffer does not overŕow and that we are reading and
processing the most recent data received using the serial port.
void setup(){
(.....) //Program code
}
void loop(){
Serial.flush(); //Erases the content of the input buffer
(.....) //Program code
}
Serial.print(data);
//data == Can be a string
Serial.print(data, format);
//format == "DEC" Decimal, "HEX" Hexadecimal or "OCT" Octal
57
An example of using the Serial.print() and Serial.println() functions can be seen in
Example 3.82. As described in Example 3.81, we can send a string or data using the
decimal, hexadecimal, and octal representations.
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
(.....) //Program code
}
void loop(){
Serial.flush(); //Erases the contents of the input buffer
Serial.print("B"); //Sending the string "B"
Serial.println("B"); //String "B" + carriage return + new line
(.....) //Program code
}
3.11.6 Serial.write
Using the Serial.write() function (Example 3.83), it is possible to send binary data
through the serial port. The binary data can be sent as a single or a set of bytes.
Serial.write(value);
//"value" is in binary
Serial.write(string);
//"string" as a set of bytes
Serial.write(vector, size);
//Defining the vector to be sent and its size
The value variable described in Example 3.83 deőnes the value to be sent in binary
via the serial port. Alternatively, data can be sent using a string as a set of bytes or
deőning a vector and its respective size.
58
4 ADVANCED RESOURCES
• Flash memory (Section 4.1) - This section describes some functions that
can be used to read and write directly from the Flash memory;
• Servo motor (Section 4.3) - This section describes an interface that can be
used to control servo motors easily;
59
• Introduction to visual design (Section 4.5) - This section describes brieŕy
how Arduino can be used for visual design, combining the firmata protocol
[50] with some third-party software as Processing [51];
Saving data is essential in any application design since it is the base of any program
workŕow. Using this library, this process becomes straightforward, as described in
Example 4.1.
60
The used library does not directly support the creation of a string vector. Instead,
it is created in SRAM, a vector containing the addresses of the individual strings
stored in Flash. This causes this instruction to occupy 2 bytes for each stored string
[52]. The process of writing variables in Flash memory is described in Example 4.2.
#include <Flash.h> //Include the used library
FLASH_STRING(teste, "Pessanha");
FLASH_ARRAY(int, teste_1, 2,2,3,0,5);
FLASH_TABLE(int, teste_2, 2, {0x00, 0x00}, {0x24, 0x34});
void setup(){
FLASH_STRING_ARRAY(teste_3, PSTR("N"), PSTR("P"));
//FLASH_STRING_ARRAY must be declared inside a function - PSTR notation
(.....) //Program code
}
void loop(){
(.....) //Program code
}
61
The data access from Flash is similar to the simplicity of using vectors, which is
one of the strengths of this library. More syntax exists when using this library [52],
but the most important one is presented here. The process of reading variables in
Flash memory is described in Example 4.4.
FLASH_STRING(teste, "Pessanha");
FLASH_ARRAY(int, teste_1, 2,2,3,0,5);
FLASH_TABLE(int, teste_2, 2, {0x00, 0x00}, {0x24, 0x34});
void setup(){
Serial.begin(9600); //Serial communication initialization - baud rate
teste_2.print(Serial); Serial.println(); //Send table data
Serial.println(teste_2.rows()); //Send table number of rows
Serial.println(teste_2.cols()); //Send table number of columns
Serial.println(sizeof(teste_2)); //Send table size
char variable[24] = {0}; //Copy destination variable
teste.copy(extract, 1, 1); //Copy 1 character with offset 1
(.....) //Program code
}
void loop(){
(.....) //Program code
}
62
memory (Section 4.1). This library is initially included in the Arduino IDE without
downloading it using the Arduino library manager. This library simpliőes the write
(Subsection 4.2.1) and read (Subsection 4.2.2) operations, making them simple
to perform. The main limitation in the EEPROM memory use is a limit in the
read/write cycles [15, 20].
Saving data is essential in any application design since it is the base of any program
workŕow. Using this library, this process becomes straightforward, as described in
Example 4.5. We can store a value between 0 and 255 (28 ´ 1), corresponding to 1
byte on each memory position.
EEPROM.write(Address, data); //"Address" - integer & "data" - byte
EEPROM.read(Address); //"Address" is an integer value
void setup(){
EEPROM.write(1,1); //Write the value 1 in memory position 1
(.....) //Program code
}
void loop(){
EEPROM.write(2,1); //Write the value 1 in memory position 2
(.....) //Program code
}
63
4.2.2 Reading data
Reading data is essential in any application design since it is the base of any
program workŕow. Using this library, this process becomes straightforward, as
described in Example 4.7. We can read a value between 0 and 255 (28 ´ 1),
corresponding to 1 byte on each memory position.
EEPROM.read(Address); //"Address" is an integer value
void setup(){
EEPROM.write(1,1); //Write the value 1 in memory position 1
EEPROM.write(2,4); //Write the value 4 in memory position 2
(.....) //Program code
}
void loop(){
EEPROM.write(2,1); //Write the value 1 in memory position 2
r = EEPROM.read(1); //EEPROM memory position one is stored in "r"
EEPROM.write(2,24); //Write the value 24 in memory position 2
r_2 = EEPROM.read(2); //EEPROM memory position 2 is stored in "r_2"
(.....) //Program code
}
64
4.3 Servo motor
A standard servo motor is an actuator that allows precise control of its position,
velocity, and acceleration according to an input signal [53], as described in
Figure 4.1. According to the desired utilization, the servo will maintain its position
if this signal remains constant. Servo motors are widely used, for example, in
robotics [54, 55, 56], with many possible applications.
Figure 4.1: Servo motor - Illustration (left) & Simpliőed schematic (right).
A servo motor, as described in Figure 4.1, has three inputs: (i) power supply (5V
for standard servo motors), (ii) ground, and (iii) input signal. The input signal will
be a PWM signal, with the duty cycle proportional to the desired servo position
(Subsection 2.1.4). Many servo motors with linear and angular motion exist and
can also be designed for continuous rotation [53]. As described in Figure 4.2, the
control circuit controls the DC motor based on the information obtained by the
potentiometer and the input signal. The potentiometer is directly coupled to the
rotation axis for continuous feedback on the axis position.
The many possible servo motors applications make this an indispensable topic
for any electronic lover or enthusiast. An external library will be used to perform
this interface, but it is also possible to perform servo motor control directly
using the analogic pins. This library is initially included in the Arduino IDE
without downloading it using the Arduino library manager. It simpliőes the servo
motor conőguration (Subsection 4.3.1), control (Subsection 4.3.2) and angle read
(Subsection 4.3.3) operations, making them simple to perform.
65
Figure 4.2: Servo motor - Real representation.
4.3.1 Configuration
66
The process of creating variables, attaching, and detaching is described in
Example 4.10. The use of this library simpliőes the servo motor control, being only
needed to conőgure the desired control pin.
void setup(){
example.attach(10); //Sets servo motor pin to "10"
example2.attach(9); //Sets servo motor pin to "9"
(.....) //Program code
}
void loop(){
example.detach(); // Detach the servo motor variable from pin "10"
example2.detach(); // Detach the servo motor variable from pin "9"
(.....) //Program code
}
4.3.2 Control
After performing the conőguration, we can quickly move the servo motor axis to
the desired position (Example 4.11). A standard servo will be controlled using the
desired shaft orientation angle (between 0 and 180 degrees). A continuous rotation
servo will be controlled using the desired direction and speed (between 0 and 180).
67
The process of controlling a servo motor is described in Example 4.12. The use of
this library simpliőes the servo motor control, being only needed to conőgure the
desired control pin.
void setup(){
example.attach(10); //Sets servo motor pin to "10"
example_2.attach(9); //Sets servo motor pin to "9"
(.....) //Program code
}
void loop(){
example.write(0); //Standard servo - Move axis to "0" degrees
example_2.write(90); //Continuous rotation servo - Stops its rotation
(.....) //Program code
}
The process of obtaining the last value passed using the write servo motor function
is described in Example 4.14. For example, sometimes, during the code execution
68
and when using some increments or a servo motor axis angle value proportional
to an input, it is not easy to understand the last command. This function simpliőes
the way to obtain this information.
void setup(){
example.attach(10); //Sets servo motor pin to "10"
(.....) //Program code
}
void loop(){
example.write(angle); //Standard servo - Move axis to "0" degrees
angle = example.read()+1; //Incrementation of one degree
(.....) //Program code
}
69
Figure 4.3: Synchronous serial communication - Illustration.
with the master deőning the data transfer rate and synchronizing the data ŕow
using a clock signal. Asynchronous communication is based on a sender and a
receiver (that can change over time) without a data transfer rate synchronization.
70
4.4.1 Configuration
An auxiliary variable must be assigned to the desired Arduino pins to start the
software serial conőguration. As described in Example 4.15, we can easily set the
pins to perform serial communication after the variable creation.
void setup(){
pinMode(4,INPUT); //Allows the set of pin 4 as "INPUT"
pinMode(5,OUTPUT); //Allows the set of pin 5 as "OUTPUT"
example.begin(9600); //Serial communication initialization - baud rate
(.....) //Program code
}
void loop(){
(.....) //Program code
}
71
4.4.2 Read data
Reading data is essential in any application design since it is the base of any
program workŕow. Using this library, this process becomes straightforward, as
described in Example 4.17. Before receiving data, it is essential to conőgure the
pins used to implement the communication.
void setup(){
pinMode(4,INPUT); //Allows the set of pin 4 as "INPUT"
pinMode(5,OUTPUT); //Allows the set of pin 5 as "OUTPUT"
example.begin(9600); //Serial communication initialization - baud rate
(.....) //Program code
}
void loop(){
received=example.read(); //The received value is stored on "received"
(.....) //Program code
}
72
4.4.3 Transmit data
Transmitting data is essential in any application design since it is the base of any
program workŕow. Using this library, this process becomes straightforward, as
described in Example 4.19. Before transmitting data, it is essential to conőgure the
pins used to implement the communication.
SoftwareSerial name = SoftwareSerial(Pin_1, Pin_2);
//"Pin_1" is the receiver (Rx) pin
//"Pin_2" is the transmission (Tx) pin
name.print(data); //Sends "data"
name.println(data); //Sends "data" + carriage return + new line
void setup(){
pinMode(4,INPUT); //Allows the set of pin 4 as "INPUT"
pinMode(5,OUTPUT); //Allows the set of pin 5 as "OUTPUT"
example.begin(9600); //Serial communication initialization - baud rate
(.....) //Program code
}
void loop(){
received=example.read(); //The received value is stored on "received"
example.print(received); //The "received" value is transmitted
(.....) //Program code
}
73
4.5 Introduction to visual design
This section’s primary purpose is to describe how visual design can be easily made
brieŕy. The firmata protocol [50] was initially created to implement a generic
communication protocol between Arduino and third-party software. The software
can read and send data through a serial port communication to perform Arduino
control. Adapting the library to each user-speciőc application during the system
design is possible, and this ŕexibility is a clear library advantage.
The Arduino interface with the open-source software Processing [51] is an
implementation that artists and designers interested in electronics usually explore.
This software allows visual programming, which creates graphical objects through
programming instructions. These graphic objects, like squares, circles, or lines,
could be simple. Nevertheless, they can also have high complexity allowing to
render of complex objects and shapes to create art. Benjamin Fry and Casey Reas
developed this software while studying in 2001 [51]. It is a useful open-source
software tool [57] that can be easily used for visual design or implemented in other
őelds to allow human-machine interaction.
74
4.6 Signal acquisition
Signal acquisition is one of the most critical topics concerning electronics since
most interfaces and applications come from a deep knowledge of it. This section
will explore the theoretical concepts of signal acquisition (Subsection 4.6.1) and
how Arduino performs it (Subsection 4.6.2).
The sampler (Figure 4.7) allows the conversion of an analog signal xa ptq to a
discrete sequence xpnq, being this sequence created by storing the values of xa ptq
at constant time intervals Ts . This relation can be described by:
The quantizer (Figure 4.7) assigns a discrete amplitude value to each one of
the samples obtained by the sampler. The discrete amplitudes are divided into
amplitude ∆ intervals, and the samples xpnq amplitude is described according to
the possible values. The possible number of intervals depends on the number of
bits, meaning a higher number corresponds to higher precision.
75
After the quantization, the encoder (Figure 4.7) assigns a binary sequence to each
sampled and quantiőed value, obtaining the corresponding digital values to the
analogic input sequence.
The sampling rate selection is essential since we have to guarantee that after the
A/D conversion, we can obtain a reliable representation of the original signal. To
choose the sampling rate, we must consider Nyquist’s theorem (sampling theorem)
represented by [58, 59, 60]:
When the sampling theorem is respected (Equation 4.2), the original signal can
be reconstructed from its samples using a simple low-pass őlter without the
occurrence of aliasing [58, 60]. Aliasing can be characterized as distortion in signal
reconstruction due to a low sampling rate [61]. Figure 4.8 represents an example of
what happens when the sampling theorem is not respected, being the input signal
(represented in red) sampled at a sampling frequency lower than the minimum
frequency for the reconstruction of the original signal (Equation 4.2). The result
of the A/D conversion is represented in blue, where we can see the existence of
aliasing, obtaining a reconstructed signal that does not represent the original.
76
microcontrollers in the Arduino product family have A/D converters with 10 bits
of resolution [1, 15, 20]. Using this resolution, an input value between 0V and 5V
will correspond to decimal values between 0 and 1023 (210 ´ 1) and a resolution of
approximately 5 mV. The őrst A/D conversion takes 25 clock cycles since it needs
to perform the A/D converter initialization, while the following ones take 13 clock
cycles [15, 20]. If we consider a 1 MHz clock, and after the initialization of the A/D
converter, we will obtain the following:
106
Nsamples “ – 77000 – 77 kHz (4.3)
13
When we have a sampling frequency of 77 kHz and consider Equation 4.2, the
maximum signal frequency that can be sampled must be less or equal to 38.5 kHz to
respect the sampling theorem and avoid aliasing. The Arduino has a system clock
of 16 MHz. However, this is not the A/D converter input clock. The system clock
is divided by a division factor (prescaler), and this will be the A/D converter input
clock, as described in Figure 4.9.
77
The prescaler division factor can be deőned by changing the content of the ADPS0,
ADPS1, and ADPS2 bits from the ADCSRA register, as described in Figure 4.10. The
possible bits combination is summarized in Table 4.1.
As described before, and taking into account the deőned division factor, the A/D
clock source (Figure 4.9) will be given by:
System clock
A{Dclock “ (4.4)
Division f actor
Using Equation 4.4, we can obtain all the possible A/D converter clock sources in
MHz, as described in Table 4.2. When analyzing Table 4.2, we can conclude that
the highest sampling frequency obtained is approximately 8 MHz. This means the
maximum input signal frequency is 4 MHz to avoid aliasing. However, the values
presented in Table 4.2 are only theoretical. The actual values correspond to values
much lower than those shown, as described in Table 4.3.
78
Table 4.2: Possible A/D converter clock values.
The syntax that can change the division factor is described in Example 4.21. This
syntax does not only serve to change the content of the ADCSRA registry since
the same syntax can change any microcontroller register’s content. The available
registers, and their content and function, are available in the datasheet of the
respective microcontroller [15, 20].
79
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
void setup(){
example.begin(9600); //Serial communication initialization - baud rate
sbi(ADCSRA, ADPS2); //Set bit ADPS2 in registry ADCSRA
cbi(ADCSRA, ADPS1); //Clear bit ADPS1 in registry ADCSRA
cbi(ADCSRA, ADPS0); //Clear bit ADPS0 in registry ADCSRA
(.....) //Program code
}
void loop(){
b = micros() //Time in microseconds since the program started
a = analogRead(0); //Analog pin 0 reading is assigned to "a"
c = micros(); //Time in microseconds since the program started
Serial.print(c-b); //Sending the value "c-b" - Sampling time
(.....) //Program code
}
80
5 CONCLUSIONS
81
BIBLIOGRAPHY
[3] Fabio Nilvetti and Marco C De Simone. Test-rig for identiőcation and control
applications. In Programme and Proceedings of International Conference on
Vibration Problems (ICOVP-2013), pages 9ś12, 2013.
[4] Uğur Sarı, Hüseyin Miraç Pektaş, Ömer Faruk Şen, and Harun Çelik.
Algorithmic thinking development through physical computing activities
with arduino in stem education. Education and Information Technologies,
pages 1ś21, 2022. doi:10.1007/s10639-022-10893-0.
[6] Braumann Johannes and Brell-Cokcan Sigrid. Digital and physical computing
for industrial robots in architecture. interfacing arduino with industrial
82
robots. In Beyond Codes and Pixels: Proceedings of the 17th International
Conference on Computer-Aided Architectural Design Research in Asia, Hong
Kong, pages 317ś326, 2012.
[9] Pedro Plaza, Elio Sancristobal, German Carro, Manuel Blazquez, Félix García-
Loro, Sergio Martin, Clara Perez, and Manuel Castro. Arduino as an
educational tool to introduce robotics. In 2018 IEEE International Conference
on Teaching, Assessment, and Learning for Engineering (TALE), pages 1ś8.
IEEE, 2018. doi:10.1109/TALE.2018.8615143.
[14] Nuno Pessanha Santos. Introdução ao Arduino. Escola Naval, 2008. doi:
10.13140/RG.2.2.16840.80649.
83
[15] Atmel Corporation. ATMEGA328P - 8-bit avr microcontroller with 32k bytes
in-system programmable ŕash. Atmel Corporation, 2015. URL: https://
ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-A
utomotive-Microcontrollers-ATmega328P_Datasheet.pdf.
[17] Tianhong Pan and Yi Zhu. Designing Embedded Systems with Arduino.
Springer, 2018.
[21] Cathy Cox and Clay Merritt. Microcontroller oscillator circuit design
considerations. Freescale Semiconductor Application Note AN1706, 1997.
[22] Rob Dekker, Frans Beenker, and Loek Thijssen. A realistic fault model
and test algorithms for static random access memories. IEEE Transactions
on Computer-Aided Design of Integrated Circuits and Systems, 9(6):567ś572,
1990. doi:10.1109/43.55188.
84
Hemink, Koji Sakui, et al. An advanced nand-structure cell technology
for reliable 3.3 v 64 mb electrically erasable and programmable read only
memories (eeproms). Japanese journal of applied physics, 33(1S):524, 1994.
doi:10.1143/JJAP.33.524.
[24] Ming-yin Hao, Hyunsang Hwang, and Jack C Lee. Memory effects of silicon-
implanted oxides for electrically erasable programmable read-only memory
applications. Applied physics letters, 62(13):1530ś1532, 1993. doi:10.106
3/1.108630.
[25] Paulo Cappelletti, Carla Golla, Piero Olivo, and Enrico Zanoni. Flash
memories. Springer Science & Business Media, 2013.
[26] Paolo Pavan, Roberto Bez, Piero Olivo, and Enrico Zanoni. Flash memory
cells-an overview. Proceedings of the IEEE, 85(8):1248ś1271, 1997. doi:
10.1109/5.622505.
[27] Jivan S Parab, Vinod G Shelake, Rajanish K Kamat, and Gourish M Naik.
Exploring the capabilities of on-chip resources programming for i/o ports,
interrupts and timer/counter. Exploring C for Microcontrollers: A Hands on
Approach, pages 37ś67, 2007. doi:10.1007/978-1-4020-6067-0_4.
[28] W. J. Buchanan. RS-232, pages 239ś274. Springer US, Boston, MA, 2004. doi:
10.1007/978-1-4020-7870-5_11.
[29] Dawoud Shenouda Dawoud and Peter Dawoud. 6 - Serial Peripheral Interface
(SPI), pages 191ś244. River Publishers, 2020.
[30] Peter Corcoran. Two wires and 30 years: A tribute and introductory tutorial to
the I2C two-wire bus. IEEE Consumer Electronics Magazine, 2(3):30ś36, 2013.
doi:10.1109/MCE.2013.2257289.
85
[32] Marcel JM Pelgrom. Analog-to-digital conversion. In Analog-to-Digital
Conversion, pages 325ś418. Springer, 2013. doi:10.1007/978-1-461
4-1371-4_8.
[34] Pavel Fiala and Aleš Voborník. Embedded microcontroller system for
pilsencube picosatellite. In 2013 IEEE 16th International Symposium on
Design and Diagnostics of Electronic Circuits & Systems (DDECS), pages 131ś
134. IEEE, 2013. doi:10.1109/DDECS.2013.6549804.
[35] David José de Souza and Nicolas César Lavinia. Conectando o PIC 16F877A:
recursos avançados. Érica, 2008.
[38] Tom Igoe. Making things talk: Practical methods for connecting physical
objects. O’Reilly, Sebastopol, USA, 2007.
[41] Tsun S. Chow. Testing software design modeled by őnite-state machines. IEEE
transactions on software engineering, pages 178ś187, 1978.
86
[42] Christo Angelov, Krzysztof Sierszecki, and Nicolae Marian. Design models for
reusable and reconőgurable state machines. In International Conference on
Embedded and Ubiquitous Computing, pages 152ś163. Springer, 2005.
[44] Dale Wheat. Arduino software. In Arduino Internals, pages 89ś97. Springer,
2011. doi:10.1007/978-1-4302-3883-6_5.
[45] T. Jamil. Risc versus cisc. IEEE Potentials, 14(3):13ś16, 1995. doi:10.110
9/45.464688.
[49] Saul Gorn, Robert W Bemer, and Julien Green. American standard code for
information interchange. Communications of the ACM, 6(8):422ś426, 1963.
87
[53] Riazollah Firoozian. Servo motors and industrial control theory. Springer,
2014.
[54] Fabio Ruggiero, Miguel Angel Trujillo, Raul Cano, H Ascorbe, Antidio Viguria,
C Peréz, Vincenzo Lippiello, Aníbal Ollero, and Bruno Siciliano. A multilayer
control for multirotor uavs equipped with a servo robot arm. In 2015 IEEE
international conference on robotics and automation (ICRA), pages 4014ś
4020. IEEE, 2015.
[55] Miodrag Rakić. Multiőngered robot hand with selfadaptability. Robotics and
Computer-Integrated Manufacturing, 5(2-3):269ś276, 1989.
[56] Sai Kiran Oruganti and Ajit Khosla. 3d printing and wireless power transfer
systems for soft robotics applications. ECS Transactions, 98(13):55, 2020.
[58] Monson H Hayes. Schaum’s outline of theory and problems of digital signal
processing. McGraw-Hill, 1999.
[60] HJ Landau. Sampling, data transmission, and the nyquist rate. Proceedings of
the IEEE, 55(10):1701ś1706, 1967.
[61] Saeed V Vaseghi. Advanced digital signal processing and noise reduction. John
Wiley & Sons, 2008.
88