L4: Variable-brightness LED

Controlling the brightness of an LED using a PWM output.

Variable-brightness LED

What you will learn in this lesson

In this lesson, we will cover:

  • Controlling the brightness of an external LED from the development board.
  • PWM outputs: what they are and what they are used for.

Prerequisites

To follow this lesson, you should have already completed Lesson 1: My first project, Lesson 2: The LED diode and Lesson 3: The LED diode (2). In this lesson, we will use the same type of circuit as in the previous lesson, but we will learn to control the LED using more values than just on and off.

Theoretical explanation

I want to know more!

On, off… and the levels in between

In previous lessons, we used the LED in a very simple way:

  • Value 100: the LED turns on.
  • Value 0: the LED turns off.

But in many projects, we want to do more than just switch a light on or off. Sometimes we want it to glow dimly, shine brightly or change gradually. For example:

  • An ambient light.
  • An indicator that gets brighter.
  • A light alarm that turns on gently.
  • A “breathing” effect, where the light gets brighter and dimmer.

To do this, we need to control the LED’s brightness.

Can a digital pin produce intermediate values?

A digital pin on the board has two main states:

  • ON: connected to the positive voltage.
  • OFF: connected to GND.

This seems like a problem: if we only have ON and OFF, how can we make an LED appear to be on at 25%, 50% or 75%?

The solution is to turn the LED on and off very quickly. So quickly that our eyes do not see individual flashes, but a light that looks brighter or dimmer.

PWM outputs

PWM stands for Pulse Width Modulation.

Although the name sounds complicated, the basic idea is simple:

  • If the LED is on almost all the time, it will look very bright.
  • If the LED is on for only a small part of the time, it will look dim.
  • If the LED is on for half the time and off for the other half, it will appear to have an intermediate brightness.

For example, over a very short period of time:

Value sent to the LEDTime onApproximate result
00%Off
2525%Dim
5050%Medium brightness
100100%Maximum brightness

The percentage of time that the signal stays on is called the duty cycle.

Why can’t we see the flashing?

Our eyes cannot detect every change when things happen very quickly. Something similar happens in films and videos: we see continuous movement, even though many still images are actually being shown one after another.

PWM works in a similar way. The LED switches between ON and OFF many times per second. Because this happens so quickly, our eyes interpret the result as a brighter or dimmer light.

Practical part

You will need the following materials:

  • ESP32 development board.
  • BatSTEM expansion board.
  • USB connection cable.
  • Breadboard.
  • Red LED.
  • 100 Ohm resistor.
  • Jumper wires.

Electronic schematic and wiring diagram

In this lesson, we will reuse the circuit from Lesson 3: The LED diode (2). The external LED will be connected to a GPIO pin on the development board through a protective resistor.

We will use GPIO4, just as in the previous lesson.


Electronic schematic


Connecting the components on the breadboard

Step by step
  1. Place the ESP32 development board on the BatSTEM expansion board.
  2. Connect a black wire between the GND connector on the expansion board and the blue rail on the breadboard. This will be our 0-volt reference, or GND rail.
  3. Connect a wire from D4 (GPIO4) on the expansion board to an unused row in the centre of the breadboard.
  4. Place a 100 Ohm resistor so that one of its leads is in the same row as the wire connected to GPIO4.
  5. Connect the red LED: its anode should be in the same row as the resistor’s other lead, and its cathode should be in a different row.
  6. Connect a black wire between the LED’s cathode row and the blue GND rail.
  7. Connect the development board to the computer using the USB cable.

Code

In this lesson, we will create two sketches. In the first, we will try different brightness levels. In the second, we will make the LED gradually get brighter and dimmer.

I want to know more!

When we use the high-level LED block, the value does not have to be just 0 or 100. We can also use intermediate values. BatSTEM Cloud generates the PWM signal needed to make the LED look brighter or dimmer.

This lets us focus on the idea behind the program without manually configuring every detail of the PWM signal.

There is also a low-level option in the GPIO category: the “set pin … to analog … %” block. This block lets you send a percentage directly to a GPIO pin. In this lesson, we will start with the “LED with name” block because it is clearer and avoids having to remember the pin number at every step.

Trying different brightness levels

Build and run the following sketch:

  1. In the setup block, create a named LED connected to GPIO4. You can call it MyLED.
  2. In the main loop, set the LED to 0.
  3. Add a wait of 1 second.
  4. Set the LED to 25.
  5. Add a wait of 1 second.
  6. Set the LED to 50.
  7. Add a wait of 1 second.
  8. Set the LED to 75.
  9. Add a wait of 1 second.
  10. Set the LED to 100.
  11. Add a wait of 1 second.
Step by step
  1. Click Devices and drag an “LED with name” block into the setup block.
  2. Enter MyLED as the LED’s name.
  3. Select GPIO4, the pin to which we connected the external LED.
  4. Drag a “set LED” block into the main loop and select MyLED.
  5. Enter 0 in the “set LED” block.
  6. Click Time and add a wait block set to 1 second.
  7. Duplicate the pair of “set LED” and “wait” blocks until you have five levels.
  8. Change the LED values to 0, 25, 50, 75 and 100.
  9. Press Run and wait for the sketch to compile and transfer to the board.
  10. Watch the LED’s brightness change step by step.

Creating a gentle lighting effect

Now we will make the LED get brighter and dimmer. Build a new sketch with this sequence:

  1. Set the LED to 0.
  2. Wait 200 milliseconds.
  3. Set the LED to 20.
  4. Wait 200 milliseconds.
  5. Set the LED to 40.
  6. Wait 200 milliseconds.
  7. Set the LED to 60.
  8. Wait 200 milliseconds.
  9. Set the LED to 80.
  10. Wait 200 milliseconds.
  11. Set the LED to 100.
  12. Wait 200 milliseconds.
  13. Repeat the same sequence downwards: 80, 60, 40, 20, 0.
Step by step
  1. Keep the “LED with name” block in setup, connected to GPIO4.
  2. In the main loop, alternate “set LED” blocks and wait blocks.
  3. Start with increasing values: 0, 20, 40, 60, 80, 100.
  4. Then add decreasing values: 80, 60, 40, 20, 0.
  5. Add a wait of 200 milliseconds after each change in brightness.
  6. Run the sketch.

When the sequence ends, the main loop will start again from the beginning, so the effect will repeat continuously.

The same idea with GPIO blocks

I want to know more!

High-level blocks let us work with an LED using a name. But we can also control the pin directly using blocks from the GPIO category.

To try this, you can build an equivalent sketch using the “set pin … to analog … %” block:

  1. In the main loop, add a “set pin … to analog … %” block.
  2. Enter 4 as the pin number.
  3. Enter the value 0.
  4. Add a wait.
  5. Repeat the same idea with the values 25, 50, 75 and 100.

The result will be similar to the “set LED” block, but you will now be controlling the GPIO pin directly. This approach is more flexible, although it also requires more care with the pin number.

Additional exercises or challenges

  1. Change the waiting times to make the effect faster or slower.
  1. Change the intermediate values to give the LED more brightness steps.
  1. Create a light signal that does the following: gradually gets brighter, stays at maximum brightness for 2 seconds, then turns off abruptly.

  2. Connect a second LED to another GPIO pin and create an effect where one gets brighter while the other gets dimmer.

Summary of what we have learned

  • We have learned that an LED does not have to be just on or off.
  • We have used intermediate values to control an external LED’s brightness.
  • We have seen that PWM simulates different brightness levels by turning the LED on and off very quickly.
  • We have created a fade effect where the light gets brighter and dimmer.
  • We have reused the previous lesson’s circuit to learn a new way to control the LED.

Next steps

  • Learn to control several colours with an RGB LED in Lesson 5.

Solutions to additional exercises

Show

A smoother effect with steps of 10

To create a smoother change in brightness, we can use more intermediate values. For example:

  1. 0
  2. 10
  3. 20
  4. 30
  5. 40
  6. 50
  7. 60
  8. 70
  9. 80
  10. 90
  11. 100

Then we repeat the same sequence in reverse. The program will be longer, but the change from one level to the next will be less abrupt.

A light signal that turns on gradually

To solve the third challenge, we can use this idea:

  1. Increase the brightness using several intermediate values.
  2. When the LED reaches 100, add a wait of 2 seconds.
  3. Then set the LED directly to 0.
  4. Add another wait before repeating the sequence.

Two LEDs changing in opposite directions

To make one LED get brighter while the other gets dimmer, we need to create two named LEDs in the setup block. For example:

  • LED_A on GPIO4.
  • LED_B on another available GPIO pin.

Then, at each step of the main loop, we use opposite values:

LED_ALED_B
0100
2080
4060
6040
8020
1000