ROBOTICS · LEVEL 1 · ARDUINO FOUNDATIONS · LESSON 04

Program an Arduino Sound-Effect Machine

Give your Arduino a voice: buttons trigger sounds, and you design a victory jingle.

Your Arduino has been silent so far. Today, you will give it a voice.

You will build a two-button sound-effect machine: one button plays a friendly “ready” sound and the other plays an alert. Then you will compose your own three-note victory jingle. The goal is not to copy a tune perfectly. It is to discover how code controls pitch, timing, and a real physical sound.

At a glance

Age range10–13
Estimated time60–75 minutes
DifficultyBeginner-plus
Parent involvementLight after the first sound test
Major conceptsPiezo output, two digital inputs, pitch, duration, functions, while waiting for release

What you will learn

  • How a piezo buzzer turns Arduino signals into sound.
  • How to wire and read two buttons using INPUT_PULLUP.
  • How tone() changes pitch and noTone() stops a sound.
  • How functions can organize several notes into named sound effects.
  • How a program can wait for a button to be released so one press plays one sound.
  • How to design, test, and improve an original short jingle.

Before you begin

Complete Lesson 2: Build a Push-to-Shine Arduino Light before this lesson. You will use the same button pattern twice: one side of the button goes to an input pin and the opposite side goes to ground. With INPUT_PULLUP, a pressed button reads LOW.

Lesson 3: Program a Mini Arduino Traffic Signal introduced named functions. Read it first if showGreen() and allLightsOff() felt new; this lesson uses the same idea for playReadySound() and playAlertSound().

This is a physical-hardware lesson rather than a Tinkercad rehearsal. Sound level and piezo polarity are worth testing on the real Uno. If Arduino IDE cannot see the board, remove all breadboard wires and run Lesson 1’s built-in Blink test before doing anything else.

What you need

Required components

QuantityItemCompatible substitute
1Arduino Uno from the Arduino Student KitGenuine Uno R3 or Uno R3 SMD
1Solderless breadboardStandard half-size breadboard
1Piezo buzzer from the kitPassive piezo buzzer or passive speaker compatible with Arduino tone()
2Four-leg tactile pushbuttonsMomentary tactile buttons that fit the breadboard
6–8Male-to-male jumper wiresSolid-core breadboard wires
1USB-A to USB-B data cableArduino-branded USB-A-to-B data cable

Optional components

  • Cardboard, tape, markers, and paper labels for a small soundboard.
  • Headphones or ear protection are not needed. Use a comfortable room volume and stop if the buzzer is unpleasantly loud.
  • A maker notebook and pencil.

Tools

None. This project is solderless.

Computer/software requirements

  • Arduino IDE 2 with Arduino Uno and its port selected.
  • A Mac running macOS 10.15 or later, or Windows 10 64-bit or newer.

Safety and setup notes

  • Unplug the USB cable before adding or moving wires.
  • Use only USB power. Do not connect the kit’s battery, wall power, or an external amplifier.
  • A small piezo buzzer does not need a series resistor in this project. Do not use a big speaker or headphones directly on an Arduino pin.
  • Check the piezo’s + marking, long leg, or red wire. Connect that side to D8; the - marking, short leg, or black wire goes to the ground rail.
  • Each button must straddle the breadboard’s center trench. One side goes to D2 or D3; the opposite side goes to ground. Neither button connects to 5 V.
  • The adult should step in if a part is warm, the board resets, a sound is uncomfortable, or the child cannot lower the volume by stopping or unplugging the project. Otherwise, let the child experiment with pitches and make imperfect sounds.

Build overview

This project has two inputs and one output:

READY button on D2 ─┐
                    ├→ Arduino chooses a named sound → piezo on D8
ALERT button on D3 ─┘

When a button is pressed, the Arduino calls a function that plays a small pattern of notes. A number such as 523 tells tone() how quickly to vibrate the piezo. Bigger frequency numbers usually sound higher. The number in delay() tells the Arduino how long to wait before moving to the next note.

The program also includes a small helper called waitForRelease(). After a button triggers one sound, the Arduino waits until that button is released. That prevents a long hold from immediately starting the same sound again and again.

Step-by-step build instructions

Step 1: Make one shared ground rail

  1. Place the breadboard with its long center trench running left to right.
  2. Use a black jumper to connect an Arduino GND pin to one long breadboard rail. This is the shared ground rail.
  3. Keep the Uno unplugged while you place the rest of the circuit.

Checkpoint: trace the black wire from the Uno’s GND pin to the rail. You will use this one rail for both buttons and the piezo’s negative side.

Step 2: Wire the piezo output

  1. Place the piezo buzzer so its two legs are in different connected breadboard rows.
  2. Find its + marking, long leg, or red wire. Connect that row to Arduino digital pin D8 with a colored jumper.
  3. Connect the piezo’s - marking, short leg, or black wire to the shared ground rail with a black jumper.
FromToWhy
Piezo positive / + / long legArduino D8Sends the changing signal that makes sound
Piezo negative / - / short legBreadboard ground railCompletes the path back to the Arduino
Arduino GNDBreadboard ground railMakes the rail a real shared ground

Checkpoint: point to the piezo’s positive and negative sides. Ask: Which wire carries the sound signal?

Step 3: Wire the READY button on D2

  1. Place the first tactile button so it straddles the center trench. One pair of legs must be on one side of the trench and the other pair on the other side.
  2. Connect one button side to Arduino digital pin D2.
  3. Connect the opposite button side to the shared ground rail.
  4. Label this button READY with tape or paper.

Checkpoint: trace D2 → button → ground. Remember: the button connects that path only while it is pressed.

Step 4: Wire the ALERT button on D3

  1. Place the second button across the center trench, away from the first.
  2. Connect one button side to Arduino digital pin D3.
  3. Connect the opposite button side to the shared ground rail.
  4. Label this button ALERT.

Checkpoint: say the entire project map out loud: “D2 is READY, D3 is ALERT, D8 is sound, and black is ground.”

Step 5: Upload the soundboard program

  1. Connect the Uno to the computer using the USB data cable.
  2. Open Arduino IDE and confirm Arduino Uno and its port are selected.
  3. Create a new sketch, remove any starter text, and paste or type the complete code below.
  4. Click Verify. Fix the first error before uploading.
  5. Click Upload and wait for Done uploading.

Checkpoint: tap READY once. You should hear a short rising sound. Tap ALERT once. You should hear a longer falling sound. Each press should play only its own sound.

Step 6: Make predictions about pitch and timing

Before changing code, answer these questions:

  • Which note in playReadySound() should sound higher: 523 or 784?
  • What will happen if you change one delay(150) to delay(400)?

Make one change, upload, and listen. Restore the original number before trying a different change. That is how you learn what each number controls.

Code

const int READY_BUTTON_PIN = 2;
const int ALERT_BUTTON_PIN = 3;
const int PIEZO_PIN = 8;

void setup() {
  pinMode(READY_BUTTON_PIN, INPUT_PULLUP);
  pinMode(ALERT_BUTTON_PIN, INPUT_PULLUP);
  pinMode(PIEZO_PIN, OUTPUT);
}

void loop() {
  if (digitalRead(READY_BUTTON_PIN) == LOW) {
    playReadySound();
    waitForRelease(READY_BUTTON_PIN);
  } else if (digitalRead(ALERT_BUTTON_PIN) == LOW) {
    playAlertSound();
    waitForRelease(ALERT_BUTTON_PIN);
  }
}

void playReadySound() {
  tone(PIEZO_PIN, 523);
  delay(120);
  noTone(PIEZO_PIN);
  delay(50);

  tone(PIEZO_PIN, 784);
  delay(180);
  noTone(PIEZO_PIN);
}

void playAlertSound() {
  tone(PIEZO_PIN, 880);
  delay(150);
  noTone(PIEZO_PIN);
  delay(50);

  tone(PIEZO_PIN, 440);
  delay(300);
  noTone(PIEZO_PIN);
}

void waitForRelease(int buttonPin) {
  while (digitalRead(buttonPin) == LOW) {
    // Wait here until the button is released.
  }
}

What the important code means

  • Variables: the three pin constants name the real connections: D2, D3, and D8. The buttonPin inside waitForRelease() is a value the function receives so it knows which button to watch.
  • setup(): this runs once. Both buttons use INPUT_PULLUP, so released reads HIGH and pressed reads LOW. D8 is an output for the piezo.
  • loop(): this runs over and over, looking first for a READY press and then for an ALERT press. else if means it chooses only one sound at a time.
  • Inputs and outputs: the two buttons are inputs. The piezo is the output.
  • Functions: playReadySound() and playAlertSound() each hold a reusable note pattern. tone() starts a frequency, delay() lets it play, and noTone() stops it.
  • The while loop: waitForRelease() repeats its tiny check only while the button remains pressed. It is not a new sound pattern; it simply makes one press count as one sound.

Arduino’s official tone() reference explains that it generates a square wave at the chosen frequency. noTone() stops that wave.

Make it work

The first version works when all of these are true:

  1. Arduino IDE says Done uploading.
  2. A tap on READY plays the short rising sound.
  3. A tap on ALERT plays the longer falling sound.
  4. READY does not trigger the alert sound, and ALERT does not trigger the ready sound.
  5. Holding a button down does not immediately restart its sound over and over; releasing it allows the next press.
  6. You can point to D2, D3, D8, the piezo’s positive side, and the shared ground rail.

Understand it

  1. Which part is the input in this project, and which part is the output?
  2. Why do the buttons read LOW when pressed in this circuit?
  3. Which sound is higher: a tone() at 880 or a tone() at 440? How do you know?
  4. What job does noTone(PIEZO_PIN) do?
  5. Why does the program wait for a button to be released after playing a sound?

Required “change it” challenge

Desired outcome: make the READY button play your own three-note victory jingle. The three notes should sound different, include at least one tiny silent pause, and last less than two seconds total.

Constraints: create a clearly named function such as playVictorySound(); use three tone() calls; include at least one noTone() plus a short delay for silence; change the READY-button branch so it calls your victory function; do not add hardware.

Hints:

  1. Bigger tone-frequency numbers usually sound higher. Start with three values such as a low, middle, and high number; you do not need to know music notes.
  2. Every note needs time to play. Use a delay() after each tone() and add noTone() before a pause.
  3. First copy and rename the ready-sound function. Change only one pitch or one timing number at a time. When it sounds right, replace playReadySound() in the READY button branch with your new function name.

Parent guidance: let the student make a sound that is odd, silly, or unexpectedly bad. That is useful evidence. A healthy struggle is deciding which numbers control pitch versus timing. If he is stuck, ask, “Which number changes how high it sounds, and which number changes how long it lasts?” Step in if he cannot restore the original working sound after 15–20 minutes, if the sound is uncomfortable, or if he cannot identify the READY branch that needs to call the new function.

Optional enhancements

Try this

Give the ALERT sound three short notes instead of two. Make it sound urgent without making it unpleasantly loud. Write a word that describes the sound before you change the code.

Challenge

Make a sound play only after the button has been held for a full second. Before you code, draw a timeline showing press, waiting, and sound. Hint: you will need a longer delay() and then a second check to see whether the button is still pressed.

Stretch

Build a cardboard soundboard with labels for a spaceship, game show, robot, or secret agent. Design a third sound on paper and explain what extra input or rule you would need to trigger it without adding a third button yet.

Debugging guide

What you noticeLikely causeSmallest next diagnostic step
The Uno is not detected or its green power LED is offComputer/cable issue, not the sound circuitUnplug all breadboard wires and run Lesson 1’s built-in Blink sketch with the supplied data cable.
No sound from either buttonPiezo is not connected to D8/ground, code did not upload, or piezo legs share one breadboard rowTrace only D8 → piezo positive and piezo negative → ground. Then upload the complete lesson code again.
READY plays ALERT or ALERT plays READYD2 and D3 wires are swappedCompare one wire at a time to the map: D2 READY, D3 ALERT.
A sound starts again and again while holding a buttonwaitForRelease() is missing or changed, or the button is not wired across the center trenchCompare the helper function to the lesson code, then confirm the button straddles the trench.
The buzzer makes only a click or an odd weak soundPiezo polarity or connection is uncertain, or a tone ends immediatelyCheck the + or long leg at D8 and make sure each tone() has a delay after it.
Sound is much too high, low, or longFrequency or delay number was changedChange back one number at a time. Frequency changes pitch; delay changes duration.
Code will not compileMissing semicolon, brace, or misspelled function nameRead the first error line, then compare it and the line above it to the complete sketch.
One button never respondsButton legs are on the same connected breadboard side, ground is missing, or wrong pin is usedTrace D2/D3 → button → ground and make sure the button crosses the center trench.

If one small diagnostic does not reveal the issue, use the Debugging Ladder. Return to the original two-sound code before debugging a custom jingle.

Recap

You turned two button presses into two different sounds. You reused the button input pattern from Lesson 2, used tone() and noTone() to control a piezo output, and kept the main program readable by putting each sound inside a named function. Your jingle challenge showed that code can be both precise and creative.

Show what you learned

Write or tell your parent:

  • What did you change in your victory jingle?
  • Which number changed pitch, and which number changed duration?
  • What failed, if anything, and what was your smallest debugging test?
  • Explain why waitForRelease() is useful in this project.

In your maker notebook, write your final three frequencies and timings. Give the sound a name, then write one sentence about what it is supposed to make someone feel or understand.

What’s next

Next, you will replace a button with a dial. In Lesson 5, a potentiometer will become an analog input that smoothly controls an LED and can also control sound. The piezo skill from today will carry forward. Continue to Lesson 5: Build a Dial-a-Signal Controller.

NEXT · LESSON 05

Lesson 5: Build a Dial-a-Signal Controller

Parent guide

Prepare in advance

  • Confirm the Uno still uploads Lesson 1’s Blink sketch.
  • Set out the Uno, breadboard, piezo, two buttons, jumper wires, cable, and notebook. Keep cardboard aside until the electronic version works.
  • Mark or point out the piezo’s + and - markings before the child wires it.
  • Keep a direct overhead photo as the first debugging step if the two button circuits become confusing.

Let the child work independently when

  • placing the two buttons across the center trench;
  • tracing each button’s input path and the piezo’s output path;
  • uploading the main code and testing one button at a time;
  • predicting pitch and timing changes; and
  • composing and testing the victory jingle.

Resist taking over when

  • the first jingle sounds awkward or too much like an alarm;
  • he mixes up which number changes pitch and which changes time but can test one number;
  • he needs to compare the D2/D3 map with his own wires; or
  • the cardboard soundboard is rough but clearly communicates its idea.

Step in when

  • a part becomes warm, the board resets, or the sound is uncomfortably loud;
  • the Uno does not connect before there is a chance to test the circuit;
  • he has made a small test on the same problem but has no new hypothesis; or
  • he cannot restore the original working soundboard after an extended jingle experiment. Save the working two-sound sketch before changing it.

Simple understanding-based assessment

Ask the student to point to the two inputs, the output, and the function that plays the alert. Then ask: “What does tone() control? Why does the code wait for release?” Award one point each for a working/tested build, a correct explanation, a deliberate three-note change, and a useful debugging/notebook note. A song that sounds good but cannot be explained is not a complete success.

Further resource: Arduino tone() reference