2012年3月16日金曜日

音楽プレーヤーをさくっと作成

AVRでSDカードの読み書きが出来るようになりました。

ポイントは

  • 5Vで動作させると面倒なので、2.7-3.6Vで駆動(信号線のレベルをSDに合わせる必要があるため)
  • 配線はサンプルスケッチの説明どおり
  • ATmega168Pでは容量不足か?ATmega328Pだと動いた


調子に乗って音声データをSDカードに入れて、それをPWMで
音にしてみました。
しょぼしょぼですが音楽プレーヤーの完成です。



動作の様子はこちら。

http://www.youtube.com/watch?v=UsRMV_p-O_8

思っていたより音が綺麗で笑えます。

PWMの出力はほぼそのままスピーカーに入れています。
一応手元の抵抗とコンデンサをつないでRCフィルター的な接続をしてみましたが、
意味はあるかわかりません。

電源は3VのACアダプタです。電圧が微妙なのは3.3Vが売り切れていたからだったりします。
スケッチを書き込むときは3V駆動ではだめなようで、
5V(USBから給電が簡単)にします。
動かすときはまた3Vに切り替えます。
まちがえて5Vを入れてしまったこともありますが、SDカードは壊れなかったようです。

まずはスペック。
音声データはモノラル8bit PCMで、サンプリングレート8000Hzとしました。
曲はビートルズのLove me do。ちなみに、オリジナルアルバムではなく、アンソロジーのテイクだったりします。
MP3データをaudacityでフォーマット変換しwavにしておきます。
ファイル名は決めうちで、wavファイルをSDカードのルートにおきます。
SDカードを取り付けた状態で電源を投入すると曲が再生されます。
終わったら停止します。つまり、1曲しか再生できずリピートもしません。
PWMはDigital9(pin15)を利用しています。
変な信号で機材を壊しては困るので、壊れても惜しくないスピーカーをつなぎます。
アクティブスピーカーじゃないと音が小さすぎるかも。

PWM周波数がデフォルトで500Hz弱と音声再生には使えない値なので、周波数は変更の必要があります。
方法はhttp://www.arduino.cc/playground/Main/TimerPWMCheatsheetを参考にしました。

これらを踏まえて、スケッチを作成しました。
ベースにしたのはサンプルのSD->DumpFileです。
読みとったデータをシリアル出力するところを書き換えて、PWMに出すようにしました。
サンプリング周波数はタイマーを使わず、delayで作っています。


  1. SDから1byte読む
  2. PWMでデータを出力
  3. delay(!!ダサい)


といった感じですね。なのでサンプリング周波数はてきとーです。
delay値は耳で聞いて決めました。めちゃくちゃですね。

そのうちちゃんとするとして、ひとまず音が出て楽しかったので勇み足で
ブログを書いたのでした。

スケッチは以下のようになりました。
簡単に出来てしまいました。


/*
SD card file dump

This example shows how to read a file from the SD card using the
SD library and send it over the serial port.

The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4

created 22 December 2010

This example code is in the public domain.

*/

#include

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 4;
int sndPin = 9;

void setup()
{
Serial.begin(9600);
Serial.print("Initializing SD card...");
// make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);

// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");

// pwm frequency is set to 31khz
TCCR1B = TCCR1B & 0b11111000 | 0x01;


// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
//File dataFile = SD.open("datalog.txt");
File dataFile = SD.open("test.wav");

//File outFile = SD.open("out.txt", FILE_WRITE);

// if the file is available, write to it:
if (dataFile) {
while (dataFile.available()) {
//Serial.write(dataFile.read());
//outFile.write(dataFile.read());
analogWrite(sndPin, dataFile.read());
//delay(1);
delayMicroseconds(80);
}
dataFile.close();
//outFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
}

void loop()
{
}

0 件のコメント:

コメントを投稿