#4 Эксперимент “Музыкальная шкатулка”
Сегодня мы научим Arduino издавать отдельные звуки и даже проигрывать целые мелодии!
Перед выполнением эксперимента прочтите:
На этом занятии мы познакомимся с простейшим генератором звукового сигнала – пьезодинамиком. До этого момента, мы могли управлять внешними устройствами при помощи лишь одной команды. Мы могли подать на какой либо пин высокий цифровой сигнал:
digitalWrite(pin, HIGH);
или низкий цифровой сигнал:
digitalWrite(pin, LOW);
Для того, чтобы воспроизвести какой-либо звук с помощью пьезодинамика, необходима специальная команда [tone], обладающая двумя обязательными и одним необязательным параметром:
tone(pin, frequency, duration);
где:
- pin – номер пина, к которому подключен пьезодинамик;
- frequency – частота воспроизводимого звука (Гц);
- duration – длительность воспроизводимого звука (мс).
При этом, параметр [duration] является необязательным.
СБОРКА УСТРОЙСТВА НА МАКЕТНОЙ ПЛАТЕ
Нам понадобятся следующие компоненты:
- Arduino Uno;
- USB-кабель для подключения к компьютеру;
- Беспаечная макетная плата;
- 1 пьезодинамик;
- 1 датчик наклона и вибрации;
- 1 фоторезистор;
- 1 резистор, номиналом 10 кОм;
- 8 соединительных проводов разных цветов.
Соберите устройство по следующей схеме:
Схема устройства на макетной плате |
Принципиальная схема устройства |
Обратите внимание:
- Датчик наклона и вибрации будет выполнять роль обычной кнопки. Нюанс в том, что в стандартном положении (контактами вниз), датчик находится в замкнутом состоянии и пропускает через себя ток, т.е. будет передавать на 3-й пин высокий цифровой сигнал. Это нужно учитывать при программировании;
- Фоторезистор мы подключили по схеме делителя напряжения (её можно посмотреть в предыдущем занятии);
- При подключении пьезодинамика следует учитывать полярность. Если на корпусе динамика есть обозначение с символом “+”, то именно этот контакт динамика подключается к сигнальному пину, другой контакт идёт на “землю”.
ПРОГРАММИРОВАНИЕ
Для начала обозначим задачу. Нам необходимо собрать и запрограммировать устройство, которое будет издавать звуковые сигналы, опираясь на сигналы датчиков освещения и вибрации. Например, при размыкании контакта на датчике вибрации (например, во время тряски или переворачивания устройства), динамик должен проиграть короткую мелодию, а при попадании яркого света на датчик освещённости, устройство должно проиграть длинную мелодию.
Сперва давайте научимся воспроизводить звуки с помощью пьезодинамика. Для этого нам будет нужна всего одна команда:
tone(8, 262, 500);
Эта команда будет воспроизводить с динамика, подключенного к 8-му пину ноту “до” первой октавы в течении 0,5 секунды. Каждая нота имеет свою частоту, ниже размещена таблица, которая поможет записать ту или иную ноту с помощью её частоты.
Нота | 1-я октава | 2-я октава | 3-я оклава |
Частота звука, Гц | |||
До | 262 | 523 | 1047 |
До диез | 277 | 554 | 1109 |
Ре | 294 | 587 | 1175 |
Ре диез | 311 | 622 | 1245 |
Ми | 330 | 660 | 1319 |
Фа | 349 | 698 | 1397 |
Фа диез | 370 | 740 | 1480 |
Соль | 392 | 784 | 1568 |
Соль диез | 415 | 831 | 1661 |
Ля | 440 | 880 | 1720 |
Си бемоль | 466 | 932 | 1865 |
Си | 494 | 988 | 1976 |
Давайте попробуем запрограммировать и сыграть гамму “до мажор” с помощью нашего пьезодинамика:
#define buzzer 8 void setup() { pinMode(buzzer, OUTPUT); } void loop() { tone(buzzer, 262, 500); delay(500); tone(buzzer, 294, 500); delay(500); tone(buzzer, 330, 500); delay(500); tone(buzzer, 349, 500); delay(500); tone(buzzer, 392, 500); delay(500); tone(buzzer, 440, 500); delay(500); tone(buzzer, 494, 500); delay(500); tone(buzzer, 523, 1000); delay(1000); }
Обратите внимание на самую первую команду:
#define buzzer 8
Инструкция define в Arduino, как и в языке C++, нужна для того, чтобы упростить написание скетчей (программ). Мы можем один раз определить название какого-то фрагмента кода, а затем везде использовать только это название. В нашем случае мы определили слово “buzzer” как символ “8”. Теперь, при упоминании в программе, “buzzer” будет автоматически восприниматься компилятором как символ “8”. Замену мы сделали не просто так, а по 2-м причинам:
- заменив номер пина на “buzzer” мы “дали имя” этому пину и в дальнейшем вместо того, чтобы вспоминать – к какому пину подключен пьезодинамик, мы просто укажем это самое имя;
- номер пина достаточно часто упоминается в программе и в случае, если мы захотим переключить динамик на другой пин, например на 12-й, нам придётся править множество команд, содержащих номер старого пина. В случае же с заменой номера на такое “имя”, мы можем просто поменять одну цифру в инструкции и наша программа без проблем заработает.
Кроме этого, после каждой команды [tone] мы ставим задержку [delay]. Это нужно для того, чтобы дать время программе проиграть нужную ноту. Если убрать [delay], то все ноты программы будут сыграны практически одновременно (хоть каждая и со своей длительностью), а так как Arduino не умеет выводить более 1 ноты за раз с одного динамика, то мы услышим лишь последнюю прописанную ноту.
Кроме этого, можно использовать команду [tone] без параметра длительности, тогда программа будет проигрывать заданную ноту до того момента пока мы программно не приглушим динамик командой:
noTone(pin);
где:
- pin – номер пина, к которому подключен пьезодинамик.
Например, код программы с гаммой можно переписать, используя команду [noTone]:
#define buzzer 8 void setup() { pinMode(buzzer, OUTPUT); } void loop() { tone(buzzer, 262); delay(500); noTone(buzzer); tone(buzzer, 294); delay(500); noTone(buzzer); tone(buzzer, 330); delay(500); noTone(buzzer); tone(buzzer, 349); delay(500); noTone(buzzer); tone(buzzer, 392); delay(500); noTone(buzzer); tone(buzzer, 440); delay(500); noTone(buzzer); tone(buzzer, 494); delay(500); noTone(buzzer); tone(buzzer, 523); delay(1000); noTone(buzzer); }
Теперь мы знаем как заставить пьезодинамик издавать нужные нам звуки и мы можем написать программу для нашей музыкальной шкатулки (комментарии внутри программы):
#define buzzer 8 void setup() { pinMode(buzzer, OUTPUT); } void loop() { if (digitalRead(3)== LOW){ // если низкий сигнал на пине датчика вибрации, то ... tone(buzzer, 262, 250); // ... проигрываем три но "до" первой октавы delay(250); tone(buzzer, 262, 250); delay(250); tone(buzzer, 262, 500); delay(500); } if (analogRead(A0)>200){ // если аналоговый сигнал с датчика освещённости больше 200, то ... tone(buzzer, 262, 500); // проигрываем гамму delay(500); tone(buzzer, 294, 500); delay(500); tone(buzzer, 330, 500); delay(500); tone(buzzer, 349, 500); delay(500); tone(buzzer, 392, 500); delay(500); tone(buzzer, 440, 500); delay(500); tone(buzzer, 494, 500); delay(500); tone(buzzer, 523, 1000); delay(1000); } }
Обратите внимание:
- устройство следует поместить в закрытый ящик или шкатулку;
- если начать трясти шкатулку, то датчик вибрации начнёт размыкать контакт и мы услышим короткую мелодию;
- если открыть шкатулку, то свет снаружи попадёт на датчик освещённости и мы услышим проигрываемую гамму;
- порог срабатывания датчика освещённости (в нашем случае 200) необходимо подбирать самостоятельно в зависимости от освещённости вашей комнаты.
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОГО ВЫПОЛНЕНИЯ
Задание 1:
- Для того, чтобы сделать нашу шкатулку ещё “более музыкальной”, в качестве воспроизводимых мелодий можно использовать узнаваемые произведения. Используя фрагменты кода с мелодиями, приведёнными ниже, дополните нашу программу так, чтобы короткая мелодия (Star Wars) играла по сигналу с датчика вибрации, а длинная (Super Mario) по сигналу с датчика освещённости.
Задание 2*:
Добавьте в схему кнопку, которая будет служить для включения и выключения музыкальной шкатулки. Каждое нажатие кнопки должно сопровождаться звуковыми сигналами.