今回は音の仕組みと圧電スピーカーの仕組みを理解して、Arduinoで音を鳴らしてみます。
音の仕組み
いよいよキッチンタイマーらしく、時間になったらアラーム音が鳴るようにプログラミングしていきます。
といきたいところですが、その前に音の仕組みと圧電スピーカーの仕組みを理解してからプログラミングすることにしましょう!
「音」の仕組みや性質は小学校で習ったと思いますが、簡単に復習しておきましょう。
「音」の正体は空気の振動でしたよね。何かが振動すると、その振動が空気を伝わって耳まで届いて音を感じます。
空気を振動させて音を発生させるものはたくさんありますが、その中でもスピーカーはよく見かけます。スピーカーは製品の中に入っていてスピーカーそのものを見る機会はなかなかないかもしれません。スピーカー本体はこのようになっています。
スピーカーの黒い部分は紙などでできていて、電気信号を加えるとこの部分が振動して音が発生します。
スピーカーから出る音の高さ(音程)は、紙の部分が1秒間に何回振動するかで決まります。
例えば、1秒間に262回振動すると「ド」の音に聴こえます。また、振動する回数が多くなると高い音が、回数が少なくなると低い音が出ます。
上の画像のようなスピーカーは紙の部分が振動して音が発生しますが、今回使用する圧電スピーカーはどのようになっているのか、その仕組みを確認しておきましょう。
圧電スピーカーの仕組み
圧電スピーカーは、次のように「圧電セラミック」という物質と金属を貼り合わせた部品です。
「セラミック」という言葉が出てきますが、この「セラミック」を使った製品は多く見かけますよね。例えばセラミック包丁とか、身近な製品でも使われています。
「圧電セラミック」は「セラミック」に高電圧をかけて電気的な処理をした物質で、不思議な性質があります。
この「圧電セラミック」に電圧をかけると、電圧をかける向きによって伸びたり縮んだりするんです。
先ほどのように圧電セラミックと金属を貼り合わせたものに電圧をかけると、圧電セラミックは伸びるのですが、金属は変化がないため、次のように部品全体が曲がります。
電池の向きを逆にすると、圧電セラミックだけ縮んで次のように曲がります。
圧電スピーカーは加える電圧によってこのように変形します。
この変形する性質を使って空気を振動させると音が発生する、という仕組みです。
例えば1秒間に262回振動するように圧電スピーカーに加える電圧を制御すると、「ド」の音が出るわけです。
圧電スピーカーは普通のスピーカーとして使えるのか?
圧電スピーカーは、電気信号を空気の振動に変換する部品で、普通のスピーカーとやっていることは同じです。
ということは、圧電スピーカーは普通のスピーカーとして使えるのでしょうか?
手元にMP3プレーヤーがあったので実験してみました。次の画像は、MP3プレーヤーに今回使用する圧電スピーカーを接続したブレッドボード回路です。
MP3プレーヤーに効果音や普通の音楽を入れて再生してみると、普通のスピーカーのように音楽が聞こえます。
ただ、普通のスピーカーにくらべて音量は小さく、音質もあまりよくないです。手元にスピーカーがないけど、音を確認したい場合などには使えそうです。
圧電スピーカーの概要はわかったところで、前回製作したスピーカーを接続した回路でスケッチを作成して音を鳴らしてみましょう。
Arduinoで音を鳴らす仕組み
それでは、Arduinoでスケッチを作成して「ド」の音を鳴らしてみましょう。
前回の記事で、圧電スピーカーをA0端子に接続しました。先ほどの圧電スピーカーの仕組みを説明した時の図を使用すると以下のように接続されています。

A0端子のスイッチをOFF、つまりdigitalWrite(A0 LOW);
にしている状態では、圧電スピーカーは普通の状態です。
このA0端子のスイッチをONにする、つまりdigitalWrite(18, HIGH);にすると、圧電スピーカーは次のように変形します。

これを繰り返せば圧電スピーカーが振動して音が発生するわけです。
それでは「ド」の音を出すにはどうすればよいか一緒に考えていきましょう!
Arduinoで「ド」の音を鳴らす
「ド」の音は、圧電スピーカーを1秒間に262回振動させればよいわけです。
つまり以下のようにArduinoのA0端子のスイッチをON/OFF制御すれば「ド」の音を出すことができます。
端子のスイッチを制御するにはdigitalWrite
を使えば実現できますよね。
あとは圧電スピーカーが1秒間に262回振動するように時間待ちをすればOKです。
指示の書き方としては次のようになります。

それでは、時間待ちのdelayのパラメータをいくつにすればよいか計算してみましょう。まずは次の部分を計算してみます。
delayの引数はミリ秒ですので、何ミリ秒になるか計算してみましょう。
上のパターンを1秒間、つまり1000msの間に262回繰り返せばいいわけですから、上の「?」の時間は、
1000ミリ秒 ÷ 262 = 3.81679…ミリ秒
とということで、約3.817ミリ秒になります。
ここでちょっと問題が発生してしまいました。
というのは、delayの引数は整数です。整数ということで四捨五入して4ミリ秒の指定delay(4);
としてしまった場合、これは「ド」の音程にならなくなってしまいます。
次のように4ミリ秒にした場合を考えてみます。
このパターンは1秒間に何回繰り返されるかというと、1回の振動が4ミリ秒ですので1000ミリ秒では、
1000 ÷ 4 = 250
ということで、1秒間に250回の振動になります。
振動が1秒間に250回の場合、「ド」の半音下ぐらいの音程になってしまいます。ということで、音階を再現するにはミリ秒の指定では精度が足りません。
そこで、Arduinoではdelay
よりさらに細かい待ち時間の指定ができる指示が用意されていますので、その内容を確認しましょう。
delay
のさらに1000分の1の精度で時間指定できる、delayMicroseconds
という指示があります。

マイクロ秒って普段あんまり耳にしませんよね。1秒 = 1,000ms(ミリ秒) = 1,000,000μs(マイクロ秒)です。
先ほどの図の1つの振動の時間をマイクロ秒にすると、1秒間、つまり1,000,000マイクロ秒で262回パターンを繰り返すわけですから、以下のように計算できます。
1000000 ÷ 262 = 3816.79…
約3817μs(マイクロ秒)になります。
ということで、マイクロ秒で以下のようにすれば圧電スピーカーは262回振動するはずです。
この制御を実際のArduinoの命令で考えると以下のようになります。

あとは上の指示を繰り返すスケッチを作ればいいのですが、スピーカーがずっと鳴っているとうるさいですよね。
そこで、3秒間「ド」の音を鳴らすようにスケッチを作成してみます。
今度は、3秒間「ド」の音を鳴らすために、上の図の1回分の振動を何回繰り返せばよいか計算する必要があります。(ドの音を3秒か鳴らすだけなのに、なんだか苦行になってきてしまいました…!)
「ド」の音は1秒間に262回振動するので3秒間では
262 x 3 = 786
ということで、786回繰り返せばOKです。
これで「ド」の音を圧電スピーカーで鳴らすための知識が一通り習得できましたのでスケッチにまとめてみましょう。
/*
* 圧電スピーカーのテスト
*
* 内容: 「ド」の音を鳴らす
* 変更履歴:
* 2019.10. 3: 新規作成
* 2024.12.12: 端子名をA0に変更
*/
// 圧電スピーカーの接続端子番号
#define PIN_SPEAKER A0
void setup() {
// 圧電スピーカー接続端子の設定
pinMode(PIN_SPEAKER, OUTPUT);
// 「ド」の音を3秒間鳴らす
for(uint16_t count=0; count<786; count++){
digitalWrite(PIN_SPEAKER, HIGH);
delayMicroseconds(1908);
digitalWrite(PIN_SPEAKER, LOW);
delayMicroseconds(1909);
}
}
void loop() {
// loopでは何もしない
}
こんなプログラミング、やってられませんよね?
今回は時間の計算に慣れていただくために、ずいぶんと面倒なスケッチを作成しました。(電子工作で何か制御するとき、こんな感じで面倒な時間を計算することもあるんです…!)
これから、キッチンタイマーのスケッチにアラーム音を追加しますが、こんなプログラミングは正直やってられませんよね。
ただ「ド」の音を出したいのに面倒な計算をしてスケッチを書くというのはやってられません。(計算自体はArduinoボードに任せてもいいですが、それでも計算式を考えるのは多変ですよね…!)
「最初から言ってよ」と言われそうですが、Arduinoでは特定の音程を出すための便利な命令があります。
そこで、次回のアラーム音追加では、その命名を習得してからアラーム音を追加します。
ミニチャレンジ課題
電子工作のプログラミングではいろいろな計算をすることが多いです。
そこで、時間の扱いに慣れるためにミニチャレンジをしてみましょう。(修行のようなチャレンジ課題になってしまっていますが…)
先ほどのスケッチは「ド」の音を3秒間鳴らす内容でしたが、今度は時報のアラームのような「ピッ、ピッ、ピッ、ピーッ」という音を鳴らしてみたいと思います。鳴らす時間は次のようにしてみます。
- 「ラ」の音を200ミリ秒鳴らす
- 800ミリ秒止める
- 「ラ」の音を200ミリ秒鳴らす
- 800ミリ秒止める
- 「ラ」の音を200ミリ秒鳴らす
- 800ミリ秒止める
- 1オクターブ高い「ラ」の音を1秒間鳴らす
「ラ」と1オクターブ高い「ラ」の1秒間の振動回数は次のようになります。
音程 | 1秒間の振動回数 |
ラ | 906回 |
1オクターブ高いラ | 1812回 |
ミニチャレンジ課題解答例
最初に「ラ」と「1オクターブ高いラ」の「ON/OFFの1回分の時間」をマイクロ秒でいくつになるか計算しておきましょう。
音程 | 1秒間の振動回数 | ON/OFF時間 | ON/OFF時間の計算式 |
ラ | 906回 | 1104マイクロ秒 | 1000000 ÷ 906 |
1オクターブ高いラ | 1812回 | 552マイクロ秒 | 1000000 ÷ 1812 |
例えば、「ラ」の音の1回分のON/OFFは次のようになります。
// 「ラ」の音程
// 1104マイクロ秒のうち、半分をON、半分をOFFにする
digitalWrite(A0, HIGH);
delayMicroseconds(552);
digitalWrite(A0, LOW);
delayMicroseconds(552);
次は、この「ラ」の1回分のパターンを何回繰り返せば200ミリ秒になるか計算が必要です。
1回分のパターンが1104マイクロ秒ですので、200ミリ秒では、
200000 ÷ 1104 = 181
ということで、181回繰り返せばOKです。つまり、「ラ」を200ミリ秒鳴らすには次のようなスケッチになります。
for(uint16_t i=0; i<181; i++) {
digitalWrite(A0, HIGH);
delayMicroseconds(552);
digitalWrite(A0, LOW);
delayMicroseconds(552);
}
同様に、「1オクターブ高いラ」は1回分のON/OFFは次のようなスケッチになります。
// 1オクターブ高いラの音程
// 552マイクロ秒のうち、半分をON、半分をOFFにする
digitalWrite(A0, HIGH);
delayMicroseconds(276);
digitalWrite(A0, LOW);
delayMicroseconds(276);
次は、この「1オクターブ高いラ」の1回分のパターンは1秒間鳴らしますので、必要な回数を計算します。
1000000 ÷ 552 = 1811回
ということで、最後の「ピーッ」のスケッチは次のようになります。
for(uint16_t i=0; i<1811; i++) {
digitalWrite(A0, HIGH);
delayMicroseconds(276);
digitalWrite(A0, LOW);
delayMicroseconds(276);
}
これまでの内容をまとめてスケッチ完成です。
/*
第30回 ミニチャレンジ課題解答例
*/
// 圧電スピーカーの接続端子番号
#define PIN_SPEAKER A0
void setup() {
// 圧電スピーカー接続端子の設定
pinMode(PIN_SPEAKER, OUTPUT);
// 「ピッ」1回分
// 最初に「ラ」を200ミリ秒鳴らす
for(uint16_t i=0; i<181; i++) {
digitalWrite(PIN_SPEAKER, HIGH);
delayMicroseconds(552);
digitalWrite(PIN_SPEAKER, LOW);
delayMicroseconds(552);
}
// 800ミリ秒止める
delay(800);
// 「ピッ」1回分
// 最初に「ラ」を200ミリ秒鳴らす
for(uint16_t i=0; i<181; i++) {
digitalWrite(PIN_SPEAKER, HIGH);
delayMicroseconds(552);
digitalWrite(PIN_SPEAKER, LOW);
delayMicroseconds(552);
}
// 800ミリ秒止める
delay(800);
// 「ピッ」1回分
// 最初に「ラ」を200ミリ秒鳴らす
for(uint16_t i=0; i<181; i++) {
digitalWrite(PIN_SPEAKER, HIGH);
delayMicroseconds(552);
digitalWrite(PIN_SPEAKER, LOW);
delayMicroseconds(552);
}
// 800ミリ秒止める
delay(800);
// 「ピーッ」
for(uint16_t i=0; i<1811; i++) {
digitalWrite(PIN_SPEAKER, HIGH);
delayMicroseconds(276);
digitalWrite(PIN_SPEAKER, LOW);
delayMicroseconds(276);
}
}
void loop() {
// loopでは何もしない
}
更新履歴
日付 | 内容 |
---|---|
2019.10.3 | 新規投稿 |
2021.8.26 | 新サイトデザイン対応 |
2024.12.12 | 端子名をA0に変更 ミニチャレンジ課題内容変更&解答例追加 |
こんにちは。最近Arduinoはじめたばかりで勉強させて頂いております。
電子工作&プログラム中々楽しいですw
えーと コピペ検証で22行でエラー出ました < にしたら受付てくれましたので
ご報告までかお
コメントどうもありがとうございます。
ご指摘どうもありがとうございました!
修正しようとしたのですが、なぜかうまく修正できませんでした…
ちょっと見た目が変ですが、これで正しく表示されていると思います。
このサイトはWordpressで作成しているのですが、ソースコードがシステムに勝手に書き換えられることもあるので、他のページでも同じような現象が出ているかもしれません。気付いたら修正いたします。
重ねて、ご指摘どうもありがとうございました!