Журнал LinuxFormat - перейти на главную

LXF104:Arduino

Материал из Linuxformat
Перейти к: навигация, поиск
Свободная электроника

Содержание

Аппаратный хакинг по новой

Arduino
ЧАСТЬ 2 Игра, которую мы создали месяц назад – немая, и это дает Грэму Моррисону повод добавить звук, используя только Arduino и динамик.

Месяц назад мы создали игру типа «Саймон сказал», используя Arduino – аппаратную платформу для простых и не очень электронных проектов. Мы разместили три кнопки и три светодиода на макетной плате и написали маленькую программу, передававшую на них случайную последовательность вспышек, которую игрок должен был повторить, нажимая на кнопки в заданном порядке. При каждом правильном воспроизведении последовательности ее длина увеличивалась на единицу, и все повторялось снова. Чем большей длины случайные последовательности вы запоминали, тем больше очков получали.

Мы собираемся надстроить проект прошлого месяца, добавив другую важную особенность – звук! Это очень просто, но оказывает потрясающий эффект на игровой процесс. Если вместе с Arduino вы купили стартовый набор компонентов, есть хороший шанс, что туда включено нечто вроде пьезоэлемента – обычно это маленькая черная круглая штука (размером примерно с «нажималку» кнопки), с маленькой дырочкой наверху. Пьезоэлемент способен как генерировать, так и улавливать звук, почему его и включают в стартовый набор. Если пьезоэлемента у вас нет, не горюйте – берите пример с нас. В магазин мы за ним не пошли, а раскурочили корпус старого компьютера, выудили оттуда динамик и припаяли два провода к контактам по краям магнита, управляющего динамиком (а вы, может, сумеете вынуть его прямо с проводами). Подойдет любой маленький динамик – вы удивитесь, какая масса электронных приборов содержит подобное. Если у вас валяется что-то сломанное и электронное, загляните вовнутрь.

Звук и свет

Подсоединив динамик к Arduino, придадим вспышкам светодиодов звук, чтобы каждой из них соответствовала определенная нота. Тогда случайная последовательность вспышек заодно будет сопровождать- ся сгенерированной мелодией, а игрок пусть повторяет последовательность вспышек/мелодию, нажимая на три кнопки.

Даже если игра «Саймон сказал», которую мы создаем, вам ни к чему, вы можете использовать то, что изучите на следующих страницах, для использования в больших проектах. Звук в Arduino будет просто работать, и есть немало приложений, где ему найдется применение.

Генерация звука

Существует несколько способов генерировать звук с помощью Arduino, разных уровней сложности. Мы воспользуемся простейшим, известным также как «битье по битам». Этот метод позволяет генерировать ноты различной тональности, но не более – просто «бип» некоторой длительности. Не спешите воротить нос – звук на самом деле очень приятный, и он знаком всем, кто вырос в 1980-х. Наш звук будет очень похож на тот, что порождали подлинные игры «Саймон» и много других электронных устройств, в том числе типичный «бип», который звучит при включении компьютера. Выбран он потому, что это самый простой и дешевый способ получения звука, и вам не нужны никакие аудиосредства, кроме динамика.

Если вы интересуетесь звуком и хотите сделать что-нибудь чуть более амбициозное, то есть другие методы генерации, использующие цифро-аналоговый преобразователь для воссоздания сэмплов и реальных звуков; есть и проекты Arduino, которые воспроизводят различные дискретные компоненты синтезаторов, включая осцилляторы, фильтры и огибающие, а также увязку всего этого с MIDI. Тем, кому интересны такие приложения, сайт Arduino предоставляет исчерпы- вающую информацию.

Бип... Бип...

Но нам-то нужен всего лишь «бип». Смотрите, как легко это делается. Присоедините положительный контакт динамика к контакту питания 9 В на Arduino (на плате динамика должны находиться маленькие знаки «плюс» и «минус», показывающие полярность). Далее соедините минусовый провод с цифровым контактом 9 на Arduino – вот и все необходимые соединения. Если у вас уже собрана игра «Саймон сказал» из прошлого номера, эти два соединения должны располагаться параллельно проводам, идущим к и от светодиодов и кнопок на макетной плате. Осталось написать код, создающий звук. Основной принцип очень похож на переключение светодиодов из «включено» в «выключено», по крайней мере с точки зрения программирования. Поэтому метод и назван битье по битам. Сперва надо установить режим для контакта, подключенного к динамику, затем послать сигналы HIGH и LOW на тот же контакт, тем самым посылая цифровой сигнал по проводу на динамик. В результате мы получим небольшой «клик», так как катушка динамика в этот момент дернется. Если вы зарисуете движение на листке бумаги, то увидите, что динамик сгенерировал прямоугольный импульс – резкое движение вверх при включении и затем такое же резкое при спаде. Теперь, послав гораздо больше таких маленьких сигналов на динамик, мы сгенерируем больше таких импульсов, и суммарный эффект от движения катушки и диффузора динамика вперед и назад даст нам звуковой тон, высота которого будет зависеть от числа таких циклов в секунду.

...Бип! Бип! Ура!

Хватит теории – перейдем к шумам. Откройте новый проект Arduino в Arduino IDE (или в любимом текстовом редакторе) и введите следующие строки в начале файла:

 #define note_len 200000
 int speakerOut = 9;
 void setup() {
   pinMode(speakerOut, OUTPUT);
 }

Эти строки говорят контроллеру Arduino, как мы хотим использовать контакты на плате. Теперь надо добавить код, генерирующий звук. Для этого просто вставьте следующую функцию:

void playTone(int note) {
  long elapsed_time = 0;
  while (elapsed_time < note_len) {
     digitalWrite(speakerOut,HIGH);
     delayMicroseconds(note / 2);
     digitalWrite(speakerOut, LOW);
     delayMicroseconds(note / 2);
     elapsed_time += (note);
   }
}

В цикле ‘while’, цифровой импульс посылается на динамик, используя функции digitalWriteHIGH для включения и LOW для выключения. Между каждым применением digitalWrite задается задержка с помощью функции delayMicroseconds. Как следует из ее названия, она останавливает работу программы на число микросекунд, заданное в скобках. В нашем случае мы присвоили это число переменной ‘note’, так как именно от значения этой задержки зависит требуемый тон: чем меньше задержка, тем быстрее импульсы посылаются на динамик, и тон будет выше. Мы затем добавляем суммарную длину всех задержек в переменную elapsed_time, чтобы знать, сколько времени у нас проигрывается звук, и когда нота проиграется с длительностью, заданной в note_len, мы выйдем из цикла while.

LXF104 50 1.jpg Все звуки в проекте генерируются с помощью функции playTone.

Для создания звука, переходим к окончательной функции – loop. Она выполняется Arduino постоянно, и здесь можно вызвать функцию playTone для создания звука:

void loop() {
playTone (3830);
}

Поместим его в игру

Теперь, создав основу для генерации звука с помощью Arduino и дешевого динамика, применим изученное к нашей игре. Первый шаг – скопировать функцию playTone из нашего предыдущего примера в исходный код игры. Мы будем использовать ее похожим способом, вызывая ее, когда необходимо издать звук. Чтобы идти в ногу с новой функцией, нам также необходимо добавить похожую строку pinMode в функцию setup() и убедиться, что описания note_len и speakerOut скопированы в начало файла. Нам также надо задать через #define различные задержки при проигрывании функции playTone. Их использование позволит нам избежать голых чисел в качестве значений, какие мы использовали в функции loop(), и так как у нас всего три кнопки, нам нужно три тона:

#define play_c 3830
#define play_d 3400
#define play_e 3038

Мы взяли величину задержки с сайта Arduino, где подобраны готовые значения для каждой ноты. Теперь можно использовать константы play_c, play_d и play_e [в музыке, С, D и E – обозначения нот до, ре, ми, – прим. ред.] как аргументы функции playTone для задания требуемого тона. Следующее, что надо добавить – издание звука при вспышке соответствующего светодиода; мы можем сделать это с помощью playSequence – функции, которая зажигает светодиоды. Перескочив в середину этой функции, вы можете вспомнить, что на прошлом уроке мы использовали условие case: требуемый светодиод зажигался в зависимости от заданного значения в текущей позиции массива. Можно просто добавить команду playTone в каждое условие для проигрывания звука, когда загорается светодиод:

switch (rand_array[i]) {
   case 0:
     digitalWrite(ledPin1, HIGH);
     playTone(play_c);
     break;
   case 1:
     digitalWrite(ledPin2, HIGH);
     playTone(play_d);
     break;
   case 2:
     digitalWrite(ledPin3, HIGH);
     playTone(play_e);
     break;
   }

Как видите, мы задали три различных ноты для трех различных светодиодов, и они должны проигрываться так же, как и световая последовательность, которую должен скопировать игрок.

Теперь, обеспечив проигрывание, необходимо добавить похожую функцию в секцию ввода в коде, чтобы при нажатии игроком кнопки динамик выдавал соответствующий звук. В прошлом месяце мы создали функцию, названную readButtons, отвечающую за ввод. Вместо распределения всех нажатий кнопки по условиям case, мы использовали вложенные if, и сюда тоже надо добавить корректные значения playTone.

if (val1==LOW){
  playTone(c);
  return 0;
} else if (val2==LOW) {
  playTone(d);
  return 1;
} else if (val3==LOW) {
  playTone(e);
  return 2;
}

Наша программа научилась проигрывать ноты при нажатии кнопок. Только не перепутайте тоны: они должны совпадать в секциях программы для ввода и проигрывания, иначе игрок будет слышать различные ноты, когда он запоминает их и когда нажимает кнопки.

Вот и вся базовая звуковая функциональность. Осталось только одно дополнение, которое вы, возможно, захотите добавить – звуки реакции системы: при правильно введенной последовательности и при ошибке. Как вы можете помнить, у нас уже есть две функции, отвечающие за эти действия – flashSuccess и flashFailure, они обе были исключены из исходного кода по причине нехватки места. Вы можете захотеть добавить соответствующий унизительный звук провала, чтобы игрок осознавал свою ошибку – например, длинный низкий тон типа такого:

playTone(8000);
playTone(8000);

Но, может быть, вам захочется создать нечто более раздражающее. Звук, генерируемый динамиком, не обязан быть мелодичным, и можно устроить настоящую какофонию, быстро подавая ноты на динамик. Наша функция playTone имеет фиксированную задержку, и нам надо исправить это, если мы хотим менять звуки быстро. Решение – ввести еще один аргумент для длительности ноты. Для этого изменим функцию playTone следующим образом:

 void playTone(int note, long note_len )

Необходимо также сменить значение #define note_len 200000 в начале исходного кода на #define duration 200000, чтобы не путать имена переменных. Проделав этих два изменения, надо обеспечить, чтобы каждый раз при вызове playTone подставлялась длительность. Например:

 playTone(play_c, duration);

Теперь у вас есть больший контроль над продолжительностью звука, генерируемого динамиком, и вы можете быстро передавать одну ноту за другой. Вот как мы заменили функцию flashFailure на устрашающий звук ошибки, вместо набора огоньков:

 void flashFailure(){
 for (int i=0; i<=10; i++){
   playTone (play_c, 10000);
   playTone (play_d, 10000);
   playTone (play_e, 10000);
 }
 }

Это просто цикл, который очень быстро проигрывает три ноты, имитируя битву лазерных пушек и ясно информируя игрока, что он сделал ошибку при попытке воспроизвести последовательность. Мы обнаружили, что при наличии звука можно обойтись без функции реакции на успех: функция ошибки достаточно информативна. Удалите flashSuccess() из void loop(), и увидите, что мы имели в виду.

Игра стала более интуитивной, и вы можете воссоздать последовательность нажатия кнопок гораздо быстрее, не дожидаясь всякий раз подтверждения. Со звуком весь проект доставляет больше удовлетворения, и хотя «бипы» немного упростили игру, зато вы можете повторять гораздо более длинные последовательности, особенно если у вас хорошая музыкальная память.

Через месяц

На следующем уроке мы сделаем другое важное дополнение к игровому механизму. Пока мы просто запускали световые последовательности, без каких-либо шансов узнать, выигрывает ли игрок, или уведомлений о том, как далеко он зашел на случай, если кто-то другой хочет добиться похожих результатов. Для решения данной проблемы мы добавим сохранение очков игрока и будем отображать их, когда игрок решит, что с него хватит. С этой целью мы запрограммируем семисегментный дисплей, напоминающий решения 1970-х, и используем его для вывода очков, а также для текущего статуса запущенной игры. До встречи, и удачи вам в аппаратном хакинге. LXF

Мультиметры

Немного освоившись в играх с Arduino, вы можете наткнуться на одно полезное устройство – мультиметр [или тестер]. Это эквивалент инструментов отладки программиста для инженера-электронщика, и он неоценим, когда у вас что-то не заработает и надо выяснить, почему.

Он также является прекрасным инструментом для обучения, помогая вам увидеть, что и как происходит в вашей схеме. Другое хорошее качество мультиметра – его дешевизна, особенно для любителей, ведь базовые модели стоят несколько сотен рублей. Большинство имеют похожие режимы и функциональность, с круговым переключателем режимов и цифровым дисплеем [в России еще встречаются стрелочные индикаторы, – прим. пер.], отображающим выходные параметры. Мультиметром можно измерять напряжения, или сопротивления резисторов, но самая полезная функция для маленьких проектов Arduino – «проводимость». Это когда вы проверяете, соединены ли два компонента или участка цепи, подавая на них небольшое напряжение с мультиметра. Для этой цели Arduino должен быть отключен от источника питания – как и любая тестируемая схема – и тест проводимости генерирует звук, когда достаточное напряжение передается от одного сенсора к другому. На переключателе эта функция обычно изображается в виде ноты или динамика. Тест на проводимость – лучший способ проверить целостность ваших проводов, до перехода к тестированию отдельных компонентов.

Принципиальная схема

В прошлом месяце была упущена одна вещь, которая облегчает понимание устройства цепи. Для проектов, состоящих более чем из двух светодиодов, трудно описать словами, как все соединено. Мы собирались включить вам в помощь электросхему, но не хватило места. К счастью, нас выручил один из читателей: Стюарт Уоткисс [Stewart Whatkiss] прислал собственную схему проекта, и мы печатаем ее здесь, добавив динамик, чтобы отразить изменения урока этого месяца.

Даже если вы не видели таких схем со школьных времен, понять ее не трудно, и она очень упрощает работу по конструированию электрической цепи. Вы можете видеть различные выходные контакты платы Arduino, и как они подключены к резисторам (показанным с их сопротивлением в 1 КОм). Другие символы обозначают переключатели и светодиоды. Переключатели показаны как кратковременный разрыв цепи, а светодиоды – как перевернутые треугольники со стрелками, изображающими излучаемый свет, идущий от элемента. Еще одно устройство – динамик; ну, его-то легко узнать.

LXF104 51 1.jpg LXF104 51 2.jpg

Персональные инструменты
купить
подписаться
Яндекс.Метрика