Музыкальная шкатулка

Тема в разделе "Глядите, что я сделал", создана пользователем samasam, 5 авг 2013.

  1. samasam

    samasam Нуб

    Добрый день.
    Я делаю небольшой проект "Музыкальная шкатулка" на Arduino Music Shield в которой должны играть разные мелодии при на нажатии на соответствующие кнопки.
    Всего кнопок должно быть 7-8 штук.
    У несколько дней воюю и не могу победить.

    Я не разобрался как заставить плеер молчать, до тех пока пока шкатулка не будет открыта. Единственное, что пришло на ум это размыкать питание самой Ардуины.

    Возникла идея, чтобы при нажатии соответствующих кнопок передавать в переменной имя трека, но пока не нашел примера как это написать.

    Код (C):

    #include <Fat16util.h>
    #include <NewSPI.h>
    #include "MusicPlayer.h"
    MusicPlayer myplayer;
     
    void setup()
    {
      Serial.begin(9600);
      myplayer.begin();
      myplayer.keyDisable(); //отключаем встроенное управление воспроизведением, освобождаем выходы 3-7
      myplayer.digitalControlEnable(); //включаем возможность слушать цифровые входы
      myplayer.attachDigitOperation(0, open_box, HIGH);
      myplayer.attachDigitOperation(1, play_2dm, HIGH);
      myplayer.attachDigitOperation(3, play_3ag, HIGH);
      myplayer.attachDigitOperation(4, play_4ay, HIGH);
      myplayer.attachDigitOperation(5, play_5md, HIGH);
      myplayer.attachDigitOperation(6, play_6tr, HIGH);
      myplayer.attachDigitOperation(7, play_7fs, HIGH);

    void loop()
    {
      myplayer.setPlayMode(MODE_NORMAL);
      myplayer.addToPlaylist("1opn.mp3");
      myplayer.addToPlaylist("2dm.mp3");
      myplayer.addToPlaylist("3ag.mp3");
      myplayer.addToPlaylist("4ay.mp3");
      myplayer.addToPlaylist("5md.mp3");
      myplayer.addToPlaylist("6tr.mp3");
      myplayer.addToPlaylist("7fs.mp3");
      myplayer.addToPlaylist("8end.mp3");
      myplayer.playList(); // я не разобрался как заставить плеер молчать, до тех пока пока шкатулка не будет открыта.
    }

    void open_box() {
      // командуем включить  трек #1
      myplayer.playSong("1opn.mp3");
      // защищаемся от возможного дребезга кнопки
      delay(50);
    // и тд.
    }
     
     
  2. DenisNP

    DenisNP Нерд

    На открытие шкатулки нужен сенсор. Это может быть что угодно: круглый реостат в петле, сенсор освещенности под крышкой, кнопка между крышкой и корпусом и т.д.

    Команда с этого сенсора должна переключать какой-то флаг. Сделайте boolean is_opened например.

    Код (C):
    boolean btn = digitalRead(порт_кнопки) == HIGH; //считаем, что открыто когда кнопка НЕ нажата
    if(!is_opened && !btn){ // было закрыто и открыли
       //или сразу запускаем песню:
       myplayer.playSong(...);
       // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
    }else if(is_opened && btn){ //было открыто и закрыли
       myplayer.opStop(); //останавливаем воспроизведение
    }
    is_opened = !btn; //открыто если кнопка не нажата, и наоборот
    Затем по нажатию на кнопку, которая должна запускать песню:

    Код (C):
    if (is_opened) {
       myplayer.playSong(...);
    }
    Насчет переменной и имени трека, я бы создал массив с именами, например:

    Код (C):
    String names = {"track1.mp3","track2.mp3","track3.mp3"};
    Затем забил бы пины нужных кнопок тоже в массив, вот так:

    Код (C):
    int pins = {51,52,53};
    И проверял бы:

    Код (C):
    for (int i=0; i<3; i++) {
       if(digitalRead(pins[i]) == HIGH){
           myplayer.playSong(names[i]);
           delay(100); // Дождемся когда человек отпустит кнопку
           break;
       }
    }
     
    samasam и Unixon нравится это.
  3. samasam

    samasam Нуб

    Спасибо за дельные советы! Прототип заработал как задумано.
    Завтра докуплю герконы и датчики освещенности, надеюсь соберу уже со всеми кнопками.

    Едиственное не добился работы цикла for

    пока рабочий вариант такой в стиле индуского "ctrl+c, ctrl+v" ;)
    Код (C):

    #include <Fat16util.h>
    #include <NewSPI.h>
    #include "MusicPlayer.h"
    MusicPlayer myplayer;
      String names = ("1.mp3","2.mp3","3.mp3","4.mp3","5.mp3","6.mp3","7.mp3","8.mp3");
      int pins[2] = {4,5};
      boolean is_opened;
      boolean is_closed;

     
    void setup()
    {
      Serial.begin(9600);
      Serial.flush();
      Serial.print('test');
      myplayer.begin();
      myplayer.keyDisable(); //отключаем встроенное управление воспроизведением, освобождаем выходы 3-7
      myplayer.digitalControlEnable(); //включаем возможность слушать цифровые входы
      myplayer.setVolume(1);

    }
    void loop()
    {

      boolean btn4 = digitalRead(4) == HIGH; //считаем, что открыто когда кнопка НЕ нажата
    if(!is_opened && !btn4)
    { // было закрыто и открыли
       //или сразу запускаем песню:
       myplayer.playSong("1.mp3");
       // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
    }
    else if(is_opened && btn4)
    { //было открыто и закрыли
       myplayer.opStop(); //останавливаем воспроизведение
    }
    is_opened = !btn4; //открыто если кнопка не нажата, и наоборот

      boolean btn5 = digitalRead(5) == LOW; //считаем, что открыто когда кнопка НЕ нажата
    if(!is_closed && !btn5)
    { // было закрыто и открыли
       //или сразу запускаем песню:
       myplayer.playSong("8.mp3");
       // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
    }
    else if(is_closed && btn5)
    { //было открыто и закрыли
       myplayer.opStop(); //останавливаем воспроизведение
    }
    is_closed = !btn5;

    /*
    if (is_opened) {
       myplayer.playSong("2.mp3");
    }

    */

    for (int i=0; i<8; i++)
     {
       if(digitalRead(pins[i]) == LOW)
       {
           myplayer.playSong(names[i]);
           delay(100); // Дождемся когда человек отпустит кнопку
           break;
       }
     }
    * /
    }
     
     
  4. DenisNP

    DenisNP Нерд

    А зачем вам отдельная переменная is_closed, если по идее is_closed всегда равно !is_opened ?

    В цикле for надо проверять, нажата ли кнопка (== HIGH), а вы проверяете, отпущена ли она.
     
  5. samasam

    samasam Нуб

    Завтра на свежую голову посмотрю. Сегодня голова другим забита.
     
  6. samasam

    samasam Нуб

    Всю электронную часть собрал.
    Картинка

    программа получилась вот такая
    код не очень красив но свой фукционал выполняет
    а отдельная переменная нужна чтобы плеер молчал во время простоя.

    Код (C):
    #include <Fat16util.h>
    #include <NewSPI.h>
    #include "MusicPlayer.h"
    MusicPlayer myplayer;
      String names = ("1.mp3","2.mp3","3.mp3","4.mp3","5.mp3","6.mp3","7.mp3","8.mp3");
      int pins[2] = {4,5};
      boolean is_opened1;
      boolean play2;  
      boolean play3;
      boolean play4;
      boolean play5;
      boolean play6;
      boolean play7;
      boolean play8;
     
    void setup()
    {
      Serial.begin(9600);
      Serial.flush();
      Serial.print('test');
      myplayer.begin();
      myplayer.keyDisable(); //отключаем встроенное управление воспроизведением, освобождаем выходы 3-7
      myplayer.digitalControlEnable(); //включаем возможность слушать цифровые входы
      myplayer.setVolume(1);

    }
    void loop()
    {

      boolean btn_opn1 = digitalRead(2) == HIGH; //считаем, что открыто когда кнопка НЕ нажата
        if(!is_opened1 && !btn_opn1)
          { // было закрыто и открыли
           //или сразу запускаем песню:
           myplayer.playSong("2.mp3");
           // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
          }
        else if(is_opened1 && btn_opn1)
          { //было открыто и закрыли
           myplayer.opStop(); //останавливаем воспроизведение
          }

    is_opened1 = !btn_opn1; //открыто если кнопка не нажата, и наоборот

      boolean btn2 = digitalRead(3) == LOW; //считаем, что открыто когда кнопка НЕ нажата
        if(!play2 && !btn2)
          { // было закрыто и открыли
           //или сразу запускаем песню:
           myplayer.playSong("2.mp3");
           // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
          }
        else if(play2 && btn2)
          { //было открыто и закрыли
           myplayer.opStop(); //останавливаем воспроизведение
          }
    play2 = !btn2; //открыто если кнопка не нажата, и наоборот
     
        boolean btn3 = digitalRead(4) == LOW; //считаем, что открыто когда кнопка НЕ нажата
        if(!play3 && !btn3)
          { // было закрыто и открыли
           //или сразу запускаем песню:
           myplayer.playSong("3.mp3");
           // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
          }
        else if(play3 && btn3)
          { //было открыто и закрыли
           myplayer.opStop(); //останавливаем воспроизведение
          }
    play3 = !btn3; //открыто если кнопка не нажата, и наоборот

      boolean btn4 = digitalRead(5) == LOW; //считаем, что открыто когда кнопка НЕ нажата
        if(!play4 && !btn4)
          { // было закрыто и открыли
           //или сразу запускаем песню:
           myplayer.playSong("4.mp3");
           // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
          }
        else if(play4 && btn4)
          { //было открыто и закрыли
           myplayer.opStop(); //останавливаем воспроизведение
          }
    play4 = !btn4; //открыто если кнопка не нажата, и наоборот

      boolean btn5 = digitalRead(6) == LOW; //считаем, что открыто когда кнопка НЕ нажата
        if(!play5 && !btn5)
          { // было закрыто и открыли
           //или сразу запускаем песню:
           myplayer.playSong("5.mp3");
           // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
          }
        else if(play5 && btn5)
          { //было открыто и закрыли
           myplayer.opStop(); //останавливаем воспроизведение
          }
    play5 = !btn5; //открыто если кнопка не нажата, и наоборот

      boolean btn6 = digitalRead(7) == LOW; //считаем, что открыто когда кнопка НЕ нажата
        if(!play6 && !btn6)
          { // было закрыто и открыли
           //или сразу запускаем песню:
           myplayer.playSong("6.mp3");
           // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
          }
        else if(play6 && btn6)
          { //было открыто и закрыли
           myplayer.opStop(); //останавливаем воспроизведение
          }
    play6 = !btn6; //открыто если кнопка не нажата, и наоборот

    unsigned int vol_1 = analogRead(A4);
      boolean btn7 = LOW; //считаем, что открыто когда кнопка НЕ нажата
       if (vol_1 < 1000)
         {
           btn7 = HIGH;
         }
       
    if(!play7 && !btn7)
    { // было закрыто и открыли
       //или сразу запускаем песню:
       myplayer.playSong("7.mp3");
       // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
    }
    else if(play7 && btn7)
    { //было открыто и закрыли
       myplayer.opStop(); //останавливаем воспроизведение
    }
    play7 = !btn7; //открыто если кнопка не нажата, и наоборот


     unsigned int vol_2 = analogRead(A5);
      boolean btn8 = HIGH; //считаем, что открыто когда кнопка НЕ нажата
       if (vol_2 < 1000)
         {
           btn8 = LOW;
         }

    if(!play8 && !btn8)
    { // было закрыто и открыли
       //или сразу запускаем песню:
       myplayer.playSong("8.mp3");
       // или ничего не делаем, если песня должна запуститься только по нажатию какой-то из других кнопок
    }
    else if(play8 && btn8)
    { //было открыто и закрыли
       myplayer.opStop(); //останавливаем воспроизведение
    }
    play8 = !btn8;

    }
     
  7. DenisNP

    DenisNP Нерд

    Ну, можно было сделать существенно короче. Но раз работает, то ладно :)
     
  8. samasam

    samasam Нуб

    С логикой все закончили.
    Но вознкла другая проблема, как запитать устройсво в автономе на неделю?
    Во время сборки и тестирования я использовал EmergencyCharger 2*AA -> USB но его хватает на пару часов.
    Потребление устройства 170 мА в покое, 250 мА при воспроизведении.
    Вариант 1. Питать через штатный разъем используя аккум 12в 7Ач, но он большой и тяжелый.
    Вариант 2. Повесить тумблер питания ардуины на открытие крышки и при каждом открытии играть файл приветстия автоматически, но тогда файл который должен играть при закрытии крышки не успеет доиграть.
     
  9. DenisNP

    DenisNP Нерд

    Нужно купить просто блок питания соответствущий и держать его включенным в розетку.
     
  10. samasam

    samasam Нуб

    Это простой и понятный способ, но там где будет стоять шкатулка нет возможность воткнуть блок питания.
    Пока пробую второй вариант с питанием от 2*18650 либо 4*ААА через Vin ток потребления 50 - 70 мА.
     
  11. samasam

    samasam Нуб

    Сегодня шкатулка переста играть файлы
    в мониторе порта пишет:
    error: card.init failed
    SD error: 1All songs in the root directory:
    error: open file failed
    SD error: 1The song is exist.

    видимо MusicShield сдох.
     
  12. Megakoteyka

    Megakoteyka Оракул Модератор

    А карту отформатировать и заново на нее файлы сложить пробовали?
     
  13. samasam

    samasam Нуб

    Все пробовал. Форматировал, перезалил файлы, заменил карточку.
    даже примеры из библиотеки FAT16 не работают.

    А сейчас еще и светодиод D1 на MusicShield перестал гореть.
    Вот теперь думаю как мне новый MusicShield в Иркутск оперативно получить. На EMS особой надежды нет.
     
  14. freearduino

    freearduino Нерд

    Здравствуйте!
    А у меня выдает ошибку:
    Arduino: 1.5.8 (Windows 7), Board: "Arduino Uno"

    Build options changed, rebuilding all

    muz_rab_.cpp.o: In function `MusicPlayer::eek:pStop()':
    C:\Users\artur\Google Диск\Программы\arduino-1.5.8-windows\arduino-1.5.8\libraries\MusicPlayer_v1_7/MusicPlayer.h:100: undefined reference to `playingState'
    C:\Users\artur\Google Диск\Программы\arduino-1.5.8-windows\arduino-1.5.8\libraries\MusicPlayer_v1_7/MusicPlayer.h:100: undefined reference to `playingState'
    collect2: error: ld returned 1 exit status
    Ошибка компиляции.

    Не как не могу разобраться...
    Может кто подскажет в чем дело?