AD9833はAmazonで購入できる信号発生器です。Amazonのページから仕様を抜粋すると、
下3つは実は意味がわかりません。ここでは波形発生器として使います。
ArduinoからSPI通信で9833にデータを送信します。5本の線をつなぎます。接続は以下の通りです。 ArduinoはArduino LEONARDを使っています。
ARDUINO : AD9833 PB13 : SCK : SCLK PB12 : MOSO : No Connection PB11 : MOSI : SDATA PB10 : SS : FSYNC
Arduino IDEの、「ツール」→「ライブラリを管理」を選択し、ライブラリマネージャを表示します。検索ボックスにAD9833と入力します。AD9833用のライブラリが表示されますのでインストールします。
「ファイル」→「スケッチ例」に以下のようにMD_AD9833というスケッチが追加されています。
MD_AD9833_Testというスケッチを見ると、MD_cmdProcessor.hというヘッダーがインクルードされていました。本当に必要かは不明ですが、MD_cmdProcessorをインストールします。Guihubからインストールします。 https://github.com/MajicDesigns/MD_cmdProcessor
Guihubのreadmeによれば、このライブラリはデバック用のツールだと思います。
Library for simple Command Line Interface アプリケーションのテストなどの単純な要件に役立つ基本的な構文を備えたテーブル駆 動のコマンド ライン インターフェイス。 パラメータとして渡された Stream から入 力を読み取り、Stream 出力に書き込みます。
以下のプログラムは1kHzの正弦波を発信するプログラムです。
// Basic MD_AD9833 test file // #include <MD_AD9833.h> #include <SPI.h> // Pins for SPI comm with the AD9833 IC #define DATA 11 ///< SPI Data pin number #define CLK 13 ///< SPI Clock pin number #define FSYNC 10 ///< SPI Load pin number (FSYNC in AD9833 usage) MD_AD9833 AD(DATA, CLK, FSYNC); // Arbitrary SPI pins void setup(void) { AD.begin(); AD.setMode(MD_AD9833::MODE_SINE); //正弦波 AD.setFrequency(MD_AD9833::CHAN_0, 1000); //1000H } void loop() { // put your main code here, to run repeatedly: delay(1000); }
まず、MIDIで鳴らした結果を張っておきます。コンピュータから音が出ますので音量に注意して下さい。
// Basic MD_AD9833 test file // with MIDI // #include <MD_AD9833.h> #include <SPI.h> #include <usbmidi.h> // Pins for SPI comm with the AD9833 IC #define DATA 11 ///< SPI Data pin number #define CLK 13 ///< SPI Clock pin number #define FSYNC 10 ///< SPI Load pin number (FSYNC in AD9833 usage) MD_AD9833 AD(DATA, CLK, FSYNC); // Arbitrary SPI pins // MIDIのノート番号を周波数に変換します。 // 57番が440Hzになるように計算しています。 // 入力nは、0から127の値で、計算の都合でfloatにしています。 // intやu8では計算がうまくできません。 float base_a4=440; //set A4=440Hz float note_to_freq(float n) { if(n>=128.) n=127.; return base_a4*pow(2,(n-57)/12); }
グローバル変数の定義
/* 波形の種類 MD_AD9833::MODE_TRIANGLE, MD_AD9833::MODE_SQUARE2, MD_AD9833::MODE_SINE, MD_AD9833::MODE_SQUARE1 */ u8 command; //MIDIのstatus、statusは予約語でエラーになるのでcommandとしました。 u8 channel, data1, data2; u8 byte_count=0; int tone_kind=MD_AD9833::MODE_TRIANGLE; //波形の種類を選択します。
一応リセットして、音が出ないようにMODE_OFFを送っておきます。
void setup(void) { AD.begin(); AD.reset(true); delay(200); AD.reset(false); AD.setMode(MD_AD9833::MODE_OFF); }
実際に音を出したり、止めたりしているルーチンです。グローバル変数のうち、 commandとdata2を使っています。data2が鳴らしたい音程を示しています。
void go_process(){ switch (command){ case 0x80: //Note OFF AD.setMode(MD_AD9833::MODE_OFF); break; case 0x90: //Note ON AD.setMode(tone_kind); //波形の種類 AD.setFrequency(MD_AD9833::CHAN_0, note_to_freq((float)data2)); break; case 0xA0: case 0xB0: case 0xE0: case 0xC0: case 0xD0: case 0xF0: break; } }
loopではMIDIの受信をしています。MIDI status(ここではcommandと名前が付いています。) の種類によって、その後読み込むデータのバイト数を決めています。channelの取り込んでいますが このアプリでは使っていません。
void loop(){ //Handle USB communication USBMIDI.poll(); // While there's MIDI USB input available... while (USBMIDI.available()) { data=USBMIDI.read(); if(data&0x80){ command = data&0xF0;; channel= data&0x0F switch (command){ case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0: byte_count=2; break; case 0xC0: case 0xD0: byte_count=1; break; case 0xF0: break; } } else if(byte_count==1){ data1=data; byte_count--; go_process(); //dataが揃ったので音を出す、止めるルーチンを呼びます。 } else if(byte_count==2){ data2=data; byte_count--; } } }