Raspberry Pi Pico
Passive Buzzer

A passive buzzer is a squeaky, piezoelectric component that can play notes of different frequencies.

Here is my simple circuit for this project. The buzzer I am using has one of its pins marked as positive. I have connected that one to pin 13 and the other pin is connected to GND to complete the circuit.

Pico Circuit

This is a small program showing how to get a tone from a buzzer,

from machine import PWM, Pin
from time import sleep

# define the pin to use for buzzing
buzz = PWM(Pin(13))
# the duty cycle to use when the note is on
volume = 2512


# buzzer, frequency, duration
def tone(buzzer, frequency,duration):
    buzzer.duty_u16(volume)
    buzzer.freq(frequency)
    sleep(duration)
    buzzer.duty_u16(0)

In the shell, you can call the subroutine with a statement like tone(buzz, 440,0.5). This will play a tone at 440hz (middle A) for half a second.

The subroutine works by setting the duty cycle of the PWM pin to something non-zero. It then sets the frequency of the PWM pin to a value that will determine which note is played. The program needs to sleep for the duration of the note before setting the duty cycle back to 0.

I then wrote some code that would allow me to play notes indefinitely. This is useful when the note needs to be stopped when the user does something like press a button. Here is my test code.

from machine import PWM, Pin
from time import sleep

# define the pin to use for buzzing
buzz = PWM(Pin(13))
# the duty cycle to use when the note is on
volume = 2512

# buzzer, frequency - plays until stopped
def note_on(buzzer, frequency):
    buzzer.duty_u16(volume)
    buzzer.freq(frequency)

# stop the noise
def note_off(buzzer):
    buzzer.duty_u16(0)
    

note_on(buzz, 440)
sleep(2)
note_off(buzz)

I then decided to make myself a music module. I wanted a way to define and play melodies without having to remember the frequencies for the notes or include them in my programs. The following code contains the previously defined subroutines along with another for working with melodies. Save the following code to the Pico as music.py.

from machine import PWM, Pin
from time import sleep

# the duty cycle to use when the note is on
volume = 2512
# the silence after a note is played
artic = 0.01

# dictionary of notes
notes = {
"B0": 31,
"C1": 33,
"CS1": 35,
"D1": 37,
"DS1": 39,
"E1": 41,
"F1": 44,
"FS1": 46,
"G1": 49,
"GS1": 52,
"A1": 55,
"AS1": 58,
"B1": 62,
"C2": 65,
"CS2": 69,
"D2": 73,
"DS2": 78,
"E2": 82,
"F2": 87,
"FS2": 93,
"G2": 98,
"GS2": 104,
"A2": 110,
"AS2": 117,
"B2": 123,
"C3": 131,
"CS3": 139,
"D3": 147,
"DS3": 156,
"E3": 165,
"F3": 175,
"FS3": 185,
"G3": 196,
"GS3": 208,
"A3": 220,
"AS3": 233,
"B3": 247,
"C4": 262,
"CS4": 277,
"D4": 294,
"DS4": 311,
"E4": 330,
"F4": 349,
"FS4": 370,
"G4": 392,
"GS4": 415,
"A4": 440,
"AS4": 466,
"B4": 494,
"C5": 523,
"CS5": 554,
"D5": 587,
"DS5": 622,
"E5": 659,
"F5": 698,
"FS5": 740,
"G5": 784,
"GS5": 831,
"A5": 880,
"AS5": 932,
"B5": 988,
"C6": 1047,
"CS6": 1109,
"D6": 1175,
"DS6": 1245,
"E6": 1319,
"F6": 1397,
"FS6": 1480,
"G6": 1568,
"GS6": 1661,
"A6": 1760,
"AS6": 1865,
"B6": 1976,
"C7": 2093,
"CS7": 2217,
"D7": 2349,
"DS7": 2489,
"E7": 2637,
"F7": 2794,
"FS7": 2960,
"G7": 3136,
"GS7": 3322,
"A7": 3520,
"AS7": 3729,
"B7": 3951,
"C8": 4186,
"CS8": 4435,
"D8": 4699,
"DS8": 4978
}


# buzzer, frequency, duration
def tone(buzzer, frequency, duration):
    buzzer.duty_u16(volume)
    buzzer.freq(frequency)
    sleep(duration)
    buzzer.duty_u16(0)

# buzzer, frequency - plays until stopped
def note_on(buzzer, frequency):
    buzzer.duty_u16(volume)
    buzzer.freq(frequency)

# stop the noise
def note_off(buzzer):
    buzzer.duty_u16(0)

# play a melody
def play_tune(buzzer, melody):
    # get each note
    for itm in melody:
        # split by colon
        n,d = tuple(itm.split(":"))
        d = float(d)
        # play note or rest
        n = notes.get(n,0)
        if n==0:
            sleep(d)
        else:
            tone(buzzer, n,d)
        # inter-note gap
        sleep(artic)

Here is an example of how you define a tune using this library. The tune is a list of strings. Each string is a note name followed by a colon, followed by the time the note should be played for.

from machine import PWM, Pin
from music import play_tune

# define the pin to use for buzzing
buzz = PWM(Pin(13))

tune = [
'FS4:0.2','G4:0.2','A4:0.2','B4:0.6','A4:0.2','B4:0.2','E5:0.2',
'D5:0.2','B4:0.2','A4:0.2','G4:0.2','E4:0.6','G4:0.2','B4:0.2',
'C5:0.2','D5:0.6','E5:0.2','D5:0.2','B4:0.2','G4:0.2','B4:0.2',
'A4:0.8','R:0.2','FS4:0.2','G4:0.2','A4:0.2','B4:0.6','A4:0.2',
'B4:0.2','E5:0.2','D5:0.2','B4:0.2','A4:0.2','G4:0.2','E4:0.6',
'FS4:0.2','G4:0.2','A4:0.2','B4:0.6','C5:0.2','B4:0.2','A4:0.2',
'G4:0.2','A4:0.2','G4:0.8','R:0.2','D5:0.2','E5:0.2','FS5:0.2',
'G5:0.6','FS5:0.2','FS5:0.2','E5:0.2','D5:0.2','E5:0.2','D5:0.2',
'B4:0.2','G4:0.6','D5:0.2','E5:0.2','FS5:0.2','G5:0.6','FS5:0.2',
'FS5:0.2','E5:0.2','D5:0.2','B4:0.2','A4:0.8','R:0.2','D5:0.2',
'D5:0.2','D5:0.2','B5:0.6','A5:0.2','A5:0.2','G5:0.2','E5:0.2',
'G5:0.2','D5:0.2','B4:0.2','G4:0.6','FS4:0.2','G4:0.2','A4:0.2',
'B4:0.2','E5:0.2','D5:0.2','B4:0.2','A4:0.2','G4:0.2','E4:0.2',
'FS4:0.2','G4:0.8','R:0.2']

play_tune(buzz, tune)

The next step for the music module is to find a better way to define tempo for your tune.