舟泊烟渚 发表于 2013-8-29 17:48:07

遥控Arduino播放音乐

本帖最后由 迷你强 于 2013-8-30 22:37 编辑

没玩几天Arduino(mega328),手头也没什么模块,看了论坛里那篇Arduino播放音乐的教程后跟着做出来了(http://www.geek-workshop.com/forum.php?mod=viewthread&tid=2611),还不错,但是缺点很明显,必须用电脑连串口输入文件名和命令,于是就改改程序加进IR接收,让板子可以摆脱电脑独立受遥控控制播放音乐,并不难,但是很实用,贴出来
分享一下。
SD卡的接线参照“Workshop Team”的上面那篇帖子,红外接收管脚可自定义,我设的D5脚。

代码当然是根据MostFunctionDemo.ino改的,库函数用word打开各种看不懂啊,不过关键地方改对就行。



//This is used for play music on SD card under the control of IR remote;
#include <SimpleSDAudio.h>
#include<IRremote.h>

int RECV_PIN = 5;   //红外线接收器OUTPUT端接在pin 5
IRrecv irrecv(RECV_PIN);   // 定义IRrecv 对象来接收红外线信号
decode_results results;   //解码结果放在decode_results构造的对象results里

// Callback target, prints output to serial
void DirCallback(char *buf) {
Serial.println(buf);
}

char AudioFileName;

// Create static buffer
#define BIGBUFSIZE (2*512)      // bigger than 2*512 is often only possible on Arduino megas!
uint8_t bigbuf;

// helper function to determine free ram at runtime
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

void setup()
{
// Open serial communications and wait for port to open:
   Serial.begin(9600);
   irrecv.enableIRIn();          //启动红外解码
   //while (!Serial) {
   // wait for serial port to connect. Needed for Leonardo only
   //}

Serial.print(F("Free Ram: "));
Serial.println(freeRam());

// Setting the buffer manually for more flexibility
SdPlay.setWorkBuffer(bigbuf, BIGBUFSIZE);

Serial.print(F("\nInitializing SimpleSDAudio V" SSDA_VERSIONSTRING " ..."));

// If your SD card CS-Pin is not at Pin 4, enable and adapt the following line:
//SdPlay.setSDCSPin(10);

// Select between SSDA_MODE_FULLRATE or SSDA_MODE_HALFRATE (62.5kHz or 31.25kHz)
// and the output modes SSDA_MODE_MONO_BRIDGE, SSDA_MODE_MONO or SSDA_MODE_STEREO
if (!SdPlay.init(SSDA_MODE_FULLRATE | SSDA_MODE_MONO)) {
    Serial.println(F("initialization failed. Things to check:"));
    Serial.println(F("* is a card is inserted?"));
    Serial.println(F("* Is your wiring correct?"));
    Serial.println(F("* maybe you need to change the chipSelect pin to match your shield or module?"));
    Serial.print(F("Error code: "));
    Serial.println(SdPlay.getLastError());
    while(1);
} else
{
    Serial.println(F("Wiring is correct and a card is present."));
}
}


void loop(void) {
uint8_t count=0,flag=0;//unsigned int,c will transfered one by one
char d={'B','E','T','H','.','A','F','M'};////////////////////////////1
char e={'M','A','D','W','O','R','L','D','.','A','F','M','\0'};/////2
char f={'B','L','U','E','B','I','~','1','.','A','F','M','\0'};/////////3
char a="";
char g={'M','E','M','O','R','I','E','S','.','A','F','M','\0'};///////4

//Add here;
Serial.println(F("Files on card:"));
SdPlay.dir(&DirCallback);

//ReEnter:
Serial.println(F("\r\nEnter filename (send newline after input):"));
while(1)
{/////////////small loop in big loop;
count=0;
if(flag==2){for(int i=0;i<13;i++){ AudioFileName=e;}count=0;}
if(flag==3){for(int i=0;i<13;i++){ AudioFileName=f;}count=0;}
if(flag==4){for(int i=0;i<9;i++){ AudioFileName=d;}count=0;}
if(flag==5){for(int i=0;i<13;i++){ AudioFileName=g;}count=0;}
//Add here;
Serial.print(F("Looking for file... "));
if(!SdPlay.setFile(AudioFileName)) //judging file name according to filename
{
    Serial.println(F(" not found on card! Error code: "));
    Serial.println(SdPlay.getLastError());
//goto ReEnter;
}
else {
   Serial.println(F("found."));
}

Serial.println(F("Press s for stop, p for play, h for pause, f to select new file, d for deinit, v to view status."));
flag = 1;
while(flag==1) {
    SdPlay.worker();
   if (irrecv.decode(&results)){
    switch(results.value) {
    case 0xFF30CF:
         count=0;
         for(int i=0;i<13;i++){ AudioFileName=a;}
         count=0;
         flag=2;/////////1
         break;
    case 0xFF18E7:
         count=0;
         for(int i=0;i<13;i++){ AudioFileName=a;}
         count=0;
         flag=3;
         break;///////////2
    case 0xFF7A85:
         count=0;
         for(int i=0;i<13;i++){ AudioFileName=a;}
         count=0;
         flag=4;
         break;///////////3
    case 0xFF10EF:
         count=0;
         for(int i=0;i<13;i++){ AudioFileName=a;}
         count=0;
         flag=5;
         break;///////////4
         
//Add here;
    case 0xFFE21D:         
         SdPlay.stop();
         Serial.println(F("Stopped."));
         break;
    case 0xFF22DD:         
         SdPlay.play();
         Serial.println(F("Play."));
         break;
    case 0xFFE01F:
         SdPlay.pause();
         Serial.println(F("Pause."));
         break;
    case 0xFFA25D:
         SdPlay.deInit();
         Serial.println(F("SdPlay deinitialized. You can now safely remove card. System halted."));
         while(1) ;
         break;
   case 0xFFB04F:
         flag = 0;
         count=0;
         for(int i=0;i<13;i++){ AudioFileName=a;}
         count=0;
         break;
   case 0xFF629D:
         Serial.print(F("Status: isStopped="));
         Serial.print(SdPlay.isStopped());
         Serial.print(F(", isPlaying="));
         Serial.print(SdPlay.isPlaying());
         Serial.print(F(", isPaused="));
         Serial.print(SdPlay.isPaused());
         Serial.print(F(", isUnderrunOccured="));
         Serial.print(SdPlay.isUnderrunOccured());
         Serial.print(F(", getLastError="));
         Serial.println(SdPlay.getLastError());
         Serial.print(F("Free RAM: "));
         Serial.println(freeRam());
         break;         
      }   
      irrecv.resume();
    }
}
}
}

该程序中有三处打头为//Add here,那三个地方是要增加歌曲或者修改歌曲名称时用到的,对应上面几行复制再改参数就行。
添加歌曲名时注意,AudioFileName的歌曲名都被自动改为大写字母、无空格、不超过12个字符(除去.afm,只有8个)的字符串,而且,不支持字符“’”,会产生错误。由于害怕里面很多库函数对AudioFileName长度有限制,就没有改长它,短了又不知道是什么歌曲,所以就没管它。SD卡中存储的afm文件显示到串口调试器里的名字才是我们需要的。
下载到板子上之后连上电池拔掉USB,然后按1,2,3等数字键选择歌曲,然后按播放键(键码不用多说了哈)就有开始播放了,
其他功能键可以自己设置,我设置的功能键在连USB时按下板子上TX灯会闪,串口调试器上也会出单词,什么功能一目了然。
有必要的朋友可以再加一个液晶显示模块显示歌名状态等。这个作品的缺点是,AFM格式文件制作有点麻烦,还比较大,然后歌曲多了的话几个数字键不够用(再进一步修改程序使其能接收两三位数字来选择歌曲即可)。

wsy0315 发表于 2013-8-30 18:57:07

受教了,很好, 支持下

zjgaoli888 发表于 2013-8-30 19:22:00

引入#include <SimpleSDAudio.h> 后就报错啊,楼主有遇到这个问题么?

FoieDEEEE_仲敬 发表于 2013-8-30 21:12:10

zjgaoli888 发表于 2013-8-30 19:22
引入#include后就报错啊,楼主有遇到这个问题么?

你是1.5.2的IDE吧,只有1.0.3以下才能用此库!

舟泊烟渚 发表于 2013-8-31 11:49:27

zjgaoli888 发表于 2013-8-30 19:22 static/image/common/back.gif
引入#include后就报错啊,楼主有遇到这个问题么?

我的IDE是1.0.5的,没有遇到你说的问题,你的SimpleSDAudio.h放在library里了吗?最好先用只有一个音乐文件的MostFuctionDemo测试一下。

whmn 发表于 2013-9-21 20:36:15

不行啊   这句有错啊   1.01的ide,
IRrecv irrecv(RECV_PIN);   // 定义IRrecv 对象来接收红外线信号
错在irrecv' was not declared in this scope
求教啊!

舟泊烟渚 发表于 2013-9-21 22:27:24

whmn 发表于 2013-9-21 20:36 static/image/common/back.gif
不行啊   这句有错啊   1.01的ide,
IRrecv irrecv(RECV_PIN);   // 定义IRrecv 对象来接收红外线信号
...

换1.0.5的试下吧。上次我用9v电源插uno结果板子和1602液晶全烧了,bootloader也刷不了,SD卡换了板子再也读不出来,但是里面文件都是好的,所以可能存在兼容性问题,只能您自己搞了,爱莫能助啊

软件-蹄飞 发表于 2014-4-5 21:05:38

whmn 发表于 2013-9-21 20:36 static/image/common/back.gif
不行啊   这句有错啊   1.01的ide,
IRrecv irrecv(RECV_PIN);   // 定义IRrecv 对象来接收红外线信号
...

因为你少了一个红外接受的库。论坛精华教程里有

蓝色骨骨头 发表于 2015-5-7 08:31:38

楼主 可以分享一下一个按键控制音乐播放的代码么 求指点

蓝色骨骨头 发表于 2015-5-8 19:57:53

大神 能指点一下只用一个按键控制音乐播放么
页: [1]
查看完整版本: 遥控Arduino播放音乐