The objective of this ESP32 Arduino Tutorial is to explain how to control a buzzer with the ESP32, using its PWM functionalities. In particular, we are going to use ESP32’s LED PWM functions.
Introduction
The objective of this ESP32 Arduino Tutorial is to explain how to control a buzzer with the ESP32, using its PWM functionalities. In particular, we are going to use ESP32’s LED PWM functions, covered in detail in this previous post.
Basically, using the LED PWM of the ESP32, we will be able to control both the duty cycle and the frequency of our output signal. Note however that we don’t need to use PWM to control a buzzer, since we just only need to vary its frequency and we can maintain a constant duty cycle.
Nevertheless, since the tone function is not yet implement on the Arduino libraries for the ESP32, using the PWM frequency control functionalities is a possible work around.
Although, as said before, we don’t need to change the duty cycle to control a buzzer and the best duty cycle is of 5 % [1][2], we will vary it just to check what it happens. The expected effect is that a change on the duty cycle will affect the volume of the buzzer [1].
We are going to also vary the frequency, which will affect the type of sound produced.
Electronic schematic
For this tutorial I’m going to use a cheap buzzer module that already has all the hardware needed to directly control it from a microcontroller GPIO (more precisely, a transistor driver). This way, we are not drawing the current from the ESP32 GPIO pin.
Check the schematic bellow in figure 1.
Figure 1 – Connection diagram between the ESP32 and a buzzer.
The code
We will start by declaring some global variables needed to control the PWM functionality of the ESP32. We will set the initial frequency (although we are going to change it later in the code), the channel of the PWM and the resolution of the duty cycle specification.
We will use channel 0 and a resolution of 8 bits for the duty cycle. For the frequency we are going to put 2000 Hz just to do the initial setup.
int freq = 2000;
int channel = 0;
int resolution = 8;
Now, in the setup function, we are going to setup the PWM with the ledcSetup function, which receives as input the PWM channel, the frequency and the duty cycle resolution.
Next, we will attach the PWM channel to an actual GPIO of the ESP32, by calling the ledcAttachPin function. This receives as input the GPIO and the channel. I’m going to use GPIO 12 of the ESP32. Please take in consideration that some ESP32 pins don’t directly map to the pins of the ESP32 boards.
We will also open start a serial communication, so we can check output some information about the execution. Check the full setup function bellow.
void setup() {
Serial.begin(115200);
ledcSetup(channel, freq, resolution);
ledcAttachPin(12, channel);
}
Now we are going to move to the main loop function, where we will experiment with our buzzer by changing the frequency and duty cycle configurations.
The first value we will vary is the duty cycle. So at the beginning of the loop we will fix the frequency. Although we configured it in the setup function, we want it to reset to the original value at the beginning of each iteration of the main loop.
So, to set the frequency again, we call the ledcWriteTone function, passing as inputs the PWM channel and the frequency to set. We will set it to 2000 Hz, as the initial configuration.
ledcWriteTone(channel, 2000);
Next we will do a for loop starting with a PWM of zero and increasing it by 10 at each iteration. We can vary the duty cycle between 0 and 255, since we specified a resolution of 8 bits.
We will introduce a small delay of 1 second in each iteration, so we can listen to the effects of changing it. We will also print the current duty cycle value.
To set the duty cycle, we just need to call the ledcWrite function, passing as input both the channel and the duty cycle value to set. Check the full loop bellow.
for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle=dutyCycle+10){
Serial.println(dutyCycle);
ledcWrite(channel, dutyCycle);
delay(1000);
}
Next we are going to vary the frequency. Thus, we will start by fixing the duty cycle on 125 (approximately 50%). Next, we will do a for cycle similar to the previous one but this time starting with a frequency of 0 Hz and increase it by 250 until 10000 Hz. We will also print the current value again to the serial port.
You can check bellow the full source code, which already includes this previously mentioned loop where the frequency is incremented by calling the ledcWriteTone function.
int freq = 2000;
int channel = 0;
int resolution = 8;
void setup() {
Serial.begin(115200);
ledcSetup(channel, freq, resolution);
ledcAttachPin(12, channel);
}
void loop() {
ledcWriteTone(channel, 2000);
for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle=dutyCycle+10){
Serial.println(dutyCycle);
ledcWrite(channel, dutyCycle);
delay(1000);
}
ledcWrite(channel, 125);
for (int freq = 255; freq < 10000; freq = freq + 250){
Serial.println(freq);
ledcWriteTone(channel, freq);
delay(1000);
}
}
Testing the code
To test the code, just upload it to the ESP32 using the Arduino IDE. Then open the serial port to check the values of frequency an duty cycle changing.
With the ESP32 connected to the buzzer, you should first ear a changing in the volume produced by the buzzer, caused by changing the duty cycle. Then, when changing the frequency, you will notice that the sound produced will also change.
You can check in the video bellow the result of running this code on a ESP32 board.