「Arduinoでブザーを鳴らせたけど、ピーッて鳴るだけ…」「メロディを鳴らしたいのに、音がつながって変な音になる」

電子工作を始めて、LEDの次にやってみたくなるのが「音」ですよね。ブザーは数十円〜100円ほどの部品ですが、tone()関数を使うと、ドレミの音階でちゃんとメロディが鳴らせます🎵

この記事では、圧電ブザー(パッシブブザー)で「かえるのうた」を鳴らすところまで作ります。難易度はArduino入門〜初級。LチカができればOKです。

さらに、ドレミの周波数を手で調べなくて済むように、Pythonで「音階→周波数」の表を計算し、楽譜テキストをArduinoの配列に変換する小さなツールも作ります。一緒に見ていきましょう!

まず確認:ブザーには「アクティブ」と「パッシブ」がある

arduino piezo buzzer breadboard
arduino piezo buzzer breadboard / Photo by Chengxin Zhao via Pexels

ここでつまずく人がとても多いので、最初に確認しておきます⚠️

種類 中身 鳴らし方 メロディ
アクティブブザー 発振回路入り 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の音階と周波数
実行結果:C4〜C5の音階と周波数

実行すると、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) + "};")
実行結果:かえるのうたをArduinoの配列に変換
実行結果:かえるのうたをArduinoの配列に変換

「かえるのうた」の前半(ドレミファミレド ミファソラソファミ)を変換すると、次のような配列が出ます。

あとはこの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ロボット入門のおすすめコース・部品を見る →

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る
Arduinoをはじめよう 第4版 (Make: PROJECTS)

もしも

Arduinoをはじめよう 第4版 (Make: PROJECTS)

Arduino公式推薦の定番入門書

Amazonで見る
徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

もしも

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

電子工作とプログラミングを同時に学べる

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。