Your First Sketch

Write and upload your first ESP32 program to blink an LED using Arduino IDE

The "blink" sketch is the "Hello World" of microcontroller programming. You will make an LED turn on and off repeatedly, and along the way, learn the fundamental structure of every Arduino-style program.

🔗How an Arduino sketch works

Every Arduino sketch has two required functions:

void setup() {
  // Runs once when the board powers on or resets
}

void loop() {
  // Runs over and over, forever
}
  • setup() is where you configure things: set pin modes, start serial communication, initialize sensors. It runs once.
  • loop() is where your main program logic goes. It runs continuously after setup() finishes -- thousands of times per second if your code is short.

This two-function structure is the same for every Arduino-compatible board, including the ESP32.

Most ESP32 development boards have a small LED soldered onto the board that is connected to a GPIO pin. On the majority of ESP32-WROOM-32 DevKit boards, this is GPIO 2.

Important: The built-in LED pin varies between boards. GPIO 2 is the most common, but some boards use GPIO 5, GPIO 22, or have no built-in LED at all. Check your specific board's documentation if GPIO 2 does not work. You can always connect an external LED to any available GPIO pin instead.

Create a new sketch in the Arduino IDE and enter this code:

#define LED_PIN 2  // Built-in LED on most ESP32 DevKit boards

void setup() {
  pinMode(LED_PIN, OUTPUT);  // Set the LED pin as an output
}

void loop() {
  digitalWrite(LED_PIN, HIGH);  // Turn LED on
  delay(1000);                  // Wait 1 second (1000 milliseconds)
  digitalWrite(LED_PIN, LOW);   // Turn LED off
  delay(1000);                  // Wait 1 second
}

Upload this sketch (click the Upload button or press Ctrl+U). After the upload completes, the LED on your board should blink on and off once per second.

🔗Understanding the code

Let's break down each line:

#define LED_PIN 2 -- This creates a constant called LED_PIN with the value 2. Using a named constant instead of writing 2 everywhere makes the code easier to read and change. If your board uses a different pin, you only need to change this one line.

pinMode(LED_PIN, OUTPUT) -- Tells the ESP32 that GPIO 2 should be an output pin. This means we will send signals out of this pin to control the LED.

digitalWrite(LED_PIN, HIGH) -- Sets the pin to HIGH (3.3 V). Current flows through the LED, and it lights up.

digitalWrite(LED_PIN, LOW) -- Sets the pin to LOW (0 V). No current flows, and the LED turns off.

delay(1000) -- Pauses the program for 1000 milliseconds (1 second). During this time, the ESP32 does nothing.

Now try modifying the sketch. Change the delay values and re-upload:

void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(100);                   // On for 0.1 seconds
  digitalWrite(LED_PIN, LOW);
  delay(100);                   // Off for 0.1 seconds
}

The LED blinks much faster. Try different values:

On delayOff delayEffect
1000 ms1000 msSlow, steady blink
100 ms100 msFast blink
50 ms950 msQuick flash, long pause
500 ms100 msLong on, short off

This kind of experimentation is one of the best ways to learn. Change values, upload, and observe what happens.

🔗Add serial output: "Hello World"

Blinking an LED is great for visual feedback, but you often need to see text output from your program -- sensor readings, status messages, or debug information. The Serial Monitor is how you do that.

Modify your sketch to include serial communication:

#define LED_PIN 2

void setup() {
  pinMode(LED_PIN, OUTPUT);

  Serial.begin(115200);     // Start serial communication at 115200 baud
  delay(1000);              // Give the serial connection a moment to initialize
  Serial.println("ESP32 Blink Sketch Started");
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  Serial.println("LED is ON");
  delay(1000);

  digitalWrite(LED_PIN, LOW);
  Serial.println("LED is OFF");
  delay(1000);
}

🔗Understanding the serial code

Serial.begin(115200) -- Initializes serial communication at 115200 bits per second (baud). This speed must match the setting in the Serial Monitor. 115200 is the standard baud rate for ESP32.

Serial.println("text") -- Sends a line of text over the serial connection. println adds a newline at the end; print does not.

delay(1000) after Serial.begin() -- The ESP32's USB-serial connection can take a moment to stabilize after reset. Without this delay, the first few messages might be lost.

🔗Using the Serial Monitor

  1. Upload the sketch
  2. Open the Serial Monitor (magnifying glass icon in the top-right of the Arduino IDE)
  3. Make sure the baud rate dropdown (bottom-right of the monitor) is set to 115200
  4. You should see:
ESP32 Blink Sketch Started
LED is ON
LED is OFF
LED is ON
LED is OFF

If you see garbled characters, check that the baud rate matches. If you see nothing at all, press the EN (reset) button on the ESP32 to restart the sketch from the beginning.

🔗Printing variables

Serial.println() can also print numbers and variables, which is essential for debugging:

int counter = 0;

void setup() {
  Serial.begin(115200);
  delay(1000);
}

void loop() {
  counter++;
  Serial.print("Loop count: ");
  Serial.println(counter);
  delay(1000);
}

Output:

Loop count: 1
Loop count: 2
Loop count: 3
...

Notice the difference between Serial.print() (no newline) and Serial.println() (adds a newline). Using print for the label and println for the value puts them on the same line.

If your board does not have a built-in LED, or you want to control a separate one, you can connect an external LED to any available GPIO pin.

🔗What you need

ComponentQuantity
LED (any color)1
220 $\Omega$ resistor1
Jumper wires2
Breadboard1

🔗Wiring

ESP32 pinConnects to
GPIO 13220 $\Omega$ resistor, then to LED anode (long leg)
GNDLED cathode (short leg)

The circuit is: GPIO 13 --> 220 $\Omega$ resistor --> LED anode (+) --> LED cathode (-) --> GND

Why a resistor? Without a current-limiting resistor, the LED would draw too much current from the GPIO pin. This could damage the LED, the ESP32, or both. A 220 $\Omega$ resistor limits the current to about $\frac{3.3 - 2.0}{220} \approx 6 \, \text{mA}$, which is safe and bright enough.

🔗Code for the external LED

#define LED_PIN 13  // External LED on GPIO 13

void setup() {
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(115200);
  delay(1000);
  Serial.println("External LED blink started");
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  Serial.println("LED ON");
  delay(500);

  digitalWrite(LED_PIN, LOW);
  Serial.println("LED OFF");
  delay(500);
}

Change LED_PIN to whichever GPIO pin you connected your LED to.

🔗Common issues

ProblemLikely causeSolution
LED does not blinkWrong pin numberCheck your board's pinout; try GPIO 2 or your board's documented LED pin
LED stays on or offLED in backwardsFlip the LED (long leg to resistor side)
Serial shows garbled textBaud rate mismatchSet Serial Monitor to 115200
Nothing in Serial MonitorSerial not initializedCheck Serial.begin(115200) is in setup()
Upload failsBoard in wrong stateHold BOOT button during upload

🔗What you learned

In this article you:

  • Learned the setup() / loop() structure that every Arduino sketch uses
  • Used pinMode(), digitalWrite(), and delay() to blink an LED
  • Used Serial.begin(), Serial.print(), and Serial.println() to send debug text
  • Wired an external LED with a current-limiting resistor

These are building blocks you will use in every project from here on.

🔗Next steps

Now that you can control a digital output (on/off), the next article explains the difference between digital and analog signals -- and how to read sensors and create smooth outputs like dimming an LED.