6. Chapter Buzzer

In this chapter, we will learn about buzzers and the sounds they make. And in our next project, we will use an active buzzer to make a doorbell and a passive buzzer to make an alarm.

6.1. Project Doorbell

We will make a doorbell with this functionality: when the Push Button Switch is pressed the buzzer sounds and when the button is released, the buzzer stops. This is a momentary switch function.

Raspberry Pi (with 40 GPIO) x1

GPIO Extension Board & Ribbon Cable x1

Breadboard x1

NPN transistorx1 (S8050)

NPN-transistor

Active buzzer x1

Active-buzzer

Push Button Switch x1

button-small

Resistor 1kΩ x1

Resistor-1kΩ

Resistor 10kΩ x2

Resistor-10kΩ

Jumper Wire

jumper-wire

6.1.1. Component knowledge

6.1.1.1. Buzzer

A buzzer is an audio component. They are widely used in electronic devices such as calculators, electronic alarm clocks, automobile fault indicators, etc. There are both active and passive types of buzzers. Active buzzers have oscillator inside, these will sound as long as power is supplied. Passive buzzers require an external oscillator signal (generally using PWM with different frequencies) to make a sound.

Active buzzer

../../../_images/Active-buzzer-knowledge.png

Passive buzzer

../../../_images/Passive-buzzer-knowledge.png

Active buzzers are easier to use. Generally, they only make a specific sound frequency. Passive buzzers require an external circuit to make sounds, but passive buzzers can be controlled to make sounds of various frequencies. The resonant frequency of the passive buzzer in this Kit is 2kHz, which means the passive buzzer is the loudest when its resonant frequency is 2kHz.

How to identify active and passive buzzer?

  1. As a rule, there is a label on an active buzzer covering the hole where sound is emitted, but there are exceptions to this rule.

  2. Active buzzers are more complex than passive buzzers in their manufacture. There are many circuits and crystal oscillator elements inside active buzzers; all of this is usually protected with a waterproof coating (and a housing) exposing only its pins from the underside. On the other hand, passive buzzers do not have protective coatings on their underside. From the pin holes, view of a passive buzzer, you can see the circuit board, coils, and a permanent magnet (all or any combination of these components depending on the model.

../../../_images/Active-buzzer-bottom.png

Passive buzzer

../../../_images/Passive-buzzer-bottom.png

Passive buzzer

6.1.1.2. Transistors

A transistor is required in this project due to the buzzer’s current being so great that GPIO of RPi’s output capability cannot meet the power requirement necessary for operation. A NPN transistor is needed here to amplify the current.

Transistors, full name: semiconductor transistor, is a semiconductor device that controls current think of a transistor as an electronic “amplifying or switching device”. Transistors can be used to amplify weak signals, or to work as a switch. Transistors have three electrodes (PINs): base (b), collector (c) and emitter (e). When there is current passing between “be” then “ce” will have a several-fold current increase (transistor magnification), in this configuration the transistor acts as an amplifier. When current produced by “be” exceeds a certain value, “ce” will limit the current output. at this point the transistor is working in its saturation region and acts like a switch. Transistors are available as two types as shown below: PNP and NPN,

../../../_images/PNP-transistor.png

PNP transistor

../../../_images/NPN-transistor-2.png

NPN transistor

Note

In our kit, the PNP transistor is marked with 8550, and the NPN transistor is marked with 8050.

Thanks to the transistor’s characteristics, they are often used as switches in digital circuits. As micro-controllers output current capacity is very weak, we will use a transistor to amplify its current in order to drive components requiring higher current.

When we use a NPN transistor to drive a buzzer, we often use the following method. If GPIO outputs high level, current will flow through R1 (Resistor 1), the transistor conducts current and the buzzer will make sounds. If GPIO outputs low level, no current will flow through R1, the transistor will not conduct currentand buzzer will remain silent (no sounds).

When we use a PNP transistor to drive a buzzer, we often use the following method. If GPIO outputs low level, current will flow through R1. The transistor conducts current and the buzzer will make sounds. If GPIO outputs high level, no current flows through R1, the transistor will not conduct current and buzzer will remain silent (no sounds). Below are the circuit schematics for both a NPN and PNP transistor to power a buzzer.

NPN transistor to drive buzzer

PNP transistor to drive buzzer

NPN-Drive

PNP-Drive

6.1.2. Circuit

Schematic diagram with RPi GPIO Extension Shield

Buzzer-Schematic

Hardware connection. If you need any support,please feel free to contact us via:

support@freenove.com

Buzzer-Fritizing

Note

In this circuit, the power supply for the buzzer is 5V, and pull-up resistor of the push button switch is connected to the 3.3V power feed. Actually, the buzzer can work when connected to the 3.3V power feed but this will produce a weak sound from the buzzer (not very loud).

6.1.3. Sketch

In this chapter, we use a button to control the active buzzer. The code is similar to that in Chapter 3.

6.1.3.1. Sketch_06_1_Doorbell

First, enter where the project is located:

$ cd ~/Freenove_Kit/Pi4j/Sketches/Sketch_06_1_Doorbell
../../../_images/java_doorbell.png

Enter the command to run the code.

$ jbang Doorbell.java
../../../_images/java_doorbell_jbang.png

During the code running, press the button to sound the buzzer and release the button to stop it.

../../../_images/Buzzer-Fritizing.png

You can see messages printed on the terminal.

../../../_images/java_doorbell_mes.png

Press Ctrl+C to exit the code.

../../../_images/java_doorbell_exit.png

You can open the code with Geany to view and edit it, with the following command.

$ geany Doorbell.java

Click the icon to run the code.

../../../_images/java_doorbell_code.png

If the code fails to run, please check Geany Configuration.

The following is program code:

 1///usr/bin/env jbang "$0" "$@" ; exit $?
 2
 3//DEPS org.slf4j:slf4j-api:2.0.12
 4//DEPS org.slf4j:slf4j-simple:2.0.12
 5//DEPS com.pi4j:pi4j-core:2.6.0
 6//DEPS com.pi4j:pi4j-plugin-raspberrypi:2.6.0
 7//DEPS com.pi4j:pi4j-plugin-gpiod:2.6.0
 8
 9import com.pi4j.Pi4J;
10import com.pi4j.io.gpio.digital.DigitalState;
11import com.pi4j.util.Console;
12
13public class Doorbell{
14    private static final int PIN_BUTTON = 18;
15    private static final int PIN_BUZZER = 17; 
16    
17    public static void myPrintln(String tempText) {  
18        Console console = new Console();
19        console.println("\u001B[32m" + tempText + "\u001B[0m"); 
20    }
21
22    public static void main(String[] args) throws Exception {
23        var pi4j = Pi4J.newAutoContext();
24        var buzzer = pi4j.dout().create(PIN_BUZZER);  
25        var button = pi4j.din().create(PIN_BUTTON);
26        
27        button.addListener(e -> {
28            if (e.state() == DigitalState.LOW) {
29                myPrintln("buzzer turned on.  >>>");
30                buzzer.high();
31            }
32            else if(e.state() == DigitalState.HIGH){
33                myPrintln("buzzer turned off. >>>");
34                buzzer.low();
35            }
36        });
37        
38        try{
39            while (true) {
40                Thread.sleep(500);
41            }
42        }
43        finally{
44            pi4j.shutdown();
45        }
46    }
47}

Please note that as the code is similar to that in chapter 3, here we do not explain it again.

In order to make the prompt messages printed by the terminal more conspicuous, we wrote the myprintln function to wrap the console.println function.

1    public static void myPrintln(String tempText) {  
2        Console console = new Console();
3        console.println("\u001B[32m" + tempText + "\u001B[0m"); 
4    }

6.2. Project Alertor

Next, we will use a passive buzzer to make an alarm.

The list of components and the circuit is similar to the doorbell project. We only need to take the Doorbell circuit and replace the active buzzer with a passive buzzer.

6.2.1. Sketch

In this chapter, we use button to control the passive buzzer to make sound.

6.2.1.1. Sketch_Alertor

First, enter where the project is located:

$ cd ~/Freenove_Kit/Pi4j/Sketches/Sketch_06_2_Alertor
../../../_images/java_Alertor.png

Enter the command to run the code.

$ jbang Alertor.java
../../../_images/java_Alertor_run.png

When the code is running, press the button to sound the buzzer and release to stop it.

You can see messages printed on the terminal.

../../../_images/java_Alertor_mes.png

Press ctrl+C to exit the code.

../../../_images/java_Alertor_exit.png

You can open the code with Geany to view and edit it, with the following command.

$ geany Alertor.java

Click the icon to run the code.

../../../_images/java_Alertor_code.png

If the code fails to run, please check Geany Configuration.

The following is program code:

  1///usr/bin/env jbang "$0" "$@" ; exit $?
  2
  3//DEPS org.slf4j:slf4j-api:2.0.12
  4//DEPS org.slf4j:slf4j-simple:2.0.12
  5//DEPS com.pi4j:pi4j-core:2.6.0
  6//DEPS com.pi4j:pi4j-plugin-raspberrypi:2.6.0
  7//DEPS com.pi4j:pi4j-plugin-gpiod:2.6.0
  8
  9import com.pi4j.Pi4J;
 10import com.pi4j.context.Context;
 11import com.pi4j.io.gpio.digital.DigitalState;
 12import com.pi4j.io.gpio.digital.DigitalInput;
 13import com.pi4j.io.gpio.digital.DigitalOutput;
 14import com.pi4j.util.Console;
 15import java.util.HashMap;
 16import java.util.Map;
 17import java.util.Random;
 18
 19class PWMController implements Runnable {
 20    private DigitalOutput pwm;
 21    private int pwmFrequency;
 22    private double pwmDutyCycle;
 23    private boolean running = true;
 24    private long period;
 25    private long highTime;
 26    private long lowTime;
 27
 28    public PWMController(DigitalOutput pwm) {
 29        this.pwm = pwm;
 30        this.pwmFrequency = 1000;
 31        this.pwmDutyCycle = 0.5;
 32        this.period = (int) (1000000 / pwmFrequency);
 33        this.highTime = (int) (period * pwmDutyCycle);
 34        this.lowTime = (int) (period - highTime);
 35    }
 36
 37    @Override
 38    public void run() {
 39        while (running) {
 40            if (highTime != 0) {
 41                pwm.high();
 42                delayUs(highTime);
 43            }
 44            if (lowTime != 0) {
 45                pwm.low();
 46                delayUs(lowTime);
 47            }
 48        }
 49    }
 50
 51    public void setPwmFrequency(int frequency) {
 52        if (frequency != 0) {
 53            this.pwmFrequency = frequency;
 54            this.period = (int) (1000000 / pwmFrequency);
 55            this.highTime = (int) (period * pwmDutyCycle);
 56            this.lowTime = (int) (period - highTime);
 57        } else {
 58            this.pwmFrequency = 0;
 59            this.period = (int) (1000);
 60            this.highTime = (int) (0);
 61            this.lowTime = (int) (period - highTime);
 62        }
 63    }
 64
 65    public void setPwmDutyCycle(double dutyCycle) {
 66        this.pwmDutyCycle = dutyCycle;
 67        this.highTime = (int) (period * pwmDutyCycle);
 68        this.lowTime = (int) (period - highTime);
 69    }
 70
 71    private void delayUs(long us) {
 72        long startTime = System.nanoTime();
 73        long endTime = startTime + (us * 1000);
 74        while (System.nanoTime() < endTime) {
 75        }
 76    }
 77
 78    public void requestStop() {
 79        running = false;
 80    }
 81}
 82
 83public class Alertor {
 84    private static final Context pi4j = Pi4J.newAutoContext();
 85    private static final Map<Integer, PWMController> pwmControllers = new HashMap<>();
 86    private static volatile int buttonState = 0;
 87    private static int PIN_BUTTON = 18;
 88    private static int PIN_BUZZER = 17;
 89
 90    public static void setPwmConfig(int pin) throws Exception {
 91        DigitalOutput pwm = pi4j.dout().create(pin);
 92        PWMController pwmController = new PWMController(pwm);
 93        Thread pwmThread = new Thread(pwmController, "PWM Controller " + pin);
 94        pwmControllers.put(pin, pwmController);
 95        pwmThread.start();
 96        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
 97            pwmController.requestStop();
 98            try {
 99                pwmThread.join();
100            } catch (InterruptedException e) {
101                Thread.currentThread().interrupt();
102            }
103        }));
104    }
105
106    public static void myPrintln(String tempText) {
107        Console console = new Console();
108        console.println("\u001B[32m" + tempText + "\u001B[0m");
109    }
110
111    public static void main(String[] args) throws Exception {
112
113        DigitalInput button = pi4j.din().create(PIN_BUTTON);
114        button.addListener(e -> {
115            buttonState = e.state() == DigitalState.LOW ? 1 : 0;
116        });
117
118        setPwmConfig(PIN_BUZZER);
119        PWMController buzzer = pwmControllers.get(PIN_BUZZER);
120        buzzer.setPwmFrequency(0);
121        buzzer.setPwmDutyCycle(0.5);
122
123        try {
124            while (true) {
125                if (buttonState == 1) {
126                    myPrintln("buzzer turned on.  >>>");
127                    buzzer.setPwmFrequency(1000);
128                } else {
129                    myPrintln("buzzer turned off. >>>");
130                    buzzer.setPwmFrequency(0);
131                }
132                Thread.sleep(100);
133            }
134        } 
135        finally {
136            for (PWMController controller : pwmControllers.values()) {
137                controller.requestStop();
138            }
139            pi4j.shutdown();
140        }
141    }
142}

Create a pi4j context for manipulating the GPIOs, and define the GPIO numbers that control the keys and buzzer.

1private static final Context pi4j = Pi4J.newAutoContext();
2private static final Map<Integer, PWMController> pwmControllers = new HashMap<>();
3private static volatile int buttonState = 0;
4private static int PIN_BUTTON = 18;
5private static int PIN_BUZZER = 17;

Initialize the button input pin, create a monitoring event, and assign the key value to buttonState when the button state changes.

1DigitalInput button = pi4j.din().create(PIN_BUTTON);
2button.addListener(e -> {
3    buttonState = e.state() == DigitalState.LOW ? 1 : 0;
4});

Initialize the PWM pin that controls the passive buzzer.

1setPwmConfig(PIN_BUZZER);
2PWMController buzzer = pwmControllers.get(PIN_BUZZER);
3buzzer.setPwmFrequency(0);
4buzzer.setPwmDutyCycle(0.5);

When buttonState is 1, the passive buzzer sounds, and when buttonState is 0, the buzzer sound is turned off. Print the information in the console.

1if (buttonState == 1) {
2    myPrintln("buzzer turned on.  >>>");
3    buzzer.setPwmFrequency(1000);
4} else {
5    myPrintln("buzzer turned off. >>>");
6    buzzer.setPwmFrequency(0);
7}