こんにちは、「メカのりまき」です。

この記事では、ELEGOO Uno R3(Arduino Uno R3の互換機)、パッシブブザー、ジョイスティック(5ポジションスイッチ)DIP化キットを使って、楽器を作りたいと思います。

本記事で使用するもの

本記事で私が使用した物は以下の通りです。

  • 「Arduino IDE2.3.6」をインストールしたPC(Windows11)
  • ELEGOO UNO R3(Arduino Uno R3でも可)
  • USBケーブル(A-B)
  • パッシブブザー
  • ジョイスティック(5ポジションスイッチ)DIP化キット
  • ブレッドボード
  • ジャンパーワイヤー

今回使用した物は、記事の最後のほうにある参考、広告のところで紹介しています。

記事を見て、気になるものがあれば、是非チェックをしてみてください。

ジョイスティック(5ポジションスイッチ)DIP化キット

今回の記事では、秋月電子通商で購入したジョイスティック(5ポジションスイッチ)DIP化キットを使って、楽器の製作をしたいと思います。

ジョイスティック(5ポジションスイッチ)DIP化キットは、「SKRHAAE010」という4方向+センタープッシュのスイッチをブレッドボードやユニバーサル基板で使いやすいようDIP化したモジュールです。

ジョイスティック(5ポジションスイッチ)DIP化キット

スティックを倒したとき、押し込んだときの出力は以下のような感じになります。

ジョイスティック(5ポジションスイッチ)DIP化キットの出力

モジュールはプルアップ回路になっているため、それぞれ、スイッチがOFFになっているとき対応するピンが「HIGH」になり、スイッチがONになっているとき対応するピンが「LOW」になります。

スティックを押し込みながら、スティックを倒した場合は、SWと倒した方向に対応するピンの2つが「LOW」になります。

斜めには倒すことができないため、方向に対応するピンを同時に「LOW」にすることはできません。

スティックの部分は何も付けずに操作することも可能ですが、スティックが小さく、長時間操作していると指が痛くなるため、今回は以下のようなキャップを3Dプリンタで製作して取り付けています。

ジョイスティック(5ポジションスイッチ)DIP化キットにつけるキャップ

楽器の製作

では、先に挙げた動画のように、スティックの操作により、ブザーから音を鳴らす楽器を作りたいと思います。

ここで、スティックの操作とブザーで鳴らす音の関係は、以下のようにしたいと思います。

スティックの操作と音の関係

なお、上記のような音の配置にした理由は、コードを構成する音ごとに配置をまとめることで、アルペジオ(コードを構成する音を順番に弾くこと)がやり易くなると思ったからです。

スティックの操作とコードの関係

空のスケッチを書き込む

回路を作成する前に、空のスケッチ(「ファイル」タブの「New Sketch」をクリックしたときに出てくる何の処理も書かれていないスケッチ)を書き込みます。

空のスケッチを書き込む

そうすることにより、前に書き込んだスケッチが、新しく作成しようとしている回路に影響を及ぼすことを防げます。

新しい回路を作成するときは、いつもこの作業をやっておくと、安全に回路を作成することができます。

回路を作成する

以下のような回路を作成します。

回路

スケッチを書き込む

回路の作成が終わりましたら、以下のようなスケッチを書き込みます。

スケッチの解説

定数と変数の宣言

まず、ブザーに繋がっているピンを、「BUZZER_PIN」という変数に格納しています。

ブザーで鳴らす音の振動数は、「BUZZER_TONES」という配列でまとめています。

配列には、音の振動数を、低い音から順番に初期値として格納しています。

BUZZER_TONES[]

参考までに、ピアノの音階と振動数の関係(小数点以下を四捨五入した場合)を以下の表に示します。

音階名   1 2 3 4 5 6 7
33 65 131 262 523 1047 2093
ド# 35 69 139 277 554 1109 2217
37 73 147 294 587 1175 2349
レ# 39 78 156 311 622 1245 2489
41 82 165 330 659 1319 2637
ファ 44 87 175 349 698 1397 2794
ファ# 46 92 185 370 740 1480 2960
49 98 196 392 784 1568 3136
ソ# 52 104 208 415 831 1661 3322
55 110 220 440 880 1760 3520
ラ# 58 117 233 466 932 1865 3729
62 123 247 494 988 1976 3951

ジョイスティック(5ポジションスイッチ)DIP化キットに繋がっているピンの番号は「SWITCH_PINS」という配列でまとめています。

配列は、ジョイスティック(5ポジションスイッチ)DIP化キットに繋がっているピンの番号を、音の配置に対応するように、初期値として格納しています。

SWITCH_PINS[]

「SWITCH_PINS」を宣言した後、スイッチの数を入れるための定数「NUMBER_OF_SWITCHES」を宣言しています。

配列「SWITCH_PINS」の要素数とスイッチの数は同じであるため、配列の要素数を「sizeof()」という関数を使って計算し「NUMBER_OF_SWITCHES」に格納しています。

「sizeof()」関数は、( )内に記述したデータのサイズをバイト単位で返します。

例えば今回の場合、「sizeof(SWITCH_PINS[0])」は、uint8_t型の変数1個分のサイズである「1」という数値を返し、「sizeof(SWITCH_PINS)」は型の変数10個分のサイズである「10」という値を返します。

sizeof(SWITCH_PINS)/siseof(SWITCH_PINS[0]

sizeof(SWITCH_PINS) / sizeof(SWITCH_PINS[0])は、配列全体のサイズを配列のデータ1個分のサイズで割ることになるので、配列にいくつの要素が入っているか計算することができます。

ピンの設定

void setup()では、初めにブザーに繋がっているピンを出力ピンとして設定した後、配列「BUZZER_TONES」の要素数と変数「NUMBER_OF_SWITCHES」を比べ条件分岐を行っています。

「BUZZER_TONES」の要素数は、「NUMBER_OF_SWITCHES」のときと同様にsizeofを利用して計算しています。

sizeof(BUZZER_TONES)/siseof(BUZZER_TONES[0]

上記の計算によって求めた配列「BUZZER_TONES」の要素数と定数「NUMBER_OF_SWITCHES」の値が一致していない場合、配列「BUZZER_TONES」と配列「SWITCH_PINS」の要素数が異なってしまい、おかしな動作になる可能性があるため、tone()関数によってエラーを知らせる音(ブブーという音)を鳴らした後、while文によって以降の処理が実行されないようにしています。

ここで、tone()関数の第3引数は、出力の切り替えを行う時間([ms]単位)、つまり、音を鳴らしている時間の長さです。

また、while()文というのは、( )内がtrueの場合、{ }内の処理を繰り返し行う文です。

今回は、( )内にtrueを入れているため、ずっと繰り返しの処理が行われます。

そして、今回繰り返しの処理は、空になっており、何も行わないという処理を繰り返すことになります。

配列「BUZZER_TONES」の要素数と定数「NUMBER_OF_SWITCHES」の値が一致している場合は、特に問題は無いためfor文を用いて、配列「SWITCH_PINS」にまとめた番号のピンをすべて入力ピンとして設定しています。

ピンを設定するfor文

スティックの操作に応じて音を鳴らす部分

スイッチが同時にONになっている状態のとき、最後にONになっているスイッチに対応した音が鳴るように工夫をしています。

スイッチが同時にONになったとき

今回のスケッチでは、スイッチがONになるのを確認して、すぐに音を鳴らすのではなく、まず、スイッチがどの順番でONになっているのかを記録して、その後、最後にONになっているスイッチに対応した音を鳴らすといったスケッチを記述しています。

まず、スイッチがどの順番でONになっているのかを記録する部分は、for文によって、全てのスイッチの状態を確認し、それらの状態を、配列「switchStates」、変数「pressedSwitchCount」にまとめています。

配列「switchStates」、変数「pressedSwitchCount」を宣言する際、「static」という型修飾子を付けています。

通常void loop内で変数を宣言した場合、void loopの最後に変数は消されるため、ループのたびに、変数を宣言し直します。

しかし、「static」を付けて宣言している場合、void loopの最後に変数は消されず、ループのたびに、変数を宣言し直すことはありません。

配列の要素「SWITCH_PINS[i]」に割り当てたスイッチがONになっていて、配列の要素「switchStates[i]」の値が0の状態だった場合は、変数「pressedSwitchCount」の値を1増やして、配列の要素「switchStates[i]」に変数「pressedSwitchCount」の値を格納します。

スイッチがONになったときの処理

配列の要素「switchStates[i]」には、変数「pressedSwitchCount」の値が入り、0ではなくなるため、スイッチがONになっている間、ループによって何度もif文の中身が実行されることはありません。

配列の要素「SWITCH_PINS[i]」に割り当てたスイッチがOFFになっていて、配列の要素「switchStates[i]」の値が0以外の場合は、変数「pressedSwitchCount」の値を1減らしたあと、for文により、配列「switchStates」に格納されている値の中で、配列の要素「switchStates[i]」よりも大きい数値の値を1減らし、その後、配列の要素「switchStates[i]」の値を0にします。

スイッチがOFFになったときの処理

上記の処理中、変数「pressedSwitchCount」の値と配列「switchStates」の中で最も大きい数は一致します。

よって、配列「switchStates」の中で、変数「pressedSwitchCount」の値と一致する要素を探せば、最後にONになったスイッチに繋がっているピンが分かります。

最後にONになったスイッチを探す方法

音を鳴らす部分については、まず、変数「pressedSwitchCount」が0の場合は、スイッチが1つもONになっていない状態なので、「notone(BUZZER_PIN)」により音を消しています。

それ以外の場合は、for文で変数「pressedSwitchCount」の値と一致する配列の要素「switchStates[i]」を探し、配列の要素「BUZZER_TONES[i]」に割り当てた音を鳴らしています。

最後にONになったスイッチに割り当てた音を鳴らす

終わりに

今回は、ELEGOO Uno R3(Arduino Uno R3の互換機)、パッシブブザー、ジョイスティック(5ポジションスイッチ)DIP化キットを使って楽器を製作しました。

もともと、別の用途で、「SKRHAAE010」を使ってみたいと思い、お試し用に、ジョイスティック(5ポジションスイッチ)DIP化キットを購入しましたが、これを使えば、スティックをグリグリ動かすだけで、良い感じに演奏できる楽器が作れるのではと、ふと思ったので実験をしてみました。

今回は、ブレッドボードで楽器を製作しましたが、ゲームコントローラのような形にすれば、持ちやすそうですし、他の指を使った操作も可能そうなので良いのではないかと思いました。

3Dプリンタで作ったスティックのキャップ部分は、まだまだ、改善の余地がありそうです。

大分先になりそうですが、そのうち気が向いたら、今回の実験を活かして、ゲームコントローラのような形をした楽器を作ってみたいなと思います。

本記事はここまでです。

ご清覧ありがとうございました。

参考

ジョイスティック(5ポジションスイッチ)DIP化キットは、秋月電子通商にて購入しました。

「ジョイスティック(5ポジションスイッチ)DIP化キット」の販売コードは115233です。

ピアノの音階と振動数の関係は、以下のサイトを参考にさせていただきました。

広告

Arduinoの互換機と電子部品が入ったスターターキットです。

これからArduinoを始めるという方におすすめのキットで、ELEGOO UNO R3、ブザー、ブレッドボード、長いジャンパーワイヤー、USBケーブル(A-B)はこの中に入っていたものを使用しました。

他にも、モータや超音波センサなど、様々な部品が入っていてお得なので、是非、購入を検討してみてください。

私が購入したのは、ブレッドボードとジャンパーワイヤーのみのセットだったのですが、投稿時(2025/11/04)に、それは売られていないようだったので、同じメーカーのブレッドボードとジャンパーワイヤーと電源モジュールがセットになったものを広告させていただきます。

今回はジャンパーワイヤーのみ使用しました。

楽天モーションウィジェットとGoogleアドセンス広告です。

気になる商品がございましたら、チェックをしてみてください。