Text
                    Оглавление
Предисловие •• «••••••••• • 11
Для кого и о чем эта книга? 11
Структура книги 11
Благодарности 12
ЧАСТЬ L ARDUINO — ОБЩИЙ ОБЗОР 13
Глава 1. Введение в Arduino 15
1.1. Arduino — что это? 15
1.2. В чем преимущество Arduino? 16
1.3. История создания Arduino 16
Глава 2. Платы семейства Arduino и платы расширения для них 19
2.1. Обзор плат семейства Arduino 19
2.1.1. Arduino Uno 20
2.1.2. Arduino Nano 21
2.1.3. Arduino Pro Mini 22
2.1.4. Arduino LilyPad 23
2.1.5. Arduino Mega2560 24
2.1.6. Arduino Leonardo 25
2.1.7. Arduino Due.. 26
2.1.8. Arduino Yun 27
2.2. Платы расширения для Arduino 28
ЧАСТЬ П. СРЕДЫ РАЗРАБОТКИ И ПРОГРАММИРОВАНИЕ
ПЛАТ ARDUINO 33
Глава 3. Среда разработки Arduino IDE 35
3.1. Установка Arduino IDE в Windows 35
3.2. Установка Arduino IDE в Linux 36
3.3. Настройка среды Arduino IDE 37
Глава 4. Облачная среда разработки Arduino Create 41
4.1. Начало работы в среде Arduino Create 41


Оглавление Глава 5. Программирование плат Arduino * 45 5.1. Базовые знания 45 5.1.1. Цифровые выводы 45 5.1.2. Аналоговые входы 46 5.1.3. Широтно-импульсная модуляция 46 5.1.4. Память в Arduino 46 5.2. Структура программы 48 5.2.1. Функции setupO и loopQ 48 5.3. Синтаксис и операторы 49 5.3.1. Управляющие операторы 49 5.3. 5.3. 5.3. 5.3. 5.3. 5.3. 5.3. 5.3. 5.3. .1. Оператор //(условие) и операторы сравнения ==, /=, < , > 49 .2. Оператор if...else 49 .3. Операторybr 50 .4. Оператор switch 51 .5. Оператор while 51 .6. Оператор do...while 52 .7. Оператор break 52 .8. Оператор continue 52 1.9. Оператор return 53 5.3.2. Синтаксис 53 5.3.2.1.; (semicolon, точка с запятой) v 53 5.3.2.2. {} (curly braces, фигурные скобки) 53 5.3.2.3. Комментарии: //(single line comment, однострочный), /* */ (multi-line comment, многострочный) 54 5.3.3. Арифметические операторы 54 5.3.3.1. = (assignment, оператор присваивания) 54 5.3.3.2. + (сложение), - (вычитание), * (умножение), /(деление) 55 5.3.3.3. % (modulo) 55 5.3.4. Операторы сравнения 55 5.3.5. Логические операторы 55 5.3.5.1. && (логическое И) 55 5.3.5.2. || (логическое ИЛИ) 55 5.3.5.3. / (логическое отрицание) 56 5.3.6. Унарные операторы 56 5.3.6.1. ++ (увеличение значения), /—(уменьшение значения) 56 5.3.6.2. +=,-=, ♦= ,/= 56 5.4. Данные 56 5.4.1. Типы данных : '. ...56 5.4.1.1. boolean 57 5.4.1.2. char 57 5A.13.byie 57 5.4.1.4. int 57 5.4.1.5. unsigned int 58 5.4.1.6. long , 58 5.4.1.7. unsigned long 58 5.4.1.8. float 59 5.4.1.9. double 59 5АЛЛО, string — текстовые строки 59
Оглавление 5.4.1.11. Массивы 60 5.4.1.12. void 61 5.4.2. Константы 61 5.4.3. Переменные 62 5.4.3.1. Объявление переменных 62 5.4.3.2. Границы переменных 62 5.4.4. Преобразование типов данных 63 SAA.l.charO 63 5.4.4.2. byteO 63 5 А A3. Ш0 63 5AAA.longO 63 5AA.5.floatO 64 5.5. Функции 64 5.5.1. Цифровой ввод/вывод 64 5.5.1.1. ФункцияpinMode 64 5.5.1.2. Функция digitalWriteO 64 5.5.1.3. Функция digitalReadO 65 5.5.2. Аналоговый ввод/вывод 66 5.5.2.1. Функция analogReadO 66 5.5.2.2. Функция analogReferenceO 61 5.5.2.3. Функция analogWriteO 67 5.5.3. Дополнительные фунции ввода/вывода 69 5.5.3.1. Функция toneO 69 5.5.3.2. Функция поТопеО 69 5.5.3.3. Функция shiftOutO 69 5.5.3.4. ФункцияpulselnO 71 5.5.4. Работа со временем 72 5.5.4.1. Функция millisO 72 5.5.4.2. Функция microsO 72 5.5.4.3. Функция delayO 73 5.5.4.4. Функция delayMicrosecondsO 74 5.5.5. Математические функции 75 5.5.5.1. Функция min(x,yx) 75 5.5.5.2. Функция max(x, у) 75 5.5.5.3. Функция absO 75 5.5.5.4. Функция constrain(x, a, b) 76 5.5.5.5. Функция mapfvalue, fromLow, fromHigh, toLow, toHigh) 76 5.5.5.6. Функцияpowfbase, exponent) 77 5.5.5.7. Функция s^fti 77 5.5.5.8. Функция sqrt(x) 77 5.5.6. Тригонометрические функции 78 5.5.6.1. Функция sin(rad) 78 5.5.6.2. Функция cosfrad) 78 5.5.6.3. Функция tan(rad) .• 78 5.5.7. Генераторы случайных значений 78 5.5.7.1. Функция randomSeed(seed) , 78 5.5.7.2. Функция randomO 79
Оглавление 5.5.8. Операции с битами и байтами 79 5.5.8.1. Функция lowByteO 80 5.5.8.2. Функщю MghByteO 80 5.5.8.3. Функция bitReadO 80 5.5.8.4. Функция bitWriteO 80 5.5.8.5. Функция bitSetO 81 5.5.8.6. Функция bitClearO 81 5.5.8.7. Функция Ыф 81 5.5.9. Внешние прерывания 81 5.5.9.1. Функция attachlnterrupt 82 5.5.9.2. Функция detachlnterrupt 82 5.6. Управление портами через регистры ATmega 83 ЧАСТЬ Ш. СОПРЯЖЕНИЕ ARDUB4O СО ВСПОМОГАТЕЛЬНЫМИ УСТРОЙСТВАМИ 87 Глава б. Arduino: вводы и выводы 89 6.1. Цифровые выводы — «бегущий огонь» на светодиодах 89 6.1.1. Подключение светодиода к выводу Arduino 90 6.1.2. Подключение к плате Arduino 8-ми светодиодов 94 6.2. Цифровые входы — управляем светодиодами с помощью кнопок 99 6.2.1. Подключение кнопки к плате Arduino 99 6.2.2. Управление кнопками количеством горящих светодиодов 106 6.3. Аналоговые входы — светодиодный индикатор аналоговых значений 109 6.3.1. Подключение потенциометра к плате Arduino Ill 6.3.2. Вывод показаний потенциометра на светодиодную шкалу 114 6.4. ШИМ — радуга на RGB-светодиоде 116 6.4.1. Подключение к плате Arduino RGB-светодиода 117 6.5. Светодиодные индикаторы 120 6.5.1. Подключение к плате Arduino семисегментного индикатора 120 6.6. Расширение цифровых выходов — микросхема 74НС595 124 6.6.1. Подключение к плате Arduino сдвигового регистра 74НС595 125 6.7. Расширение цифровых входов и выходов — микросхема МСР23017 130 6.8. Расширение аналоговых входов — мультиплексор CD4051 131 Глава 7. Использование библиотек в проектах Arduino 135 7.1. Установка библиотек 135 7.1.1. Установка библиотеки через Менеджер библиотек 136 7.1.2. Установка библиотеки из ZIP-архива 136 7.1.3. Установка библиотеки вручную 138 7.2. Подключение библиотеки 138 7.3. Создание собственной библиотеки 139 7.3.1. Создание заголовочного файла D5651.h 139 7.3.2. Создание файла реализации D5651.cpp 140 7.3.3. Создание файла keywords.txt 141 Глава 8* Arduino и последовательный порт UART 143 8.1. Библиотека Serial 143 8.Ц. Функция Serialbegin 143
Оглавление 8.1.2. Функция Serialprint 144 8.1.3. Функция Serialprintln 144 8.1.4. Функция Serialwrite 144 8.1.5. Функция Serial available 145 8.1.6. Функция Serialread 145 8.2. Использование UART для отладки программ 145 8.2.1. Подключение к плате Arduino нескольких кнопок 145 8.3. Использование UART для установки параметров 148 8.4. Библиотека SoftwareSerial 152 8.5. Соединение по UART двух плат Arduino 153 Глава 9. Подключение датчиков к плате Arduino ♦. 157 9.1. Подключение аналоговых датчиков 157 9.1.1. Подключение к плате Arduino аналогового датчика температуры LM335 158 9.2. Подключение датчиков по протоколу 1-Wire 160 9.2.1. Подключение к плате Arduino цифрового датчика температуры DS18B20 161 9.3. Подключение датчиков влажности и температуры DHT 167 9.4. Подключение датчиков по протоколу 12С 171 9.4.1. Подключение к плате Arduino датчика интенсивности света ВН1750 173 Глава 10. Использование дисплеев в проектах Arduino 177 10.1. Символьные дисплеи на микроконтроллере HD44780 177 10.1.1. Функция beginO 180 10.1.2. Функция clearO 180 10.1.3. Функция homeO 181 10.1.4. Функция setCursorO 181 10.1.5. Функция writeQ 181 10.1.6. Функция printO 181 10.1.7. Функция cursorO 182 ЮЛ .8. Функция noCursorO 182 10.1.9. Функция ЪНпкО 182 10.1.10. Функция поВНпкО 182 10.1.11. Функция displayO 183 10.1.12. Функция noDisplayO 183 10.1.13. Фушищя scrollDisplayLeftO 183 10.1.14. Функция scrollDisplayRightO 183 10.1.15. Функция autoscrollQ 183 10.1.16. Функция noAutoscrollO 184 10.1.17. Функция leftToRightO 184 10.1.18. Функция rightToLeftO 184 10.1.19. Функция createCharO 184 10.2. Подключение дисплеев на контроллере HD44780 по протоколу 12С 185 10.2.1. Вывод на ЖК-дисплей данных с датчика, работающего по протоколу 12С 187 10.3. Графический дисплей Nokia 190 10.4. OLED-дисплеи 196 10.4.1. Электронные часы на OLED-дисплее 197 10.5. Дисплеи Nextion 201 10.5.1. Создание нового проекта для дисплея Nextion 202 10.5.2. Прошивка дисплея через UART 206
J3 Оглавление 10.5.3. Прошивка дисплея с помощью карты microSD 207 10.5.4. Подключение дисплея Nextion к плате Arduino 207 Глава 11. Подключение к Arduino исполнительных устройств 213 11.1. Подключение к плате Arduino электромагнитного или твердотельного реле 213 11.2. Подключение к плате Arduino электродвигателя постоянного тока 217 11.2.1. Управление двигателем с помощью транзистора 217 11.3. Управление двигателями с помощью драйвера 219 11.4. Подключение к плате Arduino сервопривода 222 11.4.1. Использование сервопривода в проекте звуковой сигнализации 225 11.5. Подключение к плате Arduino шагового двигателя 227 11.5.1. Управление дроблением шага и направлением вращения шагового двигателя с платы Arduino 230 11.6. Подключение к плате Arduino бесколлекторного двигателя 233 Глава 12. Arduino и беспроводная связь 237 12.1.ИК-управление 237 12.1.1. Управление сервоприводом с помощью ИК-связи 240 12.2. Радиомодули для частоты 433 МГц 243 12.2.1. Управление светодиодом платы Arduino с другой такой же платы по радиоканалу 433 МГц 243 12.3. Радиомодули NRF24L01 246 12.3.1. Организация связи между двумя платами Arduino с использованием модулей NRF24L01 248 12.4. Использование Arduino с аппаратурой радиоуправления 253 12.4.1. Принципы формирования радиосигнала 255 12.4.2. Организация связи приемника с передатчиком 256 12.4.3. Разработка скетча для приема платой Arduino команд передатчика 257 12.5. Arduino и Bluetooth 260 Глава 13* Arduino и Интернет вещей 269 13.1. Подключение к Интернету с помощью платы расширения Ethernet shield 269 13.1.1. Получение IP-адреса по DHCP 270 13.1.2. Отправка данных на сайт «Народный мониторинг» через Ethernet shield 272 13.2. Подключение к Интернету с помощью платы расширения GSM/GPRS shield 279 13.2.1. Отправка и получение SMS-сообщений с помощью GSM/GPRS shield 281 13.2.2. Отправка данных на сайт «Народный мониторинг» через GSM/GPRS shield 285 Глава 14. Специальные возможности отдельных плат Arduino 291 14.1. Использование Arduino Leonardo в качестве USB-устройства 291 14.1.1. Arduino Leonardo: имитация клавиатуры 292 14.1.2. Блокируем клавиатуру с наступлением темноты 294 14.1.3. Arduino Leonardo: имитация компьютерной мыши 294 14.2. Плата Arduino Esplora 297 14.2.1. Arduino Esplora: установка цветов RGB-светодиода 300 14.2.2. Arduino Esplora: создание игры 301 14.3. Плата Arduino LilyPad 319 14.4. Плата Arduino Yun 324 14.4.1. Arduino Yun shield: управляем веб-камерой 326
Оглавление Глава 15. Взаимодействие Arduino с другими программируемыми системами 329 15.1. Использование Arduino в проектах LEGO 329 15.1.1. Получение микрокомпьютером LEGO данных с датчика влажности и температуры DHT11, подключенного к плате Arduino 330 15.2. Arduino в проектах ROS 333 15.2.1. Установка ROS 334 15.2.2. Узлы и темы в ROS 334 15.2.3. Пакет rosserial 335 15.2.4. Подготовка сообщения (publisher) на Arduino 336 15.2.5. Создание подписки (subscriber) на Arduino 340 15.2.6. Связь через ROS двух плат Arduino 342 Глава 16. Программирование в среде Arduino ШЕ других плат 345 16.1. ESP8266 — микроконтроллер с интерфейсом Wi-Fi 345 16.1.1. Установка Arduino IDE для работы с ESP8266 346 16.1.2. Печать курса валют на термопринтере в проекте Интернета вещей 349 16.2. Z-Uno — плата для прототипирования устройств Z-Wave 356 16.2.1. Установка Arduino IDE для Z-Uno 358 16.2.2. Подключение к плате Z-Uno датчика влажности DHT11 361 ЧАСТЬ IV. ПРАКТИКА РАЗРАБОТКИ ПРОЕКТОВ ДЛЯ ARDUINO 363 Глава 17. Умная теплица «Домашний цветок» 365 17.1. Мониторинг климатических параметров умной теплицы 366 17.2. Индикация показаний умной теплицы 371 17.3. Организация полива, обдува и освещения в умной теплице 377 17.4. Переносим функции мониторинга и управления теплицей на смартфон с ОС Android 386 17.5. Создаем собственное мобильное приложение для управления умной теплицей 393 17.6. Превращаем нашу умную теплицу в объект Интернета вещей 397 Глава 18. Светодиодное табло футбольных матчей 407 18.1. RGB-светодиодная лента WS2812 407 18.2. Arduino-библиотека Adafruit_NeoPixel 409 18.3. Создание табло результатов ЧМ-2018 по футболу на RGB-ленте WS2812 410 Глава 19. Голосовое управление исполнительными устройствами 417 19.1. Управление электроприборами с помощью радиорозеток UNIEL 417 19.2. Радиомодули FS1000A/MX-RM-5V 419 19.3. Модуль распознавания голоса Voice Recognition Module V2 422 19.4. Система голосового управления 426 Глава 20. Проекты для вендинга: всюду деньги, деньги, деньги 433 20.1. Купюроприемник ICT серий А7 и V7 433 20.1.1. Подключение купюроприемника ICT V7 к плате Arduino'. 437 20.1.2. Скетч для получения номинала принимаемой купюры 439 20.2. Монетоприемник СН-926 440 20.2.1. Настройка монетоприемника 441 20.2.2. Калибровка монетоприемника 442
Оглавление 20.3. Разменный автомат (хоппер) Cube Hopper MKII 442 20.3.1. Подключение хоппера к плате Arduino 444 20.3.2. Программирование хоппера 444 Глава 21. Makey: импровизированные клавиатуры 449 21.1. Makey: управление новогодней RGB-гирляндой 450 21.2. Программирование новогодней RGB-гирлянды 450 Глава 22. Arduino и интерфейс USB: управление роботами 455 22.1. Интерфейс USB 455 22.2. Плата расширения USB Host Shield 456 22.3. HID-устройства USB 457 22.4. Подключение НГО-мыши USB 460 22.5. Управление роботом с помощью руля Defender 460 22.6. Управление роботом с помощью геймпада Defender 470 Глава 23. Камера Pixy: организация компьютерного зрения 477 23.1. Настройка камеры 478 23.2. Подключение камеры Pixy к плате Arduino 479 23.3. Организация слежения камерой за объектом 481 ПРИЛОЖЕНИЯ 485 Приложение 1. Перечень использованных источников 487 Приложение 2. Описание электронного архива 489 Предметный указатель • • ••• 491
Предисловие Для кого и о чем эта книга? Книга ориентирована на читателей, желающих быстро войти в темы программиро- вания плат Arduino и использования их для связи с внешними системами в проек- тах автоматизации и робототехники. В книге содержится описание языка программирования плат Arduino в среде Arduino IDE и предлагается изучение основ работы с платами Arduino на множест- ве реальных примеров и проектов их использования, имеющих практическое зна- чение и представляющих собой законченные решения, пригодные для включения в ваши конструкции. Все проекты содержат электрические и/или монтажные схемы соединений и листинги соответствующих программ. Все задействованные в проектах книги детали и компоненты нетрудно приобрести в специализированных магазинах, кроме того, для удобства читателей на сайте из- дательства «БХВ-Петербург» (http://www.bhv.ru/books/kits) предлагаются наборы деталей и компонентов, с помощью которых вы сможете быстро адаптироваться в мире Arduino и получить удовольствие, видя, как оживают ваши творения! Книга сопровождается электронным архивом, содержащим исходный код всех рас- смотренных примеров и проектов, используемые в проектах необходимые библио- теки, а также техническую документацию на задействованные в проектах устройст- ва и датчики (см. приложение 2). Этот электронный архив можно скачать с FTP- сервера издательства «БХВ-Петербург» по ссылке ftp://ftp.bhv.ru/9785977540049.zip, а также со страницы книги на сайте www.bhv.ru. Структура книги Книга состоит из четырех частей и включает предисловие, двадцать три главы и два приложения. □ Часть I содержит описание платформы Arduino, обзор плат семейства Arduino и плат расширения для Arduino.
Предисловие □ В части II книги рассмотрены среда разработки Arduino IDE, новая облачная среда разработки Arduino Create и язык программирования для плат Arduino. □ Часть III посвящена изучению возможностей платы Arduino, использованию в связке с ней датчиков, дисплеев, исполнительных устройств, организации бес- проводного соединения плат Arduino, созданию устройств Интернета вещей. Рассмотрено также взаимодействие Arduino с другими системами и программи- рование в среде Arduino IDE других плат. □ Часть IV посвящена созданию конкретных устройств на основе платы Arduino. □ В приложениях приведены перечень использованных источников и описание электронного архива, сопровождающего книгу. Благодарности Хочу поблагодарить родных и близких, которые с пониманием относились к потра- ченному на книгу (за счет общения с ними) времени. Особая благодарность Богаче- вой Марине Николаевне за поддержку и понимание. Большая благодарность издательству «БХВ-Петербург», где поверили в необходи- мость этой книги, и всем сотрудникам издательства, которые помогали мне в ее создании. Благодарю также всех читателей, купивших эту книгу, — надеюсь, она поможет вам в разработке собственных проектов на основе Arduino.
ЧАСТЬ I Arduino — общий обзор Глава 1. Введение в Arduino Глава 2. Платы семейства Arduino и платы расширения для них
ГЛАВА 1 Введение в Arduino 00 1.1. Arduino — что это? Появление первых микроконтроллеров ознаменовало начало новой эры в развитии микропроцессорной техники. Сосредоточение в одном корпусе большинства сис- темных устройств сделало микроконтроллер подобным обычному компьютеру. В отечественной литературе они даже назывались однокристальными микроЭВМ. Соответственно и желание использовать микроконтроллеры как обычные компью- теры возникло практически одновременно с их появлением. Но желание это сдер- живалось многими факторами. Например, чтобы собрать устройство на микрокон- троллере, необходимо знать основы схемотехники, устройство и работу конкретно- го процессора, уметь программировать на ассемблере и изготавливать электронную технику. Потребуются также программаторы, отладчики и другие вспомогательные устройства. В итоге без огромного объема знаний и дорогостоящего оборудования не обойтись. Такая ситуация долго не позволяла многим любителям использовать микроконтроллеры в своих проектах. Сейчас, с появлением устройств, дающих возможность работать с микроконтроллерами без наличия серьезной материальной базы и знания многих предметов, все изменилось. Примером такого устройства может служить проект Arduino итальянских разработчиков. Arduino и его клоны представляют собой наборы, состоящие из готового электрон- ного блока и программного обеспечения. Электронный блок здесь — это печатная плата с установленным микроконтроллером и минимумом элементов, необходимых для его работы. Фактически электронный блок Arduino является аналогом материн- ской платы современного компьютера — на нем имеются разъемы для подключе- ния внешних устройств, а также разъем для связи с компьютером, по которому и осуществляется программирование микроконтроллера. Особенности используемых микроконтроллеров ATmega фирмы Atmel позволяют производить программирова- ние без применения специальных программаторов. Все, что нужно для создания нового электронного устройства, — это плата Arduino, кабель связи и компьютер. Второй частью проекта Arduino является программное обеспечение для создания управляющих программ. Оно объединило в себе простейшую среду разработки и язык программирования, представляющий собой вариант языка C/C++ для микро-
Часть I. Arduino — общий обзор контроллеров. При этом в него добавлены элементы, позволяющие создавать про- граммы без изучения аппаратной части. Так что для работы с Arduino практически достаточно знания только основ программирования на C/C++. Создано для Arduino и множество библиотек, содержащих код, работающий с различными устройст- вами. 1.2. В чем преимущество Arduino? Пользователь современного компьютера не задумывается о функционировании от- дельных частей ПК. Он просто запускает нужные программы и работает с ними. Точно так же и Arduino позволяет пользователю сосредоточиться на разработке проектов, а не на изучении устройства и принципов функционирования отдельных элементов. Нет надобности и в создании законченных плат и модулей — разработ- чик может использовать готовые платы расширения или просто напрямую подклю- чить к Arduino необходимые элементы. Все остальные усилия будут направлены на разработку и отладку управляющей программы на языке высокого уровня. В итоге доступ к разработке микропроцессорных устройств получили не только профес- сионалы, но и просто любители что-то сделать своими руками. Наличие готовых модулей и библиотек программ позволяет непрофессионалам в электронике созда- вать готовые работающие устройства для решения своих задач. А варианты исполь- зования Ardumo ограничены только возможностями микроконтроллера и имеюще- гося варианта платы, ну и, конечно, фантазией разработчика. 1.3. История создания Arduino В 2002 году программист Массимо Банци (Massimo Banzi) занял должность доцен- та в Институте проектирования взаимодействий города Ивреа (Interaction Design Institute Ivrea, IDII). Его основной задачей было продвижение новых способов раз- работки интерактивных проектов. Однако крошечный бюджет и ограниченное вре- мя доступа к лабораторной базе сводили его усилия практически на нет. В своих проектах Банци поначалу использовал устройство BASIC Stamp, разработанное ка- лифорнийской компанией Parallax. Stamp представлял собой небольшую печатную плату с размещенными на ней источником питания, микроконтроллером, памятью и портами ввода/вывода для соединения с различной аппаратурой. Программиро- вание микроконтроллера осуществлялось на языке BASIC. BASIC Stamp имел две проблемы: недостаток вычислительной мощности и достаточно высокую цену — плата с основными компонентами стоила около 100 долларов. И команда Банци решила самостоятельно разработать плату, которая удовлетворя- ла бы всем их потребностям. При этом Банци и его сотрудники поставили себе целью создать устройство, представляющее собой простую, открытую и легкодос- тупную платформу для разработки, с ценой — не более 30 долларов — приемлемой для студенческого кармана. Хотели они и выделить чем-то свое устройство на фоне прочих. Поэтому в противовес другим производителям, экономящим на количестве выводов печатной платы, они решили добавить их как можно больше, а также сде- лали свою плату синей, в отличие от обычных зеленых плат.
ГЛАВА 2 Платы семейства Arduino и платы расширения для них 2.1. Обзор плат семейства Arduino Основные версии плат Arduino представлены следующими моделями: □ Due — плата на базе 32-битного ARM микропроцессора Atmel SAM3X8E ARM Cortex-M3; □ Leonardo — плата на микроконтроллере ATmega32U4; □ Uno — самая популярная версия базовой платформы Arduino; □ Duemilanove — плата на микроконтроллере ATmegal68 или ATmega328; □ Diecimila — версия базовой платформы Arduino USB; □ Nano— компактная плата, используемая как макет. Nano подключается к компьютеру при помощи кабеля USB Mini-B; □ Mega ADK — версия платы Mega 2560 с поддержкой интерфейса USB-host для связи с телефонами на Android и другими устройствами с интерфейсом USB; □ Mega2560— плата на базе микроконтроллера ATmega2560 с использованием микроконтроллера ATMega8U2 для последовательного соединения по USB- порту; □ Mega — версия серии плат Mega на базе микроконтроллера ATmegal280; □ Arduino ВТ — плата с модулем Bluetooth для беспроводной связи и программи- рования; □ LilyPad— плата, разработанная для носимых устройств (может зашиваться в ткань); □ Fio — плата, разработанная для беспроводных применений. Содержит разъем для радио ХВее, разъем для батареи LiPo и встроенную схему подзарядки; □ Mini — самая маленькая плата Arduino; □ Pro — плата, разработанная для опытных пользователей (может являться частью большего проекта);
20 Часть I. Arduino — общий обзор П Pro Mini — как и плата Pro, разработана для опытных пользователей, которым требуется низкая цена, меньшие размеры и дополнительная функциональность; □ Arduino Yun — плата на основе Arduino Leonardo, объединяющая в себе досто- инства двух платформ, поддерживаемых Свободным сообществом: Arduino и Linux. Получившийся симбиоз предоставляет огромные возможности для использования Интернета в своих проектах. Рассмотрим более подробно некоторые из этих плат. 2.1.1. Arduino Uno Плата Arduino Uno (рис. 2.1) построена на микроконтроллере ATmega328. В отли- чие от всех предыдущих ее версий, использовавших для связи по USB микрокон- троллер FTDI USB, новая Arduino Uno использует микроконтроллер ATmega8U2. Рис. 2.1. Плата Arduino Uno Характеристики платы Arduino Uno представлены в табл. 2.1. Таблица 2.1. Характеристики платы Arduino Uno Микроконтроллер Рабочее напряжение Входное напряжение (рекомендуемое) Входное напряжение (предельное) Цифровые входы/выходы АТтеда328 5В 7-12 В 6-20 В 14 (6 из которых могут использоваться как выходы ШИМ)
Глава 2. Платы семейства Arduino и платы расширения для них 21 Аналоговые входы Постоянный ток через вход/выход Постоянный ток для вывода 3,3 В Флеш-память ОЗУ EEPROM Тактовая частота 6 40 мА 50 мА 32 Кбайт, при этом для загрузчика 2 Кбайт 1 Кбайт 16 МГц Таблица 2.1 (окончание) 0,5 Кбайт используются 2.1.2. Arduino Nano Плата Nano (рис. 2.2), построенная на микроконтроллере ATmega328 (Arduino Nano 3.0) или ATmegal68 (Arduino Nano 2.x), имеет небольшие размеры и может использоваться в лабораторных работах. Рис. 2.2. Плата Arduino Nano Arduino Nano способна получать питание через подключение USB Mini-B или от внешнего источника питания: нерегулируемого 6-20 В (вывод 30) или регулируе- мого 5 В (вывод 27). Источник с самым высоким напряжением выбирается автома- тически. Характеристики платы Arduino Nano представлены в табл. 2.2. Таблица 2.2. Характеристики платы Arduino Nano Микроконтроллер Рабочее напряжение Входное напряжение (рекомендуемое) АТтеда168 или ATmega328 5В 7-12 В
22 Часть /. Arduino — общий обзор Таблица 2.2 (окончание) Входное напряжение (предельное) Цифровые входы/выходы Аналоговые входы Постоянный ток через вход/выход Постоянный ток для вывода 3,3 В Флеш-память ОЗУ EEPROM Тактовая частота 6-20 В 14 (6 из которых могут использоваться как выходы ШИМ) 6 40 мА 50 мА 16 Кбайт (ATmega168) или 32 Кбайт (ATmega328), при этом 2 Кбайт используются для загрузчика 1 Кбайт (ATmega168) или 2 Кбайт (ATmega328) 512 байтов (ATmega168) или 1 Кбайт (ATmega328) 16 МГц 2.1.3. Arduino Pro Mini Плата Arduino Pro Mini (рис. 2.3) построена на микроконтроллере ATmegal68. Рис. 2.3. Плата Arduino Pro Mini Характеристики платы Arduino Pro Mini представлены в табл. 2.3. Таблица 2.3. Характеристики платы Arduino Pro Mini Микроконтроллер Рабочее напряжение Входное напряжение Цифровые входы/выходы Аналоговые входы Постоянный ток через вход/выход АТтеда168 3,3 В или 5 В (в зависимости от модели) 3,35-12 В (модель 3,3 В) или 5-12 В (модель 6 В) 14 (6 из которых могут использоваться как выходы ШИМ) 6 40 мА
Глава 2. Платы семейства Arduino и платы расширения для них 23 Таблица 2.3 (окончание) Флеш-память ОЗУ EEPROM Тактовая частота 16 Кбайт (2 — используются для загрузчика) 1 Кбайт 512 байтов 8 МГц (модель 3,3 В) или 16 МГц (модель 5 В) Arduino Pro Mini может получать питание: через кабель FTDI, или от платы- конвертера, или от регулируемого источника питания 3,3 или 5 В (зависит от мо- дели платформы) через вывод VCC, или от нерегулируемого источника через вывод RAW. Выводы питания: □ RAW — для подключения нерегулируемого напряжения; □ VCC — для подключения регулируемых 3,3 или 5 В; □ GND — выводы заземления. 2.1.4. Arduino LilyPad Плата Arduino LilyPad (рис. 2.4) разработана так, чтобы ее можно было зашить в ткань одежды вместе со встроенными источниками питания, датчиками, прово- дами и приводами. Рис. 2.4. Плата Arduino LilyPad Характеристики платы Arduino LilyPad представлены в табл. 2.4. Таблица 2.4. Характеристики платы Arduino LilyPad Микроконтроллер Рабочее напряжение Входное напряжение ATmega168 или ATmega328 2,7-5,5 В 2,7-5,5 В
24 Часть I. Arduino — общий обзор Таблица 2.4 (окончание) Цифровые входы/выходы Аналоговые входы Постоянный ток через вход/выход Флеш-память ОЗУ EEPROM Тактовая частота 14 (6 из которых могут использоваться как выходы ШИМ) 6 40 мА 16 Кбайт (ATmega168) или 32 Кбайт (ATmega328), при этом 2 Кбайт используются для загрузчика 1 Кбайт (ATmega168) или 2 Кбайт (ATmega328) 512 байтов (ATmega168) или 1 Кбайт (ATmega328) 16 МГц 2.1.5. Arduino Mega2560 Плата Arduino Mega (рис. 2.5) построена на микроконтроллере ATmega2560. Рис. 2.5. Плата Arduino Mega2560 Характеристики платы Arduino Mega2560 представлены в табл. 2.5. Таблица 2.5. Характеристики платы Arduino Mega2560 Микроконтроллер Рабочее напряжение Входное напряжение (рекомендуемое) АТтеда2560 5В 7-12 В
Глава 2. Платы семейства Arduino и платы расширения для них 25 Таблица 2.5 (окончание) Входное напряжение (предельное) Цифровые входы/выходы Аналоговые входы Постоянный ток через вход/выход Постоянный ток для вывода 3,3 В Флеш-память ОЗУ EEPROM Тактовая частота 6-20 В 54 (14 из которых могут использоваться как выходы ШИМ) 16 40 мА 50 мА 256 Кбайт, из которых 8 Кбайт используются для загрузчика 8 Кбайт 4 Кбайт 16 МГц 2.1.6. Arduino Leonardo Плата Arduino Leonardo (рис. 2.7) построена на базе микроконтроллера ATmega32U4, имеющего, в отличие от всех других микропроцессоров, встроенную поддержку для USB-соединения. Характеристики платы Arduino Leonardo представлены в табл. 2.6. Рис. 2.6. Плата Arduino Leonardo
26 Часть I. Arduino — общий обзор Таблица 2.6. Характеристики платы Arduino Leonardo Микроконтроллер Рабочее напряжение Входное напряжение (рекомендуемое) Входное напряжение (предельное) Цифровые входы/выходы Аналоговые входы Постоянный ток через вход/выход Постоянный ток для вывода 3,3 В Флеш-память ОЗУ EEPROM Тактовая частота ATmega32U4 5В 7-12 В 6-20 В 20 (7 из которых могут использоваться как выходы ШИМ) 12 40 мА 50 мА 32 Кбайт, из которых 4 Кбайт используются для загрузчика 2 Кбайт 1 Кбайт 16 МГц 2.1.7. Arduino Due Arduino Due (рис. 2.7) представляет собой первую плату Arduino на основе 32-битного микроконтроллера с ARM-ядром — процессора Atmel SAM3X8E ARM Cortex-M3. В отличие от других плат Arduino, максимальное рабочее напряжение, которое вы- держивают входы/выходы Arduino Due, составляет 3,3 В. Рис. 2.7. Плата Arduino Due
Глава 2. Платы семейства Arduino и платы расширения для них 27 Характеристики платы Arduino Due представлены в табл. 2.7. Таблица 2.7. Характеристики платы Arduino Due Микроконтроллер Рабочее напряжение Входное напряжение (рекомендуемое) Входное напряжение (предельное) Цифровые входы/выходы Аналоговые входы Аналоговые выходы Постоянный ток через вход/выход Постоянный ток для вывода 3,3 В Постоянный ток для вывода 5 В Флеш-память ОЗУ Тактовая частота AT91SAM3X8E 3,3 В 7-12 В 6-20 В 54 (12 из которых могут использоваться как выходы ШИМ) 12 2(ЦАП) 50 мА 800 мА 800 мА 512 Кбайт 96 Кбайт (два банка: 64 и 32 Кбайт) 84 МГц 2.1.8. Arduino Yun Arduino Yun (рис. 2.8) — это плата на основе Arduino Leonardo, объединяющая в себе, как уже упоминалось ранее, достоинства двух платформ, поддерживаемых Свободным сообществом: Arduino и Linux. Получившийся симбиоз предоставляет огромные возможности для использования Интернета в своих проектах. Arduino-часть платы содержит микроконтроллер ATmega32U4, работающий на частоте 16 МГц. «Распиновка» Arduino Yun аналогична Arduino Leonardo, поэтому вместе с Arduino Yun вы можете использовать большинство плат расширения Arduino. Linux-часть платы Arduino Yun использует микрокомпьютер Atheros AR9331, ра- ботающий под управлением операционной системы Linino— специально подго- товленной версии OpenWRT (популярного дистрибутива Linux для встраиваемых систем). Микрокомпьютер Atheros AR9331 работает на частоте 400 МГц, имеет 64 Мбайт оперативной и 16 Мбайт флеш-памяти, встроенные интерфейсы Wi-Fi и Ethernet, USB-host и слот для карты micro-SD. Linino содержит в себе пакетный менеджер opkg, который позволяет устанавливать большое количество Linux-приложений, а также интерпретатор языка Python 2.7, с помощью которого вы можете писать для Linino свои приложения.
28 Часть I. Arduino — общий обзор Рис. 2.8. Плата Arduino Yun Память для Linux-приложений может быть расширена с помощью съемного носи- теля (карты microSD или USB-флешки). 2.2. Платы расширения для Arduino Большую популярность плата Arduino приобрела не только из-за низкой стоимости, легкости разработки и программирования, но главным образом благодаря наличию плат расширения (так называемых шилдов), добавляющих Arduino дополнительную функциональность. Шилды (кроме маленьких модулей и платы LilyPad) подклю- чаются к Arduino с помощью имеющихся на них штыревых разъемов (рис. 2.9). Существует множество различных по функциональности шилдов— от простей- ших, предназначенных для макетирования, до сложных, представляющих собой отдельные многофункциональные устройства. Далее приведено краткое описание некоторых шилдов: □ Ethernet Shield (рис. 2.10) — обеспечивает подключение к Интернету; □ ХВее Shield (рис. 2.11)— обеспечивает при помощи модуля Maxstream Xbee Zigbee беспроводную связь нескольких устройств Arduino; □ MicroSD Shield (рис. 2.12) — обеспечивает запись данных на карты microSD; □ МРЗ Shield (рис. 2.13)— плата для воспроизведения звука в форматах Ogg Vorbis, МРЗ, AAC, WMA и MIDI и записи звука в формате Ogg Vorbis; □ Motor Shield (рис. 2.14)— обеспечивает управление двигателями постоянного тока;
Глава 2. Платы семейства Arduino и платы расширения для них 29 '^|lsJ'^ps#*!^i^^|?:?'" Рис. 2.9. Модульная структура установки плат расширения для Arduino Рис. 2.10. Ethernet Shield
30 Часть I. Arduino — общий обзор Рис. 2.11. ХВее Shield Рис. 2.12. MicroSD Shield
Глава 2. Платы семейства Arduino и платы расширения для них 31 Рис. 2.13. МРЗ Shield Рис. 2.14. Motor Shield □ GSM/GPRS Shield (рис. 2.15)— позволяет отправлять SMS-сообщения, делать звонки, обмениваться данными по GPRS; □ Cosmo WiFi Connect (рис. 2.16)— обеспечивает организацию беспроводной сети стандарта ПЕЕЕ 802.1 lb/g.
32 Часть I. Arduino — общий обзор Рис. 2.15. GSM/GPRS Shield Рис. 2.16. Cosmo WiFI Connect Существуют также шилды: Video Overlay Shield — для наложения текста на ана- логовое видео, EasyVR Arduino Shield— многоцелевой модуль распознавания речи, Music Shield — профессиональный аудиокодек и др. Количество плат расширения (шилдов) постоянно растет. Ознакомиться с их спи- ском можно на официальном сайте проекта Arduino по адресу http://www.arduino.cc/ playground/Main/SimilarBoards#goShie. Имеется также и еще один интересный ресурс: http://shieldlist.org/, где представлено описание 244 шилдов для Arduino.
ЧАСТЬ II Среды разработки и программирование плат Arduino Глава 3. Среда разработки Arduino IDE Глава 4. Облачная среда разработки Arduino Create Глава 5. Программирование плат Arduino
ГЛАВА 3 Среда разработки Arduino IDE Разработка собственных приложений на базе плат, совместимых с архитектурой Arduino, осуществляется в бесплатной среде разработки Arduino IDE. Среда пред- назначена для написания, компиляции и загрузки собственных программ в память микроконтроллера, установленного на плате Arduino-совместимого устройства. Основой среды разработки является язык Processing/Wiring— это фактически обычный язык C++, дополненный простыми и понятными функциями для управле- ния вводом/выводом на контактах. Существуют версии среды для операционных систем Windows, Mac OS и Linux. Последнюю версию среды Arduino (1.8.5) и бета-версию Arduino (с эксперимен- тальными возможностями) можно скачать со страницы загрузки официального сай- та: http://arduino.cc/en/Main/Software. Примечание В главе 4 вашему вниманию представлена новая облачная среда разработки Arduino Create. 3.1. Установка Arduino IDE в Windows Отправляемся на страницу http://arduino.cc/en/Main/Software (рис. 3.1), выбираем версию для операционной системы Windows и скачиваем архивный файл. Он зани- мает чуть более 80 Мбайт и содержит все необходимое, в том числе и драйверы. По окончании загрузки распаковываем скачанный файл в удобное для себя место. Теперь необходимо установить драйверы. Подключаем плату Arduino к компьюте- ру. На ней должен загореться индикатор питания — зеленый светодиод. Windows начинает попытку установки драйвера, которая заканчивается сообщением: Про- граммное обеспечение драйвера не было установлено. Открываем Диспетчер устройств. В составе устройств находим значок Arduino Uno — устройство отмечено восклицательным знаком. Щелкаем правой кнопкой мыши на значке Arduino Uno и в открывшемся окне выбираем пункт Обновить драйверы и далее пункт Выполнить поиск драйверов на этом компьютере. У ка-
36^ Часть II. Среды разработки и программирование плат Arduino зываем путь к драйверу — ту папку на компьютере, куда распаковывали скачанный архив. Пусть это будет папка drivers каталога установки Arduino. Игнорируем все предупреждения Windows и получаем в результате сообщение: Обновление про- граммного обеспечения для данного устройства завершено успешно. В заго- ловке окна будет указан и СОМ-порт, на который установлено устройство. Осталось установить и запустить среду разработки Arduino IDE. Рис. 3.1. Страница загрузки официального сайта Arduino 3.2. Установка Arduino IDE в Linux В Linux Ubuntu среда Arduino IDE устанавливается просто — она находится в репо- зитории стандартных приложений Linux. Выбираем Arduino IDE из списка доступ- ных программ в меню Ubuntu: Приложения | Центр приложений Ubuntu | Загру- зить приложение. В списке разделов выбираем Инструменты разработчика, в списке следующего уровня — Все приложения и в следующем открывшемся списке— Arduino IDE (рис. 3.2). Щелкаем левой кнопкой мыши на значке этой программы, справа от нее появляется кнопка Установить, нажимаем на эту кноп- ку, и среда устанавливается автоматически.
Глава 3. Среда разработки Arduino IDE 37 Рис. 3.2. Выбор программы из центра приложений Ubuntu 3.3. Настройка среды Arduino IDE Среда разработки Arduino (рис. 3.3) состоит из: Я редактора программного кода; □ области сообщений; □ окна вывода текста; □ панели инструментов с кнопками часто используемых команд; □ нескольких меню. Программа, написанная в среде Arduino, носит название скетч. Скетч пишется в текстовом редакторе, который имеет цветовую подсветку создаваемого про- граммного кода. Во время сохранения и экспорта проекта в области сообщений по- являются пояснения и информация об ошибках. Окно вывода текста показывает сообщения Arduino, включающие полные отчеты об ошибках и другую информа- цию. Кнопки панели инструментов позволяют проверить и записать программу, создать, открыть и сохранить скетч, открыть мониторинг последовательной шины. Разрабатываемым скетчам дополнительная функциональность может быть добав- лена с помощью библиотек, представляющих собой специальным образом оформ- ленный программный код, реализующий некоторый функционал, который можно подключить к создаваемому проекту. Специализированных библиотек существует множество. Обычно библиотеки пишутся так, чтобы упростить решение той или иной задачи и скрыть от разработчика детали программно-аппаратной реализации. Среда Arduino ШЕ поставляется с набором стандартных библиотек: Serial, EEPROM, SPI, Wire и др. Они находятся в подкаталоге libraries каталога установки
Часть II. Среды разработки и программирование плат Arduino l?oid setup() { // put your setup code here, to run once: void loop() { ; // put your main code here, to run repeatedly: Рис. 3.3. Arduino IDE — среда разработки Arduino. Необходимые библиотеки могут быть также загружены с различных ресурсов (см. главу 7). Папка загруженной библиотеки копируется в каталог стан- дартных библиотек (подкаталог libraries каталога установки Arduino). Внутри ката- лога с именем библиотеки находятся файлы *.срр, *.h. Многие библиотеки снабжа- ются примерами, расположенными в папке examples каталога установки Arduino. Если библиотека установлена правильно, то она появляется в меню Скетч | Import Library. Выбор библиотеки в меню приведет к добавлению в исходный код строчки: #include <имя библиотеки.h> Эта директива подключает заголовочный файл с описанием объектов, функций и констант библиотеки, которые теперь могут быть использованы в проекте. Среда Arduino будет компилировать создаваемый проект вместе с указанной библиотекой. Электронный архив Необходимые для работы с проектами книги подгружаемые библиотеки размещены в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2). Перед загрузкой скетча требуется задать необходимые параметры: в меню Сервис | Плата (Tools | Board) выбрать используемую плату (рис. 3.4) и в меню Сервис |
Глава 3. Среда разработки Arduino IDE 39 Рис. 3.4. Arduino IDE — выбор платы Последовательный порт (Tools | Serial Port) — задействованный последователь- ный порт (рис. 3.5). Современные платы Arduino перед загрузкой перезагружаются автоматически. На старых платах необходимо нажать кнопку перезагрузки. На большинстве плат во время процесса загрузки будут мигать светодиоды RX и ТХ. При загрузке скетча используется загрузчик (bootloader) Arduino — небольшая про- грамма, загружаемая в микроконтроллер на плате. Она позволяет загружать про- граммный код без использования дополнительных аппаратных средств. Работа загрузчика распознается по миганию светодиода на цифровом выводе D13. Монитор последовательного порта (Serial Monitor) отображает данные, посылаемые в плату Arduino (порт USB или порт последовательной шины). Для отправки дан- ных необходимо ввести в соответствующее поле текст и нажать кнопку Послать (Send) или клавишу <Enter> (рис. 3.6). Предварительно следует из выпадающего списка выбрать скорость передачи, соответствующую значению serial.begin в скетче. На ОС Мае или Linux при подключении мониторинга последовательной шины плата Arduino будет перезагружена (скетч начнется сначала).
40 Часть II. Среды разработки и программирование плат Arduino | void 3etup () { ; // put your set Рис. 3.5. Arduino IDE — выбор последовательного порта ВМ Imt Addr:l ВМ configured PolliFF Poll:FF DN >08< ASCII: e UP >08< PollsFF Pollsl Рис. 3.6. Ardulno IDE — монитор последовательного порта
щ ^т. тИШ? JL. Щ. ГЛАВА 4 Облачная среда разработки Arduino Create Arduino Create — это новая платформа, призванная заменить существующую среду разработки Arduino IDE (см. главу 3). Как пишут сами создатели платформы: «Это важный шаг в экосистеме Arduino, и мы надеемся изменить способ взаимодействия с вашими проектами и сообществом». Arduino Create сочетает в себе новый Arduino Web Editor (облачный редактор Arduino), инструменты для быстрого старта, доступ к Arduino-магазину и форуму, а также Project Hub, базирующийся на ресурсе Hackster.io, и сетевой облачный сер- вис Arduino Cloud. Основная идея новой платформы в том, что разработчик теперь имеет возможность писать код и загружать скетчи к любой плате Arduino непосредственно из браузера с помощью Arduino Web Editor— без необходимости что-либо устанавливать на свой компьютер. При использовании новой платформы Sketchbook будет храниться в облаке Arduino и станет доступен с любого устройства. Возможности Arduino Create покрывают практически всю область разработки: вы сможете создавать код прямо у себя в браузере и отправлять его на свою плату Arduino, читать документацию и описание лучших способов работы с Arduino, общаться с коллегами, исследовать проекты других разработчиков. 4.1. Начало работы в среде Arduino Create Итак, заходим на сайт Arduino Create: https://create.arduino.cc/ (рис. 4.1). Сначала там необходимо зарегистрироваться. На странице регистрации заполняем форму и нажимаем на кнопку CREATE ACCOUNT (рис. 4.2). Активация профиля осущест- вляется при переходе по ссылке в письме, пришедшем на указанную вами почту. Войдя в профиль, мы можем работать на сайте. Выбираем пункт Arduino Web Editor. Для дальнейшей работы необходимо установить плагин (рис. 4.3). Этот плагин позволит портам вашего компьютера общаться с веб-редактором в браузере, загружать скетчи из браузера в платы, подключенные к USB или к сети, использо- вать другие облачные сервисы.
42 Часть II. Среды разработки и программирование плат Arduino Рис. 4.1. Стартовая страница сервиса Arduino Create Рис. 4.2. Форма регистрации сервиса Arduino Create
Глава 4. Облачная среда разработки Arduino Create 43 жтснес pv л;?? -ч ки'млб с платформы ArdUifiO Lfsatt яд «алн плату олмуе'н; MacOS> пяогг-ск Рис. 4.3. Форма загрузки плагина сервиса Arduino Create После установки плагина (рис. 4.4) выберем пример Blynk (Examples | Basics | Blynk) и загрузим его в свою плату Arduino (рис. 4.5). Не забываем также выбрать тип платы Arduino и порт подключения (рис. 4.6). Завершена установка ardiiino-creete-agent на ваш компьютер. Рис. 4.4. Плагин arduino-create-agent установлен
44 Часть II. Среды разработки и программирование плат Arduino тШШ :ШШсШ.ёш Рис. 4.5. Загрузка примера BIynk в плату Arduino Рис. 4.6. Выбор типа платы и порта подключения
ГЛАВА 5 Программирование плат Arduino Материал этой главы основан на переводе с официального сайта проекта Arduino (http://arduino.cc) и представлен по лицензии Creative Commons Attribution- ShareAlike 3.0 License (http://creativecommons.Org/licenses/by-sa/3.0/deed.ru). 5.1. Базовые знания 5.1.1. Цифровые выводы Выводы плат Arduino могут работать и как входы, и как выходы. Аналоговые вхо- ды Arduino (на микроконтроллере ATmega) могут конфигурироваться и работать так же, как и цифровые порты ввода/вывода. Выводы Arduino настроены как порты ввода, поэтому для них не требуется декла- рации в функции pinMode (). Сконфигурированные порты ввода находятся в высо- коимпедансном состоянии. Это означает, что порт ввода дает слишком малую нагрузку на схему, в которую он включен. Для перевода порта ввода из одного состояния в другое необходимо малое значение тока. Если к выводу ничего не под- ключено, то значения на нем будут принимать случайные величины, наводимые электрическими помехами. Поэтому если на порт ввода не поступает сигнал, то рекомендуется задать порту какое-либо известное состояние. Это делается добав- лением подтягивающих резисторов 10 кОм, подключающих вход либо к питанию +5 В, либо к земле. Микроконтроллер ATmega имеет программируемые встроенные подтягивающие резисторы 20 кОм. Программирование этих резисторов осуществляется так: pinMode(pin, INPUT); // назначить выводу порт ввода digitalWrite(pin, HIGH); // включить подтягивающий резистор Выводы, сконфигурированные как порты вывода, находятся в низкоимпедансном состоянии. Эти выводы могут пропускать через себя весьма большой ток. Так, вы- воды микросхемы ATmega могут быть источником тока до 40 мА, однако такого значения тока все же недостаточно для большинства реле, соленоидов и двига- телей.
4Q Часть II. Среды разработки и программирование плат Arduino Короткие замыкания выводов Arduino или попытки подключить энергоемкие уст- ройства могут повредить выходные транзисторы вывода или весь микроконтроллер ATmega. 5.1.2. Аналоговые входы Микроконтроллеры ATmega, используемые в Arduino, содержат шестиканальный аналого-цифровой преобразователь (АЦП). Разрешение преобразователя составляет 10 битов, что позволяет на выходе получать значения от 0 до 1023. Аналоговые входы могут использоваться как цифровые выводы портов ввода/вывода, при этом они имеют номера от 14 до 19: pinMode (14f OUTPUT) ; digitalWrite(14, HIGH); Для вывода, работавшего ранее как цифровой порт вывода, команда anaiogRead будет работать некорректно. В этом случае рекомендуется сконфигурировать его как аналоговый вход. 5.1.3. Широтно-импульсная модуляция Широтно-импульсная модуляция (ШИМ) — это операция получения изменяюще- гося аналогового значения посредством цифровых устройств. Подавая на выход сигнал, состоящий из высоких и низких уровней, мы моделируем напряжение между максимальным значением (5 В) и минимальным (0 В). Длительность включения максимального значения называется шириной импульса. Для получения различных аналоговых величин ширину импульса изменяют. В результате на выходе будет получена величина напряжения, равная площади под импульсами (рис. 5.1). Вызов функции anaiogwrite () с масштабом 0-255 означает, что значение anaiogwrite(255) будет соответствовать 5 В (100% рабочий цикл— постоянное включение 5 В), а значение anaiogwrite (127) — 2,5 В (50% рабочий цикл). 5.1.4. Память в Arduino В микроконтроллерах ATmegal68, ATmega328, ATmegal280, ATmega2560, исполь- зуемых на платформах Arduino, существует три вида памяти: □ флеш-память — используется для хранения скетчей; □ ОЗУ (статическая оперативная память) — служит для хранения и работы пере- менных; □ EEPROM (энергонезависимая память) — применяется для хранения постоянной информации. Флеш-память и EEPROM являются энергонезависимыми видами памяти (данные сохраняются при отключении питания). ОЗУ представляет собой энергозависимую память.
Глава 5. Программирование плат Arduino 47 1 ш—т ттт а. ттшт шшт 90% 10% i 50% XI II j Эквивалентное постоянное напряжение | •л 1 Эквивалентное постоянное напряжение | тг -it л [Эквивалентное постоянное напряжение | Рис. 5.1. Широтно-импульсная модуляция Микроконтроллер ATmegal68 имеет: □ 16 Кбайт флеш-памяти (2 Кбайт используются для хранения загрузчика); □ 1024 байта ОЗУ; □ 512 байтов EEPROM. Для ATmega328 эти показатели следующие: □ 32 Кбайт флеш-памяти (2 Кбайт используются для хранения загрузчика); □ 2 Кбайт ОЗУ; □ 1024 байта EEPROM.
_48 Часть II. Среды разработки и программирование плат Arduino Для ATmegal280 эти показатели следующие: □ 128 Кбайт флеш-памяти (2 Кбайт используются для хранения загрузчика); П 8 Кбайт ОЗУ; □ 4096 байтов EEPROM. Для ATmega2560 эти показатели следующие: □ 256 Кбайт флеш-памяти (2 Кбайт используются для хранения загрузчика); □ 16 Кбайт ОЗУ; □ 9182 байта EEPROM. При отсутствии свободного места в ОЗУ могут произойти сбои программы. 5.2. Структура программы Arduino программируется на языке Wiring, которого на самом деле не существует, как не существует и компилятора Wiring — написанные на Wiring программы пре- образуются в программу на языке C/C++ и затем компилируются компилятором AVR-GCC. Фактически используется специализированный для микроконтроллеров AVR вариант C/C++. 5.2.1. Функции setupQ и 1оор() Базовая структура программы для Arduino состоит, по меньшей мере, из двух обя- зательных частей: функций setup () и loop (). Перед функцией setup () идет объяв- ление переменных, подключение библиотек. Функция setup () запускается один раз после каждого включения питания или сброса платы Arduino. Она используется для инициализации переменных, установки режима работы портов и прочих подгото- вительных для основного цикла программы действий. Функция setup () обязатель- но должна быть включена в программу, даже если не выполняет никаких действий. Функция loop () в бесконечном цикле выполняет основную работу программы — последовательно исполняет команды, которые описаны в ее теле. Пример простейшей программы представлен в листинге 5.1. Листинг 6-1 void setup() { Serial.begin(9600); } void loop() { Serial.println(millis ()); delay(1000);
Глава 5. Программирование плат Arduino 49_ 5.3. Синтаксис и операторы 5.3.1. Управляющие операторы 5.3.1.1. Оператор if (условие) и операторы сравнения ==, /=, <, > Оператор if используется в сочетании с операторами сравнения. Он проверяет, достигнута ли истинность условия — например, превышает ли входное значение заданное число. Формат оператора if следующий: if (someVariable > 50) { // выполнять действия } Здесь программа проверяет, больше ли значение someVariable чем 50 или нет. Если да, то выполняются определенные действия. Говоря иначе, если выражение в круг- лых скобках истинно, выполняются операторы внутри фигурных скобок. Если нет, программа пропускает этот код. Выражения, которые вычисляются внутри круглых скобок, могут состоять из одно- го или нескольких операторов. Операторы сравнения: □ х == у (х равно у); □ х != у (х не равно у); □ х < у (х меньше чем у); □ х > у (х больше чем у); □ х <= у (х меньше чем или равно у); □ х >= у (х больше чем или равно у). 5.3.1.2. Оператор if . else Конструкция if.. .else предоставляет больший контроль над процессом выполне- ния кода, чем базовый оператор if, — она позволяет сделать выбор «либо, либо». Например: if (pinInput==HIGH) {doFunlO ;} else {doFun2() ;} В отличие от одиночного оператора if, оператор if.. .else дает возможность осу- ществлять сразу несколько взаимоисключающих проверок. Каждая проверка позволяет переходить к следующему за ней оператору не раньше, чем получит логический результат истина. Когда проверка с результатом истина найдена, за- пускается вложенный в нее блок операторов, и затем программа игнорирует все следующие строки в конструкции if.. .else. Если ни одна из проверок не получила результат истина, по умолчанию выполняется блок операторов в else, если по-
50 Часть II. Среды разработки и программирование плат Arduino следний присутствует, и устанавливается действие по умолчанию. Конструкция else.. .if может быть использована как с заключительным else, так и без него, и наоборот. Допускается неограниченное число таких переходов else...if (лис- тинг 5.2). if (pinAnaloglnput < 100) {doFunlO;} else if (pinAnaloglnput >= 150) {doFun2();} else {doFun3();} Другой способ создания переходов со взаимоисключающими проверками исполь- зует оператор switch case (см. далее). 5.3.1.3. Оператор for Конструкция for служит для повторения блока операторов, заключенных в фигур- ные скобки. Она имеет счетчик приращений, обычно использующийся для опреде- ления количества повторений и завершения цикла. Оператор for подходит для любых повторяющихся действий и часто применяется в сочетании с массивами коллекций данных/выводов. Заголовок цикла for состоит из трех частей: for (initialization; condition; increment) {операторы, выполняющиеся в цикле} Инициализация (initialization) выполняется самой первой и один раз. Каждый раз в цикле проверяется условие (condition), и если оно верно, выполняется блок опе- раторов и приращение (increment), затем условие проверяется вновь. Когда логиче- ское значение условия становится ложным, цикл завершается. В листинге 5.3 при- веден пример затемнения светодиода с использованием ШИМ-вывода. // Затемнение светодиода с использованием ШИМ-вывода int PWMpin = 10; // Светодиод последовательно с R=470 Ом на 10 выводе void setup() {;} void loop () { for (int i=0; i <= 255; i { analogWrite(PWMpin, i); delay(10);
Глава 5. Программирование плат Arduino 51_ 5.3.1.4. Оператор switch Конструкция switch.. .case управляет процессом выполнения программы, позволяя программисту задавать альтернативный код, который будет выполняться при раз- ных условиях. Оператор switch сравнивает значение переменной со значением, определенном в операторах case. Когда найден оператор case, значение которого равно значению переменной, выполняется программный код, записанный в этом операторе. Ключевое слово break является командой выхода из оператора case и обычно используется в конце каждого case. Без оператора break оператор switch будет продолжать вычислять следующие выражения, пока не достигнет break или конца оператора switch. Синтаксис команды switch.. .case представлен в листин- ге 5.4. switch (var) { case label1: // код для выполнения break; case Iabel2: // код для выполнения break; case label3: // код для выполнения break; default: // код для выполнения break; Параметры: □ var — переменная, которая вычисляется для сравнения с вариантами в case; □ label — значение, с которым сравнивается значение переменной. 5.3.1.5. Оператор while Оператор while будет вычислять в цикле непрерывно и бесконечно до тех пор, по- ка выражение в круглых скобках не станет равно логическому ложно. Что-то должно изменять значение проверяемой переменной, иначе выход из цикла while никогда не будет достигнут. Это изменение может происходить как в программном коде, например, при увеличении переменной, так и во внешних условиях, напри- мер, при тестировании датчика. Синтаксис команды следующий: whi le (выражение) { // операторы
J52 Часть II. Среды разработки и программирование плат Arduino Пример использования оператора while представлен в листинге 5.5. var i=0; while($i<lOO) { // операторы 5.3.1.6. Оператор do...while Цикл do работает так же, как и цикл while, за исключением того, что условие про- веряется в конце цикла. Таким образом, цикл do будет всегда выполняться хотя бы один раз. Пример использования оператора do ... while представлен в листинге 5.6. do { delay(50); // подождать, пока датчики стабилизируются х = readSensors(); // проверить датчики } while (x < 100); 5.3.1.7. Оператор break Оператор break используется для принудительного выхода из циклов do, for или while, не дожидаясь завершения цикла по условию. Он также применяется для выхода из оператора switch. Пример приведен в листинге 5.7. 5J for (х = 0; х < 255; х ++) { digitalWrite(PWMpin, х); sens = analogRead(sensorPin); if (sens > threshold) { // выходим из цикла, если есть сигнал с датчика х = 0; break; } delay(50); } 5.3.1.8. Оператор continue Оператор continue пропускает оставшиеся операторы в текущем шаге цикла. Вместо них выполняется проверка условного выражения цикла, которая происхо- дит при каждой следующей итерации. Пример приведен в листинге 5.8.
Глава 5. Программирование плат Arduino 53 for (x = 0; x < 255; x ++) if (x > 40 && x < 120) { // если истина, то прыгаем сразу на следующую итерацию цикла continue; digitalWrite(PWMpin, x); delay(50); 5.3.1.9. Оператор return Оператор return прекращает вычисления в функции и возвращает значение из пре- рванной функции в вызывающую, если это нужно. Пример возврата значения из функции в зависимости от значения на входе аналогового входа представлен в лис- тинге 5.9. int checkSensor() { if (analogRead(O) > 200) return 1; else{ return 0; 5.3.2. Синтаксис 5.3.2.1.; (semicolon, точка с запятой) ; (точка с запятой) используется для обозначения конца оператора. int a = 13; 5.3.2.2. О (curly braces, фигурные скобки) Фигурные скобки {} — важный элемент языка программирования С. Открывающая скобка { должна всегда сопровождаться закрывающей скобкой }. Это условие известно как парность (симметричность) фигурных скобок. Основные способы использования фигурных скобок: П функции: • void Название Функции (тип данных аргумента) { оператор(ы) };
54 Часть II. Среды разработки и программирование плат Arduino О циклы: • while (логическое выражение){ оператор(ы)}; • do { оператор(ы)} while (логическое выражение); • for (инициализация; условие окончания цикла; приращения цикла) { оператор(ы)}; □ условные операторы: • if (логическое выражение) {оператор(ы)}. 5.3.2.3. Комментарии: //(single line comment, однострочный), /* У (multi-line comment, многострочный) Комментарии — это строки в программе, которые используются для информиро- вания вас самих или других о том, как работает программа. Они игнорируются компилятором и не занимают место в памяти микроконтроллера. Есть два способа пометить строку как комментарий: □ однострочный комментарий — // ; □ многострочный комментарий — /* ... */ . Пример приведен в листинге 5.10. х ~ 5; // Это комментарий в одной строке. Все после двойного // слэша - комментарий до конца строки /* это многострочный комментарий - используйте его для закомментирования целых кусков кода */ 5.3.3. Арифметические операторы 5.3.3.1. = (assignment, оператор присваивания) Присваивает переменной слева от оператора значение переменной или выражения, находящееся справа (листинг 5.11). int sensVal; // объявление переменной типа integer senVal-analogRead(O); // присваивание переменной sensVal значение/ // считанное с аналогового входа 0 Переменная слева от оператора присваивания (=) должна быть способна сохранить присваиваемое значение. Если оно выходит за диапазон допустимых значений, то сохраненное значение будет не верно. Необходимо различать оператор присваива- ния (=) и оператор сравнения (= двойной знак равенства), который осуществляет проверку на равенство.
Глава 5. Программирование плат Arduino 55^ 5.3.3.2. + (сложение), - (вычитание), * (умножение), /(деление) Операторы +, -, * и / возвращают результат выполнения соответствующих арифме- тических действий над двумя операндами. Возвращаемый результат будет зависеть от типа данных операндов — например, 9/4 возвратит 2, т. к. операнды 9 и 4 име- ют тип int. Также надо следить за тем, чтобы результат не вышел за диапазон до- пустимых значений для используемого типа данных. Так, например, сложение 1 с переменной типа int и значением 32 767 возвратит -32 768. Если операнды име- ют разные типы, то для вычислений будет использован тип с более «широким» диапазоном. Если один из операндов имеет тип float или double, то для вычисле- ний будет использована арифметика «с плавающей запятой». 5.3.3.3. % (modulo) Возвращает остаток от деления одного целого (int) операнда на другой. Примеры: х = 9 % 5; // х имеет значение 4 х = 5 % 5; // х имеет значение О Нельзя применить к типу float. 5.3.4. Операторы сравнения Операторы сравнения: □ х — у (х равно у); О х !« у (х не равно у); □ х < у (х меньше чем у); □ х > у (х больше чем у); D х<= у (х меньше чем или равно у); □ х >* у (х больше чем или равно у). 5.3.5. Логические операторы Логические операторы чаще всего используются в проверке условия оператора if. 5.3.5.1. && (логическое И) Истина, если оба операнда истина (true). Пример: if (digitalRead(2) = HIGH && digitalRead(3) = HIGH) Serial.println("ok"); 5.3.5.2. || (логическое ИЛИ) Истина, если хотя бы один операнд истина. Пример: if (digitalRead(2) = || digitalRead(3) — HIGH) Serial.println("ok");
56^ Часть II. Среды разработки и программирование плат Arduino 5.3.5.3. / (логическое отрицание) Истица, если операнд false, и наоборот. Пример: if (!(digitalRead(2)== HIGH)) Serial.println("ok"); 5.3.6. Унарные операторы 5.3.6.1. ++ (увеличение значения), /— (уменьшение значения) Унарные (имеющие один операнд) операторы ++ и - соответственно увеличивают и уменьшают значение переменной (листинг 5.12). j х++; // увеличивает значение х на единицу и возвращает старое значение х ++х; // увеличивает значение х на единицу и возвращает новое значение х х— ; // уменьшает значение х на единицу и возвращает старое значение х —х ; // уменьшает значение х на единицу и возвращает новое значение х 5.3.6.2. +=,-=,*=, /= Короткий способ записи арифметических действий над переменной и одним опе- рандом (листинг 5.13). х += у; // эквивалент записи х = х + у; х -= у; // эквивалент записи х = х - у; х *= у; // эквивалент записи х = х * у; х /= у; // эквивалент записи х = х / у; 5.4. Данные 5.4.1. Типы данных Компилятор Arduino определяет следующие типы данных: О boolean; □ unsigned long; □ char; □ float; □ byte; □ double; □ int; □ string; □ unsigned int; □ массив (array); □ long; □ void. Рассмотрим типы данных более подробно.
Глава 5. Программирование плат Arduino 57_ 5.4.1.1. boolean Логический (булевый) тип данных — boolean. Может принимать одно из двух зна- чений: true или false. Данные типа boolean занимают в памяти один байт. 5.4.1.2. char Переменная типа char занимает 1 байт памяти и может хранить один алфавитно- цифровой символ (литеру). При объявлении литеры используются одиночные кавычки: fAf (двойные кавычки используются при объявлении строки символов — ТИП string: "ABC"). Символ хранится в памяти как число, соответствующее коду символа в таблице кодировки символов ASCII. Так как символ хранится как число, в памяти над ним возможно производить арифметические действия (например, f а1 +1 будет 66, т. к. ASCII код для f а1 — 65). Тип char знаковый тип, т. е. число (код), хранящийся в памяти, может принимать значения от -128 до 127. Если необходима знаковая однобайтовая переменная, ис- пользуйте тип byte. Пример: char myChar = 'A1; char myChar =65; // Варианты эквивалентны 5.4.1.3. byte Хранит 8-битовое числовое значение без десятичной точки. Имеет диапазон от О до 255. Пример: byte someVariable=150; // объявление переменной someVariable, // имеющей тип byte 5.4.1.4. Int Тип данных int (от англ. integer — целое число) — один из наиболее часто исполь- зуемых типов данных для хранения чисел, int занимает 2 байта памяти и может хранить числа от -32 768 до 32 767. Для размещения отрицательных значений int использует так называемый допол- нительный код представления числа. Старший бит указывает на отрицательный знак числа, остальные биты инвертируются с добавлением 1. Arduino-компилятор сам заботится о размещении в памяти и представлении отри- цательных чисел, поэтому арифметические действия над целыми числами произво- дятся как обычно. Когда переменная типа int вследствие арифметической операции достигает своего максимального значения, она «перескакивает» на самое минимальное значение и наоборот (листинг 5.14).
58 Часть II. Среды разработки и программирование плат Arduino int x; х = -32,768; х = х - 1; // х теперь равно 32,767 х - 32,767; х = х + 1; // х теперь равно -32,768 5.4.1.5. unsigned int Тип данных unsigned int — беззнаковое целое число, так же, как и тип int (знако- вое), занимает в памяти 2 байта. Но, в отличие от int, тип unsigned int может хра- нить только положительные целые числа в диапазоне от 0 до 65 535. Отличие кроется в том, как unsigned int использует старший бит, иногда называе- мый знаковым битом. Если старший бит равен 1, то для типа int компилятор Arduino считает, что это число отрицательное, а остальные 15 битов несут инфор- мацию о модуле целого числа в дополнительном коде представления числа, в то время как unsigned int использует все 16 битов для хранения модуля числа. Когда переменная типа unsigned int вследствие арифметической операции дости- гает своего максимального значения, она «перескакивает» на самое минимальное значение и наоборот (листинг 5.15). unsigned int x; х = 0; х = х - 1; // х теперь равна 65535 х = х + 1; // х теперь 0 5.4.1.6. long Тип данных long используется для хранения целых чисел в расширенном диапазоне от -2 147 483 648 до 2 147 483 647. long занимает 4 байта в памяти. Пример: long varl = -178000; 5.4.1.7. unsigned long unsigned long используется для хранения положительных целых чисел в диапазоне от 0 до 4 294 967 295 и занимает 32 бита (4 байта) в памяти. Пример вывода в мил- лисекундах (мс) с начала выполнения программы приведен в листинге 5.16. void loop () { Serial.print("Time: "); time = millisO ;
Глава 5. Программирование плат Arduino // выводит время, прошедшее с момента начала выполнения программы Serial.printIn(time); functionl(); 5.4.1.8. float Тип данных float служит для хранения чисел с плавающей запятой. Этот тип часто используется для операций с данными, считываемыми с аналоговых входов. Диапа- зон значений: от -3,4028235Е+38 до 3,4028235Е+38. Переменная типа float зани- мает 32 бита (4 байта) в памяти. Тип float имеет точность 6-7 знаков (имеются в виду все знаки, а не только ман- тисса). Обычно для увеличения точности используют другой тип — double, но на платформе Arduino double и float имеют одинаковую точность. 5.4.1.9. double Тип данных double, в отличие от большинства языков программирования, на плат- форме Arduino имеет ту же точность, что и тип float, и занимает также 4 байта па- мяти. Тип double поддерживается в Arduino для совместимости кода с другими платфор- мами. 5.4.1.10. string — текстовые строки Текстовые строки в Arduino объявляются как массив (array) типа char (символов, литер), оканчивающийся символом «конца строки». Возможны следующие вариан- ты объявления текстовых строк: П объявить массив символов без присваивания значений; О объявить массив символов и присвоить значения всем элементам, кроме послед- него, — компилятор Arduino автоматически добавит символ конца строки; □ явно объявить завершающий символ; □ инициализировать массив строковой константой в двойных кавычках. Компиля- тор автоматически задаст требуемый размер на массив, равный количеству сим- волов плюс завершающий символ; □ инициализировать массив с явным заданием размера и присвоением строковой константы; □ инициализировать массив с явным заданием дополнительного размера (с запа- сом), фактически превышающего размер строковой константы при начальном присвоении. В листинге 5.17 приведены варианты объявления и присвоения строк. char Strl[15]; char Str2[8] * {faf, 'r1, fdf, fu\ f i1, fnf, fo'};
(Ю Часть II. Среды разработки и программирование плат Arduino char Str3[8] = {faf,'г', 'd', fu', 'if, 'n', 'o', '\0'}; char Str4[ ] = "arduino"; char Str5[8] = "arduino"; char Str6[15] = "arduino"; Обычно строки оканчиваются нулевым символом (код 0 в ASCII). Это позволяет функциям (таким как serial.print о) выявлять окончание строки. В противном случае могут считаться байты памяти, не принадлежащие переменной. Массив символов, выделяемый под строку, должен иметь один дополнительный элемент для символа конца строки. Если объявить строку без символа окончания строки, то это приведет к некорректной работе функций, оперирующих строками. Строки всегда объявляются внутри двойных кавычек: "Abe". При работе с большими объемами текстовой информации бывает удобно использо- вать массивы строк. Так как строки сами по себе массивы, массив строк будет дву- мерным массивом. В примере, приведенном в листинге 5.18, символ звездочки после объявления типа char* указывает на то, что мы имеем дело с массивом указателей. Это необходимо для задания двумерного массива. char* myStrings[]={"string 1", "string 2", "string 3","string 4", "string 5","string 6"}; void setup() {Serial.begin(9600);} void loop() { for (int i = 0; i < 6; i++){ Serial.println(myStrings[i]); delay(500); 5.4.1.11. Массивы Массивы (arrays)— именованный набор однотипных переменных с доступом к отдельным элементам по их индексу. Существует несколько вариантов объявле- ния массива: □ массив может быть объявлен без непосредственной инициализации элементов массива: int mylnts[6] ; □ массив может быть объявлен без явного задания размера. Компилятор сам под- считает фактическое количество элементов и создаст в памяти массив необхо- димого размера: int myPins[] = {2, 4, 8, 3, 6};
Глава 5. Программирование плат Arduino 61_ О при объявлении массива размер может быть задан явно, одновременно с ини- циализацией элементов массива. При создании массива типа char необходим дополнительный элемент массива для нулевого символа: int mySensVals[6] = {2, 4, -8, 3, 2}; char message[6] = Vhello"; Индексация массива начинается с 0. Присваивание значения элементу массива происходит следующим образом: mySensVals[0] = 10; Получение значения массива: х = mySensVals[4]; Чаще всего для перебора элементов цикла применяется цикл for, счетчик цикла используется как индекс для доступа к каждому элементу массива. Например, для вывода массива через последовательный порт (serial) можно задать следующий код: int i; for (i = 0; i < 5; i = i + 1) { Serial.println(myPins[i]); } 5.4.1.12. void Ключевое слово void используется при объявлении функций, если функция не воз- вращает никакого значения при ее вызове. 5.4.2. Константы Константы — предопределенные значения. Они используются, чтобы делать про- граммы более легкими для чтения. Объявление констант (а также базовых макросов и функций) можно посмотреть в файле \hardware\arduino\cores\arduino\wiring.h. Рассмотрим некоторые константы: □ true/false— это булевы константы, определяющие логические уровни, false легко определяется как 0 (ноль), a true, как 1, но может быть и чем-то другим, отличным от нуля. Поэтому -1, 2 и 200 — это все тоже определяется как true. #define true 0x1 #define false 0x0 □ high/low — уровни сигналов порта high и low: #define HIGH 0x1 #define LOW 0x0 □ input/output— настройка цифровых портов на ввод (input) и вывод (output) сигналов: #define INPUT 0x0 #define OUTPUT 0x1
&2 Часть II. Среды разработки и программирование плат Arduino Цифровые порты могут использоваться на ввод или вывод сигналов. Изменение ПОрта С ВВОДа На ВЫВОД ПРОИЗВОДИТСЯ При ПОМОЩИ фуНКЦИИ pinMode (): pinMode(13, OUTPUT); // 13 вывод будет выходом pinMode(12f INPUT); // 12 - входом В программе можно создавать собственные константы: #define LEFT 0x95 #define MESS__LEFT "поворот влево" 5.4.3. Переменные Переменные — это способ именовать и хранить числовые значения для последую- щего использования программой. Переменные представляют собой значения, кото- рые могут последовательно меняться, в отличие от констант, чье значение никогда не меняется. Переменные нужно декларировать (объявлять). Следующий код объявляет переменную inputvariabie, а затем присваивает ей значение, полученное от 2-го .аналогового порта: int inputVariable=O; inputVariable^analogRead(2); Переменные могут быть названы любыми именами, которые не являются ключе- выми словами языка программирования Arduino. 5.4.3.1. Объявление переменных Все переменные должны быть задекларированы до того, как они могут использо- ваться. Объявление переменной означает определение типа ее значения: int, long, float и т. д., задание уникального имени переменной, и дополнительно ей можно присвоить начальное значение. Все это следует делать только один раз в програм- ме, но значение может меняться в любое время при использовании арифметических или других разных операций. Следующий пример показывает, что объявленная переменная inputvariabie имеет тип int, и ее начальное значение равно нулю. Это называется простым присваива- нием. int inputvariabie = 0; Переменная может быть объявлена в разных местах программы, и то, где это сде- лано, определяет, какие части программы могут использовать переменную. 5.4.3.2. Границы переменных Переменные могут быть объявлены в начале программы перед void setup (), ло- кально внутри функций и иногда в блоке выражений, таком как цикл for. Место, где объявлена переменная, определяет ее границы (область видимости), т. е. воз- можность некоторых частей программы ее использовать.
Глава 5. Программирование плат Arduino 63^ О Глобальные переменные таковы, что их могут видеть и использовать любые функции и выражения программы. Такие переменные декларируются в начале программы перед функцией setup (). □ Локальные переменные определяются внутри функций или таких частей, как цикл for. Они видимы и могут использоваться только внутри функции, в кото- рой объявлены. Таким образом, могут существовать несколько переменных с одинаковыми именами в разных частях одной программы, которые содержат разные значения. Уверенность, что только одна функция имеет доступ к ее переменной, упрощает программу и уменьшает потенциальную опасность воз- никновения ошибок. 5.4.4. Преобразование типов данных 5.4.4.1. charQ char () приводит значение к типу char. Синтаксис: char(x); где х — переменная любого типа. 5.4.4.2. byteO byte () приводит значение к типу byte. Синтаксис: byte(x); где х — переменная любого типа. 5.4.4.3. intO int () приводит значение к типу int. Синтаксис: int (x) ; где х — переменная любого типа. 5.4.4.4. longO long () приводит значение к типу long. Синтаксис: long(x); где х — переменная любого типа.
64 Часть II. Среды разработки и программирование плат Arduino 5.4.4.5. floaty float () приводит значение к типу float. Синтаксис: long(x); где х — переменная любого типа. 5.5. Функции 5.5.1. Цифровой ввод/вывод Рассмотрим функции цифрового ввода/вывода: □ pinMode(); □ digitalWrite(); □ digitalRead(). 5.5.1.1. Функция pinMode Устанавливает режим работы заданного входа/выхода (pin) как входа или как выхода. Синтаксис: pinMode (pin, mode); Параметры: □ pin — номер входа/выхода (pin), который вы хотите установить; □ mode — режим. Одно из двух значений: input или output устанавливает на вход или выход соответственно. Пример: int ledPin = 13; // Светодиод, подключенный к входу/выходу 13 void setup() { pinMode(ledPin, OUTPUT); // устанавливает режим работы - выход } 5.5.1.2. Функция digitalWriteQ Подает high или low значение на цифровой вход/выход (pin). Если вход/выход (pin) был установлен в режим выход (output) функцией pinMode (), то для значения high напряжение на соответствующем входе/выходе (pin) будет 5 В (3,3 В для плат 3,3 В) и О В (земля) доя low. Если вход/выход (pin) был установлен в режим вход (input), to функция digitaiwrite со значением high будет активировать внутренний нагрузочный рези-
Глава 5. Программирование плат Arduino стор 20 кОм. Подача low в свою очередь отключает этот резистор. Нагрузочного резистора достаточно, чтобы светодиод, подключенный к входу, светил тускло. Если вдруг светодиод работает, но очень тускло, возможно, необходимо установить режим ВЫХОД (OUTPUT) функцией pinMode (). Синтаксис: digitalWrite(pin, value); Параметры: □ pin — номер входа/выхода (pin); □ value — значение high или low. Пример представлен в листинге 5.19. int ledPin =13; // Светодиод, подключенный к входу/выходу 13 void setup () { pinMode(ledPin, OUTPUT); // устанавливает режим работы - выход } void loop() { digitalWrite(ledPin, HIGH); // включает светодиод delay(1000); // ждет секунду digitalWrite(ledPin, LOW); // выключает светодиод delay(1000); // ждет секунду } 5.5.1.3. Функция digitalReadQ Функция считывает значение с заданного входа: high или low. Синтаксис: digitalRead(pin); Параметр: pin — номер входа/выхода (pin), который вы хотите считать. Пример представлен в листинге 5.20. int ledPin = 13; // Светодиод, подключенный к входу/выходу 13 int inPin =7; // кнопка на входе 7 int val =0; // переменная для хранения значения void setup () { pinMode(ledPin, OUTPUT); // устанавливает режим работы - выход для 13
66 Часть II. Среды разработки и программирование плат Arduino pinMode(inPin, INPUT); // устанавливает режим работы - вход для 7 } void loop() { val = digitalRead(inPin); // считываем значение с входа digitalWrite(ledPin, val); // устанавливаем значение на светодиоде // равным значению входа кнопки Замечание Если вход не подключен, то digitalRead может возвращать значения high или low случайным образом. Аналоговые входы (analog pins) могут быть использованы как цифровые входы/выходы (digital pins). Обращение к ним идет по номерам от 14 (для аналогового входа 0) до 19 (для аналогового входа 5). 5.5.2. Аналоговый ввод/вывод Рассмотрим функции аналогового ввода/вывода: □ analogRead(); □ analogReference(); □ analogWrite(). 5.5.2.1. Функция analogReadf) Функция считывает значение с указанного аналогового входа. Большинство плат Arduino имеют 6 каналов (8 каналов у платы Mini и Nano, 16— у Mega) с 10-битным аналого-цифровым преобразователем (АЦП). Напряжение, поданное на аналоговый вход (обычно от 0 до 5 вольт), будет преобразовано в значение от О до 1023 — это 1024 шага с разрешением 0,0049 вольт. Разброс напряжения и шаг может быть изменен функцией analogRef erence о. Считывание значения с аналого- вого входа занимает примерно 100 микросекунд (0,0001 сек), т. е. максимальная частота считывания приблизительно 10 000 раз в секунду. Синтаксис: analogRead(pin); Параметр: pin — номер порта аналогового входа, с которого будет производиться считывание: 0..5 для большинства плат, 0..7 для Mini и Nano и 0..15 для Mega. Возвращаемое значение int (0 to 1023). Замечание Если аналоговый вход не подключен, то значения, возвращаемые функцией analogRead (), могут принимать случайные значения. Пример представлен в листинге 5.21.
Глава 5. Программирование плат Arduino 67 int analogPin =3; // номер порта, к которому подключен потенциометр int val =0; // переменная для хранения считываемого значения void setup() { Serial.begin(9600); // установка связи по serial } void loop () { val = analogRead(analogPin); // считываем значение Serial.println(val); // выводим полученное значение } 5.5.2.2. Функция analogReferenceO Функция определяет опорное напряжение, относительно которого происходят ана- логовые измерения. Функция analogRead о возвращает значение с разрешением 8 битов (1024) пропорционально входному напряжению на аналоговом входе и в зависимости от опорного напряжения. Возможные настройки: □ default — стандартное опорное напряжение 5 В (на платформах с напряжением питания 5 В) или 3,3 В (на платформах с напряжением питания 3,3 В); □ internal— встроенное опорное напряжение 1,1 В на микроконтроллерах ATmegal68 и ATmega328 и 2,56 В на ATmega8; □ external — внешний источник опорного напряжения, подключенный к выводу AREF. Синтаксис: analogReference (type); Параметр: type — определяет используемое опорное напряжение (default, internal или external). Внешнее напряжение рекомендуется подключать к выводу AREF через резистор 5кОм. Рекомендуемой настройкой для вывода AREF является external. При этом про- исходит отключение обоих внутренних источников, и внешнее напряжение будет являться опорным для АЦП. 5.5.2.3. Функция analogWriteO Выдает аналоговую величину (ШИМ-волну) на порт входа/выхода. Функция может быть полезна для управления яркостью подключенного светодиода или скоростью вращения электродвигателя. После вызова anaiogwrite () на выходе будет генери- роваться постоянная прямоугольная «волна» с заданной шириной импульса до еле-
6<В Часть II. Среды разработки и программирование плат Arduino дующего ВЫЗОВа analogWrite (ИЛИ вызова digitalWrite, ИЛИ digitalRead на ТОМ же порту входа/выхода). Частота ШИМ-сигнала приблизительно 490 Гц. На большинстве плат Arduino (на базе микроконтроллера ATmegal68 или ATmega328) ШИМ поддерживают порты 3, 5, 6, 9, 10 и 11, на плате Arduino Mega — порты с 2 по 13. На более ранних версиях плат Arduino analogWrite () ра- ботает только на портах 9, 10 и 11. Для вызова analogWrite о нет необходимости устанавливать тип входа/выхода функцией pinMode (). Функция analogWrite () никак не связана с аналоговыми вхо- дами И С функцией analogRead (). Синтаксис: analogWrite(pin, value); Параметры: □ pin — порт входа/выхода, на который подается ШИМ-сигнал; □ value— период рабочего цикла: значение между 0 (полностью выключено) и 255 (сигнал подан постоянно). Замечание Период ШИМ-сигнала на портах входа/выхода 5 и 6 будет несколько длиннее. Это связано с тем, что таймер для этих выходов также задействован функциями millis о и delay(). Такой эффект более заметен при установке коротких периодов ШИМ- сигнала (0-10). Пример задания яркости светодиода пропорционально значению, снимаемому с потенциометра, представлен в листинге 5.22. int ledPin =9; // Светодиод подключен к выходу 9 int analogPin =3; // потенциометр подключен к выходу 3 int val =0; // переменная для хранения значения void setup() { pinMode(ledPin, OUTPUT); // установка порта на выход } void loop() { val = analogRead(analogPin); // считываем значение с порта, // подключенного к потенциометру analogWrite(ledPin, val / 4); // analogRead возвращает значения от 0 // до 1023, analogWrite должно быть //в диапазоне от 0 до 255
Глава 5. Программирование плат Arduino 69 5.5.3. Дополнительные фунции ввода/вывода 5.5.3.1. Функция toneQ Генерирует на порту входа/выхода сигнал— прямоугольную «волну» заданной частоты и с 50%-ным рабочим циклом. Длительность может быть задана парамет- ром, в противном случае сигнал генерируется до тех пор, пока не будет вызвана функция потопе (). К порту входа/выхода может быть подключен пьезо- или иной динамик для воспроизведения сигнала. Воспроизводиться одновременно может только один сигнал. Если сигнал уже вос- производится на одном порту, то вызов tone () с номером другого порта в качестве параметра ни к чему не приведет, если же tone () будет вызвана с тем же номером порта, то будет установлена новая частота сигнала. Использование функции tone о помешает использовать ШИМ на портах вхо- да/выхода 3 и 11 (кроме платы Arduino Mega). Синтаксис: tone(pin, frequency); tone(pin, frequency, duration); Параметры: □ pin — номер порта входа/выхода, на котором будет генерироваться сигнал; □ frequency — частота сигнала в герцах; □ duration — длительность сигнала в миллисекундах. 5.5.3.2. Функция noToneQ Останавливает сигнал, генерируемый на порту входа/выхода, вызовом функции tone (). Если сигнал не генерировался, то вызов потопе о ни к чему не приводит. Замечание Если необходимы сигналы на разных портах, то следует сначала остановить один сигнал функцией потопе (), а лишь затем создавать новый сигнал на другом порту функцией Топе (). Синтаксис: поТопе (pin) ; Параметр: pin — номер порта входа/выхода, на котором прекращается сигнал. 5.5.3.3. Функция shiftOutQ Выводит байт информации на порт входа/выхода последовательно (побитно). Вывод может осуществляться как с первого (левого), так и с последнего (правого) бита. Каждый бит последовательно подается на заданный порт, после чего на син- хронизирующий порт входа/выхода подается сигнал, информирующий о доступно- сти к считыванию бита.
JW Часть II. Среды разработки и программирование плат Arduino Такой способ передачи данных называется последовательным протоколом с син- хронизацией. Он часто используется для взаимодействия микроконтроллеров с дат- чиками и сенсорами, а также другими микроконтроллерами. Последовательная передача с синхронизацией позволяет устройствам связываться на максимальной скорости. Смотрите также документацию (на англ. языке) по протоколу последова- тельного периферийного интерфейса (SPI, Serial Peripheral Interface Protocol). Синтаксис: shiftOut(dataPin, clockPin, bitOrder, value); Параметры: □ dataPin — номер порта входа/выхода, на который выводятся биты (int); □ clockPin — номер порта, по которому производится синхронизация (int); □ bitorder— используемая последовательность вывода битов, msbfirst (Most Significant Bit First) — слева или lsbfirst (Least Significant Bit First) — справа; □ value — значение (байт) для вывода (byte). Замечание Порт вывода (dataPin) и синхронизирующий порт (clockPin) должны быть предвари- тельно сконфигурированы как порты вывода с помощью функции pinMode (). Текущая реализация функции shiftout О может выводить только один байт (8 би- тов) информации, поэтому необходимо произвести несколько действий, чтобы вывести значения больше 255. Пример вывода приведен в листинге 5.23. // Вывод будет MSBFIRST с первого (левого) бита int data = 500; // выводим старший байт shiftOut(dataPin, clock, MSBFIRST, (data » 8)); // выводим младший бит shiftOut(dataPin, clock, LSBFIRST, data); // выводим старший бит shiftOut(dataPin, clock, LSBFIRST, (data » 8)); Пример вывода счетчика от 0 до 255 на сдвиговый регистр с последовательным вводом 74НС595 представлен в листинге 5.24. // Порт, подключенный к ST__CP 74HC595 int latchPin - 8; // Порт, подключенный к SH_CP 74HC595 int clockPin = 12;
Глава 5. Программирование плат Arduino 71_ II Порт, подключенный к DS 74HC595 int dataPin «11; void setup() { // устанавливаем режим порта выхода pinMode(latchPinf OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); } void loop() { for (int j = 0; j < 256; j++) { // устанавливаем LOW на latchPin, пока не окончена передача байта digitalWritedatchPin, LOW); shiftOut(dataPin, clockPin, LSBFIRST, j); // устанавливаем HIGH на latchPin, чтобы проинформировать регистр, что // передача окончена. digitalWritedatchPin, HIGH); delay(1000); 5.5.3.4. Функция pulseln() Считывает длину сигнала на заданном порту (high или low). Например, если задано считывание high функцией puisein (), функция ожидает, пока на заданном порту не появится high. Когда high получен, включается таймер, который будет остановлен, когда на порту входа/выхода будет low. Функция puiseino возвращает длину сиг- нала в микросекундах. Функция возвращает 0, если в течение заданного времени (тайм-аута) не был зафиксирован сигнал на порту. Возможны некоторые погрешности в измерении длинных сигналов. Функция мо- жет измерять сигналы длиной от 10 микросекунд до 3 минут. Синтаксис: pulseln(pin, value); pulseln(pin, value, timeout); Параметры: □ pin — номер порта входа/выхода, на котором будет ожидаться сигнал; □ value — тип ожидаемого сигнала: high или low; □ timeout — время ожидания сигнала (тайм-аут) в секундах (unsigned long). Возвращаемые значения: длина сигнала в микросекундах или 0, если сигнал не получен до истечения тайм-аута (тип unsigned long). Пример использования функции представлен в листинге 5.25.
72 Часть II. Среды разработки и программирование плат Arduino int pin = 7; unsigned long duration; void setup() { pinMode(pin, INPUT); } void loop() { duration = pulseln(pin, HIGH); } 5.5.4. Работа со временем 5.5.4.1. Функция millisQ Возвращает количество миллисекунд с момента начала выполнения текущей про- граммы на плате Arduino. Это количество сбрасывается на ноль вследствие пере- полнения значения приблизительно через 50 дней. Параметров нет. Возвращаемое значение — количество миллисекунд с момента начала выполнения Программы (ТИП unsigned long). Пример использования функции представлен в листинге 5,26. unsigned long time; void setup() { Serial.begin(9600); } void loopO { Serial.print("Time: "); time = millis(); // выводит количество миллисекунд с момента начала выполнения программы Serial.println(time); // ждет секунду перед следующей итерацией цикла. delay(1000); 5.5.4.2. Функция microsQ Возвращает количество микросекунд с момента начала выполнения на плате Arduino текущей программы. Значение переполняется и сбрасывается на ноль при- близительно через 70 минут. На платах Arduino с 16 МГц (Duemilanove и Nano)
Глава 5. Программирование плат Arduino 73^ функция micros о имеет разрешение 4 секунды (возвращаемое значение всегда кратно 4). На платах с 8 МГц (Arduino Lilypad) разрешение функции — 8 секунд. Параметров нет. Возвращаемое значение — количество микросекунд с момента начала выполнения программы (unsigned long). Пример использования функции представлен в листинге 5.27. unsigned long time; void setup () { Serial.begin(9600); } void loop() { Serial.print("Time: "); time = micros(); // выводит количество микросекунд с момента начала выполнения // программы Serial.println(time); // ждет секунду перед следующей итерацией цикла. delay(1000); 5.5.4.3. Функция delayQ Останавливает выполнение программы на заданное в параметре количество милли- секунд (1000 миллисекунд в 1 секунде). Синтаксис: delay (ms); Параметр: ms — количество миллисекунд, на которое приостанавливается выпол- нение программы ( ТИП unsigned long). Пример использования функции представлен в листинге 5.28. int ledPin =13; // светодиод подключен на порт 13 void setup() { pinMode(ledPin, OUTPUT); // устанавливается режим порта - выход } void loop () { digitalWrite(ledPin, HIGH); // включаем светодиод
74 Часть II. Среды разработки и программирование плат Arduino delay(1000); // ожидаем секунду digitalWrite(ledPin, LOW); // выключаем светодиод delay(1000); // ожидаем секунду Не рекомендуется использовать эту функцию для событий длиннее 10 миллисе- кунд, т. к. во время останова не могут быть произведены манипуляции с портами, не могут быть считаны сенсоры или произведены математические операции. В ка- честве альтернативного подхода возможно контролирование времени выполнения тех или иных функций с помощью minis о. При использовании функции delay о работа прерываний не останавливается, продолжается запись последовательно (serial) передаваемых данных на RX-порту, ШИМ-сигнал (anaiogwrite) на портах продолжает генерироваться. 5.5.4.4. Функция delayMicrosecondsQ Останавливает выполнение программы на заданное в параметре количество микро- секунд (1 000 000 микросекунд в 1 секунде). В существующих версиях Arduino максимальная пауза, воспроизводимая коррект- но,— 16 383. Возможно, это будет изменено в следующих версиях Arduino. Для остановки выполнения программы более чем на несколько тысяч микросекунд рекомендуется использовать функцию delay (). Синтаксис: delayMicroseconds(us); Параметр: us — количество микросекунд, на которое приостанавливается выпол- нение Программы (unsigned int). Пример использования функции представлен в листинге 5.29. int outPin =8; // цифровой порт входа/выхода 8 void setup() { pinMode(outPin, OUTPUT); // устанавливается режим порта - выход } void loop () { digitalWrite(outPin, HIGH); // подаем HIGH на выход delay(50); // ожидаем 50 микросекунд digitalWrite(outPin, LOW); // устанавливаем LOW на выходе delay(50); // ожидаем 50 микросекунд
Глава 5. Программирование плат Arduino 75^ 5.5.5. Математические функции В языке представлены следующие математические функции: □ min (); □ шар (); П max (); О pow (); □ abs(); □ sq()J □ constrain(); П sqrt(). 5.5.5.1. Функция min(x,yx) Возвращает наименьшее из двух значений. Параметры: □ х — первое число, любой тип; □ у — второе число, любой тип. Возвращаемое значение — возвращает меньшее из двух сравниваемых значений. Пример использования функции: sensVal = min(sensVal, 100); // проверяем, если sensVal больше 100, то senseVal будет присвоено 100 5.5.5.2. Функция тах(х, у) Возвращает большее из двух значений. Параметры: □ х — первое число, любой тип; □ у — второе число, любой тип. Возвращаемое значение — возвращает большее из двух сравниваемых значений. Пример использования функции: sensVal = max (sensVal, 20); // проверяем, если sensVal меньше 20, то senseVal будет присвоено 20 Функция max о зачастую используется для задания нижней границы значений переменной. Функцией min () ограничивают верхнюю границу переменной. В силу специфики реализации функции max о следует избегать использования других функций в качестве параметров. Например: max (а—, 0); // может привести к некорректным, результатам а—; шах(а, 0); // так корректно 5.5.5.3. Функция ab$0 Возвращает модуль числа. Параметр: х — число.
76^ Часть II. Среды разработки и программирование плат Arduino Возвращаемые значения: □ х — если х больше или равен 0; □ -х — если х меньше 0. В силу специфики реализации функции abs () следует избегать использования дру- гих функций в качестве параметров: abs (а++); // может привести к некорректным результатам abs(а, 0); // так корректно 5.5.5.4. Функция constrainfx, a, b) Функция проверяет и, если надо, задает новое значение так, чтобы оно было в об- ласти допустимых значений, заданной параметрами. Параметры: □ х — проверяемое значение, любой тип; □ а — нижняя граница области допустимых значений, любой тип; □ ь — верхняя граница области допустимых значений, любой тип. Возвращаемое значение: □ х — если х входит в область допустимых значений [а..Ь]; □ а — если х меньше а; □ ь — если х больше ь. Пример: sensVal - constrain(sensVal, 10, 150); // ограничиваем значения sensVal диапазоном от 10 до 150 5.5.5.5. Функция map(value, fromLow, fromHigh, toLow, toHigh) Функция пропорционально переносит значение (value) из текущего диапазона зна- чений (fromLow ... fromHigh) в новый диапазон (toLow ... toHigh), заданный пара- метрами. Функция тар () не ограничивает значение рамками диапазона, как это делает функ- ция constraint). Функция constrain о может быть использована до или после вызова шар (), если необходимо ограничить допустимые значения заданным диапа- зоном. Обратите внимание, что «нижняя граница» может быть как меньше, так и больше «верхней границы». Это может быть использовано, чтобы «перевернуть» диапазон: у = тар(х, 1, 50, 50, 1); Возможно использование отрицательных значений: у = тар(х, 1, 50, 50, -100); Функция тар о оперирует целыми числами. При пропорциональном переносе дробная часть не округляется по правилам, а просто отбрасывается.
Глава 5. Программирование плат Arduino 77_ Параметры: □ value — значение для переноса; О f romLow — нижняя граница текущего диапазона; □ f romHigh — верхняя граница текущего диапазона; □ toLow — нижняя граница нового диапазона, в который переносится значение; □ toHigh — верхняя граница нового диапазона. Возвращаемое значение — значение в новом диапазоне. Пример использования функции представлен в листинге 5.30. // Переносим значение с аналогового входа // (возможные значения от 0 до 1023) в 8 бит (0..255) void setup () {;} void loop () { int val = analogRead(0); val = map(val, 0, 1023, 0, 255); analogWrite(9, val); 5.5.5.6. Функция powfbase, exponent) Вычисляет значение, возведенное в заданную степень. Функция pow () может воз- водить и в дробную степень. Параметры: □ base — ЧИСЛО (ТИП float); □ exponent — степень, в которую будет возводиться число (тип float). Возвращаемое значение — результат возведения в степень, число (тип double). 5.5.5.7. Функция sq(x) Функция возвращает квадрат числа, заданного параметром. Параметр: х — число, любой тип. Возвращаемое значение — квадрат числа. 5.5.5.8. Функция sqrt(x) Функция вычисляет квадратный корень числа, заданного параметром. Параметры: х — число, любой тип. Возвращаемое значение — квадратный корень числа (тип double).
78^ Часть II. Среды разработки и программирование плат Arduino 5.5.6. Тригонометрические функции В языке представлены следующие тригонометрические функции: □ sin о; О cos о; □ tan (). 5.5.6.1. Функция sin(rad) Возвращает синус угла, заданного в радианах в передаваемом параметре. Результат функции всегда в диапазоне -1 ... 1. Параметр: rad — угол в радианах (float). Возвращаемое значение: синус угла (тип double). 5.5.6.2. Функция cos(rad) Возвращает косинус угла, заданного в радианах в передаваемом параметре. Резуль- тат функции всегда находится в диапазоне -1 ... 1. Параметр: rad — угол в радианах (тип float). Возвращаемое значение: косинус угла (тип double). 5.5.6.3. Функция tan(rad) Возвращает тангенс угла, заданного в радианах в передаваемом параметре. Резуль- тат функции в диапазоне от минус бесконечности до плюс бесконечности. Параметр: rad — угол в радианах (тип float). Возвращаемое значение: тангенс угла (тип double). 5.5.7. Генераторы случайных значений Функции формирования случайных чисел: □ randomSeed(); □ random(). 5.5.7.1. Функция randomSeed(seed) Функция randomSeed () инициализирует генератор псевдослучайных чисел. Генери- руемая последовательность случайных чисел очень длинная, и всегда одна и та же. Точка в этой последовательности, с которой начинается генерация чисел, зависит от параметра seed. Параметр: seed — параметр, задающий начало выдачи псевдослучайных значений на последовательности (тип int, long).
Глава 5. Программирование плат Arduino 5.5.7.2. Функция randomf) Функция random () возвращает псевдослучайное число. Синтаксис: random (max); random(min, max); Параметры: □ min — нижняя граница случайных значений, включительно (опционально); □ max — верхняя граница случайных значений, включительно. Возвращаемое значение: случайное число между min и шах - 1 (тип long). Если при каждом запуске программы необходимо получать разные последователь- ности значений, генерируемых функцией randomo, то необходимо инициализиро- вать генератор псевдослучайных чисел со случайным параметром. Например, мож- но использовать значение, отдаваемое функцией anaiogRead () с неподключенного порта входа/выхода. В некоторых случаях необходимо получать одинаковую по- следовательность при каждом запуске программы на Arduino. Тогда инициализиро- вать генератор псевдослучайных чисел следует вызовом функции randomseedo с фиксированным параметром. Пример использования функции представлен в листинге 5.31. long randNumber; void setup () { Serial.begin(9600) ; } void loop() { // выводим случайное число из диапазона 0..299 randNumber = random(300); Serial.println(randNumber); // выводим случайное число из диапазона 0..19 гandNumbe г = random(10, 20); Serial.println(randNumber); delay(50); } 5.5.8. Операции с битами и байтами Функции — операции с битами и байтами: □ lowByteO; О bitSetO; □ highByteOJ О bitClear(); □ bitReadO; О bit(). □ bitWriteO;
ЕЮ Часть II. Среды разработки и программирование плат Arduino 5.5.8.1. Функция lowByteQ Извлекает младший (самый правый) байт переменной (например, типа word). Синтаксис: lowByte(x); Параметр: х — величина любого типа. Возвращает байт. 5.5.8.2. Функция highByteQ Извлекает старший (крайний левый) байт слова (или второй младший байт больше- го типа данных). Синтаксис: highByte(x); Параметр: х — величина любого типа. Возвращает байт. 5.5.8.3. Функция bitReadQ Читает определенный бит переменной. Синтаксис: bitRead(x, n); Параметры: □ х — число, из которого необходимо прочитать; □ та — указывает бит, который необходимо прочитать, начиная с 0 для младшего (правого) бита! Возвращает: значение бита (0 или 1). 5.5.8.4. Функция bitWriteQ Записывает бит числовой переменной. Синтаксис: bitWrite(x, n, b); Параметры: □ х — числовая переменная, в которую необходимо записать; □ п — номер бита, который необходимо записать, начиная с 0 для младшего (лево- го) бита; □ ь — значение, которое необходимо записать в бит (0 или 1).
Глава 5. Программирование плат Arduino 81_ 5.5.8.5. Функция bitSetQ Устанавливает (записывает 1) бит числовой переменной. Синтаксис: bitSet(x, n) Параметры: □ х — числовая переменная, которую необходимо записать; □ п— номер бита, который необходимо установить, начиная с 0 для младшего (левого) бита. 5.5.8.6. Функция bitClearQ Сбрасывает (записывает 0) бит числовой переменной. Синтаксис: bitClear(х, п); Параметры: □ х — числовая переменная, которую необходимо записать; □ п— номер бита, который необходимо установить, начиная с 0 для младшего (левого) бита. 5.5.8.7. Функция bit() Вычисляет значение указанного бита (бит 0 — это 1, бит 1 — это 2, бит 2 — это 4 и т. д.). Синтаксис: bit(n); Параметр: п — номер бита, который необходимо вычислить. Возвращает: значение бита. 5.5.9. Внешние прерывания Прерывание (англ. interrupt)— сигнал, сообщающий процессору о наступлении какого-либо события. При этом выполнение текущей последовательности команд приостанавливается, и управление передается обработчику прерывания, который выполняет работу по обработке события и возвращает управление в прерванный код. Arduino так же предоставляет свои функции для работы с прерываниями. Их всего две: П attachlnterrupt(); П detachlnterrupt().
82^ Часть II. Среды разработки и программирование плат Arduino 5.5.9.1. Функция attachlnterrupt Задает функцию обработки внешнего прерывания, т. е. функцию, которая будет вызвана по внешнему прерыванию. Если до этого была задана другая функция, то назначается новая. Вычисляет значение указанного бита (бит 0 — это 1, бит 1 — это 2, бит 2 — это 4 и т. д.). Синтаксис: attachlnterrupt(interrupt, function, mode); Параметры: □ interrupt — номер прерывания: • о — на цифровом порту 2; • 1 — на цифровом порту 3; • 2 — на цифровом порту 21 (для Arduino Mega); • з — на цифровом порту 21 (для Arduino Mega); • 4 — на цифровом порту 21 (для Arduino Mega); • 5 — на цифровом порту 21 (для Arduino Mega); О function— функция, вызываемая прерыванием (должна быть без параметров и не возвращать значений); □ mode— задает режим обработки прерывания, допустимо использование сле- дующих констанст: • low — вызывает прерывание, когда на порту low; • change — прерывание вызывается при смене значения на порту с low на high и наоборот; • rising— прерывание вызывается только при смене значения на порту с low на high; • falling — прерывание вызывается только при смене значения на порту с high на low. Возвращаемого значения нет. Внутри функции обработки прерывания не работает функция delay о, значения, возвращаемые функцией minis о, не изменяются. Возможна потеря данных, пере- даваемых по последовательному соединению (Serial data) в момент выполнения функции обработки прерывания. Переменные, изменяемые в функции, должны быть объявлены как volatile. 5.5.9.2. Функция detach Interrupt Выключает обработку внешнего прерывания. Синтаксис: detachlnterrupt(interrupt);
Глава 5. Программирование плат Arduino 83^ Параметр: interrupt— номер прерывания (0 или 1), для Arduino Mega еще 2, 3, 4 или 5. Возвращаемого значения нет. В листинге 5.32 приведен пример использования прерывания 0 при наступлении события change на порту 2. При этом светодиод на выводе 13 Arduino при каждом прерывании меняет статус (горит либо гаснет). int pin =13; volatile int state = LOW; void setup () { pinMode(pin, OUTPUT); attachInterrupt(O, blink, CHANGE); void loopO { digitalWrite(pin, state); } // функция обработки прерывания void blink () { state = !state; 5.6. Управление портами через регистры ATmega Использование встроенных функций Arduino для работы с выводами очень удобно. Однако за удобство приходится платить быстродействием. В большинстве про- грамм это не принципиально, но иногда имеет решающее значение. В таких случа- ях необходимо управлять портами Arduino напрямую через регистры ATmega. При этом мы не только увеличиваем быстродействие, но еще и уменьшаем размер программы. Рассмотрим таблицу соответствия выводов Arduino портам микроконтроллера ATmega 168 (рис. 5.2). Что мы видим: □ portd — цифровые выводы Arduino от D0-D7; □ portb — цифровые выводы Arduino от D8-D13;
84 Часть II. Среды разработки и программирование плат Arduino Ardulno: сброс цифровой вывод О (RX) цифровой вывод 1 (ТХ) цифровой вывод 2 цифровой вывод 3 (PWM) цифровой вывод 4 VCC QHD Кварцевый резонатор Кварцевый резонатор цифровой вывод 5 (PWM) цифровой вывод 6 (PWM) цифровой вывод 7 цифровой вывод 8 Atfn#Qe168 Phi GNOC* if 3PC4<ADC*SOA/PC<NT12) ЗРС1(АОС1/РС1НТ9) Aftiuino: аналоговый вывод 5 аналоговый вывод 4 аналоговый вывод 3 аналоговый вывод 2 аналоговый вывод 1 аналоговый вывод О GND аналоговый опорный сигнал VCC цифровой вывод 13 цифровой вывод 12 фРвЗ(МО81ЮС2АЛ>амТЗ) Цифровой вывод 11 (PWM) вывод 10 (PWM) Цифровые выводь! 11,12 и 13 {выводы микросхемы А£те$а16$ Ш17,13 и 19) используются портом CSP дли подключения MiSO, MOSf, SCK. Избегайте низкоомной нагрузки на этих выводах щм использовании портом CSP Рис. 5.2. Соответствие выводов Arduino портам микроконтроллера ATmega CJ portc — аналоговые выводы Arduino A0-A5 (А6-А7 доступны в Arduino Mini, Nano). Для установки выводов и чтения записи данных используются следующие команды: □ ddrd, ddrb, ddrc — для установки назначения выводов (направления передачи данных) соответствующих портов (0 — input, 1 — output); □ portd, portb, portc — регистр установки данных на выводах соответствующего порта; □ pind, pinb, pinc — считывание данных всех контактов соответствующего порта. Используя эти команды, можно заменить стандартные функции Arduino для управ- ления выводами. Например: // pinMode(13,INPUT) DDRB = DDRB & B11011111 // pinMode(5,OUTPUT) DDRD = DDRD | B00100000 // digitalWrite(7,HIGH) PORTB= PORTB | B10000000 // digitalRead(10,HIGH) PINB = (PINB & B00000100)»2 Команда anaiogwrite () выдает ШИМ-волну на порт входа/выхода. Частота ШИМ- сигнала приблизительно 490 Гц. Если вам хочется иметь ШИМ с большим разре- шением или другой частотой, чем позволяет стандартная функция anaiogwrite (),
Глава 5. Программирование плат Arduino 85 или вы желаете организовать ШИМ на других вводах, можно написать замену функции anaiogwrite (), используя прямой вывод на порты: int PWM_time=32; for (int k=O;k<PWM_time) PORTA=B00000001; for (int k=0;k<256-PWM_time) PORTA=B00000000; Теперь можно переходить к изучению Arduino на практических примерах. Этому будут посвящены главы 6-23.
ЧАСТЬ III Сопряжение Arduino со вспомогательными устройствами Глава 6. Arduino: вводы и выводы Глава 7. Использование библиотек в проектах Arduino Глава 8. Arduino и последовательный порт UART Глава 9. Подключение датчиков к плате Arduino Глава 10. Использование дисплеев в проектах Arduino Глава 11. Подключение к Arduino исполнительных устройств Глава 12. Arduino и беспроводная связь Глава 13. Arduino и Интернет вещей Глава 14. Специальные возможности отдельных плат Arduino Глава 15. Взаимодействие Arduino с другими программируемыми системами Глава 16. Программирование в среде Arduino IDE других плат
ГЛАВА 6 Arduino: вводы и выводы о© Платы Arduino позволяют использовать большую часть своих контактов вво- да/вывода для связи с устройствами во внешних схемах. Прежде всего, эти контак- ты могут служить цифровыми вводами и выводами. В то же время, часть контактов Arduino могут действовать и как аналоговые входы. Многие из имеющихся контак- тов кроме того также мультиплексированы — способны выступать в роли различ- ных коммуникационных интерфейсов, последовательных интерфейсов, широтно- импульсных модуляторов и обработчиков внешних прерываний. В этой главе мы рассмотрим использование контактов Arduino на примере простых и не очень проектов. 6.1. Цифровые выводы — «бегущий огонь» на светодиодах Первое, с чего можно начать знакомство с платформой Arduino, — это ее цифровые выводы. Цифровые выводы, имеющиеся на платах Arduino, позволяют подключать к ним другие микросхемы, а также различные датчики и приводы. Изучение воз- можностей использования цифровых выводов Arduino позволит вам организовать с ее помощью решение многих практически полезных задач. Цифровые сигналы имеют только два отдельных значения: высокий (high, 1) и низ- кий (low, 0) уровни. Вы можете задействовать цифровые сигналы в случаях, когда вход или выход будут принимать одно из этих двух значений. Например, одной из ситуаций, в которых вы можете использовать цифровой сигнал, является вклю- чение и выключение светодиода. Поскольку цифровые выводы Arduino могут выступать в роли как входов, так и вы- ходов, сначала необходимо их настроить. Для настройки цифровых выводов в Arduino используется встроенная функция pimMode (), которая имеет следующий синтаксис: pinMode (pin, mode)
9Ю Часть III. Сопряжение Arduino со вспомогательными устройствами где: □ pin — номер вывода Arduino; □ mode — устанавливаемый режим для вывода pin: • input — pin в режиме входа; • output — pin в режиме выхода; • inputpullup — в этом режиме к выводу подключается внутренний подтяги- вающий резистор 20 кОм, чтобы привести уровень на выводе к значению HIGH, если к нему ничего не подключено. 6.1.1. Подключение светодиода к выводу Arduino Рассмотрим простейший пример— подключение к выводу Arduino светодиода. Для него нам понадобятся следующие компоненты: □ плата Arduino Uno; □ кабель USB; □ плата прототипирования (монтажная плата); □ красный светодиод; □ резистор 220 Ом; □ соединительные провода типа «папа-папа» (далее в тексте — ПП) — 3 шт. Рис. 6.1. Монтажная схема подключения светодиода В представленной на рис. 6.1 монтажной схеме этого проекта для подключения светодиода к цифровому выводу мы применили ограничительный резистор номи- налом 220 Ом. Разберемся, как подобрать такой резистор, и как будет влиять номи- нал резистора на яркость светодиода. Самым главным уравнением для любого ин-
Глава 6. Anduino: вводы и выводы 91_ женера-электрика является закон Ома — он определяет отношения между напря- жением, током и сопротивлением в цепи. Закон Ома записывается следующим образом: где: V— напряжение в вольтах, /— ток в амперах, R — сопротивление в омах. В электрической схеме каждый компонент имеет какое-то собственное сопротив- ление, что вызывает при прохождении через него тока некоторое снижение его на- пряжения, называемое падением напряжения. Светодиоды также вызывают опре- деленное падение напряжения на них и предназначены для работы при определен- ном значении тока: чем больше ток через светодиод, тем ярче светодиод светится, и так до предельного значения. Для наиболее распространенных типов светодиодов максимальный ток составляет 20 мА. Обычное значение падения напряжения для светодиода — около 2 В. Учитывая, что напряжение питания, равное 5 В, должно упасть на светодиоде и резисторе, оставшиеся 3 В должны упасть на резисторе. Зная максимальное значение прямого тока через светодиод (20 мА), можно найти номинал резистора: R=V/I= 3/0,02 =150 Ом Таким образом, при протекании тока величиной 20 мА через светодиод и резистор сопротивлением 150 Ом светодиод станет светиться на полную мощность, а по ме- ре увеличения значения сопротивления ток будет уменьшаться и свечение свето- диода снижаться. И хотя сопротивление взятого нами в проект резистора (220 Ом) превышает теоретически рассчитанное значение 150 Ом, однако оно все же позво- ляет светодиоду светиться достаточно ярко. Кроме того, резисторы этого номинала очень распространены. Теперь приступим к написанию программы (скетча), которая обеспечит мигание светодиода, подключенного к цифровому выводу Arduino D5. В процедуре setup () настроим режим работы вывода (пина) 5 на выход (output): void setup () { pinMode(5,OUTPUT); } В процедуре loop () нам необходимо зажечь светодиод — подать high (1) на цифро- вой вывод D5, подождать некоторое время, затем потушить его — подать low (0) на цифровой вывод D5, опять подождать некоторое время и т. д. по кругу. Для выполнения операции «подождать некоторое время» мы воспользуемся встро- енной в Arduino функцией delay (). Эта функция просто останавливает выполнение программы на заданное в параметре количество миллисекунд (напомню: в 1 секун- де 1000 миллисекунд). Например: delay(2000); // останавливает выполнение программы на 2000 мсек (2 сек) Полный код скетча приведен в листинге 6.1.
92 Часть III. Сопряжение Arduino со вспомогательными устройствами void setup() { // настроить выводы D5 Arduino как OUTPUT pinMode(5, OUTPUT); void loop () { // включить светодиод (установить D5 HIGH) digitalWrite(5, HIGH); // пауза 1000 мсек (1 сек) delay(1000) ; // выключить светодиод (установить D5 LOW) digitalWrite(5, LOW); // пауза 1000 мсек (1 сек) delay(1000); Загрузим этот скетч в плату Arduino— мы должны наблюдать включе- ние/выключение светодиода с периодичностью 2 секунды. Допустим, вы хотите изменить вывод (пин) Arduino для подключения светодиода или время паузы в функции delay о. Можно просто внести изменения в каждую строку скетча, содержащую изменяемые параметры. Но это не совсем удобно, и в больших программах займет очень много времени. Есть и другой вариант — использовать константы и переменные. Константа и переменная — это места хра- нения данных. Они имеют имя, значение и тип. Например, следующее объявление (оно называется декларацией): int pin_ledl =5; создает переменную с именем piniedi, значением 5 и типом int. После этого мы получаем в программе возможность обратиться к ней следующим образом: const int pin_ledl = 5; Декларация: const int pin_led2 = 6; создает константу с именем pin_ied2, значением б и типом int. Константы можно определить и иначе: #define PIN_LED2 б В этом случае не надо указывать тип переменной. Таким образом, в программе возникает возможность обратиться к той или иной переменной или константе через ее имя с целью работы с ее значением. Например, в утверждении: pinMode(pin_ledl, OUTPUT);
Глава 6. Arduino: вводы и выводы 93^ уже подразумевается значение вывода (5), которое будет передаваться в функцию pinMode (). Преимущество переменных и констант заключается в том, что определе- ние значения вывода осуществляется однажды, а потом можно использовать его многократно. Константа, в отличие от переменной, не может изменять свое значение — оно пред- определено при декларации константы, а значение переменной можно менять в программе. Внесем изменения в предыдущий скетч (см. листинг 6.1), используя константу и переменную, и получим скетч, представленный в листинге 6.2. // константа пина Arduino для подключения светодиода Idefine PIN_LED 5 // переменная для паузы (тип unsigned long) unsigned long pause=1000; void setup () { // настроить вывод Arduino как OUTPUT pinMode(PIN_LED, OUTPUT); void loop() { // включить светодиод digitalWrite(PIN_LED, HIGH); // пауза delay(pause); // выключить светодиод digitalWrite(PIN_LED, LOW); // пауза delay(pause); Загрузим этот скетч в плату Arduino и убедимся, что он работает. В чем его пре- имущество перед скетчем из листинга 6.1? Если вам понадобится поменять вывод (пин) для подключения светодиода, то внести изменения надо будет только в одну строку: tdefine PIN_LED 5 Если понадобится поменять длительность паузы, внести изменения нужно будет тоже только в одну строку: unsigned long pause=1000; Вы можете поэкспериментировать со скетчем, меняя пин подключения светодиода и значение переменной pause, определяющей частоту его мигания.
94 Часть III. Сопряжение Arduino со вспомогательными устройствами 6.1.2. Подключение к плате Arduino 8-ми светодиодов Рассмотрим теперь более сложный пример: подключим к плате Arduino 8 свето- диодов и создадим из них «бегущий огонь». Для этого нам понадобятся следующие компоненты: □I плата Arduino Uno; □ кабель USB; □ плата прототипирования (монтажная плата); □ красный светодиод — 8 шт.; □ резистор 220 Ом — 8 шт.; □ соединительные провода ПП — 17 шт. Монтажная схема этого проекта приведена на рис. 6.2. Рис. 6.2. Монтажная схема подключения светодиодов для проекта «бегущий огонь» Приступим к написанию скетча. Прежде всего в процедуре setup о настроим режим работы пинов Arduino, к которым подключены светодиоды, как output (выходы): pinMode(12,OUTPUT); pinMode(11,OUTPUT); pinMode(10,OUTPUT); pinMode(9,OUTPUT);
Глава 6. Arduino: вводы и выводы 95 pinMode(8,OUTPUT); pinMode(7,OUTPUT); pinMode(6,OUTPUT); pinMode(5,OUTPUT); И в начале программы все светодиоды потушены: digitalWrite (12, LOW) ; digitalWrite (11, LOW) ; digitalWrite (10, LOW) ; digitalWrite (9, LOW); digitalWrite (8, LOW) ; digitalWrite (7,LOW) ; digitalWrite (6, LOW); digitalWrite (5, LOW) ; В основном цикле программы — loop () — нам необходимо зажечь первый свето- диод, подождать некоторое время, затем выключить его и зажечь второй светодиод, подождать некоторое время, выключить второй светодиод и зажечь третий, и т. д. по кругу. Для выполнения операции «подождать некоторое время», как и в преды- дущем примере, мы воспользуемся встроенной в Arduino функцией delay о. Эта функция просто останавливает выполнение программы на заданное в параметре количество миллисекунд. Соответственно, внесем в функцию loop () следующий код: void loop () { digitalWrite(12,HIGH); delay(1000); digitalWrite(12,LOW); digitalWrite(11,HIGH); delay(1000); digitalWrite(11,LOW); < digitalWrite(10,HIGH); delay(lOOO); digitalWrite(10,LOW); digitalWrite(9,HIGH); delay(1000); digitalWrite(9,LOW); digitalWrite(8,HIGH); delay(1000); digitalWrite(8,LOW); digitalWrite(7,HIGH); delay(1000); digitalWrite(7,LOW); digitalWrite(6,HIGH); delay(1000); digitalWrite(6,LOW); digitalWrite(5,HIGH);
96^ Часть III. Сопряжение Arduino со вспомогательными устройствами delay(1000); digitalWrite(5,LOW); } Полный код получившегося скетча приведен в листинге 6.3. void setup() { // настроить выводы Arduino 12,11,10,9,8,7,6,5 // как OUTPUT pinMode(12,OUTPUT); pinMode(11,OUTPUT); pinMode(10,OUTPUT); pinMode(9,OUTPUT); pinMode(8,OUTPUT); pinMode(7,OUTPUT); pinMode(6,OUTPUT); pinMode(5,OUTPUT); // все светодиоды "потушить". digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,LOW); digitalWrite(9,LOW); digitalWrite(8,LOW); digitalWrite(7,LOW); digitalWrite(6,LOW); digitalWrite(5,LOW); void loopO { digitalWrite(12,HIGH); delay(1000); digitalWrite(12,LOW); digitalWrite(11,HIGH); delay(lOOO); digitalWrite(11,LOW); digitalWrite*(10,HIGH) ; delay(1000); digitalWrite(10,LOW) ; digitalWrite(9,HIGH); delay(1000); digitalWrite(9,LOW); digitalWrite(8,HIGH); delay(1000); digitalWrite(8,LOW); digitalWrite(7,HIGH); delay(1000);
Глава 6. Arduino: вводы и выводы 97_ digitalWrite(7,LOW); digitalWrite(6,HIGH); delay(1000); digitalWrite(6,LOW); digitalWrite(5,HIGH); delay(1000); digitalWrite(5,LOW); Загрузим этот скетч в плату Arduino — мы должны наблюдать бегущий по свето- диодам «огонь» сначала в одну сторону, а затем в обратную. Основной недостаток нашего скетча — он слишком громоздкий. И даже объявле- ние каждого вывода с помощью переменных не исправит положения. К счастью, есть способ значительно упростить этот скетч, воспользовавшись массивами. Мас- сив — это набор переменных, доступ к которым осуществляется через их индекс. Рассмотрим варианты создания (объявления) массива: □ объявление массива без его инициализации: int pin_leds[8]; □ можно объявить массив без непосредственного указания размера. Компилятор подсчитает количество элементов и создаст массив соответствующего размера: int pin_leds [] = {5,6,7,8,9,10,11,12}; О можно одновременно инициализировать и указать размер создаваемого массива: int pin_leds [8] = {5,6,7,8,9,10,11,12}; □ объявление массива типа char: char message[8] = "Arduino"; Учтите, что в таком случае необходимо предусмотреть еще один элемент для хранения обязательного null-символа: Теперь рассмотрим, как осуществляется доступ к элементам массива. Индексация в массивах начинается с нуля. То есть, первый элемент массива будет иметь поряд- ковый номер 0. Таким образом: pin_leds[0] = 5; pin_leds[l] = 6; Как работать с массивами? Очень удобный метод работы с массивами — циклы. При этом счетчик цикла используется для индексации каждого элемента массива. Например, для создания массива с номерами пинов, задаваемыми командой pinMode (), необходимо выполнить следующий код: int i; for (i = 0; i < 8; i = i + 1) { pinMode(pin leds [i],OUTPUT);
98^ Часть III. Сопряжение Arduino со вспомогательными устройствами Внесем соответствующие изменения в предыдущий скетч (см. листинг 6.3), исполь- зуя массивы, и получим скетч, представленный в листинге 6.4. В нем, кроме массивов, мы предусмотрели для позиции горящего светодиода пере- менную pos, которая после каждой паузы станет увеличиваться на 1, а при дости- жении значения 8 будет обнуляться: pos=(pos+l)%8; При этом мы запускаем цикл for для массива pin_ieds[i] с пинами подключения светодиодов, в котором для всех элементов массива с индексом, не равным значе- нию переменной pos, выполняем команду: digitalWrite (pin_leds [i], LOW) ; а для элемента массива с индексом, равным значению переменной pos, команду: digitalWrite(pin leds[i],HIGH); // массив, элементы которого - пины // подключения светодиодов int pin_leds [8] - {12,11,10,9,8,7,6,5}; // позиция "горящего" светодиода int pos=0; // переменная для паузы (тип unsigned long) unsigned long pause=1000; void setup() { // настроить выводы Arduino как OUTPUT for (int i = 0; i < 8; i = i + 1) { pinMode(pin_leds [i],OUTPUT); } // все светодиоды "потушить", for (int i = 0; i < 8; i = i + 1) { digitalWrite (pin_leds [i], LOW) ; void loopO { // все светодиоды "потушить", for (int i = 0; i < 8; i = i + 1) { // "зажечь" светодиод, если он =pos if (i—pos) digitalWrite(pin_leds [i],HIGH); // все остальные "потушить" else digitalWrite (pin_leds [ i], LOW) ;
Глава 6. Arduino: вводы и выводы // пауза delay(pause); // изменить позицию "горящего" светодиода pos=(pos+l)%8; Электронный архив Полный вариант рассмотренного скетча находится в папке examples\6\J)6jO4 сопрово- ждающего книгу электронного архива. Напоминаю, что этот электронный архив мож- но скачать с FTP-сервера издательства «БХВ-Петербург» по ссылке ftp://ftp.bhv.ru/ 9785977540049.zip, а также со страницы книги на сайте www.bhv.ru (см. приложение 2). Загрузим этот скетч в плату Arduino и убедимся в его работоспособности. Метод расположения пинов в пределах массива очень удобен и позволяет пере- ставлять их как угодно без переподключения светодиодов. Вы можете самостоя- тельно поэкспериментировать с расположением элементов массива. 6.2. Цифровые входы — управляем светодиодами с помощью кнопок Рассмотрим еще одну функцию цифровых выводов. В предыдущем разделе мы ис- пользовали их в качестве выходов, генерируя цифровой сигнал для включения или выключения светодиодов. Сейчас мы попробуем сконфигурировать выводы Arduino в качестве входов. Это позволит подключить к Arduino, например, пере- ключатели и кнопки для взаимодействия с внешними устройствами в режиме реального времени. И в этом разделе вы научитесь определять программное дейст- вие по нажатию кнопки. Установка режима того или иного вывода (на вход или на выход) устанавливается с помощью функции pinMode (): pinMode(2,INPUT); // вывод D2 установлен как выход 6.2.1. Подключение кнопки к плате Arduino Чтобы подключить к Arduino нормально разомкнутую кнопку, можно пойти самым простым путем: один свободный проводник кнопки соединить с питанием или «землей», а другой — с цифровым выводом Arduino (рис. 6.3). Но это неправиль- но — все то время, когда кнопка не замкнута, на цифровом выводе Arduino могут появляться электромагнитные наводки, и из-за этого возможны ложные срабаты- вания. Чтобы избежать наводок, цифровой вывод обычно подключают через достаточно большой резистор (5-10 кОм) либо к питанию, либо к «земле». В первом случае это называется схемой с подтягивающим резистором (рис. 6.4), во втором — схемой со стягивающим резистором (рис. 6.5). Резисторы в обеих схемах используются для
100 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 6.3. Монтажная схема подключения кнопки к выводу Arduino +5 В Рис. 6.4. Монтажная (сверху) и принципиальная (снизу) схемы подключения кнопки к Arduino: схема с подтягивающим резистором
Глава 6. Arduino: вводы и выводы 101 +5 В ДОкОм Рис. 6.5. Монтажная (сверху) и принципиальная (снизу) схемы подключения кнопки к Arduino: . схема со стягивающим резистором установки «значения по умолчанию» из входного контакта: в схеме с подтягиваю- щим резистором это high, в схеме со стягивающим резистором — low. Но вот любопытный момент. Ранее мы утверждали, что схема, показанная на рис. 6.3, неверная, но это только в том случае, если мы используем такой режим установки: pinMode(2,INPUT); // вывод D2 установлен как выход Однако все выводы внутри платы Arduino подсоединены к шине питания 5 В через резисторы сопротивлением порядка 20-50 кОм. И эти резисторы можно программ- но подключать к выводам или отключать от них. Программное включение резисто- ров осуществляется так: pinMode(3, INPUT_PULLUP); // внутренний подтягивающий резистор 20 кОм подключен И схема подключения кнопки, показанная на рис. 6.3, уже оказывается верной! Теперь напишем программу (листинг 6.5), устанавливающую состояние светодио- да, подключенного к выводу 13 (находится на плате Arduino), в зависимости от состояния кнопки (кнопка нажата — светодиод «горит», кнопка отпущена — све- тодиод «потушен»).
102 Часть III. Сопряжение Arduino со вспомогательными устройствами В процедуре setup () устанавливаем режимы выводов, а в процедуре loop () — счи- тываем состояние кнопки в переменную buttonstate и передаем его на светодиод. Для схемы с подтягивающим резистором состояние переменной buttonstate инвер- тируем, т. к. в этом случае при нажатой кнопке состояние сигнала низкое, а свето- диод светится при высоком. Для схемы со стягивающим резистором состояние переменной buttonstate инвертировать не надо. const int LED=13; // Контакт 13 для подключения светоди'ода const int BUTTON=2; // Контакт 2 для подключения кнопки boolean buttonstate; // переменная статуса кнопки buttonstate void setup() { // определяем вывод LED (светодиод) как выход pinMode(LED, OUTPUT)'; // определяем вывод BUTTON (кнопка) как вход pinMode(BUTTON, INPUT_PULLUP); void loop() { // считываем состояние BUTTON входа (кнопки) и записываем в buttonstate buttonstate = digitalRead(BUTTON); // инверсия переменной buttonstate // для схемы с подтягивающим резистором buttonstate - ! buttonstate; // записываем состояние из buttonstate на выход LED (светодиод) digitalWrite(LED, buttonstate); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\6\_06_05 сопрово- ждающего книгу электронного архива (см. приложение 2). Загрузим этот скетч в плату Arduino — вы должны наблюдать включение свето- диода на выводе 13 при нажатии кнопки и выключение его при ее отпускании. Насколько удобно держать кнопку постоянно нажатой для свечения светодиода? Гораздо удобнее иметь возможность нажать кнопку один раз, чтобы включить све- тодиод, и, нажав ее еще раз, — выключить. Загрузим в плату Arduino скетч пере- ключения состояния светодиода при нажатии кнопки (листинг 6.6). Для отладки воспользуемся выводом данных в последовательный порт. const int LED=13; // Контакт 13 для подключения светодиода const int BUTTON=2; // Контакт 2 для подключения кнопки boolean buttonstate; // переменная статуса кнопки buttonstate
Глава 6. Arduino: вводы и выводы 103 boolean buttonStatePrev=LOW; // переменная статуса кнопки предыдущая boolean ledState=LOW; // переменная статуса светодиода void setup () { // запуск последовательного порта Serial.begin(9600); .// определяем вывод LED (светодиод) как выход pinMode(LED, OUTPUT); // определяем вывод BUTTON (кнопка) как вход pinMode(BUTTON, INPUT_PULLUP); // начальное состояние светодиода digitalWrite(LED, ledState); void loop () { // считываем состояние BUTTON входа (кнопки) buttonState = digitalRead(BUTTON); // если нажатие с LOW на HIGH if (buttonState == HIGH && buttonStatePrev=LOW) { ledState = ! ledState; // записываем состояние из ledState на выход LED (светодиод) digitalWrite(LEDr ledState); Serial.printIn(ledState); } buttonStatePrev = buttonState; Электронный архив Полный вариант рассмотренного скетча находится в папке examples\6\_06_06 сопрово- ждающего книгу электронного архива (см. приложение 2). Нажимаем на кнопку и видим, что в последовательном порту при однократном нажатии кнопки происходит несколько изменений ее состояния (рис. 6.6), и соот- ветственно, несколько переключений светодиода. Почему же так происходит? Дело в том, что кнопки представляют собой механиче- ские устройства с системой пружинного контакта, подверженной явлению, назы- ваемому дребезгом, — в процессе нажатия кнопки контакт, особенно в начале на- жатия, несколько раз замыкается и размыкается. То есть, когда вы нажимаете на кнопку, сигнал не просто меняется от низкого до высокого— он в течение нескольких миллисекунд меняет значение от одного до другого, прежде чем уста- новится значение low. Графики, приведенные на рис. 6.7, иллюстрируют отличие ожидаемого явления от реального. Нажатие кнопки происходит примерно за 25 мс. Вы могли бы предположить, что можете сразу узнать о состоянии кнопки, считав значение со входа контакта, как показано на левом графике. Однако кнопка фактически движется вверх-вниз, пока значение не установится, как показано на правом графике. Теперь, зная как ведет
104 Часть III. Сопряжение Arduino со вспомогательными устройствами При 1 нажатии кнопки трока ■',- 56Ш Ь Рис. 6.6. Вывод данных отладки в монитор последовательного порта Идеальное нажатие кнопки Реальное нажатие кнопки Размыкание ^контактов \дребеэг/ Кнопка нажат Кнопка нажата Рис. 6.7. Дребезг при нажатии кнопки себя кнопка, вы можете написать программу, которая обеспечит нормальное снятие показаний с кнопки, подверженной дребезгу, — она считывает состояние кнопки и ожидает некоторое время, после чего считывает состояние снова, чтобы убедиться, что первоначальное состояние не изменилось. Эта логика программы может быть выражена следующим образом: 1. Сохраняем предыдущее состояние кнопки и текущее состояние кнопки (при инициализации low).
Глава 6. Arduino: вводы и выводы 105 2. Считываем текущее состояние кнопки. 3. Если текущее состояние кнопки отличается от предыдущего ее состояния, ждем 5 мс, потому что кнопка, возможно, изменила состояние. 4. По истечении 5 мс считываем состояние кнопки и используем его в качестве текущего. 5. Если предыдущее состояние кнопки было low, а текущее ее high, переключаем состояние светодиода. 6. Устанавливаем предыдущее состояние кнопки для ее текущего состояния. 7. Возврат к шагу 2. 8. Составляем скетч по приведенному алгоритму (листинг 6.7), загружаем его в плату Arduino и проверяем работоспособность. Как можно видеть, одно- кратное нажатие кнопки приводит к однократному изменению состояния свето- диода. const int LEI>13; // Контакт 13 для подключения светодиода const int BUTTON=2; // Контакт 2 для подключения кнопки boolean lastButton = LOW; // Переменная для сохранения предыдущего // состояния кнопки boolean currentButton = LOW; // Переменная для сохранения текущего // состояния кнопки boolean ledOn = false; // Текущее состояние светодиода (включен/выключен) void setup () { // запуск последовательного порта Serial.begin(9600); pinMode (LED, OUTPUT); // Сконфигурировать контакт светодиода как выход pinMode (BUTTON, INPUT); // Сконфигурировать контакт кнопки как вход void loop () { currentButton = debounce(lastButton); if (lastButton == LOW && currentButton == HIGH) // если нажатие... { ledOn = lledOn; // инвертировать значение состояния светодиода Serial.println(ledOn); } lastButton = currentButton; digitalWrite(LED, ledOn); // изменить статус состояния светодиода
106 Часть III. Сопряжение Arduino со вспомогательными устройствами // Функция сглаживания дребезга // Принимает в качестве аргумента предыдущее состояние кнопки, // выдает фактическое. boolean denounce(boolean last) { boolean current = digitalRead(BUTTON); // Считать состояние кнопки if (last != current) // если изменилось... { delay(5); // ждем 5 мс current = digitalRead(BUTTON); // считываем состояние кнопки return current; // возвращаем состояние кнопки Электронный архив Полный вариант рассмотренного скетча находится в папке examples\6\J)6J)7 сопрово- ждающего книгу электронного архива (см. приложение 2). 6.2.2. Управление кнопками количеством горящих светодиодов Создадим еще один проект с использованием кнопок — будем управлять с их по- мощью количеством горящих светодиодов. Для этого нам понадобятся следующие компоненты: □ плата Arduino Uno; □ кабель USB; □ плата прототипирования (монтажная плата); □ соединительные провода ГШ — 12 шт; □ резисторы 220 Ом — 8 шт.; □ светодиоды — 8 шт; □ кнопки — 2 шт.; □ резисторы 10 кОм — 2 шт. В представленной на рис. 6.8 монтажной схеме этого проекта восемь подключен- ных к плате Arduino светодиодов расположены в ряд. При нажатии одной кнопки добавляем горящий светодиод, при нажатии другой — убираем. Весь основной цикл программы мы постоянно опрашиваем кнопки, ожидая их на- жатия. После нажатия кнопки следует реакция— изменение переменной counti (количества зажженных светодиодов). Обратите внимание, что это число не может быть меньше о и больше значения countleds. Функция changecounti () возвращает измененное состояние counti: int change_countl(int but) { if (but=0) // добавить return min(count1+1,COUNT LEDS);
Глава 6. Arduino: вводы и выводы 107 else // снять return max(count1-1,0); После изменения значения counti нам необходимо установить новые состояния для светодиодов, чтобы они соответствовали новому значению counti, — нужно зажечь светодиоды с о до counti и потушить светодиоды с counti до последнего (count_leds=8). Для этого вызываем функцию setiedso, передавая ей в качестве аргумента значение counti: void setleds(int cnt) { // включение светодиодов от 0 до counti for (int i=0; Kent; i++) digitalWrite(pinleds[i]fHIGH); // включение светодиодов от 0 до cnt for(int i=cnt;i<COUNT_LEDS;i++) digitalWrite(pinleds[i],LOW); I b\ Рис. 6.8. Монтажная схема подключения светодиодов и кнопок
108 Часть III. Сопряжение Arduino со вспомогательными устройствами Для устранения дребезга кнопок используем функцию debounce () из листинга 6.7. Создадим в Arduino ГОЕ новый скетч, занесем в него код из листинга 6.8 и загрузим скетч в плату Arduino. Напомним, что в настройках Arduino IDE необходимо вы- брать тип платы (Arduino UNO) и порт подключения платы. // количество кнопок tdefine COUNT_BUTTONS 2 // количество светодиодов #define COUNTJLEDS 8 // Выводы Arduino для подключения // список светодиодов int pinleds[8]«{4,5, 6,7,8, 9,10,11} ; // список кнопок int pinbuttons[2]={2,3}; // список сохранения предыдущих состояний кнопок int lastbuttons[2]={0,0}; // список сохранения текущих состояний кнопок int currentbuttons[2]={0,0}; // переменные - количество горящих светодиодов int countl=0; void setup() { // настроить выводы Arduino для светодиодов как выходы for(int i=0;i<COUNT_LEDS;i++) { pinMode(pinleds[i], OUTPUT); } // установить число светодиодов (0) setleds(O); // the loop function runs over and over again forever void loopO { j // проверка нажатия кнопок выбора программ for(int i=0;i<COUNT_BUTTONS;i++) { currentbuttons[i] = debounce(lastbuttons[i],pinbuttons[i]); // если нажатие... if (lastbuttons[i] == 0 && currentbuttons[i] == 1) { // реакция на нажатие - изменение count1 countl=change_countl(i); // обновление состояния setleds(countl);
Глава 6. Arduino: вводы и выводы 109 lastbuttons[i] = currentbuttons[i]; // изменение количества светодиодов int change_countl(int but) { if(but==0) // добавить ■ return min(count1+1,COUNT_LEDS); else // снять return max(count1-1,0); // (включение-выключение светодиодов) void setleds(int cnt) { // включение светодиодов от 0 до count1 for(int i=0;i<cnt;i++) digitalWrite(pinleds[i],HIGH); // включение светодиодов от 0 до cnt for(int i=cnt;i<COUNT_LEDS;i++) digitalWrite(pinleds[i],LOW); } /* Функция сглаживания дребезга * Принимает в качестве аргумента предыдущее состояние кнопки * и выдает фактическое. V int debounce(int last,int pinl) { int current = digitalRead(pinl); // Считать состояние кнопки // если изменилось... if (last != current) { delay(5); // ждем 5мс current = digitalRead(pinl); // считываем состояние кнопки return current; // возвращаем состояние кнопки Электронный архив Полный вариант рассмотренного скетча находится в папке ехатр1е8\6\_06_08 сопрово- ждающего книгу электронного архива (см. приложение 2). б.З. Аналоговые входы — светодиодный индикатор аналоговых значений В предыдущих разделах мы познакомились с цифровыми выводами Arduino, кото- рые могут работать в режиме входов — для считывания внешних цифровых сигна- лов и выходов — для выдачи цифровых данных. Но цифровые данные имеют толь- ко два состояния: high и low. В то же время мир вокруг вас является аналоговым —
110 Часть III. Сопряжение Arduino со вспомогательными устройствами большинство наблюдаемых явлений в окружающем нас мире чаще всего имеет аналоговый характер. Мир предполагает бесконечное число возможных состояний, будь то цвет солнечного света, или температура океана, или концентрация загряз- няющих веществ в воздухе. Графики на рис. 6.9 показывают, как аналоговые и цифровые сигналы отличаются друг от друга. Слева — прямоугольная волна, значения которой варьируются толь- ко между двумя значениями: 0 и 5 вольт. Точно так же, как и в случае с кнопкой, которую вы использовали в предыдущем разделе, этот сигнал, — только high или low. Справа — часть косинусоидальной волны. Несмотря на то, что ее границы все еще 0 и 5 вольт, сигнал имеет бесконечное число значений между этими двумя на- пряжениями. 8 10 0 2 4 6 8 10 Time(s) Рис. 6.9. График значений для цифровых (слева) и аналоговых {справа) сигналов 4 6 Time(s) Компьютерная система никогда не сможет осуществлять измерение аналогового значения с его бесконечным числом десятичных разрядов, потому что память и производительность компьютера небеспредельны. Если это так, то как вы можете соединить интерфейс цифрового Arduino с аналоговым реальным миром? Ответ прост— с помощью аналого-цифрового преобразователя (АЦП), который может преобразовать аналоговые значения в,цифровые представления с конечной точ- ностью. Каждый из аналоговых контактов Arduino (для Arduino Uno это А0-А5) содержит 10-разрядный АЦП для аналоговых преобразований. 10-разрядный здесь означает, что АЦП может разделить аналоговый сигнал на 210 различных значений (210 = 1024)— от 0 до 1023. Максимальное напряжение (5 В) задает опорное напряжение— его значение соответствует значению 1023 АЦП. При напряжении на контакте 0 В АЦП возвращает значение 0. Напряжение 2,5 В возвращает значе- ние 512 (половина из 1023), и т. д.
Глава 6. Arduino: вводы и выводы 111_ 6.3.1. Подключение потенциометра к плате Arduino Самый простой аналоговый датчик, с которого вы можете получить данные, — это потенциометр. Потенциометры являются переменными делителями напряжения и выглядят часто как ручки. Они присутствуют в стереосистемах, звуковых колонках, термостатах и в других изделиях, бывают разных размеров и форм, но все имеют три вывода. В представленной на рис. 6.10 монтажной схеме этого проекта один из крайних вы- водов потенциометра подключен на «землю», а другой крайний вывод — к шине +5 В. Средний вывод потенциометра подключен к аналоговому входу АО платы Arduino. Рис. 6.10. Монтажная схема подключения потенциометра к плате Arduino Для считывания данных с аналогового порта в Arduino есть функция anaiogRead (), которая возвращает аналоговое значение с аналогового входа Arduino, например: int val=analogRead(AO); Загрузим в плату Arduino скетч из листинга 6.9 — обеспечивающий вывод в мони- тор последовательного порта значений с потенциометра, подключенного к аналого- вому входу АО. пг В/ф II пин подключения среднего вывода потенциометра tdefine PIN_ANALOG АО // переменная для сохранения значения потенциометра int val; void setup() { // запуск последовательного порта Serial.begin(9600);
112 Часть III. Сопряжение Arduino со вспомогательными устройствами void loop () { // считать значение с аналогового порта val=analogRead(PIN_ANALOG); // вывести последовательный порт Serial.print("val="); Serial.println(val); delay(300); Загрузив скетч в плату, откроем монитор последовательного порта и покрутим руч- ку потенциометра— значения будут меняться в промежутке от 0 до 1023 (рис. 6.11). val-398 val-398 val-398 ;val«396 ■val-398 Val-399 W-399 val-398 val-3S0 val-l€5 val»117 val-lQ2 val«29 val-G val-Q val-194 val«328 val*424 val-646 val-917 val«1023 val**lQ23 val«1023 val«1023 val-1023 val-1023 val*1023 val-1023 Рис. 6.11. Вывод данных с аналогового входа в монитор последовательного порта Проблемы не возникнет и в том случае, если мы захотим получить с потенциометра реальные значения сопротивления в омах, — просто составим пропорцию: 1023 — ЮкОм val — X кОм Тогда: X = val х 10/1023
Глава 6. Arduino: вводы и выводы 113 В Arduino IDE для таких преобразований имеется встроенная функция шар (): map(value, fromLow, fromHigh, toLow, toHigh) Функция пропорционально переносит значение value из текущего диапазона значе- ний fromLow . . . fromHigh В НОВЫЙ диапазон toLow . . . toHigh. Обратите внимание, что «нижняя граница» может быть как меньше, так и больше «верхней границы». Это может быть использовано для того, чтобы «перевернуть» диапазон: у = тар(х, 1, 50, 50, 1); Возможно использование и отрицательных значений: у = тар(х, 1, 50, 50, -100); Функция тар () оперирует целыми числами. При пропорциональном переносе дроб- ная часть не округляется по правилами, а просто отбрасывается. Внесем изменения в предыдущий скетч (см. листинг 6.9), чтобы в монитор выво- дились не просто показания аналогового входа АО, но и чтобы мы могли видеть выставляемые значения потенциометра в омах, и получим скетч, представленный в листинге 6.10. Загружаем в плату Arduino скетч из листинга 6.10 и смотрим вывод показаний по- тенциометра в омах (рис. 6.12). // пин подключения среднего вывода потенциометра tdefine PIN_ANALOG АО // переменная для сохранения значения потенциометра int val; unsigned int valOm; void setup () { // запуск последовательного порта Serial.begin(9600); } void loopO { // считать значение с аналогового порта val=analogRead(PIN_ANALOG); // переводим в Ом valQm=map(val,0,1023,0f10000); // вывести последовательный порт Serial.print("val="); Serial.print(valQm); Serial.println(" Qm"); delay(300);
114 Часть III. Сопряжение Arduino со вспомогательными устройствами val-1000Q Ою val-10000 Cm val«10QG0 От val«9266 От val=7849 От val-7028 От val«6402 От val-5503 От val-4Q17 От val=2482 От ral>1104 От ral-О От ral*0 От val*0 От iral=O От га1-0 От /а1-0 От ral-1221 От /al-2932 От /а!«4467 От /al-5522 От ral>6304 От /al-6285 От ^al-64?l От ral«6S10 От ral*651Q От rel«6510 От ral-6510 От fal=€510 От Рис. 6.12. Вывод показаний потенциометра в монитор последовательного порта в омах 6.3.2. Вывод показаний потенциометра на светодиодную шкалу Теперь визуализируем аналоговые данные потенциометра с помощью светодиод- ной шкалы, состоящей из 10-ти светодиодов. Для этого нам понадобятся следую- щие компоненты: □ плата Arduino Uno; □ кабель USB; □ плата прототипирования; □ 10-разрядная линейная светодиодная шкала; □ резистор 220 Ом — 10 шт.; □ соединительные провода ПП — 15 шт. В представленной на рис. 6.13 монтажной схеме этого проекта для подключения светодиодной шкалы к Arduino мы задействуем 10 цифровых выводов D3-D12. Каждый из светодиодов шкалы выводом анода соединен с цифровым выводом Arduino, а катодом с «землей» через последовательно включенный ограничиваю-
Глава 6. Arduino: вводы и выводы 115 щий резистор 220 Ом. Аналоговые данные потенциометра (0-1023) масштабируем в данные шкалы (0-10) с помощью функции тар о и зажигаем на ней соответст- вующее количество светодиодов (листинг 6.11). Рис. 6.13. Монтажная схема подключения к Arduino индикатора показаний потенциометра на светодиодах // Аналоговый вход АО для подключения потенциометра const int POT=0; // переменная для хранения значения потенциометра int valpot = 0; // список контактов подключения светодиодов const int pinsled[10]={4,5,6,7,8,9,10,11,12,13}; // переменная для хранения значения шкалы int countleds = 0; void setup () { // запуск последовательного порта Serial.begin(9600); for(int i=0;i<10;i++) { // Сконфигурировать контакты подсоединения шкалы как выходы pinMode(pinsled[i],OUTPUT); digitalWrite(pinsled[i],LOW);
116 Часть III. Сопряжение Arduino со вспомогательными устройствами void loop () { // чтение данных потенциометра valpot = analogRead(POT); // масштабируем значение к интервалу 0-10 countled=map(valpot,0,1023, 0,10) ; Serial.print("countled ="); Serial.println(countled); // зажигаем количество светодиодов на шкале, равное countled for(int i=0;i<10;i++) { if(i<countleds) // зажигаем светодиод шкалы digitalWrite(pinsled[i],HIGH); else // гасим светодиод шкалы digitalWrite(pinsled[i],LOW); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\6\J)6_11 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем скетч в плату Arduino и, поворачивая ручку потенциометра, следим за показаниями шкалы из светодиодов. Данные дйя отладки выводим в монитор последовательного порта. 6.4. ШИМ — радуга на RGB-c вето диоде Arduino не может на цифровой выход выдавать произвольное напряжение: выдает- ся либо +5 В (high), либо 0 В (low). Но уровнем напряжения управляется многое, например: яркость светодиода, скорость вращения мотора или звук пьезоизлучате- ля. Решение этой проблемы обеспечивает широтно-импульсноя модуляция (ШИМ) — операция получения изменяющегося аналогового значения с использованием циф- ровых сигналов. Работу с помощью ШИМ на Arduino обеспечивают «особые» цифровые выводы, называемые PWM (Pulse-width modulation, широтно-импульсная модуляция) и обо- значенные на плате волнистой линией примерно такого вида ~. На платах Arduino Nano и Arduino Uno ШИМ поддерживают выводы 3, 5, 6, 9, 10 и 11, на плате Mega — выводы 2-13. Принцип организации ШИМ основан на том, что цифровой сигнал на выходе по- стоянно переключается между максимальным и минимальным значениями. Дли- тельность включения максимального значения называется шириной импульса. При этом отношение ширины импульса к периоду его следования (скважность) можно изменять (рис. 6.14). Если скважность равняется 100%, то все время на цифровом выходе Arduino будет напряжение логической единицы (5 вольт). Если задать скважность 50%, то половину времени на выходе будет логическая единица, а по- ловину— логический ноль, и среднее напряжение будет равняться 2,5 вольтам.
Глава 6. Arduino: вводы и выводы 117 И так далее. Таким образом, с помощью задания скважности можно менять среднее напряжение на выходе ШИМ. Выводы Arduino с функцией широтно-импульсной модуляции работают на частоте около 500 Гц. Глаз не замечает мерцания более 50 Гц, поэтому нам кажется, что светодиод, на который подается ШИМ-сигнал, не мерцает, а лишь горит в непол- ную силу — пропорционально скважности этого сигнала. Широтно-Импульсная модуляция 0% рабочего цикла - anatogWrite(O) 5v 0v 5v 25% рабочего цикла - arwJogWrtte(64) fULJUUU $0% рабочего цикла - anak»gWrtte(127) rruirurru 5v Ov 5v Ov 75% рабочего цикла - arwlogWr1te(i9i) nnnnm 100% рабочего цикла « analogWrfte(255) Красный ^ Общий 1234 Рис. 6.14. Принцип работы широтно-импульсной модуляции (ШИМ) Рис. 6.15. Контакты RGB-светодиода Посмотрим, как на основе ШИМ управлять яркостью светодиода. Создадим для этого проект генерации любого цвета, воспользовавшись специальным светодио- дом RGB. Аббревиатура RGB расшифровывается как Red, Green, Blue (красный, зеленый, си- ний)— из этих цветов можно получить любой цвет путем смешения исходных. Светодиод RGB отличается от обычного тем, что содержит три небольших кри- сталла: R, G и В, с помощью которых можно синтезировать любой цвет или отте- нок, в зависимости от подаваемых на них напряжений. RGB-светодиод имеет 4 вы- вода (рис. 6.15). 6.4.1. Подключение к плате Arduino RGB-светодиода Подключим RGB-светодиод к плате Arduino и заставим его переливаться всеми цветами радуги. В представленной на рис. 6.16 монтажной схеме этого проекта присутствует и потенциометр, с помощью которого мы сможем регулировать ско- рость изменения этих цветов.
118 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 6.16. Монтажная схема подключения RGB-светодиода для свечения цветами радуги Список семи основных цветов радуги с разложением их по компонентам R, G и В представлен в табл. 6.1. Таблица 6.1. Семь основных цветов радуги с разложением по компонентам R, G и В Цвет Красный Оранжевый Желтый Зеленый Голубой Синий Фиолетовый R 255 255 255 0 0 0 255 G 0 125 255 255 255 0 0 В 0 0 0 0 255 255 255 Наш светодиод должен переливаться от красного до фиолетового, проходя через все семь основных цветов. Алгоритм вычисления любого промежуточного цвета радуги следующий: 1. Примем за начальную точку отсчета красный цвет (255, 0, 0). 2. Будем постепенно увеличивать значение зеленой составляющей G, пока не дос- тигнем значения оранжевого (255,125,0), а затем и желтого цвета (255,255,0). 3. Постепенно уменьшим значение красной составляющей R до значения зеленого цвета (0, 255, 0).
Глава 6. Arduino: вводы и выводы 4. Постепенно увеличим значение синей составляющей В до значения голубого цвета (0, 255,255). 5. Постепенно уменьшим количество зеленой составляющей G до значения синего цвета (О, 0,255). 6. Постепенно увеличим количество красной составляющей R до значения фиоле- тового цвета (255, 0,255). 7. Выдерживаем небольшую паузу и переходим к шагу 1. Содержимое скетча, реализующего этот алгоритм, приведено в листинге 6.12. // пауза перед каждым изменением цвета радуги idefine MAX_PAUSE 30 idefine MIN_PAUSE 1 // пин подключения среднего вывода потенциометра const int PIN_POT=A0; // вывод красной ноги RGB-светодиода const int RED=11; // вывод зеленой ноги RGB-светодиода const int GREEKN10; // вывод синей ноги RGB-светодиода const int BLUE=9; // переменная для хранения значения потенциометра int pot; // переменная для хранения R-составляющей цвета int red; // переменная для хранения G-составляющей цвета int green; // переменная для хранения В-составляющей цвета int blue; void setup() void loop () { //от красного к желтому red=255;green=0;blue=0; for(green=0;green<=255;green++) setRGB(red,green,blue); //от желтого к зеленому for(red=2 55;red>=0;red—) setRGB{red,green,blue); //от зеленого к голубому for(blue=0;blue<=255;blue++) setRGB(red,green,blue);
120 Часть III. Сопряжение Arduino со вспомогательными устройствами //от голубого к синему for(green=255;green>=0;green—) setRGB(red,green,blue); //от синего к фиолетовому for(red=0;red<=2 55;red++) setRGB(red,green,blue); delay(2000); } // функция установки цвета RGB-светодиода void setRGB(int r, int g,int b) { analogWrite(RED,r); analogWrite(GREEN,g); analogWrite(BLUE,b); pot=sanalogRead(PIN__POT); delay(map(pot,0,1023, MIN_PAUSE, MAX_PAUSE)); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\6\_06_i2 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем скетч в плату и наблюдаем на свечение RGB-светодиода всеми цветами радуги. С помощью потенциометра изменяем скорость изменения цветов. 6.5. Светодиодные индикаторы Светодиодный индикатор представляет собой группу светодиодов, расположенных в определенном порядке и объединенных конструктивно. Рассмотрим один из са- мых распространенных светодиодных индикаторов — светодиодный семисегмент- ный индикатор. В светодиодных семисегментных индикаторах контакты промаркированы метками от а до g (и дополнительно dp — для отображения десятичной точки). У них также имеется один общий вывод, который определяет тип подключения индикатора: схема с общим анодом (ОА) или с общим катодом (ОК). Зажигая одновременно не- сколько светодиодов, можно формировать на индикаторе символы цифр. Назначе- ние контактов светодиодного семисегментного индикатора D5651 с общим катодом показано на рис. 6.17. 6.5.1. Подключение к плате Arduino семисегментного индикатора Создадим проект вывода на семисегментный индикатор цифр от 0 до 9. Для этого нам понадобятся следующие компоненты: □ плата Arduino Uno; □ кабель USB;
Глава 6. Arduino: вводы и выводы 121 10 9 8 7 О О О О О 3,8 ffflffl 17 16 I4 12 It I9 110 12 3 4 5 Рис. 6.17. Назначение контактов индикатора D5651 с общим катодом □ плата прототипирования; П семисегментный индикатор D5651; О резистор 220 Ом — 8 шт.; □ соединительные провода ГШ — 15 шт. Монтажная схема подключения семисегментного индикатора D5651 к плате Arduino показана на рис. 6.18. При создании скетча для хранения информации о каждой цифре будем использо- вать 1 байт, который состоит из 8 битов (каждый бит: 0 или 1). Данные для пред- ставления каждой цифры приведены в табл. 6.2. Рис. 6.18. Монтажная схема подключения семисегментного индикатора D5651 к плате Arduino
122 Часть III. Сопряжение Arduino со вспомогательными устройствами Цифра 0 1 2 3 4 5 6 7 8 9 а бит 7 1 0 1 1 0 1 1 1 1 1 b бит 6 1 1 1 1 1 0 0 1 1 1 Таблица Сегменты с бит 5 1 1 0 1 1 1 1 1 1 1 d бит 4 1 0 1 1 0 1 1 0 1 1 6.2. Значения битов для каждой цифры индикатора е битЗ 1 0 1 0 0 0 1 0 1 0 f бит 2 1 0 0 0 1 1 1 0 1 1 9 бит1 0 0 1 1 1 1 1 0 1 1 dp битО 0 0 0 0 о • 0 0 0 0 0 Число в двоичной форме В11111100 В01100000 В11011010 В11110010 В01100110 В10110110 В10111110 В11100000 В11111110 В11110110 Организуем массив для описания 10-ти цифр (от 0 до 9): // значения для вывода цифр 0-9 byte numbers [10] = { ВШ11100, // 0 В01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6 B11100000, // 7 B11111110, // 8 B11100110 // 9 Теперь напишем подпрограмму setNumber (), отвечающую за вывод значений на контакты Arduino для индикации цифры. Воспользуемся при этом Arduino- функцией bitReadO, которая возвращает состояние указанного бита числа (1 илиО). Нумерация начинается с младшего значащего бита (крайнего правого) с номером 0: x=bitRead(B01001000,6); // х=1 - шестой бит, начиная с нулевого (крайнего справа) А вот и сама подпрограмма: void setNumber (int num) { // пройти по всем битам for(int i=0;i<7;i++) { if(bitRead(numbers[num],7-i)==HIGH) // зажечь сегмент digitalWrite(pins[i],HIGH);
Глава 6. Arduino: вводы и выводы 123 else // потушить сегмент digitalWrite(pins[i],LOW); Каждую секунду (реализуем это с помощью delay (1000)) мы будем выводить на индикатор новое число от 0 до 9 (листинг 6.13). // список выводов Arduino для подключения к разрядам а-д // семисегментного индикатора int pins [7] = {11,10, 9, 8,7, 6,5,4 }; // значения для вывода цифр 0-9 byte numbers [10] = { В11111100, // 0 В01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6 B11100000, // 7 B11111110,, // 8 B11100110 // 9 }; // переменная для хранения значения текущей цифры int number=0; void setup () { // Сконфигурировать контакты как выходы for(int i=0;i<7;i++) pinMode(pins[i],OUTPUT); void loopO { setNumber(number); delay(1000); // следующая цифра number=(number+1)%10; // функция вывода цифры на семисегментный индикатор void setNumber (int num) { for(int i=0;i<7;i++) { if(bitRead(numbers[num],7-i)==HIGH) // зажечь сегмент digitalWrite(pins[i],HIGH);
124 Часть III. Сопряжение Arduino со вспомогательными устройствами else // потушить сегмент digitalWrite(pins[i],LOW); Электронный архив Полный вариант рассмотренного скетча находится в папке ехатр/еэ^Об^З сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем скетч в плату Arduino й смотрим на изменение цифр, выводимых на све- тодиодный индикатор. 6.6. Расширение цифровых выходов — микросхема 74НС595 Arduino Uno имеет 20 выводов, которые можно задействовать в разработке, но бывают проекты, для которых существующих выводов недостаточно. Например, в очень простом проекте из предыдущего раздела мы использовали уже 13 выво- дов, а более сложные проекты потребуют еще большего их количества. Конечно можно обратиться к плате Arduino Mega, но это не всегда рационально, к тому же могут быть задуманы проекты, для реализации которых не хватит и выводов Arduino Mega. Что же делать в такой ситуации? Использовать внешние микросхе- мы, имеющие функционал по расширению выводов, — например, сдвиговый ре- гистр 74НС595 (рис. 6.19). Это восьмиразрядный сдвиговый регистр с последова- тельным вводом, последовательным или параллельным выводом информации, с триггером-защелкой и тремя состояниями на выходе. Распиновка контактов сдвигового регистра 74НС595 показана на рис. 6.20, а назна- чение этих контактов представлено в табл. 6.3. 74НС595 Q1 Q2 Q3 Q4 Q5 Q6 Q7 QND VCC Q0 DS ОЕ ST_CP SH_CP MR Q71 16 ■an 15 ■вшам 14 13 ■■■■■■ 12 11 10 ■Hi 9 Рис. 6.19. Сдвиговый регистр 74НС595 Рис. 6.20. Распиновка контактов сдвигового регистра 74НС595
Глава 6. Arduino: вводы и выводы 125 Таблица 6.3. Назначение контактов микросхемы 74НС595 Контакт Vcc Q0...Q7 DS ОЕ ST_CP SH_CP MR Q7' GND Назначение Питание (2-6 В) Параллельные выходы Вход для последовательных данных Вход для переключения состояния выходов из высокоомного в рабочее (активация при получении low) Синхронизация («защелкивание») выходов Вход для тактовых импульсов Сброс значений регистра (активация при получении low) Выход для последовательного соединения регистров «Земля» Данные к микросхеме передаются последовательно по входу DS. Биты следуют в регистр друг за другом, считывание битов происходит при поступлении синхро- импульса SH_CP. После поступления всех битов во внутренние ячейки 74НС595 необходимо передать их на выводы Q0...Q7 («защелкнуть»). «Защелкивание» про- исходит при поступлении синхроимпульса ST_CP. Используя всего три выхода Arduino, можно управлять 8-ю выходами сдвигового регистра. Передал 8 битов — получил 8 выходных состояний на выходах регистра. Поступающие на DS данные при переполнении 8-ми внутренних ячеек проталки- ваются на выход Q7. А если микросхемы соединить последовательно друг за дру- гом (Q7 — к выводу DS следующего сдвигового регистра 74НС595 и т. д.), то количество контролируемых выходов можно наращивать до любого разумного предела, поскольку при каскадном включении 74НС595 (при необходимости полу- чения 16, 24 и т.д. выходов) данные от первого регистра передаются к следую- щему. 6.6.1. Подключение к плате Arduino сдвигового регистра 74НС595 Рассмотрим подключение к плате Arduino сдвигового регистра 74НС595 и реализа- цию «бегущего огня» на 8-ми светодиодах. Для этого нам понадобятся следующие компоненты:: □ плата Arduino Uno; □ кабель USB; Я плата прототипирования; □ микросхема 74НС5951; □ светодиоды — 8 шт.;
126 Часть III. Сопряжение Arduino со вспомогательными устройствами О резисторы 220 Ом — 8 шт.; □ соединительные провода ПП — 25. Монтажная схема подключения 8-ми светодиодов к плате Arduino с использовани- ем сдвигового регистра 74НС595 показана на рис. 6.21. Рис. 6.21. Монтажная схема подключения 8-ми светодиодов к плате Arduino с использованием сдвигового регистра 74НС595 На Arduino для подключения к сдвиговому регистру 74НС595 мы задействуем три следующих выхода (табл. 6.4). Таблица 6.4. Подключение Arduino к сдвиговому регистру 74НС595 Контакты Arduino Uno D7 D6 D5 Контакты 74НС595 DS ST_CP SH_CP Данные, которые нам необходимо отправлять в сдвиговый регистр (нулевой бит мы отправляем первым, и он попадает на выход Q7 сдвигового регистра), приведены в табл. 6.5.
Глава 6. Arduino: вводы и выводы 127 Таблица 6.5. Данные, отправляемые в сдвиговый регистр Номер зажигаемого светодиода 0 1 2 3 4 5 6 7 Двоичные данные В00000001 воооооою воооооюо В00001000 воооюооо • В00100000 В01000000 В1000000 В скетче создадим массив с данными, которые будем отправлять в сдвиговый регистр: // массив хранения значений шкалы 0-7 byte numbers [8] = { В00000001, // 0 ВООООООЮ, // 1 // 2 // 3 • ВОООООЮО, ВООООЮОО, ВОООЮООО, B00100000f воюооооо, B10000000 // 4 // 5 // 6 // 7 И переменную, указывающую на текущие данные: int pos=0; А также направление изменения pos — переменную dir (1 или -1) int dir=l; Каждую секунду будем изменять значение pos (от 0 до 8 и обратно), выбирать новые значения из массива numbers и отправлять в сдвиговый регистр: delay(lOOO); pos=pos+dir; send_data__74hc595 (number [pos]); if(pos=8) dir—1; if (pos—0) dir=l; Теперь напишем процедуру send_data_74hc595()— отправки последовательных данных в сдвиговый регистр. Прежде всего выставляем на D5 (вывод SH_CP сдви- гового регистра) низкий уровень low. На D7 выставляем значение бита, начиная
128 Часть III. Сопряжение Arduino со вспомогательными устройствами с младшего, затем выставляем на D5 высокий уровень high. Для получения значе- ния бита используем Arduino-функцию bitRead(x,n), где п— номер бита (0-7) в байте х, начиная с младшего: digitalWrite(5, LOW); digitalWrite(7, bitRead(x,0)); digitalWrite(5, HIGH); ' Значение выставленного бита записывается во внутреннюю ячейку сдвигового ре- гистра. Повторяем операцию для следующих битов: for(int i=0;i<8;i++) { digitalWrite(5, LOW); digitalWrite(7, bitRead(x,i)); digitalWrite(5, HIGH); } После отправки 8-ми битов необходимо значения «защелкнуть» на выходах Q0...Q7: digitalWrite(6, HIGH); digitalWrite(6, LOW); Таким образом, весь код процедуры send_data_74hc595 () выглядит так: void send_data_74hc595(byte value) { for(int i=0;i<8;i++) { digitalWrite(5, LOW); digitalWrite(7, bitRead(value,i)); digitalWrite(5, HIGH); } digitalWrite(6, HIGH); digitalWrite(6, LOW); } Полный код скетча приведен в листинге 6.14. Загружаем скетч в плату Arduino и проверяем его работу. // константы подключения пинов const int data_pin = 7; const int shjpin = 5; const int st_pin =6; // массив хранения значений шкалы 0-7 byte numbers[8] = { B00000001, // 0 B00000010, // 1 B00000100, // 2 B00001000, // 3 B00010000, // 4 B00100000, // 5
Глава 6. Arduino: вводы и выводы 129 ВОЮООООО, // 6 ВЮОООООО // 7 }; // текущее значение 0-7 int pos = 0; // текущее направление движения значения 1 или -1 int dir = 1; void setup () { // запуск последовательного порта Serial.begin(9600); // Сконфигурировать контакты подсоединения 74НС595 pinMode(data_pin,OUTPUT); pinMode(sh_pin,OUTPUT); pinMode(stjpin,OUTPUT); digitalWrite(st_pin, LOW); void loop() { // изменить текущее значение pos=pos+dir; // отправить данные в сдвиговый регистр send_data_74hc595(numbers[pos]); // для отладки Serial.print("pos=");Serial.print(pos); Serial.print(" dir=");Serial.print(dir); Serial.print(" value=");Serial.println(numbers[pos]); // при крайних позициях поменять направление if (pos=7) dir=-l; if(pos==0) dir=l; // пауза 1 сек delay(1000); } // процедура отправки данных //в сдвиговый регистр void send_data_74hc595(byte value) { // последовательная отправка байта for(int i=0;i<8;i++) { digitalWrite(sh_pin, LOW); digitalWrite(data_pin, bitRead(value,i)); digitalWrite(sh_pin, HIGH); } // защелкиваем digitalWrite (st__pin, HIGH) ; digitalWrite (st__pinf LOW);
130 Часть III. Сопряжение Arduino со вспомогательными устройствами Электронный архив Полный вариант рассмотренного скетча находится в папке examples\6\_06_14 сопрово- ждающего книгу электронного архива (см. приложение 2). 6.7. Расширение цифровых входов и выходов — микросхема МСР23017 В предыдущем разделе мы познакомились с расширителем выводов — сдвиговым регистром 74НС595. Есть и другие способы расширить количество цифровых кон- тактов платы Arduino. Так, микросхема МСР23017 (рис. 6.22) добавляет Arduino 16 портов, которые можно настроить как на вход, так и на выход. Микросхема ис- пользует популярную двухпроводную шину 12С. GPBO GPB1 GPB2 GPB3 GPB4- GPB5- GPB6- GPB7" Vbo» Vss. NC- set 8DA* «1 2 3 4 5 6 7 8 9 10 11 12 13 14 S i 28 27 26 25 24 23 22 21 20 19 18 17 16 15 GPA7 GPA6 QPA5 GPA4 GPA3 OPA2 GPA1 ■ INTA - INTB RESET -A2 -A1 •АО Рис. 6.22. Выводы микросхемы МСР23017 Адрес микросхемы МСР23017 для протокола 12С можно установить комбинацией сигналов на цифровых входах А0-А2 (рис. 6.23), что позволяет подключить к плате Arduino одновременно 8 микросхем МСР23017 — соответственно 16 х 8 = 128 кон- тактов. Рис. 6.23. Установка адреса микросхемы МСР23017
Глава 6. Arduino: вводы и выводы 131 Микросхема МСР23017 имеет 2 банка портов: A (GPA0-GPA7) и В (GPB0-GPAB), каждый из которых можно настроить на ввод или на вывод. В листинге 6.15 пока- зан пример настройки банков выводов А и В. // подключение библиотеки Wire.h ^include <Wire.h> byte input=0; void setup () { Serial.begin(9600) ; Wire.begin(0,2); // запуск 12С Wire.beginTransinission(0x20); // i2c - адрес (А0-0,Al-0,A2-0) Wire.write(0x00); // IODIRA register Wire.write(0x00); // настроить PORT А как output Wire.endTransmission(); void loop() { // чтение данных из PORT В Wire.beginTransinission(0x20); Wire.write (0x13); Wire. endTransmission () ; Wire, request From (0x20, 1) ; input=Wire. read () ; // записать полученные данные в PORT A Wire ..beginTransmission (0x20); Wire.write(0x12); // address PORT A Wire.write(input); // PORT A Wire.endTransmission(); delay(100); // пауза Электронный архив Полный вариант рассмотренного скетча находится в папке examples\6\_06_15 сопрово- ждающего книгу электронного архива (см. приложение 2). 6.8. Расширение аналоговых входов — мультиплексор CD4051 Если вашим проектам окажется недостаточно имеющихся в наличии на платах Arduino аналоговых входов, можно воспользоваться мультиплексором CD4051 (рис. 6.24).
132 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 6.24. Мультиплексор CD4051 Микросхема CD4051 представляет собой 8-канальный аналоговый мультиплексор/ демультиплексор, имеющий 8 входов (уО-у7) и один выход z (рис. 6.25). Выбор считываемого входа осуществляется подачей цифровых сигналов на выходы sO-s2. таким образом, для подключения к плате Arduino 8-ми дополнительных аналоговых датчиков необходимо задействовать три цифровых выхода модуля и один аналого- вый вход. 4051 у4 1 16 4051 в режиме мультиплексора 3 14 у1 13 уО 16- 15- уб-j—2 z-U3 у7 —I— 4 У5 5 12—1— уЗ Е- Vee- gnd- ■ 6 ■7 ■8 11- 10- 9- Vcc ■у2 Аналоговые входы sO s1 s2 Выбор аналогового входа (установка с 3-х контактов Arduino) Значение с выбранного аналогового " входа (к аналоговому входу Arduino) Назначение контактов Логическая схема работы Рис. 6.25. Контакты мультиплексора CD4051 В листинге 6.16 представлен скетч циклического опроса 8-ми аналоговых датчиков, подключенных к 8-ми входам мультиплексора и — через вход z — к аналоговому входу АО платы Arduinp. // список пинов для подключения к sO, si, s2 мультиплексора // D5, D7, D8 int pins[]={14, 13, 15}; // Массив двоичных чисел, определяющих номер выбранного входа/выхода // микросхемы 4051, с 1 по 8. int bin [] = { В000, В001, ВОЮ, ВОН, ВЮО, В101, В110, Bill } ;
Глава 6. Arduino: вводы и выводы 133 II служебные переменные int row; int rO = 0; int rl = 0; int r2 = 0; int avalue =0; void setup (void) { / // входы подключения к мультиплексору как OUTPUT for(int i=0;i<3;i++) { pinMode(pins[i],OUTPUT); } . // запуск последовательного порта Serial.begin(9600); void loop (void) { for(int i=0;i<8;i++) { // выбор входа мультиплексора row = bin [i] ; rO = row & 0x01 ; rl = (row » 1) & 0x01 ; r2 = (row » 2) & 0x01 ; digitalWrite (pins[i], rO) ; digitalWrite (pins[i], rl) ; digitalWrite (pins[i]r r2) ; // получение данных с АО avalue= analogRead(АО); // вывод в монитор последовательного порта Serial., print ("analog input ="); Serial. print (i); Serial.println(" = "); Serial.println(avalue); } // пауза delay(2000); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\6\_06_16 сопрово- ждающего книгу электронного архива (см. приложение 2).
о© ГЛАВА 7 Использование библиотек в проектах Arduino Возможности среды программирования Arduino могут быть существенно расшире- ны за счет использования библиотек. Библиотеки расширяют функциональность программ и несут в себе дополнительные функции — например, для работы с аппа- ратными средствами, функции по обработке данных и т. д. Ряд библиотек устанав- ливается автоматически вместе со средой разработки, однако вы также можете ска- чивать дополнительные библиотеки или создавать собственные. Использование библиотек существенно упрощает работу над проектами, потому что дает возмож- ность сосредоточиться на основной логике программы, не тратя время на множест- во мелочей. Сегодня огромное количество библиотек выложено в Интернете, где их можно легко скачать, причем совершенно бесплатно. Электронный архив Напомню, что необходимые для работы с проектами книги подгружаемые библиотеки размещены в каталоге libraries сопровождающего книгу электронного архива (см. при- ложение 2). 7.1. Установка библиотек Среда разработки Arduino ШЕ поставляется вместе с набором стандартных библио- тек. Функционал стандартных библиотек включает в себя функции базовых видов коммуникации и поддерживает наиболее распространенные устройства. Стандарт- ные библиотеки располагаются в папке libraries каталога установки Arduino. Список всех установленных библиотек, в том числе и базовых, можно посмотреть в Arduino ШЕ по команде Эскиз | Include Library (рис. 7.1). Если в этом списке нет необходимой библиотеки, ее нужно установить. Сделать это можно тремя способами: □ через Менеджер библиотек (Manage libraries); □ импортированием ZIP-архива библиотеки; □ вручную. Установленная библиотека появится в списке библиотек Arduino ШЕ, и ее можно будет использовать в своих скетчах. Обратите внимание: примеры добавлен-
136 Часть III. Сопряжение Arduino со вспомогательными устройствами void setup( // put yo| void loop() // put your main code here, to run repeatedly: Рис. 7.1. Список установленных библиотек в Arduino IDE ной библиотеки появятся в меню Файл | Образцы только после перезагрузки Arduino ШЕ. 7.1.1. Установка библиотеки через Менеджер библиотек Эта возможность появилось в Arduino IDE, начиная с версии 1.6.2,— соответст- вующее меню открывается командой Эскиз | Include Library | Manage Libraries. В появившемся списке (рис. 7.2) ищем нужную библиотеку, выбираем необходи- мую версию и нажимаем кнопку Install. Время загрузки зависит, как правило, от скорости интернет-соединения. По завер- шении загрузки рядом с названием библиотеки должна появиться надпись INSTALLED (рис. 7.3). После этого Менеджер библиотек можно закрыть. 7.1.2. Установка библиотеки из ZIP-архива Многие библиотеки в Интернете предлагаются для установки из ZIP-архивов. Для подключения таких библиотек необходимо их сначала скачать на компьютер. Затем в Arduino IDE выполнить команду меню Эскиз | Include Library | Add /ZIP library, в открывшемся окне выбрать путь к скачанному ZIP-архиву и нажать кнопку Open (рис. 7.4) — ZIP-архив библиотеки будет распакован в папку libraries
Глава 7. Использование библиотек в проектах Arduino 137 Рис. 7.2. Поиск библиотеки в Manage Libraries Рис. 7.3. Библиотека установлена
138 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 7.4. Установка библиотеки из ZIP-архива каталога установки Arduino, а название библиотеки появится в списке установлен- ных библиотек. 7.1.3. Установка библиотеки вручную Для ручной установки библиотеки необходимо скачать и распаковать ее ZIP-архив. Название распакованной папки является названием библиотеки. Внутри этой папки находятся файл с расширением срр, файл с расширением h, текстовый файл keywords.txt, папка examples с примерами и другие файлы, требуемые библиотеке. Распакованную папку необходимо переместить в папку libraries, расположение которой зависит от используемой вами операционной системы: О для Windows, по умолчанию, это Мои AOKyMeHTbi\ArcluinoMlbraries; □ для Mac OS X: -/Докумекты/Arduino/libraries; □ в Linux это будет папка libraries с вашими скетчами. После перезапуска Arduino IDE добавленная библиотека станет доступна для под- ключения ее к своим программам через меню Эскиз | Include Library. 7.2. Подключение библиотеки Для того чтобы подключить библиотеку, нужно написать всего одну строку в нача- ле скетча: #include <name_library. h>
Глава 7. Использование библиотек в проектах Anduino 139 например: iinclude < LiquidCrystal. h> Некоторые библиотеки при работе используют методы и функции других библио- тек — тогда нужно подключать две библиотеки: сначала подключается та, методы и функции которой использует вторая, например: // Подключение библиотеки Wire для работы с шиной I2C tinclude <Wire.h> // Подключение библиотеки LiquidCrystal_I2C tinclude <LiquidCrystal_I2C.h> Для работы с большинством библиотек нужно создать объект (экземпляр класса библиотеки), через который будут доступны их функции и методы, например: LiquidCrystal_I2C led(0x27,20,4); Здесь led— это объект библиотеки LiquidCrystai_i2c, через него и обращаются к функциям и методам библиотеки. 7.3. Создание собственной библиотеки Научимся создавать собственные библиотеки. В разд. 6.5 мы рассматривали работу со светодиодным индикатором D5651. Создадим библиотеку, которая будет упро- щать вывод цифр на этот индикатор. Назовем ее D5651. Библиотека должна иметь как минимум два файла: □ заголовочный файл (с расширением h); О файл с исходным кодом (с расширением срр). В первом файле содержится описание самого класса, переменные и константы. А второй файл содержит программный код методов. 7.3.1. Создание заголовочного файла D5651.h Все содержимое h-файла необходимо заключить в конструкцию, исключающую повторное подключение библиотеки: tifndef Buttonjh // если библиотека Button не подключена idefine Button_h // тогда подключаем ее tendif Внутри конструкции необходимо включить файл Arduino.h, содержащий стандарт- ные константы и переменные языка Arduino. В обычных программах он добавляет- ся автоматически, а для библиотеки должен быть указан явно, поэтому следует на- писать: tinclude "Arduino.h"
140 Часть III. Сопряжение Arduino со вспомогательными устройствами Необходимо также добавить описание класса. Класс — это набор функций и пере- менных, объединенных в одном месте. Функции и переменные могут быть публич- ными (public), что означает общий доступ к ним всех, кто использует библиотеку, или частными (private), что означает доступ к ним только внутри класса. Конст- руктор имеет то же имя, что и класс, но не имеет типа возвращаемого значения: class D5651 { public: D5651(byte *pins); void setNumber(int num); private: byte *pinsS; }; Содержимое создаваемого файла D5651.h приведено в листинге 7.1. #ifndef D5651_h tdefine D5651_h #include "Arduino.h" class D5651 { public: D5 65Kbyte *pins) ; void setNumber(int num); private: byte *pinsS; }; #endif 7.3.2. Создание файла реализации D5651.cpp В начале кода этого файла находится директива #inciude: #include <D5651.h> Она разрешает доступ к характеристикам, содержащимся в головном файле биб- лиотеки D5651.h. За ней следует конструктор. Он используется для создания экземпляра создаваемо- го класса: D5651::D5651(byte *pins) { for(int i=0;i<8;i++) { pinsS= pins;
Глава 7. Использование библиотек в проектах Arduino 141 for(int i=0;i< pinMode(pinsS[i], OUTPUT); // определяем вывод как вход Далее прописана реализация метода. Код D5651:: означает, что функция принадле- жит классу D5 651. Содержимое файла D5651.cpp приведено в листинге 7.2. tinclude <D5651.h> // описание конструктора класса D5651 D5651::D5651(byte *pins) { for(int i=0;i< pinsS= pins; for(int i=0;i pinMode(pinsS[i], OUTPUT); // определяем вывод как вход // вывод цифры void D5651:isetNumber(int num) { byte numbers[10] = { B11111100, // 0 В01100000, B11O11O1O, biiiiooio, . BO11OO11O, B1O11O11O, B1O11111O, B111OOOOO, впито, B11100110 j // i // 2 // 3 // 4 // 5 // 6 // 7 // 8 1 / 9 for(int i=0;i<7;i++) { if(bitRead(numbers[num],7-i)==HIGH) // зажечь сегмент digitalWrite(pinsS[i],HIGH); else // потушить сегмент digitalWrite(pinsS[i],LOW); 7.3.3. Создание файла keywords.txt Для того чтобы Arduino ГОЕ выделяла цветом новые типы и методы нашей библио- теки, необходимо создать файл keywords.txt:
142 Часть III. Сопряжение Arduino со вспомогательными устройствами D5651 KEYW0RD1 setNumber KEYW0RD2 Каждая строка этого файла содержит ключевое слово, табуляцию (не пробелы) и тип ключевого слова: keywordi определяет классы, keyword2 — методы. Электронный архив ZIP-архив с файлами библиотеки D5651 находится в папке examples\7 сопровождающе- го книгу электронного архива (см. приложение 2).
ГЛАВА 8 Arduino и последовательный порт UART Протокол обмена через последовательный порт UART предполагает двусторонний обмен данными между двумя устройствами. При этом оба устройства являются равноправными — то есть явно выраженного деления устройств на главное и под- чиненное не предполагается. Для организации обмена данными используются всего две линии: по одной данные передаются от первого устройства ко второму, а по другой — в обратном направлении. На микроконтроллере при этом задействуются два контакта (пина). Обозначаются они соответственно: ТХ— передающий и RX — принимающий. Линии передачи соединяют ТХ первого устройства с RX второго и RX первого устройства с ТХ второго. Arduino Uno имеет один аппаратный последовательный порт, подключенный к порту USB. Arduino Mega имеет три дополнительных последовательных порта. 8.1. Библиотека Serial Для работы с аппаратными UART-контроллерами в Arduino существует встроен- ный класс serial. Он предназначен для управления обменом данными через UART. Рассмотрим основные функции класса serial. 8.1.1. Функция Serial.begin Синтаксис функции: Serial .begin (speed) Функция разрешает работу порта UART и — через параметр speed — задает ско- рость обмена в бод (бит/сек). Для задания скорости передачи данных рекомендуется использовать стандартные значения: 4800,9600, 19 200, 38 400, 57 600, 115 200 бод. Например: Serial.begin(9600); // инициализация порта, скорость 9600 бод
144 Часть III. Сопряжение Arduino со вспомогательными устройствами 8.1.2. Функция Serial.print Синтаксис функции: Serial.print (val), Serial.print (val, format) Функция передает данные через последовательный порт как ASCII-текст и может принимать различные типы данных. Так, целые числа выводятся соответствующи- ми им символами ASCII, в вещественные — с помощью двух ASCII-символов: для целой и дробной части. Байты передаются как символ с соответствующим номе- ром. Символы и строки отсылаются как есть. Параметры функции: □ val — данные для передачи через последовательное соединение; □ format — базис для целых чисел или количество знаков после запятой для веще- ственных: • byte — выводит число в виде байта; • bin — выводит число в двоичном формате; • ост — выводит число в восьмеричном формате; • dec — выводит число в шестнадцатеричном формате; • hex — выводит число в десятичном формате. 8.1.3. Функция Serial.println Синтаксис функции: Serial.println() Serial.println(val) Serial.println(val, format) Функция выводит данные через последовательный порт UART в виде ASCII- символов с добавлением символов переноса строки (\г, код 13) и (\п, код 10), чтобы следующее сообщение отображалось с новой строки. В остальном она ана- логична функции print (). Параметры функции: □ val — данные для передачи через последовательное соединение; □ format — базис для целых чисел или количество знаков после запятой для веще- ственных. 8.1.4. Функция Serial.write Синтаксис функции: Serial.write(val) Функция выводит двоичные данные через последовательный порт UART и возвра- щает количество переданных байтов.
Глава 8. Arduino и последовательный порт UART 145_ Параметр функции: vai— данные для передачи через последовательное соеди- нение. 8.1.5. Функция Serial.avail able Синтаксис функции: Serial. available () Функция возвращает количество байтов, принятых последовательным портом и записанных в буфер. Буфер последовательного порта может хранить до 64 байтов. В случае пустого буфера возвращает 0. Пример: n= Serial, available(); // в n - число принятых байтов 8.1.6. Функция Serial.read Синтаксис функции: Serial. read () Функция возвращает очередной байт из буфера последовательного порта. Если буфер пуст — возвращает число 1 (Oxffff). Пример: char var= Serial.read(); // чтение байта из буфера 8.2. Использование UART для отладки программ Среда Arduino IDE не содержит отладчика, что создает проблемы в поиске ошибок кода программы. А, как известно, без ошибок программы сразу не пишутся. Фор- мальные ошибки выявляются при компиляции, а с алгоритмическими и вычисли- тельными сложнее. И основная функция отладки — увидеть состояние программы и узнать значение переменных. Это можно сделать, передав нужную информацию на компьютер через последовательный интерфейс. Среда Arduino ШЕ включает монитор последовательного порта, позволяющий получать и посылать данные обмена с платой. 8.2.1. Подключение к плате Arduino нескольких кнопок Рассмотрим, как использовать отладочную информацию в проекте подключения к плате Arduino нескольких кнопок. Для этого нам понадобятся следующие компо- ненты: □ плата Arduino Uno; □ кабель USB;
146 Часть III. Сопряжение Arduino со вспомогательными устройствами □ плата прототипирования; □ кнопка — 6 шт.; П резисторы 10 кОм — 6 шт.; □ соединительные провода. В представленной на рис. 8.1 монтажной схеме этого проекта шесть кнопок под- ключены к выводам контроллера Arduino. При определении нажатия мы будем выводить в последовательный порт номер нажатой кнопки и контакт (пин) ее под- ключения. Создадим в Arduino IDE новый скетч, занесем в него код из листинга 8.1, загрузим скетч в плату Arduino и откроем монитор последовательного порта. При нажатии на кнопку в порт должна выводиться информация о номере нажатой кнопки и кон- такте (пине) ее подключения (рис. 8.2). При отсутствии при нажатии кнопки такой информации или выводе неверной ищем ошибку или в подключении, или в коде программы. // клавиши выбора режима int pinButtons[]={5,6,7,8,9,10}; int lastButtons[]={0,0,0,0#0,0,0,0}; int currentButtons[]={0,0,0,0,0,0,0,0}; int countButtons=6; void setup(void) { // запуск последовательного порта Serial.begin(9600); void loop(void) { // проверка нажатия кнопок for(int i=0;i<countButtons;i++) { currentButtons[i] = debounce(lastButtons[i],pinButtons[ i ]); if (lastButtons[i] = 0 && currentButtons[i] == 1) { // если нажатие. // вывод номера нажатой кнопки и пина подключения Serial.print("button=");Serial.print(i); Serial.print(" pin - ")/Serial.printIn(pinButtons[i]); } lastButtons[i] = currentButtons[i]; // Функция сглаживания дребезга // Принимает в качестве аргумента предыдущее состояние кнопки, // выдает фактическое. int debounce(int last,int pinl) { int current = digitalRead(pinl); // Считать состояние кнопки
Глава 8. Arduino и последовательный порт UART 147 Рис. 8.1. Монтажная схема подключения шести кнопок button«2 pin - 7 |>utton*4 pin - 9 J3utton-3 pin - 8 button«3 pin - 8 t>utton»0 pxn - 5 butxon=2 pin - 7 button»4 pin - 9 Рис. 8.2. Вывод отладочной информации в монитор последовательного порта
148 Часть III. Сопряжение Arduino со вспомогательными устройствами if (last != current) // если изменилось... { delay(5); // ждем 5 мс current = digitalRead(pinl); // считываем состояние кнопки return current; // возвращаем состояние кнопки Электронный архив Полный вариант рассмотренного скетча находится в папке examples\8\J)BJ)1 сопрово- ждающего книгу электронного архива (см. приложение 2). 8.3. Использование UART для установки параметров При написании скетчей часто используют начальную установку параметров. Но если необходимо внести в скетч изменения, приходится его потом заново компили- ровать и загружать в плату, что не всегда удобно или даже возможно. Поэтому можно предусмотреть интерфейс для установки параметров без необходимости вносить изменения в программу. Один из вариантов — получение параметров про- граммы по последовательному порту и хранение их в памяти EEPROM. Микрокон- троллеры ATmega имеют на борту энергонезависимую память EEPROM, не поте- ряющую записанные в нее данные даже после отключения питания. 512 байтов такой памяти несут ATmega8 и ATmegal68, 1024 байта— ATmega328, 4096 бай- тов — Arduino Mega. Память типа EEPROM допускает несколько десятков тысяч циклов записи и стирания данных. Для работы с этой памятью в составе Arduino IDE имеется удобная библиотека EEPROM. Библиотека содержит две функции: чтения и записи в память данных. Функция eeprom. read считывает байт из энергонезависимой памяти EEPROM. Если байт до этого никогда не перезаписывался — вернет значение 255. Синтаксис функции: EEPROM.read(address) Параметр: address— порядковый номер ячейки памяти для чтения от 0 до 512 (или 1024) (int); Возвращаемое значение — байт, хранимый в ячейке памяти. Функция eeprom.write записывает байт в энергонезависимую память. Синтаксис функции: ЕЕPROM.write(address, value) Параметры: □ address — порядковый номер ячейки памяти для записи — от 0 до 511 (int); □ value — байт для записи — от 0 до 255 (byte). Возвращаемого значения нет.
Глава 8. Arduino и последовательный порт UART 149_ Теперь рассмотрим получение данных платой Arduino по последовательному порту. Мы уже знаем, что функция serial.available о позволяет проверить, можно ли прочитать данные из последовательного порта. Arduino имеет 64-байтовый буфер последовательного порта. Функция вызывается без параметров и возвращает коли- чество доступных для чтения байтов. if (Serial, available ()) { // выполнить, если имеются данные } Итак, напишем скетч — шаблон для получения и установки параметров по после- довательному порту. Данные будем отправлять в формате: <байт начала передачи><параметр>=<значениехбайт конца передачи> Например: *<параметр>=<значение>$ Функция seriaiEvent () вызывается, если в буфере последовательного порта есть какие-либо данные. Побайтно получаемые данные записываем в строку inputstring. При получении байта конца передачи устанавливаем признак конца получаемых данных: stringComplete - true; И начинаем парсинг полученных данных и запись данных для параметра в соответ- ствующие ячейки EEPROM. Для записи числа int необходимо использовать два байта памяти EEPROM: void savejparam2_EEPROM(int addr,int val) { EEPROM.write(addr,highByte(val)); EEPROM.write(addr+1,lowByte(val)); } Содержимое скетча представлено в листинге 8.2. // подключение библиотеки EEPROM tinclude <EEPROM.h> // данные, пришедшие из последовательного порта String inputstring = ""; // строка пришла boolean stringComplete = false; //*** данные от компа // команда int params[]={l,2,3,4,5}; int tekparam;
150 Часть III. Сопряжение Arduino со вспомогательными устройствами // данные int paramsdata[5]={0,0,0,0,0}; int tekparamsdata; // адреса в EEPROM для параметров int addrEEPRGM[]»{0,2,4,6,8}; void setup() { // запуск последовательного порта Serial.begin(9600); // резервирование 30 bytes для inputString: inputString.reserve(30); // загрузка параметров программы из EEPROM void loop () { // проверка прихода строки из последовательного порта if (stringComplete) { Serial.printIn(inputString); // парсинг строки if(parse_string()) { set_param(); // установка параметра } // очистить строку inputString = ""; stringComplete = false; // при наличии данных в буфере последовательного порта void serialEvent() { boolean flagl=false; while (Serial.available() && flagl—false) { // получить байт: char inChar = (char)Serial.read(); // если байт конца передачи if (inChar — f$f) { stringComplete = true; flagl=true; } else // добавить в inputString: inputString += inChar; // парсинг получаемых данных boolean parse_string() {
Глава 8. Arduino и последовательный порт UART 151_ int sl,s2; int lengthl=dnputString.length(); Serial.print("str=");Serial.printIn(inputString); Serial.print("lengthl=")/Serial.printIn(lengthl); if (inputString.charAt(O)!='*') return false; if (inputString.charAt(lengthl-1)!=';') return false; // for (int i=l;i<lengthl;i++) { if (inputString.charAt(i)==';') {sl=i;break;} } tekparam=inputString.substring(1,si).tolnt(); // action for (int i=sl+l;i<lengthl;i++) { if (inputString. charAt (i)==';') {s2=i;break;} } tekparamsdata=inputString.substring(sl+1,s2).tolnt(); Serial, pr int ("tekparam="); Serial, print In (tekparam); Serial.print("tekparamsdata=");Serial.printIn(tekparamsdata); return true; } // установка параметра void set_jparam() •{ if (tekparam>=0 && tekparam<5) { paramsdata [tekparam] =tekparainsdata; save_param2_EEPRC*d(addrEEPR0M[tekparam], tekparamsdata); Serial.println("param set!!!"); } else { Serial.printIn("Wrong param!!!"); // сохранить значения параметра в ЕЕPROM void savejparam2_EEPROM(int addrfint val) { EEPROM.write(addr,highByte(val)); EEPROM.write(addr+1,lowByte(val)); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\8\_08j02 сопрово- ждающего книгу электронного архива (см. приложение 2).
152 Часть III. Сопряжение Arduino со вспомогательными устройствами Загрузим этот скетч в плату Arduino и попробуем отправлять в монитор последова- тельного порта команды установки параметров. При этом в монитор последова- тельного порта выводим и отладочную информацию (рис. 8.3). *2;1342; Btr-*2;1342; lengthl-8 tekparam-2 tekparamadata-1342 param set!!! Рис. 8.З. Отправка параметров из последовательного порта в Arduino 8.4. Библиотека SoftwareSerial Библиотека SoftwareSerial дает возможность реализовать последовательный интер- фейс на любых цифровых выводах Arduino с помощью программных средств, дуб- лирующих функциональность UART (отсюда и название SoftwareSerial). Библиоте- ка позволяет программно создавать несколько последовательных портов, работаю- щих на скорости до 115 200 бод. При использовании нескольких последовательных портов в каждый момент време- ни только один из них может получать данные. На платах Arduino Mega и Arduino Mega2560 некоторые выводы не поддерживают прерывания, возникающие при изменении уровня сигнала. В силу этого, на данных платах в качестве вывода RX могут использоваться только следующие выводы: 10, И, 12, 13, 14, 15, 50, 51, 52, 53, А8 (62), А9 (63), А10 (64), АН (65), А12 (66), А13(67),А14(68),А15(69). На Arduino Leonardo некоторые выводы также не поддерживают прерывания, воз- никающие при изменении уровня сигнала. Так что на этой плате в качестве вывода
Глава 8. Arduino и последовательный порт UART 153 RX могут использоваться только следующие выводы: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). 8.5. Соединение по UART двух плат Arduino Соединим две платы Arduino и установим связь между ними по программному последовательному порту UART. Монтажная схема этого проекта показана на рис. 8.4. Ч^Гда^Ш»^ Рис. 8.4. Монтажная схема соединения двух плат Arduino по программному последовательному порту Загрузим на каждую плату Arduino скетч из листинга 8.3, который поможет нам из монитора последовательного порта Arduino ШЕ отправлять данные в другую плату Arduino, подключим каждую плату по USB к компьютеру и проверим обмен сооб- щениями: на рис. 8.5 показан процесс отправки данных из одной платы Arduino в другую, а на рис. 8.6 — прием этих данных другой платой. // подключение библиотеки SoftwareSerial iinclude <SoftwareSerial.h> // создание экземпляра SoftwareSerial // на RX-8, TX-9 SoftwareSerial mySerial(8, 9); void setup () { // Инициализируем последовательный порт Serial.begin(9600); Serial.printIn("I'm ready!");
154 Часть III. Сопряжение Arduino со вспомогательными устройствами Г'в reedy! Bello, world? Sello, world? tello, world? Sello, world? 388688 3888888 Рис. 8.5. Отправка данных из одной платы Arduino в другую 'ml-я ready! '-^ Ш Рис. 8.6. Прием платой Arduino данных, посланных в нее из другой платы
Глава 8. Arduino и последовательный порт UART 155 II устанавливаем скорость передачи данных // для последовательного порта, созданного // библиотекой SoftwareSerial mySerial.begin(9600); mySerial.println("Hello, world?"); void loopO { // получаем по Software - отправляем в монитор if (mySerial.available()) Serial.write(mySerial.read()); // пишем в монитор (аппаратный) - отправляем по Software if (Serial.available()) mySerial.write(Serial.read()); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\8\__08_03 сопрово- ждающего книгу электронного архива (см. приложение 2).
ГЛАВА 9 Подключение датчиков к плате Arduino Датчик, или сенсор, — это устройство, с помощью которого мы измеряем значение какого-либо технологического параметра. Датчики позволяют определять, что про- исходит во внешней среде, и действовать на основе этой* информации. Датчики, наверное, можно назвать органами чувств системы. Любой датчик состоит из чувствительного элемента и преобразовательной системы, выполняющей преобра- зование входного воздействия любой физической величины в сигнал, удобный для дальнейшего использования. 9.1. Подключение аналоговых датчиков Самый простой тип датчиков — аналоговые датчики. Это первичные преобразова- тели. Такой тип датчиков применяется в системах непрерывного измерения и регу- лирования. Принцип действия аналоговых датчиков состоит в том, что при измене- нии измеряемого параметра происходит соответствующее изменение его выходно- го сигнала. Выходное напряжение может принимать значения от О В до напряжения питания, хотя обычно рабочий диапазон напряжений более узкий. Примеры датчиков: □ акселерометры — для обнаружения наклона (используются в смартфонах и планшетах); □ магнитометры — для обнаружения магнитных полей (используются при созда- нии цифровых компасов); □ инфракрасные датчики — для определения расстояния до объекта; □ датчики температуры — для определения температуры; П фоторезисторы — для измерения освещенности. Между измеряемой датчиком величиной и возвращаемым напряжением устанавли- вается определенная зависимость. Например, чем больше величина, тем больше напряжение, или наоборот, чем больше величина, тем напряжение меньше.
158 Часть III. Сопряжение Arduino со вспомогательными устройствами 9.1.1. Подключение к плате Arduino аналогового датчика температуры LM335 Рассмотрим работу с аналоговыми датчиками температуры на примере датчика LM335 — недорогого температурного чувствительного элемента с диапазоном от -40 до +100 °С и точностью в 1 °С (рис. 9.1). По принципу действия датчик LM335 представляет собой стабилитрон, у которого напряжение стабилизации зависит от температуры. При повышении температуры на один градус Кельвина напряжение стабилизации увеличивается на 10 милливольт. Типовая схема включения (соответ- ствует типовой схеме включения стабилитрона) показана на рис. 9.2. '—V~ (GND) ADJ Рис. 9.1. Датчик температуры LM335 Output Рис. 9.2. Типовая схема включения датчика LM335 При взгляде на эту схему сразу можно спросить, каково же сопротивление резисто- ра R1 и какое напряжение питания должно быть при такой схеме включения? Ответ содержится в технической документации (Data Sheet), где сказано, что нормальная работа изделия гарантируется в диапазоне токов 0,45...5,00 миллиампер при сопро- тивлении резистора R1 — 2,2 кОм. Следует заметить, что предел в 5 мА превышать не следует, поскольку датчик будет перегреваться и измерять при этом собствен- ную температуру. Электронный архив Техническая документация производителей (Data Sheet) практически на все компо- ненты и устройства, задействованные в проектах этой книги, находится в каталоге datasheets сопровождающего книгу электронного архива (см. приложение 2). Согласно документации датчик проградуирован по абсолютной шкале Кельвина. При температуре -273,15 °С, а это абсолютный ноль по Кельвину, рассматривае- мый датчик должен показать нулевое напряжение. При увеличении температуры на каждый градус выходное напряжение стабилитрона будет возрастать на целых 10 мВ, или на 0,010 В. Температура 25 °С — единственная точка калибровки сенсора. При этой темпера- туре на выходе датчика должно быть: 298,15 х 0,010 = 2,9815 В. Для калибровки датчика используется схема, представленная на рис. 9.3.
Глава 9. Подключение датчиков к плате Arduino 159 4km ВыходЮмВА Рис. 9.3. Схема калибровки датчика LM335 Итак, подключаем датчик температуры LM335 по схеме, представленной на рис. 9.4, и пишем скетч (листинг 9.1) считывания данных с датчика и вывода пока- заний в последовательный порт (рис. 9.5). int lm335=0; // подключение датчика к аналоговому входу АО void setup () { Serial, begin (9600); } void loop () { double val = analogRead(lm335); // чтение double voltage = val*5.0/1024; // перевод в значение в вольтах double temp = voltage*100 - 273.15; // в градусы Цельсия Serial. print (" temp = ") ; Serial, print In (temp); delay (1000); I Рис. 9.4. Монтажная схема подключения датчика LM335 к плате Arduino
160 Часть III. Сопряжение Arduino со вспомогательными устройствами tel7 temp te«p te«p temp temp temp . temp temp ttip temp temp temp temp tenp teup - temp temp . temp > temp • temp tenp > teip • tenp > temp • temp . temp • temp ■ tmp ■ temp . . 25 68 • 26.17 ■ 25.68 > 25.68 ■ 25.68 • 26.17 • 25.68 ' 25.68 - 25.68 - 25.68 - 25.19 - 26.17 . 26 65 ■ 27.14 • 26.65 • 27.63 • 28.12 • 28.61 • 29.10 - 30.07 - 31.05 . 30.07 • 29.10 •28.61 • 28.12 • 27.63 . 27.14 . 26.65 - 26.17 Рис. 9.5. Вывод результатов измерения данных датчиком LM335 в монитор последовательного порта Электронный архив Полный вариант рассмотренного скетча находится в папке examples\9\_09_01 сопрово- ждающего книгу электронного архива (см. приложение 2). 9.2. Подключение датчиков по протоколу 1-Wire Интерфейс 1-Wire разработан фирмой Dallas Semiconductor (ныне MAXIM) в конце 1990-х годов. Этот интерфейс интересен тем, что для двустороннего обмена требу- ется всего одна линия. Правда, еще понадобится общий провод («земля») и провод питания (не всегда). Причем, на эту одну линию можно «повесить» несколько устройств. Протокол очень прост и легко реализуется на микроконтроллере про- граммно. Для взаимодействия Arduino с устройствами 1-Wire необходимо установить биб- лиотеку OneWire. Электронный архив Библиотека OneWire размещена в каталоге libraries сопровождающего книгу электрон ного архива (см. приложение 2).
Глава 9. Подключение датчиков к плате Arduino 161 9.2.1. Подключение к плате Arduino цифрового датчика температуры DS18B20 Рассмотрим подключение к Arduino цифровых датчиков температуры DS18B20, работающих по протоколу 1-Wire. DS18B20 (рис. 9.6) — цифровой термометр с программируемым разрешением от 9 до 12 битов, которое может сохраняться в памяти EEPROM прибора. DS18B20 об- менивается данными по шине 1-Wire и при этом может быть как единственным устройством на линии, так и работать в группе. Все процессы на шине управляются центральным микропроцессором. (BOTTOM VIEW) TD-92 (DS18B20) Рис. 9.6. Датчик DS18B20 Диапазон измерений датчика: от -55 до +125 °С и точностью 0,5 °С в диапазоне от-10 до +85 °С. Датчик может запитываться двумя способами: внешним питани- ем (три провода) или паразитным (питание от шины, 2 провода). Монтажная схема подключения нескольких (в нашем случае — двух) датчиков температуры DS18B20 от внешнего питания к Arduino представлена на рис. 9.7. Каждый датчик типа DS18B20 имеет уникальный 64-битный последовательный код, который позволяет общаться с множеством датчиков DS18B20, установленных на одной шине. Первые 8 битов — код серии (для DS18B20 — 28h), затем 48 битов уникального номера и в конце 8 битов CRC-кода. Такой принцип позволяет ис- пользовать один микропроцессор, чтобы контролировать множество датчиков DS18B20, распределенных по большому участку. Скетч для получения датчиков DS18B20, подключенных к шине 1-Wire, и вывода их уникальных идентификаторов в последовательный порт представлен в листин- ге 9.2.
162 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 9.7. Монтажная схема подключения нескольких датчиков DS18B20 к плате Arduino // Подключение библиотеки OneWire #include <OneWire.h> // пин подключения датчиков OneWire ds(8); void setup(void) { // запуск последовательного порта Serial, begin (9600),- void loop (void) { byte i; byte type_s; byte addr[8]; // поиск устройств if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.println(); ds.reset_search(); delay(250); return;
Глава 9. Подключение датчиков к плате Arduino 163 II вывод уникального номера Serial.print("ROM ="); for( i = 0; i < 8; i++) { Serial.write(f f); Serial.print(addr[i], HEX); if (OneWire::crc8(addr, 7) !=addr[7]) { Serial.println("CRC is not valid!"); return; } Serial.println(); // определение типа датчика switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); type_s = 1; break; case 0x28: Serial.printIn(" Chip = DS18B20"); type_s =0; break; case 0x22: Serial.println(" Chip = DS1822"); type_s = 0; break; default: Serial.println("Device is not a DS18x20 family device."); return; Электронный архив Полный вариант рассмотренного скетча находится в папке examples\9\J)9J)2 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем этот скетч в плату Arduino, запускаем монитор последовательного порта и наблюдаем вывод в последовательный порт данных уникального идентификатора для каждого датчика (рис. 9.8). Данные о температуре хранятся в оперативной памяти датчика (рис. 9.9). Память состоит из оперативной ROM и энергонезависимой EEPROM: □ первые два байта содержат данные об измеренной температуре; □ третий и четвертый байты хранят верхний (тн) и нижний (tl) пределы темпера- туры; 0 пятый и шестой — не используются;
164 Часть III. Сопряжение Arduino со вспомогательными устройствами П седьмой и восьмой— байты-счетчики. Они могут использоваться для более точного измерения температуры; □ девятый байт хранит CRC-код предыдущих восьми. Chip - DS18B20 ЭДН - 28 FF 17 8Е 73 16 S SB Chip - DS18B2Q Чо more addresses. *0М - 28 ЕЗ 4 €7 5 0 0 52 Chip - DS18B20 ROM * 28 FF 17 8Е 73 16 5 DB Chip - DS18B20 So more addresses. ROM - 28 E3 4 6? S 0 0 52 Chip - DS18B2Q ЯОМ - 28 FF 17 8E 73 16 5 Chip - DS18B20 Яо логе addresses. ROM » 28 E3 4 67 5 0 0 52 Chip - DS18B20 1 датчик 2 датчик Рис. 9.8. Вывод идентификаторов двух датчиков DS18B20 в монитор последовательного порта SCRATCHPAD (Power-up State) Temperature LSB (50h) 1 Temperature MSB (05h) J TH Register or User Byte 1 * TL Register or User Byte 2* Configuration Register* Reserved (FFh) Reserved (ОСЬ) Reserved (lOh) CRC* EEPROM 4 to / ^| _^ Th Register or User Byte t TL Register or User Byte 2 Configuration Register byteO bytel byte 2 byte3 byte 4 byte 5 byte 6 byte? byte 8 'Состояние после включения питания зависит от значений, сохраненного в EEPROM Рис. 9.9. Карта памяти датчика DS18B20 Последовательность команд для получения от датчика данных о температуре должна быть такой: 1. Произвести reset и поиск устройств на линии 1-Wire. 2. Выдать команду 0x44, чтобы запустить конвертацию температуры датчиком.
Глава 9. Подключение датчиков к плате Arduino 165 3. Подождать не менее 750 мс. 4. Выдать команду Охве, чтобы считать ОЗУ датчика (данные о температуре будут в первых двух байтах). Скетч получения данных с датчиков температуры DS18B20 и вывода данных в по- следовательный порт представлен в листинге 9.3. // Подключение библиотеки OneWire iinclude <OneWire.h> // пин подключения датчиков OneWire ds(8); void setup (void) { // запуск последовательного порта Serial.begin(9600); void loop (void) { byte i; byte present =0; byte type_s; byte data[12] ; byte addr[8]; float temperature; // поиск устройств if ( Ids.search(addr)) { Serial.println("No more addresses."); Serial.println(); ds.reset_search(); delay(250); return; // вывод уникального номера . Serial.print("ROM ="); for( i = 0; i < 8; i++) { Serial.write(f f); Serial.print(addr[i], HEX); if (OneWire::crc8(addr, 7) !=addr[7]) { Serial.println("CRC is not valid!"); return;
166 Часть IIL Сопряжение Arduino со вспомогательными устройствами Serial.println(); // определение типа датчика switch (addr[0]) { case 0x10: Serial.printIn(" Chip = DS18S20"); type_s = 1; break; case 0x28: Serial.printIn(" Chip = DS18B20"); type_s = 0; break; case 0x22: Serial.printIn(" Chip - DS1822"); type_s =0; break; default: Serial.println("Device is not a DS18x20 family device."); return; } // сброс шины ds.reset(); // выставление адреса (уникального номера) ds.select(addr); // инициализация измерения ds.write(0x44, 1); // пауза > 750 мс delay(1000); // сброс шины present = ds.reset(); // выставление адреса (уникального номера) ds.select(addr); // команда чтения памяти датчика ds.write(OxBE); Serial.print(" Data « "); Serial.print(present, HEX);• Serial.print(" "); // чтение памяти датчика, 9 байт for ( i = 0; i < 9; i++) { data[i] = ds.readO; Serial.print(data[i], HEX); Serial.print(" "); } Serial.print(" CRC="); Serial.print(OneWire::crc8(data, 8), HEX); Serial.println();
Глава 9. Подключение датчиков к плате Arduino 167 II перевод данных в значение температуры temperature= (float) ((int)data[0] | (((int)data[l]) «8)) * 0.0625 + 0.03125; Serial.print(" Temperature = "); Serial.printIn(temperature); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\9\_09J)3 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем этот скетч в плату Arduino, запускаем монитор последовательного порта и наблюдаем вывод показаний датчиков температуры DS18B20 в последователь- ный порт (рис. 9.10). Chip - DS18B20 Data - 1 48 1 4В 46 7F FF 8 10 AD CRO-AD Temperature > 20.S3 tOM - 28 FF 17 8E 73 16 5 DB Chip - DS13E20 Data - 1 4B 1 4B 46 7F FF С 10 CO CROC0 Temperature « 20.84 lo more addresses. »OM - 28 В 4 67 5 0 S 52 Chip - D518B2G Data - 1 48 1 4B 46 7F FF 8 10 AD CRC=AD !.». 2Q.53 HSIVII: КОИ - 28 FF 17 8E 73 16 5 SB . Chip « DS18B20 Data - 1 4C 1 4B 46 7F FF С 10 83 CRO83 Тедрегашге « 20.78 1 датчик lo more addresses. ION ' 28 E3 4 67 5 0 Q 52 Chip - DS18B2O Data - 1 48 1 4B 46 7F FF 8 10 AD CRC«=AD Teaperature = 20.53 ЮН - 28 FF 17 8E 73 16 5 DB Chip - DS18B20 2 датчик Рис. 9.10. Вывод показаний датчиков температуры DS18B20 в монитор последовательного порта 9.3. Подключение датчиков влажности и температуры DHT Датчики DHT11 и DHT22 (рис. 9.11) состоят из емкостного датчика влажности и термистора. Кроме того, датчики содержат чип, который преобразует аналоговый сигнал в цифровой. В процессе производства компоненты, входящие в модули DHT, могут получать разные параметры, и чтобы показания датчиков были пра- вильными, производитель калибрует каждый датчик DHT в калибровочной камере,
168 Часть III. Сопряжение Arduino со вспомогательными устройствами а поправочный коэффициент сохраняется в памяти и вызывается при считывании данных. Общие характеристики датчиков: □ DHT11: • очень низкая стоимость; • питание и I/O: 3-5 В; • определение влажности 20—80% с точностью 5%; • определение температуры 0...50 °С с точностью 2%; • частота опроса не более 1 Гц (не более одного раза в 1 сек.); • размеры 15,5x12x5,5 мм; □ DHT22: • низкая стоимость; • питание и I/O: 3-5 В; • определение влажности 0-100% с точностью 2-5%; • определение температуры —40...+125 °С с точностью ±0,5 °С; • частота опроса не бояее 0,5 Гц (не более одного раза в 2 сек.); • размеры 15,1x25x7,7 мм. Сенсор DHT22 имеет лучшие, чем у DHT11, характеристики, но более высокую стоимость. DHT11 DHT22 Рис. 9.11. Датчики DHT11 (слева) и DHT22 (справа) Преимущество этих датчиков— небольшие размеры, низкое энергопотребление, высокая дальность передачи (до 20 м), к недостаткам можно отнести относительно невысокую точность измерений. Датчики имеют 4 вывода стандарта 2,54 мм: □ 1—VCC (питание 3-5 В); □ 2 — DATA (вывод данных); □ 3 — не используется; □ 4 — GND («земля»).
Глава 9. Подключение датчиков к плате Arduino 169^ Протокол обмена — однопроводный, по структуре весьма похож на протокол дат- чиков DS18B20, но с отличиями: □ DHT не умеет работать в «паразитном» режиме (при питании по линии данных); □ каждый DS18B20 имеет персональный идентификатор, что дает возможность подключения нескольких таких датчиков к одному контакту (пину) Arduino. Однако у DHT такой возможности нет — один датчик будет использовать строго один цифровой пин. Чтобы начать получать данные с датчика, микроконтроллер должен отправить дат- чику запрос и дождаться от него ответа, что датчик готов передавать информацию. Происходит это следующим образом. Когда микроконтроллер собрался принимать данные, он должен притянуть линию данных к нулю на 18 мс, после чего отпустить ее обратно к 1. При этом микроконтроллер переходит в режим ожидания и следит за тем, что происходит с линией данных. Через 20-40 мкс, если все в порядке, дат- чик отвечает притягиванием уже со своей стороны линии данных к нулю на 80 мкс и отпускает ее на 80 мкс. Таким образом датчик дает понять микроконтроллеру, что с ним все в порядке, и он начинает передачу данных. Данные передаются побитно. Перед передачей каждого нового бита датчик притягивает линию данных к нулю на 50 мкс, после чего отпускает ее к 1. В зависимости от того, на сколько микросекунд датчик отпускает линию к 1, микроконтроллер распознает, какой бит был передан: если длительность временного промежутка до следующего притягивания к нулю 26-28 мкс, то передан 0, если 70 мкс — передана 1. Количество передаваемой информации— 40 битов (5 байтов). Первый и второй байты содержат целую и дробную часть информации о влажности, третий и четвер- тый байты содержат целую и дробную часть информации о температуре, пятый байт — контрольная сумма, которая представляет собой последние 8 битов от сло- жения предыдущих 4 байтов. После передачи пакета данных датчик переходит в спящий режим до следующего запроса со стороны микроконтроллера. Монтажная схема подключения датчика DHT22 к плате Arduino показана на рис. 9.12. Для считывания данных датчика DTH22 с помощью Arduino существует готовая библиотека DHT, которую необходимо импортировать в Arduino IDE. Электронный архив Библиотека DHT размещена в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2). Итак, загружаем на плату Arduino скетч получения данных с датчика DHT22 и вы- вода их в последовательный порт Arduino (листинг 9.4), запускаем монитор после- довательного порта и наблюдаем вывод в него значений влажности и температуры (рис. 9.13).
170 Часть III. Сопряжение Arduino со вспомогательными устройствам Рис. 9.12. Монтажная схема подключения датчика DHT22 к плате Arduino Huaidity-39 Hunidity-38 Hunu.dlty-38 Runddity-38 Tenperetare-19 Ruzaidity=38 Humidity=3S Himidity»38 Humidity»38 T«a«perature-19 га taxe«l 9 l 9 Рис. 9.13. Вывод данных влажности и температуры с датчика DHT22
Глава 9. Подключение датчиков к плате Arduino 171 II подключение библиотеки DTH iinclude "DHT.h" // пин подключения контакта DATA fdefine DHTPIN 10 // тип датчика - DHT 22 idefine DHTTYPE DHT22 // создание экземпляра объекта DHT DHT dht(DHTPIN, DHTTYPE); void setup () { // запуск последовательного порта Serial.begin(9600); // запуск DHT dht.beginO; void loopO { // получение данных с датчика int h = dht.readHumidity(); int t = dht.readTemperature(); Serial.print("Humidity="); Serial.print(h); Serial. print (" Temperature="); Serial, print In (t); // пауза (измерения не чаще раза в 2 секунды) delay(2000); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\9\J)9J)4 сопрово- ждающего книгу электронного архива (см. приложение 2). 9.4. Подключение датчиков по протоколу 12С Последовательный протокол обмена данными 12С использует для передачи данных две двунаправленные линии связи: 0 SDA (Serial Data) — шина последовательных данных; □ SCL (Serial Clock) — шина тактирования (синхронизации). Задействуются также две линии для питания. Шины SDA и SCL подтягиваются к шине питания через резисторы. При работе по протоколу 12С в сети должно присутствовать хотя бы одно ведущее устройство (master), которое инициализирует передачу данных и генерирует сиг-
172 Часть III. Сопряжение Arduino со вспомогательными устройствами налы синхронизации, а также ведомые устройства (slave), которые передают дан ные по запросу ведущего. У каждого ведомого устройства есть уникальный адрес, по которому ведущий и обращается к нему. К одной шине 12С может быть подклю чено до 127 устройств, в том числе несколько ведущих. Arduino использует для работы по интерфейсу 12С два контакта. Каждая версия Arduino имеет свои выводы 12С (табл. 9.1). Таблица 9.1. Контакты 12С для разных плат Arduino Плата Arduino Arduino Uno, Nano Arduino Mega Arduino Leonardo Arduino Due Вывод SDA 4 20 2 20 Вывод SCL 5 21 3 21 Для обмена данными с устройствами по шине 12С в Arduino есть стандартная биб- лиотека Wire. Подключим к плате Arduino несколько датчиков, работающих по протоколу 12С, и загрузим в плату Arduino скетч поиска устройств, подключенных к шине 12С (листинг 9.5). Этот скетч сканирует шину 12С и выводит в последовательный порт Arduino таблицу с адресами подключенных устройств. #include "Wire.h" void setup() { Wire.begin(); Serial.begin(9600); // запуск последовательного порта void loop () { int devices; byte err, add; Serial.println("Start scan I2C bus:.."); devices = 0; Serial.print(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E OF"), for(add = 0; addr<= 127; addr++ ) { if((addr% 0x10) == 0) { Serial.println(); if(addr< 16) Serial.print(f0f) ; Serial.print(addr, 16); Serial.print(" ") ;
Глава 9. Подключение датчиков к плате Arduino 173 Wire.beginTransmission(addr);err = Wire.endTransmissionO; if (err ==0) { if (addr<16) Serial.print("0"); Serial.print(addr, HEX); devices++; } else { Serial-, print ("—") ; } Serial.print(" "); delay(1); } Serial.println(); if (nDevices == 0) Serial.println ("No I2C devices foundW); delay(2500); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\9\_09_05 сопрово- ждающего книгу электронного архива (см. приложение 2). 9.4.1. Подключение к плате Arduino датчика интенсивности света ВН1750 Рассмотрим подключение к плате Arduino датчика интенсивности света — модуля GY-302 на базе микросхемы ВН1750 (рис. 9.14), работающего по протоколу 12С. Рис. 9.14. Модуль GY-302 на базе микросхемы ВН1750
174 Часть III. Сопряжение Arduino со вспомогательными устройствами Измерение освещенности является важным параметром при создании приложений домашней автоматики. Освещенность измеряют в люксах (1х). Люкс равен осве- щенности поверхности площадью 1 м2 при световом потоке падающего на нее из- лучения, равном 1 люмену (лм). Модуль GY-302 на базе чипа ВН1750 представляет собой высокоточный цифровой датчик интенсивности света, выдающий значение в люксах. Модуль имеет 5 выводов: □ VCC — питание 5 В; □ GND — «земля»; □ SDA — данные 12С; □ SCL— синхронизация 12С; □ ADDR — выбор адреса для протокола 12С. Разберемся с возможными адресами датчика ВН1750. Существуют два варианта подключения датчика ВН1750 к шине 12С (рис. 9.15). Рис. 9.15. Монтажные схемы подключения датчика ВН1750 к Arduino Загруженный на плату Arduino скетч из листинга 9.5 будет сканировать шину 12С и выводить в последовательный порт Arduino адрес подключенного устройства. Как видим, (рис. 9.16), модуль ВН1750 может иметь — в зависимости от уровня сигна- ла на входе ADDR— два адреса (0x23 и 0х5с). Это значит, что к одной плате Arduino можно подсоединить одновременно два датчика ВН1750. Для работы Arduino с датчиками ВН1750 написано несколько библиотек, мы здесь воспользуемся одной из них— BH1750FVI (ее можно скачать по ссылке: https://github.com/enjoyneering/BH1750FVI). Эта библиотека поддерживает все режимы датчика ВН1750, позволяет производить измерения освещенности с не- сколькими параметрами чувствительности (0,45-3,68) и разрешающей способности
Глава 9. Подключение датчиков к плате Arduino 175 50 60 70 Found I device(s) Scanning I2C bus... 00 01 02 03 04 05 06 07 08 09 OA OB ОС 00 OE OF 00 io 20 2 зо 40 5G 60 - 70 Found 1 device(s) Scanning I2C bus... 00 01 02 03 04 05 06 07 08 09 OA OB ОС 00 OE OF 00 10 20 30 40 50 80 70 Found 1 device(s) ADDR=LOW ADDR=HIGH Рис. 9.16. Адреса датчика ВН1750 "EMO: ight EMG: ight ЕМО: ight Sensitivity - 3.68, Auto Power Down Sensitivity - 3.68, j level: 55.74 +-1.Q 1; Sensitivity - 0.45, Auto Power Down level: 52.08 +-Q.5 lx Sensitivity - 1.0, Auto Power Down level: 54.OG +-0.5 lx EMO: Starts over again in 8 sec. EMO: ight 'over OK): EMO: ight EMO: ight IEMO: .ight EMO: .ight )EMO: .ight Sensitivity - l.o. Continuous Mode (default settings) level: 51.60 +-0.5 lx for 555пш wave: 0.08 Watt/mA2 Manual Power Down Sensitivity - 2.0, Continuous Mode level: 53.7G +-0.5 lx Sensitivity - Q.5, Continuous Mode level: 52.05 +-0.5 lx Sensitivity - 3.68, Auto Power Down level: 54.11 +-1.0 lx Sensitivity - 0.45, Auto Power Down level: 50.75 +-0.5 lx Sensitivity - 1.0, Auto Power Down level: 52.20 +-0.5 lx Starts over again m 8 sec. Рис. 9.17. Пример вывода данных с датчика ВН1750 в монитор последовательного порта Arduino при различных режимах измерения
176 Часть III. Сопряжение Arduino со вспомогательными устройствами (0,5-4 1х), а также в режиме энергосбережения. К библиотеке прилагается пример (BH1750FVIJDemo) вывода в последовательный порт Arduino данных с датчика ВН1750 при различных режимах измерения (рис. 9.17). Электронный архив Библиотека BH1750FVI размещена в каталоге libraries сопровождающего книгу элек- тронного архива (см. приложение 2). В следующих главах мы рассмотрим и другие датчики* работающие по прото- колу 12С.
ГЛАВА 10 Использование дисплеев в проектах Arduino Данные, получаемые с датчиков, в предыдущей главе мы выводили в монитор последовательного порта Arduino. Смотреть на показания датчиков через последо- вательный порт не всегда приемлемо — и нам необходимы более удобные устрой- ства для отображения данных. Электронные устройства, предназначенные для визуального отображения цифровой, цифро-буквенной или графической информа- ции, называются дисплеями. Й в этой главе мы рассмотрим работу Arduino с раз- личными дисплеями. 10.1. Символьные дисплеи на микроконтроллере HD44780 Жидкокристаллические (ЖК) дисплеи на основе микроконтроллера HD44780 наи- более часто используются в проектах Arduino. Такой дисплей представляет собой модуль, состоящий из микроконтроллера HD44780 и непосредственно самого ЖК-дисплея. Микроконтроллер принимает команды и отрисовывает на ЖК-дис-' плее соответствующие символы. Существует огромное количество разновидностей таких ЖК-модулей: они могут содержать 1, 2 или 4 строки с различным числом символов на строке, быть с под- светкой или без оной, а также с различным цветом подсветки. Объединяет их всех наличие контроллера HD44780, знание команд которого позволит без проблем использовать в своих проектах ту или иную модификацию этого модуля. ЖК-дисплеи Winstar WH1602 (рис. 10.1) на контроллере HD44780 имеют 16 выво- дов, назначение которых представлено в табл. 10.1. Таблица 10.1. Назначение выводов дисплея WH1602 № вывода 1 3 Название Vss Vdd Vo Функция Общий (GND) Напряжение питания (3 или 5 В) Контрастность
178 Часть III. Сопряжение Arduino со вспомогательными устройствами Таблица 10.1 (окончание) № вывода 4 5 6 7 8 9 10 11 12 13 14 15 16 Название RS R/W Е DB0 DB1 DB2 Функция Команды/Данные Чтение/Запись Разрешение чтения/записи Линия данных 0 Линия данных 1 Линия данных 2 DB3 Линия данных 3 DB4 DB5 DB6 DB7 LED+ LED- Линия данных 4 Линия данных 5 Линия данных 6 Линия данных 7 Напряжение подсветки (+) Напряжение подсветки (-) Рис. 10.1. Выводы ЖК-дисплея Winstar WH1602 Для начала рассмотрим подачу питания, настройку контрастности и подсветку (рис. 10.2). Для питания ЖК-дисплея Winstar необходим внешний источник питания 4,5-5,5 В. Выводы LED+ и LED- служат для включения подсветки. Необходимо подключить к подсветке питание, задав номинальный ток с помощью внешнего резистора R. Номинальное напряжение на аноде должно составлять 3,5 В, а ток — 40 мА. Исхо- дя из этого, номинал токоограничивающего резистора: R = (5-3,5)/0,04 = 37Om Для настройки контрастности используется делитель напряжения— в схеме на рис. 10.2 это потенциометр номиналом 10-20 кОм. Перед выводом данных на индикатор необходимо убедиться, что управляющее контрастностью напряжение
Глава 10. Использование дисплеев в проектах Arduino 179 + 5В Рис. 10.2. Схема соединений для питания, настройки контрастности и подсветки ЖК-дисплея Winstar WH1602 находится в рабочем диапазоне. Для этого с помощью потенциометра добейтесь, чтобы верхний ряд символов заполнился темными прямоугольниками. Если после подачи питания верхний ряд символов заполнился темными прямо- угольниками, можно приступать к подключению ЖК-дисплея к плате Arduino. Для управления ЖК-дисплеем необходимо 6 или 10 выводов микроконтроллера HD44780 — в зависимости от того, выбран 4- или 8-битный режим обмена данны- ми. Для сокращения требуемого числа выводов микроконтроллера HD44780 можно работать и в 4-битном режиме. В этом случае на его выводы DB4-DB7 сначала будут передаваться старшие четыре бита данных/команды, а затем — младшие че- тыре бита. Выводы DB0-DB3 останутся незадействованными. Монтажная схема подключения ЖК-дисплея к плате Arduino представлена на рис. 10.3. Дня работы с ЖК-дисплеями на контроллере HD44780 в Arduino IDE имеется встроенная библиотека LiquidCrystal. Чтобы с ней работать, необходимо ее под- ключить: ^include <LiquidCrystal.h> И СОЗДать экземпляр объекта LiquidCrystal: LiquidCrystal led(5, 7, 8, 9, 10, 11); Объект типа LiquidCrystal при создании имеет следующие параметры: □ пин подключения контакта RS (12); □ пин подключения контакта Е (11); П пин подключения контакта D4 (5); □ пин подключения контакта D5 (4); О пин подключения контакта D6 (3); □ пин подключения контакта D7 (2).
180 Часть III. Сопряжение Arduino со вспомогательными устройствами + 5В Рис. 10.3. Монтажная схема подключения ЖК-дисплея Winstar WH1602 к плате Arduino Библиотека LiquidCrystal содержит много примеров, позволяющих разобраться в ее работе. Кратко познакомимся с функциями этой библиотеки. 10.1.1. Функция beginf) Синтаксис функции: led.begin(cols, rows) Функция определяет размерность индикатора (количество символов в ширину и высоту). Параметры: □ led — Переменная ТИПа LiquidCrystal; □ cols — количество символов в строке; G rows — количество строк. 10.1.2. Функция clearQ Синтаксис функции: led. clear ()
Глава 10. Использование дисплеев в проектах Arduino 181_ Функция очищает экран жидкокристаллического индикатора и располагает курсор в верхнем левом углу. Параметр: led — переменная типа LiquidCrystai. 10.1.3. Функция homeQ Синтаксис функции: led.home () Функция располагает курсор в верхнем левом углу жидкокристаллического инди- катора. Используется для определения начального положения при выводе последо- вательного текста на экран индикатора. Чтобы еще и очистить экран индикатора, используйте вместо этой функции функцию clear (). Параметр: led — переменная типа LiquidCrystai. 10.1.4. Функция setCursorQ Синтаксис функции: lcd.setCursor (col, row) Функция позиционирует курсор жидкокристаллического индикатора, т. е. устанав- ливает положение, в котором на его экран будет выведен последующий текст. Параметры: □. led — переменная типа LiquidCrystai; □ col — номер знакоместа в ряду (начиная с 0 для первого знакоместа); □ row — номер ряда (начиная с 0 для первого ряда). 10.1.5. Функция writeQ Синтаксис функции: led.write (data) Функция записывает символ в жидкокристаллический индикатор. Параметры: Я led — переменная типа LiquidCrystai; О data — символ, записываемый в индикатор. 10.1.6. Функция printQ Синтаксис функции print (): led.print (data) led.print (data, BASE) Функция печатает текст на жидкокристаллическом индикаторе.
182 Часть III. Сопряжение Arduino со вспомогательными устройствами Параметры: □ led — переменная ТИПа LiquidCrystai; □ data — данные ДЛЯ печати (ТИП char, byte, int, long ИЛИ string); □ base (опционально) — основание, по которому печатаются числа: bin для дво- ичных (основание 2), dec для десятичных (основание 10), ост для восьмеричных (основание 8), hex для шестнадцатеричных (основание 16). 10.1.7. Функция cursorQ Синтаксис функции: led.cursor() Функция выводит на экран жидкокристаллического индикатора курсор — подчер- кивание знакоместа в позиции, в которую будет записан следующий символ. Параметр: led — переменная типа LiquidCrystai. 10.1.8. Функция noCursorQ Синтаксис функции: lcd.noCursor() Функция скрывает курсор с экрана жидкокристаллического индикатора. Параметр: led — переменная типа LiquidCrystai. 10.1.9. Функция blinkQ Синтаксис функции: led.blink() Функция выводит на экран жидкокристаллического индикатора мигающий курсор. Если она используется в комбинации с функцией cursor (), результат будет зави- сеть от конкретного индикатора. Параметр: led —т- переменная ТИПа LiquidCrystai. 10.1.10. Функция noBlinkQ Синтаксис функции: lcd.noBlink{) Функция выключает мигающий курсор на экране жидкокристаллического индика- тора. Параметр: led — переменная ТИПа LiquidCrystai.
Глава 10. Использование дисплеев в проектах Arduino 183_ 10.1.11. Функция displayQ Синтаксис функции: led. display () Функция включает жидкокристаллический индикатор после того, как он был выключен функцией noDispiayO. Эта функция восстанавливает текст (и курсор), который был на дисплее. Параметр: led — переменная типа LiquidCrystai. 10.1.12. Функция noDisplay() Синтаксис функции: lcd.noDisplay () Функция выключает жидкокристаллический индикатор без потери отображаемой на нем информации. Параметр: led — переменная типа LiquidCrystai. 10.1.13. Функция scrollDisplayLeftQ Синтаксис функции: led.scrollDisplayLeft() Функция прокручивает информацию на экране индикатора (текст и курсор) на одно знакоместо влево. Параметр: led — переменная типа LiquidCrystai. 10.1.14. Функция scrollDisplayRightQ Синтаксис функции: led.scrollDisplayRight() Функция прокручивает информацию на экране индикатора (текст и курсор) на одно знакоместо вправо. Параметр: led — переменная типа LiquidCrystai. 10.1.15. Функция autoscrollQ Синтаксис функции: lcd.autoscroll() Функция включает автоматическую прокрутку экрана жидкокристаллического ин- дикатора и заставляет каждый вывод символа на экран индикатора перемещать предыдущие символы на одно знакоместо. Если текущее направление вывода сим- волов слева направо (значение по умолчанию) — экран индикатора прокручивается
184 Часть III. Сопряжение Arduino со вспомогательными устройствами влево, если текущее направление вывода символов справа налево — экран индика- тора прокручивается вправо. Это производит на экране жидкокристаллического индикатора эффект вывода каждого нового символа в одно и то же знакоместо. Параметр: led — переменная типа LiquidCrystai. 10.1.16. Функция noAutoscrollQ Синтаксис функции: lcd.noAutoscroll () Функция выключает автоматическую прокрутку экрана жидкокристаллического индикатора. Параметр: led — переменная типа LiquidCrystai. 10.1.17. Функция leftToRightQ СиНТаКСИС фуНКЦИИ leftToRight () : lcd.leftTorRightO Функция устанавливает направление вывода символов на экран жидкокристалличе- ского индикатора слева направо (значение по умолчанию). Это означает, что последующие символы, выводимые на экран индикатора, пойдут слева направо, но не повлияют на выведенный ранее текст. Параметр: led — переменная типа LiquidCrystai. 10.1.18. Функция rightToLeftf) Синтаксис функции: lcd.rightToLeft () Функция устанавливает направление вывода символов на экран жидкокристалличе- ского индикатора справа налево (значение по умолчанию — слева направо). Это означает, что последующие символы, выводимые на экран индикатора, пойдут справа налево, но не повлияют на выведенный ранее текст. Параметр: led — переменная типа LiquidCrystai. 10.1.19. Функция createCharQ Синтаксис функции: led.createChar(num, data) Функция создает пользовательский символ (глиф) для использования на жидкокри- сталлическом дисплее. Поддерживаются до восьми символов 5x8 пикселов (нуме- рация с 0 до 7). Создание каждого пользовательского символа определяется масси- вом из восьми байтов — один байт для каждой строки. Пять младших значащих
Глава 10. Использование дисплеев в проектах Arduino 185^ битов каждого байта определяют пикселы в этой строке. Чтобы вывести пользова- тельский символ на экран, используйте функцию write () с номером символа в ка- честве параметра. Параметры: О led — Переменная ТИПа LiquidCrystai; □ num— номер создаваемого символа (0 to 7); □ data — данные символьных пикселов. 10.2. Подключение дисплеев на контроллере HD44780 по протоколу 12С К сожалению, стандартная схема подключения ЖК-дисплеев на контроллере HD44780 не всегда удобна, т. к. занимает как минимум 6 цифровых выходов платы Arduino. Использование конвертера 12С (рис. 10.4) позволяет задействовать для подключения такого дисплея к плате Arduino только два вывода. Рис. 10.4. Подключение конвертера I2C к ЖК-дисплею Winstar Монтажная схема подключения ЖК-дисплея с конвертером 12С к плате Arduino представлена на рис. 10.5. Для определения 12С-адреса дисплея загрузим в плату Arduino скетч из листинга 9.5 и запустим монитор последовательного порта (рис. 10.6). Чтобы работать с ЖК-дисплеем WH1602 по протоколу 12С, необходимо установить библиотеку LiquidCrystal_I2C, которую можно скачать из репозитория Arduino. Для этого в меню Arduino IDE выбираем команду Эскиз | Include library | Manage Libraries. Далее в строке поиска набираем i2c led, находим библиотеку LiquidCrystal_I2C и нажимаем на кнопку Install (рис. 10.7).
186 Часть III. Сопряжение Arduino со вспомогательными устройствами 5й^Ж^;,йда* +5В Рис. 10.5. Монтажная схема подключения ЖК-дисплея с конвертером I2C к плате Arduino 00 01 02 03 04 05 Об 07 08 09 QA 0В ОС 0D ОЕ OF 00 01 02 03 04 05 06 07 08 09 ОА ОВ ОС 00 ОЕ OF 12Сдля\Л/Н1602 Рис. 10.6. Поиск 12С-устройств, подключенных к Arduino
Глава 10. Использование дисплеев в проектах Arduino 187 ( by Baiazs K«l«men Vbuafcring alanalog values or an LCD with the liqtf«§Oyst*i_I2C Cbrsry. LcdBarGraph ts an Ardu.no library to draw bar graph on a : Liquid Chrystal display. This LcdBafGraphX is a fork of the original project to b* driven by the "F. Maipaittda" version LCD lib (alca. I Liqu»dCrystal_I2C) instead of the bound one. More info A library «or driving LiqoirfCrystaJ displays (LCD) by using the I2C bus and an PCF8S74 IZC adapter. This library is erived from the original Arduino LiqutdCrystal library and uses the original Wire library for communication. Рис. 10.7. Поиск библиотеки LiquidCrystalJ2C 10.2.1. Вывод на ЖК-дисплей данных с датчика, работающего по протоколу I2C Рассмотрим пример вывода на ЖК-дисплей данных с датчика атмосферного давле- ния и температуры ВМР280, работающего по протоколу 12С. Этот датчик может измерять атмосферное давление и температуру с очень высокой точностью. Так, точность измерения барометрического давления этим датчиком составляет ±1 гПа, а температуры— ±1,0 °С. Поскольку давление изменяется с высотой, датчик ВМР280 также можно использовать и как высотомер с точностью ±1 метр. Обратите внимание, что в представленной на рис. 10.8 монтажной схеме этого про- екта питание датчика ВМР280 берется с выхода Arduino 3,3 В. Подключение его к напряжению 5 В приведет к выходу датчика из строя!!! Для работы датчика ВМР280 с Arduino необходимо установить библиотеку ВМР280, которую можно скачать со страницы https://github.com/adafruit/ AdafruitJBMP280_Library. Электронный архив Библиотека Adafruit_BMP280_Library размещена в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2). С помощью созданного для этого проекта скетча (листинг 10.1) мы будем получать с датчика данные с периодичностью 5 секунд и выводить их как в фиксированные позиции ЖК-дисплея, так и в монитор последовательного порта.
188 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 10.8. Монтажная схема подключения к плате Arduino ЖК-дисплея с конвертером I2C и датчика ВМР280 j // подключение библиотеки Wire #include "Wire.h" #include <SPI.h> // подключение библиотеки LiquidCrystal_I2C #include <LiquidCrystal_I2C.h> // создание экземпляра объекта для дисплея 16x2 LiquidCrystal_I2C lcd(0x27/ 16, 2); // подключение библиотек для датчика ВМР280 #include <Adafruit_Sensor.h> #include <Adafruit_BMP280.h> // создание экземпляра объекта - подключение по I2C Adafruit_BMP280 myBMP280; // для периода опроса датчика unsigned long mi11is1=0; int val; void setup() { // запуск последовательного порта на скорости 9600 бод Serial.begin(96Q0) ; // запуск ВМР280 rnyBMP2 8 0. begin ();
Глава 10. Использование дисплеев в проектах Arduino 189 I/ инициализация дисплея lcd.initO ; // включить подсветку led.backlight(); // led.setCursor(0,0); lcd.print("P="); led.setCursor(8,0); led.print("T="); void loopO { // раз в 5 секунд if(millis()-millisl>=5000) { ' // данные атмосферного давления с ВМР280 int val=(int)myBMP280.readPressure(); Serial.print("Pressure: "); Serial.print(val); Serial.printIn(" Pa"); led.setCursor(2,0); led.print(val); led.print("Pa"); // данные температуры с ВМР280 int val= (int) myBMP280. readTemperature () ; Serial.print("Temperature: "); Serial.print(val); Serial, print In (" *C"); led.setCursor(10,0); led.print(val); lcd.print("*C"); // начать отсчет 5 секунд заново millisl=millis(); Электронный архив Полный вариант рассмотренного скетча находится в папке examplesM0\_10J)1 сопрово- ждающего книгу электронного архива (см. приложение 2). При компиляции скетча может произойти ошибка из-за отсутствия библиотеки Adafruit Unified Sensor. В этом случае необходимо доустановить эту библиотеку. Ее можно найти в репозитории Arduino. Для этого в Arduino IDE выбираем пункт Эскиз | Include library | Manage Libraries, находим библиотеку Adafruit Unified Sensor и нажимаем на кнопку Install.
190 Часть III. Сопряжение Arduino со вспомогательными устройствами 10.3. Графический дисплей Nokia Символьные дисплеи, которые мы уже изучали в предыдущей главе, имеют боль- шие возможности в плане вывода символьной информации. С их помощью можно выводить текстовые сообщения, значения различных параметров, показания датчи- ков. Но что, если нам требуется еще больший уровень информативности — с ото- бражением графиков, картинок или текстовых сообщений с использованием разных шрифтов? Поможет нам в этом деле графический дисплей — например, Nokia5110. Этот дис- плей широко распространен среди любителей Arduino. Дисплей монохромный и имеет разрешение 84x48 точек. Как правило, дисплеи Nokia 5110 поставляются на плате в паре с контроллером PCD8544 и штыревым разъемом. В продаже можно найти два варианта исполнения модулей дисплея: на синей плате (рис. 10.9, слева) и на красной (рис. 10.9, справа). Оба варианта модуля имеют по восемь выводов: □ RST — сброс (Reset); □ СЕ — выбор устройства (Chip Select); □ DC — выбор режима (Data/Command select); □ Din — данные (Data In); □ SCLK — тактирующий сигнал (Clock); □ VCC — питание 3,3 В; □ BL (LIGHT) — подсветка; □ GND — «земля». Рис. 10.9. Дисплеи Nokia5110: слева — на синей плате; справа — на красной Питание контроллера PCD8544 должно лежать в пределах 2,7-3,3 В (максимум 3,3 В — при подаче 5 В дисплей может выйти из строя). Сигнальные же выводы толерантны к напряжению 5 В и подключаются к любым цифровым выводам Arduino.
Глава 10. Использование дисплеев в проектах Arduino 191 При использовании синего модуля подсветка дисплея активизируется подачей сигнала высокого уровня на вывод BL, а при использовании красного — подачей сигнала низкого уровня на вывод LIGHT. Монтажная схема подключения дисплея Nokia5110 к плате Arduino показана на рис. 10.10. Рис. 10.10. Монтажная схема подключения дисплея Nokia5110 к плате Arduino Для управления дисплеем Nokia5110 потребуется библиотека Adafruit_GFX_ Library, которую можно скачать по адресу https://github.com/adafruit/Adafruit- GFX-Library/archive/master.zip. Установите эту библиотеку и включите в скетч следующие строки: tinclude <AdafruitJ3FX.h> iinclude <Adafruit_PCD8544.h> //'Nokia 5110 // pin 7 - Serial clock out (SCLK) // pin 6 - Serial data out (DIN) // pin 5 - Data/Command select (D/C) // pin 4 - LCD chip select (CS) // pin 3 - LCD reset (RST) Adafruit_PCD8544 display = Adafruit_PCD8544 (7, 6, 5, 4, 3) ; Электронный архив Библиотека Adafruit_GFXJJbrary размещена в каталоге libraries сопровождающего кни- гу электронного архива (см. приложение 2).
192 Часть III. Сопряжение Arduino со вспомогательными устройствами В листинге 10.2 показан простой скетч вывода текста на экран дисплея Nokia5110. #include <Adafruit_GFX.h> #include <Adafruit_PCD8544.h> // Nokia 5110 // pin 7 - Serial clock out (SCLK) // pin 6 - Serial data out (DIN) // pin 5 - Data/Command select (D/C) // pin 4 - LCD chip select (CS) // pin 3 - LCD reset (RST) Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3); void setup() { // инициализация и очистка дисплея display.begin(); display.clearDisplay(); display.display(); display.setContrast(50); // установка контраста delay(1000); display.setTextSize(1); // установка размера шрифта display.setTextColor(BLACK); // установка цвета текста display.setCursor(0,0); // установка позиции курсора display.println("Hello, world!"); display.display(); void loopO { Загрузите этот скетч в плату Arduino, и вы увидите вывод на экран текста Hello, world! Теперь попробуем поработать с графикой — выведем на экран простейшие геомет- рические фигуры (листинг 10.3). #include <Adafruit_GFX.h> #include <Adafruit_PCD8544.h> // Nokia 5110 * // pin 7 - Serial clock out (SCLK) // pin 6 - Serial data out (DIN) // pin 5 - Data/Command select (D/C)
Глава 10. Использование дисплеев в проектах Arduino 193 II pin 4 - LCD chip select // pin 3 - LCD reset (RST) Adafruit PCD8544 display - (CS) Adafruit PCD8544(7, 6, 5, 4, 3); void setup () { // инициализация и очистка дисплея display.begin(); display.clearDisplay(); display.display(); display.setContrast(50); // установка контраста delay(1000); void loop () { // пиксел display.clearDisplay(); display.drawPixel(10, 10, BLACK); display.display(); delay(1000); // линия display.clearDisplay(); display.drawLine(0, 0, 50, 30, BLACK); display.display(); delay(1000); // прямоугольник display.clearDisplay(); display.drawRect(0, 0, 10, 10, BLACK); display.display(); delay(1000); // прямоугольник залитый display.clearDisplay(); display.fillRect(0, 0, 10, 10, BLACK); display.display(); delay(1000); // треугольник display.clearDisplay() ; display.drawTriangle(0, 0, 40, 40, 30, 20, BLACK); display.display(); delay(1000); // окружность в центре display.clearDisplay(); display.drawCircle(display.width()/2, display.height()/2, 10, BLACK); display.display(); delay(1000);
194 Часть III. Сопряжение Arduino со вспомогательными устройствами Электронный архив Полный вариант рассмотренного скетча находится в папке examples\10\_10j03 сопрово- ждающего книгу электронного архива (см. приложение 2). Библиотека AdafruitGFXJLibrary позволяет выводить на экран дисплея и растро- вые изображения. Для начала необходимо получить саму картинку— в черно- белом формате с расширением bmp и размером 84x8 пикселов. А затем получить НЕХ-код этой картинки — например, в программе GLCD Tools, — и вставить его в скетч Arduino (листинг 10.4). Загрузите этот скетч в плату Arduino, и вы увидите на экране растровое изображение (рис. 10.11). Рис. 10.11. Двухцветная картинка для вывода на экран #include <Adafruit_GFX.h> #include <Adafruit_PCD8544.h> // Nokia 5110 // pin 7 - Serial clock out (SCLK) // pin 6 - Serial data out (DIN) // pin 5 - Data/Command select (D/C) // pin 4 - LCD chip select (CS) // pin 3 - LCD reset (RST) Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3); const unsigned char PROGMEM imglO[] = { Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, OxeO, Oxff, Oxfc, Oxlf, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, OxeO, Oxff, Oxfc, Oxlf, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, OxeO, Oxff, Oxfc, Oxlf, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, OxeO, Oxff, Oxfc, Oxlf, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, Oxel, Oxff, Oxfc, Oxlf, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, Oxel, Oxff, 0xf8, Oxlf, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, Oxel, Oxff, 0xf8, 0x3f, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, Oxel, Oxff, 0xf8, 0x3f, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, Oxel, Oxff, 0xf8, 0x3f, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, Oxel, Oxff, 0xf8, 0x3f, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, ОхсЗ, Oxff, OxfO, 0x3f, Oxff, Oxff, Oxff, 0x80, Oxff, Oxff, Oxff, 0x83, 0x3, OxfO, 0x20, 0x78, 0x3f, 0x83, 0x80, Oxff, Oxff, Oxff, 0x80, Oxl, OxfO, 0x40, 0x38, 0x3f, 0x83, 0x80, Oxff, Oxff, Oxff, 0x80, 0x0, OxfO, 0x0, 0x38, Oxlf, 0x7, 0x80, Oxff, Oxff, Oxff, 0x80, 0x0, OxfO, 0x0, 0x18, Oxlf, 0x7, 0x80, Oxff, Oxff, Oxff, 0x80, 0x0, OxfO, 0x10, Oxlc, Oxle, Oxf, 0x80, Oxff, Oxff, 0x3, 0x81, OxeO, 0x60, 0x78, Oxlc, Oxlc, Oxlf, 0x80, Oxff, Oxfc, 0x3, 0x3, OxeO, 0x60, 0x78, ОхЗс, Oxlc, Oxlf, 0x80, j
Глава 10. Использование дисплеев в проектах Arduino 195 Oxff, OxfO, 0x3, 0x7, OxeO, 0x60, 0xf8, ОхЗс, 0x18, 0x3f, 0x80, Oxff, OxcO, 0x3, 0x7, OxeO, OxeO, 0xf8, ОхЗе, 0x8, 0x3f, 0x80, Oxff, 0x80, 0x3, 0x7, OxeO, OxeO, 0xf8, ОхЗе, 0x0, 0x7f, 0x80, Oxff, 0x0, 0x3, 0x7, OxcO, OxeO, 0xf8, ОхЗе, 0x0, Oxff, 0x80, Oxfe, 0x0, 0x3, 0x7, OxcO, Oxcl, 0xf8, ОхЗе, 0x0, Oxff, 0x80, Oxfc, 0x0, 0x6, 0x3, Oxl, Oxcl, OxfO, 0x7e, Oxl, Oxff, 0x80, Oxfc, 0x0, 0x6, 0x0, Oxl, Oxcl, OxfO, 0x7f, Oxl, Oxff, 0x80, Oxf8, 0x0, 0x6, 0x0, 0x3, Oxcl, OxfO, 0x7f, 0x3, Oxff, 0x80, OxfO, 0x0, Oxle, 0x0, 0x7, Oxcl, OxfO, 0x7f, 0x7, Oxff, 0x80, OxfO, 0x0, 0x7e, 0x10, Oxf, 0x81, OxfO, 0x7f, 0x7, Oxff, 0x80, OxeO, Oxl, Oxfe, 0x18, Oxlf, ОхсЗ, OxfO, Oxff, 0x8f, .Oxff, 0x80, OxeO, Oxl, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, OxeO, 0x3, Oxfc, 0x0, 0x0, 0x0, 0x0, 0x0, Oxlf, Oxff, 0x80, OxeO, 0x3, Oxfc, 0x0, 0x0, 0x0, 0x0, 0x0, Oxlf, Oxff, 0x80, OxcO, 0x7, Oxfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, Oxff, 0x80, OxcO, 0x7, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, OxcO, 0x7, Oxff, Oxfc, 0x0, 0x7f, Oxff, Oxff, Oxff, Oxff, 0x80, OxcO, 0x7, Oxff, Oxfc, 0x0,. Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, OxcO, 0x7, Oxff, Oxf8, 0x0, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, OxeO, 0x3, Oxff, Oxf8, 0x0, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, OxeO, 0x3, Oxff, 0xf8, 0x0, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, OxeO, Oxl, Oxff, OxfO, 0x0, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, OxeO, 0x0, Oxff, OxeO, Oxl, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, OxfO, 0x0, 0x7f, 0x80, Oxl, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, OxfO, 0x0, 0x4, 0x0, 0x3, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, Oxf8, 0x0, 0x0, 0x0, 0x3, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, Oxf8, 0x0, 0x0, 0x0, 0x7, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, Oxfc, 0x0, 0x0, 0x0, 0x7, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80, Oxfe, 0x0, 0x0, 0x0, Oxf, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80 void setup () { // инициализация и очистка дисплея display.begin (); display. clearDisplay (); display.display (); // установка контраста display. setContrast (50); delay (1000) ; // отрисовка изображения display.drawBitmap(0, 0, imglO, 84, 44, BLACK); display.display (); void loop() {
196 Часть III. Сопряжение Arduino со вспомогательными устройствами Электронный архив Полный вариант рассмотренного скетча находится в папке examples\10\_10_04 сопрово- ждающего книгу электронного архива (см. приложение 2). 10.4. OLED-дисплеи В последнее время в проектах Arduino часто используют не простые ЖК-инди- каторы, а OLED-дисплеи, несмотря на то, что они дороже. Но, в отличие от ЖК- индикаторов, где пикселы подсвечиваются, в OLED-дисплеях они сами излучают свет— изображение получается более контрастным и насыщенным, с хорошими углами обзора. К тому же OLED-дисплеи обладают незначительным энергопотреб- лением. Для использования в Arduino-проектах удобно применять OLED-дисплеи, выпол- ненные в виде модуля на микросхеме SSD1306 с необходимой обвязкой. Эти моду- ли работают на интерфейсе 12С. Монтажная схема подключения модуля OLED- дисплея к плате Arduino показана на рис 10.12. Рис. 10.12. Монтажная схема подключения к плате Arduino OLED-дисплея 128x32 Сначала определим адрес нашего дисплея на шине 12С. Для этого загрузим в плату Arduino скетч из листинга 9.5 и запустим монитор последовательного порта. Результат работы скетча показан на рис. 10.13— найдено устройство с адресом ОхЗС. Для работы с OLED-дисплеем 128x32 имеется несколько библиотек. Самая извест- ная— Adafruit SSD1306. Есть также и библиотека OLEDI2C, которая благодаря
Глава 10. Использование дисплеев в проектах Arduino 197_ усилиям энтузиастов поддерживает использование русского шрифта. Для подклю- чение русского шрифта включите в скетч команду: extern uint8_t RusFont[]; Затем в нужном месте скетча выберите шрифт: display, set Font (RusFont) ; К сожалению, в скетче Arduino мы не можем набирать слова русскими буквами, поэтому вводим нужный текст в английской раскладке: // текст "Издательство БХВ" display.print ("Bplfntkmcndj <{D", CENTER, 40); 10 20 30 3C 40 50 60 70 Start scan I2C bus«., 00 01 02 03 04 05 Off 07 08 09 0A OB ОС OD OE OF in —— —— —— — — — —— —— — — —— 20 —— —— — -— — —— — — — — 30 40 50 60 70 Start scan I2C bus... 00 01 02 03 Q4 05 06 07 08 09 QA OB ОС OS OE OF Рис. 10.13. Адрес OLED-дисплея 128x32 найден Электронный архив Библиотека OLEDJ2C размещена в каталоге libraries сопровождающего книгу элек- тронного архива (см. приложение 2). 10.4.1. Электронные часы на OLED-дисплее В этом примере мы воспользуемся OLED-дисплеем, чтобы создать макет электрон- ных часов. Датчиком точного времени нам послужит модуль DS3231 на микросхе- ме DS3231 (рис. 10.14)— он представляет собой недорогую плату с чрезвычайно точными часами реального времени (RTC) с календарем, дополнительной памятью NW SRAM (56 байт) и возможностью температурной компенсации кварцевого генератора и кристалла. Количество дней в месяце рассчитывается с учетом висо- косных лет до 2100 года.
198 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 10.14. Модуль датчика точного времени DS3231 Модуль несет на себе литиевую батарею, которая поддерживает бесперебойную работу, даже при отключении источника питания. Микросхема подключается к плате Arduino при помощи шины 12С. Монтажная схема подключения к плате Arduino модуля датчика точного времени и OLED-дисплея показана на рис. 10.15. Рис. 10.15. Монтажная схема подключения к плате Arduino модуля датчика точного времени и OLED-дисплея
Глава 10. Использование дисплеев в проектах Arduino 199 В скетче для этого проекта (листинг 10.5) мы получаем время с микросхемы DS3231, форматируем его и выводим на дисплей (рис. 10.16). При этом использу- ются два вида шрифтов: Я SmaiiFont — для вывода времени и даты; 0 RusFont — для вывода дня недели. Рис. 10.16. Макет электронных часов в сборе // подключение библиотек tinclude <Wire.h> finclude <Time.h> finclude <DS1307RTC.h> tinclude <OLED_I2C.h> OLED display(SDA, SCL, 8); // extern uint8_t SmaiiFont []; // шрифт small extern uint8_t RusFont []; // шрифт RusFont tinElements_t tm; String strl="lf; // дни недели char wday[7] [12] = { {"Gjytltkmybr"}, (" Dnjhybe "},{" Chtlf "}, {" Xtndthu "},{" Gznybwf "},
200 Часть III. Сопряжение Arduino со вспомогательными устройствами {" Ce,,jnf "},{"Djcrhtctymt"} }; void setup() { display.begin(); void loop() { if (RTC.read(tm)) { // Стираем все с экрана display.clrScr(); // Выбираем шрифт display.setFont(SmallFont); // строка время strl="lf; strl=strl+ printf2 (tm.Hour); strl=strl+":"; strl=strl+ printf2 (tm.Minute); strl=strl+":"; strl=strl+ printf2 (tm.Second); display.print(strlf CENTER, 10); // строка дата strl=""; strl=strl+ printf2 (tm.Day); strl=strl+"/lf; strl=strl+ printf2 (tm.Month); strl=strl+"/"; strl=strl+String(tmYearToCalendar(tm.Year)) display.print(strl, CENTER, 22); display.setFont(RusFont); // строка день недели display.print(wday[tm.Wday], CENTER, 34); // Обновляем информацию на дисплее display.update(); } delay(1000); // вывод с добавлением до двух цифр String printf2(int nn) { String snn=""; if (nn >= 0 && nn < 10) {snn="0";} snn=str+String(nn); return snn;
Глава 10. Использование дисплеев в проектах Arduino 201 Электронный архив Полный вариант рассмотренного скетча находится в папке examples\10\_10__05 сопрово- ждающего книгу электронного архива (см. приложение 2). 10.5. Дисплеи Nextion К этому моменту мы уже рассмотрели подключение к Arduino различных дисплеев: символьных, графических монохромных от телефона Nokia 5110, современных OLED-дисплеев. Однако, чем сложнее дисплей, тем больше вычислительных ресурсов платы Arduino он использует. Рассмотрим дисплей Nextion, который представляет собой полноценный компью- тер с процессором, видеокартой и экраном, причем он выделяет весь свой вычисли- тельный ресурс на обработку графики и позволяет записывать в него свои про- граммы. На модулях дисплеев Nextion имеется разъем UART и выводы GPIO, что позволяет использовать дисплеи Nextion как совместно с Arduino— подключая дисплей к Arduino по шине UART (обмен с помощью унифицированных команд), так и отдельно — подключая кнопки, светодиоды, реле и пр. напрямую к выводам GPIO дисплея). Через имеющийся у дисплея Nextion разъем для карт памяти microSD в него можно загружать программы. Для работы с дисплеями Nextion необходимо установить программу Nextion Editor, которая позволяет создавать интерфейс пользователя, с использованием различных библиотечных элементов: кнопок, слайдеров, картинок, графики, текста и т. п., а также прописывать алгоритмы поведения дисплея для различных событий эле- ментов, участвующих в интерфейсе дисплея. Скачать программу Nextion Editor можно со страницы загрузки официального, сай- та: https://nextion.itead.cc/resources/download/. Версия там имеется только для операционной системы Windows. Итак, скачиваем, распаковываем, устанавливаем и запускаем программу Nextion Editor. Перед нами откроется графическое окно разработки (рис. 10.17): 1. Главное меню. 2. Меню управления выравниванием и порядком элементов. 3. Библиотека элементов. 4. Область отображения. 5. Список страниц проекта. 6. Библиотека изображений/Библиотека шрифтов. 7. Окно вывода результатов компиляции. 8. Окно для ввода кода, выполняемого при возникновении события. 9. Зона редактирования атрибутов выбранного элемента.
202 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 10.17. Элементы окна программы Nextion Editor 10.5.1. Создание нового проекта для дисплея Nextion Командой меню File | New создадим новый проект, введем название будущего про- екта и нажмем на кнопку Сохранить. Откроется окно Setting с тремя вкладками: Device и DISPLAY и project: О на вкладке Device выберем линейку и модель дисплея (рис. 10.18); □ на бкладке DISPLAY — ориентацию дисплея и кодировку (рис. 10.19). Для под- держки кириллицы необходимо выбрать кодировку iso-8859-5; □ на вкладке project можно установить пароль доступа к проекту. Теперь можно приступить к добавлению элементов. Изначально в окне списка страниц присутствует одна страница — page, название которой можно изменить, У каждого элемента, а также у страницы, имеются свойства (атрибуты), которые можно изменять в окне редактирования атрибутов выбранного элемента. Добавим для страницы фон. Предварительно добавим изображение в окне 6 (биб- лиотека изображений), нажав на кнопку +. Теперь можно установить фон страни- цы, выбрав для страницы page атрибут sta, равный image, и выбрав нужное изо- бражение из списка в поле pic (рис. 10.20). Теперь добавим шрифты, которые наверняка пригодятся для надписей на экране, Шрифты можно сгенерировать тенератором шрифтов. Выбираем команду меню Tools | Font Generator и в открывшемся окне выбираем параметры шрифта (рис. 10.21), после чего сохраняем сделанный выбор, нажав на кнопку Generare font.
Глава 10. Использование дисплеев в проектах Arduino 203 ^^ Рис. 10.18. Выбор модели дисплея Рис. 10.19. Выбор ориентации дисплея и кодировки
204 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 10.20. Добавление фона для страницы Рис. 10.21. Генерация шрифта
Глава 10. Использование дисплеев в проектах Arduino 205 Рис. 10.22. Шрифты проекта Сгенерированный шрифт можно добавить в проект. Для этого в библиотеке шриф- тов нажимаем на кнопку + и указываем путь к шрифту. Теперь добавленный шрифт можно использовать в проекте (рис. 10.22). Элементы интерфейса добавляются на экран из библиотеки элементов, местополо- жение элемента на экране устанавливаем, перемещая его с помощью мыши, для активного элемента редактируем его атрибуты (рис. 10.23). Рис. 10.23. Редактирование атрибутов элемента
206 Часть III. Сопряжение Arduino со вспомогательными устройствами Установив соответствующий флажок, задаем отправку команд для UART выбран- ного события (Touch Press или Touch Release), в поле кода можно добавить код для этого события (рис. 10.24). Рис. 10.24. События для элемента Перед прошивкой модуля необходимо проект скомпилировать, выполнив команду меню Compile. Если ошибок нет, можно приступать к прошивке модуля. Дисплеи Nextion поддерживают два вида прошивки: □ через последовательный порт UART; □ с помощью карты microSD. 10.5.2. Прошивка дисплея через UART Для прошивки дисплея через UART понадобится адаптер USB-Serial. Схема под- ключения Nextion к адаптеру USB-Serial показана на рис. 10.25. Для загрузки прошивки выбираем пункт меню Upload и в открывшемся окне на- жимаем на кнопку Go. Процесс прошивки будет отображаться в окошке программы (рис. 10.26) и на дисплейном модуле. По окончании прошивки загружаемый проект будет выполняться и отображаться на дисплейном модуле. Надо отметить, что прошивка через UART занимает весьма долгое время.
Глава 10. Использование дисплеев в проектах Arduino 207 Рис. 10.25. Схема подключения дисплея Nextion к адаптеру USB-Serial >inectediConiCOM15b3udrate:9600,Modd:NX3048T050 Q11R(RTP),fffmware Ver.S68,Device send mni)er:O2€4C4C7Ea37352e.CPU1D:61488.Rash S1S77721^6MB)d0 tbrceduploadbautkate.il5200 Start uploading Рис. 10.26. Загрузка прошивки в дисплей Nextion через последовательный порт 10.5.3. Прошивка дисплея с помощью карты microSD Подключите к компьютеру карту microSD и скопируйте на нее файл с именем проекта. Извлеките карту из компьютера и вставьте ее в соответствующий разъем дисплея. Подключите на дисплей питание и дождитесь окончания прошивки. Из- влеките карту. После выполнения всех этих действий загружаемый проект будет выполняться и отображаться на дисплейном модуле. 10.5.4. Подключение дисплея Nextion к плате Arduino Рассмотрим подключение дисплея Nextion к плате Arduino и организацию их дву- стороннего взаимодействия. Взаимодействие это происходит по последовательно- му порту. Монтажная схема подключения дисплея Nextion к плате Arduino показа- на на рис. 10.27. Для взаимодействия с дисплеем Nextion мы воспользуемся Arduino-библиотекой Nextion. При этом со стороны Arduino задействуем программный последователь- ный порт Software на пинах 2 (RX) и 3 (ТХ).
208 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 10.27. Монтажная схема подключения дисплея Nextion к плате Arduino Электронный архив Библиотека Nextion размещена в каталоге libraries сопровождающего книгу электронно- го архива (см. приложение 2). Содержимое скетча получения данных из дисплея Nextion при событиях Touch Press и Touch Release для созданной ранее прошивки для дисплея Nextion представ- лено в листинге 10.6. // подключение библиотеки для работы с Software Serial #include <SoftwareSerial.h> // подключение библиотеки для работы с Nextion #include <Nextion.h> // Nextion TX к пин 2, RX к пин 3 Arduino SoftwareSerial nextion(2, 3); . // создание объекта Nextion к порту на скорости 9600 бод Nextion myNextion(nextion, 9600); void setup() { // запуск последовательного порта Serial.begin(9600); // инициализация Nextion myNextion.init();
Глава 10. Использование дисплеев в проектах Arduino 209 void loop () { // ожидание сообщения от Nextion String message = myNextion.listen(); if(message != ""){ // при получении сообщения - // вывести его в последовательный порт Serial.println(message); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\i0\_10J)6 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем этот скетч в плату Arduino и видим в последовательном порту подклю- чение данных из Nextion при назначенных для элементов событиях Touch Press и Touch Release (рис. 10.28). 55031 ffff ffff ffff &5 0 3 1 ffff ffff ffff 65 0 1 1 ffff ffff ffff Б5 0 10 ffff ffff ffff Б5 0 2 0 ffff ffff ffff 65 0 2 0 ffff ffff ffff 65 0 1 1 ffff ffff ffff 65 0 1 0 ffff'ffff ffff 65 0 3 1 ffff ffff ffff Б5 0 3 1 ffff ffff ffff 65 0 3 1 ffff ffff ffff E5 011 ffff ffff ffff 65 010 ffff ffff ffff 65 0 1 1 ffff ffff ffff 65 0 1 0 ffff ffff ffff £5 020 ffff ffff ffff Рис. 10.28. Получение данных от дисплея Nextion по последовательному порту Разберем формат полученной строки: 65 0 2 1 ffff fffff fffff Здесь: □ 65 — первый байт: произошло событие TouchEvent; О о — номер страницы;
210 Часть III. Сопряжение Arduino со вспомогательными устройствами П 2 — номер элемента на странице; □ 1 — событие Touch Press (0 — Touch Release). Теперь рассмотрим отправку команд на дисплей Nextion (выбор страницы, уста- новка атрибутов элементов, переключение кнопок, получение атрибутов элементов и пр.). В библиотеке Nextion имеются методы для отправки команд на дисплей Nextion — например: □ sendCommand () — отправить команду; □ setcomponentText () — установить текст компонента; П buttononof f () — нажать/отжать кнопку; □ buttonToggie () — переключение переключателя; □ updateProgressBar () — изменить компонент ProgressBar; □ getcomponentText () — получить текст компонента. Содержимое скетча отправки команд на дисплей Nextion представлено в листин- ге 10.7. // подключение библиотеки для работы с Software Serial #include <SoftwareSerial.h> // подключение библиотеки для работы с Nextion #include <Nextion.h> // Nextion TX к пин 2, RX к пин 3 Arduino SoftwareSerial nextion(2, 3); // создание объекта Nextion к порту на скорости 9600 бод Nextion myNextion(nextion, 9600); // служебные переменные char buf[10]; void setup() { // запуск последовательного порта Serial.begin(9600); // инициализация Nextion. myNextion.init(); void loopO { // изменение текста на компоненте tO myNextion.setcomponentText("t0", "Smartf4String(millis())); delay(2000); // изменение размера кнопки ЬО myNext ion. sendCommand ( "bO. f ont~l");
Глава 10. Использование дисплеев в проектах Arduino 211 delay(2000); myNextion.sendCoiranand( "ЬО.font-0"); delay(2000); // изменение позиции слайдера String s="h0.val="+String(random(0,100)); Serial.printIn(s); s.toCharArray(buf, 10); myNextion.sendCommand(buf); delay(2000); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\W\_10__06 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем скетч на плату Arduino и видим на дисплее изменение атрибутов компо- нентов.
ГЛАВА 11 Подключение к Arduino исполнительных устройств Исполнительные устройства — это элементы автоматики, создающие управляю- щее воздействие на объект управления. Они изменяют положение или состояние регулирующего органа объекта управления таким образом, чтобы управляемый параметр соответствовал заданному значению. Исполнительное устройство или механизм (actuator) преобразует электрическую энергию в механическую или в фи- зическую величину для воздействия на управляемый процесс. Это могут быть световые и звуковые устройства, электромагнитные клапаны, моторы постоянного (DC) или переменного (АС) тока, сервоприводы, релейные системы и многое другое. Рассмотрим работу Arduino с некоторыми исполнительными устройствами на при- мерах. 11.1. Подключение к плате Arduino электромагнитного или твердотельного реле Реле— электрическое или электронное устройство (ключ), предназначенное для замыкания и размыкания различных участков электрических цепей. Изобрели соб- ственно реле в далеком 1831 году. А уже в 1837 году американский изобретатель Сэмюэл Морзе создал основанный на реле электромагнитный телеграфный аппа- рат: Сегодня реле широко используются практически во всех областях техники, их существует огромное количество самых разнообразных видов. Наиболее распространенными являются электромагнитные реле. Электромагнит- ное реле— электромеханическое устройство, замыкающее и/или размыкающее механические электрические контакты при подаче в обмотку реле электрического тока, порождающего магнитное поле, которое вызывает перемещение ферромаг- нитного якоря реле, связанного механически с контактами, и последующее пере- мещение контактов коммутирует внешнюю электрическую цепь. Рассмотрим устройство реле на примере широко используемого совместно с пла- тами Arduino реле фирмы SONGLE SRD-05VDC (рис. 11.1). Это реле управляется
2А4 Часть III. Сопряжение Arduino со вспомогательными устройствами напряжением 5 В и способно коммутировать постоянные токи до 10 А при напря- жении 30 В и переменные токи до10 А при напряжении 250 В. Реле имеет две раздельные цепи: цепь управления, представленную контактами А1 и А2, и управляемую цепь с контактами 1, 2 и 3 (рис. 11.2). Цепи эти электрически никак между собой не связаны. При протекании тока по обмотке катушки, вклю- ченной между контактами А1 и А2, металлический сердечник, размещенный внут- ри этой обмотки, намагничивается, и к нему притягивается подвижный якорь, со- единенный с контактом 2. Контакты 1 и 3 неподвижны. Стоит отметить, что якорь подпружинен, и пока мы не пропустим ток через обмотку сердечника, якорь будет удерживаться прижатым к контакту 1. При подаче тока сердечник, как уже говори- лось, превращается в электромагнит и притягивает якорь к контакту 3. При обесто- чивании пружина снова возвращает якорь к контакту 1. Рис. 11.1. Электромагнитное реле SRD-05VDC All 3|И А2| ]2 Рис. 11.2. Схема электромагнитного реле SRD-05VDC С подключением реле к плате Arduino связана проблема — вывод платы не может обеспечить мощность, необходимую для нормальной работы катушки реле. Поэто- му необходимо усилить ток — для чего следует включить в схему транзистор. Для усиления тока удобней применять n-p-n-транзистор, включенный по схеме с общим эмиттером (ОЭ), — как показано на рис. 11.3. При таком способе можно подклю- чать нагрузку с напряжением питания большим, чем питание микроконтроллера. Резистор на базе транзистора— ограничительный, его номинал может варьиро- ваться в широких пределах (1-10 кОм), — в любом случае транзистор будет рабо- тать в режиме насыщения. Транзистор можно взять любой, лишь бы он был п-р-п- типа. Коэффициент его усиления практически не имеет значения. Выбирается тран- зистор по току коллектора (нужный нам ток) и напряжению коллектор-эмитгер (напряжение, которым запитывается нагрузка). Я, как правило, использую транзи- сторы С945. Для включения реле, подключенного по схеме с ОЭ, на вывод Arduino необходимо подать 1, для выключения — 0 (листинг 11.1).
Глава 11. Подключение к Arduino исполнительных устройств 215 #12 ¥ 1.5 кОт к Arduino Рис. 11.3. Схема подключения электромагнитного реле к плате Arduino (р-канальное управление) int relayPin =10; void setup () // подключение Arduino к выводу D10 pinMode(relayPin, OUTPUT); // настроить вывод как выход (OUTPUT) // the loop function runs over and over again forever void loop() { digitalWrite(relayPin, HIGH); // включить реле delay(5000); digitalWrite(relayPin, LOW); // выключить реле delay(5000); Для подключения к плате Arduino можно использовать готовые модули, содержа- щие сразу несколько реле с необходимой обвязкой (рис. 11.4). Но в таких модулях обычно применяется n-канальное управление (рис. 11.5). При таком управлении реле включается подачей на вывод Arduino низкого уровня. Твердотельные реле (Solid State Relay, SSR) применяются в промышленном обору- довании— там, где нужна большая надежность и малые габариты (рис. 11.6). Во всех твердотельных оптоэлектронных реле коммутация цепей нагрузки осуществ- ляется бесконтактно— за счет управления встроенными полупроводниковыми элементами. Как правило, это тиристоры или симисторы (для коммутации пере-
216 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 11.4. Модуль из 4-х реле 5V signal Рис. 11.5. Схема подключения электромагнитного реле к плате Arduino (n-канальное управление) Рис. 11.6. Твердотельное реле
Глава 11. Подключение к Arduino исполнительных устройств 217 менного тока) и транзисторы (для коммутации постоянного тока). Такой способ управления дает ряд преимуществ перед обычными электромагнитными реле. Так же, как и в обычных реле, в твердотельных существует гальваническая развязка между напряжением катушки и напряжением на силовых контактах. Только в элек- тромеханических реле это достигается за счет разнесения катушки и силовых кон- тактов в пространстве, а в твердотельных — за счет использования оптрона, обес- печивающего оптическую развязку. Твердотельные реле при работе потребляют и теряют гораздо меньше энергии, имеют меньшие габариты, высокое быстродействие, гораздо более длительный срок службы и все это — абсолютно бесшумно! Но есть у них и минус — высокая цена. Для подключения твердотельного реле к плате Arduino минусовой контакт управ- ляющей сети подсоединяется к «земле», а плюсовой— к цифровому выводу Arduino. Выходного тока контакта Arduino для срабатывания твердотельного реле вполне достаточно. К реле можно подключить лампочку, вентилятор или, например, электромагнитный клапан для полива растений в теплице и программно управлять этими устройства- ми изменением состояния на цифровых выводах Arduino. 11.2. Подключение к плате Arduino электродвигателя постоянного тока 11.2.1. Управление двигателем с помощью транзистора Электродвигатели постоянного тока применяются в роботах на колесных или гусе- ничных платформах. И начнем мы с самого простого способа управления ими — с помощью транзистора. Выводы Arduino, сконфигурированные как output, находятся в низкоимпедансном состоянии, могут отдавать в нагрузку 40 мА, и не в состоянии обеспечить питание мощной нагрузки и большого напряжения. Одним из способов управления мощной нагрузкой является использование полевых MOSFET-транзисторов. MOSFET- транзистор — это ключ для управления большими токами при помощи небольшого напряжения (в отличие от биполярных транзисторов, управляемых током). Рассмотрим управление с выхода Arduino мощной нагрузкой— электродвигате- лем — с помощью MOSFET-транзистора. Для этого проекта нам понадобятся сле- дующие компоненты: П плата Arduino Uno; П кабель USB; П плата прототипирования; П транзистор MOSFETIRF540; П диод 1N4007;
218 Часть III. Сопряжение Arduino со вспомогательными устройствами О потенциометр 10 кОм; □ электродвигатель постоянного тока (DC) с редуктором; □ блок питания 5 В 2 А; □ соединительные провода разных типов (согласно схеме). В представленной на рис. 11.7 монтажной схеме этого проекта для управления ско- ростью двигателя с платы Arduino мы воспользуемся ШИМ, обеспечивающей получение изменяющегося аналогового значения напряжения соответствующей обработкой цифровых сигналов. Регулирование скорости двигателя будет осущест- вляться с помощью потенциометра. 1 Рис. 11.7. Монтажная схема подключения электродвигателя к плате Arduino При наличии в схеме индуктивной нагрузки (электродвигатель, электромагнитный клапан и т. п.) рекомендуется защищать MOSFET-транзистор от напряжения само- индукции с помощью защитного диода. Управление электродвигателем при помо- щи ШИМ без защитного диода может вызвать такие проблемы, как нагрев транзи- стора или его полный выход из строя, замедление вращения двигателя, потеря мощности и пр. Если же нагрузка в схеме активная: светодиод, галогенная лампа, нагревательный элемент и т. п., то защитный диод не обязателен. Содержимое скетча управления скоростью электродвигателя с платы Arduino пока- зано в листинге 11.2. Загружаем этот скетч в плату Arduino и поворотом ручки потенциометра изменяем скорость вращения двигателя.
Глава 11. Подключение к Arduino исполнительных устройств 219 II Выход для подключения MOSFET const int MOTOR=9; // Аналоговый вход АО для подключения потенциометра const int POT=0; // переменная для хранения значения потенциометра int valpot = 0; // переменная для хранения скорости двигателя int speedMotor — 0; void setup () { // выход управления двигателем как OUTPUT pinMode(MOTOR,OUTPUT); } void loopO { // чтение данных потенциометра valpot = analogRead(POT); // масштабируем значение к интервалу 0-255 speedMotor=map(valpot,0,1023,0,255); // устанавливаем новое значение ШИМ analogWrite(MOTOR,speedMotor); // пауза delay(100); } Электронный архив Полный вариант рассмотренного скетча находится в папке examples\11\_11J)2 сопрово- ждающего книгу электронного архива (см. приложение 2). 11.3. Управление двигателями с помощью драйвера Для управления электродвигателями с платы Arduino разработаны специализиро- ванные микросхемы— так называемые драйверы двигателей. Наиболее распро- страненным в среде пользователей Arduino является модуль драйвера L298 (рис. 11.8), Рис. 11.8. Модуль драйвера L298
220 Часть III. Сопряжение Arduino со вспомогательными устройствами который позволяет управлять двумя двигателями постоянного тока и обеспечивает максимальную нагрузку до 2 А на каждый двигатель. Напряжение питания двига- телей при этом может лежать в диапазоне от 5 до 35 В. Чередованием разноименных сигналов (высокий логический уровень или низкий) на парах выводов IN1-IN2 и IN3-IN4 задается направление вращения двигателей. Выводы ENA (привязан к IN1 и IN2) и ENB (привязан к IN3 и IN4) отвечают за раздельное управление каналами. Для регулировки скорости двигателей на выводы ENA и ENB подается ШИМ-сигнал. В представленной на рис. 11.9 монтажной схеме проекта управления двумя двига- телями с помощью модуля драйвера двигателей L298N направление вращения каж- дого двигателя и его скорость регулируются потенциометрами: первый потенцио- метр устанавливает направление движения и скорость для первого двигателя, второй — для второго. Среднее положение потенциометров — нулевая скорость. Осуществляется это следующим программным блоком: // чтение данных потенциометра valpotl = analogRead(POTl); // масштабируем значение к интервалу -255 - 255 speedMotorl=map(valpotl,0,1023,-255,255); if(speedMotorl<512) { digitalWrite(INI,HIGH); digitalWrite(IN2,LOW); } else { digitalWrite(INI, LOW); digitalWrite(IN2 HIGH,); } analogWrite(ENA,speedMotorl); Рис. 11.9. Монтажная схема подключения электродвигателей к плате Arduino с помощью модуля драйвера двигателей L298N
Глава 11. Подключение к Arduino исполнительных устройств 221 Содержимое скетча для управления скоростью двигателей с платы Arduino показа- но в листинге 11.3. Загружаем этот скетч в плату Arduino и поворотами ручек по- тенциометров изменяем скорость и направление вращения для каждого двигателя. Что любопытно — два двигателя как раз и позволяют создать движущуюся плат- форму. // Контакты подключения к модулю драйвера L298 const int ENA=10; const int IN1=9; const int IN2=8; const int ENB=5; const int IN3=7; const int IN4=6; // Аналоговые входы для подключения потенциометров const int POT1=0; const int POT2=1; // переменные для хранения значений потенциометров int valpotl = 0; int valpot2 = 0; // переменные для хранения скоростей двигателей int speedMotorl = 0; int speedMotor2 = 0; void setup () { // выходы как OUTPUT pinMode(ENA,OUTPUT), pinMode(INI,OUTPUT) , pinMode(IN2,OUTPUT), pinMode(ENB,OUTPUT), pinMode(IN3,OUTPUT) , pinMode(IN4,OUTPUT) , void loopO { // чтение данных потенциометра 1 valpotl = analogRead(POTl); // масштабируем значение к интервалу -255 - 255 speedMotorl=map(valpotl,0,1023,-255,255); if(speedMotorl<512) { digitalWrite(INI,HIGH); digitalWrite(IN2,LOW); } else { digitalWrite(INI, LOW);
222 Часть III. Сопряжение Arduino со вспомогательными устройствами digitalWrite (IN2 HIGH,) ; } // чтение данных потенциометра 2 valpotl = analogRead(POT2); // масштабируем значение к интервалу -255 - 255 speedMotor2=map(valpot2,0,1023,-255,255); if(speedMotor2<512) { digitalWrite(IN3,HIGH); digitalWrite(IN4,LOW); } else { digitalWrite (IN3, LOW); digitalWrite(IN4 HIGH,); } analogWrite (ENB, speedMotor2) ; // пауза delay(100); Электронный архив Полный вариант рассмотренного скетча находится в папке examplesWfW?_03 сопрово- ждающего книгу электронного архива (см. приложение 2). 11.4. Подключение к плате Arduino сервопривода Сервопривод это устройство, которое обеспечивает преобразование сигнала в строго соответствующее этому сигналу перемещение (поворот) исполнительного устройства. Представляет он собой прямоугольную коробку с мотором, схемой и редуктором внутри, а также выходным валом, который должен поворачиваться на строго фиксированный угол, определяемый входным сигналом. Существует очень много видов сервоприводов, которые различаются габаритами, материалом шесте- ренок (пластмасса, металл), способом управления (аналоговые и цифровые), ско- ростью вращения вала, крутящим моментом, диапазоном поворота (120°, 180°, непрерывного вращения) и пр. Сервопривод управляется с помощью импульсов переменной длительности — угол поворота его выходного вала определяется длительностью импульса, подаваемого по сигнальному проводу (как можно видеть, широтно-импульсная модуляция за- действована и здесь). Сервопривод ожидает импульса каждые 20 мс. Длительность импульса определяет, насколько далеко должен повернуться вал. Например, им- пульс в 1,5 мс диктует приводу поворот в положение 90° (нейтральное положение). Когда сервопривод получает команду на перемещение, его управляющий орган пе- ремещается в это положение и удерживает его. Если внешняя сила действует на сервопривод, когда он удерживает заданное положение, сервопривод будет сопро-
Глава 11. Подключение к Arduino исполнительных устройств 223 тивляться перемещению из этого положения. Максимальная величина силы, кото- рую может вьвдерживать сервопривод, характеризует вращающий момент серво- привода. Однако сервопривод не навсегда удерживает свое положение — импульсы позиционирования должны повторяться, информируя сервопривод о сохранении положения. Рис. 11.10. Комплект сервопривода MG995 Рассмотрим подключение к плате Arduino популярного сервопривода MG995 (рис. 11.10). Для этого нам понадобятся три провода (рис. 11.11): О красный провод — питание (внешний стабилизированный источник питания 4,8-7,2 В); □ черный провод — к выводу Arduino GND; □I синий — сигнальный, подключается к цифровому ШИМ-выводу платы Arduino. Для управления сервоприводами с помощью Arduino в Arduino ШЕ имеется стан- дартная библиотека Servo, поддерживающая функции для установки настроек сер- вопривода, необходимого угла поворота и считывания состояния. В листинге 11.4 представлен скетч вращения сервопривода от 0 до 120° с шагом 1°, а затем в обратную сторону. После загрузки этого скетча в плату Arduino вал сер- вопривода медленно вращается сначала в одну сторону, затем в другую. // подключение библиотеки Servo tinclude <Servo.h> // создать объект servo Servo servol;
224 Часть III. Сопряжение Arduino со вспомогательными устройстват // пин для подключения сервопривода const int pin_servo=9; // макс, значение угла поворота const int angle_max=120; // для хранения текущей позиции сервопривода int angle = 0; // для хранения направления 1 или -1 dir=l; void setup() { // подключить управление сервоприводом к пину pin_servo servol.attach(pin_servo); void loop() { for(;;) { // команда установки положения сервопривода servol.write(angle); // время на перемещение сервопривода delay(15); // if (angle=0) dir=l; else if(angle==angle_max) dir=-l; angle=angle+dir; 4.8 - 7.2 В Рис. 11.11. Подключение сервопривода к плате Arduino
Глава 11. Подключение KArduino исполнительных устройств 225 11.4.1. Использование сервопривода в проекте звуковой сигнализации Сервоприводы очень часто применяются в робототехнике, где вообще характерно использование различных двигателей, сервоприводов и датчиков, и здесь мы рас- смотрим, как с помощью сервопривода можно оснастить робота звуковой сигнали- зацией о наличии препятствий на пути его движения. Датчик расстояния — модуль НС SR-04 — находится на вращающейся в горизон- тальной плоскости платформе робота (вращение платформы как раз и осуществля- ется с помощью сервопривода) и измеряет расстояние до преграды. При обнаруже- нии объекта, находящегося на расстоянии менее 1 м от модуля, платформа останав- ливается и подает звуковой сигнал на динамик до тех пор, пока объект не удалится на большее расстояние. Для этого проекта (рис. 11.12) нам понадобятся следующие компоненты: □ плата Arduino Uno; □ ультразвуковой модуль НС SR-04; Я сервопривод; □ платформа для крепления сервопривода и модуля НС SR-04; □ динамик 8 Ом; □ резистор 500 Ом; □ транзистор КТ503е; □ источник внешнего питания 5 В (для питания сервопривода); □ соединительные провода. Рис. 11.12. Монтажная схема подключения к плате Arduino сервопривода, ультразвукового модуля НС SR-04 и динамика
226 Часть III. Сопряжение Arduino со вспомогательными устройствами Содержимое скетча, обеспечивающего работу этого проекта, показано в листин- ге 11.5. Сервопривод вращает платформу с датчиком от 0 до 180 градусов и обрат- но. На каждом шаге система проверяет показания модуля расстояния НС SR-04. Если объект нарушает границу (значение distdetect, равное 100 см), на динамик подается звуковой сигнал: tone (PIN_SPEAKER, FREQ) ; Далее система ждет, пока объект не выйдет из «зоны поражения», после чего от- ключает динамик и продолжает вращение платформы. // константы для выводов #define PIN_TRIG 12 #define PIN_ECHO 13 #define PINJSERVO 9 #define PINjSPEAKER 8 // расстояние обнаружения, см #define DIST_DETECT 100 // частота звукового сигнала #define FREQ 546 // подключение библиотеки для НС SR04 #include "Ultrasonic.h" // создание объекта Ultrasonic // Trig - 12, Echo - 13 Ultrasonic ultrasonic(PINJTRIG, PIN_ECHO); // переменная для хранения измеренного расстояния float dist__cm=0; // подключение библиотеки для серво #include <Servo.h> // создание объекта Servo Servo myservo; // переменная для хранения позиции сервопривода int pos = 0; // переменная направления перемещения сервопривода int dir=l; void setup() { // запуск последовательного порта Serial.begin(9600); // запуск серво на выходе PIN__SERVO myservo.attach(PINJSERVO); void loopO { // вычисление следующей позиции сервопривода pos=pos+dir;
Глава 11. Подключение кАгбшпо исполнительных устройств 227 I/ установить сервопривод в- позицию pos myservo.write(pos); // при достижении крайних позиций изменить // направление dir if (pos—180) dir=-l; else if(pos==0) dir=l; else ; // получить данные с дальномера dist_cm = ultrasonic.Ranging (CM); Serial. print In (dist_cm); // обнаружение объекта в зоне if (dist_an>0 && dist_cm<DIST_DETECT) { // звуковой сигнал tone(PINJ3PEAKER,FREQ); } // пока в зоне обнаружения while (dist_cm>0 && dist_cm<DIST_DETECT) { dist_cm = ultrasonic.Ranging(CM); Serial.printIn(dist_cm); } // отключить звуковой сигнал noTone (PIN_SPEAKER) ; // пауза перед сменой позиции сервопривода delay(50); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\11\_11_05 сопрово- ждающего книгу электронного архива (см. приложение 2). 11.5. Подключение к плате Arduino шагового двигателя Шаговые двигатели представляют собой электромеханические устройства, задачей которых является преобразование электрических импульсов в перемещение вала двигателя на определенный угол. Достоинствами шаговых двигателей по сравнению с обычнымии являются: О высокая точность позиционирования и повторяемости — качественные шаговые двигатели имеют точность не хуже 2,5% от величины шага, при этом ошибка не накапливается при последующих шагах; 3 шаговый двигатель может быстро стартовать, останавливаться и выполнять реверс;
228 Часть III. Сопряжение Arduino со вспомогательными устройствами □ четкая взаимосвязь угла поворота ротора от количества входных импульсов (в штатных режимах работы) позволяет выполнять позиционирование без при- менения обратной связи; □ шаговые двигатели обеспечивают получение сверхнизких скоростей вращения вала без использования редуктора; □ шаговые двигатели работают в широком диапазоне скоростей, поскольку ско- рость напрямую зависит от количества входных импульсов. Шаговые двигатели применяются там, где требуется высокая точность перемеще- ний, — например, в принтерах, факсах и копировальных машинах, в станках с ЧПУ, в ЗБ-принтерах. Минимально возможный угол перемещения шагового двигателя называется шагом. Управление шаговым двигателем сводится к задаче отработать определенное число шагов в нужном направлении и с нужной скоростью. Для управления шаговыми двигателями используют специальные устройства- драйверы шаговых двигателей. Популярный драйвер шагового двигателя А4988 (рис. 11.13) работает от напряже- ния 8-35 В и может обеспечить ток до 1 А на фазу без радиатора (и до 2 А с радиа- тором). Он имеет защиту от перегрузки и перегрева. Одним из параметров шаговых двигателей является количество шагов на один полный оборот (360°). Например, для шаговых двигателей Nema 17 (рис. 11.14)— это 200 шагов на оборот, т. е 1 шаг равен 1,8°. Драйвер А4988 позволяет увеличить это значение за счет управ- ления промежуточными шагами и имеет пять режимов микрошага: 1 (полный), 1/2, 1/4, 1/8 и 1/16 шага. Назначение контактов (выводов) драйвера А4988 приведено на рис. 11.15: □ ENABLE — включение/выключение драйвера; □ MSI, MS2, MS3 — контакты для установки микрошага; Рис. 11.13. Драйвер шаговых двигателей А4988 Рис. 11.14. Шаговый двигатель Nema 17
Глава 11. Подключение KArduino исполнительных устройств 229 О RESET — сброс микросхемы; О STEP— генерация импульсов для движения двигателей (каждый импульс — шаг), с его помощью можно регулировать скорость двигателя; Я DIR — установка направления вращения; □ VMOT — питание для двигателя (8-35 В); О GND — общий; □ 2В, 2А, 1 А, 1В — подключение обмоток двигателя; □ VDD — питание микросхемы (3,5-5 В). А4988 Рис. 11.15. Выводы драйвера А4988 Значение микрошага устанавливается комбинацией сигналов на входах MSI, MS2 и MS3. Есть пять вариантов дробления шага (табл. 11.1). MS1 0 1 0 1 1 Таблица 11Л MS2 0 0 1 1 1 . Комбинация значений для выбора микрошага MS3 0 0 0 0 1 Дробление шага 1 1/2 1/4 1/8 1/16 Для работы в режиме микрошага необходим слабый ток. На модуле А4988 ограни- чение тока осуществляется находящимся на плате потенциометром. Драйвер очень чувствителен к скачкам напряжения по питанию двигателя, поэтому производитель рекомендует устанавливать для сглаживания таких скачков электролитический конденсатор большой емкости. Имейте также в виду, что подключение или отклю- чение шагового двигателя при включенном драйвере может привести к выходу двигателя из строя.
230 Часть III. Сопряжение Arduino со вспомогательными устройствами 11.5.1. Управление дроблением шага и направлением вращения шагового двигателя с платы Arduino Создадим проект управления дроблением шага и направлением вращения шагового двигателя с платы Arduino. Для этого нам понадобятся следующие компоненты: □ плата Arduino Uno; □ драйвер А4988; □ шаговый двигатель Nema 17; □ потенциометр 10 кОм; □ кнопка; □ переключатель 2-позиционный; □ резистор 10 кОм — 3 шт.; □ провода разных типов (согласно схеме). Монтажная схема этого проекта представлена на рис. 11.16. Рис. 11.16. Монтажная схема подключения компонентов для управления дроблением шага и направлением вращения шагового двигателя Содержимое скетча, обеспечивающего работу этого проекта, показано в листин- ге 11.6. Нажатие на кнопку включает/выключает двигатель подачей сигнала low/high на вход ENABLE драйвера А4988. С помощью переключателя мы выбира- ем направление вращения двигателя (сигнал с переключателя подается напрямую
Глава 11. Подключение кАгди'то исполнительных устройств 231 на вход DIR драйвера А4988), а с помощью потенциометра — один из режимов микрошага: 1, 1/2, 1/4, 1/8, 1/16. // пины для подключения контактов STEP, DIR const int STEP 3 int DIR 2 // для регулировки скорости - пин потенциометра- idefine POT АО // для кнопки idefine BUTTON 9 // для включения/выключения idefine EN 8 // количество шагов на 1 оборот idefine ROUND 200 // скорость двигателя idefine SPEED 10 // массив пинов для MSI,MS2,MS3 int pins_steps [ ] = {7, б, 5}; int steps [5] [3] = { {0,0,0}, // 1 {lf0,0}, // 1/2 {0,1,0}, // 1/4 {1,1,0}, // 1/8 {1,1,1} // 1/16 // для кнопки int prevB=0; int tekB=0; boolean movement=false; void setup () { // режим для выводов STEP и DIR как pinModeSTEP, OUTPUT); pinMode(DIR, OUTPUT); // начальные значения digitalWrite(STEP, 1); digitalWrite(DIR, 0); // режим для enable pinMode(EN, OUTPUT);
232 , Часть III. Сопряжение Arduino со вспомогательными устройствами //не разрешать digitalWrite(EN, I); // для MS1,MS2,MS3 for(int i=0;i<3;i++) { pinMode(pins_steps[i], OUTPUT); void loop() { // получить режим микрошага digitalWrite(DIR, 1); int mode=map(analogRead(POT),0,1024,0,5); // установить for(int i=0;i<3;i++) { digitalWrite(pins_steps[i], steps[mode][i]) ; } // сделать 1 оборот i f (movement==t rue) { digitalWrite(STEP, 1); delay(SPEED); digitalWrite(STEP, 0); delay(SPEED); } // проверка нажатия кнопки tekB = debounce(prevB, BUTTON); if (prevB == 0 && tekB ==1) { movement=! movement; digitalWrite (EN, Imovement) ; } prevB = tekB; } // проверка на дребезг int debounce(int prev,int pin) { int tek = digitalRead(pin); if (prev != tek) { delay(5); tek = digitalRead(pin); return tek; Электронный архив Полный вариант рассмотренного скетча находится в папке examples\11\_11_06 сопрово- ждающего книгу электронного архива (см. приложение 2).
Глава 11. Подключение к Arduino исполнительных устройств 233 11.6. Подключение к плате Arduino бесколлекторного двигателя Бесколлекторные двигатели (рис. 11.17) используются в различных радиоуправ- ляемых летающих моделях. По сравнению с коллекторными, бесколлекторные дви- гатели эффективно работают в более широком диапазоне оборотов и имеют более высокий КПД. Конструкция двигателя при этом проще— в ней нет щеточного узла, который работает постоянно в режиме трения, создает искры и, в итоге, про- воцирует потерю энергии. Бесколлекторные двигатели питаются трехфазным пере- менным током, поэтому для их работы необходим специальный контроллер (регу- лятор скорости), преобразующий постоянный ток от аккумуляторных батарей в переменный (рис. 11.18). Рис. 11.17. Бесколлекторный двигатель Рис. 11.18. Регулятор ESC для бесколлекторного двигателя Регулятор ESC, обеспечивающий работу бесколлекторного двигателя, имеет три разъема для подключения собственно двигателя, два провода для подключения питания (обычно это литий-полимерная батарея) и 3-контактный разъем для под-
234 Часть III. Сопряжение Arduino со вспомогательными устройствами ключения к управляющему устройству (например, к плате Arduino). При этом да управления задействуются два контакта: черный — GND и белый — управляющий, а третий (красный — 5 В) можно использовать для питания платы. Регулятор последовательно переключает обмотки бесколлекторного двигателя с определенной частотой. Управляя частотой переключения обмоток, мы управля- ем скоростью вращения ротора. При программировании используется библиотека Servo: #include <Servo.h> Servo motor; // Инициализация мотора motor. attach (motorjpin, j s_position, maxjposition); где: □ motorjpin — контакт (пин) подключения; □ j s_position — начальная позиция (1500); □ maxjposition — максимальное значение (2300). Диапазон значений, подаваемых на регулятор, должен находиться в интервале 800- 2300. Содержимое скетча, обеспечивающего управление скоростью бесколлекторного двигателя с платы Arduino вращением потенциометра, показано в листинге 11.7. #include <Servo.h> Servo motor; // пин подключения мотора int motorjpin = 6; // Начальная позиция, всегда 1.5 мс для регуляторов бесколлекторных двигателей int jsjposition = 1500; // Максимальное значение ШИМ 2.3 мс int maxjposition = 2300; // Минимальное значение ШИМ 0.8 мс int minjposition = 800; void setup() { // Инициализация мотора motor. attach (motorjpin, j sjposition, max_position); // Начальная установка регулятора в нулевое положение motor.writeMicroseconds(jsjposition); delay(700);
Глава 11. Подключение к Arduino исполнительных устройств 235 void loop () { // Считывание положения потенциометра jsjposition = analogRead (АО); // Преобразование положения потенциометра js_position = map(js_position, 0r 1023, 800, 2300); motor.writeMicroseconds(jsjposition); // Задержка 20 мс delay(20); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\ii\J1J)7 сопровож- дающего книгу электронного архива (см. приложение 2).
ГЛАВА 12 Arduino и беспроводная связь Беспроводная передача данных (беспроводная связь) — связь, которая осуществля- ется в обход проводов по радиоканалу. В мире Arduino существует множество устройств беспроводной связи. Здесь мы рассмотрим некоторые из них. 12.1. ИК-управление Устройства инфракрасного (ИК) диапазона волн часто применяются в робототех- нике, поскольку на сравнительно недорогих ИК-приемопередатчиках можно орга- низовать вполне полноценный обмен данными. Самое простое их применение — использование ИК-пульта для управления роботом. При этом пульт служит в ка- честве передатчика. Для приема сигнала с пульта используется специальный ИК-приемник — датчик, который воспринимает инфракрасный сигнал только на определенной частоте (30, 33, 36, 38, 40 кГц) и игнорирующий посторонние световые шумы от ламп освеще- ния и солнца. В своих проектах мы можем задействовать любой пульт и соответствующий по частоте приемник, а можно приобрести и комплект (рис. 12.1). Рис. 12.1. Комплект в составе ИК-пульта и ИК-приемника
238 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 12.2. Монтажная схема подключения ИК-приемника к плате Arduino Монтажная схема подключения ИК-приемника к плате Arduino показана на рис. 12.2. Библиотека для работы с ИК-приемником, поставляемая в составе Arduino ШЕ, не содержит примеров. Чтобы посмотреть и попробовать примеры работы с ИК- приемником, необходимо установить расширенную библиотеку. Но сначала необ- ходимо удалить встроенную библиотеку. Для этого заходим в каталог установки Arduino ШЕ и из каталога libraries удаляем папку RobotlRRemote. Затем с сайта https://github.com/z3tO/Arduino-IRremote скачиваем архив, содержащий обнов- ленную библиотеку IRemote, и устанавливаем ее в Arduino ШЕ командой меню Эскиз | Include library | Add ZIP library. Электронный архив Библиотека IRemote размещена в каталоге libraries сопровождающего книгу электрон- ного архива (см. приложение 2). После установки расширенной библиотеки в Arduino ГОЕ появятся примеры. Выбе- рем пример IRRecvDemo (рис. 12.3) и загрузим его скетч в плату Arduino, предва- рительно поменяв контакт подключения приемника на D2, как показано на схеме подключения (см. рис. 12.2). Содержимое исправленного скетча показано в листин- ге 12.1. // подключение библиотеки #include <IRremote.h> // пин подключения приемника int RECV_PIN = 2; // создаем объект ИК-приемника IRrecv irrecv(RECV_PIN); // создаем структуру результата приема данных decode results results;
Глава 12. Arduino и беспроводная связь 239 void setup() { // запустить последовательный порт Serial.begin(9600); // запустить приемник irrecv.enablelRIn(); void loop () { // если данные получены if (irrecv.decode(&results)) { // вывод кода в последовательный порт Serial.printIn(results.value, HEX); irrecv.resume(); // ждать следующее нажатие Рис. 12.3. Пример IRRecvDemo в списке библиотек Arduino IDE
240 Часть III. Сопряжение Arduino со вспомогательными устройствами Загрузив этот скетч в плату Arduino, мы можем получить коды клавиш (табл. 12.1), которыми воспользуемся в дальнейшем в примере управления сервоприводом с ИК-пульта (см. разд. 12.1.1). Возможно для вашего пульта будут актуальны дру- гие коды. Таблица 12.1. Коды клавиш пульта для управления Кнопка пульта - ОК Т 4 Код FF22DD FFC23D FF02FD FF629D FFA857 FF42BD Действие Вращение влево Вращение вправо Стоп В крайнее левое В крайнее правое В среднее положение 12.1.1. Управление сервоприводом с помощью ИК-связи Итак, подключим к плате Arduino ИК-приемник и сервопривод (монтажная схема этого проекта представлена на рис. 12.4) и напишем скетч (листинге 12.2), преду- сматривающий, что коды, отправляемые ИК-пультом, принимаются ИК-датчиком и анализируются скетчем на совпадение с кодами из таблицы. При совпадении вызываются соответствующие подпрограммы вращения вала сервопривода. Загружаем этот скетч в плату Arduino и управляем движением сервопривода с по- мощью пульта. Рис. 12.4. Монтажная схема подключения ИК-приемника и сервопривода к плате Arduino
Глава 12. Arduino и беспроводная связь 241 II Константы для кодов пульта idefine KOD_POS0 0xFF629D fdefine KOD_POS180 0xFFA857 tdefine KOD_LEFT 0xFF22DD tdefine KOD_RIGHT 0xFFC23D idefine KOD_STOP 0xFF02FD idefine KOD_POS90 0xFF42BD // подключение библиотеки IRremote iinclude <IRremote.h> // пин подключения приемника const int RECV_PIN = 2; // создаем объект ИК-приемника IRrecv irrecv(RECV_PIN); | // создаем структуру результата приема данных decode_resuits results; // подключение библиотеки Servo iinclude <Servo.h> // создать объект servo Servo servol; // пин для подключения сервопривода const int pin_servo=9; // для хранения текущей позиции сервопривода int angle = 0; // для хранения направления 1 или -1 int dir=l; // движение 1, останов 0 int go=l; void setup () { // подключить управление сервоприводом к пину pin_servo servol.attach(pin_servo); // запустить приемник irrecv.enablelRIn(); void loopO { if (irrecv.decode(&results)) { // проверка кода и выбор действия switch(results.value) { case KOD POSO:
242 Часть III. Сопряжение Arduino со вспомогательными устроистват go=0; angle=O; gojpos (angle); break; case KOD_POS180: go=l8 0;angle=O;gojpos(angle); break; case KODJPOS90: go=90;angle=O;go_pos(angle); break; case KODJLEFT: dir=-l;go=l; break; case KOD_RIGHT: dir=l;go=l; break; case KODSTOP: break; default: break; } // ждать следующее нажатие irrecv.resume(); } // если серва движется if(go—1) { angle=angle+dir; go_pos(angle); //в крайних позициях - стоп if(angle==0 I I angle==180) go=0; // установить в позицию void gojpos(int ang) { // команда установки положения сервопривода servol.write(ang); // время на перемещение сервопривода delay(15); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\12\_12j)2 сопрово- ждающего книгу электронного архива (см. приложение 2).
Гпава 12. Arduino и беспроводная связь 243 12.2. Радиомодули для частоты 433 МГц Еще одним широко распространенным среди разработчиков способом организации беспроводной связи в проектах Arduino является использование радиомодулей, работающих на частоте 433,920 МГц. Частота 433,920 МГц выделена для работы маломощных цифровых передатчиков, например: радиобрелоков автосигнализа- ции, брелоков управления шлагбаумами, радиолюстрами, радиорозетками, радио- моделями. Радиомодули передатчика FS1000A (рис. 12.5) и приемника MX-RM-5V (рис. 12.6) позволяют организовать радиосвязь на расстоянии до 100 м. Данные при этом передаются только в одном направлении. Для полноценной работы к модулю пере- датчика необходимо припаять антенну. Рекомендуемая длина антенны для пере- датчиков с частотой 433 МГц равна 17 см. DATA +5B 3-12B f MQ / GND SE ^ "V DATA Рис. 12.5. Модуль радиопередатчика FS1000A Рис. 12.6. Модуль радиоприемника MX-RM-5V 12.2.1. Управление светодиодом платы Arduino с другой такой же платы по радиоканалу 433 МГц Подсоединим приемник к первой плате Arduino, передатчик — ко второй и попро- буем управлять включением/выключением светодиода на второй плате Arduino на- жатием кнопок, подсоединенных к первой плате Arduino. При программировании подключим библиотеку RCSwitch. Электронный архив Библиотека RCSwitch размещена в каталоге libraries сопровождающего книгу элек- тронного архива (см. приложение 2). Содержимое скетча для первой платы Arduino (с двумя кнопками и передатчиком FS1000A) показано в листинге 12.3.
244 Часть III. Сопряжение Arduino со вспомогательными устройствами // подключение библиотеки #include <RCSwitch.h> // создание объекта RCSwitch mySwitch = RCSwitch(); // пины для подключения кнопок int pinButtons[]={10,11}; // для сохранения предыдущих состояний кнопок int lastButtons[]={0,0}; // для сохранения текущих состояний кнопок int currentButtons[]={0,0}; void setup() { // активировать передатчик // пин подключения вывода Data 12 mySwitch.enableTransmit(12); void loop () { // проверка нажатия кнопок выбора программ for(int i=0;i<2;i++) { // борьба с дребезгом currentButtons [i] = debounce(lastButtons [i]fpinButtons [i]); if (lastButtons [i] == 0 && currentButtons [i] — 1) // если нажатие. { doButtons(i); } lastButtons[i] = currentButtons[i]; // обработка нажатия клавиш void doButtons(int but) { switch(but) { case 0: mySwitch.send(B0100, 4); break; case 1: mySwitch.send(B0100, 4); break; default: break;
Гпава 12. Arduino и беспроводная связь 245 II Функция сглаживания дребезга // Принимает в качестве аргумента предыдущее состояние кнопки // и выдает фактическое. int debounce (int last,int pinl) { int current = digitalRead(pinl); // Считать состояние кнопки if (last != current) // если изменилось... { delay(5); // ждем 5 мс current = digitalRead(pinl); // считываем состояние кнопки return current; // возвращаем состояние кнопки В цикле loop о ждем нажатия кнопки и с помощью функции myswitch.sendo отправляем сообщение по радиоканалу. В параметрах функции указываются сооб- щение для отправки и размер сообщения в битах. Электронный архив Полный вариант рассмотренного скетча находится в папке examples\i2\_12_03 сопрово- ждающего книгу электронного архива (см. приложение 2). Содержимое скетча для второй платы Arduino (с приемником MX-RM-5V) показа- но в листинге 12.4. // подключение библиотеки linclude <RCSwitch.h> // создание объекта RCSwitch mySwitch = RCSwitch (); // пин для подключения светодиода int pinLed=13; void setup () { // вывод светодиода как OUTPUT pinMode(pinLed, OUTPUT ); // инициализация приемника // Используется прерывание 0 (вывод 2) mySwitch.enableReceive(0); void loop () { if (mySwitch.available()) { int value = mySwitch.getReceivedValue(); if (value — B1000) digitalWrite(pinLed, HIGH); // включить
246 Часть III. Сопряжение Arduino со вспомогательными устройствами else if (value — В0100) digitalWrite(pinLed, LOW); // выключить mySwitch.resetAvailable(); Электронный архив Полный вариант рассмотренного скетча находится в папке examplesU2\J2JM сопрово- ждающего книгу электронного архива (см. приложение 2). Приемник MX-RM-5V критичен даже к небольшим пульсациям на шине питания, Если Arduino управляет устройствами, вносящими даже небольшие, но постоянные пульсации в шину питания, то приемник расценивает эти пульсации как сигнал, Влияние пульсаций на приемник можно снизить установкой на шине питания при- емника сглаживающего конденсатора или использованием для приемника отдель- ного стабилизированного источника питания. 12.3. Радиомодули NRF24L01 Еще одним— очень популярным и бюджетным— вариантом соединения двух Arduino-устройств по радиоканалу является использование беспроводных модулей NRF24L01 (рис. 12.7). Малое энергопотребление, достойный радиус действия, высокая скорость передачи и низкая цена— вот основные качества радиомодуля NRF24L01. Рис. 12.7 Радиомодуль NRF24L01 Радиомодуль NRF24L01 представляет собой полудуплексное устройство: в один момент времени оно может либо передавать, либо принимать информацию. Чтобы обеспечить двустороннюю связь, нужно постоянно переключаться из одного режи- ма в другой. Модуль передает данные на частоте от 2,4 до 2,525 ГГц — в зависимо- сти от выбранного канала, которых в NRF24L01 доступно 126. Используется моду- ляция GFSK. Модуль подключается к Arduino по интерфейсу SPI. Один модуль способен поддерживать связь сразу с шестью приемниками или передатчиками, т. е. можно объединить сразу семь устройств в общую радиосеть на частоте
Глава 12. Arduino и беспроводная связь 247 2,4 ГГц. Максимальная скорость обмена данными между модулями составляет 2Мбит/с. Дальность передачи— до 100 м. Если вам нужно большее расстояние передачи, можно использовать модуль с внешней антенной (рис. 12.8), при этом расстояние передачи может составить до 1000 м со скоростью 250 Кбит/с (или 500 м со скоростью до 2 Мбит/с). Рис. 12.8. Радиомодуль NRF24L01 с внешней антенной Как уже отмечалось, радиомодуль NRF24L01 подключается к плате Arduino при помощи SPI-интерфейса. При этом, в зависимости от используемой библиотеки, может задействоваться и дополнительный выход прерывания IRQ. Но в нашем примере мы обойдемся без него. Схема соединения контактов радиомодуля NRF24L01 и платы Arduino выглядит следующим образом (табл. 12.2). Таблица 12.2. Схема Радиомодуль NRF24L01 Arduino Uno соединения контактов радиомодуля NRF24L01 GND GND VCC +3,3 В СЕ 9 CSN 10 MOS! 11 и платы Arduino MISO 12 SCK 13 Монтажная схема подключения радиомодуля NRF24L01 к плате Arduino показана на рис. 12.9. Питание модуля — 3,3 В, но выводы модуля толерантны и к 5 В. На многих платах Arduino имеется встроенный стабилизатор напряжения на 3,3 В, но он, однако, не обладает достаточной мощностью для правильной работы NRF24L01. Особенно эта проблема актуальна для Arduino Mega. В связи с этим, для питания радиомодулей NRF24L01 рекомендуется использовать внешние стаби- лизаторы.
248 Часть III. Сопряжение Arduino со вспомогательными устройствами ?»е»'»в|а^»>*^ж»«Ж!в^?а^1щдг?;«?|^вг*%й!йЬ«ж«?5а' Рис. 12.9. Монтажная схема подключения радиомодуля NRF24L01 к плате Arduino 12.3.1. Организация связи между двумя платами Arduino с использованием модулей NRF24L01 Установим связь между двумя платами Arduino с использованием модулей NRF24L01. При этом к первой плате подсоединен датчик влажности и температуры DHT11 (монтажная схема соединений для этой платы показана на рис. 12.10). Каж- дые 30 секунд отправляем данные этого датчика по радиоканалу, кроме того, каждые 5 секунд проверяем соединение — отправляем данные и ждем ответа. При Рис. 12.10. Монтажная схема подключения модуля NRF24L01 и датчика DHT11 к плате Arduino
Глава 12. Arduino и беспроводная связь 249 отсутствии ответа сигнализируем светодиодом на выходе 13 о проблемах с соеди- нением. Для взаимодействия Arduino с модулями NRF24L01 подключим библиотеку RF24. Электронный архив Библиотека RF24 размещена в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2). Содержимое скетча для первой платы Arduino показано в листинге 12.5. // пауза отправки данных для контроля связи idefine PAUSE_SEND_STATUS 5000 . // максимальное время ожидания ответа от NRF2401 idefine TIME_WAIT_STATUS 500 // пауза отправки данных текущих температуры и влажности tdefine PAUSE_SEND_DATA 30000 // идентификатор канала idefine ID 0x357340 // номер канала idefine CHANNEL 5 // нулевой байт idefine TEMP 56 // температура текущая idefine HUMIDITY 57 // влажность текущая idefine STAT 59 // проверка статуса сети // Подключаем библиотеку для работы с шиной SPI iinclude <SPI.h> // Подключаем файл настроек из библиотеки RF24 iinclude <nRF24L01.h> // Подключаем библиотеку для работы с NRF24L01 iinclude <RF24.h> // Создаем объект radio для работы с библиотекой // RF24, указывая номера выводов nRF24L01+ (CE, CSN) RF24 radio (9, 10); // Создаем массив для приема данных int data[2]; // подключение библиотеки DTH iinclude "DHT.h" // создание экземпляра объекта DHT DHT dht(4, DHT11) ; ansigned long millissendstatus=0; ansigned long millissenddata=0; unsigned long millisgetstatus=0;
250 Часть III. Сопряжение Arduino со вспомогательными устройствами //О - передаем, 1 - получаем int mode^O; void setup(){ Serial.begin(9600); // Инициируем работу NRF24L01+ radio.begin(); // Указываем канал передачи данных (от 0 до 127), // 5 - значит передача данных осуществляется на частоте 2,405 ГГц // (на одном канале может быть только 1 приемник и до б передатчиков) radio.setChannel(CHANNEL); // Указываем скорость передачи данных (RF24_250KBPS, RF24_JLMBPS, RF24__2MBPS) radio.setDataRate (RF24_1MBPS); // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, // RF24JPA_LOW»-12dBtti, RF24JPAJiIGH=-6dBm, RF24_PA_MAX=0dBm) radio. setPALevel (RF24_PA_HIGH) ; // Открываем для передачи данных с идентификатором ID radio.openWritingPipe (ID); Serial.println("start radio"); // запуск DHT dht.begin(); Serial.println("ready"); void loopO { // отправляем данные radio if(mode=-0) { // отправка данных влажности и температуры if (millis () -millissenddata>PAUSE_SEND_DATA) { // получение данных с датчика int h = dht.readHumidityO ; Serial.print("Humidity="); Serial.print(h); data[0] = HUMIDITY; data[l] - h; // отправляем данные из массива data radio.write(&data, sizeof(data)); delay(100); int t = dht. readTemperature (); Serial.print(" Temperature="); Serial.println(t); data[0] = TEMP; data[l] = t; // отправляем данные из массива data radio.write(&data, sizeof(data)); millissenddata=millis(); millissendstatus=millis();
Глава 12. Arduino и беспроводная связь // отправка для ответа - статус сети if (millis() ~millissendstatus>PAUSE_SEND_STATUS) { data[0] - STAT; data[l] = 1; Serial.printIn("send"); // отправляем данные из массива data radio.write(sdata, sizeof(data)); delay(100); Serial.println("ok"); millissendstatus=millis(); radio.openReadingPipe(1, ID); radio.startListening(); mode=l; millisgetstatuss=millis (); delay(100); // получаем данные radio else { if(radio.available()) { radio.read(&data,sizeof(data)); Serial.print("get data="); Serial.print(data[0]); Serial.print(" "); Serial.println(data[ 1 ]); mode=0; radio.stopListening(); delay(100); radio.openWritingPipe (ID); } if (millis () -millisgetstatus>TIMEJ0AIT_STATUS) { mode=0; Serial.print("status - NO"); Serial.println(); radio.stopListening(); radio.openWritingPipe (ID); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\i2\_i2_05 сопрово- ждающего книгу электронного архива (см. приложение 2). Вторая плата Arduino, получая по радиоканалу данные температуры и влажности, выводит их в последовательный порт. Если полученные данные — это запрос ста- туса, то отправляет ответ.
252 Часть III. Сопряжение Arduino со вспомогательными устройствами Содержимое скетча для второй платы Arduino показано в листинге 12.6. // идентификатор канала #define ID 0x357340 // номер канала #define CHANNEL 5 // нулевой байт #define TEMP,56 #define HUMIDITY 57 #define STAT 59 // Подключаем библиотеку для работы с .шиной SPI #include <SPI.h> // Подключаем файл настроек из библиотеки RF24 #include <nRF24L01.h> // Подключаем библиотеку для работы с NRF24L01 #include <RF24.h> // Создаем объект radio для работы с библиотекой // RF24, указывая номера выводов NRF24L01+ (СЕ, CSN) RF24 radio(9, 10); // Создаем массив для приема данных int data[2]; void setup() { // Запуск последовательного порта Serial.begin(9600); Serial.begin(9600); // Инициируем работу NRF24L01+ radio.begin(); // Указываем канал передачи данных (от 0 до 127), // 5 - значит передача данных осуществляется на частоте 2,405 ГГц // (на одном канале может быть только 1 приемник и до б передатчиков) radio.setChannel(CHANNEL); // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS) radio.setDataRate (RF24_1MBPS); // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, // RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm) radio.setPALevel (RF24_PA_HIGH); // Открываем для приема данных с идентификатором ID radio.openReadingPipe (1, ID); Serial.println("start radio"); // Включаем приемник, начинаем прослушивать radio.startListening ();
Глава 12. Arduino и беспроводная связь 253 void loop () { // Если в буфере имеются принятые данные if(radio.available()) { // Читаем данные в массив data и указываем сколько байтов читать radio.read(&data, sizeof(data)); // проверка dataО switch(data[0]) { case TEMP: // температура текущая Serial.print("Temperatura tek="); Serial.println(data[1]); break; case HUMIDITY: // влажность текущая Serial.print("Humidity tek="); Serial.println(data[1]); break; case STAT: // проверка статуса сети Serial.print("status^"); Serial.println(data[1]); radio.stopListening (); //на отправку delay(150); radio.openWritingPipe (ID); // отправить radio.write(&data, sizeof(data)); //на получение radio.openReadingPipe (1, ID); // Включаем приемник, начинаем прослушивать radio.startListening (); break; default: break; Электронный архив Полный вариант рассмотренного скетча находится в папке examplesM 2^12^06 сопрово- ждающего книгу электронного архива (см. приложение 2). 12.4. Использование Arduino с аппаратурой радиоуправления Аппаратура радиоуправления используется для управления движущимися моделя- ми и состоит из передатчика, который находится у пилота, и размещенных на модели приемнике и исполнительных механизмах. Для управления исполнитель-
254 Часть III. Сопряжение Arduino со вспомогательными устройствами ными механизмами нередко задействуются платы Arduino, которые должны полу- чать команды от приемника и обрабатывать эти команды в соответствии с зало- женными в их программу алгоритмами. По конструкции органов управления, на которые, собственно, и воздействуют пальцы пилота, передатчики делятся на джойстиковые (рис. 12.11) и пистолетного типа. В первых — которые и используются в основном для управления летающими моделями — установлены, как правило, два двухкоординатных джойстика. Рис. 12.11. Передатчик НК-Т6А Для управления движущимися моделями требуется выполнение одновременно нескольких функций. Поэтому передатчики радиоуправления делают многоканаль- ными. Так, для авто- и судомоделей требуются два канала: управление направлени- ем движения и оборотами двигателя. Для полноценного управления самолетом нужно не менее четырех, а вертолетом — пяти каналов. Для самолетов на два двухкоординатных джойстика выводятся функции управле- ния рулем высоты, направления, элеронами и «газом» (оборотами) двигателя. Кон- кретная раскладка функций по джойстикам бывает двух типов: □ Mode 1 (рис. 12.12): слева — руль высоты (по вертикали) и руль направления (по горизонтали), справа — «газ» (по вертикали) и крен (по горизонтали); □ а также Mode 2 (рис. 12.L3): слева— «газ» (по вертикали) и руль направления (по горизонтали), справа — руль высоты (по вертикали) и крен (по горизонтали). Есть еще типы раскладок Mode 3 и 4, но они мало распространены.
(пава 12. Arduino и беспроводная связь 255 L_l вниз полный газ вверх Рис. 12.12. Раскладка Mode 1 холостой ход холостой вверх ход Рис. 12.13. Раскладка Mode 2 12.4.1. Принципы формирования радиосигнала Для того чтобы излучаемый передатчиком радиосигнал мог переносить полезную информацию, он подвергается модуляции. То есть управляющий сигнал изменяет параметры несущей радиочастоты. На практике нашли применение управление ам- плитудой и частотой несущей, обозначаемые буквами AM (Amplitude Modulation, амплитудная модуляция) и FM (Frequency Modulation, частотная модуляция). В радиоуправлении используется только дискретная двухуровневая модуляция. В варианте AM несущая имеет либо максимальный, либо нулевой уровень. В вари- анте FM излучается сигнал постоянной амплитуды либо с частотой F, либо с чуть смещенной частотой F + df. Сигнал FM-передатчика напоминает сумму сигналов двух АМ-передатчиков, работающих в противофазе на частотах F и F + df соответ- ственно. Из этого можно понять, даже не углубляясь в тонкости обработки радио- сигнала в приемнике, что в одинаковых помеховых условиях FM-сигнал имеет принципиально большую помехозащищенность, чем АМ-сигнал. АМ-аппаратура, как правило, дешевле, однако разница не очень велика. В настоящее время исполь- зование АМ-аппаратуры оправдано только для тех случаев, когда расстояние до модели относительно невелико. Как правило, это справедливо для автомоделей, судомоделей и комнатных авиамоделей. Вообще, летать с использованием АМ- аппаратуры можно лишь с большой опаской и вдали от промышленных центров. Модуляция позволяет наложить на излучаемую несущую полезную информацию. Однако в радиоуправлении используется только многоканальная передача инфор- мации. Для этого все каналы уплотняются в один посредством кодирования. Сейчас
256 Часть III. Сопряжение Arduino со вспомогательными устройствами для этого используется только импульсно-фазовая модуляция, обозначаемая бук- вами PPM (Pulse Phase Modulation) и импуЛьсно-кодовая модуляция, обозначаемая буквами PCM (Pulse Code Modulation). На рис. 12.14 приведен типовой РРМ-сигнал пятиканальной аппаратуры, имеющий фиксированную длину периода Т = 20 мс. Это означает, что информация о положе- ниях ручек управления на передатчике попадает на модель 50 раз в секунду, что определяет быстродействие аппаратуры управления. Как правило, этого хватает, поскольку скорость реакции пилота на поведение модели намного меньше. Все ка- налы пронумерованы и передаются по порядку номеров. Значение сигнала в канале определяется величиной временного промежутка между первым и вторым импуль- сом — для первого канала, между вторым и третьим — для второго канала и т. д. Диапазон изменения величины временного промежутка при движении джойстика (ручки управления) из одного крайнего положения в другое определен от 1 до 2 мс, Значение 1,5 мс соответствует среднему (нейтральному) положению джойстика Продолжительность межканального импульса составляет около 0,3 мс. Такая структура РРМ-сигнала является стандартной для всех производителей аппаратуры радиоуправления. 0,3 мс КАНАЛЫ 3 4 Т=20мс Рис. 12.14. Типовой РРМ-сигнал пятиканальной аппаратуры 12.4.2. Организация связи приемника с передатчиком Рассмотрим организацию связи приемника НК-Т6А (рис. 12Л 5), установленного на управляемой модели в нашем проекте, с передатчиком управляющего сигнала. Как можно видеть, число каналов управления у этого приемника — шесть. Для начала необходимо связать между собой передатчик и приемник в следующем порядке: 1. Установить в передатчик батарею. 2. Вставить шнур для кодирования (показан на рис. 12.15, вверху) в контакты ВАТ приемника.
Глава 12. Arduino и беспроводная связь 257 Рис. 12.15. Приемник НК-Т6А (внизу); шнур с разъемом для кодирования приемника (вверху) 3. Соединить батарею питания приемника с одним из портов канала — если свето- диоды на приемнике и передатчике вспыхивают одновременно, значит прием- ник успешно включен. 4. Зажать (нажать и удерживать) кнопку поиска частоты на передатчике и вклю- чить питание — если светодиоды на приемнике не мигают, а просто горят, то связь установлена. 5. Отпустить кнопку на передатчике, отсоединить шнур на приемнике. 6. Установить сервомашинку в какой-нибудь из каналов и проверить работоспо- собность— при движении джойстиков на передатчике сервомашинка должна вращаться. Теперь можно подключить приемник к Arduino и разработать скетч для приема команд с передатчика. 12.4.3. Разработка скетча для приема платой Arduino команд передатчика Для считывания платой Arduino данных, поступающих с передатчика на приемник, подключаем сигнальные контакты приемника на выводы Dll, D10, D9, D8 платы Arduino. He забываем подать на приемник питание 5 В. Диапазон изменения вели- чины временного промежутка при движении джойстика из одного крайнего поло- жения в другое определен величиной от 1 до 2 мс. Для определения длительности сигнала, поступающего на входы, мы воспользуемся функцией puisein (). Напом- ним, что функция считывает длину сигнала на заданном порту (high или low). Например, если задано считывание high, функция puiseino ожидает, пока на за- данном порту не появится high. Когда high получено, включается таймер, который
258 Часть III. Сопряжение Arduino со вспомогательными устройствами будет остановлен, когда на порту входа/выхода появится low. Длину сигнала функ- ция puisein () возвращает в микросекундах. Если же в течение заданного времени (тайм-аута) сигнал на порту зафиксирован не был, функция возвращает 0. Синтаксис функции puisein (): pulseln(pin, value) puisein(pin, value, timeout) Параметры: □ pin — номер порта входа/выхода, на котором будет ожидаться сигнал; □ value — тип ожидаемого сигнала (high или low); □ timeout— время ожидания сигнала (тайм-аут) в микросекундах; по умолча- нию — одна секунда. Возвращаемое значение: длина сигнала в микросекундах или 0, если сигнал не по- лучен до истечения тайм-аута. Выбираем поочередно порт для 1, 2, 3 и 4-го каналов, параметр vaiue=HiGH, timeout=2 мсек. Получаемое значение сигнала: от 1 до 2 мсек. Данные, полученные с передатчика, выводим в последовательный порт (рис. 12.16). Как можно видеть, при перемещении джойстиков передатчика изменяется значение считываемого сиг- нала. i iisr,4 - O^J '■; |Uii4V(4luti ; g I -'■■— A --* "-■•— ---»- --»- Рис. 12.16. Вывод данных, полученных платой Arduino с передатчика, в монитор последовательного порта Содержимое скетча, обеспечивающего прием платой Arduino команд передатчика, приведено в листинге 12.7. // передатчик - НК-Т6А // приемник - // приемник :
Глава 12. Arduino и беспроводная связь 259 II Chi - Rudder (руль направления, рыскание, YAW) // Ch2 - Elevator (тангаж, PITCH) // Ch3 - Throttle (газ) // Ch4 - Aileron (элероны, ROLL) unsigned long ChlValue,Ch2Value,Ch3Value,Ch4Value; unsigned long Iastl,last2,last3,last4; int pinChl=ll; int pinCh2=10; int pinCh3=9; int pinCh4=8; void setup () { Serial.begin(9600); Serial.printIn("Ready"); pinMode (pinChl, INPUT); // connect Rx channel 1 pinMode (pinCh2, INPUT); // connect Rx channel 2 pinMode (pinCh3, INPUT); // connect Rx channel 3 pinMode (pinCh4, INPUT); // connect Rx channel 4 lastl = pulseln (pinChl, HIGH); //read RC channel 1 Iast2 « pulseln (pinCh2, HIGH); //read RC channel 2 Iast3 = pulseln (pinCh3, HIGH); //read RC channel 3 Iast4 = pulseln (pin€h4, HIGH); //read RC channel 4 void loop() { // ChlValue = pulseln (pinChl, HIGH, 20000); //read RC channel 1 if (ChlValue = 0) {ChlValue = lastl;} else {lastl = ChlValue;} Serial.print (" Chi: ");Serial.print (ChlValue); // Ch2Value = pulseln (pinCh2, HIGH, 20000); //read RC channel 2 if (Ch2Value — 0) {Ch2Value = Iast2;} else {Iast2 = Ch2Value;} Serial.print(" Ch2: ");Serial.print (Ch2Value); // Ch3Value = pulseln (pinCh3, HIGH, 20000); //read RC channel 3 if (Ch3Value — 0) {Ch3Value = Iast3;} else {Iast3 = Ch3Value;} Serial.printC Ch3: ");Serial.print (Ch3Value); // Ch4Value = pulseln (pinCh4, HIGH, 20000); //read RC channel 4 if (Ch4Value — 0) {Ch4Value = Iast4;} else {Iast4 = Ch4Value;} Serial.print(" Ch4: ");Serial.print (Ch4Value); Serial.printIn("");
260 Часть III. Сопряжение Arduino со вспомогательными устройствами Электронный архив Полный вариант рассмотренного скетча находится в папке examples\i2\__12J)7 сопрово- ждающего книгу электронного архива (см. приложение 2). 12.5. Arduino и Bluetooth Беспроводной интерфейс Bluetooth является одним из самых популярных интер- фейсов, которые любители программирования Arduino выбирают для связи созда- ваемого ими устройства с мобильным приложением. Связь, как правило, осуществ- ляется с помощью подключаемых к плате Arduino Bluetooth-модулей НС-05 или НС-06 — недорогих и широко распространенных. Bluetooth-модуль общается с платой Arduino по последовательному порту и работа- ет в двух режимах: □ отправки/получения по Bluetooth данных, поступающих на него по последова- тельному порту; □ в режиме программирования модуля отправкой АТ-команд. Для входа в режим программирования необходимо подать на контакт KEY модуля (рис. 12.17) сигнал высокого уровня 3,3 В. На некоторых модулях контакт KEY от- сутствует, и на его месте присутствует контакт EN. В этом случае для входа в ре- жим программирования необходимо подать сигнал высокого уровня на контакт 34 (рис. 12.18). Рис. 12.17. Bluetooth-модуль НС-05 Рис. 12.18. Bluetooth-модуль НС-05 с контактом KEY без контакта KEY: подключение для входа в режим программирования Рассмотрим настройку модуля в режиме программирования отправкой АТ-команд по последовательному порту. Подключим модуль НС-05 к плате Arduino по схеме соединений, показанной на рис. 12.19. На контакт KEY модуля (или вывод 34 пла-
Глава 12. Arduino и беспроводная связь 261 ты) подадим 3,3 В. АТ-команды будем отправлять из монитора последовательного порта Arduino IDE. При программировании подключаем Arduino-библиотеку SoftwareSerial. Содержи- мое скетча показано в листинге 12.8. Скорость UART-модуля в режиме программи- рования 38 400 бод, но может и отличаться, в этом случае ее следует подобрать. Рис. 12.19. Монтажная схема подключения модуля НС-05 к плате Arduino для режима отправки АТ-команд tinclude <SoftwareSerial.h> // указываем пины гх и tx соответственно SoftwareSerial inySerial (2, 3) ; void setup () { pinMode(2,INPUT); pinMode(3,OUTPUT); Serial.begin(9600); mySerial.begin(38400);
262 Часть III. Сопряжение Arduino со вспомогательными устройствами Serial.println("start prg") ; void loop() { if (mySerial.available()) { char с = mySerial.read(); // читаем из software-порта Serial.print(c); // пишем в hardware-порт } if (Serial.availableO) { char с = Serial.read(); // читаем из hardware-порта mySerial.write(с); // пишем в software-порт Электронный архив Полный вариант рассмотренного скетча находится в папке examples\12\J2J)8 сопрово- ждающего книгу электронного архива (см. приложение 2). Загрузив этот скетч в плату, откроем монитор последовательного порта Arduino IDE и начнем отправлять АТ-команды (рис. 12.20). Вот список основных АТ-команд: □ at — тестовая команда. Параметров нет. Ответ модуля: ок вкя«»яа*гав«г№Зяв«г!В(*зв8НЩйЖв»я»^^ Рис. 12.20. Отправка АТ-команд в модуль НС-05
Глава 12. Anduino и беспроводная связь 263 □ at+version? — получить версию прошивки модуля. Параметров нет. Ответ МОДУЛЯ:+VERSION: <Param> где <Param> — версия прошивки Bluetooth-модуля. □ at+reset — сброс настроек. Параметров нет. Ответ модуля: ок О at+orgl — установка пользовательских настроек модуля. Параметров нет. Ответ модуля: ок □ at+addr? — получить адрес модуля. Параметров нет. Ответ МОДУЛЯ: +ADDR: <Param> где <Param> — адрес Bluetooth-модуля NAP: UAP : LAP. □ AT+NAME? ПОЛуЧИТЬ ИМЯ МОДУЛЯ. Параметров нет. Ответ МОДУЛЯ: +NAME:<Param> где <Param> — имя Bluetooth-модуля. □ AT+NAME=<Param> — установить новое имя модуля. Параметр: <Param> — имя Bluetooth-модуля. Ответ модуля: +NAME:<Param> ок (или fail) □ at+pswd? — получить пин-код доступа к Bluetooth-модулю. Параметров нет. Ответ МОДУЛЯ: + PSWD:<Param> где <Param> — пин-код. По умолчанию 1234. □ AT+PSWD=<Param> — установить код доступа к Bluetooth-модулю. Параметр: <Param> — код доступа к модулю. Ответ модуля: ок (или fail) □ AT+CLASS=<Param> — установить режим работы модуля Bluetooth-модуля. Параметр: <Param> — класс. В документации модуля не приведены возможные значения этого параметра. По умолчанию он установлен в 0. Если предполагает- ся использовать модуль в режиме master, значение не надо изменять. Если использовать модуль в режиме slave, при значении параметра, равном 0, он не-
264 Часть III. Сопряжение Arduino со вспомогательными устройствами видим для устройств с операционной системой Android. Для видимости необхо- димо установить значение параметра, равное 7936. Ответ модуля: ок □ at+class? — получить класс модуля. Параметров нет. Ответ модуля: +CLASS: <Param> где <Param> — класс модуля. □ at+role? — получить режим работы модуля. Параметров нет. Ответ МОДУЛЯ: +ROLE:<Param> где <Param> — режим работы модуля Bluetooth-модуля: • о — slave. В этом режиме другой мастер может подключиться к модулю; • 1 — master. В этом режиме модуль может сам подключиться к какому-нибудь Bluetooth-устройству; • 2 — slave-loop. Модуль отправляет обратно все байты, которые ему прислали. AT+ROLE=<Param> — установить режим работы Bluetooth-модуля. Параметр: <Param> — режим работы Bluetooth-модуля: • о — slave; • 1 — master; • 2 — slave. Ответ модуля: ок □ AT+UART=<Parami>,<Param2>,<Param3> —установить модуль для последовательно- го порта. Параметры: • <Parami> — скорость обмена (9600,19200,38400,57600,115200); • <Param2> — СТОП-бит: п о — нет; D 1 — есть; <Param3> — бит паритета: D о — нет; ° 1 — есть. Ответ модуля: ок (или fail) □ at+uart? — получить параметры обмена модуля. Параметров нет.
Глава 12. Arduino и беспроводная связь 265 Ответ модуля: +UART: <Paraml>, <Param2>, <РагашЗ> где: • <Parami> — скорость обмена (9600, 19200, 38400, 57600, 115200); • <Param2> — СТОП-бит; • <Param3> — бит паритета. □ AT+CMODE=<Param> — установить режим подключения Bluetooth-модуля. Параметр: <Param> — режим подключения Bluetooth-модуля: • о— модуль может подключаться только к определенному командой AT+BIND Bluetooth-устройству; • 1 — модуль может подключаться к любому Bluetooth-устройству; • 2 — режим slave-loop. Ответ модуля: ок 0 at+cmode? — получить режим подключения модуля. Параметров нет. Ответ МОДУЛЯ: +CMODE:<Param> где <Param> — режим подключения Bluetooth-модуля: • о — модуль может подключаться только к определенному командой AT+BIND Bluetooth-устройству; • 1 — модуль может подключаться к любому Bluetooth-устройству; • 2 — режим slave-loop. □ AT+iNQ — запуск поиска Bluetooth-устройств. Параметров нет. Ответ модуля — список найденных устройств. □ AT+BiND=<Param> — привязать Bluetooth-модуль к другому модулю. Параметр: <Param> — адрес авторизованного Bluetooth-модуля. Ответ модуля: ок (или fail) О AT+BIND? — получить адрес устройства, привязанного к Bluetooth-модулю. Параметров нет. Ответ модуля: <Param> — адрес устройства, привязанного к Bluetooth-модулю. О AT+LiNK=<Param> — соединиться с Bluetooth-устройством. Параметр: <Param> — адрес Bluetooth-устройства. Ответ модуля: ок (или fail)
266 Часть III. Сопряжение Arduino со вспомогательными устройствами После программирования модуля отсоединим контакт KEY модуля (или вывод 34) от 3,3 В и попробуем подсоединиться к модулю с телефона (или планшета) на опе- рационной системе Android (рис. 12.21-12.23). Подключившись, можно организовать обмен данными между телефоном и платой Arduino. # MtiTJEC Рис. 12.21. Модуль НС-05 (устройство МЕТЕО) найдено -f^5»tti««f; в Рис. 12.22. Запрос на соединение с найденным устройством
Глава 12. Arduino и беспроводная связь 267 Рис. 12.23. Подключение к модулю НС-05 (устройству МЕТЕО) с телефона Android состоялось
ГЛАВА 13 Arduino и Интернет вещей Интернет вещей ( Internet of Things, IoT) — это широкая сеть объектов, связанных через Интернет и способных обмениваться данными. Интернет вещей предполагает оснащение каждого устройства, будь то пылесос, холодильник или стиральная ма- шина, модулем подключения к Интернету с возможностью взаимодействия его с домашним компьютером или смартфоном домовладельца. В этой главе мы рас- смотрим организацию доступа Arduino к сети Интернет с дальнейшей отправкой данных в известные облачные сервисы и получением их оттуда. 13.1. Подключение к Интернету с помощью платы расширения Ethernet shield Самый распространенный метод обеспечить доступ платы Arduino к сети Интер- нет— использование платы Ethernet shield (рис. 13.1). Ethernet shield— это плата расширения, которая устанавливается на плату Arduino сверху. Она дает ей воз- можность выступать в роли сетевого устройства и общаться по проводной сети с аналогичными устройствами, с обычными компьютерами, принтерами, сервисами в Интернете и прочими сетевыми ресурсами. Последняя версия платы Ethernet Shield Rev3 полностью совместима с Arduino Mega 2560. Плата Ethernet shield основана на микросхеме Wiznet W5100, которая поддерживает как TCP-, так и UDP-протоколы. Одновременно открытыми могут быть до четырех подключений. Плата обладает стандартным ethernet-портом для подключения к сети с помощью патч-корда витой пары и набором контактов для подключения к Arduino. Для общения между собой Ethernet shield и Arduino задействуют контакты 4-й и с 10-го по 13-й, поэтому их использование в других целях в присутствии платы расширения невозможно. Для программирования сетевого взаимодействия подключается библиотека Ethernet из стандартного дистрибутива. При использовании этой библиотеки необходимо указывать МАС-адрес платы (уникальный идентификатор любого сетевого устрой- ства). В более новых версиях Ethernet-шилда МАС-адрес можно увидеть на наклей-
270 Часть III. Сопряжение Arduino со вспомогательными устройствами ке на плате. Если такой наклейки нет, то просто введите любую похожую комбина- цию, — главное, чтобы в вашей сети не было устройств с совпадающими МАС- адресами. На плате размещен слот для карты памяти формата microSD, которая может быть использована для хранения ресурсов, раздаваемых по сети. Для взаимодействия с такой картой следует подключить, например, библиотеку sdfatlib. Для отправки данных в облачные сервисы в примерах этого раздела мы воспользу- емся веб-клиентом на основе платы Arduino с установленной на нее платой расши- рения Ethernet shield. Рис. 13.1. Плата Ethernet shield Rev3 13.1.1. Получение IP-адреса по DHCP Соединим Ethernet shield с платой Arduino и создадим простой пример получения ими IP-адреса по DHCP. Соединяется Ethernet shield с платой Arduino так же про- сто, как и любой другой шилд, — просто состыкуйте их вместе. Следует учесть, что установка других шилдов поверх Ethernet shield весьма затруднительна. Это связано с большими размерами имеющегося на плате Ethernet shield разъема RJ-45, служащего для подключения сетевого кабеля, поэтому, если вы хотите использо- вать совместно с Arduino еще и другие шилды, лучше их размещать между Arduino и Ethernet shield. Итак, подключим плату Arduino к USB-порту компьютера, a Ethernet shield подсо- единим с помощью сетевого кабеля к маршрутизатору, имеющему выход в Интер- нет (рис. 13.2). Скетч, обеспечивающий получение IP-адреса по DHCP, представлен в листин- ге 13.1, а пример назначения статического IP-адреса — в листинге 13.2.
Глава 13. Arduino и Интернет вещей 271 " '"' v':"';/-i/^.~.'v-*"f''''';- *t-f'Ш^ж--Ъ%^-*Ш Рис. 13.2. Подключение к плате Arduino платы расширения Ethernet shield Rev3 // Получение IP-адреса по DHCP // МАОадрес Ethernet shield (можно увидеть на наклейке на плате) или // произвольный уникальный в сети tinclude <Ethernet.h> iinclude <SPI.h> byte mac[] - {0x00, OxAA, 0xBBf OxCC, OxDE, 0x02}; void setup () { // Open serial conmunications and wait for port to open: Serial.begin(9600); } // запуск Ethernet-соединения if (Ethernet.begin(mac) =0) { Serial.println("Failed to configure Ethernet using DHCP"); for (;;) // печать в последовательный порт полученного по DHCP адреса Serial.print("My IP address: "); for (byte thisByte - 0; thisByte < 4; thisByte++) { Serial.print(Ethernet.locallPO [thisByte], DEC); Serial.print("."); } Serial.println(); void loop () {;} Электронный архив Полный вариант рассмотренного скетча находится в папке examples\i3\_i3_0i сопрово- ждающего книгу электронного архива (см. приложение 2).
272 Часть III. Сопряжение Arduino со вспомогательными устройствами I/ Получение статического IP-адреса // МАС-адрес Ethernet shield (можно увидеть на наклейке на плате) или // произвольный уникальный в сети #include <Ethernet.h> #include <SPI.h> byte mac[] = {0x00, 0xAAf OxBB, OxCC, OxDE, 0x02}; // IP-адрес, назначаемый Ethernet shield: byte ip[] = { 192, 168, 0, 111 }; // IP-адрес dns сервера: byte sdns[] = { 192, 168, 1, 1 }; // адрес шлюза: byte gateway[] = { 192, 168, 0, 1 }; // маска: byte subnet[} = { 255, 255, 255, 0 }; void setup() { Serial.begin(9600); // запуск Ethernet-соединения Ethernet.begin(mac, ip, sdns, gateway, subnet); delay(lOOO); Serial.println(Ethernet.locallP() ) ; } void loop () {;} Электронный архив Полный вариант рассмотренного скетча находится в папке examples\13\_13J)2 сопрово- ждающего книгу электронного архива (см. приложение 2). 13.1.2. Отправка данных на сайт «Народный мониторинг» через Ethernet shield Получив доступ в Интернет, мы можем отправлять данные с платы Arduino в об- лачные сервисы. Рассмотрим пример отправки данных на сайт «Народный монито- ринг». «Народный мониторинг» (http://www.narodmon.ru) — это проект по сбору и ото- бражению на карте мира показаний температуры, атмосферного давления, влажно- сти и т. п. практически в реальном времени по фактическому их состоянию (а не на основе прогнозов), получаемых от различных датчиков среды, установленных как на улице для публичного доступа, так и в помещении для приватного, а также от веб-камер для частного или публичного доступа. Передавать показания датчиков на сайт «Народный мониторинг» можно посредством протоколов TCP/UDP или HTTP
Глава 13. Arduino и Интернет вещей 273 GET/POST. Минимальный интервал передачи показаний датчика — 5 минут (если передавать чаще, то возможна блокировка). Чтобы стать участником проекта, необходимо зарегистрироваться. Для этого захо- дим на сайт http://www.narodrnon.ru и выбираем пункт меню Вход | Стать участ- ником проекта. В регистрационной форме (рис. 13.3) вводим адрес электронной почты, на который будут отправлены логин и пароль для входа в профиль. Рис. 13.3. Регистрация на сайте «Народный мониторинг» Подключим к плате Arduino с установленной на нее платой расширения Ethernet shield датчик температуры LM335 (рис. 13.4) и настроим передачу показаний этого датчика на сайт «Народный мониторинг» и отображение их на его карте мира. Рис. 13.4. Монтажная схема подключения датчика температуры LM335 к плате Arduino с установленной на ней платой Ethernet shield W5100
274 Часть III. Сопряжение Arduino со вспомогательными устройствами Для добавления датчика на карту необходимо выполнить следующие действия: 1. Подключить устройство мониторинга (в нашем случае— плату Arduino с дат- чиком LM335) к источнику питания и к сети Интернет (через Ethernet shield). 2. Настроить передачу показаний на сайт «Народный мониторинг» с интервалом 5-15 минут (если чаще, то возможна блокировка). 3. Авторизоваться на сайте «Народный мониторинг», используя свой логин (e-mail или номер мобильного телефона) и пароль, полученные при регистрации. 4. В разделе сайта Мои Датчики добавить устройство, введя его уникальный ал- фавитно-цифровой код (МАС-адрес). Имейте при этом в виду, что добавление возможно только после успешной передачи показаний на сервер и при верно указанном МАС-адресе. 5. Выбрать тип данных для каждого из датчиков: температура, влажность, давле- ние и пр. 6. Установить доступ к показаниям для каждого датчика: публичный (виден всем) или приватный (только вам). 7. Указать названия для устройства мониторинга и подключенных к нему дат- чиков. 8. Выполнить привязку устройства мониторинга к карте, указав полный адрес его размещения или геокоординаты и щелкнув по строке с адресом в графе УСТРОЙСТВО раздела сайта Мои Датчики (уточнить местоположение мож- но, щелкнув на карте на маркере своего устройства и переместив в нужное место появившееся всплывающее окно). Для создания скетча (листинг 13.3) мы возьмем за основу рекомендованный ресур- сом student-proger.ru пример подключения к сервису «Народный мониторинг)) и изменим его под свои требования (сетевые параметры) и датчики. #include <SPI.h> #include <Ethernet.h> byte mac[] - { 0x94, OxDEf 0x80, 0x3Af 0x90, 0xC9 }; //МАС-адрес Arduino const unsigned long postingInterval = 600000; // интервал между отправками // данных 10 минут // IP-адрес, назначаемый Ethernet shield: byte ip[] = { 192, 168, 0, 119 }; // IP адрес, dns сервера: byte sdns[] « { 192, 168, 1, 1 }; // адрес шлюза: byte gateway!] = { 192, 168, 0, 28 }; // маска: byte subnet[] = { 255, 255, 255, 0 };
Глава 13. Arduino и Интернет вещей 275 IPAddress server(94,19,113,221); // IP сервера //IPAddress server(91,122,49,168); // IP сервера EthernetClient client; unsigned long lastConnectionTime = 0; // время последней передачи данных boolean lastConnected = false; // состояние подключения char replyBuf fer [160]; void setup () { Serial.begin(9600) ; // Ethernet connection: Ethernet.begin(mac,ip,sdns,gateway,subnet); // секунда для инициализации Ethernet delay(1000); // первое соединение через 15 секунд после запуска lastConnectionTime * millis()-postinglnterval+15000; void loop () { // если не подключены и прошло определенное время, то делаем замер, // переподключаемся и отправляем данные if (!client.connected() && (millisO - lastConnectionTime > postinglnterval)) { // формирование HTTP-запроса memset(replyBuffer, 0, sizeof(replyBuffer)); strcpy(replyBuffer/'IEH"); // Конвертируем МАС-адрес for (int k=0; k<6; k++) { int bl=mac[k]/16; int b2=mac[k]%16; char cl[2],c2[2]; if (bl>9) cl[0]=(char)(bl-10)+'Af; else cl[0] - (char)(bl) + f0f; if (b2>9) c2[0]=(char)(b2-10)+'Af; else c2[0] - (char)(b2) + f0f; strcat(replyBuffer,cl); strcat(replyBuffer,c2); } strcat(replyBuffer,"&"); strcat(replyBuffer,"3351C4BA0200003B"); strcat(replyBuffer,"=");
276 Часть III. Сопряжение Arduino со вспомогательными устройствами char temp[3]; double tmpd=(analogRead(A0)*5.0/1024)*100-273.15; int tmpi=int(tmpd); itos(tmpi, temp); strcat(replyBuffer,temp); strcat(replyBuffer, '\0f); //отправляем запрос httpRequest(); } // храним последнее состояние подключения lastConnected = client.connected(); } // функция отправки запроса void httpRequest() { if (client.connect(server, 80)) { // send the HTTP POST request: client.println("POST http://narodmon.ru/post.php HTTP/1.0"); client.println("Host: narodmon.ru"); client.println("Content-Type: application/x-www-form-urlencoded"); client.print("Content-Length: • "); client.println(len(replyBuffer)); client.println(); client.println(replyBuffer); client.println(); lastConnectionTime = millis(); } else { client.stop(); // размер данных int len(char *buf) { int i=0; do } while (buf[i]!='\0f); return i; } // функция int to string void itos(int n, char bufp[3]) // { char buf[3]={f0f,f0f,f\0f};
Гпава 13. Anduino и Интернет вещей 277 int i = 1; while (n > 0) { buf[i] = (n % 10)+48; i ; n /= 10; } for (i=0; i<3; i bufp[i]=buf[i]; Электронный архив Полный вариант рассмотренного скетча находится в папке examplesM3\_i3_03 сопрово- ждающего книгу электронного архива (см. приложение 2). Для передачи данных на сайт «Народный мониторинг» мы здесь используем ре- зервный протокол передачи HTTP POST/GET на URL http://narodmon.ru/post.php. HTTP-заголовки для POST следующие: POST http://narodmon.ru/post.php HTTP/1.0\r\n Host: narodmon. ru\r\n Content-Type: application/x-www-form-urlencoded\r\n Content-Length: NN (кол-во байт в строке данных ниже)\г\п \г\п II>MAC&rnacl=valuel&.. .&raacN=valueN[&time=UnixTime] [&name=NAME] [&lat=LAT] [&lng=LNGj После загрузки в плату Arduino этот скетч запускает Ethernet-соединение, плата получает IP-адрес в сети, один раз в 5 минут считываются данные с датчика темпе- ратуры, формируется строка с данными для отправки на сервер сайта «Народный мониторинг» и данные отправляются с использованием протокола HTTP POST. Теперь авторизуемся на сайте, используя логин и пароль, пришедшие на электрон- ную почту. Выбираем пункт меню Датчики | Мои Датчики | Добавить устройст- во и вводим МАС-адрес нашего устройства. Если данные уже были отправлены на сайт, устройство будет добавлено (рис. 13.5). Затем выбираем тип данных нашего датчика (температура), устанавливаем доступ к показаниям (приватный), указываем название устройства мониторинга и выпол- няем привязку его к карте, указав полный адрес и щелкнув по строке с адресом. Выбираем опцию Показать на карте (см. рис. 13.5) и в случае необходимости кор- ректируем положение всплывающего окна (рис. 13.6). Через некоторое время мы можем посмотреть временной график изменения данных датчика на нашем устройстве. Для этого выбираем пункт меню Профиль | Мои Датчики и значок графика для выбранного датчика. Как можно видеть, на графике представлено изменение данных датчика во времени (рис. 13.7).
278 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 13.5. Добавление устройства на сайте «Народный мониторинг» Рис. 13.6. Всплывающее окно нашего устройства на карте сайта «Народный мониторинг»
Гпава 13. Arduino и Интернет вещей 279 Рис. 13.7. Временной график переданных на сайте «Народный мониторинг» показаний датчика 13.2. Подключение к Интернету с помощью платы расширения GSM/GPRS shield Плата расширения GSM/GPRS shield предоставляет возможность использовать в Arduino-проектах для удаленного приема и передачи данных сеть мобильной GSM-связи. GSM/GPRS shield позволяет осуществить это следующими способами: 01 прием/отправка SMS; □ передача аудио (голос, CSD, DTMF); □ связь по GPRS. Рассмотрим один из вариантов этого шилда — SIM900 Quad-Band GPRS shield на основе микросхемы GSM-модуля SIM900 (рис. 13.8). Основные характеристики GSM-модуля SIM900: □ четыре диапазона GSM: 850,900,1800,1900 МГц; О класс передачи данных GPRS multi-slot class 10/8; П соответствие стандарту GSM фазы 2/2+; □ класс мощности 4 (2 Вт в диапазонах 850,900 МГц); О класс мощности 1 (1 Вт в диапазонах 1800,1900 МГц); П управление АТ-командами (GSM 07.07, 07.05 и фирменные АТ-команды SIMCom); И аудиокодеки HR, FR, EFR, AMR, подавление эха; Я CSD до 14,4 Кбит/с;
280 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 13.8. SIM900 Quad-Band GPRS shield □ РРР-стек; □ встроенный стек TCP/IP, UDP/IP; □ протоколы HTTP и FTP; □ протокол защищенных сокетов SSL; □ декодирование DTMF-tohob; □ eMail — формирование и отправка электронных писем посредством АТ-команд; □ SMS Autorun — исполнение АТ-команд, полученных по SMS от определенного абонента; □ 2,5 Mb user memory — встроенная память для пользовательских данных; □ MMS— формирование, дополнение пользовательскими файлами и отправка с помощью АТ-команд; □ AMR play — воспроизведение аудиофайлов в динамик или в сторону удаленно- го абонента; □ Jamming Detection — функция обнаружения глушения сигнала; □ FOTA — обновление прошивки модуля по беспроводному каналу; □ Easy Scan — получение информации об окружающих базовых станциях без под- ключения SIM-карты; □ PING — проверка доступности адреса в Internet посредством обмена 1СМР-па- кетами. Особенности шилда SIM900 Quad-Band GPRS shield: П совместимость с Arduino Mega; □ слот для карт SD (включение/отключение при помощи перемычки);
Глава 13. Arduino и Интернет вещей 281 П гнездо наушников «два в одном»; Я программное и аппаратное обеспечение последовательного порта — может об- щаться с Arduino через последовательный порт программного обеспечения (D2/D3) или последовательный порт (D0/D1); О интерфейс FTDI; □ слот батарейки для RTC; Я 10 цифровых входов/выходов GPIO; □ два ШИМ-выхода; □ интерфейс 12С. Рассматриваемый шилд имеет два способа включения: аппаратный (кратковремен- ное нажатие кнопки PWRKEY) и программный (используется выход D7 Arduino). 13.2.1. Отправка и получение SMS-сообщений с помощью GSM/GPRS shield В этом примере мы каждые 30 минут будем отправлять на определенный телефон- ный номер SMS-сообщение с показаниями аналогового датчика температуры LM335, подсоединенного к выводу АО платы Arduino (рис. 13.9). Установим SIM-карту Рис. 13.9. Монтажная схема подключения к плате Arduino модуля GSM/GPRS shield и датчика LM335
282 Часть III. Сопряжение Arduino со вспомогательными устройствами в слот GSM/GPRS shield, а сам GSM/GPRS shield — на плату Arduino. С помощью джамперов соединим контакты для работы через SofiwareSerial-эмуляцию. Содержимое скетча для отправки SMS показано в листинге 13.4. // подключение библиотеки SoftwareSerial #include <SoftwareSerial.h> // номер телефона для отправки sms (поменяйте на свой) #define PHONE "+79034461752" // Выводы для SoftwareSerial (у вас могут быть 7,8) SoftwareSerial Sim900Serial(2, 3); const int lm335=A0; // для подключения LM335 unsigned long millisl; void setup() { Sim900Serial(19200); // активация последовательного соединения } void loop () { if (millis()-millisl>30*60*1000) // прошло 30 минут? { SendTextMessage(); // отправить sms millisl=millis (); // подпрограмма отправки sms void SendTextMessage() { // АТ-команда установки text mode Sim900Serial.print("AT+CMGF=u\r"); delay(100); // номер телефона получателя Sim900Serial.println("AT + CMGS - \"ff); Sim900Serial.println(PHONE) ; Sim900Serial.println("\"") ;• delay(100); // сообщение - данные температуры double val = analogRead(lm335); // чтение double voltage - val*5.0/1024; // перевод в вольты double temp = voltage*100 - 273.15; // в градусы Цельсия Sim900Serial.println(temp); delay(100); // ASCII код ctrl+z - окончание передачи Sim^OOSerial.println((char)26);
Глава 13. Arduino и Интернет вещей 283 delay(100); Sim900Serial.println(); Электронный архив Полный вариант рассмотренного скетча находится в папке examplesU3W3_04 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем этот скетч в плату Arduino, проверяем его работу и, если все в порядке, изменяем скетч таким образом, чтобы Arduino отправляла SMS-сообщение с дан- ными температуры только при получении приходящего сообщения с текстом ■temp11 (ЛИСТИНГ 13.5). tinclude <SoftwareSerial. h> SoftwareSerial Sim900Serial (2, 3) ; String currStr = ""; // String phone = ""; // // True, если текущая строка является sms-сообщением boolean isStringMessage = false; void setup () { Serial.begin(19200); Sim900Serial.begin(19200); // Настраиваем прием сообщений с других устройств Sim900Serial.print("AT+CMGF=l\r"); delay(300); Sim900Serial.print("AT+IFC=1, l\r"); delay(300); Sim900Serial.print ("AT+CPBS=\"SM\"\r") ; delay (300) ; Sim900Serial.print ("AT+CNMI=1,2,2,1, 0\r") ; delay (500 ); raid loopO { if (! Sim900Serial. available ()) return; char currSymb = Sim900Serial. read (); if ('\r' — currSymb) { if (isStringMessage) // текущая строка - sms-сообщение, { if (!currStr.compareTo("temp")) // текст sms - temp
284 Часть III. Сопряжение Arduino со вспомогательными устройствами { // отправить sms на приходящий номер Sim900Serial.print("AT+CMGF=l\r"); delay(100); Sim900Serial.print ("AT + CMGS = \""); Sim900Serial.print(phone); Sim900Serial.println("\""); delay(100); double val = analogRead(АО); // чтение double voltage = val*5.0/1024; // перевод в вольты double temp = voltage*100 - 273.15; // в градусы Цельсия Serial.printIn(temp); Sim900Serial.println(temp); delay(100); Sim900Serial.println((char)26); delay(100); Sim900Serial.println(); } Serial.println(currStr); isStringMessage = false; } else { if (currStr.startsWith("+CMT")) { Serial.println(currStr); // выделить из сообщения номер телефона phone=currStr.substring(7,19); Serial.println(phone); //если текущая строка начинается с "+СМТ", //то следующая строка является сообщением isStringMessage = true; currStr = ""; } else if (f\nf != currSymb) { currStr += String(currSymb); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\13\_13J)5 сопрово- ждающего книгу электронного архива (см. приложение 2).
Глава 13. Arduino и Интернет вещей 285 13.2.2. Отправка данных на сайт «Народный мониторинг» через GSM/GPRS shield В этом примере для отправки данных на сайт «Народный мониторинг» мы восполь- зуемся возможностями платы расширения GSM/GPRS shield. Итак, устанавливаем на плату Arduino GSM/GPRS shield и подключаем к ней дат- чик— все, как показано на рис. 13.9. В режиме отправки/получения данных GPRS модуль SIM900 потребляет ток до 2 А, поэтому ему понадобится внешнее питание. Для отправки HTTP-данных по GPRS-соединению необходимо выполнить отправ- ку АТ-команд в следующей последовательности: 1. Первой отправляется команда at — ответ должен быть ок. 2. at+sapbr=i, 1 — установка GPRS-связи. 3. AT+SAPBR=3f I, "contype", "gprs" — настройка типа подключения: GPRS. 4. at+sapbr=3,i, "apn", "intemet.beeiine.ru" — настройка APN (в нашем слу- чае — для оператора «Билайн»). 5. AT+HTTPiNiT — инициализировать HTTP. 6. at+httppara="cid", l — carrier Ш для использования. 7. AT+HTTPPARA="URL", "http://narodmon.ru/post.php" — Собственно URL. 8. Строка get данных; 9. at+httpaction=o — данные методом GET; 10. Дождаться ответа. П. at+httpread — получить ответ. 12. at+httpterm — остановить HTTP. Содержимое скетча отправки данных представлено в листинге 13.6. Idefine INTERVALSEND 60000 Mefine Ш535 АО include <SoftwareSerial.h> SoftwareSerial GPRS (7, 8) ; .nt onModulePin= 9; :har aux_str[150] ; :har aux; char data[512]; Jit data_size; iint8_t answer=0; nsigned long millissend=O;
286 Часть III. Сопряжение Arduino со вспомогательными устройстват char apn[]="internet.beeline.ru"; char url[150J; String surl="http://narodmon.ru/post.php/? "; void setup() { GPRS.begin(19200); // скорость для GPRS Serial.begin(9600); Serial.println("Starting..."); pinMode(onModulePin,OUTPUT); power_on(); delay(3000); // точка доступа APN sendATcommand(ffAT+SAPBR=3flr\"CONTYPE\"r\"GPRS\fMf/ "OK", 2000); snprintf (aux_str, sizeof (aux_str), "AT+SAPBR=3, 1, \"APN\", \"%s\"", apn); sendATcommand(auxjstr, "OK"f 2000); while (sendATcoramandC^T+SAPBR^l,!", "OK", 2000) — 0) { delay(2000); } delay(1000); void loop() { // отправка раз в 10 минут if (millis ()-millissend>INTERVALSEND ) { // Initializes HTTP service answer - sendATcommand("AT+HTTPINIT", "OK", 10000); if (answer — 1) { // Sets CID parameter answer - sendATcommand("AT+HTTPPARA=\"CID\",l", "OK", 5000); if (answer = 1) {// Sets url double val « analogRead(LM335); // чтение показаний Ш335 double voltage = val*5.0/1024; // перевод в вольты double temp = voltage*100 - 273.15; // в градусы Цельсия String surll«surl+"#A0:F3:Cl:70:AA:94\n#013950005243291#"+String(temp)+"\n##"; surll.toCharArray(url,surll.length()+1); snprintf(aux_str, sizeof(aux_str), "AT+HTTPPARA=\"URL\",\"%s\"", url); answer = sendATcommand(aux_str, "OK", 5000); if (answer = 1) {// Starts GET action answer - seno7^Tcommand("AT+HTTPACTION-0", "+HTTPACTIQN:0,200", 10000);
Глава 13. Arduino и Интернет вещей 287 if (answer = 1) { sprintf(aux_str, "AT+HTTPREAD"); sendATcommand(aux_str, "OK", 5000); } else { Serial.println("Error getting the url"); } } else { Serial.println("Error setting the url"); } } else { Serial.printIn("Error setting the CID"); } } else { Serial.printIn("Error initializating"); } sendATcommand("AT+HTTPTERM", "OK", 5000); millissend=*nillis (); / отправка АТ-команд t8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout) { uint8_t х=0, answer=0; char response[150]; unsigned long previous; memset(response, f\0f, 150); // Initialize the string delay(100); while( GPRS.available() > 0) GPRS.readO; // Clean the input buffer GPRS.printIn(ATcommand); // Отправка АТ-команды x = 0; previous = millis (); // this loop waits for the answer do{ if(GPRS.available() != 0) { // if there are data in the UART input buffer, reads it and checks for the asnwer response[x] = GPRS.read();
288 Часть III. Сопряжение Arduino со вспомогательными устройствам. // check if the desired answer is in the response of the module if (strstr(response, expected_answer) != NULL) { answer = 1; // время ожидания ответа while((answer == 0) && ((millis() - previous) < timeout)); Serial *printIn(response); return answer; } // программное включение питания void power_on() { uint8_t answer=0; pinMode(onModulePin,OUTPUT); // checks if the module is started digitalWrite(onModulePin,LOW); delay(1000); digitalWrite(onModulePin,HIGH); delay(2000); digitalWrite(onModulePin,LOW); delay(3000); answer = sendATcommand("ATff, "OK", 2000); if (answer == 0) { digitalWrite(onModulePin,LOW); delay(1000); digitalWrite(onModulePin,HIGH); delay(2000); digitalWrite(onModulePin,LOW); delay(3000); digitalWrite(onModulePin,HIGH); delay(3000); digitalWrite(onModulePin,LOW);*/ // время ожидания ответа while(answer == 0) { // Send AT every two seconds and wait for the answer answer = sendATcommand("AT", "OK", 2000);
Глава 13. Arduino и Интернет вещей 289 Электронный архив Полный вариант рассмотренного скетча находится в папке examples\13\J3J)6 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем скетч в плату Arduino и проверяем отправку данных на сайт. После отправки данных можно добавить новое устройство в список устройств своего профиля на сайте «Народный мониторинг» (рис. 13.10). —1— I \ X Рис. 13.10. Добавление нового устройства на сайте «Народный мониторинг»
ГЛАВА 14 Специальные возможности отдельных плат Arduino Существует несколько версий плат Arduino, специально разработанных для опре- деленных задач. Рассмотрим их использование на конкретных примерах. 14.1. Использование Arduino Leonardo в качестве USB-устройства Возможно, наиболее важным моментом для любой платы Arduino является ее спо- собность быть запрограммированной через последовательный порт USB. Это позволяет программировать Arduino без специального оборудования— такого, например, как программатор. В случае Arduino программатор уже встроен в плату. К тому же, эта возможность обеспечивает прямое подключение к интегрированно- му универсальному синхронно/асинхроннному приемнику и передатчику ATmega (USART). Используя этот интерфейс, вы можете обмениваться данными между платой Arduino и компьютером. У разных плат Arduino возможности последовательного соединения различны — как с точки зрения аппаратной реализации адаптеров USB-to-serial, так и с точки зрения программной поддержки тех или иных функций. Для начала необходимо понять разницу между последовательным портом и USB. Микроконтроллеры ATmega328, которыми укомплектованы Arduino Uno, имеют один аппаратный последовательный порт. Он включает выводы ТХ (передача) и RX (получение), к которым можно получить доступ на цифровых выводах 0 и 1. Плата Arduino оборудована загрузчиком, который позволяет программировать ее по последовательному интерфейсу. Это те выводы, которые «мультиплексирова- ны» (т. е. выполняют более одной функции), — они служат и для линий прие- ма/передачи кабеля USB. Но последовательный порт и порт USB не совместимы. Устранение этой проблемы на Arduino осуществляется двумя способами. Первый способ— добавление вторичной микросхемы-преобразователя, что применяется, например, на платах Arduino Uno. Второй— использование микроконтрол- лера, имеющего встроенный USB (например, микроконтроллер 32U4 в Arduino Leonardo).
292 Часть III. Сопряжение Arduino со вспомогательными устройствами Плата Arduino Leonardo была первой платой, имеющей только одну микросхему — микроконтроллер 32U4 — которая выполняет функции и программируемого поль- зователем микроконтроллера, и интерфейса USB. То есть Arduino Leonardo (и по- добные платы Arduino) укомплектованы микроконтроллером, в который прямая передача USB уже встроена. В результате плата может более легко использоваться для эмуляции (имитации) USB-устройств— таких как клавиатура, мышь или джойстик. При этом обычный порт USART на ATmega не мультиплексирован с вы- водами интерфейса USB, поэтому связь с главным компьютером и вторичным последовательным устройством (таким как модуль GPS) может происходить одно- временно. 14.1.1. Arduino Leonardo: имитация клавиатуры Для плат Arduino с прямой поддержкой USB в Arduino IDE, начиная с версии 1.01, включены два класса, обеспечивающие поддержку мыши и клавиатуры. Функции клавиатуры позволяют плате Arduino (Leonardo, Micro или Due) отправлять нажа- тия клавиш на подключенный компьютер. Вот список этих функций: □ Keyboard.begin () — запускает эмуляцию клавиатуры; □ Keyboard. end () — завершает эмуляцию клавиатуры; □ Keyboard.press о — имитация нажатия и удерживания функциональных клавиш клавиатуры; □ Keyboard.print о — отправляет последовательность кодов нажатых клавиш на компьютер; □ Keyboard, print in о — отправляет последовательность кодов нажатых клавиш на компьютер с добавлением кодов новой строки и возврата каретки; □ Keyboard, release о — завершает имитацию удерживания для функциональной клавиши клавиатуры; □ Keyboard. reieaseAii о — завершает имитацию нажатия и удерживания всех на- жатых функциональных клавиш клавиатуры; □ Keyboard, write о — отправляет коды нажатия и отпускания клавиш на компью- тер. Поддерживается также эмуляция клавиш-модификаторов (табл. 14.1). Таблица 14.1. Список клавиш-модификаторов объекта Keyboard Ключ KEY_LEFT_CTRL KEY LEFT_SHIFT KEY_LEFT_ALT KEY LEFT GUI — — Шестнадцатеричное значение 0x80 0x81 0x82 0x83 KEY RIGHT CTRL 0x84 — — i Десятичное значение 128 129 130 131 132
Глава 14. Специальные возможности отдельных плат Arduino 293 Таблица 14.1 (окончание) Ключ KEY_RIGHT_SHIFT KEY_RIGHT_ALT KEY_RIGHT_GUI KEY UP ARROW KEY_DOWN_ARROW KEY_LEFT_ARROW KEY_RIGHT_ARROW Key_Backspace Key Tab Key Return KEY_ESC Key Insert Key Delete KEY_PAGE_UP KEY_PAGE_DOWN KEY_HOME Key_End KEY_CAPS_LOCK Key_Fl Key_F2 Key_F3 Key_F4 Key_F5 Key_F6 Key_F7 Key_F8 Key_F9 Key_F10 Key__Fll Key_F12 Шестнадцатеричное значение 0x85 0x86 0x87 OxDA 0xD9 0xD8 0xD7 0xB2 ОхВЗ OxBO OxBl OxDl 0xD4 .0xD3 0xD6 0xD2 0xD5 OxCl 0xC2 ОхСЗ 0xC4 0xC5 ОхСб 0xC7 0xC8 0xC9 OxCA OxCB OxCC OxCD Десятичное значение 133 134 135 218 217 216 215 178 179 176 177 209 212 211 214 210 213 193 194 195 196 197 198 199 200 201 202 203 204 205
294 Часть III. Сопряжение Arduino со вспомогательными устройствами 14.1.2. Блокируем клавиатуру с наступлением темноты Создадим простой пример использования объекта Keyboard — например, реализуем блокировку клавиатуры компьютера при наступлении темноты. Для этого подсо- единим к аналоговому входу АО платы Arduino Leonardo фоторезистор, и при наступлении темноты будем отправлять на компьютер комбинацию клавиш, блокирующую компьютер (для Windows — это комбинация <Windows>+<L>). Содержимое скетча представлено в листинге 14.1. const int LIGHT =A0; // Датчик освещенности на вывод 1 const int THRESHOLD =200; // Значение с датчика освещенности // для блокировки компьютера void setup() { Keyboard.begin(); } void loop () { int brightness = analogRead(LIGHT); // Чтение данных датчика if (brightness < THRESHOLD) { Keyboard.press(KEY_LEFT_GUI); Keyboard.press('1f); delay(100) ; Keyboard.releaseAll(); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\14\_U_01 сопрово- ждающего книгу электронного архива (см. приложение 2). 14.1.3. Arduino Leonardo: имитация компьютерной мыши Функции мыши позволяют плате Arduino Leonardo управлять положением мыши на подключенном компьютере. Вот список этих функций: □ Mouse .begin () — запускается эмуляция мыши на подключенном компьютере; □ Mouse. click () — эмулирует нажатие и отпускание кнопки мыши: • mouseleft (по умолчанию) — левая кнопка; • mouseright — правая кнопка; • MOUSEjiiDDLE — средняя кнопка;
Глава 14. Специальные возможности отдельных плат Arduino 295 П Mouse. end () — завершается эмуляция мыши на подключенном компьютере; □ Mouse.move о — перемещение курсора на подключенном компьютере (относи- тельно текущего положения курсора); Я Mouse.press о — эмуляция нажатия и постоянного удерживания кнопки мыши, нажатие отменяется функцией Mouse. release (): • mouse_left (по умолчанию) — левая кнопка; • mousejright — правая кнопка; • mouse_middle — средняя кнопка; П Mouse. release () — отмена нажатия и постоянного удерживания кнопки мыши; □ Mouse.isPressedO — проверяет текущее состояние кнопок мыши. Используя двухосевой джойстик (рис. 14.1) и не- сколько кнопок, с помощью Arduino Leonardo можно сделать свою собственную мышь! Джойстик будет контролировать местоположение мыши, а кнопки — выполнять функции левой, средней и правой кнопки мыши. Монтажная схема эмулятора компьютерной мыши на Arduino Leonardo представлена на рис. 14.2. Рис. 14.1. Двухосевой джойстик ■-4; М7 *. Е^?ии»ш»»>жячхи«г!щн*в»?*б»*зщш|?^;*жяйв4»:'* Рис. 14.2. Монтажная схема подключения эмулятора компьютерной мыши
296 Часть III. Сопряжение Arduino со вспомогательными устройствами Содержимое скетча для эмулятора компьютерной мыши представлено в листин- ге 14.2. const int LEFT_BUTTON=4; // Вход для левой кнопки мыши const int MIDDLE_BUTTON=3; // Вход для средней кнопки мыши const int RIGHT_BUTTON =2; // Вход для правой кнопки мыши const int X_AXIS=0; // Аналоговый вход для оси х джойстика const int Y_AXIS=1; // Аналоговый вход для оси у джойстика void setup() { Mouse.begin(); } void loopO { int xVal=readJoystick(X_AXIS); // Получить отклонение // джойстика по оси х int yVal=readJoystick(Y_AXIS); // Получить отклонение // джойстика по оси у Mouse.move (xVal, yVal, 0); // Перемещаем мышь readButton(LEFT_BUTTON/MOUSE_LEFT); // Чтение состояния левой кнопки readButton(MIDDLE_BUTTONfMOUSE_MIDDLE); // Чтение состояния средней readButton(RIGHT_BUTTON, MOUSE_RIGHT); // Чтение состояния правой delay(5); } // Чтение значения джойстика, масштабирование int readJoystick(int axis) { int val = analogRead(axis); // Чтение аналогового значения val = map(val, 0, 1023, -10, 10); // Масштабирование значения if (val <= 2 && val >= -2) // Убрать дрейф мыши return 0; else // Вернуть значение return val; } // Чтение состояния кнопок и отправка команд мыши void readButton(int pin, char mouseCoramand) { // Если кнопка нажата, эмулируем нажатие, если она еще не была нажата if (digitalRead(pin) == LOW) { if (!Mouse.isPressed (mouseCommand))
Глава 14. Специальные возможности отдельных плат Arduino 297 { Mouse.press (mouseCoramand); } } // Отпустить нажатие мыши else { if (Mouse.isPressed(mouseCommand)) { Mouse.release(mouseCommand); Функция readJoystick () создана для считывания значений джойстика и масштаби- рования их. Каждая ось джойстика имеет ряд значений: от 0 до 1024, полученных от входа аналого-цифрового преобразователя (АЦП). Значения от 0 до 1023 мас- штабируем к значениям от -10 до 10. Электронный архив Полный вариант рассмотренного скетча находится в папке examples\14\_14_02 сопрово- ждающего книгу электронного архива (см. приложение 2). 14.2. Плата Arduino Esplora Плата Arduino Esplora спроектирована на основе Arduino Leonardo и отличается от всех предыдущих плат Arduino наличием множества встроенных и готовых к использованию датчиков. Дизайн платы Arduino Esplora напоминает дизайн обычного геймпада с аналоговым джойстиком слева и четырьмя кнопками справа (рис. 14.3). Рис. 14.3. Плата Arduino Esplora
298 Часть III. Сопряжение Arduino со вспомогательными устройствами Arduino Esplora обладает следующими встроенными средствами ввода и вывода (рис. 14.4): 1. Аналоговый джойстик с кнопкой. 2. Четыре кнопки. 3. Линейный потенциометр. 4. Микрофон. 5. Датчик освещенности. 6. Датчик температуры. 7. Трехосевой акселерометр. 8. Зуммер для генерации звукового сигнала прямоугольной формы. 9. RGB-светодиод. 10. Два Tinkerkit-входа для подключения Tinkerkit-модулей датчиков с 3-пиновыми разъемами. 11. Два Tinkerkit-выхода для подключения Tinkerkit-модулей приводов с 3-пино- выми разъемами. 12. Разъем подключения TFT-дисплея, считывающего устройства SD-карты или других устройств, использующих протокол SPI. On Led LUd Q TxLed IRxUd Output Tmkerkit Connectors Micro USB Input Tlnkerkft Connectors ATMEGAS2U4 Reset Button 5 flight sensor) \ Analog ^~ with central button 12 LCD connector (TFD 4 Mkxophofie Г RGB Led Рис. 14.4. Средства ввода и вывода платы Arduino Esplora Как и на плате Leonardo, в Esplora используется AVR-микроконтроллер ATmega32U4 с кварцевым резоцатором 16 МГц. Arduino Esplora может определяться как обычная клавиатура или мышь и с помощью библиотек Keyboard и Mouse может быть запрограммирована на управление этими устройствами ввода.
Глава 14. Специальные возможности отдельных плат Arduino 299 Чтобы упростить написание программ для платы Esplora, существует специальная библиотека Esplora, которая содержит методы для считывания данных с датчиков и отправки информации на встроенные устройства вывода, а также высокоуровневые методы, возвращающие уже обработанные данные — например, градусы по Фарен- гейту или Цельсию, вычисленные по показаниям датчика температуры. Эта библиотека обеспечивает простой доступ к устройствам вывода — например, при отправке значений RGB-светодиоду. В примерах работы с Esplora в Arduino IDE (рис. 14.5) показаны основные функции входов и выходов устройства — с их помощью удобно экспериментировать с пла- той Arduino Esplora и познавать ее возможности: П EsploraBlink — мерцание встроенного RGB-светодиода. □ EsploraAccelerometer — считывание показаний акселерометра; □ EsploraJoystickMouse — управление курсором компьютера с помощью джой- стика; □ EspIoraLedShow — световое шоу с использованием джойстика и слайдера; □ EsploraLedShow2 — изменение цвета встроенного RGB-светодиода с использо- ванием микрофона, потенциометра и датчика освещенности; □ EsploraLightCalibrator — определение освещенности; Рис. 14.5. Примеры библиотеки Esplora
300 Часть III. Сопряжение Arduino со вспомогательными устройствами □ EsploraMusic — немного музыки в исполнении Arduino Esplora; D EsploraSoundSensor — обработка сигнала со встроенного микрофона; О EsploraTemperatureSensor— считывание показаний температурного датчика и расчет температуры в градусах Фаренгейта и Цельсия. Внимательно изучаем эти примеры, а затем приступаем к написанию своих про- грамм. 14.2.1. Arduino Esplora: установка цветов RGB-светодиода Напишем скетч для установки цвета RGB-светодиода с помощью трех кнопок: SWITCH2, SWITCH3, SWITCH4. Если нажата кнопка SWITCH2 — горит красный светодиод, не нажата — красный светодиод потушен. Если нажата кнопка SWITCH3 — горит зеленый светодиод, не нажата — зеленый светодиод потушен. Если нажата кнопка SWITCH4 — горит синий светодиод, не нажата — синий све- тодиод потушен. Сначала подключаем библиотеку Esplora: #include <Esplora.h> Создадим переменные для значений красного, зеленого и синего цветов RGB-свето- диода: int red, green, blue; В цикле loop () проверяем данные с кнопок и устанавливаем значения для соответ- ствующих переменных: red, green, blue: if (Esplora.readButton(SWITCH_2) — HIGH) red = 255; else red = 0; if (Esplora.readButton(SWITCH_3) = HIGH) green = 255; else green = 0; if (Esplora.readButton(SWITCH__4) — HIGH) blue = 255; else blue = 0; И устанавливаем цвета RGB-светодиода: Esplora.writeRGB(red, green, blue); Полное содержимое скетча показано в листинге 14.3. Загружаем его в плату Arduino и управляем цветами RGB-светодиода нажатием на кнопки SWITCH2, SWITCH3, SWITCH4.
Глава 14. Специальные возможности отдельных плат Arduino 301 II Подключение библиотеки Esplora. #include <Esplora.h> // Переменные для значений красного, зеленого и синего цветов RGB-светодиода int red, green, blue; void setup () { void loop () { // получение данных с кнопок if (Esplora.readButton(SWITCH_2) == LOW) //нажата red = 255; else red = 0; if (Esplora.readButton(SWITCH_3) == LOW) //нажата green = 255; else green = 0; if (Esplora.readButton(SWITCH_4) == LOW) //нажата blue = 255; else blue = 0; // Устанавливаем цвета RGB-светодиода: Esplora.writeRGB(red, green, blue); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\14\_14__03 сопрово- ждающего книгу электронного архива (см. приложение 2). 14.2.2. Arduino Esplora: создание игры Рассмотрим применение Arduino Esplora с TFT-дисплеем в качестве игровой консо- ли и создадим для этого игру «Змейка» (рис. 14.6). Змейка на экране дисплея будет представлять собой линейку из множества квадра- тов размеров 8x8, соединенных между собой. Данные о звеньях мы будем сохра- нять в массиве, каждый из элементов которого — координаты х и у левого верхнего угла каждого звена: // структура для описания координаты одного звена 8x8 struct Pos { int х; int у;
302 Часть III. Сопряжение Arduino со вспомогательными устройствами // массив всех звеньев змейки Pos snake[40]={{40,0},{32,0},{24,0},{16,0},{8,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0} Переменная — указатель на хвост змейки (размер змейки): int offsetsnake=6; Переменные для направления движения змейки и коэффициент для фактического смещения: // перемещение по осям х и у и коэффициент (шаг) int dX=l; // -1, 0, 1 int dY=0; // -1, 0, 1 int kXY=8; И переменные для скорости— времени, после которого происходит очередное изменение положения змейки: // скорость int speedsnake=1000; unsigned long millissnake=0; Рис. 14.6. Игра «Змейка»
Глава 14. Специальные возможности отдельных плат Arduino 303^ Кнопки SWITCH1, SWITCH2, SWITCH3, SWITCH4 будем использовать для изме- нения направления змейки, которое описано в процедуре setdir (): // получение смещения по осям х и у // получение данных с кнопок if (Esplora.readButton(SWITCHED — LOW) //нажата setdir(0,1); else if (Esplora.readButton(SWITCH_2) — LOW) //нажата setdir (-1, Ob- else if (Esplora.readButton(SWITCH_3) — LOW) //нажата setdir(0,-1); else if (Esplora.readButton(SWITCH__4) — LOW) //нажата setdir (1, Ob- else // установить новое направление движения void setdir(int x,int y) { int xl,yl; xl=*x;yl=y; if((dX+x)—0 && abs(x)>0) {yl-y;xl=dX;} if((dY+y)—0 && abs(y)>0) // установить dX-xl;dY-yl; } Полное содержимое скетча показано в листинге 14.4. Загрузим скетч в плату Arduino Esplora и проверим управление змейкой с помощью клавиш. // Подключение библиотеки для работы с TFT iinclude <TFT.h> iinclude <SPI.h> // Подключение библиотек для работы с Esplora #include <Esplora.h> // структура для описания координаты одного звена 8x8 struct Pos { int x; int у; }; // массив всех звеньев змейки Pos snake[40J«{{40,0},{32,0},{24,0},{16,0},{8,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0},
304 Часть III. Сопряжение Arduino со вспомогательными устройствами {0,0},{0,0}f{0f0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0} }; int offsetsnake=6; // перемещение по осям х и у и коэффициент (шаг) int dX=l; // -1, 0, 1 int dY=0; // -1, 0, 1 int kXY=8; // скорость int speedsnake=1000; unsigned long millissnake=:0; void setup(){ // Serial.begin(9600); // EsploraTFT.begin (); // очищаем экран - черный цвет EsploraTFT.background(0,0,0); // пауза delay(1000); void loop(){ // получение смещения по осям х и у // получение данных с кнопок if (Esplora.readButton(SWITCHJL) — LOW) //нажата setdir(0,l); else if (Esplora.readButton(SWITCH_2) == LOW) //нажата setdir(-l,0); else if (Esplora.readButton(SWITCH_3) == LOW) //нажата setdir(0,-l); else if (Esplora.readButton(SWITCH_4) == LOW) //нажата setdird, Ob- else //// изменение положения змейки if (millis()-millissnake>=speedsnake) { // стереть предыдущее EsploraTFT.fill(0, 0, 0); for(int i=0;i<offsetsnake;i++) { EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8);
Глава 14. Специальные возможности отдельных плат Arduino 305 //// новая позиция для змейки // остальные for(int i=offsetsnake-l;i>0;i—) { snake[i].x=snake[i-l].x; snake[i].y=snake[i-l].y; } // первая snake[0].x=snake[0],x+dX*kXY; snake[0].y=snake[0],y+dY*kXY; // нарисовать новое EsploraTFT.fill(255, 0, 0); for(int i=0;i<offsetsnake;i++) { EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8); } millissnake=smillis () ; // установить новое направление движения void setdir(int x,int у) { int xl,yl; xl=x;yl=y; if((dX+x)==0 && abs(x)>0) {yl=y;xl=dX;} if((dY+y)—0 && abs(y)>0) {xl=x;yl=dY;} // установить dX=xl;dY=yl; Электронный архив Полный вариант рассмотренного скетча находится в папке examples\i4\_14_04 сопро- вождающего книгу электронного архива (см. приложение 2). Добавим в скетч генерирование корма для змейки. Нам необходим массив для хра- нения координат корма с максимальным количеством 10: // массив для корма Pos food[10] = {{0,0},{0,0},{0,0},{0,0}, {0,0}, {0,0},{0,0},{0,0},{0,0},{0,0} }; int counterfood=0 ; Через время speedf ood генерируем корм и отображаем его на экране: //// появление корма if (millis()-millisfood>=speedfood && counterfood<10) { // генерация случайных х и у int xf^random(0,20)* 8; int yf=random(2,15)*8;
306 Часть III. Сопряжение Arduino со вспомогательными устройствами // проверка отсутствия в списке корма for(int i=0;i<10;i++) { if (food[i] .x=xf && food[i] .y=yf) ; else if (food[i] .x=0 && food[i].y==O){ //не попадает на змейку if(nosnake(xf,yf)) { // добавить в массив и на экран addfood(xf,yf,i); // звук Esplora.tone(262,200); counterfood++; i-10; millisfood=snillis(); } В процедуре nosnake () проверяем отсутствие сгенерированного значения коорди- нат в базе — не попадает ли корм на змейку, заносим данные в массив food и выво- дим красный квадрат на дисплей: // проверка непопадания корма на змейку boolean nosnake(int x,int у) { boolean ok=true; for(int i=0;i<40;i++) { if (snake [i] .x—x && snake [i] .y^-y) ok=false; } return ok; } // добавить корм в массив и вывести void addfood(int x,int у, int pos) { food[pos].x=x; food[pos].у=у; EsploraTFT.filMO, 0, 255); EsploraTFT.rect(x, y, 8, 8); } В цикле после изменения положения змейки проверяем, не съела ли змейка корм — не произошло ли совпадение ее головы с координатами всех позиций корма: // проверка — съела змейка корм? boolean atefood(int x,int у) { boolean ok=false; for(int i=0;i<10;i++) { if(food[i].x==x && food[i]. food[i].x-0;food[i].
Глава 14. Специальные возможности отдельных плат Arduino 307 counterfood—; ok=true; Serial.printIn(i); return ok; } Полное содержимое скетча показано в листинге 14.5. Загрузим скетч в плату Arduino Esplora и проверим его работу. // Подключение библиотеки для работы с TFT tinclude <TFT.h> tinclude <SPI.h> // Подключение библиотек для работы с Esplora tinclude <Esplora.h> // структура для описания координаты одного звена 8x8 struct Pos { int x; int у; }; // массив всех звеньев змейки Pos snake[40]={{40,16},{32,16},{24,16},{16,16},{8,16}, {0,16},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0} }; int offsetsnake-6; // массив для корма Pos food[10]={{0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0} }; int counterfood=0; // перемещение по осям х и у и коэффициент int dX=l; // -1, 0, 1 mt dY=0; // -1, 0, 1 int kXY=8; // скорость int speedsnake=300; unsigned long millissnake=0;
308 Часть III. Сопряжение Arduino со вспомогательными устройствами // время появления нового корма unsigned long speedfood=5000; unsigned long millisfood=0; // массив символов для вывода времени на экран char printout[4]; void setup(){ // Serial.begin(9600); // EsploraTFT.begin(); // очищаем экран ~ черный цвет EsploraTFT.background(0,0,0); // пауза EsploraTFT.fill(255, 255, 0); EsploraTFT.rect(0, 16, 160, 128); void loop(){ // получение смещения по осям х и у 7/ получение данных с кнопок if (Esplora.readButton(SWITCH_l) = LOW) //нажата setdir(0,l); else if (Esplora.readButton(SWITCH_2) — LOW) //нажата setdir(-l,0); else if (Esplora.readButton(SWITCH_3) — LOW) //нажата setdir(0,-l); else if (Esplora.readButton(SWITCH_4) == LOW) //нажата setdird, Ob- else //// изменение положения змейки if (miHis()-millissnake>=speedsnake) { // стереть предыдущее EsploraTFT.fill(255, 255, 0); for(int i=0;i<offsetsnake;i++) { EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8); } //// новая позиция для змейки // остальные for(int i=offsetsnake-l;i>0;i—) { snake[i].x=snake[i-l].x; snake[i].y=snake[i-1].у; } // первая snake[0].x=snake[0].x+dX*kXY; snake[0].y=snake[0].y+dY*kXY;
Глава 14. Специальные возможности отдельных плат Arduino 309 // нарисовать новое EsploraTFT.fill(255, 0, 0); for(int i=0;i<offsetsnake;i++) { EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8); } // проверка - съела змейка корм? if(atefood(snake[0].x,snake[0].y)) { Esplora.tone(494,200); delay(200); Esplora.tone(349,200); offsetsnake++; } // новый отсчет millissnake millissnake=millis(); } //// появление корма if(millis()-millisfood>=speedfood && counterfood<10) { // генерация случайных х и у int xf=random(0,2 0) * 8; int yf=random(2,15)*8; // проверка отсутствия в списке корма for(int i=0;i<10;i++) { if (food[i] .x=xf && food[i] .y==yf) r else if (food[i].x=0 && food[i] .y==0) { //не попадает на змейку if(nosnake(xf,yf)) { // добавить в массив и на экран addfood(xf,yf,i); // звук Esplora.tone(262,200); counterfood++; i=10; millisfood=*nillis () ; // установить новое направление движения void setdir(int xfint у) { int xl,yl; xl=x;yl=y; if((dX+x)==0 && abs(x)>0) {yl=y;xl=dX;} if((dY+y)=0 && abs(y)>0) {xl=x;yl=dY;}
310 Часть III. Сопряжение Arduino со вспомогательными устройствами II установить dX=xl;dY=yl; } // добавить корм в массив и вывести void addfood(int x,int у, int pos) { food[pos].x=x; food[pos].y=y; EsploraTFT.filMO, 0, 255); EsploraTFT.rect(x, y, 8, 8); } // проверка непопадания корма на змейку boolean nosnake(int x,int у) { boolean ok=true; for(int i=0;i<40;i++) { if (snake [i] .x—x && snake [i] .y==y) ok=false; } return ok; // проверка — съела змейка корм? boolean atefood(int x,int у) { boolean ok=false; for(int i=0;i<10;i++) { if (food[i] .x=x && food[i] food[i].x-0;food[i]. counterfood—; ok=true; Serial.printIn(i); return ok; Электронный архив Полный вариант рассмотренного скетча находится в папке examples\14\_U_05 сопрово- ждающего книгу электронного архива (см. приложение 2). Далее реализуем проверку выхода змейки за пределы экрана или на себя — в этом случае заканчиваем игру: // проверка выхода из границ boolean outborder(int x,int у) { boolean ok=false; if(x<0 || х>152 || у<16 И у>120) { ok=true; } return ok;
Глава 14. Специальные возможности отдельных плат Arduino 311 I/ проверка — не съела ли себя boolean out snake (int x,int у) { boolean ok=false; for(int i-l;i<40;i++) { if (x==snake[i] .x && y=snake[i] .y) { ok=true; return ok; } А также реализуем табло для вывода времени игры, суммы набранных очков, текущей длины змейки и количества корма на площадке: // табло void tablo() { // очистить EsploraTFT.filMO, 0, 0) ; EsploraTFT.rect(Of 0, 100, 16); // текст // цвет текста EsploraTFT.stroke(255,255,0); // шрифт для текста //EsploraTFT.setTextSize(1); // выводим текст // корма на поле String s = String(counterfood); s.toCharArray(printout,4); EsploraTFT.text(printout,20,2); EsploraTFT.stroke(255,255,0); // длина змейки s = String(offsetsnake); s.toCharArray(printout,4); EsploraTFT.text(printout,40,2); EsploraTFT.stroke(255,255,0); // сумма очков s = String(sum); s.toCharArray(printout,4); EsploraTFT.text(printout,70,2); EsploraTFT.stroke(255,255,0); void set time () { // очистить EsploraTFT.fill(0, 0, 0); EsploraTFT.rect(100, 0, 60, 16); // вывод времени String s = String(seconds/60); s.toCharArray(printout,4);
312 Часть III. Сопряжение Arduino со еспомогательными устройствами if(seconds/60<10) { EsploraTFT.text("0",110,2); EsploraTFT.text(printout,116,2); } else { EsploraTFT. text (printout, 110,2); } EsploraTFT.text(":",122,2); s = String(seconds%60); s.toCharArray(printout,4); if(seconds%60<10) { EsploraTFT.text("0",128,2); EsploraTFT.text(printout,134,2); } else { EsploraTFT. text (printout, 128,2) ; } EsploraTFT.stroke(255,255,0); Полное содержимое скетча показано в листинге 14.6. Загрузим скетч в плату Arduino Esplora и проверим его работу. При желании вы можете внести в игру «Змейка» собственные изменения. [ Йтшгттс ЫЛ // Подключение библиотеки для работы с TFT #include <TFT.h> #include <SPI.h> // Подключение библиотек для работы с Esplora #include <Esplora.h> // структура для описания координаты одного звена 8x8 struct Pos { int x; int у; }; // массив всех звеньев змейки Pos snake[40]={{40,16},{32,16},{24,16},{16,16},{8,16}, {0,16},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0}
Глава 14. Специальные возможности отдельных плат Arduino 313 int offsetsnake=6; // массив для корма Pos food[10]={{0,0},{0,0},{0,0}, {0,0},{0,0}, {0,0},{0,0},{0,0},{0,0},{0,0} }; int counterfood=0; // перемещение по осям х и у и коэффициент int dX=l; // -1, 0, 1 int dY=0; // -1, 0, 1 int kXY=8; // скорость int speedsnake=300; unsigned long millissnake=0; // время появления нового корма unsigned long speedfood=5000; unsigned long millisfood=0; // массив символов для вывода времени на экран char printout [ 4 ]; // сумма набранных очков int sum=100; // время игры - секунд unsigned long seconds=0; unsigned long millisseconds=0; void setup () { // Serial.begin(9600); // EsploraTFT. begin () ; // очищаем экран - черный цвет EsploraTFT.background(0,0,0); // пауза EsploraTFT.fill(255, 255, 0); EsploraTFT.rect(0, 16, 160, 128); tablo(); raid loop(){ // отсчет времени if (millis()-millisseconds>=1000) { seconds++; settime (); millisseconds=^nillis (); // получение смещения по осям х и у // получение данных с кнопок if (Esplora.readButton(SWITCHED — LOW) //нажата setdir(0,l);
314 Часть III. Сопряжение Arduino со вспомогательными устройствами else if (Esplora.readButton(-SWITCH_2) == LOW) //нажата setdir(-l,0); else if (Esplora.reacffiutton(SWITCH_3) — LOW) //нажата setdir(0,-l); else if (Esplora.readButton(SWITCH_4) = LOW) //нажата setdir(l,0); else ; //// изменение положения змейки if (millis () -millissnake^speedsnake) { // стереть предыдущее EsploraTFT.fill(255, 255, 0); for(int i=0;i<offsetsnake;i++) { EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8); } //// новая позиция для змейки // остальные for(int i=offsetsnake-1;i>0;i—) { snake[i].x-snake[i-1].x; snake[i].y=snake[i-l].y; } // первая snake[0].x=snake[0].x+dX*kXY; snake[0].y=snake[0].y+dY*kXY; // нарисовать новое EsploraTFT.fill(255/ 0, 0) ; for(int i=0;i<offsetsnake;i++) { EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8); } // проверка ~ съела змейка корм? if(atefood(snake[0].x,snake[0].y)) { Esplora.tone(494,200); delay(200); Esplora.tone(349,200); setsum(30+offsetsnake); tabloO;' offsetsnake++; } // проверка выхода из границ if(outborder(snake[0].xfsnake[0].y)) { endgame(); newgame(); tablo(); } // проверка — не съела ли себя if(outsnake(snake[0].x,snake[0].у)) { endgame ();
Глава 14. Специальные возможности отдельных плат Arduino 315 newgame (); tablo(); } // новый отсчет millissnake millissnake^^millis (); } //// появление корма if(millis()-millisfood>=speedfood && counterfood<10) { // генерация случайных х и у int xf=random(0,20)*8; int yf=random(2,15)*8; // проверка отсутствия в списке корма for(int i=0;i<10;i++) { if (food[i] ,x==xf && food[i] . else if (food[i].x—0 && food[i] .y=0) { //не попадает на змейку if(nosnake(xf,yf)) { // добавить в массив и на экран addfood(xf,yf,i); setsum(-5*counterfood); tablo(); // звук Esplora.tone(262f200); counterfood++; tablo(); i-10; millisfood=millis(); / установить новое направление движения oid setdir(int x, int y) { int xl,yl; xl=x;yl=y; if((dX+x)=0 && abs(x)>0) {yl=y;xl=dX;} if((dY+y)==0 && abs(y)>0) {xl=x;yl=dY;} // установить dX«xl;dY«yl; / добавить корм в массив и вывести oid addfood (int x#int yf int pos) { food[pos].x=x;
316 Часть III. Сопряжение Arduino со вспомогательными устройствами food[pos].y=y; EsploraTFT.filMO, 0, 255); EsploraTFT.rect(x, у, 8, 8); } // проверка непопадания корма на змейку boolean nosnake(int x,int у) { boolean ok=true; for(int i=0;i<40;i++) { if (snake [i] ,x=x && snake [i] .y==y) ok=false; } return ok; } // проверка — съела змейка корм? boolean atefood(int x,int у) { boolean ok=false; for(int i=0;i<10;i++) { if(food[i].x==x && food[i]. food[i].x=0;food[i].y=0; counterfood—; ok=true; Serial.println(i) ; return ok; } // проверка выхода из границ boolean outborder(int xfint y) { boolean ok=false; if(x<0 || х>152 И У<16 |L y>120) { ok=true; } return ok; } // проверка — не съела ли себя boolean outsnake(int xfint у) { boolean ok=false; for(int i=l;i<40;i++) { if(x==snake[i].x && y==snake[i].y) { ok=true; return ok; } // табло void tablo()
Глава 14. Специальные возможности отдельных плат Arduino 317 // очистить EsploraTET.filKO, 0f 0) ; EsploraTFT.rect(0, 0, 100, 16); // текст // цвет текста EsploraTFT.stroke(255f 255,0); // шрифт для текста //EsploraTFT.setTextSize(l); // выводим текст // корма на поле String s = String(counterfood); s.toCharArray(printout,4); EsploraTFT.text(printout,20,2); EsploraTFT.stroke(255,255,0); // длина змейки s = String(offsetsnake); s.toCharArray(printout,4); EsploraTFT.text(printout,40,2); EsploraTFT.stroke(255,255,0); // сумма очков s = String(sum); s.toCharArray(printout,4); EsploraTFT.text(printout,70,2); EsploraTFT.stroke(255,255,0); I / подсчет количества очков void endgame () { // очистите экран EsploraTFT.background(0,0,0); EsploraTFT.fill(255, 255, 0); // цвет текста EsploraTFT.stroke(255,255,0); EsploraTFT.text("GAME END",50,40); // сумма очков EsploraTFT.text("sum =",50,70); String s = String(sum); s.toCharArray(printout,4); EsploraTFT.text(printout,86,70); // ожидаем нажатия кнопки while(Esplora.readButton(SWITCH_1)==HIGH && Esplora.readButton(SWITCH_2)==HIGH & & Esplora.readButton(SWITCHJ3)==HIGH & & Esplora.readButton(SWITCH_4)==HIGH ) /начать заново id newgame () {
318 Часть III. Сопряжение Arduino со вспомогательными устройствами // очистить экран EsploraTFT.background(0,0,0); EsploraTFT.fill(255, 255, 0); EsploraTFT.rect(0, 16, 160, 128); // массив snake for(int i=0;i<1 food[i].x=0; food[i].y=0; } counterfood=0; // массив food for(int i=0;i<4 snake[i].x=0; snake[i].y=0; } snake[0].x=40;snake[0].y=16; snake[1].x-32;snake[1].y^ie; snake[2].x=24;snake[2].у=16; snake[3].x=16;snake[3] snake[4].x=8;snake[4]. snake[5].x=0;snake[5]. offsetsnake=6; // направление dX-1; dY=0; // sum=100; seconds=0; } // подсчет количества очков void setsum(int add) { sum^sum+add; void settimeO { // очистить EsploraTFT.fill(0, 0, 0); EsploraTFT.rect(100, 0, 60, 16); // вывод времени String s = String(seconds/60); s.toCharArray(printout,4); if(seconds/60<10) { EsploraTFT.text("0",110,2); EsploraTFT.text(printout,116,2); } else { EsploraTFT. text (printout, 110,2);
Глава 14. Специальные возможности отдельных плат Arduino 319 EsploraTET.text(":",122 , 2); s = String(seconds%60); s.toCharArray(printout,4); if(seconds%60<10) { EsploraTFT.text ("0f\128,2) ; EsploraTET.text'(printout, 134,2); else { EsploraTFT.text (printout, 128,2); EsploraTET.stroke(255,255,0); } Электронный архив Полный вариант рассмотренного скетча находится в папке examples\i4\_UJ)6 сопрово- ждающего книгу электронного архива (см. приложение 2). 14.3. Плата Arduino LilyPad Плата Arduino LilyPad была разработана и создана дизайнером Leah Buechley со- вместно со SparkFun для использования с предметами одежды и текстиля. Arduino LilyPad можно пришивать к ткани и с помощью токопроводящих нитей подключать питание, датчики или исполнительные устройства. Электронная схема, собранная на ткани, включая саму плату Arduino LilyPad, не боится стирки — ее можно сти- рать вручную, естественно, предварительно отключив питание. Печатная плата LilyPad Arduino имеет форму круга диаметром около 50 мм. Плата выполнена на микроконтроллерах ATmegal68V или ATmega328V. Напряжение питания платы — в интервале от 2,7 до 5,5 В. При отрицательном питании или большем чем 5,5 В плата может выйти из строя. Существуют три варианта этой платы: 3 LilyPad Arduino 328 (рис. 14.7) — на базе микроконтроллера ATmega328; 3 LilyPad Arduino USB (рис. 14.8)— на базе микроконтроллера ATmega32U4. Этот вариант отличается наличием USB-порта для связи с компьютером и разъ- ема для литиевой батареи; !) LilyPad Simple Snap (рис. 14.9)— благодаря специальным контактам из кнопок может отстегиваться от схемы, содержит встроенный литиевый аккумулятор. Рассмотрим плату LilyPad Arduino 328, построенную на базе микроконтроллера \Tmega328 (см. рис. 14.7). Плата имеет 22 контакта (рис. 14.10). Контакты + и - предназначены для питания платы. Остальные контакты аналогичны контактам \rduino Uno. Также на плате присутствуют штырьковые контакты для подключе- ния переходника USB-Serial, необходимого для загрузки скетчей из компьютера.
320 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 14.7. Плата LilyPad Arduino 328 Рис. 14.8. Плата LilyPad Arduino USB
Глава 14. Специальные возможности отдельных плат Arduino 321 Рис. 14.9. Плата LilyPad Simple Snap Контакты для FTDI USB Питание датчиков -GND -; Питание датчиков + 5 В Светодиод ., Индикатор *^ *» питания Тестовый светодиод для PIN 13 Рис. 14.10. Контакты и разъемы платы LilyPad Arduino 328
322 Часть III. Сопряжение Arduino со вспомогательными устройствами Технические характеристики платы LilyPad Arduino 328: □ микроконтроллер: ATmega328V; □ количество цифровых контактов: 14 (6 из которых могут использоваться как вы- ходы ШИМ); □ количество аналоговых контактов: 6; □ рабочее и входное напряжение: 2,7-5,5 В; □ флеш-память: 16 Кбайт (2 Кбайт используются для загрузчика); О ОЗУ: 1 Кбайт; Для подключения платы LilyPad Arduino 328 к компьютеру требуется преобразова- тель USB-Serial (рис. 14.11). т&шттшшттшаш тт1шшятетатш шттттщшшштшжтж Рис. 14.11. Монтажная схема подключения LilyPad Arduino 328 к преобразователю USB-Serial Для загрузки скетчей из Arduino ШЕ на плату LilyPad Arduino 328 необходимо в меню Инструменты выбрать порт подключения платы LilyPad и ее тип — LilyPad Arduino (рис. 14.12). На дешевых переходниках USB-Serial отсутствует контакт DTR, который соединя- ется с выводом RESET Arduino и сбрасывает микроконтроллер перед загрузкой в него новой программы. Если такого контакта нет, то при загрузке скетча на плату LilyPad Arduino происходит ошибка (рис. 14.13). В таких случаях необходимо после нажатия кнопки Загрузить — когда компиля- ция скетча завершится и появится надпись Загружаем — нажать и отпустить на плате Arduino кнопку сброса.
Глава 14. Специальные возможности отдельных плат Arduino 323 ш^ттшшяяшшщтяшшшшшш ms^m&mm»immM9imm№mmmMmmmm Рис. 14.12. Настройки Arduino IDE для LilyPad Arduino 328 Рис. 14.13. Ошибка при загрузке скетча на плату LilyPad Arduino
324 Часть III. Сопряжение Arduino со вспомогательными устройствами 14.4. Плата Arduino Yun Одной из самых слабых сторон платформы Arduino до недавних времен являлось отсутствие связи. Плата Arduino Yun решает эту проблему, потому что представля- ет собой плату Arduino со встроенным модулем Wi-Fi. Кроме того, Yun несет на борту второй микропроцессор, на котором работает облегченная версия Linux с предустановленным языком программирования Python. Кроме Python вы можете также установить Ruby, PHP или Node. □ Arduino-часть платы содержит микроконтроллер ATmega32U4, работающий на частоте 16 МГц. «Распиновка» Arduino Yun аналогична Arduino Leonardo, поэтому вместе с Arduino Yun вы можете использовать большинство плат рас- ширения Arduino. □ Linux-часть платы Arduino Yun использует микрокомпьютер Atheros AR9331, работающий под управлением операционной системы Linino — специально под- готовленной версии OpenWRT (популярного дистрибутива Linux для встраивае- мых систем). На Arduino Yun можно создать какое-либо устройство Интернета вещей или даже «поднять» небольшой сайт и использовать его как главное устройство «умного дома». Недостатком Arduino Yun является его высокая цена. Эта проблема решается ис- пользованием платы расширения Arduino Yun shield (рис. 14.14), которая добавляет вашей плате Arduino функционал Linux-части Arduino Yun. В чем отличие «полно- ценной» Arduino Yun от Arduino Yun shield? И Arduino Yun, и Yun Shield имеют одинаковый процессор, размер памяти и объем оперативной памяти для системы Linux. В принципе, Yun Shield, состыкованный с платой Arduino Leonardo, — это и Рис. 14.14. Arduino Yun shield, состыкованный с платой Arduino
Глава 14. Специальные возможности отдельных плат Arduino 325 есть Arduino Yun, но обладание платой Yun Shield даст вам большую гибкость, по- тому что она может использоваться и с другими платами Arduino: Arduino Uno, Duemilanove и Mega. Рассмотрим работу с платой Arduino Yun shield — состыкуем ее с платой Arduino и подадим питание. Подключиться к плате можно как по Ethernet, так и по Wi-Fi. Плата создает точку доступа Iduino-xxxxxx (рис. 14.15), к которой можно подклю- читься с компьютера или планшета. wmgmmggm Рис. 14.15. Точка доступа платы Arduino Yun shield Эта точка доступа имеет IP-адрес 192.168.240.1. Для входа в веб-интерфейс в брау- зере набираем адрес http://i92.i68.240.1 и на странице авторизации вводим пароль: iduino. Если необходим выход в Интернет, можно подсоединиться к сети Wi-Fi, имеющей доступ в Интернет (рис. 14.16). Рис. 14.16. Настройки подключения к Интернету по Wi-Fi с помощью платы Arduino Yun shield
326 Часть III. Сопряжение Arduino со вспомогательными устройствами После перезагрузки плата Arduino с установленной на ней платой расширения Arduino Yun shield будет находиться в сети Wi-Fi с доступом в Интернет. Все основные модули шилда Yun: Wi-Fi, Ethernet, USB-хост — подключены к про- цессору AR9331. Работать с этими устройствами, запускать скрипты и взаимодей- ствовать с различными веб-службами позволяет библиотека Bridge. Существует несколько вспомогательных классов, предназначенных для этого взаимодействия. 14А1. Arduino Yun shield: управляем веб-камерой В этом проекте мы подключим к плате Arduino Yun shield веб-камеру и организуем создание снимков при срабатывании датчика движения, подключенного к плате Arduino. Итак, сначала подключим веб-камеру в USB-разъем Arduino Yun shield и соеди- нимся с Arduino Yun shield no ssh (рис. 14.17). Рис. 14.17, Подключение к плате Arduino Yun shield no ssh Теперь выполним в терминале команды: Обновление: opkg update Установка UVC-драйвера: opkg install kmod-video-uvc Установка утилиты fswebcam: opkg install fswebcam
Глава 14. Специальные возможности отдельных плат Arduino 327 Для проверки камеры попробуем сделать тестовый снимок (рис. 14.18): fswebcam test.png Затем подключаем к плате Arduino датчик движения HC-SR501 (рис. 14.19). Рис. 14.18. Создание снимка с веб-камеры утилитой fswebcam Рис. 14.19. Монтажная схема подключения к плате Arduino датчика движения HC-SR501 Методы класса Process библиотеки Bridge позволяют плате Arduino запускать на плате Yun shield linux-процессы. И в скетче (листинг 14.7) после обнаружения дви- жения датчиком HC-SR501 мы формируем на основании даты имя файла и запуска- ем соответствующие linux-процессы.
328 Часть III. Сопряжение Arduino со вспомогательными устройствами Далее с полученными картинками можно делать что-угодно — например, отправ- лять их в какой-либо облачный сервис. // Подключение библиотек Bridge #include <Bridge.h> #include <Process.h> // process Process picture; //- имя файла картинки String filename; // пин подключения HC-SR501 int pin_HCSR501 = 4; // путь сохранения картинки String path = "/root/imgs/"; void setup() { // Bridge Bridge.begin(); } void loop(void) { // датчик сработал if (digitalRead(pin_HCSR501) == true) { // формирование имени файла filename = ""; // запуск процесса в linux (получение даты) picture.runShellCommand("date +%s"); while(picture.running()); // получение данных из linux while (picture.available()>0) { char с = picture.read(); filename += c; } filename.trim() ; filename += ".png"; // запуск процесса в linux (получение картинки с камеры) picture.runShellCommand("fswebcam " + path + filename + " -r 640x320") while(picture.running() ) ; delay(5000); Электронный архив Полный вариант рассмотренного скетча находится в папке examplesM4\_i4_07 сопрово- ждающего книгу электронного архива (см. приложение 2).
ГЛАВА 15 Взаимодействие Arduino с другими программируемыми системами 15.1. Использование Arduino в проектах LEGO LEGO Mindstorms — конструктор (набор сопрягаемых деталей и электронных бло- ков) для создания программируемого робота — впервые был представлен компани- ей LEGO в 1998 году. В 2013 году вышла 3-я модель серии— LEGO Mind- storms EV3. Наборы LEGO Mindstorms комплектуются стандартными деталями LEGO (балки, оси, колеса, шестерни, сервомоторы), а также сенсорами, двигателями и програм- мируемым блоком. Программируемый блок (рис. 15.1) оснащен процессором Sitara AMI808 (ARM9) частотой 300 МГц от Texas Instruments, несет на борту 64 Мбайт оперативной памяти, 16 Мбайт флеш-памяти и слот для карт памяти microSDHC объемом до 32 Гбайт. В наличии имеются USB-xoct и модуль связи Bluetooth, воз- можно подключение к сети Wi-Fi через USB-донгл, поддерживаются устройства Рис. 15.1. Программируемый блок (микрокомпьютер) конструктора LEGO Mindstorm EV3
330 Часть III. Сопряжение Arduino со вспомогательными устройствами Apple. Блок оснащен монохромным LCD-дисплеем с разрешением 178x128, а для подключения датчиков на нем имеются 4 порта ввода и 4 порта вывода команд. Очень часто в проектах с использованием конструктора LEQO Mindstorm EV3 не хватает возможностей его стандартных датчиков или для подключения необходи- мых датчиков недостаточно имеющихся у микрокомпьютера LEGO 4-х портов. В такой ситуации допустимо задействовать возможности платформы Arduino. Каждый порт микрокомпьютера LEGO Mindstorm EV3 поддерживает целый ряд различных протоколов — в основном, это сделано для совместимости с датчиками NXT и датчиками сторонних производителей. Так, в каждом порту микрокомпью- тера имеется канал аналого-цифрового преобразователя и реализована поддержка протоколов 12С и UART. Способность микрокомпьютера LEGO работать по протоколу 12С открывает воз- можность подключить к каждому из его портов до 127 подчиненных устройств. И здесь мы рассмотрим способ превратить плату Arduino в 12С-датчик для этого микрокомпьютера. К плате Arduino могут быть подключены множество датчиков разных типов, и Arduino будет отправлять данные по протоколу 12С на микроком- пьютер LEGO, выступая в роли своеобразного конвертера: получая запрос (по но- меру датчика) из микрокомпьютера LEGO на значение этого датчика и отправляя полученное значение в микрокомпьютер LEGO. 15.1.1. Получение микрокомпьютером LEGO данных с датчика влажности и температуры DHT11, подключенного к плате Arduino Итак, подключим к плате Arduino датчик влажности и температуры DHT11 и выве- дем его показания на экран микрокомпьютера LEGO. Схема подключения платы Arduino (справа) к порту датчиков микрокомпьютера LEGO (слева) приведена на рис. 15.2 (для лучшего понимания коннектор для под- ключения датчиков LEGO к порту микрокомпьютера LEGO показан в увеличенном виде). Программное обеспечение для сопряжения микрокомпьютера LEGO и платы Arduino состоит из двух частей: первая часть— программа для среды LEGO Mindstorm EV3, вторая часть — скетч, выполняемый на Arduino. Для создания программы в среде LEGO Mindstorm необходимо скачать блоки Dexter Industries EV3 (Dexter.ev3b) и импортировать их в ПО LEGO Mindstorms EV3 командой меню среды LEGO Mindstorm Инструменты | Мастер импорта блоков. А затем сформировать программу, которая отсылает на плату Arduino по протоколу 12С числа 1 и 2 и выводит приходящие в ответ данные на экран (рис. 15.3). Электронный архив Файл Dexter.ev3b размещен в папке examples\15\ сопровождающего книгу электронного архива (см. приложение 2).
Глава 15. Взаимодействие Arduino с другими программируемыми системами 331 6-SDA_Blue 5-SCL_Yellow 4-4.3VJ3reei 3-GND_Recf 2-GND_Black 1-ANA White EV3 Рис. 15.2. Схема подключения платы Arduino к порту датчиков микрокомпьютера LEGO Рис. 15.3. Программа в среде LEGO Mindstorm EV3 Примечание Изучение программирования в среде LEGO Mindstorm не укладывается в рамки этой книги. В скетче для Arduino (листинг 15.1) плата Arduino, получив запрос от микрокомпь- ютера LEGO, получает значение либо влажности, либо температуры с датчика DHT11 и отправляет 1 байт данных на микрокомпьютер LEGO. Результат работы объединенной системы Arduino-LEGO представлен на рис. 15.4. iinclude "DHT.h" iinclude <Wire.h> idefine SLAVE_ADDRESS 0x04 idefine DHTPIN 17 tdefine DHTTYPE DHT11 // DHT 11 DHT dht(DHTPIN, DHTTYPE); int data; int val, flag=0;
332 Часть III. Сопряжение Arduino со вспомогательными устройствами void setup() { Serial.begin(9600); Wire.begin(SLAVE_ADDRESS); Wire.onReceive(receiveData); Wire.onRequest(sendData); dht.begin(); Serial.println("Ready!"); void loop() { if(flag=l) { Serial.print("val=");Serial.println(val); flag=0; if(val==l) data = dht.readHumidity(); else data = dht.readTemperature(); void receiveData(int byteCount) { while(Wire.available()>0) { val=Wire.read(); flag=l; // callback for sending data void sendData() { Wire.write(data); Рис. 15.4. Результат работы объединенной системы Arduino-LEGO
Глава 15. Взаимодействие Arduino с другими программируемыми системами 333 Электронный архив Полный вариант рассмотренного скетча находится в папке examples\15\_15_01 сопрово- ждающего книгу электронного архива (см. приложение 2). 15.2. Arduino в проектах ROS ROS (Robot Operating System, операционная система для роботов) — это структура программной системы (фреймворк), предоставляющая функционал для распреде- ленной работы по программированию роботов. ROS (под названием Switchyard) была первоначально разработана в 2007 году в Лаборатории искусственного интел- лекта Стэнфордского университета. При разработке робота обычно приходится реализовывать свою архитектуру, свой протокол обмена сообщениями, драйвер пульта управления, логику навигации и пр. И даже если имеется возможность использовать для этих задач различные готовые библиотеки, то все равно остается серьезная проблема — объединить их для робота в единую систему. Разработчики ROS позиционируют свою систему именно как операционную — для программ взаимодействия и управления роботом ROS играет роль операционной системы, предоставляя программам управления свои интерфей- сы, библиотеки и готовые приложения. ROS работает под уже готовой ОС (Ubuntu Linux), в которой реализует свой дополнительный слой абстракции— конкретно для управления роботами. ROS обеспечивает стандартные службы операционной системы, такие как аппаратная абстракция, низкоуровневый контроль устройств, реализация часто используемых функций, передача сообщений между процессами и управление пакетами. ROS развивается в двух направлениях: в качестве уже описанной здесь операцион- ной системы и в виде поддерживаемых пользователями пакетов (ros-pkg), органи- зованных в наборы {стеки), реализующие различные функции робототехники. Так, ROS содержит вспомогательные библиотеки и приложения для роботов: преобра- зование систем координат, утилиты для визуализации данных и распознавания объектов, стек навигации и многое другое. Реализованы для ROS и драйверы, по- зволяющие единым образом работать со многими устройствами: джойстиками, устройствами GPS, камерами, лазерными дальномерами и пр. ROS основан на архитектуре графов, где обработка данных происходит в узлах, которые могут получать и передавать между собой сообщения (структурированные данные). Комбинируя готовые узлы ROS и, по необходимости, дописывая собст- венные, можно существенно сократить время разработки и позволить себе скон- центрироваться только на тех задачах, которые действительно нужно решить. К настоящему времени под управлением ROS работает уже много роботов. Вот неполный их список: PR2, TurtleBot, PR1, HERB, STAIR I и II, Nao, Husky A200, iRobot Create, LEGO Mindstorms NXT. ROS выпускается в соответствии с условиями лицензии BSD и с открытым исход- ным кодом. Она бесплатна для использования как в исследовательских, так и в коммерческих целях. Пакеты из ros-pkg распространяются на условиях различных открытых лицензий.
334 Часть III. Сопряжение Arduino со вспомогательными устройствами 15.2.1. Установка ROS Шаги по установке ROS Fuerte Turtle под Ubuntu Linux расписаны на официальном сайте системы: http://wwлv.ros.org/wiki/fuerteЯnstallation/Ubuntu. Рассмотрим ее установку на компьютер с операционной системой Ubuntu 12.04 (Precise Pangolin). Добавляем адрес сервера ROS, чтобы менеджер пакетов знал откуда брать паке- ты ROS: sudo sh -с 'echo "deb http://packages.ros.org/ros/ubuntu precise main" > /etc/apt/sources.list.d/ros-latest.list? Получаем ключ: wget http://packages.ros.org/ros.key -0 - I sudo apt-key add - Обновляем список пакетов — тем самым сервер ROS.org будет проиндексирован: sudo apt-get update Отдаем команду установки ROS Fuerte (рекомендованная конфигурация Desktop- Full): sudo apt-get install ros-fuerte-desktop-full Разработчики ROS стремятся интегрировать в систему лучшие открытые робото- технические библиотеки, сохраняя при этом модульность системы, чтобы пользо- ватель мог установить только те модули, которые ему действительно необходимы. Некоторые библиотеки вынесены из ROS и устанавливаются в ОС стандартным образом, что позволяет использовать эти библиотеки и без ROS. Установим необ- ходимый нам пакет rosseriai: sudo apt-get install ros-fuerte-ros-coirm Отдельно необходимо установить и пакеты rosinstaii и rosdep: sudo apt-get install python-rosinstall python-rosdep В начале новой сессии bash необходимо прописать установку переменных окруже- ния ROS: echo "source /opt/ros/fuerte/setup.bash" » -/.bashrc . ~/.bashrc На этом установка ROS завершена. 15.2.2. Узлы и темы в ROS Узел— это исполняемый файл пакета ROS. Узлы ROS используют клиентские библиотеки ROS для связи с другими узлами. Клиентские библиотеки ROS позво- ляют реализовывать узлы ROS на различных языках программирования, например: □ Rospy — клиентская библиотека для Python; П Roscpp — клиентская библиотека для C++; □ Rosjava — клиентская библиотека для Java.
Глава 15. Взаимодействие Arduino с другими программируемыми системами 335 Узлы могут публиковать сообщения по теме (publisher), а также подписаться на те- му для приема сообщений (subscriber). Сообщения — тип данных, используемых для публикации или подписки на тему. Типы сообщений описываются в файлах сообщений msg — простых текстовых файлах с полем типа и полем имени в строке. Типы полей, которые можно использовать: □ int8; □ string; □ intl6; □ time; □ int32; О duration; □ int64; D other msg files; □ float32; , □ variable-length array[]; □ float64; О fixed-length array[C]. Файлы msg служат для генерации исходного кода для сообщений на разных языках. Файлы msg хранятся в подкаталоге msg каталога пакета. Узлы могут также предоставлять или использовать службы (Service). Службы по- зволяют узлам послать запрос и получить ответ. Файлы служб srv — такие же простые текстовые файлы, как и файлы msg, но они состоят из двух частей: запроса и ответа. Эти две части, разделяются линией: . Вот пример файла srv: int64 A int64 В int64 Sum В этом примере айв — это запрос, a Sum— это ответ. Файлы srv хранятся в подкаталоге srv каталога пакета. 15.2.3. Пакет rossenal Библиотека rosserial устанавливает соединение точка-точка (point-to-point connection) через последовательный порт с недорогими контроллерами (типа Arduino) так, что вы можете посылать сообщения ROS туда и обратно. Библиотека rosserial состоит из общего Р2Р-протокола, библиотеки для работы с Arduino и узлов для ПК. Библиотека rosserial для работы с Arduino находится в каталоге проекта serial (в ка- талоге serial_arduino\libraries). Для работы нам понадобится и библиотека ros_lib, поэтому копируем каталог rosjib в библиотечный каталог libraries Arduino IDE (рис. 15.5). Электронный архив Библиотека rosjib размещена в каталоге libraries сопровождающего книгу электронно- го архива (см. приложение 2).
336 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 15.5. Подключение библиотеки rosjib 15.2.4. Подготовка сообщения (publisher) на Arduino Создадим скетч для Arduino, демонстрирующий создание узла ROS, публикующего сообщения в тему. Для этого соединим плату Arduino с подключенным к ней дат- чиком температуры DS18B20 по последовательному порту (в рассматриваемом случае — это порт /dev/ttyusBO) с компьютером, на котором запущена ROS, и бу- дем отправлять в ROS значения температуры с датчика, используя библиотеки One Wire и roslib. Работу с датчиком температуры, работающим по протоколу 1-Wire, мы подробно рассмотрели в предыдущих главах (см. например, главы 11 и 72), поэтому здесь остановимся на работе библиотеки roslib. В каждую программу ROS для Arduino необходимо включить заголовочный файл ros.h и файлы заголовков для всех типов сообщений, которые мы будем использо- вать, — в нашем случае это std__msgs/Float32.h: #include <ros.h> #include <std_msgs/Float32.h> Далее нам необходимо создать экземпляр объекта узла seriainode, что позволит нашей программе выступать в качестве подписчика (subscriber), либо публиковать сообщения (publisher): ros::NodeHandle nh; Создаем экземпляр publisher для нашего узла seriainode, публикующий сообще- ния типа std_msgs: :Float32 В тему temperature: stdjnsgs::Float32 float32_msg; ros::Publisher chatter("temperature", &fIoat32_msg);
Глава 15. Взаимодействие Arduino с другими программируемыми системами 337 В подпрограмме setup о необходимо инициализировать узел и объявить о роли узла chatter в качестве publisher: nh.initNodeO; nh.advertise(chatter); В цикле loop () после считывания данных с датчика температуры публикуем сооб- щение в тему и вызываем ros:: spinonce (), где обрабатываются все функции обрат- ного вызова соединения. chatter.publish( &float32_msg ); nh. spinOnce (); Код этого скетча представлен в листинге 15.2. tinclude <OneWire.h> OneWire ds(10); // линия 1-Wire будет на pin 10 tinclude <ros.h> jfinclude <std_msgs/Float32.h> ros::NodeHandle nh; stdjnsgs::Float32 float32_msg; ros::Publisher chatter("temperature", &f Ioat32_msg), void setup (void) { nh. initNode () ; nh.advertise(chatter); } void loop (void) { byte i; byte present = 0; byte data[12]; byte addr[8]; if ( !ds.search(addr)) { ds.reset_search(); return; } ds.reset (); ds.select(addr); ds.write(0x4 4,1); // запускаем конвертацию delay(1000); // скорее всего достаточно 750 ms present = ds.reset(); ds.select(addr); ds.write(OxBE); // считываем ОЗУ датчика
33Q . Часть III. Сопряжение Arduino со вспомогательными устройствами for ( i = 0; i < 9; i++) { // обрабатьгоаем 9 байтов data[i] = ds.readO; } Serial.print(" CRC="); Serial.print( OneWire::crc8( data, 8), HEX); Serial.println(); // высчитываем температуру int HighByte, LowByte, Temp; float Tempfl,Tempf2; LowByte = data[0]; HighByte = datafl]; Temp = (HighByte « 8) + LowByte; Tempf l=Temp/16; Tempf2= (Temp%16) *100/16; fIoat32_msg.data=Tempf1+Tempf2/100; // публикуем сообщение chatter.publish( &float32_msg ); nh.spinOnce(); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\15\_15__02 сопрово- ждающего книгу электронного архива (см. приложение 2). Теперь проверим работу этого скетча. Первое, что необходимо выполнить, — это команду roscore. Команда rosnode отображает информацию об узлах ROS, которые работают в настоящий момент. Команда rosnode list выдает список этих активных узлов. В терминале увидим: /rosout Соответственно, есть только один работающий узел: rosout. Этот узел работает всегда, т. к. он собирает и логирует отладочные сообщения узлов. Команда rosrun позволяет назначить имя пакета, чтобы непосредственно запустить его узел: $ rosrun [package_name] [node_name] Запускаем узел seriainode.py пакета rosseriaipython, который соединяет нашу Arduino с остальной частью ROS. Необходимо выставить используемый последова- тельный порт: rosrun rosserialjpython serial_node.py /dev/ttyUSBO В терминале набираем: $ rosnode list И смотрим список активных узлов: /rosout /serial node
Глава 15. Взаимодействие Arduino с другими программируемыми системами 339 Утилита rxgraph, являющаяся частью пакета rxtoois, позволяет визуально показать узлы и темы, запущенные в настоящий момент. Набираем в терминале: $ rxgraph Результат показан на рис. 15.6. Node [/rosout] Publications: */rosout_agg [rosgraphjnsgs/Logj Subscriptions: */rosout [rosgraph msgs/ Log] Services: * /rosoufc/setjoggerjevel */rosout/get loggers Wd:2O7S Connections: * topic: /rosout Uo:http:// ubuntu1:44019/ * direction: inbound * transport TCPROS Рис. 15.6. Утилита rxgraph демонстрирует список активных узлов и тем Утилита rostopic позволяет получить информацию о темах ROS. Команда rostopic echo показывает данные, опубликованные в теме. Набираем в терминале: $ rostopic echo /temperature и видим постоянно поступающие с Arduino данные датчика температуры (рис. 15.7). ;c|at2; 23.75 Рис. 15.7. Публикация сообщений из Arduino в тему temperature
340 Часть III. Сопряжение Arduino со вспомогательными устройствами 15.2.5. Создание подписки (subscriber) на Arduino Теперь рассмотрим пример использования Arduino в качестве узла subscriber для приема сообщений. В этом примере мы будем включать/выключать светодиод, подключенный к выводу 13 Arduino, получая сообщения из ROS. Включаем заголовочный файл ros.h и файлы заголовков для всех типов сообщений, которые мы будем использовать, — в нашем случае это stdjnsgs/Empty.h (для пус- тых сообщений): #include <ros.h> #include <stdjnsgs/Empty.h> Далее необходимо создать экземпляр объекта узла serial jiode, что позволит нашей программе выступать в качестве подписчика (subscriber), либо публиковать сооб- щения (publisher): ros::NodeHandle nh; Создаем экземпляр subscriber для нашего узла, публикующий пустые сообщения типа stdjnsgs: : Float32 В тему toggle_led: •ros::Subscriber<std_msgs::Empty> sub("toggle_led", &messageCb ); Создаем для нашего узла функцию обратного вызова messagecb. Эта функция должна постоянно получать сообщение в качестве аргумента. Для нашей функции обратного вызова messagecb назначим тип сообщения stdjnsgs::Empty. По получе- нии сообщения функция инвертирует значение сигнала на выводе 13 Arduino, при этом включая/выключая светодиод. void messageCb ( const stdjnsgs:: Empty& togglejnsg) { digitalWrite(13, HIGH-digitalRead(13)); // blink the led } В подпрограмме setup о необходимо инициализировать узел и объявить о роли узла в качестве подписчика на сообщения: nh.initNode(); nh.subscribe(sub); И наконец, в цикле loop () вызываем ros:: spinOnce (), где обрабатываются все функции обратного вызова соединения: nh.spinOnce(); Код этого скетча представлен в листинге 15.3. #include <ros.h> #include <stdjtisgs/Empty.h> ros::NodeHandle nh; void messageCb ( const stdjnsgs:: Empt у & togglejnsg) { digitalWrite(13, HIGH-digitalRead(13)); // blink the led
Глава 15. Взаимодействие Arduino с другими программируемыми системами 341 ros::Subscriber<std_msgs::Empty> sub("toggle_led", SmessageCb ); void setup () { pinMode(13, OUTPUT); nh.initNodeO ; nh. subscribe (sub); } void loop () { nh. spinOnce (); delay(1); } Запускаем узел serial node, py пакета rosseriaipython, который соединяет нашу Arduino с остальной частью ROS. Необходимо выставить используемый последова- тельный порт (здесь использована другая плата Arduino, подключенная к порту ttyACMO): rosrun rosserial_python serial__node. ру /dev/ttyACMO Переходим на компьютер с запущенной ROS и проверяем список активных узлов: $ rosnode list Смотрим результат: /rosout /serial_node Наш узел запущен как подписчик на сообщения по теме toggieied, но никаких сообщений он пока не получил. Связь по темам осуществляется путем отправки сообщений ROS между узлами. Для общения издателя и абонента издатель (publisher) и абонент (subscriber) должны отправлять и получать сообщения одина- кового типа. Это означает, что тип темы определяется типом сообщений, которые в ней публикуются. Тип сообщения, отправляемого в тему, может быть определен с помощью команды rostopic type: $ rostopic type toggle_led Результат: std_msgs /Empty Теперь используем rostopic с сообщениями — rostopic pub публикует данные в тему: rostopic pub [topic] [msg_type] [args] Отправим единичное сообщение: rostopic pub toggle_led stdjnsgs/Empty —once Светодиод должен изменить значение на противоположное.
342 Часть III. Сопряжение Arduino со вспомогательными устройствами Для отправки сообщения в цикле (-г) с определенной частотой введем команду: rostopic pub toggle_led stdjnsgs/Empty -r 1 Эта команда публикует сообщение с частотой 1 Гц в тему toggieled. Светодиод будет мигать с частотой 2 раза в секунду. Электронный архив Полный вариант рассмотренного скетча находится в папке examplesM5^15^03 сопрово- ждающего книгу электронного архива (см. приложение 2). 15.2.6. Связь через ROS двух плат Arduino Теперь создадим пример передачи сообщений через ROS между двумя платами Arduino. На одной плате Arduino, соединенной с ROS, находится датчик температу- ры DS18B20 (см. разд. 15.2.4). Подключим к ROS по другому последовательному порту вторую плату Arduino, к которой подключен дисплей WH0802 — на него мы и будем выводить показания температуры с датчика, расположенного на первой плате Arduino. Скетч для публикации показаний температуры у нас уже есть. Скетч для получения сообщений с показаниями температуры, публикуемыми в тему temperature, представлен в листинге 15.4. // подключить библиотеку LiquidCrystal #include <LiquidCrystal,h> // создание экземпляра объекта LiquidCrystal LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // rosserial #include <ros.h> # include <stdjnsgs/Empty.h> #include <std_msgs/Float32.h> ros::NodeHandle nh; void messageCb( const stdjnsgs::Float32& togglejnsg) { digitalWrite(13, HIGH-digitalRead(13)); // blink the led led.setCursor(0, 0); led.print("Temp="); led.setCursor(0, 1); led.print(togglejnsg.data);} ros::Subscriber<stdjnsgs::Float32> sub("temperature", SmessageCb void setup() { led.begin(8, 2) ; pinMode(13, OUTPUT); nh.initNode(); nh.subscribe(sub);
Глава 15. Взаимодействие Arduino с другими программируемыми системами 343 void loop () { nh. spinOnce () ; delay(1000); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\15\_15_04 сопрово- ждающего книгу электронного архива (см. приложение 2). Теперь посмотрим, как реализовать передачу в ROS. Запустить два узла serial_node с одним именем не получится. Но одна из особенностей ROS состоит в том, что вы можете переназначить имена (Names) узлов из командной строки: $ rosrun rosserial_python serial_node.ру /dev/ttyUSBO name:=seriall $ rosrun rosserial_python serial_node.py /dev/ttyACMO name:=serial2 Посмотрим список активных узлов командой rosnodeiist: /rosout /seriall /serial2 А командой rxgraph посмотрим узлы и темы (рис. 15.8). При этом показания темпе- ратуры отображаются на дисплее WH0802. 1 ►ubscriptons: ieraces: Нот ctirecticm: outbo^^vd [ * direction: Мэошх! Рис. 15.8. Утилита rxgraph — список активных узлов и тем
ГЛАВА 16 Программирование в среде Arduino IDE других плат Начиная с версии 1.6.5, Arduino IDE предоставила официальную поддержку для добавления сторонних плат. Это позволяет программировать в знакомой среде и на понятном Arduino языке Arduino-несовместимые платы и, соответственно, исполь- зовать их в своих проектах. 16.1. ESP8266 — микроконтроллер с интерфейсом Wi-Fi С конца 2014 года на китайских торговых площадках появились Wi-Fi-модули ESP8266. Причем, как выяснилось, это не просто модули Wi-Fi, а полноценные 32-битные микроконтроллеры со своими наборами GPIO, в том числе поддержи- вающими шины SPI, UART и 12С. При этом сами модули состоят из минимального количества деталей: собственно микросхемы ESP8266, флеш-памяти и кварцевого генератора. Характеристики этих модулей представлены в табл. 16.1. В настоящее время выпускается более 12 модификаций плат модулей ESP8266, различающихся количеством выводов и вариантами исполнения. Модули продают- ся с загруженной прошивкой, которая образует мост Wi-Fi —► UART для подключе- ния к другому микроконтроллеру, в том числе и к Arduino. Настройка соединений и обмен данными осуществляются с помощью АТ-команд. Возможно два варианта работы с модулем ESP8266: [I использование его совместно с платой Arduino, которая будет управлять моду- лем по UART; п создание собственной прошивки для модуля ESP8266 и его применение как самодостаточного устройства. Таблица 16.1. Характеристики модулей ESP8266 Частота ! Wi-Fi 2412-2484 МГц Стандарт 802.11 b/g/n Мощность + 20 дБ
346 Часть III. Сопряжение Arduino со вспомогательными устройствами Таблица 16.1 (окончание) Поддерживаемые типы шифрования Поддерживаемые режимы работы Напряжение питания Потребление тока Количество доступных выводов GPIO Внешняя флеш-память RAM данных RAM инструкций Температурный режим WEP, WPA, WPA2 Клиент (STA), точка доступа (АР), клиент+точка доступа (STA+AP) 1,7-3,6 В 70 мА (пиковое значение 240 мА) 4-10 512 Кбайт 80 Кбайт 32 Кбайт От-40 до+70 °С Один из недостатков плат ESP8266 — малое количество контактов, что сильно ограничивает их применение в больших проектах. Эта проблема решена в новой линейке контроллеров ESP— ESP32, которые отличаются большей производи- тельностью, большим объемом оперативной памяти, имеют поддержку не только Wi-Fi, но и Bluetooth, а также обладают большим количеством выводов. Более под- робно ознакомиться с описанием микроконтроллера ESP32 можно, например, по этой ссылке: http://micpic.ru/home/proekty-na-esp32/194-opisanie-mikrokontrollera- esp32.html. 16.1.1. Установка Arduino IDE для работы с ESP8266 Arduino IDE для ESP8266 позволяет создавать прошивки и прошивать их в ESP8266 точно так же, как вы это делаете с Arduino. К тому же, большая часть библиотек для Arduino, не использующих внутренние порты и прочие аппаратные возможно- сти плат Arduino, после небольшой доработки отлично работают и на ESP-модулях, В настоящее время для использования с ESP8266 адаптировано уже достаточно много библиотек. Рассмотрим установку Arduino DDE для ESP8266. Сначала необходимо скачать с официального сайта Arduino среду разработки Arduino DDE версии не ниже 1.6.5 и установить ее на компьютер (см. главу 3). Далее запускаем Arduino IDE, выбираем пункт меню Файл | Настройки и в поле Additional Boards Manager URLs вводим: http://arduino.esp8266.com/stable/package_esp8266com_index.json Нажимаем кнопку OK (рис. 16.1). Затем выбираем пункт меню Инструменты | Плата | BoardsManager и в списке ищем плату ESP8266. Выбираем этот пункт и версию и нажимаем на кнопку Install (рис. 16.2) — запустится процесс скачивания и установки Arduino IDE для ESP8266 (рис. 16.3).
Глава 16. Программирование в среде Arduino IDE других плат 347 Рис. 16.1. Добавление адреса в поле Additional Boards Manager URLs для скачивания Arduino IDE для ESP8266 Рис. 16.2. Выбор платы ESP8266 в окне Boards Manager
348 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 16.3. Процесс скачивания и установки Arduino IDE для ESP8266 По завершении этого процесса рядом с наименованием платы ESP8266 возникнет надпись INSTALLED (рис. 16.4), а в списке плат, открываемом по команде меню Инструменты | Плата, появятся платы ESP8266 (рис. 16.5). c-sir.vz КиРагл^ л»с-и Рис. 16.4. Arduino IDE для ESP8266 установлена
Глава 16. Программирование в среде Arduino IDE других плат 349 Рис. 16.5. Выбор плат ESP8266 в Arduino IDE для ESP8266 16.1.2. Печать курса валют на термопринтере в проекте Интернета вещей Наличие у модулей ESP8266 интерфейса Wi-Fi позволяет использовать их в проек- тах Интернета вещей (IoT). Создадим на ESP8266 проект IoT-принтера, который ^удет печатать курс валют на текущую дату, получая через Интернет данные с сай- а cbr.ru. В качестве принтера в этом проекте мы воспользуемся бюджетным ермопринтером, выпускаемым специально для Arduino (рис. 16.6). 1ринтер использует термобумагу 2,25 дюйма, которую можно приобрести в мага- ине канцелярских товаров. Вам также понадобится регулируемый источник пита- ия от 5 до 9 В постоянного тока, который может обеспечить ток более 1,5 А. )бщение с принтера с платой Arduino мы организуем с помощью UART-соеди- ения.
350 Часть III. Сопряжение Arduino со вспомогательными устройствами Рис. 16.6. Термопринтер для Arduino Прежде всего необходимо провести начальный тест принтера. Подключите принтер к блоку питания, держа нажатой кнопку на его верхней панели, — будет распечата- на таблица шрифтов и некоторая дополнительная информация (рис. 16.7). Нуж- ный нам параметр— скорость обмена по последовательному порту (Baudrate); 19 200 бод. Рис. 16.7. Распечатка тестовой страницы Подключим теперь термопринтер к модулю ESP8266 (в проекте использовалась отладочная плата NodeMCU — удобная платформа на основе модуля ESP8266) по схеме, представленной на рис. 16.8, и загрузим на плату NodeMCU код из листин- га 16.1 (для программирования нам потребуется Arduino-библиотека для принтера
Глава 16. Программирование в среде Arduino IDE других плат 351 Adafruit Thermal). В результате мы увидим вывод на принтер тестовых данных (рис. 16.9). Электронный архив Библиотека Adafruit Thermal размещена в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2). I+SV2A ; : ! Рис. 16.8. Монтажная схема подключения термопринтера к отладочной плате NodeMCU ESP8266 Рис. 16.9. Вывод тестовых данных из скетча на принтер
352 Часть III. Сопряжение Arduino со вспомогательными устройствами #include flAdafruit_Thermal.hlf AdafruitJThermal printer(&Serial); // Pass addr to printer constructor void setup() { // запуск последовательного порта Serial.begin(19200); // инициализация принтера printer.begin(); delay(3000) ; // настройки по умолчанию printer.wake(); printer.setDefault(); printer.println(); printer.printlnO ; delay(1000); printer.println("test "); printer.println("esp8266 iot"); printer.println("thermal printer"); } void loopO { Нашему проекту для правильной работы необходимо знать реальное время, для по- лучения которого мы воспользуемся модулем часов реального времени (RTC) на микросхеме DS3231. Подключение модуля DS3231 к модулю NodeMCU ESP8266 осуществляется по протоколу 12С: соединяем контакты NodeMCU D3 (GPIO0) и D4 (GPIO2) соответственно с контактами SCL и SDA модуля DS3231 (рис. 16.10). Теперь нам необходимо получать из Интернета актуальный курс валют. Курсы ва- лют в формате XML доступны на сайте Сбербанка по адресу: www.cbr.ru/scripts/ XML_daily.asp?date_req==<data>, где <data> — дата в формате dd/mm/yyyy. Если параметр date_req в запросе отсутствует, то вы получите данные на последнюю зарегистрированную дату. Чтобы делать запросы по адресу получения XML-файла, сначала мы устанавливаем соединение с точкой доступа для подключения к Интернету: WiFi .mode (WIFI_STA) ; WiFi.begin(ssid, password); Затем создаем TCP-соединение с сервером cbr.ru: WiFiClient client; const int httpPort = 80; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); return;
Глава 16. Программирование в среде Arduino IDE других плат 353 ч н ч ч ч ч ч ч ч ч ч ч ч ч ч ч - ч ч - - Рис. 16.10. Схема подключения модуля DS3231 к модулю NodeMCU ESP8266 Формируем строку для запроса XML-файла: String url = Vscripts/XML_daily.asp?date_req=="+getDateStr(); Serial.print("Requesting URL: "); Serial.println(url); Процедура getDatestr () выдает строку в формате dd/mm/yyyy на текущий день: String getDateStr() { String str = String(day) + "/" + formatDigit(month, 2) + "/20" + formatDigit(year, 2);
354 Часть III. Сопряжение Arduino со вспомогательными устройствами return str; } Отправляем данные на сервер: client.print(String("GET ") + url + " HTTP/1.l\r\n" + '"Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); delay(10); И выводим в последовательный порт ответ сервера: String line; while(client.available()){ line - client.readStringUntil(f\r'); Serial.print(line); delay(10); Электронный архив Полный вариант рассмотренного скетча находится в папке examplesU6W6_02 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем этот скетч в плату NodeMCU и видим результат его работы в мониторе последовательного порта (рис. 16.11). Работа со строками в Arduino достаточно проблемна, поэтому внесем в наш скетч следующие изменения: int k=O; while(client.available()){ line « client.readStringUntil('\rf); if(k>0) k++; if(line.substring(11,14)=="840") k=l; if(k—5) { if(dollar—line.substring(9,16)) ; // если курс изменился - выводим на печать else { dollar=line.substring(9,16); printer.println(); printer.println(getTimeStr()); printer.print("$= "); printer.print(dollar); printer.print (•" rub"); printer.println(); delay(10);
Глава 16. Программирование в среде Arduino IDE других плат 355 Connecting to MacBook-Pro-Victor WiFi connected IP address: 192.168.2.19 24.08.17 11:48:21 connecting to cbr.ru Requesting URL: /scripts/5№_daily.asp?datejce<j»24/08/2017 HTTP/1.1 200 OK Server: nginx/1.11.10 Date: Thu, 24 Aug 2017 08:47:02 GMT Content-Type: text/ml Content-Length: 5804 Connection: close Vary: Accept-Encoding Cache-Control: private X-Powered-By: ASP.NET <?яа1 version*"!.0" encoding«wwindQws-1251'' ?> <ValCurs Date--24.08.2Q17" шик-"Foreign Currency <Valute ID»"R01010"> <CharCode>AUD</CharCode> <8oiBxnal>l</No]Binal > <Нагае>Авс7ралийский доллар</Ша!ве> <Value>46,6486</Value> I</Valute> !<Valute ID»"R0102QA''> <CharCode>AZN</CharCode> <Nominal>K/Noininal> <Назве>Азербайд»анский маках</На2ве> <Value>35,0719</Value> Рис. 16.11. Результат получения XML-файла с сайта cbr.ru в мониторе последовательного порта Рис. 16.12. Вывод курса доллара с сайта cbr.ru на принтер
356 Часть III. Сопряжение Arduino со вспомогательными устройствами Электронный архив Полный вариант рассмотренного скетча находится в папке examples\16\_i6J)3 сопрово- ждающего книгу электронного архива (см. приложение 2). Загружаем этот скетч в плату NodeMCU и видим, как на печать выводится курс доллара (рис. 16.12). 16.2. Z-Uno — плата для прототипирования устройств Z-Wave Z-Wave — это распространенный протокол радиопередачи данных, предназначен- ный для домашней автоматизации. Передача данных осуществляется на частотах 869,0 МГц (Россия), 868,42 МГц (Европа, страны СЕРТ, Китай, Сингапур, ОАЭ, ЮАР), 908,42 МГц (США, Мексика), 921,42 МГц (Австралия, Бразилия, Новая Зеландия), 919,8 МГц (Гонконг), 865,2 МГц (Индия), 868,2 МГц (Малайзия), 951-956 и 922-926 МГц (Япония). Модуляция FSK (частотная). Скорость передачи: 42 Кбит/с, 100 Кбит/с и 9,6 Кбит/с (для совместимости со старыми устройствами). Скважность не более 1%. Предельная мощность передачи — 1 мВт. Протокол Z-Wave весьма популярен, и существует огромное множество совмести- мых устройств. Однако все, кто когда-либо автоматизировал свое жилище, сталки- вались с тем, что чего-то все-таки не хватает. Совсем недавно для облегчения разработки устройств Z-Wave было создано устройство Z-Uno (рис. 16.13). Более правильно назвать Z-Uno платформой, а не устройством, т. к. устройств на этой маленькой плате можно сделать много. Разработчик устройства— компания Z-Wave.me. Рис. 16.13. Плата Z-Uno
Глава 16. Программирование в среде Arduino IDE других плат 357 Z-Uno — это Arduino в мире Z-Wave. На этой плате вы можете собрать все ваши устройства. Код пишется на языке С в стиле Arduino прямо в среде Arduino IDE. Эта же среда используется и для загрузки кода в плату по USB (есть также возмож- ность залить новый код по радио через контроллеры Z-Wave — так называемая пе- репрошивка ОТА). Код управляет всеми ножками платы, как в Arduino. Привычный набор функций Arduino дополнен специфическими для работы с сетью Z-Wave — получения и отправки команд. Все сложности Z-Wave скрыты «под капотом» Z-Uno. Основное отличие Z-Uno от плат Arduino — наличие радиопередатчика Z-Wave и полная поддержка сетей этого стандарта. В России продаются более сотни совместимых с Z-Wave устройств — различных датчиков и контроллеров, а всего в мире реализуется свыше 1400 наименований от более чем четырехсот производителей. Сеть Z-Wave представляет собой самоорга- низующуюся ячеистую mesh-сеть. То есть при отсутствии получателя сигнала в зоне прямой видимости сигнал к нему пойдет через соседние радиоузлы сети до тех пор, пока не будет найден получатель. Каждое устройство перед началом рабо- ты должно быть добавлено в сеть. Сеть Z-Wave может содержать до 232 устройств, каждое из которых имеет свой уникальный 8-битный идентификатор (ID). Технические характеристики платы Z-Uno: □ 28 Кбайт флеш-памяти для скетчей; П 4 Кбайт RAM; □ Z-Wave радиотрансивер на каналах 9,6, 40 и 100 Кбит/с; □ 22 вывода GPIO (некоторые перекрываются с другими функциями); □ 4 вывода АЦП; □ 5 выводов ШИМ; □ 2 вывода UART; 0 вход USB (в режиме serial) ; □ 64 Кбайт EEPROM; □ вывод SPI (master или slave режимы); □ 4 ИК-контроллера и один ИК-приемник с функцией обучения; □ по одному контроллеру TRIAC/ZEROX для диммирования; □ одно прерывание; □ 2 таймера (16 МГц или от внешнего источника); □ вывод 12С (программный на «ногах» GPIO); 3 вывод 1-Wire (программный на «ногах» GPIO); □ 8x6 сканер кнопок (в том числе в режиме глубокого сна); Я 2 сервисных светодиода, одна сервисная кнопка; 0 один пользовательский светодиод (как контакт 13 у Arduino). Назначение контактов платы Z-Uno показано на рис. 16.14.
358 Часть III. Сопряжение Arduino со вспомогательными устройствами Service LEO Battery connector U User LEO Externakonnector Wire antenna Power Pin Digital Pin UARTPin • External Timer Pin Antenna GNDPin Analog Read Pin SPtPin • IR Pin . LED Analog Write Pin Interrupt Pin < TRIACPin < Button Рис. 16.14. Назначение контактов платы Z-Uno 16.2.1. Установка Arduino IDE для Z-Uno Пользовательские скетчи заливаются в Z-Uno из Arduino ГОЕ. Для работы в Arduino IDE с Z-Uno необходимо установить соответствующий пакет, который содержит компилятор, загрузчик, библиотеки и Н-файлы проекта Z-Uno. Это делается из по- явившегося в Arduino ГОЕ, начиная с версии 1.6.5, Менеджера плат (Board Manager). Итак, запускаем Arduino ГОЕ 1.6.5. Выбираем команду меню Файл | Настройки, в поле Additional Boards Manager URLs добавляем адрес: z-uno. z-wave .me/f iles/z-uno/package_z-wave .me_index. j son и нажимаем кнопку OK (рис. 16.15). Перезапускаем Arduino IDE. Выбираем команду меню Инструменты | Плата | Boards Manager, находим в списке плат Z-Uno by Z-WANE>ME и нажимаем кнопку Install (рис. 16.16). После загрузки Плата Z-WANE>ME Z-Uno появится в списке плат (рис. 16.17). Пункт меню Записать Загрузчик (см. рис. 16.17) позволяет обновить загрузчик скетча Z-Uno и стек Z-Wave до самой последней версии, входящей в пакет Z-Uno. Также в меню появится флажок для включения шифрования (класс команд Security), компактной отправки пакетов (класс команд Multicommand) и рабочей частоты Frequency (RU, EU, USA). Эти функции не поддерживаются некоторыми
Глава 16. Программирование в среде Arduino IDE других плат 359 Рис. 16.15. Добавление в поле Additional Boards Manager URLs адреса для скачивания пакета поддержки проекта Z-Uno Рис. 16.16. Процесс скачивания и установки пакета поддержки проекта Z-Uno
360 Часть III. Сопряжение Arduino со вспомогательными устройствами Ш Рис. 16.17. Выбор платы Z-Uno в Arduino IDE Рис. 16.18. Примеры использования платы Z-Uno в Arduino IDE
Глава 16. Программирование в среде Arduino IDE других плат 361 контроллерами. В меню Файл | Образцы появятся примеры, специфичные для Z-Uno (рис. 16.18). С них и можно начать изучение возможностей Z-Uno. 16.2.2. Подключение к плате Z-Uno датчика влажности DHT11 Рассмотрим проект подключения датчика DHT11 к плате Z-Uno и отправку значе- ний влажности и температуры в каналы Multilevel Sensor. Схема соединений пока- зана на рис. 16.19. Содержимое скетча приведено в листинге 16.2 (для программи- рования используется библиотека ZUNODHT). Рис. 16.19. Монтажная схема подключения к плате Z-Uno датчика DHT11 // добавить библиотеку #include "ZUNO_DHT.h" // пин подключения data DHT11 #define DHTPIN 9 DHT dht(DHTPIN, DHT11); int humidity; // переменная для данных влажности int temperature; // переменная для данных температуры // установить каналы для отправки ZUNO_SETUP_CHANNELS( ZUNO_SENSOR_MULTILEVEL_TEMPERATURE(getterTemperature) , ZUNO_SENSOR_MULTILEVEL_HUMIDITY(getterHumidity)
362 Часть III. Сопряжение Arduino со вспомогательными устройствами void setup() { dht.begin(); Serial.begin(); Serial.println("start"); void loop() { // получение данных с датчика humidity = dht. readHumidity (); temperature = dht.readTemperature() Serial.print("Humidity = "); Serial.print(humidity); Serial.print(" % "); Serial.print("Temperature = "); Serial.print(temperature); Serial.println(" *C") ; // отправка данных в каналы zunoSendReport(1); zunoSendReport(2); // пауза 30 секунд delay(30000); } byte getterTemperature() { return temperature; } byte getterHumidity() { return humidity; В окне канала Z-Wave данные температуры и влажности после добавления устройств будут выглядеть следующим образом (рис. 16.20). 22 *с Рис. 16.20. Отображение данных в окне канала Z-Wave
ЧАСТЬ IV О© Практика разработки проектов для Arduino Глава 17. Умная теплица «Домашний цветок» Глава 18. Светодиодное табло футбольных матчей Глава 19. Голосовое управление исполнительными устройствами Глава 20. Проекты для вендинга: всюду деньги, деньги, деньги... Глава 21. Makey: импровизированные клавиатуры Глава 22. Arduino и интерфейс USB: управление роботами Глава 23. Камера Pixy: организация компьютерного зрения
ГЛАВА 17 Умная теплица «Домашний цветок» Теплицы предназначены для обеспечения оптимального микроклимата, способст- вующего росту и развитию растений. Это могут быть и большие промышленные сооружения, и небольшое место на подоконнике для выращивания любимого цвет- ка. Но даже за самой крохотной теплицей на подоконнике нужен уход: осуществ- лять полив, поддерживать нужную температуру, уровень освещенности и т. п. Многие с удовольствием занялись бы подобным хозяйством, вот только ни сил, ни времени для этого нет. И только мечта подсказывает: вот бы иметь такую конст- рукцию, которая была бы настолько умной, что делала бы все сама. Такая теплица окажется востребованной теми, кто не хочет тратить много времени на уход за рас- тениями, а также может не иметь для этого возможности в случае длительного отсутствия — командировок, отпуска и т. п. Назовем такую теплицу «умной» и приступим к ее созданию. Какие же функции будет выполнять наша теплица? Прежде всего, нам потребуется оперативно получать всю необходимую информа- цию об климатических параметрах нашей теплицы: температуре и влажности воз- духа, температуре и увлажненности почвы, а также освещенности внутри тепли- цы, — т. е. осуществлять мониторинг климатических параметров теплицы. Какую проблему решит функция мониторинга? Прежде всего — устранит беспо- койство насчет того, все ли в порядке с растениями во время нашего отсутствия: есть ли вода в системе, не выключалось ли электричество, может ли система венти- ляции обеспечить нужную температуру, если в помещении стало слишком жарко, и т. п. Выводить данные мониторинга можно на дисплей при самой теплице, или опове- щать нас о критических значениях климатических параметров с помощью «тре- вожных» светодиодов, или пересылать нам данные через Интернет на смартфон или планшет. Следующая функция — обеспечение автономности теплицы: при снижении уров- ня увлажненности почвы в теплице ниже определенного значения— включить полив, при снижении в ней температуры— включить обогрев, при превышении
366 Часть IV. Практика разработки проектов для Arduino температуры — включить вентиляцию, освещенность в теплице тоже необходимо регулировать по определенному циклу. К функции автономности тесно примыкает и следующая функция — необходимо будет реализовать возможность управления теплицей: осуществлять полив, обогрев, вентиляцию, регулировать освещенность растений. Управление можно организо- вать с помощью автоматики или удаленно— через Интернет со смартфона или планшета (рис. 17.1). JC Данные с датчиков t, h, освещенность Данные с датчиков с|«-- , h, освещенность Полив, свет, | вентилятор | ^ вентилятор Рис. 17.1. Схема взаимодействия в умной теплице 17.1. Мониторинг климатических параметров умной теплицы Начнем наш проект с реализации функции мониторинга параметров умной тепли- цы и обеспечим получение следующих данных об окружающей среде внутри нее: П температура воздуха; □ влажность воздуха; □ увлажненность почвы; □ освещенность цветка. Для реализации функции мониторинга нам понадобятся следующие компоненты: □ плата Arduino Uno; □ кабель USB; □ плата прототипирования;
Глава 17. Умная теплица «Домашний цветок» 367^ □ соединительные провода—15 шт.; □ фоторезистор; □ резистор 10 кОм; □ датчик температуры ТМРЗ6; □ датчик температуры и влажности воздуха DHT11; □ модуль влажности почвы. Наборы компонентов серии «Дерзай!» Многие из упомянутых здесь и далее компонентов имеются в наборах электроники се- рии «Дерзай», предлагаемых издательством «БХВ-Петербург» (см. http://www.bhv.ru/ books/kits). Познакомимся с датчиками, которые обеспечат функции мониторинга параметров нашего проекта. Датчик температуры и влажности воздуха DHT11 мы рассматривали в главе 9 (см. разд. 9.3). С помощью фоторезистора (рис. 17.2) осуществляется измерение освещенности: в темноте сопротивление фоторезистора весьма велико, но когда на него попадает свет, это сопротивление падает пропорционально его освещенности. /\\ Pint DC voltage ♦2.7-5.6V Pin 2 Analog Voltage РШЗ GND Output Рис. 17.2. Фоторезистор Рис. 17.3. Аналоговый датчик температуры ТМР36 Аналоговый датчик температуры ТМР36 (рис. 17.3) позволяет легко преобразовать выходной уровень напряжения в показания температуры в градусах Цельсия. Каждые 10 мВ соответствуют 1 °С. Формула для преобразования выходного на- пряжения в температуру: Т,°С = [(Vout, мВ - 500] / 10
368 Часть IV. Практика разработки проектов для Arduino Модуль влажности почвы (рис. 17.4) предназначен для определения влажности земли, в которую он погружен. Он позволяет узнать о недостаточном или избыточ- ном поливе ваших домашних или садовых растений. Модуль состоит из двух час- тей: контактного щупа YL-28 и датчика YL-38, соединенных между собой двумя проводами. Между двумя электродами щупа YL-28 создается небольшое напряже- ние. Если почва сухая, сопротивление велико, и ток будет меньше. Если земля влажная — сопротивление меньше, ток — чуть больше. По итоговому аналоговому сигналу можно судить о степени влажности. Рис. 17.4. Модуль влажности почвы Монтажная схема этого проекта представлена на рис. 17.5, а его начальный общий вид — на рис. 17.6. Рис. 17.5. Монтажная схема подключения к плате Arduino датчиков для мониторинга параметров проекта умной теплицы «Домашний цветок»
Глава 17. Умная теплица «Домашний цветок» 369 Рис. 17.6. Проект «Домашний цветок»: подключение датчиков Содержимое скетча, обеспечивающего работу этого проекта, приведено в листин- ге 17.1. Фоторезистор, датчик температуры ТМР36 и модуль влажности почвы — обычные аналоговые датчики. Аналоговые значения датчика ТМР36 мы преобразо- вываем в показания температуры в градусах Цельсия. Для работы с датчиком тем- пературы и влажности воздуха DHT11 подключается Arduino-библиотека DHT. Данные с датчиков снимаются с интервалом 5 секунд и значения выводятся (пока!) в последовательный порт Arduino. Электронный архив Библиотека DHT размещена в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2). Создадим в Arduino IDE новый скетч, занесем в него код из листинга 17.1 и загру- зим этот скетч в плату Arduino. // подключение библиотеки DHT #include "DHT.h" // тип датчика DHT #define DHTTYPE DHT11 // контакт подключения входа данных модуля DHT11 int pinDHTll=9;
370 Часть IV. Практика разработки проектов для Arduino // контакт подключения аналогового выхода модуля влажности почвы int pinSoilMoisture-AO; // контакт подключения аналогового выхода датчика температуры ТМР36 int pinTMP36=Al; // контакт подключения аналогового выхода фоторезистора int pinPhotoresistor=A2; // создание экземпляра объекта DHT DHT dht(pinDHTll, DHTTYPE); void setup() { // запуск последовательного порта Serial.begin(9600); dht.begin(); void loop() { // получение данных с DHT11 float h = dht.readHumidity(); if (isnan(h)) { Serial.println("Failed to read from DHT"); } else { Serial.print("HumidityDHTll= "); Serial.print(h)/Serial.println(" %"); } // получение значения с аналогового вывода модуля влажности почвы int valO=analogRead(pinSoilMoisture); Serial.print("SoilMoisture= "); Serial.println(valO); // получение значения с аналогового вывода датчика температуры ТМР36 int vall=analogRead(pinTMP36); // перевод в мВ int mV=vall*1000/1024; . // перевод в градусы Цельсия int t=(mV-500)/10; Serial.print("TempTMP36= "); Serial.print(h)/Serial.println(" C"); // получение значения с аналогового вывода фоторезистора int val2=analogRead(pinPhotoresistor); Serial.print("Light= "); Serial.printIn(val2); // пауза 5 секунд Serial.println( )(; delay(5000);
Глава 17. Умная теплица «Домашний цветок» 371_ Электронный архив Полный вариант рассмотренного скетча находится в папке examples\i7\_i7_01 сопрово- ждающего книгу электронного архива (см. приложение 2). Загрузив скетч в плату, открываем монитор последовательного порта и наблюдаем вывод в него показаний наших датчиков (рис. 17.7). HumidityDHTll- 38.00 % SoilMoisHuraidityDHTll- 38.00 % SoilMoisture» 531 ■егарТМРЗб» 23 С Light» 589 HumidityDHTll» 38.00 % SoilMoisture» 530 етрТМРЗб» 23 С Light- 586 HumidityDHTll» 38.00 % SoilMoisture» 530 ТетрТМРЗб» 23 С Light- 607 HumidityDHTll» 38.00 % SoilMoisture» 530 ТетрТМРЗб» 23 С Light» 598 HumidityDHTll» 38.00 % SoilMoisture» 531 ТетрТМРЗб» 23 С Light» 668 HumidityDHTll» 38.00 % SoilMoisture» 530 ТетрТМРЗб» 23 С Light» 621 HumidityDHTll» 38.00 % SoilMoisture» 530 ТетрТМРЗб» 23 С Light» 576 Рис. 17.7. Вывод показаний наших датчиков в монитор последовательного порта Arduino 17.2. Индикация показаний умной теплицы Смотреть на показания датчиков через монитор последовательного порта не всегда приемлемо, поэтому мы создадим более удобную систему индикации показаний. Во-первых, мы реализуем вывод данных с датчиков на дисплей, во-вторых, подключим светодиоды, которые будут сигнализировать о наступлении неблаго- приятных климатических условий, требующих нашего вмешательства (например, понижении увлажненности почвы, слишком высокой температуре, недостаточной освещенности).
372 Часть IV. Практика разработки проектов для Arduino Дополнительно к компонентам, использовавшимся в разд. 17.1, нам понадобятся также: □ светодиод красный — Зшт.; П резистор 220 Ом — 3 шт.; □ ЖК-дисплей Nokia5110. Выбор двухцветного графического ЖК-дисплея Nokia5110 (рис. 17.8) обусловлен его дешевизной и умеренным энергопотреблением, позволяющим подключать этот дисплей к плате Arduino без дополнительного питания (см. также разд. 10.3). Рис. 17.8. ЖК-дисплей Nokia5110 Монтажная схема развития нашего проекта с учетом дополнительных компонентов (светодиодов и ЖК-дисплея) представлена на рис. 17.9. Приступим к написанию скетча и определим условия, при которых необходимо сигнализировать светодиодами о наступлении неблагоприятных климатических параметров: □ температура воздуха — выше tempdetect; □ увлажненность почвы — ниже moisturedetect; □ освещенность — ниже lightdetect. Значения для констант temp_detect, moisture_detect и light_detect необходимо определить самостоятельно. При наступлении неблагоприятного параметра будет
Глава 17. Умная теплица «Домашний цветок» 373 Рис. 17.9. Монтажная схема подключения к плате Arduino датчиков, светодиодов и ЖК-дисплея для проекта умной теплицы «Домашний цветок» загораться соответствующий светодиод, сигнализирующий нам, что необходимо предпринять какие-то действия: □ включить полив почвы; □ включить лампу освещения; О включить вентилятор. Контакты (пины) Arduino для подключения светодиодов определены константами LED_TEMP, LED_MOISTURE И LEDJLIGHT. Текущие значения температуры и влажности воздуха, увлажненности почвы и освещенности будут выводиться на дисплей Nokia5110. Для работы с дисплеем подключаются Arduino-библиотеки AdafruitGFX и Adafruit_PCD8544. Электронный архив Библиотеки Adafruit_GFX и Adafruit_PCD8544 размещены в каталоге libraries сопровож- дающего книгу электронного архива (см. приложение 2). Создадим в Arduino ГОЕ новый скетч, занесем в него код из листинга 17.2 и загру- зим этот скетч в плату Arduino. // подключение библиотек для nokia5110 tinclude <Adafruit_GFX.h> ttiftclude <Adafruit PCD8544.h>
374 Часть IV. Практика разработки проектов для Arduino // подключение библиотеки DHT #include "DHT.h" // тип датчика DHT #define DHTTYPE DHT11 // контакт подключения входа данных модуля DHT11 int pinDHTll=9; // контакт подключения аналогового выхода модуля влажности почвы int pinSoilMoisture=AO; // контакт подключения аналогового выхода датчика температуры ТМРЗб int pinTMP36=Al; // контакт подключения аналогового выхода фоторезистора int pinPhotoresistor=A2; // пины светодиодов индикации tdefine LEDJTEMP 5 #define LED_MOISTURE 6 tdefine LED_LIGHT 7 // значения для условий #define TEMPJDETECT 30 #define MOISTURE_DETECT 500 #define LIGHT_DETECT 250 // создание экземпляра объекта DHT DHT dht(pinDHTll, DHTTYPE); // Nokia 5110 // pin 13 - Serial clock out (SCLK) // pin 12 - Serial data out (DIN) // pin 11 - Data/Command select (D/C) // pin 10 - LCD chip select (CS) // pin 8 - LCD reset (RST) Adafruit_PCd8544 display = Adafruit_PCD8544(13, 12, 11, 10, 8); void setup() { // запуск последовательного порта Serial.begin(9600); // pinMode (LEDJTEMP, OUTPUT) ;digitalWrite (LEDJTEMP, LOW) ; pinMode (LED_MOISTURE,OUTPUT) ;digitalWrite (LED_MOISTORE, LOW) ; pinMode (LED_LIGHT,OUTPUT) ;digitalWrite (LED_LIGHT,LOW) ; // dht.begin(); // инициализация дисплея display.begin(); // установить контраст фона экрана display.setContrast(60); display.clearDisplay(); // очистить экран display.setTextSize(l); // размер шрифта display.setTextColor(BLACK); // цвет
Глава 17. Умная теплица «Домашний цветок» 375 // заставка display.setCursor(15,15); display.print("Home Flower"); display.display(); delay(2000); void loopO { display.clearDisplay(); display.setCursor(5,0); display.print("Home Flower"); // получение данных с DHT11 float h = dht.readHumidity(); display.setCursor(5,10); if (isnan(h)) { Serial.println("Failed to read from DHT"); display.print("airH= error"); } else { Serial.print("HumidityDHTll= "); Serial.print(h);Serial.println(" %"); display.print("airH^");display.print(h);display.print("%"); } // получение значения с аналогового вывода модуля влажности почвы display.setCursor(5,20); int valO=analogRead(pinSoilMoisture); Serial.print("SoilMoisture= "); Serial.println(valO); display.print("soilM=");display.print(valO); // получение значения с аналогового вывода датчика температуры ТМРЗб display.setCursor(5,30); int vall=analogRead(pinTMP36); // перевод в мВ int mV= vall*1000/1024; // перевод в градусы Цельсия int t=(mV-500)/10+75;//t=23; Serial.print("TempTMP36= "); Serial.print(t);Serial.println(" C"); display.print("airT=");display.print(t);display.print(" C"); // получение значения с аналогового вывода фоторезистора display.setCursor(5,40) ; int val2=analogRead(pinPhotoresistor); Serial.print("Light= "); Serial.println(val2); display.print("Light=");display.print(val2); // обновить display.display();
376 Часть IV. Практика разработки проектов для Arduino //// проверка условий // увлажненность почвы if(valO > MOISTURE_DETECT) digitalWrite(LED_MOISTURE,HIGH); else digitalWrite(LED_MOISTURE,LOW); // температура воздуха if(t > TEMP_DETECT) digitalWrite(LED_TEMP,HIGH); else digitalWrite (LEDJTEMP, LOW) ; // освещенность if(val2 < LIGHT_DETECT) digitalWrite(LED_LIGHT,HIGH); else digitalWrite(LED_LIGHT,LOW); // пауза 5 секунд Serial.println(); delay(5000); SoilMoisHumidityDKril= 38.00 SoilMoisture» 531 ГешрТМРЗб- 23 С Light» 589 HumidityDKTll= 38.00 % SoilMoisture» 530 TempTMP36= 23 С Light- 586 HumidityDHTll- 38.00 % SoilMoisture» 530 TempTMP36= 23 С Light» 607 HumidityDKTll= 38.00 % SoilHoisture» 530 ГетрТМР36= 23 С Light» 598 HumidityDHT11» 38.00 % SoilMoisture» 531 ТешрТМРЗб» 23 С Light- 668 HumidityDHTll» 38.00 % SoilMoisture» 530 ТегарТМРЗб» 23 С Light» 621 HumidityDKTll» 38.00 % SoilMoisture» 530 ТетрТМРЗб» 23 С Light» 576 Рис. 17.10. Вывод показаний датчиков в монитор последовательного порта Arduino
Глава 17. Умная теплица «Домашний цветок» 377 Электронный архив Полный вариант рассмотренного скетча находится в папке examples\17\_17_02 сопрово- ждающего книгу электронного архива (см. приложение 2). После загрузки скетча в плату показания наших датчиков выводятся не только в монитор последовательного порта (рис. 17.10), но и на дисплей (рис. 17.11), а также о наступлении неблагоприятных климатических условий сигнализируют светодиоды. Рис. 17.11. Вывод показаний датчиков на дисплей Nokia5110 17.3. Организация полива, обдува и освещения в умной теплице Добавим нашей умной теплице функции управления — организуем полив цветка, его обдув и освещение. Выполняться эти операции будут по нажатию соответст- вующих кнопок. Дополнительно к компонентам, использовавшимся в предыдущих разделах, нам понадобятся также: □ плата расширения Relay shield на 4 реле; П вентилятор 12 В; 0 мембранный насос 12 В; П лампа освещения;
378 Часть IV. Практика разработки проектов для Arduino □ кнопки — 3 шт.; □ резистор 10 кОм — 3 шт. Для полива почвы мы воспользуемся мембранным вакуумным насосом (рис. 17.12)— он способен всасывать воду из емкости и подавать ее в нужное место. Рабочее на- пряжение насоса 12 В, потребляемый рабочий ток 0,5-0,7 А, расход воды 1,5 л/мин. К насосу необходимо прикрепить шланги требуемой длины. Рис. 17.12. Мембранный вакуумный насос При превышении внутри теплицы установленных значений температуры воздуха мы будем производить обдув цветка с помощью вентилятора. Вентилятор можно взять любой, работающий от 12 В,— например, из старого системного блока (рис. 17.13). Рис. 17.13. Вентилятор 12 В Искусственные источники света для эффективного выращивания растений должны излучать спектр, аналогичный тому, который получают растения в естественной среде. Если полной аналогии достичь сложно, то освещение должно удовлетворять
Глава 17. Умная теплица «Домашний цветок» 379_ хотя бы минимальным потребностям. Чтобы обеспечить наиболее комфортные для развития растений условия, подбираются специальные лампы, оказывающие на них различное влияние. Рекомендуется использовать следующие лампы: □ светодиодные фитолампы; □ энергосберегающие лампы дневного спектра; □ люминесцентные. Насос, вентилятор и лампу подключать напрямую к Arduino нельзя! И нам придет- ся обеспечить управление ими через реле. Можно воспользоваться, например, пла- той расширения Relay shield (рис. 17.14), которая содержит 4 реле с необходимой обвязкой. Рис. 17.14. Плата расширения Relay shield Монтажная схема развития нашего проекта с учетом дополнительных компонентов представлена на рис. 17.15. Допишем код скетча с учетом сделанных в схеме дополнений. Для этого создадим переменные типа Boolean (true— включено, false— выключено) для состояния трех реле: □ насос — status_pump; □ лампа — status_lamp; □ вентилятор — statusf un. В цикле loop () отслеживаем нажатие кнопок с проверкой на дребезг (процедура debounce ()) и при нажатии кнопки изменяем статус соответствующей переменной и отправляем команду для изменения статуса соответствующего реле на противо- положное:
380 Часть IV. Практика разработки проектов для Arduino !Ш1Г '.: Luc--. ; i I* .1И\\„ ;й; ♦ 12В ш | '1уШ1 ш % U Рис. 17.15. Монтажная схема развития проекта умной теплицы «Домашний цветок»: мониторинг параметров и ручное управление □ включение/выключение насоса (полив почвы); □ включение/выключение освещения; □ включение/выключение вентилятора. Создадим в Arduino IDE новый скетч, занесем в него код из листинга 17.3 и загру- зим этот скетч в плату Arduino. // подключение библиотек для nokia5110 #include <Adafruitj3FX.h> #include <Adafruit PCD8544.h>
Глава 17. Умная теплица «Домашний цветок» 381 II подключение библиотеки DHT Hnclude "DHT.h" // тип датчика DHT ttdefine DHTTYPE DHT11 // контакт подключения входа данных модуля DHT11 int pinDHTll=9; // контакт подключения аналогового выхода модуля влажности почвы int pinSoilMoisture=AO; // контакт подключения аналогового выхода датчика температуры ТМРЗб int pinTMP36=Al; // контакт подключения аналогового выхода фоторезистора int pinPhotoresistor=A2; // пины светодиодов индикации tdefine LED_TEMP 5 idefine LED_MOISTURE 6 idefine LED_LIGHT 7 // значения для условий idefine TEMP_DETECT 30 idefine MOISTURE_DETECT 500 idefine LIGHT_DETECT 250 // кнопки idefine COUNT_BUTTONS 3 int pinButtons[]={A4,A5,A6}; int lastButtons[]={0,0,0,0}; int currentButtons [ ] = {0,0, 0,0} ; // реле int pinRelays[] = {2,3,4}; // статусы полива, освещения, вентилятора boolean statusRelays[]={false,false,false}; // создание экземпляра объекта DHT DHT dht(pinDHTll, DHTTYPE); // Nokia 5110 // pin 13 - Serial clock out (SCLK) // pin 12 - Serial data out (DIN) // pin 11 - Data/Command select (D/C) // pin 10 - LCD chip select (CS) // pin 8 - LCD reset (RST) Adafruit_PCD8544 display = Adafruit_PCD8544(13, 12, 11, 10, 8); unsigned long millisupdate=0;
382 Часть IV. Практика разработки проектов для Arduino void setup() { // запуск последовательного порта Serial.begin(9600); // pinMode (LEDJTEMP, OUTPUT) /digitalWrite (LED_TEMP, LOW) ; pinMode (LEDJtolSTURE, OUTPUT) /digitalWrite (LED_MOISTORE,LOW) ; pinMode (LEDJLJGHT,OUTPUT);digitalWrite (LED_LIGHT, LOW) ; // dht.beginO; // инициализация дисплея display.begin(); // установить контраст фона экрана display.setContrast(60); display.clearDisplay(); // очистить экран display.setTextSize(l); // размер шрифта display.setTextColor(BLACK); // цвет // заставка display.setCursor(15,15) ; display.print("Home Flower"); display.display(); delay(2000); void loop() { // каждые 5 сек - получение показаний датчиков //и вывод на дисплей if (millis() -millisupdate>5000) { millisupdate==millis (); display.clearDisplay(); display.setCursor(5,0); display.print("Home Flower"); // получение данных с DHT11 float h = dht.readHumidityO/ display.setCursor(5,10); if (isnan(h)) { Serial.println("Failed to read from DHT")'; display.print("airH= error"); } else { Serial.print("HumidityDHTll= "); Serial.print(h);Serial.println(" %") display.print("airH=");display.print(h);display.print("%");
Глава 17. Умная теплица «Домашний цветок» 383 // получение значения с аналогового вывода модуля влажности почвы display.setCursor(5,20); int valO=analogRead(pinSoilMoisture); Serial.print("SoilMoisture= "); Serial.println(valO); display.print("soilM=")/display.print(valO); // получение значения с аналогового вывода датчика температуры ТМР36 display.setCursor(5f30); int vall=analogRead(pinTMP36); // перевод в мВ int mV= vall*1000/1024; // перевод в градусы Цельсия int t«(mV-500)/10+75;//t«23; Serial.print("TempTMP36= "); Serial.print(t);Serial.println(" C"); display.print("airT=");display.print(t);display.print(" C"); // получение значения с аналогового вывода фоторезистора display.setCursor(5f40); int val2=analogRead(pinPhotoresistor); Serial.print("Light= "); Serial.println(val2); display.print("Light=");display.print(val2); // обновить display.display(); // вывод состояния полива, лампы, вентилятора Serial.print("pump - "); Serial.println(statusRelays[2]); Serial.print("fun - "); Serial.println(statusRelays[1]); Serial.print("lamp - "); Serial.println(statusRelays[0]); //// проверка условий // увлажненность почвы if(valO > MOISTURE_DETECT) digitalWrite(LED_MOISTURE,HIGH); else digitalWrite(LED_MOISTORE,LOW); // температура воздуха if(t > TEMP_DETECT) digitalWrite (LED_TEMP,HIGH) ; else digitalWrite(LEDJTEMP,LOW); // освещенность if(val2 < LIGHT_DETECT) digitalWrite(LED_LIGHT,HIGH); else digitalWrite (LED_LIGHTf LOW) ; // пауза 5 секунд Serial.println(); } // проверка нажатия кнопок выбора программ for(int i=0;i<COUNT BUTTONS;i
384 Часть IV. Практика разработки проектов для Arduino currentButtons[i] = debounce(lastButtons[i],pinButtons[i]); if (lastButtons[i] == 0 && currentButtons[i] ==1) // если нажатие... doButtons(i); lastButtons[i] = currentButtons[i]; // при нажатии кнопок void doButtons(int but) { // изменить статус statusRelays[but]=!statusRelays[but]; // изменить состояние реле digitalWrite(pinRelays[but],statusRelays[but]); /* Функция сглаживания дребезга * Принимает в качестве аргумента предыдущее состояние кнопки * и выдает фактическое. */ int debounce(int last,int pinl) { int current = digitalRead(pinl); // Считать состояние кнопки if (last != current) // если изменилось... delay(5); current = digitalRead(pinl); return current; // ждем 5 мс // считываем состояние кнопки // возвращаем состояние кнопки Электронный архив Полный вариант рассмотренного скетча находится в папке examples\1A_17__03 сопрово- ждающего книгу электронного архива (см. приложение 2). После загрузки скетча в плату мы можем управлять включением/выключением на- соса, лампы и вентилятора с помощью кнопок. В монитор последовательного порта выводятся показания датчиков и установленные нами состояния реле: полив, вен- тиляция, освещение (рис. 17.16). На дисплей— показания датчиков. Общий вид проекта с учетом добавленных компонентов приведен на рис. 17.17.
TempTMP36= 25 С Light- 362 pump - 0 fun - 0 lamp - 0 HumidltyDHTll= 35.00 % :SoilMoisture= 474 ТетрТМРЗб- 25 С Light- 362 pump - 0 fun - 0 lamp - 0 |HumidityDHTll= 35.00 % ;SoilMoisture= 459 TempTMP36= 25 С Light- 362 pump - 0 fun - 1 lamp - 1 HumidityDKTll= 35.00 % SoilHoisture- 447 рГетрТМР36= 25 С tight- 361 pump - 0 fun - 0 lamp - 1 ;HumidityDKTll= 35.00 % SoilMoisture= 446 TempTMP36= 25 С Light- 366 pump - 0 fun - 1 lamp - 1 Рис. 17.16. Вывод показаний датчиков и состояний реле в монитор последовательного порта Arduino ш I ■6 О) I 1 Рис. 17.17. Пррект «Домашний цветок»: подключение реле, насоса и лампы
386 Часть IV. Практика разработки проектов для Arduino 17.4. Переносим функции мониторинга и управления теплицей на смартфон с ОС Android Перенесем функции мониторинга и управления теплицей на смартфон (или план- шет) с операционной системой Android. Во-первых, это очень удобно, во-вторых, мы сможем исключить из системы ряд деталей, а именно дисплей и кнопки. Эти функции на себя возьмет смартфон/планшет. Связь Arduino со смартфоном будет осуществляться по Bluetooth, и нам понадобится Bluetooth-модуль НС-05, позво- ляющий наладить двунаправленную радиосвязь по протоколу Bluetooth (этот модуль мы уже рассматривали в разд. 12.5). Подключение Bluetooth-модуля к плате Arduino осуществляется по последователь- ному порту. Аппаратный последовательный порт Arduino у нас занят — через него осуществляется отладка программы, поэтому для связи с Bluetooth-модулем мы воспользуемся программным последовательным портом. В качестве контактов про- граммного последовательного интерфейса мы задействуем цифровые выводы 17 и 18, которые освободятся после удаления из системы кнопок. Монтажная схема развития нашего проекта с учетом сделанных изменений пред- ставлена на рис. 17.18. Заметьте, что питание Bluetooth-модуля НС-05 — 3,3 В! Теперь нам надо удалить из предыдущего скетча фрагменты кода, связанные с вы- водом данных на дисплей и обработкой нажатий клавиш, и добавить отправку дан- ных в Bluetooth-модуль НС-05 по SoftwareSerial, а также получение и обработку данных, поступающих по SoftwareSerial, для команд включения/выключения насо- са, вентилятора и лампы. Формат команд отправки данных мониторинга в SoftwareSerial представлен в табл. 17.1, а формат команд управления из SoftwareSerial — в табл. 17.2. Таблица 17.1. Команды отправки данных мониторинга в SoftwareSerial Команда aH=<data>\r\n SM=<data>\r\n aT=s<data>\r\n Ph=<data>\r\n PM=<data>\r\n FN=<data>\r\n LM=<data>\r\n Описание Данные влажности с датчика DHT11 Данные увлажненности почвы soiiMoisture Данные температуры с датчика ТМР36 Данные освещенности — с фоторезистора Состояние реле включения/выключения (1/0) насоса Состояние реле включения/выключения (1/0) вентилятора Состояние реле включения/выключения (1/0) лампы
Глава 17. Умная теплица «Домашний цветок» 387 Таблица 17.2. Команды управления из SoftwaneSerial Команда РМ=1# РМ=0# FN=1# FN=0# LM=1# LM=0# Описание Включение насоса Выключение насоса Включение вентилятора Выключение вентилятора Включение лампы Выключение лампы + 12* -220В Рис. 17.18. Монтажная схема развития проекта умной теплицы «Домашний цветок»: мониторинг параметров, обеспечение комфортных условий и связь по Bluetooth
388 Часть IV. Практика разработки проектов для Arduino Создадим в Arduino ШЕ новый скетч, занесем в него код из листинга 17.4 и загру- зим этот скетч в плату Arduino. // подключение библиотеки SoftwareSerial #include <SoftwareSerial.h> // подключение библиотеки DHT #include "DHT.h" // тип датчика DHT #define DHTTYPE DHT11 // контакты подключения bluetooth-модуля НС-05 int pinBlRx=17; int pinBlTx=18; // контакт подключения входа данных модуля DHT11 int pinDHTll=9; // контакт подключения аналогового выхода модуля влажности почвы int pinSoilMoisture=AO; // контакт подключения аналогового выхода датчика температуры ТМРЗб int pinTMP36=Al; // контакт подключения аналогового выхода фоторезистора int pinPhotoresistor=A2; // пины светодиодов индикации #define LED_TEMP 5 #define LED_MOISTURE 6 #define LED_LIGHT 7 // значения для условий #define TEMP_DETECT 30 #define MOISTURE_DETECT 500 #define LIGHT_DETECT 250 // реле int pinRelays[]={2,3,4}; // статусы полива, освещения, вентилятора boolean statusRelays[]={false,false,false}; // создание экземпляра объекта SoftwareSerial SoftwareSerial HC05Serial(pinBlRx,pinBlTx); // создание экземпляра объекта DHT DHT dht(pinDHTll, DHTTYPE); unsigned long millisupdate=O; // для получения данных из SoftwareSerial String inputStringO = "";
Глава 17. Умная теплица «Домашний цветок» 389 // признак конца полученной строки boolean stringCompleteO = false; void setup() { // запуск последовательного порта Serial.begin(9600); // pinMode (LEDJTEMP, OUTPUT) ;digitalWrite (LED_TEMP, LOW) ; pinMode(LED_MOISTURE,OUTPUT);digitalWrite(LED_MOISTURE,LOW); pinMode (LED_LIGHT,OUTPUT) ;digitalWrite (LED_LIGHT,LOW-) ; // инициализация dht dht.begin(); // запуск SoftwareSerial HC05Serial.begin(9600); // резервирование 50 bytes для the inputString: inputStringO.reserve(50); void loopO { // ожидание конца строки для анализа поступившего запроса: serialEventO(); if (stringCompleteO) { Serial.println(inputStringO); parse_stringO(inputStringO); // очистить : inputStringO = ""; stringCompleteO = false; } // каждые 5 сек - получение показаний датчиков //и вывод на дисплей if (millis()-millisupdate>5000) { millisupdate=4Tiillis () ; // получение данных с DHT11 float h = dht.readHumidity(); if (isnan(h)) { Serial.println("Failed to read from DHT"); HC05Serial.println("Hl=l01"); delay(10); } else { Serial.print("HumidityDHTll= "); Serial.print(h);Serial.println(" %");
390 Часть IV. Практика разработки проектов для Arduino HC05Serial.print("аН=");HC05Serial.print(h);HC05Serial.println(); delay(10); } // получение значения с аналогового вывода модуля влажности почвы int valO-analogRead(pinSoilMoisture); Serial.print("SoilMoisture= "); Serial.println(valO); HC05Serial.print("SM=");HC05Serial.print(h);HC05Serial.println(); delay(10 ); // получение значения с аналогового вывода датчика температуры ТМР36 int vall=analogRead(pinTMP36); // перевод в мВ int mV= vall*1000/1024; // перевод в градусы Цельсия int t-(mV-500)/10+75;//t-23; Serial.print("TempTMP36= "); Serial.print(t);Serial.println(" C"); HC05Serial.print("aT=");HC05Serial.print(t);HC05Serial.println(); delay(10); // получение значения с аналогового вывода фоторезистора int val2=analogRead(pinPhotoresistor); Serial.print("Light= "); Serial.println(val2); HC05Serial.print("Ph=");HC05Serial.print(val2);HC05Serial.println(); delay(10); // обновить // вывод состояние полива, лампы, вентилятора Serial.print("pump - "); Serial.println(statusRelays[2]); Serial.print("fun - "); Serial.println(statusRelays[1]); Serial.print("lamp - "); Serial.println(statusRelays[0]); HC05Serial.print("P№=");HC05Serial.print(statusRelays[2]); HC05Serial.print(" ") ; delay(10); HC05Serial.print("FN^");HC05Serial.print(statusRelays[1]); HC05Serial.print(" ") ; delay(lO); HC05Serial.print("LM=");HC05Serial.print(statusRelays[0]); HC05Serial.println(" ") ; delay(10 ); //// проверка условий. // увлажненность почвы if(valO > MOISTURE_DETECT) digitalWrite(LED__MOISTURE,HIGH) ; else digitalWrite(LEDJtolSTURE,LOW); // температура воздуха if(t > TEMP_DETECT) digitalWrite (LED__TEMP,HIGH) ; else digitalWrite (LED_TEMP, LOW);
Глава 17. Умная теплица «Домашний цветок» 391 // освещенность if(val2 < LIGHT_DETECT) digitalWrite(LED_LIGHT,HIGH); else digitalWrite(LED_LIGHTf LOW); // пауза 5 секунд Serial.println(); // SerialEvent для НС05 void serialEventO() { while (HC05Serial.available()) { // получить очередной байт: char inChar = (char)HC05Serial.read(); // добавить в строку inputStringO += inChar; // /n - конец передачи if (inChar — f#f) { stringCompleteO = true; // парсинг строки из android void parse__stringO (String inputString) { // длина строки int lengthl=inputString.length(); if(lengthl!=5) {Serial.println("ERROR1"); return;} if(inputString.charAt(2)!='=') {Serial.printIn("ERROR2"); return;} if(inputString.charAt(4)!='#') {Serial.printIn("ERROR3"); return;} String paraml=inputString.substring(0,2); int param2=inputString.substring(3,4).tolnt(); Serial.print("paraml=");Serial.println(paraml); Serial. print (ffparam2="); Serial. println (param2); if (paraml="PM") doCommand (2, min (param2,1)); else if(paraml=="FN") doCommand (1,min (param2,1)); else if(paraml=="LM") doCommand (0, min (param2,1)); // исполнение команды от смартфона void doCommand(int relay, int status1)
392 Часть IV. Практика разработки проектов для Arduino aH»34 SM-449 aT-24 Ph=222 РМ=1 FH=O LM=O aH=30 SM-443 aT=24 Ph=239 PM=1 FH-0 LM=O aH»33 SM-446 aT=24 Ph-370 PM=1 FH=O LM=O aH=32 SM-446 aT-24 Ph=287 PM-1 FH-0 LM=O aH-32 5M-44Q eT-24 Ph«268 PM=1 FH=O LU=O aH-34 SM-449 aT-24 Ph-404 PM»I FH-G LM-0 aH-31 SM-447 aT-24 Ph-392 PM-1 FM-0 LH-0 aH=33 SM-446 aT-24 Ph=310 PM=1 FH=O LH=O aH=30 SU=448 aT-24 Ph-366 PM=1 FH=O LM=O eH-34 SM-447 aT-24 Ph-261 PM=1 FH=Q LM=O аИ-33 SU-448 aT-24 Ph-309 PM-1 FM=O LM=O aH-33 5M-440 aT-24 Ph-414 PM=1 FH=O LM-Q aH=31 SM-440 aT-24 Ph-353 PM-1 FH=O LM=O aH-32 SM-446 aT-24 Ph=394 PM-1 FH=O LM-0 Рис. 17.19. Получение в приложение Bluetooth Terminal, установленное на планшете, данных мониторинга с платы Arduino aH=35 SU=440 aT=24 Ph=334 PM=1 FN=O LM=O aH=35 5M=440 aT=24 Ph=333 PM=1 FN=O LM=O aH=35 SM=440 aT=24 Ph=334 PM=1 FH=O LM=O aH-35 SMM4Q aT=24 Ph=334 PM-1 FM=Q LM=O FH=1# aH-35 SM=440 aT=24 Ph=334 PM=1 FN»1 LM=O aH-35 SM=440 aT=24 Ph=333 PM=1 FN=1 LM=O aH=35 SU«440 aT»24 Ph=334 PM»Q FN=1 LM=O aH«35 SM=440 aT-24 Ph=333 PM=O FH=1 LM=O aH=35 SH»440 aT=24 Ph=334 PM=O FH=1 LM=1 LM»O# aN»3S SM-440 aT=24 Ph>334 PM=O FH=1 LM=O Рис. 17.20. Отправка из приложения Bluetooth Terminal, установленного на планшете, команд управления на плату Arduino
Глава 17. Умная теплица «Домашний цветок» 393 // изменить статус statusRelays[relay]=statusl; // изменить состояние реле digitalWrite(pinRelays[relay],statusRelays[relay]) Получать на смартфон/планшет данные и отправлять с него команды мы будем (пока!) из приложения Bluetooth Terminal, которое скачаем из Google Play. Устано- вим его на смартфон/планшет, подключимся из Bluetooth Terminal к нашему Bluetooth-модулю и увидим на смартфоне/планшете отправленные с платы Arduino данные (рис. 17.19). Из этого же приложения мы отправляем на плату Arduino команды управления: включения/выключения насоса, вентилятора и лампы (рис. 17.20). 17.5. Создаем собственное мобильное приложение для управления умной теплицей Использовать приложение Bluetooth Terminal не вполне удобно. Нам нужно полно- ценное приложение. Глубоко вникать в вопросы программирования для операци- онной системы Android не входит в наши планы, поэтому нам нужна простая и по- нятная система создания кода для Android— наподобие системы Sctratch для Arduino. К счастью, подобный визуальный редактор есть— это Арр Invertor 2, онлайн-редактор визуального программирования для Android, доступ к которому можно получить на странице: http://ai2.appinventor.mit.edu. После авторизации (можно использовать профиль Google) или регистрации попада- ем в свой профиль программы, где можем создать новый проект (рис. 17.21). Рис. 17.21. Создание проекта в своем профиле Арр Invertor 2
394 Часть IV. Практика разработки проектов для Arduino Сначала в панели Designer создаем интерфейс нашего приложения (рис. 17.22), перетаскивая на экран необходимые компоненты. Кроме визуальных компонентов необходимо добавить три невизуальных: П Bluetooth client — из раздела Connectivity; □ Clock— из раздела Sensors (для получения данных из Bluetooth с периодич- ностью, установленной в Clock); □ Notifer — из раздела Userlnterface. Рис. 17.22. Создание интерфейса приложения в панели Designer Затем переходим в раздел Block, где создаем код: □ для инициализации Bluetooth-соединения и создания Bluetooth-клиента; □ для отправки сообщений при изменении состояний чекбоксов для насоса, венти- лятора и лампы; □ для получения по таймеру сообщений, поступающих по Bluetooth из Arduino. После чего создаем Арр-приложение (рис. 17.23) и загружаем его на смарт- фон/планшет. Теперь нам надо внести небольшие изменения в наш скетч (см. листинг 17.4), заме- нив разделитель с пробела на символ * при отправке данных с Arduino на Android. Электронный архив Код этого скетча находится в папке examples\17\_17_05 сопровождающего книгу элек- тронного архива (см. приложение 2).
Глава 17. Умная теплица «Домашний цветок» 395 ;~-!.v * vi--- *■'-<-'- T^J'-'' '■'¥&-' 'йД £'■;:• > Рис. 17.23. Генерация Арр-приложения Загружаем этот скетч в плату Arduino и запускаем на смартфоне/планшете наше приложение (рис. 17.24). Затем соединяемся из него по Bluetooth с платой Arduino (рис. 17.25) и получаем возможность наблюдать за состоянием датчиков нашей теплицы и отправлять команды управления поливом, обдувом и освещением (рис. 17.26). Рис. 17.24. Приложение запущено на планшете Электронный архив Разработанное приложение и файл проекта находятся в папке examples\17\Android со- провождающего книгу электронного архива (см. приложение 2).
396 Часть IV. Практика разработки проектов для Arduino Рис. 17.25. Подключение приложения по Bluetooth к плате Arduino Рис. 17.26. Приложение в работе: получение данных с датчиков и отправка команд управления
Глава 17. Умная теплица «Домашний цветок» 397_ 17.6. Превращаем нашу умную теплицу в объект Интернета вещей Теперь мы превратим нашу умную теплицу в объект Интернета вещей (IoT) — это позволит мониторить данные теплицы из любой точки мира, где у нас будет доступ к Интернету. Для этого необходимо организовать отправку этих данных на пуб- личный интернет-сервер— например, на сайт «Народный мониторинг» (http:// narodmon.ru). Сайт «Народный мониторинг» — геоинформационный сервис, позволяющий ото- бражать на карте мира и контролировать (на ПК, смартфонах и других гаджетах) показания датчиков г их участников (температуры, влажности, атмосферного давления, скорости i фавления ветра, радиации, энергопотребления и многих других), а также трансляций частных и городских веб-камер для публичного или частного (приватного) просмотра (см. также главу 13). Дополнительно к компонентам, использовавшимся в предыдущих разделах этой главы, нам понадобится только один модуль — Ethernet shield W5100, который мы уже рассматривали в разд. 13.1. В скетч из предыдущего раздела мы внесем лишь незначительные изменения. При включении Arduino добавим запуск Ethernet и получение IP-адреса Ethernet- шилдом W5100. Процедура ethernetbegin () получает IP-адрес либо с помощью DHCP, либо назначает плате статический адрес (в зависимости от значения кон- станты DHCP) (листинг 17.5). ' Листинг 17.5 byte arduino_mac[] = { 0x35, 0x75, 0x02, OxFF, OxFF, 0x01 }; String MAC="35-75-02-FF-FF-01"; EthernetClient client; #define DHCP 1 // 0-dhcp, 1 - manual // если адрес статический // (установить #define DHCP 1) int mip[4]={192,168,0,121}; int mmask[4]={255,255,255,0}; int mgateway[4]={192,168,0,28}; int mdns[4]={192,168,l,l}; // запустить ethernet void ethernet_begin() { if(DHCP==0) { if(Ethernet.begin(arduino_raac)==0) Serial.println("dhcp - error"); else Serial.println("dhcp - ok");
398 Часть IV. Практика разработки проектов для Arduino else { " IPAddress arduino_ip (mip [ 0],mip [ 1 ],mip [2],mip [3]); IPAddress dns_ip (mdns [0] ,mdns [1] ,mdns [2],mdns [3]); IPAddres s gateway_ip(mgateway[0],mgateway[1],mgateway[2],mgateway[3]); IPAddress subnetjmask(ramask[O],mmask[l],mmask[23,mmask[3]); E the met. begin (arduinojnac, arduino_ip, dns_ip, gateway_ipf subnet jcnask); Для отправки данных на сервер «Народного мониторинга» необходимо отправить данные методом GET на адрес: http://narodmon.ru/get?ID=MAC&macl=valuel&...SmacN При каждом опросе датчиков формируем строку, но отправляем данные один раз в 5 минут. Итак, создадим в Arduino IDE новый скетч, занесем в него код из листинга 17.6 и загрузим этот скетч в плату Arduino. // подключение библиотеки SoftwareSerial tinclude <SoftwareSerial.h> // подключение библиотеки DHT #include "DHT.h" // тип датчика DHT #define DHTTYPE DHT11 // контакты подключения bluetooth-модуля HC-05 int pinBlRx=17; int pinBlTx=18; // контакт подключения входа данных модуля DHT11 int pinDHTll=9; // контакт подключения аналогового выхода модуля влажности почвы int pinSoilMoisture=AO; // контакт подключения аналогового выхода датчика температуры ТМРЗб int pinTMP36=Al; // контакт подключения аналогового выхода фоторезистора int pinPhotoresistor=A2; // пины светодиодов индикации #define LEDJTEMP 5 #define LED_MOISTURE 6 #define LED_LIGHT 7 // значения для условий #define TEMP DETECT 30
Глава 17. Умная теплица «Домашний цветок» 399_ #define MOISTURE_DETECT 500 #define LIGHTJDETECT 250 // реле int pinRelays[]={2,3,4}; // статусы полива/ освещения, вентилятора boolean statusRelays[]-{false,false,false}; // создание экземпляра объекта SoftwareSerial SoftwareSerial HC05Serial(pinBlRx,pinBlTx); // создание экземпляра объекта DHT DHT dht(pinDHTll, DHTTYPE); // для получения данных из SoftwareSerial String inputStringO = ""; // признак конца полученной строки boolean stringCompleteO = false; // Ethernet #include <SPI.h> tinclude <Ethernet.h> byte arduinojnac[] = { 0x35, 0x75, 0x02, OxFF, OxFF, 0x01 }; String MAC="35-75-02-FF-FF-01"; EthernetClient client; #define DHCP 1 // 0-dhcp, 1 - manual // если адрес статический // (установить #define DHCP 1) int mip[4]={192,168,0,121}; int mmask[4]-{255,255,255,0}; int mgateway[4]={192,168,0,28}; int mdns[4]={192,168,l,l}; // IoT-сервер char server[] = "narodmon.ru"; String strNarodmon=""; unsigned long millisupdatel^O; unsigned long millisupdate2=0; void setup() { // запуск последовательного порта Serial.begin(9600); // pinMode (LED^TEMP, OUTPUT);digitalWrite (LED_TEMP,LOW) ; pinMode (LED_MOISTURE,OUTPUT) ;digitalWrite (LED_MOISTORE, LOW) ; pinMode (LED^LIGHT,OUTPUT) ;digitalWrite (LED_LIGHT, LOW);
400 Часть IV. Практика разработки проектов для Arduino // инициализация dht dht.begin(); // запуск SoftwareSerial HC05Seriar.begin(9600); // резервирование 50 bytes для the inputString: inputStringO.reserve(50); // установка сетевого соединения ethernet_begin(); print_ip () ; void loop() { // ожидание конца строки для анализа поступившего запроса: serialEventO(); if (stringCompleteO) { Serial.println(inputStringO); parse_stringO(inputStringO); // очистить : inputStringO = ""; stringCompleteO = false; } // каждые 5 сек - получение показаний датчиков //и вывод в software serial на экран телефона if (millis() -millisupdatel>5000) { millisupdatel=millis(); strNarodmon=""; // получение данных с DHT11 float h = dht.readHumidity(); if (isnan(h)) { Serial.println("Failed to read from DHT"); HC05Serial.println("Hl=101"); delay(10); } else { Serial.print("HumidityDHTll= "); Serial.print(h);Serial.println(" %") ; HC05Serial.print("aH=");HC05Serial.print(h);HC05Serial.print("*"); strNarodmon=strNarodmon+"&Hl=f4String(h); delay(10); } // получение значения с аналогового вывода модуля влажности почвы int valO=analogRead(pinSoilMoisture); Serial.print("SoilMoisture= "); Serial.println(valO);
Глава 17. Умная теплица «Домашний цветок» 401 HC05Serial.print("SM=");HC05Serial.print(valO);HC05Serial.print("*"); strNarodmon=strNarodmon+"&H2="+String(map(valO,0,1024,0,100)); delay(10); // получение значения с аналогового вывода датчика температуры ТМРЗб int vall=analogRead(pinTMP36); // перевод в мВ int mV= vall*1000/1024; // перевод в градусы Цельсия int t=(mV-500)/10+75; Serial.print("ТетрТМРЗ6= "); Serial.print(t)/Serial.println(" C"); HC05Serial.print("aT=");HC05Serial.print(t);HC05Serial.print("*"); strNarodmon=strNarodmon+"&Tl=f4String(t); delay(10); // получение значения с аналогового вывода фоторезистора int val2=analogRead(pinPhotoresistor); Serial.print("Light= "); Serial.println(val2); HC05Serial.print("Ph=");HC05Serial.print(val2);HC05Serial.print("*") ; strNarodmon=strNarodmon+"&Ll="+String(val2); delay(10); // обновить // вывод состояния полива, лампы, вентилятора Serial.print("pump - "); Serial.println(statusRelays[2]); Serial.print("fun - "); Serial.println(statusRelays[1]); Serial.print("lamp - "); Serial.println(statusRelays[0]); HC05Serial.print("PM=");HC05Serial.print(statusRelays[2]); HC05Serial.print("*"); delay(10); HC05Serial.print("FN=");HC05Serial.print(statusRelays[1]); HC05Serial.print("*"); delay(lO); HC05Serial.print("LM=");HC05Serial.print(statusRelays[0]); delay(10); //// проверка условий // увлажненность почвы if(valO > MOISTURE_DETECT) digitalWrite(LED_MOISTURE,HIGH); else digitalWrite (LED_MOISTORE, LOW) ; // температура воздуха if(t > TEMP_DETECT) digitalWrite(LED_TEMP,HIGH); else digitalWrite(LEDJTEMP,LOW); // освещенность if(val2 < LIGHT_DETECT) digitalWrite(LED_LIGHT,HIGH);
402 Часть IV. Практика разработки проектов для Arduino else digitalWrite (LED_LIGHT, LOW) ; Serial.println(); } if(millis()-millisupdate2>5*60000) { millisupdate2=millis(); if (client.connect(server, 80)) { client.print("GET /get?ID="); client.print(MAC); client.print(strNarodmon); client.println(" HTTP/1.1"); client.print("Host: "); client.printIn(server); client.printIn("Connection: close"); client.println(); client.println(); client.stop(); client.flush(); } else Serial.println("error send narodmon"); Serial.println(strNarodmon); // SerialEvent для НС05 void serialEventO() { while (HC05Serial.available()) { // получить очередной байт: char inChar = (char)HC05Serial.read(); // добавить в строку inputStringO += inChar; // /n - конец передачи if (inChar — '#•) { stringCompleteO = true; // парсинг строки из android void parse_stringO(String inputString) { // длина строки int lengthl=inputString.length();
Глава 17. Умная теплица «Домашний цветок» 403 if (lengthl!*5) {Serial.printIn("ERR0R1"); return;} if(inputString.charAt(2)!='=') {Serial.printIn("ERROR2"); return;} if(inputString.charAt(4)! ='#f) {Serial.printIn("ERROR3"); return;} String paraml^inputString.substring(0,2); int param2=inputString.substring(3,4).tolnt(); Serial.print("paraml^");Serial.println(paraml); Serial.print("рагат2=");Serial.println(param2); if (paraml="PMff) doCoramand (2,min (param2,1)); else if (paraml==="FN") doCommand (1, min (param2,1)); else if(paraml=="LM") doCommand(0,min(param2,1)); // исполнение команды от смартфона void doCommand(int relay, int statusl) { // изменить статус statusRelays[relay]=statusl; // изменить состояние реле digitalWrite(pinRelays[relay],statusRelays[relay]); // запустить ethernet void ethernet_begin() { if(DHCP==0) { if(Ethernet.begin(arduino_mac)==0) Serial.printIn("dhcp - error"); else Serial.printIn("dhcp - ok"); } else { • IPAddress arduino_ip (mip [0 ],mip [ 1 ],mip [2],mip [ 3]); IPAddress dns_ip (mdns [0],mdns [ 1 ],mdns [2 ],mdns [3]) ; I PAddress gateway_ip (mgateway [ 0 ], mgateway [ 1 ], mgateway [ 2 ], mgateway [ 3 ]); IPAddress subnet__mask(mmask[O] rmmask[l] fmmask[2] /mmask[3]) ; E the met. begin (arduino_macf arduino__ipf dns___ipf gateway_ip, subnetjnask);
404 Часть IV. Практика разработки проектов для Arduino // вывести ip-адрес void print_ip() { Serial.print("My IP address: "); for (byte i-hisByte = 0; thisByte < 4; thisByte++) { // print the value of each byte of the IP address: Serial.print(Ethernet.locallPO [thisByte], DEC); Serial.print("."); } Serial.println(); Serial.print("My SUBNET: ") ; for (byte thisByte = 0; thisByte < 4; thisByte++) { // print the value of each byte of the IP address: Serial.print(Ethernet.subnetMask()[thisByte], DEC); Serial.print("."); } Serial.println(); Serial.print("My GATEWAYIP: ") ; for (byte thisByte = 0; thisByte < 4; thisByte++) { // print the value of each byte of the IP address: Serial.print(Ethernet.gatewaylPO [thisByte], DEC); Serial.print("."); } Serial.println(); Serial.print("My DNS: ") ; for (byte thisByte = 0; thisByte < 4; thisByte++) { // print the value of each byte of the IP address: Serial.print(Ethernet.dnsServerIP()[thisByte], DEC); Serial.print("."); } Serial.println(); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\i7\_i7_07 сопрово- ждающего книгу электронного архива (см. приложение 2). После загрузки скетча в плату и отправки данных необходимо зарегистрироваться в сервисе «Народный мониторинг» и настроить визуализацию наших данных, а за- тем — добавить наше устройство на карту «Народного мониторинга». Для этого вводим МАС-адрес устройства: String MAC="35-75-02-FF-FF-01"; и нажимаем на кнопку ОК (рис. 17.27). Далее выбираем пункт меню Датчики | Настройка датчиков и триггеров, где из- меняем названия датчиков и адрес местонахождения устройства (рис. 17.28). Более
Глава 17. Умная теплица «Домашний цветок» 405 Рис. 17.27. Добавление устройства на карту сервиса «Народный мониторинг» Рис. 17.28. Установка названий для датчиков и адреса устройства
406 Часть IV. Практика разработки проектов для Arduino точно положение устройства на карте можно подстроить с помощью пункта меню Подвинуть по карте. Теперь вы можете увидеть на карте всплывающее окно с последними показаниями датчиков своей умной теплицы (рис. 17.29) и следить за ними из любого места, где есть доступ к сети Интернет. Рис. 17.29. Всплывающее окно с данными нашей теплицы на карте сайта «Народный мониторинг
ГЛАВА 18 Светодиодное табло футбольных матчей Светодиодные ленты RGB представляют собой группы RGB-светодиодов, собран- ных последовательно на гибкой ленте с нанесенными на нее проводниками. Свето- диодные ленты бывают двух типов: аналоговые и цифровые. В аналоговых лентах все светодиоды включены в параллель. Следовательно, вы можете задавать цвет всей светодиодной ленты, но не можете установить определенный цвет для кон- кретного светодиода. Эти ленты просты в подключении и не дороги. Цифровые светодиодные ленты устроены немного сложнее — каждый ее светодиод дополня- ется микросхемой, что делает возможным управлять любым из них раздельно. Такие ленты дороже обычных, но имеют большие возможности по применению, — например, в цветомузыке, световых шоу, динамической фоновой подсветке. 18.1. RGB-светодиодная лента WS2812 Как уже было сказано, каждый светодиод цифровой RGB-ленты дополняется мик- росхемой (трехканальным ШИМ-контроллером)— например: LPD6803, WS2801, WS2811, WS2812. У меня в наличии имелась RGB-светодиодная лента WS2812 длиной 5 метров (рис. 18.1). Каждый метр ленты содержит 30 SMD-светодиодов WS2812 типоразмера 5050. Рис. 18.1. RGB-светодиодная лента WS2812
408 Часть IV. Практика разработки проектов для Arduino Схема подключения ленты к плате Arduino представлена на рис. 18.2. На ленте все- го три шины: «земля», питание и управление. Управление работает так: в течение первых 50 мс происходит инициализация ленты путем заземления управляющей шины. После этого платой Arduino отправляется в ленту пачка из пакетов по 24 бита (8 битов на каждый цветовой канал), содержащих информацию о яркости свето- диодов, — каждый пакет предназначается для одного светодиода. Данные в пачке ничем не разделяются, т. е. каждый следующий пакет идет непосредственно за пре- дыдущим. Получив всю пачку (длина пачки равна 24 бита х количество светодио- дов в ленте), контроллер первого диода берет первые 24 бита, использует информа- цию по назначению, а остальную пачку ретранслирует дальше. Таким образом, до последнего светодиода доходит пачка из одного 24-битного пакета. На различных лентах расположение контактов отличается Рис. 18.2. Схема подключения RGB-ленты WS2812 к плате Arduino Каждый RGB-светодиод потребляет до 60 мА при максимальной яркости белого цвета (красный + зеленый + синий). В реальных условиях ток будет меньше. Но в любом случае необходимо использовать внешний блок питания. В месте подклю- чения ленты к источнику тока следует включить конденсатор (1000 цР, 6,3 В или выше) — это защитит ее секции от начального всплеска тока. Кроме того, между выводом Arduino и вводом данных на первом светодиоде желательно добавить ре- зистор от 300 до 500 Ом — для предотвращения всплесков напряжения, которые могут повредить первую секцию ленты. Для управления такой лентой из Arduino мы воспользуемся библиотекой Adafruit_ NeoPixel.
Глава 18. Светодиодное табло футбольных матчей 409 18.2. Arduino-библиотека AdafruitJSIeoPixel Библиотека AdafruitNeoPixel предназначена для управления адресуемыми RGB- светодиодными лентами на контроллерах WS2811 и WS2812. Библиотеку можно скачать со страницы: https://github.com/adafruit/Adafruit_NeoPixel. Электронный архив Библиотека AdafruitJMeoPixel размещена в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2). Для использования в скетче библиотеку необходимо подключить: #include <Adafruit_NeoPixel.h> Затем нужно инициализировать объект AdafruitjsieoPixel. Функция инициализации имеет три аргумента: первый — количество светодиодов в ленте, второй — контакт Arduino для подключения (по умолчанию 6), третий — тип используемой ленты (описание можно посмотреть в примерах библиотеки): Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800); В функции setup о следует вызвать функцию объекта strip.begin о для подготов- ки к выводу данных и функцию strip, show () для отправки данных в ленту: void setup () { strip.begin(); strip.show() ; } Существуют два способа установки цвета конкретного светодиода в ленте: □ первый: strip.setPixelColor(n, red, green, blue); где: • n — номер светодиода (отсчет ведется от 0); • red, green, blue — уровни яркости (0-255) красной, зеленой и синей состав- ляющей цвета светодиода. Например: strip.setPixelColor(11, 255, 0, 255); // Установка красного цвета // для 12-го светодиода Функция setPixelColor () не имеет непосредственного влияния на светодиоды. Чтобы отправить цветовые данные на ленту, необходимо вызвать функцию strip. show () — это обновляет всю полосу сразу. П альтернативный синтаксис имеет только два аргумента: strip.setPixelColor(n, color);
410 Часть IV. Практика разработки проектов для Arduino где: color— 32-битный тип, объединяющий красный, зеленый и синий цвета в одно число. Конвертировать отдельные значения красного, зеленого и синего в единый 32-битный тип для дальнейшего использования можно следующим образом: uint32_t magenta =* strip.Color(255, 0f 255); Затем вы можете использовать это значение для установки цвета функцией setPixeicoior (). Можно также запросить цвет ранее установленного пиксела с использованием функции getPixeicoior (): uint32_t color = strip.getPixelColor(11); Функция возвращает 32-битное объединенное значение цвета. Количество заяв- ленных светодиодов можно запросить с помощью функции numPixeis (): uint32_t num = strip.numPixeis (); Общую яркость всех светодиодов можно отрегулировать с помощью функции setBrightnessO. Она принимает один аргумент— число в диапазоне от о (вы- ключено) до 255 (максимальная яркость). Например, чтобы установить полосу с lU яркости: strip.setBrightness (64); Так же, как и для функции setPixeio, здесь необходимо вызвать функцию strip, show (). Для хранения данных каждого светодиода необходимы три байта оперативной памяти. Когда лента состоит из сотен светодиодов, a Arduino Uno имеет только 2 Кбайт оперативной памяти (часть из которых используют другие библиотеки), и это может стать реальной проблемой! Поэтому для управления действительно большим количеством светодиодов лучше использовать Arduino Mega или Due. Закрепим полученные знания при создании проекта. 18.3. Создание табло результатов ЧМ-2018 по футболу на RGB-ленте WS2812 Рассмотрим проект создания табло, отражающего результат текущего матча чем- пионата мира по футболу 2018 года с использованием RGB-светодиодной ленты WS2812. На табло поочередно отображаются флаги участников матча и текущий результат. Изменение участников матча и счета производится с планшета или смартфона на ОС Android, флаги всех участников чемпионата хранятся на SD-карте. Сначала режем ленту на отрезки по 15 светодиодов — получается 10 отрезков, от- резки клеим на пластину ДСП, соблюдая расстояние между отрезками 3 см (подби- ралось по расстоянию между светодиодами на ленте). В результате получаем пря- моугольник 15x10 см (рис. 18.3). Соединяем отрезки проводами. Электрическая схема устройства представлена на рис. 18.4. Для связи Arduino с планшетом/
Глава 18. Светодиодное табло футбольных матчей 411 Рис. 18.3. Общий вид создаваемого табло NCOS ♦зз в Рис. 18.4. Электрическая схема табло
412 Часть IV. Практика разработки проектов для Arduino смартфоном на ОС Android используется Bluetooth-модуль НС-05, работу которого мы подробно рассматривали в главах 12 и 17. Для проекта необходимы изображения флагов всех стран-участниц ЧМ-2018 раз- мером 15x10. Изучение форматов GIF, PNG, JPG и BMP привело к выводу, что самым удобным форматом для перевода содержимого файла картинки в данные для пикселов светодиодной ленты будет 24-битный формат BMP (BMP-24). После слу- жебных заголовков в нем идет массив растра, где на каждый пиксел изображения отводятся 3 байта, которые определяют 3 компонента цвета: Blue, Green, Red, — они идут именно в таком порядке. Но это еще не все! Во-первых, строки идут от нижней к верхней, а во-вторых, если размер строки не кратен 4, то он дополняется байтами Oxff. Электронный архив Изображения флагов стран-участниц ЧМ-2018 размером 15x10 пикселов в формате ВМР-24 вы можете найти в папке examples\18\flags_18_1 сопровождающего книгу электронного архива (см. приложение 2). Приступим теперь к написанию скетча, обеспечивающего работу этого проекта. Как уже отмечалось, в скетче используется библиотека Adafruit_NeoPixel, понадо- бится нам также и библиотека SD — для работы с файловой системой SD-карты. Один раз в 200 мс вызывается программа вывода информации на ленту (данные хранятся в двух массивах: byte fiagi [150] [3] и byte f iag2 [150] [3]) и массивы для хранения изображения цифр счета 0-9 (byte figure [Ю] [180]). Предусмотрены 9 режимов вывода, которые идут последовательно один за другим: 1. Анимация «въезда» первого флага снизу. 2. Отображение первого флага несколько секунд. 3. Анимация «ухода» первого флага вниз. 4. Анимация «въезда» второго флага сверху. 5. Отображение второго флага несколько секунд. 6. Анимация «ухода» второго флага вверх. 7. Анимация «въезда» счета: одна цифра — слева, другая — справа. 8. Отображение счета несколько секунд. 9. Удаление счета (темный экран несколько секунд). 10. Переход на шаг 1. Данные текущего режима и состояния анимации хранятся в структуре anim: struct ANIM {' int posl; // текущий режим int offsetx; // текущее смещение х при анимации int offsety; // текущее смещение у при анимации int timeview; // продолжительность режима int figl; // счет - 1
Глава 18. Светодиодное табло футбольных матчей 413 int fig2; // }; ANIM ANIMl={10,10,6,0,32,l,3,0}; При получении платой Arduiho no Bluetooth с планшета/смартфона данных о командах-участницах матча и текущем счете между ними, по последовательному порту Serial 1 происходит подгрузка в массивы цифр для счета и— из файлов на SD-карте — данных для показа флагов (листинг 18.1). byte serdata[6]={0,0,0,0,0f0}; // буфер данных Bluetooth hc-05 int offserdata=0; void loopO { if (Seriall.availableO) { byte c=Seriall.read(); Serial.write(c); if (c==46) offserdata=0; if (c=47) { String filel=="file_"+String (serdata [2]-48)+".bmp"; download_flag(filel,1); filel="fileJ4String (serdata [3]-48)+".bmp"; download_flag(filel , 2); ANIM1.figl=serdata[4]-48; ANIM1.fig2=serdata[5]-4 8; } else {offserdata=(offserdata+1)%6; serdata[offserdata]=c;} } if(millis()-millisflash>200) { flash(); millisflash=millis(); void download_flag(String filestr,int num) { Serial.println(); Serial.println(filestr); filestr.toCharArray(filename,20); myFile = SD.open(filename, FILE_READ);
414 Часть IV. Практика разработки проектов для Arduino if (myFile) { myFile.seek(54); // смещение данных в файле bmp for(int i=l,k=0,s=9;i<160;i++) { if (i%16>0 && num=l) { flagl[s*15+k] [2]«myFile.read();//Serial.print (flagl[k] [O],HEX); flagl[s*15+k][1]-myFile.read();//Serial.print(flagl[k][1],HEX); flagl[s*15+k][O]=myFile.read();//Serial.print(flagl[k][2],HEX); //Serial.print(" "); else if (i%16>0 && num=2) { flag2[s*15+k]'[2]-myFile.read();//Serial.print(flag2[kj [O],HEX); flag2[s*15+k][1]-myFile.read();//Serial.print(flag2[k][1],HEX); flag2[s*15+k][0]-myFile.read();//Serial.print(flag2[k][2],HEX); //Serial.print(" "); k=(k+l)%15; } else { // пропускаем байты дополнения myFile. read (); myFile. read () /myFile. read (); s—; myFile.close(); Электронный архив Весь скетч здесь не приводится, поскольку код содержимого массивов и код заполне- ния массивов при анимации занимают много места. Полный вариант рассмотренного скетча находится в папке examples\18\_18__01 сопровождающего книгу электронного архива (см. приложение 2). В процессе эксплуатации табло возникла неприятная проблема — сгоревшие све- тодиоды. За месяц сгорело 4 штуки, а каждый сгоревший светодиод не пропускал пакеты через себя. Приходилось кидать обводную перемычку на следующий свето- диод, но при этом смещалось изображение. В скетче (см. его полный код) создан массив с позициями сгоревших светодиодов int badieds[] и добавлена функция correctstrip(). Для управления данными для табло: выбора команды-участницы 1, команды- участницы 2 и текущего счета написана программа для смартфона/планшета с опе- рационной системой Android (рис. 18.5). Программа максимально проста и преду-
Глава 18. Светодиодное табло футбольных матчей 415 сматривает соединение по Bluetooth с конкретным модулем НС-05, выбор команд- участниц матча, ввод текущего счета и отправку данных на модуль НС-05. Электронный архив Папка с файлами Android-программы для среды Eclipse находится в файле example$\ 18\Android\18.zip сопровождающего книгу электронного архива (см. приложение 2). Рис. 18.5. Интерфейс программы на Android для настройки табло
ГЛАВА 19 Голосовое управление исполнительными устройствами Голосовое управление — способ взаимодействия с устройством при помощи голоса. В отличие от распознавания речи, голосовое управление предназначено для ввода управляющих команд— например: «включить чайник», «открыть шторы», «вы- ключить звук». И хотя с помощью системы голосового управления можно вводить и контент (числа и текст), такой ввод будет крайне некомфортным, поскольку при- дется делать четкие паузы между отдельными словами. Распознавание отдельных команд несколько проще, чем распознавание слитного текста, и не требует значительных вычислительных мощностей. Благодаря этому, сегодня существует богатый выбор программного обеспечения и оборудования (специализированных цифровых сигнальных процессоров), имеющих небольшую стоимость и обеспечивающих высокое качество распознавания команд. Позднее (см. разд. 19.3) мы создадим проект для Arduino с использованием специ- ального модуля голосового распознавания, обеспечивающего голосовое управление светом и электроприборами: плата Arduino будет получать распознанные данные с модуля голосового распознавания, анализировать их и отправлять по радиоканалу команды включения/выключения исполнительным устройствам, к которым под- ключены световые и электроприборы. А сначала научимся дистанционно управлять электроприборами с помощью радио- сигнала. 19.1. Управление электроприборами с помощью радиорозеток UNIEL В качестве исполнительных устройств мы воспользуемся радиорозетками UNDEL (рис. 19.1). Радиорозетки UNIEL непосредственно устанавливаются в любую элек- тророзетку и к ним уже подключается электроприбор, включением и выключением которого можно управлять с дистанционного пульта. Радиус действия на открытой местности — до 25 м, частота приемопередачи команд — 433,9 МГц. С помощью таких радиорозеток можно управлять внутренним и внешним освещением, систе- мами полива, электрокотлами, нагревателями, вентиляторами — т. е. практически
418 Часть IV. Практика разработки проектов для Arduino всеми приборами, которые можно включить в розетку. В продаже имеются модули радиорозеток для нагрузок 300, 1000 и 3600 Вт. Весь их ассортимент можно по- смотреть на странице официального сайта производителя: http://www.uniel.rii/rii/ catalog/1235. Настройка пульта и розеток UNIEL осуществляется установкой в них групп пере- ключателей: в пульте управления устанавливается код группы, а в каждой розетке необходимо установить и код группы, и код розетки. Так, на рис. 19.2 в пульте Рис. 19.1. Радиорозетки UNIEL Рис. 19.2. Настройка пульта и розеток UNIEL
Глава 19. Голосовое управление исполнительными устройствами 419 установлен код группы 11000, на обеих розетках код группы 11000, а коды розеток разные: 10000 и 00100. Но нам необходимо управлять радиорозетками не с пульта, а с платы Arduino. Для этого надо заменить пульт управления розетками UNIEL на радиомодули, рабо- тающие на частоте 433 МГц. Мы воспользуемся для этого радиомодулями FS1000A/MX-RM-5V (можно применить и другие радиомодули). 19.2. Радиомодули FS1000A/MX-RM-5V Комплект радиомодуля: передатчик FS1000A и приёмник MX-RM-5V (рис. 19.3) — мы уже знакомились с ними в главе 12— можно приобрести в Китае дешевле 100 рублей. Для управления розетками служит передатчик, а приемник необходим для определения параметров передачи радиосигнала пультом. Рис. 19.3. Радиомодули: стремя контактами — передатчик FS1000A; с четырьмя — приемник MX-RM-5V Для Arduino разработаны библиотеки, позволяющие работать с разными управляе- мыми исполнительными устройствами на частотах 433/315 МГц. Я использовал библиотеку RCSwitch (Arduino library to operate low cost 315 MHz /433 MHz remote control devices), скачать которую можно со страницы: http://code.google.eom/p/ rc-switch/. Скачиваем архив и распаковываем его в папку libraries. Электронный архив Библиотека RCSwitch размещена в каталоге libraries сопровождающего книгу элек- тронного архива (см. приложение 2). Для начала по схеме соединений, приведенной в табл. 19.1, подключим к плате Arduino приемник MX-RM-5V (модуль на рис. 19.3 с четырьмя контактами) и за- пустим пример ReceiveDemoAdvanced из библиотеки RCSwitch. Нажимаем на пульт и смотрим, что выдает скетч в последовательный порт (рис. 19.4).
420 Часть IV. Практика разработки проектов для Arduino Таблица 19.1. Соединение контактов Arduino и приемника MX-RM-5V Плата Arduino +5 В GND 2 Приемник MX-RM-5V VCC GND DATA (любой) Decimal: 345425 (24Bit) Binary: 000001010100010101010001 Tn-State: OOFFFOFFFFOF PulseLength1 309 microsecondsProtocol:: 1 Raw data: 9612,240,988,248,992,240,988,244,992,240,1004,848,376,240,996,860,384,232,1000,856,384,232,1000,856,380,236,1000,856,388,232,992,860,388 Decimal: 348500 (24Bit) Binary: 000001010101000101010100 Tn-State: 0OFFFFOFFFFO PulseLength: 309 microseconds Protocol: 1 Raw data• 9604,244,988,244,984,248,988,244,992,244,992,860,376,240,996,856,380,236,996,860,376,240,1000,856,380,240,996,856,384,236,992,864,380,2- Decimal- 349268 (24Bit) Binary. 00000101010101B001010100 Tn-State- OOFFFFFOFFFO PulseLength. 309 microseconds Protocol: 1 Raw data: 9596,252,984,248,988,244,984.248,988.244,996,856,376,244,996,860,372,244,992,864,372.244,992,864,376,244,992,864,376,240,996,860,372.24^ Decimal: 349265 (24Bit) Binary 000001010101010001010001 Tn-State OOFFFFFOFFOF PulseLength: 309 microseconds Protocol: 1 Raw data: 9600,248,988,244,988,244,1000,232,996,236,988,868,380,244,992,856,380,240,992,860,380,240,10G0,852,380,240,992,860,376,244,988,864,380, Decimal. 349460 (24Bit) Binary 000001010101010100010100 Tn-State: OOFFFFFFOFFO PulseLength: 309 microseconds Protocol: 1 Raw data. 9608.240,1004,228,1000,232.992,244,988,244,992,86Q, 376,244,992.860,380,240,996,856,380,240.992,860,384,236.992.860,384,236,992,860,384. Рис. 19.4. Данные и параметры с пульта UNIEL Запомним параметры 24Bit, PulseLength: 309 microseconds, Protocol: 1 — они нам понадобятся при написании скетча. Коды запоминать не нужно. Для отправки дан- ных библиотека использует код группы и код устройства! Теперь попробуем управлять розетками UNIEL из Arduino через передатчик FS1000A. Для этого подключим по схеме соединений, приведенной в табл. 19.2, к плате Arduino передатчик FS1000A (модуль на рис. 19.3 с тремя контактами) и пишем скетч, использующий библиотеку RCSwitch (листинг 19.1). Таблица 19.2. Соединение контактов Arduino и передатчика FS1000A Плата Arduino +5 В GND 10 Передатчик FS1000A VCC GND DATA
Глава 19. Голосовое управление исполнительными устройствами 421 Радиорозетки UNIEL (3 штуки) вставляем в обычные электророзетки, выставляем код группы 11000, а код розеток для каждой разный: 10000, 01000 и 00100, загру- жаем скетч из листинга 19.2 в плату Arduino и наблюдаем включение розеток по кругу, а затем выключение. include "RCSwitch.h" RCSwitch mySwitch = RCSwitch(); void setup() { Serial.begin(9600); mySwitch.enableTransmit(10); mySwitch.setPulseLength(309); mySwitch.setProtocol(1); // mySwitch. setRepeatTransmit (15); } void loopO { // включение // группа 11000 код розетки А mySwitch.switchOn("11000", "10000") ; Serial.print("A - on"); delay(5000); // группа 11000 код розетки В mySwitch.switchOn("11000"f "01000"); Serial.print("В - on"); delay(5000); // группа 11000 код розетки В mySwitch.switchOn("11000", "00100"); - - Serial7print1-"e--—onwt Г" delay(5000); // выключение mySwitch.switchOff("11000", "10000"); Serial.print("A - off"); delay(5000); mySwitch.switchOff("11000", "01000"); Serial.print("B - off"); delay(5000); mySwitch.switchOff("11000", "00100"); Serial.print("C - off"); delay(5000); Пользуясь пультом, мы можем управлять 3-мя (а также 4-мя или 5-ю — в зависи- мости от пульта) розетками, а при управлении из Arduino количество управляемых розеток становится равным 25. Если же менять и код группы, то — 25х25 розеток!
422 Часть IV. Практика разработки проектов для Arduino 19.3. Модуль распознавания голоса Voice Recognition Module V2 Возможности модуля распознавания голоса Voice Recognition Module V2 (рис. 19.5) соответствуют его цене (менее 1000 рублей при покупке в Китае) — блок распозна- ет лишь 15 заранее записанных голосовых команд (3 блока по 5 команд). Причем одновременно распознавать 15 команд он не может— только 5 команд загружен- ного блока, а для распознавания следующих пяти команд ему необходимо подгру- зить следующий блок. Поэтому мы будем использовать цепочки слов (2-3) с пау- зами, необходимыми для загрузки следующего блока, например: Кафе - лампа - выключить Фонтан - включить Рис. 19.5. Модуль Voice Recognition Module V2 И еще один момент. Модуль реагирует только на записанный голос конкретного человека и не реагирует на голос другого человека, так что для двух человек при- дется команды дублировать. Для обучения модуля необходимо посылать ему по последовательному порту команды и произносить фразы. Итак, скачиваем на компьютер (под ОС Windows) рекомендуемую производителем программу работы с СОМ-портом— AccessPort (страница загрузки: http://www. sudt.com/en/ap/download.htm) и подключаем модуль к СОМ-порту компьютера через плату Arduino. Модуль Voice Recognition Module V2 и плата Arduino соединяются по схеме, приведенной в табл. 19.3. Создадим в Arduino IDE новый скетч, занесем в него код из листинга 19.2 и загру- зим этот скетч в плату Arduino. Обратите внимание, что при программировании в скетче использована библиотека SoftwareSerial.
Глава 19. Голосовое управление исполнительными устройствами 423 Таблица 19.3. Соединение контактов Arduino и модуля Voice Recognition Module V2 Плата Arduino +5 В GND 3 2 Модуль Voice Recognition Module V2 vcc GND Tx Rx #include "SoftwareSerial.h" SoftwareSerial mySerial(2, 3); // RX, TX void setup() { Serial.begin(9600); mySerial.begin(9600); } void loop() { if (mySerial.available()) Serial.write(mySerial.read()); if (Serial.availableO) mySerial.write(Serial.read()); Плата Arduino к компьютеру уже подключена, выставляем в программе AccessPort настройки согласно рис. 19.6. Теперь все команды и ответы «ходят» между компьютером и модулем. Приступаем к его обучению, предварительно изучив техническую документацию на него. Электронный архив Напомню, что техническая документация производителей (Data Sheet) практически на все компоненты и устройства, задействованные в проектах этой книги, в том числе и на модуль Voice Recognition Module V2 (см. файл arduino98__Manual_elechouse1.pdf), нахо- дится в папке datasheets сопровождающего книгу электронного архива (см. приложение 2). Посылаем в модуль первую команду: аавв — запрос информации о модуле, полу- ченный ответ: V2.0 By ELECHOUSE www.elechouse.com Далее — обучение первого блока: команда ааи (рис. 19.7). После того, как в окне терминала появится приглашение START, произносим в микрофон первую фразу. В ответ появляется надпись Again — ждем, молчим,
424 Часть IV. Практика разработки проектов для Arduino Рис. 19.6. Настройки в программе AccessPort ■TV2.0 By ELECHOUSE www.elechouse.com START No voice START Again START Finish one START Again START Finish one START Again START Finish one START Again START Finish one START Again START Finish one Croup} finished' Рис. 19.7. Обучение модуля в программе AccessPort 00000000:йй 11
Глава 19. Голосовое управление исполнительными устройствами 425 снова появляется приглашение START. Второй раз произносим в микрофон пер- вую фразу для подтверждения. В случае удачной записи появляется ответ Finish one, говорящий о том, что первая команда успешно записана. Ответ Different гово- рит о том, что вторая попытка звучала не так, как первая, и модуль ее не распознал. Надпись Too loud говорит о том, что вы слишком долго говорите в микрофон (дольше 1300 мс). В том же порядке записываем четыре оставшиеся фразы. Ответ Groupl finished ! подтверждает, что первый блок успешно записан. Для проверки распознавания командой АА21 вызываем блок 1 и произносим в мик- рофон записанные для него управляющие фразы. При распознавании в терминал выводится подтверждение. Затем обучаем блоки 2 и 3, посылая команды: АА12 — для первого блока и АА13 — для второго. Для вызова из памяти блоков 2 и 3 — отдаем в терминал команды АА22 и АА23 соответственно. И проверяем правильность распознавания (рис. 19.8). Если мы хотим получать от голосового модуля ответы в кратком виде (не Result: 15, а просто 15), необходимо отправить модулю команду АА37. No voice START Again START Finish one START Again START Too loud START Again START Finish one START Again START Finish one СгоирЗ finished < Croup! Imported I Result:! 1 Result: 13 Result: 12 Result 14 Result 15 Result! 5 Result 14 2T Рис. 19.8. Проверка правильности распознавания в программе AccessPort
426 Часть IV. Практика разработки проектов для Arduino 19.4. Система голосового управления Для системы голосового управления посиделками на кухне модуль Voice Recog- nition Module V2 обучаем следующим образом. Заносим в блоки команды для включения/выключения фонтана и управления освещением (огни RGB, лампа, ноч- ник) для двух человек (табл. 19.4). Таблица 19.4. Команды обучения модуля Voice Recognition Module V2 № 1 2 3 4 5 Блок1 «Кафе» (1-й голос) «Фонтан» (1-й голос) «Тест» (1-й голос) «Кафе» (2-й голос) «Фонтан» (2-й голос) Блок 2 «Огни» (1-й голос) «Лента» (1-й голос) «Ночник» (1-й голос) «Включить» (2-й голос) «Выключить» (2-й голос) БлокЗ «Включить» (1-й голос) «Выключить» (1-й голос) «Огни» (2-й голос) «Лента» (2-й голос) «Ночник» (2-й голос) В соответствии с проведенным обучением построим в программе правильные цепочки, а остальные комбинации отбросим. Вот примеры правильных цепочек: □ «Кафе» (1-й голос) —> «Ночник» (1-й голос) —» «Выключить» (1-й голос) □ «Фонтан» (2-й голос) —► «Включить» (2-й голос) □ «Кафе» (2-й голос) —► «Огни» (2-й голос) -+ «Включить» (2-й голос) Для наглядности добавим свето-цветовую индикацию, подключив 3 светодиода к контактам (пинам) 7, 8 и 9 Arduino. Назначение светодиодов представлено в табл. 19.5. Таблица 19.5. Комбинации светодиодов и режим программы № 1 2 3 4 Красный (Pin 7) + - - + Желтый (Pin 8) - + — + Зеленый (pin 9) - - + + Режим программы Загружен блок 1 Первое слово из блока 1 — начало правильной цепочки. Загружен блок 2 Слово из блока 2 — продолжение правильной цепочки. Загружен блок 2 Слово из блока 3 (2-е слово для цепочки из 2-х слов) — правиль- ная цепочка Электрическая схема устройства голосового управления посиделками на кухне представлена на рис. 19.9. Теперь приступим к написанию скетча. После программы инициализации мы от- правляем в модуль распознавания голоса команду загрузки блока 1 и ожидаем по
Глава 19. Голосовое управление исполнительными устройствами 427 Voice Module ♦5 В Рис. 19.9. Электрическая схема устройства голосового управления посиделками на кухне последовательному порту команды от модуля. При распознавании модулем слов из блоков 1, 2 и 3 в Arduino приходит индекс распознанного слова com. Скорректиро- ванный код com (с 11-15, 21-25, 31-35 до 1-5) в случае правильной комбинации накапливается в переменной kod по формуле: kod=kod+iO(bank-i)*(com&7), где bank — номер загруженного блока. В случае неправильной цепочки устанавлива- ются значения переменных bank=i, kod=o и подгружается блок 1. В случае правиль- ной цепочки подгружается следующий блок для возможного продолжения цепочки. Значение блока берется из var_ok[i] [1] для var_ok[i] [O]=kod. Если var_ok[i] [i]=4, идет отправка команды включения/выключения по радиоканалу, затем обнуление kod и загрузка первого блока для распознавания. Значения var_ok[i] [2] — индекс номера кода розетки для отправки, var_ok[i] [2] — действие (включение, выключе- ние, тест). Код этого скетча представлен в листинге 19.3. #include "RCSwitch.h" #include "SoftwareSerial.h" SoftwareSerial mySerial(2, 3); // RX, TX RCSwitch mySwitch = RCSwitch(); byte com = 0; char* kod_group="11000"; // код группы
428 Часть IV. Практика разработки проектов для Arduino unsigned long FRAZA_TIME=2000; unsigned long millisl=0; int fraza_poz=l; int varl; int offset[4]={0,1,10,100}; unsigned int kod=0; // накапливающийся код цепочки int id_do=0; // фразы //1 банк // 11,12,13,14,15 // кафе(1),фонтан(1),тест(1),кафе(2),фонтан(2) // 21,22,23,24,25 // огни(1),лента(1),ночник(1),включить(2),выключить(2) // 31,32,33,34,35 // включить(1),выключить(1),огни(2),лента(2),ночник(2), // все возможные комбинации // 1,2,3 - выбор банка // 4 - ok end unsigned int var_ok[29j [4]={ //1 голос {1,2,0,0},{2,2,0,0}, {11,3,0,0},{21,3,0,0},{31,3,0,0},{42,4,1,1},{52,4,2,2},' {111, 4, 3,1}, {121, 4,4,1}, {131,4,5,1},{211,4,6,2},{221,4,7,2},{231,4,8,2}, // тест {3,2,0,0},{43,3,0,0},{243,4,9,3}, /7 2 голос {4,3,0,0},{5,3,0,0}, {304,2,0,0},{404,2,0,0},{504,2,0,0},{105,4,10,1},{205,4,11,2}, {344,4,12,1},{354,4,13,1},{444,4,14,1},{454,4,15,2},{544,4,16,2},{554,4,17,2} }; // коды отправки по RF char kodModule[][б] = { "00000", "00010","00010", // фонтан вкл-выкл 1 голос "10000","01000","00100","10000","01000","00100", // // огни,лампа,ночник вкл-выкл 1 голос "00000", // тест "00010","00010", // фонтан вкл-выкл 2 голос "10000","01000","00100","10000","01000","00100" // // огни,лампа,ночник вкл-выкл 2 голос }; void setup() { Serial.begin(9600); mySerial.begin(9600); pinMode(13, OUTPUT);
Глава 19. Голосовое управление исполнительными устройствами 429 pinMode(7, OUTPUT); pinMode(8, OUTPUT); pinMode(9, OUTPUT); digitalWrite(7,HIGH); // включить светодиоды digitalWrite(8,HIGH); digitalWrite(9,HIGH); // радиомодуль настройки mySwitch.enableTransmit(10); mySwitch.setPulseLength(309); mySwitch.setProtocol(1) ; delay(2000); // настройки Voice Prcognition Module mySerial.write(OxA; // избавляемся от текста mySerial.write(0x37); // и оставляем байты delay(1000); mySerial.write(OxAA); // вызываем из памяти mySerial.write(0x21);// команды 1-й группы delay(2000); digitalWrite(7,LOW); // выключить светодиоды digitalWrite(8,LOW); digitalWrite(9,LOW); Serial.println("okey"); } void loop() { varl=fraza_poz; if(get_word(fraza_poz)!=varl) { switch(fraza_poz) { case 0: Serial.print("false=");Serial.println(kod); kod=0;fraza_poz=l; break; case 4: Serial.print("ok=");Serial.println(kod); ledOn(7);ledOn(8);ledOn(9); command_UNIEL(id_do); // отправить команду kod=0;fraza_poz=l;id_do=0; delay(1000);ledsOff(); break; case 1: Serial.print("wait=");Serial.println(kod); kod=0; breaks- default : Serial.print("wait=");Serial.println(kod); break; } new_bank(fraza_poz);
430 Часть IV. Практика разработки проектов для Arduino if (millis()-millisl>FRAZA_TIME && fraza_poz>l) {kocHO; f razaj?oz=l; new_bank (f raza_poz);} digitalWrite(13, LOW); } // получить id слова из банка int get_word(int bank) { while(mySerial.available()) { com = mySerial.read();// читаем входящие байты и присваиваем // значение переменной com digitalWrite(13f HIGH); Serial.print("word_id=")/Serial.printIn(com,HEX); if(com>OxlO*bank && com<0xl6*bank) { kod=kod+offset[bank]*(int(com & 7)); fraza_j?oz=0; for(int i=0;i<29;i++) {if (kod=var_ok[i] [0]) {fraza_jpoz=var_ok[i] [1]; if(fraza_poz==4) iddo=i+l; Serial.print("fraza_poz=");Serial.printIn(frazajpoz); return frazajpoz; } // выбор нового банка Voice Recognition Module V2 int new_bank(int bank) { Serial.print("NEW=");Serial.println(fraza_poz); mySerial.write(OxAA); // вызываем из памяти byte bankl=0x20+bank; mySerial.write(0x20+bank);// команды 1-й группы delay(1000) ; mySerial.flush(); ledsOff(); ledOn(6+bank); // отправка команды розетке UNIEL no rf void command_UNIEL(int id) Serial.print("id»");Serial.print(id-1); Serial.print(" id[3]=");Serial.printIn(var_ok[id-1][3]);
Глава 19. Голосовое управление исполнительными устройствами 431 Serial.print(" kod=");Serial.println(var_ok[id-l][2]); if(var_ok[id-l][3]==1) // включение mySwitch.switchOn(kod_group, kodModule[var_ok[id-1][2]]); else if(var_ok[id-l][3]==2) // выключение mySwitch.switchOff(kod_group, kodModule[var_ok[id-1][2]]); else if(var_ok[id-l][3]==3) // тест for(int i=3;i< {mySwitch.switchOn(kod_group, kodModule[i]); delay(1000);} for(int i=3;i<6;i++) {mySwitch.switchOff(kod_group, kodModule[i]); delay(lOOO);} } else ; } // включить светодиод void ledOn(int pin) { digitalWrite(pin,HIGH); } // выключить светодиоды void ledsOff() { digitalWrite(7,LOW); digitalWrite(8, LOW); digitalWrite(9,LOW); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\19\_19J)1 сопрово- ждающего книгу электронного архива (см. приложение 2).
ГЛАВА 20 Проекты для вендинга: всюду деньги, деньги, деньги Продажа товаров и услуг с помощью автоматизированных систем (торговых авто- матов) называется вендингом. Вендинг получил широкое распространение в мире как удобный и не очень требовательный способ вести торговлю или оказывать услуги. На рынке представлен большой выбор торговых автоматов. Но если вас не устраивает цена, или вы желаете добавить функционала действующему автомату, или решили собрать что-то новенькое — Arduino в качестве микроконтроллера для управления отдельными блоками устройства вам в этом поможет. Рассмотрим работу Arduino с купюроприемником, монетоприемником и хоппером. Купюроприемник (он же банкнотник, купюрник, валидатор, биллакцептор) — устройство, предназначенное для приема наличных платежей банкнотами. Купю- роприемники осуществляют прием купюр, распознавание номинала и (при наличии механизма укладки и кассеты) хранение принятых купюр. Монетоприемник — устройство, предназначенное для приема платежей монетами или жетонами. Хоп- пер — устройство для выдачи сдачи монетами. Кугаороприемники, монетоприемники и хопперы устанавливают в платежные тер- миналы, развлекательные, лотерейные и игровые автоматы, а также в вендинговые (торговые) автоматы. 20.1. Купюроприемник ЮТ серий А7 и V7 Купюроприемники ICT серий А7 и V7 (MDB-версия) по-настоящему проверены временем — на российском рынке эта модель появилась еще в 2003 году и с успе- хом эксплуатируется до сих пор как в индустрии игорного бизнеса, так и в вендин- ге и системах моментальных платежей (рис. 20.1). Модель поставляется с механиз- мом укладки на 200, 400 и 800 купюр и предоставляет возможность быстрой заме- ны микропрограммы с помощью ПК. Основные возможности: □ осуществляет прием купюры, поданной в любом направлении; □ уровень распознавания купюр — более 96%; □ время операции — 3 секунды (включая время укладки);
434 Часть IV. Практика разработки проектов для Arduino Рис. 20.1. Купюроприемник ICTV7 □ обеспечивает работу по протоколу PULSE, RS 232, MDB; □ имеет контейнер укладчика на 300 купюр; □ напряжение питания — 12 В; □ позволяет обновлять микропрограмму в Flash Rom; О имеется модель с горизонтальным механизмом укладки. Немаловажный факт — в Интернете можно приобрести работающие б/у экземпля- ры по цене до 1000 рублей (лично я приобрел два у разных продавцов). Для настройки купюроприемник имеет три блока переключателей: первый и второй блоки переключателей находятся с боковой стороны купюроприемника (рис. 20.2), третий блок спрятан: разворачиваем купюроприемник к себе лицевой стороной и кассетой вверх, над лицевой панелью находим пластиковую крышку — чтобы она открылась, достаточно потянуть ее немного вверх, — вы увидите плату и, поискав, найдете и колодку с четырьмя переключателями (рис. 20.3). Каждый переключатель (в просторечии «дип») имеет два положения: on — вниз и off— вверх. Рассмотрим назначение переключателей: □ первый блок: • sw 1-5 — настройка приема по номиналам купюр; • sw 6 — качество приема. Если установить HighAcceptance, то купюроприем- ник принимает даже помятые купюры;
Fnaea 20. Проекты для вендинга: всюду деньги, деньги, деньги... 435 • sw7 — отключает прием inhibit (сигнал, устанавливающий блокировку прие- ма купюр); • sw 8 — настройка уровня сигнала inhibit; □ второй блок: • sw 1-2 — настройка количества импульсов; • sw 3-4 — настройка длины импульса и длины паузы. Сводная таблица настройки переключателей первого и второго блоков пред- ставлена в табл. 20.1; Ш Рис. 20.2. Купюроприемник ЮТ V7: слева — вид спереди; справа — вид сбоку; вверху—увеличенное изображение первого (слева) и второго (справа) блоков переключателей
436 Часть IV. Практика разработки проектов для Arduino □ третий блок (который под крышкой): • sw 1 — полярность импульса High (on) или Low (off); • SW 2 — ПРОТОКОЛ pulse (on) ИЛИ rs232 (off); • sw 3-4 — не используются. Чтобы любые изменения вступили в силу, купюроприемник надо перезагрузить. тшаштШШШ Ш8ШЯтж Рис. 20.3. Купюроприемник ICT V7, вид спереди: слева — крышка закрыта; справа — крышка открыта; вверху — увеличенное изображение третьего блока переключателей
Глава 20. Проекты для вендинга: всюду деньги, деньги, деньги... 437 Таблица 20Л Функция Reject Ruble 10 Accept Ruble 10 Reject Ruble 50 Accept Ruble 50 Reject Ruble 100 Accept Ruble 100 Reject Ruble 500 Accept Ruble 500 Reject Ruble 1000 Accept Ruble 1000 High Acceptance High Security Harness disable Harness enable Inhibit Active High Inhibit Active Low 1 pulse/Ruble 10 2 pulse/Ruble 10 5 pulse/Ruble 10 20 pulse/Ruble 10 50ms on/50 ms off 60ms on/300 ms off 30ms on/50 ms off 150ms on/150 ms off . Таблица настройки переключателей первого и второго блоков Переключатели первого блока 1 on off 2 on off 3 on off 4 on off 5 on off 6 on off 7 on off 8 on off Переключатели второго блока 1 off on off on 2 off off on on 3 off on off on 4 off off on on 20.1.1. Подключение купюроприемника ICT V7 к плате Arduino Купюроприемник оснащен кабелем для подключения к автомату, на конце кабеля имеется разъем 3x3 (рис. 20.4). Назначение интересующих нас выводов следующее: □ красный — 12 В; □ оранжевый — GND;
438 Часть IV. Практика разработки проектов для Arduino □ желтый — inhibit*; □ зеленый — inhibit-; □ синий — signal+; □ фиОЛеТОВЫЙ—SIGNAL-. Рис. 20.4. Кабель подключения купюроприемника ЮТ V7 Подключаем купюроприемник к плате Arduino по протоколу pulse. Схема подклю- чения приведена на рис. 20.5, а установка переключателей — в табл. 20.2. Такое их положение определяет режим pulse с полярностью High, 1 импульс на 10 руб. (5— на 50 руб., 10— на 100 руб.), длительность импульса 50 мсек, качество приема низкое, отсутствие сигнала блокировки купюроприемника и прием купюр номиналом 10, 50 и 100 рублей с отторжением 500- и 1000-рублевых купюр. Таблица 20.2. Таблица установки переключателей Первый блок 1 off 2 off 3 off 4 on 5 on 6 off 7 off 8 off Второй блок 1 off 2 off 3 off 4 off Третий блок 1 on 2 on 3 off 4 off +12 V ICV7 красный +12В оранжевый GND синий SIGNAL+ - ММ R1 - i i *- i i 4,7К — Arduino ТХХ АО D2 А1 D3 А2 D4 A3 D5 А4 D6 А5 D7 А6 D8 А7 по иу D10 D11 +З.ЗВ D12 D13 +5В GND I ± - —I Рис. 20.5. Схема подключения купюроприемника ЮТ V7 к плате Arduino
Гпава 20. Проекты для вендинга: всюду деньги, деньги, деньги... 439 20.1.2. Скетч для получения номинала принимаемой купюры Выход D2 платы Arduino подсоединен к выходу signal+ купюроприемника и уста- новлен в режим получения данных (input). Через резистор 4,7 кОм (см. рис. 20.5) он подтянут к питанию +5 В, и на нем находится уровень high. После получения купюры купюроприемник посылает импульсы продолжительностью 50 мсек на вы- ход signal*, устанавливая на входе D2 уровень low и вызывая процедуру обработки прерывания, где инкрементируется счетчик количества импульсов. В основном цикле программы (листинг 20.1) проверяется время, прошедшее после получения первого импульса, и если оно превысило 1000 мсек, выводится номинал получен- ной купюры (на основе количества импульсов), а счетчик обнуляется до поступле- ния первого импульса при приеме новой купюры. const int moneyPin=2; // подключение SIGNAL+ int money=0; // номинал принятой купюры unsigned long timeAllPulse=2000; // макс, время приема купюры unsigned long timeCount=0; void setup () { Serial.begin(9600) ; pinMode (moneyPin, INPUT); attachlnterrupt(0,count_pulse,FALLING); Serial.println("ready"); void loop() { // прошло максимальное время приема купюры? - вывести номинал if(money>0 && (millis ()-timeCount)>timeAllPulse) { Serial,print("moneys"); Serial.println(10*money); money=0; // обработка прерывания - получить кол-во импульсов // void countjpulse () { detachlnterrupt(0); money++;
440 Часть IV. Практика разработки проектов для Arduino if(money==l) timeCount=millis () ; attachlnterrupt(0,count_pulse,FALLING); } Электронный архив Полный вариант рассмотренного скетча находится в папке examples\20\J20J)1 сопрово- ждающего книгу электронного архива (см. приложение 2). 20.2. Монетоприемник СН-926 Монетоприемник — это устройство для приема монет (жетонов), которые исполь- зуются во всех видах торговых автоматов, сенсорных киосках, платежных терми- налах, автономных устройствах услуг. Их цель — принять и распознать металличе- ские деньги (монеты, жетоны). Монетоприемники можно разделить на четыре вида: □ монетоприемники эталонного типа (компараторы); □ программируемые монетоприемники; □ монетоприемники-селекторы; □ монетоприемники с функцией выдачи сдачи. Устройства для приема монет или жетонов делятся на два вида: □ программируемые — способные распознавать монеты различных номиналов; □ компараторные — принимающие монеты или жетоны только одного типа. Программируемые монетоприемники используются во всех торговых и платежных терминалах. Для игровых или развлекательных автоматов достаточно компаратор- ных монетников (эталонного типа). В зависимости от наличия свободного места внутри самого аппарата, монетоприемники устанавливаются сбоку (пристраивается дополнительный бокс) или за фасадной панелью автомата. Монета (жетон) попада- ет в монетоприемник, проверяется там на предмет подлинности (в современных устройствах сверяется до 24 параметров), и далее, в случае одобрения, аппарат по- лучает команду выдать товар или произвести какую-либо операцию. Новые модели монетоприемников, благодаря встроенным оптическим датчикам, исключают такие распространенные виды мошенничества, как монета (жетон) на нитке. Выбор моне- топриемников, как дополнительного оборудования, достаточно широк, что дает возможность, исходя из конкретных задач, подобрать оптимальную модель. Рассмотрим программируемый монетоприемник СН-926 (рис. 20.6), который мож- но приобрести на ЕЬау по достаточно приемлемой цене (дешевле 1000 руб.). Он может принять до 6 видов различных монет диаметром от 15 до 32 мм и толщиной от 1,2 до 3,8 мм. Рабочее напряжение— 12 В. Выходной сигнал— импульсный. Частота импульсов устанавливается с помощью трехпозиционного переключателя: fast — 20 мс, medium — 50 мс, slow — 100 мс.
Глава 20. Проекты для вендинга: всюду деньги, деньги, деньги... 441 Рис. 20.6. Монетоприемник СН-926 20.2.1. Настройка монетоприемника Рассмотрим процесс программирования (настройки) монетоприемника СН-926: 1. Включить питание, установить переключатель 1 в позицию NC. 2. Переключателем 2 выбрать нужную скорость обмена (fast, medium, slow). 3. Нажать одновременно кнопки ADD и MINUS и удерживать их более 3 секунд, отпустить — на индикаторе появится А. 4. Нажать и отпустить кнопку SET — на индикаторе появится Е. 5. Кнопками ADD и MINUS установить количество разных монет для приема: от 1 до 6 (я установил 5 — для настройки монетоприемника на прием 50 коп., 1, 2, 5 и 10 рублей). 6. Нажать кнопку SET более 3 секунд — на индикаторе появится HI (количество экземпляров первой монеты для калибровки). 7. Кнопками ADD и MINUS установить значение Н для первой монеты.
442 Часть IV. Практика разработки проектов для Arduino 8. Нажать кнопку SET более 3 секунд — на индикаторе появится Р1 (количество выдаваемых импульсов при успешном приеме первой монеты) — выбирается от 1 до 50. 9. Кнопками ADD, MINUS установить значение импульсов для первой монеты (я выбрал 1 — для первой, 2 — для второй, 3 — для третьей, 4 — для четвер- той, 5 — для пятой); 10. Нажать кнопку SET более 3 секунд— на индикаторе появится F1 (точность опознания первой монеты) — выбирается от 1 до 30 (я выбрал 10). 11. Кнопками ADD и MINUS установить значение F для первой монеты. 12. Нажать кнопку SET более 3 секунд. 13. Повторить шаги 6-12 для других выбранных монет. По окончании на индика- торе появится А. 14. Нажать и отпустить кнопку SET — на индикаторе появится Е. Теперь выключаем/включаем монетоприемник и проводим его калибровку. 20.2.2. Калибровка монетоприемника Процесс калибровки монетоприемника СН-926 заключается в следующем: 1. Нажать кнопку SET более 3 секунд — на индикаторе появится А1. 2. Начинаем опускать в монетоприемник монеты номинала 1 в количестве HI. 3. По загрузке последней монеты на ивдикаторе начинает мигать А1. 4. Нажать кнопку SET — на индикаторе появится А2. 5. Повторить загрузку монет для номиналов 2-5. 6. Нажать кнопку SET более 3 секунд. После включения/выключения монетоприемник готов к приему монет. Мы можем опускать в него монеты— на индикаторе высвечивается количество импульсов. Если монеты какого-либо номинала не проходят, повторяем настройку сначала. 20.3. Разменный автомат (хоппер) Cube Hopper MKII Хоппер Cube Hopper MK II (рис. 20.7) при внесении купюры через купюроприем- ник осуществляет ее размен на монеты, а также хранит и выдает сдачу монетами одного номинала — это один из самых распространенных хопперов, он разработан всемирно известной компанией Suzo, известнейшим игроком на рынке развлека- тельного оборудования. Модель Cube Hopper MK II специально предназначена для игровой и вендинговой индустрии, выполнена из износостойкого пластика и обла- дает высокой надежностью.
Глава 20. Проекты для вендинга: всюду деньги, деньги, деньги... 443 Характеристики хоппера Cube Hopper MKII: □ количество номиналов: 1; □ есть варианты под монеты достоинством 1, 2, 5 и 10 рублей; □ скорость выдачи монет: 7 монет/сек; П размер монет: 18-31 мм; □ толщина монет: 1,5-3,20 мм; □ питание: 12 В постоянного тока (DC) ±10% или 24 В постоянного тока от -25 до+10%; □ температура окружающей среды: от 0 до +50 °С; □ вместимость: 450 монет диаметром 24 мм (опционально в устройство допуска- ется установить до трех расширителей держателя монет, что дает возможность загружать в его бункер более 1200 монет (жетонов) диаметром 24 мм); □I современное электронное управление оптическими датчиками выдачи; □ работает в двух протоколах: ccTalk или параллельный; □ имеет квадратный форм-фактор — выдача монет (жетонов) может быть осуще- ствлена с 4 различных сторон в зависимости от необходимости. Рис. 20.7. Хоппер Cube Hopper MK II
444 Часть IV. Практика разработки проектов для Arduino 20.3.1. Подключение хоппера к плате Arduino Для подключения к плате Arduino используются следующие контакты на разъеме хоппера: □ pin 6 — выход оптического сенсора; □ pin 8 —+12 В; □ pin 9 — «земля». При подаче на pin 8 напряжения +12 В хоппер начинает выдавать монеты. Выдав каждую монету, хоппер выдает на pin 6 отрицательный импульс длительностью 35 мс. При подключении ко входу платы Arduino pin 6 хоппера подтягивается рези- стором 10 кОм к контакту +5 В. Монтажная схема соединений разменного автомата в составе купюроприемника и хоппера показана на рис. 20.8. 20.3.2. Программирование хоппера Как уже отмечалось, при внесении купюры через купюроприемник хоппер произ- водит размен ее на монеты. Если в нем недостаточно для этого монет, прием денег купюроприемником блокируется. Содержимое скетча, обеспечивающего эту функ- циональность, представлено в листинге 20.2. Загружаем скетч в плату Arduino и проверяем его работу. // пин включения/выключения купюроприемника #define PIN_KUP_ON 12 // пин включения/выключения хоппера tdefine PIN_HOPPER_ON 11 // пин сигнала хоппера #define PIN_HOPPER_S 4 // пин сигнала хоппера #define PIN_BLOCK 9 #define KUP_ON 0 #define KUP_OFF 1 #define HOPPER_ON 1 #define HOPPER_OFF 0 // время ожидания монеты в хоппере (хоппер пустой) #define TIME_WAIT_HOPPER 5000 // для хоппера поправка #define TIME1_MAX 200 // адреса EEPROM для хранения // блокировано? #define ADDR_BLOCK 27 // для EEPROM #include <EEPROM.h>
+ 12 В i Рис. 20.8. Монтажная схема соединений разменного автомата в составе купюроприемника и хоппера
446 Часть IV. Практика разработки проектов для Arduino I / купюроприемник const int moneyPin2=2; int pulse2=0; // макс, время ожидания импульса после приема купюры unsigned long timeAHPulse2=500; unsigned long timeCount2=0; unsigned int suirH); // параметры номинала монеты - 10 руб. unsigned int nominal=10; // блокировка приема int block=0; void setup() { Serial.begin(9600); block=EEPROM. read (ADDRJ3LOCK) ; pinMode (PIN_KUP_ON, OUTPUT) ; // проверка отсутствия монет if (digitalRead(PIN_BLOCK)—0 && block—1) digitalWrite(PIN_KUP_ON,KUP_OFF) ; else digitalWrite(PIN_KUP_ON,KUP_ON) ; pinMode (PIN__HOPPER_ON, OUTPUT) ; digitalWrite (PIN_HOPPER__ON,HOPPER_OFE;) ; attachlnterrupt(0f count_pulse2f FALLING); void loop() { // прошло максимальное время ожидания импульса приема купюры? if(pulse2>0 && (millis()-timeCount2)>timeAHPulse2 ) { sum=sum+pulse2*10; Serial.print("sumpulse2=");Serial.println(pulse2*10); i f(sum>=nominal) { Serial.print("sum=")/Serial.printIn(sum) ; // блокировка купюроприемника digitalWrite (PIN_KUP__ON,KUP_OFF) ; detachlnterrupt(0);' // выдача монет if(exchange(sum)) { // успешно digitalWrite (PINJOJP_ON,KUP_ON) ; attachlnterrupt {0, count_j?ulse2, FALLING); } else { if (digitalRead(PIN_BLOCK)=l) { digitalWrite(PIN_KUP_ON,KUP_ON); attachlnterrupt(0,count_pulse2/ FALLING);
Глава 20. Проекты для вендинга: всюду деньги, деньги, деньги... 447 Ыоск=1; } Serial.print ("sum="); Serial.println (sum); EEPRQM. write (ADDR_BLOCK, block) ; // обработка прерывания купюроприемника - получить кол-во импульсов void count_pulse2() { detachlnterrupt(0); pulse2++; if(pulse2==l) timeCount2=smillis (); delay(lO); attachlnterrupt(0,count_pulse2,FALLING); //attachlnterrupt(1,count_pulse2,CHANGE); } // выдача размена boolean exchange (int surnma) { boolean lastSignal=HIGH; boolean currentsignal=HIGH; unsigned long millisl=0; int count; unsigned int timel=0; timel=TIMEl_MAX; count=sum/nominal; int pulse3=0; unsigned long millis2==millis () ; digitalWrite(PIN_HOPPER_ONf HOPPER_ON); while(pulse3<count) { currentSignal=debounce(lastSignal,PIN_HOPPER_S); if(lastSignal==HIGH && currentSignal==LOW) { pulse3++; Serial.println(pulse3); millisl-millisO; //delay(40); } lastsignal=currentSignal; if (millis () -millisl> TIME_WAIT_HOPPER) break; } delay(timel); digitalWrite(PIN_HOPPER_ON,HOPPER_OFF); delay(1000);
448 Часть IV. Практика разработки проектов для Arduino sum=sum-pulse3*nominal; if(pulse3<count) return false; else return true; /* Функция сглаживания дребезга * Принимает в качестве аргумента предыдущее состояние кнопки * и выдает фактическое. */ int debounce(int last,int pinl) { int current = digitalRead(pinl); // Считать состояние кнопки if (last != current) // если изменилось... { delay(5); // ждем 5мс current = digitalRead(pinl); // считываем состояние кнопки return current; // возвращаем состояние кнопки Электронный архив Полный вариант рассмотренного скетча находится в папке examples\20\_20J)2 сопрово- ждающего книгу электронного архива (см. приложение 2).
ГЛАВА 21 Макеу: импровизированные клавиатуры В 2012 году на Kickstarter был более чем успешно запущен проект МаКеу МаКеу, который позволял превратить в сенсорные кнопки любые предметы, которые хоть немного проводят электрический ток. Более того, плата подключалась к компьюте- ру и превращалась в USB-клавиатуру — с МаКеу МаКеу клавиатурой оказывались фрукты, цветы и прочие предметы (рис. 21.1). Рис. 21.1. Импровизированная клавиатура: используем в качестве клавиш любые токопроводящие полоски Естественно, через некоторое время предприимчивые китайцы наладили производ- ство более дешевых аналогов, одним из которых стала плата Makey TouchKeyUSB Shield — плата расширения (шилд) к Arduino Uno (рис. 21.2).
450 Часть IV. Практика разработки проектов для Arduino I Рис. 21.2. Плата расширения Makey TouchKeyUSB Shield 21.1. Makey: управление новогодней RGB-гирляндой Рассмотрим проект управления RGB-лентой, используемой в качестве гирлянды для новогодней елки. С помощью платы расширения Makey TouchKeyUSB Shield мы будем определять прикосновения к новогодним «игрушкам»— кружкам из фольгированной цветной бумаги разного цвета (красного, зеленого, синего, желто- го, сиреневого и белого)— и зажигать RGB-ленту соответствующим цветом. Монтажная схема подключения к плате Arduino нашей новогодней RGB-гирлянды показана на рис. 21.3, вся конструкция в сборе— на рис. 21.4, а в работе— на рис. 21.5. 21.2. Программирование новогодней RGB-гирлянды Содержимое скетча, обеспечивающего работу этого проекта, показано в листин- ге 21.1: нажатие на «игрушку» определенного цвета приводит к изменению цвета RGB-ленты на соответствующий. Чтобы лента постоянно горела, последний цвет запоминается. При одновременном выборе нескольких цветов переключение цвета не происходит — введен фильтр, определяющий одновременное нажатие.
Глава 21. Макеу: импровизированные клавиатуры 451 I I -12 В Рис. 21.3. Монтажная схема подключения к плате Arduino новогодней RGB-гирлянды
452 Часть IV. Практика разработки проектов для Arduino Рис. 21.4. Вся схема в сборе Рис. 21.5. Новогодняя RGB-гирлянда во всем своем блеске
Глава 21. Makey: импровизированные клавиатуры 453 // pins для RGB strip int pinRed=6; int pinGreen=7; int pinBlue=5; // переменные для хранения данных с touch int InDataO = 0, InDatal = 0, InData2 = 0, InData3 = 0, InData4 = 0, InData5 = О; int TouchSensitivity =30; // int AllData=O; int tekpos=0; // массив значений rgb ленты для разных нажатий int leds[8][3]={{0,0,0}, {1,0,0}, // г {0,1,0}, // g {0,0,1}, // b {1,1,0}, // yellow {1,0,1}, // r+b {1,1,1}, // white {0,0,0} // нажато несколько }; void setup() { Serial.begin(9600); for(int i = A0; i <= A5; i+f) { //pins touch Red, Green, Blue, Yellow, ,White pinMode(5, INPUT); // настройка пинов RGB strip pinMode(pinRed, OUTPUT); pinMode(pinGreen, OUTPUT); pinMode(pinBlue, OUTPUT); tekpos=random(1,3) ; setRGB(tekpos); //TIMSKO &= !(1 « TOIEO); void loop() { // получение данных с touch InDataO = 1024 - analogRead(AO); InDatal = 1024 - analogRead(Al); InData2 = 1024 - analogRead(A2); InData3 = 1024 - analogRead(A3);
454 Часть IV. Практика разработки проектов для Arduino InData4 = 1024 - analogRead(A4); InData5 = 1024 - analogRead(A5); // определение нажатой AllData=0; if(InDataO >= TouchSensitivity) AllData=AllData+5; if(InDatal >= TouchSensitivity) AllData=AllData+6; if(InData2 >= TouchSensitivity) AllData=AllData+7; if(InData3 >= TouchSensitivity) AllData=AllData+8; if(InData4 >= TouchSensitivity) AllData=AllData+9; if(InData5 >= TouchSensitivity) AllData=AllData+10; // AllData=*nin (AllData, 11) ; AllData=max (AllData, 4); AllData=AllData-4; Serial.print("AllData=");Serial.println(AllData); // включение ленты if(AllData>0 && AllData<7) { tekpos=AHData; setRGB(tekpos); delay(100); // процедура включения ленты void setRGB(int pos) { digitalWrite(pinRed,leds[pos][0]); digitalWrite(pinGreen,leds[pos][1]) digitalWrite(pinBlue,leds[pos][2]); Электронный архив Полный вариант рассмотренного скетча находится в папке examplesxznjzijoi сопро- вождающего книгу электронного архива (см. приложение 2).
ГЛАВА 22 о© Arduino и интерфейс USB: управление роботами 22.1. Интерфейс USB Последовательный интерфейс USB используется для подключения периферийных устройств. Соответственно, существуют понятия «главное устройство» — хост (он управляет обменом данными через интерфейс и выступает инициатором обмена) и «периферийное устройство» — клиент (в процессе обмена данными он «подчи- няется» хосту). Логики работы хоста и клиента принципиально различны, поэтому нельзя напрямую соединять устройства «хост — хост» и «клиент — клиент». Име- ются специальные устройства — хабы, которые подключаются в качестве клиента к одному хосту и, в то же время, выступают хостом для других периферийных устройств. Хабы также применяются для «разветвления» шины USB. Физически интерфейс USB (до версии 2.0) использует 4 провода (рис. 22.1): □ «земля» (GND); □ +5 В (VBUS); □ D-, D+— линии приема/передачи данных (обозначения D+ и D- условны, с электрическими потенциалами это никак не связано). Спецификация USB 1.0 определяла два типа разъемов: А— на стороне контролле- ра или концентратора USB и В — на стороне периферийного устройства. Впослед- ствии были разработаны миниатюрные разъемы для применения USB в переносных Standard A - D+ D- use j Рис. 22.1. Назначение контактов USB 1.0 и USB 2.0
456 Часть IV. Практика разработки проектов для Arduino и мобильных устройствах, получившие название Mini-USB. Новая версия миниа- тюрных разъемов, называемых Micro-USB, была представлена USB Implemented Forum 4 января 2007 года. Благодаря встроенным линиям питания, USB позволяет подключать периферийные устройства без собственного источника питания (максимальная сила тока, потреб- ляемого устройством по линиям питания шины USB, не должна превышать 500 мА, yUSB 3.0 — 900 мА). Стандарт USB поддерживает концепцию plug-and-play. Эта концепция подразуме- вает, что пользователю достаточно «воткнуть» устройство в соответствующий порт компьютера. Далее его операционная система автоматически определит тип под- ключенного устройства, найдет подходящий для этого устройства драйвер, сконфи- гурирует устройство и т. д. Для того чтобы это все работало, стандартом USB пре- дусмотрены некие общие требования для всех устройств: □ каждое устройство содержит дескриптор (описание) устройства; □ есть общий для всех USB-устройств механизм, который позволяет ОС прочитать дескриптор устройства для того, чтобы идентифицировать устройство и узнать его характеристики; □ есть общий для всех USB-устройств механизм, который позволяет ОС выпол- нить первичную конфигурацию устройства (например, присвоить устройству новый адрес). 22.2. Плата расширения USB Host Shield Очень соблазнительно иметь возможность подключать к Arduino USB-устройства, которых великое множество. Плата расширения USB Host Shield 2.0 (рис. 22.2) позволяет платам Arduino выступать в роли родительского USB-устройства для практически любой имеющейся USB-периферии. С этой платой открывается масса Рис. 22.2. Плата расширения USB Host Shield 2.0
Глава 22. Arduino и интерфейс USB: управление роботами 457^ новых возможностей для создания интересных устройств. В настоящее время пла- той USB Host Shield 2.0 поддерживаются следующие классы устройств: □ НТО-устройства — такие как клавиатуры, мыши, джойстики и др.; □ игровые устройства: Sony PlayStation 3, Nintendo Wii, Xbox 360; □ USB-преобразователи: FTDI, PL-2303, ACM, а также некоторые аппараты и GPS-приемники; □ Android-устройства; □ цифровые фотоаппараты: Canon (EOS, PowerShot), Nikon и др. Для программирования платы расширения USB Host Shield используется специаль- ная библиотека USBJHost, скачать которую можно со страницы https://github.com/ felis/USBJIost_Shield_2.0. Электронный архив Библиотека USBJHost размещена в каталоге libraries сопровождающего книгу элек- тронного архива (см. приложение 2). Спецификацию и примеры использования библиотеки USB_Host можно найти на сайте Circuits@Home по адресу: http://www.circuitsathome.com/arduino_usb_host_ shieldjprojects. 22.3. HID-устройства USB НТО (Human Interface Device)— устройство, подключаемое к вычислительной технике, с тем, чтобы с ней мог работать человек. Говоря проще, HID— это устройство ввода информации. Устройства ввода необходимы для непосредствен- ного участия человека в работе компьютера: для введения исходных данных для вычислений, для выбора параметров действия, для редактирования имеющихся данных и результатов и т. д. HID-устройства ввода различаются по типу вводимой информации: □ для текстовой информации — это преимущественно клавиатуры. Они служат для управления техническими и механическими устройствами (компьютер, калькулятор, кнопочный телефон). Каждой клавише устройства соответствует один или несколько определенных символов. Возможно увеличить количество действий, выполняемых с клавиатуры, с помощью сочетаний клавиш. В клавиа- турах такого типа клавиши сопровождаются наклейками с изображением симво- лов или действий, соответствующих нажатию; □ для звуковой информации— это микрофон. Электроакустические приборы, преобразующие звуковые колебания в колебания электрического тока, исполь- зуются во многих устройствах (телефоны и магнитофоны, приборы звукозаписи и видеозаписи на радио и телевидении, устройства радиосвязи); □ для графической информации: • сканер — устройство для считывания плоского изображения и представления его в растровой электронной форме;
458 Часть IV. Практика разработки проектов для Arduino • цифровая камера — устройство (фотоаппарат), использующее массив полу- проводниковых светочувствительных элементов (матрицу), на которую изо- бражение фокусируется с помощью системы линз объектива. Полученное изображение сохраняется в электронном виде в памяти самой камеры или же на дополнительном цифровом носителе; • веб-камера— цифровая видео- или фотокамера, способная в реальном вре- мени фиксировать изображения, предназначенные для дальнейшей передачи по сети Интернет как в потоковом режиме, так и за определенные промежут- ки времени; • плата захвата (тюнер) — электронное устройство для преобразования ана- логового видеосигнала в цифровой видеопоток. Используется для захвата те- лесигнала, сигнала с камер видеонаблюдения и др. HID-устройства управления различаются по функционалу: □ относительное позиционирование (обрабатывают информацию о перемещении): • мышь — манипулятор, преобразующий механические движения в движение курсора на экране. Различают механические, оптические, гироскопические, сенсорные мыши; • трекбол — манипулятор, чей принцип работы сходен с шариковой механи- ческой мышью и аналогичен мыши по принципу действия и по функциям. Однако пользователь не передвигает мышь, а управляет с помощью ладони или пальцев непосредственно шариком, закрепленным на специальном дер- жателе с датчиками; • трекпойнт— миниатюрный тензометрический джойстик, применяемый в ноутбуках для замены мыши. Трекпойнт считывает направление и силу давления пальца пользователя; • тачпад — сенсорная панель, применяемая, в основном, в портативных ком- пьютерах. В отличие от трекпойнта, считывающего давление пальца, тачпад считывает емкостные характеристики при соприкосновении пальца с поверх- ностью емкостных датчиков. Поэтому управление тачпадом с помощью непроводящих предметов (ручка, карандаш, стилус) достаточно проблема- тично; • джойстик— устройство ввода информации, которое представляет собой качающуюся в двух плоскостях ручку, боковое давление которой считывает- ся датчиками в основании устройства. Используется как игровой гаджет, а также как средство управления (например, роботизированной техникой на производстве); □ абсолютное позиционирование (высчитывают абсолютные координаты на плос- кости, в качестве которой выступает устройство): • графический планшет — устройство для ввода графики (отдельных линий и рисунков) от руки непосредственно в компьютер. Состоит из пера и плоского планшета, чувствительного к нажатию пера;
Глава 22. Arduino и интерфейс USB: управление роботами 459^ • тачскрин (сенсорный экран)— устройство ввода информации, представ- ляющее собой экран, реагирующий на прикосновения к нему (используется в современных смартфонах, платежных и информационных терминалах). Отдельно хочется выделить специальные HID-устройства для компьютерных игр: □ игровые мыши — отличаются от обычных компьютерных мышей высокой чув- ствительностью, настраиваемым весом, большим количеством программируе- мых кнопок; □ кейпады— специальные игровые клавиатуры-приставки, в которых кнопки скомбинированы для максимального удобства игрока (в современные модели встраивается мини-джойстик); □ руль и педали —манипуляторы для игр жанра «автогонки» (рэйсинг); □ джойстики — используются для игр жанра «авиасимуляторы»; □ геймпады— специальные игровые манипуляторы, используемые в аркадных жанрах (перешли с игровых консолей); □ танцевальные платформы — специальные платформы с датчиками давления. Управление производится с помощью ног. Используются для игр жанра «танце- вальные аркады»; □ музыкальные инструменты (гитары, барабаны) — специальные манипуляторы в форме музыкальных инструментов с кнопками и датчиками давления. Исполь- зуются для игр жанра «музыкальные аркады». Операционные системы, как правило, имеют встроенные драйверы НТО-класса, так что у разработчиков отпадает необходимость в трудоемкой собственной разработке драйвера для нового устройства. Чтобы определить устройство как НТО, необходи- мо поддержать ряд структур, описывающих HID-интерфейс, а также написать алгоритм обмена по interrupt-каналу (каналу прерываний) передачи данных. Во многих отношениях устройства НТО не имеют никаких особенных отличий от других USB-устройств. Однако кроме требований, которые относятся ко всем USB-устройствам, устройства HID выдвигают ряд дополнительных требований: П НТО-устройство должно иметь interrupt in — конечную точку для выдачи дан- ных в хост, interrupt Out — конечная точка для получения периодических дан- ных от хоста, является опциональной и может не использоваться; □ НТО-устройство должно содержать дескриптор класса — Device class Descriptor И ОДИН ИЛИ более дескрипторов репорта HID Report Descriptor; □ НТО-устройство должно поддерживать специфический для класса управляющий запрос GetReport, а также опционально поддерживать дополнительный запрос SetJReport; □ для передачи interrupt in (данные из устройства в хост) устройство должно по- ложить данные репорта в FIFO соответствующей конечной точки и разрешить передачу;
460 Часть IV. Практика разработки проектов для Arduino □ для передачи interrupt out (данные из хоста в устройство) устройство должно разрешить соответствующую конечную точку out, а затем, после прихода паке- та, забрать данные из FIFO. 22.4. Подключение HID-мыши USB В библиотеке USBHost 2.0 имеется пример для подключения к Arduino НШ-мыши USB — USBHIDBootMouse.pde. Загружаем его и смотрим в мониторе последователь- ного порта результат работы скетча (рис. 22.3). i dy=-4 dy=-5 ix=il dy—3 jx*=9 dy=O jx=4 dy=O Jx-3 dy=3 ix-l dy=l dx=l dy=O jx=4 dy=O llx-12 dy«2 llx-12 dy-1 dx=12 dy«2 jx-14 dy-1 Йх-l dy-l fe Рис. 22.3. Скетч для подключения HID-мыши USB 22.5. Управление роботом с помощью руля Defender В этом проекте мы будем управлять роботом с помощью игрового манипулятора — руля Defender Forsage Drift GT (рис. 22.4). Для беспроводной передачи управляю- щих команд от манипулятора к роботу воспользуемся беспроводным радиомодулем NRF24L01, работу с которым мы рассмотрели в главе 12 (см. разд. 12.3). Руль подсоединяется к плате Arduino через USB Host Shield. Для отправки роботу управляющих команд от руля подсоединяем к этой плате радиомодуль 2,4 ГГц NRF24L01. Блок робота выполнен в виде гусеничной платформы. К плате Arduino, установленной на роботе, подсоединяется такой же радиомодуль 2,4 ГГц NRF24L01,
Глава 22. Arduino и интерфейс USB: управление роботами 461 Рис. 22.4. Руль Defender Forsage Drift GT L293 Рис. 22.5. Электрическая схема блока робота
462 Часть IV. Практика разработки проектов для Arduino назначение которого — прием команд, управляющих роботом. Электрическая схе- ма блока робота представлена на рис. 22.5. В качестве драйвера двигателей здесь применена микросхема L293. Загружаем в плату Arduino скетч USB_HIDJDesc.pde (листинг 22.1), входящий в при- меры библиотеки USBJrlost, подсоединяем к Arduino через USB Host Shield наш руль И получаем Descriptor Report НШ-уСТроЙСТВа (рИС. 22.6). USB Usbj //USBHub Hub'WUsb); HIDUniversal2 Hid(SUsb); Collection Application Collection Logical Report Size(08) Report Count(04) Logical Mm (00) Logical Max(FFOO) Physical Mm (00) Physical Max(FFOO) Usage X Usage Y Usage Z Usage Rz Input(00000010) Report Size(04) Renort Count(01) Рис. 22.6. Получение Descriptor Report НЮ-устройства Usage Page Gen Desktop Ctrls(Ol) Usage Game Pad Collection Application Collection Logical Report Size(08) Report Count(04) Logical Min(00) Logical Max(FFOO) Physical Min(00) Physical Max(FFOO) Usage X Usage Y
Глава 22. Arduino и интерфейс USB: управление роботами 463 Usage Z Usage Z Usage Rz Input(00000010) Report Size(04) Report Count(01) Logical Max(07) Physical Max(3B01) Unit(14) Usage Hat Switch Input(01000010) Unit(00) Report Size(01) Report Count(0C) Logical Max(01) Physical Max(01) Usage Page Button(09) Usage Min(01) Usage Max(0C) Input(00000010) Usage Page Undef(00) Report Size(08) Report Count(02) Logical Max(01) Physical Max(01) Usage Input(00000010) End Collection Collection Logical Report Size(08) Report Count(04) Physical Max(FFOO) Logical Max(FFOO) Usage Output(00000010) End Collection End Collection Для создания своего кода возьмем код примера USBHIDJoystick.pde, входящего в библиотеку USBHost и реализующего функционал джойстика, и перепишем файлы hidjoystickrptparser.h (листинг 22.2) и hidjoystickrptparser.cpp (листинг 22.3) для сохранения данных в структуре. Затем добавим отправку данных руля по радиока- налу с помощью библиотеки для радиомодуля NRF24L01 (листинг 22.4). Отправку производим каждые 300 мс.
464 Часть IV. Практика разработки проектов для Arduino #if !defined( HIDJOYSTICKRPTPARSER_H_) #define HIDJOYSTICKRPTPARSER_H_ #include <inttypes.h> # include <avr/pgmspace. h> #include "avrpins.h" #include "max3421e.h" #include "usbhost.h" #include ffusb_ch9.h" #include "Usb.h" #if defined(ARDUINO) && ARDUINO >=100 #include "Arduino.h" #else #include <WProgram.h> #endif # include "printhex.h" #include "hexdump.h" #include "message.h" #include "confdescparser.h" #include "hid.h" struct GamePadEventData { uint8_t X, Y, Zl, Z2, Rz; }; class JoystickEvents { public: virtual void OnGamePadChanged(const GamePadEventData *evt); virtual void OnHatSwitch(uint8_t hat); virtual void OnButtonUp (uint8__t but__id); virtual void OnButtonDn(uint8_t but_id); uint8_t X; uint8_t Y; uint8_t Zl; uint8_t Z2; uint8__t Rz; }; #define RPT_GEMEPAD_LEN 5 class JoystickReportParser : public HIDReportParser { JoystickEvents *joyEvents;
Глава 22. Arduino и интерфейс USB: управление роботами 465 uint8_t oldPad [RPT_GEMEPAD_LEN ] ; uint8__t oldHat; ( uintl6_t oldButtons; public: JoystickReportParser(JoystickEvents *evt); virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); #endif // HIDJOYSTICKRPTPARSER_H_ Электронный архив Полный вариант рассмотренного скетча (файл hidjoystickrptparser.h) находится в папке exemples\22\_22_02 сопровождающего книгу электронного архива (см. приложение 2). #include "hidjoystickrptparser.h" JoystickReportParser::JoystickReportParser(JoystickEvents *evt) : joyEvents(evt), oldHat(OxDE), oldButtons(0) { for(uint8_t i=0; i<RPT_GEMEPAD_LEN; i oldPad[i] = OxD; void JoystickReportParser::Parse(HID *hid, bool is_rpt_idf uint8_t len, uint8_t *buf) { bool match = true; // Checking if there are changes in report since the method was last called for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i if (buf[i] != oldPad[i]) { match = false; break; // Calling Game Pad event handler if (Imatch && joyEvents) { joyEvents->OnGamePadChanged((const GamePadEventData*)buf);
466 Часть IV. Практика разработки проектов для Arduino for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i]; } uint8_t hat = (buf[5] & OxF); // Calling Hat Switch event handler if (hat != oldHat && joyEvents) { joyEvents->OnHatSwitch(hat); oldHat = hat; uintl6_t buttons = (0x0000 | buf[6]); buttons «= 4; buttons |= (buf[5] » 4); uintl6_t changes = (buttons A oldButtons); // Calling Button Event Handler for every button changed if (changes) for (uint8_t i=0; KOxOC; { uintl6__t mask = (0x0001 « i) ; if (((mask & changes) > 0) && joyEvents) if ((buttons & mask) > 0) j oyEvents->OnButtonDn(i+1); else j oyEvents->OnButtonUp(i+1); } oldButtons = buttons; void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt) { X=evt->X; Y=evt->Y; Zl-evt->Zl; Z2=evt->Z2; Rzs=evt->Rz; void JoystickEvents::OnHatSwitch(uint8_t hat) { Serial.print("Hat Switch: "); PrintHex<uint8 t>(hat);
Глава 22. Arduino и интерфейс USB: управление роботами 467 Serial.printIn("и); } void JoystickEvents::0nButtonUp(uint8_t but_id) { Serial.print("Up: "); Serial.printIn(but_id, DEC); } void JoystickEvents:;0nButtonDn(uint8_t but_id) { Serial.print("Dn: "); Serial.printIn(but_id, DEC); Электронный архив Полный вариант рассмотренного скетча (файл hidjoystickrptparser.cpp) находится в папке examples\22\mm22_03 сопровождающего книгу электронного архива (см. приложение 2). # include <avr/pgmspace.h> #include <avrpins.h> #include <max3421e.h> #include <usbhost.h> #include <usb_ch9.h> #include <Usb.h> #include <usbhub.h> # include <avr/pgmspace.h> #include <address.h> #include <hid.h> #include <hiduniversal.h> #include "hidjoystickrptparser.h" #include <printhex.h> #include <message.h> #include <hexdump.h> #include <parsetools.h> USB Usb; USBHub Hub(&Usb); HIDUniversal Hid(&Usb); JoystickEvents JoyEvents; JoystickReportParser Joy(&JoyEvents); #include <SPI.h> #include <Mirf.h> #include <nRF24L01.h>
468 Часть IV. Практика разработки проектов для Arduino #include <MirfHardwareSpiDriver.h> #define MAX_BUFF 32 // Буфер приема-передачи void setup() { Serial.begin( 115200 ); Serial.println("Start"); if (Usb.lrg.t() == -1) Serial.println("OSC did not start."); delay( 200 ); if (!Hid.SetReportParser(0, &Joy)) ErrorMessage<uint8_t>(PSTR("SetReportParser"), 1 ); Mirf.spi = &MirfHardwareSpi; Mirf.init(); Mirf.setRADDR((byte *)"defender"); // Здесь задаем адрес Mirf.payload = MAX_BUFF; // Здесь задаем буфер Mirf.channel = 10; // Это канал приема-передачи - должен // быть одинаковым у устройств. Mirf .configO ; Serial.println("Start.."); } char buff [MAX_BUFF]; int c_count = 0; void loop() { Usb.TaskO ; buff[0]=map(JoyEvents.X,0,255,1,100); buff[l]=map(JoyEvents.Y,0,255,1,100);; buff [2] =inap(JoyEvents.Zl, 0,255,1,100) ; buff[3]=raap(JoyEvents.Z2,0,255,1,100); buff[4]=JoyEvents.Rz+1; buff[5]=0; Mirf.setTADDR((byte *)"automobilel"); // Адрес! Serial.print(">"); Mirf.send((uint8_t *)buff); while(Mirf.isSending()){ } Serial.println(buff); delay(300); Электронный архив Полный вариант рассмотренного скетча (файл J22j04.ino) находится в папке examples\ 22\J22_O4 сопровождающего книгу электронного архива (см. приложение 2).
Глава 22. Arduino и интерфейс USB: управление роботами 469_ Теперь необходимо написать скетч приема данных и отправки команд двигателям робота. Первый байт из буфера данных: влево (0-50)— вправо (51-100), второй байт: вперед (51-100)— назад (1-50). Надо только правильно перевести байты в данные для микросхемы L293. Полученный скетч представлен в листинге 22.5. #include <SPI.h> tinclude <Mirf.h> #include <nRF24L01.h> #include <MirfHardwareSpiDriver.h> #define MAX_BUFF 32 // Буфер приема-передачи void setup(){ Serial.begin(9600); Mirf.spi = &MirfHardwareSpi; Mirf.initO; Mirf.setRADDR((byte *)"automobilel"); // Здесь задаем адрес Mirf.payload = MAXJ3UFF; // Здесь задаем буфер Mirf.channel = 10; // Это канал приема-передачи - должен // быть одинаковым у устройств. Mirf .configO ; // настраиваем выводы для моторов pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(6, OUTPUT); Serial.println("Start.."); char buff[MAX_BUFF]; void loop(){ delay(10); //receiving if (Mirf.dataReadyO) { Mirf.getData((uint8_t *)buff); int fbl-buff[0]; int lr»buf£[l]; gol2(fbl,lrl); } delay(100 );
470 Часть IV. Практика разработки проектов для Arduino void gol2(int fb,int lr) { // вперед-назад if(fb>50) {digitalWrite(3,HIGH);digitalWrite(4,Ь(ЖГ; digitalWrite(5/HIGH);digitalWrite(6,LOW);} else if(fb<50) {digitalWrite(3,LOW)/digitalWrite(4,HIGH); digitalWrite(5,LOW)/digitalWrite(6,HIGH)/} else {digitalWrite(3,LOW)/digitalWrite(4,LOW)/ digitalWrite(5,LOW)/digitalWrite(6,LOW)/} // влево-вправо int lrl=map(abs(50-lr),1,50,1,255)/ int fbl=map(abs(50-fb), 1,50,1,255)/ if(lr<50) {int left=min(255,max(0,fbl-lrl/2))/ int right=min(255,fbl+lrl/2)} else {int right=roin(255,max(0,fbl-lrl/2))/ int left=min(255,fbl+lrl/2)} analogWrite(9, left); analogWrite(10, right)/ Электронный архив Полный вариант рассмотренного скетча находится в папке examples\22\J22J>5 сопро- вождающего книгу электронного архива (см. приложение 2). 22.6. Управление роботом с помощью геймпада Defender Робот iRobot Create (рис. 22.7) — программируемый робот. Он разработан в 2007 го- ду компанией iRobot на базе платформы робота-пылесоса Roomba. Электронный интерфейс робота имеет 7 разъемов mini-DIN и разъем DB-25 для обмена данными, электронные датчики и световые индикаторы. Программный интерфейс робота по- зволяет управлять его поведением: считывать информацию с сенсоров при помощи серии команд, включать команды режима, команды привода, звуковые команды, демонстрационные команды и команды опроса сенсоров. Эти команды можно посылать на последовательный порт робота с компьютера или платы Arduino. Скачать описание открытого интерфейса робота можно по ссылке: http://www. irobotxom/fdelibraiy/^
Глава 22. Arduino и интерфейс USB: управление роботами 471 Рис, 22.7. Робот iRobot Create Электронный архив Этот же файл под именем Create Open Interface_v2.pdf содержится в папке datasheets со- провождающего книгу электронного архива (см. приложение 2). Для подсоединения робота к плате Arduino используем его 25-контактный разъем DB-25 с распаянным согласно данным табл. 22.1 переходником (рис. 22.8). Рис. 22.8. Переходник для подключения робота к плате Arduino
472 Часть IV. Практика разработки проектов для Arduino Таблица 22.1. Соединение платы Arduino и робота iRobot Create iRobot Create 1(Rx) 2(Tx) 14(GND) 8 (+5 B) Arduino 4 3 GND Vin В этом проекте также задействованы плата расширения USB Host Shield и беспро- водной геймпад Defender Scorpion RS3 (рис. 22.9), подключаемый к плате как HID-устройство. Беспроводной геймпад имеет два аналоговых джойстика, 12 кно- пок, D-pad и индикатор заряда батарей. На геймпаде может быть включен режим вибрации. Если геймпад не используется в течение продолжительного времени, он автоматически выключается. Совместим этот геймпад с ПК и Sony PlayStation 3. Интерфейс — Bluetooth. Рис. 22.9. Беспроводной геймпад Defender Scorpion RS3 Итак, устанавливаем на плату Arduino шилд USB Host Shield. К USB-входу шилда подсоединяем USB-ресивер геймпада (рис. 22.10) и соединяем плату Arduino с роботом iRobot Create через переходник (см. рис. 22.8) проводами, распаянными согласно табл. 22.1. В библиотеке USBJHost содержится пример для беспроводного джойстика PS3. Чтобы пример заработал с геймпадом Defender Scorpion RS3, необходимо испра- вить заголовочный файл PS3Enums.h, входящий в эту библиотеку. Исправления касаются значения для кнопок геймпада в массиве buttons [ ].
Глава 22. Arduino и интерфейс USB: управление роботами 473 Рис. 22.10. Подключение USB-ресивера геймпада к USB-входу шилда Электронный архив Исправленный файл PS3Enums.h находится в папке libraries\USB_Host сопровождающего книгу электронного архива (см. приложение 2). Выберем следующее назначение кнопок и джойстиков геймпада: □ правый джойстик — для управления движением; □ кнопка Start/10 — для перевода робота iRobot Create в режим full (полное управ- ление); □ кнопка Select/9 — для перевода iRobot Create в пассивный режим; □ кнопки R1 и R2 — для проигрывания мелодий iRobot Create; □ кнопки LI, L2 — для установки светодиодов iRobot Create; □ кнопка 4 (квадрат) — выполнение скрипта движения по квадрату. Скетч для Arduino, представленный в листинге 22.6, отслеживает состояние кнопок и джойстиков и выполняет отправку команд на iRobot Create. #include <SoftwareSerial.h> SoftwareSerial mySerial(4,3); #include <PS3USB.h> USB Usb; PS3USB PS3(&Usb); Button Btarr[16]={UP, RIGHT, DOWN, LEFT, SELECT, START, L3, R3, L2, R2, LI, Rl, TRIANGLE, CIRCLE, CROSS, SQUARE}; AnalogHat Joyarr[4]={LeftHatX,LeftHatY,RightHatX,RightHatY};
474 Часть IV. Практика разработки проектов для Arduino boolean printAngle; uint8_t state = 0; int status_buttons[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long millis_buttons[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; long millisjDUttonsltiei^SOO, 500, 500, 500', 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000}; int status_joys[4]={0,0,0,0}; int millis_joys[4]={0,0,0,0}; int mp_joys [4] = {2000, -500,2000, -500} ; int dHatLeft=0; int dHatRight=0; void setup() { Serial.begin(115200) ; if (Usb.InitO == -1) { Serial.print(F("\r\n OSC did not start")); while(1); //halt } Serial.print(F("\r\nPS3 USB Library Started")); mySerial.begin(57600); } void loop() { Usb.TaskO; // joys for(int i=0;i<4;i++) { if((PS3.getAnalogHat(Joyarr[i]) !- status_joys[i]) && (millis()-millis_joys[i]>200)) { millis_j oys[i] =millis();status_j oys[i]=PS3.getAnalogHat(Joyarr[i]); int hat=roap(PS3.getAnalogHat(Joyarr[i]),0,255,map_joys[i]* (-1),map_joys[i]); if(i<2) dHatLeft=l; else dHatRight=l; if(dHatLeft>0) {dHatLeft=0;} if(dHatRight>0) {dHatRight=0; go_irobot(status_joys[3],status_joys[2]);}
Глава 22. Arduino и интерфейс USB: управление роботами 475 II buttons for(int i=0;i if(PS3.getButtonPress(Btarr[i]) && status_buttons[i]==0) millis_buttons[i]==millis ();status_buttons[i]=l; put_actions(i); } else {if(millis0-millis_buttons[i]>millis_buttonsl[i]) status_buttons[i]=0; // действия по нажатии кнопки void put_actions(int btnl) { switch(btnl) { case 4: mySerial.write(128); break; // start case 5: mySerial.write(132); break; // led case 8: mySerial.write((int)139); mySerial.write((int)8); mySerial.write((int)255);mySerial.write((int)255); break; case 10: mySerial.write(139);mySerial.write(4); mySerial.write((byte)0);mySerial.write(255); break; // music 6 case 9: mySerial.write(141);mySerial.write(6); break; // 40 см и останов case 12: mySerial.write(152);mySerial.write(13);mySerial.write(137); mySerial.write(1);mySerial.write(44);mySerial.write(128); mySerial.write((byte)0);mySerial.write((int)156); mySerial.write((int)1);mySerial.write((int)144); mySerial.write(137);mySerial.write((byte)0);mySerial.write((byte)0); mySerial.write((byte)0);mySerial.write((byte)0);mySerial.write(153); break; // music 5 case 11: mySerial.write(141) ;mySerial.write(5); break; case 13: mySerial.write(152);mySerial.write(17) ;mySerial.write(137); mySerial.write(1);mySerial.write(44) ;mySerial.write(128); mySerial.write((byte)O);mySerial.write((int)156); mySerial.write((int)l);mySerial.write((int)144);
476 Часть IV. Практика разработки проектов для Arduino mySerial.write (137) ;mySerial.write (1) ;mySerial.write (44) ; mySerial.write ( (byte)O);mySerial.write (1);mySerial.write ((int)157); mySerial.write ((byte)O) ;mySerial.write (90) ; mySerial.write (153) /mySerial.write (153) ; break; default: break; // отправка команд для движения робота void go_irobot (int vl,int rl) { int v2,r2,lfl,rtl; if(vl<128 && rl<128) {Ifl=vl+abs(rl-128)/2;rtl=max(0,vl-abs(rl-128)/2);} else if(vl<128 && rl>=128) {Ifl=max(0,vl-abs(rl-128)/2);rtl=vl+abs(rl-128)/2;} else if(vl>=128 && rl<128) {Ifl=vl-abs(rl-128)/2;rtl=*nin(255, vl+abs(rl-128)/2);} else if(vl>=128 && rl>=128) {lfl=min(255,vl+abs(rl-128)/2);rtl=vl-abs(rl-128)/2;} else ; lfl=map(lfl,0,255,250,-250); rtl=map(rtl,0,255,250,-250); mySerial.write(145); mySerial.write(highByte(rtl));mySerial.write(lowByte(rtl)); mySerial.write(highByte(If1));mySerial.write(lowByte(If1)); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\22\_22_06 сопрово- ждающего книгу электронного архива (см. приложение 2). Для загрузки скетча в плату Arduino предварительно скопируйте его на своем компьютере в папку libraries\USB_Host\examples, откройте в Arduino IDE и нажмите на кнопку Загрузить.
ГЛАВА 23 ©0 Камера Pixy: организация компьютерного зрения Камера Pixy (рис. 23.1) — это популярная система машинного зрения для Arduino и Raspberry Pi. В отличие от большинства камер, Pixy выполняет обработку изобра- жения на своем борту, освобождая мощности микроконтроллера для других задач. Встроенные в его прошивку алгоритмы способны обнаруживать и отслеживать множество объектов одновременно. Рис. 23.1. Камера PixyCam В частности, для обнаружения объектов Pixy использует алгоритм цветовой фильт- рации на основе оттенков. Поэтому объект должен иметь четкий цветовой оттенок. Камера может одновременно распознавать объекты семи цветовых оттенков, кото- рые можно запрограммировать. Обмен данными с микроконтроллерами осуществ- ляется по одному из интерфейсов I2C, SPI, UART или через аналоговые выходы. Pixy может находить сотни объектов за кадр. Она использует алгоритм связанных компонентов, чтобы определить, где один объект начинается, а другой заканчива-
478 Часть IV. Практика разработки проектов для Arduino ется. Затем Pixy компилирует размеры и местоположение каждого объекта и пере- дает их через один из своих интерфейсов (например, SPI). 23.1. Настройка камеры В качестве утилиты настройки для Pixy используется PixyMon — она работает как в ОС Windows, так и в Mac OS и в Linux. Версию для Windows можно скачать по ссылке: http://cmucam.Org/attachnients/download/1246/pixymonwindows-2.0.9.exe. Скачав и установив утилиту PixyMon, подсоединим камеру Pixy к компьютеру с помощью USB-кабеля и запустим утилиту. Для настройки камеры на определенные цвета выбираем в меню пункт Action | Set Signature<X>... и на изображении выделяем с помощью мыши участок нужного цвета. Так же поступаем и для настройки камеры на следующие шесть сигнатур. После этого на экране видим выделение объектов для всех настроенных сигнатур (рис. 23.2). response: 0 (0x0) > ос setSgRegion Q 3 HINTdREGl) region (user-selected region}? (select region with mouse) 50 73 68 74 Signature set! response: 0 (0x0) >runprogArg81 response: 0(0x0) Рис. 23.2. Определение объектов запрограммированных сигнатур в утилите PixyMon
Глава 23. Камера Pixy: организация компьютерного зрения 479 Рис. 23.3. Тонкая настройка сигнатур в программе PixyMon Для каждой сигнатуры в меню File | Configure можно установить и более тонкие настройки ( рис. 23.3). 23.2. Подключение камеры Pixy к плате Arduino Подключение камеры Pixy к плате Arduino выполняется с помощью входящего в комплект камеры переходника, который подсоединяется к контактам ISCP платы Arduino (рис. 23.4). Общение камеры с платой Arduino при этом осуществляется по интерфейсу SPI. Для программирования камеры используется библиотека Pixy. Установим библио- теку в Arduino IDE и запустим из этой библиотеки пример hello_world. Как можно видеть, в монитор последовательного порта с камеры Pixy выводятся данные об обнаруженных объектах (рис. 23.5). Электронный архив Библиотека Pixy размещена в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2).
480 Часть tV. Практика разработки проектов для Arduino Рис. 23.4. Подключение камеры Pixy к плате Arduino Рис. 23.5. Вывод в монитор последовательного порта данных, приходящих в Arduino с камеры Pixy
Глава 23. Камера Pixy: организация компьютерного зрения 481 23.3. Организация слежения камерой за объектом В этом проекте мы организуем слежение камерой Pixy, укрепленной на подвесе из двух сервоприводов, за объектом определенного цвета. Система ищет объект с цве- том заданной сигнатуры и с максимальными размерами, определяет удаление его центра от центра камеры и дает команды на сервомоторы для смещения подвеса. Монтажная схема этого проекта представлена на рис. 23.6, а содержимое скетча, обеспечивающего ее работу, — в листинге 23.1. Загружаем скетч в плату Arduino и проверяем работу системы. fritzmg Рис. 23.6. Монтажная схема подключения к плате Arduino камеры Pixy, укрепленной на подвесе из двух сервоприводов // подключение библиотек ttinclude <SPI.h> #include <Pixy.h> #include <Servo.h> // создание объектов Pixy pixy; Servo servoX; Servo servoY;
482 Часть IV. Практика разработки проектов для Arduino void setup() { Serial.begin(9600); Serial.print("Starting..An"); servoX.attach(9); servoY.attach(10); // запуск pixy pixy.init(); } void loopO { static int i = 0; int j; uintl6_t blocks; char buf[32]; // получить данные с камеры blocks = pixy.getBlocks(); // если блоки найдены if (blocks) // анализируем 1 из каждых 50 кадров if (i%50=0) { sprintf(buf, "Detected %d:\n", blocks); Serial.print(buf); for (j=0; j<blocks; sprintf(buf, " block %d: ", j); // если объект сигнатуры 1 int maxlength=0; int maxlengthx=0; int maxlengthy=0; int centerx=0; int centery=0; if(pixy.blocks[j].signature==l) { Serial.print(pixy.blocks[j].signature);Serial.print(" "); Serial.print(pixy.blocks[j 3.x);Serial.print(" "); Serial.print(pixy.blocks[j].у);Serial.print(" "); Serial.print(pixy.blocks[j].width);Serial.print(" "); Serial.print(pixy.blocks[j].height);Serial.printIn(" "); // вычисляем максиьлальный объект if(maxlength<pixy.blocks[j].width I I maxlength<pixy.blocks[j].height) { mxlength=max (pixy. blocks [ j ] . width, pixy. blocks [ j 3 . height);
Глава 23. Камера Pixy: организация компьютерного зрения 483 maxlengthx=pixy.blocks[j].width; maxlengthy=pixy.blocks[j].height; centerx=pixy.blocks[j].x+pixy.blocks[j].width/2; centery=pixy.blocks[j].y+pixy.blocks[j].height/2; } // поворот сервоприводов servoX.write(map(centerx,0+50,320-50,0,180)); servoY.write(map(centery,0+50,240-50,0,180)); Электронный архив Полный вариант рассмотренного скетча находится в папке examples\23\_23J)i сопро- вождающего книгу электронного архива (см. приложение 2).
ПРИЛОЖЕНИЯ Приложение 1. Перечень использованных источников Приложение 2. Описание электронного архива
ПРИЛОЖЕНИЕ 1 Перечень использованных источников □ http://www.rlocman.ru/review/article.html?di=111906 — Дэвид Кушнер, «Как разрабатывали и продвигали Arduino», «Радиолоцман», ноябрь 2011 г.; □ http://www.arduino.ee — официальная документация проекта Arduino; □ http://www.cxein.net — авторские материалы с сайта «Паяльник»; □ http://www.playarduino.ru — авторские материалы с сайта PlayArduino; □ Петин В. А. Лекции по Arduino для школ Казахстана (будут распространяться только на DVD в школах Казахстана).
ПРИЛОЖЕНИЕ 2 Описание электронного архива Электронный архив с материалами, сопровождающими книгу, можно скачать с FTP-сервера издательства «БХВ-Петербург» по ссылке ftp://ftp.bhv.ru/ 9785977540049.zip, а также со страницы книги на сайте www.bhv.ru. В архиве находятся следующие папки: □ \examples — исходники примеров и проектов глав 7-23 для Arduino IDE; □ Mibraries — библиотеки Arduino, используемые в примерах и проектах книги и не включенные в среду разработки Arduino ЮЕ; □ \datasheets— документация производителей (data sheet) на рассматриваемые в книге микросхемы и модули.
Предметный указатель Арр lnvertor 2 393 Arduino О Due 17,26,27 О Leonardo 20,25-27,152,324 0 LilyPad23,24 0 Mega 17,24,148,152 О Mega2560 152 О Nanol7,21,22 О Pro Mini 22,23 О Unol7,20,21 О Yun20,27 В Bluetooth-модуль НС-05 260,262,266,386, 412,415 Cosmo WiFi Connect Shield 31,32 E Ethernet Shield 28,29 G GSM/GPRS Shield 31,32 H LEGO Mindstorms 329 LilyPad Arduino 17,328 321 M МАС-адрес 269,271,272,274,275,277,404 MicroSD Shield 28,30 Motor Shield 28,31 MP3 Shield 28,31 О OLED-дисплеи 196 RGB-лента 450 RGB-светодиод 117,299-301,407 RGB-светодиодная лента WS2812 408,410 Robot Operating System (ROS) 333 w Wi-Fi-модуль ESP8266 345-353 Wi-Fi/Bluetooth-модуль ESP32 346 X XBee Shield 28, 30 НЮ-интерфейс 459 НГО-устройства 457-459,462 ZIP-архив библиотеки 136
492 Предметный указатель Адаптер О USB-Serial 206 О USB-to-serial291 Амплитудная модуляция 255 Аналоговые 0 входы Arduino 45, 109 0 датчики 157 Аналоговый датчик температуры 0 LM335 158, 273, 274, 281, 282, 285, 286 0 ТМР36 367, 369, 370, 374, 375, 381, 383, 386,388,390,398,401 Аналого-цифровой преобразователь (АЦП) 46 Аппаратные UART-контроллеры 143 Аппаратура радиоуправления 253 Арифметические операторы 54 0 RCSwitch 243,419-421, 427 0 RF24 249 0 rosjib 335, 336 0 rosserial 335 0 SD412 0 sdfatlib 270 0 Serial 143 О Servo 223,234 О SoftwareSerial 152,261, 422 О USBJHost 457, 460, 462, 463,472 О Wire 172 О ZUNO_DHT361 Библиотеки Arduino 37, 38, 135 в Веб-камера 326 Вентилятор 378 Базовая структура программы для Arduino 48 Бесколлекторные двигатели 233, 234 Беспроводная передача данных 237 Беспроводной 0 геймпад Defender Scorpion RS3 472 0 интерфейс Bluetooth 260 0 радиомодуль NRF24L01 246-248,460, 463 Библиотека 0 AdafruitSSD1306 196 0 Adafruit Thermal Printer 351 0 Adafruit Unified Sensor 189 0 Adafruit_GFX_Library 191, 194 0 AdafruitNeopixel 408, 409, 412 0 BH1750FVI 174, 176 0 BMP280 187 0 DHT169,369 0 Esplora 299-301 0 Ethernet 269 0 IRRemote238 0 Keyboard 298 0 LiquidCrystal 179, 180 0 LiquidCrystal_12C 185 0 Mouse 298 0 NRF24L01 463 0 OLEDJ2C196 0 OneWirel60 0 Pixy 479 Голосовое управление 417 Графический дисплей Nokia5110 190 Д Датчик 157,158, 161 0 атмосферного давления и температуры ВМР280 187 0 влажности DHT11 361 0 влажности и температуры DHT11 248, 330,331 0 движения HC-SR501 327, 328 0 расстояния НС SR-04 225 0 температуры и влажности воздуха DHT11 367, 369, 370, 374, 375, 381, 382, 386, 388, 389, 398,400 0 точного времени 197 ■> DS3231 198 Дисплей 177, 179, 201 0 Nextion201,207,210 0 WH0802 342, 343 Драйвер двигателей 0 L293 462,469 0 L298 219,221 0 шагового двигателя А4988 228 Драйверы двигателей 219 Дребезг 103,104 Дробление шага шагового двигателя 230
Предметный указатель 493 Ж Жидкокристаллические дисплеи 177 ЖК-дисплей Nokia5110 372,373,377 ЖК-индикаторы 196 Заголовочный файл библиотеки 139 и Игра «Змейка» 301 Издатель (publisher) 335,336,340,341 ИК-приемник 237,238,240,241 ИК-приемопередатчик 237 ИК-пульт237,240 Интернет вещей 269,324,349,397 Интерфейс 0 I2C196 0 SPI479 0 USB455 Искусственные источники света 378 Исполнительное устройство 213 Камера Pixy 477,479-481 Клиент 455 Конвертер 12С 185 Контроллер PCD8544 190 Купюроприемник 433-437 л Логические операторы 55 Люминесцентные лампы 379 м Массимо Банци 16,17 Мембранный вакуумный насос 378 Менеджер библиотек 135,136 Микрокомпьютер Atheros AR9331 27,324 Микроконтроллер 0 32U4 291,292 0 ATmega 45 0 ATmegal68 19,21-24 0 ATmegal68V 319 0 ATmega2560 24 0 ATmega328 17,19-24,291,319 0 ATmega328V 319,322 0 ATmega32U4 25,27,298,319,324 0 ESP32 346 0 HD44780 177,179 Микросхема 0 DS3231 197,352,353 0 ESP8266 345 0 L293 462,469 0 LPD6803 407 0. МСР23017 130 0 SIM900 279 О WiznetW5100 269 О WS2801 407 О WS2811 407,409 О WS2812 407,408,409,410 Модуль О влажности почвы 368 О распознавания голоса Voice Recognition Module V2 422,423,426,430 0 часов реального времени DS3231 352 Монетоприемник 433,440,441 Монитор последовательного порта 39 Мультиплексор CD4051 131,132 н Назначение статического IP-адреса 270 Настройка контрастности 178,179 Нормально разомкнутая кнопка 99 Облачная среда разработки Arduino Create 35 Операторы сравнения 49,55 Основные АТ-команды 262 Отладочная информация Arduino 145,152 Отладочная плата NodeMCU 350,354,356 п Передатчик 0 FS1000A243 0 НК-Т6А 254,257,258 Переменные 62,82 Плата Arduino 185,192,194,196,209,211 0 Esplora 297-301,303,307,312 0 Leonardo 291,292,294,295,297,324 0 LilyPad319 0 Arduino Yun 324
494 Предметный указатель Плата LilyPad О ArduinoUSB320 О Simple Snap 321 Плата Z-Uno 356-361 Плата расширения О Arduino Yun Shield 324-326 О Ethernet Shield 269-274 О Ethernet Shield W5100 397 0 GSM/GPRS Shield 279,282,285 0 Makey TouchKeyUSB Shield 449,450 0 Relay Shield 377,379 0 USB Host Shield 456,457,460,462,472 Платформа Wiring 17 Платы расширения (шилды) 28 Подключение О библиотек 138 О русского шрифта 197 Подписчик (subscriber) 336,340 Подтягивающий резистор 99-102 Поиск устройств, подключенных к шине I2C 172 Получение IP-адреса по DHCP 270,271 Последовательный 0 интерфейс USB 455 0 порт UART 143,144,153 0 порт USB 291 Потенциометр 111,117,179 Преобразователь USB-Serial 322 Приемник 0 НК-Т6А 256,257 0 MX-RM-5V 245,246 Приложение Bluetooth Terminal 392, 393 Программа 0 AccessPort422,423,425 0 Nextion Editor 201 Программатор 291 Протокол 0 1-Wire 160,161,336 0 Bluetooth 386 0 12С 171-173,176,185,187,330 0 радиопередачи данных Z-Wave 356-358, 362 Процессор 0 Atmel SAM3X8E ARM Cortex-M3 26 0 SitaraAM1808(ARM9)329 Радиоканал 433,920 МГц 243 Радиомодули FS1000A/MX-RM-5V 419 Радиомодуль 0 передатчика FS1000A 243 0 приемника MX-RM-5V 243 Радиопередатчик FS1000A 419,420 Радиоприемник MX-RM-5V 419,420 Радиорозегки UNIEL 417,418,421 Разменный автомат (хоппер) 433,442,443 Распознавание речи 417 Реле 213,214 Робот iRobot Create 470-472 Руль Defender Forsage Drift GT 460,461 Сайт «Народный мониторинг» 272-27r4, 277-279,285, 289,397 Светодиодная лента WS2812 407 Светодиодные 0 ленты RGB 407 0 фитолампы 379 Светодиодный индикатор 120 0 D5651 120,139 Сдвиговый регистр 74НС595 124-126 Сенсор 157 Сервопривод 222,226,240 0 MG995 223 Символьные дисплеи 177,190 Скетч 37 Создание библиотек 139 Среда 0 Arduino Create 41,42,43 0 разработки Arduino 35,37 Стягивающий резистор 99,101,102 Схема с общим эмиттером 214 Твердотельные реле 215,217 Термопринтер 349,350 Типы данных 56 Узлы ROS 338 Унарные операторы 56 Управляющие операторы 49 Установка драйверов Arduino 35 Утилита PixyMon 478,479