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.

PWM signals on ESP8266 have 10-bit resolution. To generate a PWM signal on the ESP8266 pins with Arduino IDE, use analogWrite(pin, value). The value is an integer between 0 and 1023.
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.

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 time period at which LED is set to HIGH. The following figure illustrates how PWM works.

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 1023 by default. When value is 0, PWM is disable on that pin. A value of 1023 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);
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:
- ESP8266 (read Best ESP8266 development boards)
- 5mm LED
- 330 Ohm resistor
- Breadboard
- Jumper wires
- Optional Oscilloscope (read Best Oscilloscopes for Beginners)
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.

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 < 1023; dutyCycle++){
// changing the LED brightness with PWM
analogWrite(ledPin, dutyCycle);
delay(1);
}
// decrease the LED brightness
for(int dutyCycle = 1023; dutyCycle > 0; dutyCycle--){
// changing the LED brightness with PWM
analogWrite(ledPin, dutyCycle);
delay(1);
}
}
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 1023 to increase the LED brightness.
for(int dutyCycle = 0; dutyCycle < 1023; dutyCycle++){
// changing the LED brightness with PWM
analogWrite(ledPin, dutyCycle);
delay(1);
}
And then, between 1023 and 0 to decrease brightness.
for(int dutyCycle = 1023; 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 1023 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 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’s the connections you need to make:

ESP-01 | FTDI Programmer |
RX | TX |
TX | RX |
CH_PD | 3.3V |
GPIO 0 | GND |
VCC | 3.3V |
GND | GND |
Demonstration
After uploading your sketch, the LED connected to GPIO 2 should increase and decrease its brightness over time.

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

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 interesting. Besides controlling the LED brightness, PWM can also be used to control the DC motors speed.
You may also like trying our other projects:
- ESP8266 DHT Temperature and Humidity Readings in OLED Display
- ESP8266 DHT Temperature and Humidity Web Server
- Hack a PIR Motion Sensor with an ESP8266
- Build an ESP8266 Web Server
If you like ESP8266 make sure you take a look at our resources:
- Home Automation using ESP8266 (eBook + Video Course)
- Free ESP8266 Tutorials and Projects
- MicroPython Programming with ESP32 and ESP8266
Thanks for reading.
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.
Great!
I’m glad you found our guide useful.
Thanks for following our work.
Regards,
Sara
Thank you for putting the PWM range being up to 1023 in a big green box at the top. Saved me a lot of debugging.