This guide shows how to read temperature from multiple DS18B20 temperature sensors with the ESP32 using Arduino IDE. We’ll show you how to wire the sensors on the same data bus to the ESP32, install the needed libraries, and a sketch example you can use in your own projects. This tutorial is also compatible with the ESP8266 and the Arduino boards.
The Arduino Core for ESP8266 and ESP32 uses one SPI flash memory sector to emulate an EEPROM. When you initialize the EEPROM object (calling begin) it reads the contents of the sector into a memory buffer. Reading a writing is done over that in-memory buffer. Whenever you call commit it write the contents back to the flash sector.
Due to the nature of this flash memory (NOR) a full sector erase must be done prior to write any new data. If a power failure (intended or not) happens during this process the sector data is lost.
Also, writing data to a NOR memory can be done byte by byte but only to change a 1 to a 0. The only way to turn 0s to 1s is to perform a sector erase which turns all memory positions in that sector to 1. But sector erasing must be done in full sectors, thus wearing out the flash memory faster.
Some months ago, Espressif announced the production of a new chip, named ESP32-PICO-D4.
It’s a complete SiP (System in Package), that is a chip which integrates the esp32 microcontroller, a 4Mbit flash memory, a crystal oscillator, filter capacitors and RF matching links. The chip datasheet is available on the official website.
Using this chip, it’s possible to create very small modules. I recently received one of those from Aliexpress:
To better understand how small it is, let’s compare its size with a “classic” ESP-WROOM-32 module and with a 1 euro coin:
The module includes a chip antenna; it’s also possible to connect an external antenna thanks to the presence of an I-PEX connector.
In conclusion, the availability of the ESP32-PICO-D4 SiP makes it possible to use the esp32 chip in applications where the available space is very small…
PlatformIO is an opensource ecosystem (as it’s defined in the homepage of the project) to develop IoT projects.
The heart of the platform is a software component named PlatformIO Core. This component includes:
a cross-platform compiler
a libraries and dependences manager
a serial monitor
PlatformIO Core is developed in Python and therefore it can run on different operating systems (Windows, Linux, MacOS).
Although you can use the Core component directly, PlatformIO’s strength lies in its IDE, which allows the development of multi-platform projects and integrates with the Core itself.
In this article I’m going to show you how to use PlatformIO to develop projects running on the esp32 chip.
PlatformIO IDE is provided as a plugin for two different development tools: Atom and VisualStudio Code. I tried both solutions and I preferred VSCode: both the installation and the use are simpler and more immediate.
Install VSCode after having downloaded the package from Microsoft’s website (the installer is available for Windows, Linux and MacOS).
Open the Package Manager:
search the PlatformIO IDE package, then click on Install:
wait until the installation is complete:
Now it’s time to develop your first program, which traditionally will display the sentence Hello world! on the terminal.
If it doesn’t show up automatically, open the PlatformIO’s homepage:
then click on New Project:
give a name to the project and choose a devboard based on the esp32 chip (in this example I’ll use a Lolin32 board by Wemos). PlatformIO supports both the esp-idfframework and the arduino-esp32 one. All my tutorials are based on the first one:
PlatformIO automatically creates some folders for your project. Choose the src folder (it stands for source, that is the folder which will contain the source code) and create a new file:
name the file main.c and type the simple program as it follows:
run the compiler by clicking on the corresponding button in the bottom bar:
the editor displays an error… indeed your code is using the printf() function without having included the library:
add the missing line, now you should be able to complile the code without errors:
PlatformIO can also upload the compiled program to your board. Thanks to its auto-detect feature, you usually don’t need to specify the serial port the board is connected to:
PlatformIO also includes a serial monitor you can use to test your program. By default, this monitor connects to the serial port with a speed of 9600 baud. The esp32 chip instead has a default speed of 115200 baud; you have therefore to change the platformio.ini file included in your folder as it follows:
Now open the serial monitor; you should see the correct output of your program:
I found the use of PlatformIO really immediate: after a few minutes I was able to develop, compile, load and test a program. Try it and leave a comment with your impressions!
In the previous posts I explained how to receive and send advertising packets based on the Bluetooth LE standard.
The payload (that is the amount of “useful” data) of those packets is at most 31 bytes. It isn’t much: if – for example – you want to include the device name, little place remains for other data.
The BLE standard allows peripherals to send additional data using the scan request – scan response process.
When a device receives an advertising packet, it can contact the transmitter by sending a scan request packet to request further information. When receiving a scan request package, the peripheral can respond with a scan response packet:
Advertising and scan request packets have the same format; it’s therefore possible to transfer, using scan response, additional 31 bytes of data.
The esp framework offers two modes for configuring the content of a scan response packet: using the esp_ble_adv_data_t struct or creating a byte array (raw mode). These modes are similar to the ones used to configure advertising packets you learned in previous articles (struct and raw mode).
In the first case, you have to declare a second struct, in addition to the one related to the advertising packet, to define the content of the scan response packet:
Very important is set to true the set_scan_rsp parameter. It’s indeed this parameter what tells the driver that this struct is related to the scan response packet.
You can then pass the new struct to the driver, with the same function used previously:
The driver will call the callback function twice: one to indicate the successful configuration of the advertising packet and one for the configuration of the scan response one. The two events are different:
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:[...]case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:[...]
You have to wait until both the events have triggered before starting the advertising process. In my example program (you can download the source code from my Github repository) I use two booleanvariables:
If you want to use the raw mode instead, you have to declare a byte array and fill it with the content of the payload of the packet. Then you can use a specific function of the framework to pass the array to the driver:
When using this new function, it also changes the event that the driver passes to your callback function when the configuration is complete. The new event is ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT. As in the previous example, when this event is triggered you can start the advertising process:
For the advertising process to work, the data contained in the array must correspond to a valid payload.
The payload contains one or more AD (advertising data) structures. Each structure is made by 3 fields:
an initial byte that represents the length (in bytes) of the structure, excluding itself
a byte that represents the type of the data contained in the structure
a variable number of bytes which are the actual data
The codes that can be used to define the type of data can be found in the Bluetooth specifications. Depending on the type of data, it is then necessary to apply a particular format to the data that follows. The necessary information is found in the Core Specification Supplement document (available on the Bluetooth.com website).
Let’s see a simple example: the ADType 0x09 represents the complete local name, which is the name of the device. This name must be specified in AD data with simply a sequence of the ASCII codes that correspond to the different letters.
Rui Santos writes, “In this project, you’re going to learn how to control the ESP8266 or the ESP32 with voice commands using Alexa (Amazon Echo Dot). As an example, we’ll control two 12V lamps connected to a relay module. We’ll also add two 433 MHz RF wall panel switches to physically control the lamps.”
In the previous posts you learned how to use the esp32 chip to receive and parse the advertising packets transmitted by BLE peripherals. As a practical example, I developed a program to detect the presence of a particular iBeacon and activate an output accordingly.
In today’s tutorial, you’ll learn how to transmit advertising packets instead.
You’ve already discovered that the Bluetooth driver included in the esp-idf stack is executed in a dedicated thread. Whenever the driver needs to send a notification to your program, it calls a callback function indicating which event has triggered.
The advertising process is very simple:
the program configures the data to be transmitted with esp_ble_gap_config_adv_data()
the driver reports that it has finished the configuration with the event ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT
the program can now start the advertising process with esp_ble_gap_start_advertising()
the driver reports that the process has started with the event ESP_GAP_BLE_ADV_START_COMPLETE_EVT
It’s possible to tell the driver which data to include in the advertising packet with the following command:
Using the flags, you can publish some features of your device. The available constants are:
you can combine them with the OR operator. If, for example, you want to tell the world that your device is limited discoverable (i.e. it sends the advertising packets only for a limited time, usually 30 seconds) and that it doesn’t support classic Bluetooth (BR/EDR, Basic Rate/Enhanced Data Rate) you’ll write:
accepts as parameter an esp_ble_adv_params_t struct:
You can configure the minimum and maximum transmission interval of the packet. The two parameters can assume a value from 0x20 to 0x4000. To calculate the interval in milliseconds, the value specified must be multiplied for 0.625. This means that the minimum value (0x20) corresponds to an interval of 12.5ms.
The esp_gap_ble_api.h file lists the constants that can be used for the other parameters (esp_ble_adv_type_t, esp_ble_addr_type_t …).
For example, let’s configure the advertising process as it follows:
In my previous article I explained the Bluetooth Low Energy technology and the advertising process.
You learned that a BLE device can leverage the advertising packets to send data; in this case the device is called broadcaster and the devices which receive data are called observers.
The payload of an advertising packet has the following structure:
ADV ADDR is the device MAC address (this is the address displayed by the program developed in the previous article) and ADV DATA is a field, with a max length of 31 bytes, that contains one or more structures, each with 3 elements:
AD length is the total length (in bytes) of each data structure
AD type is the type of data contained in the structure
A device, for example, can transmit its local name using the AD type 0x09:
In scan mode, the Bluetooth driver returns to the program the received data (ADV DATA) in thescan_result->scan_rst.ble_adv array. This array contains uint8_t values and it’s size is scan_result->scan_rst.adv_data_len.
The Bluedroid library contains a method, esp_ble_resolve_adv_data(), which allows to get the value for a specific AD type passing the raw data. The header file esp_gap_ble_api.h contains definitions for the most common AD types:
In my Github repository you can find an updated version of the scan program. Thanks to what explained above, now the program can also display – if available – the name of the device:
A particular family of broadcaster devices are the iBeacons. These devices have been designed by Apple to allow interaction with IOS devices (iPhone …) based on location awareness. Let’s make an example: an iPhone can “notice” that it is close to a particular iBeacon, associated with a room in a museum, and therefore offer the user a brief guide to the exhibited works.
iBeacon specifications are available on Apple’s developer portal. iBeacons work transmitting advertising packets with specific payload (ADV DATA):
The first structure has AD type = flags (0x01). Each bit has a different meaning, usually iBeacons use 0x0A value for AD data.
The second structure has type = 0xFF, that is Manufacturer Specific Data. The Bluetooth standard allows the different manufacturers to use this ID to transmit custom data. The total data length is 25 bytes (0x1A – 0x01 that is the length of the AD type field).
Apple specifications further subdivide the AD data field in several elements:
The first field is the manufacturer/company; iBeacons normally use the code 0x004C, assigned to Apple Inc. The next two fields define the iBeacon type and have a fixed value (0x02 e 0x15). The UUID field, together with the Major and Minor ones (optional, they can have a value of 0) uniquely identifies each iBeacon. (insieme con i campi Major e Minor (facoltativi, possono essere impostati a 0) identificano univocamente il singolo iBeacon. Finally, the TX power field contains a measurement, one meter away from the iBeacon, of the received power and is useful for precisely estimate the distance between the phone and the iBeacon itself.
I developed a program for the esp32 chip which turns a relay on if it detects a specific iBeacon. Via menuconfig you can configure the UUID of the iBeacon which triggers the led, the pin the led is connected to and the timeout – in seconds – after which the program turns the led off if the iBeacon is not detected anymore. You can moreover set a power threshold to control the distance at which the iBeacon is detected.
To parse the received packet and get the UUID value, in my program I used the method described in this article (parsing using astruct).
The program verifies if the received packet (event ESP_GAP_SEARCH_INQ_RES_EVT) was sent by an iBeacon checking that the packet length is 30 bytes and that its header contains the values listed above:
I have been working on some games for the ESP32 and needed some decent quality audio with a minimum number of additional components. I was bouncing between using the DAC and using the I2S bus. The DAC requires less external parts, so I went that way. I ended up creating a very simple library for use in he Arduino IDE. (Note: This only works with ESP32)
Check out the video after the break.
This website stores some user agent data. These data are used to provide a more personalized experience and to track your whereabouts around our website in compliance with the European General Data Protection Regulation. If you decide to opt-out of any future tracking, a cookie will be set up in your browser to remember this choice for one year. I Agree, Deny