This scenario presents how to handle the brightness control of the tri-coloured LEDs. One is observable via camera, as presented in the figure (component 9A), while another is hidden inside the black enclosure and lights a colour sensor (component 9B). Both LEDs are electrically bound and cannot be controlled independently. Those LEDs have 3 colour channels, controlled independently: R (Red), G (Green) and B (Blue). Mixing of those colours creates other ones, such as pink and violet. Each R G B channel can be controlled with a separate GPIO to switch it on or off or control brightness using a PWM signal, as presented in this tutorial.
A good understanding of the PWM signal and duty cycle is necessary. We also use built-in timers to control the PWM hardware channels of the ESP32 chip. In this case, we do not use an external library; instead, we use built-in tools in the Arduino framework for ESP32 so that no additional libraries will be included in the project.
Implement a program that will light LEDs consecutively with R, G, and B. Use 50% of the maximum brightness. Use a PWM signal to control each GPIO for R, G and B, each colour separately to let you easily observe it.
Assuming you will use 8-bit PWM resolution, the minimum value is 0, and the max (full brightness) is 255. Note that full brightness may be too bright for the observation camera, so consider using a range between 0 and 60 (eventually up to 100).
To use PWM in ESP32, it is best to use built-in ledc*
functions LEDC documentation on the ESP32 manufacturer's page.
The leds
use timers and have channels attached to the timer. We will use 1 channel per colour (R, G and B, so 3 in total). A PWM frequency is controlled with the timer to be shared for all 3 R, G and B channels. Channels control the PWM duty cycle.
Define some parameters, including channel numbers, PWM resolution (here 8-bit) and PWM frequency (5000Hz):
#define RGBLED_B_PIN 26 #define RGBLED_G_PIN 21 #define RGBLED_R_PIN 33 #define PWM1_Ch 5 #define PWM2_Ch 6 #define PWM3_Ch 7 #define PWM_Res 8 #define PWM_Freq 5000
GPIO pins controlling LEDS are 33 (Red), 21 (Green) and 26 (Blue), respectively.
Initialise 3 channels for PWM and make them dark:
ledcSetup(PWM1_Ch, PWM_Freq, PWM_Res); ledcSetup(PWM2_Ch, PWM_Freq, PWM_Res); ledcSetup(PWM3_Ch, PWM_Freq, PWM_Res); ledcAttachPin(RGBLED_R_PIN, PWM1_Ch); ledcAttachPin(RGBLED_G_PIN, PWM2_Ch); ledcAttachPin(RGBLED_B_PIN, PWM3_Ch); delay(100); ledcWrite(PWM1_Ch,0); ledcWrite(PWM2_Ch,0); ledcWrite(PWM3_Ch,0);
To control the LED (via PWM), use ledcWrite(PWM_Channel, duty_cycle_value);
.
Write a loop for each colour (R, G, then B) to light the colour from dark to max value (60 or 100, give it a test).
Mind to compose code to increase and decrease each colour. A hint is below (PWM Channel 3 so that controls Blue):
// Increase brightness for (int dutyCycle = 0; dutyCycle <= 100; dutyCycle++) { // Gradually increase duty cycle for Red LED ledcWrite(PWM3_Ch, dutyCycle); delay(20); // Delay for smooth transition } delay(100); // Decrease brightness for (int dutyCycle = 100; dutyCycle >= 0; dutyCycle--) { // Gradually decrease duty cycle for Red LED ledcWrite(PWM3_Ch, dutyCycle); delay(20); // Delay for smooth transition }
ledc
library, including (among others):analogWrite(pin,value);
to keep compatibility with genuine Arduino,ledcFade(pin, start_dutycycle, end_dutycycle, fade_time_ms);
that you can use instead of the loop above,ledcDetach(pin);
to detach a pin from the channel (and thus release the PWM channel),ledcWriteNote(pin, note, octave);
where note
is one of the values: NOTE_C, NOTE_Cs, … (and so on, music notes, up to NOTE_B) - it is useful when PWM controls a speaker, to generate a perfect musical note, but we do not use speakers here, sorry.You should be able to observe the pulsing colours of the RGB LED, increasing and decreasing brightness linearly.
What if I bind a PWM channel to more than one GPIO?: As you control the duty cycle writing to the channel rather than the GPIO, you will control those GPIOs simultaneously (in parallel) with the same signal. That can be handy to control parallelly separate devices that should behave the same way, i.e. servos.
What is the maximum number of channels?: the MCU we use here is ESP32-S3, so it has 8 PWM channels. You can use timers and software implementation of the PWM signal if you need more, but that is a bit tricky and may not be as precise as hardware PWM implementation.
What is the maximum bit resolution for PWM?: it is between 1 and 14 bits in this particular MCU.
What PWM frequency should I use?: there is no straightforward answer to this question: assuming you observe LED remotely with a camera, even 50Hz would be enough. But it would give a severe flickering experience to the live user, on the other hand. In the example above, we propose 5kHz, which this MCU can easily handle.