ББК 32.973.26
Б71
Блум Джереми
Б71 Изучаем Arduino: инструменты и методы технического волшебства:
Пер. с англ. — СПб.: БХВ-Петербург, 2015. — 336 с.: ил.
ISBN 978-5-9775-3585-4
Книга посвящена проектированию электронных устройств на основе микро-
контроллерной платформы Arduino. Приведены основные сведения об аппаратном
и программном обеспечении Arduino. Изложены принципы программирования
в интегрированной среде Arduino IDE. Показано, как анализировать электрические
схемы, читать технические описания, выбирать подходящие детали для собствен
ных проектов. Приведены примеры использования и описание различных датчи
ков, электродвигателей, сервоприводов, индикаторов, проводных и беспроводных
интерфейсов передачи данных. В каждой главе перечислены используемые ком
плектующие, приведены монтажные схемы, подробно описаны листинги про
грамм. Имеются ссылки на сайт информационной поддержки книги. Материал
ориентирован на применение несложных и недорогих комплектующих для экспе
риментов в домашних условиях.
Для радиолюбителей
УДК 004
ББК 32.973.26
Authorized Russian translation o f the English edition o f Exploring Arduino®: Tools and Techniques for Engineering
Wizardry, ISBN 978-1-118-54936-0 © 2013 by John Wiley & Sons, Inc. All Rights Reserved.
This translation published under license by BHV-St Petersburg, © 2015.
Авторизованный перевод с английского на русский язык произведения Exploring Arduino®' Tools and Techniques
for Engineering Wizardry, ISBN 978-1-118-54936-0 © 2013 by John W iley & Sons, Inc. Все права защищены.
Этот перевод публикуется по лицензии издательством "БХВ-Петербург", © 2015
Об авторе..................................................................................................................................... 15
О техническом редакторе..................................................................................................... 16
Благодарности............................................................................................................................17
Введение.......................................................................................................................................19
Для кого эта книга..........................................................................................................................19
О чем эта книга.............................................................................................................................. 20
Что вам понадобится..................................................................................................................... 20
Электронные ресурсы к книге...................................................................................................... 20
Дополнительный материал и поддержка..................................................................................... 21
Что такое Arduino?......................................................................................................................... 21
О движении Open Source............................................................................................................... 22
Несколько советов читателю........................................................................................................ 22
Дополнительная информация издательства "БХВ-Петербург"
к русскоязычному изданию книги................................................................................................ 23
О техническом редакторе
чества проектов, которые дадут навыки, необходимые для реализации своих собст
венных разработок. Более подробно об особенностях Arduino мы расскажем в гла
ве 1. Если вы интересуетесь внутренним устройством Arduino, то вам повезло —
это платформа с открытым исходным кодом, и все схемы и документация находят
ся в свободном доступе на сайте Arduino.
1 Большая часть видеоуроков по Arduino переведена на русский язык. Локализованную версию можно
найти на канале http://www.youtube.com/AmperkaRU. — Примем, пер.
Введение 23
Дополнительная информация
издательства "БХВ-Петербург"
к русскоязычному изданию книги_________________
Для выполнения проектов, описанных в книге, издательство подготовило специ
альный набор, который включает в себя Arduino Uno, плату прототипирования и
необходимые электронные компоненты. Подробную информацию о наборе можно
получить по адресу http://www.bhv.ru/books/193108.
В этой части_____________________________________
Список деталей
Для повторения примеров главы вам потребуются следующие детали:
♦ плата Arduino Uno;
♦ USB-кабель.
При изучении платформы Arduino для повторения проектов из книги вам потребу
ются три главных компонента:
♦ основная плата Arduino;
♦ платы расширения;
♦ интегрированная среда разработки Arduino — Arduino IDE.
В этой книге рассмотрены преимущественно фирменные платы Arduino. Подойдут
и выпускаемые в большом ассортименте клоны Arduino — платы, совместимые как
с аппаратной, так и с программной частью Arduino. Там, где это будет необходимо,
вы найдете рекомендации по поводу пригодности тех или иных плат для различных
устройств. Большинство проектов базируется на плате Arduino Uno. Сначала мы
рассмотрим общие функциональные возможности всех разновидностей плат
Arduino, а затем укажем особенности, присущие каждой плате. В результате вы
сможете подобрать подходящую плату Arduino для каждого конкретного проекта.
Arduino Uno (рис. 1.3) — основная плата линейки Arduino, она будет использовать
ся в большинстве примеров книги. Плата укомплектована микроконтроллером
ATm ega328 и микросхемой 16U2 преобразователя USB. Микроконтроллер
ATmega 328 может быть выполнен в исполнении DIP или SMD.
Уникальность платы Arduino LilyPad (рис. 1.9) в том, что она разработана как часть
одежды. Ее можно вшить в ткань вместе с датчиками, светодиодами и т. п. Для
программирования платы необходим кабель FTDI.
Резюме________________________________________
В этой главе вы узнали о следующем:
♦ Из каких компонентов состоит плата Arduino.
♦ Как загрузчик Arduino позволяет запрограммировать плату Arduino через ин
терфейс USB.
♦ Каковы различия между основными платами Arduino.
♦ Как установить Arduino IDE и соединить плату Arduino с компьютером.
♦ Как загрузить и выполнить первую программу.
Цифровые контакты ввода
широтно-импульсная модуляция
Список деталей
Для повторения примеров главы понадобятся следующие детали:
♦ плата Arduino Uno;
♦ макетная плата;
♦ перемычки;
♦ 1 резистор номиналом 10 кОм;
♦ 3 резистора номиналом 220 Ом;
♦ кабель USB;
Ф кнопка;
Ф одноцветный светодиод 0 5 мм;
Ф RGB-светодиод 0 5 мм с общим катодом.
отверстия. Все красные отверстия соединены между собой и служат, как правило,
для подачи питания. Для большинства проектов из этой книги это +5 В. Все синие
отверстия тоже электрически соединены друг с другом и играют роль шины зазем
ления. Каждые пять отверстий, расположенных вертикальными рядами, также со
единены друг с другом. Посередине есть свободное место для удобства установки
компонентов на макетной плате. Электрические соединения отверстий показаны на
рис. 2.1 утолщенными линиями.
вить как поток воды, а напряжение — как высоту перепада. Вода (или ток)
всегда течет из точки с большей высотой (более высокое напряжение) к точке
с меньшей высотой (или более низкому напряжению). Ток, как вода в реке, все
гда будет идти по пути наименьшего сопротивления в цепи;
♦ по аналогии сопротивление является отверстием для протекания тока. Когда во
да (ток) течет через узкую трубу, за одинаковое количество времени проходит
меньшее количество, чем через широкую трубу. Узкая труба эквивалентна
большему сопротивлению, потому что вода будет течь медленнее. Широкая
труба эквивалентна малому сопротивлению, потому что вода (ток) может течь
быстрее.
Закон Ома определяется следующим образом:
Таким образом, при сопротивлении резистора 150 Ом через него и светодиод про
текает ток 20 мА. По мере увеличения сопротивления ток будет уменьшаться.
Резистор 220 Ом обеспечивает достаточную яркость свечения светодиода, к тому
же этот номинал очень распространен.
Еще одно важное соотношение — формула для расчета мощности, которая показы
вает, сколько ватт рассеивается на каждом компоненте. Увеличение мощности рас
Гпава 2. Цифровые контакты ввода-вывода, широтно-импульсная модуляция 47
void s e tu p ()
{
pinMode (LED, OUTPUT); / / Конфигурируем контакт светодиода как выход
digitalW rite(L E D , HIGH); / / Устанавливаем значение HIGH на выходе
}
void lo o p () {
/ / В цикле ничего не выполняем
}
Соберите схему, как показано на рис. 2.2, и загрузите код листинга 2.1 в плату
Arduino. Обратите внимание, что в этой программе я использовал оператор ини
48 Часть I. Общие сведения о платформе Arduino
void s e tu p ()
{
pinMode (LED, OUTPUT); / / Конфигурируем контакт светодиода как выход
}
void lo o p ()
{
fo r ( in t i=100; i<=1000; i=i+100)
{
digitalW rite(L E D , HIGH);
d e la y (i);
digitalW rite(L E D , LOW);
d e la y (i);
}
}
Скомпилируйте код листинга 2.2, загрузите его на свою плату Arduino и посмотри
те, что происходит. Теперь разберемся, как это работает.
Гпава 2. Цифровые контакты ввода-вывода, широтно-импульсная модуляция 49
Функция an aio g w rite () имеет два аргумента: номер контакта и 8-разрядное значе
ние в диапазоне от 0 до 255, устанавливаемое на этом контакте.
В листинге 2.3 приведен код программы генерации ШИМ-сигнала на контакте 9
для плавного управления яркостью светодиода.
void s e tu p ()
{
pinMode (LED, OUTPUT); / / Конфигурируем контакт светодиода как выход
}
void lo o p ()
{
fo r (in t i=0; i<256; i++)
{
analogWrite(LED, i ) ;
d e la y (10);
}
fo r (in t i=255; i>=0; i — )
{
analogWrite(LED, i) ;
d e la y (10);
}
}
Проверьте, что шины питания и земли обеих плат надежно соединены друг с другом.
Тогда в дальнейшем вы сможете легко менять элементы на макетной плате.
Прежде чем написать программу опроса состояния кнопки, важно понять назначе
ние резистора в этой схеме. Почти для всех цифровых входов необходим дополни
тельный стягивающий (pull-dow n) или подтягивающий (p u ll-u p ) резисторы для ус
тановки ’’значения по умолчанию” на входном контакте. Представьте себе, что в
схеме на рис. 2.5 нет резистора 10 кОм. В этом случае при нажатии на кнопку на
выводе будет значение high . Н о что происходит, когда кнопка не нажата? В такой
ситуации входной контакт не привязан ни к чему, как говорят, ’’висит в воздухе”.
А поскольку вывод физически не подключен ни к 0 В, ни к 5 В, чтение значения
может дать неожиданный результат. Электрические помехи на близлежащих выво
дах могут привести к тому, что значение напряжения будет колебаться между high
и low. Чтобы предотвратить это, стягивающий резистор подключают так, как пока
зано на оис. 2.5.
Гпава 2. Цифровые контакты ввода-вывода, широтно-импульсная модуляция 53
v oid s e tu p ()
{
pinMode (LED, OUTPUT); // Сконфигурировать контакт светодиода
// как выход
pinMode (BUTTON, INPUT); / / Сконфигурировать контакт кнопки
// как вход
}
void lo o p ()
{
i f (digitalRead(BUTTON) == LOW)
{
digitalW rite(L E D , LOW);
}
e ls e
{
digitalW rite(L E D , HIGH);
}
}
void s e tu p ()
{
pinMode (LED, OUTPUT); // Сконфигурировать контакт светодиода
// как выход
pinMode (BUTTON, INPUT); // Сконфигурировать контакт кнопки
// как вход
}
/*
* Функция сглаживания дребезга
* принимает в качестве аргумента предыдущее состояние кнопки
* и выдает фактическое.
*/
boolean debounce(boolean l a s t)
{
boolean c u rre n t = digitalRead(BUTTON); / / Считать состояние кнопки
i f ( l a s t != cu rre n t) / / Если изменилось...
Гпава 2. Цифровые контакты ввода-вывода, широтно-импульсная модуляция 57
{
d e la y (5); / / Ждем 5 мс
c u rre n t = digitalRead(BUTTON); / / Считываем состояние кнопки
re tu r n c u rre n t; / / Возвращаем состояние кнопки
}
}
void lo o p ()
{
cu rren tB u tto n = d e b o u n c e (la stB u tto n );
i f (la s tB u tto n == LOW && c u rren tB u tto n == HIGH) / / Если нажатие
{
ledOn = !ledOn; / / Инвертировать значение
/ / состояния светодиода
}
la stB u tto n = c u rren tB u tto n ;
digitalW rite(L E D , ledOn); / / Изменить статус
/ / состояния светодиода
}
Теперь рассмотрим текст листинга 2.5 подробнее. Сначала заданы номера контак
тов для подключения кнопки и светодиода. Затем объявлены три глобальные логи
ческие переменные, которые будут изменяться в программе (значение глобальной
переменной можно менять в любой части программы). Каждой из трех переменных
присвоены начальные значения ( low, low и fa ls e ). Далее в программе значения этих
переменных могут изменяться с помощью оператора присваивания =.
Рассмотрим функцию подавления дребезга кнопки boolean debounce () . Эта функ
ция принимает логическую переменную (имеющую только два состояния:
tr u e /f a ls e , high / low, вкл./выкл., 1/0) предыдущего состояния кнопки и возвращает
текущее значение состояния кнопки. Внутри функции текущее состояние кнопки
сравнивается с предыдущим с помощью оператора != (не равно). Если состояния
отличаются, то кнопка, возможно, нажата. Затем ожидаем 5 мс (этого достаточно,
чтобы состояние кнопки стабилизировалось после дребезга), прежде чем проверить
состояние кнопки снова. Затем вновь проверяем состояние кнопки. Как вы помни
те, функции могут возвращать результат. Данная функция возвращает текущее зна
чение булевой локальной переменной, которая объявлена и используется только
в функции debounce (). Когда функция debounce () вызывается из основного цикла,
возвращенное значение записывается в глобальную переменную cu rren tB u tto n , ко
торая была определена в начале программы.
После вызова функции debounce () И установки значения переменной cu rren tB u tto n
происходит сравнение текущего и предыдущего значений состояния кнопки с по
мощью оператора && (логический оператор "И", означающий, что выражение
в скобках выполнится, только если истинно каждое из равенств, разделенных опе
ратором &&).
Если ранее состояние кнопки было low, а теперь high , значит, кнопка была нажата и
нужно инвертировать значение переменной ledOn. Это действие выполняет опера
58 Часть I. Общие сведения о платформе Arduino
void s e tu p ()
{
pinMode (BLED, OUTPUT); / / Сконфигурировать
/ / BLUE контакт светодиода как выход
Гпава 2 . Цифровые контакты ввода-вывода, широтно-импульсная модуляция 59
/*
* Выбор режима светодиода.
* Передача номера режима и установка заданного режима светодиода.
*/
void setM ode(int mode)
{
/ / Красный
i f (mode == 1)
{
digitalW rite(R LED , HIGH);
digitalW rite(G LED , LOW);
digitalW rite(B LED , LOW);
}
/ / Зеленый
e ls e i f (mode == 2)
{
digitalW rite(R LED , LOW);
digitalW rite(G LED , HIGH);
digitalW rite(B LED , LOW);
}
/ / Синий
e ls e i f (mode == 3)
{
digitalW rite(R LED , LOW);
60 Часть I. Общие сведения о платформе Arduino
void loop()
{
cu rren tB u tto n = d e b o u n c e(lastB u tto n ); / / Чтение статуса
/ / кнопки
i f (la stB u tto n == LOW && cu rren tB u tto n == HIGH) / / Если нажата кнопка
{
Гпава 2. Цифровые контакты ввода-вывода, широтно-импульсная модуляция 61
ledMode++; / / Инкремент
/ / переменной
/ / статуса светодиода
}
lastButton = currentButton;
/ / Прошли по циклу все режимы
/ / свечения светодиода
/ / Сброс на начальный вариант =0
i f (ledMode == 8)
ledMode = 0;
setMode(ledMode); / / Изменить режим светодиода
62 Часть /. Общие сведения о платформе Arduino
Резюме________________________________________
В этой главе вы узнали о следующем:
♦ Как работать с макетной платой.
♦ Как выбрать резистор для ограничения тока светодиода.
♦ Как подключить внешний светодиод к плате Arduino.
♦ Как использовать ШИМ, как замену аналогового вывода.
♦ Как считывать состояние кнопки.
♦ Как подавить дребезг кнопки.
♦ Для чего нужны подтягивающий и стягивающий резисторы.
Опрос аналоговых
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino Uno;
♦ макетная плата;
♦ перемычки;
♦ потенциометр 10 кОм;
♦ 2 резистора номиналом 10 кОм;
♦ 3 резистора номиналом 220 Ом;
♦ кабель USB;
♦ фоторезистор;
♦ датчик температуры ТМР36 (или любой другой аналоговый датчик на 5 В);
♦ RGB-светодиод с общим катодом.
3.1. Понятие
об аналоговых и цифровых сигналах_____________
Данные об окружающем мире все устройства неизбежно получают в аналоговом
виде. Вспомните ночник из предыдущей главы. Для управления цифровым входом
там была кнопка. Переключатель — это цифровое устройство, он имеет только два
возможных состояния: включено или выключено, high или low, 1 или 0, и т. д. Циф
ровая информация представляет собой серию бинарных (цифровых) данных. Каж
дый бит принимает только одно из двух возможных значений.
Но мир вокруг нас редко представляет информацию только двумя способами. Вы
гляните в окно. Что вы видите? Если это дневное время, вы, вероятно, видите сол
нечный свет, деревья, колышущиеся на ветру, и возможно, проезжающие машины
и гуляющих людей. Все это нельзя отнести к двоичным данным. Солнечный свет не
просто включен или выключен, его яркость варьируется в течение дня. Точно так
же у ветра не два единственных состояния, он все время дует порывами с различ
ной скоростью.
1 На русском: ЬЦр:/МПй.атрегка.ги/видеоуроки:4-аналоговые-входы.
Гпава 3. Опрос аналоговых датчиков 65
Потенциометр и мультиметр внешне могут выглядеть не так, как показано на рис. 3.4.
void setu p ()
{
S e r i a l . b e g in (9600);
}
void lo o p ()
{
val = analogRead(POT);
S e ria l.p rin tIn (v a l);
d e la y (500);
}
Если выводятся непонятные символы, убедитесь, что скорость передачи данных уста
новлена правильно. В программе порт инициализирован на скорость 9600 бод, такое
же значение необходимо установить в настройках монитора последовательного порта.
/ / Температурный оповещатель
co n st i n t BLED=9; / / Контакт 9 для вывода BLUE RGB-светодиода
co n st i n t GLED=10; / / Контакт 9 для вывода GREEN RGB-светодиода
co n st i n t RLED=11; / / Контакт 9 для вывода RED RGB-светодиода
co n st i n t TEMP=0; / / КонтактАО для подключения датчика температуры
void s e tu p ()
{
pinMode (BLED, OUTPUT); // Сконфигурировать BLUE контакт светодиода
// как выход
pinMode (GLED, OUTPUT); // Сконфигурировать GREEN контакт светодиода
// как выход
pinMode (RLED, OUTPUT); // Сконфигурировать RED контакт светодиода
// как выход
}
v oid loop ()
{
v a l = anaiogRead(TEMP);
— —1 ___ Т> — ~ / ГТТГ1ЦЛТЧ \ .
Гпава 3. Опрос аналоговых датчиков 75
В коде листинга 3.2 нет ничего принципиально нового, он сочетает в себе все из
ложенное ранее о системах, взаимодействующих с окружающей средой и платой
Arduino.
ли значения 200 (темнота) и 900 (максимальное освещение). У вас могут быть дру
гие цифры. Они зависят от условий освещения, значения резистора R2 и характери
стик фоторезистора.
/ / Автоматический ночник
co n st i n t RLED=9; // Контакт 9 для ШИМ-вывода RED RGB-светодиода
co n st i n t LIGHT=0; // Контакт АО для входа фоторезистора
co n st i n t MIN_LIGHT=200; // Нижний порог освещенности
co n st i n t MAX_LIGHT=900; // Верхний порог освещенности
in t val = 0 ; // Переменная для сохранения считанного
// аналогового значения
void s e tu p ()
{
pinMode(RLED, OUTPUT); / / Сконфигурировать RED-контакт светодиода
/ / как выход
}
Гпава 3. Опрос аналоговых датчиков 79
void loop ()
{
val = analogRead(LIGHT); // Чтение показаний
// фоторезистора
val = шар(v a l , MIN_LIGHT, MAX_LIGHT, 255, 0 ); / / Вызов функции map()
val = c o n s tra in ( v a l, 0, 255); // Ограничение границ
analogWrite(RLED, v a l) ; // Управление светодиодом
}
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Чем отличаются аналоговые сигналы от цифровых.
♦ Как преобразовать аналоговые сигналы в цифровые.
♦ Как считать аналоговый сигнал с потенциометра.
♦ Как вывести на экран данные, используя монитор последовательного порта.
♦ Как взаимодействовать через интерфейс с аналоговыми датчиками.
♦ Как создать собственные аналоговые датчики.
♦ Как ограничить значения для управления аналоговыми выходами.
Управление окружающе[
В этой части_____________________________________
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino Uno;
♦ USB-кабель;
♦ батарея 9 В;
♦ разъем для батареи 9 В;
♦ стабилизатор напряжения L4940V5;
♦ электролитический конденсатор 22 мкФ;
♦ электролитический конденсатор 0,1 мкФ;
♦ керамический конденсатор 1 мкФ;
♦ 4 синих светодиода;
♦ 4 резистора номиналом 1 кОм;
♦ биполярный п-р-п транзистор PN2222;
♦ диод 1N4004;
♦ перемычки;
♦ провода;
♦ ИК-датчик расстояния Sharp GP2Y0A41SK0F ИК с кабелем;
♦ стандартный серводвигатель;
♦ двигатель постоянного тока;
♦ макетная плата;
♦ потенциометр;
♦ драйвер двигателя SN 754410.
84 Часть II. Управление окружающей средой
void setu p ()
{
pinMode (MOTOR, OUTPUT);
}
void lo o p ()
{
for ( in t i=0; i<256; i++)
{
analogWrite(MOTOR, i ) ;
d e la y (10);
}
d e la y (2000);
for ( in t i=255; i>=0; i — )
{
analogWrite(MOTOR, i ) ;
d e la y (10);
}
d e la y (2000);
}
Если все собрано правильно, то после запуска программы скорость вращения дви
гателя сначала плавно увеличится, а затем уменьшится. На основе описанного про
екта можно сконструировать, например, макет движущегося робота.
Воспользуемся нашими знаниями аналоговых датчиков и попробуем вручную
управлять скоростью вращения вала двигателя с помощью потенциометра. Подсо
единим потенциометр к аналоговому входу АО, как показано на рис. 4.4. Обратите
внимание, что контакт Arduino 5 В необходимо соединить с шиной питания на
макетной плате.
Теперь изменим программу так, чтобы управлять скоростью вращения двигателя,
регулируя положение ручки потенциометра. При полностью выведенном движке
потенциометра двигатель остановлен, при полностью введенном — вал двигателя
вращается с максимальной скоростью. Не забывайте, что контроллер Arduino рабо
тает очень быстро, цикл повторяется несколько тысяч раз в секунду! Поэтому ма
лейшее изменение положения движка потенциометра сразу же сказывается на час
тоте вращения двигателя. Описанный алгоритм реализует программный код, при
веденный в листинге 4.2. Загрузите программу в плату Arduino и регулируйте
скорость вращения двигателя с помощью потенциометра.
90 Часть II. Управление окружающей средой
void s e tu p ()
{
pinMode (MOTOR, OUTPUT);
}
void lo o p ()
{
v a l = analogRead(POT);
v a l = m ap(val, 0, 1023, 0, 255);
analogWrite(MOTOR, val)
}
Гпава 4. Использование транзисторов и управляемых двигателей 91
Почему схема называется Н-мостом? Ответ прост. Обратите внимание, что изобра
жение двигателя в сочетании с четырьмя переключателями похоже на прописную
букву "Н". Хотя на схеме изображены просто выключатели, на самом деле это
транзисторы, подобные тем, которые были в предыдущем примере. В реальной
схеме Н-моста также есть некоторые дополнительные цепи, в том числе защитные
диоды.
Н-мост может находиться в четырех основных состояниях: "выключен", "торможе
ние", "вперед" и "назад". В выключенном состоянии все выключатели разомкнуты
и двигатель не вращается. В состоянии "вперед" два выключателя замкнуты, в ре
зультате через обмотку двигателя течет ток и вал вращается. В состоянии "назад"
ток течет в противоположном направлении, и направление вращения вала обратное.
Если Н-мост находится в состоянии торможения, то обмотка замкнута, вращение
замедляется и двигатель останавливается.
Необходимо помнить об опасности короткого замыкания цепей Н-моста. Что про
изойдет, если все четыре выключателя будут замкнуты? Это вызовет короткое за
мыкание между шиной +9 В и землей. В результате батарея очень быстро нагреет
ся, что может привести к ее разрыву. Кроме того, короткое замыкание может по
вредить Н-мост или другие элементы схемы.
Для нашего эксперимента выберем микросхему SN 754410— четырехканальный
драйвер Н-полумоста, которая имеет встроенную защиту от короткого замыкания.
92 Часть II. Управление окружающей средой
Вход Вы ход
А EN Y
Н Н Н
L Н L
X L Z
Сначала напишем код функций для выполнения описанных действий (листинг 4.3).
/ / Остановка двигателя
void brake ()
{
d ig ita lW rite (EN, LOW);
d ig ita lW rite (MCI, LOW);
d ig ita lW rite (MC2, LOW);
d ig italW rite(E N , HIGH)
}
void lo o p ()
{
v al = analogR ead(РОТ);
/ / Движение вперед
i f (val > 562)
{
v e lo c ity = m ap(val, 563, 1023, 0, 255);
fo rw a rd (v e lo c ity );
}
/ / Движение назад
e ls e i f (val < 462)
{
v e lo c ity = m ap(val, 461, 0, 0, 255);
96 Часть II. Управление окружающей средой
r e v e r s e ( v e lo c ity ) ;
}
/ / Остановка
e ls e
{
b ra k e ();
}
}
Цифровое 0
т ~ " ...... .................................
462 512 562
> 1023
значение
Рис. 4.8. Принцип управления двигателем
void s e tu p ()
{
pinMode(EN, OUTPUT);
pinMode(MCI, OUTPUT);
pinMode(MC2, OUTPUT);
b ra k e (); / / Остановка двигателя при инициализации
}
Глава 4. Использование транзисторов и управляемых двигателей 97
void loop ()
{
v al = analogR ead(РОТ);
/ / Движение вперед
i f (val > 562)
{
v e lo c ity = m ap(val, 563, 1023, 0, 255);
fo rw a rd (v e lo c ity );
}
/ / Движение назад
e ls e i f (val < 462)
{
v e lo c ity = m ap(val, 461, 0, 0, 255);
r e v e r s e ( v e lo c ity ) ;
}
/ / Остановка
e ls e
{
b ra k e ();
}
}
/ / Движение двигателя вперед с заданной скоростью
/ / (диапазон 0-255)
void forw ard ( in t ra te )
{
d ig italW rite(E N , LOW);
digitalW rite(M C I, HIGH);
digitalW rite(M C 2, LOW);
analogW rite(EN, r a t e ) ;
}
/ / Движение двигателя в обратном направлении с заданной скоростью
/ / (диапазон 0-255)
void re v e rse ( in t ra te )
{
d ig italW rite(E N , LOW);
digitalW rite(M C I, LOW);
digitalW rite(M C 2, HIGH);
analogW rite(EN, r a t e ) ;
}
/ / Остановка двигателя
void brake ()
{
d ig ita lW rite (EN, LOW) ;
digitalW rite(M C I, LOW);
digitalW rite(M C 2, LOW);
d ig italW rite(E N , HIGH);
}
98 Часть II. Управление окружающей средой
Как и двигатели постоянного тока, серводвигатели требуют для работы ток больше,
чем выдает встроенный источник питания Arduino. Хотя иногда удается запустить
один-два сервопривода от блока питания платы Arduino. У серводвигателей, в от
личие от двигателей постоянного тока, есть дополнительный сигнальный провод
для установки угла поворота вала. Питание и земляной провод серводвигателя
нужно подсоединить к источнику постоянного напряжения.
Сервоприводы управляются по сигнальной линии с помощью прямоугольных им
пульсов регулируемой длительности. Для стандартного сервопривода подача им
пульса длительностью 1 мс приводит к установке сервопривода в положение 0°,
импульс длительностью 2 мс устанавливает сервопривод в положение 180°, им
пульса 1,5 мс — 90°. После того как импульс подан, вал сервопривода устанавлива
ется в определенную позицию и остается там до поступления следующей команды.
Тем не менее, чтобы постоянно поддерживать точное положение вала сервоприво
да, необходимо отправлять сигнальные импульсы каждые 20 мс. Библиотека
Arduino Servo, которую мы будем использовать для управления серводвигателями,
позаботится об этом.
Чтобы лучше понять, как управлять серводвигателями, изучим графики, приведен
ные на рис. 4.10.
В примерах, изображенных на рис. 4.10, импульс подается каждые 20 мс. Длитель
ность импульса возрастает от 1 до 2 мс, при этом угол поворота серводвигателя
(показанный справа от графика импульсов) увеличивается от 0 до 180°.
100 Часть II. Управление окружающей средой
Как упоминалось ранее, для работы серводвигателя требуется ток, больший, чем
выдает встроенный в Arduino блок питания. Однако большинство серводвигателей
работает от напряжения 5 В, а не 9 или 12 В как двигатели постоянного тока. Не
смотря на это, необходим отдельный блок питания серводвигателя.
Мы рассмотрим, как с помощью источника 9 В и стабилизатора напряжения полу
чить напряжение 5 В для питания сервопривода. Интегральный стабилизатор на
пряжения — чрезвычайно простое устройство, у которого обычно три контакта:
♦ вход;
♦ выход;
♦ заземление.
Заземляющий вывод соединен как с землей входного, так и с землей выходного на
пряжения. Для работы стабилизатора входное напряжение должно быть выше, чем
выходное, причем величина выходного напряжения фиксирована в зависимости от
типа стабилизатора.
Падение напряжения приводит к нагреву, поэтому необходимо позаботиться о теп
лоотводе (например, алюминиевом радиаторе). Для наших экспериментов возьмем
5-вольтовый стабилизатор напряжения L4940V5, который способен выдавать ток
до 1,5 А. Схема включения стабилизатора приведена на рис. 4.11.
Гпава 4. Использование транзисторов и управляемых двигателей 101
102 Часть II. Управление окружающей средой
void s e tu p ()
{
myServo. attach(SERVO);
}
Гпава 4. Использование транзисторов и управляемых двигателей 103
void loop ()
{
v a l = analogR ead(РОТ); / / Чтение данных потенциометра
v al = m ap(val, 0, 1023, 0, 179); / / Преобразование к нужному диапазону
m y S e rv o .w rite(v a l); / / Установить положение сервопривода
d e la y (15);
}
4.13. Создание
радиального датчика расстояния_________________
В завершение этой главы применим знания, полученные ранее, для создания даль
номера. Система состоит из инфракрасного (ИК) датчика расстояния, установлен
ного на серводвигателе, и четырех светодиодов. Четыре позиции вала серводвига
теля панорамируют датчик по периметру комнаты, что позволяет примерно опре
делить расстояние до объектов в каждой из четырех областей. Яркость четырех
светодиодов меняется в зависимости от расстояния до объекта в каждой области.
Так как инфракрасный свет является частью электромагнитного спектра, невиди
мой для человеческого глаза, подобная система может использоваться для создания
"ночного видения". ИК-датчик расстояния работает следующим образом. Излуче
ние ИК-светодиода воспринимается фотоприемником, который расположен рядом
со светодиодом. Таким образом определяется расстояние до объекта, которое пре
образуется в аналоговое напряжение и далее анализируется с помощью микрокон
троллера. Даже если в комнате темно и расстояние до объекта неизвестно, дально
мер позволит его узнать, потому что он работает в диапазоне, невидимом для чело
веческого глаза.
Разные модели ИК-датчиков могут иметь различные интерфейсы. Если ваш датчик
отличается от рассмотренного в этом примере, необходимо ознакомиться с доку
ментацией, чтобы убедиться, что он является аналоговым.
/ / Ж -датчик расстояния
#include <Servo.h>
const i n t SERV0=9; / / Вывод 9 для подключения сигнального провода
/ / сервопривода
const i n t IR=0; / / Подключение Ж -датчика расстояния к аналоговому
/ / входу АО
const i n t LED1=3; / / Вывод светодиода 1
const i n t LED2=5; / / Вывод светодиода 2
const i n t LED3=6; / / Вывод светодиода 3
const i n t LED4=11; / / Вывод светодиода 4
void s e tu p ()
{
myServo. attach(SERVO);
pinMode(LED1, OUTPUT); // Сконфигурировать
pinMode(LED2, OUTPUT); // контакты подключения
pinMode(LED3, OUTPUT); // четырех светодиодов
pinMode(LED4, OUTPUT); // как выходы
}
void loop()
{
/ / Поворот вала сервопривода по четырем позициям
d i s t l = re a d D ista n c e (15);
an alo g W rite(LED1, d i s t l );
d e la y (300);
d is t2 = re a d D ista n c e (65) ;
an alo g W rite(LED2, d i s t 2 );
d e la y (300);
d is t3 = re a d D ista n c e (115);
an alo g W rite(LED3, d i s t 3 );
d e la y (300);
d is t4 = re a d D ista n c e (165) ;
analogWrite(LED4, d i s t 4 ) ;
d e la y (300);
}
диодов, зависит от конкретной ситуации. У меня для самого дальнего объекта дат
чик выдавал значение 50, до ближайших — 500.
После загрузки кода и запуска программы система должна функционировать, как
на демонстрационных видеоклипах, перечисленных в начале главы.
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Как работают двигатели постоянного тока.
♦ Что двигатели являются индуктивными нагрузками, которые следует снабдить
надлежащей защитой и схемой питания, чтобы безопасно взаимодействовать
с платой Arduino.
♦ Как управлять скоростью и направлением вращения двигателя с помощью
ШИМ и Н-моста.
♦ Что серводвигатели точно позиционируются и управляются с помощью Arduino
библиотеки Servo.
♦ Как создать вторичный источник питания 5 В от батареи 9 В с помощью стаби
лизатора напряжения.
♦ Что ИК-датчики получают инфракрасный сигнал, отраженный от объекта, и воз
вращают аналоговые значения, соответствующие расстоянию до данного объекта.
♦ Что комментарии важны для отладки и совместного использования программ.
Работаем <
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino Uno;
♦ USB-кабель;
♦ 4 кнопки;
♦ 5 резисторов номиналом 10 кОм;
♦ 1 резистор номиналом 150 Ом;
♦ перемычки;
♦ провода;
♦ макетная плата;
♦ потенциометр 10 кОм;
♦ динамик 8 Ом.
скачайте на рабочий стол. Затем в Arduino ГОЕ создайте пустой новый файл. Как
вы, наверное, заметили, Arduino ГОЕ создает новый файл внутри папки с одно
именным названием. Добавляя в эту папку новые файлы, вы можете включать их
в свою программу, в результате код будет лучше структурирован. Скопируйте файл
pitches.h, сохраненный на рабочем столе, в папку, созданную Arduino ГОЕ, для но
вого проекта. Теперь заново откройте в Arduino IDE этот файл. Обратите внимание
на две вкладки (рис. 5.3).
Далее массивы потребуются нам, чтобы создать структуру, которая может содер
жать последовательность нот, воспроизводимую на динамике.
/ / Массив НОТ
in t n o te s [] = {
NOTE_A4, NOTE_E3, NOTE_A4, 0,
N0TE_A4, NOTE_E3, NOTE_A4, 0,
NOTE_E4, NOTE_D4, NOTE_C4, NOTE_B4, NOTE_A4, NOTE_B4/ NOTE_C4, NOTE_D4,
NOTE_E4, NOTE_E3, NOTE_A4, 0
};
/ / Массив длительностей звучания нот в мс
in t tim es [ ] = {
250, 250, 250, 250,
250, 250, 250, 250,
125, 125, 125, 125, 125, 125, 125, 125,
250, 250, 250, 250
};
116 Часть II. Управление окружающей средой
Обратите внимание, что длина обоих массивов одинакова (20 элементов). Некото
рые ноты задаются в виде нулевых значений, — это музыкальные паузы. Длитель
ность звучания каждой ноты берем из второго массива. Для тех, кто знаком с тео
рией музыки, обратите внимание, что я задал длительность четвертных нот 250 мс,
а восьмых— 125 мс.
Сначала попробуйте воспроизвести мою мелодию, а затем попытайтесь создать
свою собственную!
/ / Массив нот
i n t n o te s [] = {
N0TE_A4, N0TE_E3, N0TE_A4, 0,
N0TE_A4, N0TE_E3, N0TE_A4, 0,
N0TE_E4, N0TE_D4, N0TE_C4, N0TEJB4, N0TE_A4, N0TE_B4, NOTE_C4, N0TE_D4,
N0TE_E4, N0TE_E3, N0TE_A4, 0
};
void s e tu p ()
{
Глава 5. Работаем со звуком 117
void lo o p ()
{
/ / Чтобы повторить воспроизведение, необходимо нажать кнопку R eset
}
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Как динамики создают вибрацию воздуха, которая распространяется в про
странстве и воспринимается нашей барабанной перепонкой в виде звука.
♦ Что изменение электрического тока индуцирует магнитное поле, которое гене
рирует звук из громкоговорителя.
♦ Как создавать звуки произвольной частоты и длительности с помощью функции
tone ( ) .
♦ Что язык программирования Arduino поддерживает массивы, что удобно для
перебора последовательностей данных.
♦ Что громкость можно регулировать потенциометром, соединенным последова
тельно с динамиком.
ш ш жт ш
USB и последовательный hi
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino Uno;
♦ плата Arduino Leonardo;
♦ USB-кабель А - В (для Uno);
♦ USB-кабель А - микро В (для Leonardo);
♦ светодиод;
♦ RGB-светодиод с общим катодом;
♦ резистор номиналом 150 Ом;
♦ 3 резистора номиналом 220 Ом;
♦ 2 резистора номиналом 10 кОм;
♦ кнопка;
♦ фоторезистор;
♦ датчик температуры ТМР36;
♦ двухкоординатный джойстик (SparkFun, Parallax или Adafruit);
♦ перемычки;
♦ провода;
♦ макетная плата;
♦ потенциометр.
Иногда для уменьшения размера платы чип FTDI встраивают в кабель (USB-кабель
с чипом FTDI изображен на рис. 6.3) или устанавливают на дополнительной плате
адаптера (рис. 6.4).
Плата Arduino со съемным адаптером FTDI целесообразна для проектов, в которых
нет необходимости подключаться к компьютеру через USB. В результате умень
шится стоимость и габариты готового устройства.
Гпава 6. USB и последовательный интерфейс 121
♦ LilyPad Arduino;
♦ Arduino Fio;
♦ Arduino Mini;
♦ Arduino Ethernet.
void setu p ()
{
S e r ia l.b e g in (9600); / / Инициализация последовательного порта
/ / на скорости 9600
}
126 Часть II. Управление окружающей средой
void lo o p ()
{
i n t v a l = analogRead(POT); // Чтение данных с потенциометра
i n t p er = m ap(val, 0, 1023, 0, 100); / / Перевод в процентное значение
S e ria l.p rin t(" A n a lo g Reading: " );
S e ria l.p rin t(v a l); // Вывод аналогового значения
S e r i a l . p r i n t (" P ercentage: " );
S e ria l.p rin t(p e r); // Вывод значения в процентах
S e r i a l . p r i n t l n ("%");
d e la y (1000); // Ожидание 1 сек перед
// получением новых данных
}
void s e tu p ()
{
S e r ia l.b e g in (9600); / / Инициализация последовательного порта
/ / н а скорости 9600
}
void lo o p ()
{
S e r i a l . p r i n t l n ("\nAnalog Pin\tRaw V a lu e \tP e rc e n ta g e " );
S e r i a l . p r i n t l n ("------------------------------------------------------------------ ") ;
Глава 6. USB и последовательный интерфейс 127
Decimal S e r i a l . p r i n t l n (23); 23
Hexadecimal S e r i a l . p r i n t l n (23,HEX); 17
Octal S e r i a l . p r i n t l n (23,OCT); 27
void s e tu p ()
{
S e r ia l.b e g in (9600); / / Инициализация последовательного порта
/ / н а скорости 9600
}
130 Часть II. Управление окружающей средой
void lo o p ()
{
/ / Вывод только при получении данных
i f ( S e r ia l.a v a il a b le () > 0)
{
d ata = S e r i a l . r e a d (); / / Чтение байта из буфера
S e r i a l . p r i n t ( d a t a ) ; / / Вывод в последовательный порт
}
}
void s e tu p ()
{
S e r ia l.b e g in (9600); / / Инициализация последовательного порта
/ / на скорости 9600
pinMode(LED, OUTPUT);
}
Глава 6. USB и последовательный интерфейс_________________________________________ 133
void lo o p ()
{
/ / Если в буфере есть символ
i f ( S e r ia l .a v a i l a b l e () > 0)
{
d a ta = S e r i a l . r e a d (); / / Чтение байта из буфера
/ / Включение светодиода
i f (data == Ч 1)
{
digitalW rite(L E D , HIGH);
S e ria l.p rin tln (" L E D ON");
}
/ / Выключение светодиода
e ls e i f (data == ' 0' )
{
digitalW rite(L E D , LOW);
S e ria l.p rin tln (" L E D OFF");
}
}
}
void s e tu p ()
{
S e r i a l .b e g i n (9600); / / Инициализация последовательного порта
/ / н а скорости 9600
/ / Установить контакты на выход OUT
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
}
void lo o p ()
{
/ / Пока в буфере есть данные
w hile ( S e r ia l . a v a il a b le () > 0)
{
rv a l = S e r i a l . p a r s e l n t (); // Первое число
gval = S e r i a l . p a r s e l n t (); // Второе число
b v al = S e r i a l . p a r s e l n t (); // Третье число
i f ( S e r ia l.r e a d () == *\ nf ) // Конец передачи
{
/ / Установка яркости светодиода
analogWrite(RED, r v a l) ;
analogWrite(GREEN, g v a l);
analogWrite(BLUE, b v a l);
}
}
}
Скопируйте код из листинга 6.6 и загрузите его на плату Arduino. Arduino посылает
обновленное значение от потенциометра в последовательный порт компьютера
каждые 50 мс. Если отправлять данные быстрее, приложение на Processing не будет
успевать их обрабатывать и буфер последовательного порта на вашем компьютере
переполнится.
void s e tu p ()
{
S e r i a l .b e g i n (9600); / / Инициализация последовательного порта
/ / н а скорости 9600
}
void lo o p ()
{
138 Часть II. Управление окружающей средой
Теперь напишем код для обработки входящих данных. Программа из листинга 6.7
считывает данные из буфера последовательного порта и регулирует яркость цвета
на экране вашего компьютера в зависимости от полученного значения. Скопируйте
листинг 6.7 и внесите одно важное изменение. В программе на Processing должен
быть указан конкретный последовательный порт получения данных. Замените
"COM3" на номер вашего последовательного порта. Помните, что в Linux и Мае он
будет выглядеть примерно как /dev/ttyUSBO. Если вы не уверены, скопируйте точ
ное название порта из Arduino IDE.
v oid s e tu p ()
{
s i z e (500,500); / / Размер окна
p o rt = new S e r i a l ( t h i s , "COM3", 9600); / / Инициализация
/ / последовательного порта
p o r t .b u f f e r U n t il ( 1\ n f ); / / Символ конца строки
}
v oid draw ()
{
background(0 ,0 ,b r ig h tn e s s ) ; / / Перерисовать окно
}
нить (кнопка с изображением треугольника в верхнем левом углу окна), при этом
должно появиться небольшое окно. При повороте движка потенциометра цвет окна
должен меняться от черного к синему (рис. 6.13).
Теперь, когда вы видели результат, для лучшего понимания рассмотрим, как это
работает. В отличие от Arduino, библиотека s e r i a l не импортируется автоматиче
ски. Объявив im port p ro c essin g . s e r i a l . * И S e r ia l p o rt, ВЫ импортируете библио
теку s e r i a l и создаете объект s e r i a l под названием p o rt.
Как и в Arduino, в Processing тоже есть функция setu p (), которая работает только
в начале программы. В этом примере функция setu p о задает последовательный
порт и создает окно размером 500x500 пикселов командой s i z e (500,500) . Команда
port = new s e r i a l ( th is , "COM3", 9600) сообщает Processing о создании экземпляра
последовательного порта. Экземпляр (под названием p o rt) будет работать и об
щаться на COM3 (или другом последовательном порту) со скоростью 9600 бод.
Скорость обмена данными между платой Arduino и программой на компьютере
должна быть задана одинаковой, в противном случае возникнут ошибки. Команда
p o r t.b u f f e r U n tii ( '\п ') сообщает Processing-приложению о буферизации последо
вательного ввода до получения символа новой строки (' \п ').
Вместо loop о в Processing есть другие специальные функции. В нашем примере
использованы функции draw () и seriaiEvent (). Функция draw () похожа на loop ()
в Arduino, она работает непрерывно и обновляет экран. Функция background () зада
ет цвет окна, имеет три аргумента для установки значений красного, зеленого и си
него компонентов цвета. В нашем примере значение с потенциометра управляет
интенсивностью синего компонента, а красный и зеленый установлены в нуль. При
желании программу можно переделать, чтобы регулировать интенсивность других
компонентов. Поскольку интенсивности RGB цветов являются 8-битовыми значе
ниями от 0 до 255, значения потенциометра масштабируются функцией тар () перед
передачей.
Функция seriaiEvent о вызывается всякий раз, когда выполняется условие
b u f f e ru n tii (), указанное в функции setu p (). При каждом появлении символа пере
140 Часть II. Управление окружающей средой
void s e tu p ()
{
s i z e (640,256);
img = lo ad lm ag e("h sv .jp g ” ) ; / / Загрузка фоновой картинки
Гпава 6. USB и последовательный интерфейс 141
void draw ()
{
background(0); / / Цвет фона
im age(img, 0 ,0 ) ; / / Изображение
}
void m ousePressed()
{
co lo r c = get(mouseX, mouseY); / / Получить RGB-цвет по позиции
/ / курсора мыши
При нажатии кнопки мыши вызывается функция m ousePressedO . Цвет пиксела, где
вы щелкнули мышью, сохраняется в объекте c o lo r с именем с. Метод g et () сооб
щает приложению, откуда можно получить цвет (в данном случае из координат
курсора мыши). Затем преобразуем значение в строку, состоящую из целых значе
ний красного, зеленого и синего компонентов цвета. Эти значения также выводятся
в монитор последовательного порта.
Включите плату Arduino и загрузите в нее код из листинга 6.5. Запустите
Processing-приложение и настройте цвет светодиода, подключенного к Arduino, вы
бирая цвет из палитры.
Гпава 6. USB и последовательный интерфейс 143
Если плата "зависла" в режиме эмуляции мыши или клавиатуры, чтобы перепрограм
мировать ее, нажмите и отпустите кнопку Reset, удерживая нажатой кнопку Загрузить
в Arduino IDE.
void s e tu p ()
{
pinMode (LED, OUTPUT); / / Контакт светодиода как выход OUTPUT
K eyboard.begin(); / / Запуск эмуляции клавиатуры
}
void lo o p ()
{
c u rren tB u tto n = d e b o u n c e (la stB u tto n ); / / Чтение состояния
i f (la stB u tto n == LOW && c u rren tB u tto n == HIGH) / / Если наж атие...
running = !running; / / Переключить статус записи
la s tB u tto n = cu rren tB u tto n ; / / Установить статус кнопки
i f (running) / / Запись включена
{
digitalW rite(L E D , HIGH); / / Включить светодиод
i f (m illis () % 1000 == 0) / / Прошло 1000 мс
{
i n t tem p eratu re = analogRead(TEMP); / / Чтение данных
/ / с датчика температуры
i n t b rig h tn e s s = analogRead(LIGHT); / / Чтение данных
/ / с датчика освещенности
K e y b o a rd .p rin t(c o u n te r); / / Вывод индекса данных
Keyboard. p r i n t (” , ”); / / Вывод разделителя
K e y b o a rd .p rin t(te m p e ra tu re ); / / Вывод температуры
K e y b o a rd .p rin t( " ," ) ; / / Вывод разделителя
K e y b o a rd .p rin tln (b rig h tn e s s ); / / Вывод освещенности
/ / и символа новой строки
counter++; / / Инкремент индекса
146 Часть II. Управление окружающей средой
e ls e
{
digitalW rite(L E D , LOW); / / Запись выключена,
/ / погасить светодиод
}
}
}
/*
* Функция устранения дребезга кнопки
* Получает предыдущий и возвращает текущий статус.
*/
boolean debounce(boolean la s t)
{
boolean c u rre n t = digitalRead(BUTTON); / / Чтение состояния кнопки
i f ( l a s t != c u rre n t) / / Состояние изменилось...
{
d e la y (5); / / Ждем 5 мс
c u rre n t = digitalRead(BUTTON); / / Чтение состояния кнопки
}
re tu rn c u rre n t; / / Возврат текущего
/ / состояния кнопки
}
void s e tu p ()
{
Keyboard. b e g in ();
}
void loop ()
{
i n t b rig h tn e s s = analogRead(LIGHT); / / Чтение данных датчика
148 Часть II. Управление окружающей средой
/ / Создаем мышь!
const i n t LEFT_BUTT0N=4; // Вход для левой кнопки мыши
const i n t MIDDLE_BUTT0N=3; // Вход для средней кнопки мыши
const i n t RIGHT_BUTTON =2; // Вход для правой кнопки мыши
const i n t X_AXIS=0; // Аналоговый вход для оси х джойстика
const i n t Y_AXIS=1; // Аналоговый вход для оси у джойстика
void s e tu p ()
150 Ч а с т ь II. У п р а в л е н и е о к р у ж а ю щ е й с р е д о й
{
M ouse.begin();
}
void lo o p ()
{
i n t xVal = readJoystick(X _A X IS); // Получить отклонение
// джойстика по оси х
i n t yVal = readJoystick(Y _A X IS); // Получить отклонение
// джойстика по оси у
Mouse.move (xVal, yVal, 0); // Перемещаем мышь
{
Mouse. release(mouseCommand);
}
}
)
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Как подключить плату Arduino к компьютеру через USB-преобразователь по
следовательного порта.
152 Ч а с т ь II. У п р а в л е н и е о к р у ж а ю щ е й ср е д о й
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino Uno;
♦ USB-кабель А - В (для Uno);
♦ 8 красных светодиодов;
♦ 3 желтых светодиода;
♦ 5 зеленых светодиодов;
♦ 8 резисторов номиналом 220 Ом;
♦ сдвиговый регистр SN74HC595N в DIP-корпусе;
♦ инфракрасный датчик расстояния GP2Y0A41SK0F с кабелем;
♦ перемычки;
♦ макетная плата.
♦ SER— это вход данных (DATA на рис. 7.1). По этому входу передаются 8 по
следовательных битов данных для установки значений на параллельных вы
ходах;
♦ SRCLK— это тактовый вход (CLOCK на рис. 7.1). При подаче импульса высо
кого напряжения high на этот вход происходит считывание одного бита данных
с входа DATA в сдвиговый регистр. Для получения всех 8 битов данных необ
ходимо подать 8 импульсов на этот контакт;
♦ RCLK — это вход (LATCH на рис. 7.1) называется также защелкой и служит для
одновременного вывода последовательных данных на параллельные выходы.
Выводы SRCLR и ОЕ не используются в примерах из книги, но они могут приго
диться вам в других проектах, поэтому посмотрим, каково их назначение. ОЕ —
разрешение вывода данных на параллельные выходы. Черта сверху означает, что
активный уровень для этого входа — низкий. Когда на этом входе низкий уровень,
параллельные выходы будут включены, когда высокий— выключены. В наших
примерах контакт ОЕ подключен к земле, поэтому параллельные выходы постоян
но находятся во включенном состоянии. Вы можете соединить его с контактом
ввода-вывода Arduino, чтобы одновременно включать или выключать все свето
диоды. SRCLR — это вход сброса. Подача на него напряжения низкого уровня
очищает содержимое регистра сдвига. В наших примерах он подключен к шине
5 В, чтобы предотвратить очистку сдвигового регистра.
v oid s e tu p ()
{
/ / Установить контакты на вывод (OUTPUT)
pinMode(SER, OUTPUT);
pinMode(LATCH, OUTPUT);
pinMode(CLK, OUTPUT);
Гпава 7. Сдвиговы е регист ры 159
7.3.4. Преобразование
между двоичным и десятичным форматами
В листинге 7.1 данные для включения светодиодов передавались в виде двоичной
строки. Это позволяет наглядно отобразить включенные и выключенные светодио
ды. Тем не менее, данные можно записать в десятичном виде, преобразовав их из
двоичного (base2) в десятичный (base 10) формат. Каждый разряд двоичного числа
(начиная с младшего, самого правого) представляет следующую степень числа 2.
Преобразовать двоичное представление числа в десятичное очень просто. Рассмот
рим этапы преобразования двоичного кода в десятичный (рис. 7.5).
void s e tu p ()
{
/ / Установить контакты на вывод (OUTPUT)
pinMode(SER, OUTPUT);
pinMode(LATCH, OUTPUT);
pinMode(CLK, OUTPUT);
}
void lo o p ()
{
fo r ( in t i = 0; i < 14; i++)
{
digitalW rite(LATCH, LOW); // LATCH - низкий
shiftO ut(SER , CLK, MSBFIRST, s e q [ i ] ) ; // Старший бит - первый
digitalW rite(LATCH, HIGH); // LATCH - высокий
d e la y (100); // Скорость анимации
}
}
// Гистограмма расстояния
const int SER=8; // Контакт для подключения вывода DATA
const int LATCH =9; // Контакт для подключения вывода LATCH
164 Часть II. Управление окружающей средой
void setup()
{
// Установить контакты на вывод (OUTPUT)
pinMode(SER, OUTPUT);
pinMode(LATCH, OUTPUT);
pinMode(CLK, OUTPUT);
}
void loop()
{
int distance = analogRead(DIST);
distance = map(distance, minVal, maxVal, 0, 8);
distance = constrain(distance,0,8);
digitalWrite(LATCH, LOW); // LATCH - низкий - начало отправки
shiftOut(SER, CLK, MSBFIRST, vals[distance]); // Старший бит - первый
digitalWrite(LATCH, HIGH); // LATCH - высокий
delay(10); // Скорость анимации
}
Глава 7. Сдвиговые регистры 165
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Как работают сдвиговые регистры.
♦ Чем отличается последовательная и параллельная передача данных.
♦ В чем различие между десятичной и двоичной формой представления данных.
♦ Как создать световую анимацию с помощью сдвигового регистра.
______ Интерфейсы передач!
В этой части_____________________________________
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino Uno;
♦ USB-кабель В (для Uno);
♦ 1 красный светодиод;
♦ 3 желтых светодиода;
♦ 4 зеленых светодиода;
♦ 8 резисторов номиналом 220 Ом;
♦ 2 резистора номиналом 4,7 кОм;
♦ сдвиговый регистр SN74HC595N в DIP-корпусе;
♦ 12С датчик температуры TC74A0-5.0VAT;
♦ перемычки;
♦ макетная плата.
1 На русском: http://wiki.amperka.ru/BnaeoypoKn:7-i2c-n-processing.
Глава 8. Интерфейсная шина 12С 171
рим датчик температуры ТС74. Из рис. 8.2 видно, что этот датчик может иметь
несколько разных адресов. В примерах данной главы у датчика TC74A0-5.0VAT
(исполнение Т0-220) 12С-адрес задан как 1001000.
использовать А4 и А5 как аналоговые входы нельзя, потому что они заняты обме
ном с устройствами 12С.
void s e tu p ()
{
/ / Запуск последовательного порта
S e r i a l .b e g i n (9600);
/ / Создание объекта Wire
W ire .b e g in ();
}
void lo o p ()
{
/ / Отправка запроса
/ / Выбор устройства отправкой адреса устройства
W ire.beginT ransm ission(tem p_address);
/ / Установка бита asking в 0 для чтения
W ire .w rite (0);
/ / Отправка стоп-бита
W ire. endT ransm ission();
void s e tu p ()
{
/ / Запуск последовательного порта
S e r ia l.b e g in (9600);
/ / Создание объекта Wire
Wire .becrin () ;
Гпава 8. Интерфейсная шина 12С 181
void lo o p ()
{
/ / Отправка запроса
/ / Выбор устройства отправкой адреса устройства
W ire.beginT ransm ission(tem p_address);
/ / Установка бита asking в 0 для чтения
W ire .w rite (0);
/ / Отправка стоп-бита
W ire. endT ransm ission();
После загрузки кода листинга 8.2 в плату Arduino можно наблюдать, как меняется
цвет светодиодов при изменении температуры. Дотроньтесь до датчика рукой, что
бы повысить температуру. Светодиодная гистограмма должна измениться. Теперь
182 Часть III. Интерфейсы передачи данных
Выберите свой любимый шрифт и размер (для этой программы я рекомендую раз
мер около 200). После этого нажмите кнопку ОК. Шрифт будет автоматически
установлен в папку data данного проекта.
Программа на Processing должна выполнить следующее:
♦ Сгенерировать графическое окно на компьютере для отображения данных тем
пературы в градусах Цельсия и Фаренгейта.
Гпава 8. Интерфейсная шина 12С 183
void s e tu p ()
{
s i z e (400,400);
/ / Измените "COM9" на имя вашего последовательного порта
p o rt = new S e r i a l ( t h i s , "COM9", 9600);
p o r t .b u f f e r U n t il ( 1. 1);
/ / Измените имя шрифта, выбранное вами
fo n t = lo ad F o n t(nAgencyFB-Bold-200.vlwn) ;
te x tF o n t(fo n t, 200);
}
void draw ()
{
background(0 ,0 ,0 );
f i l l (46, 209, 2 );
tex t(tem p _ c, 70, 175);
f i l l (0, 102, 153);
tex t(tem p _ f, 70, 370);
}
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Как организовать связь платы Arduino с несколькими 12С ведомыми устройства
ми (если они имеют разные адреса) по двухпроводному протоколу 12С.
♦ Как библиотека Wire облегчает связь с 12С-устройствами, подключенными
к выводам А4 и А5 платы.
♦ Как объединить связь по протоколу 12С со сдвиговыми регистрами и обменом по
последовательному порту для создания более сложных систем.
♦ Как генерировать шрифты для динамически обновляемых текстов в программе
на Processing.
♦ Как отображать данные, полученные от 12С-устройств, подключенных к Arduino,
с помощью приложения на Processing.
Интерфейсная
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino Uno;
♦ USB-кабель В (для Uno);
♦ 1 красный светодиод;
♦ 1 желтый светодиод;
♦ 1 зеленый светодиод;
♦ 1 синий светодиод;
♦ 4 резистора номиналом 100 Ом;
♦ 2 резистора номиналом 4,7 кОм;
♦ динамик;
♦ цифровой SPI потенциометр МСР4231;
♦ перемычки;
♦ макетная плата.
Так как техническая реализация протокола SPI может быть разной, необходимо изу
чать техническое описание, прилагаемое к каждому устройству.
№ Р еж и м SPI П о л я р н о с ть с и н х р о н и за ц и и Ф аза с и н х р о н и за ц и и
Л и н и и S PI О писание
void lo o p ()
{
fo r (in t i=0; i<=128; i++)
{
setL ed(SSI, REGO, i ) ;
setL ed(SSI, REG1, i ) ;
Гпава 9. Интерфейсная шина SPI 197
setLed(SS2, REGO, i) ;
setLed(SS2, REG1, i ) ;
d e la y (10) ;
}
d e la y (300);
fo r ( in t i=128; i>=0; i — )
{
setL ed(SS I, REGO, i);
setL ed(SS I, REG1, i) ;
setLed(SS2, REGO, i) ;
setLed(SS2, REG1, i);
d e la y (10) ;
}
d e la y (300) ;
}
Данный проект может послужить основой для разработки многих гораздо более инте
ресных устройств. Досконально разобравшись с описанной далее схемой и кодом про
граммы, вы сможете творчески переработать эти идеи и создавать свои собственные
оригинальные конструкции на основе платы Arduino.
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Что согласно протоколу SPI для организации обмена требуются три общие
линии (две линии данных и линия синхронизации) и по одной дополнительной
линии выбора для каждого ведомого устройства.
♦ Что библиотека Arduino SPI позволяет облегчить коммуникации между платой
Arduino и ведомыми устройствами.
♦ Что можно обмениваться данными с несколькими устройствами SPI, используя
общие линии данных и синхронизации и раздельные линии SS выбора ведомого
устройства.
♦ Как управлять SPI цифровыми потенциометрами с помощью библиотеки
Arduino SPI.
♦ Как пользоваться техническими описаниями устройств.
♦ Как одновременно регулировать громкость и частоту звукового сигнала, исполь
зуя библиотеку Топе и цифровой потенциометр SPI.
Гпава 9. Интерфейсная шина SPI 199
void s e tu p ()
{
/ / Настройка выводов выбора SS на выход
pinMode(SSI, OUTPUT);
pinMode(SS2, OUTPUT);
/ / Инициализация аппаратного SPI
S P I.b e g in ();
}
void lo o p ()
{
tone(SPEAKER, freq); // Частота звука
Взаимо
с жидкокристаллическими д|
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino Uno;
♦ USB-кабель В (для Uno);
♦ микрофон;
♦ цифровой SPI-потенциометр МСР4231;
♦ перемычки;
♦ макетная плата;
♦ динамик;
♦ две кнопки;
♦ вентилятор;
♦ 16х2-символьный ЖК-дисплей;
♦ 2 резистора номиналом 4,7 кОм;
♦ 2 резистора номиналом 10 кОм;
♦ 1 резистор номиналом 150 Ом;
♦ 1 потенциометр 10 кОм;
♦ датчик температуры ТС74А0-5.0 VAT I2C;
♦ набор перемычек;
♦ макетная плата.
10.1. Настройка
жидкокристаллического дисплея__________________
В устройствах, описанных в этой главе, мы применим жидкокристаллический дис
плей. Подобные индикаторы часто встречаются и имеют множество модификаций.
Наиболее распространены дисплеи, содержащие 16x2 символов, имеющие 16 (или
14, если нет подсветки) контактов в один ряд. Для рассмотренных далее примеров
выбран 16-контактный ЖК-дисплей, на экране которого одновременно может ото
бражаться 32 символа (16 столбцов и 2 строки).
Если у вашего дисплея нет штырьков для монтажа, необходимо сначала припаять
их, чтобы можно было установить его на макетной плате. Если штыревые контакты
припаяны (как на рис. 10.1), можно сразу закрепить индикатор на макетной плате.
Теперь нужно подключить дисплей, смонтированный на макетной плате, к Arduino.
Все параллельные ЖК-индикаторы имеют одинаковые выходы и их можно под
ключить в одном из двух вариантов: 4-контактном и 8-контактном. Для передачи
информации служат четыре вывода, есть также контакты готовности данных, вы
бора режима команд или режима индикации, установки режимов чтения или записи
данных. Назначение всех контактов приведено в табл. 10.1.1
1 Vss Заземление
2 Vdd Питание +5 В
3 Vo Регулировка контрастности (потенциометр)
5 RW Чтение/запись
6 En Готовность данных
15 A Анод подсветки
16 К Катод подсветки
♦ Контакт RW у нас всегда будет соединен с землей, это означает, что данные все
гда передаются в дисплей, а не читаются из него.
♦ Сигнал на контакте EN сообщает, что данные готовы к приему или передаче.
♦ Контакты D 4-D7 используются для передачи данных, а контакты D0-D3 оста
ются неподключенными.
Если ЖК-дисплей снабжен встроенной системой светодиодной подсветки с внут
ренним ограничивающим резистором, можно непосредственно подключить анод
к +5 В, а катод к земле, если такого резистора нет, следует добавить токоограничи
вающий резистор в линию между анодом и катодом. Подробности необходимо
уточнять в техническом описании конкретного дисплея.
В табл. 10.2 приведен рекомендуемый порядок соединения контактов ЖК-дисплея
и платы Arduino. Можно подключить дисплей и к другим контактам ввода-вывода.
206 Часть III. Интерфейсы передачи данных
RS D2
EN D3
D4 D4
D5 D5
D6 D6
D7 D7
void s e tu p ()
{
/ / Настройка экземпляра дисплея - число столбцов и строк:
le d .b e g in (16, 2 );
/ / Вывод текстового сообщения на экран дисплея
le d .p rin t( " J e re m y 1s D isp la y " );
}
void lo o p ()
{
/ / Установить курсор на вторую строку в первую позицию
l e d . s e tc u r s o r (О Д );
208 Часть III. Интерфейсы передачи данных
вю ооо,
вю ооо,
вю о о о ,
вю ооо,
вю ооо,
вю о о о ,
вю о о о ,
};
Я назвал этот массив р20, чтобы показать, что этот символ заполняет 20% про
странства. В функции setu p () вызываем библиотечную функцию createC har (),
чтобы назначить данному массиву идентификатор ГО пользовательского символа.
Пользовательские символы имеют ГО от 0 до 7, вы можете в общей сложности
сформировать восемь таких символов. Определим массив р20 как пользовательский
символ с ГО=0:
le d .c re a te C h a r (0, р 2 0 );
Для отображения пользовательского символа на дисплее поместите курсор в нуж
ное место и выполните команду
le d .w r ite ( (byte) 0);
Добавьте остальные пользовательские символы и с помощью двух вложенных цик
лов в основном цикле программы loop () обновляйте прогресс-бар. Код данной про
граммы приведен в листинге 10.2.
/ / Прогресс-бар на Ж -дисплее
/ / Подключение библиотеки L iq u id C ry stal
#include < L iquidC rystal.h>
/ / Инициализация экземпляра библиотеки L iq u id C ry stal
L iq u id C ry stal lc d (2 , 3, 4, 5, 6, 7);
В11000,
В11000,
В11000,
В11000,
В11000,
В11000,
};
b y te рбО[8] = {
В11100,
В11100,
В11100,
В11100,
В11100,
В11100,
В11100,
В11100,
};
b y te р8 0 [8] = {
В11110,
В11110,
В11110,
В11110,
В11110,
В11110,
В11110,
В11110,
};
b y te р100[8] = {
В11111,
В11111,
В11111,
В11111,
В11111,
В11111,
В11111,
В11111,
};
void s e tu p ()
{
/ / Настройка экземпляра дисплея - число столбцов и строк:
le d .b e g in (16, 2 );
/ / Вывод текста на Ж -дисплей
le d .p rin t( " J e re m y Ts D isp lay ");
led.createChar(1 , р4 0);
led.createChar(2, рбО);
led.createChar(3, р80);
led.createChar(4, plOO);
}
void loop()
{
/ / Курсор в начало второй строки
l e d . s e tC u rs o r(0 ,1 );
/ / Очистка второй строки
/ / 16 пробелов
l c d .p r i n t ( " " );
/ / Перебор каждого символа на второй строке
fo r ( in t i = 0; i<16; i++)
{
/ / Перебор каждого значения (р20 - plOO)
fo r ( in t j=0; j<5; j++)
{
le d .s e tC u r s o r ( i, 1 ); / / Столбец установки курсора
l e d . w r i t e ( j ); / / Вьюод символа
d e la y (100); / / Задержка
}
}
}
В начале каждого цикла во все 16 позиций второй строки выводится символ пробе
ла (строка очищается). Внешний цикл fo r о перебирает все 16 знакомест строки.
Во внутреннем цикле fo r () в каждое знакоместо с задержкой выводится увеличи
вающийся пользовательский символ прогресс-бара.
В10101,
воою о,
вооооо,
};
Вывод данных на экран ЖК-дисплея будет осуществлен в функции setu p (). Разме
щаем курсор в нужной позиции и с помощью библиотечных функций p r i n t о и
w rite () выводим надписи на экран (листинг 10.4).
/ / Стало жарко!
i f (с >= set_temp)
{
/ / Издать звук динамиком
i f (!one_time)
{
tone(SPEAKER, 400);
d e la y (500);
one_time = tr u e ;
}
Глава 10. Взаимодействие с жидкокристаллическими дисплеями 217
/ / Выключить динамик
e ls e
{
noTone(SPEAKER);
}
/ / Стало прохладнее
e lse
{
/ / Выключить динамик
/ / Сбросить состояние one_time в f a ls e
/ / Выключить вентилятор и значок на Ж -дисплее
noTone(SPEAKER);
one_time = f a ls e ;
digitalW rite(F A N , LOW);
le d .s e tC u r s o r (15,1) ;
l e d .w r i t e (1);
}
void s e tu p ()
{
pinMode(FAN, OUTPUT);
/ / Создание объекта Wire (12С-датчик температуры)
W ire .b e g in ();
/ / Настройки дисплея (число столбцов и строк)
le d .b e g in (16, 2 );
/ / Определить пользовательские символы
l e d . c re a te C h a r(0, d eg ree);
le d .c re a te C h a r(1, fa n _ o ff);
le d .c re a te C h a r(2, fan_on);
/ / Вывод закрепленных сообщений на дисплее
l e d . s e tC u rs o r(0 ,0 );
l e d . p r i n t (" C u rre n t:") ;
l e d . s e tC u rs o r(10,0) ;
l e d . w r i t e ( (b y te )0 );
l e d . s e tC u rs o r(1 1 ,0 );
le d .p r in t( " C " );
l e d . s e tC u rs o r(0 ,1 );
l e d . p r i n t ( " S e t : ") ;
l e d . s e tC u rs o r(10,1) ;
l e d . w r i t e ( (b y te )0 );
le d .s e tC u r s o r (11,1) ;
l e d .p r i n t( " C " ) ;
le d .s e tC u r s o r (15,1) ;
le d .w rite '(l) ;
}
void lo o p ()
{
/ / Получить значение от датчика температуры
Wire.beginTransmission(TEMP_ADDR);
W ire .w rite (0);
W ire. endT ransm ission();
W ire. requestFrom(TEMP_ADDR, 1);
220 Часть III. Интерфейсы передачи данных
/ / Ожидаем передачу
/ / Получить 1 байт
w h ile (W ire .a v a ila b le () == 0);
i n t с = W ire .re a d ();
/ / Установить курсор
/ / и вывести текущее значение
l e d . s e tC u rs o r(8 ,0 );
l e d . p r i n t (с );
/ / Проверка на дребезг для двух кнопок
currentDownTempButton = debounce(lastDownTempButton, DOWN_BUTTON);
currentUpTempButton = debounce(lastUpTempButton, UP_BUTTON);
/ / Уменьшить пороговое значение температуры
i f (lastDownTempButton== LOW && currentDownTempButton == HIGH)
{
set_tem p— ;
}
/ / Увеличить пороговое значение температуры
e ls e i f (lastUpTempButton== LOW && currentUpTempButton == HIGH)
{
set_temp++;
}
/ / Не жарко!
e ls e
{
/ / Выключить динамик
/ / Сбросить состояние one_time в f a ls e
/ / Выключить вентилятор и значок на Ж -дисплее
noTone(SPEAKER);
one_time = f a ls e ;
digitalW rite(F A N , LOW);
le d .s e tC u r s o r (15,1) ;
l e d . w r i t e (1) ;
}
}
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Как подключить ЖК-дисплей к плате Arduino по стандартной схеме.
♦ Как создавать собственные символы для ЖК-дисплея с помощью генерации
произвольных растровых изображений.
♦ Как изменить функцию устранения дребезга кнопки для нескольких кнопок.
♦ Как объединить датчики, двигатели, кнопки и ЖК-дисплей в едином автоном
ном устройстве.
Беспроводная связь
с помощью радиомоду
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ 2 платы Arduino (рекомендуется Uno или Leonardo);
♦ USB-кабели для программирования плат Arduino;
♦ источники питания для каждой платы Arduino;
♦ адаптер SparkFun USB ХВее Explorer;
♦ 2 радиомодуля ХВее Series 1;
♦ 2 платы расширения ХВее shield;
♦ кнопка;
♦ пьезозуммер;
♦ RGB-светодиод с общим катодом;
♦ 1 резистор номиналом 10 кОм;
♦ потенциометр 10 кОм;
♦ 1 резистор номиналом 150 Ом;
♦ 3 резистора номиналом 220 Ом;
♦ набор перемычек;
♦ 2 макетные платы.
способов для организации беспроводной связи, для плат Arduino проще всего при
менить радиомодули ХВее, которые производит компания Digi. Модули ХВее ра
ботают как беспроводной последовательный порт, что позволяет для связи с ними
использовать чтение и отправку последовательных данных, а это мы уже изучили.
В этой главе описана беспроводная связь только модулей ХВее, но мы рассмотрим
некоторые важные сведения, которые касаются беспроводной связи в целом.
Радиомодули ХВее позволяют осуществить связь между Arduino и компьютером
или между несколькими платами Arduino. Далее мы расскажем об этом подробно.
Следует помнить, что ХВее модули серий 1 и 2 несовместимы друг с другом. Для на
чинающих я рекомендую модули серии 1, т. к. они намного проще в настройке.
Есть различия и внутри каждой серии. Для большинства модулей выпускаются мо
дификации Pro и поп-Рго, они полностью совместимы, но габариты, стоимость,
энергопотребление и дальность действия первых больше (примерно 1 миля для Pro
и 300 футов для поп-Рго1). Я рекомендую начинать с более дешевой версии модулей
и переходить на Pro, если вам понадобится большая дальность.
Кроме того, существуют модули ХВее для частот 2,4 ГГц и 900 МГц. Частота
900 МГц дает выигрыш в дальности действия, такой сигнал лучше проникает
сквозь строительные конструкции, но она разрешена не во всех странах. Модули,
работающие на частотах 2,4 ГГц и 900 МГц, несовместимы друг с другом.
Для питания модуля ХВее необходимо напряжение 3,3 В, при подаче питания 5 В мо
дуль выйдет из строя.
226 Часть III. Интерфейсы передачи данных
Стабилизатор 3,3 В
Большинство плат Arduino работает от источника 5 В, логические уровни также
находятся в диапазоне от 0 (низкий уровень) до 5 В (высокий уровень). Напряже
ние питания модулей ХВее равно 3,3 В, логические уровни тоже другие. Хотя
у Arduino есть встроенный стабилизатор на 3,3 В, его ток недостаточен для питания
ХВее-модуля. Поэтому на большинстве ХВее-переходников установлен линейный
стабилизатор для питания модуля ХВее.
Светодиодные индикаторы
На большинстве плат расширения установлены два светодиодных индикатора:
♦ Associate — мигает, когда модуль работает в режиме последовательного обмена
данными;
♦ RSSI — загорается на короткое время при получении данных.
Г пава 11. Беспроводная связь с помощью радиомодулей ХВее_________________________ 227
4. Теперь установите значения PAN ID, адрес источника, адреса отправителя и по
лучателя. Можно задать множество других опций конфигурации, но мы в этой
книге ограничиваемся только четырьмя перечисленными параметрами. Чтобы
изменить значение настройки, просто щелкните по ней мышью. Установите сле
дующие значения: ID — 1234; DL — 1001; MY — 1000.
5. Нажмите кнопку Write в верхней части окна, чтобы записать эти значения
в ХВее-модуль. Измененные параметры будут выделены синим цветом
(рис. 11.11).
Вы настроили свой первый модуль ХВее! Теперь аккуратно извлеките один модуль
из адаптера ХВее Explorer и установите другой. Выполните описанные действия со
вторым модулем ХВее, поменяв значения параметров DL и MY, чтобы модули
могли обмениваться данными между собой. На рис. 11.12 показана конфигурация
для второго ХВее-модуля.
Гпава 17. Беспроводная связь с помощью радиомодулей ХВее 233
234 Часть III. Интерфейсы передачи данных
Ваши модули ХВее настроены и готовы для связи друг с другом. Назначив им
идентификатор PAN ГО, отличный от значения по умолчанию, вы уменьшаете ве
роятность помех другим сетям ХВее. Теперь можно сразу перейти к разделу 11.3.
7. Чтобы убедиться, что все настроено верно, введите одну из команд a tid , atmy
или atdl без значений и нажмите клавишу <Enter>, при этом на дисплей будет
выведено текущее значение параметра.
Питание от батареи
Можно питать плату Arduino от батареи, подключив ее к разъему питания или вхо
ду Vm. С этих входов напряжение поступает на встроенный стабилизатор, который
выдает напряжение 5 В для питания микропроцессора и других компонентов. На
рис. 11.14 показана 9-вольтовая батарея со встроенным выключателем и разъемом
питания.
Вместо 9-вольтовой батареи можно использовать несколько батареек АА с напря
жением 1,5 В. Если соединить последовательно четыре таких батарейки, получится
напряжение около 6 В. Минимальное падение напряжения на встроенном в Arduino
стабилизаторе равно 1 В. При входном напряжении 5,5 В на шине питания будет
Гпава 11. Беспроводная связь с помощью радиомодулей ХВее 237
4,5 В. Можно рассчитывать, что плата будет работать и при напряжении 4,5 В, что
приемлемо для платы на базе ATMega, хотя и ниже напряжения при питании
от USB.
void s e tu p ()
{
S e r ia l.b e g in (9600); / / Запуск последовательного порта
}
void lo o p ()
{
v a l = map(analogRead(POT), 0, 1023, 0, 255); / / Чтение и
// масштабирование данных
S e r ia l.p rin tln ( v a l); // Отправка данных
d e la y (50); // Задержка
}
void s e tu p ()
{
s iz e (500,500); / / Размер окна
p o rt = new S e r i a l ( t h i s , "COM3", 9600); / / Инициализация
/ / последовательного порта
Гпава 11. Беспроводная связь с помощью радиомодулей ХВее 239
void draw ()
{
background(0 ,0 ,b r ig h tn e s s ); / / Перерисовать окно
}
При запуске программы она должна работать так же, как это было при подсоедине
нии платы Arduino непосредственно к компьютеру. Теперь вы можете ходить
вокруг дома и офиса (если питаете Arduino от батареи) и менять цвет на экране
компьютера.
void s e tu p ()
{
S e r i a l .b e g i n (9600); / / Инициализация последовательного
/ / порта на скорости 9600
/ / Установить выводы на выход OUT
pinMode (RED, OUTPUT);
pinMode (GREEN, OUTPUT);
pinMode (BLUE, OUTPUT);
}
void lo o p ()
{
/ / Пока в буфере есть данные
w hile ( S e r ia l . a v a il a b le () > 0)
{
rv a l = S e r i a l . p a r s e l n t (); // Первое число
gval = S e r i a l . p a r s e l n t (); // Второе число
bval = S e r i a l . p a r s e l n t (); // Третье число
i f ( S e r ia l . r e a d () == ' \ n ') // Конец передачи
{
/ / Установить яркость R,G,B светодиода
analogWrite(RED, r v a l) ;
analogWrite(GREEN, g v a l);
analogWrite(BLUE, b v a l);
}
}
}
Далее соединяем элементы, как вы делали в главе 6 (рис. 11.18). К плате Arduino
присоединяем переходник ХВее и модуль ХВее.
Как и в предыдущем разделе, подключаем адаптер USB ХВее Explorer к компьюте
ру и запускаем программу на Processing (листинг 11.4). Убедитесь, что файл hsv.jpg
находится в папке data в каталоге программы. И не забудьте установить правильное
имя последовательного порта.
void s e tu p ()
{
s i z e (640,256);
img = lo a d lm a g e ("h sv .jp g "); / / Загрузка фоновой картинки
p o rt = new S e r i a l ( t h i s , "COM9", 9600); / / Открыть последовательный порт
}
242 Часть III. Интерфейсы передачи данных
void draw ()
{
background(0); / / Установка цвета фона
im age(img,0 ,0 ) ; I I Картинка
}
void m ousePressed()
{
c o lo r с = get(mouseX, mouseY); / / Получить RGB-цвет по позиции курсора мыши
S trin g c o lo rs = i n t ( r e d ( c ) ) + " ," ti n t ( g r e e n ( c ) ) + " ," + in t( b lu e ( c ) ) + "\n";
/ / Преобразовать в строку
p rin t(c o lo rs ); / / Вывод для отладки
p o r t .w r i t e ( c o lo r s ) ; / / Отправка переменной в Arduino
}
Гпава 11. Беспроводная связь с помощью радиомодулей ХВее 243
При запуске программы появится экран выбора цвета как в главе 6. Выберите цвет.
Данные будут переданы по беспроводной связи на плату Arduino, и подключенный
к ней светодиод должен светить выбранным цветом. Передаваемые значения мож
но контролировать в мониторе последовательного порта.
Теперь ясно, что с помощью модулей ХВее можно обмениваться данными с ком
пьютером в двух направлениях. В следующем разделе мы рассмотрим беспровод
ной обмен между двумя платами Arduino напрямую.
Чтобы посетителям было удобно, рекомендую взять большую кнопку звонка, протянув
провода через стену к плате Arduino.
Теперь необходимо выбрать тип платы Arduino и способ питания приемника. Я ис
пользовал плату Uno, подключенную к сетевому USB-адаптеру. Подойдет также
батарея или USB-кабель, соединенный с компьютером. Функциональность прием
ника можно расширить, добавив светодиоды или компьютерное Processing-
приложение.
void setup()
{
// Для платы Leonardo выводы Rx/Tx
//не мультиплексированы с USB г
// Код для Leonardo (Seriall = RX/TX)
// Для UNO измените Seriall на Serial
Seriall.begin(9600);
}
void loop()
{
Seriall.println(digitalRead(BUTTON)); // Отправка статуса кнопки
delay(50); // Небольшая задержка
}
i n t offLED = RED;
i n t fre q = 131;
unsigned long prev_tim e = 0 ; / / Таймер для переключения цвета светодиода
/ / и частоты звука
void s e tu p ()
{
S e r i a l . b e g in (9600);
}
void lo o p ()
{
/ / Для переключения звука и цвета светодиода
/ / прошло 100 мс?
i f (m illis () >= prev_tim e + 100)
{
/ / Переключение светодиода
i f (onLED == GREEN)
{
onLED = RED;
offLED = GREEN;
}
e ls e
{
onLED = GREEN;
offLED = RED;
}
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Что выпускается множество разновидностей модулей ХВее.
♦ Что для использования радиомодулей ХВее с большинством плат Arduino необ
ходимо конвертировать логические уровни с 5 до 3,3 В.
♦ Как настроить модули ХВее из программы X-CTU (для ОС Windows) или с по
мощью терминала (для операционных систем Linux и Мае).
♦ Как организовать автономное питание платы Arduino.
♦ Как установить беспроводную связь между компьютером и платой Arduino
с помощью модулей ХВее.
♦ Как с помощью модулей ХВее организовать беспроводную связь между двумя
платами Arduino.
♦ Как реализовать временную задержку с помощью функции m i n i s о .
Дополнительные темы и
В этой части_____________________________________
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino (рекомендуется Uno);
♦ USB-кабель для программирования платы Arduino;
♦ кнопка;
♦ пьезозуммер;
♦ RGB-светодиод с общим катодом;
♦ 1 резистор номиналом 10 кОм;
♦ 1 резистор номиналом 100 Ом;
♦ 1 резистор номиналом 150 Ом;
♦ 3 резистора номиналом 220 Ом;
♦ электролитический конденсатор ЮмкФ;
♦ микросхема 74НС14 (шесть инверторов с триггерами Шмитта);
♦ набор перемычек;
♦ 2 макетные платы.
12.2.3. Многозадачность
Одна из причин использования прерываний — предоставление псевдомного
задачности. С помощью Arduino никогда нельзя обеспечить реальную многозадач
ность, т. к. на плате только один микроконтроллер, который за один такт может
выполнить только одну команду. Однако, поскольку микроконтроллер выполняет
команды очень быстро, можно прибегнуть к прерываниям, чтобы выполнять раз
ные задачи почти одновременно. Например, с помощью прерывания можно в про
256 Часть IV. Дополнительные темы и проекты
void s e tu p ()
{
pinMode (RED, OUTPUT);
pinMode (GREEN, OUTPUT);
pinMode (BLUE, OUTPUT);
/ / Режим прерывания RISING (переход c LOW на HIGH)
attachlnterrupt(BUTTON_INT, swap, RISING);
}
void swap()
{
/ / Выключить текущий цвет
analogW rite(selectedLED , 0);
/ / Новое значение для переменной selectedLED
i f (selectedLED == GREEN)
selectedLED = RED;
e ls e i f (selectedLED == RED)
selectedLED = BLUE;
e ls e i f (selectedLED == BLUE)
selectedLED = GREEN;
}
void lo o p ()
{
fo r ( in t i = 0; i<256; i++)
{
analogW rite(selectedLED , i ) ;
d e la y (10);
}
fo r ( in t i = 255; i>= 0; i — )
{
analogW rite(selectedLED , i ) ;
d e la y (10);
}
}
Таймер Timerl служит для включения ШИМ-сигнала на выводах 9 и 10, поэтому при
работе с библиотекой TimerOne выполнить функцию analogW rite () для этих контак
тов не удастся.
void s e tu p ()
{
pinMode(LED, OUTPUT);
T im erl. i n i t i a l i z e (1000000); / / Значение для переполнения 1000000 мкс
/ / (1 секунда)
T im erl. a tta c h ln te r r u p t( b lin k y ) ; / / Выполнять b lin k y ()n p n переполнении
}
void loop()
{
/ / Вставьте сюда любой код
}
void s e tu p ()
{
/ / Запуск последовательного порта
S e r i a l .b e g i n (9600);
pinMode (SPEAKER, OUTPUT);
/ / Запуск для кнопки аппаратного прерывания по RISING
attachlnterrupt(BUTTON_INT, changeKey, RISING);
/ / S e t up tim e r i n te r r u p t
T im erl. i n i t i a l i z e (500000); / / Период 0,5 секунды
268 Часть IV. Дополнительные темы и проекты
void changeKeyO
{
octave_multiplier = 1;
if (key = NOTE_C)
key = NOTE_D;
else if (key == NOTE_D)
key = NOTE_E;
else if (key == NOTE_E)
key = NOTE_F;
else if (key == NOTE_F)
key = NOTE_G;
else if (key == NOTE_G)
key = NOTE_A;
else if (key == NOTE_A)
key = NOTE_B;
else if (key == NOTE_B)
key = NOTE_C;
}
void loop()
{
Serial.print("Key: ") ;
Serial.print(key);
Serial.print(" Multiplier: ");
Serial.print(octavejmiltiplier);
Serial.print(" Frequency: ");
Serial.println(key*octavejmiltiplier);
delay(100);
}
Значения частот для нот можно найти в Интернете. Базовые частоты определены
для нот второй октавы. Обратите внимание, что переменные key и octave_
multiplier должны быть объявлены как volatile, потому что их значения меняются
во время обработки прерываний. Функция changeKey () вызывается каждый раз при
срабатывании прерывания по нажатию кнопки и изменяет базовое значение пере
Гпава 12. Аппаратные прерывания и прерывания по таймеру 269
менной key. Функция changeP itch () вызывает tone () для установки частоты сигна
ла для динамика. Она запускается каждые полсекунды по прерыванию таймера.
При каждом вызове она удваивает базовую частоту, пока не будет достигнуто ее
16-кратное увеличение. Затем процесс повторяется с начальной базовой частоты.
В цикле loop о в последовательный монитор каждые 0,1с выводятся значения
переменных key, octave m u itip iie r и частоты.
Резюме________________________________________
В этой главе вы узнали следующее;
♦ Как выбрать альтернативу: опрос входов в цикле или использование прерыва
ний.
♦ Что реализация прерываний на различных платах Arduino неодинакова. На плате
Due прерывания можно задать для любого контакта, на других платах для пре
рываний доступны только определенные контакты.
♦ Как создать противодребезговую защиту кнопок на аппаратном уровне с по
мощью RC-цепочки и триггера Шмитта.
♦ Что с помощью функций обработки прерываний можно асинхронно опрашивать
входы Arduino.
♦ Как с помощью сторонней библиотеки TimerOne организовать прерывания по
таймеру.
♦ Как комбинировать прерывания таймера, аппаратные прерывания и опрос в од
ной программе, чтобы параллельно выполнять несколько задач.
тштШ:
,Щ£,
Обмен
с картами п
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino (рекомендуется Uno);
♦ USB-кабель для программирования платы Arduino;
♦ источник питания для платы Arduino (блок питания или аккумулятор);
♦ инфракрасный датчик расстояния;
♦ плата часов реального времени;
♦ плата расширения SD card shield;
♦ карта памяти SD;
♦ набор перемычек;
♦ макетная плата;
♦ компьютер с картридером.
1 Н а русск ом : 11Ц;р:/Лу1ккатрегка.ги/видеоуроки:11-$с1-карты-и-регистрация-данных.
272 Часть IV. Дополнительные темы и проекты
D ate T im e V a lu e l V a lu e 2
♦ имеют вход выбора (CS), который может быть контактом по умолчанию (53 на
Mega, 10 на других платах Arduino);
♦ подают питание 3,3 В на SD-карту и согласуют логические уровни.
Вот список наиболее распространенных плат расширения для SD-карт:
♦ Cooking Hacks Micro SD shield (http://www.exploringarduino.com/parts/
cooking-hacks-SD-shield) (рис. 13.7) используется для иллюстрации примеров
этой главы. Это самый маленький переходник из рассматриваемых нами, и его
можно подключить либо к цифровым контактам (8-13 на Uno), либо к 6-кон
тактному ICSP на Arduino. При подключении к контактам 8-13 вход выбора CS
соединен с контактом 10. При подключении к разъему ICSP вход CS можно со
единить с любым контактом Arduino. Это полезно, если контакт 10 платы
Arduino занят. Переходник поставляется с SD-картой 2 Гбайт.
зует контакт 10, а SD-карта— контакт 4. Необходимо следить, чтобы оба уст
ройства не были включены одновременно; активной может быть только одна
линия CS (низкий логический уровень).
♦ Adafruit data logging shield (http://www.exploringarduino.com/parts/ adafruit-
data-logging-shield) (рис. 13.11) особенно хорошо подходит для экспериментов,
280 Часть IV. Дополнительные темы и проекты
которые мы рассмотрим далее в этой главе, потому что включает в себя часы
реального времени (RTC) и интерфейс SD-карты. Вывод CS SD-карты на этом
переходнике назначен по умолчанию (53 на Mega, 1 0 — на других платах
Arduino), а чип часов реального времени подключен к шине 12С.
На плате расширения SparkFun MicroSD shield (http://www.exploringarduino.com/
parts/spark-fun-microSD-shield) (рис. 13.12) установлен только слот SD-карты. Тем
не менее, предусмотрено монтажное поле для припаивания дополнительных ком
понентов. Вывод CS SD-карты подключен к контакту 8, его необходимо указать
при использовании библиотеки SD с этим переходником.
if (!SD.begin(CS_pin))
{
Serial.println("Card Failure");
return;
}
Serial.println("Card Ready");
282 Часть IV. Дополнительные темы и проекты
В первой строке расположена команда создания нового файла (или открытие, если
он уже существует) с названием lo g .c sv . Если файл создан/открыт успешно, пере
менная d a ta F ile получит значение tru e , и начнем процесс записи данных в файл.
В противном случае сообщаем об ошибке в последовательный порт. Запись строки
данных В файл осуществляет функция d a t a F i l e .p r i n tl n O ; чтобы предотвратить
добавление символа новой строки, вызывайте функцию d a ta F ile . p r i n t о . Все дан
ные направляются в буфер и записываются в файл только после выполнения
команды d a ta F ile . c lo se ().
Теперь напишем простую программу, которая создает на SD-карте файл log.csv и
каждые 5 секунд записывает в него через запятую метки и какое-либо сообщение
(листинг 13.3). В каждой строке файла CSV будет записана временная метка (теку
щее значение функции minis о) и некоторый текст. Программа может показаться
вам бесполезной, но на самом деле это важный пример, подготавливающий взаи
модействие с реальными датчиками, чем мы займемся в дальнейших проектах.
void s e tu p ()
{
S e r i a l .b e g i n (9600);
S e r i a l . p r i n t l n ( " I n i t i a l i z i n g C ard ");
/ / Установить CS как выход
pinMode(CS_PIN, OUTPUT);
/ / Для питания карты используется вывод 8, установить HIGH
pinMode(POW_PIN, OUTPUT);
digitalW rite(POW _PIN, HIGH);
i f ( !S D .begin(CS_PIN))
{
S e r ia l.p r in tln ( " C a r d F a ilu r e " ) ;
re tu rn ;
}
S e r ia l.p r in tln ( " C a r d Ready");
}
v oid loop()
{
long timestam p = m i l l i s O ;
S trin g d a ta S trin g = "H ello T here!";
/ / Открыть файл и записать в него
F ile d a ta F ile = S D .open("log.csv", FILE_WRITE);
i f (d a ta F ile)
{
d a ta F ile .p rin t( tim e s ta m p );
d a t a F i l e .p r i n t ( " ," ) ;
d a t a F i l e .p r i n tl n ( d a t a S tr in g ) ;
d a t a F i l e .c l o s e (); / / Данные не записаны,
/ / пока соединение не закрыто!
♦ при каждом проходе цикла loop ( ) временная метка обновляется значением те
кущего времени, прошедшего с начала выполнения программы в миллисекун
дах. Переменная должна иметь тип long, потому что m i n i s о возвращает число
больше, чем 16 бит.
Файл открывается для записи и в него добавляются данные, разделенные запятыми.
Мы также выводим эти данные в последовательный порт для отладочных целей.
Если вы откроете терминал последовательного порта, то увидите вывод данных как
на рис. 13.14.
Программа из листинга 13.4 открывает файл для чтения и считывает целые значе
ния. Значение сохраняется в переменной частоты обновления, которую необходимо
будет определить в начале программы. После чтения файл следует закрыть.
Теперь можно объединить листинги 13.3 и 13.4 и менять скорость записи, основы
ваясь на содержимом файла speed.txt, как показано в листинге 13.5.
void s e tu p ()
{
S e r i a l . b e g in (9600);
S e r i a l . p r i n t l n ( " I n i t i a l i z i n g C ard ");
/ / Установить CS как выход
pinMode(CS_PIN, OUTPUT);
/ / Для питания карты используется контакт 8, установить HIGH
pinMode(POW_PIN, OUTPUT);
digitalW rite(POW _PIN, HIGH);
i f ( !SD.begin(CS_PIN))
{
S e r i a l . p r i n t l n ("Card F a ilu r e " );
re tu rn ;
}
S e r ia l.p r in tln ( " C a r d Ready");
/ / Чтение настроек (sp e e d .tx t)
F ile commandFile = S D .o p e n (" sp e e d .tx t" );
i f (commandFile)
{
S e ria l.p rin tln ( " R e a d in g Command F ile " ) ;
w h ile(co m m an d F ile.av ailab le())
{
r e fre s h _ r a te = com m andF ile.parselnt();
}
S e r ia l.p r in t( " R e f r e s h Rate = " );
S e r i a l .p r i n t ( r e f r e s h _ r a t e ) ;
S e r i a l . p r i n t l n ("ms") ;
commandFile. c l o s e (); / / Закрыть файл настроек
}
e ls e
{
S e ria l.p rin tln ( " C o u ld not read command f i l e . " ) ;
re tu rn ;
}
}
v oid loop()
{
long timeStamp = m i l l i s O ;
S trin g d a ta S trin g = "H ello T here!";
/ / Открыть файл и записать в него
F ile d a ta F ile = SD.open(" lo g .c s v " f FILE_WRITE);
i f (d a ta F ile)
{
d a ta F ile .p rin t(tim e S ta m p );
d a ta F ile .p rin t( " f " ) ;
d a t a F i l e .p r i n tl n ( d a t a S tr in g ) ;
d a t a F i l e .c l o s e (); / / Закрыть файл
288 Ч аст ь IV. Д о п о л н и т е л ь н ы е т е м ы и про ект ы
Далее предполагается, что вы используете эту плату. Тем не менее, можно просто
собрать схему из элементов на макетной плате и подключить непосредственно
к Arduino. Потребуется кварцевый резонатор на 32,768 кГц, подтягивающие рези
сторы номиналом 2,2 кОм и круглая батарейка 3,0 В размером с монету. Если вы
решили собрать плату самостоятельно, можете приобрести эти компоненты и со
брать их на макетной плате по схеме, приведенной на рис. 13.19.
290 Часть IV. Дополнительные темы и проекты
Отметим, что последний контакт на RTC не связан с Arduino; это меандр, генери
руемый RTC, в нашем примере он не задействован. В программе следует подать на
контакт А2 уровень low и на АЗ уровень high (+5 В), чтобы обеспечить питание
RTC. Если вы собрали свой модуль RTC на макетной плате, то установка будет вы
глядеть немного по-другому.
Если после запуска программы вы заметите, что она через некоторое время останав
ливается, то причина может заключаться в нехватке оперативной памяти. Так проис
ходит из-за строк, которые занимают большой объем оперативной памяти, это отно
сится к командам вывода в последовательный порт S e r ia l , p r i n t () и
S e r i a l . p r i n t l n ( ) . Проблему можно решить, удалив из программы указанные коман
ды и поручив компилятору хранить строки не в оперативной памяти, а во флэш-
памяти Arduino. Для этого для строк используем обертку F (), например
S e r i a l . p r i n t l n (F ( " H e ll o " ) ). Описанный метод реализован в листинге 13.6.
Обновленная программа (листинг 13.6) использует RTC в качестве таймера для ре
гистрации данных. Программа перемещает большинство строк во флэш-память,
чтобы предотвратить переполнение оперативной памяти.
void setup()
{
Serial.begin(9600);
Serial.println(F("Initializing Card"));
// Настроить контакты CS и питания как выходы
pinMode(CS_PIN, OUTPUT);
Гпава 13. Обмен данными с картами памяти SD 293
S e r i a l . p r i n t l n ( F ("Card R eady"));
/ / 4Te,ii^' конфигурационного файла (sp e e d .tx t)
F ile commandFile = SD.open(" s p e e d .tx t" );
i f (commandFile)
{
S e ria l.p rin tln (F (" R e a d in g Command F il e " ) ) ;
while(com m andFile. a v a il a b le ())
{
r e fre s h _ r a te = co m m andF ile.parselnt();
}
S e ria l.p rin t(F ( " R e f re s h Rate = " ) ) ;
S e ria l.p rin t(re f re s h _ ra te );
S e r ia l.p r in tln ( F ( " m s " ) );
commandFile. c l o s e ();
}
e ls e
{
S e ria l.p rin tln ( F ( " C o u ld no t read command f i l e . " ) ) ;
re tu rn ;
}
/ / Запись заголовка
F ile d a ta F ile = S D .open("log.csv", FILE_WRITE);
i f (d a ta F ile)
{
d a t a F i l e .p r i n tI n ( F ("\nNew Log S ta r te d ! " ) ) ;
294 Часть IV. Дополнительные темы и проекты
void loop()
{
/ / Получить значение даты и времени и перевести в строковые значения
DateTime d atetim e = RTC.nowO;
year = S tr in g (d a te tim e .y e a r(), DEC);
month = S trin g (d a te tim e .m o n th (), DEC);
day = S trin g (d a te tim e .d a y (), DEC);
hour = S tr in g (d a te tim e .h o u r(), DEC);
minute = S trin g (d a te tim e .m in u te (), DEC);
second = S trin g (d a te tim e .s e c o n d (), DEC);
/ / Собрать строку текущей даты и времени
d ate = year + " /" + month + " /" + day;
tim e = hour + " :" + m inute + " :" + second;
S trin g d a ta S trin g = "H ello T here!";
/ / Открыть файл и записать значения
F ile d a ta F ile = S D .open("log.csv", FILE_WRITE);
i f (d a ta F ile)
{
d a ta F ile .p r in t( d a te ) ;
d a t a F i l e .p r i n t (F (", ") ) ;
d a ta F ile .p r in t( tim e ) ;
d a t a F i l e .p r i n t (F ( " ," ) ) ;
d a t a F i l e .p r i n tl n ( d a t a S tr in g ) ;
d a t a F i l e . c l o s e () ;
/ / Вывод в последовательный порт для отладки
S e r ia l.p rin t(d a te );
S e r i a l . p r i n t (F ( " ," ) ) ;
S e r ia l.p r in t( tim e ) ;
S e r i a l . p r i n t (F (", ") ) ;
S e r ia l.p r in tln ( d a ta S tr in g ) ;
}
e ls e
{
S e r ia l.p r in tI n ( F ( " C o u ld n 't open log f i l e " ) ) ;
}
d e la y ( r e f r e s h _ r a te ) ;
Гпава 13. Обмен данными с картами памяти SD 295
void s e tu p ()
{
S e r i a l . b e g in (9600);
S e r i a l . p r i n t l n ( r e i n i t i a l i z i n g Card") ) ;
/ / Настроить контакты CS и питания как выходы
pinMode(CS_PIN, OUTPUT);
pinMode(SD_POW_PIN, OUTPUT);
pinMode(RTC_POW_PIN, OUTPUT);
pinMode(RTC_GND_PIN, OUTPUT);
/ / Установка питания карты и RTC
digitalWrite(SD_POW_PIN, HIGH);
digitalWrite(RTC_POW_PIN, HIGH);
digitalWrite(RTC_GND_PIN, LOW);
/ / Инициализация Wire и RTC
W ire.beginO ;
RTC. b e g in ();
/ / Если RTC не запущены, загрузить дату/время с компьютера
i f (! R T C .isrunning())
{
S e r i a l . p r i n t l n ( F ("RTC i s NOT ru n n in g !" ));
RTC. adj u s t (DateTime (__DATE__, __TIME__) ) ;
}
/ / Инициализация карты SD
i f ( !SD.begin(CS_PIN))
{
S e ria l.p rin tln ( F ( " C a rd F a ilu r e " ) );
re tu rn ;
}
Гпава 13. Обмен данными с картами памяти SD 299
vo id loop()
{
/ / Получить значение даты и времени и перевести в строковые значения
DateTime d atetim e = RTC.nowO;
year = S tr in g (d a te tim e . y e a r (), DEC);
month = S trin g (d a te tim e .m o n th (), DEC);
day = S tr in g (d a te tim e .d a y (), DEC);
hour = S tr in g (d a te tim e .h o u r(), DEC);
m inute = S trin g (d a te tim e .m in u te (), DEC);
second = S trin g (d a te tim e .s e c o n d (), DEC);
/ / Собрать строку текущей даты и времени
d ate = year + " /" + month + " /" + day;
tim e = hour + " :" + m inute + " :" + second;
/ / Собрать данные движения
raw = analogRead(IR_PIN);
/ / При изменении значения более чем на 75 между показаниями
/ / фиксируем факт прохода через дверь,
i f (abs(raw -raw_prev) > 75)
a c tiv e = tr u e ;
e ls e
a c tiv e = f a ls e ;
raw_prev = raw;
/ / Открыть лог-файл и записать в него,
i f (a c tiv e | | update_tim e == 20)
{
F ile d a ta F ile = S D .open("log.csv", FILE_WRITE);
i f (d a ta F ile)
{
d a t a F i l e .p r i n t ( d a t e ) ;
300 Часть IV. Дополнительные темы и проекты
Резюме________________________________________
В этой главе вы узнали следующее:
♦ Что данные удобно хранить в CSV-файлах, использующих строки и запятые
в качестве разделителей.
♦ Как отформатировать SD-карту памяти в операционных системах Windows, Mac
и Linux.
♦ Что есть множество плат расширения SD-карт для Arduino, каждая со своими
особенностями.
♦ Как использовать Arduino библиотеку SD для записи и чтения из файла на
SD-карте.
♦ Как с помощью RTC вставить временные метки в данные регистратора.
♦ Как преодолеть ограничения оперативной памяти за счет хранения строк во
флэш-памяти.
♦ Как обнаружить движение по изменению аналогового значения, полученного
с ИК-датчика расстояния.
♦ Как построить на компьютере график данных от регистратора, используя про
грамму просмотра электронных таблиц.
ваш и
14
Подключение Arduino к И
Список деталей
Для повторения примеров главы вам понадобятся следующие детали:
♦ плата Arduino (рекомендуется Uno);
♦ USB-кабель для программирования платы Arduino;
♦ плата расширения Ethernet shield;
♦ фоторезистор;
♦ датчик температуры ТМР36;
♦ RGB-светодиод;
♦ 1 резистор номиналом 10 кОм;
♦ 1 резистор номиналом 150 Ом;
♦ 3 резистора номиналом 220 Ом;
♦ динамик или пьезозуммер;
♦ кабель Ethernet;
♦ доступ к проводному маршрутизатору;
♦ набор перемычек;
♦ макетная плата.
IP-адрес
IP-адрес представляет собой уникальный адрес, который идентифицирует каждое
устройство, подключенное к сети. При работе в локальной сети есть на самом деле
304 Часть IV. Дополнительные темы и проекты
два вида IP-адресов: IP-адреса внутренней сети и глобальный IP-адрес. Если в ва
шем доме или офисе установлен маршрутизатор (см. рис. 14.1), то каждое устрой
ство в пределах локальной сети обладает локальным IP-адресом, который виден
всем устройствам вашей сети. Маршрутизатор/модем имеет один глобальный
IP-адрес, который виден всему Интернету. Если вы хотите установить связь через
Интернет между компьютером в другом месте и устройством, подключенным
к маршрутизатору, необходимо преобразование сетевых адресов (NAT).
МАС-адрес
МАС-адреса, в отличие от IP-адресов, уникальны в пределах всей Сети (на практи
ке они часто таковыми не являются). МАС-адреса назначаются каждому сетевому
физическому устройству и не меняются. Например, когда вы покупаете компьютер,
уникальные МАС-адреса присвоены и внутреннему модулю Wi-Fi, и адаптеру
Ethernet. Это позволяет по МАС-адресу идентифицировать физические устройства
в Сети.
HTML
HTML, или язык гипертекстовой разметки, является языком разметки документов
в Интернете. Для отображения веб-страницы с вашего Arduino напишем простой
HTML-документ, который создает кнопки и ползунки для отправки данных.
HTTP
HTTP, или протокол передачи гипертекста, определяет протокол для связи через
World Wide Web (Всемирную паутину) и используется в браузерах. HTTP задает
информацию заголовка, которая передается в виде части сообщения. Этот заголо
вок определяет, какая веб-страница будет отображаться и подтверждает успешное
получение данных.
GET/POST
GET и POST определяют два способа передачи информации на удаленный веб
сервер. Если вам встретится URL, который выглядит как www.jeremyblum.
com/?s=arduino, то это запрос GET. GET определяет ряд переменных, следующих
за вопросительным знаком в URL. В данном случае передается переменная s со
значением arduino. Когда страница получает этот URL, он идентифицирует пере
менную s, выполняет поиск и возвращает страницу результатов. POST очень
похож, но информация не видна непосредственно в URL. Вместо этого, данные пе
редаются в фоновом режиме. POST обычно используется, чтобы скрыть конфиден
циальную информацию.
DHCP
DHCP, или протокол динамической конфигурации узла, подключает устройства
к локальной сети за один шаг. Чаще всего при подключении к Wi-Fi или проводной
сети у вас на устройстве не установлен вручную IP-адрес, по которому маршру
Гпава 14. Подключение Arduino к Интернету 305
DNS
Аббревиатура DNS расшифровывается как Domain Name System (система домен
ных имен). Каждый веб-сайт, который расположен на сервере в сети Интернет,
имеет уникальный IP-адрес. При вводе в www.google.com DNS-сервер смотрит на
список, который информирует его о IP-адресе, связанном с этим URL. Затем он пе
редает IP-адрес обратно в браузер вашего компьютера, чтобы браузер мог общаться
с сервером Google. DNS позволяет вводить понятные имена вместо запоминания
IP-адреса всех ваших любимых веб-сайтов. Можно образно сравнить DNS для веб
сайтов со списком контактов в телефоне для телефонных номеров.
Клиенты и серверы
В этой главе вы узнаете, как использовать Arduino с платой расширения Ethernet
shield в качестве сервера и клиента. Все устройства, подключенные к Интернету,
выступают в роли сервера или клиента (хотя на самом деле часто исполняют обе
роли). Сервер выдает информацию по запросу от запрашивающего компьютера,
поступающему по сети. Это может быть запрос веб-страницы, данных из информа
ционной базы, электронной почты и многого другого. Клиент— это устройство,
которое запрашивает данные и получает ответ. При подключении компьютера
к Интернету веб-браузер вашего компьютера выступает в качестве клиента.
HTML-страница из листинга 14.1 содержит четыре элемента формы. Тег <form> за
дает начало формы, тег </form> — конец формы. Каждый элемент формы с тегом
308 Часть IV. Дополнительные темы и проекты
<input> определяет, какие данные будут переданы на сервер при отправке формы.
В нашем примере переменная называется ь и на сервер передается номер необхо
димого вывода RGB-светодиода. Пустой элемент a c tio n указывает, что страница
перезагружается при отправке формы. Значение скрытых полей (in p u t с типом
hidden) будут отправлены на сервер при нажатии кнопки submit. Для выбора часто
ты мы добавляем новый HTML-элемент (in p u t с типом range). Это позволяет сде
лать ползунок диапазона. Вы можете перемещать ползунок с шагом 100 для выбора
частоты, которая будет передаваться в переменной с именем s. Старые браузеры не
поддерживают этот элемент (слайдер) и он будет отображаться как поле ввода.
Чтобы увидеть, как будет выглядеть страница, запустите ваш браузер (я рекомен
дую Google Chrome). В Chrome нужно нажать комбинацию клавиш <Ctrl>+<0>
(в Windows) или <Cmd>+<0> (в OS X), чтобы вызвать диалоговое окно Открыть.
Откройте созданный HTML-файл (рис. 14.3).
/ / Arduino веб-сервер
/ / Часть адаптированного кода под лицензией MIT L icense от
/ / h t t p : //b ild r.o rg /2 0 1 1 /0 6 /a r d u in o - e th e r n e t- p in - c o n tr o l/
#in clu d e < E thernet.h>
#include <SPI.h>
co n st i n t BLUE =5;
co n st i n t GREEN =6;
310 Часть IV. Дополнительные темы и проекты
co n st i n t RED =7;
co n st i n t SPEAKER =3;
/ / МАС-адрес устройства
/ / Должен быть написан на этикетке вашего устройства
/ / или можете использовать этот
byte mac[] = { 0x90, 0хА2, OxDA, 0x00, 0х4А, 0хЕ0 };
/ / Сервер на порту 80
E th ern e tS e rv er s e rv e r = E th e rn e tS e rv e r(80); //Порт 80
boolean re c e iv in g = f a ls e ; / / Отслеживание данных GET
void s e tu p ()
{
S e r i a l . b e g in (9600);
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
/ / Соединение c DHCP
i f (!E th ern e t.b eg in (m a c))
{
S e ria l.p rin tln ( " C o u ld not C onfigure E th ern e t w ith DHCP.");
re tu rn ;
}
e ls e
{
S e r i a l . p r i n t l n ("E th ern et C onfigured!" );
}
/ / Запуск сервера
s e r v e r .b e g in ();
S e r i a l . p r i n t ("S erver S ta r t e d .\nLocal IP: " );
S e r i a l . p r i n tln ( E th e r n e t. l o c a l l P () );
}
void lo o p ()
{
E th e rn e tC lie n t c l i e n t = s e r v e r . a v a il a b le ();
i f (c lie n t)
{
/ / Запрос HTTP заканчивается пустой строкой
boolean cu rren tL in elsB la n k = tru e ;
boolean sentH eader = f a ls e ;
Гпава 14. Подключение Arduino к Интернету 311
Как только вы найдете эту опцию, зарезервируйте текущий IP-адрес платы Arduino,
назначив ее МАС-адрес, установленный в предыдущей программе. Для применения
настройки необходима перезагрузка маршрутизатора. Убедитесь в правильности
настройки, перезагрузив маршрутизатор и посмотрев, что Arduino получает тот же
IP-адрес после восстановления.
ДЙКёуё------------------------------------------------”
# include <SPI.h>
# in clu d e <E thernet.h>
# in clu d e < H ttpC lient.h>
#in clu d e <Xively.h>
/ / МАС-адрес E th e rn e t-адаптера
b y te mac[] = { 0x90, 0xA2, OxDA, 0x00, 0x4A, OxEO };
Гпава 14. Подключение Arduino к Интернету 321
v oid s e tu p ()
{
/ / Запуск последовательного порта
S e r i a l .b e g i n (9600);
S e r i a l .p r i n t ln ( " S t a r t i n g s in g le d atastre am upload to X i v e l y ..." ) ;
S e r i a l . p r i n t l n ();
w hile (E thernet.begin(m ac) != 1)
{
S e r i a l . p r i n t l n ("E rror g e ttin g IP address v ia DHCP, try in g a g a i n . . . " ) ;
d e la y (15000);
}
}
v oid lo o p ()
{
i n t sensorV alue = analogR ead(sensorP in);
d a ta s tre a m s [ 0 ] .s e tF lo a t(s e n s o rV a lu e );
S e ria l.p rin t(" R e a d sen so r value " );
S e r ia l.p r in tln ( d a ta s tr e a m s [0 ] .g e t F l o a t O );
S e ria l.p rin tln (" U p lo a d in g i t to X iv ely ");
i n t r e t = x iv e ly c lie n t.p u t( f e e d , xivelyK ey);
S e r i a l .p r i n t ( " x i v e l y c li e n t.p u t re tu rn e d " );
S e ria l.p rin tln ( re t);
S e r i a l . p r i n t l n ();
d e la y (15000);
}
Загрузите программу в плату Arduino, и все будет готово к передаче данных. При
первом подключении Arduino сервер Xively автоматически добавляет выдачу дан
ных на веб-странице, открытой вами ранее.
В программе вы создаете объект, который содержит всю информацию о вашем
потоке. Данные представлены в виде массива d atastream s [ ], содержащего имя дат
322 Часть IV. Дополнительные темы и проекты
чика и тип значений (в данном случае float). Объект xivelyFeed содержит иденти
фикатор потока, информацию о потоке данных и количестве потоков данных, кото
рые находятся в массиве.
#include <SPI.h>
#in clu d e < E thernet.h>
# in clu d e C H ttp C lien t. h>
#include <Xively.h>
324 Часть IV. Дополнительные темы и проекты
/ / Feed ID
XivelyFeed f e e d (1242622121, d atastre am s, 2 /* number o f d atastream s * / ) ;
E th e rn e tC lie n t c l i e n t ;
X iv ely C lien t x i v e l y c l i e n t ( c l i e n t ) ;
void s e tu p ()
{
/ / Запуск последовательного порта
S e r ia l.b e g in (9600);
S e r i a l .p r i n t ln ( " S t a r t i n g double d atastre am upload to X i v e l y . . . " ) ;
S e r i a l . p r i n t l n ();
w hile (E thernet.begin(m ac) != 1)
{
S e r i a l.p r in tln ( " E r r o r g e ttin g IP address v ia DHCP, try in g a g a i n . . . " ) ;
d e la y (15000);
}
}
void lo o p ()
{
i n t lig h tV alu e = an a lo g R e a d (lig h tP in );
d a ta s tre a m s [ 0 ] .s e tF lo a t( lig h tV a lu e ) ;
S e ria l.p rin t(" R e a d l i g h t value " );
S e r i a l . p r in tln ( d a ta s tr e a m s [ 0 ] .g e t F l o a t ( ) );
i n t tempValue = analogR ead(tem pPin);
d a ta s tre a m s [1 ].se tF lo at(te m p V alu e);
S e ria l.p rin t(" R e a d temp value " );
S e r i a l . p r in tln ( d a ta s tr e a m s [ 1 ] .g e tF lo a t( ) );
S e ria l.p rin tln (" U p lo a d in g i t to X iv ely ");
Гпава 14. Подключение Arduino к Интернету 325
Итак, из платы Arduino вы успешно создали как веб-сервер, так и клиент удаленной
веб-службы. Попробуйте теперь добавить цифровые датчики и визуальную обрат
ную связь, чтобы сделать вашу систему по-настоящему интерактивной.
326 Часть IV. Дополнительные темы и проекты
Резюме_______________________________________
В этой главе вы узнали следующее:
♦ Каков смысл параметров IP, DHCP, DNS, MAC и др.
♦ В чем состоят различия между клиентами и серверами.
♦ Как создать HTML-код для формы управления платой Arduino через Интернет.
♦ Как запустить веб-сервер на вашей плате Arduino.
♦ Как управлять контактами ввода-вывода на Arduino через Интернет.
♦ Как подключить Arduino к серверу Xively для построения графиков.
♦ Как отображать онлайн-данные, поступающие от нескольких датчиков.
Доку|
на микроконтролле
и схема план
♦ AREF — вывод для подключения опорного напряжения для АЦП (< 5 В);
♦ GND — заземление.
Остальные выводы контроллера — вводы-выводы общего назначения. Каждый из
них сопоставляется с уникальным номером контакта в программном обеспечении
Arduino, так что вам не придется помнить букву и номер порта. Названия в скобках
представляют собой запись альтернативных функций для каждого вывода. Напри
мер, выводы PD0 и PD1 также являются контактами универсального синхронно
асинхронного приемопередатчика Rx и Тх соответственно. Выводы РВ6 и РВ7
служат для подключения внешнего кварцевого резонатора. На плате Arduino Uno
к ним подключен кварцевый резонатор 16 МГц и вы не можете их использовать
в качестве контактов ввода-вывода. Если у вас возникли проблемы с расшифровкой
названий, дополнительную информацию можно отыскать в тех разделах техниче
ского описания, где приведена терминология. На сайте Arduino в разделе
http://arduino.cc/en/Hacking/PinM appingl68 можно найти схему подключения вы
водов ATmega к пронумерованным контактам платы Arduino (рис. П.4).
A F
analogRead() 67, 74 FAT16 272
analogW rite() 50, 51 FAT32 272
Arduino for() 255
0 Due 32 FTDI 120
0 IDE 36
0 Leonardo 32 Q
0 L ilyPad35
0 Mega 2560 32 General Public License, GPL 22
0 M ega ADK 32 GET 304>313
0 Nano 32, 120 Set0 142
0 Uno 2 8,32
ArduPilot 35 H
ASCII 130
ATmega 328 119,327 HTM L-код 308
0 цоколевка 329 Н-мост 91
attachlnterruptO 256,262
О ipconfig315
IP-адрес 303
constrain() 78
createChar() 209 ^
П LCD 203
loop() 40, 47
dataFile.close() 282
dataFile.print() 282 M
delay() 40,255
DHCP 304 map() 78, 96
digipot 190 millis() 247
digitalRead() 54
digitalWrite() 40, 47, 56 м
Domain Name System, DNS 305
DynDNS 316 notoneQ 111,216
334 Предметный указатель
Q setup() 47
shiftOut() 158,161
Open Source 22 SparkFun XBee USB Explorer 228
S P I 186
p SPI.begin() 195
SPI.transfer() 195
PAN 223
pinMode() 40, 47 “|“
Port Forwarding 316
POST 304 tone() 109, 110, 117,216
Processing 136, 182
pull-down 52 у
pull-up 52
UART 227
p USB- xo ct 124
RS-232 119 w
RTC 288
RTC.adjust() 290 volatile 262
RTC.now() 290
s w
Wire.beginTransmission() 178
SCL 170 Wire.read() 178
SD.begin() 282
SD.open() 286 у
SDA 170 A
SD-карта 272 XBee 224
Serial.available() 129 X-CTU 230
Serial.begin() 124
Serial.parselnt() 134 ^
Serial.print() 124 ^
Serial.printlnO 6 7 ,124 zigB ee 224
Serial.read() 129
Предметный указатель 335
А 3
Адаптер F T D I120 Загрузчик 30
Адрес устройства 12С 171 Закон Ома 46
Акселерометр 72
Аналого-цифровой преобразователь, АЦП I/
65, 173
0 точность 66 Коллизия 227
Комментарий
g 0 многострочный 39
0 однострочный 39
Беспроводная связь 223 Компоненты Arduino 28
Библиотека
0 Ethernet 308 |\/|
0 HttpClient 318
0 LiquidCrystal 206 М АС-адрес 304
0 RTClib 290 Массив 114
0 SD 280 Микроконтроллер 28
О serial 184 3 2 и 4 123
0 Servo 99 Микросхема
л -1лоо 0 74НС14 259
0 S oftw areSenal228 Л ..тт-.».,..
09 SPI 1195
ЬР1 9 5 ,3308
08 °0 DS1307
74НС595289 155
0 TimerOne 264 0 МСР4213 190
! ! пе 9 0 МСР4231 190
6 - Ге 8177 о SN754410 91
0 Xively 318 Модуль ХВее 223
Блок питания 2 35,237 А
0 настройка 229
D 0 настройка в Linux 234
® 0 настройка в Windows 230
Веб-сервис Xively 317
о
Оператор
Гироскоп 72 ^
0 % 144
О const 48
Д
0 for 49
Датчик 0 if/else 54
0 AD7414 172 0 include 103
0 расстояния 71, 104, 162, 296
0 температуры 71, 212, 323 |"|
0 температуры ТС74 172
Делитель напряжения 75 Переменная 40
Динамик 110 Плата
Дребезг контактов 55, 257 0 Arduino Leonardo 245
0 Arduino Uno 247
у^ 0 Leonardo 143
0 макетная 43
Ж К-дисплей 203 0 расширения ХВее 226
336 Предметный указатель
Платы "|"
О Arduino 31
О расширения для SD-карты 276 Таймер 264
Потенциометр 67 Транзистор 86
О цифровой 190 Триггер Ш митта 259
Прерывание
0 аппаратное 254 У
0 по таймеру 264
Противо-ЭДС 86 Управляющий символ 126
Протокол
0 12С 170 Ф
0 SPI 187
Файл HTML 308
р Формат CSV 143,271
■ Формула для расчета мощности 47
Регистр сдвига 154 Фоторезистор 76
Резистор Функция
0 подтягивающий 5 2 ,1 7 3 ,2 5 7 J масштабирования значений 78
Л „ 0 предотвращения дребезга 215
0 стягивающий 52 ^ ^ г
0 токоограничивающий 45, 114 ц
С Цифроаналоговый преобразователь,
^ Ц А П 109
Светодиод 44 Цикл for 49
0 трехцветный 58
Серводвигатель 98 ...
Сервопривод 98 ^
Скважность 51 Ш ина
Стабилизатор напряжения 100 л Т2Г 17Л
^ м а I д а 186
0 включения двигателя постоянного Ш иротно-импульсная модуляция,
тока 85 Ш ИМ 50 ,1 0 4
0 включения стабилизатора напряжения
100 ~
0 Н-моста91 ^
0 платы Arduino Uno 331 Эффект "бегущий всадник" 161