Добрый день. Я делаю небольшой проект "Музыкальная шкатулка" на 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); // и тд. }
На открытие шкатулки нужен сенсор. Это может быть что угодно: круглый реостат в петле, сенсор освещенности под крышкой, кнопка между крышкой и корпусом и т.д. Команда с этого сенсора должна переключать какой-то флаг. Сделайте 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; } }
Спасибо за дельные советы! Прототип заработал как задумано. Завтра докуплю герконы и датчики освещенности, надеюсь соберу уже со всеми кнопками. Едиственное не добился работы цикла 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; } } * / }
А зачем вам отдельная переменная is_closed, если по идее is_closed всегда равно !is_opened ? В цикле for надо проверять, нажата ли кнопка (== HIGH), а вы проверяете, отпущена ли она.
Всю электронную часть собрал. Картинка программа получилась вот такая код не очень красив но свой фукционал выполняет а отдельная переменная нужна чтобы плеер молчал во время простоя. Код (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; }
С логикой все закончили. Но вознкла другая проблема, как запитать устройсво в автономе на неделю? Во время сборки и тестирования я использовал EmergencyCharger 2*AA -> USB но его хватает на пару часов. Потребление устройства 170 мА в покое, 250 мА при воспроизведении. Вариант 1. Питать через штатный разъем используя аккум 12в 7Ач, но он большой и тяжелый. Вариант 2. Повесить тумблер питания ардуины на открытие крышки и при каждом открытии играть файл приветстия автоматически, но тогда файл который должен играть при закрытии крышки не успеет доиграть.
Это простой и понятный способ, но там где будет стоять шкатулка нет возможность воткнуть блок питания. Пока пробую второй вариант с питанием от 2*18650 либо 4*ААА через Vin ток потребления 50 - 70 мА.
Сегодня шкатулка переста играть файлы в мониторе порта пишет: error: card.init failed SD error: 1All songs in the root directory: error: open file failed SD error: 1The song is exist. видимо MusicShield сдох.
Все пробовал. Форматировал, перезалил файлы, заменил карточку. даже примеры из библиотеки FAT16 не работают. А сейчас еще и светодиод D1 на MusicShield перестал гореть. Вот теперь думаю как мне новый MusicShield в Иркутск оперативно получить. На EMS особой надежды нет.
Здравствуйте! А у меня выдает ошибку: Arduino: 1.5.8 (Windows 7), Board: "Arduino Uno" Build options changed, rebuilding all muz_rab_.cpp.o: In function `MusicPlayer: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 Ошибка компиляции. Не как не могу разобраться... Может кто подскажет в чем дело?