0% found this document useful (0 votes)
199 views394 pages

C Tutorial

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
199 views394 pages

C Tutorial

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 394

█ www.freenove.

com

Important Information
Thank you for choosing Freenove products!

Getting Started

First, please read the Read Me First.pdf document in the unzipped folder you created.
If you have not yet downloaded the zip file, associated with this kit, please do so now and unzip it.

Get Support and Offer Input

Freenove provides free and responsive product and technical support, including but not limited to:
 Product quality issues
 Product use and build issues
 Questions regarding the technology employed in our products for learning and education
 Your input and opinions are always welcome
 We also encourage your ideas and suggestions for new products and product improvements
For any of the above, you may send us an email to:

support@freenove.com
Safety and Precautions

Please follow the following safety precautions when using or storing this product:
 Keep this product out of the reach of children under 6 years old.
 This product should be used only when there is adult supervision present as young children lack
necessary judgment regarding safety and the consequences of product misuse.
 This product contains small parts and parts, which are sharp. This product contains electrically conductive
parts. Use caution with electrically conductive parts near or around power supplies, batteries and
powered (live) circuits.
 When the product is turned ON, activated or tested, some parts will move or rotate. To avoid injuries
to hands and fingers keep them away from any moving parts!
 It is possible that an improperly connected or shorted circuit may cause overheating. Should this happen,
immediately disconnect the power supply or remove the batteries and do not touch anything until
it cools down! When everything is safe and cool, review the product tutorial to identify the cause.
 Only operate the product in accordance with the instructions and guidelines of this tutorial, otherwise
parts may be damaged or you could be injured.
 Store the product in a cool dry place and avoid exposing the product to direct sunlight.
 After use, always turn the power OFF and remove or unplug the batteries before storing.

Any concerns?  support@freenove.com


www.freenove.com █

About Freenove

Freenove provides open source electronic products and services worldwide.

Freenove is committed to assist customers in their education of robotics, programming and electronic circuits
so that they may transform their creative ideas into prototypes and new and innovative products. To this end,
our services include but are not limited to:

 Educational and Entertaining Project Kits for Robots, Smart Cars and Drones
 Educational Kits to Learn Robotic Software Systems for Arduino, Raspberry Pi and micro: bit
 Electronic Component Assortments, Electronic Modules and Specialized Tools
 Product Development and Customization Services

You can find more about Freenove and get our latest news and updates through our website:

http://www.freenove.com

sale@freenove.com

Copyright

All the files, materials and instructional guides provided are released under Creative Commons Attribution-
NonCommercial-ShareAlike 3.0 Unported License. A copy of this license can be found in the folder containing
the Tutorial and software files associated with this product.

This means you can use these resource in your own derived works, in part or completely but NOT for the
intent or purpose of commercial use.

Freenove brand and logo are copyright of Freenove Creative Technology Co., Ltd. and cannot be used without
written permission.

TM

Any concerns?  support@freenove.com


█ www.freenove.com Preface 1

Contents

Important Information....................................................... 1
Contents ................................................................................. 1
Preface .................................................................................... 1
ESP32-WROVER ........................................................................................................................................................................ 2
Extension board of the ESP32-WROVER .......................................................................................................................... 5
CH340 ........................................................................................................................................................................................... 6
Programming Software ......................................................................................................................................................... 16
Environment Configuration ................................................................................................................................................. 19
Notes for GPIO......................................................................................................................................................................... 23

Chapter 0 LED ................................................................... 25


Project 0.1 Blink ....................................................................................................................................................................... 25

Chapter 1 LED ................................................................... 30


Project 1.1 Blink ....................................................................................................................................................................... 30

Chapter 2 Button & LED ................................................ 36


Project 2.1 Button & LED ...................................................................................................................................................... 36
Project 2.2 MINI table lamp ................................................................................................................................................. 41

Chapter 3 LED Bar ........................................................... 44


Project 3.1 Flowing Light ...................................................................................................................................................... 44

Chapter 4 Analog & PWM ............................................ 49


Project 4.1 Breathing LED ..................................................................................................................................................... 49
Project 4.2 Meteor Flowing Light....................................................................................................................................... 56

Chapter 5 RGB LED.......................................................... 59


Project 5.1 Random Color Light ......................................................................................................................................... 59
Project 5.2 Gradient Color Light......................................................................................................................................... 64

Chapter 6 LEDPixel .......................................................... 66


Project 6.1 LEDPixel ................................................................................................................................................................ 66
Project 6.2 Rainbow Light..................................................................................................................................................... 73

Chapter 7 Buzzer.............................................................. 75
Project 7.1 Doorbell................................................................................................................................................................ 75
Project 7.2 Alertor ................................................................................................................................................................... 81

Any concerns?  support@freenove.com


2 Preface www.freenove.com █

Project 7.3 Alertor (use timer) ............................................................................................................................................. 84


Project 7.4 Alertor (use idf) .................................................................................................................................................. 88

Chapter 8 Serial Communication................................ 91


Project 8.1 Serial Print............................................................................................................................................................ 91
Project 8.2 Serial Read and Write ...................................................................................................................................... 96

Chapter 9 AD/DA Converter ........................................ 99


Project 9.1 Read the Voltage of Potentiometer............................................................................................................ 99
Project 9.2 Get Voltage (use idf) ......................................................................................................................................106

Chapter 10 Touch Sensor ............................................ 113


Project 10.1 Read Touch Sensor ......................................................................................................................................113
Project 10.2 Touch Lamp ....................................................................................................................................................118

Chapter 11 Potentiometer & LED............................. 123


Project 11.1 Soft Light .........................................................................................................................................................123
Project 11.2 Soft Colorful Light ........................................................................................................................................126
Project 11.3 Soft Rainbow Light .......................................................................................................................................130

Chapter 12 Photoresistor & LED ............................... 134


Project 12.1 NightLamp ......................................................................................................................................................134

Chapter 13 Thermistor ................................................. 139


Project 13.1 Thermometer .................................................................................................................................................139
Project 13.2 Thermometer (use esp-idf) .......................................................................................................................144

Chapter 14 Joystick ....................................................... 147


Project 14.1 Joystick .............................................................................................................................................................147

Chapter 15 74HC595 & LED Bar Graph .................. 152


Project 15.1 Flowing Water Light.....................................................................................................................................152

Chapter 16 74HC595 & 7-Segment Display. ........ 158


Project 16.1 7-Segment Display. .....................................................................................................................................158
Project 16.2 4-Digit 7-Segment Display .......................................................................................................................165

Chapter 16 74HC595 & LED Matrix ......................... 172


Project 16.3 LED Matrix .......................................................................................................................................................172

Chapter 17 Relay & Motor .......................................... 181


Project 17.1 Relay & Motor ...............................................................................................................................................181

Chapter 17.2 Motor & Driver ..................................... 188


Any concerns?  support@freenove.com
█ www.freenove.com Preface 3

Project 17.2 Control Motor with Potentiometer .........................................................................................................188

Chapter 18 Servo ........................................................... 196


Project 18.1 Servo Sweep ...................................................................................................................................................196
Project 18.2 Servo Knop .....................................................................................................................................................202

Chapter 19 Stepper Motor ......................................... 206


Project 19.1 Stepper Motor ...............................................................................................................................................206

Chapter 20 LCD1602..................................................... 215


Project 20.1 LCD1602 ..........................................................................................................................................................215

Chapter 21 Ultrasonic Ranging ................................. 223


Project 21.1 Ultrasonic Ranging .......................................................................................................................................223
Project 21.2 Ultrasonic Ranging .......................................................................................................................................230

Chapter 22 Matrix Keypad .......................................... 233


Project 22.1 Matrix Keypad ................................................................................................................................................233
Project 22.2 Keypad Door ..................................................................................................................................................240

Chapter 23 Infrared Remote ...................................... 246


Project 23.1 Infrared Remote Control ............................................................................................................................246
Project 23.2 Control LED through Infrared Remote ..................................................................................................254

Chapter 24 Hygrothermograph DHT11 ................. 260


Project 24.1 Hygrothermograph ......................................................................................................................................260
Project 24.2 Hygrothermograph ......................................................................................................................................267

Chapter 25 Infrared Motion Sensor ......................... 272


Project 25.1 Infrared Motion Detector with LED Indicator ......................................................................................272

Chapter 26 Attitude Sensor MPU6050 ................... 277


Project 26.1 Read a MPU6050 Sensor Module ...........................................................................................................277

Chapter 27 Bluetooth ................................................... 285


Project 27.1 Bluetooth Passthrough ...............................................................................................................................285
Project 27.2 Bluetooth Low Energy Data Passthrough.............................................................................................291
Project 27.3 Bluetooth Control LED ................................................................................................................................303

Chapter 28 Bluetooth Media by DAC ..................... 309


Project 28.1 Playing Bluetooth Music through DAC .................................................................................................309

Chapter 29 Bluetooth Media by PCM5102A ........ 316


Project 29.1 Playing Bluetooth Music through PCM5102A ....................................................................................316

Any concerns?  support@freenove.com


4 Preface www.freenove.com █

Chapter 30 WiFi Working Modes ............................. 323


Project 30.1 Station mode..................................................................................................................................................323
Project 30.2 AP mode ..........................................................................................................................................................327
Project 30.3 AP+Station mode .........................................................................................................................................332

Chapter 31 TCP/IP ......................................................... 336


Project 31.1 As Client ...........................................................................................................................................................336
Project 31.2 As Server ..........................................................................................................................................................347

Chapter 32 Camera Web Server ............................... 353


Project 32.1 Camera Web Server .....................................................................................................................................353

Chapter 33 Camera Tcp Server ................................. 362


Project 33.1 Camera Tcp Server .......................................................................................................................................362

Chapter 34 Soldering Circuit Board ......................... 380


Project 34.1 Soldering a Buzzer .......................................................................................................................................380
Project 34.2 Soldering a Flowing Water Light .............................................................................................................384

What’s next? .................................................................... 388


End of the Tutorial ......................................................... 388

Any concerns?  support@freenove.com


█ www.freenove.com Preface 1

Preface
ESP32 is a micro control unit with integrated Wi-Fi launched by Espressif, which features strong properties
and integrates rich peripherals. It can be designed and studied as an ordinary Single Chip Micyoco(SCM) chip,
or connected to the Internet and used as an Internet of Things device.

ESP32 can be developed using the Arduino platform, which will definitely make it easier for people who have
learned arduino to master. Moreover, the code of ESP32 is completely open-source, so beginners can quickly
learn how to develop and design IOT smart household products including smart curtains, fans, lamps and
clocks.

Generally, ESP32 projects consist of code and circuits. Don't worry even if you've never learned code and
circuits, because we will gradually introduce the basic knowledge of C programming language and electronic
circuits, from easy to difficult. Our products contain all the electronic components and modules needed to
complete these projects. It's especially suitable for beginners.

We divide each project into four parts, namely Component List, Component Knowledge, Circuit and Code.
Component List helps you to prepare material for the experiment more quickly. Component Knowledge allows
you to quickly understand new electronic modules or components, while Circuit helps you understand the
operating principle of the circuit. And Code allows you to easily master the use of SEP32 and accessory kit.
After finishing all the projects in this tutorial, you can also use these components and modules to make
products such as smart household, smart cars and robots to transform your creative ideas into prototypes
and new and innovative products.

In addition, if you have any difficulties or questions with this tutorial or toolkit, feel free to ask for our quick
and free technical support through support@freenove.com

Any concerns?  support@freenove.com


2 Preface www.freenove.com █

ESP32-WROVER

ESP32-WROVER has launched a total of two antenna packages, PCB on-board antenna and IPEX antenna
respectively. The PCB on-board antenna is an integrated antenna in the chip module itself, so it is convenient
to carry and design. The IPEX antenna is a metal antenna derived from the integrated antenna of the chip
module itself, which is used to enhance the signal of the module.
PCB on-board antenna IPEX antenna

In this tutorial, the ESP32-WROVER is designed based on the PCB on-board antenna-packaged ESP32-
WROVER module.
ESP32-WROVER

Any concerns?  support@freenove.com


█ www.freenove.com Preface 3

The hardware interfaces of ESP32-WROVER are distributed as follows:

Compare the left and right images. We've boxed off the resources on the ESP32-WROVER in different colors
to facilitate your understanding of the ESP32-WROVER.
Box color Corresponding resources introduction
GPIO pin

LED indicator

Camera interface

Reset button, Boot mode selection button

USB port

Any concerns?  support@freenove.com


4 Preface www.freenove.com █

For more information, please visit: https://www.espressif.com/sites/default/files/documentation/esp32-


wrover_datasheet_en.pdf

Any concerns?  support@freenove.com


█ www.freenove.com Preface 5

Extension board of the ESP32-WROVER

And we also design an extension board, so that you can use the ESP32 more easily in accordance with the
circuit diagram provided. The followings are their photos.
The hardware interfaces of ESP32-WROVER are distributed as follows:

We've boxed off the resources on the ESP32-WROVER in different colors to facilitate your understanding of
the ESP32-WROVER.
Box color Corresponding resources introduction
GPIO pin
LED indicator
GPIO interface of development board
power supplied by the extension board
External power supply
In ESP32, GPIO is an interface to control peripheral circuit. For beginners, it is necessary to learn the
functions of each GPIO. The following is an introduction to the GPIO resources of the ESP32-WROVER
development board.
In the following projects, we only use USB cable to power ESP32-WROVER by default.
In the whole tutorial, we don’t use T extension to power ESP32-WROVER. So 5V and 3.3V (including EXT 3.3V)
on the extension board are provided by ESP32-WROVER.
We can also use DC jack of extension board to power ESP32-WROVER.In this way, 5v and EXT 3.3v on
extension board are provided by external power resource.

Any concerns?  support@freenove.com


6 Preface www.freenove.com █

CH340

ESP32 uses CH340 to download codes. So before using it, we need to install CH340 driver in our computers.

Windows

Check whether CH340 has been installed


1. Connect your computer and ESP32 with a USB cable.

2. Turn to the main interface of your computer, select “This PC” and right-click to select “Manage”.

Any concerns?  support@freenove.com


█ www.freenove.com Preface 7

3. Click “Device Manager”. If your computer has installed CH340, you can see“USB-SERIAL CH340 (COMx)”.
And you can click here to move to the next step.

CH340 Port

Installing CH340
1. First, download CH340 driver, click http://www.wch-ic.com/search?q=CH340&t=downloads to download
the appropriate one based on your operating system.

Any concerns?  support@freenove.com


8 Preface www.freenove.com █

Windows

Linux

MAC

If you would not like to download the installation package, you can open
“Freenove_Ultimate_Starter_Kit_for_ESP32/CH340”, we have prepared the installation package.

Any concerns?  support@freenove.com


█ www.freenove.com Preface 9

2. Open the folder “Freenove_Ultimate_Starter_Kit_for_ESP32/CH340/Windows/”

3. Double click “CH341SER.EXE”.

Any concerns?  support@freenove.com


10 Preface www.freenove.com █

4. Click “INSTALL” and wait for the installation to complete.

5. Install successfully. Close all interfaces.

Any concerns?  support@freenove.com


█ www.freenove.com Preface 11

6. When ESP32 is connected to computer, select “This PC”, right-click to select “Manage” and click “Device
Manager” in the newly pop-up dialog box, and you can see the following interface.

7. So far, CH340 has been installed successfully. Close all dialog boxes.

Any concerns?  support@freenove.com


12 Preface www.freenove.com █

MAC

First, download CH340 driver, click http://www.wch-ic.com/search?q=CH340&t=downloads to download the


appropriate one based on your operating system.

Windows

Linux

MAC

If you would not like to download the installation package, you can open
“Freenove_Ultimate_Starter_Kit_for_ESP32/CH340”, we have prepared the installation package.
Second, open the folder “Freenove_Ultimate_Starter_Kit_for_ESP32/CH340/MAC/”

Run it.

Any concerns?  support@freenove.com


█ www.freenove.com Preface 13

Third, click Continue.

Fourth, click Install.

Any concerns?  support@freenove.com


14 Preface www.freenove.com █

Then, waiting Finsh.

Finally, restart your PC.

Any concerns?  support@freenove.com


█ www.freenove.com Preface 15

If you still haven't installed the CH340 by following the steps above, you can view readme.pdf to install it.

ReadMe

Any concerns?  support@freenove.com


16 Preface www.freenove.com █

Programming Software

Arduino Software (IDE) is used to write and upload the code for Arduino Board.
First, install Arduino Software (IDE): visit https://www.arduino.cc, click "Download" to enter the download page.

Select and download corresponding installer according to your operating system. If you are a windows user,
please select the "Windows Installer" to download to install the driver correctly.

After the download completes, run the installer. For Windows users, there may pop up an installation dialog
box of driver during the installation process. When it popes up, please allow the installation.
After installation is complete, an Arduino Software shortcut will be generated in the desktop. Run the Arduino
Software.

Any concerns?  support@freenove.com


█ www.freenove.com Preface 17

The interface of Arduino Software is as follows:

Menus

Toolbar

Text editor

Message
area

Console

Configured board
and serial port

Any concerns?  support@freenove.com


18 Preface www.freenove.com █

Programs written with Arduino Software (IDE) are called sketches. These sketches are written in the text
editor and saved with the file extension.ino. The editor has features for cutting/pasting and
searching/replacing text. The message area gives feedback while saving and exporting and also displays
errors. The console displays text output by the Arduino Software (IDE), including complete error messages
and other information. The bottom right-hand corner of the window displays the configured board and
serial port. The toolbar buttons allow you to verify and upload programs, create, open, and save sketches,
and open the serial monitor.

Verify
Check your code for compile errors .
Upload
Compile your code and upload them to the configured board.
New
Create a new sketch.
Open
Present a menu of all the sketches in your sketchbook. Clicking one will open it within the
current window and overwrite its content.
Save
Save your sketch.
Serial Monitor
Open the serial monitor.

Additional commands are found within the five menus: File, Edit, Sketch, Tools, Help. The menus are context
sensitive, which means only those items relevant to the work currently being carried out are available.

Any concerns?  support@freenove.com


█ www.freenove.com Preface 19

Environment Configuration

First, open the software platform arduino, and then click File in Menus and select Preferences.

Second, click on the symbol behind "Additional Boards Manager URLs"

Any concerns?  support@freenove.com


20 Preface www.freenove.com █

Third, fill in https://raw.githubusercontent.com/espressif/arduino-esp32/gh-


pages/package_esp32_index.json in the new window, click OK, and click OK on the Preferences window
again.

Fourth, click Tools in Menus, select Board:"ArduinoUno", and then select "Boards Manager".

Any concerns?  support@freenove.com


█ www.freenove.com Preface 21

Fifth, input "esp32" in the window below, and press Enter. click "Install" to install.

Any concerns?  support@freenove.com


22 Preface www.freenove.com █

When finishing installation, click Tools in the Menus again and select Board: "Arduino Uno", and then you
can see information of ESP32-WROVER. click "ESP32-WROVER" so that the ESP32 programming
development environment is configured.

Any concerns?  support@freenove.com


█ www.freenove.com Preface 23

Notes for GPIO

Strapping Pin

There are five Strapping pins for ESP32:MTDI、GPIO0、GPIO2、MTDO、GPIO5。


With the release of the chip's system reset (power-on reset, RTC watchdog reset, undervoltage reset), the
strapping pins sample the level and store it in the latch as "0" or "1" ", and keep it until the chip is powered
off or turned off.
Each Strapping pin is connecting to internal pull-up/pull-down. Connecting to high-impedance external
circuit or without an external connection, a strapping pin's default value of input level will be determined by
internal weak pull-up/pull-down. To change the value of the Strapping, users can apply an external pull-
down/pull-up resistor, or use the GPIO of the host MCU to control the level of the strapping pin when the
ESP32's power on reset is released.
When releasing the reset, the strapping pin has the same function as a normal pin.
The followings are default configurations of these five strapping pins at power-on and their functions under
the corresponding configuration.

If you have any questions about the information of GPIO, you can click here to go back to ESP32-WROVER
to view specific information about GPIO.
If you have any difficulties or questions with this tutorial or toolkit, feel free to ask for our quick and free
technical support through support@freenove.com at any time.
or check: https://www.espressif.com/sites/default/files/documentation/esp32-wrover_datasheet_en.pdf

Any concerns?  support@freenove.com


24 Preface www.freenove.com █

Flash Pin

GPIO6-11 has been used to connect the integrated SPI flash on the module, and is used when GPIO 0 is
power on and at high level. Flash is related to the operation of the whole chip, so the external pin GPIO6-11
cannot be used as an experimental pin for external circuits, otherwise it may cause errors in the operation of
the program.
GPIO16-17 has been used to connect the integrated PSRAM on the module.
Because of external pull-up, MTDI pin is not suggested to be used as a touch sensor. For details, please refer
to Peripheral Interface and Sensor chapter in "ESP32 Data_Sheet".
For more relevant information, please check:
https://www.espressif.com/sites/default/files/documentation/esp32-wrover_datasheet_en.pdf.

Cam Pin

When using the camera of our ESP32-WROVER, please check the pins of it. Pins with underlined numbers
are used by the camera function, if you want to use other functions besides it, please avoid using them.

CAM_Pin GPIO_pin
I2C_SDA GPIO26
I2C_SCL GPIO27
CSI_VYSNC GPIO25
CSI_HREF GPIO23
CSI_Y9 GPIO35
XCLK GPIO21
CSI_Y8 GPIO34
CSI_Y7 GPIO39
CSI_PCLK GPIO22
CSI_Y6 GPIO36
CSI_Y2 GPIO4
CSI_Y5 GPIO19
CSI_Y3 GPIO5
CSI_Y4 GPIO18
If you have any questions about the information of GPIO, you can click here to go back to ESP32-WROVER
to view specific information about GPIO.
or check: https://www.espressif.com/sites/default/files/documentation/esp32-wrover_datasheet_en.pdf.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 0 LED 25

Chapter 0 LED
This chapter is the Start Point in the journey to build and explore ESP32 electronic projects. We will start with
simple “Blink” project.

Project 0.1 Blink

In this project, we will use ESP32 to control blinking a common LED.

Component List

ESP32-WROVER x1 USB cable

Power
ESP32-WROVER needs 5v power supply. In this tutorial, we need connect ESP32-WROVER to computer via
USB cable to power it and program it. We can also use other 5v power source to power it.

In the following projects, we only use USB cable to power ESP32-WROVER by default.
In the whole tutorial, we don’t use T extension to power ESP32-WROVER. So 5V and 3.3V (includeing EXT
3.3V) on the extension board are provided by ESP32-WROVER.
We can also use DC jack of extension board to power ESP32-WROVER.In this way, 5v and EXT 3.3v on
extension board are provided by external power resource.

Any concerns?  support@freenove.com


26 Chapter 0 LED www.freenove.com █

Sketch

According to the circuit, when the GPIO2 of ESP32-WROVER output level is high, the LED turns ON.
Conversely, when the GPIO2 ESP32-WROVER output level is low, the LED turns OFF. Therefore, we can let
GPIO2 circularly output high and low level to make the LED blink.
Upload the following Sketch:
Freenove_Ultimate_Starter_Kit_for_ESP32\Sketches\Sketch_01.1_Blink.
Before uploading the code, click "Tools", "Board" and select "ESP32 Wrover Module".

Select the serial port.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 0 LED 27

Note: For macOS users, if the uploading fails, please set the baud rate to 115200 before clicking
“Upload Using Programmer”.

Sketch_01.1_Blink

Click “Upload”,Download the code to ESP32-WROVER and your LED in the circuit starts Blink.

If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


28 Chapter 0 LED www.freenove.com █

The following is the program code:


1 #define PIN_LED 2
2 // the setup function runs once when you press reset or power the board
3 void setup() {
4 // initialize digital pin LED_BUILTIN as an output.
5 pinMode(PIN_LED, OUTPUT);
6 }
7
8 // the loop function runs over and over again forever
9 void loop() {
10 digitalWrite(PIN_LED, HIGH); // turn the LED on (HIGH is the voltage level)
11 delay(1000); // wait for a second
12 digitalWrite(PIN_LED, LOW); // turn the LED off by making the voltage LOW
13 delay(1000); // wait for a second
14 }

The Arduino IDE code usually contains two basic functions: void setup() and void loop().
After the board is reset, the setup() function will be executed firstly, and then the loop() function.
setup() function is generally used to write code to initialize the hardware. And loop() function is used to write
code to achieve certain functions. loop() function is executed repeatedly. When the execution reaches the end
of loop(), it will jump to the beginning of loop() to run again.

Reset 1 // the setup function runs once when you press reset or power the board
2 void setup() {
… …
5 }
6
7 // the loop function runs over and over again forever
8 void loop() {
… …
13 }

Reset
Reset operation will lead the code to be executed from the beginning. Switching on the power, finishing
uploading the code and pressing the reset button will trigger reset operation.
In the circuit, ESP32-WROVER's GPIO2 is connected to the LED, so the LED pin is defined as 2.
1 #define PIN_LED 2
This means that after this line of code, all PIN_LED will be treated as 2.
In the setup () function, first, we set the PIN_LED as output mode, which can make the port output high level
or low level.
4 // initialize digital pin PIN_LED as an output.
5 pinMode(PIN_LED, OUTPUT);
Then, in the loop () function, set the PIN_LED to output high level to make LED light up.
10 digitalWrite(PIN_LED, HIGH); // turn the LED on (HIGH is the voltage level)

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 0 LED 29

Wait for 1000ms, that is 1s. Delay () function is used to make control board wait for a moment before executing
the next statement. The parameter indicates the number of milliseconds to wait for.
11 delay(1000); // wait for a second
Then set the PIN_LED to output low level, and LED light off. One second later, the execution of loop () function
will be completed.
12 digitalWrite(PIN_LED, LOW); // turn the LED off by making the voltage LOW
13 delay(1000); // wait for a second
The loop() function is constantly being executed, so LED will keep blinking.

Reference
void pinMode(int pin, int mode);
Configures the specified pin to behave either as an input or an output.
Parameters
pin: the pin number to set the mode of.
mode: INPUT, OUTPUT, INPUT_PULLDOWM, or INPUT_PULLUP.
void digitalWrite (int pin, int value);
Writes the value HIGH or LOW (1 or 0) to the given pin which must have been previously set as an output.
For more related functions, please refer to https://www.arduino.cc/reference/en/

Any concerns?  support@freenove.com


30 Chapter 1 LED www.freenove.com █

Chapter 1 LED
This chapter is the Start Point in the journey to build and explore ESP32 electronic projects. We will start with
simple “Blink” project.

Project 1.1 Blink

In this project, we will use ESP32 to control blinking a common LED.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

LED x1 Resistor 220Ω x1 Jumper M/M x2

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 1 LED 31

Component knowledge

LED
A LED is a type of diode. All diodes only work if current is flowing in the correct direction and have two poles.
A LED will only work (light up) if the longer pin (+) of LED is connected to the positive output from a power
source and the shorter pin is connected to the negative (-). Negative output is also referred to as Ground
(GND). This type of component is known as “diodes” (think One-Way Street).
All common 2 lead diodes are the same in this respect. Diodes work only if the voltage of its positive electrode
is higher than its negative electrode and there is a narrow range of operating voltage for most all common
diodes of 1.9 and 3.4V. If you use much more than 3.3V the LED will be damaged and burn out.

Note: LEDs cannot be directly connected to a power supply, which usually ends in a damaged component. A
resistor with a specified resistance value must be connected in series to the LED you plan to use.
Resistor
Resistors use Ohms (Ω) as the unit of measurement of their resistance (R). 1MΩ=1000kΩ, 1kΩ=1000Ω.
A resistor is a passive electrical component that limits or regulates the flow of current in an electronic circuit.
On the left, we see a physical representation of a resistor, and the right is the symbol used to represent the
presence of a resistor in a circuit diagram or schematic.

The bands of color on a resistor is a shorthand code used to identify its resistance value. For more details of
resistor color codes, please refer to the appendix of this tutorial.
With a fixed voltage, there will be less current output with greater resistance added to the circuit. The
relationship between Current, Voltage and Resistance can be expressed by this formula: I=V/R known as
Ohm’s Law where I = Current, V = Voltage and R = Resistance. Knowing the values of any two of these
allows you to solve the value of the third.
In the following diagram, the current through R1 is: I=U/R=5V/10kΩ=0.0005A=0.5mA.

Any concerns?  support@freenove.com


32 Chapter 1 LED www.freenove.com █

WARNING: Never connect the two poles of a power supply with anything of low resistance value (i.e. a metal
object or bare wire) this is a Short and results in high current that may damage the power supply and electronic
components.
Note: Unlike LEDs and diodes, resistors have no poles and re non-polar (it does not matter which direction
you insert them into a circuit, it will work the same)
Breadboard
Here we have a small breadboard as an example of how the rows of holes (sockets) are electrically attached.
The left picture shows the way to connect pins. The right picture shows the practical internal structure.

Power
ESP32-WROVER needs 5v power supply. In this tutorial, we need connect ESP32-WROVER to computer via
USB cable to power it and program it. We can also use other 5v power source to power it.

In the following projects, we only use USB cable to power ESP32-WROVER by default.
In the whole tutorial, we don’t use T extension to power ESP32-WROVER. So 5V and 3.3V (includeing EXT
3.3V) on the extension board are provided by ESP32-WROVER.
We can also use DC jack of extension board to power ESP32-WROVER.In this way, 5v and EXT 3.3v on
extension board are provided by external power resource.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 1 LED 33

Circuit

First, disconnect all power from the ESP32-WROVER. Then build the circuit according to the circuit and
hardware diagrams. After the circuit is built and verified correct, connect the PC to ESP32-WROVER.

CAUTION: Avoid any possible short circuits (especially connecting 5V or GND, 3.3V and GND)! WARNING: A
short circuit can cause high current in your circuit, generate excessive component heat and cause permanent
damage to your hardware!
Schematic diagram

Hardware connection. If you need any support, please contact us via: support@freenove.com

Longer Pin

Don't rotate ESP32-WROVER 180° for connection.

Any concerns?  support@freenove.com


34 Chapter 1 LED www.freenove.com █

Sketch

According to the circuit, when the GPIO2 of ESP32-WROVER output level is high, the LED turns ON.
Conversely, when the GPIO2 ESP32-WROVER output level is low, the LED turns OFF. Therefore, we can let
GPIO2 circularly output high and low level to make the LED blink.
Upload the following Sketch:
Freenove_Ultimate_Starter_Kit_for_ESP32\Sketches\Sketch_01.1_Blink.
Before uploading the code, click "Tools", "Board" and select "ESP32 Wrover Module".

Select the serial port.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 1 LED 35

Note: For macOS users, if the uploading fails, please set the baud rate to 115200 before clicking
“Upload Using Programmer”.

Sketch_01.1_Blink

Click “Upload”,Download the code to ESP32-WROVER and your LED in the circuit starts Blink.

If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


36 Chapter 2 Button & LED www.freenove.com █

Chapter 2 Button & LED


Usually, there are three essential parts in a complete automatic control device: INPUT, OUTPUT, and CONTROL.
In last section, the LED module was the output part and ESP32 was the control part. In practical applications,
we not only make LEDs flash, but also make a device sense the surrounding environment, receive instructions
and then take the appropriate action such as LEDs light up, make a buzzer turn ON and so on.

Control:
ESP32,
RPI, Arduino,
MCU and etc.

Input: Output:
switches, sensors LED, buzzer,
and etc. motor and etc.

Next, we will build a simple control system to control a LED through a push button switch.

Project 2.1 Button & LED

In the project, we will control the LED state through a Push Button Switch. When the button is pressed, our
LED will turn ON, and when it is released, the LED will turn OFF.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 2 Button & LED 37

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M x4 LED x1 Resistor 220Ω x1 Resistor 10kΩ x2 Push button x1

Any concerns?  support@freenove.com


38 Chapter 2 Button & LED www.freenove.com █

Component knowledge

Push button
This type of push button switch has 4 pins (2 Pole Switch). Two pins on the left are connected, and both left
and right sides are the same per the illustration:

When the button on the switch is pressed, the circuit is completed (your project is powered ON).

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 2 Button & LED 39

Sketch

This project is designed for learning how to use push button switch to control a LED. We first need to read
the state of switch, and then determine whether to turn the LED ON in accordance to the state of the switch.
Upload following sketch:
Freenove_Ultimate_Starter_Kit_for_ESP32\Sketches\Sketch_02.1_ButtonAndLed.
Sketch_02.1_ButtonAndLed

Download the code to ESP32-WROVER, then press the key, the LED turns ON, release the switch, the LED
turns OFF.

If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


40 Chapter 2 Button & LED www.freenove.com █

The following is the program code:


1 #define PIN_LED 2
2 #define PIN_BUTTON 13
3 // the setup function runs once when you press reset or power the board
4 void setup() {
5 // initialize digital pin PIN_LED as an output.
6 pinMode(PIN_LED, OUTPUT);
7 pinMode(PIN_BUTTON, INPUT);
8 }
9
10 // the loop function runs over and over again forever
11 void loop() {
12 if (digitalRead(PIN_BUTTON) == LOW) {
13 digitalWrite(PIN_LED,HIGH);
14 }else{
15 digitalWrite(PIN_LED,LOW);
16 }
17 }

In the circuit connection, LED and button are connected with GPIO2 and GPIO13 respectively, so define ledPin
and buttonPin as 2 and 13 respectively.
1 #define PIN_LED 2
2 #define PIN_BUTTON 13
In the while cycle of main function, use digitalRead(buttonPin) to determine the state of button. When the
button is pressed, the function returns low level, the result of “if” is true, and then turn on LED. Otherwise,
turn off LED.
11 void loop() {
12 if (digitalRead(PIN_BUTTON) == LOW) {
13 digitalWrite(PIN_LED,HIGH);
14 }else{
15 digitalWrite(PIN_LED,LOW);
16 }
17 }

Reference
int digitalRead (int pin);
This function returns the value read at the given pin. It will be “HIGH” or “LOW”(1 or 0) depending on the
logic level at the pin.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 2 Button & LED 41

Project 2.2 MINI table lamp

We will also use a push button switch, LED and ESP32 to make a MINI table lamp but this will function
differently: Press the button, the LED will turn ON, and pressing the button again, the LED turns OFF. The ON
switch action is no longer momentary (like a door bell) but remains ON without needing to continually press
on the Button Switch.
First, let us learn something about the push button switch.

Debounce for Push Button

The moment when a push button switch is pressed, it will not change from one state to another state
immediately. Due to tiny mechanical vibrations, there will be a short period of continuous buffeting before it
completely reaches another state too fast for humans to detect but not for computer microcontrollers. The
same is true when the push button switch is released. This unwanted phenomenon is known as “bounce”.
press stable release stable

Ideal state

Virtual state

Therefore, if we can directly detect the state of the push button switch, there are multiple pressing and
releasing actions in one pressing cycle. This buffeting will mislead the high-speed operation of the
microcontroller to cause many false decisions. Therefore, we need to eliminate the impact of buffeting. Our
solution: to judge the state of the button multiple times. Only when the button state is stable (consistent) over
a period of time, can it indicate that the button is actually in the ON state (being pressed).
This project needs the same components and circuits as we used in the previous section.

Any concerns?  support@freenove.com


42 Chapter 2 Button & LED www.freenove.com █

Sketch

Sketch_02.2_Tablelamp

Download the code to the ESP32-WROVER, press the button, the LED turns ON, and press the button again,
the LED turns OFF.

If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 2 Button & LED 43

The following is the program code:


1 #define PIN_LED 2
2 #define PIN_BUTTON 13
3 // the setup function runs once when you press reset or power the board
4 void setup() {
5 // initialize digital pin PIN_LED as an output.
6 pinMode(PIN_LED, OUTPUT);
7 pinMode(PIN_BUTTON, INPUT);
8 }
9
10 // the loop function runs over and over again forever
11 void loop() {
12 if (digitalRead(PIN_BUTTON) == LOW) {
13 delay(20);
14 if (digitalRead(PIN_BUTTON) == LOW) {
15 reverseGPIO(PIN_LED);
16 }
17 while (digitalRead(PIN_BUTTON) == LOW);
18 delay(20);
19 while (digitalRead(PIN_BUTTON) == LOW);
20 }
21 }
22
23 void reverseGPIO(int pin) {
24 digitalWrite(pin, ! digitalRead(pin));
25 }

When judging the push button state, if it is detected as "pressed down", wait for a certain time to detect again
to eliminate the effect of bounce. When confirmed, flip the LED on and off. Then it starts to wait for the
pressed button to be released, and waits for a certain time to eliminate the effect of bounce after it is released.
12 if (digitalRead(PIN_BUTTON) == LOW) {
13 delay(20);
14 if (digitalRead(PIN_BUTTON) == LOW) {
15 reverseGPIO(PIN_LED);
16 }
17 while (digitalRead(PIN_BUTTON) == LOW);
18 delay(20);
19 while (digitalRead(PIN_BUTTON) == LOW);
20 }
The subfunction reverseGPIO() means reading the state value of the specified pin, taking the value back and
writing it to the pin again to achieve the function of flipping the output state of the pin.
23 void reverseGPIO(int pin) {
24 digitalWrite(pin, ! digitalRead(pin));
25 }

Any concerns?  support@freenove.com


44 Chapter 3 LED Bar www.freenove.com █

Chapter 3 LED Bar


We have learned how to control a LED blinking, next we will learn how to control a number of LEDs.

Project 3.1 Flowing Light

In this project, we use a number of LEDs to make a flowing light.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M x10 LED bar graph x1 Resistor 220Ω x10

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 3 LED Bar 45

Component knowledge

Let’s learn about the basic features of these components to use and understand them better.
LED bar
A LED bar graph has 10 LEDs integrated into one compact component. The two rows of pins at its bottom
are paired to identify each LED like the single LED used earlier.

Any concerns?  support@freenove.com


46 Chapter 3 LED Bar www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

If LED bar does not work, try to rotate it for 180°. The label is random.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 3 LED Bar 47

Sketch

This project is designed to make a flowing water lamp. Which are these actions: First turn LED #1 ON, then
turn it OFF. Then turn LED #2 ON, and then turn it OFF... and repeat the same to all 10 LEDs until the last LED
is turns OFF. This process is repeated to achieve the “movements” of flowing water.
Upload following sketch:
Freenove_Ultimate_Starter_Kit_for_ESP32\Sketches\Sketch_03.1_FlowingLight.
Sketch_03.1_FlowingLight

Download the code to ESP32-WROVER and LED bar graph will light up from left to right and from right to
left.

If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


48 Chapter 3 LED Bar www.freenove.com █

The following is the program code:


1 byte ledPins[] = {15, 2, 0, 4, 5, 18, 19, 21, 22, 23};
2 int ledCounts;
3
4 void setup() {
5 ledCounts = sizeof(ledPins);
6 for (int i = 0; i < ledCounts; i++) {
7 pinMode(ledPins[i], OUTPUT);
8 }
9 }
10
11 void loop() {
12 for (int i = 0; i < ledCounts; i++) {
13 digitalWrite(ledPins[i], HIGH);
14 delay(100);
15 digitalWrite(ledPins[i], LOW);
16 }
17 for (int i = ledCounts - 1; i > -1; i--) {
18 digitalWrite(ledPins[i], HIGH);
19 delay(100);
20 digitalWrite(ledPins[i], LOW);
21 }
22 }
Use an array to define 10 GPIO ports connected to LED bar graph for easier operation.
1 byte ledPins[] = {15, 2, 0, 4, 5, 18, 19, 21, 22, 23};
In setup(), use sizeof() to get the number of array, which is the number of LEDs, then configure the GPIO port
to output mode.
5 ledCounts = sizeof(ledPins);
6 for (int i = 0; i < ledCounts; i++) {
7 pinMode(ledPins[i], OUTPUT);
8 }
Then, in loop(), use two “for” loop to realize flowing water light from left to right and from right to left.
12 for (int i = 0; i < ledCounts; i++) {
13 digitalWrite(ledPins[i], HIGH);
14 delay(100);
15 digitalWrite(ledPins[i], LOW);
16 }
17 for (int i = ledCounts - 1; i > -1; i--) {
18 digitalWrite(ledPins[i], HIGH);
19 delay(100);
20 digitalWrite(ledPins[i], LOW);
21 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 4 Analog & PWM 49

Chapter 4 Analog & PWM


In previous study, we have known that one button has two states: pressed and released, and LED has light-
on/off state, then how to enter a middle state? How to output an intermediate state to let LED "semi bright"?
That's what we're going to learn.
First, let’s learn how to control the brightness of a LED.

Project 4.1 Breathing LED

Breathing light, that is, LED is turned from off to on gradually, and gradually from on to off, just like "breathing".
So, how to control the brightness of a LED? We will use PWM to achieve this target.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

LED x1 Resistor 220Ω x1 Jumper M/M x2

Any concerns?  support@freenove.com


50 Chapter 4 Analog & PWM www.freenove.com █

Related knowledge

Analog & Digital


An analog signal is a continuous signal in both time and value. On the contrary, a digital signal or discrete-
time signal is a time series consisting of a sequence of quantities. Most signals in life are analog signals. A
familiar example of an analog signal would be how the temperature throughout the day is continuously
changing and could not suddenly change instantaneously from 0℃ to 10℃. However, digital signals can
instantaneously change in value. This change is expressed in numbers as 1 and 0 (the basis of binary code).
Their differences can more easily be seen when compared when graphed as below.

In practical application, we often use binary as the digital signal, that is a series of 0’s and 1’s. Since a binary
signal only has two values (0 or 1), it has great stability and reliability. Lastly, both analog and digital signals
can be converted into the other.
PWM
PWM, Pulse-Width Modulation, is a very effective method for using digital signals to control analog circuits.
Common processors cannot directly output analog signals. PWM technology makes it very convenient to
achieve this conversion (translation of digital to analog signals)
PWM technology uses digital pins to send certain frequencies of square waves, that is, the output of high
levels and low levels, which alternately last for a while. The total time for each set of high levels and low levels
is generally fixed, which is called the period (Note: the reciprocal of the period is frequency). The time of high
level outputs are generally called “pulse width”, and the duty cycle is the percentage of the ratio of pulse
duration, or pulse width (PW) to the total period (T) of the waveform.
The longer the outputs of high levels last, the longer the duty cycle and the higher the corresponding voltage
in the analog signal will be. The following figures show how the analog signal voltages vary between 0V-5V
(high level is 5V) corresponding to the pulse width 0%-100%:

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 4 Analog & PWM 51

The longer the PWM duty cycle is, the higher the output power will be. Now that we understand this
relationship, we can use PWM to control the brightness of a LED or the speed of DC motor and so on.
It is evident from the above that PWM is not real analog, and the effective value of the voltage is equivalent
to the corresponding analog. Therefore, we can control the output power of the LED and other output
modules to achieve different effects.

ESP32 and PWM


On ESP32, the LEDC(PWM) controller has 16 separate channels, each of which can independently control
frequency, duty cycle, and even accuracy. Unlike traditional PWM pins, the PWM output pins of ESP32 are
configurable, with one or more PWM output pins per channel. The relationship between the maximum
frequency and bit precision is shown in the following formula, where the maximum value of bit is 31.

80,000,000
Freqmax =
1≪𝑏𝑖𝑡
8
For example, generate a PWM with an 8-bit precision (2 =256. Values range from 0 to 255) with a maximum
frequency of 80,000,000/255 = 312,500Hz.)

Any concerns?  support@freenove.com


52 Chapter 4 Analog & PWM www.freenove.com █

Circuit

This circuit is the same as the one in engineering Blink.


Schematic diagram

Hardware connection. If you need any support, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 4 Analog & PWM 53

Sketch

This project is designed to make PWM output GPIO2 with pulse width increasing from 0% to 100%, and then
reducing from 100% to 0% gradually.
Sketch_04.1_BreathingLight

Download the code to ESP32-WROVER, and you'll see that LED is turned from on to off and then from off to
on gradually like breathing.

Any concerns?  support@freenove.com


54 Chapter 4 Analog & PWM www.freenove.com █

The following is the program code:


1 #define PIN_LED 2 //define the led pin
2 #define CHN 0 //define the pwm channel
3 #define FRQ 1000 //define the pwm frequency
4 #define PWM_BIT 8 //define the pwm precision
5 void setup() {
6 ledcSetup(CHN, FRQ, PWM_BIT); //setup pwm channel
7 ledcAttachPin(PIN_LED, CHN); //attach the led pin to pwm channel
8 }
9
10 void loop() {
11 for (int i = 0; i < 255; i++) { //make light fade in
12 ledcWrite(CHN, i);
13 delay(10);
14 }
15 for (int i = 255; i > -1; i--) { //make light fade out
16 ledcWrite(CHN, i);
17 delay(10);
18 }
19 }

The PWM pin output mode of ESP32 is not the same as the traditional controller. It controls each parameter
of PWM by controlling the PWM channel. Any number of GPIO can be connected with the PWM channel to
output PWM. In setup(), you first configure a PWM channel and set the frequency and precision.
6 ledcSetup(CHN, FRQ, PWM_BIT); //setup pwm channel

Then the GPIO is associated with the PWM channel.


7 ledcAttachPin(PIN_LED, CHN); //attach the led pin to pwm channel

In the loop(), There are two “for” loops. The first makes the ledPin output PWM from 0% to 100% and the
second makes the ledPin output PWM from 100% to 0%. This allows the LED to gradually light and extinguish。
11 for (int i = 0; i < 255; i++) { //make light fade in
12 ledcWrite(CHN, i);
13 delay(10);
14 }
15 for (int i = 255; i > -1; i--) { //make light fade out
16 ledcWrite(CHN, i);
17 delay(10);
18 }
You can also adjust the rate of the state change of LED by changing the parameters of the delay() function in
the “for” loop.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 4 Analog & PWM 55

double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)


Set the frequency and accuracy of a PWM channel.

Parameters
chan: channel index. Value range :0-15
freq: frequency, it could be a decimal.
bit_num: precision of values.

void ledcAttachPin(uint8_t pin, uint8_t channel);


void ledcDetachPin(uint8_t pin);
Bind/unbind a GPIO to a PWM channel.
void ledcWrite(uint8_t channel, uint32_t duty);
Writes the pulse width value to a PWM channel.

Any concerns?  support@freenove.com


56 Chapter 4 Analog & PWM www.freenove.com █

Project 4.2 Meteor Flowing Light

After learning about PWM, we can use it to control LED bar graph and realize a cooler flowing light.
The component list, circuit, and hardware are exactly consistent with the project Flowing Light.

Sketch

Meteor flowing light will be implemented with PWM.


Sketch_04.2_FlowingLight2

Download the code to ESP32-WROVER, and LED bar graph will gradually light up and out from left to right,
then light up and out from right to left.

The following is the program code:


1 const byte ledPins[] = {15, 2, 0, 4, 5, 18, 19, 21, 22, 23}; //define led pins
2 const byte chns[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; //define the pwm channels
3 const int dutys[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4 1023, 512, 256, 128, 64, 32, 16, 8, 4, 2,
5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
6 }; //define the pwm dutys
7 int ledCounts; //led counts
8 int delayTimes = 50; //flowing speed ,the smaller, the faster
9 void setup() {
10 ledCounts = sizeof(ledPins); //get the led counts
11 for (int i = 0; i < ledCounts; i++) { //setup the pwm channels
Any concerns?  support@freenove.com
█ www.freenove.com Chapter 4 Analog & PWM 57

12 ledcSetup(chns[i], 1000, 10);


13 ledcAttachPin(ledPins[i], chns[i]);
14 }
15 }
16
17 void loop() {
18 for (int i = 0; i < 20; i++) { //flowing one side to other side
19 for (int j = 0; j < ledCounts; j++) {
20 ledcWrite(chns[j], dutys[i + j]);
21 }
22 delay(delayTimes);
23 }
24 for (int i = 0; i < 20; i++) { //flowing one side to other side
25 for (int j = ledCounts - 1; j > -1; j--) {
26 ledcWrite(chns[j], dutys[i + (ledCounts - 1 - j)]);
27 }
28 delay(delayTimes);
29 }
30 }

First we defined 10 GPIO, 10 PWM channels, and 30 pulse width values.


const byte ledPins[] = {15, 2, 0, 4, 5, 18, 19, 21, 22, 23}; //define led pins
const byte chns[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; //define the pwm channels
const int dutys[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1023, 512, 256, 128, 64, 32, 16, 8, 4, 2,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}; //define the pwm dutys

In setup(), set the frequency of 10 PWM channels to 1000Hz, the accuracy to 10bits, and the maximum
pulse width to 1023. Attach GPIO to these PWM channels.
for (int i = 0; i < ledCounts; i++) { //setup the pwm channels
ledcSetup(chns[i], 1000, 10);
ledcAttachPin(ledPins[i], chns[i]);
}

Any concerns?  support@freenove.com


58 Chapter 4 Analog & PWM www.freenove.com █

In loop(), a nested for loop is used to control the pulse width of the PWM, and LED bar graph moves one grid
after each 1 is added in the first for loop, gradually changing according to the values in the array duties. As
shown in the table below, the value of the second row is the value in the array duties, and the 10 green
squares in each row below represent the 10 LEDs on the LED bar graph. Every 1 is added to I, the value of the
LED bar graph will move to the right by one grid, and when it reaches the end, it will move from the end to
the starting point, achieving the desired effect.
0 1 2 3 4 5 7 8 9 1 11 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3
0 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
d 0 0 0 0 0 0 0 0 0 10 5 2 1 6 3 1 8 4 2 0 0 0 0 0 0 0 0 0 0
23 1 5 2 4 2 6
i 2 6 8
0
1
2
3

1
8
1
9
2
0

In the code, two nested for loops are used to achieve this effect.
for (int i = 0; i < 20; i++) { //flowing one side to other side
for (int j = 0; j < ledCounts; j++) {
ledcWrite(chns[j], dutys[i + j]);
}
delay(delayTimes);
}
for (int i = 0; i < 20; i++) { //flowing from one side to the other
for (int j = ledCounts - 1; j > -1; j--) {
ledcWrite(chns[j], dutys[i + (ledCounts - 1 - j)]);
}
delay(delayTimes);
}

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 5 RGB LED 59

Chapter 5 RGB LED


In this chapter, we will learn how to control a RGB LED. It can emit different colors of light. Next, we will use
RGB LED to make a multicolored light.

Project 5.1 Random Color Light

In this project, we will make a multicolored LED. And we can control RGB LED to switch different colors
automatically.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

RGBLED x1 Resistor 220Ω x3 Jumper M/M x4

Any concerns?  support@freenove.com


60 Chapter 5 RGB LED www.freenove.com █

Related knowledge

RGB LED has integrated 3 LEDs that can respectively emit red, green and blue light. And it has 4 pins. The
long pin (1) is the common port, that is, 3 LED 's positive or negative port. The RGB LED with common positive
port and its symbol is shown below. We can make RGB LED emit various colors of light by controlling these 3
LEDs to emit light with different brightness,

Red, green, and blue are known as three primary colors. When you combine these three primary-color lights
with different brightness, it can produce almost all kinds of visible lights. Computer screens, single pixel of cell
phone screen, neon, and etc. are working under this principle.

RGB

8 8 8
If we use three 8-bit PWMs to control the RGB LED, in theory, we can create 2 *2 *2 =16777216 (16 million)
colors through different combinations.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 5 RGB LED 61

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


62 Chapter 5 RGB LED www.freenove.com █

Sketch

We need to create three PWM channels and use random duty cycle to make random RGB LED color.
Sketch_05.1_ColorfulLight

With the code downloaded to ESP32-WROVER, RGB LED begins to display random colors.

If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 5 RGB LED 63

The following is the program code:


1 const byte ledPins[] = {15, 2, 4}; //define red, green, blue led pins
2 const byte chns[] = {0, 1, 2}; //define the pwm channels
3 int red, green, blue;
4 void setup() {
5 for (int i = 0; i < 3; i++) { //setup the pwm channels,1KHz,8bit
6 ledcSetup(chns[i], 1000, 8);
7 ledcAttachPin(ledPins[i], chns[i]);
8 }
9 }
10
11 void loop() {
12 red = random(0, 256);
13 green = random(0, 256);
14 blue = random(0, 256);
15 setColor(red, green, blue);
16 delay(200);
17 }
18
19 void setColor(byte r, byte g, byte b) {
20 ledcWrite(chns[0], 255 - r); //Common anode LED, low level to turn on the led.
21 ledcWrite(chns[1], 255 - g);
22 ledcWrite(chns[2], 255 - b);
23 }

Define the PWM channel and associate it with the pin connected to RGB LED, and define the variable to hold
the color value and initialize it in setup().
1 const byte ledPins[] = {15, 2, 4}; //define red, green, blue led pins
2 const byte chns[] = {0, 1, 2}; //define the pwm channels
3 int red, green, blue;
4 void setup() {
5 for (int i = 0; i < 3; i++) { //setup the pwm channels,1KHz,8bit
6 ledcSetup(chns[i], 1000, 8);
7 ledcAttachPin(ledPins[i], chns[i]);
8 }
9 }
In setColor(), this function controls the output color of RGB LED by the given color value. Because the circuit
uses a common anode, the LED lights up when the GPIO outputs low power. Therefore, in PWM, low level is
the active level, so 255 minus the given value is necessary.
19 void setColor(byte r, byte g, byte b) {
20 ledcWrite(chns[0], 255 - r); //Common anode LED, low level to turn on the led.
21 ledcWrite(chns[1], 255 - g);
22 ledcWrite(chns[2], 255 - b);
23 }

Any concerns?  support@freenove.com


64 Chapter 5 RGB LED www.freenove.com █

In loop(), get three random Numbers and set them as color values.
12 red = random(0, 256);
13 green = random(0, 256);
14 blue = random(0, 256);
15 setColor(red, green, blue);
16 delay(200);

The related function of software PWM can be described as follows:


long random(min, max);
This function will return a random number(min --- max-1).

Project 5.2 Gradient Color Light

In the previous project, we have mastered the usage of RGB LED, but the random display of colors is rather
stiff. This project will realize a fashionable light with soft color changes.

Component list and the circuit are exactly the same as the random color light.

Using a color model, the color changes from 0 to 255 as shown below.

In this code, the color model will be implemented and RGB LED will change colors along the model.
Sketch_05.2_SoftColorfulLight
The following is the program code:
1 const byte ledPins[] = {15, 2, 4}; //define led pins
2 const byte chns[] = {0, 1, 2}; //define the pwm channels
3
4 void setup() {
5 for (int i = 0; i < 3; i++) { //setup the pwm channels
6 ledcSetup(chns[i], 1000, 8);
7 ledcAttachPin(ledPins[i], chns[i]);
8 }
9 }
10
11 void loop() {
12 for (int i = 0; i < 256; i++) {
13 setColor(wheel(i));
14 delay(20);
15 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 5 RGB LED 65

16 }
17
18 void setColor(long rgb) {
19 ledcWrite(chns[0], 255 - (rgb >> 16) & 0xFF);
20 ledcWrite(chns[1], 255 - (rgb >> 8) & 0xFF);
21 ledcWrite(chns[2], 255 - (rgb >> 0) & 0xFF);
22 }
23
24 long wheel(int pos) {
25 long WheelPos = pos % 0xff;
26 if (WheelPos < 85) {
27 return ((255 - WheelPos * 3) << 16) | ((WheelPos * 3) << 8);
28 } else if (WheelPos < 170) {
29 WheelPos -= 85;
30 return (((255 - WheelPos * 3) << 8) | (WheelPos * 3));
31 } else {
32 WheelPos -= 170;
33 return ((WheelPos * 3) << 16 | (255 - WheelPos * 3));
34 }
35 }

In setColor(), a variable represents the value of RGB, and a hexadecimal representation of color is a common
representation, such as 0xAABBCC, where AA represents the red value, BB represents the green value, and
CC represents the blue value. The use of a variable can make the transmission of parameters more convenient,
in the split, only a simple operation can take out the value of each color channel
18 void setColor(long rgb) {
19 ledcWrite(chns[0], 255 - (rgb >> 16) & 0xFF);
20 ledcWrite(chns[1], 255 - (rgb >> 8) & 0xFF);
21 ledcWrite(chns[2], 255 - (rgb >> 0) & 0xFF);
22 }

The wheel() function is the color selection method for the color model introduced earlier. The pos parameter
ranges from 0 to 255 and outputs a color value in hexadecimal.

Any concerns?  support@freenove.com


66 Chapter 6 LEDPixel www.freenove.com █

Chapter 6 LEDPixel
This chapter will help you learn to use a more convenient RGB LED lamp, which requires only one GPIO
control and can be connected in infinite series in theory. Each LED can be controlled independently.

Project 6.1 LEDPixel

Learn the basic usage of LEDPixel and use it to flash red, green, blue and white.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Freenove 8 RGB LED Module x1 Jumper F/M x3

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 6 LEDPixel 67

Related knowledge

Freenove 8 RGB LED Module


The Freenove 8 RGB LED Module is as below.
It consists of 8 WS2812, each of which requires only one pin to control and supports cascade. Each WS212
has integrated 3 LEDs, red, green and blue respectively, and each of them supports 256-level brightness
adjustment, which means that each WS2812 can emit 2^24=16,777,216 different colors.
You can use only one data pin to control eight LEDs on the module. As shown below:

And you can also control many modules at the same time. Just connect OUT pin of one module to IN pin of
another module. In this way, you can use one data pin to control 8, 16, 32 … LEDs.

Pin description:
(IN) (OUT)
symbol Function symbol Function
S Input control signal S Output control signal
V Power supply pin, +3.5V~5.5V V Power supply pin, +3.5V~5.5V
G GND G GND

Any concerns?  support@freenove.com


68 Chapter 6 LEDPixel www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 6 LEDPixel 69

Sketch

This code uses a library named "Freenove_WS2812_Lib_for_ESP32", if you have not installed it, please do so
first.
Library is an important feature of the open source world, and we know that Arduino is an open source platform
that everyone can contribute to. Libraries are generally licensed under the LGPL, which means you can use
them for free to apply to your creations.
How to install the library
There are two ways to add libraries.
The first way, open the Arduino IDE, click Tools Manager Libraries.

In the pop-up window, Library Manager, search for the name of the Library, “Freenove WS2812 Lib for ESP32”.
Then click Install.

The second way,open Arduino IDE,click SketchInclude LibraryAdd .ZIP Library,In the pop-up window,
find the file named “./Libraries/Freenove_WS2812_Lib_for_ESP32.Zip” which locates in this directory,and
click OPEN.

Any concerns?  support@freenove.com


70 Chapter 6 LEDPixel www.freenove.com █

Sketch_06.1_LEDPixel

Download the code to ESP32-WROVER and RGB LED begins to light up in red, green, blue, white and black.

The following is the program code:


1 #include "Freenove_WS2812_Lib_for_ESP32.h"
2
3 #define LEDS_COUNT 8 // The number of led
4 #define LEDS_PIN 2 // define the pin connected to the Freenove 8 led strip
5 #define CHANNEL 0 // RMT channel
6
7 Freenove_ESP32_WS2812 strip = Freenove_ESP32_WS2812(LEDS_COUNT, LEDS_PIN, CHANNEL, TYPE_GRB);
8
9 u8 m_color[5][3] = { {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 255}, {0, 0, 0} };
10 int delayval = 100;
11
12 void setup() {
13 strip.begin();

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 6 LEDPixel 71

14 strip.setBrightness(10);
15 }
16 void loop() {
17 for (int j = 0; j < 5; j++) {
18 for (int i = 0; i < LEDS_COUNT; i++) {
19 strip.setLedColorData(i, m_color[j][0], m_color[j][1], m_color[j][2]);
20 strip.show();
21 delay(delayval);
22 }
23 delay(500);
24 }
25 }
To use some libraries, first you need to include the library's header file.
1 #include "Freenove_WS2812_Lib_for_ESP32.h"
Define the pins connected to the ring, the number of LEDs on the ring, and RMT channel values。
3 #define LEDS_COUNT 8 // The number of led
4 #define LEDS_PIN 2 // define the pin connected to the Freenove 8 led strip
5 #define CHANNEL 0 // RMT channel
Use the above parameters to create a LEDPixel object strip.
7 Freenove_ESP32_WS2812 strip = Freenove_ESP32_WS2812(LEDS_COUNT, LEDS_PIN, CHANNEL, TYPE_GRB);
Define the color values to be used, as red, green, blue, white, and black.
9 u8 m_color[5][3] = { {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 255}, {0, 0, 0} };
Define a variable to set the time interval for each led to light up. The smaller the value is, the faster it will
light up.
10 int delayval = 50;
Initialize strip() in setup() and set the brightness.
13 strip.begin();
14 strip.setBrightness(10);
In the loop(), there are two “for” loops, the internal for loop to light the LED one by one, and the external for
loop to switch colors. strip.setLedColorData() is used to set the color, but it does not change immediately.
Only when strip.show() is called will the color data be sent to the LED to change the color.
17 for (int j = 0; j < 5; j++) {
18 for (int i = 0; i < LEDS_COUNT; i++) {
19 strip.setLedColorData(i, m_color[j][0], m_color[j][1], m_color[j][2]);
20 strip.show();
21 delay(delayval);
22 }
23 delay(500);
24 }

Any concerns?  support@freenove.com


72 Chapter 6 LEDPixel www.freenove.com █

Reference
Freenove_ESP32_WS2812(u16 n = 8, u8 pin_gpio = 2, u8 chn = 0, LED_TYPE t = TYPE_GRB)
Constructor to create a LEDPixel object.
Before each use of the constructor, please add “#include "Freenove_WS2812_Lib_for_ESP32.h”
Parameters
n:The number of led.
pin_gpio:A pin connected to an led.
Chn: RMT channel, which uses channel 0 by default, has a total of eight channels, 0-7. This means that you
can use eight LEDPixel modules for the display at the same time, and these modules do not interfere with
each other
t:Types of LED.
TYPE_RGB:The sequence of LEDPixel module loading color is red, green and blue.
TYPE_RBG:The sequence of LEDPixel module loading color is red, blue and green.
TYPE_GRB:The sequence of LEDPixel module loading color is green, red and blue.
TYPE_GBR:The sequence of LEDPixel module loading color is green, blue and red.
TYPE_BRG:The sequence of LEDPixel module loading color is blue, red and green.
TYPE_BGR:The sequence of LEDPixel module loading color is blue,g reen and red.
void begin(void);
Initialize the LEDPixel object
void setLedColorData (u8 index, u8 r, u8 g, u8 b);
void setLedColorData (u8 index, u32 rgb);
void setLedColor (u8 index, u8 r, u8 g, u8 b);
void setLedColor (u8 index, u32 rgb);
Set the color of led with order number n.
void show(void);
Send the color data to the led and display the set color immediately.
void setBrightness(uint8_t);
Set the brightness of the LED.
If you want to learn more about this library, you can visit the following website:
https://github.com/Freenove/Freenove_WS2812_Lib_for_ESP32

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 6 LEDPixel 73

Project 6.2 Rainbow Light

In the previous project, we have mastered the use of LEDPixel. This project will realize a slightly complicated
rainbow light. The component list and the circuit are exactly the same as the project fashionable light.

Sketch

Continue to use the following color model to equalize the color distribution of the 8 LEDs and gradually
change.

Sketch_06.2_RainbowLight

Download the code to ESP32-WROVER, and the Freenove 8 RGB LED Strip displays different colors and the
color changes gradually.

Any concerns?  support@freenove.com


74 Chapter 6 LEDPixel www.freenove.com █

The following is the program code:


1 #include "Freenove_WS2812_Lib_for_ESP32.h"
2
3 #define LEDS_COUNT 8 // The number of led
4 #define LEDS_PIN 2 // define the pin connected to the Freenove 8 led strip
5 #define CHANNEL 0 // RMT channel
6
7 Freenove_ESP32_WS2812 strip = Freenove_ESP32_WS2812(LEDS_COUNT, LEDS_PIN, CHANNEL, TYPE_GRB);
8
9 void setup() {
10 strip.begin();
11 }
12
13 void loop() {
14 for (int j = 0; j < 255; j += 1) {
15 for (int i = 0; i < LEDS_COUNT; i++) {
16 strip.setLedColorData(i, strip.Wheel((i * 256 / LEDS_COUNT + j) & 255));
17 }
18 strip.show(); // Send color data to LED, and display.
19 delay(5);
20 }
21 }

In the loop(), two “for” loops are used, the internal “for” loop(for-j) is used to set the color of each LED, and
the external “for” loop(for-i) is used to change the color, in which the self-increment value in i+=1 can be
changed to change the color step distance. Changing the delay parameter changes the speed of the color
change. Wheel(i * 256 / LEDS_COUNT + j) & 255) will take color from the color model at equal intervals
starting from i.
14 for (int j = 0; j < 255; j += 1) {
15 for (int i = 0; i < LEDS_COUNT; i++) {
16 strip.setLedColorData(i, strip.Wheel((i * 256 / LEDS_COUNT + j) & 255));
17 }
18 strip.show(); // Send color data to LED, and display.
19 delay(5);
20 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 7 Buzzer 75

Chapter 7 Buzzer
In this chapter, we will learn about buzzers that can make sounds.

Project 7.1 Doorbell

We will make this kind of doorbell: when the button is pressed, the buzzer sounds; and when the button is
released, the buzzer stops sounding.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M x6

NPN transistorx1 Active buzzer x1 Push button x1 Resistor 1kΩ x1 Resistor 10kΩ x2
(S8050)

Any concerns?  support@freenove.com


76 Chapter 7 Buzzer www.freenove.com █

Component knowledge

Buzzer
Buzzer is a sounding component, which is widely used in electronic devices such as calculator, electronic
warning clock and alarm. Buzzer has two types: active and passive. Active buzzer has oscillator inside, which
will sound as long as it is supplied with power. Passive buzzer requires external oscillator signal (generally use
PWM with different frequency) to make a sound.

Active buzzer Passive buzzer

Active buzzer is easy to use. Generally, it can only make a specific frequency of sound. Passive buzzer
requires an external circuit to make a sound, but it can be controlled to make a sound with different
frequency. The resonant frequency of the passive buzzer is 2kHz, which means the passive buzzer is loudest
when its resonant frequency is 2kHz.
Next, we will use an active buzzer to make a doorbell and a passive buzzer to make an alarm.

How to identify active and passive buzzer?


1. Usually, there is a label on the surface of active buzzer covering the vocal hole, but this is not an absolute
judgment method.
2. Active buzzers are more complex than passive buzzers in their manufacture. There are many circuits and
crystal oscillator elements inside active buzzers; all of this is usually protected with a waterproof coating
(and a housing) exposing only its pins from the underside. On the other hand, passive buzzers do not
have protective coatings on their underside. From the pin holes viewing of a passive buzzer, you can see
the circuit board, coils, and a permanent magnet (all or any combination of these components depending
on the model.
Active buzzer Passive buzzer

Transistor
Because the buzzer requires such large current that GPIO of ESP32 output capability cannot meet the
requirement, a transistor of NPN type is needed here to amplify the current.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 7 Buzzer 77

Transistor, the full name: semiconductor transistor, is a semiconductor device that controls current. Transistor
can be used to amplify weak signal, or works as a switch. It has three electrodes(PINs): base (b), collector (c)
and emitter (e). When there is current passing between "be", "ce" will allow several-fold current (transistor
magnification) pass, at this point, transistor works in the amplifying area. When current between "be" exceeds
a certain value, "ce" will not allow current to increase any longer, at this point, transistor works in the saturation
area. Transistor has two types as shown below: PNP and NPN,

PNP transistor NPN transistor

In our kit, the PNP transistor is marked with 8550, and the NPN transistor is marked with 8050.

Based on the transistor's characteristics, it is often used as a switch in digital circuits. As micro-controller's
capacity to output current is very weak, we will use transistor to amplify current and drive large-current
components.

When use NPN transistor to drive buzzer, we often adopt the following method. If GPIO outputs high level,
current will flow through R1, the transistor will get conducted, and the buzzer will sound. If GPIO outputs low
level, no current flows through R1, the transistor will not be conducted, and buzzer will not sound.

When use PNP transistor to drive buzzer, we often adopt the following method. If GPIO outputs low level,
current will flow through R1, the transistor will get conducted, and the buzzer will sound. If GPIO outputs high
level, no current flows through R1, the transistor will not be conducted, and buzzer will not sound.

NPN transistor to drive buzzer PNP transistor to drive buzzer

Any concerns?  support@freenove.com


78 Chapter 7 Buzzer www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Note: in this circuit, the power supply for buzzer is 5V, and pull-up resistor of the button connected to the
power 3.3V. The buzzer can work when connected to power 3.3V, but it will reduce the loudness.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 7 Buzzer 79

Sketch

In this project, a buzzer will be controlled by a push button switch. When the button switch is pressed, the
buzzer sounds and when the button is released, the buzzer stops. It is analogous to our earlier project that
controlled a LED ON and OFF.

Sketch_07.1_Doorbell

Download the code to ESP32-WROVER, press the push button switch and the buzzer will sound. Release the
push button switch and the buzzer will stop.

Any concerns?  support@freenove.com


80 Chapter 7 Buzzer www.freenove.com █

The following is the program code:


1 #define PIN_BUZZER 13
2 #define PIN_BUTTON 4
3
4 void setup() {
5 pinMode(PIN_BUZZER, OUTPUT);
6 pinMode(PIN_BUTTON, INPUT);
7 }
8
9 void loop() {
10 if (digitalRead(PIN_BUTTON) == LOW) {
11 digitalWrite(PIN_BUZZER,HIGH);
12 }else{
13 digitalWrite(PIN_BUZZER,LOW);
14 }
15 }
The code is logically the same as using button to control LED.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 7 Buzzer 81

Project 7.2 Alertor

Next, we will use a passive buzzer to make an alarm.


Component list and the circuit is similar to the last section. In the Doorbell circuit only the active buzzer needs
to be replaced with a passive buzzer.

Sketch

In this project, the buzzer alarm is controlled by the button. Press the button, then buzzer sounds. If you
release the button, the buzzer will stop sounding. It is logically the same as using button to control LED, but
in the control method, passive buzzer requires PWM of certain frequency to sound.

Sketch_07.2_Alertor

Any concerns?  support@freenove.com


82 Chapter 7 Buzzer www.freenove.com █

Download the code to ESP32-WROVER, press the button, then alarm sounds. And when the button is released,
the alarm will stop sounding.

The following is the program code:


1 #define PIN_BUZZER 13
2 #define PIN_BUTTON 4
3 #define CHN 0 //define the pwm channel
4
5 void setup() {
6 pinMode(PIN_BUTTON, INPUT);
7 pinMode(PIN_BUZZER, OUTPUT);
8 ledcSetup(CHN, 0, 10); //setup pwm channel
9 ledcAttachPin(PIN_BUZZER, CHN); //attach the led pin to pwm channel
10 ledcWriteTone(CHN, 2000); //Sound at 2KHz for 0.3 seconds
11 delay(300);
12 }
13
14 void loop() {
15 if (digitalRead(PIN_BUTTON) == LOW) {
16 alert();
17 } else {
18 ledcWriteTone(CHN, 0);
19 }
20 }
21
22 void alert() {
23 float sinVal; // Define a variable to save sine value
24 int toneVal; // Define a variable to save sound frequency
25 for (int x = 0; x < 360; x += 10) { // X from 0 degree->360 degree
26 sinVal = sin(x * (PI / 180)); // Calculate the sine of x
27 toneVal = 2000 + sinVal * 500; //Calculate sound frequency according to the sine of x
28 ledcWriteTone(CHN, toneVal);
29 delay(10);
30 }
31 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 7 Buzzer 83

The code is the same as the active buzzer logically, but the way to control the buzzer is different. Passive
buzzer requires PWM of certain frequency to control, so you need to create a PWM channel through
ledcSetup(). Here ledcWriteTone() is designed to generating square wave with variable frequency and duty
cycle fixed to 50%, which is a better choice for controlling the buzzer.
8 ledcSetup(CHN, 0, 10); //setup pwm channel
9 ledcAttachPin(PIN_BUZZER, CHN); //attach the led pin to pwm channel
10 ledcWriteTone(CHN, 2000); //Sound at 2KHz for 0.3 seconds
In the while cycle of main function, when the button is pressed, subfunction alert() will be called and the alertor
will issue a warning sound. The frequency curve of the alarm is based on the sine curve. We need to calculate
the sine value from 0 to 360 degree and multiply a certain value (here is 500) and plus the resonant frequency
of buzzer.
22 void alert() {
23 float sinVal; // Define a variable to save sine value
24 int toneVal; // Define a variable to save sound frequency
25 for (int x = 0; x < 360; x += 10) { // X from 0 degree->360 degree
26 sinVal = sin(x * (PI / 180)); // Calculate the sine of x
27 toneVal = 2000 + sinVal * 500; //Calculate sound frequency according to the sine of x
28 ledcWriteTone(CHN, toneVal);
29 delay(10);
30 }
31 }
If you want to close the buzzer, just set PWM frequency of the buzzer pin to 0.
18 ledcWriteTone(CHN, 0);
Reference
double ledcWriteTone(uint8_t channel, double freq);
This updates the tone frequency value on the given channel.

This function has some bugs in the current version (V1.0.4): when the call interval is less than 20ms, the
resulting PWM will have an exception. We will get in touch with the authorities to solve this problem and
give solutions in the following two projects.

Any concerns?  support@freenove.com


84 Chapter 7 Buzzer www.freenove.com █

Project 7.3 Alertor (use timer)

Due to some bugs in the function ledcWriteTone(), this project uses timer to generate software PWM to
control the buzzer. The circuit is exactly the same as the last project.

Sketch

The core of the code of this project is to create a timer to change the GPIO state to generate 50% pulse width
PWM, and change the PWM frequency by changing the timing time of the timer.
Sketch_07.3_Alertor

Download the code to ESP32-WROVER, press the button, then the alarm sounds. And when the button is
released, the alarm will stop sounding.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 7 Buzzer 85

The following is the program code:


1 #define BUZZER_PIN 13
2 #define PIN_BUTTON 4
3 hw_timer_t * timer = NULL;
4
5 bool isAlerting = false;
6
7 void IRAM_ATTR onTimer() {
8 digitalWrite(BUZZER_PIN, ! digitalRead(BUZZER_PIN));
9 }
10
11 void setup() {
12 pinMode(PIN_BUTTON, INPUT);
13 pinMode(BUZZER_PIN, OUTPUT);
14 // Use 1st timer of 4 (counted from zero).
15 // Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more info).
16 timer = timerBegin(0, 80, true);
17 // Attach onTimer function to our timer.
18 timerAttachInterrupt(timer, &onTimer, true);
19 }
20 void loop() {
21 if (digitalRead(PIN_BUTTON) == LOW) {
22 if (! isAlerting) {
23 isAlerting = true;
24 // Set alarm, 1ms, repeat
25 timerAlarmWrite(timer, 1000, true);
26 // Start an alarm
27 timerAlarmEnable(timer);
28 }
29 alert();
30 } else {
31 if (isAlerting) {
32 isAlerting = false;
33 timerAlarmDisable(timer);
34 digitalWrite(BUZZER_PIN, LOW);
35 }
36 }
37 }
38
39 void alert() {
40 float sinVal;
41 int toneVal;
42 for (int x = 0; x < 360; x += 1) {
43 sinVal = sin(x * (PI / 180));

Any concerns?  support@freenove.com


86 Chapter 7 Buzzer www.freenove.com █

44 toneVal = 2000 + sinVal * 500;


45 timerAlarmWrite(timer, 500000 / toneVal, true);
46 delay(1);
47 }
48 }

In the code, first define a timer variable, timer, and then create the timer in setup(), setting the function
onTimer() that the timer will execute.
3 hw_timer_t * timer = NULL;
4
5 // Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more info).
6 timer = timerBegin(0, 80, true);
7 // Attach onTimer function to our timer.
8 timerAttachInterrupt(timer, &onTimer, true);

In the loop(), use the timerAlarmWrite() to set the timer time and use timerAlarmEnable() to start the timer.
Using the flag bit isAlerting, the code to set and start the timer is executed only when the key is pressed.
22 if (! isAlerting) {
23 isAlerting = true;
24 // Set alarm, 1ms, repeat
25 timerAlarmWrite(timer, 1000, true);
26 // Start an alarm
27 timerAlarmEnable(timer);
28 }

After the key is released, stop the timer and make the buzzer's GPIO output low.
31 if (isAlerting) {
32 isAlerting = false;
33 timerAlarmDisable(timer);
34 digitalWrite(BUZZER_PIN, LOW);
35 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 7 Buzzer 87

Reference
typedef struct hw_timer_s hw_timer_t;
Timer type, used to define a timer variable.
hw_timer_t * timerBegin(uint8_t timer, uint16_t divider, bool countUp);
Initialize the timer.
parameters
timer: The timer to initialize
divider: The frequency divider coefficient of the timer, the value range is 2-65535. The default clock
frequency is 80MHz.
countUp: true means counter up technique and false means counter down.
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge);
Bind the function to execute when the interrupt is generated for the timer.
void timerAlarmWrite(hw_timer_t *timer, uint64_t interruptAt, bool autoreload);
Set the timer time.
void timerAlarmEnable(hw_timer_t *timer);
void timerAlarmDisable(hw_timer_t *timer);
Start/stop the timer.

Any concerns?  support@freenove.com


88 Chapter 7 Buzzer www.freenove.com █

Project 7.4 Alertor (use idf)

Although using software “timer” to generate PWM is to achieve our purpose, but frequent interruption will
reduce the execution efficiency of the main program code, and when the project is too large, this problem
will be more serious. Obviously, software PWM is not the optimal choice.

This project uses the function in esp-idf-sdk code base to make the hardware PWM with adjustable frequency,
and then control the buzzer.

Because the code of this project applies the functions in the esp-idf-sdk code base, which is beyond the
scope of "Arduino", and there are many unfamiliar functions, it will be more complex.

The circuit is exactly the same as the previous project.

Sketch

Sketch_07.4_Alertor

Download the code to ESP32-WROVER, press the button, then the alarm sounds. And when the button is
released, the alarm will stop sounding.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 7 Buzzer 89

The following is the program code:


1 #include "driver/ledc.h"
2
3 #define BUZZER_PIN 13
4 #define PIN_BUTTON 4
5
6 #define LEDC_HS_TIMER LEDC_TIMER_0
7 #define LEDC_LS_TIMER LEDC_TIMER_1
8
9 #define LEDC_HS_MODE LEDC_HIGH_SPEED_MODE
10 #define LEDC_LS_MODE LEDC_LOW_SPEED_MODE
11
12 #define LEDC_HS_CH0_GPIO (BUZZER_PIN)
13 #define LEDC_HS_CH0_CHANNEL LEDC_CHANNEL_0
14
15 bool isAlerting = false;
16
17 void setup() {
18 pinMode(PIN_BUTTON, INPUT);
19 ledc_channel_config_t ledc_channel = {
20 LEDC_HS_CH0_GPIO,
21 LEDC_HIGH_SPEED_MODE,
22 LEDC_CHANNEL_0,
23 LEDC_INTR_DISABLE,
24 LEDC_HS_TIMER,
25 0,
26 0
27 };
28 ledc_timer_config_t ledc_timer = {
29 LEDC_HIGH_SPEED_MODE,
30 LEDC_TIMER_10_BIT,
31 LEDC_HS_TIMER,
32 5000
33 };
34 // Set configuration of timer0 for high speed channels
35 ledc_timer_config(&ledc_timer);
36 // Set LED Controller with previously prepared configuration
37 ledc_channel_config(&ledc_channel);
38 ledc_fade_func_install(0);
39 }
40 void loop() {
41 if (digitalRead(PIN_BUTTON) == LOW) {
42 if (! isAlerting) {
43 isAlerting = true;

Any concerns?  support@freenove.com


90 Chapter 7 Buzzer www.freenove.com █

44 ledc_set_duty_and_update(LEDC_HS_MODE, LEDC_CHANNEL_0, 0, 0);


45 }
46 alert();
47 }
48 else {
49 if (isAlerting) {
50 isAlerting = false;
51 ledc_set_duty_and_update(LEDC_HS_MODE, LEDC_CHANNEL_0, 0, 0);
52 }
53 }
54 }
55
56 void alert() {
57 float sinVal;
58 int toneVal;
59 for (int x = 0; x < 360; x += 1) {
60 sinVal = sin(x * (PI / 180));
61 toneVal = 2000 + sinVal * 500;
62 ledc_set_freq(LEDC_HS_MODE, LEDC_TIMER_0, toneVal);
63 ledc_set_duty_and_update(LEDC_HS_MODE, LEDC_CHANNEL_0, 512, 0);
64 delay(1);
65 }
66 }

The project code uses a lot of new functions, which are standard functions from the idf-sdk library. The code
logic of the project is the same, but the method of generating PWM is different.

Functionality Overview
Getting LED to work on a specific channel in either high or low speed mode requires three steps:

1. Configure Timer by specifying the PWM signal’s frequency and duty cycle resolution.
2. Configure Channel by associating it with the timer and GPIO to output the PWM signal.
3. Change PWM Signal that drives the output in order to change LED’s intensity. This can be done under
the full control of software or with hardware's fading functions.

For more information, please visit:


https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 8 Serial Communication 91

Chapter 8 Serial Communication


Serial Communication is a means of communication between different devices/devices. This section describes
ESP32's Serial Communication.

Project 8.1 Serial Print

This project uses ESP32's serial communicator to send data to the computer and print it on the serial monitor.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Micro USB Wire x1

Any concerns?  support@freenove.com


92 Chapter 8 Serial Communication www.freenove.com █

Related knowledge

Serial communication
Serial communication generally refers to the Universal Asynchronous Receiver/Transmitter (UART), which is
commonly used in electronic circuit communication. It has two communication lines, one is responsible for
sending data (TX line) and the other for receiving data (RX line). The serial communication connections of
two devices is as follows:
Device 1 Device 2

RX RX
TX TX

Before serial communication starts, the baud rate of both sides must be the same. Communication between
devices can work only if the same baud rate is used. The baud rates commonly used is 9600 and 115200.

Serial port on ESP32


Freenove ESP32 has integrated USB to serial transfer, so it could communicate with computer connecting to
USB cable.
ESP32 USB to Serial Computer

UART
UART COM
USB

Arduino Software also uploads code to Freenove ESP32 through the serial connection.
Your computer identifies serial devices connecting to it as COMx. We can use the Serial Monitor window of
Arduino Software to communicate with Freenove ESP32, connect Freenove ESP32 to computer through the
USB cable, choose the correct device, and then click the Serial Monitor icon to open the Serial Monitor
window.

Interface of serial monitor window is as follows. If you can't open it, make sure Freenove ESP32 has been
connected to the computer, and choose the right serial port in the menu bar "Tools".

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 8 Serial Communication 93

Title bar
Data-
Data- sending
sending button
area

Data-
receiving
area

Configure
bar

Circuit

Connect Freenove ESP32 to the computer with USB cable

Any concerns?  support@freenove.com


94 Chapter 8 Serial Communication www.freenove.com █

Sketch

Sketch_08.1_SerialPrinter

Download the code to ESP32-WROVER, open the serial port monitor, set the baud rate to 115200, and press
the reset button. As shown in the following figure:

Above the trip is the system


information, and below is
the result of the code.

Set the relevant information

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 8 Serial Communication 95

As shown in the image above, "ESP32 initialization completed! " The previous is the printing message when
the system is started, it uses the baud rate of 120,000, which is incorrect, so the garbled code is displayed.
The user program is then printed at a baud rate of 115200.

How do I disable messages printed at system startup?


Use a jumper wire and connect one of its ends to GPIO5 of development board and the other to GND, so
that we can disable the system to print out startup messages.
For more information, click here.
The following is the program code:
1 void setup() {
2 Serial.begin(115200);
3 Serial.println("ESP32 initialization completed! ");
4 }
5
6 void loop() {
7 Serial.printf("Running time : %.1f s\n", millis() / 1000.0f);
8 delay(1000);
9 }

Reference
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1,
int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL);
Initializes the serial port. Parameter baud is baud rate, other parameters generally use the default value.
size_t println( arg );
Print to the serial port and wrap. The parameter arg can be a number, a character, a string, an array of
characters, etc.
size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
Print formatted content to the serial port in the same way as print in standard C.
unsigned long millis();
Returns the number of milliseconds since the current system was booted.

Any concerns?  support@freenove.com


96 Chapter 8 Serial Communication www.freenove.com █

Project 8.2 Serial Read and Write

From last section, we use serial port on Freenove ESP32 to send data to a computer, now we will use that to
receive data from computer.

Component and circuit are the same as in the previous project.

Sketch

Sketch_08.2_SerialRW

Download the code to ESP32-WROVER, open the serial monitor, and set the bottom to Newline, 115200. As
shown in the following figure:

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 8 Serial Communication 97

Newline, 115200 baud

Then type characters like 'ABCDEG' into the data sent at the top and click the Send button to print out the
data ESP32 receives.

Any concerns?  support@freenove.com


98 Chapter 8 Serial Communication www.freenove.com █

The following is the program code:


1 String inputString = ""; //a String to hold incoming data
2 bool stringComplete = false; // whether the string is complete
3
4 void setup() {
5 Serial.begin(115200);
6 Serial.println(String("\nESP32 initialization completed! \n")
7 + String("Please input some characters,\n")
8 + String("select \"Newline\" below and click send button. \n"));
9 }
10
11 void loop() {
12 if (Serial.available()) { // judge whether data has been received
13 char inChar = Serial.read(); // read one character
14 inputString += inChar;
15 if (inChar == '\n') {
16 stringComplete = true;
17 }
18 }
19 if (stringComplete) {
20 Serial.printf("inputString: %s \n", inputString);
21 inputString = "";
22 stringComplete = false;
23 }
24 }

In loop(), determine whether the serial port has data, if so, read and save the data, and if the newline
character is read, print out all the data that has been read.

Reference
String();
Constructs an instance of the String class.
For more information, please visit
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/
int available(void);
Get the number of bytes (characters) available for reading from the serial port. This is data that’s already
arrived and stored in the serial receive buffer.
Serial.read();
Reads incoming serial data.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 9 AD/DA Converter 99

Chapter 9 AD/DA Converter


We have learned how to control the brightness of LED through PWM and understood that PWM is not the
real analog before. In this chapter, we will learn how to read analog, convert it into digital and convert the
digital into analog output. That is, ADC and DAC.

Project 9.1 Read the Voltage of Potentiometer

In this project, we will use the ADC function of ESP32 to read the voltage value of potentiometer. And then
output the voltage value through the DAC to control the brightness of LED.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Rotary potentiometer x1 Resistor 220Ω x1 LED x1 Jumper M/M x5

Any concerns?  support@freenove.com


100 Chapter 9 AD/DA Converter www.freenove.com █

Related knowledge

ADC
An ADC is an electronic integrated circuit used to convert analog signals such as voltages to digital or binary
form consisting of 1s and 0s. The range of our ADC on ESP32 is 12 bits, that means the resolution is
2^12=4096, and it represents a range (at 3.3V) will be divided equally to 4096 parts. The rage of analog values
corresponds to ADC values. So the more bits the ADC has, the denser the partition of analog will be and the
greater the precision of the resulting conversion.

Subsection 1: the analog in rang of 0V---3.3/4095 V corresponds to digital 0;


Subsection 2: the analog in rang of 3.3/4095 V---2*3.3 /4095V corresponds to digital 1;

The following analog will be divided accordingly.
The conversion formula is as follows:

Analog Voltage
𝐴𝐷𝐶 𝑉𝑎𝑙𝑢𝑒 = ∗ 4095
3.3
DAC
The reversing of this process requires a DAC, Digital-to-Analog Converter. The digital I/O port can output
high level and low level (0 or 1), but cannot output an intermediate voltage value. This is where a DAC is
useful. ESP32 has two DAC output pins with 8-bit accuracy, GPIO25 and GPIO26, which can divide VDD
(here is 3.3V) into 2*8=256 parts. For example, when the digital quantity is 1, the output voltage value is
3.3/256 *1 V, and when the digital quantity is 128, the output voltage value is 3.3/256 *128=1.65V, the higher
the accuracy of DAC, the higher the accuracy of output voltage value will be.

The conversion formula is as follows:

DAC Value
𝐴𝑛𝑎𝑙𝑜𝑔 𝑉𝑜𝑙𝑡𝑎𝑔𝑒 = ∗ 3.3 (V)
255

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 9 AD/DA Converter 101

ADC on ESP32
ESP32 has two digital analog converters with successive approximations of 12-bit accuracy, and a total of 16
pins can be used to measure analog signals. GPIO pin sequence number and analog pin definition are
shown in the following table.
Pin number in Arduino GPIO number ADC channel
A0 GPIO 36 ADC1_CH0
A3 GPIO 39 ADC1_CH3
A4 GPIO 32 ADC1_CH4
A5 GPIO 33 ADC1_CH5
A6 GPIO 34 ADC1_CH6
A7 GPIO 35 ADC1_CH7
A10 GPIO 4 ADC2_CH0
A11 GPIO 0 ADC2_CH1
A12 GPIO 2 ADC2_CH2
A13 GPIO 15 ADC2_CH3
A14 GPIO 13 ADC2_CH4
A15 GPIO 12 ADC2_CH5
A16 GPIO 14 ADC2_CH6
A17 GPIO 27 ADC2_CH7
A18 GPIO 25 ADC2_CH8
A19 GPIO 26 ADC2_CH9
The analog pin number is also defined in ESP32's code base. For example, you can replace GPIO36 with A0
in the code.
Note: ADC2 is disabled when ESP32's WiFi function is enabled.
DAC on ESP32
ESP32 has two 8-bit digital analog converters to be connected to GPIO25 and GPIO26 pins, respectively, and
it is immutable. As shown in the following table.
Simulate pin number GPIO number
DAC1 25
DAC2 26
The DAC pin number is already defined in ESP32's code base; for example, you can replace GPIO25 with DAC1
in the code.
Note: In this ESP32, GPIO26 is used as the camera's IIC-SDA pin, which is connected to 3.3V through a
resistor.Therefore, DAC2 cannot be used.

Any concerns?  support@freenove.com


102 Chapter 9 AD/DA Converter www.freenove.com █

Component knowledge

Potentiometer
A potentiometer is a three-terminal resistor. Unlike the resistors that we have used thus far in our project
which have a fixed resistance value, the resistance value of a potentiometer can be adjusted. A potentiometer
is often made up by a resistive substance (a wire or carbon element) and movable contact brush. When the
brush moves along the resistor element, there will be a change in the resistance of the potentiometer’s output
side (3) (or change in the voltage of the circuit that is a part). The illustration below represents a linear sliding
potentiometer and its electronic symbol on the right.

What between potentiometer pin 1 and pin 2 is the resistor body, and pins 3 is connected to brush. When
brush moves from pin 1 to pin 2, the resistance between pin 1 and pin 3 will increase up to body resistance
linearly, and the resistance between pin 2 and pin 3 will decrease down to 0 linearly.
In the circuit. The both sides of resistance body are often connected to the positive and negative electrode of
the power. When you slide the brush pin 3, you can get a certain voltage in the range of the power supply.

Rotary potentiometer
Rotary potentiometer and linear potentiometer have similar function; their only difference is: the resistance
is adjusted by rotating the potentiometer.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 9 AD/DA Converter 103

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


104 Chapter 9 AD/DA Converter www.freenove.com █

Sketch

Sketch_09.1_ADC_DAC

Download the code to ESP32-WROVER, open the serial monitor, and set the baud rate to 115200. As shown
in the following figure,

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 9 AD/DA Converter 105

The serial monitor prints ADC values, DAC values, and the output voltage of the potentiometer. In the code,
we made the voltage output from the DAC pin equal to the voltage input from the ADC pin. Rotate the handle
of the potentiometer and the print will change. When the voltage is greater than 1.6V (voltage needed to turn
on red LED), LED starts emitting light. If you continue to increase the output voltage, the LED will become
more and more brighter. When the voltage is less than 1.6v, the LED will not light up, because it does not
reach the voltage to turn on LED, which indirectly proves the difference between DAC and PWM. (if you have
an oscilloscope, you can check the waveform of the DAC output through it.)
The following is the code:
1 #define PIN_ANALOG_IN 4
2
3 void setup() {
4 Serial.begin(115200);
5 }
6
7 void loop() {
8 int adcVal = analogRead(PIN_ANALOG_IN);
9 int dacVal = map(adcVal, 0, 4095, 0, 255);
10 double voltage = adcVal / 4095.0 * 3.3;
11 dacWrite(DAC1, dacVal);
12 Serial.printf("ADC Val: %d, \t DAC Val: %d, \t Voltage: %.2fV\n", adcVal, dacVal, voltage);
13 delay(200);
14 }
In loop(),the analogRead() function is used to obtain the ADC value, and then the map() function is used to
convert the value into an 8-bit precision DAC value. The function dacWrite() is used to output the value. The
input and output voltage are calculated according to the previous formula, and the information is finally
printed out.
8 int adcVal = analogRead(PIN_ANALOG_IN);
9 int dacVal = map(adcVal, 0, 4095, 0, 255);
10 double voltage = adcVal / 4095.0 * 3.3;
11 dacWrite(DAC1, dacVal);
12 Serial.printf("ADC Val: %d, \t DAC Val: %d, \t Voltage: %.2fV\n", adcVal, dacVal, voltage);

Reference
uint16_t analogRead(uint8_t pin);
Reads the value from the specified analog pin. Return the analog reading on the pin. (0-4095 for 12 bits).
void dacWrite(uint8_t pin, uint8_t value);
This writes the given value to the supplied analog pin.
long map(long value,long fromLow,long fromHigh,long toLow,long toHigh);
Re-maps a number from one range to another. That is, a value of fromLow would get mapped to toLow, a
value of fromHigh to toHigh, values in-between to values in-between, etc.

Any concerns?  support@freenove.com


106 Chapter 9 AD/DA Converter www.freenove.com █

Project 9.2 Get Voltage (use idf)

If you have a voltmeter, in the previous project, you may discover there is a slight error between the voltage
values for ESP32 and the voltmeter values.
ESP32 provides ADC calibration, but the Arduino code base doesn't use it. The functions in the IDF-SDK library
help to obtain more accurate ADC and voltage values.

Related Knowledge

Minimizing Noise
The ESP32 ADC’s sensitive to noise will lead to large discrepancies in ADC readings. To minimize noise, users
may connect a 0.1uF capacitor to the ADC input pad in use. Multisampling may also be used to further
mitigate the effects of noise.

Graph illustrating noise mitigation using capacitor and multisampling of 64 samples.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 9 AD/DA Converter 107

ADC Calibration
The esp_adc_cal/include/esp_adc_cal.h API provides functions to correct for differences in measured voltages
caused by variation of ADC reference voltages (Vref) between chips. The designed ADC reference voltage is
1100mV, however the true reference voltage can range from 1000mV to 1200mV amongst different ESP32s.

Graph illustrating the effect of differing reference voltages on the ADC voltage curve.

Correcting ADC readings using this API involves characterizing one of the ADCs at a given attenuation to
obtain a characteristics curve (ADC-Voltage curve) that takes into account the difference in ADC reference
voltage. The characteristics curve is in the form of y = coeff_a * x + coeff_b and is used to convert ADC
readings to voltages in mV. Calculation of the characteristics curve is based on calibration values, which can
be stored in eFuse or provided by the user.

For more details, please visit:


https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/adc.html

Any concerns?  support@freenove.com


108 Chapter 9 AD/DA Converter www.freenove.com █

PIN Numbering
ADC serial pin number of Arduino pin number of IDF- GPIO number
number SDK
A0 ADC1_CHANNEL_0 GPIO 36
A1 ADC1_CHANNEL_1 GPIO 37
A2 ADC1_CHANNEL_2 GPIO 38
A3 ADC1_CHANNEL_3 GPIO 39
ADC1 A4 ADC1_CHANNEL_4 GPIO 32
A5 ADC1_CHANNEL_5 GPIO 33
A6 ADC1_CHANNEL_6 GPIO 34
A7 ADC1_CHANNEL_7 GPIO 35
A10 ADC2_CHANNEL_0 GPIO 4
A11 ADC2_CHANNEL_1 GPIO 0
A12 ADC2_CHANNEL_2 GPIO 2
A13 ADC2_CHANNEL_3 GPIO 15
A14 ADC2_CHANNEL_4 GPIO 13
ADC2 A15 ADC2_CHANNEL_5 GPIO 12
A16 ADC2_CHANNEL_6 GPIO 14
A17 ADC2_CHANNEL_7 GPIO 27
A18 ADC2_CHANNEL_8 GPIO 25
A19 ADC2_CHANNEL_9 GPIO 26

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 9 AD/DA Converter 109

Sketch

Sketch_09.2_ADC

Download the code to ESP32-WROVER, open the serial monitor, and set the baud rate to 115200. As shown
in the following illustration,

By rotating the handle of the potentiometer, the voltage value printed by the serial monitor will change. If
you have a voltmeter, you can verify that this value is more accurate than the value using analogRead(), but
there are some limits to the range.

Any concerns?  support@freenove.com


110 Chapter 9 AD/DA Converter www.freenove.com █

The following is the program code:


1 #include "esp_adc_cal.h"
2 #define PIN_ANALOG_IN 4 // A10, ADC2_CHANNEL_0D
3
4 #define DEFAULT_VREF 1100 //Use adc2_vref_to_gpio() to obtain a better estimate
5 #define NUM_OF_SAMPLES 64 //Multisampling, and get average
6
7 adc_channel_t channel = ADC_CHANNEL_0; // ADC1:GPIO36, ADC2:GPIO4
8 adc_unit_t unit = ADC_UNIT_2; // ADC2
9 adc_atten_t atten = ADC_ATTEN_DB_11; // Full scale 0-3.9V, precision range 150mV-2450mV
10
11 esp_adc_cal_characteristics_t *adc_chars;
12
13 esp_adc_cal_value_t val_type;
14
15
16 void setup() {
17 Serial.begin(115200);
18 //Check if Two Point or Vref are burned into eFuse
19 check_efuse();
20 //Configure ADC
21 if (unit == ADC_UNIT_1) { // ADC1 and ADC2 are initialized differently
22 adc1_config_width(ADC_WIDTH_BIT_12);
23 adc1_config_channel_atten((adc1_channel_t)channel, atten);
24 }
25 else {
26 adc2_config_channel_atten((adc2_channel_t)channel, atten);
27 }
28 //Characterize ADC
29 adc_chars = (esp_adc_cal_characteristics_t*)calloc(1,
30 sizeof(esp_adc_cal_characteristics_t));
31 esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12,
32 DEFAULT_VREF, adc_chars);
33 print_char_val_type(val_type);
34 }
35
36 void loop() {
37 uint32_t adc_reading = 0;
38 for (int i = 0; i < NUM_OF_SAMPLES; i++) { // Multisampling
39 if (unit == ADC_UNIT_1) {
40 adc_reading += adc1_get_raw((adc1_channel_t)channel);
41 }
42 else {
43 int raw;

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 9 AD/DA Converter 111

44 adc2_get_raw((adc2_channel_t)channel, ADC_WIDTH_BIT_12, &raw);


45 adc_reading += raw;
46 }
47 }
48 adc_reading /= NUM_OF_SAMPLES;
49 //Convert adc_reading to voltage in mV
50 uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
51 printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage);
52 delay(1000);
53 }
54
55 void check_efuse()
56 {
57 //Check TP is burned into eFuse
58 if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
59 printf("eFuse Two Point: Supported\n");
60 }
61 else {
62 printf("eFuse Two Point: NOT supported\n");
63 }
64
65 //Check Vref is burned into eFuse
66 if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) {
67 printf("eFuse Vref: Supported\n");
68 }
69 else {
70 printf("eFuse Vref: NOT supported\n");
71 }
72 }
73
74 void print_char_val_type(esp_adc_cal_value_t val_type)
75 {
76 if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
77 printf("Characterized using Two Point Value\n");
78 }
79 else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
80 printf("Characterized using eFuse Vref\n");
81 }
82 else {
83 printf("Characterized using Default Vref\n");
84 }
85 }

Any concerns?  support@freenove.com


112 Chapter 9 AD/DA Converter www.freenove.com █

For most ADC related applications, analogRead() is sufficient. This method can be used in applications where
ADC conversion accuracy is required.
About the project used in the IDF API, here is a detailed description:
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/adc.html

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 10 Touch Sensor 113

Chapter 10 Touch Sensor


ESP32 offers up to 10 capacitive touch GPIO, and as you can see from the previous section, mechanical
switches are prone to jitter that must be eliminated when used, which is not the case with ESP32's built-in
touch sensor. In addition, on the service life, the touch switch also has advantages that mechanical switch is
completely incomparable.

Project 10.1 Read Touch Sensor

This project reads the value of the touch sensor and prints it out.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M x1

Any concerns?  support@freenove.com


114 Chapter 10 Touch Sensor www.freenove.com █

Related knowledge

Touch sensor
ESP32's touch sensor supports up to 10 GPIO channels as capacitive touch pins. Each pin can be used
separately as an independent touch switch or be combined to produce multiple touch points. The following
table is a list of available touch pins on ESP32.
Name of touch sensing signal Functions of pins GPIO number
T0 GPIO4 GPIO4
T1 GPIO0 GPIO0
T2 GPIO2 GPIO2
T3 MTDO GPIO15
T4 MTCK GPIO13
T5 MTDI GPIO12
T6 MTMS GPIO14
T7 GPIO27 GPIO27
T8 32K_XN GPIO33
T9 32K_XP GPIO32
The touch pin number is already defined in ESP32's code base. For example, in the code, you can use T0 to
represent GPIO4.
The electrical signals generated by touch are analog data, which are converted by an internal ADC converter.
You may have noticed that all touch pins have ADC functionality.
The hardware connection method is shown in the following figure.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 10 Touch Sensor 115

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


116 Chapter 10 Touch Sensor www.freenove.com █

Sketch

Sketch_10.1_TouchRead

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 10 Touch Sensor 117

Download the code to ESP32-WROVER, open the serial monitor, and set the baud rate to 115200. As shown
in the following figure,

Touched by hands, the value of the touch sensor will change. The closer the value is to zero, the more
obviously the touch action will be detected. The value detected by the sensor may be different in different
environments or when different people touch it. The code is very simple, just look at Reference.
Reference
uint16_t touchRead(uint8_t pin);
Read touch sensor value. (values close to 0 mean touch detected)

Any concerns?  support@freenove.com


118 Chapter 10 Touch Sensor www.freenove.com █

Project 10.2 Touch Lamp

In this project, we will use ESP32's touch sensor to create a touch switch lamp.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M x3 LED x1 Resistor 220Ω x1

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 10 Touch Sensor 119

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


120 Chapter 10 Touch Sensor www.freenove.com █

Sketch

Sketch_10.2_TouchLamp

Download the code to ESP32-WROVER, open the serial monitor, and set the baud rate to 115200. As shown
in the following figure,

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 10 Touch Sensor 121

With a touch pad, the state of the LED changes with each touch, and the detection state of the touch sensor
is printed in the serial monitor.

The following is the program code:


1 #define PIN_LED 2
2 #define PRESS_VAL 14 //Set a threshold to judge touch
3 #define RELEASE_VAL 25 //Set a threshold to judge release
4
5 bool isProcessed = false;
6 void setup() {
7 Serial.begin(115200);
8 pinMode(PIN_LED, OUTPUT);
9 }
10 void loop() {
11 if (touchRead(T0) < PRESS_VAL) {
12 if (! isProcessed) {
13 isProcessed = true;
14 Serial.println("Touch detected! ");
15 reverseGPIO(PIN_LED);
16 }
17 }
18
19 if (touchRead(T0) > RELEASE_VAL) {
20 if (isProcessed) {
21 isProcessed = false;
22 Serial.println("Released! ");
23 }
24 }

Any concerns?  support@freenove.com


122 Chapter 10 Touch Sensor www.freenove.com █

25 }
26
27 void reverseGPIO(int pin) {
28 digitalWrite(pin, ! digitalRead(pin));
29 }
The closer the return value of the function touchRead() is to 0, the more obviously the touch is detected. This
is not a fixed value, so you need to define a threshold that is considered valid (when the value of the sensor
is less than this threshold). Similarly, a threshold value is to be defined in the release state, and a value in
between is considered an invalid disturbance value.
2 #define PRESS_VAL 14 //Set a threshold to judge touch
3 #define RELEASE_VAL 25 //Set a threshold to judge release
In loop(), first determine whether the touch was detected. If yes, print some messages, flip the state of the
LED, and set the flag bit isProcessed to true to avoid repeating the program after the touch was successful.
11 if (touchRead(T0) < PRESS_VAL) {
12 if (! isProcessed) {
13 isProcessed = true;
14 Serial.println("Touch detected! ");
15 reverseGPIO(PIN_LED);
16 }
17 }
It then determines if the touch key is released, and if so, prints some messages and sets the isProcessed to
false to avoid repeating the process after the touch release and to prepare for the next touch probe.
19 if (touchRead(T0) > RELEASE_VAL) {
20 if (isProcessed) {
21 isProcessed = false;
22 Serial.println("Released! ");
23 }
24 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 11 Potentiometer & LED 123

Chapter 11 Potentiometer & LED


We have learned how to use ADC and DAC before. When using DAC output analog to drive LED, we found
that, when the output voltage is less than led turn-on voltage, the LED does not light; when the output analog
voltage is greater than the LED voltage, the LED lights. This leads to a certain degree of waste of resources.
Therefore, in the control of LED brightness, we should choose a more reasonable way of PWM control. In this
chapter, we learn to control the brightness of LED through a potentiometer.

Project 11.1 Soft Light

In this project, we will make a soft light. We will use an ADC Module to read ADC values of a potentiometer
and map it to duty cycle of the PWM used to control the brightness of a LED. Then you can change the
brightness of a LED by adjusting the potentiometer.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Rotary potentiometer x1 Resistor 220Ω x1 LED x1 Jumper M/M x5

Any concerns?  support@freenove.com


124 Chapter 11 Potentiometer & LED www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 11 Potentiometer & LED 125

Sketch

Sketch_11.1_Softlight

Download the code to ESP32-WROVER, by turning the adjustable resistor to change the input voltage of
GPIO25, ESP32 changes the output voltage of GPIO4 according to this voltage value, thus changing the
brightness of the LED.
The following is the code:
1 #define PIN_ANALOG_IN 4
2 #define PIN_LED 25
3 #define CHAN 0
4 void setup() {
5 ledcSetup(CHAN, 1000, 12);
6 ledcAttachPin(PIN_LED, CHAN);
7 }
8
9 void loop() {
10 int adcVal = analogRead(PIN_ANALOG_IN); //read adc
11 int pwmVal = adcVal; // adcVal re-map to pwmVal
12 ledcWrite(CHAN, pwmVal); // set the pulse width.
13 delay(10);
14 }
In the code, read the ADC value of potentiometer and map it to the duty cycle of PWM to control LED
brightness.

Any concerns?  support@freenove.com


126 Chapter 11 Potentiometer & LED www.freenove.com █

Project 11.2 Soft Colorful Light

In this project, 3 potentiometers are used to control the RGB LED and in principle it is the same as the Soft
Light project. Namely, read the voltage value of the potentiometer and then convert it to PWM used to control
LED brightness. Difference is that the original project only controlled one LED, but this project required (3)
RGB LEDs.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Rotary potentiometer x3 Resistor 220Ω x3 RGBLED x1 Jumper M/M x13

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 11 Potentiometer & LED 127

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


128 Chapter 11 Potentiometer & LED www.freenove.com █

Sketch

Sketch_11.2_SoftColorfulLight

Download the code to ESP32-WROVER, rotate one of the potentiometers, then the color of RGB LED will
change.
If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 11 Potentiometer & LED 129

The following is the program code:


1 const byte ledPins[] = {15, 2, 4}; //define led pins
2 const byte chns[] = {0, 1, 2}; //define the pwm channels
3 const byte adcChns[] = {13, 12, 14}; // define the adc channels
4 int colors[] = {0, 0, 0}; // red, green,blue values of color.
5 void setup() {
6 for (int i = 0; i < 3; i++) { //setup the pwm channels
7 ledcSetup(pwmChns[i], 1000, 8); //1KHz, 8bit(0-255).
8 ledcAttachPin(ledPins[i], chns[i]);
9 }
10 }
11
12 void loop() {
13 for (int i = 0; i < 3; i++) {
14 colors[i] = map(analogRead(adcChns[i]), 0, 4096, 0, 255); //calculate color
value.
15 ledcWrite(pwmChns[i], 256 - colors[i]); //set color
16 }
17 delay(10);
18 }

In the code you can read the ADC values of the 3 potentiometers and map it into a PWM duty cycle to control
the 3 LED elements to vary the color of their respective RGB LED.

Any concerns?  support@freenove.com


130 Chapter 11 Potentiometer & LED www.freenove.com █

Project 11.3 Soft Rainbow Light

In this project, we use potentiometer to control Freenove 8 RGB LED Module.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Freenove 8 RGB LED Module x1 Jumper F/M x3


Jumper M/M x3

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 11 Potentiometer & LED 131

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


132 Chapter 11 Potentiometer & LED www.freenove.com █

Sketch

Sketch_11.3_Soft_Rainbow_Light

Download the code to ESP32-WROVER, rotate the handle of the potentiometer, and the color of the lamp
ring will change.

If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 11 Potentiometer & LED 133

The following is the program code:


1 #include "Freenove_WS2812_Lib_for_ESP32.h"
2
3 #define PIN_POT 13 // Define analog input pins
4 #define LEDS_COUNT 8 // The number of led
5 #define LEDS_PIN 2 // define the pin connected to the Freenove 8 led strip
6 #define CHANNEL 0 // RMT module channel
7 #define BRIGHTNESS 100 // breghtness, the value range is 0-255.
8 Freenove_ESP32_WS2812 strip = Freenove_ESP32_WS2812(LEDS_COUNT, LEDS_PIN, CHANNEL, TYPE_GRB);
9
10 void setup() {
11 strip.setBrightness(BRIGHTNESS);
12 strip.begin();
13 }
14
15 void loop() {
16 int colorPos = map(analogRead(PIN_POT), 0, 4095, 0, 255);
17 for (int i = 0; i < LEDS_COUNT; i++) {
18 strip.setLedColorData(i,strip.Wheel(colorPos + i * 255 / 8)); // Set color data.
19 }
20 strip.show(); // Send color data to LED, and display.
21 delay(10);
22 }

The overall logical structure of the code is the same as the previous project rainbow light, except that the
starting point of the color in this code is controlled by potentiometer.

Any concerns?  support@freenove.com


134 Chapter 12 Photoresistor & LED www.freenove.com █

Chapter 12 Photoresistor & LED


In this chapter, we will learn how to use a photoresistor.

Project 12.1 NightLamp

A photoresistor is very sensitive to the amount of light present. We can take advantage of the characteristic
to make a nightlight with the following function: when the ambient light is less (darker environment) the LED
will automatically become brighter to compensate and when the ambient light is greater (brighter
environment) the LED will automatically dim to compensate.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Photoresistor x1 Resistor LED x1 Jumper M/M x4


220Ω x1 10KΩ x1

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 12 Photoresistor & LED 135

Component knowledge

Photoresistor
A photoresistor is simply a light sensitive resistor. It is an active component that decreases resistance with
respect to receiving luminosity (light) on the component's light sensitive surface. A photoresistor’s resistance
value will change in proportion to the ambient light detected. With this characteristic, we can use a
photoresistor to detect light intensity. The photoresistor and its electronic symbol are as follows.

The circuit below is used to detect the change of a photoresistor’s resistance value:

In the above circuit, when a photoresistor’s resistance vale changes due to a change in light intensity, the
voltage between the photoresistor and resistor R1 will also change. Therefore, the intensity of the light can
be obtained by measuring this voltage.

Any concerns?  support@freenove.com


136 Chapter 12 Photoresistor & LED www.freenove.com █

Circuit

The circuit of this project is similar to project Soft Light. The only difference is that the input signal is changed
from a potentiometer to a combination of a photoresistor and a resistor.
Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 12 Photoresistor & LED 137

Sketch

The circuit used is similar to the project Soft Light. The only difference is that the input signal of the AIN0 pin
of ADC changes from a potentiometer to a combination of a photoresistor and a resistor.
Sketch_12.1_Nightlamp

Download the code to ESP32-WROVER, if you cover the photoresistor or increase the light shining on it, the
brightness of the LED changes accordingly.
If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


138 Chapter 12 Photoresistor & LED www.freenove.com █

The following is the program code:


1 #define PIN_ANALOG_IN 4
2 #define PIN_LED 12
3 #define CHAN 0
4 #define LIGHT_MIN 372
5 #define LIGHT_MAX 2048
6 void setup() {
7 ledcSetup(CHAN, 1000, 12);
8 ledcAttachPin(PIN_LED, CHAN);
9 }
10
11 void loop() {
12 int adcVal = analogRead(PIN_ANALOG_IN); //read adc
13 int pwmVal = map(constrain(adcVal, LIGHT_MIN, LIGHT_MAX), LIGHT_MIN, LIGHT_MAX, 0, 4095);
14 // adcVal re-map to pwmVal
15 ledcWrite(CHAN, pwmVal); // set the pulse width.
16 delay(10);
17 }

Reference
constrain(amt,low,high)
#define constrain(amt,low,high) ((amt)<(low)? (low):((amt)>(high)? (high):(amt)))
Constrain the value amt between low and high.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 13 Thermistor 139

Chapter 13 Thermistor
In this chapter, we will learn about thermistors which are another kind of resistor

Project 13.1 Thermometer

A thermistor is a type of resistor whose resistance value is dependent on temperature and changes in
temperature. Therefore, we can take advantage of this characteristic to make a thermometer.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Thermistor x1 Resistor 10kΩ x1 Jumper M/M x3

Any concerns?  support@freenove.com


140 Chapter 13 Thermistor www.freenove.com █

Component knowledge

Thermistor
A thermistor is a temperature sensitive resistor. When it senses a change in temperature, the resistance of the
thermistor will change. We can take advantage of this characteristic by using a thermistor to detect
temperature intensity. A thermistor and its electronic symbol are shown below.

The relationship between resistance value and temperature of a thermistor is:

1 1
Rt = R ∗ EXP[ B ∗ ( − ) ]
T2 T1
Where:
Rt is the thermistor resistance under T2 temperature;
R is the nominal resistance of thermistor under T1 temperature;
EXP[n] is nth power of E;
B is for thermal index;
T1, T2 is Kelvin temperature (absolute temperature). Kelvin temperature=273.15 + Celsius temperature.
For the parameters of the thermistor, we use: B=3950, R=10k, T1=25.
The circuit connection method of the thermistor is similar to photoresistor, as the following:

We can use the value measured by the ADC converter to obtain the resistance value of thermistor, and then
we can use the formula to obtain the temperature value.
Therefore, the temperature formula can be derived as:

1 𝑅𝑡
T2 = 1/( + ln( )/𝐵)
T1 R

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 13 Thermistor 141

Circuit

The circuit of this project is similar to the one in the last chapter. The only difference is that the photoresistor
is replaced by the thermistor.
Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


142 Chapter 13 Thermistor www.freenove.com █

Sketch

Sketch_13.1_Thermometer

Download the code to ESP32-WROVER, the terminal window will display the current ADC value, voltage value
and temperature value. Try to “pinch” the thermistor (without touching the leads) with your index finger and
thumb for a brief time, you should see that the temperature value increases.
If you have any concerns, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 13 Thermistor 143

The following is the code:


1 #define PIN_ANALOG_IN 4
2 void setup() {
3 Serial.begin(115200);
4 }
5
6 void loop() {
7 int adcValue = analogRead(PIN_ANALOG_IN); //read ADC pin
8 double voltage = (float)adcValue / 4095.0 * 3.3; // calculate voltage
9 double Rt = 10 * voltage / (3.3 - voltage); //calculate resistance value of thermistor
10 double tempK = 1 / (1/(273.15 + 25) + log(Rt / 10)/3950.0);//calculate temperature (Kelvin)
11 double tempC = tempK - 273.15; //calculate temperature (Celsius)
12 Serial.printf("ADC value : %d,\tVoltage : %.2fV, \tTemperature : %.2fC\n", adcValue,
voltage, tempC);
13 delay(1000);
14 }

In the code, the ADC value of ADC module A0 port is read, and then calculates the voltage and the resistance
of thermistor according to Ohms Law. Finally, it calculates the temperature sensed by the thermistor,
according to the formula.

Any concerns?  support@freenove.com


144 Chapter 13 Thermistor www.freenove.com █

Project 13.2 Thermometer (use esp-idf)

This project uses the function in esp-idf to get more accurate temperature value. The circuit is exactly the
same as the last project.

Sketch

Sketch_13.2_Thermometer

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 13 Thermistor 145

Download the code to ESP32-WROVER, the terminal window will display the current ADC value, voltage value
and temperature value. Try to “pinch” the thermistor (without touching the leads) with your index finger and
thumb for a brief time, you should see that the temperature value increases.
If you have any concerns, please contact us via: support@freenove.com

The following is the program code:


1 #include "esp_adc_cal.h"
2 #define PIN_ANALOG_IN 4 // A10, ADC2_CHANNEL_0
3
4 #define DEFAULT_VREF 1100 //Default vref
5 #define NO_OF_SAMPLES 64 //Multisampling
6
7 adc_channel_t channel = ADC_CHANNEL_0; // ADC1:GPIO36, ADC2:GPIO4
8 adc_unit_t unit = ADC_UNIT_2; // ADC2
9 adc_atten_t atten = ADC_ATTEN_DB_11; // Full scale 0-3.9V, precision range 150mV-2450mV
10
11 esp_adc_cal_characteristics_t *adc_chars;
12
13 esp_adc_cal_value_t val_type;
14
15 void setup() {
16 Serial.begin(115200);
17 if (unit == ADC_UNIT_1) {
18 adc1_config_width(ADC_WIDTH_BIT_12);
19 adc1_config_channel_atten((adc1_channel_t)channel, atten);
20 }
21 else {

Any concerns?  support@freenove.com


146 Chapter 13 Thermistor www.freenove.com █

22 adc2_config_channel_atten((adc2_channel_t)channel, atten);
23 }
24
25 //Characterize ADC
26 adc_chars = (esp_adc_cal_characteristics_t*)calloc(1,
27 sizeof(esp_adc_cal_characteristics_t));
28 esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12,
29 DEFAULT_VREF, adc_chars);
30
31 }
32
33 void loop() {
34 uint32_t adc_reading = 0;
35 //Multisampling
36 for (int i = 0; i < NO_OF_SAMPLES; i++) {
37 if (unit == ADC_UNIT_1) {
38 adc_reading += adc1_get_raw((adc1_channel_t)channel);
39 }
40 else {
41 int raw;
42 adc2_get_raw((adc2_channel_t)channel, ADC_WIDTH_BIT_12, &raw);
43 adc_reading += raw;
44 }
45 }
46 adc_reading /= NUM_OF_SAMPLES;
47 //Convert adc_reading to voltage in mV
48 uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
49 //printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage);
50
51 double vol = voltage / 1000.0f;
52 double Rt = 10 * vol / (3.3 - vol); //calculate resistance value of thermistor
53 double tempK = 1 / (1 / (273.15 + 25) + log(Rt / 10) / 3950.0); //calculate temperature
54 (Kelvin)
55 double tempC = tempK - 273.15; //calculate temperature (Celsius)
56 Serial.printf("ADC value : %d,\tVoltage : %.2fV, \tTemperature : %.2fC\n", adc_reading,
vol, tempC);
57
58 delay(1000);
59 }

The part of the code that captures the ADC is consistent with the previous potentiometer section, and the
part that calculates the temperature is consistent with the previous project.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 14 Joystick 147

Chapter 14 Joystick
In the previous chapter, we have learned how to use rotary potentiometer. Now, let's learn a new electronic
module joystick which working on the same principle as rotary potentiometer.

Project 14.1 Joystick

In this project, we will read the output data of a joystick and display it to the Terminal screen.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Joystick x1 Jumper F/M x5

Any concerns?  support@freenove.com


148 Chapter 14 Joystick www.freenove.com █

Component knowledge

Joystick
A joystick is a kind of input sensor used with your fingers. You should be familiar with this concept already as
they are widely used in gamepads and remote controls. It can receive input on two axes (Y and or X) at the
same time (usually used to control direction on a two dimensional plane). And it also has a third direction
capability by pressing down (Z axis/direction).

X
Y

This is accomplished by incorporating two rotary potentiometers inside the joystick Module at 90 degrees of
each other, placed in such a manner as to detect shifts in direction in two directions simultaneously and with
a push button switch in the “vertical” axis, which can detect when a User presses on the Joystick.

When the joystick data is read, there are some differences between the axes: data of X and Y axes is analog,
which needs to use the ADC. The data of the Z axis is digital, so you can directly use the GPIO to read this
data or you have the option to use the ADC to read this.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 14 Joystick 149

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


150 Chapter 14 Joystick www.freenove.com █

Sketch

In this project’s code, we will read the ADC values of X and Y axes of the joystick, and read digital quality of
the Z axis, then display these out in terminal.
Sketch_14.1_Joystick

Download the code to ESP32-WROVER, open the serial port monitor, the baud rate is 115200, as shown in
the figure below, shift (moving) the joystick or pressing it down will make the data change.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 14 Joystick 151

The following is the code:


1 int xyzPins[] = {13, 12, 14}; //x,y,z pins
2 void setup() {
3 Serial.begin(115200);
4 pinMode(xyzPins[2], INPUT_PULLUP); //z axis is a button.
5 }
6
7 void loop() {
8 int xVal = analogRead(xyzPins[0]);
9 int yVal = analogRead(xyzPins[1]);
10 int zVal = digitalRead(xyzPins[2]);
11 Serial.printf("X,Y,Z: %d,\t%d,\t%d\n", xVal, yVal, zVal);
12 delay(500);
13 }

In the code, configure xyzPins[2] to pull-up input mode. In loop(), use analogRead () to read the value of
axes X and Y and use digitalRead () to read the value of axis Z, then display them.
8 int xVal = analogRead(xyzPins[0]);
9 int yVal = analogRead(xyzPins[1]);
10 int zVal = digitalRead(xyzPins[2]);
11 Serial.printf("X,Y,Z: %d,\t%d,\t%d\n", xVal, yVal, zVal);
12 delay(500);

Any concerns?  support@freenove.com


152 Chapter 15 74HC595 & LED Bar Graph www.freenove.com █

Chapter 15 74HC595 & LED Bar Graph


We have used LED bar graph to make a flowing water light, in which 10 GPIO ports of ESP32 is occupied.
More GPIO ports mean that more peripherals can be connected to ESP32, so GPIO resource is very precious.
Can we make flowing water light with less GPIO? In this chapter, we will learn a component, 74HC595, which
can achieve the target.

Project 15.1 Flowing Water Light

Now let’s learn how to use the 74HC595 IC chip to make a flowing water light using less GPIO.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

74HC595 x1 LED Bar Graph x1 Resistor 220Ω x8 Jumper M/M x15

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 15 74HC595 & LED Bar Graph 153

Related knowledge

74HC595
A 74HC595 chip is used to convert serial data into parallel data. A 74HC595 chip can convert the serial data
of one byte into 8 bits, and send its corresponding level to each of the 8 ports correspondingly. With this
characteristic, the 74HC595 chip can be used to expand the IO ports of a ESP32. At least 3 ports are required
to control the 8 ports of the 74HC595 chip.

The ports of the 74HC595 chip are described as follows:


Pin name GPIO Description
number
Q0-Q7 15, 1-7 Parallel data output
VCC 16 The positive electrode of power supply, the voltage is 2~6V
GND 8 The negative electrode of power supply
DS 14 Serial data Input
OE 13 Enable output,
When this pin is in high level, Q0-Q7 is in high resistance state
When this pin is in low level, Q0-Q7 is in output mode
ST_CP 12 Parallel Update Output: when its electrical level is rising, it will update the
parallel data output.
SH_CP 11 Serial shift clock: when its electrical level is rising, serial data input register will
do a shift.
MR 10 Remove shift register: When this pin is in low level, the content in shift register
will be cleared.
Q7' 9 Serial data output: it can be connected to more 74HC595 in series.
For more detail, please refer to the datasheet on the 74HC595 chip.

Any concerns?  support@freenove.com


154 Chapter 15 74HC595 & LED Bar Graph www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 15 74HC595 & LED Bar Graph 155

Sketch

In this project, we will make a flowing water light with a 74HC595 chip to learn about its functions.
Sketch_15.1_FlowingLight2

Download the code to ESP32-WROVER. You will see that LED bar graph starts with the flowing water pattern
flashing from left to right and then back from right to left.
If you have any concerns, please contact us via: support@freenove.com

The following is the program code:


1 int latchPin = 12; // Pin connected to ST_CP of 74HC595(Pin12)
2 int clockPin = 13; // Pin connected to SH_CP of 74HC595(Pin11)
3 int dataPin = 14; // Pin connected to DS of 74HC595(Pin14)
4
5 void setup() {
6 // set pins to output
7 pinMode(latchPin, OUTPUT);
8 pinMode(clockPin, OUTPUT);
9 pinMode(dataPin, OUTPUT);
10 }
11
12 void loop() {

Any concerns?  support@freenove.com


156 Chapter 15 74HC595 & LED Bar Graph www.freenove.com █

13 // Define a one-byte variable to use the 8 bits to represent the state of 8 LEDs of LED bar
14 graph.
15 // This variable is assigned to 0x01, that is binary 00000001, which indicates only one LED
16 light on.
17 byte x = 0x01; // 0b 0000 0001
18 for (int j = 0; j < 8; j++) { // Let led light up from right to left
19 writeTo595(LSBFIRST, x);
20 x <<= 1; // make the variable move one bit to left once, then the bright LED move one step
21 to the left once.
22 delay(50);
23 }
24 delay(1000);
25 x = 0x80; //0b 1000 0000
26 for (int j = 0; j < 8; j++) { // Let led light up from left to right
27 writeTo595(LSBFIRST, x);
28 x >>= 1;
29 delay(50);
30 }
31 delay(1000);
32 }
33 void writeTo595(int order, byte _data ) {
34 // Output low level to latchPin
35 digitalWrite(latchPin, LOW);
36 // Send serial data to 74HC595
37 shiftOut(dataPin, clockPin, order, _data);
38 // Output high level to latchPin, and 74HC595 will update the data to the parallel output
39 port.
40 digitalWrite(latchPin, HIGH);
41 }

In the code, we configure three pins to control the 74HC595 chip and define a one-byte variable to control
the state of the 8 LEDs (in the LED bar graph Module) through the 8 bits of the variable. The LEDs light ON
when the corresponding bit is 1. If the variable is assigned to 0x01, that is 00000001 in binary, there will be
only one LED ON.
17 x=0x01;

In the loop(), use “for” loop to send x to 74HC595 output pin to control the LED. In "for" loop, x will shift one
bit to the LEFT in one cycle, then when data of x is sent to 74HC595, the LED that is turned ON will move one
bit to the LEFT once.
18 for (int j = 0; j < 8; j++) { // Let led light up from right to left
19 writeTo595(LSBFIRST, x);
20 x <<= 1;
21 delay(50);
22 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 15 74HC595 & LED Bar Graph 157

In second “for” loop, the situation is the same. The difference is that x is shift from 0x80 to the RIGHT in order.

The subfunction writeTo595() is used to write data to 74HC595 and immediately output on the port of
74HC595.
Reference
<< operator
"<<" is the left shift operator, which can make all bits of 1 byte shift by several bits to the left (high) direction
and add 0 on the right (low). For example, shift binary 00000001 by 1 bit to left:
byte x = 1 << 1;
← ← ← ← ← ← ←
← 0 0 0 0 0 0 0 1 ← 0
The result of x is 2(binary 00000010).
0 0 0 0 0 0 1 0

There is another similar operator" >>". For example, shift binary 00000001 by 1 bit to right:
byte x = 1 >> 1;
→ → → → → → →
0 → 0 0 0 0 0 0 0 1 →
The result of x is 0(00000000).
0 0 0 0 0 0 0 0

X <<= 1 is equivalent to x = x << 1 and x >>= 1 is equivalent to x = x >> 1

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);


This is used to shift an 8-bit data value in with the data appearing on the dataPin and the clock being
sent out on the clockPin. Order is as above. The data is sampled after the cPin goes high. (So clockPin
high, sample data, clockPin low, repeat for 8 bits) The 8-bit value is returned by the function.

Parameters
dataPin: the pin on which to output each bit. Allowed data types: int.
clockPin: the pin to toggle once the dataPin has been set to the correct value. Allowed data types: int.
bitOrder: which order to shift out the bits; either MSBFIRST or LSBFIRST. (Most Significant Bit First, or, Least
Significant Bit First).
value: the data to shift out. Allowed data types: byte.

For more details about shift function, please refer to:


https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/

Any concerns?  support@freenove.com


158 Chapter 16 74HC595 & 7-Segment Display. www.freenove.com █

Chapter 16 74HC595 & 7-Segment Display.


In this chapter, we will introduce the 7-Segment Display.

Project 16.1 7-Segment Display.

We will use 74HC595 to control 7-segment display and make it display hexadecimal character "0-F".

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

74HC595 x1 7-segment display x1 Resistor 220Ω x8 Jumper M/M

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & 7-Segment Display. 159

Component knowledge

7-segment display
A 7-segment display is a digital electronic display device. There is a figure "8" and a decimal point represented,
which consists of 8 LEDs. The LEDs have a common anode and individual cathodes. Its internal structure and
pin designation diagram is shown below:

As we can see in the above circuit diagram, we can control the state of each LED separately. Also, by combining
LEDs with different states of ON and OFF, we can display different characters (Numbers and Letters). For
example, to display a “0”: we need to turn ON LED segments A, B, C, D, E and F, and turn OFF LED segments
G and DP.

In this project, we will use a 7-Segment Display with a common anode. Therefore, when there is an input low
level to a LED segment the LED will turn ON. Defining segment “A” as the lowest level and segment “DP” as
the highest level, from high to low would look like this: “DP”, “G”, “F”, “E”, “D”, “C”, “B”, “A”. Character "0"
corresponds to the code: 1100 0000b=0xc0.

Any concerns?  support@freenove.com


160 Chapter 16 74HC595 & 7-Segment Display. www.freenove.com █

For detailed code values, please refer to the following table (common anode).
CHAR DP G F E D C B A Hex ASCII
0 1 1 0 0 0 0 0 0 0xc0 1100 0000
1 1 1 1 1 1 0 0 1 0xf9 1111 1001
2 1 0 1 0 0 1 0 0 0xa4 1010 0100
3 1 0 1 1 0 0 0 0 0xb0 1011 0000
4 1 0 0 1 1 0 0 1 0x99 1001 1001
5 1 0 0 1 0 0 1 0 0x92 1001 0010
6 1 0 0 0 0 0 1 0 0x82 1000 0010
7 1 1 1 1 1 0 0 0 0xf8 1111 1000
8 1 0 0 0 0 0 0 0 0x80 1000 0000
9 1 0 0 1 0 0 0 0 0x90 1001 0000
A 1 0 0 0 1 0 0 0 0x88 1000 1000
B 1 0 0 0 0 0 1 1 0x83 1000 0011
C 1 1 0 0 0 1 1 0 0xc6 1100 0110
D 1 0 1 0 0 0 0 1 0xa1 1010 0001
E 1 0 0 0 0 1 1 0 0x86 1000 0110
F 1 0 0 0 1 1 1 0 0x8e 1000 1110

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & 7-Segment Display. 161

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


162 Chapter 16 74HC595 & 7-Segment Display. www.freenove.com █

Sketch

In this section, the 74HC595 is used in the same way as in the previous section, but with different values
transferred. We can learn how to master the digital display by sending the coded value of "0" - "F".
Sketch_16.1_7_Segment_Display

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & 7-Segment Display. 163

Verify and upload the code, and you'll see a 1-bit, 7-segment display displaying 0-f in a loop.

The following is the program code:


1 int dataPin = 15; // Pin connected to DS of 74HC595(Pin14)
2 int latchPin = 2; // Pin connected to ST_CP of 74HC595(Pin12)
3 int clockPin = 4; // Pin connected to SH_CP of 74HC595(Pin11)
4 // Define the encoding of characters 0-F for the common-anode 7-Segment Display
5 byte num[] = {
6 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
7 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e
8 };
9
10 void setup() {
11 // set pins to output
12 pinMode(latchPin, OUTPUT);
13 pinMode(clockPin, OUTPUT);
14 pinMode(dataPin, OUTPUT);
15 }
16
17 void loop() {
18 // display 0-F on digital tube
19 for (int i = 0; i < 16; i++) {
20 writeData(num[i]);// Send data to 74HC595
21 delay(1000); // delay 1 second
22 writeData(0xff); // Clear the display content
23 }
24 }
25
26 void writeData(int value) {
27 // Make latchPin output low level
28 digitalWrite(latchPin, LOW);
29 // Send serial data to 74HC595
30 shiftOut(dataPin, clockPin, LSBFIRST, value);
31 // Make latchPin output high level
32 digitalWrite(latchPin, HIGH);
33 }

Any concerns?  support@freenove.com


164 Chapter 16 74HC595 & 7-Segment Display. www.freenove.com █

First, put encoding of “0”- “F” into the array.


4 // Define the encoding of characters 0-F for the common-anode 7-Segment Display
5 byte num[] = {
6 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
7 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e
8 };
Then, in the loop, we transfer the member of the “num” to 74HC595 by calling the writeData function, so
that the digital tube displays what we want. After each display, “0xff” is used to eliminate the previous effect
and prepare for the next display.
17 void loop() {
18 // display 0-F on digital tube
19 for (int i = 0; i < 16; i++) {
20 writeData(num[i]);// Send data to 74HC595
21 delay(1000); // delay 1 second
22 writeData(0xff); // Clear the display content
23 }
24 }
In the shiftOut() function, whether to use LSBFIRST or MSBFIRST as the parameter depends on the physical
situation.
26 void writeData(int value) {
27 // Make latchPin output low level
28 digitalWrite(latchPin, LOW);
29 // Send serial data to 74HC595
30 shiftOut(dataPin, clockPin, LSBFIRST, value);
31 // Make latchPin output high level, then 74HC595 will update data to parallel output
32 digitalWrite(latchPin, HIGH);
33 }
If you want to display the decimal point, make the highest bit of each array become 0, which can be
implemented easily by num[i]&0x7f.
30 shiftOut(dataPin,clockPin, LSBFIRST, value & 0x7f);

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & 7-Segment Display. 165

Project 16.2 4-Digit 7-Segment Display

Now, let’s try to control more digit 7-segment display

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

74HC595 x1 7-segment display x1 Resistor 220Ω x8 Jumper M/M

Any concerns?  support@freenove.com


166 Chapter 16 74HC595 & 7-Segment Display. www.freenove.com █

Component knowledge

4 Digit 7-Segment Display


A 4 Digit 7-segment display integrates four 7-segment displays into one module, therefore it can display
more characters. All of the LEDs contained have a common anode and individual cathodes. Its internal
structure and pin designation diagram is shown below:

The internal electronic circuit is shown below, and all 8 LED cathode pins of each 7-segment display are
connected together.

Display method of 4 digit 7-segment display is similar to 1 digit 7-segment display. The difference between
them is that the 4-digit displays each Digit is visible in turn, one by one and not together. We need to first
send high level to the common end of the first digit display, and send low level to the remaining three
common ends, and then send content to 8 LED cathode pins of the first Digit Display. At this time, the first 7-
segment display will show visible content and the remaining three will be OFF.

Similarly, the second, third and fourth 7-segment displays will show visible content in turn by scanning the
display. Although the four number characters are displayed in turn separately, this process is so fast that it is
imperceptible to the naked eye. This is due to the principle of optical afterglow effect and the vision
persistence effect in human sight. This is how we can see all 4 number characters at the same time. However,
if each number character is displayed for a longer period, you will be able to see that the number characters
are displayed separately.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & 7-Segment Display. 167

Circuit

Schematic diagram

Hardware connection:

Any concerns?  support@freenove.com


168 Chapter 16 74HC595 & 7-Segment Display. www.freenove.com █

Sketch

In this code, we use the 74HC595 IC chip to control the 4-digit 7-segment display, and use the dynamic
scanning method to show the changing number characters.
Sketch_16.2_4_Dight_7-Segment_Display

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & 7-Segment Display. 169

Compile and upload code to ESP32-WROVER, then the digital tube displays as shown.

The following is the program code:


1 int latchPin = 2; // Pin connected to ST_CP of 74HC595(Pin12)
2 int clockPin = 4; // Pin connected to SH_CP of 74HC595(Pin11)
3 int dataPin = 15; // Pin connected to DS of 74HC595(Pin14)
4 int comPin[] = {25,26,27,14};// Common pin (anode) of 4 digit 7-segment display
5
6 // Define the encoding of characters 0-F of the common-anode 7-Segment Display
7 byte num[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
8 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
9
10 void setup() {
11 // set pins to output
12 pinMode(latchPin, OUTPUT);
13 pinMode(clockPin, OUTPUT);
14 pinMode(dataPin, OUTPUT);
15 for (int i = 0; i < 4; i++) {
16 pinMode(comPin[i], OUTPUT);
17 }
18 }
19
20 void loop() {
21 for (int i = 0; i < 4; i++) {
22 // Select a single 7-segment display
23 electDigitalDisplay (i);
24 // Send data to 74HC595
25 writeData(num[i]);
26 delay(5);
27 // Clear the display content
28 writeData(0xff);
29 }
30 }
31
32 void electDigitalDisplay(byte com) {
33 // Close all single 7-segment display
34 for (int i = 0; i < 4; i++) {
35 digitalWrite(comPin[i], LOW);
36 }

Any concerns?  support@freenove.com


170 Chapter 16 74HC595 & 7-Segment Display. www.freenove.com █

37 // Open the selected single 7-segment display


38 digitalWrite(comPin[com], HIGH);
39 }
40
41 void writeData(int value) {
42 // Make latchPin output low level
43 digitalWrite(latchPin, LOW);
44 // Send serial data to 74HC595
45 shiftOut(dataPin, clockPin, LSBFIRST, value); // Make latchPin output high level
46 // Make latchPin output high level, then 74HC595 will update data to parallel output
47 digitalWrite(latchPin, HIGH);
48 }
First, define the pin of 74HC595 and 7-segment display common end, character encoding.
1 int latchPin = 2; // Pin connected to ST_CP of 74HC595(Pin12)
2 int clockPin = 4; // Pin connected to SH_CP of 74HC595(Pin11)
3 int dataPin = 15; // Pin connected to DS of 74HC595(Pin14)
4 int comPin[] = {25,26,27,14};// Common pin (anode) of 4 digit 7-segment display
5
6 // Define the encoding of characters 0-F of the common-anode 7-Segment Display
7 byte num[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
8 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
Second, initialize all the pins to output mode.
10 void setup() {
11 // set pins to output
12 pinMode(latchPin, OUTPUT);
13 pinMode(clockPin, OUTPUT);
14 pinMode(dataPin, OUTPUT);
15 for (int i = 0; i < 4; i++) {
16 pinMode(comPin[i], OUTPUT);
17 }
18 }
Then, since there are four digital tubes, we need to write a subfunction to control it to turn ON any digital
tube. In order not to affect a new display, each time we want to turn ON a digital tube, we need to set the
other digital tube OFF.
32 void electDigitalDisplay(byte com) {
33 // Close all single 7-segment display
34 for (int i = 0; i < 4; i++) {
35 digitalWrite(comPin[i], LOW);
36 }
37 // Open the selected single 7-segment display
38 digitalWrite(comPin[com], HIGH);
39 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & 7-Segment Display. 171

The usage of the writeData function is the same as in the previous two sections, so it won't be covered again
here.
41 void writeData(int value) {
42 // Make latchPin output low level
43 digitalWrite(latchPin, LOW);
44 // Send serial data to 74HC595
45 shiftOut(dataPin, clockPin, LSBFIRST, value);
46 // Make latchPin output high level, then 74HC595 will update data to parallel output
47 digitalWrite(latchPin, HIGH);
48 }
In the loop function, because there are four digital tubes, a “for loop” is used to display the values of each
one in turn. For example, when i =0, turn ON the first digital tube to display the first value, then turn ON the
second digital tube to display the second value, until all four digital tubes display their own values. Because
the displaying time from the first number to the fourth number is so short, it may display many times in one
second, but our eyes can't keep up with the speed of the digital tube, so we look as if the digital tube is
displaying different Numbers at the same time.
20 void loop() {
21 for (int i = 0; i < 4; i++) {
22 // Select a single 7-segment display
23 electDigitalDisplay(i);
24 // Send data to 74HC595
25 writeData(num[i]);
26 delay(5);
27 // Clear the display content
28 writeData(0xff);
29 }
30 }
If you want to display the decimal point, make the highest bit of each array become 0, which can be
implemented easily by num[i]&0x7f.
45 shiftOut(dataPin,clockPin, LSBFIRST, value & 0x7f);

Any concerns?  support@freenove.com


172 Chapter 16 74HC595 & LED Matrix www.freenove.com █

Chapter 16 74HC595 & LED Matrix


Thus far we have learned how to use the 74HC595 IC chip to control the LED bar graph and the 7-segment
display. We will now use 74HC595 IC chips to control a LED matrix.

Project 16.3 LED Matrix

In this project, we will use two 74HC595 IC chips to control a monochrome (one color) (8X8) LED matrix to
make it display both simple graphics and characters.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

74HC595 x2 8*8 LEDMatrix x1 Resistor 220Ω x8 Jumper M/M

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & LED Matrix 173

Component knowledge

LED Matrix
A LED matrix is a rectangular display module that consists of a uniform grid of LEDs. The following is an 8X8
monochrome (one color) LED matrix containing 64 LEDs (8 rows by 8 columns).

In order to facilitate the operation and reduce the number of ports required to drive this component, the
positive poles of the LEDs in each row and negative poles of the LEDs in each column are respectively
connected together inside the LED matrix module, which is called a common anode. There is another
arrangement type. Negative poles of the LEDs in each row and the positive poles of the LEDs in each column
are respectively connected together, which is called a common cathode.
The LED matrix that we use in this project is a common anode LED matrix.
Connection mode of common anode Connection mode of common cathode

Any concerns?  support@freenove.com


174 Chapter 16 74HC595 & LED Matrix www.freenove.com █

Here is how a common anode LED matrix works. First, choose 16 ports on ESP32 board to connect to the 16
ports of LED matrix. Configure one port in columns for low level, which makes that column the selected port.
Then configure the eight port in the row to display content in the selected column. Add a delay value and
then select the next column that outputs the corresponding content. This kind of operation by column is
called scan. If you want to display the following image of a smiling face, you can display it in 8 columns, and
each column is represented by one byte.

1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0
0 1 0 0 0 0 1 0
1 0 1 0 0 1 0 1
1 0 0 0 0 0 0 1
1 0 0 1 1 0 0 1
0 1 0 0 0 0 1 0
0 0 1 1 1 1 0 0

Column Binary Hexadecimal


1 0001 1100 0x1c
2 0010 0010 0x22
3 0101 0001 0x51
4 0100 0101 0x45
5 0100 0101 0x45
6 0101 0001 0x51
7 0010 0010 0x22
8 0001 1100 0x1c
To begin, display the first column, then turn off the first column and display the second column. (and so on) ....
turn off the seventh column and display the 8th column, and then start the process over from the first column
again like the control of LED bar graph project. The whole process will be repeated rapidly in a loop. Due to
the principle of optical afterglow effect and the vision persistence effect in human sight, we will see a picture
of a smiling face directly rather than individual columns of LEDs turned ON one column at a time (although
in fact this is the reality we cannot perceive).

Then, to save the number of GPIO, we use a 74HC595. When the first column is turned ON, set the lights that
need to be displayed in the first column to "1", otherwise to "0", as shown in the above example, where the
value of the first column is 0x1c. This value is sent to 74HC595 to control the display of the first column of the
LED matrix. Following the above idea, turn OFF the display of the first column, then turn ON the second
column, and then send the value of the second column to 74HC595 ...... Until each column is displayed, the
LED matrix is displayed again from the first column.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & LED Matrix 175

Circuit

In circuit of this project, the power pin of the 74HC595 IC chip is connected to 3.3V. It can also be connected
to 5V to make LED matrix brighter.
Schematic diagram

Any concerns?  support@freenove.com


176 Chapter 16 74HC595 & LED Matrix www.freenove.com █

Hardware connection:

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & LED Matrix 177

Sketch

The following code will make LED matrix display a smiling face, and then display scrolling character "0-F".

Any concerns?  support@freenove.com


178 Chapter 16 74HC595 & LED Matrix www.freenove.com █

Download the code to ESP32-WROVER, and the LED matrix display a smiling face, and then display characters
"0 to F" scrolling in a loop on the LED matrix.

Sketch_16.3_LED_Matrix
The following is the program code:
1 int latchPin = 2; // Pin connected to ST_CP of 74HC595(Pin12)
2 int clockPin = 4; // Pin connected to SH_CP of 74HC595(Pin11)
3 int dataPin = 15; // Pin connected to DS of 74HC595(Pin14)
4
5 // Define the pattern data for a smiling face
6 const int smilingFace[] = { //"^ⅴ^"
7 0x1C, 0x22, 0x51, 0x45, 0x45, 0x51, 0x22, 0x14
8 };
9 // Define the data of numbers and letters, and save them in flash area
10 const int data[] PROGMEM = {
11 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // " "
12 0x00, 0x00, 0x21, 0x7F, 0x01, 0x00, 0x00, 0x00, // "1"
13 0x00, 0x00, 0x23, 0x45, 0x49, 0x31, 0x00, 0x00, // "2"
14 0x00, 0x00, 0x22, 0x49, 0x49, 0x36, 0x00, 0x00, // "3"
15 0x00, 0x00, 0x0E, 0x32, 0x7F, 0x02, 0x00, 0x00, // "4"
16 0x00, 0x00, 0x79, 0x49, 0x49, 0x46, 0x00, 0x00, // "5"
17 0x00, 0x00, 0x3E, 0x49, 0x49, 0x26, 0x00, 0x00, // "6"
18 0x00, 0x00, 0x60, 0x47, 0x48, 0x70, 0x00, 0x00, // "7"
19 0x00, 0x00, 0x36, 0x49, 0x49, 0x36, 0x00, 0x00, // "8"
20 0x00, 0x00, 0x32, 0x49, 0x49, 0x3E, 0x00, 0x00, // "9"
21 0x00, 0x00, 0x3E, 0x41, 0x41, 0x3E, 0x00, 0x00, // "0"
22 0x00, 0x00, 0x3F, 0x44, 0x44, 0x3F, 0x00, 0x00, // "A"
23 0x00, 0x00, 0x7F, 0x49, 0x49, 0x36, 0x00, 0x00, // "B"
24 0x00, 0x00, 0x3E, 0x41, 0x41, 0x22, 0x00, 0x00, // "C"
25 0x00, 0x00, 0x7F, 0x41, 0x41, 0x3E, 0x00, 0x00, // "D"
26 0x00, 0x00, 0x7F, 0x49, 0x49, 0x41, 0x00, 0x00, // "E"
27 0x00, 0x00, 0x7F, 0x48, 0x48, 0x40, 0x00, 0x00 // "F"
28 };
29
30 void setup() {
31 // set pins to output
32 pinMode(latchPin, OUTPUT);
33 pinMode(clockPin, OUTPUT);
34 pinMode(dataPin, OUTPUT);
35 }
36
37 void loop() {
38 // Define a one-byte variable (8 bits) which is used to represent the selected state of 8
39 column.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 16 74HC595 & LED Matrix 179

40 int cols;
41 // Display the static smiling pattern
42 for (int j = 0; j < 500; j++ ) { // repeat 500 times
43 cols = 0x01;
44 for (int i = 0; i < 8; i++) { // display 8 column data by scanning
45 matrixRowsVal(smilingFace[i]);// display the data in this column
46 matrixColsVal(~cols); // select this column
47 delay(1); // display them for a period of time
48 matrixRowsVal(0x00); // clear the data of this column
49 cols <<= 1; // shift "cols" 1 bit left to select the next column
50 }
51 }
52 // Display the dynamic patterns of numbers and letters
53 for (int i = 0; i < 128; i++) {
54 for (int k = 0; k < 10; k++) { // repeat image of each frame 10 times.
55 cols = 0x01; // Assign binary 00000001. Means the first column is selected.
56 for (int j = i; j < 8 + i; j++) { // display image of each frame
57 matrixRowsVal(pgm_read_word_near(data + j));// display the data in this column
58 matrixColsVal(~cols); // select this column
59 delay(1); // display them for a period of time
60 matrixRowsVal(0x00); // close the data of this column
61 cols <<= 1; // shift "cols" 1 bit left to select the next column
62 }
63 }
64 }
65 }
66
67 void matrixRowsVal(int value) {
68 // make latchPin output low level
69 digitalWrite(latchPin, LOW);
70 // Send serial data to 74HC595
71 shiftOut(dataPin, clockPin, LSBFIRST, value);
72 // make latchPin output high level, then 74HC595 will update the data to parallel output
73 digitalWrite(latchPin, HIGH);
74 }
76
77 void matrixColsVal(int value) {
78 // make latchPin output low level
79 digitalWrite(latchPin, LOW);
80 // Send serial data to 74HC595
81 shiftOut(dataPin, clockPin, MSBFIRST, value);
82 // make latchPin output high level, then 74HC595 will update the data to parallel output
83 digitalWrite(latchPin, HIGH);
84 }

Any concerns?  support@freenove.com


180 Chapter 16 74HC595 & LED Matrix www.freenove.com █

The first “for” loop in the “while” loop is used to display a static smile. Displaying column information from left
to right, one column at a time with a total of 8 columns. This repeats 500 times to ensure sufficient display
time.
40 int cols;
41 // Display the static smiling pattern
42 for (int j = 0; j < 500; j++ ) { // repeat 500 times
43 cols = 0x01; // Assign 0x01(binary 00000001) to the variable, which represents the first
44 column is selected.
45 for (int i = 0; i < 8; i++) { // display 8 column data by scanning
46 matrixRowsVal(smilingFace[i]); // display the data in this column
47 matrixColsVal(~cols); // select this column
48 delay(1); // display them for a period of time
49 cols <<= 1; // shift "cols" 1 bit left to select the next column
50 }
51 }
The second “for” loop is used to display scrolling characters "0 to F", for a total of 17* 8 = 144 columns.
Displaying the 0-8 column, then the 1-9 column, then the 2-10 column...... and so on…128-136 column in
consecutively to achieve the scrolling effect. The display of each frame is repeated a certain number of times
and the more repetitions, the longer the single frame display will be and the slower the scrolling movement.
52 // Display the dynamic patterns of numbers and letters
53 for (int i = 0; i < 128; i++) {
54 for (int k = 0; k < 10; k++) { // repeat image of each frame 10 times.
55 cols = 0x01; // Assign binary 00000001. Means the first column is selected.
56 for (int j = i; j < 8 + i; j++) { // display image of each frame
57 matrixRowsVal(pgm_read_word_near(data + j));// display the data in this column
58 matrixColsVal(~cols); // select this column
59 delay(1); // display them for a period of time
60 matrixRowsVal(0x00); // close the data of this column
61 cols <<= 1; // shift "cols" 1 bit left to select the next column
62 }
63 }
64 }
The amount of pins of ESP32 is limited, so you need to find ways to save pins. If you use ESP32’s GPIO to
control the lattice without using 74HC595, you need 16 pins for the use of LED matrix. In this example, we
use two 74HC595 to drive the LED matrix, requiring only three pins, so that we could save the rest of 13
pins.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 17 Relay & Motor 181

Chapter 17 Relay & Motor


In this chapter, we will learn a kind of special switch module, relay module.

Project 17.1 Relay & Motor

In this project, we will use a push button switch indirectly to control the motor via a relay.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M 9V battery (prepared by yourself) & battery line

Any concerns?  support@freenove.com


182 Chapter 17 Relay & Motor www.freenove.com █

Resistor 10kΩ x2 Resistor 1kΩ x1 Resistor 220Ω x1

NPN transistor x1 Relay x1 Motor x1 Push button x1 LED x1 Diode x1

Component knowledge

Relay
A relay is a safe switch which can use low power circuit to control high power circuit. It consists of
electromagnet and contacts. The electromagnet is controlled by low power circuit and contacts are used in
high power circuit. When the electromagnet is energized, it will attract contacts.
The following is a schematic diagram of a common relay and the feature and circuit symbol of a 5V relay used
in this project:
Diagram Feature: Symbol

Pin 5 and pin 6 are connected to each other inside. When the coil pins 3 and 4 get connected to 5V power
supply, pin 1 will be disconnected to pin 5&6 and pin 2 will be connected to pin 5&6. So pin 1 is called close
end, pin 2 is called open end.
Inductor
The symbol of Inductance is “L” and the unit of inductance is the “Henry” (H). Here is an example of how
this can be encountered: 1H=1000mH, 1mH=1000μH.
An inductor is an energy storage device that converts electrical energy into magnetic energy. Generally, it
consists of winding coil, with a certain amount of inductance. Inductors hinder the change of current passing
through it. When the current passing through it increases, it will attempt to hinder the increasing trend of
current; and when the current passing through it decreases, it will attempt to hinder the decreasing trend of
current. So the current passing through inductor is not transient.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 17 Relay & Motor 183

The reference circuit for relay is as follows. The coil of relays can be equivalent to that of inductors, when the
transistor disconnects power supply of the relay, the current in the coil of the relay can't stop immediately,
causing an impact on power supply. So a parallel diode will get connected to both ends of relay coil pin in
reversing direction, then the current will pass through diode, avoiding the impact on power supply.

Motor
A motor is a device that converts electrical energy into mechanical energy. Motor consists of two parts: stator
and rotor. When motor works, the stationary part is stator, and the rotating part is rotor. Stator is usually the
outer case of motor, and it has terminals to connect to the power. Rotor is usually the shaft of motor, and can
drive other mechanical devices to run. Diagram below is a small DC motor with two pins.

When a motor gets connected to the power supply, it will rotate in one direction. Reverse the polarity of
power supply, then the motor rotates in opposite direction.

+ - - +

Any concerns?  support@freenove.com


184 Chapter 17 Relay & Motor www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Note: the motor circuit uses A large current, about 0.2-0.3A without load.We recommend that you
use a 9V battery to power the extension board.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 17 Relay & Motor 185

Sketch

Use buttons to control the relays and motors.


Sketch_17.1_Control_Motor_by_Relay

Any concerns?  support@freenove.com


186 Chapter 17 Relay & Motor www.freenove.com █

Download the code to ESP32-WROVER. When the DC motor is connected to a power supply, it will rotate in
one direction. If you reverse the polarity of the power supply, the DC motor will rotate in opposite direction.

+ - - +
The following is the program code:
1 int relayPin = 13; // the number of the relay pin
2 int buttonPin = 15; // the number of the push button pin
3
4 int buttonState = HIGH; // Record button state, and initial the state to high level
5 int relayState = LOW; // Record relay state, and initial the state to low level
6 int lastButtonState = HIGH; // Record the button state of last detection
7 long lastChangeTime = 0; // Record the time point for button state change
8
9 void setup() {
10 pinMode(buttonPin, INPUT_PULLUP); // Set push button pin into input mode
11 pinMode(relayPin, OUTPUT); // Set relay pin into output mode
12 digitalWrite(relayPin, relayState); // Set the initial state of relay into "off"
13 }
14 void loop() {
15 int nowButtonState = digitalRead(buttonPin);// Read current state of button pin
16 // If button pin state has changed, record the time point
17 if (nowButtonState ! = lastButtonState) {
18 lastChangeTime = millis();
19 }
20 // If button state changes, and stays stable for a while, then it should have skipped the
21 bounce area
22 if (millis() - lastChangeTime > 10) {
23 if (buttonState ! = nowButtonState) { // Confirm button state has changed
24 buttonState = nowButtonState;
25 if (buttonState == LOW) { // Low level indicates the button is pressed
26 relayState = ! relayState; // Reverse relay state
27 digitalWrite(relayPin, relayState); // Update relay state
28 }
29 }
30 }
31 lastButtonState = nowButtonState; // Save the state of last button
32 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 17 Relay & Motor 187

In Chapter 2, the pressing and releasing of the button will result in mechanical vibrating. If we don't solve this
problem, some unexpected consequences may happen to the procedure. Click here to return to Chapter 2
Button & LED
To eliminate the vibrating, we record the electrical level of the button with nowButtonState, and the time point
for the last change of pin level with lastChangeTime If the state of the button changes, it will record the time
point of the change.
15 int nowButtonState = digitalRead(buttonPin);// Read current state of button pin
16 // If button pin state has changed, record the time point
17 if (nowButtonState ! = lastButtonState) {
18 lastChangeTime = millis();
19 }
If the state of the pin changes and keeps stable for a period of time, it can be considered as a valid key state
change, update the key state variable buttonState, and determine whether the key is pressed or released
according to the current state.
15 // If button state changes, and stays stable for a while, then it should have skipped the
16 bounce area
17 if (millis() - lastChangeTime > 10) {
18 if (buttonState ! = nowButtonState) { // Confirm button state has changed
19 buttonState = nowButtonState;
20 if (buttonState == LOW) { // Low level indicates the button is pressed
21 relayState = ! relayState; // Reverse relay state
22 digitalWrite(relayPin, relayState); // Update relay state
23 }
24 }
25 }
26 lastButtonState = nowButtonState; // Save the state of last button

Any concerns?  support@freenove.com


188 Chapter 17.2 Motor & Driver www.freenove.com █

Chapter 17.2 Motor & Driver


In this chapter, we will learn about DC motors and DC motor drivers and how to control the speed and
direction of a DC motor.

Project 17.2 Control Motor with Potentiometer

Control the direction and speed of the motor with a potentiometer.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M 9V battery (prepared by yourself) & battery line

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 17.2 Motor & Driver 189

Rotary potentiometer x1 Motor x1 L293D

Component knowledge

L293D
L293D is an IC chip (Integrated Circuit Chip) with a 4-channel motor drive. You can drive a unidirectional DC
motor with 4 ports or a bi-directional DC motor with 2 ports or a stepper motor (stepper motors are covered
later in this Tutorial).

Port description of L293D module is as follows:


Pin name Pin number Description
In x 2, 7, 10, 15 Channel x digital signal input pin
Out x 3, 6, 11, 14 Channel x output pin, input high or low level according to In x pin, get
connected to +Vmotor or 0V
Enable1 1 Channel 1 and channel 2 enable pin, high level enable
Enable2 9 Channel 3 and channel 4 enable pin, high level enable
0V 4, 5, 12, 13 Power cathode (GND)
+V 16 Positive electrode (VCC) of power supply, supply voltage 3.0~36V
+Vmotor 8 Positive electrode of load power supply, provide power supply for the Out
pin x, the supply voltage is +V~36V
For more detail, please refer to the datasheet for this IC Chip.

Any concerns?  support@freenove.com


190 Chapter 17.2 Motor & Driver www.freenove.com █

When using L293D to drive DC motor, there are usually two connection options.
The following connection option uses one channel of the L239D, which can control motor speed through
the PWM, However the motor then can only rotate in one direction.

The following connection uses two channels of the L239D: one channel outputs the PWM wave, and the
other channel connects to GND, therefore you can control the speed of the motor. When these two channel
signals are exchanged, not only controls the speed of motor, but also can control the steering of the motor.

GND

GND

In practical use the motor is usually connected to channel 1 and 2 by outputting different levels to in1 and
in2 to control the rotational direction of the motor, and output to the PWM wave to Enable1 port to control
the motor’s rotational speed. If the motor is connected to channel 3 and 4 by outputting different levels to
in3 and in4 to control the motor's rotation direction, and output to the PWM wave to Enable2 pin to control
the motor’s rotational speed.

Circuit

Use caution when connecting this circuit, because the DC motor is a high-power component, do not use the
power provided by the ESP32 to power the motor directly, which may cause permanent damage to your
ESP32! The logic circuit can be powered by the ESP32 power or an external power supply, which should share
a common ground with ESP32.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 17.2 Motor & Driver 191

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Note: the motor circuit uses A large current, about 0.2-0.3A without load.We recommend that you
use a 9V battery to power the extension board.

Any concerns?  support@freenove.com


192 Chapter 17.2 Motor & Driver www.freenove.com █

Sketch

Sketch_17.2_Control_Motor_by_L293D

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 17.2 Motor & Driver 193

Download code to ESP32-WROVER, rotate the potentiometer in one direction and the motor speeds up
slowly in one direction. And then rotate the potentiometer in the other direction and the motor will slow down
to stop. And then rotate it in an inverse direction to accelerate the motor.

less than 2048

2048

greater than 2048

Any concerns?  support@freenove.com


194 Chapter 17.2 Motor & Driver www.freenove.com █

The following is the sketch:


1 int in1Pin = 12; // Define L293D channel 1 pin
2 int in2Pin = 14; // Define L293D channel 2 pin
3 int enable1Pin = 13; // Define L293D enable 1 pin
4 int channel = 0;
5
6 boolean rotationDir; // Define a variable to save the motor's rotation direction
7 int rotationSpeed; // Define a variable to save the motor rotation speed
8
9 void setup() {
10 // Initialize the pin into an output mode:
11 pinMode(in1Pin, OUTPUT);
12 pinMode(in2Pin, OUTPUT);
13 pinMode(enable1Pin, OUTPUT);
14
15 ledcSetup(channel,1000,11); //Set PWM to 11 bits, range is 0-2047
16 ledcAttachPin(enable1Pin,channel);
17 }
18
19 void loop() {
20 int potenVal = analogRead(A0);// Convert the voltage of rotary potentiometer into digital
21 rotationSpeed = potenVal - 2048;
22 if (potenVal > 2048)
23 rotationDir = true;
24 else
25 rotationDir = false;
26 // Calculate the motor speed
27 rotationSpeed = abs(potenVal - 2048);
28 //Control the steering and speed of the motor
29 driveMotor(rotationDir, constrain(rotationSpeed,0,2048));
30 }
31
32 void driveMotor(boolean dir, int spd) {
33 if (dir) {// Control motor rotation direction
34 digitalWrite(in1Pin, HIGH);
35 digitalWrite(in2Pin, LOW);
36 }
37 else {
38 digitalWrite(in1Pin, LOW);
39 digitalWrite(in2Pin, HIGH);
40 }
41 ledcWrite(channel, spd); // Control motor rotation speed
42 }
The ADC of ESP32 has a 12-bit accuracy, corresponding to a range from 0 to 4095. In this program, set the

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 17.2 Motor & Driver 195

number 2048 as the midpoint. If the value of ADC is less than 2048, make the motor rotate in one direction.
If the value of ADC is greater than 2048, make the motor rotate in the other direction. Subtract 2048 from the
ADC value and take the absolute value and use this result as the speed of the motor.
20 int potenVal = analogRead(A0);// Convert the voltage of rotary potentiometer into digital
21 rotationSpeed = potenVal - 2048;
22 if (potenVal > 2048)
23 rotationDir = true;
24 else
25 rotationDir = false;
26 // Calculate the motor speed
27 rotationSpeed = abs(potenVal - 2048);
28 //Control the steering and speed of the motor
29 driveMotor(rotationDir, constrain(rotationSpeed,0,2048));
30 }
Set the accuracy of the PWM to 11 bits and range from 0 to 2047 to control the rotation speed of the motor.
15 ledcSetup(channel,1000,11); //Set PWM to 11 bits, range is 0-2047
Function driveMotor is used to control the rotation direction and speed of the motor. The dir represents
direction while spd refers to speed.
34 void driveMotor(boolean dir, int spd) {
35 // Control motor rotation direction
36 if (rotationDir) {
37 digitalWrite(in1Pin, HIGH);
38 digitalWrite(in2Pin, LOW);
39 }
40 else {
41 digitalWrite(in1Pin, LOW);
42 digitalWrite(in2Pin, HIGH);
43 }
44 // Control motor rotation speed
45 ledcWrite(channel, spd);
46 }

Any concerns?  support@freenove.com


196 Chapter 18 Servo www.freenove.com █

Chapter 18 Servo
Previously, we learned how to control the speed and rotational direction of a motor. In this chapter, we will
learn about servos which are a rotary actuator type motor that can be controlled to rotate to specific angles.

Project 18.1 Servo Sweep

First, we need to learn how to make a servo rotate.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Servo x1 Jumper M/M x3

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 18 Servo 197

Component knowledge

Servo
Servo is a compact package which consists of a DC motor, a set of reduction gears to provide torque, a sensor
and control circuit board. Most servos only have a 180-degree range of motion via their “horn”. Servos can
output higher torque than a simple DC motor alone and they are widely used to control motion in model cars,
model airplanes, robots, etc. Servos have three wire leads which usually terminate to a male or female 3-pin
plug. Two leads are for electric power: positive (2-VCC, Red wire), negative (3-GND, Brown wire), and the
signal line (1-Signal, Orange wire), as represented in the Servo provided in your Kit.

We will use a 50Hz PWM signal with a duty cycle in a certain range to drive the Servo. The lasting time of
0.5ms-2.5ms of PWM single cycle high level corresponds to the servo angle 0 degrees - 180 degree linearly.
Part of the corresponding values are as follows:
High level time Servo angle
0.5ms 0 degree
1ms 45 degree
1.5ms 0 degree
2ms 45 degree
2.5ms 180 degree

When you change the servo signal value, the servo will rotate to the designated angle.

Any concerns?  support@freenove.com


198 Chapter 18 Servo www.freenove.com █

Circuit

Use caution when supplying power to the servo, it should be 5V. Make sure you do not make any errors when
connecting the servo to the power supply.
Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 18 Servo 199

Sketch

How to install the library


If you haven't installed it yet, please do so before learning. The steps to add third-party Libraries are as follows:
open arduino->Sketch->Include library-> Manage libraries. Enter " ESP32Servo" in the search bar and
select "ESP32Servo" for installation. Refer to the following operations:

Use the ESP32Servo library to control the servo motor and let the servo motor rotate back and forth.

Any concerns?  support@freenove.com


200 Chapter 18 Servo www.freenove.com █

Sketch_18.1_Servo_Sweep

Compile and upload the code to ESP32-WROVER, the servo will rotate from 0 degrees to 180 degrees and
then reverse the direction to make it rotate from 180 degrees to 0 degrees and repeat these actions in an
endless loop.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 18 Servo 201

The following is the program code:


1 #include <ESP32Servo.h>
2
3 Servo myservo; // create servo object to control a servo
4 int posVal = 0; // variable to store the servo position
5 int servoPin = 15; // Servo motor pin
6 void setup() {
7 myservo.setPeriodHertz(50); // standard 50 hz servo
8 myservo.attach(servoPin, 500, 2500); // attaches the servo on servoPin to the servo
object
9 }
10 void loop() {
11 for (posVal = 0; posVal <= 180; posVal += 1) { // goes from 0 degrees to 180 degrees
12 // in steps of 1 degree
13 myservo.write(posVal); // tell servo to go to position in variable 'pos'
14 delay(15); // waits 15ms for the servo to reach the position
15 }
16 for (posVal = 180; posVal >= 0; posVal -= 1) { // goes from 180 degrees to 0 degrees
17 myservo.write(posVal); // tell servo to go to position in variable 'pos'
18 delay(15); // waits 15ms for the servo to reach the position
19 }
20 }
Servo uses the ESP32Servo library, like the following reference to ESP32Servo library:
1 #include <ESP32Servo.h>
ESP32Servo library provides the ESP32Servo class that controls it. ESP32Servo class must be instantiated before
using:
3 Servo myservo; // create servo object to control a servo
Set the control servo motor pin, the time range of high level.
8 myservo.attach(servoPin,500,2500);
After initializing the servo, you can control the servo to rotate to a specific angle:
17 myservo.write(posVal);
Reference
class Servo
Servo class must be instantiated when used, that is, define an object of Servo type, for example:
Servo myservo;
The function commonly used in the servo class is as follows:
setPeriodHertz(data): Set the frequency of the servo motor.
attach(pin,low,high): Initialize the servo,
pin: the port connected to servo signal line.
low: set the time of high level corresponding to 0 degree.
high: set the time of high level corresponding to 180 degrees.
write(angle): Control servo to rotate to the specified angle.

Any concerns?  support@freenove.com


202 Chapter 18 Servo www.freenove.com █

Project 18.2 Servo Knop

Use a potentiometer to control the servo motor to rotate at any angle.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Servo x1 Jumper M/M x6 Rotary potentiometer x1

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 18 Servo 203

Circuit

Use caution when supplying power to the servo, it should be 5V. Make sure you do not make any errors when
connecting the servo to the power supply.
Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


204 Chapter 18 Servo www.freenove.com █

Sketch

Sketch_18.2_Servo_Sweep

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 18 Servo 205

Compile and upload the code to ESP32-WROVER, twist the potentiometer back and forth, and the servo
motor rotates accordingly.

The following is the program code:


1 #include <ESP32Servo.h>
2 #define ADC_Max 4095 // This is the default ADC max value on the ESP32 (12 bits ADC width);
3
4 Servo myservo; // create servo object to control a servo
5
6 int servoPin = 15; // GPIO pin used to connect the servo control (digital out)
7 int potPin = 34; // GPIO pin used to connect the potentiometer (analog in)
8 int potVal; //variable to read the value from the analog pin
9
10 void setup()
11 {
12 myservo.setPeriodHertz(50);// Standard 50hz servo
13 myservo.attach(servoPin, 500, 2500); // attaches the servo on servoPin to the servo object
14 Serial.begin(115200);
15 }
16
17 void loop() {
18 potVal = analogRead(potPin); // read the value of the potentiometer (value
19 between 0 and 1023)
20 Serial.printf("potVal_1: %d\t",potVal);
21 potVal = map(potVal, 0, ADC_Max, 0, 180);// scale it to use it with the servo (value between
0 and 180)
22 myservo.write(potVal); // set the servo position according to the scaled
value
23 Serial.printf("potVal_2: %d\n",potVal);
24 delay(15); // wait for the servo to get there
25 }
In this experiment, we obtain the ADC value of the potentiometer and store it in potVal. Use map function
to convert it into corresponding angle value and we can control the motor to rotate to a specified angle,
and print the value via serial.

Any concerns?  support@freenove.com


206 Chapter 19 Stepper Motor www.freenove.com █

Chapter 19 Stepper Motor


In this project, we will learn how to drive a stepper motor, and understand its working principle.

Project 19.1 Stepper Motor

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Stepper Motor x1 ULN2003 Stepper Motor Driver x1 Jumper F/M x6

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 19 Stepper Motor 207

Component knowledge

Stepper Motor
Stepper motors are an open-loop control device, which converts an electronic pulse signal into angular
displacement or linear displacement. In a non-overload condition, the speed of the motor and the location
of the stops depends only on the pulse signal frequency and number of pulses and is not affected by changes
in load as with a DC motor. A small four-phase deceleration stepper motor is shown here:

The electronic schematic diagram of a four-phase stepper motor is shown below:

The outside case or housing of the stepper motor is the stator and inside the stator is the rotor. There are a
specific number of individual coils, usually an integer multiple of the number of phases the motor has, when
the stator is powered ON, an electromagnetic field will be formed to attract a corresponding convex
diagonal groove or indentation in the rotor’s surface. The rotor is usually made of iron or a permanent
magnet. Therefore, the stepper motor can be driven by powering the coils on the stator in an ordered
sequence (producing a series of “steps” or stepped movements).

Any concerns?  support@freenove.com


208 Chapter 19 Stepper Motor www.freenove.com █

A common driving process is as follows:

In the course above, the stepper motor rotates a certain angle once, which is called a step. By controlling the
number of rotation steps, you can control the stepper motor rotation angle. By controlling the time between
two steps, you can control the stepper motor rotation speed. When rotating clockwise, the order of coil
powered on is: ABCDA…… . And the rotor will rotate in accordance with the order, step by step
down, called four steps four pats. If the coils is powered on in the reverse order, DCBAD… , the
rotor will rotate in anti-clockwise direction.

There are other methods to control stepper motors, such as: connect A phase, then connect A B phase, the
stator will be located in the center of A B, which is called a half-step. This method can improve the stability of
the stepper motor and reduces noise. The sequence of powering the coils looks like this: A ABB BCC
CDDDAA……, the rotor will rotate in accordance to this sequence at a half-step at a time, called
four-steps, eight-part. Conversely, if the coils are powered ON in the reverse order the stepper motor will
rotate in the opposite direction.

The stator in the stepper motor we have supplied has 32 magnetic poles. Therefore, to complete one full
revolution requires 32 full steps. The rotor (or output shaft) of the stepper motor is connected to a speed
reduction set of gears and the reduction ratio is 1:64. Therefore, the final output shaft (exiting the stepper
motor’s housing) requires 32 X 64 = 2048 steps to make one full revolution.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 19 Stepper Motor 209

ULN2003 Stepper motor driver


A ULN2003 stepper motor driver is used to convert weak signals into more powerful control signals in order
to drive the stepper motor. In the illustration below, the input signal IN1-IN4 corresponds to the output signal
A-D, and 4 LEDs are integrated into the board to indicate the state of these signals. The PWR interface can
be used as a power supply for the stepper motor. By default, PWR and VCC are connected.

Any concerns?  support@freenove.com


210 Chapter 19 Stepper Motor www.freenove.com █

Circuit

When building the circuit, note that rated voltage of the stepper motor is 5V, and we need to use the
breadboard power supply independently. Additionally, the breadboard power supply needs to share Ground
with ESP32.
Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 19 Stepper Motor 211

Sketch

This code uses the four-step, four-part mode to drive the stepper motor in the clockwise and anticlockwise
directions.
Sketch_19.1_Drive_Stepper_Motor

Any concerns?  support@freenove.com


212 Chapter 19 Stepper Motor www.freenove.com █

Compile and upload the code to the ESP32-WROVER, the stepper motor will rotate 360° clockwise and stop
for 1s, and then rotate 360° anticlockwise and stop for 1s. And it will repeat this action in an endless loop.

The following is the program code:


1 // Connect the port of the stepper motor driver
2 int outPorts[] = {14, 27, 26, 25};
3
4 void setup() {
5 // set pins to output
6 for (int i = 0; i < 4; i++) {
7 pinMode(outPorts[i], OUTPUT);
8 }
9 }
10
11 void loop(){
12 // Rotate a full turn
13 moveSteps(true, 32 * 64, 3);
14 delay(1000);
15 // Rotate a full turn towards another direction
16 moveSteps(false, 32 * 64, 3);
17 delay(1000);
18 }
19
20 //Suggestion: the motor turns precisely when the ms range is between 3 and 20
21 void moveSteps(bool dir, int steps, byte ms) {
22 for (unsigned long i = 0; i < steps; i++) {
23 moveOneStep(dir); // Rotate a step
24 delay(constrain(ms,3,20)); // Control the speed
25 }
26 }
27
28 void moveOneStep(bool dir) {
29 // Define a variable, use four low bit to indicate the state of port
30 static byte out = 0x01;
31 // Decide the shift direction according to the rotation direction
32 if (dir) { // ring shift left
33 out ! = 0x08 ? out = out << 1 : out = 0x01;
34 }
35 else { // ring shift right

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 19 Stepper Motor 213

36 out ! = 0x01 ? out = out >> 1 : out = 0x08;


37 }
38 // Output singal to each port
39 for (int i = 0; i < 4; i++) {
40 digitalWrite(outPorts[i], (out & (0x01 << i)) ? HIGH : LOW);
41 }
42 }
43
44 void moveAround(bool dir, int turns, byte ms){
45 for(int i=0;i<turns;i++)
46 moveSteps(dir,32*64,ms);
47 }
48 void moveAngle(bool dir, int angle, byte ms){
49 moveSteps(dir,(angle*32*64/360),ms);
50 }
In this project, we define four pins to drive stepper motor.
1 // Connect the port of the stepper motor driver
2 int outPorts[] = {14, 27, 26, 25};
moveOneStep Function is used to drive the stepper motor to rotate clockwise or counterclockwise. The
parameter "dir" indicates the direction of rotation. If "dir" returns true, the stepper motor rotates clockwise,
otherwise the stepper motor rotates counterclockwise.
28 void moveOneStep(bool dir) {
… …
42 }
Define a static byte variable, calculate the value of the variable according to the rotation direction of the
motor, and use the keyword static to save the position status of the previous step of the stepper motor. Use
the four low bits of the variable to control the output state of the four pins.
29 // Define a variable, use four low bit to indicate the state of port
30 static byte out = 0x01;
31 // Decide the shift direction according to the rotation direction
32 if (dir) { // ring shift left
33 out ! = 0x08 ? out = out << 1 : out = 0x01;
34 }
35 else { // ring shift right
36 out ! = 0x01 ? out = out >> 1 : out = 0x08;
37 }
Make the pin to output corresponding level based on the value of the variable.
38 // Output singal to each port
39 for (int i = 0; i < 4; i++) {
40 digitalWrite(outPorts[i], (out & (0x01 << i)) ? HIGH : LOW);
41 }

Any concerns?  support@freenove.com


214 Chapter 19 Stepper Motor www.freenove.com █

The moveSteps function can control the direction of the stepper motor, the number of rotation steps, and the
speed of rotation. According to the previous knowledge, the stepper motor needs 32*64 steps for one
revolution. The speed of rotation is determined by the parameter ms. The larger the ms is, the slower the
rotation speed is. There is a range for the speed of the motor, which is determined by the motor itself and
according to our test, the value of ms is limited to 3-20.
20 //Suggestion: the motor turns precisely when the ms range is between 3 and 20
21 void moveSteps(bool dir,int steps, byte ms) {
22 for (unsigned long i = 0; i < steps; i++) {
23 moveOneStep(dir); // Rotate a step
24 delay(constrain(ms,3,20)); // Control the speed
25 }
26 }
The function moveTurns() is a further package of moveSteps(), which is used to control the stepper motor to
rotate a specified number of turns. The parameter "turns" represents the number of turns that need to be
rotated.
44 void moveAround(bool dir, int turns, byte ms){
45 for(int i=0;i<turns;i++)
46 moveSteps(dir,32*64,ms);
47 }
The function moveAround () is a further package of moveSteps (), which is used to control the stepper motor
to rotate by a specified angle, and the parameter "angle" represents the angle to be rotated.
48 void moveAngle(bool dir, int angle, byte ms){
49 moveSteps(dir,(angle*32*64/360),ms);
50 }
In the loop function, call the moveSteps function to loop the stepper motor: rotate clockwise one turn and
stop for 1s, then rotate counterclockwise one turn and stop for 1s.
11 void loop(){
12 // Rotate a full turn
13 moveSteps(true, 32 * 64, 3);
14 delay(1000);
15 // Rotate a full turn towards another direction
16 moveSteps(false, 32 * 64, 3);
17 delay(1000);
18 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 20 LCD1602 215

Chapter 20 LCD1602
In this chapter, we will learn about the LCD1602 Display Screen

Project 20.1 LCD1602

In this section we learn how to use LCD1602 to display something.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

LCD1602 Module x1 Jumper F/M x4

Any concerns?  support@freenove.com


216 Chapter 20 LCD1602 www.freenove.com █

Component knowledge

I2C communication
I2C (Inter-Integrated Circuit) is a two-wire serial communication mode, which can be used for the connection
of micro controllers and their peripheral equipment. Devices using I2C communication must be connected to
the serial data (SDA) line, and serial clock (SCL) line (called I2C bus). Each device has a unique address and
can be used as a transmitter or receiver to communicate with devices connected to the bus.

LCD1602 communication'
The LCD1602 display screen can display 2 lines of characters in 16 columns. It is capable of displaying numbers,
letters, symbols, ASCII code and so on. As shown below is a monochrome LCD1602 display screen along with
its circuit pin diagram

I2C LCD1602 display screen integrates a I2C interface, which connects the serial-input & parallel-output
module to the LCD1602 display screen. This allows us to only use 4 lines to the operate the LCD1602.

The serial-to-parallel IC chip used in this module is PCF8574T (PCF8574AT), and its default I2C address is
0x27(0x3F). You can also view the ESP32 bus on your I2C device address through command "i2cdetect -y 1".

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 20 LCD1602 217

Below is the PCF8574 pin schematic diagram and the block pin diagram:
PCF8574 chip pin diagram: PCF8574 module pin diagram

PCF8574 module pin and LCD1602 pin are corresponding to each other and connected with each other:

So we only need 4 pins to control the 16 pins of the LCD1602 display screen through the I2C interface.
In this project, we will use the I2C LCD1602 to display some static characters and dynamic variables.

Any concerns?  support@freenove.com


218 Chapter 20 LCD1602 www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 20 LCD1602 219

Sketch

How to install the library


We use the third party library LiquidCrystal I2C. If you haven't installed it yet, please do so before learning.
The steps to add third-party Libraries are as follows: open arduino->Sketch->Include library-> Manage
libraries. Enter " LiquidCrystal I2C" in the search bar and select " LiquidCrystal I2C " for installation.

Use I2C LCD 1602 to display characters and variables.

Any concerns?  support@freenove.com


220 Chapter 20 LCD1602 www.freenove.com █

Sketch_20.1_Display_the_string_on_LCD1602

Compile and upload the code to ESP32-WROVER and the LCD1602 displays characters.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 20 LCD1602 221

If you cannot see anything on the display or the display is not clear, try rotating the white knob on back of
LCD1602 slowly, which adjusts the contrast, until the screen can display clearly.

The following is the program code:


1 #include <LiquidCrystal_I2C.h>
2 #include <Wire.h>
3
4 #define SDA 13 //Define SDA pins
5 #define SCL 14 //Define SCL pins
6
7 /*
8 * note: If lcd1602 uses PCF8574T, IIC's address is 0x27,
9 * or lcd1602 uses PCF8574AT, IIC's address is 0x3F.
10 */
11 LiquidCrystal_I2C lcd(0x27,16,2);
12
13 void setup() {
14 Wire.begin(SDA, SCL); // attach the IIC pin
15 lcd.init(); // LCD driver initialization
16 lcd.backlight(); // Turn on the backlight
17 lcd.setCursor(0,0); // Move the cursor to row 0, column 0
18 lcd.print("hello, world! "); // The print content is displayed on the LCD
19 }
20
21 void loop() {
22 lcd.setCursor(0,1); // Move the cursor to row 1, column 0
23 lcd.print("Counter:"); // The count is displayed every second
24 lcd.print(millis() / 1000);
25 delay(1000);
26 }

Any concerns?  support@freenove.com


222 Chapter 20 LCD1602 www.freenove.com █

Include header file of Liquid Crystal Display (LCD)1602 and I2C.


1 #include <LiquidCrystal_I2C.h>
2 #include <Wire.h>
Instantiate the I2C LCD1602 screen. It should be noted here that if your LCD driver chip uses PCF8574T, set
the I2C address to 0x27, and if uses PCF8574AT, set the I2C address to 0x3F.
11 LiquidCrystal_I2C lcd(0x27,16,2);
Initialize I2C and set its pins as 13,14. And then initialize LCD1602 and turn on the backlight of LCD.
14 Wire.begin(SDA, SCL); // attach the IIC pin
15 lcd.init(); // LCD driver initialization
16 lcd.backlight(); // Turn on the backlight
Move the cursor to the first row, first column, and then display the character.
17 lcd.setCursor(0,0); // Move the cursor to row 0, column 0
18 lcd.print("hello, world! "); // The print content is displayed on the LCD
Print the number on the second line of LCD1602.
12 void loop() {
13 //set the cursor to column 0, line 1
14 //(note:parameter "0" is the first columns,
15 //parameter "1" is the second row, since counting begins with 0)
16 lcd.setCursor(0, 1);//0 stand for column, 1 stand for row
17 // print the number of seconds since reset:
18 lcd.print("Counter:");
19 lcd.print(millis() / 1000);
20 }
Reference
class LiquidCrystal
The LiquidCrystal class can manipulate common LCD screens. The first step is defining an object of
LiquidCrystal, for example:
LiquidCrystal_I2C lcd(0x27,16,2);
Instantiate the Lcd1602 and set the I2C address to 0x27, with 16 columns per row and 2 rows
per column.
init();
Initializes the Lcd1602’s device
backlight();
Turn on Lcd1602’s backlight.
setCursor(column,row);
Sets the screen‘s column and row.
column:The range is 0 to 15.
row:The range is 0 to 1.
print(String);
Print the character string on Lcd1602

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 21 Ultrasonic Ranging 223

Chapter 21 Ultrasonic Ranging


In this chapter, we learn a module which use ultrasonic to measure distance, HC SR04.

Project 21.1 Ultrasonic Ranging

In this project, we use ultrasonic ranging module to measure distance, and print out the data in the terminal.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper F/M x4 HC SR04 x1

Any concerns?  support@freenove.com


224 Chapter 21 Ultrasonic Ranging www.freenove.com █

Component Knowledge

The ultrasonic ranging module uses the principle that ultrasonic waves will be sent back when encounter
obstacles. We can measure the distance by counting the time interval between sending and receiving of the
ultrasonic waves, and the time difference is the total time of the ultrasonic wave’s journey from being
transmitted to being received. Because the speed of sound in air is a constant, about v=340m/s, we can
calculate the distance between the ultrasonic ranging module and the obstacle: s=vt/2.

2S=V·t.
The HC-SR04 ultrasonic ranging module integrates both an ultrasonic transmitter and a receiver. The
transmitter is used to convert electrical signals (electrical energy) into high frequency (beyond human hearing)
sound waves (mechanical energy) and the function of the receiver is opposite of this. The picture and the
diagram of the HC SR04 ultrasonic ranging module are shown below:

Pin description:
Pin Description
VCC power supply pin
Trig trigger pin
Echo Echo pin
GND GND
Technical specs:
Working voltage: 5V Working current: 12mA
Minimum measured distance: 2cm Maximum measured distance: 200cm
Instructions for use: output a high-level pulse in Trig pin lasting for least 10us, the module begins to transmit
ultrasonic waves. At the same time, the Echo pin is pulled up. When the module receives the returned
ultrasonic waves from encountering an obstacle, the Echo pin will be pulled down. The duration of high level
in the Echo pin is the total time of the ultrasonic wave from transmitting to receiving, s=vt/2.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 21 Ultrasonic Ranging 225

Circuit

Note that the voltage of ultrasonic module is 5V in the circuit.


Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


226 Chapter 21 Ultrasonic Ranging www.freenove.com █

Sketch

Sketch_21.1_Ultrasonic_Ranging

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 21 Ultrasonic Ranging 227

Download the code to ESP32-WROVER, open the serial port monitor, set the baud rate to 115200 and you
can use it to measure the distance between the ultrasonic module and the object. As shown in the following
figure:

The following is the program code:


1 #define trigPin 13 // define trigPin
2 #define echoPin 14 // define echoPin.
3 #define MAX_DISTANCE 700 // Maximum sensor distance is rated at 400-500cm.
4 //timeOut= 2*MAX_DISTANCE /100 /340 *1000000 = MAX_DISTANCE*58.8
5 float timeOut = MAX_DISTANCE * 60;
6 int soundVelocity = 340; // define sound speed=340m/s
7
8 void setup() {
9 pinMode(trigPin,OUTPUT);// set trigPin to output mode
10 pinMode(echoPin,INPUT); // set echoPin to input mode
11 Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
12 }
13
14 void loop() {
15 delay(100); // Wait 100ms between pings (about 20 pings/sec).
16 Serial.printf("Distance: ");
17 Serial.print(getSonar()); // Send ping, get distance in cm and print result
18 Serial.println("cm");
19 }
20
21 float getSonar() {
22 unsigned long pingTime;
23 float distance;
24 // make trigPin output high level lasting for 10us to trigger HC_SR04

Any concerns?  support@freenove.com


228 Chapter 21 Ultrasonic Ranging www.freenove.com █

25 digitalWrite(trigPin, HIGH);
26 delayMicroseconds(10);
27 digitalWrite(trigPin, LOW);
28 // Wait HC-SR04 returning to the high level and measure out this waiting time
29 pingTime = pulseIn(echoPin, HIGH, timeOut);
30 // calculate the distance according to the time
31 distance = (float)pingTime * soundVelocity / 2 / 10000;
32 return distance; // return the distance value
33 }
First, define the pins and the maximum measurement distance.
1 #define trigPin 13 // define trigPin
2 #define echoPin 14 // define echoPin.
3 #define MAX_DISTANCE 700 //define the maximum measured distance
If the module does not return high level, we cannot wait for this forever, so we need to calculate the time
period for the maximum distance, that is, time Out. timeOut= 2*MAX_DISTANCE/100/340*1000000. The
result of the constant part in this formula is approximately 58.8.
5 float timeOut = MAX_DISTANCE * 60;
Subfunction getSonar () function is used to start the ultrasonic module to begin measuring, and return the
measured distance in cm units. In this function, first let trigPin send 10us high level to start the ultrasonic
module. Then use pulseIn () to read the ultrasonic module and return the duration time of high level. Finally,
the measured distance according to the time is calculated.
21 float getSonar() {
22 unsigned long pingTime;
23 float distance;
24 // make trigPin output high level lasting for 10μs to triger HC_SR04?
25 digitalWrite(trigPin, HIGH);
26 delayMicroseconds(10);
27 digitalWrite(trigPin, LOW);
28 // Wait HC-SR04 returning to the high level and measure out this waitting time
29 pingTime = pulseIn(echoPin, HIGH, timeOut);
30 // calculate the distance according to the time
31 distance = (float)pingTime * soundVelocity / 2 / 10000;
32 return distance; // return the distance value
33 }
Lastly, in loop() function, get the measurement distance and display it continually.
14 void loop() {
15 delay(100); // Wait 100ms between pings (about 20 pings/sec).
16 Serial.printf("Distance: ");
17 Serial.print(getSonar()); // Send ping, get distance in cm and print result
18 Serial.println("cm");
19 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 21 Ultrasonic Ranging 229

About function pulseIn():


int pulseIn(int pin, int level, int timeout);
pin: the number of the Arduino pin on which you want to read the pulse. Allowed data types: int.
value: type of pulse to read: either HIGH or LOW. Allowed data types: int.
timeout (optional): the number of microseconds to wait for the pulse to start; default is one second.

Any concerns?  support@freenove.com


230 Chapter 21 Ultrasonic Ranging www.freenove.com █

Project 21.2 Ultrasonic Ranging

Component List and Circuit

Component List and Circuit are the same as the previous section.

Sketch

How to install the library


We use the third party library UltrasonicSensor. If you haven't installed it yet, please do so before learning.
The steps to add third-party Libraries are as follows: open arduino->Sketch->Include library-> Manage
libraries. Enter "UltrasonicSensor" in the search bar and select "UltrasonicSensor" for installation.
Refer to the following operations:

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 21 Ultrasonic Ranging 231

Sketch_21.2_Ultrasonic_Ranging

Download the code to ESP32-WROVER, open the serial port monitor, set the baud rate to 115200. Use the
ultrasonic module to measure distance. As shown in the following figure:

Any concerns?  support@freenove.com


232 Chapter 21 Ultrasonic Ranging www.freenove.com █

The following is the program code:


1 #include <UltrasonicSensor.h>
2 //Attach the trigger and echo pins to pins 13 and 14 of esp32
3 UltrasonicSensor ultrasonic(13, 14);
4
5 void setup() {
6 Serial.begin(115200);
7 //set the speed of sound propagation according to the temperature to reduce errors
8 int temperature = 22; //Setting ambient temperature
9 ultrasonic.setTemperature(temperature);
10 }
11
12 void loop() {
13 int distance = ultrasonic.distanceInCentimeters();
14 Serial.printf("Distance: %dcm\n",distance);
15 delay(300);
16 }
First, add UltrasonicSensor library.
1 #include <UltrasonicSensor.h>
Define an ultrasonic object and associate the pins.
3 UltrasonicSensor ultrasonic(13, 14);
Set the ambient temperature to make the module measure more accurately.
9 ultrasonic.setTemperature(temperature);
Use the distanceInCentimeters function to get the distance measured by the ultrasound and print it out
through the serial port.
16 void loop() {
17 int distance = ultrasonic.distanceInCentimeters();
18 Serial.printf("Distance: %dcm\n",distance);
19 delay(300);
20 }
Reference
class UltrasonicSensor
class UltrasonicSensor must be instantiated when used, that is, define an object of Servo type, for example:
UltrasonicSensor ultrasonic(13, 14);
setTemperature(value): The speed of sound propagation is different at different temperatures. In
order to get more accurate data, this function needs to be called. value is the temperature value of the
current environment.
distanceInCentimeters(): The ultrasonic distance acquisition function returns the value in centimeters.
distanceInMillimeters():The ultrasonic distance acquisition function returns the value in millimeter.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 22 Matrix Keypad 233

Chapter 22 Matrix Keypad


Earlier we learned about a single push button switch. In this chapter, we will learn about matrix keyboards,
which integrates a number of push button switches as keys for the purposes of input.

Project 22.1 Matrix Keypad

In this project, we will attempt to get every key code on the matrix keypad to work.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M x8 4x4 Matrix Keypad x1

Any concerns?  support@freenove.com


234 Chapter 22 Matrix Keypad www.freenove.com █

Component knowledge

4x4 Matrix Keypad


A keypad matrix is a device that integrates a number of keys in one package. As is shown below, a 4x4 keypad
matrix integrates 16 keys:

Similar to the integration of a LED matrix, the 4x4 keypad matrix has each row of keys connected with one pin
and this is the same for the columns. Such efficient connections reduce the number of processor ports
required. The internal circuit of the Keypad Matrix is shown below.

The usage is similar to the LED matrix, using a row or column scanning method to detect the state of each
key’s position by column and row. Take column scanning method as an example, send low level to the first 1
column (Pin1), detect level state of row 5, 6, 7, 8 to judge whether the key A, B, C, D are pressed. Then send
low level to column 2, 3, 4 in turn to detect whether other keys are pressed. Therefore, you can get the state
of all of the keys.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 22 Matrix Keypad 235

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


236 Chapter 22 Matrix Keypad www.freenove.com █

Sketch

This code is used to obtain all key codes of the 4x4 matrix keypad, when one of the keys is pressed, the key
code will be printed out via serial port.

How to install the library


We use the third party library Keypad. If you haven't installed it yet, please do so before learning. The steps
to add third-party Libraries are as follows: open arduino->Sketch->Include library-> Manage libraries.
Enter " Keypad" in the search bar and select " Keypad " for installation.
Refer to the following operations:

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 22 Matrix Keypad 237

Sketch_22.1_Get_Input_Characters

Any concerns?  support@freenove.com


238 Chapter 22 Matrix Keypad www.freenove.com █

Download the code to ESP32-WROVER, open the serial port monitor, set the baud rate to 115200, press the
keyboard, the value of the pressed keys will be printed out via the serial port. As shown in the following
figure:

The following is the program code:


1 #include <Keypad.h>
2 // define the symbols on the buttons of the keypad
3 char keys[4][4] = {
4 {'1', '2', '3', 'A'},
5 {'4', '5', '6', 'B'},
6 {'7', '8', '9', 'C'},
7 {'*', '0', '#', 'D'}
8 };
9 byte rowPins[4] = {14, 27, 26, 25}; // connect to the row pinouts of the keypad
10 byte colPins[4] = {13, 21, 22, 23}; // connect to the column pinouts of the keypad
11
12 // initialize an instance of class NewKeypad
13 Keypad myKeypad = Keypad(makeKeymap(keys), rowPins, colPins, 4, 4);
14
15 void setup() {
16 Serial.begin(115200); // Initialize the serial port and set the baud rate to 115200
17 Serial.println("ESP32 is ready! "); // Print the string "ESP32 is ready! "
18 }
19
20 void loop() {
21 // Get the character input
22 char keyPressed = myKeypad.getKey();
23 // If there is a character input, sent it to the serial port
24 if (keyPressed) {
25 Serial.println(keyPressed);
26 }
27 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 22 Matrix Keypad 239

First, add header file, define 4*4 matrix keyboard key value and the matrix keyboard pin.
1 #include <Keypad.h>
2 // define the symbols on the buttons of the keypad
3 char keys[4][4] = {
4 {'1', '2', '3', 'A'},
5 {'4', '5', '6', 'B'},
6 {'7', '8', '9', 'C'},
7 {'*', '0', '#', 'D'}
8 };
9 byte rowPins[4] = {14, 27, 26, 25}; // connect to the row pinouts of the keypad
10 byte colPins[4] = {13, 21, 22, 23}; // connect to the column pinouts of the keypad
Second, define a matrix keyboard object and associate the keys and pins with it.
13 Keypad myKeypad = Keypad(makeKeymap(keys), rowPins, colPins, 4, 4);
Finally, get the key value and print it out via the serial port.
20 void loop() {
21 // Get the character input
22 char keyPressed = myKeypad.getKey();
23 // If there is a character input, sent it to the serial port
24 if (keyPressed) {
25 Serial.println(keyPressed);
26 }
27 }
Reference
class Keypad You need to add the library each time you use the Keypad.
Keypad(char *userKeymap, byte *row, byte *col, byte numRows, byte numCols);
Constructor, the parameters are: key code of keyboard, row pin, column pin, the number of rows, the
number of columns.
char getKey();
Get the key code of the pressed key. If no key is pressed, the return value is NULL.
void setDebounceTime(uint);
Set the debounce time with a default time of 10ms.
void setHoldTime(uint);
Set the duration for the key to keep stable state after pressed.
bool isPressed(char keyChar);
Judge whether the key with code "keyChar" is pressed.
char waitForKey();
Wait for a key to be pressed, and return key code of the pressed key.
KeyState getState();
Get the state of the keys.
bool keyStateChanged();
Judge whether there is a change of key state, then return True or False.
For More information about Keypad, please visit: http://playground.arduino.cc/Code/Keypad

Any concerns?  support@freenove.com


240 Chapter 22 Matrix Keypad www.freenove.com █

Project 22.2 Keypad Door

In this project, we use keypad as a keyboard to control the action of the servo motor.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M Servo x1 4x4 Matrix Keypad x1

NPN transistorx1 Active buzzer x1 Resistor 1kΩ x1


(S8050)

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 22 Matrix Keypad 241

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


242 Chapter 22 Matrix Keypad www.freenove.com █

Sketch

Sketch_22.2_Keypad_Door

Verify and upload the code to the ESP32-WROVER and press the keypad to input password with 4 characters.
If the input is correct, the servo will move to a certain degree, then return to the original position. If the input
is wrong, an input error alarm will be generated.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 22 Matrix Keypad 243

The following is the program code:


1 #include <Keypad.h>
2 #include <ESP32Servo.h>
3
4 // define the symbols on the buttons of the keypad
5 char keys[4][4] = {
6 {'1', '2', '3', 'A'},
7 {'4', '5', '6', 'B'},
8 {'7', '8', '9', 'C'},
9 {'*', '0', '#', 'D'}
10 };
11
12 byte rowPins[4] = {14, 27, 26, 25}; // connect to the row pinouts of the keypad
13 byte colPins[4] = {13, 21, 22, 23}; // connect to the column pinouts of the keypad
14
15 // initialize an instance of class NewKeypad
16 Keypad myKeypad = Keypad(makeKeymap(keys), rowPins, colPins, 4, 4);
17
18 Servo myservo; // Create servo object to control a servo
19 int servoPin = 19; // Define the servo pin
20 int buzzerPin = 18; // Define the buzzer pin
21
22 char passWord[] = {"1234"}; // Save the correct password
23
24 void setup() {
25 myservo.setPeriodHertz(50); // standard 50 hz servo
26 myservo.attach(servoPin, 500, 2500); // attaches the servo on servoPin to the servo object
27 // set the high level time range of the servo motor
28 for an accurate 0°-180° sweep
29 myservo.write(0); // Set the starting position of the servo motor
30 pinMode(buzzerPin, OUTPUT);
31 Serial.begin(115200);
32 }
33
34 void loop() {
35 static char keyIn[4]; // Save the input character
36 static byte keyInNum = 0; // Save the number of input characters
37 char keyPressed = myKeypad.getKey(); // Get the character input
38 // Handle the input characters
39 if (keyPressed) {
40 // Make a prompt tone each time press the key
41 digitalWrite(buzzerPin, HIGH);
42 delay(100);
43 digitalWrite(buzzerPin, LOW);

Any concerns?  support@freenove.com


244 Chapter 22 Matrix Keypad www.freenove.com █

44 // Save the input characters


45 keyIn[keyInNum++] = keyPressed;
46 // Judge the correctness after input
47 if (keyInNum == 4) {
48 bool isRight = true; // Save password is correct or not
49 for (int i = 0; i < 4; i++) { // Judge each character of the password is correct or
50 not
51 if (keyIn[i] ! = passWord[i])
52 isRight = false; // Mark wrong password if there is any wrong character.
53 }
54 if (isRight) { // If the input password is right
55 myservo.write(90); // Open the switch
56 delay(2000); // Delay a period of time
57 myservo.write(0); // Close the switch
58 Serial.println("passWord right! ");
59 }
60 else { // If the input password is wrong
61 digitalWrite(buzzerPin, HIGH);// Make a wrong password prompt tone
62 delay(1000);
63 digitalWrite(buzzerPin, LOW);
64 Serial.println("passWord error! ");
65 }
66 keyInNum = 0; // Reset the number of the input characters to 0
67 }
68 }
69 }
70
First, we need to set the value of the password.
22 char passWord[] = {"1234"}; // Save the correct password
Second, each time the key is pressed, the buzzer makes a short sound and stores the key value entered.
37 char keyPressed = myKeypad.getKey(); // Get the character input
38 // Handle the input characters
39 if (keyPressed) {
40 // Make a prompt tone each time press the key
41 digitalWrite(buzzerPin, HIGH);
42 delay(100);
43 digitalWrite(buzzerPin, LOW);
44 // Save the input characters
45 keyIn[keyInNum++] = keyPressed;

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 22 Matrix Keypad 245

Third, if the button has been pressed for four times, ESP32 begins to judge if the password is correct.
47 if (keyInNum == 4) {
48 bool isRight = true; // Save password is correct or not
49 for (int i = 0; i < 4; i++) { // Judge each character of the password is correct or
50 not
51 if (keyIn[i] ! = passWord[i])
52 isRight = false; // Mark wrong password if there is any wrong character.
53 }
54
If the password is correct, control the servo motor to open the lock and wait for 2 seconds before closing the
lock. If it is not correct, the buzzer makes a long sound and prints the error message through the serial port.
55 if (isRight) { // If the input password is right
56 myservo.write(90); // Open the switch
57 delay(2000); // Delay a period of time
58 myservo.write(0); // Close the switch
59 Serial.println("passWord right! ");
60 }
61 else { // If the input password is wrong
62 digitalWrite(buzzerPin, HIGH);// Make a wrong password prompt tone
63 delay(1000);
64 digitalWrite(buzzerPin, LOW);
65 Serial.println("passWord error! ");
66 }
Finally, remember to empty the keyInNum every time.
67 keyInNum = 0; // Reset the number of the input characters to 0
For More information about Keypad, please visit: http://playground.arduino.cc/Code/Keypad .

Any concerns?  support@freenove.com


246 Chapter 23 Infrared Remote www.freenove.com █

Chapter 23 Infrared Remote


In this chapter, we'll learn how to use an infrared remote control, and control a LED.

Project 23.1 Infrared Remote Control

First, we need to understand how infrared remote control works, then get the command sent from infrared
remote control.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M x4 Infrared Remote x1


(May need CR2025 battery x1, please check the holder)

Infrared Remote x1 Resistor 10kΩ x1

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 23 Infrared Remote 247

Component knowledge

Infrared Remote
An infrared(IR) remote control is a device with a certain number of buttons. Pressing down different buttons
will make the infrared emission tube, which is located in the front of the remote control, send infrared ray with
different command. Infrared remote control technology is widely used in electronic products such as TV, air
conditioning, etc. Thus making it possible for you to switch TV programs and adjust the temperature of the
air conditioning when away from them. The remote control we use is shown below:

Pull out

Infrared receiver
An infrared(IR) receiver is a component which can receive the infrared light, so we can use it to detect the
signal emitted by the infrared remote control. DATA pin here outputs the received infrared signal.

Any concerns?  support@freenove.com


248 Chapter 23 Infrared Remote www.freenove.com █

When you use the infrared remote control, the infrared remote control sends a key value to the receiving
circuit according to the pressed keys. We can program the ESP32-WROVER to do things like lighting, when a
key value is received.
The following is the key value that the receiving circuit will receive when each key of the infrared remote
control is pressed.
ICON KEY Value ICON KEY Value
FFA25D FFB04F

FFE21D FF30CF

FF22DD FF18E7

FF02FD FF7A85

FFC23D FF10EF

FFE01F FF38C7

FFA857 FF5AA5

FF906F FF42BD

FF6897 FF4AB5

FF9867 FF52AD

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 23 Infrared Remote 249

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


250 Chapter 23 Infrared Remote www.freenove.com █

Sketch

This sketch uses the infrared receiving tube to receive the value sent form the infrared remote control, and
print it out via the serial port.

How to install the library


We use the third party library IRremoteESP8266. If you haven't installed it yet, please do so first. The steps to
add third-party Libraries are as follows: open arduino->Sketch->Include library-> Manage libraries. Enter "
IRremoteESP8266" in the search bar and select " IRremoteESP8266" for installation.
Refer to the following operations:

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 23 Infrared Remote 251

Sketch_23.1_Infrared_Remote_Control

Download the code to ESP32-WROVER, open the serial port monitor, set the baud rate to 115200, press the
IR remote control, the pressed keys value will be printed out through the serial port. As shown in the
following figure: (Note that when the remote control button is pressed for a long time, the infrared receiving
circuit receives a continuous high level, that is, it receives a hexadecimal "F")

Any concerns?  support@freenove.com


252 Chapter 23 Infrared Remote www.freenove.com █

Normal

Abnormal

The following is the program code:


1 #include <Arduino.h>
2 #include <IRremoteESP8266.h>
3 #include <IRrecv.h>
4 #include <IRutils.h>
5
6 const uint16_t recvPin = 15; // Infrared receiving pin
7 IRrecv irrecv(recvPin); // Create a class object used to receive class
8 decode_results results; // Create a decoding results class object
9
10 void setup() {
11 Serial.begin(115200); // Initialize the serial port and set the baud rate to 115200
12 irrecv.enableIRIn(); // Start the receiver
13 while (! Serial) // Wait for the serial connection to be established.
14 delay(50);
15 Serial.println();
16 Serial.print("IRrecvDemo is now running and waiting for IR message on Pin ");
17 Serial.println(recvPin); //print the infrared receiving pin
18 }
19
20 void loop() {
21 if (irrecv.decode(&results)) { // Waiting for decoding
22 serialPrintUint64(results.value, HEX);// Print out the decoded results
23 Serial.println("");
24 irrecv.resume(); // Release the IRremote. Receive the next value
25 }
26 delay(1000);
27 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 23 Infrared Remote 253

First, include header file. Each time you use the infrared library, you need to include the header file at the
beginning of the program.
1 #include <Arduino.h>
2 #include <IRremoteESP8266.h>
3 #include <IRrecv.h>
4 #include <IRutils.h>
Second, define an infrared receive pin and associates it with the receive class. Apply a decode_results to
decode the received infrared value.
6 const uint16_t RecvPin = 15; // Infrared receiving pin
7 IRrecv irrecv(RecvPin); // Create a class object used to receive class
8 decode_results results; // Create a decoding results class object
Third, enable infrared reception function, if you do not use this function, you won't receive the value from the
infrared remote control.
12 irrecv.enableIRIn(); // Start the receiver
Finally, put the received data into the results class and print out the data through the serial port. Note that
you must use resume() to release the infrared receive function every time when you receive data, otherwise
you can only use the infrared receive function once and cannot receive the data next time.
20 void loop() {
21 if (irrecv.decode(&results)) { // Waiting for decoding
22 serialPrintUint64(results.value, HEX); // Print out the decoded results
23 Serial.println("");
24 irrecv.resume(); // Release the IRremote. Receive the next value
25 }
26 delay(1000);
27 }
Reference
class IRrecv You need to add the library each time you use the Infrared Reception.
IRrecv irrecv(Pin):Create a class object used to receive class, and associated with Pin.
enableIRIn():Before using the infrared decoding function, enable the infrared receiving function. Otherwise the
correct data will not be received.
decode(&results): Determine whether the infrared has received data, and if so, return true and store the data
in the decode_results class. If no data is received, false is returned.
resume():Release the IRremote. Or, the infrared reception and decoding function cannot be used again.
For more information about Infrared Remote Control, please visit:
https://github.com/crankyoldgit/IRremoteESP8266/tree/master/src

Any concerns?  support@freenove.com


254 Chapter 23 Infrared Remote www.freenove.com █

Project 23.2 Control LED through Infrared Remote

In this project, we will control the brightness of LED lights through an infrared remote control.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M x10 Infrared Remote x1


(May need CR2025 battery x1, please check the
holder)
LED x1 Resistor 1kΩ x2

Infrared receiver x1 Resistor 10kΩ x1

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 23 Infrared Remote 255

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


256 Chapter 23 Infrared Remote www.freenove.com █

Sketch

The sketch controls the brightness of the LED by determining the key value of the infrared received.
Sketch_23.2_Control_LED_through_Infrared_Remote

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 23 Infrared Remote 257

Compile and upload the code to the ESP32-WROVER. When pressing "0", "1", "2", "3" of the infrared remote
control, the buzzer will sound once, and the brightness of the LED light will change correspondingly.
rendering

The following is the program code:


1 #include <Arduino.h>
2 #include <IRremoteESP8266.h>
3 #include <IRrecv.h>
4 #include <IRutils.h>
5
6 const uint16_t recvPin = 15; // Infrared receiving pin
7 IRrecv irrecv(recvPin); // Create a class object used to receive class
8 decode_results results; // Create a decoding results class object
9
10 int ledPin = 14; // the number of the LED pin
11 int buzzerPin = 13; // the number of the buzzer pin
12
13 void setup()
14 {
15 //Initialize the ledc configuration
16 ledcSetup(0,1000,8); // set the channel, frequency, esolution_bits
17 ledcAttachPin(ledPin,0); // attach the channel to GPIO pin
18 pinMode(buzzerPin, OUTPUT); // set buzzer pin into output mode
19 irrecv.enableIRIn(); // Start the receiver
20 }
21
22 void loop() {
23 if (irrecv.decode(&results)) { // Waiting for decoding
24 handleControl(results.value); // Handle the commands from remote control
25 irrecv.resume(); // Receive the next value
26 }
27 }

Any concerns?  support@freenove.com


258 Chapter 23 Infrared Remote www.freenove.com █

28 void handleControl(unsigned long value) {


29 // Make a sound when it receives commands
30 digitalWrite(buzzerPin, HIGH);
31 delay(100);
32 digitalWrite(buzzerPin, LOW);
33 // respond to the commands
34 switch (value) {
35 case 0xFF6897: // Receive the number '0'
36 ledcWrite(0, 0); // Turn off LED
37 break;
38 case 0xFF30CF: // Receive the number '1'
39 ledcWrite(0, 7); // Dimmest brightness
40 break;
41 case 0xFF18E7: // Receive the number '2'
42 ledcWrite(0, 63); // Medium brightness
43 break;
44 case 0xFF7A85: // Receive the number '3'
45 ledcWrite(0, 255); // Strongest brightness
46 break;
47 }
48 }
The handleControl() function is used to execute events corresponding to infrared code values. Every time
when the function is called, the buzzer sounds once and determine the brightness of the LED based on the
infrared key value. If the key value is not "0", "1", "2", "3", the buzzer sounds once, but the brightness of LED
will not change.
28 void handleControl(unsigned long value) {
29 // Make a sound when it receives commands
30 digitalWrite(buzzerPin, HIGH);
31 delay(100);
32 digitalWrite(buzzerPin, LOW);
33 // respond to the commands
34 switch (value) {
35 case 0xFF6897: // Receive the number '0'
36 ledcWrite(0, 0); // Turn off LED
37 break;
38 case 0xFF30CF: // Receive the number '1'
39 ledcWrite(0, 7); // Dimmest brightness
40 break;
41 case 0xFF18E7: // Receive the number '2'
42 ledcWrite(0, 63); // Medium brightness
43 break;
44 case 0xFF7A85: // Receive the number '3'
45 ledcWrite(0, 255); // Strongest brightness
46 break;

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 23 Infrared Remote 259

47 }
48 }
Each time when the command is received, the function above will be called in the loop() function.
22 void loop() {
23 if (irrecv.decode(&results)) { // Waiting for decoding
24 handleControl(results.value); // Handle the commands from remote control
25 irrecv.resume(); // Receive the next value
26 }
27 }

Any concerns?  support@freenove.com


260 Chapter 24 Hygrothermograph DHT11 www.freenove.com █

Chapter 24 Hygrothermograph DHT11


In this chapter, we will learn about a commonly used sensor called a Hygrothermograph DHT11.

Project 24.1 Hygrothermograph

Hygrothermograph is an important tool in our lives to give us data on the temperature and humidity in our
environment. In this project, we will use the ESP32 to read temperature and humidity data of the DHT11
Module.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper M/M x4 DHT11 x1 Resistor 10kΩ x1

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 24 Hygrothermograph DHT11 261

Component knowledge

The temperature & humidity sensor DHT11 is a compound temperature & humidity sensor, and the output
digital signal has been calibrated by its manufacturer.

DHT11 uses customized single-line communication protocol, so we can use the library to read data more
conveniently.
After being powered up, it will initialize in 1s. Its operating voltage is within the range of 3.3V-5.5V.
The SDA pin is a data pin, which is used to communicate with other devices.
The NC pin (Not Connected Pin) is a type of pin found on various integrated circuit packages. Those pins
have no functional purpose to the outside circuit (but may have an unknown functionality during
manufacture and test). Those pins should not be connected to any of the circuit connections.

Any concerns?  support@freenove.com


262 Chapter 24 Hygrothermograph DHT11 www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 24 Hygrothermograph DHT11 263

Sketch

How to install the library


The code is used to read the temperature and humidity data of DHT11, and print them out.
We use the third party library DHTesp. If you haven't installed it yet, please do so now. The steps to add third-
party libraries are as follows: open arduino->Sketch->Include library-> Manage libraries. Enter " DHTesp " in
the search bar and select " DHTesp " for installation.
Refer to the following operations:

Any concerns?  support@freenove.com


264 Chapter 24 Hygrothermograph DHT11 www.freenove.com █

Sketch_24.1_Temperature_and_Humidity_Sensor

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 24 Hygrothermograph DHT11 265

Compile and upload the code to the ESP32-WROVER, turn on the serial monitor, and set the baud rate to
115200. Print out data of temperature and humidity sensor via the serial port.

The following is the program code:


1 #include "DHTesp.h"
2
3 DHTesp dht; //Define the DHT object
4 int dhtPin = 13;//Define the dht pin
5
6 void setup() {
7 dht.setup(dhtPin, DHTesp::DHT11);//Initialize the dht pin and dht object
8 Serial.begin(115200); //Set the baud rate to 115200
9 }
10
11 void loop() {
12 flag:TempAndHumidity newValues = dht.getTempAndHumidity();//Get the Temperature and humidity
13 if (dht.getStatus() ! = 0) { //Judge if the correct value is
14 read
15 goto flag; //If there is an error, go back to
16 the flag and re-read the data
17 }
18 Serial.println(" Temperature:" + String(newValues.temperature) +
" Humidity:" + String(newValues.humidity));
19 delay(1000);
20 }

Any concerns?  support@freenove.com


266 Chapter 24 Hygrothermograph DHT11 www.freenove.com █

In this project code, we use a third party library, DHTesp, and we need to define the objects for it first;
Otherwise we could not use its functionality.
1 #include "DHTesp.h"
3 DHTesp dht; //Define the DHT object
Initialize the connection pin of DHT and select the type of temperature and humidity sensor as DHT11. If the
temperature and humidity sensor is DHT12, we can also change it to DHT12.
7 dht.setup(dhtPin, DHTesp::DHT11);//Initialize the dht pin and dht object
Due to the use of the single-line protocol, data may be lost in the transmission process. So each time when
getting the data of the temperature and humidity sensor, we need to call the getStatus function to determine
whether the data is normal. If not, use goto to go back to line 12 and re-execute the program.
12 flag:TempAndHumidity newValues = dht.getTempAndHumidity();//Get the Temperature and
13 humidity
14 if (dht.getStatus() ! = 0) { //Judge if the correct value is read
15 goto flag; //If there is an error, go back to the flag and re-read
16 the data
17 }
Get the temperature and humidity data and store it in a TempAndHumidity class called newValues.
12 TempAndHumidity newValues = dht.getTempAndHumidity(); //Get the Temperature and humidity
Reference
class DHTesp
Make sure that the library and header files are added before using the object every time.
setup(Pin, DHTesp::DHTxx): Select the type of DHTxx and associate Pin with the DHTesp class.
Parameter 1: the pin to be associated.
Parameter 2: select the type of sensor, DHT11 or DHT12.
getTempAndHumidity():Obtain temperature and humidity data. The received data must be stored in the
‘TempAndHumidity’ class.
getStatus():To judge whether the obtained data format is normal, the return value of 0 means the data is normal,
and the return value of non-0 means the data is abnormal or the data fails to be obtained.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 24 Hygrothermograph DHT11 267

Project 24.2 Hygrothermograph

In this project, we use L2C-LCD1602 to display data collected by DHT11.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

LCD1602 Module x1 Resistor 10kΩ x1

Jumper F/M x4 DHT11 x1


Jumper M/M x4

Any concerns?  support@freenove.com


268 Chapter 24 Hygrothermograph DHT11 www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 24 Hygrothermograph DHT11 269

Sketch

This code uses the DHTesp and LiquidCrystal_I2C libraries, so make sure the relevant library files are added
before writing the program.
Sketch_24.2_Temperature_and_Humidity_Sensor

Any concerns?  support@freenove.com


270 Chapter 24 Hygrothermograph DHT11 www.freenove.com █

Download the code to ESP32-WROVER. The first line of LCD1602 shows the temperature value, and the
second line shows the humidity value. Try to “pinch” the thermistor (without touching the leads) with your
index finger and thumb for a brief time to observe the change in the LCD display value.

The following is the program code:


1 #include <Wire.h>
2 #include <LiquidCrystal_I2C.h>
3 #include "DHTesp.h"
4
5 #define SDA 13 //Define SDA pins
6 #define SCL 14 //Define SCL pins
7
8 DHTesp dht; // create dht object
9 LiquidCrystal_I2C lcd(0x27,16,2); //initialize the LCD
10 int dhtPin = 18; // the number of the DHT11 sensor pin
11
12 void setup() {
13 Wire.begin(SDA, SCL); // attach the IIC pin
14 lcd.init(); // LCD driver initialization
15 lcd.backlight(); // Turn on the backlight
16 dht.setup(dhtPin, DHTesp::DHT11); //attach the dht pin and initialize it
17 }
18
19 void loop() {
20 // read DHT11 data and save it
21 flag:TempAndHumidity DHT = dht.getTempAndHumidity();
22 if (dht.getStatus() ! = 0) { //Determine if the reading is successful, and if it
23 fails, go back to flag and re-read the data
24 goto flag;
25 }
26 lcd.setCursor(0, 0); //set the cursor to column 0, line 1
27 lcd.print("Temperature:"); //display the Humidity on the LCD1602
28 lcd.print(DHT.temperature);
29 lcd.setCursor(0, 1); //set the cursor to column 0, line 0
30 lcd.print("Humidity :"); //display the Humidity on the LCD1602
31 lcd.print(DHT.humidity);
32 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 24 Hygrothermograph DHT11 271

First, add the library function header file.


1 #include <Wire.h>
2 #include <LiquidCrystal_I2C.h>
3 #include "DHTesp.h"
Second, initialize the pins associated with the DHT11 sensor and I2C-LCD1602.
8 DHTesp dht; // create dht object
9 LiquidCrystal_I2C lcd(0x27,16,2); //initialize the LCD
10 int dhtPin = 18; // the number of the DHT11 sensor pin
11
12 void setup() {
13 Wire.begin(SDA, SCL); // attach the IIC pin
14 lcd.init(); // LCD driver initialization
15 lcd.backlight(); // Turn on the backlight
16 dht.setup(dhtPin, DHTesp::DHT11); //attach the dht pin and initialize it
17 }
Finally, the data of temperature and humidity sensor are obtained and displayed on LCD1602. The first row
shows the temperature and the second shows the humidity.
21 flag:TempAndHumidity DHT = dht.getTempAndHumidity();
22 if (dht.getStatus() ! = 0) { //Determine if the reading is successful, and if it
23 fails, go back to flag and re-read the data
24 goto flag;
25 }
26 lcd.setCursor(0, 0); //set the cursor to column 0, line 1
27 lcd.print("Temperature:"); //display the Humidity on the LCD1602
28 lcd.print(DHT.temperature);
29 lcd.setCursor(0, 1); //set the cursor to column 0, line 0
30 lcd.print("Humidity :"); //display the Humidity on the LCD1602
31 lcd.print(DHT.humidity);

Any concerns?  support@freenove.com


272 Chapter 25 Infrared Motion Sensor www.freenove.com █

Chapter 25 Infrared Motion Sensor


In this chapter, we will learn a widely used sensor, infrared motion sensor.

Project 25.1 Infrared Motion Detector with LED Indicator

In this project, we will make a motion detector, with the human body infrared pyroelectric sensors.
When someone is in close proximity to the motion detector, it will automatically light up and when there is
no one close by, it will be out.
This infrared motion sensor can detect the infrared spectrum (heat signatures) emitted by living humans and
animals.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

HC SR501 x1 LED x1 Resistor 220Ω x1 Jumper F/M x3


Jumper M/M x2

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 25 Infrared Motion Sensor 273

Component knowledge

The following is the diagram of the infrared Motion sensor(HC SR-501):


Top Bottom Schematic

Description:
Working voltage: 5v-20v(DC) Static current: 65uA.
Automatic Trigger. When a living body enters into the active area of sensor, the module will output high
level (3.3V). When the body leaves the sensor’s active detection area, it will output high level lasting for time
period T, then output low level(0V). Delay time T can be adjusted by the potentiometer R1.
According to the position of jumper cap, you can choose non-repeatable trigger mode or repeatable
mode.
L: non-repeatable trigger mode. The module output high level after sensing a body, then when the delay
time is over, the module will output low level. During high level time, the sensor no longer actively senses
bodies.
H: repeatable trigger mode. The distinction from the L mode is that it can sense a body until that body
leaves during the period of high level output. After this, it starts to time and output low level after delaying T
time.
Induction block time: the induction will stay in block condition and does not induce external signal at
lesser time intervals (less than delay time) after outputting high level or low level
Initialization time: the module needs about 1 minute to initialize after being powered ON. During this
period, it will alternately output high or low level.
One characteristic of this sensor is when a body moves close to or moves away from the sensor’s dome
edge, the sensor will work at high sensitivity. When a body moves close to or moves away from the sensor’s
dome in a vertical direction, the sensor cannot detect well (please take note of this deficiency). Note: The
sensing range (distance before a body is detected) is adjusted by the potentiometer.
We can regard this sensor as a simple inductive switch when in use.

Any concerns?  support@freenove.com


274 Chapter 25 Infrared Motion Sensor www.freenove.com █

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 25 Infrared Motion Sensor 275

Sketch

In this project, we will use the infrared motion sensor to trigger a LED, essentially making the infrared motion
sensor act as a motion switch. Therefore, the code is very similar to the earlier project "push button switch
and LED”. The difference is that, when infrared motion sensor detects change, it will output high level; when
button is pressed, it will output low level. When the sensor output high level, the LED turns ON, or it will turn
OFF.
Sketch_25.1_Infrared_Motion_Sensor

Verify and upload the code, and put the sensor on a stationary table and wait for about a minute. Then try to
move away from or move closer to the infrared motion sensor and observe whether the LED turns ON or OFF
automatically.

You can rotate the potentiometer on the sensor to adjust the detection effect, or use different modes by
changing the jumper.

Apart from that, you can also use this sensor to control some other modules to implement different functions
by reediting the code, such as the induction lamp, induction door.

Any concerns?  support@freenove.com


276 Chapter 25 Infrared Motion Sensor www.freenove.com █

Move to the Infrared Motion Sensor

Move away from the Infrared Motion Sensor

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 26 Attitude Sensor MPU6050 277

Chapter 26 Attitude Sensor MPU6050


In this chapter, we will learn about a MPU6050 attitude sensor which integrates an accelerometer and
gyroscope.

Project 26.1 Read a MPU6050 Sensor Module

In this project, we will read acceleration and gyroscope data of the MPU6050 sensor

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Breadboard x1

Jumper F/M x4 MPU6050 x1

Any concerns?  support@freenove.com


278 Chapter 26 Attitude Sensor MPU6050 www.freenove.com █

Component knowledge

MPU6050
MPU6050 sensor module is a complete 6-axis motion tracking device. It combines a 3-axis gyroscope, a 3-
axis accelerometer and a DMP (Digital Motion Processor) all in a small package. The settings of the
accelerometer and gyroscope of MPU6050 can be changed. A precision wide range digital temperature sensor
is also integrated to compensate data readings for changes in temperature, and temperature values can also
be read. The MPU6050 Module follows the I2C communication protocol and the default address is 0x68.
MPU6050 is widely used to assist with balancing vehicles, robots and aircraft, mobile phones and other
products which require stability to control stability and attitude or which need to sense same.

The port description of the MPU6050 module is as follows:


Pin name Pin number Description
VCC 1 Positive pole of power supply with voltage 5V
GND 2 Negative pole of power supply
SCL 3 I2C communication clock pin
SDA 4 I2C communication clock pin
XDA 5 I2C host data pin which can be connected to other devices.
XCL 6 I2C host clock pin which can be connected to other devices.
AD0 7 I2C address bit control pin.
Low level: the device address is 0x68
High level: the device address is 0x69
INT 8 Output interrupt pin
For more detail, please refer to datasheet.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 26 Attitude Sensor MPU6050 279

Circuit

Note that the power supply voltage for MPU6050 module is 5V in the circuit.
Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


280 Chapter 26 Attitude Sensor MPU6050 www.freenove.com █

Sketch

How to install the library


In this project, we will read the acceleration data and gyroscope data of MPU6050, and print them out.
We use the third party library MPU6050_tockn. If you haven't installed it yet, please do so now. The steps to
add third-party Libraries are as follows: open arduino->Sketch->Include library-> Manage libraries. Enter "
MPU6050_tockn " in the search bar and select " MPU6050_tockn " for installation.
Refer to the following operations:

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 26 Attitude Sensor MPU6050 281

Sketch_26.1_Acceleration_Detection

Any concerns?  support@freenove.com


282 Chapter 26 Attitude Sensor MPU6050 www.freenove.com █

Download the code to ESP32-WROVER, open the serial port monitor, set the baud rate to 115200 and you
can use it to measure the distance between the ultrasonic module and the object. As shown in the following
figure:

The following is the program code:


1 #include <MPU6050_tockn.h>
2 #include <Wire.h>
3
4 #define SDA 13
5 #define SCL 14
6
7 MPU6050 mpu6050(Wire);//Attach the IIC
8 int16_t ax,ay,az;//define acceleration values of 3 axes
9 int16_t gx,gy,gz;//define variables to save the values in 3 axes of gyroscope
10
11 long timer = 0;
12
13 void setup() {
14 Serial.begin(115200);
15 Wire.begin(SDA, SCL); //attach the IIC pin
16 mpu6050.begin(); //initialize the MPU6050
17 mpu6050.calcGyroOffsets(true); //get the offsets value
18 }
19
20 void loop() {
21 if(millis() - timer > 1000){ //each second print the data
22 mpu6050.update(); //update the MPU6050

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 26 Attitude Sensor MPU6050 283

23 getMotion6(); //gain the values of Acceleration and Gyroscope value


24 Serial.print("\na/g:\t");
25 Serial.print(ax); Serial.print("\t");
26 Serial.print(ay); Serial.print("\t");
27 Serial.print(az); Serial.print("\t");
28 Serial.print(gx); Serial.print("\t\t");
29 Serial.print(gy); Serial.print("\t\t");
30 Serial.println(gz);
31 Serial.print("a/g:\t");
32 Serial.print((float)ax / 16384); Serial.print("g\t");
33 Serial.print((float)ay / 16384); Serial.print("g\t");
34 Serial.print((float)az / 16384); Serial.print("g\t");
35 Serial.print((float)gx / 131); Serial.print("d/s \t");
36 Serial.print((float)gy / 131); Serial.print("d/s \t");
37 Serial.print((float)gz / 131); Serial.print("d/s \n");
38 timer = millis();
39 }
40 }
41 void getMotion6(void){
42 ax=mpu6050.getRawAccX();//gain the values of X axis acceleration raw data
43 ay=mpu6050.getRawAccY();//gain the values of Y axis acceleration raw data
44 az=mpu6050.getRawAccZ();//gain the values of Z axis acceleration raw data
45 gx=mpu6050.getRawGyroX();//gain the values of X axis Gyroscope raw data
46 gy=mpu6050.getRawGyroX();//gain the values of Y axis Gyroscope raw data
47 gz=mpu6050.getRawGyroX();//gain the values of Z axis Gyroscope raw data
48 }
Two library files "MPU6050_tockn.h" and "Wire.h" are used in the code and will be compiled with others.
Class MPU6050 is used to operate the MPU6050. When using it, please instantiate an object first.
7 MPU6050 mpu6050(Wire);//Attach the IIC
In the setup function, IIC and MPU6050 are initialized and the offset difference of MPU6050 is obtained.
13 void setup() {
14 Serial.begin(115200);
15 Wire.begin(SDA, SCL); //attach the IIC pin
16 mpu6050.begin(); //initialize the MPU6050
17 mpu6050.calcGyroOffsets(true); //get the offsets value
18 }
The getMotion6 function is used to obtain the x, y, z axis acceleration raw data and the Gyroscope raw data.
41 void getMotion6(void){
42 ax=mpu6050.getRawAccX();//gain the values of X axis acceleration raw data
43 ay=mpu6050.getRawAccY();//gain the values of Y axis acceleration raw data
44 az=mpu6050.getRawAccZ();//gain the values of Z axis acceleration raw data
45 gx=mpu6050.getRawGyroX();//gain the values of X axis Gyroscope raw data
46 gy=mpu6050.getRawGyroX();//gain the values of Y axis Gyroscope raw data
47 gz=mpu6050.getRawGyroX();//gain the values of Z axis Gyroscope raw data

Any concerns?  support@freenove.com


284 Chapter 26 Attitude Sensor MPU6050 www.freenove.com █

48 }
Finally, the original data of the gyroscope is updated and acquired every second, and the original data, the
processed acceleration and angular velocity data are printed out through the serial port.
20 void loop() {
21 if(millis() - timer > 1000){ //each second print the data
22 mpu6050.update(); //update the MPU6050
23 getMotion6(); //gain the values of Acceleration and Gyroscope value
24 Serial.print("\na/g:\t");
25 Serial.print(ax); Serial.print("\t");
26 Serial.print(ay); Serial.print("\t");cc
27 Serial.print(az); Serial.print("\t");
28 Serial.print(gx); Serial.print("\t\t");
29 Serial.print(gy); Serial.print("\t\t");
30 Serial.println(gz);
31 Serial.print("a/g:\t");
32 Serial.print((float)ax / 16384); Serial.print("g\t");
33 Serial.print((float)ay / 16384); Serial.print("g\t");
34 Serial.print((float)az / 16384); Serial.print("g\t");
35 Serial.print((float)gx / 131); Serial.print("d/s \t");
36 Serial.print((float)gy / 131); Serial.print("d/s \t");
37 Serial.print((float)gz / 131); Serial.print("d/s \n");
38 timer = millis();
39 }
40 }

Reference
Class MPU6050
This is a class library used to operate MPU6050, which can directly read and set MPU6050. Here are some
member functions:
MPU6050 mpu6050(Wire): Associate MPU6050 with IIC.
begin(): Initialize the MPU6050.
calcGyroOffsets(true): If the parameter is true, get the gyro offset and automatically correct the offset.
If the parameter is false, the offset value is not obtained and the offset is not corrected.
getRawAccX():Gain the values of X axis acceleration raw data.
getRawAccY():Gain the values of Y axis acceleration raw data.
getRawAccZ():Gain the values of Z axis acceleration raw data.
getRawGyroX():Gain the values of X axis Gyroscope raw data.
getRawGyroY():Gain the values of Y axis Gyroscope raw data.
getRawGyroZ():gain the values of Z axis Gyroscope raw data.
getTemp():Gain the values of MPU6050’temperature data.
update():Update the MPU6050. If the updated function is not used, the IIC will not be able to retrieve the
new data.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 285

Chapter 27 Bluetooth
This chapter mainly introduces how to make simple data transmission through Bluetooth of ESP32-WROVER
and mobile phones.
Project 27.1 is classic Bluetooth and Project 27.2 is low power Bluetooth.If you are an iPhone user, please start
with Project 27.2.

Project 27.1 Bluetooth Passthrough

Component List

ESP32-WROVER x1 Micro USB Wire x1

In this tutorial we need to use a Bluetooth APP called Serial Bluetooth Terminal to assist in the experiment. If
you've not installed it yet, please do so by clicking: https://www.appsapk.com/serial-bluetooth-terminal/ The
following is its logo.

Any concerns?  support@freenove.com


286 Chapter 27 Bluetooth www.freenove.com █

Component knowledge

ESP32's integrated Bluetooth function Bluetooth is a short-distance communication system, which can be
divided into two types, namely Bluetooth Low Energy(BLE) and Classic Bluetooth. There are two modes for
simple data transmission: master mode and slave mode.
Master mode
In this mode, works are done in the master device and it can connect with a slave device. And we can search
and select slave devices nearby to connect with. When a device initiates connection request in master mode,
it requires information of the other Bluetooth devices including their address and pairing passkey. After
finishing pairing, it can connect with them directly.
Slave mode
The Bluetooth module in slave mode can only accept connection request from a host computer, but cannot
initiate a connection request. After connecting with a host device, it can send data to or receive from the host
device.
Bluetooth devices can make data interaction with each other, as one is in master mode and the other in slave
mode. When they are making data interaction, the Bluetooth device in master mode searches and selects
devices nearby to connect to. When establishing connection, they can exchange data. When mobile phones
exchange data with ESP32, they are usually in master mode and ESP32 in slave mode.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 287

Circuit

Connect Freenove ESP32 to the computer using the USB cable.

Sketch

Sketch_27.1_SerialToSerialBT

Any concerns?  support@freenove.com


288 Chapter 27 Bluetooth www.freenove.com █

Compile and upload the code to the ESP32-WROVER, open the serial monitor, and set the baud rate to
115200. When you see the serial printing out the character string as below, it indicates that the Bluetooth of
ESP32 is ready and waiting to connect with the mobile phone.

Make sure that the Bluetooth of your phone has been turned on and Serial Bluetooth Terminal has been
installed.

Click "Search" to search Bluetooth devices nearby and select "ESP32 test" to connect to.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 289

Turn on software APP, click the left of the terminal. Select "Devices"

Select ESP32test in classic Bluetooth mode, and a successful connecting prompt will appear as shown on the
right illustration.

And now data can be transferred between your mobile phone and computer via ESP32-WROVER.

Send 'Hello!'' from your phone, when the computer receives it, reply "Hi" to your phone.

Any concerns?  support@freenove.com


290 Chapter 27 Bluetooth www.freenove.com █

Reference
Class BluetoothSerial
This is a class library used to operate BluetoothSerial, which can directly read and set BluetoothSerial.
Here are some member functions:
begin(localName,isMaster): Initialization function of the Bluetooth
name: name of Bluetooth module; Data type: String
isMaster: bool type, whether to set Bluetooth as Master. By default, it is false.
available(): acquire digits sent from the buffer, if not, return 0.
read(): read data from Bluetooth, data type of return value is int.
readString(): read data from Bluetooth, data type of return value is String.
write(val): send an int data val to Bluetooth.
write(str): send an Srtring data str to Bluetooth.
write(buf, len): Sends the first len data in the buf Array to Bluetooth.
setPin(const char *pin): set a four-digit Bluetooth pairing code. By default, it is 1234
connet(remoteName): connect a Bluetooth named remoteName, data type: String
connect(remoteAddress[]): connect the physical address of Bluetooth, data type: uint8-t.
disconnect():disconnect all Bluetooth devices.
end(): disconnect all Bluetooth devices and turn off the Bluetooth, release all occupied space

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 291

Project 27.2 Bluetooth Low Energy Data Passthrough

Component List

ESP32-WROVER x1 Micro USB Wire x1

Circuit

Connect Freenove ESP32 to the computer using the USB cable.

Any concerns?  support@freenove.com


292 Chapter 27 Bluetooth www.freenove.com █

Sketch

Sketch_27.2_BLE

Serial Bluetooth
Compile and upload code to ESP32, the operation is similar to the last section.
First, make sure you've turned on the mobile phone Bluetooth, and then open the software.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 293

Click "Search" to search Bluetooth devices nearby and select "ESP32 test" to connect to.

Turn on software APP, click the left of the terminal. Select "Devices"

Select BLUETOOTHLE, click SCAN to scan Low Energy Bluetooth devices nearby.

Any concerns?  support@freenove.com


294 Chapter 27 Bluetooth www.freenove.com █

Select"ESP32-Bluetooth"

Lightblue
If you can't install Serial Bluetooth on your phone, try LightBlue.If you do not have this software installed on
your phone, you can refer to this link:
https://apps.apple.com/us/app/lightblue/id557428110#?platform=iphone.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 295

Step1. Upload the code of Project27.2 to ESP32.


Step2. Click on serial monitor.

1 2

Step3. Set baud rate to 9600.

Turn ON Bluetooth on your phone, and open the Lightblue APP.

Any concerns?  support@freenove.com


296 Chapter 27 Bluetooth www.freenove.com █

In the Scan page, swipe down to refresh the name of Bluetooth that the phone searches for. Click
ESP32_Bluetooth.

Receive

Click “Receive”. Select the appropriate Data format in the box to the right of Data Format. For example, HEX
for hexadecimal, utf-string for character, Binary for Binary, etc. Then click SUBSCRIBE.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 297

Back to the serial monitor on your computer. You can type anything in the left border of Send, and then click
Send.

And then you can see the mobile Bluetooth has received the message.

Any concerns?  support@freenove.com


298 Chapter 27 Bluetooth www.freenove.com █

Similarly, you can select “Send” on your phone. Set Data format, and then enter anything in the sending box
and click Write to send.

Send

And the computer will receive the message from the mobile Bluetooth.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 299

And now data can be transferred between your mobile phone and computer via ESP32-WROVER.
The following is the program code:
1 #include <BLEDevice.h>
2 #include <BLEServer.h>
3 #include <BLEUtils.h>
4 #include <BLE2902.h>
5 #include <String.h>
6
7 BLECharacteristic *pCharacteristic;
8 bool deviceConnected = false;
9 uint8_t txValue = 0;
10 long lastMsg = 0;
11 String rxload="Test\n";
12
13 #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
14 #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
15 #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
16
17 class MyServerCallbacks: public BLEServerCallbacks {
18 void onConnect(BLEServer* pServer) {
19 deviceConnected = true;
20 };
21 void onDisconnect(BLEServer* pServer) {
22 deviceConnected = false;
23 }
24 };
25
26 class MyCallbacks: public BLECharacteristicCallbacks {
27 void onWrite(BLECharacteristic *pCharacteristic) {
28 std::string rxValue = pCharacteristic->getValue();
29 if (rxValue.length() > 0) {
30 rxload="";
31 for (int i = 0; i < rxValue.length(); i++){
32 rxload +=(char)rxValue[i];
33 }
34 }
35 }
36 };
37
38 void setupBLE(String BLEName){
39 const char *ble_name=BLEName.c_str();
40 BLEDevice::init(ble_name);
41 BLEServer *pServer = BLEDevice::createServer();
42 pServer->setCallbacks(new MyServerCallbacks());

Any concerns?  support@freenove.com


300 Chapter 27 Bluetooth www.freenove.com █

43 BLEService *pService = pServer->createService(SERVICE_UUID);


44 pCharacteristic=
pService->createCharacteristic(CHARACTERISTIC_UUID_TX,BLECharacteristic::PROPERTY_NOTIFY);
45 pCharacteristic->addDescriptor(new BLE2902());
46 BLECharacteristic *pCharacteristic =
pService->createCharacteristic(CHARACTERISTIC_UUID_RX,BLECharacteristic::PROPERTY_WRITE);
47 pCharacteristic->setCallbacks(new MyCallbacks());
48 pService->start();
49 pServer->getAdvertising()->start();
50 Serial.println("Waiting a client connection to notify...");
51 }
52
53 void setup() {
54 Serial.begin(9600);
55 setupBLE("ESP32_Bluetooth");
56 }
57
58 void loop() {
59 long now = millis();
60 if (now - lastMsg > 1000) {
61 if (deviceConnected&&rxload.length()>0) {
62 Serial.println(rxload);
63 rxload="";
64 }
65 if(Serial.available()>0){
66 String str=Serial.readString();
67 const char *newValue=str.c_str();
68 pCharacteristic->setValue(newValue);
69 pCharacteristic->notify();
70 }
71 lastMsg = now;
72 }
73 }
Define the specified UUID number for BLE vendor.
13 #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
14 #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
15 #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 301

Write a Callback function for BLE server to manage connection of BLE.


17 class MyServerCallbacks: public BLEServerCallbacks {
18 void onConnect(BLEServer* pServer) {
19 deviceConnected = true;
20 };
21 void onDisconnect(BLEServer* pServer) {
22 deviceConnected = false;
23 }
24 };
Write Callback function with BLE features. When it is called, as the mobile terminal send data to ESP32, it will
store them into reload.
26 class MyCallbacks: public BLECharacteristicCallbacks {
27 void onWrite(BLECharacteristic *pCharacteristic) {
28 std::string rxValue = pCharacteristic->getValue();
29 if (rxValue.length() > 0) {
30 rxload="";
31 for (int i = 0; i < rxValue.length(); i++){
32 rxload +=(char)rxValue[i];
33 }
34 }
35 }
36 };
Initialize the BLE function and name it.
55 setupBLE("ESP32_Bluetooth");
When the mobile phone send data to ESP32 via BLE Bluetooth, it will print them out with serial port; When
the serial port of ESP32 receive data, it will send them to mobile via BLE Bluetooth.
59 long now = millis();
60 if (now - lastMsg > 1000) {
61 if (deviceConnected&&rxload.length()>0) {
62 Serial.println(rxload);
63 rxload="";
64 }
65 if(Serial.available()>0){
66 String str=Serial.readString();
67 const char *newValue=str.c_str();
68 pCharacteristic->setValue(newValue);
69 pCharacteristic->notify();
70 }
71 lastMsg = now;
72 }

Any concerns?  support@freenove.com


302 Chapter 27 Bluetooth www.freenove.com █

The design for creating the BLE server is:


1. Create a BLE Server
2. Create a BLE Service
3. Create a BLE Characteristic on the Service
4. Create a BLE Descriptor on the characteristic
5. Start the service.
6. Start advertising.
38 void setupBLE(String BLEName){
39 const char *ble_name=BLEName.c_str();
40 BLEDevice::init(ble_name);
41 BLEServer *pServer = BLEDevice::createServer();
42 pServer->setCallbacks(new MyServerCallbacks());
43 BLEService *pService = pServer->createService(SERVICE_UUID);
44 pCharacteristic=
pService->createCharacteristic(CHARACTERISTIC_UUID_TX,BLECharacteristic::PROPERTY_NOTIFY);
45 pCharacteristic->addDescriptor(new BLE2902());
46 BLECharacteristic *pCharacteristic =
pService->createCharacteristic(CHARACTERISTIC_UUID_RX,BLECharacteristic::PROPERTY_WRITE);
47 pCharacteristic->setCallbacks(new MyCallbacks());
48 pService->start();
49 pServer->getAdvertising()->start();
50 Serial.println("Waiting a client connection to notify...");
51 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 303

Project 27.3 Bluetooth Control LED

In this section, we will control the LED with Bluetooth.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Micro USB Wire x1 LED x1 Resistor 220Ω x1 Jumper M/M x2

Breadboard x1

Any concerns?  support@freenove.com


304 Chapter 27 Bluetooth www.freenove.com █

Circuit

Connect Freenove ESP32 to the computer using a USB cable.

Schematic diagram

Hardware connection. If you need any support, please contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 305

Sketch

Sketch_27.3_Bluetooth_Control_LED

Any concerns?  support@freenove.com


306 Chapter 27 Bluetooth www.freenove.com █

Compile and upload code to ESP32. The operation of the APP is the same as 27.1, you only need to change
the sending content to "LED on" and "LED off" to operate LEDs on the ESP32-WROVER.
Data sent from mobile APP:

Display on the serial port of the computer:

The phenomenon of LED

Send:“led_on”

Send:“led_off”

Attention: If the sending content isn't "led-on' or "led-off", then the state of LED will not change. If the LED is
on, when receiving irrelevant content, it keeps on; Correspondingly, if the LED is off, when receiving irrelevant
content, it keeps off.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 27 Bluetooth 307

The following is the program code:


1 #include "BluetoothSerial.h"
2 #include "string.h"
3 #define LED 2
4 BluetoothSerial SerialBT;
5 char buffer[20];
6 static int count = 0;
7 void setup() {
8 pinMode(LED, OUTPUT);
9 SerialBT.begin("ESP32test"); //Bluetooth device name
10 Serial.begin(115200);
11 Serial.println("\The device started, now you can pair it with Bluetooth! ");
12 }
13
14 void loop() {
15 while(SerialBT.available())
16 {
17 buffer[count] = SerialBT.read();
18 count++;
19 }
20 if(count>0){
21 Serial.print(buffer);
22 if(strncmp(buffer,"led_on",6)==0){
23 digitalWrite(LED,HIGH);
24 }
25 if(strncmp(buffer,"led_off",7)==0){
26 digitalWrite(LED,LOW);
27 }
28 count=0;
29 memset(buffer,0,20);
30 }
31 }
Use character string to handle function header file.
1 #include "string.h"
Define a buffer to receive data from Bluetooth, and use "count" to record the bytes of data received.
17 char buffer[20];
18 static int count = 0;
Initialize the classic Bluetooth and name it as "ESP32test"
26 SerialBT.begin("ESP32test"); //Bluetooth device name

Any concerns?  support@freenove.com


308 Chapter 27 Bluetooth www.freenove.com █

When receive data, read the Bluetooth data and store it into buffer array.
15 while(SerialBT.available()){
16 buffer[count] = SerialBT.read();
17 count++;
18 }
Compare the content in buffer array with "led_on" and "led_off" to see whether they are the same. If yes,
execute the corresponding operation.
22 if(strncmp(buffer,"led_on",6)==0){
23 digitalWrite(LED,HIGH);
24 }
25 if(strncmp(buffer,"led_off",7)==0){
26 digitalWrite(LED,LOW);
27 }
After comparing the content of array, to ensure successful transmission next time, please empty the array
and set the count to zero.
28 count=0;
29 memset(buffer,0,20);

Reference
strncmp() functions are often used for string comparisons, which are accurate and stable.
int strncmp(const char *str1, const char *str2, size_t n)
str1: the first string to be compared
str2: the second string to be compared
n: the biggest string to be compared
Return value: if stir1>str2, then return value>0.
If return value is 0, then the contents of str1 and str2 are the same.
If str1< str2, then return value<0.
Function memset is mainly used to clean and initialize the memory of array
void *memset(void *s, int c, unsigned long n)
Function memset() is to set the content of a certain internal storage as specified value.
*s: the initial address of the content to clear out.
c:to be replaced as specified value
n: the number of byte to be replaced

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 28 Bluetooth Media by DAC 309

Chapter 28 Bluetooth Media by DAC


ESP32 integrates Classic Bluetooth and Bluetooth Low Energy(BLE). It can transmit not only simple data and
orders, but also files including texts and audios. In this section, we will utilize the audio's receiving function of
Bluetooth to receive music from mobile phones and play it.

Project 28.1 Playing Bluetooth Music through DAC

Use the Bluetooth audio receiving function of ESP32 to transcode the audio data from mobile phones and
play the music through DAC output pin.
The accuracy of ESP32's DAC is only eight bits, so the music would be distorted to some extent using this
tutorial.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Micro USB Wire x1 Speaker

Any concerns?  support@freenove.com


310 Chapter 28 Bluetooth Media by DAC www.freenove.com █

Component knowledge

signal conversion
Bluetooth devices receive music data from mobile devices, which cannot play through earphones and
speakers directly. To output DAC signal, Bluetooth devices need to decode these data with I2S decoding
chip. The power of these audio signals is so small that it can only drives low-power music listening devices,
such as earphone. Amplify the power of these DAC signals with power amplifier chip, so that it can drive
relatively bigger-power music playing devices, such as speakers.

In this chapter, we use ESP32-WROVER's built-in audio decoding feature to convert the received Bluetooth
data directly into an audio signal and output it via ESP32-WROVER's DAC pin.

Circuit

Schematic diagram

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 28 Bluetooth Media by DAC 311

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Sketch

Before compiling the code, follow these steps for the setting:
1,“Tools”“Partition Scheme””Huge APP (3MB No OTA/1MB SPIFFS)”;
2,“Tools”“Flash Mode””DOUT”;
3,“Tools”“Flash Frequency””80MHz”;
You can refer to the following picture for configuration
Sketch_28.1_Bluetooth_Music_by_DAC
Note: ESP32 board support packages are different and will cause compilation failures. We provide
two codes, if you can't use it, please change another code.

Any concerns?  support@freenove.com


312 Chapter 28 Bluetooth Media by DAC www.freenove.com █

Compile and upload the code to the ESP32-WROVER and open the serial monitor. ESP32 takes a few
seconds to initialize the program. When you see the prompt as shown in the figure below, it means that the
Bluetooth function of ESP32 is ready and waiting for the connection of other Bluetooth devices.

Please use your mobile phone to search and connect a Bluetooth device named "ESP32". After the
connection is successful, you can use ESP32 to play the audio files in your mobile phone.

The following is the program code:


1 #include "BluetoothSerial.h"
2 #include "driver/i2s.h"
3 #include "nvs.h"
4 #include "nvs_flash.h"
5 #include "esp_bt.h"
6 #include "bt_app_core.h"
7 #include "bt_app_av.h"
8 #include "esp_bt_main.h"
9 #include "esp_bt_device.h"
10 #include "esp_gap_bt_api.h"
11 #include "esp_a2dp_api.h"
12 #include "esp_avrc_api.h"
13
14 #define CONFIG_CLASSIC_BT_ENABLED
15 #define CONFIG_BT_ENABLED
16 #define CONFIG_BLUEDROID_ENABLED
17
18 BluetoothSerial SerialBT;
19
20 static void bt_av_hdl_stack_evt(uint16_t event, void *p_param){

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 28 Bluetooth Media by DAC 313

21 if(event==0) {
22 /* initialize A2DP sink */
23 esp_a2d_register_callback(&bt_app_a2d_cb);
24 esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
25 esp_a2d_sink_init();
26 /* initialize AVRCP controller */
27 esp_avrc_ct_init();
28 esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
29 /* set discoverable and connectable mode, wait to be connected */
30 esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
31 }
32 }
33
34 void setup() {
35 Serial.begin(115200);
36 SerialBT.begin("ESP32");
37 Serial.println("Init seccess! ");
38
39 esp_err_t err = nvs_flash_init();
40 if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
41 ESP_ERROR_CHECK(nvs_flash_erase());
42 err = nvs_flash_init();
43 }
44 i2s_config_t i2s_config;
45 i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN);
46 i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT;
47 i2s_config.sample_rate = 44100;
48 i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; //2-channels
49 i2s_config.communication_format = I2S_COMM_FORMAT_I2S_MSB;
50 i2s_config.intr_alloc_flags = 0;
51 i2s_config.dma_buf_count = 6;
52 i2s_config.dma_buf_len = 60;
53 i2s_config.tx_desc_auto_clear = true;
54 i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
55 i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
56 i2s_set_pin(I2S_NUM_0, NULL);
57
58 esp_bluedroid_init();
59 esp_bluedroid_enable();
60 bt_app_task_start_up();
61 bt_app_work_dispatch(bt_av_hdl_stack_evt, 0, NULL, 0, NULL);
62 Serial.println("Please use your Bluetooth device to connect the ESP32! ");
63 }
64

Any concerns?  support@freenove.com


314 Chapter 28 Bluetooth Media by DAC www.freenove.com █

65 void loop(){
66 ;
67 }

Add program files related to Bluetooth and API interface files.


1 #include "BluetoothSerial.h"
2 #include "driver/i2s.h"
3 #include "nvs.h"
4 #include "nvs_flash.h"
5 #include "esp_bt.h"
6 #include "bt_app_core.h"
7 #include "bt_app_av.h"
8 #include "esp_bt_main.h"
9 #include "esp_bt_device.h"
10 #include "esp_gap_bt_api.h"
11 #include "esp_a2dp_api.h"
12 #include "esp_avrc_api.h"
Set the Bluetooth in slave mode through macro definition and use it to receive data from other devices.
14 #define CONFIG_CLASSIC_BT_ENABLED
15 #define CONFIG_BT_ENABLED
16 #define CONFIG_BLUEDROID_ENABLED
Initialize the serial port and set the baud rate to 115200; initialize Bluetooth and name it as "ESP32".
35 Serial.begin(115200);
36 SerialBT.begin("ESP32");
37 Serial.println("Init seccess! ");
Define an I2S interface variable and initialize it.
44 i2s_config_t i2s_config;
45 i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN);
46 i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT;
47 i2s_config.sample_rate = 44100; // sampling frequency of audio data
48 i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;//Left and right channels
49 i2s_config.communication_format = I2S_COMM_FORMAT_I2S_MSB;
50 i2s_config.intr_alloc_flags = 0; //Set interrupt priority
51 i2s_config.dma_buf_count = 6; //Set up DMA data partitions
52 i2s_config.dma_buf_len = 60; //Set the DMA capacity for each partition
53 i2s_config.tx_desc_auto_clear = true; //Set automatic clearing of DMA data
54 i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);//Initialize I2S function
55 i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);//Set the DAC to dual channel mode
56 i2s_set_pin(I2S_NUM_0, NULL); //Set the output pin as GPIO25
Initialize the Bluetooth hardware device, establish a Bluetooth thread task, and print out messages to prompt
the user to take the next step.
58 esp_bluedroid_init();
59 esp_bluedroid_enable();
60 bt_app_task_start_up();

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 28 Bluetooth Media by DAC 315

61 bt_app_work_dispatch(bt_av_hdl_stack_evt, 0, NULL, 0, NULL);


62 Serial.println("Please use your Bluetooth device to connect the ESP32! ");

Bluetooth thread task: Set Bluetooth to slave mode; initialize Bluetooth command resolution function; set
Bluetooth to be visible to other devices and in waiting for connection mode.
20 static void bt_av_hdl_stack_evt(uint16_t event, void *p_param){
21 if(event==0) {
22 /* initialize A2DP sink */
23 esp_a2d_register_callback(&bt_app_a2d_cb);
24 esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
25 esp_a2d_sink_init();
26 /* initialize AVRCP controller */
27 esp_avrc_ct_init();
28 esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
29 /* set discoverable and connectable mode, wait to be connected */
30 esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
31 }
32 }

Any concerns?  support@freenove.com


316 Chapter 29 Bluetooth Media by PCM5102A www.freenove.com █

Chapter 29 Bluetooth Media by PCM5102A


In the previous section, ESP32's own DAC was used to output the audio signal, and obviously there was some
distortion in the sound quality. In this section, with the help of PCM5102A chip, you will enjoy higher-quality
music.

Project 29.1 Playing Bluetooth Music through PCM5102A

In this project, we will use PCM5102A chip to transcode audio data into stereo and output it.

Component List

ESP32-WROVER x1 GPIO Extension Board x1

Micro USB Wire x1 Audio Converter & Amplifier Speaker

Jumper F/M x4
Jumper F/F x2

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 29 Bluetooth Media by PCM5102A 317

Component knowledge

The front and reverse view of Audio Converter & Amplifier module.
front view reverse view schematic diagram

Interface description for Audio Converter & Amplifier module


Pin Name Introductions
1 SCK System clock input
2 BCK Audio data bit clock input
3 DIN Audio data input
4 LCK Audio data word clock input
5 VCC Power input,3.3V~5.0V
6 GND Power Ground
7 L External audio left channel input
8 G Power Ground
9 R External audio right channel input
10 G Power Ground
11 R+ Positive pole of right channel horn
12 R- Negative pole of right channel horn
13 L+ Positive pole of left channel horn
14 L- Negative pole of left channel horn

Speaker Headphone
interface interface

I2S input
interface
External audio
input interface
Power
interface

Any concerns?  support@freenove.com


318 Chapter 29 Bluetooth Media by PCM5102A www.freenove.com █

Speaker interface: Connect left channel speaker and right channel speaker. Group L: L+ & L-; Group R:
R+& R-. The two interfaces of the speaker can be connected to the interfaces of group L or group R. But
when one interface is connected to group L, the other cannot be connected to group R. Doing so may cause
the module to malfunction.
Headphone interface: the interface to connect the headphones.
I2S input interface: connect to the device with I2S. Used to transcode audio data into DAC audio signals.
External audio input interface: connect to external audio equipment. Used to amplify externally input
audio signals.
Power interface: connect to external power supply. External power supply selection range: 3.3V-5.0V.

Circuit

Schematic diagram

Hardware connection. If you need any support, please feel free to contact us via: support@freenove.com

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 29 Bluetooth Media by PCM5102A 319

Sketch

Before compiling and upload the program, please check whether your configuration conforms with the
following illustration.
Sketch_29.1_Bluetooth_Music_by_PCM5102A
Note: ESP32 board support packages are different and will cause compilation failures. We provide two
codes, if you can't use it, please change another code.

Compile and upload the code to the ESP32-WROVER and open the serial monitor. ESP32 takes a few
seconds to initialize the program. When you see the prompt as shown in the figure below, it means that the
Bluetooth function of ESP32 is ready and waiting for the connection of other Bluetooth devices.

Please use your mobile phone to search and connect a Bluetooth device named "ESP32". After the
connection is successful, you can use ESP32 to play the audio files in your mobile phone.

Any concerns?  support@freenove.com


320 Chapter 29 Bluetooth Media by PCM5102A www.freenove.com █

The following is the program code:


1 #include "BluetoothSerial.h"
2 #include "driver/i2s.h"
3 #include "nvs.h"
4 #include "nvs_flash.h"
5 #include "esp_bt.h"
6 #include "bt_app_core.h"
7 #include "bt_app_av.h"
8 #include "esp_bt_main.h"
9 #include "esp_bt_device.h"
10 #include "esp_gap_bt_api.h"
11 #include "esp_a2dp_api.h"
12 #include "esp_avrc_api.h"
13
14 #define CONFIG_I2S_LRCK_PIN 25
15 #define CONFIG_I2S_BCK_PIN 26
16 #define CONFIG_I2S_DATA_PIN 22
17 BluetoothSerial SerialBT;
18
19 void setup() {
20 Serial.begin(115200);
21 SerialBT.begin("ESP32");
22 Serial.println("Init seccess! ");
23
24 esp_err_t err = nvs_flash_init();
25 if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
26 ESP_ERROR_CHECK(nvs_flash_erase());
27 err = nvs_flash_init();
28 }
29
30 i2s_config_t i2s_config;
31 i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
32 i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT;
33 i2s_config.sample_rate = 44100;

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 29 Bluetooth Media by PCM5102A 321

34 i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
35 i2s_config.communication_format = I2S_COMM_FORMAT_I2S_MSB;
36 i2s_config.intr_alloc_flags = 0;
37 i2s_config.dma_buf_count = 6;
38 i2s_config.dma_buf_len = 60;
39 i2s_config.tx_desc_auto_clear = true;
40 i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
41 i2s_pin_config_t pin_config;
42 pin_config.bck_io_num = CONFIG_I2S_BCK_PIN;
43 pin_config.ws_io_num = CONFIG_I2S_LRCK_PIN;
44 pin_config.data_out_num = CONFIG_I2S_DATA_PIN;
45 pin_config.data_in_num = -1;
46 i2s_set_pin(I2S_NUM_0, &pin_config);
47
48 bt_app_task_start_up();
49
50 /* initialize A2DP sink */
51 esp_a2d_register_callback(&bt_app_a2d_cb);
52 esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
53 esp_a2d_sink_init();
54 /* initialize AVRCP controller */
55 esp_avrc_ct_init();
56 esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
57 /* set discoverable and connectable mode, wait to be connected */
58 esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
59 Serial.println("Please use your Bluetooth device to connect the ESP32! ");
60 }
61
62 void loop(){
63 ;
64 }
Define an I2S configuration class and initialize it; define an I2S pin configuration class and associate I2S signals
with these pins.
30 i2s_config_t i2s_config;
31 i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
32 i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT;
33 i2s_config.sample_rate = 44100;
34 i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
35 i2s_config.communication_format = I2S_COMM_FORMAT_I2S_MSB;
36 i2s_config.intr_alloc_flags = 0;
37 i2s_config.dma_buf_count = 6;
38 i2s_config.dma_buf_len = 60;
39 i2s_config.tx_desc_auto_clear = true;
40 i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);//

Any concerns?  support@freenove.com


322 Chapter 29 Bluetooth Media by PCM5102A www.freenove.com █

41 i2s_pin_config_t pin_config;
42 pin_config.bck_io_num = CONFIG_I2S_BCK_PIN;
43 pin_config.ws_io_num = CONFIG_I2S_LRCK_PIN;
44 pin_config.data_out_num = CONFIG_I2S_DATA_PIN;
45 pin_config.data_in_num = -1;
46 i2s_set_pin(I2S_NUM_0, &pin_config);
In this chapter, the procedure is very similar to the previous section. The difference only lies in the I2S
configuration. The audio quality of the DAC output from the PCM5102 chip after decoding is significantly
higher than that of the ESP32's own 8-bit precision DAC.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 30 WiFi Working Modes 323

Chapter 30 WiFi Working Modes


In this chapter, we'll focus on the WiFi infrastructure for ESP32-WROVER.
ESP32-WROVER has 3 different WiFi operating modes: station mode, AP mode and AP+station mode. All
WiFi programming projects must be configured with WiFi operating mode before using WiFi, otherwise WiFi
cannot be used.

Project 30.1 Station mode

Component List

Micro USB Wire x1 ESP32-WROVER x1

Component knowledge

Station mode
When ESP32 selects Station mode, it acts as a WiFi client. It can connect to the router network and
communicate with other devices on the router via WiFi connection. As shown below, the PC is connected to
the router, and if ESP32 wants to communicate with the PC, it needs to be connected to the router.

Any concerns?  support@freenove.com


324 Chapter 30 WiFi Working Modes www.freenove.com █

Circuit

Connect Freenove ESP32 to the computer using the USB cable.

Sketch

Sketch_30.1_Station_mode

Enter the correct Router


name and password.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 30 WiFi Working Modes 325

Because the names and passwords of routers in various places are different, before the Sketch runs, users
need to enter the correct router’s name and password in the box as shown in the illustration above.
After making sure the router name and password are entered correctly, compile and upload codes to ESP32-
WROVER, open serial monitor and set baud rate to 115200. And then it will display as follows:

When ESP32-WROVER successfully connects to “ssid_Router”, serial monitor will print out the IP address
assigned to ESP32-WROVER by the router.
The following is the program code:
1 #include <WiFi.h>
2
3 const char *ssid_Router = "********"; //Enter the router name
4 const char *password_Router = "********"; //Enter the router password
5
6 void setup(){
7 Serial.begin(115200);
8 delay(2000);
9 Serial.println("Setup start");
10 WiFi.begin(ssid_Router, password_Router);
11 Serial.println(String("Connecting to ")+ssid_Router);
12 while (WiFi.status() != WL_CONNECTED){
13 delay(500);
14 Serial.print(".");
15 }
16 Serial.println("\nConnected, IP address: ");
17 Serial.println(WiFi.localIP());
18 Serial.println("Setup End");
19 }
20
21 void loop() {
22 }

Any concerns?  support@freenove.com


326 Chapter 30 WiFi Working Modes www.freenove.com █

Include the WiFi Library header file of ESP32.


1 #include <WiFi.h>
Enter correct router name and password.
3 const char *ssid_Router = "********"; //Enter the router name
4 const char *password_Router = "********"; //Enter the router password
Set ESP32 in Station mode and connect it to your router.
10 WiFi.begin(ssid_Router, password_Router);
Check whether ESP32 has connected to router successfully every 0.5s.
12 while (WiFi.status() != WL_CONNECTED){
13 delay(500);
14 Serial.print(".");
15 }
Serial monitor prints out the IP address assigned to ESP32-WROVER
17 Serial.println(WiFi.localIP());
Reference
Class Station
Every time when using WiFi, you need to include header file "WiFi.h.".
begin(ssid, password,channel, bssid, connect): ESP32 is used as Station to connect hotspot.
ssid: WiFi hotspot name
password: WiFi hotspot password
channel: WiFi hotspot channel number; communicating through specified channel; optional parameter
bssid: mac address of WiFi hotspot, optional parameter
connect: blloean optional parameter, defaulting to true. If set as false, then ESP32 won't connect WiFi.
config(local_ip, gateway, subnet, dns1, dns2): set static local IP address.
local_ip: station fixed IP address.
subnet:subnet mask
dns1,dns2: optional parameter. define IP address of domain name server
status: obtain the connection status of WiFI
local IP(): obtian IP address in Station mode
disconnect(): disconnect wifi
setAutoConnect(boolen): set automatic connection Every time ESP32 is power on, it will connect WiFi
aitomatically.
setAutoReconnect(boolen): set automatic reconnection Every time ESP32 disconnects WiFi, it will
reconnect to WiFi automatically.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 30 WiFi Working Modes 327

Project 30.2 AP mode

Component List & Circuit

Component List & Circuit are the same as in Section 30.1.

Component knowledge

AP mode
When ESP32 selects AP mode, it creates a hotspot network that is separate from the Internet and waits for
other WiFi devices to connect. As shown in the figure below, ESP32 is used as a hotspot. If a mobile phone or
PC wants to communicate with ESP32, it must be connected to the hotspot of ESP32. Only after a connection
is established with ESP32 can they communicate.

Circuit

Connect Freenove ESP32 to the computer using the USB cable.

Any concerns?  support@freenove.com


328 Chapter 30 WiFi Working Modes www.freenove.com █

Sketch

Set a name and a


password for ESP32 AP.

Before the Sketch runs, you can make any changes to the AP name and password for ESP32 in the box as
shown in the illustration above. Of course, you can leave it alone by default.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 30 WiFi Working Modes 329

Compile and upload codes to ESP32-WROVER, open the serial monitor and set the baud rate to 115200. And
then it will display as follows.

When observing the print information of the serial monitor, turn on the WiFi scanning function of your phone,
and you can see the ssid_AP on ESP32, which is called "WiFi_Name" in this Sketch. You can enter the password
"12345678" to connect it or change its AP name and password by modifying Sketch.

Any concerns?  support@freenove.com


330 Chapter 30 WiFi Working Modes www.freenove.com █

Sketch_30.2_AP_mode
The following is the program code:
1 #include <WiFi.h>
2
3 const char *ssid_AP = "WiFi_Name"; //Enter the router name
4 const char *password_AP = "12345678"; //Enter the router password
5
6 IPAddress local_IP(192,168,1,100);//Set the IP address of ESP32 itself
7 IPAddress gateway(192,168,1,10); //Set the gateway of ESP32 itself
8 IPAddress subnet(255,255,255,0); //Set the subnet mask for ESP32 itself
9
10 void setup(){
11 Serial.begin(115200);
12 delay(2000);
13 Serial.println("Setting soft-AP configuration ... ");
14 WiFi.disconnect();
15 WiFi.mode(WIFI_AP);
16 Serial.println(WiFi.softAPConfig(local_IP, gateway, subnet) ? "Ready" : "Failed!");
17 Serial.println("Setting soft-AP ... ");
18 boolean result = WiFi.softAP(ssid_AP, password_AP);
19 if(result){
20 Serial.println("Ready");
21 Serial.println(String("Soft-AP IP address = ") + WiFi.softAPIP().toString());
22 Serial.println(String("MAC address = ") + WiFi.softAPmacAddress().c_str());
23 }else{
24 Serial.println("Failed!");
25 }
26 Serial.println("Setup End");
27 }
28
29 void loop() {
30 }
Include WiFi Library header file of ESP32.
1 #include <WiFi.h>
Enter correct AP name and password.
3 const char *ssid_AP = "WiFi_Name"; //Enter the router name
4 const char *password_AP = "12345678"; //Enter the router password
Set ESP32 in AP mode.
15 WiFi.mode(WIFI_AP);
Configure IP address, gateway and subnet mask for ESP32.
16 WiFi.softAPConfig(local_IP, gateway, subnet)
Turn on an AP in ESP32, whose name is set by ssid_AP and password is set by password_AP.
18 WiFi.softAP(ssid_AP, password_AP);

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 30 WiFi Working Modes 331

Check whether the AP is turned on successfully. If yes, print out IP and MAC address of AP established by
ESP32. If no, print out the failure prompt.
19 if(result){
20 Serial.println("Ready");
21 Serial.println(String("Soft-AP IP address = ") + WiFi.softAPIP().toString());
22 Serial.println(String("MAC address = ") + WiFi.softAPmacAddress().c_str());
23 }else{
24 Serial.println("Failed!");
25 }
26 Serial.println("Setup End");
Reference
Class AP
Every time when using WiFi, you need to include header file "WiFi.h.".
softAP(ssid, password, channel, ssid_hidden, max_connection):
ssid: WiFi hotspot name
password: WiFi hotspot password
channel: Number of WiFi connection channels, range 1-13. The default is 1.
ssid_hidden: Whether to hide WiFi name from scanning by other devices. The default is not hide.
max_connection: Maximum number of WiFi connected devices. The range is 1-4. The default is 4.
softAPConfig(local_ip, gateway, subnet): set static local IP address.
local_ip: station fixed IP address.
Gateway: gateway IP address
subnet:subnet mask
softAP(): obtian IP address in AP mode
softAPdisconnect (): disconnect AP mode.

Any concerns?  support@freenove.com


332 Chapter 30 WiFi Working Modes www.freenove.com █

Project 30.3 AP+Station mode

Component List

Micro USB Wire x1 ESP32-WROVER x1

Component knowledge

AP+Station mode
In addition to AP mode and station mode, ESP32 can also use AP mode and station mode at the same time.
This mode contains the functions of the previous two modes. Turn on ESP32's station mode, connect it to the
router network, and it can communicate with the Internet via the router. At the same time, turn on its AP
mode to create a hotspot network. Other WiFi devices can choose to connect to the router network or the
hotspot network to communicate with ESP32.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 30 WiFi Working Modes 333

Circuit

Connect Freenove ESP32 to the computer using the USB cable.

Sketch

Sketch_30.3_AP_Station_mode

Please enter the correct


names and passwords of
Router and AP.

It is analogous to project 30.1 and project 30.2. Before running the Sketch, you need to modify ssid_Router,
password_Router, ssid_AP and password_AP shown in the box of the illustration above.

Any concerns?  support@freenove.com


334 Chapter 30 WiFi Working Modes www.freenove.com █

After making sure that Sketch is modified correctly, compile and upload codes to ESP32-WROVER, open serial
monitor and set baud rate to 115200. And then it will display as follows:

When observing the print information of the serial monitor, turn on the WiFi scanning function of your phone,
and you can see the ssid_AP on ESP32.

The following is the program code:


1 #include <WiFi.h>
2
3 const char *ssid_Router = "********"; //Enter the router name
4 const char *password_Router = "********"; //Enter the router password
5 const char *ssid_AP = "WiFi_Name"; //Enter the AP name
6 const char *password_AP = "12345678"; //Enter the AP password
7
8 void setup(){
9 Serial.begin(115200);
10 Serial.println("Setting soft-AP configuration ... ");
11 WiFi.disconnect();

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 30 WiFi Working Modes 335

12 WiFi.mode(WIFI_AP);
13 Serial.println("Setting soft-AP ... ");
14 boolean result = WiFi.softAP(ssid_AP, password_AP);
15 if(result){
16 Serial.println("Ready");
17 Serial.println(String("Soft-AP IP address = ") + WiFi.softAPIP().toString());
18 Serial.println(String("MAC address = ") + WiFi.softAPmacAddress().c_str());
19 }else{
20 Serial.println("Failed!");
21 }
22
23 Serial.println("\nSetting Station configuration ... ");
24 WiFi.begin(ssid_Router, password_Router);
25 Serial.println(String("Connecting to ")+ ssid_Router);
26 while (WiFi.status() != WL_CONNECTED){
27 delay(500);
28 Serial.print(".");
29 }
30 Serial.println("\nConnected, IP address: ");
31 Serial.println(WiFi.localIP());
32 Serial.println("Setup End");
33 }
34
35 void loop() {
36 }

Any concerns?  support@freenove.com


336 Chapter 31 TCP/IP www.freenove.com █

Chapter 31 TCP/IP
In this chapter, we will introduce how ESP32 implements network communications based on TCP/IP protocol.
There are two roles in TCP/IP communication, namely Server and Client, which will be implemented
respectively with two projects in this chapter.

Project 31.1 As Client

In this section, ESP32 is used as Client to connect Server on the same LAN and communicate with it.

Component List

ESP32-WROVER x1 Micro USB Wire x1

Component knowledge

TCP connection
Before transmitting data, TCP needs to establish a logical connection between the sending end and the
receiving end. It provides reliable and error-free data transmission between the two computers. In the TCP
connection, the client and the server must be clarified. The client sends a connection request to the server,
and each time such a request is proposed, a "three-times handshake" is required.

Three-times handshake: In the TCP protocol, during the preparation phase of sending data, the client and the
server interact three times to ensure the reliability of the connection, which is called "three-times handshake".
The first handshake, the client sends a connection request to the server and waits for the server to confirm.
The second handshake, the server sends a response back to the client informing that it has received the
connection request.
The third handshake, the client sends a confirmation message to the server again to confirm the connection.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 31 TCP/IP 337

the first handshake

the second handshake

the third handshake

TCP is a connection-oriented, low-level transmission control protocol. After TCP establishes a connection, the
client and server can send and receive messages to each other, and the connection will always exist as long
as the client or server does not initiate disconnection. Each time one party sends a message, the other party
will reply with an ack signal.

The client sends a data


message, and the server
replies with a
confirmation signal.

The server sends a data


message, and the client
replies with a
confirmation signal.

Any concerns?  support@freenove.com


338 Chapter 31 TCP/IP www.freenove.com █

Install Processing
In this tutorial, we use Processing to build a simple TCP/IP communication platform.
If you've not installed Processing, you can download it by clicking https://processing.org/download/. You can
choose an appropriate version to download according to your PC system.

Unzip the downloaded file to your computer. Click "processing.exe" as the figure below to run this software.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 31 TCP/IP 339

Use Server mode for communication


Open the “Freenove_Ultimate_Starter_Kit_for_ESP32\Sketches\Sketches\Sketch_31.1_WiFiClient\
sketchWiFi\sketchWiFi.pde”, and click "Run".

Stop

Run

The new pop-up interface is as follows. If ESP32 is used as client, select TCP SERVER mode for sketchWiFi.

Server mode

Receiving
Local IP address
box

Local port
number
Clear receive

Send box
Listening
Clear send

Send button

When sketchWiFi selects TCP SERVER mode, ESP32 Sketch needs to be changed according to sketchWiFi's
displaying of LOCAL IP or LOCAL PORT.

Any concerns?  support@freenove.com


340 Chapter 31 TCP/IP www.freenove.com █

If ESP32 serves as server, select TCP CLIENT mode for sketchWiFi.

Client mode

Remote IP
address

Remote port
number

When sketchWiFi selects TCP CLIENT mode, the LOCAL IP and LOCAL PORT of sketchWiFi need to be
changed according to the IP address and port number printed by the serial monitor.

Mode selection: select Server mode/Client mode.


IP address: In server mode, this option does not need to be filled in, and the computer will automatically
obtain the IP address.
In client mode, fill in the remote IP address to be connected.
Port number: In server mode, fill in a port number for client devices to make an access connection.
In client mode, fill in port number given by the Server devices to make an access connection.
Start button: In server mode, push the button, then the computer will serve as server and open a port number
for client to make access connection. During this period, the computer will keep monitoring.
In client mode, before pushing the button, please make sure the server is on, remote IP address
and remote port number is correct; push the button, and the computer will make access
connection to the remote port number of the remote IP as a client.
clear receive: clear out the content in the receiving text box
clear send: clear out the content in the sending text box
Sending button: push the sending button, the computer will send the content in the text box to others.

Circuit

Connect Freenove ESP32 to the computer using USB cable.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 31 TCP/IP 341

Sketch

Before running the Sketch, please open “sketchWiFi.pde.” first, and click “Run”.

The newly pop up window will use the computer’s IP address by default and open a data monitor port.

Next, open Sketch_31.1_WiFiClient.ino. Before running it, please change the following information based on
"LOCAL IP" and "LOCAL PORT" in the figure above.

REMOTE_IP needs to be filled in according to the interface of sketchWiFi.pde. Taking this tutorial as an
example, its REMOTE_IP is “192.168.1.133”. Generally, by default, the ports do not need to change its value.

Any concerns?  support@freenove.com


342 Chapter 31 TCP/IP www.freenove.com █

Click LISTENING, turn on TCP SERVER's data listening function and wait for ESP32 to connect.

Click it

Compile and upload code to ESP32-WROVER, open the serial monitor and set the baud rate to 115200. ESP32
connects router, obtains IP address and sends access request to server IP address on the same LAN till the
connection is successful. When connect successfully, ESP32 can send messages to server.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 31 TCP/IP 343

ESP32 connects with TCP SERVER, and TCP SERVER receives messages from ESP32, as shown in the figure
below.

Any concerns?  support@freenove.com


344 Chapter 31 TCP/IP www.freenove.com █

Sketch_31.1_As_Client
The following is the program code:
1 #include <WiFi.h>
2
3 const char *ssid_Router = "********"; //Enter the router name
4 const char *password_Router = "********"; //Enter the router password
5 #define REMOTE_IP "********" //input the remote server which is you want to connect
#define REMOTE_PORT 8888 //input the remote port which is the remote provide
6 WiFiClient client;
7
8 void setup() {
9 Serial.begin(115200);
10 delay(10);
11
12 WiFi.begin(ssid_Router, password_Router);
13 Serial.print("\nWaiting for WiFi... ");
14 while (WiFi.status() != WL_CONNECTED) {
15 Serial.print(".");
16 delay(500);
17 }
18 Serial.println("");
19 Serial.println("WiFi connected");
20 Serial.println("IP address: ");
21 Serial.println(WiFi.localIP());
22 delay(500);
23
24 Serial.print("Connecting to ");
25 Serial.println(REMOTE_IP);
26
27 while (!client.connect(REMOTE_IP, REMOTE_PORT)) {
28 Serial.println("Connection failed.");
29 Serial.println("Waiting a moment before retrying...");
30 }
31 Serial.println("Connected");
32 client.print("Hello\n");
33 client.print("This is my IP.\n");
34 }
35
36 void loop() {
37 if (client.available() > 0) {
38 delay(20);
39 //read back one line from the server
40 String line = client.readString();
41 Serial.println(REMOTE_IP + String(":") + line);

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 31 TCP/IP 345

42 }
43 if (Serial.available() > 0) {
44 delay(20);
45 String line = Serial.readString();
46 client.print(line);
47 }
48 if (client.connected () == 0) {
49 client.stop();
50 WiFi.disconnect();
51 }
52 }
Add WiFi function header file.
1 #include <WiFi.h>
Enter the actual router name, password, remote server IP address, and port number.
3 const char *ssid_Router = "********"; //Enter the router name
4 const char *password_Router = "********"; //Enter the router password
5 #define REMOTE_IP "********" //input the remote server which is you want to connect
6 #define REMOTE_PORT 8888 //input the remote port which is the remote provide
Apply for the method class of WiFiClient.
7 WiFiClient client;
Connect specified WiFi until it is successful. If the name and password of WiFi are correct but it still fails to
connect, please push the reset key.
13 WiFi.begin(ssid_Router, password_Router);
14 Serial.print("\nWaiting for WiFi... ");
15 while (WiFi.status() ! = WL_CONNECTED) {
16 Serial.print(".");
17 delay(500);
18 }
Send connection request to remote server until connect successfully. When connect successfully, print out the
connecting prompt on the serial monitor and send messages to remote server.
28 while (!client.connect(REMOTE_IP, REMOTE_PORT)) {//Connect to Server
29 Serial.println("Connection failed.");
30 Serial.println("Waiting a moment before retrying...");
31 }
32 Serial.println("Connected");
33 client.print("Hello\n");
When ESP32 receive messages from servers, it will print them out via serial port; Users can also send messages
to servers from serial port.
37 if (client.available() > 0) {
38 delay(20);
39 //read back one line from the server
40 String line = client.readString();
41 Serial.println(REMOTE_IP + String(":") + line);
42 }

Any concerns?  support@freenove.com


346 Chapter 31 TCP/IP www.freenove.com █

43 if (Serial.available() > 0) {
44 delay(20);
45 String line = Serial.readString();
46 client.print(line);
47 }
If the server is disconnected, turn off WiFi of ESP32.
48 if (client.connected () == false) {
49 client.stop();
50 WiFi.disconnect();
51 }
Reference
Class Client
Every time when using Client, you need to include header file "WiFi.h."
connect(ip, port, timeout)/connect(*host, port, timeout): establish a TCP connection.
ip, *host:ip address of target server
port: port number of target server
timeout: connection timeout
connected(): judge whether client is connecting. If return value is 1, then connect successfully; If return
value is 0, then fail to connect.
stop(): stop tcp connection
print(): send data to server connecting to client
available(): return to the number of bytes readable in receive buffer, if no, return to 0 or -1.
read(): read one byte of data in receive buffer
readString(): read string in receive buffer

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 31 TCP/IP 347

Project 31.2 As Server

In this section, ESP32 is used as a server to wait for the connection and communication of client on the same
LAN.

Component List

ESP32-WROVER x1 Micro USB Wire x1

Circuit

Connect Freenove ESP32 to the computer using a USB cable.

Any concerns?  support@freenove.com


348 Chapter 31 TCP/IP www.freenove.com █

Sketch

Before running Sketch, please modify the contents of the box below first.
Sketch_31.2_As_Server

Compile and upload code to ESP32-WROVER board, open the serial monitor and set the baud rate to
115200. Turn on server mode for ESP32, waiting for the connection of other devices on the same LAN. Once
a device connects to server successfully, they can send messages to each other.
If the ESP32 fails to connect to router, press the reset button as shown below and wait for ESP32 to run again.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 31 TCP/IP 349

Serial Monitor

IP address and
serial port

Processing:
Open the “Freenove_Ultimate_Starter_Kit_for_ESP32\Sketches\Sketches\Sketch_31.2_WiFiServer\
sketchWiFi\sketchWiFi.pde”.
Based on the messages printed by the serial monitor, enter correct IP address and serial port in Processing to
establish connection and make communication.

Enter IP address and


serial port of the serial
monitor.

Any concerns?  support@freenove.com


350 Chapter 31 TCP/IP www.freenove.com █

The following is the program code:


1 #include <WiFi.h>
2
3 #define port 80
4 const char *ssid_Router = "********"; //input your wifi name
5 const char *password_Router = "********"; //input your wifi passwords
6 WiFiServer server(port);
7
8 void setup()
9 {
10 Serial.begin(115200);
11 Serial.printf("\nConnecting to ");
12 Serial.println(ssid_Router);
13 WiFi.disconnect();
14 WiFi.begin(ssid_Router, password_Router);
15 delay(1000);
16 while (WiFi.status() != WL_CONNECTED) {
17 delay(500);
18 Serial.print(".");
19 }
20 Serial.println("");
21 Serial.println("WiFi connected.");
22 Serial.print("IP address: ");
23 Serial.println(WiFi.localIP());
24 Serial.printf("IP port: %d\n",port);
25 server.begin(port);
26 WiFi.setAutoConnect(true);
27 WiFi.setAutoReconnect(true);
28 }
29
30 void loop(){
31 WiFiClient client = server.available(); // listen for incoming clients
32 if (client) { // if you get a client
33 Serial.println("Client connected.");
34 while (client.connected()) { // loop while the client's connected
35 if (client.available()) { // if there's bytes to read from the
client
36 Serial.println(client.readStringUntil('\n')); // print it out the serial monitor
37 while(client.read()>0); // clear the wifi receive area cache
38 }
39 if(Serial.available()){ // if there's bytes to read from the
serial monitor
40 client.print(Serial.readStringUntil('\n')); // print it out the client.
41 while(Serial.read()>0); // clear the wifi receive area cache

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 31 TCP/IP 351

42 }
43 }
44 client.stop(); // stop the client connecting.
45 Serial.println("Client Disconnected.");
46 }
47 }
Apply for method class of WiFiServer.
6 WiFiServer server(port); //Apply for a Server object whose port number is 80
Connect specified WiFi until it is successful. If the name and password of WiFi are correct but it still fails to
connect, please push the reset key.
13 WiFi.disconnect();
14 WiFi.begin(ssid_Router, password_Router);
15 delay(1000);
16 while (WiFi.status() != WL_CONNECTED) {
17 delay(500);
18 Serial.print(".");
19 }
20 Serial.println("");
21 Serial.println("WiFi connected.");
Print out the IP address and port number of ESP32.
22 Serial.print("IP address: ");
23 Serial.println(WiFi.localIP()); //print out IP address of ESP32
24 Serial.printf("IP port: %d\n",port); //Print out ESP32's port number
Turn on server mode of ESP32, start automatic connection and turn on automatic reconnection.
25 server.begin(); //Turn ON ESP32 as Server mode
26 WiFi.setAutoConnect(true);
27 WiFi.setAutoReconnect(true);
When ESP32 receive messages from servers, it will print them out via serial port; Users can also send messages
to servers from serial port.
35 if (client.available()) { // if there's bytes to read from the
client
36 Serial.println(client.readStringUntil('\n')); // print it out the serial monitor
37 while(client.read()>0); // clear the wifi receive area cache
38 }
39 if(Serial.available()){ // if there's bytes to read from the
serial monitor
40 client.print(Serial.readStringUntil('\n')); // print it out the client.
41 while(Serial.read()>0); // clear the wifi receive area cache
42 }

Any concerns?  support@freenove.com


352 Chapter 31 TCP/IP www.freenove.com █

Reference
Class Server
Every time use Server functionality, we need to include header file"WiFi.h".
WiFiServer(uint16_t port=80, uint8_t max_clients=4): create a TCP Server.
port: ports of Server; range from 0 to 65535 with the default number as 80.
max_clients: maximum number of clients with default number as 4.
begin(port): start the TCP Server.
port: ports of Server; range from 0 to 65535 with the default number as 0.
setNoDelay(bool nodelay): whether to turn off the delay sending functionality.
nodelay: true stands for forbidden Nagle algorithm.
close(): close tcp connection.
stop(): stop tcp connection.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 32 Camera Web Server 353

Chapter 32 Camera Web Server


In this section, we'll use ESP32's video function as an example to study.

Project 32.1 Camera Web Server

Connect ESP32 using USB and check its IP address through serial monitor. Use web page to access IP address
to obtain video and image data.

Component List

Micro USB Wire x1 ESP32-WROVER x1

Circuit

Connect Freenove ESP32 to the computer using USB cable.

Any concerns?  support@freenove.com


354 Chapter 32 Camera Web Server www.freenove.com █

Sketch

Click Tools in the menu bar, select Flash Mode: "QIO", and select Partition Scheme:" Huge APP (3MB No
OTA/1MB SPIFFS) “, as shown in the figure below.

The reason for this configuration is that the Sketch occupies about 2MB of program storage, while in the
previous default mode, it was about 1.2M. Therefore, we need to choose a more appropriate partitioning
scheme for ESP32.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 32 Camera Web Server 355

Sketch_32.1_As_CameraWebServer

Before running the program, please modify your router’s name and password in the box shown in the
illustration above to make sure that your Sketch can compile and work successfully.

Compile and upload codes to ESP32, open the serial monitor and set the baud rate to 115200, and the serial
monitor will print out a network link address.

Any concerns?  support@freenove.com


356 Chapter 32 Camera Web Server www.freenove.com █

If your ESP32 has been in the process of connecting to router, but the information above has not been printed
out, please re-check whether the router name and password have been entered correctly and press the reset
key on ESP32-WROVER to wait for a successful connection prompt.

Open a web browser, enter the IP address printed by the serial monitor in the address bar, and access it.
Taking the Google browser as an example, here's what the browser prints out after successful access to
ESP32's IP.

enter IP address

select pixel of the picture

adjust camera parameters

set camera left and


right, up and down

crop the picture turn on video


transmission

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 32 Camera Web Server 357

Click on Start Stream. The effect is shown in the image below.

Note: If sketch compilation fails due to ESP32 support package, follow the steps of the image to open
the CameraWebServer. This sketch is the same as described in the tutorial above.

Any concerns?  support@freenove.com


358 Chapter 32 Camera Web Server www.freenove.com █

The following is the main program code. You need include other code files in the same folder when write
your own code.
1 #include "esp_camera.h"
2 #include <WiFi.h>
3
4 // Select camera model
5 #define CAMERA_MODEL_WROVER_KIT
6 //#define CAMERA_MODEL_ESP_EYE
7 //#define CAMERA_MODEL_M5STACK_PSRAM
8 //#define CAMERA_MODEL_M5STACK_WIDE
9 //#define CAMERA_MODEL_AI_THINKER
10
11 #include "camera_pins.h"
12
13 const char *ssid_Router = "********"; //input your wifi name
14 const char *password_Router = "********"; //input your wifi passwords
15 camera_config_t config;
16
17 void startCameraServer();
18 void config_init();
19
20 void setup() {
21 Serial.begin(115200);
22 Serial.setDebugOutput(true);
23 Serial.println();
24
25 config_init();
26 config.frame_size = FRAMESIZE_VGA;
27 config.jpeg_quality = 10;
28
29 // camera init
30 esp_err_t err = esp_camera_init(&config);
31 if (err != ESP_OK) {
32 Serial.printf("Camera init failed with error 0x%x", err);
33 return;
34 }
35
36 sensor_t * s = esp_camera_sensor_get();
37 s->set_vflip(s, 1); //flip it back
38 s->set_brightness(s, 1); //up the blightness just a bit
39 s->set_saturation(s, -1); //lower the saturation
40
41 WiFi.begin(ssid_Router, password_Router);
42 while (WiFi.status() != WL_CONNECTED) {

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 32 Camera Web Server 359

43 delay(500);
44 Serial.print(".");
45 }
46 Serial.println("");
47 Serial.println("WiFi connected");
48
49 startCameraServer();
50
51 Serial.print("Camera Ready! Use 'http://");
52 Serial.print(WiFi.localIP());
53 Serial.println("' to connect");
54 }
55
56 void loop() {
57 ;
58 }
59
60 void config_init(){
61 config.ledc_channel = LEDC_CHANNEL_0;
62 config.ledc_timer = LEDC_TIMER_0;
63 config.pin_d0 = Y2_GPIO_NUM;
64 config.pin_d1 = Y3_GPIO_NUM;
65 config.pin_d2 = Y4_GPIO_NUM;
66 config.pin_d3 = Y5_GPIO_NUM;
67 config.pin_d4 = Y6_GPIO_NUM;
68 config.pin_d5 = Y7_GPIO_NUM;
69 config.pin_d6 = Y8_GPIO_NUM;
70 config.pin_d7 = Y9_GPIO_NUM;
71 config.pin_xclk = XCLK_GPIO_NUM;
72 config.pin_pclk = PCLK_GPIO_NUM;
73 config.pin_vsync = VSYNC_GPIO_NUM;
74 config.pin_href = HREF_GPIO_NUM;
75 config.pin_sscb_sda = SIOD_GPIO_NUM;
76 config.pin_sscb_scl = SIOC_GPIO_NUM;
77 config.pin_pwdn = PWDN_GPIO_NUM;
78 config.pin_reset = RESET_GPIO_NUM;
79 config.xclk_freq_hz = 20000000;
80 config.pixel_format = PIXFORMAT_JPEG;
81 config.fb_count = 1;
82 }

Any concerns?  support@freenove.com


360 Chapter 32 Camera Web Server www.freenove.com █

Add procedure files and API interface files related to ESP32 camera.
1 #include "esp_camera.h"
2 #include <WiFi.h>
3
4 // Select camera model
5 #define CAMERA_MODEL_WROVER_KIT
6 //#define CAMERA_MODEL_ESP_EYE
7 //#define CAMERA_MODEL_M5STACK_PSRAM
8 //#define CAMERA_MODEL_M5STACK_WIDE
9 //#define CAMERA_MODEL_AI_THINKER
10
11 #include "camera_pins.h"
Enter the name and password of the router
13 const char *ssid_Router = "********"; //input your wifi name
14 const char *password_Router = "********"; //input your wifi passwords
Initialize serial port, set baud rate to 115200; open the debug and output function of the serial.
21 Serial.begin(115200);
22 Serial.setDebugOutput(true);
23 Serial.println();
Configure parameters including interface pins of the camera. Note: It is generally not recommended to change
them.
60 void config_init(){
61 config.ledc_channel = LEDC_CHANNEL_0;
62 config.ledc_timer = LEDC_TIMER_0;
63 config.pin_d0 = Y2_GPIO_NUM;
64 config.pin_d1 = Y3_GPIO_NUM;
65 config.pin_d2 = Y4_GPIO_NUM;
66 config.pin_d3 = Y5_GPIO_NUM;
67 config.pin_d4 = Y6_GPIO_NUM;
68 config.pin_d5 = Y7_GPIO_NUM;
69 config.pin_d6 = Y8_GPIO_NUM;
70 config.pin_d7 = Y9_GPIO_NUM;
71 config.pin_xclk = XCLK_GPIO_NUM;
72 config.pin_pclk = PCLK_GPIO_NUM;
73 config.pin_vsync = VSYNC_GPIO_NUM;
74 config.pin_href = HREF_GPIO_NUM;
75 config.pin_sscb_sda = SIOD_GPIO_NUM;
76 config.pin_sscb_scl = SIOC_GPIO_NUM;
77 config.pin_pwdn = PWDN_GPIO_NUM;
78 config.pin_reset = RESET_GPIO_NUM;
79 config.xclk_freq_hz = 20000000;
80 config.pixel_format = PIXFORMAT_JPEG;
81 config.fb_count = 1;
82 }

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 32 Camera Web Server 361

ESP32 connects to the router and prints a successful connection prompt. If it has not been successfully
connected, press the reset key on the ESP32-WROVER.
41 WiFi.begin(ssid_Router, password_Router);
42 while (WiFi.status() ! = WL_CONNECTED) {
43 delay(500);
44 Serial.print(".");
45 }
46 Serial.println("");
47 Serial.println("WiFi connected");
Open the video streams server function of the camera and print its IP address via serial port.
49 startCameraServer();
50
51 Serial.print("Camera Ready! Use 'http://");
52 Serial.print(WiFi.localIP());
53 Serial.println("' to connect");
Configure the display image information of the camera.
The set_vflip() function sets whether the image is flipped 180°, with 0 for no flip and 1 for flip 180°.
The set_brightness() function sets the brightness of the image, with values ranging from -2 to 2.
The set_saturation() function sets the color saturation of the image, with values ranging from -2 to 2.
36 sensor_t * s = esp_camera_sensor_get();
37 s->set_vflip(s, 1); //flip it back
38 s->set_brightness(s, 1); //up the blightness just a bit
39 s->set_saturation(s, -1); //lower the saturation
Modify the resolution and sharpness of the images captured by the camera. The sharpness ranges from 10 to
63, and the smaller the number, the sharper the picture. The larger the number, the blurrier the picture. Please
refer to the table below.
26 config.frame_size = FRAMESIZE_VGA;
27 config.jpeg_quality = 10;
Reference
Image resolution Sharpness Image resolution Sharpness
FRAMESIZE_QQVGA 160x120 FRAMESIZE_VGA 640x480
FRAMESIZE_QQVGA2 128x160 FRAMESIZE_SVGA 800x600
FRAMESIZE_QCIF 176x144 FRAMESIZE_XGA 1024x768
FRAMESIZE_HQVGA 240x176 FRAMESIZE_SXGA 1280x1024
FRAMESIZE_QVGA 320x240 FRAMESIZE_UXGA 1600x1200
FRAMESIZE_CIF 400x296 FRAMESIZE_QXGA 2048x1536

Any concerns?  support@freenove.com


362 Chapter 33 Camera Tcp Server www.freenove.com █

Chapter 33 Camera Tcp Server


In the previous section, we used web page to display the video data captured by ESP32, and in this section,
we will use a mobile phone to display it.

Project 33.1 Camera Tcp Server

Connect ESP32 using USB and check its IP address through serial monitor. Use a mobile phone to obtain
video and image data.

Component List

Micro USB Wire x1 ESP32-WROVER x1

Install Freenove app

There are three ways to install app, you can choose any one.
Method 1
Use Google play to search “Freenove”, download and install.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 33 Camera Tcp Server 363

Any concerns?  support@freenove.com


364 Chapter 33 Camera Tcp Server www.freenove.com █

Method 2
Visit https://play.google.com/store/apps/details?id=com.freenove.suhayl.Freenove, and click install.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 33 Camera Tcp Server 365

Method 3
Visit https://github.com/Freenove/Freenove_app_for_Android, download the files in this library, and install
freenove.apk to your Android phone manually.

Click here to
download.

Any concerns?  support@freenove.com


366 Chapter 33 Camera Tcp Server www.freenove.com █

Menu
Open application “Freenove”, as shown below:

MENU

Device
Selection
Area

Home Page Store

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 33 Camera Tcp Server 367

Freenove 4WD Car for Raspberry Pi


In this chapter, we use Freenove 4WD Car for Raspberry Pi, so it is necessary to understand the interface of
this mode.

IP address Take photos Buzzer RGB led

Connect

Set

Control Car moving. Control camera angle and position.


Drag the middle dot to The ring in the middle is use to reset.
anywhere in the area.

Circuit

Connect Freenove ESP32 to the computer using USB cable.

Any concerns?  support@freenove.com


368 Chapter 33 Camera Tcp Server www.freenove.com █

Sketch

Click Tools in the menu bar, select Flash Mode: "QIO", and select Partition Scheme:" Huge APP (3MB No
OTA/1MB SPIFFS) “, as shown in the figure below.

After making sure the Tools is configured correctly, don’t run Sketch. Due to WiFi, we need to modify Sketch
a little bit based on physical situation.

In the box in the figure above, ssid_Router and password_Router are the user's Router name and password,
which need to be modified according to the actual name and password. ssid_AP and password_AP are name
and password of a AP created by ESP32, and they are freely set by the user. When all settings are correct,
compile and upload the code to ESP32, turn on the serial port monitor, and set the baud rate to 115200. The
serial monitor will print out two IP addresses.

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 33 Camera Tcp Server 369

There are two methods for you to check camera data of ESP32 via mobile phone APP.

Method 1:
Using your phone's WiFi function, select the WiFi name represented by ssid_AP in Sketch and enter the
password “password_AP” to connect.

Any concerns?  support@freenove.com


370 Chapter 33 Camera Tcp Server www.freenove.com █

Next, open Freenove app and select 4WD Car for Raspberry Pi mode.

Enter the IP address printed by serial port in the new interface, which generally is “192.168.4.1”

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 33 Camera Tcp Server 371

Click “Connect”.

Method 2:
Using your phone's WiFi function, select the router named ssid_Router and enter the password “ssid_password”
to connect. And then open Freenove app and select 4WD Car for Raspberry Pi mode. The operation is similar
to Method 1.

Enter the IP address printed by serial port in the new interface, which generally is not “192.168.4.1” but
another one. The IP address in this example is “192.168.1.100”. After entering the IP address, click “Connect”.

The following is the main program code. You need include other code files in the same folder when write
your own code.
Sketch_33.1_Camera_Tcp_Server
1 #include "esp_camera.h"
2 #include <WiFi.h>
3 #include <WiFiClient.h>
4 #include <WiFiAP.h>
5
6 #define CAMERA_MODEL_WROVER_KIT

Any concerns?  support@freenove.com


372 Chapter 33 Camera Tcp Server www.freenove.com █

7 #include "camera_pins.h"
8 #define LED_BUILT_IN 2
9
10 const char *ssid_Router = "********";
11 const char *password_Router = "********";
12 const char *ssid_AP = "********";
13 const char *password_AP = "********";
14
15 WiFiServer server_Cmd(5000);
16 WiFiServer server_Camera(8000);
17 extern TaskHandle_t loopTaskHandle;
18
19 void setup() {
20 Serial.begin(115200);
21 Serial.setDebugOutput(false);
22 Serial.println();
23 pinMode(LED_BUILT_IN, OUTPUT);
24 cameraSetup();
25
26 WiFi.softAP(ssid_AP, password_AP);
27 IPAddress myIP = WiFi.softAPIP();
28 Serial.print("AP IP address: ");
29 Serial.println(myIP);
30 server_Camera.begin(8000);
31 server_Cmd.begin(5000);
32 /////////////////////////////////////////////////////
33 WiFi.begin(ssid_Router, password_Router);
34 Serial.print("Connecting ");
35 Serial.print(ssid_Router);
36 while (WiFi.status() != WL_CONNECTED) {
37 delay(500);
38 Serial.print(".");
39 WiFi.begin(ssid_Router, password_Router);
40 }
41 Serial.println("");
42 Serial.println("WiFi connected");
43 /////////////////////////////////////////////////////
44 Serial.print("Camera Ready! Use '");
45 Serial.print(WiFi.softAPIP());
46 Serial.print(" or ");
47 Serial.print(WiFi.localIP());
48 Serial.println("' to connect in Freenove app.");
49
50 disableCore0WDT();

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 33 Camera Tcp Server 373

51 xTaskCreateUniversal(loopTask_Cmd, "loopTask_Cmd", 8192, NULL, 1, &loopTaskHandle, 0);


52 //loopTask_Cmd uses core 0.
53 xTaskCreateUniversal(loopTask_Blink, "loopTask_Blink", 8192, NULL, 1, &loopTaskHandle,
54 0);//loopTask_Blink uses core 0.
55 }
56 //task loop uses core 1.
57 void loop() {
58 WiFiClient client = server_Camera.available(); // listen for incoming clients
59 if (client) { // if you get a client,
60 Serial.println("Camera Server connected to a client.");// print a message out the
serial port
61 String currentLine = ""; // make a String to hold incoming data from the client
62 while (client.connected()) { // loop while the client's connected
63 camera_fb_t * fb = NULL;
64 while (client.connected()) {
65 fb = esp_camera_fb_get();
66 if (fb != NULL) {
67 uint8_t slen[4];
68 slen[0] = fb->len >> 0;
69 slen[1] = fb->len >> 8;
70 slen[2] = fb->len >> 16;
71 slen[3] = fb->len >> 24;
72 client.write(slen, 4);
73 client.write(fb->buf, fb->len);
74 }
75 else {
76 Serial.println("Camera Error");
77 }
78 }
79 }
80 // close the connection:
81 client.stop();
82 Serial.println("Camera Client Disconnected.");
83 }
84 }
85
86 void loopTask_Cmd(void *pvParameters) {
87 Serial.println("Task Cmd_Server is starting ... ");
88 while (1) {
89 WiFiClient client = server_Cmd.available(); // listen for incoming clients
90 if (client) { // if you get a client,
91 Serial.println("Command Server connected to a client.");// print a message out
the serial port
92 String currentLine = ""; // make a String to hold incoming data from the client

Any concerns?  support@freenove.com


374 Chapter 33 Camera Tcp Server www.freenove.com █

93 while (client.connected()) { // loop while the client's connected


94 if (client.available()) { // if there's bytes to read from the client,
95 char c = client.read(); // read a byte, then
96 client.write(c);
97 Serial.write(c); // print it out the serial monitor
98 if (c == '\n') { // if the byte is a newline character
99 currentLine = "";
100 }
101 else {
102 currentLine += c; // add it to the end of the currentLine
103 }
104 }
105 }
106 // close the connection:
107 client.stop();
108 Serial.println("Command Client Disconnected.");
109 }
110 }
111 }
112 void loopTask_Blink(void *pvParameters) {
113 Serial.println("Task Blink is starting ... ");
114 while (1) {
115 digitalWrite(LED_BUILT_IN, !digitalRead(LED_BUILT_IN));
116 delay(1000);
117 }
118 }
119
120 void cameraSetup() {
121 camera_config_t config;
122 config.ledc_channel = LEDC_CHANNEL_0;
123 config.ledc_timer = LEDC_TIMER_0;
124 config.pin_d0 = Y2_GPIO_NUM;
125 config.pin_d1 = Y3_GPIO_NUM;
126 config.pin_d2 = Y4_GPIO_NUM;
127 config.pin_d3 = Y5_GPIO_NUM;
128 config.pin_d4 = Y6_GPIO_NUM;
129 config.pin_d5 = Y7_GPIO_NUM;
130 config.pin_d6 = Y8_GPIO_NUM;
131 config.pin_d7 = Y9_GPIO_NUM;
132 config.pin_xclk = XCLK_GPIO_NUM;
133 config.pin_pclk = PCLK_GPIO_NUM;
134 config.pin_vsync = VSYNC_GPIO_NUM;
135 config.pin_href = HREF_GPIO_NUM;
136 config.pin_sscb_sda = SIOD_GPIO_NUM;

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 33 Camera Tcp Server 375

137 config.pin_sscb_scl = SIOC_GPIO_NUM;


138 config.pin_pwdn = PWDN_GPIO_NUM;
139 config.pin_reset = RESET_GPIO_NUM;
140 config.xclk_freq_hz = 20000000;
141 config.pixel_format = PIXFORMAT_JPEG;
142
143 psramFound();
144 config.frame_size = FRAMESIZE_QVGA;
145 config.jpeg_quality = 10;
146 config.fb_count = 1;
147
148 // camera init
149 esp_err_t err = esp_camera_init(&config);
150 if (err != ESP_OK) {
151 Serial.printf("Camera init failed with error 0x%x", err);
152 return;
153 }
154 Serial.println("Camera configuration complete!");
155 }
Include header files that drive camera and WiFi.
1 #include "esp_camera.h"
2 #include <WiFi.h>
3 #include <WiFiClient.h>
4 #include <WiFiAP.h>
5
6 #define CAMERA_MODEL_WROVER_KIT
7 #include "camera_pins.h"
8 #define LED_BUILT_IN 2
Set name and password for router that ESP32 needs to connect to. And set ESP32 to open two servers, whose
port are 82 and 5000 respectively.
10 const char *ssid_Router = "********";
11 const char *password_Router = "********";
12 const char *ssid_AP = "********";
13 const char *password_AP = "********";
Enable ESP32’s server function and set two monitor ports as 5000 and 8000. In general, the two port numbers
do not require modifications.
15 WiFiServer server_Cmd(5000);
16 WiFiServer server_Camera(8000);
17 extern TaskHandle_t loopTaskHandle;
Initialize serial port, set baud rate to 115200; open the debug and output function of the serial.
20 Serial.begin(115200);
21 Serial.setDebugOutput(true);
22 Serial.println();

Any concerns?  support@freenove.com


376 Chapter 33 Camera Tcp Server www.freenove.com █

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 33 Camera Tcp Server 377

Define a variable for camera interface and initialize it.


120 void cameraSetup() {
121 camera_config_t config;
122 config.ledc_channel = LEDC_CHANNEL_0;
123 config.ledc_timer = LEDC_TIMER_0;
124 config.pin_d0 = Y2_GPIO_NUM;
125 config.pin_d1 = Y3_GPIO_NUM;
126 config.pin_d2 = Y4_GPIO_NUM;
127 config.pin_d3 = Y5_GPIO_NUM;
128 config.pin_d4 = Y6_GPIO_NUM;
129 config.pin_d5 = Y7_GPIO_NUM;
130 config.pin_d6 = Y8_GPIO_NUM;
131 config.pin_d7 = Y9_GPIO_NUM;
132 config.pin_xclk = XCLK_GPIO_NUM;
133 config.pin_pclk = PCLK_GPIO_NUM;
134 config.pin_vsync = VSYNC_GPIO_NUM;
135 config.pin_href = HREF_GPIO_NUM;
136 config.pin_sscb_sda = SIOD_GPIO_NUM;
137 config.pin_sscb_scl = SIOC_GPIO_NUM;
138 config.pin_pwdn = PWDN_GPIO_NUM;
139 config.pin_reset = RESET_GPIO_NUM;
140 config.xclk_freq_hz = 20000000;
141 config.pixel_format = PIXFORMAT_JPEG;
142
143 psramFound();
144 config.frame_size = FRAMESIZE_QVGA;
145 config.jpeg_quality = 10;
146 config.fb_count = 1;
147
148 // camera init
149 esp_err_t err = esp_camera_init(&config);
150 if (err != ESP_OK) {
151 Serial.printf("Camera init failed with error 0x%x", err);
152 return;
153 }
154 Serial.println("Camera configuration complete!");
155 }

Any concerns?  support@freenove.com


378 Chapter 33 Camera Tcp Server www.freenove.com █

Loop function will constantly send camera data obtained to mobile phone APP.
62 while (client.connected()) { // loop while the client's connected
63 camera_fb_t * fb = NULL;
64 while (client.connected()) {
65 fb = esp_camera_fb_get();
66 if (fb != NULL) {
67 uint8_t slen[4];
68 slen[0] = fb->len >> 0;
69 slen[1] = fb->len >> 8;
70 slen[2] = fb->len >> 16;
71 slen[3] = fb->len >> 24;
72 client.write(slen, 4);
73 client.write(fb->buf, fb->len);
74 }
75 else {
76 Serial.println("Camera Error");
77 }
78 }
79 }
The loopTask_Cmd() function sends the received instruction back to the phone app and prints it out through
a serial port.
86 void loopTask_Cmd(void *pvParameters) {
87 Serial.println("Task Cmd_Server is starting ... ");
88 while (1) {
89 WiFiClient client = server_Cmd.available(); // listen for incoming clients
90 if (client) { // if you get a client,
91 Serial.println("Command Server connected to a client.");// print a message out
the serial port
92 String currentLine = ""; // make a String to hold incoming data from the client
93 while (client.connected()){ // loop while the client's connected
94 if (client.available()) { // if there's bytes to read from the client,
95 char c = client.read(); // read a byte, then
96 client.write(c);
97 Serial.write(c); // print it out the serial monitor
98 if (c == '\n') { // if the byte is a newline character
99 currentLine = "";
100 }
101 else {
102 currentLine += c; // add it to the end of the currentLine
103 }
104 }
105 }
106 // close the connection:
107 client.stop();

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 33 Camera Tcp Server 379

108 Serial.println("Command Client Disconnected.");


109 }
110 }
111 }
loopTask_ Blink()function will control the blinking of LED. When you see LED blinking, it indicates that ESP32
has been configured and starts working.
112 void loopTask_Blink(void *pvParameters) {
113 Serial.println("Task Blink is starting ... ");
114 while (1) {
115 digitalWrite(LED_BUILT_IN, !digitalRead(LED_BUILT_IN));
116 delay(1000);
117 }
118 }
If you do not have a router near you, or if you are outdoors, you can annotate the following code, and then
compile and upload it to ESP32. And you can display the video images on your phone by Method 1.
32 /////////////////////////////////////////////////////
33 WiFi.begin(ssid_Router, password_Router);
34 Serial.print("Connecting ");
35 Serial.print(ssid_Router);
36 while (WiFi.status() != WL_CONNECTED) {
37 delay(500);
38 Serial.print(".");
39 WiFi.begin(ssid_Router, password_Router);
40 }
41 Serial.println("");
42 Serial.println("WiFi connected");
43 /////////////////////////////////////////////////////

Any concerns?  support@freenove.com


380 Chapter 34 Soldering Circuit Board www.freenove.com █

Chapter 34 Soldering Circuit Board

Project 34.1 Soldering a Buzzer

We have tried to use a buzzer in a previous chapter, and now we will solder a circuit that when the button is
pressed, the buzzer sounds.
This circuit does not need programming and can work when it is powered on. And when the button is not
pressed, there is no power consumption.
You can install it on your bike, bedroom door or any other places where it is needed.

Component List

Pin header x2 LED x1 Resistor 220Ω x1 Active buzzer x1 Push button x1

AA Battery Holder x1

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 34 Soldering Circuit Board 381

Circuit

We will solder the following circuit on the main board.


Schematic diagram Hardware connection.
If you need any support, please feel free to contact
us via: support@freenove.com

Any concerns?  support@freenove.com


382 Chapter 34 Soldering Circuit Board www.freenove.com █

Soldering the Circuit

Insert the components on the main board and solder the circuit on its back.

rendering after soldering:


Front Back

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 34 Soldering Circuit Board 383

Testing circuit

Connect the circuit board to power supply (3~5V). You can use ESP32 board or battery box as the power
supply.

Tear the label off

Anode

Cathode

Press the push button after connecting the power, and then the buzzer will make a sound.

Any concerns?  support@freenove.com


384 Chapter 34 Soldering Circuit Board www.freenove.com █

Project 34.2 Soldering a Flowing Water Light

From previous chapter, we have learned to make a flowing water light with LED. Now, we will solder a circuit
board, and use the improved code to make a more interesting flowing water light.

Component List

Pin header x5 Resistor 220Ω x8 LED x1 74HC595 x1

Circuit

Solder the following circuit on the main board.


Schematic diagram Hardware connection

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 34 Soldering Circuit Board 385

Soldering the Circuit

Insert the components on the main board and solder the circuit on its back.

Rendering after soldering:


Front Back

Any concerns?  support@freenove.com


386 Chapter 34 Soldering Circuit Board www.freenove.com █

Connecting the Circuit

Connect the board to ESP32 with jumper wire in the following way.

VCC —3.3V/5V
GND —GND
SH_CP—GPIO13
ST_CP —GPIO12
DS —GPIO14

Sketch

The following is the program code:


1 int latchPin = 12; // Pin connected to ST_CP of 74HC595(Pin12)
2 int clockPin = 13; // Pin connected to SH_CP of 74HC595(Pin13)
3 int dataPin = 14; // Pin connected to DS of 74HC595(Pin14)
4
5 void setup() {
6 // set pins to output
7 pinMode(latchPin, OUTPUT);
8 pinMode(clockPin, OUTPUT);
9 pinMode(dataPin, OUTPUT);
10 }
11
12 void loop() {
13 // Define a one-byte variable to use the 8 bits to represent the state of 8 LEDs of LED bar

Any concerns?  support@freenove.com


█ www.freenove.com Chapter 34 Soldering Circuit Board 387

14 graph.
15 // This variable is assigned to 0x01, that is, binary 00000001, which indicates only one LED light
16 on.
17 byte x = 0x01; // 0b 0000 0001
18 for (int j = 0; j < 8; j++) { // Let LED light up from right to left
19 writeTo595(LSBFIRST, x);
20 x <<= 1; // make the variable move one bit to left once, then the bright LED move one step
21 to the left once.
22 delay(50);
23 }
24 delay(100);
25 x = 0x80; //0b 1000 0000
26 for (int j = 0; j < 8; j++) { // Let LED light up from left to right
27 writeTo595(LSBFIRST, x);
28 x >>= 1;
29 delay(50);
30 }
31 delay(100);
32 }
33 void writeTo595(int order, byte _data ) {
34 // Output low level to latchPin
35 digitalWrite(latchPin, LOW);
36 // Send serial data to 74HC595
37 shiftOut(dataPin, clockPin, order, _data);
38 // Output high level to latchPin, and 74HC595 will update the data to the parallel output
39 port.
40 digitalWrite(latchPin, HIGH);
41 }
In fact, this code is copied from chapter 15. If you have any questions for the code, please click "Chapter 15
74HC595 & LED Bar Graph" to return to Chapter 15 to study again.

Any concerns?  support@freenove.com


388 What’s next? www.freenove.com █

What’s next?
Thanks for your reading. This tutorial is all over here. If you find any mistakes, omissions or you have other
ideas and questions about contents of this tutorial or the kit and etc., please feel free to contact us:

support@freenove.com
We will check and correct it as soon as possible.

If you are interesting in processing, you can learn the Processing.pdf in:
Freenove_Ultimate_Starter_Kit_for_ESP32\C\Processing.pdf

If you want to learn more about Arduino, Raspberry Pi, smart cars, robots and other interesting products in
science and technology, please continue to focus on our website. We will continue to launch cost-effective,
innovative and exciting products.

http://www.freenove.com/

End of the Tutorial


Thank you again for choosing Freenove products.

Any concerns?  support@freenove.com

You might also like