Learn Arduino by Albert Denys
Learn Arduino by Albert Denys
By ALBERTO DENYS
LEARN ARDUINO
IDE C++ PROGRAMMING
SENSORS, WIRELESS COMMUNICATION, ETHERNET, WIFI AND ETHERNET
By Alberto Denys Aguiar
Copyright @ 2021
All rights reserved. No part of this publication may be reproduced, distributed, or transmitted in any form or by
any means, including photocopying, recording, or other electronic or mechanical methods, without the prior
written permission of the publisher, except in the case of brief quotations embodied in critical reviews and certain
other noncommercial uses permitted by copyright law.
PREFACE
This book was written to help you develop your own projects using Arduino. The material is segmented in the
areas of knowledge of systems, networks and programming. Each of these areas is presented in a comprehensive
way, each group of knowledge consolidated by a set of projects. In the final project, knowledge from all areas is
consolidated in the design of a small weather station.
FIRST STEPS
The book is to be used as supporting material in the assembly of various Arduino projects. In the development,
assembly and testing of the projects it is necessary to use a Windows or Mac laptop with several auxiliary programs
installed.
The book has many images used to clarify and illustrate the topics covered. They are photos, diagrams and colored
circuits with a great number of details. The best reading experience, due to the images with small details, is to use
a Kindle, Android, Windows or Apple Tablet with 8" screen or larger in LANDSCAPE mode. You can install Kindle
reader on the laptop.
The book can also be found in an app format at the Windows Store under the name Arduino Computer Science.
TABLE OF CONTENTS
1. ARDUINO BASICS 6
1.1. ARDUINO HARDWARE 7
1.2. ARDUINO IDE 25
1.3. C++ LANGUAGE OVERVIEW 36
1.4. ARDUINO SPECIFIC FUNCTIONS 74
2. EXPERIMENTS 94
2.1. BASIC PROGRAMS 95
2.2. SENSORS 123
2.3. INPUT AND OUTPUT DEVICES 153
2.4. RADIO COMMUNICATIONS 176
2.5. BLUETOOTH, ETHERNET AND WIFI 218
3. BRINGING IT ALL TOGETHER IN ONE PROJECT – WEATHER STATION 280
3.1. PROJECT 282
3.2. MODULES TEST 285
3.3. ALTITUDE CONFIGURATION 296
3.4. POOLING 298
3.5. INTERRUPT 306
3.6. USING THE ARDUINO PRO MINI 314
3.7. ARDUINO PRO MINI WIFI 318
4. ARDUINO HARDWARE 330
4.1. ARDUINO SENSORS 331
4.2. USING ARDUINO WITH DISPLAYS AND KEYBOARDS 365
5. NETWORK 371
5.1. OSI MODEL 372
5.2. ARDUINO NETWORK EXAMPLES 383
1. ARDUINO BASICS
All processors (Central Processor Unit - CPU) use instructions in binary format. As we have already studied, it is
exceedingly difficult to work directly with binary instructions. Until 1970 all programming that directly accessed
the CPU was done using a language called Assembler that works with the CPU basic operations. Each CPU had a
specific Assembler, because the language was based on the physical structure of the CPU, how many registers it
had, what set of instructions it supported, how much memory it was able to address. Only specialized personnel
were able to program in Assembler and still normally for a specific CPU. When a new CPU was launched, the
previous learning was lost.
C was originally developed at Bell Laboratories by Dennis Ritchie in 1972 to develop the UNIX operating system. C
is a high-level, structured language that maintains a close relationship with binary code. A program written in C
runs quickly, using little memory, and is a replacement for Assembler. It evolved in the 1980s to object-oriented
C ++. So, every time a manufacturer launches a new processor, it also launches a program development package
that uses C++.
This chapter introduces the hardware, the development environment, standard C ++ programming and the specific
C ++ functions needed to develop projects using Arduino. Anyone who has mastered the Arduino can skip this
chapter and go straight to Chapter 2 which presents several projects.
1.1. ARDUINO HARDWARE
In this block we will study the hardware of the Arduino kit. The items to be studied are:
The Arduino kit is a board containing the ATmega328/P microcontroller manufactured by ATMEL. There are
several kit models. Next, we see the Arduino UNO kit revision 3.
A microcontroller is an extremely limited device in terms of processing and memory. Its main use is the
implementation of equipment that uses complex combinatory logic. As we studied in COMPUTER SYSTEMS ONE,
combinatorial logic is used in devices that have multiple inputs and multiple outputs. Combinatorial logic performs
some function that uses the input signals to produce the output signals. As we saw in the lesson, it is not easy to
design the circuit that implements the necessary function when the number of inputs and outputs is greater than
two or three inputs and outputs. In addition, the circuits begin to become physically bulky, complex, and
expensive.
The appearance of the microprocessor in the 1970s facilitated the implementation of this type of circuit since we
can program a standardized circuit - the microcontroller - to implement several different circuits. As the necessary
processing is not intensive, the microcontroller usually has a simple CPU and little memory.
The Arduino microcontroller operates with 8 bits (1 Byte). The kit's memory consists of 32 KBytes of flash memory
where the program that the Arduino will execute is stored, 1 KBytes of EEPROM memory that contains the
program used by the kit for its own operation and 2 KBytes of RAM used for the execution of the program.
The table compares the size of the various types of memory used by the Arduino with those used in a simple
smartphone. The memories used on the smartphone are 1,000,000 times larger than those used by the Arduino.
Another important item of comparison between Arduino and a CPU of a modern smartphone is the processing
capacity. Processing capacity is indicated in MIPS - Millions of instructions per second. In the case of Arduino, the
microcontroller used can run 20 MIPS, while a typical smartphone CPU (ARM) is capable of running more than
70,000 MIPS.
ATMEGA328/P CAPABILITIES
The ATmega328/P was designed to control sensors and devices of low complexity offering a standardized low-
cost solution. To perform these functions the microcontroller offers several types of inputs and outputs:
• 14 digital input/output lines
• 6 analog input lines
• Two 8-bit Timers
• One 16-bit Timer
• Real Time Counter
• Six PWM Channels – 8-channel 10-bit ADC
• 6-channel 10-bit ADC
• Two Master/Slave Serial Interface – interface full-duplex
• One Programmable Serial USART – interface half-duplex
• One Byte-oriented 2-wire Serial Interface
• Programmable Watchdog Timer
• One On-chip Analog Comparator
• Interrupt and Wake-up on Pin Change
PINING
The ATmega328/P is available in two types of encapsulation, with 28 pins and 32 pins. The kit presented has a 28-
pin integrated circuit. The ATmega328/P is inserted into a printed circuit together with other integrated circuits
and electronic components that together make up the KIT. In the kit the inputs and outputs are placed on the
sides of the board to facilitate connection with the other circuits.
Below we see the most important inputs and outputs for our work. An external 9V power supply must be
connected to its own connector.
The USB interface is used to connect the kit to a computer that has the programming IDE installed. We can see
the reset switch and the digital and analog input and output lines. Once powered by a 9V source the kit is capable
of supplying voltages of 5V and 3.3V for auxiliary circuits used, for example, feeding a sensor or other external
element.
SENSORS
Sensors are electronic devices that measure certain natural physical quantities, such as temperature, humidity,
pressure, light, sound waves and gases, among others. There are also acceleration and positioning sensors on the
X, Y and Z axes, traditionally used in inertial navigation systems on airplanes and rockets, and currently used in
positioning systems on smartphones, which allow changing the direction of the display when you rotated the
phone.
Current sensors are too small to fit inside smartphones and other mobile devices. In the photo below a pressure
sensor board prepared for use by Arduino. The pressure sensor is the integrated circuit marked by the yellow
circle. The size can be compared with the fingers that hold the plate. It goes inside the smartphone allowing the
altitude or the weather to be calculated.
The printed circuit board provides the necessary elements for the sensor to function correctly, such as resistors,
capacitors, and auxiliary integrated circuits. Several boards containing sensors have been developed for use on
Arduino.
Each sensor has a specific function indicated by the manufacturer in a complex datasheet in general. Below is the
pressure sensor datasheet. See that the manufacturer's document has more than 22 pages.
You can search the internet using the phrase BOSCH BMP180 DATASHEET. Several sources provide the original
datasheet. Analyze the datasheet. It is complicated. Understanding how a component works and being able to
test its functioning from the datasheet information is a task that takes several days, especially if you have to
connect it to a microcontroller. There are three tasks to be performed:
1. What is the accessory hardware needed to activate the device, that is, how to power it, if it needs auxiliary
components such as resistors, capacitors, and other integrated circuits? To do this you need to study the
device's pinout, supply voltage and current. Usually, to facilitate the task, the manufacturer suggests a circuit
as indicated in the datasheet. If you look carefully you will see 4 long, narrow components on the board. They
are the two resistors (R1 and R2) and the two capacitors (C2 and C3) indicated on the circuit.
You also see a larger component right next to the GND signal. This component is a voltage regulator to prevent
the circuit from being burned if the voltage is reversed or an overvoltage is applied. The component next to the
VCC signal is a capacitor used to filter electrical noise. Follow the circuit suggested by the manufacturer:
2. How the device is organized internally. The block diagram indicates that the sensor element measures the
pressure and temperature and passes the analog value to the analog-to-digital converter (ADC - Analog to
Digital Converter). Then the digital value is transferred to a control unit that stores the data in memory
locations inside the control unit. The control unit interacts with the microcontroller through the SDA and SCL
connections. The control of the entire device is performed by an EEPROM memory.
3. How the device communicates with the microcontroller. For this you must study the communication
protocol, which in this case is the I2C.
Communication involves hardware and software. The software is the program that allows the microcontroller
to communicate with the device. The manufacturer or whoever markets the device usually provides a program
that allows the designer to test the device. Below is a flowchart of the communication program.
Anyway, using a sensor device is a task that takes time to understand the device, develop a test circuit, develop
test software, test, and correct problems, and finally arrive at a final project.
The IDE unzips the ZIP file. The unzipped file can be viewed in sequence. There are several files describing the
library and two directories, one containing examples of use for Arduino (EXAMPLES) and another containing the
source codes of the library (SRC). The examples will appear in IDE´s FILE menu.
The SRC directory has three files. The README file describes the library. The H file contains a summary of the
functions contained in the library. The .H file must be declared at the beginning of the Arduino program so that
the compiler knows what functions it should include and where it can find these functions.
Sometimes a library is developed for several different models of sensors. It contains several conditional
compilation directives of type ifdef .............. then ............. define. When in an Arduino program you find a #define
XXXXX it means that this directive will indicate to the library which conditional definition will be used.
The following is a fragment of the HEADER file (.h) with an initial comment indicating that the header was
developed for the BOSCH BMP180 pressure sensor and the library was developed by Mike Grusin of SparkFun
Electronics. The following is a brief description of the library. The header file is a file of definitions and declarations.
It does not contain a CPP program. So, you can see the conditional definitions and then the PROTOTYPES of the
functions. A function prototype indicates the name of the function, the types of variables passed to the function
and the return type of the function. The .h file is like an index of all the functions found in the CPP file.
The CPP file contains the functions that will make the Arduino work in conjunction with the sensor. In this case,
we only copy the initialization function of a temperature measurement, since the BMP180 sensor measures
pressure and temperature.
1.2. ARDUINO IDE
In this lesson we will study how the Arduino kit works and how to write programs in the Arduino IDE. The IDE is
an integrated development environment that allows you to write and upload the program, via the USB connection,
to the Arduino. The IDE indicates, during the development of the program, if there is any syntax error, facilitating
the task of the developer. It does not suggest corrections, since it is a simple IDE, it just points out the error.
The topics covered in this lesson are:
THE ARDUINO KIT ENVIRONMENT - IDE
DOWNLOADING IDE
PRESENTING THE IDE
WRITING AND TESTING THE FIRST PROGRAM
STEPS TO PROGRAM ARDUINO
THE ARDUINO KIT ENVIRONMENT - IDE
The company that created the Arduino Kit developed an IDE - Integrated Development Environment - that allows
Arduino programming using the C++ language. The Arduino Kit IDE can be downloaded and installed on the
computer. In this case the program can be developed on the computer and using a USB cable loaded in the
Arduino's flash memory (32 KByte). From there, as soon as you energize the Kit, it starts running the program that
was loaded into the flash memory. If you develop another program and load this new program into Arduino's flash
memory, the previous program will be deleted and replaced by the new program.
There is an option for you to develop the program on an Arduino website and directly load the program into the
Kit. However, the simplest, safest and fastest option is to download the IDE. So, you don't need an internet
connection.
The IDE offers:
A text editor that allows you to write the program. This editor reviews the syntax so that if you entered a wrong
command, sentence, or symbol it immediately indicates.
Offers several functions that perform standardized tasks in the kit and that would be difficult to write using the
binary language. The IDE offers these functions already tested and debugged, that is, without programming errors.
There are timers, sine, cosine, power, square root, and other functions of this type ready for use.
Offers an extremely simple platform to streamline development - implement the program, load it into the kit, test,
discover errors, modify the program, reload, test again and so on.
DOWNLOADING IDE
You can download the Arduino from the website https://arduino.cc/en/main/software
In software choose the type of download according to your computer. I used the Windows app and was redirected
to the Microsoft Store that downloaded and installed the IDE.
PRESENTING THE IDE
Once installed, the IDE has the format shown in the figure. It automatically creates two functions called setup and
loop. The setup function is where you must initialize the kit's input and output pin functions. As you saw in the
HARDWARE, the ATMEL 328p microprocessor offers more functionality than the number of pins available in the
physical enclosure. Therefore, before running any program, you have to tell the microprocessor what functions
you will use and set the pins correctly. You should only configure the pins you are going to use.
In the loop function you must write the program to be executed. When turned on, the kit executes the setup
function once and then executes the loop function, starting on the first line and executing line by line until reaching
the last line, going back to the first line, and repeating the cycle indefinitely.
Although the connection to the kit is made using the USB cable it is a serial connection that uses a virtual computer
interface called COM. The IDE indicates at the bottom right the number of the virtual COM interface through which
it connected with the kit, in this case COM 6. If the interface number does not appear, the IDE was unable to
connect to the kit. Let us do a simple program to see how the organization is.
ALERT - for those who already program in C - the LOOP function is different from the MAIN function. The MAIN
function is executed only once, so the entire definition and assignment of values at the beginning of the function
is only performed once. In the case of Arduino, the loop function is executed continuously and, therefore, the
variables are continuously declared and assigned. Redeclaring the variables does not cause a problem, but their
value is reassigned at each loop which can cause a problem in your program logic.
WRITING AND TESTING THE FIRST PROGRAM
The next step is to save the program. On the File menu click save. Enter the name and location where you want to
save the program.
The next step is to run the program. To do this, you must connect the Arduino to your computer using the USB
cable that comes with the Arduino Kit. Then press the left most button with the V. The Arduino will compile the
program, that is, transform the C++ language program into the binary code that the microprocessor understands.
Then click the button with the right arrow. The Arduino will ask you to confirm the virtual COM port to which the
Kit is connected. When you connect the Kit to the USB port, the computer automatically tries to allocate a virtual
COM for the Kit. The Arduino asks you to confirm that the port shown is correct. An error may also occur when
the IDE uploads the program and the COM port is not configured. Go to the TOOLS menu select PORT and choose
the correct port.
In this step, the Arduino also reports the amount of Flash memory used by the program and the amount of RAM
required to run the program. Our program will use 924 Bytes of the 32 KBytes of Flash memory and 9 Bytes of the
2 KBytes of RAM.
Then it loads the program on the microprocessor and immediately the program starts to run. The IDE also indicates
which COM interface is in use at the bottom right. The result is below. See pin 13 and the LED on.
When you install the Arduino IDE, there are several examples that are installed together. To access the examples,
go to File → Examples:
STEPS TO PROGRAM ARDUINO
1. Write the program in the IDE's editor.
2. Compile the program.
3. If everything is correct, then save the program on the computer.
4. Connect the USB cable to the Kit.
5. Load the program in the Kit.
6. If necessary, indicate to the Kit which COM port it should use.
7. See if the Kit runs the program correctly.
8. If necessary, modify the program.
9. Reload it in the Kit.
It is not necessary to connect and disconnect the kit. Just connect at the beginning of the work and leave it
connected while modifying the program.
ARDUINO is a flexible, powerful, and low-cost kit. In a small production it is not worth developing specific boards
for different projects. The ideal is to incorporate a card already assembled in the project.
1.3. C++ LANGUAGE OVERVIEW
In this lesson we will study the C++ language. The Arduino IDE uses C++ as a program language. Once the program
is written, the IDE transforms it into a binary that uses the machine instructions that the ATMEL 328P
microcontroller understands. This chapter is a summary of the C ++ language. Learning the C ++ language takes up
a book of more than 800 pages and takes more than 6 months of practice. The topics covered in this lesson are:
DATA TYPES, CONSTANTS AND VARIABLES IN C ++
CONSTANTS AND VARIABLES
STRING TYPE
CONVERSION OF DATA TYPES
CONVERSION OF THE RESULT
FORMATTING
SCOPE OF THE VARIABLE AND QUALIFIERS
WRITING A PROGRAM IN C++
STRUCTURE
COMMENTS
DELIMITATORS - LINE FINISHER
FLOW-CONTROL
COMPARISONS
OPERATORS
FUNCTIONS
DATA TYPES, CONSTANTS AND VARIABLES IN C ++
The C ++ language has many data types. It is a formal language requiring each constant and variable to be declared
before its use and its type of data informed. The constant and variable remains throughout the program with the
declared data type unless its type is modified through a conversion command or using a transformation function.
Next, we'll look at the data types.
A variable can be modified throughout the program. It must always be declared with an initial value since it can
be used, by mistake, before to have a valid value, generating an error and aborting the program. A typical
statement is:
int var = 0; //that declares a var variable of type integer.
Comments can be made after the command line using //. If the comment is too long and you use more than one
line write the comment between / * comment * /.
Constants and variables can be written in uppercase and lowercase letters. The name var is different from the
name Var which is different from the name vAr. C ++ treats it as 3 different constants or variables. It is a good rule
to spell out the variables in lower case and the constants in upper case. So, you can tell without looking at the
statement whether it is variable or constant.
The name must be suggestive of the use to be given for the variable or constant unless it is used for some local
operation as part of an if() for example. So, seaLevelAltitude is a good name. It starts with a small letter and capital
letters allow you to quickly understand what it is for. Modern IDEs simplify the job of writing long variable names
because you just start writing the name of a variable already declared and the IDE completes it. The Arduino IDE
does not do this.
NUMERIC TYPE
BYTE (equal to unsigned char) - is an unsigned 8-bit number between 0 and 255. Declaration byte var;
CHAR - is an 8-bit number with sign between -128 and +127. Declaration char b;
WORD (equal to unsigned int) - is an unsigned 16-bit number between 0 and 65,535. Declaration word c;
INT (equal to short) - is a 16-bit number signed between – 32,768 to +32,767. Declaration int k;
UNSIGNED LONG - is an unsigned 32-bit number between 0 and 42,94,967,295. Declaration unsigned long d;
LONG - is a 32-bit number with sign between -2,147,483,648 and +2,147,483,647. Declaration long t;
FLOAT - is a 32-bit real number with sign between -3.4028235E38 and +3.4028235E38 with 7 decimal places of
precision. Declaration float s;
BOOL - is an 8-bit number. It can have two values True or False. Declaration bool state;
All numerical processing performed by the Arduino Logical Unit (ALU) is done in 8 bits. Therefore, arithmetic using
numbers of type byte, char and bool is performed quickly. 16-bit arithmetic is also fast because the Arduino
register structure (see COMPUTER SYSTEMS ONE at Microsoft Store) is structured in 16 bits. Any other type of
numeric data is processed through library functions of the compiler that require a greater processing load from
Arduino. The processing load is greater for the long type and much greater for the float type. If your algorithm is
complex, with many addition and subtraction operations, try if possible, to use all processing in integer arithmetic
by converting to float at the end. Functions like sine, cosine and other complex functions are implemented using
look up tables and extrapolation between table points.
INTEGER
The origin of C (1969) was as a medium to high level language that allowed to directly program a CPU without the
need to use binary commands. It reflects this proximity to the CPU hardware. So, you can represent integer values
using Binary, Octal, Hexadecimal and Decimal format.
Doing manually:
Decimal (Base 10) 543 = 5 x 102 + 4 x 101 + 3 x 100 = 5 x 100 + 4 x 10 + 3 x 1 = 543
Binary (Base 2) 100110 = 1 x 25 + 0 x 24 + 0 x 23 + 1 x 22 + 1 x 21 + 0 x 20 = 1 x 32 + 0 x 16 + 0 x 8 + 1 x 4 + 1 x 2 + 0 x
1 = 38
Octal (Base 8) 423 = 4 x 82 + 2 x 81 + 3 x 80 = 4 x 64 + 2 x 8 + 3 x 1 = 275
Hexa (Base 16) 0xAF10 = 10 (=A) x 163 + 15 (=F) x 162 + 1 x 161 + 0 x 160 = 10 x 4096 + 15 x 256 + 1 x 16 + 0 x 1 =
44816
Using the Windows calculator in PROGRAMMER mode you can do the various conversions. Before entering the
number, you have to click on the type of number you are going to enter, as indicated by the red arrow. As you
enter the number, the calculator will display the results in the other numeric bases.
A decimal integer can be negative or positive. When using the u|U (unsigned) modifier we limit it to a positive
integer.
STRING TYPE
The String type basically uses ASCII encoding, that is, it is a text or represents a number as a text. Print functions
generally deal with strings. Numbers must be converted to text (strings) before they can be printed.
String() - creates a string instance. Examples:
String string1 = String(13); // equivalent to string1 = "13";
String string2 = String(13, BIN); // equivalent to string2 = "1101";
String phrase1 = "How are you?";
String name = String("Mary");
String action = String ("drink coffee.");
String phrase = String (name + action); // phrase = "Mary drink coffee."; If you want to print a phrase like “The
temperature value is 50 degrees centigrade” and the value 50 is obtained from a temperature sensor, that is, it is
an integer or float value loaded into a variable then it has to be converted to string. Every argument of the print
() function must be of type string. The code is:
int temperature = 0;
temperature = getTemperature();
print("The temperature value is "+ String (temperature) +" degrees centigrade");
And if the temperature value is float and you have a fixed space to print the sentence, as for example on a display,
you can do:
float temperature = 0.0;
temperature = getTemperature();
print ("The temperature value is " + String (temperature, 2) + " degrees centigrade");
In this case, the temperature is printed to two decimal places like 50.00. If you want to print without decimal
places, just do String (temperature, 0).
VOID – when declaring a function, it is necessary to declare the return type of the function. Since C does not have
subroutines, functions that do not return a value are declared as void type.
int return_integer(){
do something;
return 101;
}
void without_return(){
do something;
}
In Arduino:
void setup(){
without_return();
}
void loop(){
int var;
var = return_integer();
if(var==101){ do something; }
}
VARIABLE CONVERSION
byte() - converts a variable to an unsigned 8-bit number.
char() - convert a variable into a signed 8-bit number.
float() - converts a variable to a float number → int i = 16; float (i); → i = 16.0
int() - converts a variable to a 16-bit integer with sign → float x = 7.23; int (x); x = 7
long() - convert a variable into a long (32) signed bit number.
word() - converts a variable to an unsigned 16-bit integer.
String() - convert a number to a string.
CONVERSION OF THE RESULT
It is possible to change the result of an account using the expressions:
(unsigned int) → float x = 16.3; int i = -15; int j; j = (unsigned int)(x + i); → j = 1;
(unsigned long)
FORMATTING
When indicating the initial value in a constant or variable declaration, we can use the letters U, L, UL and F.
long k = 0L; // declaring that variable 0 is of type long
long k = 0UL; // declaring that the variable is of type unsigned long
float b = 0F; // replacing the value declaration 0.0
STATIC – a variable declared inside a function is destroyed once the execution of the program leaves the function.
Destroyed in the case means that the compiler can reuse the memory position allocated to the variable. When a
variable is declared static, the compiler does not reuse the memory position. So, if the program re-enters the
function it finds the same value assumed by the variable the last time the function was executed.
void loop()
{
int val;
val = decision(10); //val = 0
val = decision(-10); //val = 1
val = decision(10); //val = 2
}
int decision(int value)
{
static int step; //the first time inside the function step is null
if(value < 0)
{
step = 1;
}
if(value > 0)
{
If(step!=null) //if step is not tested there is an error
{
step = step + 1;
}
else
{
step = 0;
}
}
return(step);
}
If the first value is negative, decision(-10), the program will produce an error because the step variable is not
tested. How to fix this?
STRUCTURE
Every C/C ++ program has a function called main() that is executed whenever the program is started. The
instructions are executed serially until the last one, when the program returns control to the operating system. If
you have written any loop code inside the main() function, you must take care to ensure the correct output of this
loop, otherwise the program will be permanently running. The main() function returns an integer value telling the
operating system if the program executed was successful or if a problem occurred.
int main(){
...............
}
The Arduino is a controller and as such it must perform the same task all the time. Thus, the C/C++ structure of
the kit has been modified. The main() function is called loop(). The function has a void type, that is, it does not
return any value to the operating system simply because in this case there is no operating system and because
the function will always be in a loop.
ALERT - for those who already program in C - the LOOP function is different from the MAIN function. The MAIN
function is executed only once, so the entire definition and assignment of values at the beginning of the function
is only performed once. In the case of Arduino, the loop function is executed continuously and, therefore, the
variables are continuously redeclared and reassigned. Redeclaring the variables does not cause a problem, but
their value is reassigned at each loop which can cause a problem in your program logic
In Arduino the setup() function is executed before the loop() function and its purpose is to prepare the Arduino
environment, declaring the variables and constants and loading the corresponding initial values. Then the program
control switches to the loop() function and remains with it until the kit is turned off. The variables declared in
setup() are only valid within the setup().
COMMENTS
Commentary is a widely used resource that serves mainly to clarify points of the program. The comment does not
take up programming memory as it is deleted from the executable program.
There are two types of comments:
// this is a comment line
/* this is a comment
covering several
lines */
FLOW-CONTROL
The program flow can be changed using the following instructions:
IF
if(conditional){
code
}
else{
code
}
The if may or may not be followed by the else. Code represents the instructions to be executed if the conditional
is true. In the case of if .... else the code that follows the if is executed if the conditional is true, if it is false the
code that follows the else is executed.
COMPARISONS
SWITCH
switch(variable){
case value:
code
break;
case value:
code
break;
default:
code
}
The statement break interrupts the execution of the program and continues execution at the end of the switch.
If no case condition is met, the default condition is executed. If there is no default condition, the program
continues normally after testing all conditions.
Example:
int a = 10; int b = 5; int c = 0;
switch(a){
case 5:
c = a;
break;
case 10:
c = b;
break;
default:
c = 50;
break;
}
At the end of the code segment c = 5.
GOTO
It allows to divert the flow of the program.
goto label;
...................
code
…………………
label:
code
………………..
int a = 1;
if(a == 1){
goto 1;
}
else{
goto 2;
}
………………..
1:
Instructions ………………..
2:
More instructions………………..
WHILE LOOP
The condition is tested at the beginning of the loop. The loop is executed while the condition is true. The while
loop may not be executed if the condition is not met.
while(conditional){
code
}
int x = 0;
int y = 5;
while(x < y){
x = x + 1;
}
FOR LOOP
The loop is executed a number of times depending on the initial value of the variable and the test performed at
each start of the loop. At each interaction, the variable is increased or decreased by a certain value.
for(variable initialization; conditional; variable increment){
code
}
int k = 0;
for(i = 0; i < 5; i++)
{
k = k + i; // k = 0, 1, 3, 6, 10
}
OPERATORS
BITWISE operators operate bit by bit. Thus, operation 00110110 & 11101011 results in 00100010. Logical
operators work on variables:
var1 = True;
var2 = False;
var3 = 10;
if(var1&&var2) {var3=5;}
if(var1||var2) {var3=15;}
print(var3);
15
Composite operators allow you to combine two operators into a single operation:
var1=5;
var1+=15;
print(var1);
20
FUNCTIONS
The C/C ++ language has a large number of functions. The syntax (prototype) of the function is:
type functionName(type [argumentName1] [, type argumentName2, ………..]);
int add2Numbers(int a, double b); //Prototype declaration
………………………
Int add2Numbers(int a, double b) //Function
{
Code
}
In C/C ++, the prototype of each function must be declared at the beginning of the module. In the case of Arduino
this is not necessary. Following is the structure of an Arduino program. The program has no practical use. It is just
to demonstrate the coding style. I prefer to put the keys as I present them in the program. It is more visual.
void setup() {
Serial.begin(9600);
Serial.println("FIRST TEST");
}
void loop() {
static int a = 5;
static int b = 10;
static int c = 0;
static int d = 0;
if(c < 100) {
Serial.println(c);
delay(1000);
c = c + sum(a, b);
}
Else {
c = decrement(c);
Serial.println(c);
delay(1000);
}
}
int decrement(int z) {
return(z-1);
}
It is possible to follow the execution of the program through the Serial Monitor. It can be found in the Tools menu.
For the Serial Monitor to work, it is necessary to configure the serial interface between the kit and the computer
using the command Serial.begin (9600). The instruction Serial.println (c) prints the value of variable c on one line.
Above we see the output of the Serial Monitor. Values between 0 and 90 are printed by the if. The next interaction
is the value of c = 105 and then it is printed by the else already decremented from 1 and the value 104 is printed.
The value is decremented to 99 when then the if starts to act again and increments 99 + 15 = 114. The value is
greater than 100 and the else decrements and prints 113.
You can write your function, or the function can be made available by the language. To use these functions, it is
necessary to declare at the beginning of the module a file called HEADER that allows the language to identify the
necessary function. Below are the most used functions. In the prototypes below, when the data type is not
indicated, any type can be used, as long as it is consistent with the area of the function, that is, if the function is
mathematical then the types are numeric. If the argument (s) is of a certain type, the result is of the same type,
unless explicitly stated.
The function can be pre-tested. Then a program that tests the pow() function. The result is printed on the serial
monitor. We inserted a 2-second delay (2000 milliseconds) so that the printed output on the serial monitor is
slower.
1.4. ARDUINO SPECIFIC FUNCTIONS
In this lesson we will study the functions related to the Arduino Kit. The functions obey the C++ language syntax
and are implemented by the compiler (IDE).
Digital pin 5 is programmed as an input using the pullup resistor. Digital pin 13, which is connected to the yellow
LED, is programmed as an output. The central position of the switch is connected to pin 5 of the Arduino. One pole
is connected at 5V and another pole is connected at 0V. When the switch is connected at 5V the LED lights up,
when the switch is connected at 0V the LED goes out.
HIGH|LOW
The voltage value on an ATMEL 328P microcontroller pin is understood as:
• HIGH - tells the microcontroller to place a voltage greater than 2.5V (Volts) on the indicated Output pin if
the circuit is being powered with 5.0V and greater than 1.65V if the circuit is being powered with 3.3V;
• LOW – indicates to the microcontroller to place on the indicated Output pin a voltage less than 2.5V if the
circuit is being supplied with 5.0V and less than 1.65V if the circuit is being supplied with 3.3V;
OUTPUT
To write a logic voltage value on a digital pin just use the digitalWrite function (pin, value).
digitalWrite(5, HIGH);
digitalWrite(5, LOW);
INPUT
The HIGH or LOW value indicates the value read on an input pin.
true|false
False is defined as the integer 0 (zero) and True as the integer 1 (one) or any non-zero integer value. Thus -34 is
true, as well as 12. The constants true and false must be written in lower case.
ANALOG INPUT
The ATMEL 328P microcontrollers contain 6 analog-to-digital conversion channels. The A/D converter has a
resolution of 10 bits, providing integers between 0 and 1023. The 6 pins used for digital analog conversion can
also be used, if necessary, as conventional digital pins, increasing the number of digital pins to 20 pins. How are
analog pins different from digital pins when programming? The analog pin receives an A in front of the number -
A0, A1, A2, A3, A4 and A5.
As the converter is accurate from 0 to 1023 (10 bits) each integer corresponds to 5V / 1024 = 0.0048828125V. So,
if the conversion result is 1001101101 it means that at the analog input, we have a voltage of 1001101101 = 621
x 0.0048828125V = 3.0322265625V.
When the analog pin is used for input, it is not necessary to program the pin, we can simply use the command
value = analogRead(A4).
int value;
void loop() {
value = analogRead(A4);
}
The Atmel328P has only one digital analog converter in the microcontroller. This circuit is used by all inputs. When
the line value = analogRead (A4) is executed, the voltage of pin A4 is connected to the A/D converter. The
converter takes time to process the input signal and provide the output. So, it is interesting to use the value
provided by the converter after a few moments:
int value, output;
void loop() {
value = analogRead(A4);
delay(5); //5 milliseconds delay
output = value * 2; // output = value x 2
}
ANALOG REFERENCE
The voltage reference for the A / D converter is equal to the Arduino supply voltage, that is, 5V or 3.3V. It is not
necessary to program this voltage. There is an internal voltage reference of 1.1V and an external voltage reference
can be provided. The external reference must be between 0V and 5V, otherwise the converter circuit can be
damaged. What is the need for other types of reference, especially the external reference? Because the analog
source can supply voltages with amplitude much less than 0V to 5V, for example a microphone whose output
varies between -1V and 1V. In this case it is necessary to use a circuit to make the output between 0V and 2V and
indicate that the reference is 2V. The step becomes 2V/1024 = 0.001953125V and the converter does not lose
accuracy → 0V = 0000000000 and 2V = 1111111111. The values between 0000000000 and 0111111111 are
representing the values -1V to 0V and the values 1000000000 to 1111111111 are representing values between
0.001953125V and 1V.
The values for programming analogReference () are:
• DEFAULT - between 0V and 5V or between 0V and 3.3V depending on the supply voltage.
• INTERNAL – 1,1V.
• EXTERNAL – the voltage value on the AREF pin.
Example → analogReference(EXTERNAL);
PWM PROGRAMMING
The PWM outputs use digital pins 3, 5, 6, 9, 10 and 11. What is a PWM-Pulse Width Modulation or Pulse Width
Modulation? It is a technique in which a square wave signal is modified causing the time when the pulses are 0 or
1 to be modified. The signal frequency remains the same. In the case of Arduino UNO pins 3, 9, 10 and 11 operate
at the frequency of 490 Hz and pins 5 and 6 at the frequency of 980 Hz.
A simple example can be seen above. This digital signal has a frequency of, say, 490 Hz, that is, each division on
the top line has 1/490 of the second = 0.002041 = 2.041 milliseconds. Waveforms 1 and 4 are square, while 2 has
more 0 volts content and 3 more 5 volts content. If we install an integrator circuit composed of a resistor and a
capacitor, we will have an output that varies according to the waveform, plus level zero the signal leaves the center
(2.5 volts provided by the average square wave between 5V and 0V) and remains less than 2.5 volts, if there is
more level 5V the signal is above 2.5 volts.
The command you type using the PWM output is analogWrite (digital pin, value). The value is used to modulate
the 490 Hz or 980 Hz signal depending on the pin used.
In the program below a potentiometer is connected to an analog pin and an LED to a digital pin that has PWM
capability. The idea is to modify the brightness of the LED by varying the potentiometer. As our eye is an integrating
device, it will play the role of the low-pass filter with the resistor and capacitor.
int value = 0;
void setup() {
pinMode(9, OUTPUT);
{
void loop() {
value = analogRead(A4);
delay(5); //5 milliseconds delay
//analogRead values range from 0 to 1023, analogWrite values range from 0 to 255
analogWrite(9, value/4);
}
Note that it is necessary to divide the output value of the A/D conversion by 4 to transform it into PWM output.
The A/D converter has a 10-bit output while the PWM input is accurate to 8 bits.
The two functions pulseIn and pulseInLong use the micros() function that uses interrupt to work. They do
not work if the noInterrupts () function is called.
shiftIn(Data Pin, Clock Pin, Order) – moves one byte of data into the microcontroller, through the data pin, one
bit at a time. The Order command indicates whether the first bit read will be of a more significant or less significant
order:
D8 D7 D6 D5 D4 D3 D2 D1 D0 → DIGITAL PIN → LSBFIRST
D0 D1 D2 D3 D4 D5 D6 D7 D8 → DIGITAL PIN → MSBFIRST
Each bit is read when the clock pin passes from low to high (LOW to HIGH). To force the clock pin to be LOW before
calling shiftIn() precede this command with digitalWrite (Pin Clock, LOW).
Read Byte = shiftIn(Data Pin, Clock Pin, Order)
• Data Pin (int) - digital pin used to input bits.
• Clock Pin (int) - digital pin that will provide the clock that will be used to read the data.
• Order - reading order of the bits
MSBFIRST (Most Significant Bit First) or
LSBFIRST (Least Significant Bit First).
• Read Byte (byte)
The instructions shiftIn() and shiftOut() are used when we want to increase the number of inputs and outputs of
the Arduino Kit. The Arduino has only 13 digital pins. As an example, using the integrated 74HC165 it is possible
to create 8 more digital input pins and using the integrated 74HC595 it is possible to create 8 digital output pins.
To do this it is necessary to use 3 digital pins to drive the 74HC165 and 3 digital pins to drive the 74HC595.
shiftOut (dataPin, clockPin, bitOrder, value) - Shifts out a byte of data one bit at a time. The clock pin indicates to
the external circuit when the bit is available on the data pin. The bit is written on the data pin and then the clock
pin is pulsed from HIGH to LOW. If the external circuit reads the bits in the transition from LOW to HIGH, it is
necessary to force the clock pin level to LOW before executing the shiftOut instruction. So, it is in LOW, changes
to HIGH allowing the external circuit to read the bit and returns to LOW.
DIGITAL PIN → D8 D7 D6 D5 D4 D3 D2 D1 D0 → LSBFIRST
DIGITAL PIN → D0 D1 D2 D3 D4 D5 D6 D7 D8 → MSBFIRST
Each bit is read when the clock pin passes from low to high (LOW to HIGH). To force the clock pin to be LOW before
calling shiftIn() precede this command with digitalWrite (Pin Clock, LOW).
• Data Pin (int) - digital pin used to output bits.
• Clock pin (int) - digital pin that will provide the clock that will be used for the external circuit to read the
data.
• Order - reading order of the bits:
'SBFIRST (Most Significant Bit First) or
LSBFIRST (Least Significant Bit First).
• Value (byte) - the byte to be transmitted by the data pin.
TIMING
delay(miliseconds) – this command introduces a delay during the execution of the program. The delay is in
milliseconds, so delay(1000) would be equivalent to a delay of 1000 milliseconds or 1 second. Upon finding a delay
instruction, the computer stops processing and activates an internal timer programmed for the defined time. It
continues processing only after the timer has ended.
delayMicroseconds() – introduces a delay between 3 and 16383 microseconds. As 16383 is equal to 16,383
milliseconds it is interesting to use the delay() command in this case.
micros() e millis() – return the elapsed time since the start of the current program in microseconds and
milliseconds. This is important to check how long each segment of code takes to run. Remember that Arduino
programming is always closely linked to the real world, that is, something has to be executed or read within a
specific time interval. For example, if you are developing a sensor to count the number of cars that pass-through
a given street and your program runs in 100 milliseconds, this means that you will only detect cars at a maximum
speed of 36 km/h, or 10 meters per second. To detect cars at 140 km/h your program must be executed in less
than 25 milliseconds.
EXTERNAL INTERRUPTIONS
An external interrupt is used when we want an external signal to interact and change the current state of the
Arduino, usually by modifying the code segment that is being executed. When an interruption occurs the execution
of any program stops and the code segment that handles the interruption is executed. After the interrupt
execution is finished, normal program execution returns to the point where it was interrupted. The interrupt
normally calls a function placed outside the normal chain of execution. If there is no interruption, this function
will never be performed. This function should be as small as possible so as not to delay the execution of the main
program.
In Arduino UNO the pins used for interrupts are digital pins 2 and 3. Internal interrupts do not work within
functions that use external interrupts. The delay(), micros() and millis() functions also do not work because they
use internal interrupts. The delayMicroseconds() function works since it does not use internal interrupts.
The function is attachInterrupt (digitalPinToInterrupt(pin), Function Name, action):
digitalPinToInterrupt(pin) – indicates which pin to use to receive the interrupt trigger (Pin 2 or 3).
Function Name – is the function to be executed when the interrupt is triggered.
Action – is the type of applied external action that will trigger the interruption:
• LOW - the interruption is triggered whenever the digital pin is in LOW (0 Volts). If you need to trigger
the interruption at a level of 5 volts (HIGH), just invert the digital signal with an inverter, for example,
the 7404 (see Computer Systems One in the Microsoft Store);
• CHANGE - the interruption is triggered whenever the voltage level applied to the digital pin changes
from LOW to HIGH or from HIGH to LOW;
• RISING - the interruption is triggered whenever the digital pin voltage changes from LOW to HIGH;
• FALLING - the interruption is triggered whenever the digital pin voltage changes from HIGH to LOW.
2. EXPERIMENTS
The following is a series of experiments divided by functional blocks:
BASIC PROGRAMS - these experiments test the capabilities of the Arduino itself, the digital inputs and outputs,
analog inputs, interruption, signal generation and shift operations.
SENSORS - a series of sensors are analyzed and tested. In this way any other type of sensor can be tested following
the methodology used in this chapter.
INPUT AND OUTPUT DEVICES - are devices that allow you to interact with the Arduino through keyboards, displays
and relays.
RADIO COMMUNICATIONS - Arduino is a microcontroller used to collect data obtained through a wide variety of
sensors and to control actuators, which can be keyboards, displays, relays and motors. The radio communication
modules allow you to obtain the data and control the Arduino remotely.
BLUETOOTH, ETHERNET AND WIFI - using communication via ethernet or WIFI it is possible to read data and
control devices via Arduino from any part of the earth, using the Internet for this. So, the Arduino becomes an IoT
device.
The experiments presented in this chapter are not covered in depth, since many readers have as their objective
the practical execution of the experiment. Anyone who wants a more detailed approach can study chapters 4
and 5.
2.1. BASIC PROGRAMS
The purpose of this chapter is to present some experiences that use basic Arduino-specific functions. These
functions are implemented by the Arduino IDE and use the hardware capability of the integrated Atmel328P. The
experiences can be found in greater detail in the chapter indicated next to each title.
ANALOG INPUT
DIGITAL INPUT
DIGITAL OUTPUT
INTERRUPT
TONE
PULSEIN
SHIFTIN AND SHIFTOUT
PULSE WIDTH MODULATION
You can use as a Solid Wire 22AWG or 24AWG jumper. One way to achieve this is to cut 2 meters of UTP CAT5
cable and use the 8 wires, which are solid, like jumpers.
ANALOG INPUT
We will use the Serial Monitor to analyze how the analog input works. The A/D converter converts between 0V
and 5V in 1023 steps. Let us connect the 10K pot as shown in the figure. Varying the central cursor, the voltage in
it varies between 0V and 5V. The indication on the Serial Monitor will vary from the decimal amount from 0 to
1023.
ASSEMBLY
In the assembly a breadboard can be used, or the potentiometer can be connected directly to the Arduino pins.
The potentiometer I used allows the direct connection of a male-female jumper, but this causes bad contact in
the potentiometer. The solution was to solder wires on the pot pins.
PROGRAM ANALOG INPUT
void setup()
{
Serial.begin(9600);
}
void loop()
{
int value = 0;
value = analogRead (A4); // reads on analog pin 4
delay(5000); // 5 second delay
Serial.print(value); // prints the value read as a decimal number
Serial.print(""); // print spaces
Serial.println(value, BIN); // prints the value read as a binary number
}
SERIAL MONITOR
DIGITAL INPUT
Let us now do a digital reading. Let us connect a switch on digital pin 5 of the Arduino. When the switch is activated,
the LED on pin 13 is turned on.
ASSEMBLY
The wires were soldered on the slide switch.
PROGRAM DIGITAL INPUT
When the value read on pin 5 is 5V the LED is lit. When the value read on pin 5 is 0V the LED is extinguished.
int status = 0;
void setup()
{
pinMode(5, INPUT_PULLUP); //sets pin 5 as a digital input with pullup
pinMode(13, OUTPUT); //sets pin 13 as a digital output
}
void loop()
{
status = digitalRead(5); //read the value of port 5
if(status == HIGH)
{
digitalWrite(13, HIGH); //write the value HIGH (5V) in port 13
}
else
{
digitalWrite(13,LOW); //write the value LOW (0V) in port 13
}
}
DIGITAL OUTPUT
To test the digital output, we will use pin 4 of the Arduino to light an LED. Let us use the switch from the previous
experiment to turn on the LED.
ASSEMBLY
PROGRAM DIGITAL OUTPUT
int status = 0;
void setup()
{
pinMode(4, OUTPUT); //sets pin 4 as a digital output
pinMode(5, INPUT_PULLUP); //sets pin 5 as a digital input with pullup
pinMode(13, OUTPUT); //sets pin 13 as a digital output
}
void loop()
{
status = digitalRead(5);
if(status == HIGH) //if pin 5 value = 5V
{
digitalWrite(13, HIGH); //then writes 5V in pins 13 and 4
digitalWrite(4, HIGH);
}
else
{
digitalWrite(13, LOW); //else writes 0V in pins 13 and 4
digitalWrite(4, LOW);
}
}
See that when BUILTIN_LED turns on (HIGH) the same happens with our LED.
INVERTING THE LED
If the circuit is the opposite, with the resistor connected to 5V, the behavior is also inverted. When BUILTIN_LED
is HIGH our LED is LOW. When our LED lights up, the yellow LED on the Arduino goes out. When our LED goes out,
the yellow LED lights up.
INTERRUPT
The interrupt is used whenever a specific action must be performed immediately without waiting for the program
being executed to finish. The running program is stopped, the command passes to the function called by the
interruption, this function is executed, finally the command is returned to the instruction where the program was
interrupted (Computer Systems One). The Arduino has two digital pins that accept hardware interrupts, pins 2 and
3. To execute the interruption we will use a push button switch that I installed on the breadboard. One pin is
connected to digital pin 2 of the Arduino and the other is connected to the GND. So, by pressing the button the
interruption is triggered.
ASSEMBLY
PROGRAM INTERRUPT
Const byte pinLEDkit = 13;
const byte pinLEDkit = 13;
const byte pinInter = 2;
const byte pinOurLED = 4;
int status = 0;
void setup()
{
pinMode(pinOurLED, OUTPUT);
pinMode(pinInter, INPUT_PULLUP);
pinMode(pinLEDkit, OUTPUT);
//Interrupt definition
attachInterrupt(digitalPinToInterrupt(pinInter), LedAction, LOW);
}
void loop()
{
if(status == 1)
{
digitalWrite(pinLEDkit, HIGH);
status = 0;
}
else
{
digitalWrite(pinLEDkit, LOW);
status = 1;
}
delay(1000);
}
PROGRAM TONE
To see what happens on pin 13, I connected an oscilloscope to it. The oscilloscope was calibrated as follows:
• the vertical axis of each dotted square equivalent to 1V.
• the horizontal axis of each square is equivalent to 200µsec.
The oscilloscope has two channels CH1 (yellow) and CH2 (green). The measurement was made with CH1. See the
signal occupies 5 vertical divisions (5V) and 5 horizontal n divisions (1msec) equivalent to 1KHz.
ASSEMBLY
Connect Arduino pins 10 and 12 using a male-to-male jumper.
PROGRAM PULSEIN
const byte pinTONE = 10;
const byte pinPULSEIN = 12;
void setup()
{
pinMode(pinTONE, OUTPUT);
pinMode(pinPULSEIN, INPUT);
Serial.begin(9600);
}
void loop()
{
unsigned long period = 0L;
unsigned long frequency = 1000L;
tone(pinTONE, frequency); //tone generation
period = pulseIn(pinPULSEIN, HIGH); //pulse duration detection
Serial.print("Progr Freq = ");
Serial.print(frequency);
Serial.print(" Real Freq = ");
Serial.println(1000000/(period*2)); //print frequency
delay(10000);
}
Delay(10000) creates a 10 second delay so that we can change the frequency and upload the new code.
Note that for the frequencies 100Hz, 50 and 40Hz, the programmed is the same as real. For the frequency 10Hz,
the actual frequency is completely different from the programmed one. Frequency 1000Hz has a 1% to 2% error.
This error occurs between 40Hz and 1000Hz. Outside this range, the error increases and the TONE function can
be used but is not accurate.
OK. We got our oscilloscope with some imagination.
SHIFTIN AND SHIFTOUT
These instructions allow you to move one byte of data into the microcontroller (shiftIn) or out of the
microcontroller (shiftOut) by one of the data pins, one bit at a time. These instructions allow you to expand the
physical input and output capacity of the Arduino.
• byte value = shiftIn(dataPin, clockPin, bitOrder)
• shiftOut(dataPin, clockPin, bitOrder, byte value)
ASSEMBLY
Let us test shiftOut() using the integrated 74HC595. The 74HC95 is a shift-register. The circuit can be seen below.
At each of the exits QA, QB, QC, QD, QE, QF e QG we will connect a 330Ω resistor connected to a led connected to
the GND. When QX is at 5V the led turns on. Our goal is to transmit a byte to the shift register using an Arduino
digital pin. The chosen byte is 170 = 1 x 128 + 0 x 64 + 1 x 32 + 0 x 16 + 1 x 8 + 0 x 4 + 1 x 2 = 1 0 1 0 1 0 1 0.
Below we see the circuit assembly with the byte 170 at the 74HC595 outputs. After serializing byte 170, the
program shifts bit by bit from byte 170 by writing each new byte to the 74HC595. The least significant bits are
reset to zero. Then he writes the byte 170 again and does a right shift bit by bit. The table is as follows:
OPERATION QA QB QC QD QE QF QG QH TIME(msec)
Write 170 1 0 1 0 1 0 1 0 1000
Shift Left 0 1 0 1 0 1 0 0 500
Shift Left 1 0 1 0 1 0 0 0 500
Shift Left 0 1 0 1 0 0 0 0 500
Shift Left 1 0 1 0 0 0 0 0 500
Shift Left 0 1 0 0 0 0 0 0 500
Shift Left 1 0 0 0 0 0 0 0 500
Shift Left 0 0 0 0 0 0 0 0 500
Shift Left 0 0 0 0 0 0 0 0 500
Write 170 1 0 1 0 1 0 1 0 1000
Shift Right 0 1 0 1 0 1 0 1 500
Shift Right 0 0 1 0 1 0 1 0 500
Shift Right 0 0 0 1 0 1 0 1 500
Shift Right 0 0 0 0 1 0 1 0 500
Shift Right 0 0 0 0 0 1 0 1 500
Shift Right 0 0 0 0 0 0 1 0 500
Shift Right 0 0 0 0 0 0 0 1 500
Shift Right 0 0 0 0 0 0 0 0 500
PROGRAM SHIFTOUT
int latchPin = 8; //connected to 74HC595 pin 12 RCLK
int clockPin = 10; // connected to 74HC595 pin 11 SRCLK
int dataPin = 9; // connected to 74HC595 pin 14 SER
byte dataToShift = 170; //1x128+0x64+1x32+0x16+1x8+0x4+1x2+0x1 = 10101010
void setup()
{
//pin configuration
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop()
{
digitalWrite(latchPin, LOW); //ground latchPin and hold
shiftOut(dataPin, clockPin, LSBFIRST, dataToShift); //display 170
digitalWrite(latchPin, HIGH); //return the latch pin high
delay(1000); //delay 1000 msec (1 sec)
for(int i = 0; i < 8; i++)
{
digitalWrite(latchPin, LOW);
dataToShift = dataToShift << 1; //shift one bit to the left
shiftOut(dataPin, clockPin, LSBFIRST, dataToShift); // the bits slide to the left
digitalWrite(latchPin, HIGH);
delay(500);
}
dataToShift = 170; //restore data
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, dataToShift); //display 170
digitalWrite(latchPin, HIGH);
delay(1000);
for(int i = 0; i < 8; i++)
{
digitalWrite(latchPin, LOW);
dataToShift = dataToShift << 1; //shift one bit to the left
shiftOut(dataPin, clockPin, LSBFIRST, dataToShift); // the bits slide to the right
digitalWrite(latchPin, HIGH);
delay(500);
}
}
Using 3 digital pins it is possible to create 8 digital pins. The 74HC595's Q H' output (pin 9) can be connected to the
second 74HC595 SER input allowing the same 3 digital pins to create 16 new digital pins.
PULSE WIDTH MODULATION
We studied PWM in lesson 3. Now we are going to test how PWM works in practice.
First, I upload the program below. It reads the voltage on analog pin A4. This voltage is provided by the cursor of
a 10K potentiometer connected to the 5V and the GND (see ANALOG INPUT). The analogWrite instruction works
with 256 steps, while the analog input works with 1024 steps. So, it is necessary to divide the value returned by
the analogRead() instruction by four before writing it in analogWrite(). We will write on the serial monitor the
value read in analogRead() and we will show on a LED connected to pin 9 the result of the instruction
analogWrite().
ASSEMBLY
Connect the 330 Ohm resistor to the digital pin 9. Connect the LED to the other side of the resistor and to the
ground. Connect the center pin of the potentiometer to the analog pin A4 and the other pins to the 5V and to the
ground, forming a voltage divider.
PROGRAM PULSE WIDTH MODULATION
int value = 0;
void setup()
{
pinMode(9, OUTPUT);
Serial.begin(9600);
}
void loop()
{
value = analogRead(A4);
delay(5);
analogWrite(9, value/4);
Serial.println(value/4);
}
You will see that moving the pot from side to side the LED will be more bright or less bright. At one end of the pot
the LED goes out. In the middle of the course the LED is half- light. At the other end of the pot, the LED lights up.
2.2. SENSORS
The Arduino is indicated for uses of IoT (Internet of Things). Its low cost combined with small memory and reduced
processing capacity make the Arduino a good choice for data collection systems that use the most diverse sensors.
In this lesson we will do several experiments using sensors. Most of the sensors that we will be using have internal
processors that make the Arduino's life easier, providing pre-processed data.
The 5K resistor can be replaced with a 4.7K resistor (4K7). In the case of the example, two 10K resistors were used
in parallel. VCC and GND voltages are provided by Arduino.
ASSEMBLY
The assembly can be seen below. The two side power lines on the breadboard were powered from the Arduino,
the red line with + 5V and the blue line with 0V (GND). There is a SHIELD that facilitates the connection, indicating
who is VCC, GND and OUT and with an easier connector to be inserted in the breadboard. The shield can be seen
on the breadboard as a comparison.
ENVIRONMENT
Below we list a program developed by ADAFRUIT that commercializes the DTH11 Sensor. The program was
modified to simplify. In our test the #define DHTTYPE DHT11. The pin of the Arduino connected to the sensor is 4.
You can modify the pin as indicated in the comment.
The program and libraries can be found at https://www.arduinolibraries.info/libraries/dht-sensor-library (this URL
can be copied from the notebook corresponding to this lesson). The search phrase on GOOGLE is dht11 arduino
library .zip download.
It is also necessary to download the Adafruit_Sensor library. Search GOOGLE with the phrase adafruit_sensor
library zip download. The library URL is https://www.arduinolibraries.info/libraries/adafruit-unified-sensor .
After downloading the library go to the IDE menu SKETCH ➔ ADD LIBRARY ➔ ADD .ZIP LIBRARY and indicate the
library to be loaded. After loading, go to the same submenu and see if DHT sensor library and Adafruit sensor
library are present.
PROGRAM TEMPERATURE AND HUMIDITY SENSOR
This code takes up little memory and can be used in complex projects. If you want a complete code, you can use
the sample code that comes with the DTH.h library and which can be found in lesson 3 of the System module.
void setup()
{
Serial.begin(9600);
dht.begin(); //DTH initialization
sensor_t sensor; //creates an object to receive sensor parameters
delayMS = sensor.min_delay / 100; //discovers sensor reading delay
}
void loop()
{
delay(delayMS); //waits sensor minimum delay
sensors_event_t event; //creates an object to store readings
dht.temperature().getEvent(&event); //trigger a temperature reading
if (isnan(event.temperature)) //if reading is not a number then error
{
Serial.println(F("Error reading temperature!"));
}
else
{
Serial.print(F("Temperature: "));
Serial.print(event.temperature); //print temperature
Serial.println(F("°C"));
}
dht.humidity().getEvent(&event); //trigger a humidity reading
if (isnan(event.relative_humidity))
{
Serial.println(F("Error reading humidity!"));
}
else
{
Serial.print(F("Humidity: "));
Serial.print(event.relative_humidity); //print humidity
Serial.println(F("%"));
}
}
We can see the sensor in operation using the SERIAL MONITOR. Above a screenshot of the serial monitor.
PRESSURE AND TEMPERATURE SENSOR - BMP180
HARDWARE
Below we can see the corresponding shield. SDA is the data connection with the Arduino and SCL the
synchronization line. VCC is connected to the Arduino 3.3V pin and GND to the Arduino GND pin. Pin 3.3 is for
selecting the voltage of 1.8 Volts and if 3.3 Volts is used it does not need to be connected.
The connector is not soldered on the board. So, you can use the board by soldering wires or with connector. The
connector is ideal for use on a breadboard.
ASSEMBLY
• VCC – 3.3 Volts – CONNECT ARDUINO 3.3V TO POWER THE BMP-180
• GND – 0 Volts
• SDA – PIN A4
• SCL – PIN A5
ENVIRONMENT
To test the BMP180 sensor it will be necessary to include the Arduino IDE libraries SFE_BMP180.h and Wire.h. Ask
google → sparkfun bmp180 arduino .zip library → select BMP180 Barometric Pressure Sensor Hookup -
learn.sparkfun …. → you will be redirected to the website → https://learn.sparkfun.com/tutorials/bmp180-
barometric-pressure-sensor-hookup-/all.
PROGRAM PRESSURE AND TEMPERATURE SENSOR
The program below is a fully functional code. This code takes up little memory and can be used in complex projects.
If you want a complete code, you can use the sample code that comes with the SFE_BMP180.h library and which
can be found in lesson 3 of the System module.
#include <SFE_BMP180.h>
#include <Wire.h>
SFE_BMP180 pressure; // Creating an SFE_BMP180 object called "pressure"
#define ALTITUDE 600.0 // Sensor altitude in meters, modify if necessary
void setup() {
Serial.begin(9600);
pressure.begin(); //Initialize the sensor
}
void loop() {
char status;
double T, P, p0; //Temperature, Pressure at sensor altitude, sea-level pressure
/*
start temperature measure
If status = 0 then error
If status != 0 then indicates time interval to complete measurement
*/
status = pressure.startTemperature(); //start temperature measure
if (status != 0)
{
delay(status); // Wait for the measurement to complete:
status = pressure.getTemperature(T); //get temperature value
if (status != 0) // if status = 1 then success if status = 0 then error
{
Serial.print("Temperature: ");
Serial.print(T,2);
Serial.print(" deg C, ");
/*
same process as the one used in the temperature
parameter from 0 to 3 (highest res, longest wait).
*/
status = pressure.startPressure(3);
if (status != 0)
{
delay(status);
status = pressure.getPressure(P,T);
if (status != 0)
{
Serial.print("absolute pressure: ");
Serial.print(P,2);
Serial.print(" miliBar, ");
p0 = pressure.sealevel(P,ALTITUDE);
Serial.print("relative (sea-level) pressure: ");
Serial.print(p0,2);
Serial.print(" miliBar, ");
}
else Serial.println("error retrieving pressure measurement\n");
}
else Serial.println("error starting pressure measurement\n");
}
else Serial.println("error retrieving temperature measurement\n");
}
else Serial.println("error starting temperature measurement\n");
delay(5000); // Pause for 5 seconds.
}
MPU6050 ACCELEROMETER AND GYRO
HARDWARE
This SHIELD is a combination of a 3-axis accelerometer (X, Y and Z) with a 3-axis gyroscope (X, Y and Z). The disconnected
AD0 pin defines that the sensor's I2C address is 0x68. Connect the AD0 pin to the Arduino 3.3V pin so that the address
changes to 0x69. This change allows you to have two MPU-6050 modules on the same Arduino. The connections
between the MPU6050 and the Arduino are shown in the table below.
ASSEMBLY
The shield comes with two connectors. You can use the shield with or without a connector. Either way you will
need to solder the connector or wires needed to connect the device to the Arduino.
ENVIRONMENT
To test the MPU6050 sensor it will be necessary to include the Wire.h library that already exists in the Arduino
IDE. Upload the program and turn on the MONITOR SERIAL.
PROGRAM ACCELEROMETER AND GYROSCOPE
// Based on the original program by JohnChi
#include<Wire.h>
const int MPU = 0x68; // Indicates the I2C communication address
int AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ; // variables to store sensor values
void setup() {
Serial.begin(9600); // Initializes serial communication between Arduino and serial monitor
Wire.begin(); // Initializes I2C communication
Wire.beginTransmission(MPU); // Starts I2C communication as an MPU-6050 device
Wire.write(0x6B); //PWR_MGMT_1 register
Wire.write(0); //Initializes MPU-6050
Wire.endTransmission(true); // Transmits bytes and releases the I2C bus
}
void loop() {
Wire.beginTransmission(MPU); // Starts communication with the MPU-6050
Wire.write(0x3B); // Starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false); // keeps the bus connected
// Request 14 sensor bytes from memory position 0x3B and releases the bus
Wire.requestFrom(MPU, 14, true);
readValues();
printValues();
delay(300); //Waits 300 ms
}
void readValues() {
// Stores the value of the sensors in the corresponding variables
// Since they are 16 bits (2 bytes) per variable, two Wire.read () are used through shift (<<8)
AcX=Wire.read()<<8|Wire.read(); //0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
AcY=Wire.read()<<8|Wire.read(); //0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
AcZ=Wire.read()<<8|Wire.read(); //0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
Tmp=Wire.read()<<8|Wire.read(); //0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
GyX=Wire.read()<<8|Wire.read(); //0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
GyY=Wire.read()<<8|Wire.read(); //0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
GyZ=Wire.read()<<8|Wire.read(); //0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
}
void printValues() {
Serial.print("AcX = "); Serial.print(AcX); //print X value from acelerometer
Serial.print(" | AcY = "); Serial.print(AcY); //print Y value from acelerometer
Serial.print(" | AcZ = "); Serial.print(AcZ); //print Z value from acelerometer
//print Temperature in Degrees Centigrade
Serial.print(" | Tmp = "); Serial.print(36.53 + Tmp/340.00);
Serial.print(" | GyX = "); Serial.print(GyX); //print X value from gyro
Serial.print(" | GyY = "); Serial.print(GyY); //print Y value from gyro
Serial.print(" | GyZ = "); Serial.println(GyZ); //print Z value from gyro
}
Note that the program uses only the WIRE library that is native to the Arduino IDE. This library takes care of I2C
communication. The program works directly with the sensor electronics, such as the memory positions that store
the various measurements, without resorting to other libraries that mask the complexity of the sensor electronics.
ULTRASONIC RANGING MODULE – HC-SR04
HARDWARE
The HC-SR04 module allows you to measure distances between 2 cm and 400 cm. The measurement accuracy is
3 mm. The HC-SR04 sensor uses the principle of sonar to determine its distance from an object, just as bats do.
The sensor has an ultrasonic transmitter and receiver.
The Arduino must emit a 10 µS pulse at the module's TRIGGER input. The module has a high-frequency transmitter
that emits 8 pulses at a frequency of 40 KHz. The module emits a pulse at the ECHO output whose width indicates
the distance from the obstacle. To obtain the distance in centimeters the Arduino must divide the ECHO pulse
width in microseconds by 58, for distance in inches divide by 148.
ASSEMBLY
When using a shield with pins it is possible to make the direct connection between the shield and the Arduino. I
used a ribbon with 4 wires male (to connect on the shield) and female (to connect on Arduino).
• VCC – 5.0 Volts (Red)
• TRIG – D5 (Green)
• ECHO – D6 (Yellow)
• GND – 0V (Brown)
PROGRAM ULTRASONIC RANGING MODULE
To test the HC-SR04 sensor, we must first install the HCSR04_ultrasonic_sensor-2.0.2 library obtained from the
link https://www.arduinolibraries.info/libraries/hcsr04-ultrasonic-sensor .
One of the applications of the sensor is to turn the lights on and off in a certain environment depending on the
level of natural light. The level can be adjusted by the potentiometer. The digital output is high whenever the
lighting level is higher than the set level and low whenever the lighting level falls below the set value. So, when
night falls, the D0 signal goes from 5V to 0V. A relay can be activated when the input level changes to 0V. We can
then connect the light sensor module to the relay module to activate the lighting of a room, a street, or a building.
In this case we do not need an Arduino. The circuit diagram can be seen below. The LM393 is a comparator. The
voltages between the + and - inputs are compared and if the + input voltage is higher or lower than the input
voltage - then the comparator output is 0V or 5V. In an input we have a 10K resistor for earth and the 10K
potentiometer for 5V. At the other input we have a 10K resistor for earth and the LDR for 5V. The resistance of
the LDR varies depending on the light level. Thus, by adjusting the potentiometer, it is possible to calibrate the
comparator circuit so that it acts when a certain brightness is reached. At this moment, output D0 changes state.
ASSEMBLY
Assembly is quite simple. Connect 5V, GND and D0 pin to Arduino D2 pin.
We will see the result initially on the serial monitor. I took advantage of a previous assembly wire, so there is a
brown wire connected to the GND, a red wire connected to the 5V and a green wire connected from D0 to the
Arduino digital input D2. There is a yellow wire left that is not connected at all.
PROGRAM LIGHTING SENSOR MODULE DIGITAL OUTPUT
The first test program aims to check the value of the digital output D0. For this we will connect it to the D2 pin of
the Arduino and read its value and show it on the serial monitor. Possible values are LOW (0 = 0V) and HIGH (1 =
5V).
void setup()
{
Serial.begin(9600);
pinMode(2, INPUT);
}
void loop()
{
int val = 0;
val = digitalRead(2);
Serial.print(val);
delay(1000);
}
The test result shows 0 when the LDR is in the light and 1 when the LDR is in the dark. So, the sensor is ideal for
turning on something when it gets dark.
We will now test the voltage value at the LDR terminals. For this we will read the analog voltage on pin A0 of the
Arduino. Where does this analog voltage come from? We will connect a wire to the Arduino pin A0 and connect
the other end of this wire directly to the terminal + of the LM393. The measured analog signal value is shown on
the serial monitor.
The Arduino analog input uses a 10-bit digital analog converter, providing values between 0 and 1023. The first
value read was obtained before connecting the wire to the LDR. Zero values are read with the wire connected to
the 0V (GND). Values around 46 indicate the value read on the + pin of LM393 when the LDR is well lit. The values
around 275 indicate the values read on the + pin of the LM393 when LDR is in the dark (I put my hand around the
LDR). Values around 107 when I shadowed my hand at the LDR.
To calibrate the analog converter, I connected input A0 to 3.3V and obtained the value 683. Making a simple 3
rule, if 3.3V = 683 then we have 0.004831V per step. Multiplying by:
0.004831V x 46 = 0.222V -- > too much light
0.004831V x 275 = 1.328V -- > dark
0.004831V x 107 = 0.517V -- > half-light
As we can see in the diagram below, what we have is a voltage divider whose equation is:
Working with the original equation, we obtain the equation that provides the LDR resistance from the R5 = 10K
resistance, the 5V supply and the voltage value at the LDR + terminal which is V_LDR.
Substituting the values, we have:
Too Much Light - 464Ω
Half-Light – 1153Ω
Dark – 3617Ω
2.3. INPUT AND OUTPUT DEVICES
Input and output devices are essential for computers and controllers to be able to interact with the environment.
Some of the most important ones like displays and keyboards are studied in this lesson. Relays allow you to control
large electrical loads such as electric motors using small powers.
The following program is very simple. Shows the static operation of the display. See below for an example in
conjunction with a keyboard.
PROGRAM LCD DISPLAY
#include <LiquidCrystal.h> // include the library code
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
// initialize the library by associating any needed LCD interface pin
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup()
{
lcd.begin(20, 4); // set up the LCD's number of 20 columns and 4 rows
lcd.clear(); // clear display
lcd.print("hello, world!"); //print text in column 0 and row 0
}
void loop()
{
lcd.setCursor(0,1); //set column 0 and row 1
lcd.print("Line 2"); //print text
lcd.setCursor(5,2);
lcd.print("Line 3");
lcd.setCursor(10,3);
lcd.print("Line 4");
delay(500);
}
TECLADO TTP229
HARDWARE
We will now test a keyboard built around the TTP229-BSF / 8229-BSF integrated circuit. The keyboard can have 8
or 16 keys. We will test the 16-key model. The keyboard is capacitive which means that it is activated by the
proximity of our finger, without having to physically press mechanical keys.
The SCL pin must be connected to the Arduino D8 pin and the SDO to the Arduino D9 pin. The I2C output provides
the status of all keys transmitted serially. The outputs OUT1 to OUT8 provide the status of each individual key. To
activate the 16-key mode, it is necessary to solder a jumper indicated in red in the image.
The operating voltage (VDC) can be selected between 2.4V and 5.5V. The output can be of the I2C type using SCL
for synchronization and clock and SDO to transmit the data to the Arduino.
ASSEMBLY
The assembly of the keyboard test circuit is shown below. The connection table is on the right. In them we have
the pins of the Arduino, the Keyboard and the colors of the wires.
The actual assembly can be seen below. I did not use a breadboard. I used male-female jumpers connecting the
female pins to the keyboard terminals and the male pins to the Arduino.
PROGRAM KEYBOARD
Following is the test program created by WWW.HOBBYCOMPONENTS.COM. This program does not use any
library, not even the Wire library. Each key pressed is indicated on the Serial Monitor.
/* Define the digital pins used for the clock and data */
#define SCL_PIN 8
#define SDO_PIN 9
PROJECT
The objective of the project is to study the interaction between the keyboard and the display. Each key pressed
on the keyboard is written on the display. For this to happen we must combine the two programs previously
studied and modify them according to the needs of the project.
The keyboard program uses the Serial Monitor to indicate the key that was pressed. The serial monitor works on
the laptop together with the Arduino IDE. After loading the program on Arduino, we no longer need the IDE. The
Arduino can be powered with a 9V power supply (or a 9V battery) starting to work autonomously, which is how it
should be used. The IDE is just to load the program and perform some tests to eliminate bugs and improve the
program.
Our goal is quite simple. Instead of the Arduino displaying the key on the serial monitor, it will display the key on
the display. So, we can disconnect the IDE.
Each digit occupies a 5x8 pixel block. Thus, key 11 occupies two blocks. Each space occupies a block. The phrase is
written at the beginning of the setup (column 0 and line 0). At the end of the setup, the cursor is placed in
lcd.setCursor(0.1) column 0 and line 1. From then on, each digit written, the cursor is incremented. However,
when being incremented beyond the number 20 the next digit is written in line 3. The cursor behavior when
reaching 20 should be:
• It returns to zero or
• Jumps to the zero position of the next line
None of these happens. How to set up a program so that the cursor obeys one of the two previous logics?
PROGRAM (CODE KEYBOARD AND LCD DISPLAY 2)
#include <LiquidCrystal.h> // include the library code
// initialize the library by associating any needed LCD interface pin
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#define SCL_PIN 8 //clock pin
#define SDO_PIN 9 //data pin
byte Key; //used to store key state
int column = 0, row = 1; //Cursor column and row values
void setup()
{
lcd.begin(20, 4); // set up the LCD's number of 20 columns and 4 rows
lcd.print("Keypad keys pressed "); //print text in column 0 and row 0
pinMode(SCL_PIN, OUTPUT); //configure clock pin
pinMode(SDO_PIN, INPUT); //configure data pin
lcd.setCursor(column, row); //set column 0 and row 1
}
void loop()
{
Key = Read_Keypad(); //read the current state of the keypad
if (Key) //if a key has been pressed
{
lcd.print(Key); //output it to display
lcd.print(“ “);
Cursor(Key); //call Cursor() function
}
delay(500); //wait 0.5 seconds
}
void Cursor(byte Key)
{
//we need to know if Key occupies one or two blocks of the display
if(Key < 10) column = column + 3;
// if Key is single digit then put cursor 3 spaces ahead else 4 spaces
else column = column + 4;
//maintain a security value so as not to fail to show any key
if(column > 16)
{
column = 0; //reset column
row++; //next row
if(row > 3) row = 1; //if row greater than 3 return to first row
}
}
The result of the changes can be seen below:
As we are testing the column at 16, the last 3 or 4 positions are not used. How to use as many positions as possible?
I do not need to print the space if the next number is printed on the next line. That is true? Modify the program
to optimize the use of the display.
This project is autonomous, that is, after uploading the program we can disconnect the Arduino from the laptop
and supply it with 9V and we will have a working keyboard and display device.
CONVENTIONAL RELAY MODULE
HARDWARE
This module allows the interface between the Arduino, which operates with low voltages (3.3V and 9V) and
currents (1A), with power devices, such as motors, electric heaters, among others, that operate with high voltages
(up to AC220V) and currents (up to 10A). The module operates at 5V voltage and between 15 and 20 mA per
channel. Each input is electrically isolated from the output using an optical coupler. Thus, the supply voltage of
the optical coupler diodes may be less than the supply voltage of the relay coils. In the test we will use the same
voltage for VCC and RY-VCC.
See that the relay contacts are completely isolated from the low voltage and low current circuit.
A voltage of 0V at the IN1 input causes the current to flow through resistor R1, lighting LED1, as well as the U1
optical coupler diode. The voltage between collector and emitter of the U1 optical coupler transistor is reduced
by causing resistor R2 and the base of transistor Q1 to be connected to the RY-VCC supply. The collector of
transistor Q1 goes to a voltage close to zero and the relay coil is energized. Contact 1, which is closed with contact
2, starts to close with contact 3. Diode D1 prevents the relay from de-energizing a negative voltage created by the
electromotive force of the relay coil from burning the transistor Q1.
ASSEMBLY
The relay can connect lamps, motors, heaters, equipment as long as the maximum load indicated is 240V and 10A,
that is, 2.4 KVA. The relay can also connect another much larger power relay, thus eliminating the indicated power
limitation.
PROGRAM RELAY MODULE
The program is quite simple. Every 5 seconds a digital level between LOW and HIGH is written on the digital port.
void setup()
{
Serial.begin(9600);
pinMode(2, OUTPUT);
}
void loop()
{
digitalWrite(2, LOW);
Serial.println(val);
delay(5000);
digitalWrite(2, HIGH);
Serial.println(val);
delay(5000);
}
In addition to the relay output lighting a green or red LED every 5 seconds, we also have an output on the serial
monitor. I turned on the Show Timestamp to show the time of each action.
The test setup is shown below. The leds are connected as shown on the side. When the central blade of the relay
closes on one side it turns on the green led, when it closes on the other side the red led is on.
2.4. RADIO COMMUNICATIONS
In this lesson we will study how to implement remote communication with the Arduino using a radio transmitting
and receiving module operating at 433 MHz. To perform the laboratory, it will be necessary to operate two
Arduino IDE simultaneously. Next, we study the use of 2.4 GHz transceivers to connect the Arduino.
#include <VirtualWire.h>
uint8_t buf[20];
uint8_t buflen = 20;
void setup()
{
Serial.begin(9600);
vw_set_rx_pin(12);
vw_setup(2400);
vw_rx_start();
delay(2000);
}
void loop()
{
if (vw_get_message(buf, &buflen))
{
Serial.print(buflen);
Serial.print(" ");
for (int i = 0; i < buflen; i++) Serial.write(buf[i]);
Serial.println(" ");
buflen = 20;
}
}
CONNECTING ARDUINO USING 2.4GHz RADIO
DESCRIPTION
All the information provided below was taken from NORDIC SEMICONDUCTOR documents, manufacturer of the
integrated circuit that are the core of the module that we will test. This semiconductor is widely used in remote
devices such as mice and keyboards.
The device has a transmitter and a receiver that use the same antenna. The module's operating mode is HALF-
DUPLEX. The module transmits or receives. With this method of communication one of the modules is always the
main and all the others are secondary. This is done to minimize collisions with two modules transmitting at the
same time. Collisions must be corrected by retransmitting the collided frames.
OSI MODEL PHYSICAL LAYER
The semiconductor uses the 2.4/2.5GHz frequency that is open, that is, it is not necessary to have a permission
for use. It is the same frequency used by the WIFI equipment. The electrical characteristics (layer 1 of the OSI
model) are as follows:
Voltage: 1.9V-3.6V
Current Consumption
• Transmitting: 115mA
• Receiving: 45mA
• Standby: 4.2µA
Maximum output power: 20 dBm
Reception sensitivity
• 2Mbp: -92dBm
• 1Mbps: -95dBm
• 250kbps: -104dBm
The nRF24L01 semiconductor uses FSK (Frequency Shift Keying) digital modulation studied in Computer Networks
One and reviewed in the previous lesson. The maximum data rate is 2Mbps.
OSI MODEL DATA LINK LAYER
The semiconductor also offers all the functionality of layer 2 of the OSI model directly in the hardware: error
control (CRC16), physical address, automatic retransmission in case of error.
The protocol used, called Enhanced ShockBurst, is the owner of NORDIC and implements a FRAME with a preamble
for frame synchronism, an address to differentiate one module from another, a field called PCF (Packet Code
Field), a data field and a CRC for error control.
The PCF field is divided into a field indicating the length of the data field, a FRAME identification field and a field
indicating whether the Frame should be confirmed or not. Note that the PCF field uses 9 bits. This is only possible
because FRAME operates on a layer 1 device that works with bits.
It is possible to set up a network with up to 256 stations. One of them should be the main one. The others receive
requests from the main station and respond to requests. We can also imagine a scheme in which the main station
contacts each station asking if it has something to transmit. If it has then transmits.
LIBRARY
We will use the RF24 library that can be obtained at https://www.arduinolibraries.info/libraries/rf24 developed
by TMRh20 and maintained by TMRh20 and Avamander. The .zip file must be imported by Arduino. The SPI library
must also be included since the communication between the module and the Arduino uses an I2C interface. We
already used this library in the SYSTEMS module. You can choose the pins used by the RF24 library. The pins used
by the SPI library are previously defined.
PIN DIAGRAM
There are several types of card that use the same integrated circuit. The module used in the test is shown below.
It does not use an external antenna and has no amplification circuit. The antenna is made on the printed circuit
itself and is the white figure in a kind of semicircle. Note that the pins have a marking indicating their function.
The color diagram used in the test, the name of the module pins and the Arduino pins to be connected are
indicated in the table.
The pinout diagram for other types of plates can be seen below. See that VCC and GND are together and care must
be taken when connecting the cards. ARD = ARDUINO. Other types of modules with amplifiers to extend the range
and external antenna can be seen below.
INITIAL TEST
We will do the test suggested by the RF24 library. In the FILE menu EXAMPLES submenu look for the RF24 library.
In the suggested examples select GETTING STARTED.
As there are two Arduino kits, you have to use the methodology suggested in lesson 1 of this module. The program
must be modified. A program must have bool radioNumber = 0; and in the other program bool radioNumber = 1;
to differentiate the two radios. We repeat the pinout table for module connection on Arduino.
In this way the program is doing a PING PONG and the result is to measure the total time between the sending of
the PING, its reception, the sending of the PONG and its reception by the main transmitter.
As we can see in the capture of the serial monitor, the round trip delay is 1.75 milliseconds.
PROGRAM RADIO 2.4 GHz
/*
* Getting Started example sketch for nRF24L01+ radios
* This is a very basic example of how to send data from one node to another
* Updated: Dec 2014 by TMRh20
*/
#include <SPI.h>
#include "RF24.h"
/****************** User Config ***************************/
/*** Set this radio as radio number 0 or 1 ***/
bool radioNumber = 1; //One radio is set to 0 and other radio is set to 1
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8); // pin CE, pin CSN
/**********************************************************/
byte addresses[][6] = {"1Node","2Node"};
// Used to control whether this node is sending or receiving
bool role = 0;
void setup()
{
Serial.begin(115200);
Serial.println(F("RF24/examples/GettingStarted"));
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
radio.begin();
// Set the PA Level low to prevent power supply related issues since this is a
// getting_started sketch, and the likelihood of proximity of the devices. RF24_PA_MAX is default.
radio.setPALevel(RF24_PA_LOW);
// Open a writing and reading pipe on each radio, with opposite addresses
if(radioNumber)
{
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
}
else
{
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}
// Start the radio listening for data
radio.startListening();
}
void loop()
{
/****************** Ping Out Role ***************************/
if (role == 1)
{
radio.stopListening(); // First, stop listening so we can talk.
Serial.println(F("Now sending"));
// Take the time, and send it. This will block until complete
unsigned long start_time = micros();
if (!radio.write( &start_time, sizeof(unsigned long) ))
{
Serial.println(F("failed"));
}
radio.startListening(); // Now, continue listening
// Set up a timeout period, get the current microseconds
unsigned long started_waiting_at = micros();
// Set up a variable to indicate if a response was received or not
boolean timeout = false;
while ( ! radio.available() ) // While nothing is received
{
// If wait longer than 200ms timeout and exit while loop
if (micros() - started_waiting_at > 200000 )
{
timeout = true;
break;
}
}
if ( timeout ) // Describe the results
{
Serial.println(F("Failed, response timed out."));
}
else
{
// Grab the response, compare, and send to debugging spew
unsigned long got_time;
radio.read( &got_time, sizeof(unsigned long) );
unsigned long end_time = micros();
// Spew it
Serial.print(F("Sent "));
Serial.print(start_time);
Serial.print(F(", Got response "));
Serial.print(got_time);
Serial.print(F(", Round-trip delay "));
Serial.print(end_time-start_time);
Serial.println(F(" microseconds"));
}
// Try again 1s later
delay(1000);
}
/****************** Pong Back Role ***************************/
if ( role == 0 )
{
unsigned long got_time;
if( radio.available()) // Variable for the received timestamp
{
while (radio.available()) // While there is data ready
{
radio.read( &got_time, sizeof(unsigned long) ); // Get the payload
}
radio.stopListening(); // First, stop listening so we can talk
// Send the final one back.
radio.write( &got_time, sizeof(unsigned long) );
// Now, resume listening so we catch the next packets.
radio.startListening();
Serial.print(F("Sent response "));
Serial.println(got_time);
}
}
/****************** Change Roles via Serial Commands ***************************/
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == 0 )
{
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
role = 1; // Become the primary transmitter (ping out)
}
else
if ( c == 'R' && role == 1 )
{
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
role = 0; // Become the primary receiver (pong back)
radio.startListening();
}
}
} // Loop
RESULT
• The transmitter sends the read millisecond:
unsigned long start_time = micros();
if (!radio.write( &start_time, sizeof(unsigned long) ))
• The receiver receives and sends back the same number.
• The transmitter receives the echoed value and compares it with the current value:
unsigned long end_time = micros();
Serial.print(F(", Round-trip delay "));
Serial.print(end_time-start_time);
FINAL TEST
The purpose of the test is to remotely trigger a relay and obtain confirmation that the relay has been activated.
We will use two Arduino kits, Arduino 1 and Arduino 2.
Arduino 1 has a switch connected to a digital input. Pressing the switch, the digital input changes the level. Arduino
1 is in transmission mode and sends the level read on the digital port to the other Arduino, which acts as a receiver
and that activates the relay, connected to a digital output, in an appropriate way to the received logic level. The
relay output is connected to an Arduino 2 digital input. Arduino 2 switches to transmission mode and the result of
the received command is read at the input port and transmitted back to Arduino 1. Immediately after sending the
command for Arduino 2, Arduino 1 changes its mode to reception to wait for confirmation of receipt of the
command. The confirmation signal is received and a LED is activated with the return command. We can thus see
if the command was obeyed.
void setup()
{
Serial.begin(9600);
radio.begin();
radio.openWritingPipe(address);
radio.stopListening(); // Enter Transmission mode
pinMode(2, INPUT_PULLUP); //Switch 1
pinMode(3, INPUT_PULLUP); //Switch 2
pinMode(4, OUTPUT); //Led 1
pinMode(5, OUTPUT); //Led 2
}
void loop()
{
frame[0] = digitalRead(2); //Reads input D2 and stores it in the first position
frame[1] = digitalRead(3); //Reads input D3 and stores it in the second
Serial.print("1- "); // Went through reading the key values
Serial.print(frame[0]);
Serial.print(" ");
Serial.println(frame[1]);
// transmits the state of the switches to the Arduino 2
radio.write(&frame, sizeof(frame));
radio.openReadingPipe(0, address); // switches to reception
radio.startListening();
// creates variable and stores current microseconds
unsigned long started_waiting_at = micros();
while(!radio.available()) // if not received
{
// tests reception start with current microseconds
if (micros() - started_waiting_at > 20000) continue;
}
if(radio.available()) // if received data
{
radio.read(&frame, sizeof(frame)); // read the Arduino 2 response
digitalWrite(4, frame[0]); //writes in led 1
digitalWrite(5, frame[1]); //writes in led 2
Serial.print("2- "); // went through the Arduino 2 response
Serial.print(frame[0]);
Serial.print(" ");
Serial.println(frame[1]);
}
radio.openWritingPipe(address); //switches to transmission
radio.stopListening();
delay(2000); //Waits for 2 seconds
}
RF24 radio(7,8);
void setup()
{
Serial.begin(9600);
radio.begin();
radio.openReadingPipe(0, address); // enter receiving mode
radio.startListening();
pinMode(2, OUTPUT); //relay 1
pinMode(3, OUTPUT); //relay 2
pinMode(4, INPUT_PULLUP); // central contact of relay 1
pinMode(5, INPUT_PULLUP); // central contact of relay 2
digitalWrite(2, HIGH); // initializes relay 1
digitalWrite(3, HIGH); // initializes relay 2
}
void loop()
{
if(radio.available()) // if received data
{
radio.read(&frame, sizeof(frame)); //read data
action1 = frame[0]; // load action1 variable
action2 = frame[1]; // load action2 variable
Serial.print("1- "); // went through receiving data from Arduino 1
Serial.print(action1);
Serial.print(" ");
Serial.println(action2);
// triggers relay 1 if the state has changed
if(action1 != action1_last) digitalWrite(2, action1);
// triggers relay 2 if the state has changed
if(action2 != action2_last) digitalWrite(3, action2);
delay(200); // wait for Arduino 1 to switch to reception
radio.openWritingPipe(address); // switches to transmission mode
radio.stopListening();
frame[0] = digitalRead(4); //read D4 state
frame[1] = digitalRead(5); //read D5 state
Serial.print("2- "); // passed through the relay status transmission
Serial.print(frame[0]);
Serial.print(" ");
Serial.println(frame[1]);
// transmits the status of the relays to the Arduino 1
radio.write(&frame, sizeof(frame));
action1_last = action1; // updates the state of the relay 1
action2_last = action2; // updates the state of the relay 2
radio.openReadingPipe(0, address); // switched to receive mode
radio.startListening();
}
}
In the receiver we use the action1_last and action2_last variables to store the previous command. The relay is
only activated if action1 or action2 has changed. This is done because the relay is an electromechanical device
that has a useful life given by the number of times it is activated. The system makes a new transmission every 2
seconds and would damage the relay. The program only activates the relay if the action is modified.
RESULTS
The result using the serial monitor can be seen below. I used the serial monitor to debug the program. Do not
think I wrote the program, and everything worked right away. It never happens. The mystery is to quickly debug
the program using existing tools. In the case of Arduino, the most effective tool is the serial monitor. The Arduino
is a controller like those that existed in the 1980s. The debugging at this time was done by printing messages on
screen in each loop (while) and testing (if) performed in the program. To differentiate in which location of the
program the printing was done, print the numbers 1, 2, 3 ... with the values of the variables in the corresponding
segment.
2.5. BLUETOOTH, ETHERNET AND WIFI
In this lesson we study how to connect the Arduino using computer network technologies. The first lab uses
Bluetooth devices. Next, we experiment with an Ethernet connection and finally a WIFI connection.
USING BLUETOOTH
CONNECTING ARDUINO TO A NETWORK USING ETHERNET
CONNECTING ARDUINO USING WIFI
THE ESP8266 MODULE AS WEBSERVER
USING THE ESPWIFI LIBRARY
USING BLUETOOTH
BLUETOOTH MODULE (NETWORK – LESSON 3)
One of the connection methods between devices is through Bluetooth. The Bluetooth connection is limited to 10
meters. It is widely used for connecting external keyboards and mouses to tablets and laptops. In this lesson, we
will use a module that uses an HC-05 board mounted on the module board.
SPECIFICATIONS
The specifications below refer to the HC-5 board and are taken from its datasheet.
HARDWARE FEATURES
• Sensitivity -80dBm
• Transmit Power 4dBm
• ISM 2.4GHz Band
• GFSK (Gaussian Frequency Shift Keying) Modulation
• 10m range
• Power voltage 1.8V to 3.6V
• Integrated antenna
• UART (Universal Asynchronous Receiver Transmitter) interface with programmable baud rate
• PIO (Programmable Input Output) control
SOFTWARE FEATURES
• Default Baud Rate 38400bps
• Supported Baud Rate(bps) 9600, 19200, 38400, 57600, 115200, 230400 and 460800
• Supports type AT commands
• Provides authentication and encryption security mechanisms.
The module used by Arduino has a regulator and can be powered with 5V or 3.3V. The module also has an LED
that indicates whether the HC-05 card is paired or not.
PROJECT
The project block diagram can be seen below. A DHT11 sensor provides temperature and humidity measurements
for the Arduino (see lesson 3 of the Arduino Systems module). The measurements are collected and processed by
the Arduino and transmitted to the laptop through a connection made between the Bluetooth module HC-05 and
the laptop's Bluetooth interface. An application must be installed on the laptop that can read the data sent by the
Bluetooth module. The laptop can be replaced with a smartphone with a similar application installed. In the test
we will use an application for Windows and an application for Android smartphone.
SCHEMATIC DIAGRAM
The module containing the HC-05 has a voltage regulator that supports any input voltage between 6V and 3.3V,
so we can supply the module with 5V. However, the TX and RX pins are connected directly to the HC-05 board and
operate with 3.3V. The TX pin will transmit a digital signal between 0V and 3.3V. The Arduino considers any signal
above 2.5V as logic level 1, it is not necessary to make any conversion between the HC-05 TX connection and
Arduino RX. However, the HC-05 RX pin operates between 0V and 3.3V. Conversion between Arduino TX and HC-
05 RX is required.
VOLTAGE DIVIDER
This conversion must be done using a voltage divider:
I will use 4K7 resistors as R1 and 6K8 as R2. I am using these because I have them in stock. R1 + R2 = 11K5.
Substituting in the equation VHC-05 = (6K8/11K5) x VARDUINO = 0.5913 x 5V = 2.96V
So, the value for level 1 is less than 3.3V but is high enough (> 1.65V) to be recognized by HC-05 as level 1.
PAIRING METHOD
The module presents the HC-05 login. To pair the module, turn on Bluetooth on your laptop or smartphone.
Select the HC-05 device. Enter password 1234.
PROGRAM BLUETOOTH 1
The HC-05 module is connected to pins D0 (RX) and D1 (TX) of the Arduino. The D4 pin is configured by the DHT11
library used in the program. The Arduino pins D0 and D1 are pre-configured as INPUT and OUTPUT respectively.
These pins are used by Arduino to communicate via USB with the IDE installed on the laptop. So, turn off the HC-
05 module at the time of uploading the program via the IDE by removing the 5V supply or disconnecting the
connections with the RX and TX pins. The Bluetooth module will work in parallel with the Serial Monitor.
Everything that appears on the Serial Monitor will be transmitted via the Bluetooth module.
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#define DHTPIN 4
#define DHTTYPE DHT11
DHT_Unified dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
sensors_event_t event;
dht.temperature().getEvent(&event);
Serial.print(F("Temperature: "));
Serial.print(event.temperature);
Serial.println(F("°C"));
dht.humidity().getEvent(&event);
Serial.print(F("Humidity: "));
Serial.print(event.relative_humidity);
Serial.println(F("%"));
delay(2000);
}
Thus, it is possible to transmit and receive in addition to avoiding the use of the Arduino TX and RX pins. The library
commands can be studied in lesson 4 of the programming module. How can we use this type of communication
in a practical situation? Let us redo the first example by adding control of the type of data we want to receive.
The assembly is identical to that of the first test. The program will be modified as follows:
1. If the Windows app sends the H command, then the Arduino sends the humidity measurements.
2. If the Windows app sends the T command, then the Arduino sends the temperature measurements.
The result can be seen below. After receiving the T command, the system transmits only the temperature. Upon
receiving the H command, the system transmits only humidity. Instead of the temperature and humidity sensor,
we can have a set of relays that can be activated to start a motor from commands sent from the laptop or
smartphone. The smartphone application allows customization of buttons to send commands when pressed. You
do not even need to write the command, just press the button and the previously configured command is sent.
ASSEMBLY
The 6K8 resistor is hidden under the green wire connected to pin 10 of the Arduino.
CONNECTING ARDUINO TO A NETWORK USING ETHERNET
ETHERNET MODULE
We will test the Ethernet module that contains the integrated ENC28J60. This integrated circuit implements all the
functionalities of an Ethernet port requiring a minimum of interaction with the Arduino. We will use the libraries
etherShield.h and ETHER_28J60.h which, in addition to interacting with the integrated, also create a layer that
implements some services and functionalities of layer 3 (network layer) as the possibility of configuring an IP address.
To better understand the lesson, see the COMPUTER NETWORK ONE app on the Microsoft Store.
HARDWARE
The hardware is simple and consists basically of the integrated circuit, a crystal to implement the clock for the integrated
circuit, and some discrete components. We have connecting pins for the interface between the Arduino and the module
and an RJ-45 connector that allows the connection of a UTP cable.
IEEE 802.3 STANDARD
PHYSICAL LAYER
• Supports one 10Base-T Port with automatic polarity detection and correction.
• Suports Full and Half duplex modes.
• Loopback mode.
• Fully compatible with 10/100/1000Base-T networks.
DATALINK LAYER MAC (Medium Access Control) SubLayer - Frame
• Frame Address
• Unicast
• Multicast
• Broadcast
• Automatic retransmission on collision
• Programmable padding and CRC generation
• Automatic rejection of erroneous frames
LAPTOP CONFIGURATION
For the project to work correctly, it is necessary to correctly configure the laptop's Ethernet interface. After
connecting the Arduino to the USB interface, see if the red LED on the Ethernet module lights up. If it lights up it
means that the module is correctly powered.
Select Properties, IP version 4 and Properties. Use the following IP address. OK.
WHEN THE EXPERIENCE IS COMPLETE DON'T FORGET TO RETURN TO THE ETHERNET PROPERTIES AND CHANGE
THE SELECTION TO OBTAIN AN IP ADDRESS AUTOMATICALLY.
SCHEMATIC DIAGRAM
The connection table indicates how the module and Arduino pins should be connected. The power of the Ethernet
module is 3.3V. WOL and CLK pins are not used in this test. The connection between the Arduino and the laptop
is the conventional one using the USB port. The connection between the Ethernet module and the laptop uses a
CAT5, CAT5E or CAT6 UTP cable. As we saw in the specifications of the integrated circuit the data rate of the
internet port is 10Base-T, that is, 10 Mbps maximum, therefore, the type of UTP cable is not critical.
When assembling, make a color scheme for the connections. If you are going to use a parallel wire cable,
disassemble the cable, remove each wire from the cable and use each wire separately. It does not look aesthetic,
but it is safer. Avoid connection error because it is difficult to work with a parallel cable.
ASSEMBLY
The assembly can be seen below. I used the breadboard just to mount the sensor. I connected the Ethernet module
directly to the Arduino using colored wires with the same colors as the scheme. Take care not to invert the power.
If you invert the module it will probably burn.
See that I used a cable with parallel wires, but I separated each wire. As I said earlier it is easier to work because
you can connect wire by wire. Note that in the diagram I separated the connector area to indicate the correct
connections. Connections are made on the opposite side to what is written. Do everything carefully and calmly.
LIBRARY
There are outdated versions of the library. The initial version of the library was written in 2010. It references a
type called prog_char that existed in the initial version of the Arduino library. If you try to compile the program an
error will occur. The links indicated below offer the new version of the library. They are made available in the
comments area of the code corresponding to this lesson.
https://drive.google.com/file/d/0B8E8Odwh-UGicnY1LUtDWjN3cTA/view?usp_web
https://drive.google.com/file/d/0B8E8Odwh-UGiUXdBOW5nMG84cXc/view
Below we indicate the location where the libraries are stored. If the wrong library is loaded the only way to delete
it is to access the directory and delete it.
PROGRAM USING ETHERNET
In the program we first declare the libraries of the Ethernet module. We declare a 6-character mac[] array (uint8_t)
and load into this array the MAC address we want to give to our card. Next, we declare a 4-character ip[] array
and load the desired IP address into this array. Choose an IP address that does not conflict with your WIFI network.
As my network has the network address 192.168.0.0, so I chose the address 192.168.2.253. As we will
communicate with the Browser using HTML language then the port number is 80. Finally, we create an object
called ether that inherits the properties of the ETHER_28J60 class.
Next, we include the DHT-11 sensor library and the same initialization and definition values that we saw in lesson
3 of the Systems module. We created the auxiliary variables int temp and int hum.
In the setup we initialize the Serial Monitor, the DHT-11 sensor and the Ethernet module indicating its MAC, IP,
and the port to be used in the communication.
The loop reads the temperature and humidity, printing the values read on the Serial Monitor. Next, it is checked
whether a service request has been made by a customer. If the request was made, an HTML page is mounted line
by line and stored in the transmission buffer of the Ethernet module. Finally, the command ether.respond() is sent
to transmit the complete HTML page.
#include "etherShield.h"
#include "ETHER_28J60.h"
static uint8_t mac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24};
static uint8_t ip[4] = {192, 168, 2, 253};
static uint8_t port = 80;
ETHER_28J60 ether;
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#define DHTPIN 4
#define DHTTYPE DHT11
void setup() {
// Initializes the card with the settings provided
ether.setup(mac, ip, port);
dht.begin();
Serial.begin(9600);
}
void loop() {
sensors_event_t event;
dht.temperature().getEvent(&event);
Serial.print(F("Temperature: "));
temp = event.temperature;
Serial.print(temp);
Serial.println(F("C"));
dht.humidity().getEvent(&event);
Serial.print(F("Humidity: "));
hum = event.relative_humidity;
Serial.print(hum);
Serial.println(F("%"));
if (ether.serviceRequest()) {
ether.print((char*)"<H1>ENC28J60 TEST</H1><br/>");
ether.print((char*)"<b>Temperature: ");
ether.print(temp);
ether.print((char*)"C<br/><br/>");
ether.print((char*)"<b>Humidity: ");
ether.print(hum);
ether.print((char*)"%<br/><br/>");
ether.respond();
}
delay(200);
}
RESULT
The Arduino will play the role of WEB Server and the Browser on the laptop will play the Client. Each time you
start your browser with address 192.168.2.253, the Arduino will send the temperature and humidity values. As
the environment is Client-Server, Arduino cannot initiate a connection, it needs a request from the client (see
COMPUTER SYSTEMS ONE). Each time you start your browser with address 192.168.2.253, the Arduino will send
the temperature and humidity values. As the environment is Client-Server, Arduino cannot initiate a connection,
it needs a request from the client.
CONNECTING ARDUINO USING WIFI
WiFi and the cellular network are currently the most used methods to connect any device on the Internet. WiFi
uses the 2.4GHz and 5GHz frequencies that do not require a license to use. On the other hand, anyone can use
these frequencies, including their microwave oven that runs at 2.4GHz, causing a lot of noise and interference in
these frequencies. One advantage is that the devices operate at low power and interference is limited to nearby
access points. We studied the functioning of WiFi in COMPUTER NETWORK ONE available in the Microsoft store.
ELECTRICAL CHARACTERISTICS
• Operating voltage and logic level: 3.3V
• Typical operating current: 500 mA
• Deep sleep power <5uA
• Standby power consumption of <1.0mW
802.11 CHARACTERISTICS
• 802.11 b / g / n
• + 20dBm output power in 802.11b mode - direct sight range without interference 90 meters
• Maximum data rate: 2 Mbps
• Communication with the module: Serial using AT protocol for modem
NETWORK CHARACTERISTICS
• Network communication: TCP/UDP protocol stack
• Encryption: OPEN/WEP/WPA_PSK/WPA2_PSK/WPA_WPA2_PSK
PHYSICAL CHARACTERISTICS
• Operating temperature range -40C ~ 125C
FIRST CONTACT
The ESP8266 has a FLASH memory (SRAM) that contains the device's firmware and operating parameters. The
problem is that both the firmware and the operating parameters are updated frequently. The biggest change
made over time is the data rate used by the ESP8266 serial interface (UART pins TX and RX). In the first modules
the speed was 115200 bps and in the modern modules it is 9600 bps.
The ESP8266 module operates with 3.3V. If your Arduino kit works with 3.3V everything will be easier. If your kit
works with 5V then we will have to use a voltage divider between the digital pin TX of the Arduino and the pin RX
of the WiFi module. Between the pin TX of the module and the pin RX of the Arduino it will not be necessary. The
Arduino considers that a value above 2.5V is bit 1, so the value of 3.3V is identified by Arduino as bit 1.
CIRCUIT
The Arduino's 3.3V power supply cannot handle powering the ESP-01 module. It is necessary to use an external
3.3V source that supplies more than 0.5A. It is also necessary to place a 10 µF/50V capacitor on the 3.3V supply
to filter out the noise and stabilize the voltage. You can try to use a 5V external source and put two diodes in series
on the source output that support at least 1A. Each diode will provide a voltage drop that will vary depending on
the current consumed by the module and should vary between 0.8V and 1V. Thus, the power will vary between
3.4V and 3.0V, that is, it will not be a stabilized source. If the communication has an error, try to use a stabilized
3.3V source.
In this experiment I use a voltage divider of 4K7 and 2K2. You can use the previously used 6K8 and 4K7 voltage
divider.
PROGRAM WIFI ESP-01 INITIAL TEST
The program uses the SoftwareSerial library. Declares a new esp8266 object of type SoftwareSerial and indicates
the digital pin 2 of the Arduino as the RX pin and the digital pin 3 of the Arduino as the TX pin. Initializes the Serial
Monitor at 9600 bps. Initializes the esp8266 object at speed 115200. Sends the command AT+RST\r\n to reset the
ESP-01 module. This type of command is used to configure modems and means ATtention followed by the
command ending with Carriage Return (\r) and LineFeed or NewLine (\n). There are documents on the Internet
detailing the AT commands of the integrated - ESP8266 AT Instruction Set.
The command is transmitted from Arduino to ESP-01 by the sendData function. Reception is done by the
receiveData function.
#include <SoftwareSerial.h>
SoftwareSerial esp8266(2, 3);
void setup() {
Serial.begin(9600);
esp8266.begin(115200); //starts with communication in 115200
sendData("AT+RST\r\n");//reset esp8266
}
void loop() {
receiveData();
delay(1000);
}
void receiveData() {
while(esp8266.available()) //while esp8266 buffer is not empty
{
char c = esp8266.read(); //read char in buffer
Serial.print(c); //send command
}
}
RESULT
The result can be seen below. The command is sent by the Arduino to ESP-01 (AT+RST). It is answered by ESP-01
(OK). It is executed by ESP-01 and after the reset, ESP-01 sends the result indicating that it was left by external
action (cause: 1) and that everything went well (boot mode: (3.7)).
OK the module is working. If you receive no response, or if the response consists of random characters, replace
115200 with 9600 and repeat the process. Your module probably already uses the modern version of the control
program.
Another simple action is to check the WIFI stations that your laptop can identify if there is any station
corresponding to the ESP-01. I summarized the list of stations to show that one appears with the name of
ESP_EFD33D without security.
Most parameters exist for the purpose of compatibility with older devices. Currently all data transmission is done
with 8 bits of data and 1 stop bit. You can use a parity bit. If the <parity> bit is set to 1 (ODD), bits 1 are counted
and if the count is odd, a bit 1 is added in the transmission after the last data bit and before the stop bit, otherwise
the added bit is a bit 0. If set to 2 (EVEN) bit 1 is added if the count is even, otherwise the added bit is a bit 0.
Flow control is no longer used. It was widely used at the time of video terminals connected to large computers
when the connection was exceptionally long and coordination between the monitor or other equipment and the
modem was necessary. The long connection degrades the shape of the bits and with flow control the error rate
was reduced.
Then the setup code is as follows for the provisional configuration:
CODE WIFI ESP-01 CHANGING SPEED
#include <SoftwareSerial.h>
SoftwareSerial esp8266(2, 3);
void setup()
{
Serial.begin(9600);
esp8266.begin(115200);
sendData("AT+UART_CUR=9600,8,1,0");
delay(2000);
sendData("AT+RST\r\n");
}
void loop()
{
}
CONFIGURING ESP-01
We will then carry out the configuration of the ESP8266 as a WIFI station and make the connection to a WIFI access
point and observe the IP obtained by the station. We will use a methodology that allows us to analyze the result
of the AT commands. It will not be the methodology to be used in the final project, but it will allow to analyze in
detail how the ESP8266 works and how it interacts with the Arduino.
CIRCUIT
The following assembly can be used to test any type of AT command.
We will install a PUSH-BUTTON switch connected to the digital pin 12 of the Arduino and the GND. Pin 12 is
configured as INPUT_PULLUP. Thus, when the switch is pressed, it connects pin 12 in the GND, passing from HIGH
to LOW the level of this pin. This switch will be used to execute the ESP8266 configuration instructions in step-by-
step mode so that we can see what happens. The rest of the assembly will be the same as the previous assembly.
TESTING THE WIFI ESP-01 COMMANDS
I used a specific WIFI access point to do the tests. You can use your WIFI access point to do the tests. I connected
a network cable between the laptop's ETHERNET interface to one of the access point's inputs. I configured the
access point with the SSID ArduinoTest and PASSWORD Test1234. I configured the router's IP network as
192.168.2.0 with the router automatically assuming IP 192.168.2.1 as the default gateway (COMPUTER NETWORK
ONE – MICROSOFT STORE).
#include <SoftwareSerial.h>
SoftwareSerial esp8266(2, 3);
int flag = 0;
int action = 1;
void setup()
{
Serial.begin(9600);
esp8266.begin(9600);
pinMode(12,INPUT_PULLUP);
}
void loop()
{
ExecuteCommand();
receiveData();
}
void receiveData()
{
while(esp8266.available()) //assembly esp8266 response
{
char c = esp8266.read();
Serial.print(c);
}
}
void ExecuteCommand()
{
action = digitalRead(12);
if(action == 0)
{
switch(flag)
{
case 0:
esp8266("AT+RST\r\n"); //reset
break;
case 1:
esp8266("AT+CWMODE_CUR=1\r\n");//station mode
break;
case 2:
esp8266("AT+CWLAP\r\n");//list all wifi stations
break;
case 3:
//register esp8266 to access point ArduinoTest
esp8266("AT+CWJAP_CUR=\"ArduinoTest\",\"Test1234\"\r\n");
break;
case 4:
esp8266("AT+CIPSTA_CUR?\r\n"); //display received IP
flag++;
break;
}
}
flag++;
action = 0;
delay(1000);
}
RESULT
On the router we can see that there is a station associated with MAC A4:CF:12:EF:D3:3D. 8 packets were received
by the access point and 4 packets were transmitted to ESP8266.
Once the module is connected to the router and the notebook also then we can ping between the notebook and
the module through the WIFI router.
THE ESP8266 MODULE AS WEBSERVER
The next step is to use the module as a TCP server. We can consult the module using the laptop's Browser. Thus,
it is possible to use the module so that it is possible to remotely access the Arduino kit. WEBSERVER is a TCP server
that uses HTTP layers 6 and 7. The TCP server can keep several connections open simultaneously and each of these
connections can have several active streams. Each stream uses a specific TCP port (SOCKET – see COMPUTER
SYSTEMS ONE).
PROGRAM
The module registers with the SSID access point ArduinoTest and PASSWORD Test1234. Both SSID and PWD must
be entered between "". The AT command is:
AT+CWJAP="ArduinoTest","Test1234"\r\n
C++ does not accept "within others". So, it is necessary to use the \ character before each quotation mark. This
character tells the C ++ compiler that the quote must be kept. It is called escape code and is removed by the
compiler in the final assembly of the program.
The TCP server, once configured, goes into reception mode, listening to the network to see if there are any
packets/ flows destined for it. If data sent to the module is available, the AVAILABLE command indicates this.
To reply to the client it is necessary to know the number of the flow that the TCP created on the server (module
esp8266) to send the reply to the client. The flow number is the red number following the string + IPD, 1,370: GET.
So, the find() function is used to find the substring + IPD, and the next byte is read. The next byte is an ASCII
character from the stream number. To transform it into an integer number it is necessary to subtract 48, thus
obtaining an integer (see ASCII table).
CODE WIFI ESP-01 AS WEBSERVER
#include <SoftwareSerial.h>
SoftwareSerial esp8266(2, 3); //RX and TX pin
void setup()
{
Serial.begin(9600);
esp8266.begin(9600); //communication with esp8266
sendData("AT+RST\r\n", 2000); //module reset
//register at the access point
sendData("AT+CWJAP=\"ArduinoTest\",\"Test1234\"\r\n", 2000);
delay(5000);
sendData("AT+CWMODE=1\r\n", 1000); //WIFI station mode
sendData("AT+CIFSR\r\n", 1000); //requests IP and MAC address
// allows multiple simultaneous TCP streams
sendData("AT+CIPMUX=1\r\n", 1000);
sendData("AT+CIPSERVER=1,80\r\n", 1000); // configure as TCP server
}
void loop()
{
if (esp8266.available()) // there is data received?
{
if (esp8266.find("+IPD,")) // detects the string
{
delay(300);
// flow number (character) - 48 (int)
int connectionId = esp8266.read() - 48;
sendData(closeCommand, 3000);
}
}
}
void sendData(String command, const int timeout)
{
String response = "";
esp8266.print(command);
long int time = millis();
while ( (time + timeout) > millis()) // wait for timeout for response
{
while (esp8266.available())
{
char c = esp8266.read();
response += c;
}
}
Serial.print(response);
}
RESULT
The result can be followed on the serial monitor. I compressed the presentation. What you are going to see is a
little bit different.
Initially the module is reset. It then connects to the access point. Enter station mode. Reports your IP and MAC.
The IP is important because it is what you are going to use in the laptop's browser to connect to the module. The
module is configured to accept multiple TCP streams simultaneously. It is then configured as a TCP server. It can
only be configured as a server if it is configured to receive multiple simultaneous streams. The module then starts
listening to the network to see if there are any service requests sent by a customer.
Open the Browser on your laptop and enter the module's IP in the top bar and press ENTER. The browser will send
a request to the TCP server using the IP/TCP/HTTP protocols. The module will receive the request sent by the
laptop and routed through the WIFI router. The request block starts with the string + IPD,1. The flow identifier 1
follows the comma. From there, communication is made between the module and the client's browser. In the end
the connection is terminated by the server. Note that in the TCP client-server system the server is passive, it listens
to the network to detect a request from a client. When the request arrives, it becomes the active element. It
responds to the customer's request and ends communication.
USING THE ESPWIFI LIBRARY
There are libraries that hide the use of AT commands. We will then test the use of some of these libraries. These
libraries also use the SoftwareSerial library when communicating with the module, but the use is internal, that is,
you cannot work directly with it. The hardware is the same only the program is modified. In this example we will
turn on and off the LED connected on pin 13 of the kit.
PROGRAM (CODE USING ESPWIFI LIBRARY)
#include "WiFiEsp.h"
#include "SoftwareSerial.h"
RingBuffer buf(8);
int statusLed = LOW;
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(9600);
Serial1.begin(9600);
WiFi.init(&Serial1);
WiFi.config(IPAddress(192,168,2,110));
if(WiFi.status() == WL_NO_SHIELD)
{
Serial.println("WiFi shield not present");
while (true);
}
while(status != WL_CONNECTED)
{
Serial.print("Attempting to connect to WPA SSID: ");
status = WiFi.begin(ssid, pass);
}
Serial.println("You're connected to the network");
server.begin();
}
void loop()
{
WiFiEspClient client = server.available();
if (client)
{
buf.init();
while (client.connected())
{
if(client.available())
{
char c = client.read();
buf.push(c);
if(buf.endsWith("\r\n\r\n"))
{
sendHttpResponse(client);
break;
}
if(buf.endsWith("GET /H"))
{
digitalWrite(LED_BUILTIN, HIGH);
statusLed = 1;
}
else
{
if (buf.endsWith("GET /L"))
{
digitalWrite(LED_BUILTIN, LOW);
statusLed = 0;
}
}
}
}
client.stop();
}
}
void sendHttpResponse(WiFiEspClient client)
{
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("");
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head>");
client.println("<title>TEST USING WIFIESP LIBRARY</title>");
client.println("</head>");
client.println("<body>");
client.println("<p style='line-height:2'><font>ESP8266 WIFI MODULE</font></p>");
client.println("<font>BUILTIN LED STATUS</font>");
if (statusLed == HIGH)
{
client.println("<p style='line-height:0'><font color='green'>ON</font></p>");
client.println("<a href=\"/L\">OFF</a>");
}
else
{
if (statusLed == LOW)
{
client.println("<p style='line-height:0'><font color='red'>OFF</font></p>");
client.println("<a href=\"/H\">ON</a>");
}
}
client.println("</body>");
client.println("</html>");
delay(1);
}
RESULT
CONCLUSION
The use of a WIFI network is interesting when we must interface with several Arduino devices operating as sensors
/ controllers in a small area such as a building or a house. In general, small access points allow connections over
distances of 20 meters when there are few walls between the access point and the WiFi module. In an external
environment it is possible to reach distances of around 100 meters operating in 802.11b mode.
3. BRINGING IT ALL TOGETHER IN ONE PROJECT – WEATHER STATION
the project aims to develop a weather station connected to the internet that shows the value of temperature,
humidity, and atmospheric pressure on a display.
In Systems Lesson 3 we saw how these three sensors work and developed test projects for each one. Now we
must combine the three projects into one project. For this we will have to start with a functional project in which
we must specify how the equipment will work, then a hardware project indicating how all the components should
be interconnected and finally create a program that performs the functional specification.
• PROJECT
• MODULES TEST
• TEST 1 - PROGRAM WITHOUT ALTITUDE ADJUSTMENT
• TEST 2 - PROGRAM WITH ALTITUDE ADJUSTMENT BY POOLING
• TEST 3 - PROGRAM WITH ALTITUDE ADJUSTMENT BY INTERRUPTHARDWARE
• TEST 4 - USING THE ARDUINO PRO MINI
• TEST 5 – ARDUINO PRO MINI WIFI
3.1. PROJECT
Let us define the parameters of our project.
DATA PRESENTATION
The first step is to define how the measurements will be shown on the display. The display has 4 lines with 20
characters per line. We can do the following:
• ROW 1 – Temperature – Temperature XX deg C
• ROW 2 – Humidity – Humidity XX %
• ROW 3 – Pressure Measured at Altitude – Abs YYYY mB Alt XXXX m
• ROW 4 – Sea Level Pressure – Sea Level YYYY mB
TEMPERATURE MEASUREMENT – BMP180 OU DHT11
The second step is to define what temperature measurement will be displayed. Both the pressure sensor and the
humidity sensor read the temperature. Which of these temperatures will be displayed? Reviewing lesson 3, we
see that the BMP180 sensor has better accuracy. We will use BMP180 to read the temperature.
TREATMENT OF READING ERRORS
The third step is to define how our project will handle reading errors. The user does not want to know if the
reading was successful or unsuccessful. The user wants to see the measured value so we will not indicate any
errors.
ALTITUDE ADJUSTMENT
The last problem is how to adjust the altitude so that the device delivers pressure at sea level. Why know the
pressure at sea level? Because the pressure at sea level is used in meteorological reports and allows to compare
whether the pressure is low (rain) normal or high (sun). One possibility is to use a potentiometer with one end
connected to 5V, the other end connected to GND and the central cursor connected to analog input A3. When
being manipulated to one side or the other, the voltage of the central cursor varies between 0V and 5V, changing
the voltage in A3 and thus the digital value read by the Arduino. A specific function in the program will convert
this digital value at an altitude between 0 and 3000 meters. The adjustment operation is shown on the display
allowing the user to adjust the altitude. To start the altitude adjustment operation, simply activate a switch
connected to an Arduino digital pin. Returning the switch to the previous position ends the adjustment.
TEST ASSEMBLY WITHOUT ALTITUDE ADJUSTMENT
We will assemble and test the project in parts. When developing a new project, the ideal is to test each module
that makes up the whole project until the it is working correctly. To test each module, we will use a specific
program. If a problem occurs when we put all the modules together, we will know that the error is in some specific
hardware interaction or an error of the final code.
When assembling each module, be careful with the wrong connections, especially the connections to the power
supply, and the bad contact between the connections and components. A loose connection can be quite difficult
to detect and can give the impression that the program is buggy. Will be better if you can solder 22 or 24 AWG
solid wires to the potentiometer and switch terminals. So, you can confirm that each module is OK, and the
corresponding connections are OK. Next, we test the complete program. We will first test the program without
adjusting the Altitude. If everything works correctly then we move on to the last phase of the project which is to
test the altitude adjustment.
3.2. MODULES TEST
In the following items we will test each module separately to check if everything is working OK. The suggestion is
that you assemble a module, test this module, if it is OK then assemble the next module on the breadboard and
do the test. The program below was reproduced from Chapter 2 (Experiments – 2.3).
LCD DISPLAY TEST
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
lcd.begin(20, 4);
lcd.clear();
lcd.print("hello, world!");
}
void loop() {
lcd.setCursor(0,1);
lcd.print("Line 2");
lcd.setCursor(5,2);
lcd.print("Line 3");
lcd.setCursor(10,3);
lcd.print("Line 4");
delay(500);
}
Below you can see the actual assembly as it was. You can also see the test result of the display. In all the confusion
of the assembly the display is working correctly!! This assembly already has the potentiometer and the switch for
altitude adjustment.
BMP180 TEST
Now we are going to test the pressure module using the test program and checking its operation with the Serial
Monitor. The program below was reproduced from Chapter 2 (Experiments – 2.2). I removed the comments and
simplified the PRESSURE AND TEMPERATURE SENSOR TEST program. If necessary, go back to lesson 4 to see the
detailed program.
#include <SFE_BMP180.h>
#include <Wire.h>
SFE_BMP180 pressure;
#define ALTITUDE 600.0
void setup() {
Serial.begin(9600);
pressure.begin();
}
void loop() {
char status;
double T,P,p0,a;
status = pressure.startTemperature();
delay(status);
status = pressure.getTemperature(T);
Serial.print("temperature: ");
Serial.print(T,2);
Serial.print(" deg C, ");
status = pressure.startPressure(3);
delay(status);
status = pressure.getPressure(P,T);
Serial.print("absolute pressure: ");
Serial.print(P,2);
Serial.print(" mb, ");
p0 = pressure.sealevel(P,ALTITUDE);
Serial.print("relative (sea-level) pressure: ");
Serial.print(p0,2);
Serial.print(" mb");
Serial.println("");
delay(5000);
}
DHT11 TEST
The display has now been tested. The pressure sensor has already been tested. We will now test the humidity
sensor using the test program in lesson 3. Change pin 4 to pin 7. At the end of the code we can see the test result
on the Serial Monitor. I removed the comments and simplified the HUMIDITY AND TEMPERATURE SENSOR TEST
program. The program below was reproduced from Chapter 2 (Experiments – 2.2).
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#define DHTPIN 7
#define DHTTYPE DHT11 // DHT 11
void setup() {
Serial.begin(9600);
dht.begin();
sensor_t sensor;
dht.temperature().getSensor(&sensor);
dht.humidity().getSensor(&sensor);
delayMS = sensor.min_delay / 100;
}
void loop() {
delay(delayMS);
sensors_event_t event;
dht.temperature().getEvent(&event);
Serial.print(F("Temperature: "));
Serial.print(event.temperature);
Serial.println(F("°C"));
dht.humidity().getEvent(&event);
Serial.print(F("Humidity: "));
Serial.print(event.relative_humidity);
Serial.println(F("%"));
}
We are now ready to take the first test of our project program. We know that all the devices are working. If a
problem occurs it is due to an error in our program.
FINAL TEST AND DEBUG PROGRAM
The probability that a program will not work as expected is normally 100%. As a result, it is important to master
debugging strategies that allow solving problems in an orderly and methodical way. The more complex the
program, the greater the possibility of error.
We will share the program's features and test them part by part. So, we can divide the problem into simple and
objective parts and test them.
TEST 1 - MAIN PROGRAM WITHOUT ALTITUDE ADJUSTMENT
First, let us test if the program inserts the correct values on the display. We are not interested in the error control
subroutine. I removed the error control vectors. We will reinsert them later. I simplified the error control function.
Load the WEATHER STATION WITHOUT ALTITUDE ADJUSTMENT program.
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#include <SFE_BMP180.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#define DHTPIN 7
#define DHTTYPE DHT11
#define ALTITUDE 600.0
DHT_Unified dht(DHTPIN, DHTTYPE);
uint32_t delayMS;
SFE_BMP180 pressure;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
dht.begin(); //Initialize DTH11
pressure.begin() ; //Initialize BMP180
lcd.begin(20, 4); //Initialize LCD
lcd.clear();
}
void loop() {
char status;
double T, P, p0, a;
delay(1000);
sensors_event_t event; // Get temperature event
dht.temperature().getEvent(&event);
delay(500);
dht.humidity().getEvent(&event); // Get humidity event and print its value.
lcd.setCursor(0,1); //set column 0 and row 1
if (isnan(event.relative_humidity)) {
ErrorAction(0, 1);
}
else {
//humidity with 2 decimal places
lcd.print("Humidity " + String(event.relative_humidity,2) + " %");
}
delay(500);
lcd.setCursor(0,0); //set column 0 and row 0
status = pressure.startTemperature();
if (status != 0) { //all status returns 1 if successful, 0 if failure
// Wait for the measurement to complete:
delay(status);
status = pressure.getTemperature(T);
if (status != 0) {
//print temperature T with 0 decimal places
lcd.print("Temperature " + String(T,0) + " deg C");
// Parameter from 0 to 3 (highest res, longest wait).
status = pressure.startPressure(3);
if (status != 0) {
delay(status);
status = pressure.getPressure(P,T);
if (status != 0)
{
lcd.setCursor(0,2);
//print pressure P with 0 decimal places
lcd.print("Abs " + String(P,0) + " mB Alt " + String(ALTITUDE,0) + " m");
p0 = pressure.sealevel(P,ALTITUDE);
lcd.setCursor(0,3);
lcd.print("Sea Level " + String(p0,0) + " mB");
}
else ErrorAction(1, 2);
}
else ErrorAction(1, 2);
}
else ErrorAction(1, 1);
}
else ErrorAction(1, 1);
delay(3000);
}
void ErrorAction(int sensorType, int nRows) {
lcd.setCursor(0,nRows);
lcd.print("Error Sensor " + sensorType);
}
The compiled program occupies 42% of the Arduino's memory, which is 32K. The variables used occupy 33% of
the space dedicated to them, which is 2048 bytes.
ROW 1 – Temperature – Temperature XX deg C
ROW 2 – Humidity – Humidity XX.YY %
ROW 3 – Pressure Measured at Altitude – Abs YYYY mB A XXXX
ROW 4 – Sea Level Pressure – Sea Level YYYY mB
Right now, we have the program running at an altitude of 600 m fixed and without error processing. We will now
include the altitude adjustment.
3.3. ALTITUDE CONFIGURATION
The pressure varies according to the altitude. The pressure value at sea level is used by meteorologists to indicate
whether the weather is good (high pressure) or rainy (low pressure). The normal pressure is 1023 millibars which
is equivalent to 1 atmosphere. Expert knowledge is required to make corrections to see if the pressure at a given
altitude is low or high. The pressure measured by the BMP180 sensor is the absolute pressure. Pressure at sea
level is the relative pressure. If the sensor is at sea level, then the absolute pressure is equal to the relative
pressure. To obtain the pressure at sea level, it is necessary to inform the BMP180 sensor the altitude of the
location so that it can make the correction automatically. We need a method to enter the operating altitude of
the sensor, since the meter will be used by someone who does not have access to the program.
A simple potentiometer with one end connected to 5V and the other end connected to 0V (GND), and the cursor
connected to A3 analog pin on the Arduino does this. Thus, when moving the potentiometer cursor from side to
side, we vary the voltage read by the analog pin A3 between 0V and 5V. Mounting a scale correlating the value of
the voltage with the altitude we can adjust the altitude.
To configure the altitude, we must create a scale that correlates the value of the voltage read by pin A3 in altitude.
The Arduino A/D converter operates with 10 bits ranging from 0 to 1023. We will use the following conversion:
The equation used is altitude = analogRead(A3) * 3. When A3 = 0 then altitude = 0 meters, when A3 = 1023 then
altitude = 3069 meters. Note that each step of the converter represents 3 meters in the altitude adjustment. So,
there is no use trying to adjust the altitude from meter to meter. The A/D converter does not have the necessary
precision. The least significant digit in the altitude will be flashing due to this step of 3 meters.
We also need to inform on LCD display if we are in adjustment mode or in operating mode. A one-pole and two-
position switch connected to a digital pin can tell the Arduino which mode the meter is at, 0V in adjustment, 5V
in operation. This pin must be configured to work in PULLUP mode.
void loop(){
…………………………………………………………
dht.temperature().getEvent(&event);
AltitudeCalibration()
delay(500);
dht.humidity().getEvent(&event);
………………………………………………………..
AltitudeCalibration();
delay(500);
AltitudeCalibration();
……………………………………………………….
delay(1000);
AltitudeCalibration();
Delay(1000);
AltitudeCalibration();
Delay(1000);
AltitudeCalibration();
}
Let us see what changes in the program WEATHER STATION WITHOUT ALTITUDE ADJUSTMENT BY INTERRUPT:
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // old line in the program header
LiquidCrystal lcd(12, 11, 6, 5, 4, 3); // new line in the program header
The central pin of the programming start switch must also be changed from the Arduino digital pin 9 to pin 2.
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#include <SFE_BMP180.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#define DHTPIN 7
#define DHTTYPE DHT11
float ALTITUDE = 600.0;
DHT_Unified dht(DHTPIN, DHTTYPE);
uint32_t delayMS;
SFE_BMP180 pressure;
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);
const byte pinInter = 2;
void setup() {
dht.begin();
pressure.begin();
lcd.begin(20, 4);
pinMode(pinInter, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pinInter), AltitudeCalibration, CHANGE);
lcd.clear();
}
void loop() {
char status;
double T, P, p0, a;
delay(1000);
sensors_event_t event;
dht.temperature().getEvent(&event);
delay(500);
dht.humidity().getEvent(&event);
lcd.setCursor(0,1);
if (isnan(event.relative_humidity)) {
ErrorAction(0, 1);
}
else {
lcd.print("Humidity " + String(event.relative_humidity,0) + " %");
}
delay(500);
lcd.setCursor(0,0);
status = pressure.startTemperature();
if (status != 0) {
delay(status);
status = pressure.getTemperature(T);
if (status != 0) {
lcd.print("Temperature " + String(T,0) + " deg C");
status = pressure.startPressure(3);
if (status != 0) {
delay(status);
status = pressure.getPressure(P,T);
if (status != 0) {
lcd.setCursor(0,2);
lcd.print(" ");
lcd.setCursor(0,2);
lcd.print("Abs " + String(P,0) + " mB Alt " + String(ALTITUDE,0) + " m");
p0 = pressure.sealevel(P,ALTITUDE);
lcd.setCursor(0,3);
lcd.print("Sea Level " + String(p0,0) + " mB");
}
else ErrorAction(1, 2);
}
else ErrorAction(1, 2);
}
else ErrorAction(1, 1);
}
else ErrorAction(1, 1);
delay(3000);
}
void ErrorAction(int sensorType, int nRows) {
lcd.setCursor(0,nRows);
lcd.print("Error Sensor " + sensorType);
}
void AltitudeCalibration() {
float altitude = 0.0;
noInterrupts();
lcd.setCursor(0,2);
lcd.print("Altitude Calibration");
while(digitalRead(pinoInter) == LOW) {
altitude = analogRead(A3) * 3;
if(abs(ALTITUDE - altitude) > 5) {
ALTITUDE = altitude;
lcd.setCursor(0,3);
lcd.print(" ");
lcd.setCursor(0,3);
lcd.print(String(ALTITUDE,0));
}
delay(2000);
}
interrupts();
}
To further reduce the oscillation, a 1 µF/25V capacitor from pin A3 to GND can be used. The capacitor filters the
electric noise in the A3 pin. Each step of the A/D converter is 5V/1023 = 4.9 mV. Any ambient noise caused by an
electric motor or other equipment can induce voltages that make the reading inaccurate.
3.6. USING THE ARDUINO PRO MINI
Once the project is working well you can replace the Arduino board which is an expensive and large board with a
smaller and cheaper board. In this case we use as an example the board called Pro Mini that is a simple board
containing only the AT328 controller. Below we see all the assembly done using a Breadboard powered by a 5V
power supply. This assembly can be done inside a box by soldering the components. You can see the card installed
on the breadboard. In this assembly, a pin header was soldered on both sides of the board to allow the board to
be inserted into the Breadboard. Some pins are placed in the middle of the board, connections A4, A5 and GND
among others, and we weld wires (yellow, green, and black).
The card does not have a USB connection, making it quite small. It also does not provide a 5V voltage. It must be
powered by a 5V supply. To be programmed the board must be connected to an FTDI FT232RL board which is a
USB converter for RS232 TTL level (0V/5V) interface. The board allows the interface between the laptop and the
Arduino Pro Mini. The connection is made using a USB cable with USB mini A termination as indicated. The
connection between the boards is direct, pin by pin.
When we connect the two boards, the laptop powers the Arduino Pro Mini. On the laptop, the IDE environment
must be configured to download the program. After the download we can turn off the Arduino and connect the
5V source on the breadboard.
In the IDE select from the Tools menu the type of card used as Arduino Pro or Arduino Pro Mini. Also select the
correct serial port as we saw earlier.
If your goal is to design and manufacture equipment with Arduino, then this board is ideal. You should assess
whether it is worth buying an FTDI card for configuring the cards. You must obtain the correct USB cable.
You can also use the Arduino USB interface to download the program on the board. It is a way to trick the IDE. It
works and there is no need to buy an interface, just the USB cable with the USB mini A connector.
The ATMEL AT328 chip must be removed from the Arduino UNO kit board to not conflict with the AT328 chip on
the Arduino Pro Mini board. We will only use the USB interface structure of the Arduino UNO kit. The laptop is
connected to the Arduino Uno board in the conventional way we already know, using the same cable used in the
Arduino Uno kit.
The kit board must be connected to the Pro Mini board as shown in the following figure.
You also must inform the IDE that the circuit is the Arduino Pro Mini, using the Tools menu, so that the IDE sends
the corresponding signals.
3.7. ARDUINO PRO MINI WIFI
We will connect a WIFI module to the project allowing the consultation of the parameters measured by the
internet. Thus, the mini weather station can be consulted from anywhere in the world if its IP is accessible. The
WIFI module will operate as a server.
Following is the complete diagram with altitude adjustment by interrupt. As the ESP-01 only works with 3.3V it is
necessary to provide a 3.3V source with 500 mA or more of capacity.
CONNECTIONS
The project is using almost all the Arduino pins and will use almost all its processing and storage capacity. This is
an example of Internet of Things. If you use a cell phone modem instead of a WIFI modem, you can distribute mini
weather stations over a large area and obtain the temperature, humidity and atmospheric pressure of these mini
stations by assembling a map in real time.
INITIAL TESTS
As we have already studied in NETWORKS LESSON 5, the ESP-01 module firmware is constantly evolving. In view
of this, we need to determine what speed the module communicates with Arduino, whether the old 115,200 bps
or the current 9,600 bps. This test will tell us if the module is working correctly.
TEST PROGRAM (USING ARDUINO MINI PRO)
Let us reset the ESP-01 module to see if it is working. The program uses a speed of 115200 bps. There are modules
that operate at 9600 bps. If the answer is not appropriate change the speed.
#include <SoftwareSerial.h>
SoftwareSerial esp8266(9, 10); //RX, TX
void setup() {
Serial.begin(9600);
esp8266.begin(115200);
sendData("AT+RST\r\n");
}
void loop() {
receiveData();
delay(2000);
}
void sendData(String command) {
esp8266.print(command);
}
void receiveData() {
while(esp8266.available()) {
char c = esp8266.read();
Serial.print(c);
}
}
The restart at 115200 bps was successful. The date is the firmware recorded on the board.
PROGRAM (WEATHER STATION WITH WIFI INTERNET CONNECTION)
#include <SFE_BMP180.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include "SoftwareSerial.h"
#define DHTPIN 7
#define DHTTYPE DHT11
DHT_Unified dht(DHTPIN, DHTTYPE);
uint32_t delayMS;
SFE_BMP180 pressure;
const byte pinInter = 2;
See that the program uses almost all the resources of Arduino.
4. ARDUINO HARDWARE
There are many sensors that the Arduino can use. It is impossible and very expensive to carry out experiments
with all the sensors found on the market. In this lesson we select and study in detail some of these sensors,
showing how to understand the technical parameters of the sensor, how to discover the appropriate libraries and
how to analyze the functions available for the chosen sensor. We show how to develop a project, write a program
that solves the needs of the project and finally test and eliminate the errors found.
4.1. ARDUINO SENSORS
Next, we complement the chapter on sensor experiments with some additional information. Each sensor has
certain operating parameters, mainly those related to the measurement accuracy and operating range. In general,
the cost of the component is associated with these parameters, the greater the accuracy the greater the cost, the
greater the operating range, the greater the cost. We also present some more complete programs, provided by
the sensor manufacturers themselves and some sensor-related libraries. Following the methodology of the items
below, it will be possible to study other sensors and implement new projects.
• Measurement Range – temperature and humidity measurement range. This temperature range depends on
the type of detector used.
• Accuracy – is the accuracy of the measurement. The numerical value read may appear to be more accurate
because the DHT11 analog-to-digital converter has 8 bits, but the sensor has the indicated accuracy. The
sensor humidity accuracy is ± 5%. If the indicated value is 57.12 this means that the real value can be between
59,976 and 54,264 and we will present the result as 57%. It is clear that decimal places, for both temperature
and humidity, have no practical use. The ideal is to present the result using only two digits. In the case of
temperature if the displayed value is 20.760C the actual temperature must be between 19.760C and 21.760C,
but we will present the result as 200C.
These characteristics vary from device to device and vary depending on the temperature. The program suggested
by the manufacturer and which indicates the maximum and minimum values measured by the device being tested.
COMMUNICATION WITH ARDUINO
Communication with the Arduino is of the I2C type. I2C communication is serial and uses two wires, the SDA (Serial
DAta) which is the data communication wire and the SCL (Serial CLock) wire which is the synchronization clock
wire. Communication allows multiple devices to be connected to the Arduino using only one pair of wires. The
microcontroller controls the devices indicating the time when each one can start the transmission. The SCL wire
is used by the microcontroller to send a synchronization clock to all devices. This type of bus was created in 1982
to save microprocessed controllers that at the time were expensive and bulky.
As in this test there is only a single I2C component, the SCL wire is not used (pin 3 of DTH11). In the case of
ARDUINO, a library called WIRE was created that works with the I2C protocol.
ENVIRONMENT
Follow the procedures in Chapter 1 item 1.1. SENSOR → LIBRARY to load the two .ZIP libraries into the Arduino
IDE environment. After loading the libraries go to examples and see that the examples of the DTH sensor appear
in the list.
Load the DHT_Unified_Sensor example. In the #define section, see that the #define DHT22 is not commented on.
Comment on this #define and remove the comment from #define DHT11.
PROGRAM TEMPERATURE AND HUMIDITY SENSOR
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#define DHTPIN 4 // Digital pin connected to the DHT sensor
// Feather HUZZAH ESP8266 note: use pins 3, 4, 5, 12, 13 or 14 --
// Pin 15 can work but DHT must be disconnected during program upload.
uint32_t delayMS;
void setup() {
Serial.begin(9600);
// Initialize device.
dht.begin();
Serial.println(F("DHTxx Unified Sensor Example"));
// Print temperature sensor details.
sensor_t sensor;
dht.temperature().getSensor(&sensor);
Serial.println(F("------------------------------------"));
Serial.println(F("Temperature Sensor"));
Serial.print (F("Sensor Type: ")); Serial.println(sensor.name);
Serial.print (F("Driver Ver: ")); Serial.println(sensor.version);
Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id);
Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("°C"));
Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("°C"));
Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("°C"));
Serial.println(F("------------------------------------"));
// Print humidity sensor details.
dht.humidity().getSensor(&sensor);
Serial.println(F("Humidity Sensor"));
Serial.print (F("Sensor Type: ")); Serial.println(sensor.name);
Serial.print (F("Driver Ver: ")); Serial.println(sensor.version);
Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id);
Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("%"));
Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("%"));
Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("%"));
Serial.println(F("------------------------------------"));
// Set delay between sensor readings based on sensor details.
delayMS = sensor.min_delay / 100;
}
void loop() {
// Delay between measurements.
delay(delayMS);
// Get temperature event and print its value.
sensors_event_t event;
dht.temperature().getEvent(&event);
if (isnan(event.temperature)) {
Serial.println(F("Error reading temperature!"));
}
else {
Serial.print(F("Temperature: "));
Serial.print(event.temperature);
Serial.println(F("°C"));
}
// Get humidity event and print its value.
dht.humidity().getEvent(&event);
if (isnan(event.relative_humidity)) {
Serial.println(F("Error reading humidity!"));
}
else {
Serial.print(F("Humidity: "));
Serial.print(event.relative_humidity);
Serial.println(F("%"));
}
}
Note that the maximum humidity value detected by the DHT11 under test is 80% instead of 90%. The typical
humidity of an equatorial forest is 90% to 100%, so this device will not be able to measure this humidity, but I am
sure you will notice if you are in a rain forest, the humidity is unbearable.
PRESSURE AND TEMPERATURE SENSOR - BMP180
HARDWARE
The circuit suggested by the manufacturer in its datasheet is indicated below. The µController represents the
Arduino. The suggested circuit is available on a board that can be used by the Arduino. Below we can see the
corresponding shield. SDA is the data connection with the Arduino and SCL the synchronization line. VCC is
connected to the Arduino 3.3V pin and GND to the Arduino GND pin. Pin 3.3 is for selecting the voltage of 1.8 Volts
and if 3.3 Volts is used it does not need to be connected.
Resistors and capacitors are installed in the sensor module board.
It is important to say that the model BMP180 has been replaced by the model BMP280 which has more extended
and precise characteristics. The operation of the two models is similar. Typical measurement resolution values are
0.10C and 0.01 hPa. The resolution depends on the number of bits of the digital analog converter used, which is
16 bits for temperature and 19 bits for pressure.
The absolute accuracy of the sensor varies with the temperature due to the mechanical and electrical construction
of the temperature and pressure sensors. The sensor elements are not normally linear over the entire temperature
range. The sensor electronics calibrates the response by trying to eliminate variations in the measured values
from sensor to sensor and to linearize the output curve. At 250C the typical accuracy is ± 0.50C. Over the entire
temperature range the typical accuracy of ± 1.00C. In the case of pressure, the precision indication is divided into
two parts according to the non-linearity in relation to the temperature at which the measurement is made.
Analyzing the data, we concluded that two digits for temperature and 3/4 for pressure is ideal, that is, if the
pressure result is 970.27 we can present the pressure as 970. If the temperature is 23.89 we can present it as 23.
ENVIRONMENT
To test the BMP180 sensor it will be necessary to include the Arduino IDE libraries SFE_BMP180.h and Wire.h. Ask
google → sparkfun bmp180 arduino .zip library → select BMP180 Barometric Pressure Sensor Hookup -
learn.sparkfun …. → you will be redirected to the website https://learn.sparkfun.com/tutorials/bmp180-
barometric-pressure-sensor-hookup-/all .
Once on the website, look for the button SPARKFUN BMP180 ARDUINO LIBRARY to download the compressed
library. Follow the steps described in chapter 1 and the DHT11 sensor chapter to load the library. The WIRE.H
library does not need to be loaded, it is already installed in the IDE.
After loading this library go to the FILE menu and select examples. Load the example BMP180_altitude_example.
Below we list a program developed by Mike Grusin of SparkFun that commercializes the SHIELD of the BMP180
presented in the assembly. You must modify the altitude you are at for the pressure sensor to make the
appropriate corrections. See the value in red below. Always place a decimal point to tell the compiler that the
value is FLOAT.
#define ALTITUDE 1600.0 // Altitude of SparkFun HQ in meters
Upload the program and turn on the MONITOR SERIAL (IDE menu TOOLS).
Hardware connections:
- (GND) to GND
+ (VDD) to 3.3V
/*
Leave the IO (VDDIO) pin unconnected. This pin is for connecting the BMP180 to systems with lower logic levels
such as 1.8V Have fun! -Your friends at SparkFun.
The SFE_BMP180 library uses floating-point equations developed by the Weather Station Data Logger project:
http://wmrx00.sourceforge.net/
Our example code uses the "beerware" license. You can do anything you like with this code. No really, anything.
If you find it useful, buy me a beer someday.
V10 Mike Grusin, SparkFun Electronics 10/24/2013
V1.1.2 Updates for Arduino 1.6.4 5/2015
*/
// Your sketch must #include this library, and the Wire library.
// (Wire is a standard library included with Arduino.):
#include <SFE_BMP180.h>
#include <Wire.h>
SFE_BMP180 pressure;
void setup()
{
Serial.begin(9600);
Serial.println("REBOOT");
//Initialize the sensor (it is important to get calibration values stored on the device).
void loop()
{
char status;
double T,P,p0,a;
/*
Loop here getting pressure readings every 10 seconds.
If you want sea-level-compensated pressure, as used in weather reports,
you will need to know the altitude at which your measurements are taken.
We're using a constant called ALTITUDE in this sketch:
*/
Serial.println();
Serial.print("provided altitude: ");
Serial.print(ALTITUDE,0);
Serial.print(" meters, ");
Serial.print(ALTITUDE*3.28084,0);
Serial.println(" feet");
/*
If you want to measure altitude, and not pressure, you will instead need
to provide a known baseline pressure. This is shown at the end of the sketch.
You must first get a temperature measurement to perform a pressure reading.
Start a temperature measurement:
If request is successful, the number of ms to wait is returned.
If request is unsuccessful, 0 is returned.
*/
status = pressure.startTemperature();
if (status != 0)
{
// Wait for the measurement to complete:
delay(status);
// Retrieve the completed temperature measurement:
// Note that the measurement is stored in the variable T.
// Function returns 1 if successful, 0 if failure.
status = pressure.getTemperature(T);
if (status != 0)
{
// Print out the measurement:
Serial.print("temperature: ");
Serial.print(T,2);
Serial.print(" deg C, ");
Serial.print((9.0/5.0)*T+32.0,2);
Serial.println(" deg F");
/*
Start a pressure measurement:
The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
If request is successful, the number of ms to wait is returned.
If request is unsuccessful, 0 is returned.
*/
status = pressure.startPressure(3);
if (status != 0)
{
// Wait for the measurement to complete:
delay(status);
/*
Retrieve the completed pressure measurement:
Note that the measurement is stored in the variable P.
Note also that the function requires the previous temperature measurement (T).
(If temperature is stable, you can do one temperature measurement
for a number of pressure measurements.)
Function returns 1 if successful, 0 if failure.
*/
status = pressure.getPressure(P,T);
if (status != 0)
{
// Print out the measurement:
Serial.print("absolute pressure: ");
Serial.print(P,2);
Serial.print(" mb, ");
Serial.print(P*0.0295333727,2);
Serial.println(" inHg");
/*
The pressure sensor returns abolute pressure, which varies with altitude.
To remove the effects of altitude, use the sealevel function and your current altitude.
This number is commonly used in weather reports.
Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m.
Result: p0 = sea-level compensated pressure in mb
*/
p0 = pressure.sealevel(P,ALTITUDE);
Serial.print("relative (sea-level) pressure: ");
Serial.print(p0,2);
Serial.print(" mb, ");
Serial.print(p0*0.0295333727,2);
Serial.println(" inHg");
/*
On the other hand, if you want to determine your altitude from the pressure reading,
use the altitude function along with a baseline pressure (sea-level or other).
Parameters: P = absolute pressure in mb, p0 = baseline pressure in mb.
Result: a = altitude in m.
*/
a = pressure.altitude(P,p0);
Serial.print("computed altitude: ");
Serial.print(a,0);
Serial.print(" meters, ");
Serial.print(a*3.28084,0);
Serial.println(" feet");
}
else Serial.println("error retrieving pressure measurement\n");
}
else Serial.println("error starting pressure measurement\n");
}
else Serial.println("error retrieving temperature measurement\n");
}
else Serial.println("error starting temperature measurement\n");
delay(5000); // Pause for 5 seconds.
}
MPU6050 ACCELEROMETER AND GYRO
HARDWARE
This module is a combination of a 3-axis accelerometer (X, Y and Z) with a 3-axis gyroscope (X, Y and Z). The
disconnected AD0 pin defines that the sensor's I2C address is 0x68. Connect the AD0 pin to the Arduino 3.3V pin
so that the address changes to 0x69. This change allows you to have two MPU-6050 modules on the same circuit.
The active component is smaller than the fingertip. To give you an idea, we present on the right the photograph
of a 3-axis gyroscope used by bombers of World War II, which is a cube with about 60 cm of edge. This shield uses
an accelerometer in addition to the gyroscope. It is really too small!!!
This component is used in drones and smartphones. On the drone it allows to perform inertial navigation together
with the autopilot and a GPS. In the case of the smartphone, it allows your screen to change orientation and you
can navigate by gestures.
The datasheet of the manufacturer InvenSense provides, in addition to various data (it is a PDF with 52 pages),
the pinout and the basic circuit to connect the MPU6050. In the shield in addition to this basic circuit comes a
voltage regulator and the SDA and SCL lines have two 2K2 resistors connected to the VCC.
The datasheet of the manufacturer InvenSense provides, in addition to various data (it is a PDF with 52 pages),
the pinout and the basic circuit to connect the MPU6050. In the shield in addition to this basic circuit comes a
voltage regulator and the SDA and SCL lines have two 2K2 resistors connected to the VCC.
All resistors and capacitors are mounted on the module board.
*/
}
WIRE LIBRARY
Use pins A4 (SDA) and A5 (SCL) on the Arduino UNO. Device addresses are 7-bit numbers, that is, they range from
0 to 127.
BEGIN – initiates I2C communication with the device
Wire.begin()
BEGINTRANSMISSION – initiates transmission to the device
Wire.beginTransmission(Address) – starts the transmission by indicating the device address
The MPU-6050 has two addresses selected by pin AD0. If the pin is connected at 3.3V the address will be
0x69 if not connected (in the example) the address will be 0x68.
ENDTRANSMISSION – ends transmission and sends all bytes of WRITE instructions to the device
Wire.endTransmission(argument)
Argument = true a stop message is sent after transmission and the I2C bus is released
Argument = false a restart message is sent after transmission and the I2C bus is not released blocking its use
by another device
The function returns (BYTE)
0 – Success
1 – Data too large to fit in the transmission buffer
2 – Received NACK (No Acknowledge) at the broadcast address
3 – NACK received for data
4 – Another error
WRITE – transmits a value to the device addressed by beginTransmission
Wire.write(byte) – send a byte
Wire.write(string) – sends a string as a series of bytes
Wire.write(data, length) – send an array of length as a series of bytes
The function returns the number of bytes transmitted (BYTE)
REQUESTFROM – used for the Arduino to request device bytes. The bytes are read into a buffer on the Arduino
and are effectively retrieved using the functions Available() e Read().
Wire.requestFrom(address, quantity)
Wire.requestFrom(address, quantity, stop)
address – device address
quantity – number of bytes to be read
stop – true to release the bus after the operation and false to keep the bus in use.
The function returns the number of bytes read from the device (BYTE)
AVAILABLE – returns the number of bytes available in the reception buffer to be read. See example:
#include <Wire.h>
void setup(){
Wire.begin();
}
void loop(){
Wire.requestFrom(2, 6); // requests 6 bytes from device 2
while(Wire.available()) { char c = Wire.read(); }
}
READ – returns the next read byte.
Move the module and see the acceleration and positioning measurements changing quickly.
ULTRASONIC RANGING MODULE – HC-SR04
HARDWARE
● Power Supply: +5V DC
● Quiescent Current: <2mA
● Working Current: 15mA
● Effectual Angle: <15°
● Ranging Distance: 2cm – 400 cm/1" - 13ft
● Resolution: ±0.3 cm
● Measuring Angle: 30 degree
● Trigger Input Pulse width: 10uS
TIMING
The Arduino must emit a 10 µS pulse at the module's TRIGGER input (line 1 of the timing diagram). The module
has a high-frequency transmitter that emits 8 pulses at a frequency of 40 KHz. The module emits a pulse at the
ECHO output whose width indicates the distance from the obstacle. To obtain the distance in centimeters the
Arduino must divide the ECHO pulse width in microseconds by 58, for distance in inches divide by 148.
PROGRAM ULTRASONIC RANGING MODULE
#include <HCSR04.h> // including the library
HCSR04 hc(5, 6); // initialization class HCSR04 (trig pin, echo pin)
void setup()
{
Serial.begin(9600); //serial monitor
}
void loop()
{
Serial.println( hc.dist() ); //distance print
}
Analyzing the program, we see that after adding the library, the hc object of the HSR04 class is initialized. The class
uses Arduino digital pin 5 for HCSR04's TRIGGER pin (Input) and Arduino digital pin 6 for HCRS04's ECHO pin
(Output).
See that the program is quite simple. Complexity is hidden by the library. Let us look at the library. It has two files,
a .h file that contains the library definitions and another .cpp file that contains the program itself. The program
defines a class called HCSR04.
The class is initialized indicating how the program parameters will be passed to the class. The parameters are an
integer out (trigger), an array int echo [] and an integer n indicating the number of sensors. The library works for
a single sensor or for more than one sensor. The class can be initialized in two ways:
HCSR04::HCSR04(int out,int echo){this->init(out,new int[1]{echo},1);}
HCSR04::HCSR04(int out,int echo[],int n){this->init(out,echo,n);}
The first class initialization declaration uses only one sensor, resizing the array to a single element (new int [1] also
indicating that n is 1. The second class initialization declaration maintains the echo [] array and the parameter n
that will determine the dimension of the array. This type of declaration in which several types of declaration are
possible is called OVERLOAD.
Initialization allocates Arduino digital pins using statements:
pinMode(this->out, OUTPUT); //trigger pin
for(int i=0;i<n;i++){ pinMode(this->echo[i], INPUT); } //echo pin
#include "HCSR04.h"
////////////////////////////////////consttruct/destruct
void HCSR04::init(int out, int echo[], int n)
{
this->out = out;
this->echo = echo;
this->n = n;
pinMode(this->out, OUTPUT);
for(int i=0;i<n;i++){ pinMode(this->echo[i], INPUT); }
}
HCSR04::HCSR04(int out,int echo){this->init(out,new int[1]{echo},1);}
HCSR04::HCSR04(int out,int echo[],int n){this->init(out,echo,n);}
HCSR04::~HCSR04()
{
~this->out;
delete[] this->echo;
~this->n;
}
///////////////////////////////////////////////////dist
float HCSR04::dist(int n) const
{
digitalWrite(this->out, LOW);
delayMicroseconds(2);
digitalWrite(this->out, HIGH);
delayMicroseconds(10);
digitalWrite(this->out, LOW);
noInterrupts();
float d=pulseIn(this->echo[n], HIGH);
interrupts();
return d / 58.0;
}
float HCSR04::dist() const{return this->dist(0);}
4.2. USING ARDUINO WITH DISPLAYS AND KEYBOARDS
Keyboards, displays and relays are input and output devices that act directly on the Arduino. In this lesson we will
study these devices, in addition to studying a sensor that is activated by light.
LIBRARY
The functions available in the library are as follows:
LiquidCrystal() – initializes the library variables. Informs how the display should work, whether using 4 pins or 8
pins to communicate with the Arduino, if the rw pin is connected to the ground or to the Arduino. The function
syntax is:
LiquidCrystal(rs, enable, d4, d5, d6, d7);
LiquidCrystal(rs, rw, enable, d4, d5, d6, d7);
LiquidCrystal(rs, enable, d0, d1, d2, d3, d4, d5, d6, d7);
LiquidCrystal(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
rs pin – data/instruction selection LCD pin
enable – enable/disable LCD pin
rw – read/write LCD pin
d4 …. d7 – LCD communication pins
d0 …. d7 – LCD communication pins
lcd.begin() – initializes the LCD hardware. Tells how many rows and columns the display has.
lcd.begin(cols, rows);
cols – number of columns
rows – number of rows
lcd.clear() – resets the display content and positions the cursor in column 0 and line 0.
lcd.home() – position the cursor in column 0 and line 0. Does not reset the display content.
lcd.setCursor() – positions the cursor in the indicated column and row. Column and row start at 0.
lcd.setCursor(col, row);
lcd.write() – write a character at the current cursor position.
lcd.write(char);
lcd.print() – write text from the current cursor position.
lcd.print(“text”);
lcd.cursor() – displays a cursor (underscore) at the next position to be written. The cursor is continuous, it does
not flash.
lcd.noCursor() – delete the cursor.
lcd.blink() – has a blinking underscore.
lcd.noBlink() – delete the cursor.
lcd.display() – turns the display on. Text and cursor are restored.
lcd.noDisplay() – turns off the display. The text and the cursor remain the same.
lcd.scrollDisplayLeft() – scrolls the contents of the display, text and cursor, one position to the left.
lcd.scrollDisplayRight() – scrolls the contents of the display, text and cursor, one position to the right.
lcd.autoscroll() – turns on automatic scrolling of the LDC. This causes each character output to the display to
push previous characters over by one space. Use lcd.leftToRight() or lcd.rightToLeft() to set the scroll
direction.
lcd.noAutoscroll() – turns off automatic scrolling.
lcd.leftToRight() and lcd.rightToLeft() – sets the writing direction on the display.
lcd.createChar() – creates a new character containing five columns and 8 rows. Up to 8 characters can be created.
On the website https://maxpromer.github.io/LCD-Character-Creator/ you draw the character and it generates
the code.
5. NETWORK
Connecting networked devices is a fundamental need when it comes to Internet of Things devices. In addition, the
Arduino is a microcontroller with little storage capacity (this can be modified) and little processing making it
important to transmit the data collected by sensors to some central processing, storage and presentation
equipment.
Computer networks began to be developed in the 1960s and, like telephone networks, are open, interconnected
networks. Several manufacturers produce equipment that has to be interconnected to create these networks.
This is only possible through the use of technical standardization that ensures that equipment from different
manufacturers work correctly with each other without degrading the final quality of the network.
In Chapter 2.4. and 2.5. we studied how to design, assemble and test experiments using various network
technologies in conjunction with Arduino. All of these technologies use the OSI model as a conceptual support and
as a functional structure for their operation.
As a complement to the experiments in these chapters, we will study the OSI model here and how it fits into each
experiment performed. In addition, some more technical details not shown in the experiments will be covered
here.
5.1. OSI MODEL
The telecommunications market is regulated by technical standards. As the equipment are produced by many
manufacturers, and used by different companies, operating in several countries, it becomes essential a technical
standardization that allows to interconnect this equipment, without causing interruption or loss of quality in the
offered service.
OSI MODEL (OPEN SYSTEMS INTERCONNECTION)
ENCAPSULATION
PHYSICAL LAYER REVIEW
MODULATION AND CODIFICATION
DIGITAL MODULATION
Standardizing bodies exist since the beginning of the twentieth century, with global or regional performance. The
International Telecommunications and Telegraph Advisory Committee (CCITT), currently the International
Telecommunication Union (ITU), is the international organization affiliated with the United Nations. The IEEE -
Institute of Electrical and Electronic Engineers, and the ANSI - American National Standards Institute are regional
bodies active in the States United. See:
http://www.itu.org
http://www.ieee.org
http://www.ansi.org
OSI MODEL (OPEN SYSTEMS INTERCONNECTION)
Computer networks began to be standardized from the 1980s, due to the same needs of telecommunications -
interconnectivity between equipment from various manufacturers. However, the equipment used in networks,
not to mention computers, has an extraordinarily strong software dimension. An effort was made to standardize
the network's operating software, so that different equipment from different manufacturers could talk to each
other. The separation of the functions of the layered model allows the faster and simpler development of
products, programs, and equipment for the network market. Some parameters were defined:
• Each functional layer represents a certain level of network abstraction.
• Each functional layer performs a set of similar, well-defined functions.
• The boundaries between the layers are chosen to minimize the flow of information through the interfaces.
• The number of layers should be such that they keep similar functions grouped together, without being excessive
or reduced unnecessarily increasing the complexity of each layer.
The interfaces between layers are very well specified in terms of inputs and outputs. The transformation that the
layer applies to incoming information, to obtain the information that comes out, that is, the transfer function
implemented by the layer, is also very well documented. The designer then is free to implement the layer as best
as possible, as long as your project performs the required transformations and delivers the information at the
layer interfaces obeying the required standards. The layers defined in the OSI model are as follows:
• PHYSICAL LAYER - is related to the signals and currents that are transmitted and received from the electric
or electromagnetic means. It is also related to the connectors that interface with this medium. Its
information unit is BIT.
• DATA LINK LAYER - makes the adaptation between the physical medium and its electrical signals and the
network layer that is implemented completely at the program level. It receives the bits and groups the bits
in bytes. Your information unit is the FRAME. The Framework must accommodate inherent characteristics
of physical implementation, such as error and synchronism control, and at the same time characteristics
inherent to the structure of the upper layers, such as protocols and addressing.
• NETWORK LAYER - The network layer is responsible for creating a hierarchical addressing structure that
allows the discovery of a certain destination automatically. This function is called ROUTING. Through the
routing function, routing rules are created along the network, allowing the information units called PACKETS
to be delivered to the destination. The routing rules are indicated in the ROUTING TABLES. The network
address is a fundamental part of the routing strategy.
• TRANSPORT LAYER - makes the connection between the network layer and the session layer. Because the
session layer can maintain multiple independent DATA FLOWS between two or more computers
simultaneously, it becomes necessary to create some mechanism that identifies each of these flows. This is
done by the address of the transport layer, called the PORT. The transport layer information unit is the
SEGMENT.
• SESSION LAYER - allows the simultaneous establishment of several STREAMS or INDEPENDENT SESSIONS
between them. For example, you may be querying a database while the automatic message receiving
program is receiving an email, and a stock exchange application is receiving the updated quotations. In this
case we have at least three active sessions, with several computers. The session layer must be able to
administer each of these sessions.
• PRESENTATION LAYER - The basic function of the presentation layer is to make proper conversion between
file formats, encode, decode, encrypt, decrypt files and data. It should know the format of the file received
and do its conversion so that it can be displayed properly on the devices of the computer. An example is the
reception of an image file, encoded according to the specific format, and its decoding to be displayed on the
screen.
• APPLICATION LAYER - takes care of the interface between the computer system and the user. It is
responsible for how the user interacts with an application.
The OSI model creates a computational environment that hides the processing details from the users. The user
does not need to know if the processing is done on the equipment itself, on a nearby server, or on the other side
of the planet.
ENCAPSULATION
As we have seen, each layer of the OSI model receives data from the previous layer, processes this data according
to the functions it must perform, and delivers the data to the next layer. The processing done by the layer always
requires the addition of a header and optionally a trailer, with information necessary to its processing in the next
layer of the same level along the network. A message sent from computer A (layer 7 - Application) will have added
one header per layer (the number inside the rectangle) until it is transmitted by the physical layer, to computer B.
Upon arriving at computer B the same message suffers the reverse process being decapsulated.
Each layer communicates with the corresponding layer on the other device, and with no other layer. That is, layer
7 receives the information entered by the user and adds its header, if any, and passes the result of this operation
to layer 6. This header only makes sense for layer 7 of the target device, and for no other. For the lower layers,
the layer 7 header is only raw data. Each layer extracts its header, using the information encoded in it for its own
use, passing to the top layer the rest as raw data. The various equipment used in a computer network implements
the layers necessary for its operation. We can, therefore, design a network under a hardware vision, or under a
software vision. The software view is especially important because it indicates how the information is transported
along the network. There is often a confusion between the hardware, which is the visible element of the network,
and the operational functions of each equipment, linked to the protocols being executed. The basic rule is that all
communication on the network happens between layers of the same level.
At this point the specific name of the equipment used in the sample network is not important, but rather note
that they perform functions only in some layers of the OSI model. There are then devices operating only on layer
1, devices operating on layers 1 and 2, devices operating on layers 1, 2, and 3, and so on. In this case the devices
are said to be layer 1, layer 1 only and layer 2 only for those operating in layers 1 and 2, and layer 3 for those
operating in layers 1,2, and 3.
PHYSICAL LAYER REVIEW
The physical layer is responsible for transmitting BITS through the communication channel. The purpose of this
layer is to ensure the correct transport of the bits from the sending device to the receiving device. The BIT is a
logical abstraction whose physical representation depends on the type of modulation used, the voltages and
currents involved in the process (see Computer Systems One in Microsoft Store).
• The basic function of the physical layer is then to provide the appropriate levels of voltage and current in
order to allow the physical medium of transport, which may be a metallic cable, optical fiber, or radio
channel, to be correctly driven by the transmitter, carrying the binary information to the receiver. The
receiver must be properly coupled to the transmission medium, allowing the reception of digital information
with the least possible errors. For this objective to be achieved, the three elements that make up the channel
must be adequate:
• CONNECTORS AND INTERFACES - must provide adequate electrical, mechanical, and optical coupling
between the transmission medium and the modulation devices.
• TRANSMISSION MEDIA - must be compatible with the modulation method used and the desired cost
and benefit requirements. As the transmission medium must be robust, simple to install and maintain,
and adequately meet the technical requirements.
• TYPE OF MODULATION - is defined according to the technical needs of data transport, such as
transmission rate and error rate, the desired cost-benefit, and other engineering parameters.
Your WIFI router uses exactly this system. The router's WIFI radio uses amplitude, frequency, and phase
modulation to transmit the bits and achieves a higher data rate.
5.2. ARDUINO NETWORK EXAMPLES
Following the examples presented in chapter 3 have some technical aspects presented in more detail.
The receiver circuit consists of a radio frequency stage composed of a tuned amplifier Q1 and an oscillator/PLL Q2
circuit. The two transistors receive the amplitude modulated signal and deliver the demodulated signal to the two
integrated circuits. This demodulated signal is composed of the bits that modulated the transmitter signal,
attenuated by the distance between transmitter and receiver and with environmental electrical noise. This signal
is in the order of µV, depending on the distance and the supply voltage (the higher the supply voltage of the
transmitter the greater the transmission power), it is amplified by the two operational amplifiers. The first
amplifier multiplies the signal 220 times. The second amplifier inserts a level of 2.5V, to obtain a signal between
0V and 5V at the output and amplifies the signal an additional 120 times. The total amplification is about 26,000
times. So, in the receiver's DATA output I get the same bits sent by the transmitter.
INITIAL TEST (PHYSICAL LAYER)
We will present an initial test to show the functioning of the transmitter/receiver module without using the
Arduino. For this we will assemble a square wave generator equal to the one we assembled in class 5 of the
COMPUTER SYSTEMS ONE module.
The NE555 integrated is an 8-pin timing integrated circuit. We will use it to generate a periodic signal between 0V
and 5V that is not a square wave. The 74HC74 flip-flop will turn this signal into a square wave. The formula for
calculating the frequency of the generated signal is as follows:
We will test the performance of the transmitter-receiver set using different frequencies, changing the resistances
of the NE555 circuit. We will use the signal analyzer to present the signals at the NE555 output (Channel0), the
74HC74 output (transmitter input - Channel1) and the receiver output (Channel2). Each minor division on the
timescale at the top of the screen is 20µsec. We will estimate the bps rate using this time scale. In the NE555
circuit we use a 10nF capacitor (10x10-9F) and the resistors R1 and R2 are identical. This makes the signal generated
quite different from a square wave, but the 74HC74 transforms this signal into a square wave.
ASSEMBLY
Note that in the test setup I placed the transmitter next to the receiver. This will increase the maximum transfer
rate of the bits. The transfer rate is a function of the bandwidth characteristic of the transistors used in the
transmitter and receiver, the supply voltage of the transmitter (transmission power), the distance between
transmitter and receiver and the size of the antenna used. Keeping the voltage, the distance and the antenna we
can vary the data rate (the frequency of the square wave) to see how is the limit of the transmitter/receiver set.
SIGNAL ANALYZER AND OSCILOSCOPE
The first test was done with a resistor R1 = R2 = 680Ω. In the analyzer we observed that the wave period is about
38µsec, equivalent to a data rate of 50Kbps. The specification of the transmitter/receiver set for a normal situation
is 4000bps. We are in a limit situation. We observed that the received signal (Channel2) does not correctly follow
the transmitted signal (Channel1). The signal from the signal analyzer hides what happens.
OSCILOSCOPE
With the oscilloscope we can see the actual waveforms. Note that in addition to losing the synchronism between
transmitter and receiver when the signal disappears, the transmitter/receiver system works as a low-pass filter
with a very degraded square wave, making the signal analyzer unable to work the signal properly.
The second test was performed with a 6K8 resistor. The signal period is about 285µsec. The data rate is 7Kbps. For
a supply voltage of 5V and the transmitter located near to the receiver this data rate is acceptable.
On the other hand, note that the signal fluctuates a little at the beginning. This is because the received signal, even
under favorable conditions, is not perfect, has noise and other imperfections, the analyzer interprets these
imperfections as several narrow bits. Any digital system, like an Arduino digital input, will interpret the signal in
the same way as the signal analyzer. Below the same signals seen on the oscilloscope.
The initial test showed the use of the transmitter/receiver set as layer 1 devices of the OSI model. The set transmits
and receives bits without error control. A bit enters the transmitter and a bit exits the receiver.
FINAL TEST
You can see the final test in Chapter 2.3. The functions of the library used in the final test are those found in layer
2 of the OSI model, such as error control and BITS grouping in BYTES. For this, it needs the data transmission rate
to be defined, creating a synchronization between the transmitted data and the received data.
ETHERNET MODULE AND NETWORK CAPTURE
Next, we study the operation of the Ethernet module using Wireshark, which is a program for analyzing network
traffic. Wireshark presents traffic separated by layer from the OSI model. For a more in-depth study of Wireshark,
search the Windows Store - Computer Network One or Basics for Computer Science.
NETWORK CAPTURE
We use the WIRESHARK application, studied in COMPUTER NETWORK ONE, to analyze the traffic generated
between IP 192.168.2.254 (laptop) and IP 192.168.2.253 (Ethernet module). The steps are:
• Start WIRESHARK
• Select ETHERNET port
• Apply ip.dst==192.168.2.253 filter
• See that the first packet that appears is a SYN (COMPUTER NETWORK ONE) packet starting a TCP stream.
• Select this packet by clicking on it.
• A window will open indicating a series of possible actions. Select Follow.
• Another window will open indicating other possible actions. Select TCP Stream.
• Another window will open indicating the customer's traffic in red, that is, who initiated the TCP flow and in
blue the server's traffic, that is, who serves the customer's request.
• You can clearly see the request and response in this window. See the materialization of the result in your
browser.
RESULT
The Arduino will play the role of WEB Server and the Browser on the laptop will play the Client. Each time you
start your browser with address 192.168.2.253, the Arduino will send the temperature and humidity values. As
the environment is Client-Server, Arduino cannot initiate a connection, it needs a request from the client (see
COMPUTER SYSTEMS ONE). Each time you start your browser with address 192.168.2.253, the Arduino will send
the temperature and humidity values. As the environment is Client-Server, Arduino cannot initiate a connection,
it needs a request from the client.
I checked the Ethernet module response package for the laptop. Note that the libraries etherShield.h and
ETHER_28J60.h transform the module into a WEB server. The response given to the browser by the program does
not include HTTP/1.0 200 OK Content-Type: text / html which is the server indicating to the client what type of
response it is giving. This is not part of the content of the response generated by the program, which follows.
WIFI MODULE AND NETWORK CAPTURE
WIFI routers are widely used in corporate and home networks. So it is important to use how the Arduino can
connect to these networks.
NETWORK CAPTURE
The TCP flow can be seen below. The customer is in red. The server response is in blue.
The result in the browser is following. In this example we send two fixed values. The value to be transmitted could
be a temperature, pressure, relay activation value. Depends on the specific project.
WIFI MODULE - ESP8266 AT COMMANDS
The following is a summary of the AT commands. They were copied from the document:
ESP8266 BASIC AT COMMANDS
ESP8266 WIFI AT COMMANDS
ESP8266 TCP AT COMMANDS