11  Control

11.0.1 Not-so-good LED dimmer

As we saw last time, we can use a potentiometer to control the brightness of an LED or another output device. Add this potentiometer in series in the circuit you have just built, turn the knob and see what happens.

see diagram
see wiring scheme

11.1 PWM with ESP32

Pulse-width modulation (PWM) is a method of controlling the average power delivered by an electrical signal. The average value of voltage (and current) fed to the load is controlled by switching the supply between 0 and 100% at a rate faster than it takes the load to change significantly. PWM is a technique for getting analog results with digital means. Digital control is used to create a square wave, a signal switched between on and off. This on-off pattern can simulate voltages in between the full Vcc of the board and off by changing the portion of time the signal spends on versus the time that the signal spends off. PWM is used in many applications such as controlling motor speed, heat output of heaters and variable speed fan controllers.

Use the following code to activate LED pin with PWM.

Download code
/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-pwm-arduino-ide/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.  
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

// the number of the LED pin
const int ledPin = D9;  // 16 corresponds to GPIO 16

void setup() {
  // set the LED as an output
  pinMode(ledPin, OUTPUT);
}

void loop(){
  // increase the LED brightness
  for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){   
    // changing the LED brightness with PWM
    analogWrite(ledPin, dutyCycle);
    delay(15);
  }

  // decrease the LED brightness
  for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--){
    // changing the LED brightness with PWM
    analogWrite(ledPin, dutyCycle);
    delay(15);
  }
}


If for some reason you are working with an older version of ESP32 board manager (2.0.17 or lower), then use the code below. If you have no idea what I’m talking about, just ignore this.

Download code
// the number of the LED pin
const int ledPin = D9;

// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;
 
void setup(){
  // configure LED PWM functionalitites
  ledcSetup(ledChannel, freq, resolution);
  
  // attach the channel to the GPIO to be controlled
  ledcAttachPin(ledPin, ledChannel);
}
 
void loop(){
  // increase the LED brightness
  for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){   
    // changing the LED brightness with PWM
    ledcWrite(ledChannel, dutyCycle);
    delay(15);
  }

  // decrease the LED brightness
  for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--){
    // changing the LED brightness with PWM
    ledcWrite(ledChannel, dutyCycle);   
    delay(15);
  }
}

11.2 Relay

A relay is an electromagnetic switch that opens and closes circuits electromechanically or electronically. A relatively small electric current that can turn on or off a much larger electric current operates a relay.

The right side in the image above has a set of four pins and a set of three pins. The top set consists of:

  • VCC should be connected to the ESP32 VCC (5 volts)
  • GND connects to the ESP32 GND.
  • IN1 and IN2 are input pins, used to control the bottom and top relays, respectively, and should be connected to a GPIO pin in the ESP32.

The terminals on the left are connected to the load, the equipment that consumes power. The signal you send to the IN pins determines whether the relay is active or not. The relay is triggered when the input goes below about 2V. This means that you’ll have the following scenarios:

  • Normally Closed (NC) configuration:
    • HIGH signal – current is flowing
    • LOW signal – current is not flowing
  • Normally Open (NO) configuration:
    • HIGH signal – current is not flowing
    • LOW signal – current is flowing

Whether you use the NC or NO configuration, you should always connect one of them to the COM (common) terminal.

You should use a normally closed configuration when the current should be flowing most of the time, and you only want to stop it occasionally.

Use a normally open configuration when you want the current to flow occasionally (for example, to turn on a lamp occasionally).

The other set of three pins (on the left in the figure above) are GND, VCC, and JD-VCC. The JD-VCC pin powers the electromagnet of the relay. Notice that the module has a jumper cap connecting the VCC and JD-VCC pins; the one shown here is yellow, but yours may be a different color.

With the jumper cap on, the VCC and JD-VCC pins are connected. That means the relay electromagnet is directly powered from the ESP32 power pin, so the relay module and the ESP32 circuits are not physically isolated from each other.

Without the jumper cap, you need to provide an independent power source to power up the relay’s electromagnet through the JD-VCC pin. That configuration physically isolates the relays from the ESP32 with the module’s built-in optocoupler, which prevents damage to the ESP32 in case of electrical spikes.

The figure above shows in a very simple way that the relay behaves like a switch with respect to the top circuit.

You should NOT build the above circuit, since it is a high voltage circuit (220 V). In class we will use 5, 12 or 24 volts.

Let’s make an LED blink, but now using a relay. The code below is the same you used to make the LED blink, when it got its energy from pin A4. This time, we will use A4 to signal the relay to open or close the circuit.

Download code
int LED_pin = A4;

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_pin as an output.
  pinMode(LED_pin, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_pin, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(3000);                       // wait for a second
  digitalWrite(LED_pin, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}
see diagram
see wiring scheme

11.3 SHT31 Sensor

The SHT31 is a high-precision temperature and humidity sensor that can be used in a wide range of applications. It measures temperature and humidity using a capacitive humidity sensor and a band-gap temperature sensor. It has a wide measurement range of -40°C to 125°C for temperature and 0-100% for relative humidity. The SHT31 is a digital sensor, which means it communicates with the microcontroller over a digital interface. See more details on the Adafruit’s github page for the SHT31 and full specs on the SHT31 datasheet.

11.3.1 Libraries

To use the SHT31 sensor with an ESP32 microcontroller, we will need to use the Adafruit_SHT31 library. This library is specifically designed to work with the SHT31 sensor and makes it easy to read temperature and humidity values from the sensor.

To install the library, follow these steps:

  1. Open the Arduino IDE
  2. Go to Sketch > Include Library > Manage Libraries
  3. Search for “Adafruit_SHT31” and click the Install button
  4. Wait for the library to install

11.3.2 Wiring

To connect the SHT31 sensor to the ESP32 microcontroller, we will need to use four wires: VCC, GND, SDA, and SCL. Here is a table that shows how to connect the wires:

SHT31 Pin ESP32 Pin
VCC 3V3
GND GND
SDA GPIO21
SCL GPIO22

Note: The ESP32’s 3V3 pin provides 3.3 volts of power, which is the correct voltage for the SHT31 sensor. Do not use the 5V pin, as it will damage the sensor.

11.3.3 Code

Here is the code for reading temperature and humidity values from the SHT31 sensor.

Download code
/*
 * This program is a modification of
 * http://www.esp32learning.com/code/esp32-and-sht31-sensor-example.php
 */
#include <Arduino.h>   // Include the Arduino library
#include <Wire.h>      // Include the Wire library for I2C communication
#include "Adafruit_SHT31.h" // Include the SHT31 library from Adafruit

Adafruit_SHT31 sht31 = Adafruit_SHT31(); // Create an instance of the SHT31 object

void setup() {
  Serial.begin(115200);        // Initialize the serial communication with a baud rate of 112500
  if (! sht31.begin(0x44)) {   // Check if SHT31 is connected and start it with address 0x44
    // Print an error message if SHT31 is not found
    Serial.println("Couldn't find SHT31");
    while (1) delay(1);  // Wait indefinitely
  }
}

void loop() {
  // Read temperature from SHT31 and assign it to "temperature"
  float temperature = sht31.readTemperature(); 
  // Read relative humidity from SHT31 and assign it to "humidity"
  float humidity = sht31.readHumidity();

  if (! isnan(temperature)) {     // Check if t is not NaN (not a number)
    Serial.print("temp_deg_C:");  // Print temperature label
    Serial.print(temperature);    // Print temperature value
    Serial.print("\t");           // Write a tab space
  } 
  else {
    // Print an error message if temperature reading fails
    Serial.println("Failed to read temperature");
  }

  if (! isnan(humidity)) {        // Check if h is not NaN (not a number)
    Serial.print("rel_hum_%:");   // Print humidity label
    Serial.print(humidity);       // Print humidity value
  } 
  else {
    // Print an error message if humidity reading fails
    Serial.println("Failed to read humidity");
  }

  Serial.println();    // Break line
  delay(1000);         // Wait 1 second
}

11.4 Challenges

11.4.1 High temperature activates fan

You will receive a low-voltage fan. Build a control system that turns the fan on if temperature goes above a given threshold, e.g. 30 °C.

11.4.2 Traffic lights

Using red, orange and green LEDs, build a traffic light system that responds to temperature:

  • red turns on if \(T>30\) °C
  • orange turns on if \(27<T<30\) °C
  • green turns on if \(T<27\) °C

11.4.3 Bonus

Build an PMW-based control system where the duty cycle tempends on temperature.

11.5 Extra codes and examples