Arduinoで音を出す

Arduino
DSC_0882

今回は、本体に発音デバイスが搭載されていないArduinoで、音を鳴らしてみます。

※今回の回路およびプログラムは、Arduino UNO R3・R4の両方に対応しています。

Arduinoで音を出す

Arduinoで音を出す方法

Arduinoのボード上には音を出す部品が付いていません。よって、音を出すためには何らかの部品を外付けする必要があります。音を出す方法には、

①モーターやサーボなどをArduinoで制御して、楽器を操作する
②通電すると音が出るようなデバイスを接続する
③スピーカーを接続してArduinoで音声信号を発生する

などの方法が考えられます。

①はなかなか魅力的です。が、装置が複雑になりそうなので次の機会に…(いつかやりますが)。

②には単音の電子ブザーやオルゴールICなどがあります。Arduinoは開始の信号を送るだけでよいので回路もソフトウェアも単純なもので可能です。電流量の問題が発生した場合は、モータードライバーのような外付け回路が必要になるかも知れません。

③はスピーカーを接続し、音声信号自体はArduinoでソフトウェア的に生成する、というものです。回路は簡単ですが、ソフトウェア次第で出す音の自由度は最も高そうです。

というわけで、今回はArduinoにスピーカーを接続して、ソフトウェアで音声信号を生成することに挑戦します。

圧電スピーカー

今回は、Arduinoに圧電スピーカーと呼ばれる素子を接続します。

概要

圧電スピーカーはスピーカーの一種です。電圧をかけると変形する性質を持った『圧電体』を内蔵していて、電気的な音声信号を入力するとその圧電体の変形によって周囲の空気を振動させ、音を発することが出来ます。

特徴は以下の通りです。

・オーディオ用などで一般的な『ダイナミック・スピーカー』に較べて電力消費が少ないです。電流量だけでいうなら、Arduinoなどのマイコンの出力端子に直接接続することが可能です。ただし圧電体は機械的な刺激を加えると起電力を発生するため、Arduino側の保護のために電流制限抵抗を挿入したり、逆起電力が発生したときのためにダイオードを挿入する方が安全です。

・一般的に周波数特性(≒音質)が悪く、音楽鑑賞用には向きません。

・構造が単純で接点など機械的に摩耗する部分がないため、故障が少なく長寿命です。

製品名・呼称

圧電スピーカーは、別名『圧電サウンダー』『ピエゾ(piezoelectric)スピーカー』などとも呼ばれます。また、実態は圧電スピーカーなのに『圧電ブザー』『パッシブブザー』と非常に紛らわしい呼び方の製品もあります。よく確認した方がいいでしょう。

圧電スピーカーとよく似たものに『クリスタルスピーカー』があります。1980年代ころまでは安価な圧電素子としてロッシェル塩の結晶がよく使われていたことからこの名が付いたのですが、ロッシェル塩は湿気で劣化しやすいため現在はほとんど使われていません。新たに入手するのは困難ですが(もし中古品として入手できてもちゃんと動くか怪しいですが)、古い書籍を見るとよく名前が出てきますので参考まで。

外観

圧電スピーカーは非常に小型の製品が多いです。上の写真の製品は直径12mm・高さ8mmの樹脂製の円筒形で、上面には小さな穴が開き、下面からは2本の端子が生えています。この製品では上面『+』の表記がありますので、配線の際には『+』側をArduinoの出力端子に接続します。

このほか、形状が平たい円板上のものや、ピン端子ではなくリード線になっているものなどがあります。

回路記号

スピーカーは回路図ではこのような記号で表します。

旧記号では、圧電スピーカー(クリスタルスピーカー)とダイナミックスピーカーで記号が違っていて、

圧電スピーカー(クリスタルスピーカー)はこの記号

ダイナミックスピーカーはこの記号です。古い書籍を読むときの参考まで。

制作&実験

使用部品

今回使用した部品は以下の通りです。

種別型番数量備考参考単価
圧電スピーカー不明130円~
ジャンパー線2圧電スピーカーがピン端子タイプのため、メス~オスのもの
赤×1本、黒×1本

回路

小型の圧電スピーカーなら、このようにArduinoに直結…一方の端子をArduinoの出力端子(この例ではD2)に、もう一方の端子をGNDに接続するだけでOKです。

圧電スピーカーには極性がないものが多いのですが、+/-が表記されていたりリード線が赤黒だったりした場合は『+』側(赤黒だったら赤い線)をArduinoの出力端子に・『ー』側(赤黒だったら黒い線)をGNDに接続します。

圧電スピーカーの種類によっては、このように電流制限抵抗(この例では1kΩ)を経由してArduinoの適当な出力端子に接続した方がよいかも知れません。さらに、赤で描いたダイオードを挿入すると逆起電力が発生した際にArduinoを保護することが出来ます。

配線

今回使用する圧電ブザーはArduinoに直結可能なものなので、このように最小限の構成です。配線は、回路図の項でも書いたとおり、スピーカーの2つの端子をそれぞれArduinoの出力端子とGNDに接続するだけです。

実際の配線がこちら。圧電スピーカーがピン端子、しかも端子間隔がICピッチではなくブレッドボードに刺さらないので、メス~オスのリード線で配線しています。

例1:digitalWrite()で音声信号を作る

まず、音声専用の関数を使わず、直接出力端子を制御して音声信号を生成します。

スケッチ

C++
#define SPPIN 2

void setup() {
  pinMode(SPPIN, OUTPUT);
}

void loop() {
  digitalWrite(SPPIN, HIGH);
  delayMicroseconds(1132);
  digitalWrite(SPPIN, LOW);
  delayMicroseconds(1132);
}

プログラム解説

定数の設定
C++
#define SPPIN 2

今回スピーカーを接続した端子の番号を定数SPPINとして定義しています。

初期設定
C++
void setup() {
  pinMode(SPPIN, OUTPUT);
}

setup()関数の中では、pinMode()関数を使ってスピーカーを接続した端子を出力に設定しています。

出力のHIGH・LOWを一定周期で切り替える
C++
void loop() {
  digitalWrite(SPPIN, HIGH);
  delayMicroseconds(1132);
  digitalWrite(SPPIN, LOW);
  delayMicroseconds(1132);
}

今回は、圧電スピーカーにHIGH・LOWのパルスを連続して送ることで音を鳴らします。1秒間に何個のパルスを送るか、を『周波数』といい、これが音の高さを決めます。

今回はまず『オーケストラのチューニング』や『ラジオの時報の音』に使われている『A4(ピアノの鍵盤の中央のドの右側にある最初のラ)』の音を鳴らしてみます。周波数で言うと440Hz(『Hz』は周波数の単位で『ヘルツ』と読みます)、つまり1秒間に440個のパルスを送ることになります。

プログラムで生成されるパルスのイメージは下図の通りです。これは正確な波形を表しているわけではありません。信号の立ち上がり・立ち下がりを『関数の実行時間のあいだ直線的に増減する』と表現してしまいましたが、実際には『その区間のどこかで垂直に立ち上がり・立ち下がり』になっている方が正しい気もします(オシロ欲しい)。

このプログラムでは、digitalWrite()関数を使ってHIGH・LOWを切り替え、その度にdelayMicroseconds()関数で指定時間待ちます。これがパルスの山や谷の幅になります。440Hzにするためには、周期(パルスのHIGH・LOW1回分の時間)は1÷440≒0.0022723秒=2272.3μ秒です。HIGHとLOWの時間はその半分ずつで、それぞれ2272.3÷2≒1136μ秒となります。

digitalWrite()関数自体の実行に約4μ秒かかるらしいので、delayMicroseconds()関数に与える引数は1136-4=1132とすればよさそうです。

実行結果

手元に周波数カウンタがないのでWebで公開されているオシレータとの聞き比べですが、440Hzよりちょっと低くて438Hzくらいになってしまいました。周波数が低いということはどこか想定より時間がかかっている箇所があるのですが、今回はそこには深く突っ込まないことにします。

まぁ次の例で挙げるとおり実際には専用の関数を使った方がはるかに簡単なので、この例はあくまで『マイコンで任意の高さの音を出すにはどうするか』という原理を確かめるだけの実験です。

例2:tone()関数を使う

実はArduinoには、任意の周波数の音を出すための関数が用意されています。今度はこの関数を使ってみましょう。回路は例1と同じものを使います。

スケッチ

C++
#define SPPIN 2

void setup() {
  pinMode(SPPIN, OUTPUT);
}

void loop() {
  tone(SPPIN, 440);
  delay(500);
  tone(SPPIN, 880);
  delay(500);
  noTone(SPPIN);
  delay(1000);
}

プログラム解説

tone()関数で音を出す
C++
void loop() {
  tone(SPPIN, 440);
  delay(500);
  tone(SPPIN, 880);
  delay(500);
  noTone(SPPIN);
  delay(1000);
}

この例では、digitalWrite()で直接出力ピンのHIGH/LOWを切り替えるのではなく、tone()関数を使って指定の周波数のパルスを発生させています。

書式
C++
void tone(int pin, int frequency  [, int duration])
引数
引数意味
pinint出力ピン番号
frequencyint出力する音声信号の周波数(Hz)
durationint音声信号の出力継続時間(ms)。省略可。
動作

pinで指定した出力ピンから、周波数frequency [Hz] の音声信号を、duration [ms] の間出力します。

以下の2点に注意が必要です。

・durationを省略した場合は、音が鳴りっぱなしになります。
・第3引数を指定してもtone()関数は音の継続時間だけ処理を待つことをせず、実行後すぐに次の命令に移ります。

この例では、2つのtone()関数はそれぞれ440Hz(A4)と880Hz(A5)の音を出力しています。

tone()関数で出した音を必要な長さだけ保つ
C++
void loop() {
  tone(SPPIN, 440);
  delay(500);
  tone(SPPIN, 880);
  delay(500);
  noTone(SPPIN);
  delay(1000);
}

tone()関数はすぐに処理を終えてしまうので、音を出したい長さだけ待つ必要があります。この例ではdelay()関数を用いて、音を出した後500msだけその音を保つようにしています。

noTone()関数で音を止める
C++
void loop() {
  tone(SPPIN, 440);
  delay(500);
  tone(SPPIN, 880);
  delay(500);
  noTone(SPPIN);
  delay(1000);
}

noTone()関数は、現在出力されている音声信号の出力を停止します。

書式
C++
void noTone(int pin)
引数
名前意味
pinint音声信号の出力を停止するピン番号
動作

pinで指定した出力ピンの音声信号出力を停止します。

音が止まった状態で一定時間待つ
C++
void loop() {
  tone(SPPIN, 440);
  delay(500);
  tone(SPPIN, 880);
  delay(500);
  noTone(SPPIN);
  delay(1000);
}

noTone()関数で音声信号の出力を停止した後、delay()関数で1000msその状態を保っています。

実行結果

このように、440Hz(A4)を500ms → 880Hz(A5)を500ms → 無音を1000ms のループを繰り返します。

間違った例

tone()関数の第3引数が『音声信号の出力継続時間』であったことから、やりがちな間違いを示します。

C++
#define SPPIN 2

void setup() {
  pinMode(SPPIN, OUTPUT);
}

void loop() {
  tone(SPPIN, 440, 500);
  tone(SPPIN, 880, 500);
  delay(1000);
}

このスケッチは、一見『440Hzの音を500ms、880Hzの音を500ms、その後1000ms休む』、つまり先ほどの例と同じ動作をするように思えますが、実は意図とはまったく違う動作をします。

880Hzの音が500ms → 無音500ms の繰り返しとなってしまっています。

これは、tone()関数が『第3引数の指定にかかわらず、音を出したらすぐに関数自体の実行は終了して、次の命令に移ってしまう』ためです。つまりこのプログラムでは、

tone(SPPIN,440,500); により440Hzの音を出す
・が、実際にその音が出る間もないうちに tone(SPPIN,880,500); により880Hzの音を出す
・880Hzの音は500ms持続するが、880Hzの音が出た直後から delay(1000); による1000msのカウントも始まっている
・500ms後に880Hzの音の出力は停止するが、delay(1000); のカウントは既に500ms進んでいるので、無音の時間は残りの500msになる

となってしまうのです。第3引数の指定にかかわらず、tone()関数は音を出し始めたらただちに終了してしまうことに注意してください。

まとめ

・Arduinoに圧電ブザーを接続し、出力をHIGH・LOW交互に一定間隔で切り替えると音を鳴らすことが出来る。
・tone()関数を使えば、簡単に任意の周波数の音を出すことができる

コメント

タイトルとURLをコピーしました