公開日:2021/12/11
title.png

19th Season


#19-2 オルゴール化328duino

 328duinoを使って、オルゴールを作るのが今回のテーマです。

 328duinoとは、170タイポイントのミニブレッドボード上に構築する、Arduino UNO等に採用されているATmega328P-PUその物、と言っても過言でない程のMCUボードです(下図)。

ar95_328duino_1.jpgar95_328duino_2.jpg

 予め、以下の記事を参照して328duino(第二形態)の構築と、Arduino IDEへの組み込みを済ませてください。

  「#9-5 ブレッドボードにArduinoっぽい物

  「#9-9 328duinoをArduino IDEに組み込む

 準備が整ったら、先に進みましょう。

オルゴール

 小さな箱に入っていて、蓋を開けると突起の付いたドラムが回転、長さの異なる金属の板を弾くことで音楽を奏でる装置です。

  オルゴールを検索する(別ウインドウが開きます)

 今回は、Arduinoでオルゴールを作って行きます。

 「蓋を開ける」と言う動作は、何らかのスイッチなどを仕込んでおいて、蓋が開いたことを感知したら音楽を奏でる様にすることもできます。これ、言うは易しなのですが、やろうとすると意外と大変です。スイッチの位置や蓋との接点などをきっちりと作り込んでおかないと、うまく作動しません。

 そこで今回は、CdSセルで明るさを感知して音楽を奏でるような形にしたいと思います。

 CdSセル(下図)で周囲の明るさを判定することで、蓋の状態を検知して音楽を演奏します。

ar35_photor.jpg

演奏

 音楽の演奏は、「#5-8 MMLで音楽を奏でる」で作成したプログラム(play_mml.ino)のplay_mml()関数を応用して使います。
 本物のオルゴールはドラムの突起が金属の板を弾いて音を出すので、弾いた瞬間の音が大きくて、そのあと少し余韻を引くような感じの音、でしょうか?play_mml()関数では、「余韻」の部分を表現することはできませんが、以下の点においてオルゴールの音に近づけてみようと思います。

選曲

 「オルゴールと言えば、どんな曲?」と、思いを巡らせた結果、「エリーゼのために」を選曲しました。著作権は消滅していますが、楽譜には版権が付いている場合があるので、フリーの楽譜🎼を探してMML (Music Macro Language)を起こしました。
 作成したMMLは、完成プログラム(music_box.ino)で確認して下さい。

 MMLはASCII文字列で作成するので、1曲分となると、そこそこのサイズになります。Arduino UNOで大量の文字列定数を保持する場合、PROGMEMを使ってFlashメモリ上に領域確保するのが基本です。さもないと、リードオンリの文字列定数がRAM上に領域確保されてしまって、RAM容量不足を招きかねません。

 しかし、1個の文字列をPROGMEMにするのは兎も角、複数の文字列定数を配列定義して使うのは、ものすごく面倒臭いのですw(1__)w。今回は「エリーゼのために」のMMLが400バイト程で、RAM容量には余裕が有ったので、PROGMEMは使いませんでした(↓)。

  // I gave up to make mbx_orgel[ ] a PROGMEM, because it's too complex to do so.
  const char *mbx_orgel[ ]=
  {
    // For Elise
    "E516,D#516",
    "E516,D#516,E516,B416,D516,C516",
    :
    : (中略)
    :
    NULL  // 最後はNULLで終端する
  };


 PROGMEM宣言を使っていないため、派手に長い曲(MML)を記述するとRAMが枯渇しますので、ご注意ください。

 RAM容量に注意しながら、自分でMMLさえ作成すれば曲は何でも良いので、オリジナルのオルゴールを作ることが出来ますよ。

システム設計

 328duinoなので、170タイポイントミニブレッドボード(下図)上に、全ての部品を載せたいと思います。

a136_bb170tp.jpg

 更にオルゴールなので、小さな箱の中にすべての部品を押し込んで独立動作するようにしたいです。この時の最大の問題は、電源の確保でしょう。

電源の確保

 単体で自立(独立動作)させるため、ボタン電池ホルダ(下図)を使い、ボタン電池(CR2032等)で328duinoに電源を供給します。

a146_coincel.jpg

 従って、動作電圧Vcc=3Vとなります。ATmega328のVcc=3V(マージン10% → 2.7V)における最大動作周波数は、10MHzです。
 今回のアプリケーションでは、CdSセルの電圧をアナログ端子(AD変換器)から読み出して、音楽を演奏するだけですので、CPUの負荷はそれほど大きくありません。内蔵RC発振器8MHzでの動作で十分なはずです。

パッシブブザー

 play_mml()関数を使って音楽を演奏するためには、スピーカなどの装置が必要となります。スピーカを鳴らすためには、アンプ回路、スピーカ本体等がかさばって、なるべく小さくしたい今回のアプリケーションには向きません。

 このため、音質としては今一つなのですが、パッシブブザーを使います。

 インターネットで検索してみると、ブザーをArduino UNO等に直結して使っている例が散見されます。本HPでも、何度かその様な使い方をしていました。

※もしかして、アクティブブザーと混同していたのかも?

 しかし、パッシブブザーの抵抗値を測定してみたところ、50〜100Ω程の値が観測されました。更に、入手したデータシートによると、抵抗値16Ωが規定されているものがありました。他のデータシートでは、最大電流値(<30mA)で規定されているものもありました。
 5VのUNOでは、直結してしまうと約300mA(≒5V/16Ω)程流す計算であり、ATmega328の絶対最大定格(Iiop=40mA)違反となってしまいます(!)。
 直列に電流制限抵抗が必要なのでしたm(1__)m。

 電流制限抵抗値は、電源電圧Vcc、パッシブブザーの抵抗(または最大電流)値によって異なります。

 電流制限すると、その分、鳴る音は小さくなります。電流を取って大きな音で鳴らしたい場合には、トランジスタなどを使って、電流を流し込む必要があります。
 今回のアプリケーションでは、ミニブレッドボード上にトランジスタ回路を形成する物理的スペースが無い(後ほど配置配線図でご確認ください)ので、ATmega328からの直接駆動可能な範囲の電流値で鳴らします。

 また、ブザーは電磁的な素子なので、並列に保護ダイオードを接続して使うべきらしいです。最終的な回路は、後ほど完成回路図で確認して見てください。

センサ

 明るさを感知するためにCdSセルを使います。普通は、適切な抵抗との直列接続で分圧して使います。今回、ミニブレッドボード上の限られたスペースを有効利用するため、直列抵抗はATmega328の内蔵プルアップ抵抗を使います(抵抗1個分の設置スペースをケチる)。
 内蔵プルアップ抵抗値の規定は、Rpu=20kΩ(MIN)〜50kΩ(MAX)です(ATmega328データシートより)。

a192_cds.png

 上図の様な回路となりますので、アナログ端子A0からanalogRead()して電圧値を読み取ることで、CdSセルに掛かる電圧 → 従ってCdSセルの抵抗値 → すなわち周囲の明るさ、を判定することができます。

 明るさを判定するCdSセルの電圧値は、定数で指定しておく必要があります(↓)。

  const int mbx_CDS_ON=200;  // mbx: CdS ON [LSB]/1024
  const int mbx_CDS_OFF=400;  // mbx: CdS OFF [LSB]/1024


※上の値は、手持ちのATmega328とCdSセルによる校正値(参考値)です。

 そもそも、内蔵プルアップ抵抗値スペックに大きな特性ばらつき(20〜50[kΩ])がありますし、CdSセルそのものにも、素子ばらつきがあるはずなので、お使いになる環境によって閾値は変わるはずです。
 ここは工作する各位が校正して使うしかありません。

 明るくした(蓋を開いた)状態でCdSセルの電圧値を測定してmbx_CDS_ONを決定、暗くした(ふたを閉めた)状態でCdSセルの電圧値を測定してmbx_CDS_OFFを決定、です。mbx_CDS_ON,mbx_CDS_OFF共、十分な余裕(マージン)を持って設定してください。

 mbx_CDS_ON<mbx_CDS_OFFとすることでヒステリシスを持ち、mbx_CDS_ON〜mbx_CDS_OFF間の電圧値の場合は不感帯(直前の状態を保持)となります。

パイロットLED

 オプションですが、見た目で「動いてるね」って判る様に、パイロットLEDを設置しておきます。
 LEDも、通常は適切な電流制限抵抗と直列に繋いで光らせるのですが、ここでもスペースをケチるため、内蔵プルアップ抵抗を使います

 Rpu=20kΩ(MIN)〜50kΩ(MAX)でVcc=3Vだと、ソース可能な最大電流値If=60〜150[μA]と、LEDを光らせるには電流不足ですね。そこで、隣接する3端子分のプルアップ抵抗をショートして、×3倍の電流を流します。
 それでもIf=180〜450[μA]にしかならないので、なるべくVfが小さくて、小さな電流値でも明るく光る赤色LED等を推奨します。

 オルゴールのデバッグが終了して完成品となったら、LEDがピカピカ光るのは目障りかもしれないので、その場合はブレッドボードからLEDを引っこ抜いてください。

完成した回路図

 以上の検討結果より完成した回路図を以下図に示します。

a192_schem.png

 以下の通り、PowerPointを使って部品の配置を決めました。

a192_pandr.jpg

 SSWは、極小のスライドスイッチです。小さなボタン電池駆動なので、電源スイッチを設けておきました。

 所狭しとギチギチに部品が詰まっていて、プログラムの書き込み回路などを接続する余地はありません。プログラムを書き込む場合には、一旦、邪魔になる部品を外して、必要な信号線を繋ぐしかありません。最終的に回路を構築する場合以外、システムやプログラムのデバッグは、別途UNOを使って実施した方が効率が良いと思います。

 以下、他の回路素子を配置する前に、プログラムを328duinoへ書き込んでいる様子です。

a192_serprg.jpg

 Arduino UNOをISP(書き込み装置)として使って、シリアルプログラミングモード(SPI)で328duinoへプログラムを書き込みました。書き込み手順は以下の通りです。

  書き込み手順:

Arduino UNO 接続 328duino(第二形態)
5V Vcc
GND GND
D13(SCK) SCK
D12(MISO) MISO
D11(MOSI) MOSI
D10(RESO) RES

 最初に言及した通り、先に328duino(第二形態)を構築してあることが前提なので、既に適切なブートローダ(+ヒューズ)が書き込まれている前提です。

※UARTで接続して、普通に書き込む方法も可能ですが、DTRからリセット信号を作る回路を作り込む必要があり、今回の様にブレッドボード上に配置できない場合には、返って面倒だと思います。シリアルプログラミングモード(SPI)であれば、配線を接続するだけ(上の接続表)なので幾分かマシでしょう。

工作と実験

 完成したプログラムを以下にリンクしておきます。

  完成プログラム:music_box.ino

 プログラム(music_box.ino)とシステムに関してはArduino UNOを使っても動作可能なので、上で示した回路図の周辺回路をArduino UNOに接続すると、デバッグすることが出来ます。

 プログラム(music_box.ino)をコンパイル&書き込みすると、デバッグ用として以下コマンドをシリアルモニタから受け付けています。

  シリアルモニタコマンド:

 少なくとも、各位の環境にて、【cds】コマンドを使いながら、明るさを判定するための閾値を計測して、定数に反映する必要があります。
 尚、上のコマンドはデバッグ用であり、完成後はシリアルモニタ無しで自立できるようになっています。

 プログラム(music_box.ino)の書き込みが終わったら、残りの周辺回路をブレッドボード上に配置して、オルゴールを完成させてください。以下、完成した「オルゴール化328duino」です。

a192_328d_mbox.jpg

 実は、パッシブブザーとボタン電池ホルダは、他の部品や配線と干渉して真っすぐ挿せないのですが、少し傾けるとブレッドボードに挿すことはできました。完成です。
 スイッチをONすると、明るさに応じて「エリーゼのために」が演奏されるはずです。CdSセルを手で覆い隠すなどして、動作を確認して下さい。

BOD検出

 なんでだろう?この子に時折邪魔されている気がする……。

 ATmega328に内蔵されたBOD (Brown Out Detector)は、低電圧検出回路です。電源電圧Vccが一定以下に低下すると、チップにリセットをかける機能を担っています。電池駆動するケース等で、電池容量が減ってきてVccが一定以下に低下した時、「誤動作させるくらいならリセットしてしまえ」とばかりにリセットをかける回路です。
 328duino(第二形態)は、内蔵RC発振器8MHzで低電圧動作できることを狙っているので、BOD検出レベルを設定可能な最下限値1.8V(TYP)に設定してあります(ATmega328のヒューズEで指定可能)。

 ボタン電池CR2032を使っていてVcc=3V駆動なので、Vcc>>1.8Vと、BOD検出されるはずは無いのですが、どういう訳かBOD検出されてしまい、動作しませんでした(※、当初)。

※5V(や3.3V)を供給すると動くのに、ボタン電池(3V)に繋ぎ変えると動作しなくなる、という状態でした。

 「#9-4 ATmega328のヒューズ書き込み」を参考に、プログラム(ser_prog.ino)を使い、ATmega328のヒューズEに0xffを書き込んで【wrfe,ff】、BOD検出を無効化したところ正常動作しました。

 ボタン電池が経たっていたのか??確かに使い古しの電池でしたが、原因は不明です。皆様の実験でも、発生する場合がありますので、留意してください。

工作中の様子とデモ動画

 「オルゴール化328duino」工作中の様子と、完成したオルゴールのデモを動画にしてみましたので、ご覧ください。




 蓋が閉まった状態で待機中にも、ATmega328はフル稼働しているので、電池をガシガシ消費しています。すぐに電池切れしてしまうでしょう(1^^;)。実用性は薄いかもしれないですね……。


btn_arduino.png

btn_prev.png btn_next.png

home