Для дальнейших экспериментов нам понадобится еще несколько новых устройств
индикации.
Раньше мы дело имели только с обычными светодиодами,
а сейчас познакомимся с новыми.
Для начала разберемся с пьезодинамиком — у нас появится звуковая индикация.
Давайте взглянем на схемку, которую я уже собрал, посмотрим, что она будет делать.
Вот так вот выглядит наш пьезодинамик или их называют пьезопищалка,
или зуммер — не важно.
У него есть всего два вывода: один из них я подключил к рельсе «земля»,
которая впоследствии соединяется с входом «земля» Arduino,
а второй подключен к цифровому пину, откуда мы будем ею управлять.
Затем, чтобы каким-то образом управлять пьезодинамиком,
я подключил снова датчик освещенности,
и у нас в совокупности получится такой классический эксперимент терменвокс.
Конечно, принцип его работы отличается от настоящего терменвокса: здесь мы будем
прикрывать фоторезистор от света, чтобы изменять высоту звучания пьезодинамика.
Давайте теперь посмотрим на скетч, который я подготовил.
У нас определены макроопределения
для пищалки и для фоторезистора.
Затем пин для динамика сделан выходом,
а затем я использую встроенную в язык Arduino функцию tone
для генерации сигнала определенной частоты для пищалки,
потому что если мы просто будем включать цифровой сигнал, звука мы не добьемся.
Поэтому в библиотеку Arduino уже встроена функция tone для работы с пищалкой.
Она использует 3 параметра.
Во-первых, мы ей говорим, какой пин нужен,
где подключена пищалка; затем какую
частоту в герцах туда нужно отправлять.
Здесь, как мы видим, я считываю аналоговый вход и умножаю его на 4,
потому что частоту в диапазоне от 0 до 1024 пьезодинамик
будет воспроизводить плохо, а если это увеличить в 4 раза,
то это будет как раз тот диапазон, с которым пищалка вполне справляется — там,
максимум до 4 килогерцов у нас будет получаться звук.
И третий параметр, не обязательный — это длительность звука.
Здесь я указал 10 миллисекунд, и loop у нас будет очень быстро обновляться.
На самом деле, можно было бы этот параметр даже не указывать.
В таком случае, возможно, была бы полезна функция noTone, которую я здесь просто
закомментировал, но чтобы она была перед глазами, как она выглядит.
Она отключает пищание на том пине, который вы ей указываете,
если вы не указали сразу длительность звука.
Теперь давайте попробуем включить это и посмотреть, что получится.
[ПИЩАНИЕ] Мы слышим вот такой вот звук,
и он, в зависимости от количества света на
фоторезисторе, меняется.
Честно говоря, на музыку это не очень похоже.
Настоятельно вам рекомендую щадить людей, которые находятся рядом с вами,
и не пытаться создавать мелодии с помощью пьезодинамиков.
Кроме этого, не пытайтесь подключать сразу несколько из них,
потому что полифонии вы все равно не добьетесь.
Используйте пьезодинамики для звуковой индикации.
Вам не всегда удобно смотреть на ваше устройство,
но зато вы можете о каких-то событиях, которые произошли в рамках программы,
сообщать определенным звуком определенной высоты, определенной длительности.
Двигаемся дальше.
Следующим новым устройством индикации у нас будет так
называемая светодиодная сборка, а именно шкала.
Светодиодной сборкой она называется потому,
что она состоит из десятка светодиодов, объединенных в один корпус.
То есть никаких хитростей кроме этого там внутри нет.
Соответственно, у нее есть 20 ножек, для каждого светодиода по 2.
И, обратите внимание, что здесь они одинаковой длины, поэтому вам нужно будет
экспериментальным путем обнаружить, где у вас «плюс», где «минус».
Про свои сборки я знаю,
что анод, то есть «плюс» у них находится со стороны маркировки.
Вот таким вот образом я устанавливаю шкалу на макетку.
К каждому из светодиодов подводится резистор, иначе он сгорит, а со
стороны «плюса» они у меня подсоединены к цифровым выходам Arduino со 2 по 11.
Нулевой и первый, как мы недавно говорили, стараемся не использовать.
И вот такой вот скетч я подготовил для проверки шкалы.
Это классический бегущий огонек,
когда мы будем просто по очереди включать светодиоды.
Что здесь интересного?
Во-первых, я не стал прописывать макроопределения для всех пинов,
для каждого светодиода, потому что мы все равно собираемся работать с ними подряд.
Поэтому я обозначил только пин, к которому подключен первый из 10 светодиодов и
последний — сейчас увидите, почему.
Затем я сделал еще одно макроопределение — это время задержки,
то есть сколько будет гореть каждый светодиод.
Теперь смотрите: вместо того, чтобы писать pin mode для каждого из 10 пинов,
с помощью которых мы управляем шкалой, я сделал цикл.
И здесь у нас есть некоторые новые нюансы.
Во-первых, счетчик может начинаться не с 0, да?
Здесь я его приравниваю к LED1, который у нас в данном случае равен 2.
Далее здесь у нас счетчик будет идти до тех пор,
пока он меньше или равен номеру последнего пина.
И обратите внимание на вот это место, где я счетчик увеличиваю не так,
как писал ранее: i = i + 1, а написал просто i + + — это так называемый
оператор инкремента, он увеличивает переменную на единицу.
И еще одна новость: раньше я очень пристально обращал ваше внимание
на фигурные скобки, на то, что они должны быть там, где это необходимо, где нужно
выделить какой-то фрагмент кода, и они должны попарно друг другу соответствовать.
Но для повышения читаемости и упрощения жизни иногда можно поступить проще.
Если в управляющей конструкции в операторе for вам нужно исполнять всего
лишь одну инструкцию, то фигурные скобки можно, в принципе, опустить.
То же самое, на самом деле, касается условного оператора if.
Таким образом, я здесь pin mode поместил в цикл,
но фигурных скобок перед и после не присутствует.
Если для вас этот момент сложный,
возьмите за правило писать фигурные скобки везде.
Затем мы настраиваем все нужные выходы как выходы,
просто передавая в pin mode переменную-счетчик i.
То есть сначала output станет второй пин, затем третий и так до одиннадцатого.
Что же происходит в loop?
В loop у нас еще один цикл for.
И здесь я еще одну новость вам показываю
— это еще один способ увеличивать переменную,
то есть i + = 1 — это то же самое, что i + + и i = i + 1.
Такая сокращенная запись подходит и для других арифметических операторов,
можно писать «- = », «* = », «/ = »,
если вам нужно работать со значением одной и той же переменной: например,
i * = 2, каждый раз i будет увеличиваться вдвое.
И внутри этого цикла мы последовательно включаем каждый светодиод,
затем ждем столько времени,
сколько указано в макроопределении LED_ON, и выключаем.
Затем переходим к следующей операции, и загорается следующий светодиод.
Давайте посмотрим, как это работает.
Вот такой бегущий огонек мы получили.
Как мы и написали, светодиоды включаются на 200 миллисекунд,
выключаются и так вот последовательно в цикле происходит.
Теперь давайте из шкалы сделаем действительно шкалу, которая увеличивается
или уменьшается в связи с увеличением или уменьшением какого-то значения.
Давайте наша шкала будет убывать или возрастать в
связи с поворотом ручки потенциометра.
Я вновь его включил в схему, «минус» я беру из той же рельсы,
к которой подключены все резисторы, и она соединена с «землей» Arduino,
«плюс» я привел на рельсу «плюс» и сюда вот к выводу
потенциометра — ну, просто, чтобы провода не путались.
Давайте посмотрим, что за скетч у нас получится.
Какова будет логика работы данного скетча?
В прошлый раз мы последовательно включали все 10 светодиодов из шкалы,
а теперь нам нужно включать то 2, то 5, то 10 — то есть не все сразу.
Нам нужно будет определять, какой светодиод включать последним.
Это будет связано как раз с тем, на сколько повернута ручка потенциометра.
Как я это реализую?
Ну, я добавил строчку с макроопределением для аналогового входа,
setup остался таким же, и здесь появляется новая строчка,
где мы используем очень полезную функцию языка Arduino.
Я создал переменную lastLed, в которой будет храниться номер последнего пина,
который нужно включать, и сохраняю в него то, что вернет функция map.
Она предназначена для перевода значения из одного диапазона в значение из
другого диапазона.
Как мы знаем, на аналоговом входе мы можем получить значения от 0 до 1023,
а на выходе нам нужно получить значение от 2 до 11 —
то есть у нас какой-то из пинов от второго до одиннадцатого будет последним.
Что принимает функция map в качестве параметров?
Сначала ей нужно дать значение, с которым работать.
В данном случае это значение возвращает analogRead: просто считывает
аналоговый вход.
Затем ей нужно дать 2 значения — это начало и конец входного
диапазона, то есть диапазона значений,
который может принимать первый аргумент.
И четвертый и пятый параметры — это начало и конец выходного диапазона.
Что это значит буквально?
Если analogRead с ANALOG_IN даст нам 0,
то это превратится в значение 2,
то есть начало входного и выходного диапазонов совпадают.
Если мы считаем 1023,
то мы получим 11, map превратит это в 11.
Любое промежуточное значение она превратит в какое-то
промежуточное значение из выходного диапазона; она вернет целое число,
то есть округлит его до ближайшего целого.
Итого в переменной lastLed у нас получится номер светодиода,
который нужно отключать последним.
Что происходит далее?
Далее у нас снова цикл со счетчиком, только на этот раз он изменяется не до
константы, не до фиксированного значения, а до значения lastLed, которое каждый раз
вычисляется и будет новым в зависимости от того, на сколько повернут потенциометр.
То есть если с помощью map мы вычислили, что последний светодиод
должен светиться на седьмом пине, то цикл будет бежать до 7.
А внутри него мы точно так же включаем и выключаем пин,
номер которого равен текущему значению счетчика,
и делаем задержку на значение LED_ON.
В данном случае я LED_ON сделал очень маленьким, в пару миллисекунд.
То есть у нас каждый светодиод горит очень мало времени, но,
поскольку они включаются и выключаются очень часто,
мы глазом даже не заметим, что они быстро моргают.
Давайте посмотрим, как это выглядит.
Вот такая шкала у нас получилась: очень удобное устройство индикации,
и к данному моменту вы уже понимаете, что вы можете вводить любое значение,
которое тем или иным способом вычислили,
то есть не обязательно отображать напрямую то, что получаете на входе.
Теперь перейдем к следующей светодиодной сборке: к семисегментному индикатору.