Learn Arduino Tutorials Open the 3D lab

Project 9 · Intermediate · 7 min read · 20 minutes to build

Arduino piano with 8 buttons and a buzzer — INPUT_PULLUP explained

Eight buttons, one buzzer, zero resistors — and you can play Do Re Mi. This project shows the trick that saves you a resistor on every button, and how one short loop can watch many inputs at once.

An Arduino UNO wired to eight push buttons in a row and a passive buzzer on a breadboard, like a little keyboard
Try this project in 3DRun the code, press the parts, break things safely — free, in your browser.Open in 3D →

What you need

  • Arduino UNO R3 (or a compatible board)
  • USB cable (A to B)
  • Half-size breadboard
  • Push button (6 mm)
  • Passive piezo buzzer
  • Jumper wires (male–male)

Don't have the parts? Build it in 3D first.

What you will build

A row of eight buttons that work like piano keys, and a buzzer. Press a key and its note plays for as long as you hold it; let go and it stops. The eight keys play one octave of the C major scale — Do, Re, Mi, Fa, Sol, La, Ti, Do — and the serial monitor prints the name of each note you play.

Musical keyboards, keypads on alarm panels and the buttons on arcade machines all do what this sketch does: scan many inputs, find the one that is pressed, react.

How it works

In the push button project, each button needed a 10 kΩ pull-down resistor. Eight buttons would need eight resistors. The UNO has a shortcut built in: every pin has its own pull-up resistor inside the chip that you can switch on in code with INPUT_PULLUP.

  • Key not pressed: the internal pull-up (about 20–50 kΩ; our lab uses 35 kΩ) holds the pin at 5 V. It reads HIGH.
  • Key pressed: the button joins the pin straight to GND. It reads LOW.

So the logic is "upside down": pressed = LOW. The current through the pull-up while you press is tiny: 5 V ÷ 35 kΩ ≈ 0.14 mA. More in pull-up and pull-down resistors.

Each key has its own pin and its own note:

KeyPinNoteFrequency
12Do (C)262 Hz
23Re (D)294 Hz
34Mi (E)330 Hz
45Fa (F)349 Hz
56Sol (G)392 Hz
67La (A)440 Hz
78Ti (B)494 Hz
89Do (high C)523 Hz

The last Do is twice the first (262 × 2 ≈ 523): one octave higher.

Close-up of the eight push buttons in a row across the breadboard's middle gap
Each key joins its pin to the ground rail while you hold it.

The wiring

The buttons sit across the breadboard's middle gap in a row, starting in columns 1, 4, 7, 10, 13, 16, 19 and 22. Each button spans its own column and the column two to the right (so the first spans columns 1 and 3).

  1. Push the eight buttons in across the gap, one at each of those columns.
  2. Jumper wire from GND → the top − rail (at column 2). Now the whole rail is ground.
  3. For each key: a wire from its pin to the top of its first column — pin 2 → 1a, pin 3 → 4a, pin 4 → 7a, pin 5 → 10a, pin 6 → 13a, pin 7 → 16a, pin 8 → 19a, pin 9 → 22a.
  4. For each key: a short wire from the − rail down to the top of its second column — 3a, 6a, 9a, 12a, 15a, 18a, 21a, 24a.
  5. Push the buzzer in with its + leg in 26b and its other leg in 29b.
  6. Jumper wires: pin 10 → 26a, 29a → GND.
Part pinGoes toWhat it does
Each key, first columnPins 2–9The pin that reads that key
Each key, second columnTop − rail → GNDPressing pulls the pin LOW
Buzzer +Pin 10Plays the note with tone()
Buzzer −GNDThe return path
Schematic of the mini piano: eight buttons from D2–D9 to GND, and D10 to the buzzer
The schematic from the 3D lab's Wiring tab.

The code, line by line

const int BUZZER = 10;
const int KEYS[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
const int NOTES[] = { 262, 294, 330, 349, 392, 440, 494, 523 };   // C D E F G A B C
const char* NAMES[] = { "Do", "Re", "Mi", "Fa", "Sol", "La", "Ti", "Do" };
int playing = -1;

void setup() {
  for (int i = 0; i < 8; i++) pinMode(KEYS[i], INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  int down = -1;
  for (int i = 0; i < 8; i++) {
    if (digitalRead(KEYS[i]) == LOW) down = i;   // pressed keys read LOW
  }
  if (down != playing) {
    playing = down;
    if (playing < 0) noTone(BUZZER);
    else {
      tone(BUZZER, NOTES[playing]);
      Serial.println(NAMES[playing]);
    }
  }
}
  • Three arrays in step: key i is on pin KEYS[i], plays NOTES[i] and is called NAMES[i]. const char* is how C++ stores a list of words.
  • int playing = -1; remembers which key is sounding. −1 means "none" — a number that can never be a real key.
  • for (…) pinMode(KEYS[i], INPUT_PULLUP); switches on the internal pull-up on all eight pins in one line.
  • The scan: down starts at −1; the loop checks every key, and any key that reads LOW is pressed, so down = i. If two keys are held, the higher one wins, because it is checked last.
  • if (down != playing) — only act when something changes, just like the button project. Otherwise tone() would restart thousands of times a second.
  • noTone(BUZZER) stops the sound when no key is down.
  • tone(BUZZER, NOTES[playing]) — with no duration, the note plays until the next tone() or noTone(). That is why it lasts as long as you hold the key.

Common mistakes

  • Notes play by themselves. INPUT_PULLUP is missing (plain INPUT), so the pins float. Use INPUT_PULLUP.
  • A key plays all the time. That button is not across the gap, or both its wires are on the same side of it. The pin and the rail must go to different columns of the button.
  • No key works. The − rail is not wired to GND. One wire from GND to the rail is all it takes.
  • Notes are in the wrong order. A key wire is on the wrong pin. Pin 2 is Do; count up from there.
  • The note never stops. The noTone() line is missing or playing is never reset to −1.

Try these challenges

  1. Shift every note up an octave: double the numbers in NOTES[].
  2. Make the lowest key win instead of the highest (hint: stop the scan with break; at the first pressed key).
  3. Light the board's L LED on pin 13 while any key is down.
  4. In the 3D lab, turn sound on in the toolbar and press the keys in 3D. Can you play "Ode to Joy" from the tune project? It starts Mi Mi Fa Sol.

Check yourself

  1. With INPUT_PULLUP, what does a pressed button read?

  2. Why does this circuit need no resistors on the buttons?

  3. What does playing = -1 mean in this sketch?

Questions people ask

What is INPUT_PULLUP on Arduino?

It is a pin mode that turns on a resistor inside the chip, connecting the pin to 5 V. The pin then reads HIGH when nothing is connected and LOW when a button joins it to GND — no external resistor needed.

How many buttons can an Arduino UNO read?

One per pin: up to 18 if you use D2–D13 and A0–A5 as digital inputs (keep D0 and D1 free for the serial monitor). For more, use a button matrix or a shift register.

Can the Arduino piano play two notes at once?

Not with one buzzer and tone(): it plays one frequency at a time. In this sketch the highest pressed key wins.

Why is the logic inverted with a pull-up?

Because the resistor holds the pin HIGH when idle, and the button pulls it LOW. Just remember: with INPUT_PULLUP, LOW means pressed.

What's next

You have mastered inputs and sound. Next, make something move: drive a DC motor with a transistor in the motor project.

Try this project in 3DRun the code, press the parts, break things safely — free, in your browser.Open in 3D →
Next: Control a DC motor with Arduino — TIP120 transistor and PWM speed →

Your progress stays on this device — no account, nothing sent anywhere.

Teach with this project

Put the live 3D project on your own class page or blog — free. Copy this code:

<iframe src="https://learnarduino.tech/?embed#/projects/piano" title="Arduino piano with 8 buttons and a buzzer — INPUT_PULLUP explained — live in 3D" width="100%" height="480" style="border:0;border-radius:12px" allow="fullscreen" loading="lazy"></iframe>

Last updated 2026-10-29

Read next