ESP8266 NodeMCU PWM with Arduino IDE – Dim LED (Analog Output)

This tutorial shows how to generate PWM signals with ESP8266 NodeMCU using Arduino IDE. As an example, we’ll dim the LED brightness by changing the duty cycle over time.

ESP8266 Pulse-Width Modulation (PWM) pins with Arduino IDE

To generate a PWM signal on the ESP8266 pins with Arduino IDE, use analogWrite(pin, value). The value is an integer between 0 and 255.

For ESP8266 releases before 3.0, the default range is between 0 and 1023. The PWM range may be changed by calling analogWriteRange(new_range).

You might also like reading other guides about PWM:

Before proceeding with this tutorial you should have the ESP8266 add-on installed in your Arduino IDE. Follow the next tutorial to Install ESP8266 in Arduino IDE.

ESP8266 NodeMCU PWM (Pulse-Width Modulation)

The ESP8266 GPIOs can be set either to output 0V or 3.3V, but they can’t output any voltages in between. However, you can output “fake” mid-level voltages using pulse‑width modulation (PWM), which is how you’ll produce varying levels of LED brightness for this project.

If you alternate an LED’s voltage between HIGH and LOW very fast, your eyes can’t keep up with the speed at which the LED switches on and off; you’ll simply see some gradations in brightness.

ESP8266 Fade LED with Pulse-Width Modulation (PWM) using analogWrite function

That’s basically how PWM works — by producing an output that changes between HIGH and LOW at a very high frequency.

The duty cycle is the fraction of the time period at which LED is set to HIGH. The following figure illustrates how PWM works.

How Pulse-Width Modulation (PWM) works on ESP8266 to Fade an LED

A duty cycle of 50 percent results in 50 percent LED brightness, a duty cycle of 0 means the LED is fully off, and a duty cycle of 100 means the LED is fully on. Changing the duty cycle is how you produce different levels of brightness.

analogWrite()

To produce a PWM signal on a given pin you use the following function:

analogWrite(pin, value);
  • pin: PWM may be used on pins 0 to 16
  • value: should be in range from 0 to PWMRANGE, which is 255 by default. When value is 0, PWM is disable on that pin. A value of 255 corresponds to 100% duty cycle

You can change the PWM range by calling:

analogWriteRange(new_range);

By default, ESP8266 PWM frequency is 1kHz. You can change PWM frequency with:

analogWriteFreq(new_frequency);

Valid values are from 100Hz to 40000Hz.

ESP8266 NodeMCU Dim LED with PWM

In this section, we’ll build a simple example that dims an LED so that you see how to use PWM in your projects. You’ll need the following parts:

If you’re using an ESP-01, you need an FTDI programmer or a Serial Adapter to upload code.

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Schematic

After uploading the code, wire an LED to your ESP8266 as shown in the following schematic diagram. We’re connecting the LED to GPIO 2, but you can use any other suitable GPIOs.

ESP8266 LED Connected to GPIO 2 Wiring Schematic Diagram

If you’re using an ESP-01, you can check the board pinout here.

ESP8266 NodeMCU PWM Code

Copy the code to your Arduino IDE and upload it to your ESP8266.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

const int ledPin = 2; 

void setup() {
  
}

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

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

View raw code

How the code works

Continue reading this section to learn how the code works, or skip to the next section.

Start by defining the pin LED is attached to. In this case, LED is attached to GPIO 2 (D4).

const int ledPin = 2;

In the loop(), you vary the duty cycle between 0 and 255 to increase the LED brightness.

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

And then, between 255 and 0 to decrease brightness.

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

To set the LED brightness, you need to use analogWrite() function that accepts as arguments GPIO where you want to get the PWM signal and a value between 0 and 255 to set the duty cycle.

Upload the Code

In your Arduino IDE, go to Tools > Board and select your ESP8266 model (If you’re using an ESP-01, select “Generic ESP8266 Module”) .

Go to Tools > Port and select the COM port the ESP8266 is connected to.

If you’re using an ESP-01, you need an FTDI programmer or Serial Adapter to upload code. Here are the connections you need to make:

ESP8266 ESP-01 connected to FTDI programmer to upload new Arduino Sketch
ESP-01FTDI Programmer
RXTX
TXRX
CH_PD3.3V
GPIO 0GND
VCC3.3V
GNDGND

Demonstration

After uploading your sketch, the LED connected to GPIO 2 should increase and decrease its brightness over time.

ESP8266 Fading LED PWM Circuit Wiring Schematic diagram

You can connect GPIO 2 to an oscilloscope to see how the PWM signal changes over time.

ESP8266 Fading LED PWM Circuit Wiring Schematic diagram oscilloscope demonstration

Read our buying guide: Best Oscilloscopes for Beginners and Electronics Hobbyists.

Wrapping Up

We hope you’ve found this guide about the ESP8266 PWM usage helpful. Besides controlling the LED brightness, PWM can also be used to control the DC motor’s speed.

You may also like trying our other projects:

If you like ESP8266 make sure you take a look at our resources:

Thanks for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Recommended Resources

Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino, and Node-RED.

Home Automation using ESP8266 eBook and video course » Build IoT and home automation projects.

Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no prior experience!

What to Read Next…


Enjoyed this project? Stay updated by subscribing our newsletter!

18 thoughts on “ESP8266 NodeMCU PWM with Arduino IDE – Dim LED (Analog Output)”

  1. Thanks for putting this article together. I recently started using ESP8266 and was trying to use it to drive a 12V DC motor. I was not able to get the full speed using PCM and was starting to think that it might have something to with a 3.3V logic on PWM pins. Turns out that I was incorrectly assuming it to have an 8 bit resolution just like Arduino Uno. Your article helped clarify that the resolution of PWM on ESP8266 is 10 bit. The motor now runs as expected.

    Reply
  2. I found another site that is using your tutorial. I was not sure if you were aware.
    You may want to look closer at the site.

    Reply
    • Thanks for letting us know.
      Yes, we are aware, and unfortunately, there’s nothing we can do.
      I think “he” stopped doing that, at least for a while.
      Regards,
      Sara

      Reply
      • do you mean a lameh youtuber who puts his face on “his proyects” ‘s pcbs ??? i hate ppl who stole the credit from the real creators…

        Reply
  3. Hi team,
    using the scetch with an ESP8266 as supposed I’m in doubt if there is an
    “analogWriteRange(new_range)” missing.
    Thank-you for all the tutorials

    Reply
  4. Hi Sara,
    congratulations for the great work you are doing: you are inspiring many developers with your articles for sure: I am among them.
    I would like to ask if you have already explored the reading of an external PWM signal, this could be very useful on many robotic application: I haven’t found anything around and there is no implementation for that in the pwm.h API (Except pwm_get_duty that doesen’t work I belive to read an external PWM signal).
    Beside that are you visiting the European Maker Faire in Roma next 8-10 october?
    Thanks again
    All the best.
    L.

    Reply
  5. Hallo Sara,

    I was wondering if you also have a guide on how to read duty cycles from for example a smt172. Would like to read that since your guides are way so clear and this site is my go to site for esp32/8266. Kind regards

    Reply
    • Hi.
      Thanks for following our work.
      Unfortunately, we don’t have any tutorials about that specific subject.
      Regard,s
      Sara

      Reply
  6. Hello Sara,
    I have been trying to get a 90 degree phase shift on two PWM channels for quite some time… unfortunately without success until now.
    The goal is to simulate a two channel incremental encoder. The duty cycle should always be 50%.
    Do you have any ideas?
    Thanks in advance

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.