How to Use a Buzzer to Play Music with Raspberry Pi Pico

Raspberry Pi Pico Buzzer
(Image credit: Tom's Hardware)

Whether you’re building a game that beeps when you lose a turn, an alarm clock that wakes you up or just a cute display that plays 8-bit music, a low-cost piezo buzzer can be a great part of your Raspberry Pi Pico project. The extremely-cheap buzzers -- you can often find them for less than $1 apiece -- are dead-simple to program in MicroPython and can even vary the frequency to produce musical notes.

There are two types of piezo buzzers: active and passive. Active buzzers will make noise if they are just hooked up to power with no microcontroller involved while passive ones will not. Passive buzzers are preferred for this kind of project because they offer a better range of sounds, though in our testing, both worked.

Below, we’ll show you how to wire the Raspberry Pi Pico to a piezo buzzer and program it in MicroPython to play a short tune.

Here’s what you need

  • Raspberry Pi Pico: See our article on how to set up Raspberry Pi Pico.
  • Passive Piezo Buzzer: We used these, but any will do. An active buzzer may also work.
  • Two jumper wires: We used female-to-female jumpers, but if you are also using a breadboard, you’ll need male-to-male jumpers.

Wiring a Buzzer to Raspberry Pi Pico

This couldn’t be simpler. You connect the ground pin on the buzzer to a GND pin on the Pico and the positive buzzer pin to a standard GPIO pin on the pico, in our case GP15. Our passive buzzer didn’t have negative or positive labels on its pins and worked with either one plugged into either Pico pin. 

(Image credit: Tom's Hardware)

Programming the Buzzer 

1. Start by importing Pin and PWM from the machine library and sleep from the utime library. 

from machine import Pin, PWM
from utime import sleep

2. Initialize PWM (aka pulse width modulation) on Pin 15 and assign it to the variable buzzer. 

buzzer = PWM(Pin(15))

3. Assign a freq property to buzzer. You must choose a number that ranges between 10 and 12,000. The higher the number, the higher pitched the sound. Let’s try 500. 

buzzer.freq(500)

4. Set the duty_u16 property of the buzzer object to 1000. This makes the buzzer as loud as it can be. A lower value is quieter and 0 is no sound at all. Considering how quiet these buzzers are, maximum volume isn’t very loud at all. 

buzzer.duty_u16(1000)

5. Set a 1 second delay and then set duty to 0 so that the sound stops. If you don’t do this, the buzz will continue, even after the program is finished executing.

sleep(1)
buzzer.duty_u16(0)

Your final code for this simple test should look like this. 

from machine import Pin, PWM
from utime import sleep

buzzer = PWM(Pin(15))
buzzer.freq(500)
buzzer.duty_u16(1000)
sleep(1)
buzzer.duty_u16(0)

Playing Music with a Buzzer on Raspberry Pi Pico 

Because you can use different frequencies, you can create a full array of musical notes. There are a few lists of musical note frequencies online and many of them trace back to Brett Hagman’s Arduino tone library on Github. We’ll use these values to create a list we can use to play any song early in our code. 

1. Import the necessary libraries and initialize PWM on pin 15.

from machine import Pin, PWM
from utime import sleep

buzzer = PWM(Pin(15))

2.  Create a dictionary called notes with the following values. 

tones = {
"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
}

3. Create a list (aka array) of notes for your song. Use the letter P to represent pauses in the music. Each note should be in quotation marks. 

song = ["E5","G5","A5","P","E5","G5","B5","A5","P","E5","G5","A5","P","G5","E5"]

Hat tip to the folks on this thread for sharing the notes for this famous riff.

4. Create a function called playtone that will take any frequency and play it at full volume. 

def playtone(frequency):
    buzzer.duty_u16(1000)
    buzzer.freq(frequency)

5. Create a function called bequiet that will silence the buzzer by change duty_u16 to 0. 


def bequiet():
    buzzer.duty_u16(0)

6. Create a function called playsong that you will use to iterate through the array of notes and play each or pause when it sees P. 

def playsong(mysong):
    for i in range(len(mysong)):
        if (mysong[i] == "P"):
            bequiet()
        else:
            playtone(tones[mysong[i]])
        sleep(0.3)
    bequiet()

Here’s what’s going on here. First, we create a for loop that iterates through all the values in the mysong array. If the value is equal to P, it triggers be quiet and, if not, it triggers playtone. Note that playtone requires a numeric frequency value so we have to get the number for each note from the tones list. If we just playtone(mysong[i]), it will fail because it will try to play the string “E5,” instead of frequency 659, which is the integer it needs.

For each tone or pause, the system maintains state for 0.3 seconds of sleep. If you want a faster tempo, you can lower that time. If you want a slower tempo, increase it.

7. Trigger the playsong function with the song parameter.

playsong(song)

When you run this code, you will hear your buzzer play a familiar melody.  Here’s what the complete code should look like: 

from machine import Pin, PWM
from utime import sleep
buzzer = PWM(Pin(15))

tones = {
"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
}

song = ["E5","G5","A5","P","E5","G5","B5","A5","P","E5","G5","A5","P","G5","E5"]

def playtone(frequency):
    buzzer.duty_u16(1000)
    buzzer.freq(frequency)

def bequiet():
    buzzer.duty_u16(0)

def playsong(mysong):
    for i in range(len(mysong)):
        if (mysong[i] == "P"):
            bequiet()
        else:
            playtone(tones[mysong[i]])
        sleep(0.3)
    bequiet()
playsong(song)

So now you know how to play music with the Raspberry Pi Pico and a piezo buzzer. You can make this play any song, provided you have the notes. 

Avram Piltch
Avram Piltch is Tom's Hardware's editor-in-chief. When he's not playing with the latest gadgets at work or putting on VR helmets at trade shows, you'll find him rooting his phone, taking apart his PC or coding plugins. With his technical knowledge and passion for testing, Avram developed many real-world benchmarks, including our laptop battery test.