PWM Tutorial for Arduino, ESP8266 and ESP32

In this tutorial you learn what Pulse Width Modulation (PWM) is and how to create different PWM signals from your Arduino, ESP8266 or ESP32 microcontroller.

In two detailed example you change the brightness of an LED and control the speed of a DC motor by using the PWM signal from the microcontroller.

PWM thumbnail

Table of Contents

How does PWM for Microcontroller Work?

The digital inputs / outputs on your microcontroller have a constant voltage of 3.3V (for ESP8266 and ESP32 boards) or 5V (for Arduino boards). But in some cases you want to control the voltage to a specific value between 0V and the maximum voltage.

In case of PWM, a signal is pulsing between HIGH (3.3V or 5V) and LOW (0V). How often the signal is changing between HIGH and LOW is defined by the PWM frequency. The PWM frequency on Arduino pins are 976 cycles per seconds (Herz), for the ESP8266 up to 1 kHz and for the ESP32 up to 40 MHz.

To generate a PWM signal you use the function analogWrite(pin, value). This function create a square wave PWM signal. You can control the shape of the PWM signal with the duty cycle of (value/255). A 0% to 100% duty cycle corresponds to a value between 0 and 255.

The following table shows broadly the relation between the duty cycle and the average output voltage if the maximum voltage is 5V for Arduino microcontroller and 3.3V for ESP8266 and ESP32 microcontroller.

Duty CycleOutput voltage (Arduino)Output voltage (ESP8266 and ESP32)analogWrite(X)
0%0V0V0 = 0%*255
0.25%1.25V0.825V63.75 = 25%*191.25
0.5%2.5V1.65V127.5 = 50%*255
0.75%3.75V2.475V191.25 = 75%*255
100%5V3.3V255 = 100%*255

I used my oscilloscope to measure the duty cycles of the table above for the Arduino output voltage. Therefore I connected digital pin 11 of the Arduino Uno to my PicoScope and set up a measurement for the duty cycle. You can do the exactly same measurement for the ESP8266 or the ESP32

The code for the quick measurement is the following. For each measurement I changed the value for the analogWrite function.

Duty Cycle 0%
Note that the 0% duty cycle is measured as 100% because there is no square wave at 0% and also at 100%. Therefore be careful how the duty cycle is measured. In my case I have to see if the voltage is 0 at 100% duty cycle.

Duty Cycle 25%

Duty Cycle 50%

Duty Cycle 75%

Duty Cycle 100%

The following table gives you an overview of all components and parts that I used for this tutorial. I get commissions for purchases made through links in this table.

ComponentAmazon LinkAliExpress Link
Arduino Nano AmazonAliExpress
Arduino Pro Mini AmazonAliExpress
Arduino Uno AmazonAliExpress
Arduino Mega AmazonAliExpress
ESP32 ESP-WROOM-32AmazonAliExpress
ESP8266 NodeMCU AmazonAliExpress
ESP8266 WeMos D1 Mini AmazonAliExpress
Resistor and LED in Package AmazonAliExpress
DC Motor -AliExpress
L298N Motor Driver Module -AliExpress
DC Motor with L298N Motor Driver Module Amazon-

How to Change the Brightness of an LED by PWM

In the following example we want to change the brightness of an LED by changing the duty cycle of the regarding PWM signal.

The following fritzing sketches show the circuit done with different Arduino, ESP8266 and ESP32 microcontroller boards. We have to make sure that the LED is connected to a microcontroller pin that is PWM able.

I recommend to get the Microcontroller Datasheet eBook where you can find the pinouts of the different microcontroller boards, that include the information which pins are able to use PWM. You get the eBook for free if you join the DIYI0T newsletter.

Wiring between LED and Arduino Microcontroller for PWM

The following pictures show the wiring between different Arduino boards, the LED that brightness we want to control and a 220Ω resistor to prevent the LED from too high voltages.

For this example I use the digital pin 11 that is able to create PWM signals but you can use any other PWM able pin as well.

Wiring between LED and ESP8266 Microcontroller for PWM

The following pictures show the connection between different ESP8266 boards like the ESP8266 NodeMCU or the ESP8266 WeMos D1 Mini and the LED as well as the 220Ω resistor.

We need a resistor in series to the LED to prevent the LED for too high voltages.

You can choose any digital I/O pin of the ESP8266 for this example, because all digital I/O pins of the ESP8266 are able to create PWM signals, but make sure that you also change the pin in the program script. I select pin D4 for this example.

Wiring between LED and ESP32 Microcontroller for PWM

The following picture shows the wiring between the ESP32 ESP-WROOM-32 microcontroller board, the LED and the 220Ω resistance to prevent the LED for too high voltages.

Because any digital I/O pin of the ESP32 is able to create PWM signals, you can choose any other digital pin but make sure to change the program script. In my case, I connect pin 4 of the ESP32 to the LED.

Program Code to Change the Brightness of an LED by PWM

The program code is pretty straight forward. We have to define the pins and some variables for the time and the height to increment the brightness of the LED. If you want to know how to change the color for multicolor LEDs, using different PWM signals, you find this in my LED tutorial.

int LEDpin = 11;   // for Arduino microcontroller
//int LEDpin = D4;   // for ESP8266 microcontroller
//int LEDpin = 4;   // for ESP32 microcontroller

int bright = 0;    // initial value of LED brightness
int incremt = 5;   // incremental change in PWM frequency
int time = 100;    // time period the PWM frequency is changing

void setup()
  {
    pinMode(LEDpin, OUTPUT);  // define the LEDpin as output pin
  }

void loop()
  {
    analogWrite(LEDpin, bright);  // set LED brightness as PWM signal
    delay(time);                  // wait for a time period
    bright = bright + incremt;    // increment LED brightness
    // if the brightness is out of range, reduce brightness
    if (bright <=0 || bright >=255) incremt = - incremt;
  }

In the first part of the Arduino code, we define the pin that connects the LED to the microcontroller. Because this script is for Arduino, ESP32 and ESP8266 microcontrollers, you have to comment out two of the first three lines that defines the pin.

Also we have to define three additional variables:

  • bright: initial value of the LED brightness and therefore 0 to shut down the LED.
  • increment: the incremental change in the PWM frequency. Each increment the LED increases and decreases the brightness.
  • time: the time period in milliseconds for each PWM cycle.

In the setup function, we fine the pin, that we defines as LED pin at the beginning of the script, as output pin to use the pin with PWM.

We start the loop function, with the analogWrite(pin, value) function we set the analog value (PWM wave) for the brightness to the LED pin. After the delay of 0.1 seconds, the brightness in incremented. If the brightness reaches the minimum (0) or maximum (255) value, the increment is changed from a positive value to a negative value.

The following video shows the change of the brightness of the LED due to the PWM function.

YouTube

By loading the video, you agree to YouTube's privacy policy.
Learn more

Load video

How to Control the Speed of a DC Motor by PWM

The second example shows how we can change the speed of an DC motor with the help of a PWM signal. We use the L298N motor driver module to connect the Arduino, ESP8266 or ESP32 to the DC motor. It is also recommend to power the DC motor with an external power supply. Therefore I use 4 AA batteries, each with 1.5V so in total 6V.

I want to focus on the PWM signal in this example. Therefore I do not further describe the DC motor example. But if you are interested in DC motors, I will write an extra article about DC motors, that explains everything in detail.

Microcontroller Datasheet eBook

The 35 pages Microcontroller Datasheet Playbook contains the most useful information of 14 Arduino, ESP8266 and ESP32 microcontroller boards.

Wiring between DC Motor and Arduino Microcontroller for PWM

The following pictures show the connections for the speed control of a DC motor via PWM signal from the Arduino microcontroller. The DC motor is connected to the L298N motor driver.

We use 4 AA batteries or a laboratory power supply for the power supply of the L298N motor driver. The Arduino microcontroller is powered via USB or also via the laboratory power supply

To control the speed and rotation direction of the DC motor, we connect the pins ENA, INT1 and INT2 to the digital pins of the Arduino board.

Wiring between DC Motor and ESP8266 Microcontroller for PWM

The wiring between the ESP8266 board, the power supply, the L298N motor driver and the DC motor is shown in the following picture.

Four AA batteries of a laboratory power supply can be used as power supply for the motor driver. The ESP8266 board is powered from the USB connection and ground is connection to each other.

The speed and rotation direction of the DC motor, are controlled via the pins ENA, INT1 and INT2 pins of the L298N motor driver and connected to the digital pins of the ESP8266 board. The DC motor itself is connected directly to the motor driver.

Wiring between DC Motor and ESP32 Microcontroller for PWM

The following picture shows how to connect a DC motor to the ESP32 ESP-WROOM-32. For the power supply of 6V, you can use 4 AA batteries or a laboratory power supply. The ESP32 board is powered from the USB connection or also from the laboratory power supply.

To control the DC motor, we can not connect the DC motor directly to the ESP32, but we need the L298N motor driver. Pins ENA, INT1 and INT2 to control the speed and rotation direction of the DC motor are connected to three digital pins of the ESP32. The DC motor is then connected to the L298N motor driver.

Program Code to Control the Speed of a DC Motor by PWM

For the program code we want to increase the motor speed each second. At the start, the voltage provided through the PWM signal is to low to start the motor. This is why it takes some intervals in the for loop until the motor is turning.

// Arduino connection to L298N
int enA = 10; // PWM for Motor A
int in1 = 9;  // Control Rotation of Motor A
int in2 = 8;  // Control Rotation of Motor A

// ESP8266 connection to L298N
//int enA = D4; // PWM for Motor A
//int in1 = D5;  // Control Rotation of Motor A
//int in2 = D6;  // Control Rotation of Motor A

// ESP32 connection to L298N
//int enA = 4; // PWM for Motor A
//int in1 = 0;  // Control Rotation of Motor A
//int in2 = 2;  // Control Rotation of Motor A

int motor_speed = 0; 

void setup()
{
  // set all the motor control pins to outputs
  pinMode(enA, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
}

void loop()
{
  // run the motor between 0 and 250 in increments of 10
  digitalWrite(in1, LOW); // Input1 LOW = move forward
  digitalWrite(in2, HIGH);  // Input2 HIGH = move forward
  for(motor_speed = 0; motor_speed < 250; motor_speed += 10)
  {
    analogWrite(enA, motor_speed); // PWM output
    delay(1000);
  }
}

In the first part of the script we define the pins that connect the microcontroller to the L298N module, that is connected to the DC motor. In total we have to define 3 pins:

  • enA: transfers the PWM signal to the L298N module and must be a pin that is able to produce a PWM signal.
  • int1 and int2: control the rotation direction of the motor. The following table shows how to control int1 and int2 to stop the motor, move forward and move backwards.
int1
LOWHIGH
int2LOWMotor stopsMotor moves backwards
HIGHMotor moves forwardMotor stops

Because this script is for Arduino, EPS8266 and ESP32 microcontroller boards, you have to select only the lines for your microcontrolle and comment the other lines. The current script is commented in a way, that is for Arduino boards.

To increase the motor speed, the speed has to be saved to a variable that we call motor_speed and has an initial value of 0.

In the setup function we define all digital pins, that connects the board to the L298N as outputs.

We start the loop function by setting int1 LOW and int2 HIGH. Therefore the DC motor rotates in the forward direction. In the for loop we increase the motor speed each second by 10 between 0 and 250. The motor speed in written as analog output (PWM signal) to the enA connection.

The following video shows the Arduino script in action for the Arduino Uno as example.

YouTube

By loading the video, you agree to YouTube's privacy policy.
Learn more

Load video

Conclusion

I hope you enjoined this article about the PWM signal. The PWM signal is a very handy tool which is used a lot in practical examples. It is recommended to know how PWM is working. Therefore if you have any further questions, use the comment section below to ask.

2 thoughts on “PWM Tutorial for Arduino, ESP8266 and ESP32”

  1. I will right awɑy clսtch your rѕs feed as I can’t to find your e-mail subscription link or e-newsletter service.

    Do you have any? Please let me know іn ordеr that I could ѕubscribe.
    Thanks.

    Reply

Leave a Comment