You are on page 1of 94

ARDUINO

INTRODUCTION AND ADVANCED RESOURCES

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

CHAPTER 1 INTRODUCTION PAGE 1

CHAPTER 2 HARDWARE VS. SOFTWARE PAGE 3


2.1 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1.1 Microprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.2 Microcontroller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.3 Available Memory Types and Amounts . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.4 Available Pinout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2 Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.1 Installation and Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.2 Development Cycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.3 Interaction with other Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

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

CHAPTER 5 CONCLUSIONS PAGE 81

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:

• Hardware vs. Software (Chapter 2) - This chapter explores Arduino as a


combination of hardware and software. Understanding each component
and how we can combine them is essential to develop our applications;

• Instruction Index (Chapter 3) - This chapter describes the most important


instructions used by the Arduino Integrated Development Environment
(IDE), giving an essential learning practical approach;

• Advanced Resources (Chapter 4) - This chapter presents in detail some


advanced resources that we can use. This list is not intended to be extensive
since many new implementations emerge almost daily;

• Conclusions (Chapter 5) - This chapter describes some conclusions and


thoughts that can motivate or inspire future work or studies in the area.

2
2 HARDWARE VS. SOFTWARE

Before starting to perform fast prototyping and system development, it is essential


to understand how the Arduino development platform works. Understanding
the relationship between hardware and software is crucial when using Arduino
to correctly comprehend its potential and limitations. We must maximize its
potential and simultaneously mitigate its limitations during its use. Hardware and
software are like puzzle pieces that we must use together to design a system. This
chapter is divided into the following two sections:

• Hardware (Section 2.1) - This section starts by exploring some basic


hardware concepts, like what is a microprocessor or a microcontroller. The
Arduino development board pinout, memory types, and amounts are also
analyzed to understand the used hardware better. Understanding the used
hardware is essential to know a priori if it is possible to develop the system
we want, exploring the existing potentials and limitations;

• 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:

• Microprocessor (Subsection 2.1.1) - This subsection brieŕy describes the


deőnition of a microprocessor, which is a critical component since it can
perform processing being the brain of a system;

• Microcontroller (Subsection 2.1.2) - This subsection explores the general


deőnition of a microcontroller and brieŕy introduces the block diagram of
the ATMega328P microcontroller [15] used in the Arduino Uno Rev 3 [12];

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);

• Available Pinout (Subsection 2.1.4) - This section represents the Arduino


pinout, which is essential for rapid prototyping and system development.
As described before, knowing the hardware’s potentialities and limitations
is critical for maximizing its use.

2.1.1 Microprocessor

A microprocessor is an integrated circuit with the capacity to execute speciőc


instructions [16] (Figure 2.2). Its processing speed is determined by a circuit that
produces a clock signal - an external signal that synchronizes its operations. Its
processing power is typically affected by characteristics such as communication
bus size (number of used bits), the number of cores, and the type of instructions
(Chapter 3), among many others. The microprocessor will read and execute the
programs stored in external memory. Combined with other components, it can be
used to develop and create standalone systems - embedded systems [17].

Figure 2.2: Microprocessor - Simpliőed schematic.

A microprocessor alone is not enough to perform prototyping and system


development since it needs to be combined with external hardware (Figure 2.2).

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

As described brieŕy in the previous subsection, a microcontroller is designed


and built to integrate several components (peripherals) into a single integrated
circuit. This integration avoids using external components when implementing
a standard microcontroller-based system (embedded system). Figure 2.3 shows
examples of the available components inside a microcontroller, assembling the
standard operation needed resources into a single integrated circuit [18, 19].

Figure 2.3: Microcontroller - Simpliőed schematic.

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]:

• AVR CPU - Central Processing Unit (CPU) or microprocessor [15, 20];

6
• Oscillator Circuits/Clock Generation - Signal (clock) that is used to
synchronize the microprocessor operations (synchronous operation) [21];

• Static Random-Access Memory (SRAM) - It is the main memory whose data


is lost when the power is not available - removed (volatile memory) [22];

• Electrically-Erasable Programmable Read-Only Memory (EEPROM) - It


is used to store data that is maintained when the power is not available -
removed (non-volatile memory) [23, 24];

• 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];

• 8bit or 16bit Timer/Counter (T/C) - A timer/counter that can be used to


measure time intervals or the number of times a speciőc event occurs [27];

• Universal Synchronous Asynchronous Receiver Transmitter (USART)


- Used to implement communications over a serial port (socket that
implements a serial interface) using the RS232 standard [28];

• Serial Peripheral Interface (SPI) - It is used to implement a synchronous


serial communication interface in short-distance communications [29];

• Two-Wire Interface (TWI) - It is used to implement a simple serial


communication protocol that uses just two pins (wires) [30];

• Analog-to-Digital converter (A/D) - Used to convert analogic into digital


signals to perform data processing using the microprocessor [31, 32];

• Watchdog - It monitors the running program in speciőc time intervals,


checking if it stops or presents an unexpected behavior [33, 34].

This section is not intended to be an extensive microcontroller review. You should


consult the used microcontroller datasheet for a more detailed description of its
components and operating modes [1, 15, 20].

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].

Flash Used to store the sketch & the bootloader (non-volatile)


SRAM It is used to store variables during program execution (volatile)
EEPROM It can be used to store information (non-volatile)

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

Analyzing the available Arduino Uno Rev 3 pinout is essential to understand


what can be used for fast prototyping and system development using this model
(Figure 2.5). This model has several analogic and digital pins (Table 2.3), allowing
a maximum current of 40 mA. The only exception is the 3.3 V (3V3) pin that allows
a maximum current of 50 mA.

Figure 2.5: Arduino Uno Rev 3 - Schematic representation.

Table 2.3: Arduino Uno Rev 3 - Available pinout [12].

Digital Input/Output 14 (6 with Pulse Width Modulation - PWM)


Analog Input 6
Ground (GND) 3
5V 1
3.3 V 1
Analog Reference (AREF) 1
Reset (RST) 1

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).

Figure 2.7: Pulse Width Modulation signal example.

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]:

Vres “ Aref ˜ 2res ô Vres “ 5 ˜ 210 – 0.00488 V – 5 mV (2.4)

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 ):

Vres “ Aref ˜ 2res ô Vres “ 2 ˜ 210 – 1.953 V – 2 mV (2.5)

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.

analogReference(type) //"DEFAULT", "INTERNAL" or "EXTERNAL"


analogReference(DEFAULT) //Keeps the default 5V reference
analogReference(INTERNAL) //Changes the reference to 1.1V (ATMega328P)
analogReference(EXTERNAL) //AREF input pin is used as a reference

Example 2.1: analogReference() - Description [15, 37].

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).

2.2.1 Installation and Use

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).

Figure 2.8: Arduino website - Software tab [1].

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.

Figure 2.10: FTDI pinout - Illustration [38].

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.

Figure 2.11: Arduino IDE - Board & Serial port conőguration.

2.2.2 Development Cycle

As initially described in the previous subsection, the development cycle is critical


for prototyping and system development. A standard development cycle can be
divided into the following four stages (Figure 2.12 and Figure 2.13):

• 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];

• Compile - In this stage, we convert our sketch written in a high-level


programming language that is understandable by humans to a low-level
binary language that is understood by the Arduino microcontroller [43];

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.

Figure 2.12: Standard application development cycle schematic - Illustration.

Figure 2.13: Development cycle schematic - Illustration using Arduino.

2.2.3 Interaction with other Software

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].

Figure 2.15: Arduino website - Playground tab content [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]:

• Complex Instruction Set Computers (CISC) - This architecture uses


instructions with complex addressing modes, making it possible to create
very compact programs by resorting to fewer instructions. As a disadvantage,
this architecture requires a high clock cycle to be able to execute its functions
fast and typically has multiple different addressing modes increasing its
complexity;

• Reduced Instruction Set Computers (RISC) - This architecture uses


minimal simple and fast instructions. Since we are using a higher number
of instructions with shorter execution times to perform the same task, using
this architecture and optimizing the program, we will typically obtain a faster
processing speed when compared with the CISC architecture.

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;

• Types of available variables (Section 3.3) - This section describes the


variable types and how we can deőne and use them in our sketch;

• Digital Input/Output (Section 3.4) - This section describes the functions


used to read or change the digital pins’ state;

• Analog Input/Output (Section 3.5) - This section describes the functions


used to read the analogic pins;

• 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;

• Mathematical functions (Section 3.7) - This section describes the functions


that can be used to perform mathematical operations on data variables;

• Trigonometric functions (Section 3.8) - This section describes the


functions that can be used to perform trigonometric operations on data
variables;

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;

• Interrupts (Section 3.10) - This section describes interrupts which are


events that temporarily suspend the main program and can be used to
perform speciőc changes in the main program ŕow;

• Serial communication (Section 3.11) - This section describes the functions


that can be used to communicate over a serial port, sending or receiving data.

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.

3.1 Base functions


As initially described, this section will explore the two main functions to be
implemented when developing our sketch - setup and loop. Utilizing these
functions is mandatory, even if their use is considered unnecessary (what does not
happen). The setup function (Subsection 3.1.1) is used to perform initialization,
and the loop function (Subsection 3.1.2) is used to create a loop containing a set
of instructions that will be continuously executed. Both functions are necessarily
from the void type since they cannot return any value after execution. The
implementation of both functions is described in Example 3.1.
void setup(){ //Instruction set executed at the system (board) start
(.....) //Program code
}

void loop(){ //Instruction set that runs in a loop


(.....) //Program code
}

Example 3.1: Setup & Loop functions - Description.

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.

int button=3; //Integer variable "button" initialized with value "3"


(.....) //Global variables initialization

void setup(){ //Instruction set executed at the system (board) start


Serial.begin(9600); //Serial communication initialization - baud rate
pinMode(button,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}

void loop(){ //Instruction set that runs in a loop


(.....) //Program code
}

Example 3.2: Setup function - Example.

3.1.2 Loop

The loop function allows the execution of a speciőc set of instructions in a


successive loop (Example 3.3). This continuous loop allows, for example, to
continuously monitor the input value from an external sensor and take a speciőc
action according to predeőned conditions. The successive read and condition
test of the value of a particular pin (monitoring) is called polling. During the
sketch design, you must use your creativity to ensure that the developed prototype
will have the desired behavior as an embedded system. As described before, this
function is from the void type since it cannot return any value after execution.

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

void setup(){ //Instruction set executed at the system (board) start


Serial.begin(9600); //Serial communication initialization - baud rate
pinMode(sensor,INPUT); //Allows the set of pin 3 as "INPUT"
pinMode(12,INPUT); //Allows the set of pin 12 as "INPUT"
pinMode(13,OUTPUT); //Allows the set of pin 13 as "OUTPUT"
(.....) //Program code
}

void loop(){ //Instruction set that runs in a 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)
}
if(val<500){ //Test if "val" is less than 500
digitalWrite(13,LOW); //If true, the digital pin 13 turns "LOW" (0V)
}
(.....) //Program code
}

Example 3.3: Loop function - Example.

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.

if(condition){ //Test condition


Instruction 1; //If true
(.....) //Program code
} else{ //The use of the "else" statement is dispensable
Instruction A; //If false
(.....) //Program code
}

Example 3.4: If/Else cycle - Description.

According to the adopted structure, certain instructions (instruction set) can be


executed when a condition variable is equal, greater, lesser, or different than a
speciőc value, as described in Table 3.1.

Table 3.1: Possible conditions - X vs. Y.

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.

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(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
}

Example 3.5: If/Else cycle - Example.

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++"

Example 3.6: For cycle - Description.

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
}

Example 3.7: For cycle - Example.

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
}

Example 3.8: Switch/Case cycle - Description.

An illustration of implementing the switch/case cycle can be seen in Example 3.9.


The integer variable val is continuously tested, and if it achieves a value equal to
500, the digital pin 13 turns HIGH (5 V). If the condition is not met (false), and
since we have deőned what happens in that case through the default condition,
the digital pin 13 turns LOW (0 V). If pin 13 is already at a LOW state, the system
will not have any change in its output when the condition is not met (default
case execution). Since all the cycles are included inside the loop function, the
conditions are continuously tested (polling ). When developing the sketch, we
must consider this to ensure that the system has the expected behavior.

int sensor=3; //Integer variable "button" initialized with value "3"


int val; //Initialization of the integer variable "val"
(.....) //Global variables initialization

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
}

Example 3.9: Switch/Case cycle - Example.

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
}

Example 3.10: While cycle - Description.

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.

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
int i = 0; //Integer variable "i" initialized with value "0"
(.....) //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(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
}

Example 3.11: While cycle - Example.

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);

Example 3.12: Do/While cycle - Description.

An example of the do/while cycle implementation can be seen in Example 3.13.


The cycle is always executed once since the condition is only tested at the end of
the cycle. At the end of the cycle, if the integer variable i is less than or equal to 10,
the tested condition is met, and 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
int i = 0; //Integer variable "i" initialized with value "0"
(.....) //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(){
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
}

Example 3.13: Do/While cycle - Example.

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).

boolean variable = value; //"value" can be "true" or "false"

Example 3.14: Boolean variable - Description.

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.

boolean test = false; //Boolean variable "test" with value "false"


int i = 0; //Integer variable "i" initialized with value "0"
(.....) //Global variables initialization

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
}

Example 3.15: Boolean variable - Example.

3.3.2 Char vs. Unsigned char

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

Example 3.16: Char vs. Unsigned char variables - Description.

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"

Example 3.17: Char vs. Unsigned char variables - Example.

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"

Example 3.18: Byte variable - Description.

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"

Example 3.19: Byte variable - Example.

3.3.4 Int vs. Unsigned int

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"

Example 3.20: Int vs. Unsigned int variables - Description.

An example of using integer and unsigned integer variables can be seen in


Example 3.21. These variables can be assigned directly using a decimal number.
int example = -150; //Decimal "-150" is assigned to "example"
int example_1 = -32768; //Decimal "-32768" is assigned to "example_1"
unsigned int ex_3 = 65535; //Decimal "65535" is assigned to "ex_3"

Example 3.21: Int vs. Unsigned int variables - Example.

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"

Example 3.22: Long vs. Unsigned long variables - Description.

An example of using a long and unsigned long variables can be seen in


Example 3.23. These variables can be assigned directly using a decimal number.
long ex = -15000000; //Decimal "-15000000" is assigned to "ex"
unsigned long ex_1 = 4000000; //Decimal "4000000" is assigned to "ex_1"

Example 3.23: Long vs. Unsigned long variables - Example.

3.3.6 Float vs. Double

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"

Example 3.24: Float vs. Double variables - Description.

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"

Example 3.25: Float vs. Double variables - Example.

3.3.7 Array vs. String

An array variable is a vector containing several same-type variables that can be


accessed using an index number. A string variable is commonly used to designate
an array of char variables (Example 3.26).
variable_type variable_name[index] = val; //Array initialization

Example 3.26: Array vs. String variables - Description.

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

Example 3.27: Array vs. String variables - Example.

3.4 Digital Input/Output


This section will describe the functions that can manage the interface with the
digital pins, allowing the read (input) or write (output) of digital values. We
must know how to interface with the world around us, and it is essential to read,
process, and act on it. As will be described, we can use the pinMode() function
(Subsection 3.4.1) to deőne the digital pin as input or output, the digitalWrite()
function (Subsection 3.4.2) to deőne a pin as HIGH (5 V) or LOW (0 V), and the

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"

Example 3.28: pinMode() - Description.

An example of using the pinMode() function can be seen in Example 3.29. We


can deőne the digital pins as INPUT or OUTPUT according to the desired system
behavior.
(.....) //Global variables initialization

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
}

Example 3.29: pinMode() - Example.

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"

Example 3.30: digitalWrite() - Description.

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.

int sensor=3; //Integer variable "sensor" initialized with value "3"


int val; //Initialization of the integer variable "val"
(.....) //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(){
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
}

Example 3.31: digitalWrite() - Example.

3.4.3 digitalRead

Using the digitalRead() function, it is possible to read a speciőc digital pin


returning an integer value (Example 3.32). If the input voltage is 5 V (HIGH ), we
obtain the integer value 1 (logical value 1). If that is not the case, and we have an
input value of 0 V (LOW ), we obtain the integer value 0 (logical value 0).

Integer variable = digitalRead(Pin number);

Example 3.32: digitalRead() - Description.

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.

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==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
}

Example 3.33: digitalRead() - Example.

3.5 Analog Input/Output


This section will describe the functions that can manage the interface with the
analogic pins, allowing the read (input) and write (output). The vast majority of the
sensors we can use to acquire data from the surrounding world are analogic, and it
is essential to be able to read their measurements. As will be described, we can use
the analogRead() function (Subsection 3.5.1) to read the voltage value arriving at

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

Using the analogRead() function, it is possible to perform analogic-to-digital


conversion and read a speciőc analogic input (voltage value) using 10 bits of
resolution (Example 3.34). Having a 10 bits resolution (210 ) means that an input
voltage value between 0 V and 5 V will be mapped to an integer value between 0
and 1023.
Integer_variable = analogRead(Pin number);

Example 3.34: analogRead() - Description.

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
}

Example 3.35: analogRead() - Example.

38
3.5.2 analogWrite

Using the analogWrite() function, it is possible to emulate a PWM signal with a


constant frequency of approximately 490 Hz (Example 3.36). We can vary the
obtained equivalent DC voltage by changing the signal duty cycle, as described in
Subsection 2.1.4.

analogWrite(Pin number, value); //"value" between 0 (0V) and 255 (5V)

Example 3.36: analogWrite() - Description.

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.

int sensor=3; //Integer variable "sensor" initialized with value "3"


int out=9; //Integer variable "out" initialized with value "9"
int val; //Initialization of the integer variable "val"
(.....) //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(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
}

Example 3.37: analogWrite() - Example.

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

Using the millis() function, it is possible to return the amount of time in


milliseconds since the program started running (Example 3.38). The counter will
overŕow (back to zero) after approximately 50 days of execution when using an
unsigned long variable.
unsigned long time = millis(); //"time" will be in milliseconds

Example 3.38: millis() - Description.

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
}

Example 3.39: millis() - Example.

40
3.6.2 micros

Using the micros() function, it is possible to return the amount of time in


microseconds since the program started running (Example 3.40). The counter will
overŕow (back to zero) after approximately 70 minutes of execution when using an
unsigned long variable.

unsigned long time = micros(); //"time" will be in microseconds

Example 3.40: micros() - Description.

An example of using the micros() function can be seen in Example 3.41. As


stated before, this function will return the time in microseconds since the program
started.

unsigned long time; //Unsigned long variable "time"


(.....) //Global variables initialization

void setup(){
(.....) //Program code
}
void loop(){
time = micros(); //Time in microseconds since the program started
(.....) //Program code
}

Example 3.41: micros() - Example.

3.6.3 delay

Using the delay() function, it is possible to perform a speciőed number of


milliseconds of time delay in the running program (Example 3.42). For example,
this function can be useful to maintain a state for a certain amount of time.

delay(t); //The time delay in milliseconds is given by "t"

Example 3.42: delay() - Description.

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.

int led=13; //Integer variable "led" initialized with value "13"


(.....) //Global variables initialization

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
}

Example 3.43: delay() - Example.

3.6.4 delayMicroseconds

Using the delayMicroseconds() function, it is possible to perform a speciőed


number of microseconds of time delay in the running program (Example 3.44). For
example, and as described before, this function can be useful to maintain a state
for a certain amount of time.

delayMicroseconds(t); //The time delay in microseconds is given by "t"

Example 3.44: delayMicroseconds() - Description.

An illustration of using the delayMicroseconds() function can be seen in


Example 3.45. This can be useful to suspend the running program for a predeőned
time interval according to the desired system behavior.

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
}

Example 3.45: delayMicroseconds() - Example.

3.7 Mathematical Functions


This section will describe the functions used to perform mathematical operations
in the program variables. As will be described, we can use the min() function
(Subsection 3.7.1) to compare two values and return the smallest one, the max()
function (Subsection 3.7.2) to compare two values and return the highest one,
the abs() function (Subsection 3.7.3) that can be used to return the modulus of
a speciőc number, the constrain() function (Subsection 3.7.4) that can be used
to return a value limited to a speciőc user-deőned range, the map() function
(Subsection 3.7.5) that can be used to perform a mapping between range sets, the
pow() function (Subsection 3.7.6) that can be used to obtain the power of a number,
and the sqrt() function (Subsection 3.7.7) that can be used to obtain the square root
of a number.

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.

Smaller_variable = min(value1, value2);

Example 3.46: min(value1, value2) - Description.

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.

int S = min(5,9); //The value assigned to "S" is "5"

Example 3.47: min(value1, value2) - Example.

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.

Highest_variable = max(value1, value2);

Example 3.48: max(value1, value2) - Description.

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.

int H = max(5,9); //The value assigned to "H" is "9"

Example 3.49: max(value1, value2) - Example.

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

Example 3.50: abs(value) - Description.

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.

int Module = 0; //Integer variable "Module" initialized with value "0"


Module = abs(-5); //The value assigned to "Module" is "5"

Example 3.51: abs(value) - Example.

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.

val = constrain(value, value1, value2);


val = constrain(test value, lower range value, upper range value);
//"val" = "value" if "value" is located inside ["value1","value2"]
//"val" = "value1" if "value" is lower than "value1"
//"val" = "value2" if "value" is higher than "value2"

Example 3.52: constrain(value, value1, value2) - Description.

An example of using the constrain() function can be seen in Example 3.53. As


described before, this function will return a value limited to a speciőc user-deőned
range that can be useful to deőne a speciőc variable interval for data processing.

int val = 0; //Integer variable "val" initialized with value "0"


val = constrain(5,2,10); //The value assigned to "val" is "5"

Example 3.53: constrain(value, value1, value2) - Example.

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.

new_interval_value = map(value, value1, value2, value 3, value 4);


//"value" is the value to map
//"value1" is the lower bound of the current range
//"value2" is the upper bound of the current range
//"value3" is the lower bound of the new range to take into account
//"value4" is the upper bound of the new range to take into account

Example 3.54: map(value, value1, value2, to value 3, to value 4) - Description.

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.

int val; //Initialization of the integer variable "val"


int f[10]; //Integer array initialization with 11 memory positions
(.....) //Global variables initialization

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
}

Example 3.55: map(value, value1, value2, to value 3, to value 4) - Example.

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.

Obtained_value = pow(value, exponent);

Example 3.56: pow(value, exponent) - Description.

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.

int val = 0; //Integer variable "val" initialized with value "0"


val = pow(2,2); //The value assigned to "val" is "4"

Example 3.57: pow(value, exponent) - Example.

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);

Example 3.58: sqrt(value) - Description.

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.

int val = 0; //Integer variable "val" initialized with value "0"


val = sqrt(9); //The value assigned to "val" is "3"

Example 3.59: sqrt(value) - Example.

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

Example 3.60: sen(value) - Description.

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

Example 3.61: cos(value) - Description.

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

Example 3.62: tan(value) - Description.

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.

randomSeed(value); //"value" is a decimal number

Example 3.63: randomSeed(value) - Description.

An example of using the randomSeed() function can be seen in Example 3.64. By


changing this value, we can add randomness to the obtained sequence of numbers.

int seed=24; //Integer variable "seed" initialized with value "24"


(.....) //Global variables initialization

void setup(){
randomSeed(seed) //Change the point where the sequence starts
(.....) //Program code
}
void loop(){
(.....) //Program code
}

Example 3.64: randomSeed(value) - Example.

49
3.9.2 random

Using the random() function, it is possible to generate random numbers (pseudo-


random numbers), as described in Example 3.65.

Result = random(value); //"value" is the maximum possible value


Result = random(v1, v2); //"v1" is the minimum & "v2" is the maximum
//The maximum value "v2" is not included in the considered interval
//"Result" belongs to the interval ["v1", ("v2"-1)]

Example 3.65: random() - Description.

An example of using the random() function can be seen in Example 3.66. We


can generate random numbers inside a speciőc interval that can be used in our
program according to the desired embedded system behavior.

int seed=24; //Integer variable "seed" initialized with value "24"


long random_value; //Unsigned long variable "random_value"
(.....) //Global variables initialization

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
}

Example 3.66: random() - Example.

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

Using the attachInterrupt() function, it is possible to deőne the operation of


an external interrupt (Example 3.67). Using this instruction, we can deőne the
function to be executed, the pin where the interrupt will occur, and what signal
variation will be considered.

attachInterrupt(interrupt, function, mode);


//Arduino Uno Rev. 3
//interrupt == 0 corresponds to digital pin "2"
//interrupt == 1 corresponds to digital pin "3"

//Arduino Mega Rev. 3


//interrupt == 0 corresponds to digital pin "2"
//interrupt == 1 corresponds to digital pin "3"
//interrupt == 2 corresponds to digital pin "21"
//interrupt == 3 corresponds to digital pin "20"
//interrupt == 4 corresponds to digital pin "19"
//interrupt == 5 corresponds to digital pin "18"

//Notes:
//The defined "function" should be from the void type
//"mode" defines how an external interrupt is recognized

Example 3.67: attachInterrupt(interrupt, function, mode) - Description.

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.

LOW Interrupt is performed whenever the logical value on the pin is 0 (0 V)


CHANGE Interrupt is performed whenever the logical value on the pin changes
RISING Interrupt is performed whenever the pin changes from 0 (0 V) to 1 (5 V)
FALLING Interrupt is performed whenever the pin changes from 1 (5 V) to 0 (0 V)

3.10.2 detachInterrupt

Using the detachInterrupt() function (Example 3.68), it is possible to disable a


previously deőned interrupt using the attachInterupt() function, as described in
Subsection 3.10.1. This function can be used inside a speciőc test condition to
control the system’s behavior over time.

detachInterrupt(interrupt);
//Arduino Uno Rev. 3
//interrupt == 0 corresponds to digital pin "2"
//interrupt == 1 corresponds to digital pin "3"

//Arduino Mega Rev. 3


//interrupt == 0 corresponds to digital pin "2"
//interrupt == 1 corresponds to digital pin "3"
//interrupt == 2 corresponds to digital pin "21"
//interrupt == 3 corresponds to digital pin "20"
//interrupt == 4 corresponds to digital pin "19"
//interrupt == 5 corresponds to digital pin "18"

Example 3.68: detachInterrupt(interrupt) - Description.

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

Example 3.69: interrupts() - Description.

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
}

Example 3.70: interrupts() - Example.

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

Example 3.71: noInterrupts() - Description.

An example of using the noInterrupts() function can be seen in Example 3.72. We


can use it to disable interrupts during the program execution easily.
void setup(){
(.....) //Program code
}

void loop(){
noInterrupts(); //Instruction that disables the use of interrupts

53
(.....) //Program code
interrupts(); //Instruction that enables the use of interrupts
(.....) //Program code
}

Example 3.72: noInterrupts() - Example.

3.11 Serial communication


This section will describe the functions of controlling serial data communication
between devices. As will be described, the Serial.available() function
(Subsection 3.11.1) can be used to obtain the number of bytes received, the
Serial.begin() function (Subsection 3.11.2) can be used to start the serial
communication, the Serial.read() function (Subsection 3.11.3) can be used
to read data from the serial port, the Serial.flush() function (Subsection 3.11.4)
can be used to erase all the existing data in the input buffer, the Serial.print()
and Serial.println() functions (Subsection 3.11.5) can be used to send decimal,
hexadecimal, and octal data through the serial port and the Serial.write() function
(Subsection 3.11.6) can be used to send binary data through the serial port.

3.11.1 Serial.available

Using the Serial.available() function (Example 3.73), it is possible to obtain the


number of bytes received using the serial port. Using this function, it is possible
to check if we are receiving data to be able to adjust the program ŕow.

int Number_bytes = Serial.available(); //Number of received bytes

Example 3.73: Serial.available() - Description.

An example of using the Serial.available() function can be seen in Example 3.74.


We can use this function to check if we receive data via serial port and only perform
some action when some data is received.

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
}

Example 3.74: Serial.available() - Example.

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.

Serial.begin(int baud rate); //Defining the baud rate

Example 3.75: Serial.begin() - Description.

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.

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

55
}

void loop(){
(.....) //Program code
}

Example 3.76: Serial.begin() - Example.

3.11.3 Serial.read

Using the Serial.read() function (Example 3.77), it is possible to read data


throughout the serial port. This function will return -1 if no data is available.

Received_data = Serial.read(); //Data received through the serial port

Example 3.77: Serial.read() - Description.

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.

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
}

Example 3.78: Serial.read() - Example.

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.

Serial.flush(); //Flush (erase) the input buffer

Example 3.79: Serial.flush() - Description.

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
}

Example 3.80: Serial.flush() - Example.

3.11.5 Serial.print vs Serial.println

Using the Serial.print() and Serial.println() functions (Example 3.81), it is possible


to send data through the serial port. The main difference between the functions
is that the Serial.println() function also sends with the data a carriage return and
new-line characters.

Serial.print(data);
//data == Can be a string
Serial.print(data, format);
//format == "DEC" Decimal, "HEX" Hexadecimal or "OCT" Octal

Example 3.81: Serial.print() vs Serial.println() - Description.

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
}

Example 3.82: Serial.print() vs Serial.println() - Example.

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

Example 3.83: Serial.write() - Description.

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

This chapter will explore advanced resources essential to most applications,


making it easier to perform system design and prototyping. The advanced
resources explored in this chapter do not represent the totality of the existing
ones since new ones emerge almost daily. This chapter will also describe
external libraries that simplify the implementations. These libraries can be easily
downloaded using the library manager when not directly available in the Arduino
IDE. This chapter is divided into the following sections:

• Flash memory (Section 4.1) - This section describes some functions that
can be used to read and write directly from the Flash memory;

• EEPROM memory (Section 4.2) - This section describes some functions


that can be used to read and write directly from the EEPROM memory;

• Servo motor (Section 4.3) - This section describes an interface that can be
used to control servo motors easily;

• Software serial communication (Section 4.4) - This section describes in


detail a software serial communication implementation that can be used
to increase the number of possible simultaneous communications with
external devices (overcome a hardware limitation);

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];

• Signal acquisition (Section 4.6) - This section explores the theoretical


concepts of signal acquisition and how Arduino performs it.

4.1 Flash memory


In a microcontroller (Subsection 2.1.2), the amount of available SRAM memory
is usually much smaller than the available Flash memory. As described in
Subsection 2.1.3, Arduino is not an exception, and the available memory easily
becomes a limitation in programs that use many or large variables. Considering
this, an obvious solution would be to use Flash memory to store some variables.
The only limitation in the Flash memory utilization is that the writing can only be
performed during the program upload. This means we should only use Flash to
store constant variables to avoid taking up SRAM space unnecessarily. To interface
easily with the Flash memory, the Flash library [52] will be used, which is not
included initially in the IDE software but can be easily downloaded using the
Arduino library manager. This library simpliőes the write (Subsection 4.1.1) and
read (Subsection 4.1.2) operations, making them simple to perform.

4.1.1 Writing data

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.

FLASH_STRING(name, data); //"data" is a string


FLASH_ARRAY(type, name, data); //"type" define the "data" type
FLASH_TABLE(type, name, columns, data); //"columns" defines table width
FLASH_STRING_ARRAY(name, PSTR(data), PSTR(data), ...); //PSTR notation

Example 4.1: Flash library writing - Description.

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
}

Example 4.2: Flash library writing - Example.

4.1.2 Reading data

As described in the previous subsection, reading data is also 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.3.
name[index]; //"index" defines the read vector position
sizeof(name); //Return the variable "name" size
name.length(); //Return the length of the variable "name"
name.rows(); //Return a FLASH_TABLE variable "name" number of rows
name.cols(); //Return a FLASH_TABLE variable "name" number of columns
name.copy(variable, size, offset); //Copy variable "name" content
name.print(Serial); //Print the variable using serial communication

Example 4.3: Flash library reading - Description.

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.

#include <Flash.h> //Include the used Flash 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(){
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
}

Example 4.4: Flash library reading - Example.

4.2 EEPROM memory


As described in Subsection 2.1.3, the Arduino Uno Rev 3 has 1 kilobyte [12, 15]
and the Arduino Mega Rev 3 has 4 kilobytes [13, 20] of EEPROM memory. This
type of memory has the advantage of storing the information even after a turn-
off or reset since it is non-volatile. Another advantage is the capacity to store
information during the program execution, which does not happen with Flash

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].

4.2.1 Writing data

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

Example 4.5: EEPROM library writing - Description.

The process of writing variables in EEPROM memory is represented in Example 4.6.


As described, writing in the EEPROM memory can be made during the program
execution (loop function). The average writing time is about 3.3 milliseconds,
having an expected life cycle of approximately 100 thousand write cycles [15, 20].
#include<EEPROM.h> //Include the used EEPROM library

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
}

Example 4.6: EEPROM library writing - Example.

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

Example 4.7: EEPROM library reading - Description.

The process of reading variables in EEPROM memory is described in Example 4.8.


As described, writing in the EEPROM memory can be made during our program
execution (loop function). We should continuously read the EEPROM content to
consider the most recent memory value.
#include<EEPROM.h> //Include the used EEPROM library

int r=0; //Integer variable "r" initialized with value "0"


int r_2=0; //Integer variable "r" initialized with value "0"
(.....) //Global variables initialization

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
}

Example 4.8: EEPROM library reading - Example.

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

To start the conőguration, an auxiliary variable must be assigned to an Arduino


pin to create the servo motor conőguration. As described in Example 4.9, after the
variable creation, we can easily set a pin to perform servo motor control.

Servo servo_name; //Servo motor variable creation "servo_name"


servo_name.attach(pin) //Set servo motor "pin" number
servo_name.attach(pin, min, max) //Optional
//"min" pulse width of the minimum angle - 0 degrees (microseconds)
//"max" pulse width of the maximum angle - 180 degrees (microseconds)
servo_name.detach() //Detach the servo motor variable from its pin

Example 4.9: Servo motor library conőguration - Description.

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.

#include<Servo.h> ////Include the used Servo library

Servo example; //Servo variable "example"


Servo example2; //Servo variable "example2"
(.....) //Global variables initialization

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
}

Example 4.10: Servo motor library conőguration - Example.

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).

Servo servo_name; //Servo motor variable creation "servo_name"


servo_name.write(angle) //Standard - Move to "angle" (degrees)
servo_name.write(s) //Continuous rotation - "s" is the rotation speed

Example 4.11: Servo motor library control - Description.

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.

#include<Servo.h> ////Include the used Servo library

Servo example; //Servo variable "example"


Servo example_2; //Servo variable "example_2"
(.....) //Global variables initialization

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
}

Example 4.12: Servo motor library control - Example.

4.3.3 Angle read

During the program execution, and depending on the desired application,


obtaining the last control command used to control the servo motor may be
essential, as described in Example 4.13.

Servo servo_name; //Servo motor variable creation "servo_name"


int angle = servo_name.read() //Returns the last write function value

Example 4.13: Servo motor library read - Description.

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.

#include<Servo.h> ////Include the used Servo library

Servo example; //Servo variable "example"


int angle=0; //Integer variable "angle" initialized with value "0"
(.....) //Global variables initialization

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
}

Example 4.14: Servo motor library read - Example.

4.4 Serial communication


When we are developing a system, it is possible that we need to use other
pins to perform serial communication than the standard ones. We can use an
additional library to simplify this implementation, expanding the Arduino board
communication capabilities by implementing serial communication on more
pins. As described in Subsection 2.1.2, the standard serial communication is
synchronous and is implemented using a USART, as described in Figure 4.3.
When implementing serial communication, we can have a synchronous
(Figure 4.3) or asynchronous (Figure 4.4) operation with distinct operating modes.
The synchronous communication is based on a master and slave implementation,

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.

Figure 4.4: Asynchronous serial communication - Illustration.

It is possible to simulate software asynchronous serial communication using an


additional library. Since we are not using the USART hardware, we will not
have an input buffer, losing all the information we did not read when it was
received. This library is initially included in the Arduino IDE without downloading
it using the Arduino library manager. It simpliőes the software serial conőguration
(Subsection 4.4.1), read (Subsection 4.4.2) and transmit (Subsection 4.4.3) data
operations, making them simple to perform.

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.

SoftwareSerial name; //Software serial variable creation "name"


SoftwareSerial name = SoftwareSerial(Pin_1, Pin_2);
//"Pin_1" is the receiver (Rx) pin
//"Pin_2" is the transmission (Tx) pin
name.begin(baud_rate); // Serial communication initialization

Example 4.15: Software serial library conőguration - Description.

The process of conőguring the software serial communication is described in


Example 4.16. When performing this conőguration, it is also necessary to conőgure
the communication baud rate that should be ideally less or equal to 9600 baud and
deőne the used pins as input and output.

#include<SoftwareSerial.h> ////Include the used Serial library

SoftwareSerial example = SoftwareSerial(4,5); //Rx - Pin 4 & Tx - Pin 5


(.....) //Global variables initialization

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
}

Example 4.16: Software serial library conőguration - Example.

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.

SoftwareSerial name = SoftwareSerial(Pin_1, Pin_2);


//"Pin_1" is the receiver (Rx) pin
//"Pin_2" is the transmission (Tx) pin
char received; //Initialization of the char variable "received"
received=name.read(); //The received value is stored on "received"

Example 4.17: Software serial library read data - Description.

The process of reading data using a software serial communication is described in


Example 4.18. As described before, since we will not have an input buffer available,
all the data received without immediate reading will be lost.

#include<SoftwareSerial.h> ////Include the used Serial library

SoftwareSerial example = SoftwareSerial(4,5); //Rx - Pin 4 & Tx - Pin 5


char received; //Initialization of the char variable "received"
(.....) //Global variables initialization

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
}

Example 4.18: Software serial library read data - Example.

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

Example 4.19: Software serial library transmit data - Description.

The process of transmitting data using a software serial communication is


described in Example 4.20. Since software implements this transmission, it is
recommended that the baud rate is less or equal to 9600 baud to avoid errors.
#include<SoftwareSerial.h> ////Include the used Serial library

SoftwareSerial example = SoftwareSerial(4,5); //Rx - Pin 4 & Tx - Pin 5


char received; //Initialization of the char variable "received"
(.....) //Global variables initialization

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
}

Example 4.20: Software serial library transmit data - Example.

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.

Figure 4.5: Hello World - Processing [51].

Figure 4.6: Graphic objects example - Processing.

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).

4.6.1 Theoretical Concepts

We usually consider a continuous signal sampled using a speciőc sampling rate


when performing processing. To perform sampling of an analogic signal, we have
to use an A/D converter as described in Figure 4.7. The basic constitution of an
A/D are [58]: (i) sampler or continuous-to-discrete (C/D), (ii) quantizer, and (iii)
encoder.

Figure 4.7: A/D converter - Illustration.

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:

xpnq “ xa pnTs q n ϵ N ` (4.1)

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]:

fsampling ě 2 ˆ fsignal (4.2)

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.

Figure 4.8: Aliasing - Illustration.

4.6.2 Arduino analysis

After brieŕy describing the theoretical concepts behind signal acquisition, it is


essential to explore how the Arduino microcontroller performs it. The used

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.

Figure 4.9: A/D converter prescaler [15].

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.

Figure 4.10: ADCSRA registry [15].

Table 4.1: Division factor combinations [15].

ADPS2 ADPS1 ADPS0 Division factor (prescaler)


0 0 0 2
0 0 1 2
0 1 0 4
0 1 1 8
1 0 0 16
1 0 1 32
1 1 0 64
1 1 1 128

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.

Division factor A/D clock (MHz)


2 8
4 4
8 2
16 1
32 0.5
64 0.25
128 0.125

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].

//Function definition - Simplification


#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
sbi(Registry,bit); //Set "bit" in "registry"
cbi(Registry,bit); //Clear "bit" in "registry"

Example 4.21: Division factor (prescaler) - Description.

An illustration of the ADCSRA registry conőguration can be seen in Example 4.22.


In this example, it is also implemented in the loop function, a set of functions
that can measure the needed time to perform the A/D conversion. The obtained
sampling rate of the average of 1000 samples is represented in Table 4.3, where we
can see that the maximum experimental obtained sampling rate is – 125 kHz.

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
}

Example 4.22: Division factor (prescaler) - Example.

Table 4.3: A/D conversion experimental results.

Division factor Sampling rate (kHz)


128 –8
64 –16
32 –31
16 –50
8 –63
4 –83
2 –125

80
5 CONCLUSIONS

This document is intended to open the doors to a deeper understanding of Arduino


and does not intend to correspond to all the existing knowledge in this őeld.
Constant research and development must be guaranteed to improve skills and
acquire more knowledge. Who would have thought that an academic project would
go this far? Probably no one would. This real example highlights the persistence
and dedication needed to make this project a worldwide success. To succeed, one
must have an attitude of a continuous search for knowledge because knowledge
does not occupy memory space.
Even with the passing of the years, and considering the initial veriőed rapid
development of the platform over the years, it is still used in many applications.
It is perfect for learning and electronic enthusiasts. The vast Arduino community,
which is growing daily, frequently contributes with simple tutorials and
implementations that can be useful during learning.
It is essential to disseminate knowledge, and in the future, more tutorials
approaching more advanced topics will be developed and shared with the Arduino
community. Any contributions, work sharing, and notes are welcome. Use the
contact means described on the cover to reach me.

Sapientia est lux

81
BIBLIOGRAPHY

[1] Arduino. Arduino Website, 2022. URL: https://www.arduino.cc/.

[2] Nuno Pessanha Santos. Arduino Introdução e Recursos Avançados. Escola


Naval, 2009. doi:10.13140/RG.2.2.17609.08807.

[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.

[5] Yoshiharu Kato. Splish: a visual programming environment for arduino to


accelerate physical computing experiences. In 2010 Eighth International
Conference on Creating, Connecting and Collaborating through Computing,
pages 3ś10. IEEE, 2010. doi:10.1109/C5.2010.20.

[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.

[7] Arduino. Arduino Forum, 2022. URL: https://forum.arduino.cc/.

[8] Pierre E Hertzog and Arthur J Swart. ArduinoÐenabling engineering students


to obtain academic success in a design-based module. In 2016 IEEE Global
Engineering Education Conference (EDUCON), pages 66ś73. IEEE, 2016. do
i:10.1109/EDUCON.2016.7474533.

[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.

[10] Hari Kishan Kondaveeti, Nandeesh Kumar Kumaravelu, Sunny Dayal


Vanambathina, Sudha Ellison Mathe, and Suseela Vappangi. A systematic
literature review on prototyping with arduino: Applications, challenges,
advantages, and limitations. Computer Science Review, 40:100364, 2021.
doi:10.1016/j.cosrev.2021.100364.

[11] Ahmad Adamu Galadima. Arduino as a learning tool. In 2014


11th International Conference on Electronics, Computer and Computation
(ICECCO), pages 1ś4. IEEE, 2014. doi:10.1109/ICECCO.2014.6997
577.

[12] Arduino. Arduino Uno Rev3, 2022. URL: https://store.arduino.cc


/products/arduino-uno-rev3?_gl.

[13] Arduino. Arduino mega 2560 rev3, 2022. URL: https://store.arduin


o.cc/products/arduino-mega-2560-rev3?_gl.

[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.

[16] R. J. Mitchell. Microprocessor systems: An introduction. Red Globe Press


London, Boston, MA, 1995.

[17] Tianhong Pan and Yi Zhu. Designing Embedded Systems with Arduino.
Springer, 2018.

[18] Dimosthenis E Bolanakis. A survey of research in microcontroller education.


IEEE Revista Iberoamericana de Tecnologias del Aprendizaje, 14(2):50ś57,
2019. doi:10.1109/RITA.2019.2922856.

[19] Steven F Barrett. Arduino microcontroller: Processing for everyone! Synthesis


Lectures on Digital Circuits and Systems, 7(2):1ś371, 2012. doi:10.2200/
S00421ED1V01Y201205DCS038.

[20] Atmel Corporation. ATMEGA2560 - 8-bit atmel microcontroller with


16/32/64kb in-system programmable ŕash. Atmel Corporation, 2014. URL:
https://ww1.microchip.com/downloads/en/devicedoc/atm
el-2549-8-bit-avr-microcontroller-atmega640-1280-128
1-2560-2561_datasheet.pdf.

[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.

[23] Seiichi Aritome, Ikuo Hatakeyama, Tetsuo Endoh, Tetsuya Yamaguchi,


Susumu Shuto, Hirohisa Iizuka, Tooru Maruyama, Hiroshi Watanabe, Gertjan

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.

[31] Robert H Walden. Analog-to-digital converter survey and analysis. IEEE


Journal on selected areas in communications, 17(4):539ś550, 1999. doi:
10.1109/49.761034.

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.

[33] MS Hefny and HH Amer. Design of an improved watchdog circuit


for microcontroller-based systems. In ICM’99. Proceedings. Eleventh
International Conference on Microelectronics (IEEE Cat. No. 99EX388), pages
165ś168. IEEE, 1999. doi:10.1109/ICM.2000.884831.

[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.

[36] Michael Barr. Pulse width modulation. Embedded Systems Programming,


14(10):103ś104, 2001.

[37] Nuno Pessanha Santos. Arduino e a Aquisição de Dados - A Problemática na


taxa de amostragem. Escola Naval, 2009. doi:10.13140/RG.2.2.2767
5.41761.

[38] Tom Igoe. Making things talk: Practical methods for connecting physical
objects. O’Reilly, Sebastopol, USA, 2007.

[39] Future Technology Devices International Limited. Future technology devices


international limited - ftdi, 2022. URL: https://ftdichip.com/.

[40] Nathan Ensmenger. The multiple meanings of a ŕowchart. Information &


Culture, 51(3):321ś351, 2016.

[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.

[43] Norman Dunbar. Arduino compilation. In Arduino Software Internals, pages


9ś72. Springer, 2020. doi:10.1007/978-1-4842-5790-6_2.

[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.

[46] G Arroz, JC Monteiro, and A Oliveira. Arquitectura de Computadores, dos


Sistemas Digitais aos Microprocessadores. IST Press, Lisbon, Portugal, 2007.

[47] Emily Blem, Jaikrishnan Menon, and Karthikeyan Sankaralingam. Power


struggles: Revisiting the risc vs. cisc debate on contemporary arm and
x86 architectures. In 2013 IEEE 19th International Symposium on High-
Performance Computer Architecture (HPCA), pages 1ś12, 2013. doi:10.1
109/HPCA.2013.6522302.

[48] M. Tecnology. Advanced RISC Computing Speciőcation, 1992. URL: http:


//www.bitsavers.org/pdf/mips/ARC_1.2_Specification_1
992.pdf.

[49] Saul Gorn, Robert W Bemer, and Julien Green. American standard code for
information interchange. Communications of the ACM, 6(8):422ś426, 1963.

[50] Hans-Christoph Steiner. Firmata: Towards making microcontrollers act like


extensions of the computer. In New Interfaces for Musical Expression, 2009.

[51] Daniel Shiffman. Learning Processing: a beginner’s guide to programming


images, animation, and interaction. Morgan Kaufmann, 2009.

[52] Mikal Hart. Flash Arduino library, 2023. URL: https://github.com/sch


inken/Flash.

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.

[57] Processing. Welcome to processing!, 2023. URL: https://processing.o


rg/.

[58] Monson H Hayes. Schaum’s outline of theory and problems of digital signal
processing. McGraw-Hill, 1999.

[59] PP Vaidyanathan. Generalizations of the sampling theorem: Seven decades


after nyquist. IEEE Transactions on Circuits and Systems I: Fundamental
Theory and Applications, 48(9):1094ś1109, 2001.

[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

You might also like