Arduinoのブザーでメロディを鳴らす!tone()の使い方とPythonで音階の周波数表を作る方法
「Arduinoでブザーを鳴らせたけど、ピーッて鳴るだけ…」「メロディを鳴らしたいのに、音がつながって変な音になる」
電子工作を始めて、LEDの次にやってみたくなるのが「音」ですよね。ブザーは数十円〜100円ほどの部品ですが、tone()関数を使うと、ドレミの音階でちゃんとメロディが鳴らせます🎵
この記事では、圧電ブザー(パッシブブザー)で「かえるのうた」を鳴らすところまで作ります。難易度はArduino入門〜初級。LチカができればOKです。
さらに、ドレミの周波数を手で調べなくて済むように、Pythonで「音階→周波数」の表を計算し、楽譜テキストをArduinoの配列に変換する小さなツールも作ります。一緒に見ていきましょう!
まず確認:ブザーには「アクティブ」と「パッシブ」がある

ここでつまずく人がとても多いので、最初に確認しておきます⚠️
| 種類 | 中身 | 鳴らし方 | メロディ |
|---|---|---|---|
| アクティブブザー | 発振回路入り | digitalWrite(pin, HIGH)で決まった音が鳴る |
向かない |
| パッシブブザー(圧電ブザー) | 発振回路なし | tone()で周波数を指定して鳴らす |
できる |
イメージとしては、アクティブブザーは「ボタンを押すと決まった音が出るチャイム」、パッシブブザーは「自分で弾く楽器」です。メロディを鳴らすならパッシブブザーを選びましょう。
見分け方の目安として、裏返したときに基板(緑色など)が見えるものはパッシブ、樹脂でふさがれているものはアクティブであることが多いです。いちばん確実なのは、5VとGNDに直接つないでみること。それだけで「ピー」と鳴ればアクティブです。
配線
- ブザーの+側(足が長いほう・+の印)→ D8ピン
- ブザーの-側 → GND
- 音が大きすぎるときは、100Ω程度の抵抗を直列に入れると少し小さくなります
tone()の基本と、知っておきたい3つの注意点
tone()は、指定したピンから指定した周波数の矩形波(ON/OFFをくり返す信号)を出す関数です。書き方は2通りあります。
tone(ピン, 周波数):noTone(ピン)を呼ぶまで鳴り続けるtone(ピン, 周波数, 長さ):指定したミリ秒だけ鳴る
周波数の単位はHz(ヘルツ)です。たとえばtone(8, 440, 500)なら、D8ピンから「ラ」の音(440Hz)が0.5秒鳴ります。
ただし、公式リファレンスには次の注意が書かれています👇
- 同時に鳴らせるのは1音だけ。別のピンで鳴っている間に
tone()を呼んでも無視されます - Mega以外のボードでは、ピン3と11のPWM出力(analogWrite)に影響が出ます。LEDの明るさ調整などと一緒に使うときは、別のピンを使いましょう
- 31Hzより低い音は出せません
そしてもう1つ、いちばん大事なのが「tone()は待ってくれない」ことです。これは後のスケッチで詳しく見ます。
Pythonでドレミの周波数表を作る
メロディを鳴らすには、「ドは何Hz?」「ソは何Hz?」が分かる必要があります。ネットで表を探してもいいのですが、実は計算式1つで全部求められます。
ピアノなどで使われる「平均律」では、ラ(A4)を440Hzとして、半音上がるごとに周波数が2の12乗根倍(約1.0595倍)になります。つまり、12半音上がる(1オクターブ上がる)と、ちょうど2倍です。
ポイントをまとめるとこんな感じです👇
- 音に番号をつけて計算します(MIDIノート番号。真ん中のドC4が60、ラA4が69)
- 周波数 = 440 × 2(番号 − 69) / 12
tone()の周波数は整数なので、四捨五入してArduinoの#define形式で出力します
# 平均律で音階の周波数を計算して、Arduino用の定数を出力する
NAMES = ["C", "CS", "D", "DS", "E", "F", "FS", "G", "GS", "A", "AS", "B"]
def note_freq(midi):
# A4(MIDI番号69)=440Hz を基準に、半音ごとに 2の12乗根 倍
return 440 * 2 ** ((midi - 69) / 12)
# C4(ド, MIDI 60)から C5(MIDI 72)まで
for midi in range(60, 73):
name = NAMES[midi % 12] + str(midi // 12 - 1)
f = note_freq(midi)
print(f"#define NOTE_{name:<4} {round(f):4d} // {f:.2f} Hz")

実行すると、C4(ド)からC5(1つ上のド)までの13音が出力されます。
A4がぴったり440、C5(523)がC4(262)のほぼ2倍になっているのが分かりますね。ここで出た値(262, 294, 330…)は、Arduino公式のサンプル「toneMelody」で使われている音階表と同じ値です。CS4のように「S」がついているのは、♯(シャープ)の音です。
楽譜テキストをArduinoの配列に変換する
周波数が分かっても、曲を1音ずつ配列に手で打ち込むのは大変ですし、打ち間違いも起きますよね。そこで、「音名:長さ」で書いた楽譜テキストを、Arduinoにそのまま貼れる配列に変換するスクリプトを作ります。
ここが重要です👇
C4:4は「ドの4分音符」、C4:2は「ドの2分音符」。数字が大きいほど短い音です- 休符は
R:4のように書くと、周波数0(鳴らさない)に変換されます - 音名からMIDI番号を求め、さっきと同じ式で周波数にしています
# 「音名:長さ」の楽譜テキストを、Arduinoの配列に変換する
SCORE = """
C4:4 D4:4 E4:4 F4:4 E4:4 D4:4 C4:2
E4:4 F4:4 G4:4 A4:4 G4:4 F4:4 E4:2
"""
# 長さ: 4 = 4分音符、2 = 2分音符、8 = 8分音符(数字が大きいほど短い)
# 休符は R:4 のように書く
NAMES = ["C", "CS", "D", "DS", "E", "F", "FS", "G", "GS", "A", "AS", "B"]
def to_midi(note):
name, octave = note[:-1], int(note[-1])
return NAMES.index(name) + (octave + 1) * 12
notes, durations = [], []
for token in SCORE.split():
note, length = token.split(":")
if note == "R":
notes.append("0") # 0 は休符として扱う
else:
f = 440 * 2 ** ((to_midi(note) - 69) / 12)
notes.append(str(round(f)))
durations.append(length)
print(f"// {len(notes)}音")
print("int melody[] = {" + ", ".join(notes) + "};")
print("int durations[] = {" + ", ".join(durations) + "};")

「かえるのうた」の前半(ドレミファミレド ミファソラソファミ)を変換すると、次のような配列が出ます。
あとはこの2行をコピーして、Arduinoのスケッチに貼り付けるだけです。別の曲にしたいときは、SCOREの中身を書き換えて実行し直してください😊
Arduinoでメロディを鳴らすスケッチ
いよいよArduino側です。先ほど出力した配列を貼り付けて、1音ずつtone()で鳴らします。
// 圧電ブザー(パッシブ)で「かえるのうた」を鳴らす
const int BUZZER_PIN = 8; // ブザーの+側をつなぐピン
const int WHOLE = 1600; // 全音符の長さ(ミリ秒)。小さくするとテンポが速くなる
// melody_to_arduino.py の出力をそのまま貼り付け
int melody[] = {262, 294, 330, 349, 330, 294, 262, 330, 349, 392, 440, 392, 349, 330};
int durations[] = {4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 2};
const int NOTE_COUNT = sizeof(melody) / sizeof(melody[0]); // 音の数を自動で数える
void playMelody() {
for (int i = 0; i < NOTE_COUNT; i++) {
int noteLength = WHOLE / durations[i]; // 4分音符なら 1600 / 4 = 400ミリ秒
if (melody[i] > 0) {
tone(BUZZER_PIN, melody[i], noteLength); // 鳴らし始めたら、すぐ次の行へ進む
}
// ここが重要:tone() は待ってくれないので、自分で待つ
// 音の長さの1.3倍待つと、音と音の間にすき間ができて聞き取りやすい
delay(noteLength * 1.3);
noTone(BUZZER_PIN);
}
}
void setup() {
playMelody(); // 電源を入れたら1回だけ演奏
}
void loop() {
// 何もしない(くり返したいときは playMelody(); と delay(2000); をここに書く)
}
ポイントをまとめるとこんな感じです👇
WHOLE / durations[i]で音の長さを計算します。4分音符なら1600÷4=400ミリ秒sizeof(melody) / sizeof(melody[0])で、配列に入っている音の数を自動で数えています。曲を差し替えても書き直し不要です- テンポを速くしたいときは
WHOLEを小さく(例:1200)します - 書き込みが終わると、リセット直後に1回だけ演奏されます
実機で動かしたときの動き(表示例)としては、ドレミファミレド~とメロディが流れ、最後の「ミ」を長めに鳴らして止まります。
なぜ delay() が必要なの?
これ、実行せずに答えられますか? 上のスケッチからdelay(noteLength * 1.3);の行を消すと、どうなるでしょう?
答えは、メロディにならず、ほぼ最後の音だけが鳴ったように聞こえるです。
公式リファレンスにもあるとおり、tone()はノンブロッキング(鳴らし始めたら終わるのを待たずに、すぐ次の行へ進む)関数です。長さを指定していても待ってはくれません。同じピンで鳴っている間に次のtone()を呼ぶと、周波数がすぐに上書きされます。つまり、delayがないとforループが一瞬で最後まで回り、14音が次々と上書きされてしまうんですね。
だから、音の長さぶんは自分で待つ必要があります。1.3倍にしているのは、音と音の間に少しすき間をつくるため。ぴったり1.0倍にすると、同じ音が続くところ(たとえば「ソソソ」)が1つの長い音につながって聞こえてしまいます。
うまく鳴らないときのチェックリスト
- 「ピー」という同じ音しか鳴らない→アクティブブザーの可能性大。パッシブブザーに交換しましょう
- まったく鳴らない→+と-の向き、ピン番号(スケッチは8番)を確認
- 音が小さい・ガサガサする→圧電ブザーは周波数によって音量が変わります。オクターブを上げる(C5〜)と聞こえやすくなることがあります
- LEDの明るさ調整がおかしくなった→ピン3・11のPWMとtone()がぶつかっています。LEDを別のPWMピン(5・6・9・10など)に移しましょう
まとめ
- メロディを鳴らすならパッシブブザー。アクティブブザーは決まった音しか出ない
tone(ピン, 周波数, 長さ)で音を鳴らし、noTone()で止める- 音階の周波数は「440 × 2(番号−69)/12」で計算できる。Pythonで表や配列を作ると打ち間違いがない
tone()は待ってくれないので、delay()で音の長さぶん待つのがコツ- 同時に鳴らせるのは1音だけ、ピン3・11のPWMに影響する、31Hz未満は出せない
ブザー1つでも、音が鳴ると電子工作が一気に楽しくなりますよね。ボタンを押したら効果音を鳴らす、温度が上がったらアラームを鳴らす…と応用も広がります。好きな曲の楽譜をSCOREに書いて、ぜひ試してみてください🚀
こちらも読まれています
📡 Arduinoをもっと深く学ぼう!
Arduino・ラズパイ・ロボットプログラミングを体系的に学びたい方へ。おすすめのUdemyコースや電子部品もまとめています。
Arduinoロボット入門のおすすめコース・部品を見る →📚 関連商品・おすすめ書籍
※本記事にはアフィリエイトリンクが含まれます。




