ESP32 Capacitive Touch Sensor in Arduino IDE

Hello readers, I hope you are all doing great. Welcome to the 2nd lecture of Section 5(ESP32 Sensors) in the ESP32 Programming Series. In the previous tutorial, we discussed the built-in ESP32 Hall Effect Sensor. In this tutorial, we will discuss another inbuilt sensor of the ESP32 i.e. Capacitive Touch Sensor.

ESP32 Board has 10 built-in capacitive touch pins, which generate an electrical signal when someone touches these pins. These ESP32 touch pins are normally used to wake up the board from deep sleep mode. These touch pins are also used to replace the normal mechanical buttons with touch pads, improving the presentation of the IoT projects.

Here's the video demonstration of the ESP32 Capacitive Touch Sensor:

Before going forward, let's first understand how this touch sensor works:

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

What is a Capacitive Touch Sensor?

Capacitance is determined by the geometry of the conductors and the dielectric materials used. Changing any of these factors will result in changing the capacitance.

C = Ad

As we know, the human body also carries a small electric charge. So, when a body approaches the metallic plates(of a capacitor), the mutual capacitance between the two metal plates decreases. This change in capacitance is used to detect the touch in these capacitive sensors.

Capacitive touch sensor in ESP32

  • ESP32 offers 10 Capacitive-sensitive GPIO pins, operating at a normally HIGH state.
  • So, at open state, these pins provide +5V at the output but when someone touches any of these pins, the respective pin voltage drops to 0.
  • These ESP32 Capacitive Touch Sensor Pins are labeled in the below figure:(for detailed pinout, please read ESP32 Pinout)

So, if someone touches any of these pins, ESP32 can easily detect it. The pin mapping of touch-sensitive pins in DOIT ESP32 DevKit V1 with GPIO pins is shown below:

ESP32 Capacitive Touch Pins
No. Parameter Name Parameter Value
1
Touch0 GPIO4
2
Touch1 GPIO0(not available in DOIT ESP32 Dev-kit V1 30-pin module but available in the 36-pin module)
3
Touch2 GPIO2
4
Touch3 GPIO15
5
Touch4 GPIO13
6
Touch5 GPIO12
7
Touch6 GPIO14
8
Touch7 GPIO27
9
Touch8 GPIO33
10
Touch9 GPIO32

Programming ESP32 Capacitive Sensor

We are using the Arduino IDE development environment for programming ESP32. If you are new to Arduino IDE, read out How to Install ESP32 in Arduino IDE. Let's use the builtin Touch Sensor example in Arduino IDE:

  • Open the Arduino IDE, go to File > Examples > ESP32 > Touch. An image from Arduino IDE is attached below for your reference:

In Arduino IDE there are two example codes available for the ESP32 touch sensor. We will discuss and implement both example codes in this tutorial. So, let's first open the TouchRead Code:

ESP32 TouchRead Example

Here's the code for the TouchRead Example:

// ESP32 Touch Test
void setup()
{
    Serial.begin(115200);
    delay(1000); // give me time to bring up serial monitor
    Serial.println("ESP32 Touch Test");
}

void loop()
{
    Serial.println(touchRead(T0)); // get value using T0
    delay(1000);
}

Code Description

  • This is a basic code to test/understand the touch sensor feature of ESP32.
  • In this code, we are using a touch-sensitive pin to read the variation in capacitance and print the respective readings on the serial monitor.

Setup() Function

Inside the setup() function, the serial monitor is initialized at a baud rate of 115200 to display the sensor readings. Finally, we printed the message(ESP32 Touch Test) on the Serial Monitor:

void setup()
{
    Serial.begin(115200);
    delay(1000); // give me time to bring up serial monitor
    Serial.println("ESP32 Touch Test");
}

Loop() Function

  • Inside the loop function, the touchRead(T0) function takes the T0 capacitive sensor pin as an argument and reads the output of T0(GPIO Pin4).
  • The observed output is continuously printed on the serial monitor with a delay of 1 sec.
void loop()
{
    Serial.println(touchRead(T0)); // get value using T0
    delay(1000);
}

Testing/Result

  • Upload the above code into the ESP32 development board and connect a jumper wire to the T0 capacitive sensor pin(GPIO4).
  • To open the serial monitor in Arduino IDE, go to Tools > Serial monitor or use the Ctrl+Shift+M shortcut key.
  • Select the 115200 baud rate on the serial monitor.
  • Now hold the metal end of the jumper wire connected to the GPIO4.
  • To check the results, open the serial plotter, go to Toole > Serial Plotter or use Ctrl+Shift+L shortcut keys.
  • As you can see in the above figure, the sensor's value drops to 0 when we touch the metallic part of the capacitive sensor pin.
  • When we are not touching the sensor pin, the normal sensor output is around 107.
  • Here's the Serial Monitor showing the touch results:

ESP32 Touch Interrupt Example

These capacitive touch sensor pins are mainly used to generate an external interrupt for waking up ESP32 from low power modes(deep sleep mode). Moreover, can also be used to control external peripherals like LED blinking or tuning on a DC motor, when a capacitive touch-interrupt is observed. So, let's have a look at How to Generate external interrupt by touching the ESP32 capacitive touch pins:

ESP32 Touch Interrupt Code

Here's the ESP32 Touch Interrupt Code:

const int CAPACITIVE_TOUCH_INPUT_PIN = T0; // GPIO pin 4
const int LED_OUTPUT_PIN = LED_BUILTIN;
const int TOUCH_THRESHOLD = 40; // turn on light if touchRead value < this threshold
volatile boolean _touchDetected = false;

void setup()
{
    Serial.begin(115200);
    pinMode(LED_OUTPUT_PIN, OUTPUT);
    pinMode(LED_OUTPUT_PIN, LOW);
    touchAttachInterrupt(CAPACITIVE_TOUCH_INPUT_PIN, touchDetected, TOUCH_THRESHOLD);
}

void touchDetected()
{
    _touchDetected = true;
}

void loop()
{
    if(_touchDetected)
    {
        Serial.println("Touch detected.");
        _touchDetected = false;

        Serial.println("blink the LED");
        digitalWrite(LED_OUTPUT_PIN, HIGH);
        delay(1000);
        digitalWrite(LED_OUTPUT_PIN, LOW);
        delay(1000);
    }
}

Let's understand the code by parts:

Variables Initialization

  • The first step is to select the GPIO or touch sensor input pin to trigger an interrupt. We are using T0 or GPIO4 as an interrupt pin.
  • Select the LED output pin which will react or blink on the occurrence of an interrupt.
  • In the code, we are using the threshold value of 40. When a body, containing an electric charge touches a touch-sensitive pin, the threshold value decreases below 40.
  • The default state of the touchDetect variable is set to false.
const int CAPACITIVE_TOUCH_INPUT_PIN = T0; // GPIO pin 4
const int LED_OUTPUT_PIN = LED_BUILTIN;
const int TOUCH_THRESHOLD = 40; // turn on light if touchRead value < this threshold
volatile boolean _touchDetected = false;

Setup() Function

  • In the Setup Function, we initialized the serial monitor with a baud rate of 115200 so that you can display the results on the serial monitor for debugging purposes.
  • Set the LED pin as output and set the default state to LOW.
  • Attach the interrupt with the capacitive touch pin T0 using touchAttachInterrupt(), it takes the T0 pin, touchDetected and threshold value as arguments.
void setup()
{
    Serial.begin(115200);
    pinMode(LED_OUTPUT_PIN, OUTPUT);
    pinMode(LED_OUTPUT_PIN, LOW);
    touchAttachInterrupt(CAPACITIVE_TOUCH_INPUT_PIN, touchDetected, TOUCH_THRESHOLD);
}
  • touchDetected() function will be called when an interrupt is triggered i.e. someone touches the T0 Pin.
  • This Function will change the state of the "_touchDetected" variable to true.
void touchDetected()
{
    _touchDetected = true;
}

Loop() Function

  • Inside the loop() function, we are using the ‘if’ statement which is continuously checking the state of variable "_touchDetected".
  • Once the variable state is changed to true, an interrupt is triggered and the output LED (inbuilt LED) will start blinking with a delay of 1 second.
  • The result will be printed on the serial monitor.
void loop()
{
    if(_touchDetected)
    {
        Serial.println("Touch detected.");
        _touchDetected = false;

        Serial.println("blink the LED");
        digitalWrite(LED_OUTPUT_PIN, HIGH);
        delay(1000);
        digitalWrite(LED_OUTPUT_PIN, LOW);
        delay(1000);
    }
}

Testing of ESP32 Touch Sensitive Pin

  • Open the serial monitor with a 115200 baud rate.
  • Connect a male-to-female jumper wire with T0 or GPIO 4 of ESP32.
  • Hold the metallic end of the jumper wire.
  • LED will blink with a delay of 1 sec.
  • See the results displayed on the serial monitor.

This concludes the tutorial; I hope you found this helpful and also hope to see you again with a new tutorial on ESP32.

ESP32 Hall Effect Sensor in Arduino IDE

Hello readers, I hope you all are doing great. Welcome to Section 5 of the ESP32 Programming Series. In this section, we are going to interface different Embedded Sensors with the ESP32 Microcontroller Board. ESP32 development board is featured with some inbuilt sensors(i.e. hall effect sensor, capacitive touch sensor) so, in the initial tutorials of this section, we will explore these built-in ESP32 sensors and in the later lectures, we will interface third-party sensors with the ESP32.

In today's lecture, we will discuss the working/operation of the ESP32 built-in Hall Effect Sensor. Hall Effect sensor is used to detect the variation in the magnetic field of its surroundings. So, let's first understand What's Hall Effect:

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

What is the Hall Effect?

The Hall Effect phenomenon was first discovered by Edwin Hall in 1879. When current passes through a conductor, the electrons move in a straight line and thus the voltage difference across the conductor's surface remains zero, as shown in the below figure:

However, when a magnet is placed near the current-carrying conductor in a way that the direction of the magnetic field is perpendicular to the flow of current, the electrons get diverted and don't follow a straight line, which results in generating a small potential difference across the conductor's surface, as shown in the below figure:

This small potential difference generated because of magnetic field presence is called Hall Voltage. This magnetic field influence over the current-carrying conductor is termed the Hall Effect.

Hall Effect Sensor

A Hall Effect Sensor is a non-contact type embedded sensor, used to detect the presence & intensity of a magnetic field in its surroundings. Different third-party Hall Effect Sensors available in the market are shown in the below figure:

  • A normal Hall Effect Sensor Pinout consists of 3 Pins i.e.
  1. Vcc: Normally +5V, few +3.3V are also available.
  2. GND: We need to provide Ground here.
  3. OUT: The Output Pin to give the sensor's response.
  • When a perpendicular magnetic field is placed near a Hall-effect sensor, it changes the status of its Output Pin.
  • The analog Hall Effect Sensors can also detect the strength of the magnetic field i.e. greater the magnetic field greater will be the sensor's output or voltage deviation.

Applications of Hall Effect sensor

  • In an Automotive system, Hall Sensors are used to detect speed, distance, position etc.
  • Used in Proximity sensing.
  • Used in Current sensing.
  • Used in Anti-lock braking system.
  • Used in Internal combustion engines to assist with ignition timing.
  • To switch an electric circuit ON and OFF.

Hall Effect Sensor in ESP32

In ESP32, the Hall effect sensor is located inside the ESP-WROOM-32 metallic cover. As the Hall Effect sensor is a non-contact type, it doesn't have to be in contact with the magnet. We just need to place the magnet above this metallic sheet and the ESP32 Hall Effect sensor will detect it.

Programming ESP32 Hall Effect Sensor using Arduino IDE

To understand the working of the Hall sensor with ESP32, let's test the builtin ESP32 example:

  • You can find the code through File> Examples> ESP32 > Hall Sensor, as shown in the below figure:

Arduino IDE code

Here's the code for this ESP32 Hall Sensor example:

int val = 0;

void setup()
{
   Serial.begin (9600);
}

void loop() 
{
   val = hallRead();
   Serial.print ("sensor value = ");
   Serial.println (val);//to graph

   delay(100);
}

Code Description

The code is quite simple, where the hallRead() function is called to read the hall sensor value, store it into a variable and then print it on the Serial monitor. Finally added a small delay to get the next value. Let me explain the code line by line for the beginners:

Variables Declaration

  • The first step will be the declaration of an integer-type variable to store the hall sensor value. The initial value assigned to the variable is zero.
int val = 0;

Setup() Function

  • Inside the setup function, the only task is to initialize the serial port at a 9600 baud rate for serial communication.
void setup()
{
   Serial.begin (9600);
}

Loop() Function

  • Inside the loop function, we called a function ‘hallRead()’ to read the sensor value and store those readings into the variable ‘val’.
  • Printed the sensor readings on the serial monitor or serial plotter using serial.println() function.
  • A delay of 0.3 sec is added at the end.
void loop() 
{
   val = hallRead();
   Serial.print ("sensor value = ");
   Serial.println (val);//to graph

   delay(100);
}

ESP32 Hall Effect Sensor - Testing

  • After successfully uploading the code into ESP32, open the serial plotter or serial monitor to monitor the results.
  • Place a magnet near the ESP32 board.
  • The sensor reading will increase/decrease depending on the magnet pole(i.e. North or South Pole) facing the Hall sensor.
  • Now click on Tools > Serial Plotter to visually analyze the sensor's output.
  • The Serial Plotter of our project is shown in the below figure:
  • As you can see in the above figure, the sensor is giving negative output when facing the North Pole of the magnet.
  • In the case of a South Pole, the sensor's output is positive.
  • In the absence of a magnetic field, the sensor's output is almost 0.
  • The distance between the magnet and the Hall sensor decides the amount of potential difference generated.
  • The greater the distance between the two, the smaller the hall voltage or potential difference will be.
  • We have attached an image from the Arduino IDE serial monitor for your reference.

This concludes the tutorial. I hope you found this helpful, test it out and if feel any difficulty, let me know in the comments. In the next tutorial, we will have a look at another built-in sensor of ESP32 i.e. Capacitive Touch Sensor. Thanks for reading.

ESP32 Over The Air (OTA) Web Updater

Hello readers, I hope you are all doing great. In this tutorial, we are going to discuss the OTA web updater on the ESP32.

We already covered the fundamentals of OTA programming in ESP32, in our previous tutorial where we used the Arduino IDE to upload OTA code into the ESP32 module using the network port.

In the OTA web updater, you need to create a web server page for OTA programming.

[caption id="attachment_166886" align="aligncenter" width="1920"] ESP32 OTA web updater[/caption]

Fig.1 ESP32 OTA web updater

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

Over the Air Web Updater

  • "Over-the-air" refers to the ability to wirelessly download an application, configuration, or firmware to internet-enabled devices, also known as IoT. (OTA). It functions similarly to our computers, laptops, tablets, and phones.
  • Instead of using a serial port and a wired medium to upload a code, the OTA web updater allows the user to update the code or firmware wirelessly via a web server.
  • When sensor nodes are frequently placed in remote or difficult-to-reach locations, OTA programming can be used.

Steps to implement an OTA web updater using ESP32

  • Using the serial communication port, upload the code containing the instructions to enable the OTA web updater (so that in the future you can update the code using a browser instead of a wired medium).
  • The code uploaded via the serial port will launch a web server, allowing you to upload new code over the air.
  • The new code, which has been uploaded using a web server, should contain instructions to keep the OTA web updater enabled on the ESP32 board so that you can use the OTA programming feature in future applications as well.
  • Create a .bin using Arduino IDE compiler and upload the file on the server.

Fig. 2

Code for OTA web updater implementation in ESP32

In this tutorial, we will discuss only the OTA web updater method using Arduino IDE and ESP32 dev-Kit V1 module.

If you want to know more about the basics of ESP32 and how to get started with Arduino IDE, then read Introduction to ESP32 Programming Series.

  • You can find the code through File> Examples> ArduinoOTA> BasicOTA.
  • An image has been attached below for reference:

Fig. 3

  • This code should be uploaded serially through a serial communication port only then you can access the OTA web updater feature.

Code

#include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> #include <ESPmDNS.h> #include <Update.h>   const char* host = "esp32"; const char* ssid = "SSID"; const char* password = "password";   WebServer server(80);   /* * Login page */   const char* loginIndex = "<form name='loginForm'>" "<table width='20%' bgcolor='A09F9F' align='center'>" "<tr>" "<td colspan=2>" "<center><font size=4><b>ESP32 Login Page</b></font></center>" "<br>" "</td>" "<br>" "<br>" "</tr>" "<td>Username:</td>" "<td><input type='text' size=25 name='userid'><br></td>" "</tr>" "<br>" "<br>" "<tr>" "<td>Password:</td>" "<td><input type='Password' size=25 name='pwd'><br></td>" "<br>" "<br>" "</tr>" "<tr>" "<td><input type='submit' onclick='check(this.form)' value='Login'></td>" "</tr>" "</table>" "</form>" "<script>" "function check(form)" "{" "if(form.userid.value=='admin' && form.pwd.value=='admin')" "{" "window.open('/serverIndex')" "}" "else" "{" " alert('Error Password or Username')/*displays error message*/" "}" "}" "</script>";   /* * Server Index Page */   const char* serverIndex = "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>" "<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>" "<input type='file' name='update'>" "<input type='submit' value='Update'>" "</form>" "<div id='prg'>progress: 0%</div>" "<script>" "$('form').submit(function(e){" "e.preventDefault();" "var form = $('#upload_form')[0];" "var data = new FormData(form);" " $.ajax({" "url: '/update'," "type: 'POST'," "data: data," "contentType: false," "processData:false," "xhr: function() {" "var xhr = new window.XMLHttpRequest();" "xhr.upload.addEventListener('progress', function(evt) {" "if (evt.lengthComputable) {" "var per = evt.loaded / evt.total;" "$('#prg').html('progress: ' + Math.round(per*100) + '%');" "}" "}, false);" "return xhr;" "}," "success:function(d, s) {" "console.log('success!')" "}," "error: function (a, b, c) {" "}" "});" "});" "</script>";   /* * setup function */ void setup(void) { Serial.begin(115200);   // Connect to WiFi network WiFi.begin(ssid, password); Serial.println("");   // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP());   /*use mdns for host name resolution*/ if (!MDNS.begin(host)) { //http://esp32.local Serial.println("Error setting up MDNS responder!"); while (1) { delay(1000); } } Serial.println("mDNS responder started"); server.on("/", HTTP_GET, []() { server.sendHeader("Connection", "close"); server.send(200, "text/html", loginIndex); }); server.on("/serverIndex", HTTP_GET, []() { server.sendHeader("Connection", "close"); server.send(200, "text/html", serverIndex); });   /*handling uploading firmware file */ server.on("/update", HTTP_POST, []() { server.sendHeader("Connection", "close"); server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); ESP.restart(); }, []() { HTTPUpload& upload = server.upload(); if (upload.status == UPLOAD_FILE_START) { Serial.printf("Update: %s\n", upload.filename.c_str()); if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size Update.printError(Serial); } } else if (upload.status == UPLOAD_FILE_WRITE) { /* flashing firmware to ESP*/ if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { Update.printError(Serial); } } else if (upload.status == UPLOAD_FILE_END) { if (Update.end(true)) { //true to set the size to the current progress Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); } else { Update.printError(Serial); } } }); server.begin(); }   void loop(void) { server.handleClient(); delay(1); }

Code Description

The first task is to add the header files, required to perform over the air (OTA) web updates using the ESP32 module.
  • WiFi.h : This header file allows the ESP32 board to connect to the internet. It can serve either as a server or a client.
  • ESPmDNS.h : This library is used to implement multicast DNS query support for the ESP32 chip. A multicast UDP service is used to provide local network service.
  • WiFiClient.h : It is used to create a client that can connect to a specific port and IP address.

Fig. 4

  • Enter the SSID and password.

Fig. 5

  • You can style the HTML page anytime as per your requirements or use the default style given in the example code.

Setup()

  • Initialize the serial monitor at a 115200 baud rate.
  • WiFi.begin() function is used to initialize the Wi-Fi module with Wi-Fi credentials used as arguments.

Fig. 6

  • Wait until the ESP32 is connected to the Wi-Fi network.

Fig. 7

  • If the device is connected to a local Wi-Fi network then print the details on the serial monitor.
  • WiFi.localIP() function is used to fetch the IP address.
  • Print the IP address on the serial monitor using Serial.println() function.

Fig. 8

  • Use multicast Domain Name System (mDNS) for hostname resolution.
  • Hostname has been defined as a global variable at the beginning of code.
  • Start the mDNS responder for esp32 or host using MDNS.begin() function.

Fig. 9

  • Return the index page which is stored in serverIndex.
  • Send the status OK (200 represents ‘OK’) to inform the client.

Fig. 10

  • Handling the uploading of firmware files.

Fig. 11

  • Start uploading the new firmware into the ESP32 board.

Fig. 12

  • Server.begin() function will start the server to listen for incoming connections.

Fig. 13

Loop()

  • Server.handleCLient() function is used to handle the client devices.
  • It will monitor the client devices and provide the requested HTML page.

Fig. 14

  • After successfully uploading the code into ESP32 board using serial communication port, open the serial monitor with 115200 baud rate.
  • Press EN or enable button from the ESP32 board.
  • You can see the IP address printed on the serial monitor, once the ESP32’s Wi-Fi module is connected to wi-fi network.
  • We have attached a screenshot below for your reference:

Fig. 15 Serial monitor

Testing

  • Now the ESP32 module is ready for over the air (OTA) programming.
  • For testing the OTA web updater, remove the ESP32 module from your computer and power the ESP32 board using another power source.
  • Open the browser and enter the IP address from the Serial Monitor as shown in the above image.
  • A web page with an IP address of 168.43.223 is shown below:

Fig. 16

  • Enter the username and password on the login page. As per the example code:
Username: admin Password: admin
  • You can change the username and password details if you wish to.
  • Click on Login.
  • A new browser page with URL 192.168.43.223/serverIndex will be displayed on the screen, as shown below:

Fig. 17

  • You can style the browser page as per your requirements.

Test code

  • Write a new code in Arduino IDE.
  • The code should contain two sections:
  1. The instructions to keep OTA web updater feature enabled
  2. Instructions to blink the LED (you can replace the LED code with another code as per your requirements).
#include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> #include <ESPmDNS.h> #include <Update.h>   const char* host = "esp32"; const char* ssid = "SSID"; const char* password = "password";   //variabls to blink without delay: const int led = 2; unsigned long previousMillis = 0; // will store last time LED was updated const long interval = 1000; // interval at which to blink (milliseconds) int ledState = LOW; // ledState used to set the LED   WebServer server(80);   /* * Login page */   const char* loginIndex = "<form name='loginForm'>" "<table width='20%' bgcolor='A09F9F' align='center'>" "<tr>" "<td colspan=2>" "<center><font size=4><b>ESP32 Login Page</b></font></center>" "<br>" "</td>" "<br>" "<br>" "</tr>" "<td>Username:</td>" "<td><input type='text' size=25 name='userid'><br></td>" "</tr>" "<br>" "<br>" "<tr>" "<td>Password:</td>" "<td><input type='Password' size=25 name='pwd'><br></td>" "<br>" "<br>" "</tr>" "<tr>" "<td><input type='submit' onclick='check(this.form)' value='Login'></td>" "</tr>" "</table>" "</form>" "<script>" "function check(form)" "{" "if(form.userid.value=='admin' && form.pwd.value=='admin')" "{" "window.open('/serverIndex')" "}" "else" "{" " alert('Error Password or Username')/*displays error message*/" "}" "}" "</script>";   /* * Server Index Page */   const char* serverIndex = "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>" "<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>" "<input type='file' name='update'>" "<input type='submit' value='Update'>" "</form>" "<div id='prg'>progress: 0%</div>" "<script>" "$('form').submit(function(e){" "e.preventDefault();" "var form = $('#upload_form')[0];" "var data = new FormData(form);" " $.ajax({" "url: '/update'," "type: 'POST'," "data: data," "contentType: false," "processData:false," "xhr: function() {" "var xhr = new window.XMLHttpRequest();" "xhr.upload.addEventListener('progress', function(evt) {" "if (evt.lengthComputable) {" "var per = evt.loaded / evt.total;" "$('#prg').html('progress: ' + Math.round(per*100) + '%');" "}" "}, false);" "return xhr;" "}," "success:function(d, s) {" "console.log('success!')" "}," "error: function (a, b, c) {" "}" "});" "});" "</script>";   /* * setup function */ void setup(void) { pinMode(led, OUTPUT);   Serial.begin(115200);   // Connect to WiFi network WiFi.begin(ssid, password); Serial.println("");   // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP());   /*use mdns for host name resolution*/ if (!MDNS.begin(host)) { //http://esp32.local Serial.println("Error setting up MDNS responder!"); while (1) { delay(1000); } } Serial.println("mDNS responder started"); /*return index page which is stored in serverIndex */ server.on("/", HTTP_GET, []() { server.sendHeader("Connection", "close"); server.send(200, "text/html", loginIndex); }); server.on("/serverIndex", HTTP_GET, []() { server.sendHeader("Connection", "close"); server.send(200, "text/html", serverIndex); }); /*handling uploading firmware file */ server.on("/update", HTTP_POST, []() { server.sendHeader("Connection", "close"); server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); ESP.restart(); }, []() { HTTPUpload& upload = server.upload(); if (upload.status == UPLOAD_FILE_START) { Serial.printf("Update: %s\n", upload.filename.c_str()); if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size Update.printError(Serial); } } else if (upload.status == UPLOAD_FILE_WRITE) { /* flashing firmware to ESP*/ if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { Update.printError(Serial); } } else if (upload.status == UPLOAD_FILE_END) { if (Update.end(true)) { //true to set the size to the current progress Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); } else { Update.printError(Serial); } } }); server.begin(); }   void loop(void) { server.handleClient(); delay(1);   //loop to blink without delay unsigned long currentMillis = millis();   if (currentMillis - previousMillis >= interval) { // save the last time you blinked the LED previousMillis = currentMillis;   // if the LED is off turn it on and vice-versa: ledState = not(ledState);   // set the LED with the ledState of the variable: digitalWrite(led, ledState); } }

Test Code Description

  • We are using the same old code with an additional LED blinking part.
  • In this code, we are using inbuilt LED for testing.
  • Define the GPIO pin to which LED is connected.
  • GPIO 2 is connected to the inbuilt LED.
  • To add delay, we are using timers instead of delay() function.
  • The variable interval is defining the time delay.
  • Set LED’s state to low.

Fig. 18

Arduino Loop() Function

  • Blink the LED after every 1000ms or 1sec delay as defined in variable ‘interval’.

Fig. 19

How to generate a bin file

  • Compile the code in Arduino IDE.
  • Go to Sketch > Export compiled Binary or press Crl+Alt+S to generate .bin file.

Fig. 20

Fig. 21 bin file

  • Upload the .bin file on the browser with 192.168.43.223/serverIndex URL and click on update option.
  • At 100% progress the inbuilt LED from the ESP32 board will start blinking.

Fig 22

Fig. 23 LED blink

  • Similarly, you can upload a new code using over the air web updater.

This concludes the tutorial. I hope, you found this helpful and I hope to see you soon for the new ESP32 tutorial.

ESP32 OTA (Over The Air) Programming

Hello readers, hope you all are doing great. In this tutorial, we are going to discuss a mechanism that allows users to update the ESP32 with a new program wirelessly or over the air (without using a USB cable to upload a new program).

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

Over-The-Air (OTA) programming

Fig. 1 ESP32 OTA

  • OTA programming is the mean by which a product manufacturer or product service provider can update the features or functionality of the device wirelessly or over the air, after the device has been deployed in the field where connecting a cable or uploading the code serially is difficult.
  • One key advantage of OTA is that a single central node can send an update to multiple ESPs on the same network.
  • The device must have a provisioning client capable of receiving, processing, and setting parameters in order to receive, process, and set parameters in a mobile device over the air.

Applications of OTA programming

Mobile Phones:

  • In order to improve the compatibility with hardware and enhance the stability of software and applications, software updates are required.
  • OTA updates are intended to improve the underlying operating system, time zone rules, read-only apps installed on the system partition these updates have no effect on user-installed applications.

IoT (internet of things) application:

  • The ability to wirelessly download an application, configuration, or firmware to internet-enabled devices, also known as IoT, is referred to as over-the-air (OTA). It works in the same way that our computers, laptops, tablets, and phones do.
  • Application, where sensor nodes are frequently placed in remote or difficult-to-reach locations OTA programming can be used.

Fig. 2 OTA programming for IoT

 

How does OTA programming work?

There are two methods of OTA implementation.

  • Basic OTA: In the basic OTA method the program is updated into ESP32 over the air using Arduino IDE.
  • OTA web updater: In web updater OTA the program is updated over the air using a web browser.

Implementing OTA Update feature using ESP32

In this tutorial, we will discuss only the basic OTA method using Arduino IDE and ESP32 module.

If you want to know more about the basics of ESP32 and how to get started with Arduino IDE, then follow the tutorial Introduction to ESP32 Programming Series.

  • For Basic OTA programming with ESP32, it is required to install the python 2.7.x version in your system.
  • Follow the link to download python: https://www.python.org/downloads/
  • Install the python into your system.
  • Upload the basic OTA code into ESP32 using the serial port.
  • Upload the new ESP32 test code over the air using the network port into esp32 module.

To implement the Basic OTA method, an example is available is Arduino IDE.

  • You can find the code through File> Examples> ArduinoOTA> BasicOTA.
  • An image has been attached below for reference:

Fig. 3

Arduino IDE Code

  • It is required to first upload the basic OTA code serially (using serial com port).
  • Because in default mode the ESP32 is not ready for OTA updates (as there is no inbuilt OTA firmware available inside the ESP32 board).
  • Only after that you can access the OTA feature
#include <WiFi.h> #include <ESPmDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h>   const char* ssid = "SSID"; const char* password = "Password";   void setup() { Serial.begin(115200); Serial.println("Booting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else // U_SPIFFS type = "filesystem";   // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() Serial.println("Start updating " + type); }) .onEnd([]() { Serial.println("\nEnd"); }) .onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }) .onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.begin(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void loop() { ArduinoOTA.handle(); }

Code Description

  • The first step is to add all the necessary header files. Here we are using four header files.
  • WiFi.h: This header file allows the ESP32 board to connect to the internet. It can serve either as a server or a client.
  • ESPmDNS.h: This library is used to implement multicast DNS query support for the ESP32 chip. A multicast UDP service is used to provide local network service.
  • WiFiUdp.h: This is a library for Arduino wifi shield. It is used to send data to a UDP host over a wireless network.
  • ArduinoOTA.h: this library allows users to update the code in the ESP32 board using wifi instead of using the serial port.
  • Next, you need to add your wifi credentials. Enter the SSID and password.

Arduino Setup() Function

  • Inside the setup () function, the first task is to begin the serial monitor at a 115200 baud rate so that, you can print the results and other required details on the serial monitor for verification purposes.
  • Set ESP32 Wi-Fi module in station mode(esp32 will act as a client device) using WiFi.mode() function.
  • Enable ESP32’s Wi-Fi module using WiFi.begin() function which is using SSID and password as arguments.
  • Wait until the ESP32 is not connected with the wifi network.
  • ESP.restart() function will reset the ESP32. ESP.restart() function tells SDK to reboot.
  • If an error occurred in OTA programming, print the error on the serial monitor

  • ArduinoOTA.begin() function is used to initialize the OTA updater.
  • Wi-Fi.lockIP() is used to fetch the IP address.
  • Print the IP address on the serial monitor.

Arduino Loop() Function

  • Inside the loop() function, ArduinoOTA.handle() function is used for updating the ESP32 code over the air using the network port instead of the serial port.
  • Compile the code and upload serially using serial com port.
  • Open the serial monitor, set the baud rate to 115200.
  • You can see the IP address on the serial monitor once the ESP32 is connected to the Wi-Fi network.

Fig. 11 Serial monitor

Uploading new program into ESP32 module Over the Air

Code

#include <WiFi.h> #include <ESPmDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h>   const char* ssid = "public"; const char* password = "ESP32@123";   //variabls for blinking an LED with Millis const int led = 2; // ESP32 Pin to which onboard LED is connected unsigned long previousMillis = 0; // will store last time LED was updated const long interval = 1000; // interval at which to blink (milliseconds) int ledState = LOW; // ledState used to set the LED   void setup() {   pinMode(led, OUTPUT);   Serial.begin(115200); Serial.println("Booting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } ArduinoOTA .onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else // U_SPIFFS type = "filesystem";   // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() Serial.println("Start updating " + type); }) .onEnd([]() { Serial.println("\nEnd"); }) .onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }) .onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); });   ArduinoOTA.begin();   Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); }   void loop() { ArduinoOTA.handle();   //loop to blink without delay unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { // save the last time you blinked the LED previousMillis = currentMillis; // if the LED is off turn it on and vice-versa: ledState = not(ledState); // set the LED with the ledState of the variable: digitalWrite(led, ledState); } }
  • In the test code, which we are going to upload using a wireless network port over the air, a LED blinking function is added just to test whether the OTA functionality is working fine or not.

Note: It is required to upload the OTA programming handler code every time you upload a new code into ESP32 over the air. So that, OTA programming remains enabled for future use.

Code Description

  • Add the required header files.

  • Enter Wi-FI credentials over which you are going to upload the code wirelessly.
  • Define the GPIO pin to which LED is connected.
  • GPIO 2 is connected to the inbuilt LED.
  • To add delay, we are using timers instead of delay() function.
  • The variable interval is defining the time delay.
  • Set LED’s state to low.

Arduino Setup() Function

  • Although in the example code serial monitor is initialized but it is not required anymore as we are using the network port for communication.
  • Initialize ESP32 Wi-Fi in station mode using WiFi.mode() function.
  • Wait until esp32 is connected to the Wi-Fi network.

  • ArduinoOTA.begin() function is used to initialize the OTA updater.
  • Wi-Fi.lockIP() is used to fetch the IP address.
  • Print the IP address on the serial monitor.

Arduino Loop() Function

  • Blink the LED after every 1000ms or 1sec delay as defined in variable ‘interval’.

  • Compile the above code.
  • Go to the Tools menu, then click on port and select the network port as shown in the image below.

This concludes the tutorial. I hope you found this helpful. In the next tutorial, we will discuss the OTA web updater in ESP32.

ESP32 Low Power Modes

Hello readers, hope you all are doing great. In this tutorial, we will discuss low power modes in ESP32, their purpose and their implementation to increase the battery life by reducing power consumption.

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

Purpose of Low Power Modes

Fig.1

Along with multiple wireless and processing features, ESP32 also provides us with a power-saving feature by offering sleep modes. When you are powering the ESP32 module from the live supply using an adaptor or a USB cable, there is nothing to worry about power consumption. But when you are using a battery, as a power source to ESP32, you need to manage the power consumption for longer battery life.

Low Power Modes in ESP32

When ESP32 is in sleep mode, a small amount of power is required to maintain the state of ESP32 in RAM (random access memory) and retain necessary data. Meanwhile, the power supply won’t be consumed by any unnecessary peripheral or inbuilt modules like Wi-Fi and Bluetooth.

ESP32 offers 5 power modes. Each mode is configurable and offers different power-saving capabilities:

  1. Active Mode
  2. Modem Sleep Mode
  3. Light Sleep Mode
  4. Deep Sleep Mode
  5. Hibernation Mode

Fig. 2

Active Mode:

  • In active mode, all the modules and features of ESP32, like processing cores, Wi-Fi, Bluetooth, radio etc. remain active all the time.
  • Most of the power consumption occurs in this power mode which can vary between 160 -240mA and sometimes the maximum consumption could reach up to 790mA (when both Wi-Fi and Bluetooth are enabled or active at the same time).

Modem Sleep Mode:

  • In this mode, radio, Wi-Fi, Bluetooth will be disabled and everything else will remain active. Power consumption in this mode varies from 3 to 20mA.
  • Sleep modes can switch between modem and active modes as per the predefined intervals, by following the associated sleep pattern.

Light Sleep Mode:

  • During this mode, the central processing unit is paused by turning/powering off its clock.
  • ULP- coprocessor and RTC (real-time clock) remain active during light sleep mode and power consumption is 0.8mA.

Deep Sleep mode:

  • In this mode, the Ultra Low Power (ULP) coprocessor remains active while the ESP32 core and other digital peripherals remain inactive.
  • The ULP coprocessor wakes up the core processor when required.
  • The amount of power consumed in this mode is 10uA.

Fig 3

Hibernation Mode:

    • In this mode, the ULP coprocessor and internal oscillator both are disabled.
  • Only a real-time clock (RTC) remains active to wake up the processor and other required modules from hibernation mode and the power consumption in this mode is extremely low that is approximately 2.5uA.

For a better understanding of low power modes in ESP32, we are going to implement deep sleep mode in esp32 and will also discuss how to wake up the device from deep sleep mode.

Deep Sleep mode and Wakeup Using Capacitive Touch-sensitive pins

To implement deep sleep modes we are going to use another ESP32 feature that is Capacitive Touch Sensing pins. These pins can sense the presence of a body that holds an electric charge.

So we are going to use these touch-sensitive pins for waking up ESP32 from deep sleep mode using the Arduino IDE compiler.

In Arduino IDE examples are given for deep sleep mode with various wake-up methods.

  • Follow the image attached below to open the example code:

Fig. 4 Example code.

  • Arduino IDE Code

#define Threshold 40 /* Greater the value, more the sensitivity */ RTC_DATA_ATTR int bootCount = 0; touch_pad_t touchPin; /* Method to print the reason by which ESP32 has been awaken from sleep */ void print_wakeup_reason(){ esp_sleep_wakeup_cause_t wakeup_reason;   wakeup_reason = esp_sleep_get_wakeup_cause();   switch(wakeup_reason) { case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break; case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break; case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break; case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break; default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break; } }   /* Method to print the touchpad by which ESP32 has been awaken from sleep */ void print_wakeup_touchpad(){ touchPin = esp_sleep_get_touchpad_wakeup_status();   switch(touchPin) { case 0 : Serial.println("Touch detected on GPIO 4"); break; case 1 : Serial.println("Touch detected on GPIO 0"); break; case 2 : Serial.println("Touch detected on GPIO 2"); break; case 3 : Serial.println("Touch detected on GPIO 15"); break; case 4 : Serial.println("Touch detected on GPIO 13"); break; case 5 : Serial.println("Touch detected on GPIO 12"); break; case 6 : Serial.println("Touch detected on GPIO 14"); break; case 7 : Serial.println("Touch detected on GPIO 27"); break; case 8 : Serial.println("Touch detected on GPIO 33"); break; case 9 : Serial.println("Touch detected on GPIO 32"); break; default : Serial.println("Wakeup not by touchpad"); break; } }   void callback(){ //placeholder callback function }   void setup(){ Serial.begin(115200); delay(1000); //Take some time to open up the Serial Monitor   //Increment boot number and print it every reboot ++bootCount; Serial.println("Boot number: " + String(bootCount));   //Print the wakeup reason for ESP32 and touchpad too print_wakeup_reason(); print_wakeup_touchpad();   //Setup interrupt on Touch Pad 3 (GPIO15) touchAttachInterrupt(T3, callback, Threshold);   //Configure Touchpad as wakeup source esp_sleep_enable_touchpad_wakeup();   //Go to sleep now Serial.println("Going to sleep now"); esp_deep_sleep_start(); Serial.println("This will never be printed"); }   void loop(){ //This will never be reached }

Code Description

  • The first step is to set the threshold value for touch-sensitive pins.
  • When a body, containing an electric charge touches a touch-sensitive pin, the threshold value decreases below 40, that decrease in the threshold value will make ESP32 wake up from deep sleep mode. In the example code threshold value is 40.
  • The next task is to store the data into RTC memory (using RTC_DATA_ATTR ) because in deep sleep mode only RTC remains active and all other peripherals, processors, wireless modules will be disabled.
  • ESP32 offers 8kB SRAM on RTC to store the data.
  • But when you press EN/reset button the data stored in RTC memory will also be erased.
  • bootCount an integer type variable is used to count the number of times ESP32 has woken up during sleep mode. The value of bootCount variable is stored in RTC memory.
  • The print_wakeup_reason() function is used to print the reason for ESP32 wakeup from deep sleep whether it is due to an external interrupt, timer, or touch-sensitive pins.
  • The ESP32 has multiple capacitive touch-sensitive GPIO pins which can be used to wake up esp32 from deep sleep mode.
  • Print_wakeup_touchpad() function is used to print the GPIO pin which made ESP32 wake up from sleep mode.
  • When you hold a capacitive sensitive pin for a longer duration the threshold value (initialized globally) decreases from its predefines value i.e., 40 which will cause ESP32 to wake up, at that time the callback() function comes into action.
  • This function will be used as an argument inside the touchAttachInterrupt() function.

Setup()

  • Inside the setup() function the first task is to start the serial monitor with a baud rate of 115200.
  • Next, if there is any increment in boot count due to wake up calls, then print that count on the serial monitor.

Call the respective functions to print the wake-up reason:
  • Print_wakeup_reason() is used to print whether the ESP32 wake-up is caused by an external interrupt, timer or a capacitive sensitive pin.
  • If the wake up is due to a capacitive sensitive pin then the print_wakeup_touchpad() function will print the GPIO pin number which caused the wake-up.
  • The next task is to attach the interrupt using touchAttachInterrupt() function, to capacitive sensitive GPIO pin which you will use to wake up ESP32.
  • In this example we are using GPIO 15 capacitive sensitive pin as a wakeup interrupt pin.
  • esp_sleep_enable_touchpad_wakeup() is used to enable touch sensor feature.
  • esp_deep_sleep_start() function is used to make ESP32 enter to deep sleep mode.
  • Once ESP32 enters the sleep mode no other operation or data communication is possible until it receives a wakeup call.

Fig 12

Loop()

  • In this example code, there is nothing, written inside the loop function. But you can change the code as per your requirements.

Code Testing

  • To test the code, use a connecting wire (male to female) and connect one side to ESP32’s touch-sensitive pin (which you have mentioned in the code as an interrupt).
  • When you touch that pin an interrupt will be generated to wake ESP32 from sleep.
  • You can see the results on a serial monitor or can check the current consumption or can run other functions once it is awake like blinking LED.
  • In this code, we are using GPIO_15 touch-sensitive pin.

Fig. 13 waking up esp32 using capacitive sensitive GPIO pin

We have attached a screenshot from the serial monitor for reference.

Fig. 14

Deep Sleep mode and Wakeup Using Interrupt method

Arduino IDE Code

#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ #define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */ RTC_DATA_ATTR int bootCount = 0; /* Method to print the reason by which ESP32 has been awaken from sleep */ void print_wakeup_reason(){ esp_sleep_wakeup_cause_t wakeup_reason; wakeup_reason = esp_sleep_get_wakeup_cause(); switch(wakeup_reason) { case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break; case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break; case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break; case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break; default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break; } }   void setup(){ Serial.begin(115200); delay(1000); //Take some time to open up the Serial Monitor   //Increment boot number and print it every reboot ++bootCount; Serial.println("Boot number: " + String(bootCount));   //Print the wakeup reason for ESP32 print_wakeup_reason();   /* First we configure the wake up source We set our ESP32 to wake up every 5 seconds */ esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");   /* Next we decide what all peripherals to shut down/keep on By default, ESP32 will automatically power down the peripherals not needed by the wakeup source, but if you want to be a poweruser this is for you. Read in detail at the API docs http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html Left the line commented as an example of how to configure peripherals. The line below turns off all RTC peripherals in deep sleep. */ //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); //Serial.println("Configured all RTC Peripherals to be powered down in sleep");   /* Now that we have setup a wake cause and if needed setup the peripherals state in deep sleep, we can now start going to deep sleep. In the case that no wake up sources were provided but deep sleep was started, it will sleep forever unless hardware reset occurs. */ Serial.println("Going to sleep now"); Serial.flush(); esp_deep_sleep_start(); Serial.println("This will never be printed"); }   void loop(){ //This is not going to be called }

Code Description

  • The first task is, to define the timer period for which ESP32 will be in deep sleep mode.
  • As we know that ESP32 operates at the MHz frequency range so the timer will be in microseconds. So, it is required to convert the time into seconds.
  • To add a timer of 5sec we need to multiply 5*1000000.
  • bootCount an integer type variable is used to count the number of times ESP32 has woken up during sleep mode. The value of bootCount variable is stored in RTC memory.

Fig 15

  • The print_wakeup_reason() function is used to print the reason for ESP32 wakeup from deep sleep whether it is due to an external interrupt, timer or touch-sensitive pins.

Fig. 16

Setup()

  • As discussed earlier, inside the setup function first we need to initialize the serial monitor at 115200 baud rate and then print the value of bootCount variable which is incrementing every time a wakeup interrupt occurs.

Fig. 17

  • The esp_sleep_enable_wakeup() function is used to enable the timer to generate a timer interrupt by passing time in microsecond as an argument.
  • In the beginning of code we have defined some global variable to add 5 sec timer (or 5000000us) and after every 5 sec ESP32 should wake up from deep sleep till 5 sec.

Fig. 18

  • esp_deep_sleep_start() function is used to make ESP32 enter the deep sleep mode.

Fig. 19

Testing

  • You can see the results of above code on serial monitor as shown is the image attached below.

Fig 20

This concludes the tutorial. I hope you found this useful, and I hope to see you soon for the new ESP32 tutorial.

ESP32 PWM(Pulse Width Modulation) in Arduino IDE

Hello readers, I hope you all are doing great. Welcome to the 3rd Lecture of Section 2 in the ESP32 Programming Series. In this tutorial, we are going to discuss another important feature of ESP32 i.e. PWM(Pulse Width Modulation).

Pulse Width Modulation is a technique to reduce the voltage by pulsating it. In today's lecture, we will first understand the basic concept of PWM, and after that will design two projects to fully grasp it. In the first project, we will control the brightness of an LED, while in the second one, we will control the speed of a DC Motor.

  • Here's the video demonstration of PWM Control in ESP32:

Before going forward, let's first have a look at the PWM working:

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

What is Pulse Width Modulation?

PWM is used to control the power delivered to the load by pulsating the ON-Time of the voltage pulse, without causing any power loss. Let's understand the PWM concept with the help of below image:

  • As you can see in the above image, Figure A shows a simple 5V DC signal.
  • Figure D shows a simple circuit with a manual switch, now if we turn the switch ON & OFF manually, the Load will also behave in the same way. Its waveform is shown in Figure B, when the switch is ON, we are getting +5V and when it's OFF, output is 0V.
  • Instead of manual switching, if we place a fast automatic switching circuit (FETs, MOSFETs etc.), the output pulse won't show fluctuations, instead, it will get steady but its overall power will be reduced.
  • Let's understand the working of PWM with an example:

Suppose a DC Motor runs at 200RPM over 5V. Now, if we want to reduce its speed to 100 RPM, we need to reduce its input voltage to 2.5V(approx). So, either we can replace the 5V battery with a 2.5V Battery or use a PWM circuit to reduce the voltage level from 5V to 2.5V. In this specific case, the PWM pulse will be ON for 50% of the time and get OFF for the remaining 50% of the time.

The behavior of the PWM signal is determined by the following factors:

  • Frequency
  • Duty Cycle
  • Resolution

PWM Frequency:

  • The Frequency of a signal is defined as the number of cycles per second, denoted by "f" and the measuring unit is hertz(Hz).
  • The Frequency (f) of a signal is inversely proportional to its time period(t).
  • Let's understand the signal Frequency with the help of below image:

As you can see in the below figure, we have taken two signals for a duration of 1 second. The first signal completes 10 Cycles in 1 second, so we can say it has a frequency of 10Hz, while the second one has a frequency of 5Hz as it completes 5 cycles in 1 second. So, I hope now it's clear that the number of cycles per second is the frequency of a signal.

  • The frequency of a PWM signal depends on the provided clock source.
  • In the case of microcontrollers, the clock source is provided by the crystal oscillator. So, a 40MHz Crystal Oscillator can produce high-frequency PWM signals as compared to a 20MHz oscillator.

PWM Duty Cycle:

Duty Cycle is the ratio of ON time(when the signal is high) to the total time taken to complete the cycle. The duty cycle is represented in the form of a percentage (%) or ratio. Let's understand the PWM Duty Cycle with the help of below image:

  • The 1st graph shows no signal, so we can say it has a 0% Duty Cycle because there's no ON-Time.
  • The 2nd graph shows 5 cycles of a signal and in each cycle, the signal is ON only for 25% of the total time. So, its Duty Cycle is 25%.
  • In the 3rd graph, the signal has a duty cycle of 50% because it's HIGH for 50% of the cycle.
  • You can calculate the 4th graph, its duty cycle is 75% as it is HIGH for 75% of the total duration.
  • The last graph shows a pure DC Signal of 5V, and as it is HIGH for the whole cycle, its duty cycle will be 100%.

Resolution:

The resolution of a PWM signal defines the number of steps it can have from zero power to full power. The resolution of the PWM signal is configurable for example, the ESP32 module has a 1-16 bit resolution, which means we can configure maximum a of 65536 (2^16) steps from zero to full power.

Implementing PWM using ESP32

In the ESP WROOM-32 module, there are 16 PWM channels. All the channels are divided into two groups containing 8 channels in each group. The resolution can be programmed between 1 to 16 bits and frequency also depends upon the programmed resolution of the PWM signal.

Now

For the demonstration of PWM in ESP32 we are going to explain two examples:

  1. Controlling LED brightness using PWM
  2. Controlling DC motor speed using PWM

ESP32 Code for Controlling LED brightness using PWM

We are using Arduino IDE to compile and upload the code into the ESP WROOM-32 board.

  • If you are new to Arduino IDE and ESP32 then follow our previous tutorial, Introduction to ESP32 programming series for detailed information.
  • ESP32’s inbuilt LED is used in this code. You can also connect an external LED as per your requirements.

Arduino IDE Code:

// Global variable declaration to set PWM properties
const int ledChannel = 0; // select channel 0
const int resolution = 8; //8-bit resolutin i.e., 0-255
const int frequency = 5000; // set frequency in Hz
int dutyCycle = 0;

void setup()
{
    Serial.begin(115200);
    ledcSetup(ledChannel, frequency, resolution); // configure LED PWM functionalities
    ledcAttachPin(LED_BUILTIN, ledChannel); // attach the channel to the GPIO to be controlled
}

void loop()
{
    while(dutyCycle <200)
    {
        ledcWrite(ledChannel, dutyCycle++); // changing the LED brightness with PWM
        Serial.print(" duty Cycle ++ :");
        Serial.println(dutyCycle); // display the duty cycle on serial monitor
        delay(5);
    }
    while(dutyCycle>0)
    {
        ledcWrite(ledChannel, dutyCycle--); // changing the LED brightness with PWM
        Serial.print(" duty Cycle -- :");
        Serial.println(dutyCycle); // display the duty cycle on serial monitor
        delay(5);
    }
}

Code Description

Global Variable declaration:
  • The first step is to declare variables for setting PWM properties.
  • As we have already mentioned that ESP WROOM-32 has 16 PWM channels (0 to 15). So, the first step will be to select a PWM channel between 0-15. In the Arduino IDE code, we are using PWM channel_0 to generate a PWM signal.
  • The next step will be to choose the resolution. The maximum resolution for ESP32 is 16-bit. You can choose any value between 1-16. PWM resolution is the factor that decides the maximum duty cycle.
  • For example, if we choose 10-bit resolution then the maximum duty cycle of the output signal will be 2^10 that is 1024 (0-1023) and similarly, for 8-bit resolution the duty cycle will be 2^8=256 (0- 255).
  • 5KHz or 5000Hz is the PWM signal frequency.
  • We also need to initialize a variable to store the duty cycle value.

// Global variable declaration to set PWM properties
const int ledChannel = 0; // select channel 0
const int resolution = 8; //8-bit resolutin i.e., 0-255
const int frequency = 5000; // set frequency in Hz
int dutyCycle = 0;

Arduino Setup() Function

  • Inside setup() function we are going to start serial monitor at 115200 baud rate.

Serial.begin(115200);
  • To configure PWM properties we are calling the ledcSetup() function which uses PWM properties (like PWM channel, frequency and PWM resolution) as arguments.

ledcSetup(ledChannel, frequency, resolution); // configure LED PWM functionalities
  • ledcAttachPin() function is used to assign the LED_BUILTIN pin to the PWM channel.

ledcAttachPin(LED_BUILTIN, ledChannel); // attach the channel to the GPIO to be controlled

Arduino Loop() Function

  • Inside the loop function, we going to run a conditional control loop (while loop) to change the LED brightness along with the change in duty cycle.
  • At first, the value of the duty cycle is going to increase continuously until it reaches max 8-bit resolution ( that is 255).
  • The serial monitor will print the duty cycle value with some delay.

while(dutyCycle <200)
    {
        ledcWrite(ledChannel, dutyCycle++); // changing the LED brightness with PWM
        Serial.print(" duty Cycle ++ :");
        Serial.println(dutyCycle); // display the duty cycle on serial monitor
        delay(5);
    }

  • After increasing the duty cycle to maximum resolution another while loop is used to decrease the duty cycle to value 0 from 255 and proportionally the LED brightness and the PWM output will be printed on the serial monitor.

while(dutyCycle>0)
{
    ledcWrite(ledChannel, dutyCycle--); // changing the LED brightness with PWM
    Serial.print(" duty Cycle -- :");
    Serial.println(dutyCycle); // display the duty cycle on serial monitor
    delay(5);
}

Code Testing

  • You can see the change in the value of the duty cycle on the serial monitor. We have attached a screenshot below from the Arduino IDE serial monitor for reference.

  • For a better understanding of PWM output you can use an oscilloscope (either CRO or DSO) by connecting the PWM output pint and GND pint to the oscilloscope probe, if available.
  • You can also use a serial plotter to see the PWM output if you do not have an oscilloscope.
  • To access the serial plotter, use sort-cut key shift+ctrl+L or follow the image attached below:

Fig. 8 Arduino IDE Serial Plotter

  • We have attached a screenshot of the PWM output waveform from the serial plotter for better understanding.
  • You can vary the value of duty cycle anywhere between 0-8 bit resolution.
  • For example in the image attached below the duty cycle is 200.

Fig. 9 Serial plotter PWM output

ESP32 Code for Controlling DC motor speed using PWM

Fig. 10

In this example, we are going to implement PWM using ESP WROOM-32 to control the speed of a DC motor.

The speed of the DC motor depends upon the input power supply. So, by varying the power input we can also vary (increase or decrease) the speed of DC motor.

Hardware components required:

  • ESP WROOM-32 board
  • DC motor
  • L298N motor driver
  • Connecting wires
  • Data cable

L298N motor driver: A motor driver is used between the ESP32 board and DC motor to resolve the power compatibility issues.

Both the ESP32 board and DC motor operate at different power ratings due to which you can not connect the two devices directly. So a motor driver is used to receive a low power input from the ESP32 board and drive/run DC motor at slightly high power.

L298N can drive a DC motor that operated between 5 to 35 voltage range and maximum current of 2A.

There are various DC motor drivers available in the market for example L293D, DRV8833, MAX14870 single brushed motor driver etc. You can choose the driver of your choice depending upon the application and power ratings.

Fig. 11

FIG. 12 IC L298N pin-out

  • You can also change the direction of rotation by connecting the input as per the table drawn below:
IN_1 IN_2 Rotation
HIGH LOW DC motor rotates in a clockwise direction
LOW HIGH The motor rotates in an anti-clockwise direction
LOW LOW Motor STOP
HIGH HIGH Motor STOP

Table 1

Arduino Code

//configure GPIO pins to connect motor driver
int enable1Pin = 14;
int M_Pin1 = 26;
int M_Pin2 = 27;

// Setting PWM properties
const int freq = 10000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 150;

void setup()
{
    Serial.begin(115200);

    // sets the pins as outputs:
    pinMode(M_Pin1, OUTPUT);
    pinMode(M_Pin2, OUTPUT);
    pinMode(enable1Pin, OUTPUT);

    //Configure LED PWM functionalities
    ledcSetup(pwmChannel, freq, resolution);

    // attach the channel to the GPIO to be controlled
    ledcAttachPin(enable1Pin, pwmChannel);

    Serial.print("Testing DC Motor...");
}

void loop()
{
    // Move the DC motor in anti-clockwise direction at maximum speed
    Serial.println("Moving reverse");
    digitalWrite(M_Pin1, LOW);
    digitalWrite(M_Pin2, HIGH); 
    delay(500);

    // Move DC motor forward with increasing speed
    Serial.println("Moving Forward");
    digitalWrite(M_Pin1, HIGH);
    digitalWrite(M_Pin2, LOW);

    //----while loop----
    while (dutyCycle <= 255)
    {
        ledcWrite(pwmChannel, dutyCycle); 
        Serial.print("Speed increasing with duty cycle: ");
        Serial.println(dutyCycle);
        dutyCycle = dutyCycle +5;
        delay(100);
    }

    while (dutyCycle >150)
    {
        ledcWrite(pwmChannel, dutyCycle); 
        Serial.print("Speed decreasing with duty cycle: ");
        Serial.println(dutyCycle);
        dutyCycle = dutyCycle -5;
        delay(100);
    }

    // _____Stop the DC motor
    Serial.println("STOP DC motor");
    digitalWrite(M_Pin1, LOW);
    digitalWrite(M_Pin2, LOW);
    delay(500);
}

Code Description

  • The first step is to configure GPIOs which are to be connected with the DC motor driver (L298N).
  • Here we are using three GPIOs, the first one is connected with the Enable_A pin and the rest of the two are connected with motor inputs.
  • You can also control 2 motors with the same driver using Enable_2 and its respective input pins.

//configure GPIO pins to connect motor driver
int enable1Pin = 14;
int M_Pin1 = 26;
int M_Pin2 = 27;
  • The next step is to define variables to store PWM properties as discussed in the previous example.
  • You can vary the frequency and duty cycle of the PWM signal as per your requirements but, within the desired range.
  • Here we are assigning 10000Hz or 10KHz frequency with 8-bit resolution (0-255 duty cycle) and the initial duty cycle value is 150 for PWM channel 0.

// Setting PWM properties
const int freq = 10000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 150;

Arduino Setup() Function

  • Inside the setup function, the first task is to initialize the serial monitor with a 115200 baud rate.

Serial.begin(115200);
  • Set the operating mode of three GPIO pins (which are to be connected with motor driver board) as output.

// sets the pins as outputs:
pinMode(M_Pin1, OUTPUT);
pinMode(M_Pin2, OUTPUT);
pinMode(enable1Pin, OUTPUT);

  • Call the function ledcSetup() to configure PWM properties by passing PWM properties as arguments.

//Configure LED PWM functionalities
ledcSetup(pwmChannel, freq, resolution);
  • Next, you need to select the GPIO pin which will provide the PWM output from ESP32 to the motor driver using ledcAttachPin() function which uses the PWM output pin and PWM channel as two arguments.

// attach the channel to the GPIO to be controlled
ledcAttachPin(enable1Pin, pwmChannel);

Arduino Loop() Function

  • Start rotating the motor in the anti-clockwise direction. Follow Table 1 for more details regarding the direction of rotation.
  • Add the delay of 0.5 sec or as per your requirements.

Fig. 19

  • Rotate the DC motor in a clockwise direction by setting M_PIN1 as high ND m_Pin2 as low.

Fig. 20

  • As we have initialized the duty cycle variable with a value of 150. Now, increase the motor speed by increasing the value of the Duty cycle from 150 by increasing 5 steps continuously until it reaches the maximum value that is 255.

Fig. 21 Increasing speed

  • After reaching the maximum speed at 255 duty cycle, now let's decrease the speed of DC motor till 150 duty cycle with the decrease of 5 steps every time.

Fig. 22 Reducing speed

  • Stop duty cycle by either writing both the motor pins(M_Pin1, M_Pin2) to LOW or HIGH (like XOR gate).

Fig. 23 STOP DC motor

Code Testing

  • For a better understanding, open the serial monitor using shortcut keys ctrl+shift+M.
  • On the serial monitor, you can see the increase and decrease in duty cycle and can compare it with DC motor speed.

Fig. 24 PWM output on serial monitor

  • You can also check the PWM output on the Serial plotter by pressing the ctrl+shift+L keys.
  • It is visible through the waveform that the duty cycle is varying from 150 to 255 and reverse and proportionally the seed of the DC motor.

Fig. 25 PWM output on Serial Plotter

This concludes the tutorial. I hope you found this useful, and I hope to see you soon for the new ESP32 tutorial.

ESP32 Web Server in Access Point (AP) Mode

Hello readers, hope you all are doing great. This is our 3rd tutorial in the ESP32 programming series. In our previous tutorial, we discussed the ESP32 Web server, where we created the ESP32 web server in STA mode.

ESP32 can be operated as an access point (AP) or a Wi-Fi station (STA mode). So, in this tutorial, we will create an ESP32 web server in access point (AP) mode. Here's the video demonstration of ESP32 WebServer in Access Point Mode:

As I mentioned above, in our 2nd tutorial, we already discussed the basics of the ESP32 web server. So, in this tutorial, we will only discuss how to create the ESP32 in access point mode.

For detailed information about the basics of the ESP32 web server and how client-server communication takes place, follow our previous tutorial (i.e., Create a Web Server with ESP32).

Where To Buy?
No.ComponentsDistributorLink To Buy
1ESP32AmazonBuy Now

What happens in Access Point (AP) mode?

In Access Point Mode the ESP32 creates its own wireless Wi-Fi network in this mode, similar to the one provided by your existing router. In access point mode, we don't need to connect the ESP2 to a Wi-Fi network. In the Wi-Fi network it creates, the ESP32 Wi-Fi board can connect up to 5 devices.

Fig 1 ESP32 as an Access Point

So, in access point mode, nearby Wi-Fi devices such as mobile phones, laptops, or a secondary ESP32 module acting as a station can connect directly to the AP (ESP32 module) without the need for an external Wi-Fi router.

On the other hand, in Station mode, the ESP32 wi-fi module connects to your Wi-Fi network through a router. The router acts as a conduit for communication between the web client and the ESP32. The Wi-Fi router provides the IP address. This IP address can be used by web clients to connect to the Web server on a local network.

To know about how to set up/operate Arduino IDE for ESP32 compilation, follow our first tutorial i.e., Introduction to ESP32 programming series.

ESP32 Web Server in Access Point (AP) Mode

Here we are using an inbuilt example from Arduino IDE(ESP32). You can modify the example code as per your requirements or can write your own code.

  • To find the Wi-Fi Access Point example in Arduino IDE :
  • Click on File from the top menu bar.
  • Place the mouse cursor on the example option from the list.
  • Look for the WiFi option.
  • There you will find the WiFiAccessPoint option, click on that and compile the program.

A screenshot is attached below to help you find the example code in Arduino IDE.

Fig 2 Wi-Fi access point example

The first task while writing the WiFi code is to add the required wifi header files or libraries in the code.

Here we are adding three libraries.

  • WiFi.h: This header file contains all the functions related to Wi-Fi activities like enabling the Wi_Fi, connecting to a wi-fi network etc.
  • WiFiClient.h: This header file is used to create a client that can connect with a specific IP address.
  • WiFiAP.h: This header file is used to configure and manage ESP32’s wifi module in Access Point (AP) mode.

Fig 3: Libraries

Define the LED pin or a GPIO (for peripheral interface) which we going to control through web server. Here we are using the inbuilt LED which is internally connected with GPIO2

Give a name (SSID) to the ESP32 Access Point and set the password for security purpose ( if you wish to).

While creating a web server we also need to assign a port and usually port 80 is used for local web server.

Arduino Setup() function

Inside the setup function, the LED pin is initialized as an output one and then initialized the serial monitor with a baud rate of 115200.

The next task is to configure the ESP32 Wi-Fi module in access point mode. For that, here we are calling a function called WiFi.softAP. Where we are passing two parameters, ssid and password, respectively.

After configuring the AP mode, we need to fetch the IP address of the access point by calling the WiFi.softAPIP() function and printing it on the serial monitor.

Then, after fetching the IP address, we will start the server using the server. perform.

Arduino Loop() function

After configuring the Access Point mode and initializing the server, the server will next wait for the station or client connection, which can be a mobile phone, a laptop, or another ESP32 board configured in STA mode.

Once the connection is established between the access point and the client device, the access point will wait for the data input.

A string type variable called currentLine has been defined to hold the incoming data from the client.

If there is a byte to be read from the client, then it will be stored inside the char type variable c.

HTTP header always starts with a response code e.g.: HTTP/1.1 200 ok

An HTML page will be created on the client’s browser, from where the client device can control (ON/OFF) the LED.

Different URLs will be created to turn ON and OFF the LED depending upon the HTML input received from the client device i.e., H (to turn ON the LED) and L ( to turn OFF the LED).

Client.stop() function is responsible for closing the connection between Access Point and client or station device.

Note: If you need any guidance regarding how to upload or compile a code for the ESP32 module in Arduino IDE, follow our first tutorial on the ESP32 programming series.

Testing ESP32 web server with hardware in Access Point with Arduino IDE

Here we are going to control the ESP32’s inbuilt LED through an ESP32 web server (AP mode).

We will connect our station or client device through Wi-Fi to the ESP32 module, which (ESP32) is currently acting as an access point (AP).

To establish the connection go to your mobile phone’s Wi-Fi setting.

The Access Point is advertising itself with a pre-defined SSID so that the station devices or clients can find the AP device and can communicate with each other.

If you find a wi-fi device (AP) named ESP32_AP (or as per your SSID) connect to that after entering the assigned password.

Fig. Scanning for available Wi-Fi devices in mobile phone

Fig. Connected with ESP32 AP

As we are using the inbuilt LED, no external components are required.

After connecting to the access point, you can find the IP address of the AP device printed on the Serial Monitor. As shown in the image below:

Fig.: Serial Monitor

Enter the IP address in the browser. Now you can turn the LED ON or OFF using the web page as shown in the images below.

A web page with URL 192.168.4.1/H will be displayed on the browser when LED is turned ON

Fig.: URL when LED is turned ON

LED is blue color represents the inbuilt LED which is connected to GPIO_2.

Fig.: ESP32 LED ON

Another web page with URL 192.168.4.1/L will be created when the AP will receive the input to turn OFF the inbuilt LED. As shown in the image below:

Fig.: Web page displaying the LED off state.

This concludes today’s tutorial. We hope you find it helpful.

In our next tutorial, we will discuss another ESP32 feature that is BLE (Bluetooth low energy).

Syed Zain Nasir

I am Syed Zain Nasir, the founder of <a href=https://www.TheEngineeringProjects.com/>The Engineering Projects</a> (TEP). I am a programmer since 2009 before that I just search things, make small projects and now I am sharing my knowledge through this platform.I also work as a freelancer and did many projects related to programming and electrical circuitry. <a href=https://plus.google.com/+SyedZainNasir/>My Google Profile+</a>

Share
Published by
Syed Zain Nasir