Монстр в коробке
Компоненты и расходные материалы
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
Об этом проекте
*** ОБНОВЛЕНО до версии 4 ***
Недавно я переписал код Arduino для этого проекта. Вот краткое изложение изменений:
- Главный цикл теперь реализован как конечный автомат.
- Все время теперь основано на оценке времени события и текущего времени.
- время больше не зависит от кадров
- разрешено удаление delay () в основном цикле
- устраняет проблему "порт занят" при подключении к Arduino IDE
- Реле теперь используют нормально открытые, а не нормально закрытые соединения *** Обновите свои релейные соединения !!! ***
- Добавлен светодиод обнаружения движения.
- Добавлен индикатор готовности к пробуждению.
- Добавлен индикатор паузы.
- Удален переключатель триггера действия.
- Добавлена возможность добавлять дополнительное время к Red Lights &Smoke
- позволяет этим эффектам работать немного дольше, чем у баунсера крышки
- Добавлено много комментариев.
Вы найдете весь последний код здесь, на github
Монстр в коробке
Я люблю реквизит на Хэллоуин, я видела и читала о каком-то замечательном монстре в коробке построил в прошлом году и решил, что должен построить свою собственную. Идея довольно проста:создать иллюзию, что какой-то контейнер содержит опасного монстра, который находится на грани побега. Иллюзию можно создать с помощью любой комбинации движения, звука, света, дыма и, конечно же, неожиданности.
Что в коробке!?!?
Вам нужна коробка, достаточно большая, чтобы в ней могло поместиться что-то большое и пугающее. Это также добавляет иллюзии, если ящик кажется старым, сильно изношенным и, возможно, достаточно сильным, чтобы удержать монстра в страхе. Сначала я искал что-то в благотворительных магазинах и в Интернете, но никогда не покупал что-то, что мне нравилось, поэтому я создал свое собственное. Это было не очень сложно.
Я использовал 15 6-футовых пикетов для сосновых заборов от Home Depot, чтобы сделать коробку размером примерно 3 фута x 2,5 фута x 2,5 фута. Я отрезал всю доску по длине настольной пилой и собрал коробку, используя пневматический гвоздезабиватель 18 калибра. Похоже, это сработало, но позже я понял, что стержни были недостаточно прочными, чтобы удерживать коробку вместе из-за всех ударов и отскоков, которые она будет делать. Чтобы укрепить коробку, я позже скрутил ее 1-дюймовыми шурупами для гипсокартона (изнутри наружу, чтобы они не были видны).
После постройки я состарил дерево с помощью черного чая, уксуса и стальной ваты. Затем я украсил его трафаретами и этикетками, которые нашел в Интернете и / или создал и распечатал.
Brainzzzzz !!!
Опора имеет 2 рабочих состояния:«Спящий» и «Пробуждение». Во время сна ящик относительно спокоен и издает только храп и легкое рычание. Монстр просыпается, когда злоумышленник срабатывает с датчиком движения. Когда монстр просыпается, монстр рычит, вдыхает дым, отскакивает от крышки, а внутренняя часть коробки светится красным.
Я использовал Arduino Uno вместе с WaveShield и релейным модулем, чтобы управлять поведением этой опоры. WaveShield загружен небольшой коллекцией звуков сна и рев. Датчик движения PIR обеспечивает вход в Arduino для переключения коробки между «спящим» и «бодрствующим» режимами. В режиме ожидания Arduino активирует релейные каналы для запуска двигателя крышки, красных огней и дымогенератора. и воспроизвести звуки на WaveShield. Еще одна функция, которую я добавил, - это кнопка паузы. Это позволило мне временно заставить монстра замолчать, когда к нему подходят младшие дети.
Это Алииииииве!
Подъемник крышки - это устройство, которое быстро поднимает и опускает крышку, заставляя ее хлопать и подпрыгивать, как будто монстр пытается убежать. Это можно сделать несколькими способами, наиболее популярными из которых являются пневматические приводы и вращающиеся кулачки. Хотя я думаю, что пневматический привод с электронным управлением позволил бы мне сделать движения крышки более случайными, я решил использовать вращающийся кулачок, поскольку он казался более простым и наименее дорогим вариантом.
Я купил подержанный мотор стеклоочистителя на местной свалке металлолома за 15 долларов. Это было забавно. Я вошел и попросил мотор. Парень за стойкой спросил, «какой марки и модели автомобиль», когда я сказал «мне все равно», его голова немного наклонилась в сторону, и он посмотрел на меня немного сбоку. После того, как я объяснил, чем я занимаюсь, он захотел построить такой :)
Эти двигатели, независимо от марки / модели, работают от 12 вольт, вращаются с разумной скоростью и обладают большим крутящим моментом:идеально! Примечание. Когда вы его получите, убедитесь, что в нем есть старые жгуты проводов, так вам будет намного проще прикрепить к нему провод. также убедитесь, что у него есть шатун и смещенная стойка. Если главная опора двигателя - единственное физическое соединение, которое вам нужно работать с кулачком, скорее всего, соскользнет.
Установите мотор где-нибудь внутри коробки. Ставлю свой на одну из боковых стенок. Помните, что к нему будет подключен большой вращающийся кулачок, и он должен иметь возможность свободно вращаться и очищаться от любых предметов, особенно проводов, которые вы собираетесь положить в коробку. На YouTube есть несколько хороших руководств по работе с этими двигателями.
Я вырезал кулачок диаметром 12 дюймов из куска полуслойной древесины. сначала я вырезал идеальный круг. Я установил его на двигатель и использовал его, чтобы определить необходимую высоту двигателя в коробке. Я хотел, чтобы крышка приподнялась примерно на 2 дюйма. После подгонки я использовал лобзик, чтобы произвольно вырезать «зубья» на кулачке, изо всех сил стараясь сохранить их произвольную ширину и глубину.
Наконец, я прикрепил ролик к нижней стороне крышки, используя 2 металлических L-образных кронштейна, 1-дюймовую нейлоновую прокладку и болт с квадратным подголовком. Ролик расположен прямо над кулачком, так что он движется по зубцам кулачка.
Я использовал шину 12 В источника питания ATX для питания двигателя через реле, управляемое Arduino. Да, для того, чтобы все выстроить в линию, действительно требуется немного проб и ошибок. После повторного позиционирования ролика один или два раза ... трижды хорошо ... все выровнялось, и крышка начала подпрыгивать, как и планировалось!
Дыхание огня:дым и свет
Я использовал дешевый дымогенератор мощностью 400 Вт для создания дымовых эффектов. Из коробки это было радиоуправляемое. Чтобы управлять им с помощью Arduino, я открыл приемник и припаял две выводные линии к контактным площадкам спусковой кнопки. Это предоставило мне линии, которые я подключил к релейному каналу, управляемому Arduino. Это был простой прием, которому я научился, просмотрев несколько видеороликов на YouTube. Я также добавил старый шланг для пылесоса, чтобы дым выходил струей прямо из-под крышки. Мне понравился визуальный эффект, он помог уменьшить конденсацию пара на электронике внутри коробки.
Для фонарей я просто отрезал удлинитель для легких нагрузок и подключил его к релейному каналу. Связанная с ним цепочка из 100 красных светодиодов может затем включаться и выключаться Arduino.
Используйте свой внешний голос
WaveShield имеет 1/8 дюймовое гнездо для наушников, а также выход, а также 2 контакта ввода-вывода для прямого подключения. Я использовал патч-аккорд 1/8 дюйма для подключения к усилителю бас-гитары мощностью 30 Вт, который я позаимствовал из моей репетиционной комнаты. Подойдет любое количество динамиков с усилителем, включая динамики ПК. Но использование чего-то с солидным низким уровнем определенно является плюсом.
Закрепи это
Я купила пластиковые цепочки в магазине на Хэллоуин и напечатала висячий замок на 3D-принтере. Обертывание ими ящика добавило глубины и ощущения иллюзии.
Хэллоуин !!!
Поставьте ящик во дворе и спрячьте датчик движения в ближайшем кусте. Я использовал длинный провод динамика для подключения датчика, чтобы я мог поэкспериментировать с расположением так, чтобы монстр просыпался, когда кто-то приближался (около 5 футов) к ящику.
С наступлением темноты я понял, что все детали на внешней стороне ящика становились все труднее различимы. В конце концов я осветил его стробированным прожектором и остался очень доволен эффектом.
Подойдя к подъездной дорожке, любители уловок замечают рычащий ящик:одни с любопытством, другие на самом деле его боялись. Когда они приблизились и чудовище ожило, они вскакивали, и некоторые даже аплодировали. Это был огромный успех.
Улучшения
Мне надоело искать способы спрятать датчик движения в кустах, поэтому я приклеил его горячим клеем к животу пластиковой крысы, которую я мог бы разместить где-нибудь на подъездной дорожке или под ближайшим кустом. Я также установил телефонный разъем RJ11 на задней части коробки, чтобы я мог подключить датчик движения крысы с помощью телефонной веревки длиной 50 футов, что намного лучше, чем две жилы провода динамика, которые я использовал ранее.
Вы заметите, что я также добавил к этой новой пластине переключатель и несколько светодиодных индикаторов. Переключатель ПРИОСТАНОВЛЯЕТ все функции на приставке, не выключая его. Мой главный аварийный выключатель - это удлинитель внутри, и к нему трудно получить доступ, плюс он использует только сигнальное напряжение (5 В) на этом внешнем переключателе. Этот переключатель отлично подходит для остановки монстра для молодых любителей трюков и других, которые хотят заглянуть внутрь в ночь на Хэллоуин.
Ой! Для эффекта я накидываю пластиковые цепочки на коробку, и временами они могут быть громоздкими. Особенно, если вечером нужно залезть в ящик. Чтобы упростить задачу, я привязал к концам цепей черные пружинные карабины. Это позволяет мне быстро отсоединить / зацепить концы за проушины, которые я вкрутил в нижние углы коробки. Не очень высокотехнологично, но очень полезно.
Будущее
Есть несколько вещей, которые я хочу добавить в будущем. Может быть, пульт дистанционного управления, чтобы я мог приостановить или вызвать монстра на расстоянии. Я также добавлю некоторую обратную связь к подъемнику крышки, чтобы Arduino мог «знать», когда крышка открыта или закрыта. Несколько раз атлет останавливался на высокой точке цикла, которая делала «внутренности» коробки видимыми до следующего цикла пробуждения. Наконец, я могу подключить внешнее освещение / стробоскопы к Arduino, чтобы позволить им управлять с помощью программы и / или брелока дистанционного управления.
Репозиторий GitHub
Вы найдете последний код и схемы подключения Здесь, на GitHub
Код
- Набросок "Монстр в коробке"
- MonsterSounds.h
- MonsterSounds.ino
Набросок "Монстр в коробке" C / C ++
/ * Используемые контакты Wave Shield:2, 3, 4, 5, 10, 11, 12 и 13 Контакты 13, 12, 11 всегда используются SD-картой (это единственные контакты, которые имеют высокоскоростной SPI интерфейс). Затем есть еще 5 контактов, используемых для связи с ЦАП и SD-картой, но их можно настроить для подключения к любому контакту Arduino. Однако по умолчанию библиотека настроена на использование контактов 10 (для SD-карты) и контактов 2, 3, 4 и 5 для ЦАП. Для переключения этих выводов требуется изменение библиотеки - на выводы ссылаются их «аппаратные» имена выводов (например, PORTD и т. Д.), А не выводы arduino. Это означает, что доступны контакты 6, 7, 8, 9 и 6 аналоговых входов (также известные как цифровые входы / выходы 14-20). Https://learn.adafruit.com/adafruit-wave-shield-audio- shield-for-arduino / faq * / # include "MonsterSounds.h" #define RESERVED_00 0 // Зарезервировано для последовательного RX # define RESERVED_01 1 // Зарезервировано для Serial TX # define RESERVED_02 2 // Зарезервировано для Wave Shield #define RESERVED_03 3 // Зарезервировано для волнового экрана # define RESERVED_04 4 // Зарезервировано для волнового экрана # define RESERVED_05 5 // Зарезервировано для волнового экрана # define FOG_MACHINE 6 // Подключите цифровой вывод на Arduino к модулю реле # define RED_LEDS 7 // Подключите цифровой вывод на Arduino к релейному модулю # define LID_BOUNCER 8 // Подключите цифровой вывод на Arduino к релейному модулю #define RESERVED_09 9 // Подключите цифровой вывод на Arduino к релейному модулю # define RESERVED_10 10 // Зарезервировано для Wave Shield #define RESERVED_11 11 // Зарезервировано для Wave Shield #define RESERVED_12 12 // Зарезервировано для Wave Shield #define RESERVED_13 13 // Зарезервировано для Wave Shield #define PIR_SENSOR A 0 // Вход PIR # define MOTION_LED A1 // Светодиод:загорается при обнаружении движения (независимо от состояния паузы / сна / пробуждения) #define PAUSED_LED A2 // Светодиод:загорается, когда система приостановлена # define READY_LED A3 // Светодиод:загорается когда монстр находится в состоянии READY_TO_WAKE #define PAUSE_BUTTON A4 // Вход переключателя паузы # define DEBUG_BUTTON A5 // Вход переключателя отладки // Настройки таймера эффектов - в секундах (ИЗМЕНИТЬ) #define WAKE_DELAY 30 // Минимальное время между 'пробуждением' событий в секундах # define WAKE_DELAY_DEBUG 10 // переопределение WAKE_DELAY при включении переключателя DEGUB # define SLEEP_SOUND_DELAY 1 // количество секунд ожидания между попыткой сработать следующий звук "сна" #define WAKE_MIN 3 // минимальное время пробуждения in Seconds #define WAKE_MAX 5 // Максимальное количество времени "бодрствования" в секундах #define RED_LIGHT_EXTRA_TIME 1 // Позволяет красным светам работать немного дольше, чем шезлонг крышки, при желании # define SMOKE_EXTRA_TIME 2 // Позволяет дыму выходить при желании немного длиннее, чем крышка крышки // Эффекты Таймеры Настройки - в миллисекундах (не редактирует ЭТ) #define WAKE_DELAY_MILLIS WAKE_DELAY * 1000 # определить WAKE_DELAY_DEBUG_MILLIS WAKE_DELAY_DEBUG * 1000 # определить SLEEP_SOUND_DELAY_MILLIS SLEEP_SOUND_DELAY * 1000 #define WAKE_MIN_MILLIS WAKE_MIN * 1000 # определить WAKE_MAX_MILLIS WAKE_MAX * 1000 # определить RED_LIGHT_EXTRA_TIME_MILLIS RED_LIGHT_EXTRA_TIME * 1000 # определяют SMOKE_EXTRA_TIME_MILLIS SMOKE_EXTRA_TIME * 1000MonsterSound звуки; статическое беззнаковое долгое времяSinceLastSnore =0; статическое беззнаковое долгое время wakeAllowedTimer =0; статическое беззнаковое длинное lidBounceTimer =0; статическое беззнаковое длинное время lidBounceDuration =0; статическое беззнаковое длинное время SmokeTimer =0; статическое беззнаковое длинное статическое длительное время =0; redLightTimer =0; static unsigned long redLightDuration =0; enum States {STATE_INITIALIZE, // Только при запуске setup () и в первый раз в loop () STATE_PAUSED, // Отключить все звуки и эффекты STATE_SLEEPING, // Нет эффектов, звуки сна , не позволяет запускать пробуждение STATE_READY_TO_WAKE, // Нет эффекты, звуки сна, позволяют активировать бодрствование STATE_AWAKE}; // Запускает эффекты и звуки пробуждения монстра State state =STATE_INITIALIZE; void setup () {// инициализирует последовательную связь:Serial.begin (9600); // Устанавливаем все контакты реле pinMode (LID_BOUNCER, OUTPUT); pinMode (RED_LEDS, ВЫХОД); pinMode (FOG_MACHINE, ВЫХОД); pinMode (PAUSED_LED, ВЫХОД); pinMode (MOTION_LED, ВЫХОД); pinMode (READY_LED, ВЫХОД); // Принудительное отключение всех эффектов stopAllEffects (); pinMode (PIR_SENSOR, INPUT); pinMode (PAUSE_BUTTON, INPUT_PULLUP); pinMode (DEBUG_BUTTON, INPUT_PULLUP); звуки.initialize (); // Звуки монстров звуки.playSystemReady (); задержка (1000); Serial.println (); Serial.print («*** Система готова ***»); Serial.println (); } / * * ПРИМЕЧАНИЕ. Все кнопки используют подтягивания, поэтому НИЗКИЙ означает, что кнопка НАЖАТА. * Помните, что подтягивание означает, что логика переключения инвертирована. * Он становится ВЫСОКИМ, когда он открыт, и НИЗКИМ, когда он нажимается. * * Датчик движения PIR НЕ ведет себя подобным образом. * // * * Основной цикл обработки * - Управляет конечным автоматом монстра * / void loop () {boolean pauseSwitchClosed =digitalRead (PAUSE_BUTTON) ==LOW; логическое motionDetected =digitalRead (PIR_SENSOR) ==HIGH; digitalWrite (MOTION_LED, digitalRead (PIR_SENSOR)); переключатель (состояние) {case STATE_INITIALIZE:if (pauseSwitchClosed) {goToPause (); } еще {goToSleep (); } ломать; case STATE_PAUSED:если (! pauseSwitchClosed) {goToSleep (); digitalWrite (PAUSED_LED, LOW); } else {digitalWrite (PAUSED_LED, HIGH); } ломать; case STATE_SLEEPING:если (pauseSwitchClosed) {goToPause (); } иначе, если (isAllowedToWake ()) {goToReadyToWake (); } еще {processSleeping (); } ломать; case STATE_READY_TO_WAKE:если (pauseSwitchClosed) {goToPause (); digitalWrite (READY_LED, LOW); } иначе, если (motionDetected) {goToAwake (); digitalWrite (READY_LED, LOW); } еще {processSleeping (); } ломать; case STATE_AWAKE:если (pauseSwitchClosed) {goToPause (); } иначе, если (processAwakeAnimation ()) {goToSleep (); } // processAwakeAnimation () возвращает истину, когда все анимации полностью завершены break; по умолчанию:Serial.println («НЕИЗВЕСТНОЕ СОСТОЯНИЕ»); ломать; // Мы никогда сюда не доберемся}} / * * Переход в состояние паузы * / inline void goToPause () {Serial.println ("PAUSED"); состояние =STATE_PAUSED; stopAllEffects (); Sounds.stopAll ();} / * * Переход в состояние сна * / inline void goToSleep () {Serial.println ("GOING TO SLEEP"); состояние =STATE_SLEEPING; wakeAllowedTimer =millis ();} / * * Переход в состояние готовности к пробуждению * Это особый случай состояния сна * / inline void goToReadyToWake () {Serial.println ("READY TO WAKE"); состояние =STATE_READY_TO_WAKE; } / * * Переход в состояние пробуждения * - разбудить монстра и обработать эффекты и звуки * / inline void goToAwake () {Serial.println ("AWAKE"); состояние =STATE_AWAKE; wakeMonster ();} / * * обработать цикл активности SLEEP * - Запустить звуки сна * - Обновить таймер сна * / inline void processSleeping () {if ((millis () - timeSinceLastSnore)> SLEEP_SOUND_DELAY_MILLIS) {Sound.playSnore ( ); timeSinceLastSnore =millis (); }} / * * Определяет, разрешено ли монстру просыпаться в это время. * - Проверьте переключатель отладки, если он закрыт, мы используем более короткий таймер разрешенного пробуждения * - Монстр должен спать в течение заранее определенного минимального времени, прежде чем он может быть разбужен * - Загорается светодиод, когда он готов к пробуждению * / inline boolean isAllowedToWake ( ) {логическое isDebug =digitalRead (DEBUG_BUTTON) ==LOW; беззнаковый длинный requiredDelay =WAKE_DELAY_MILLIS; если (isDebug) {requiredDelay =WAKE_DELAY_DEBUG_MILLIS; } логическое isAllowed =(millis () - wakeAllowedTimer)> requiredDelay; если (isAllowed) {digitalWrite (READY_LED, HIGH); } return isAllowed;} / * * Wake Monster * Запускает анимацию пробуждения * Воспроизводит звуки пробуждения * * Вызовите это ОДИН РАЗ, чтобы запустить состояние пробуждения. * / void wakeMonster () {int activityDuration =random (WAKE_MIN_MILLIS, WAKE_MAX_MILLIS); // это как долго монстр будет активен Serial.print ("wake duration:"); Serial.print (activityDuration); Serial.println ("мс"); bounceLid (activityDuration); flashRedLight (activityDuration + RED_LIGHT_EXTRA_TIME_MILLIS); activateSmoke (activityDuration + SMOKE_EXTRA_TIME_MILLIS); Sounds.playRoar ();} / * * Управляет ходом анимации ПРОБУЖДЕНИЯ * Вызов этого КАЖДОГО ЦИКЛА во время состояния ПРОБУЖДЕНИЯ. * Возвращает ИСТИНА, когда все анимации завершены * / boolean processAwakeAnimation () {printTimersToLog (); логическое done1 =false; логическое done2 =false; логическое done3 =false; если (millis () - lidBounceTimer> lidBounceDuration) {bounceLid (0); done1 =true; } если (millis () - redLightTimer> redLightDuration) {flashRedLight (0); done2 =true; } если (millis () - smokeTimer> smokeDuration) {activateSmoke (0); done3 =true; } return done1 &&done2 &&done3;} / * * Управление эффектом:подпрыгивание крышки коробки * - дирация - это количество миллисекунд, в течение которых должен выполняться эффект * - длительность 0 означает, что эффект должен быть остановлен * / inline void bounceLid (unsigned большая продолжительность) {if (duration <=0) {energizeRelay (LID_BOUNCER); lidBounceDuration =0; } else {// запускаем подпрыгивание крышки de_energizeRelay (LID_BOUNCER); lidBounceTimer =millis (); lidBounceDuration =продолжительность; }} / * * Управление эффектом:мигание красным светом * - дирация - это количество миллисекунд, в течение которых эффект должен выполняться * - длительность 0 означает, что эффект должен быть остановлен * / inline void flashRedLight (unsigned long duration) {if (duration <=0) {energizeRelay (RED_LEDS); redLightDuration =0; } else {// запускаем мигание света de_energizeRelay (RED_LEDS); redLightTimer =миллис (); redLightDuration =продолжительность; }} / * * Start / Stop Effect:Activate Smoke * - дирация - это количество миллисекунд, в течение которых должен выполняться эффект * - длительность 0 означает, что эффект должен быть остановлен * / inline void activateSmoke (unsigned long duration) {// ' нажмите кнопку «дыма» // продолжительность должна быть фиксированным периодом времени, необходимым для того, чтобы машина отреагировала на действие // установить тайм-аут для остановки после продолжительности if (duration <=0) {energizeRelay (FOG_MACHINE); SmokeDuration =0; } else {// запускаем мигание света de_energizeRelay (FOG_MACHINE); SmokeTimer =миллис (); SmokeDuration =продолжительность; }} / * * Остановить все эффекты * - Это эффективно выключает монстра * / inline void stopAllEffects () {bounceLid (0); flashRedLight (0); activateSmoke (0);} / * * Печатает таймеры анимации пробуждения в журнал один раз в секунду * / inline void printTimersToLog () {static unsigned long timeofLastTimerLog =0; if (millis () - timeofLastTimerLog> =1000) {Serial.print ("крышка:"); Serial.print ((millis () - lidBounceTimer)> lidBounceDuration? 0:(lidBounceDuration - (millis () - lidBounceTimer))); Serial.print ("свет:"); Serial.print ((millis () - redLightTimer)> redLightDuration? 0:(redLightDuration - (millis () - redLightTimer))); Serial.print ("дым:"); Serial.println ((millis () - smokeTimer)> smokeDuration? 0:(smokeDuration - (millis () - smokeTimer))); timeofLastTimerLog =миллис (); }} / * * Реле включения * Устанавливает нормально открытый (NO) терминал в OPEN * Нормально закрытый становится закрытым * / inline void energizeRelay (int channel) {digitalWrite (channel, HIGH); } / * * Реле обесточивания * Устанавливает нормально разомкнутую (NO) клемму в положение ЗАКРЫТО. * Обычно закрытый становится ОТКРЫТЫМ * / inline void de_energizeRelay (int channel) {digitalWrite (channel, LOW); }
MonsterSounds.h C / C ++
Заголовок Arduino для библиотеки звуков монстров/ * ПРИМЕЧАНИЕ О ПИН-кодах ARDUINO * Контакты 13, 12, 11 всегда используются SD-картой (это единственные контакты, которые имеют высокоскоростной интерфейс SPI). * Кроме того, есть еще 5 контактов, используемых для связи с ЦАП и SD-картой, но их можно настроить для подключения к любому контакту Arduino. * Однако по умолчанию библиотека настроена на использование контактов 10 (для SD-карты) и контактов 2, 3, 4 и 5 для ЦАП. * Для переключения этих контактов требуется изменение библиотеки - на контакты ссылаются их «аппаратные» имена контактов (например, PORTD и т. Д.), А не по контактам Arduino. * Это означает, что доступны контакты 6, 7, 8, 9 и 6 аналоговых входов (также известные как цифровые входы / выходы 14-20). * * / #include#include #include #include static const char roar0 [] ="ROAR0000.wav"; static const char roar1 [] ="ROAR0001.wav"; static const char roar2 [] ="ROAR0002.wav"; static const char * const roarSounds [] ={roar0, roar1, roar2}; static const char sleep0 [] ="SNORE000.wav"; static const char sleep1 [] ="SNORE001.wav"; static const char sleep2 [] ="SNORE002.wav"; static const char * const sleepSounds [] ={sleep0, sleep1, sleep2}; int previousRoarSound =-1; класс MonsterSounds {частный:карта SdReader; // Этот объект содержит информацию о карте FatVolume vol; // Содержит информацию о разделе на карте FatReader root; // Содержит информацию о корневом каталоге тома FatReader file; // Этот объект представляет файл WAV для фразы WaveHC wave; // Одиночный волновой объект - одновременно воспроизводится только один звук void playfile (char * name); общедоступные:void initialize (); void playSystemReady (); void playRoar (); void playSnore (); void stopAll ();};
MonsterSounds.ino C / C ++
Код Arduino для библиотеки звуков монстров/ * ПРИМЕЧАНИЕ О ПИН-кодах ARDUINO * Контакты 13, 12, 11 всегда используются SD-картой (это единственные контакты, которые имеют высокоскоростной интерфейс SPI). * Кроме того, есть еще 5 контактов, используемых для связи с ЦАП и SD-картой, но их можно настроить для подключения к любому контакту Arduino. * Однако по умолчанию библиотека настроена на использование контактов 10 (для SD-карты) и контактов 2, 3, 4 и 5 для ЦАП. * Для переключения этих контактов требуется изменение библиотеки - на контакты ссылаются их «аппаратные» имена контактов (например, PORTD и т. Д.), А не по контактам Arduino. * Это означает, что доступны контакты 6, 7, 8, 9 и 6 аналоговых входов (также известные как цифровые входы / выходы 14-20). * * / void MonsterSounds ::initialize () {Serial.println ("Инициализация звуков ..."); if (! card.init ()) Serial.println (F ("Ошибка инициализации карты!")); if (! vol.init (card)) Serial.println (F («Нет раздела!»)); если (! root.openRoot (vol)) Serial.println (F («Не удалось открыть каталог»)); Serial.println (F ("Файлы найдены:")); root.ls (); randomSeed (analogRead (0));} void MonsterSounds ::playSystemReady () {this-> playfile ("WELCOME0.WAV");} void MonsterSounds ::playRoar () {int index =random (3); // 0, 1, 2 while (index ==previousRoarSound) {index =random (3); } previousRoarSound =index; this-> playfile (roarSounds [index]);} void MonsterSounds ::playSnore () {if (! wave.isplaying) // Не прерывайте существующий звук храпом {int index =random (3); // 0, 1, 2 this-> playfile (sleepSounds [index]); }} void MonsterSounds ::stopAll () {wave.stop (); // Остановить любой проигрываемый в данный момент WAV} // --------------------------------------- ---------------------------- // playfile () // Открыть и начать воспроизведение WAV-файла // ------ -------------------------------------------------- ----------- void MonsterSounds ::playfile (char * name) {PgmPrint ("Воспроизведение звука:"); Serial.println (имя); if (wave.isplaying) {// уже что-то играет, так что прекратите! wave.stop (); // останавливаем его} if (! file.open (root, name)) {PgmPrintln ("Файл не найден"); возвращение; } if (! wave.create (файл)) {PgmPrintln ("Недействительный WAV"); возвращение; } // хорошо, пора играть! wave.play ();}
Изготовленные на заказ детали и корпуса
monstersounds_7vLZD3NU4t.zipСхема
Производственный процесс