2024年7月5日金曜日

出入り検知器をPCB化する(その7)メロディ生成

 メインの基板が働く目途が立ったのでメロディ回路作成に取り組んだ。前回のメイン基板の写真で空いている8ピンICソケットにPIC16F18313を挿してURATインターフェイスを通じてメロディを発生させるようにする。

3声のシンセサイザを作りたかったが試したらPIC16F18313の少ないメモリー(プログラム=3.5KB、データRAM=256B)では1声の単音色が限界だった。 音階はクロックの1MHzを使ってNCO1(数値制御発信器、次図)で発生させた。

一般的には特定の周波数を発生させるには高い周波数のクロックを分周器で分周するのが普通であるが、分周器は整数分の1の分周しかできない(PLLを使った高級な分周器では分数の分周が出来るものもあるらしい)。一方音楽に使うためには12音階を数オクターブを発生させる必要がある。12音階は整数比ではない(1音階の周波数比は2の12乗根=約1.060)ため分周で正確に発生させることはできない。特に分周器を使って高い周波数を出す場合は分周比が少なくなり周波数精度が悪くなる。音楽では単に周波数精度だけでなく正しい音階からの絶対的な周波数のずれが唸りとなって聞こえるのでこれはいただけない。分周で精度を上げるにはクロック周波数を上げ分周比も大きくする必要があるが、Excelで計算してみるとA8まで周波数誤差を0.5Hz以内に収めるためにはPICのクロックが32MHzでも足りない。

一方NCO1は動作がやや複雑である。中心となる加算器で加算値を足し合わせ、加算器のオーバーフローを出力とする。NCO1では周波数が高くなるほど周波数精度が高くなる。それもクロックが低いほど加算数が大きくなり周波数精度も高くなる。クロックが1MHz、20ビット加算器を使うとA1の55Hzを出すための加算値は115、A8の7040Hzを出すための加算値は14764である。実際には出力を方形波とするためにオーバーフローを2分周して出力しており、その時の加算値が上の値である。周波数誤差で見るとNCO1では音階毎の周波数誤差の凸凹が少なく、全音階で0.4Hz以下に収まっており、高音になるほど周波数誤差が大きくなりがちな分周方式と違ってNCO1方式は音楽向きである。

NCO1の弱点は求める周波数を出すための加算数の計算がやや面倒な事であるが、これは予めExcel等で計算しておくことで対処できる。

結局、PIC18F27Q43からUARTで音階と音の長さを纏めた1行を送ることでメロディを奏でさせることとした。音階はMIDIの音階コードを流用して16進数で表す。音の長さは簡略化して1文字で表す。例えばA4(440Hz)の四分音符は「455」と表現する。1音を3バイトで表すのでRAMのうち141バイトを使って47音(休符を含む)まで演奏できる。

音階はNCO1で簡単に実現できた。音の長さはメモリー容量の関係でタイマー割込みは使わず1msの遅延を必要回数繰り返すことで実現した。この繰り返し回数は拍数(BPM)から簡単に算出できる。ON/OFFの割合を変えることでスタッカートやレガートも出来る。一応次の様に文字を割り当てた。i や j や l を使っていないのは視覚的に判別しにくいからである。

一方、使い慣れたはずのUARTインターフェイスが全く使い物にならず苦労した。送信は出来るが受信が全くできない。ソフトやハードをあれやこれやチェックしても全く動かない。さんざん悩んだ挙句に最終的に2番ピン(RA5)が死んでいることが分かり、これをPPSの機能で空いている6番ピン(RA1)に振り替える事で解決した。この事は、PICを交換しても駄目だったのでロット不良か或いはまがい物を買った可能性がある(このPICは秋月で買ったんだけど・・・)。

UARTインターフェイスは AquesTalk pico と似たようなものにした。

次のバージョンでは和音を出したいのでPIC16F18313の上位互換のPIC16F18326(14ピン、プログラム=28KB,データRAM=2KB)、或いは別のPICを使ってできないかあれやこれや検討している。しかしPICに搭載されているNCOはせいぜい1個であり和音には程遠い。(複数個ある)タイマー1は使えないか?またPWMを使ってエンベロープ機能も搭載できないか?PWNはタイマー2と組み合わせる必要があり、タイマー2のクロックにはシステムクロック/4しか使えないが要求を満たせるか、また音の合成はどうするか?など検討している。

(その8へ続く)

0 件のコメント:

コメントを投稿