Text
                    Виктор Петин
Arduino и
Raspberry Pi
в проектах Internet
2-е издание Of Things
Санкт-Петербург
«БХВ-Петербург»
2019


УДК 004.4 ББК 32.973.26-018.2 П29 Петин В. А. П29 Arduino и Raspberry Pi в проектах Internet of Things. — 2-е изд., перераб. и доп. — СПб.: БХВ-Петербург, 2019. — 432 с: ил. — (Электроника) ISBN 978-5-9775-3951-7 Рассмотрено создание простых устройств в рамках концепции Интернета вещей (IoT, Internet of Things) на базе популярной платформы Arduino и микро- компьютера Raspberry Pi. Описана установка и настройка среды разработки при- ложений Arduino IDE, а также среда макетирования Frizing. Раскрыты технические возможности, особенности подключения и взаимодействия различных датчиков и исполнительных устройств. Показана организация доступа устройств к сети Ин- тернет, отправка и получение ими данных с использованием популярных облач- ных IoT-сервисов: Narodmon, ThingSpeak, Xively, Weaved, Blynk, Wyliodrin и др. Уделено внимание обмену данными с помощью платы GPRS/GSM Shield. Рас- смотрен проект создания собственного сервера для сбора по сети данных с различ- ных устройств на платформе Arduino. Показано, как использовать фреймворк WeblOPi для работы с Raspberry Pi. Во втором издании добавлены Arduino-проекты со счетчиками воды и датчи- ками переменного тока, проект по созданию GPS-трекера на Arduino, проекты на платформе ThingWorx для конкурсов JuniorSkills, а также усовершенствованы про- екты на основе популярного Wi-Fi-модуля ESP8266 (метеостанция, отправка дан- ных по MQTT, Wi-Fi-пульт для квадрокоптера, печать курса валют на термоприн- тере). На сайте издательства размещен архив с исходными кодами программ и библиотек. Для интересующихся современной электроникой УДК 004.4 ББК 32.973.26-018.2 Группа подготовки издания: Руководитель проекта Евгений Рыбаков Зав. редакцией Екатерина Сависте Компьютерная верстка Ольги Сергиенко Дизайн обложки Марины Дамбиевой Подписано в печать 31.10.18. Формат 70хЮ01/16. Печать офсетная. Усл. печ. л. 34,83 Тираж 1000 экз. Заказ № 7786. "БХВ-Петербург", 191036, Санкт-Петербург, Гончарная ул., 20. Отпечатано с готового оригинал-макета ООО"Принт-М", 142300, МО., г. Чехов,ул. Полиграфистов, д. 1 ISBN 978-5-9775-3951-7 © сюо "бхв", 2019 © Оформление. ООО "БХВ-Петербург", 2019
Оглавление Глава 1. Интернет вещей (вместо введения) ♦ 9 Глава 2. Среда программирования Arduino IDE 13 2.1. Установка Arduino IDE 14 2.1.1. В ОС Windows 14 2.1.2. В ОС Linux 16 2.1.3. В Mac OS X 17 2.2. Настройка Arduino IDE 17 Глава 3. Среда разработки Fritzing 21 3.1. Загрузка и установка среды Fritzing 21 3.2. Главное окно среды Fritzing 21 3.3. Создание схемы соединений 24 3.4. Создание принципиальной схемы 25 3.5. Добавление компонентов в среду Fritzing 26 Глава 4. Arduino и аналоговые датчики 29 4.1. Аналоговые датчики (сенсоры) 29 4.2. Arduino и датчик температуры LM335 31 4.3. Arduino, Ethernet Shield/W5100 и облачные сервисы 33 4.3.1. Отправка данных на сайт «Народный мониторинг» 37 4.3.2. Чтение данных с фоторезистора 43 4.3.3. Отправка данных в сервис ThingSpeak 45 4.4. Arduino и инфракрасные датчики расстояния SHARP 53 4.4.1. Подключение датчиков Sharp к Arduino 55 4.4.2. Подсчет количества посетителей магазина 57 4.4.3. Приложение ThingTweet сервиса ThingSpeak 59 4.4.4. Отправка данных о количестве посетителей в Twitter из Arduino 61 4.5. Arduino и датчики переменного тока SCT 66 4.5.1. Подключение датчика SCT-013 Sharp к Arduino 68 4.5.2. Отправка данных в сервис ThingSpeak 71 4.6. Arduino и счетчик расхода воды 76 4.6.1. Счетчик воды Бетар СГВ-15Д 77
Оглавление 4.6.2. Подключение счетчика к плате Arduino 78 4.6.3. Отправка данных о расходе воды в «облако» 79 Глава 5. Использование Arduino в качестве контроллера исполнительных устройств 83 5.1. Arduino и электромагнитное реле 83 5.1.1. Электромагнитное реле 83 5.1.2. Устройство и принцип работы электромагнитного реле 84 5.1.3. Подключение реле к Arduino 85 5.2. Arduino и твердотельное реле 87 5.3. Arduino и диммер , 88 5.3.1. Диммер 88 5.3.2. Подключение диммера к Arduino 89 5.3.3. Скетч управления диммером 90 5.4. Arduino и сервоприводы 92 5.4.1. Принципы управления сервоприводами 93 5.4.2. Управление сервоприводом с помощью Arduino 95 5.5. Arduino и библиотека TinyWebServer 97 5.5.1. Использование файлов с SD-карты для формирования веб-страниц 98 5.5.2. Включение/выключение реле с веб-страницы 99 5.5.3. Веб-страница для управления реле 100 5.5.4. Веб-страница для управления сервоприводом 105 Глава 6. Arduino и устройства 12С 109 6.1. Обзор протокола 12С 109 6.2. Arduino и библиотека Wire 113 6.3. Arduino и датчик освещенности ВН1750 на шине 12С 116 6.4. Arduino и сервис Xively 119 6.4.1. Отправка данных в сервис Xively 122 6.4.2. Получение данных из сервиса Xively 125 6.5. Arduino и датчик влажности и температуры SHT21 на шине 12С 127 6.6. Arduino и сервис Xively (продолжение) 130 6.6.1. Отправка мультиданных в сервис Xively 130 6.6.2. Получение мультиданных из сервиса Xively 133 6.7. Arduino и часы реального времени на шине 12С 136 6.8. Arduino и SD-карта: чтение и запись данных 141 Глава 7. Arduino и 1-Wire .• 145 7.1. Технология 1-Wire 145 7.2. Применение 1-Wire 148 7.3. Интерфейс 1-Wire 149 7.3.1. Обмен информацией по шине 1-Wire 150 7.3.2. Протокол обмена информацией 1-Wire 153 7.4. Arduino и цифровой датчик температуры DS18B20 155 7.4.1. Цифровой датчик температуры DS18B20 155 7.4.2. Использование библиотеки One Wire для получения данных температуры с датчика DS18B20 158
Оглавление Глава 8. Сервер для сбора данных с Ethernet-модулей датчиков, установленных на Arduino 161 8.1. Датчики влажности DHT11 и DHT22 161 8.1.1. Подключение датчиков DHT к Arduino 163 8.1.2. Библиотека DHT 163 8.2. Модуль датчика движения HC-SR501 165 8.3. Модуль датчика звука FC-04 168 8.4. Ethernet-модуль датчиков на Arduino 169 8.5. Сервер сбора данных 173 Глава 9, Обмен данными с помощью платы GPRS/GSM Shield 177 9.1. Отправка и получение SMS-сообщений 179 9.2. Отправка данных на сайт «Народный мониторинг» 182 9.3. GPS-трекер на Arduino и GPRS/GSM Shield : 187 Глава 10. Проект Blynk: управление Arduino с планшета 193 10.1. Начало работы: тестовый пример 194 10.2. Управление с планшета исполнительными устройствами, подключенными к Arduino 202 10.3. Отправка данных из Arduino на экран планшета 205 Глава 11. IoT-платформа ThingWorx 211 11.1. Подключение к платформе ThingWorx 212 11.2. Мини-теплица на Arduino 212 11.3. Создание «вещи» в ThingWorx и задание ее свойств 218 11.4. Изменение свойств «вещи» в ThingWorx 221 11.5. Создание веб-страницы для отображения принимаемых данных 226 11.6. Отправка данных с Arduino в сервис ThingWorx 233 11.7. Создание в ThingWorx потока данных и построение графиков 239 11.8. Создание на веб-странице кнопок для отправки команд управления актуаторами на Arduino 243 11.9. Создание скетча для получения Arduino-устройством данных из ThingWorx 249 Глава 12. Микрокомпьютер Raspberry Pi 253 12.1. Технические характеристики и возможности Raspberry Pi 254 12.2. Установка операционной системы 257 12.3. Первоначальная настройка ОС Raspbian 260 12.3.1. Меню конфигурации 260 12.3.2. Настройка сетевых параметров 262 12.3.3. Настройка доступа по Wi-Fi 262 12.3.4. Подключение Зв-модема 265 12.4. Интерфейс GPIO 269 12.4.1. Управление GPIO из оболочки bash 272 12.4.2. Управление GPIO командами языка Python 272 12.5. Raspberry Pi и датчик температуры DS18B20 на шине 1-Wire 275 12.5.1. Подключение датчика DS18B20 к Raspberry Pi 275 12.5.2. Отправка данных с датчика DA18B20 в сервис «Народный мониторинг» 278 12.6. Raspberry Pi и датчик освещенности ВН1750 на шине 12С 281 12.6.1. Подключение датчика ВН1750 к Raspberry Pi 281 12.6.2. Получение ца Raspberry Pi данных с датчика ВН1750 283
Оглавление Глава 13. WeblOPi — веб-интерфейс и облако для Raspberry Pi 285 13.1. Установка WeblOPi на ОС Raspbian 285 13.2. Задание пользовательского пароля WeblOPi 287 13.3. Настройка сервера WeblOPi 288 13.4. Javascript-библиотека webiopi.js 289 13.4.1. Функции библиотеки webiopi.js 290 13.5. Проект управления веб-камерой на сервоприводах 296 13.6. WeblOPi — подключение устройств 302 13.7. Доступ к устройству из сервиса Weaved 304 13.7.1. Установка сервиса Weaved 304 13.7.2. Подключение к Raspberry Pi в сервисе Weaved 308 Глава 14. Проект Wyliodrin: управление удаленными устройствами из боаузеоа • 311 14.1. Добавление устройства в профиль 312 14.2. Запись образа Wyliodrin на SD-карту 313 14.2.1. ...в ОС Windows 314 14.2.2. ...в ОС Linux 315 14.2.3. ...в Mac OS 316 14.2.4. ...в ОС Raspbian 316 14.3. Запись на SD-карту настроек Wyliodrin 316 14.4. Подключение Raspberry Pi к Wyliodrin 317 14.5. Создание приложения в графической среде программирования 319 14.6. Включение/выключение светодиода с веб-страницы 323 14.7. Подключение платы Arduino к сервису Wyliodrin 325 14.7.1. ...с помощью библиотеки Firmata 325 14.7.2. ...без использования библиотеки Firmata 332 14.8. Совместная работа Raspberry Pi и платы GrovePi 336 14.9. Обмен сообщениями между платами Raspberry Pi через сервис Wyliodrin 340 14.10. Отправка данных в сервис Wyliodrin с мобильного устройства , 343 Глава 15. Wi-Fi-модуль ESP8266 ......349 15.1. Режим АТ-команд 350 15.2. Отладочные платы NodeMCU 355 15.3. Прошивка NodeMCU 356 15.3.1. Запуск веб-сервера 358 15.3.2. Подключение к ESP8266 модулей датчиков средствами языка Lua 359 15.4. Arduino IDE для ESP8266 361 15.5. Подключение модулей ESP8266 к сети Интернет по Wi-Fi 364 15.6. Метеостанция на ESP8266 366 15.6.1. Подключение датчика температуры DS18B20 367 15.6.2. Подключение датчика влажности DHT22 370 15.7. Отправка данных метеостанции в сервис ThingSpeak 372 15.8. Протокол MQTT — простой протокол для Интернета вещей 378 15.9. Использование MQTT-сервера CloudMQTT 379 15.10. Мобильное приложение IoT Manager 382 15.11. Отправка данных брокеру CloudMQTT для приложения IoT Manager (тестовый пример) 384
Оглавление 15.12. Отправка данных метеостанции по MQTT в сервис CloudMQTT для приложения IoT Manager 387 15.13. Создание на модуле ESP8266 пульта для управления квадрокоптером AR.Drone2.0 392 15.13.1. Подключение модуля ESP8266 ESP-07 к квадрокоптеру по Wi-Fi 392 15.13.2. Удаленное программирование квадрокоптера AR.Drone через Wi-Fi 392 15.13.3. Получение навигационных данных от квадрокоптера AR.Drone 394 15.13.4. Отправка команд взлета и посадки 400 15.13.5. Подключение гироскопа-акселерометра MPU6050 для управления ARJDrone 2.0 402 15.14. Печать курса валют на термопринтере 405 15.14.1. Подключение термопринтера к модулю NodeMCU ESP8266 405 15.14.2. Подключение модуля DS3231 к модулю NodeMCU ESP8266 408 15.14.3. Получение XML-файла с курсом валют с сайта cbr.ru 411 15.14.4. Обработка данных курса валют и печать на принтер 413 15.15. Интернет-часы на модулях ESP8266 и ТМ1637 с синхронизацией по NTP 415 Заключение •% 421 Приложение. Описание электронного архива 423 Предметный указатель 425
ГЛАВА 1 Интернет вещей (вместо введения) Интернет вещей (Internet of Things, IoT) — это широкая сеть объектов, связанных через Интернет и способных обмениваться данными. Идея Интернета вещей впервые возникла еще в 1999 году у Кевина Эштона— ис- следователя из Массачусетского технологического института (MIT), предложивше- го тогда концепцию системы управления через Интернет промышленными объек- тами. Интернет вещей предполагает оснащение каждого устройства, будь то пыле- сос, холодильник или стиральная машина, модулем подключения к Интернету с возможностью взаимодействия его с домашним компьютером или смартфоном домовладельца. Интернет вещей — это не только множество различных приборов и датчиков, объ- единенных между собой проводными и беспроводными каналами связи и подклю- ченных к сети Интернет, а тесная интеграция реального и виртуального миров, в среде которой общение осуществляется между людьми и устройствами. Решения на базе Интернета вещей становятся сейчас все более востребованными именно потому, что дают поставщикам «умных» решений возможность получать дополцительную прибыль,— «умное» поведение может дать существенный прирост «полезности», потребительской стоимости устройства или системы. Так, вентилятор, который «сам» выключается при достижении нужной температуры, экономит владельцу электроэнергию и поэтому может стоить для него дороже. А вентилятор, который еще и «видит», когда в помещении есть люди, а когда нет, — ценен еще больше. Но как техника может стать «умной»? Во-первых, за счет, собственно, своей конст- рукции — эта конструкция может быть такой, что поведение системы будет выгля- деть разумным. Во-вторых, за счет «интеллектуализации»— оснащения системы устройствами сбора информации, ее обработки и принятия решений. Такой подход позволяет обеспечить достаточно сложное и «разумное» поведение гораздо более простыми способами, чем за счет создания соответствующей конструкции. Наконец, третий путь— поведение системы становится «разумным» вследствие того, что она взаимодействует с другими системами. Так, для экономии энергии
j/0 Глава 1 системе отопления требуется краткосрочный прогноз погоды. Этот прогноз можно получить, установив соответствующие датчики и систему обработки информации с них, способную прогнозировать погоду (мини-метеостанцию), а можно просто запросить погоду в Интернете. И в том, и в другом случае поведение системы ото- пления будет выглядеть «разумным». Важно, что в последнем примере с точки зрения заказчика система ведет себя прак- тически одинаково— соответственно, заказчик готов заплатить за эту функцио- нальность одну и ту же цену. Однако для поставщика такой системы организация подключения ее к Интернету будет стоить значительно дешевле, чем разработка интеллектуальной метеостанции. Благодаря интеллекту и коннективности у оборудования появляется новый набор функций. Их можно разделить на четыре группы: □ мониторинг; □ управление; □ оптимизация; □ автономность. Каждая функция, важная и сама по себе, оказывается своего рода ступенькой для следующего уровня. Например, функция мониторинга служит основой для управ- ления, оптимизации и автономности техники. Компания может выбирать такой на- бор функций, чтобы ее продукция была максимально полезной для потребителя, — и тем самым укреплять свою конкурентную позицию. Возьмем, к примеру, автоматическую теплицу, которая самостоятельно осуществ- ляет полив, поддержание нужной температуры, уровня освещенности и пр. Такая теплица окажется востребованной теми, кто не хочет тратить много времени на уход за растениями, а также может не иметь для этого возможности в периоды дли- тельного отсутствия: командировок, отпуска и т. п. Какую проблему клиента решит функция мониторинга? Прежде всего — устранит беспокойство насчет того, все ли в порядке с растениями во время его отсутствия: есть ли вода в системе, не выключалось ли электричество, может ли система венти- ляции обеспечить нужную температуру, если в помещении стало слишком жарко, и др. Клиент наверняка заплатит больше, если предоставить ему возможность в любой момент знать, каковы условия в его теплице. Таким образом, продажная стоимость теплицы с функцией удаленного мониторин- га параметров может возрасти существенно, в то время, как ее реализация для про- изводителя будет достаточно простой. В результате применение технологии Ин- тернета вещей позволит производителю получить дополнительную прибыль. Еще выше потребительская стоимость будет у той же теплицы, если добавить функцию управления, — чтобы пользователь мог удаленно не только получать ин- формацию об условиях в теплице, но и менять их по своему усмотрению. Наверняка в теплице подогрев включается автоматически, если температура падает ниже заданного предела, но, возможно, не стоит его включать, если знать, что по
Интернет вещей (вместо введения) 11_ прогнозу погоды совсем скоро ожидается повышение температуры? Таким обра- зом, функция оптимизации за счет использования дополнительной информации позволит сэкономить деньги на содержание теплицы и получить урожай с меньши- ми затратами. Наконец, средствами Интернета вещей несложно начать следить за количеством расходуемых материалов — к примеру, удобрений, — и автоматизировать их заказ, либо контролировать состояние элементов, требующих замены или обслуживания: насосов, вентиляторов, нагревающих элементов, организовав таким образом само- диагностику и самообслуживание теплицы вплоть до полной ее автономности. В этой книге мы познакомимся с практическими примерами создания простейших устройств для Интернета вещей на базе популярного контроллера Arduino и микро- компьютера Raspberry Pi. Чтобы Arduino и Raspberry Pi стали полноценными уст- ройствами для Интернета вещей, их необходимо оснастить датчиками и исполни- тельными устройствами и предоставить им доступ к сети Интернет. Соответствен- но, мы рассмотрим работу Arduino и Raspberry Pi с различными датчиками и устройствами, а также организацию доступа их к Сети с дальнейшей отправкой данных в известные облачные сервисы и получением их оттуда. А последняя, 15-я глава книги, посвящена использованию в качестве устройства для Интернета вещей новой, но быстро набирающей популярность платформы, — модулей Wi-Fi ESP8266. Все необходимые для работы листинги из этой книги вы найдете в сопровождаю- щем книгу электронном архиве, который можно загрузить с FTP-сервера изда- тельства «БХВ-Петербург» по ссылке: ftp://ftp.bhv.ru/9785977539517.zip или со страницы книги на сайте www.bhv.ru (см. приложение). Архив также содержит библиотеки Arduino и модуля ESP8266, используемые в примерах и проектах книги и не включенные в среду разработки Arduino IDE.
ГЛАВА 2 Среда программирования Arduino IDE Разработка собственных приложений на базе плат, совместимых с архитектурой Arduino, осуществляется в официально бесплатной среде программирования Arduino IDE. Среда предназначена для написания, компиляции и загрузки собст- венных программ в память микроконтроллера, установленного на плате Arduino- совместимого устройства. Основой среды разработки является язык Pro- cessing/Wiring — это фактически обычный C++, дополненный простыми и понят- ными функциями для управления вводом/выводом на контактах устройства. Для операционных систем Windows, Mac OS и Linux существуют свои версии среды. Скачать среду Arduino IDE можно с ее официального сайта: www.arduino.cc. Последняя версия Arduino IDE — 1.6.5 — имеет множество улучшений по сравне- нию с предыдущими. Вот далеко неполный их список: □ включена поддержка значительного количества платформ; □ организовано определение и отображение плат в меню списка портов вместе с последовательным портом; □ увеличена скорость компиляции; □ добавлено автосохранение при компиляции/загрузке скетча; □ в основу монитора последовательного порта положена современная библиотека JSSC (вместо старой RXTX), что дало возможность повысить его быстродейст- вие; □ для опций Найти/Заменить организовано несколько вкладок; □ улучшено множество библиотек Arduino IDE (String, Serial, Print и пр.); □ обновлены инструменты и компиляторы (avr-gss, arm-gss, avrdude, bossac); □ переработан интерфейс командной строки; □ добавлен вывод информации о размере скетча и использовании памяти; □ в редакторе теперь отображаются номера строк; □ меню с большим количеством строк имеют полосы прокрутки; □ организована загрузка устройства Arduino Yun через сеть;
14^ Глава 2 □ улучшен класс HardwareSerial; □ увеличены стабильность и производительность USB; □ библиотека SPI теперь поддерживает транзакции для улучшения совместимости при использовании одновременно нескольких SPI-устройств; □ появилась возможность настроить подменю с конфигурациями; □ устранены проблемы загрузки на Leonardo, Micro и Yun; □ усовершенствованы библиотеки для Arduino— в частности: Bridge, TFT, Ethernet, Robot_Control, SoftwareSerial, GSM — и устранены проблемы в их ра- боте; □ устранено множество незначительных ошибок пользовательского интерфейса. 2.1. Установка Arduino IDE 2.1.1. В ОС Windows Отправляемся на страницу http://arduino.ee/en/Maiii/Software (рис. 2.1), выбираем версию для операционной системы Windows и скачиваем соответствующий архив- ный файл. Его объем составляет чуть более 80 Мбайт и содержит все необходимое, в том числе и драйверы. По окончании загрузки распаковываем скачанный файл в удобное для себя место. Download the Axduino Software Рис. 2.1. Страница загрузки официального сайта Arduino
Среда программирования Arduino IDE t£ Для установки драйверов подключаем устройство (пусть это будет Arduino Uno) к компьютеру — на контроллере должен загореться индикатор питания (зеленый светодиод). Начавшаяся тут же попытка Windows автоматически установить драй- веры заканчивается сообщением: Программное обеспечение драйвера не было установлено. Не беда: открываем Диспетчер устройств и в составе устройств находим значок Arduino Uno — он там помечен восклицательным знаком. Щелкаем правой кнопкой мыши на этом значке и в открывшемся окне выбираем опцию Обновить драйверы и далее — Выполнить поиск драйверов на этом компьютере. Указываем путь к драйверам — ту папку на компьютере, куда распаковывали скачанный архив, — пусть это будет папка drivers каталога установки Arduino (например, C:\arduino- 1.6.5\drivers). Игнорируем все предупреждения Windows и получаем в результате сообщение: Обновление программного обеспечения для данного устройства завершено успешно. В заголовке окна будет указан и СОМ-порт, на который уста- новлено устройство. Осталось запустить среду разработки Arduino IDE (рис. 2.2). Как уже отмечалось ранее, в новой версии Arduino IDE в списке доступных портов отображается и на- звание подключенной платы Arduino. void setup() { // put your 3et void loop() { // put your mai Рис. 2.2. Среда разработки Arduino IDE: выбор порта
16 Глава 2 2.1.2. В ОС Linux В Linux Ubuntu среда Arduino ШЕ устанавливается еще проще, поскольку она на- ходится в репозитории стандартных приложений Linux. Итак, в меню Ubuntu Приложения | Центр приложений Ubuntu | Загрузить при- ложение выбираем из списка доступных программ Arduino ШЕ, затем в списке разделов выбираем Инструменты разработчика, в списке следующего уровня — Все приложения и в следующем открывшемся списке — Arduino ШЕ. В открыв- шемся окне (рис. 2.3) щелкаем левой кнопкой мыши на значке этой программы — справа от нее появляется кнопка Установить, нажимаем на эту кнопку, и среда устанавливается автоматически. Для запуска Arduino ШЕ выбираем опцию меню Приложения | Программирование | Arduino IDE. Рис. 2.3. Установка Arduino IDE из центра приложений Ubuntu Надо заметить, что при таком способе устанавливается не последняя версия про- граммы Arduino IDE. И чтобы работать именно с ее последней версией, нужно скачать со страницы загрузки официального сайта проекта Arduino (https:// www.arduino.ee/en/Main/Software) архив с версией программы для Linux (см. рис. 2.1) и распаковать его в желаемое место— например, в /home/ <user>/Arduino. Осталось для запуска программы выполнить из терминала команды: cd ~/Arduino ./arduino
Среда программирования Arduino IDE 17_ 2.1.3. В Mac OS X Для установки Arduino IDE в операционной системе Mac OS X, как и в предыду- щих случаях, скачиваем со страницы загрузки официального сайта проекта Arduino (https://www.arduino.cc/en/Main/Software) архив с версией программы для OS X (см. рис. 2.1), распаковываем его и копируем содержимое архива в папку Про- граммы — после чего значок Arduino появляется в списке программ Launchpad (рис. 2.4). Рис. 2.4. Установка Arduino IDE в OS X 2.2. Настройка Arduino IDE Среда разработки Arduino состоит из: □ редактора программного кода; □ области сообщений; □ окна вывода текста; □ панели инструментов с кнопками часто используемых команд; □ нескольких меню. Программа, написанная в среде Arduino, носит название скетч. Скетч пишется в текстовом редакторе, который имеет цветовую подсветку создаваемого про-
1J3 Глава 2 граммного кода. Во время сохранения и экспорта проекта в области сообщений по- являются пояснения и информация об ошибках. Окно вывода текста показывает сообщения Arduino, включающие полные отчеты об ошибках и другую информа- цию. Кнопки панели инструментов позволяют проверить и записать программу, создать, открыть и сохранить скетч, открыть мониторинг последовательной шины. Дополнительная функциональность может быть добавлена разрабатываемым скет- чам с помощью библиотек, представляющих собой специальным образом оформ- ленный программный код, реализующий некоторый функционал, который можно подключить к создаваемому проекту. Специализированных библиотек существует множество. Обычно библиотеки пишутся так, чтобы упростить решение той или иной задачи и скрыть от разработчика детали программно-аппаратной реализации. Среда Arduino IDE поставляется с набором стандартных библиотек: Serial, EEPROM, SPI, Wire и др. Они находятся в подкаталоге libraries каталога установки Arduino. Внутри каталога с именем библиотеки находятся файлы *.срр и *.h. Необходимые библиотеки могут быть также загружены с различных ресурсов — папка загруженной библиотеки просто копируется в каталог стандартных библио- тек (тот же самый подкаталог libraries каталога установки Arduino). Многие библио- теки снабжаются примерами, расположенными в папке examples. Если библиотека установлена правильно, то она появляется в меню Эскиз | Импорт библиотек. Вы- бор библиотеки в меню приведет к добавлению в исходный код строчки: #include <имя библиотеки.h> Эта директива подключает заголовочный файл библиотеки с описанием ее объек- тов, функций и констант, которые теперь могут быть использованы в проекте, по- скольку среда Arduino станет компилировать создаваемый проект уже вместе с ука- занной библиотекой. При загрузке скетча используется загрузчик (bootloader) Arduino — небольшая про- грамма, загружаемая в микроконтроллер на плате. Она позволяет загружать про- граммный код без использования дополнительных аппаратных средств. Работа загрузчика распознается по миганию светодиода на цифровом выводе D13. Перед загрузкой скетча требуется задать необходимые параметры в меню Инстру- менты | Плата (рис. 2.5) и Инструменты | Порт (см. рис. 2.2). Современные платформы Arduino перед загрузкой перезагружаются автоматиче-. ски. На старых же платформах для этого необходимо нажать кнопку перезагрузки. На большинстве плат во время процесса загрузки мигают светодиоды RX и ТХ. Монитор последовательного порта (Serial Monitor) отображает данные, посылаемые в платформу Arduino (плату USB или плату последовательной шины). Для отправки данных необходимо ввести в соответствующее поле текст и нажать кнопку Отпра- вить (Send) или клавишу <Enter> (рис. 2.6), после чего из выпадающего списка в правом нижнем углу окна монитора выбрать скорость передачи, соответствую- щую значению serial.begin в скетче. На Мае ОС или в Linux при подключении мониторинга последовательной шины платформа Arduino будет перезагружена (скетч начнется сначала).
Среда программирования Arduino IDE 19 void setup () { // put youc set void loop() { /7 put your mai Лпкнпй Ы, a P^o M-m Рис. 2.5. Arduino IDE: выбор платы tt+CMGF-1 Ж M+CNMI-2, 2 +СНГ: -+79034461752"*—, "15/02/20,14:58:10+12" OK м + eras • +CM6S: 22 OK Рис. 2.6. Arduino IDE: монитор последовательного порта
ГЛАВА 3 Среда разработки Fritzing Среда разработки Fritzing представляет собой инструмент разработчика с открытым исходным кодом, предназначенный для прототипирования и создания программно- го кода на базе Arduino, а также и для обучения пользователей этим процедурам. Среда работает как на Windows, так и на Mac OS и на Linux. С помощью Fritzing можно создать принципиальную схему устройства и оформить ее представление в виде соединения макетов элементов, разработать печатную пла- ту, написать код программы и загрузить его в плату Arduino. В отличие от других систем проектирования, у Fritzing простой интерфейс, который делает разработку электронных схем интуитивно понятной. 3.1. Загрузка и установка среды Fritzing Для установки среды разработки Fritzing перейдите на страницу ее загрузки (http://fritzing.org/download/?donation=0) и выберите свою операционную систему (рис. 3.1). На момент подготовки этой книги актуальна версия среды 0.9.2Ь. Для установки программы на компьютер следуйте инструкциям, приведенным на стра- нице загрузки. 3.2. Главное окно среды Fritzing В первый раз открыв среду разработки Fritzing, вы увидите окно, изображенное на рис. 3.2. Для разработки схемы соединения элементов разрабатываемого нами проекта пере- ключимся на вкладку Макетная плата (рис. 3.3). В правой части окна находятся панели инструментов со всеми элементами и оп- циями. Они содержат как основные компоненты: провода, кнопки, резисторы и пр., так и различные специализированные компоненты — например, платы Arduino и датчики. Если компонент настраивается, то в панели инструментов Инспектор отображают- ся настраиваемые параметры для этого компонента (рис. 3.4).
22 Глава 3 Рис. 3.1. Страница зафузки Fritzing Рис. 3.2. Окно программы Fritzing
Среда разработки Fritzing 23 ^Mgfigy "1*ГН H Рис. 3.3. Вкладка Макетная плата 4.^79 л -0S& Г: Г! '" Рис. З.4. Панель Инспектор для настройки параметров компонента
24 Глава 3 3.3. Создание схемы соединений В качестве примера соберем небольшую схему, в которой к выводу 13 платы Arduino Uno будет подключен светодиод. Для этого добавим на вкладку Макетная плата следующие элементы: Arduino Uno, светодиод и резистор. Резистор перетащим на макетную плату так, чтобы каждый его вывод попал на от- дельный столбец на плате. При этом, когда компонент подключается к тому или иному отверстию макетной платы, весь столбец отверстий становится светло- зеленым, а зеленая линия указывает на электрическое соединение между отвер- стиями. В свойствах компонента на панели Инспектор выберем номинал резисто- ра: 220 Ом. Затем поместим на плату светодиод. Здесь так же, как и на реальной макетной пла- те, мы можем добавлять провода, чтобы подключать необходимые нам элементы: для добавления провода наведите курсор мыши на отверстие на макетной плате (оно подсвечивается синим— это означает, что можно начинать вести провод), щелкните на нем левой кнопкой мыши и, не отпуская кнопки, перетащите второй конец провода в требуемую точку. Добавив таким образом необходимые провода, мы получим схему, представленную на рис. 3.5. Чтобы использовать ее в дальней- шем, необходимо сохранить ее в нужном формате (командой меню Файл | Экс- порт). ш. Рис. 3.5. Схема подключения светодиода к выводу 13 Arduino Uno
Среда разработки Fntzing 3.4. Создание принципиальной схемы В предыдущем разделе мы рассмотрели создание схемы соединений. Теперь созда- дим на основе этой схемы (см. рис. 3.5) принципиальную схему устройства, для чего переключимся на вкладку Принципиальная схема (рис. 3.6). j Ш Рис. 3.6. Вкладка Принципиальная схема для нашей схемы соединений: исходное состояние Как можно видеть, среда Fritzing создала все необходимые соединения, надо только привести их к более опрятному виду. Для этого в меню Fritzing выбираем команду Вид | Подогнать окно — чтобы автоматически сцентрировать и отмасштабировать схему на рабочем поле. Затем, перетаскивая и поворачивая компоненты, постара- емся добиться того, чтобы проводники не пересекались, или же количество таких пересечений стало минимальным (рис. 3.7). После этого в левом нижнем углу окна среды Fritzing нажимаем кнопку Автотрас- сировка, и схема приводится в порядок. Теперь ее можно сохранить для публика- ции в удобном формате (командой меню Файл | Экспорт).
26 Глава 3 Рис. 3.7. Вкладка Принципиальная схема для нашей схемы соединений: состояние после необходимой корректировки 3.5. Добавление компонентов в среду Fritzing Панели инструментов в правой части окна Fritzing содержат библиотеки уже имеющихся распространенных элементов, а также некоторые модули ряда произ- водителей. Все это мы можем использовать сразу после установки Fritzing. Но рано или поздно возникает необходимость добавить какой-либо компонент или шилд, с которым мы планируем работать далее. Как же добавить новый компонент в биб- лиотеку Fritzing? Вы можете создать собственный компонент с нуля или найти готовые компоненты на просторах Интернета. Большое количество таких компонентов собрано на рус- скоязычном ресурсе «Роботоша» по адресу: http://robotosha.ru/arduino/fritzing- library.html (рис. 3.8). Скачаем оттуда какой-нибудь компонент— например, 16-кнопочную клавиатуру (файл KEYPAD 4x4.fepz) и добавим ее в библиотеку Fritzing. Итак, выбираем раздел, в который мы собираемся добавить новый компонент, — пусть это будет, например: MINE | My Parts (Мои компоненты). Щелкаем правой кнопкой мыши, выбираем пункт Import и в открывшемся окне выбираем скачан-
Среда разработки Fritzing 27 Рис. 3.8. Компоненты для Fritzing на сайте «Роботоша» :mmr Рис. 3.9. Компонент добавлен в раздел MINE
28 Глава 3 ный на свой компьютер файл компонента с расширением fepz, fbz или febz — ком- понент появится в нашей библиотеке (рис. 3.9). Теперь щелкнем правой кнопкой мыши на разделе MINE и выберем команду SaveBin — чтобы иметь возможность задействовать новый компонент и в после- дующих сессиях работы с Fritzing. Если этого не сделать сразу, то при выходе из Fritzing программа еще раз предложит вам сохранить изменения. Вот, пожалуй, и все — мы рассмотрели основные возможности программы Fritzing, которые пригодятся нам при дальнейшей работе с этой книгой.
ГЛАВА 4 Arduino и аналоговые датчики 4.1. Аналоговые датчики (сенсоры) Датчик (сенсор)— это устройство, с помощью которого мы измеряем значение какого-либо технологического параметра. Датчики позволяют определять, что про- исходит во внешней среде, и действовать на основе этой информации, — их, на- верное, можно назвать органами чувств системы. Любой датчик состоит из чувст- вительного элемента и преобразовательного устройства, выполняющего преобра- зование входного воздействия на датчик любой физической величины в сигнал, удобный для дальнейшего использования. Самый простой тип датчиков — аналоговые датчики (первичные преобразователи), применяемые в системах непрерывного измерения и регулирования. Принцип дей- ствия аналоговых датчиков состоит в том, что в зависимости от изменения изме- ряемого параметра происходит соответствующее изменение их выходного сигнала. При этом выходное напряжение датчика может принимать значение от О В до напряжения его питания. Впрочем, обычно рабочий диапазон напряжений аналого- вых датчиков более узкий. Примерами таких датчиков могут служить: □ акселерометры— для обнаружения наклона (используются в смартфонах и планшетах); □ магнитометры — для обнаружения магнитных полей (используются при созда- нии цифровых компасов); О инфракрасные датчики — для определения расстояния до объекта; □ датчики температуры — для определения температуры; □ фоторезисторы — для измерения освещенности. Между измеряемой величиной датчиков и возвращаемым напряжением установле- на определенная зависимость. Например, чем больше величина, тем больше напря- жение. Или, наоборот, — чем больше величина, тем напряжение меньше. Так, ин- фракрасный датчик расстояния Sharp GP2Y0A02YK измеряет расстояние от себя до объекта — и чем меньше расстояние, тем больше напряжение. Если объект нахо-
30 Глава 4 дится на расстоянии 20 см, сенсор выдает на сигнальном проводе примерно 2,5 В. На расстоянии 60 см— примерно 1 В, а на расстоянии 150 см— примерно 0,4 В (рис. 4.1). Иногда зависимость более сложная: напряжение растет до определенного значения, затем падает пропорционально ему. Здесь все зависит от конкретного датчика. 2.5 L5 г \ \ \ — White Refleclivily:90% .... Gray Reflectivity: 18% \ 0.5 °0 10 20 30 40 50 60 70 80 90 100110120(30140150 Distance to reflective object L (cm) Рис. 4.1. Диаграмма зависимости выходного напряжения от расстояния для датчика Sharp GP2Y0A02YK Диаграммы для других аналоговых датчиков можно найти в документации на них или получить экспериментально. Преимуществом сенсоров с аналоговым сигналом является крайняя простота их использования с Arduino. А главный недостаток аналогового сигнала — неустойчи- вость к внешним шумам: если провод от сенсора до микроконтроллера будет дос- таточно длинным, он начнет работать как антенна и улавливать внешние электро- магнитные поля, — т. е. провод сам станет влиять на выходное напряжение и тем самым искажать показания датчика. Поэтому разумный предел длины провода для аналогового сенсора — не более 50 см. Аналого-цифровые преобразователи (АЦП) Датчики, выдающие аналоговый сигнал (напряжение), оцифровываются в управляю- щей программе с помощью аналого-цифровых преобразователей (АЦП). Микрокон- троллеры Atmega, используемые в Arduino, содержат шестиканальный АЦП. Разре- шение такого преобразователя составляет 10 битов, что позволяет на выходе полу- чать значения от 0 до 1023. Различные платы Arduino имеют разные количества аналоговых входов. Например, платы UNO и Duemilanovo имеют 6 аналоговых входов, Nano— 8, Yin— 12, Mega — 16. Основным применением аналоговых входов большинства платформ Arduino явля-
Arduino и аналоговые датчики 31_ ется чтение показаний аналоговых датчиков, для чего в Arduino существует стандарт- ная функция anaiogReadO. Вот пример чтения данных с аналогового входа АО: int valuel^analogRead(АО); Диапазон входного напряжения от 0 до 5 В в программе проецируется на диапазон целочисленных значений от 0 до 1023. Для масштабирования значения к другим зна- чениям можно использовать функцию шар (): int value2=map(value 1,0,1024,min,max); 4.2. Arduino и датчик температуры LM335 Познакомимся с работой аналоговых датчиков температуры на примере датчика LM335 (рис. 4.2) — недорогого температурного чувствительного элемента с диапа- зоном от -40 до +100 °С и с точностью в 1 °С. LM335 Рис. 4.2. Датчик температуры LM335 Рис. 4.3. Типовая схема включения датчика LM335 По принципу действия датчик LM335 представляет собой стабилитрон, у которого напряжение стабилизации зависит от температуры, — при повышении температу- ры на один градус Кельвина напряжение стабилизации увеличивается на 10 милли- вольт. Типовая схема включения датчика (соответствует типовой схеме включения стабилитрона) показана на рис. 4.3 (номинал резистора R1 равен 2,2 кОм). При взгляде на эту типовую схему сразу возникает вопрос о напряжении питания (V+), подаваемом на датчик с учетом указанного номинала резистора R1. Ответ со- держится в технической документации на датчик (Datasheet), где сказано, что нор- мальная работа изделия гарантируется в диапазоне токов 0,45-5,00 миллиампер. Следует заметить, что предел в 5 мА превышать не следует, поскольку датчик ста- нет перегреваться и измерять собственную температуру. Согласно Datasheet датчик проградуирован в абсолютной шкале Кельвина. При температуре -273,15 °С (это абсолютный ноль по Кельвину) рассматриваемый дат- чик должен показать и нулевое напряжение. А при увеличении температуры на каждый градус выходное напряжение стабилитрона станет возрастать на целых 10 мВ, или на 0,010 В.
32 Глава 4 Температура 25 °С — единственная точка калибровки датчика. При этой темпера- туре на выходе датчика должно присутствовать напряжение 298Д 5 х 0,010 = = 2,9815 В. Для калибровки датчика используется схема, представленная на рис. 4.4. V+ JL R1 LM13S LM23S LM335 ~ Выход Т ЮмВЛК 10 кОм* * Калиброван для 2,982 В при 25°С Рис. 4.4. Схема калибровки датчика LM335 Итак, подключаем датчик температуры LM335 по схеме, представленной на рис. 4.5, и пишем скетч считывания данных с датчика и вывода показаний в после- довательный порт (листинг 4.1). Вывод результатов измерения данных датчиком LM335 в последовательный порт показан на рис. 4.6. Рис. 4.5. Схема подключения датчика LM335 к Arduino int lm335=0; // подключение датчика к аналоговому входу АО void setup() { Serial.begin(9600);
Arduino и аналоговые датчики 33^ void loop () Ч double val = analogRead(lm335); // чтение double voltage = val*5.0/1024; // перевод в значение в вольтах double temp = voltage*100 - 273.15; // перевод в градусы Цельсия Serial.print(" temp = "); Serial.println(temp); delay(1000); temp . temp > temp . temp . temp • temp • temp . temp . temp . temp . temp > te«p > te«p • tenp > temp > teep . tup - tenp < teap . tenp ■ temp • teap • tetp • temp > teap > teep > temp tenp tenp • 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 Рис. 4.6. Вывод результатов измерения данных датчиком LM335 в последовательный порт 4.3. Arduino, Ethernet Shield/W5100 и облачные сервисы Реализуя концепцию Интернета вещей, согласно которой доступ к данным датчи- ков должен быть обеспечен из любой точки мира, давайте сейчас организуем от- правку данных из Arduino в облачные сервисы, для чего необходимо предоставить плате Arduino доступ к сети Интернет. Самый распространенный способ предоставления такого доступа — использование платы Ethernet Shield (рис. 4.7)— платы расширения, которая состыковывается с платой Arduino посредством сопряженных разъемов и дает ей возможность, вы-
34 Глава 4 ступая в роли сетевого устройства, общаться по проводной сети с аналогичными устройствами, с обычными компьютерами, принтерами, сервисами в Интернете И прочими сетевыми ресурсами. Рис. 4.7. Плата Ethernet Shield Rev3 Плата Ethernet Shield Плата Ethernet Shield основана на чипе Wiznet W5100, который поддерживает как TCP-, так и UDP-протоколы. Одновременно открытыми могут быть до четырех под- ключений. Плата обладает стандартным Ethernet-портом для подключения к сети с помощью патч-корда «витая пара» и набором контактов для сопряжения с Arduino. Для общения между собой Ethernet Shield и Arduino задействуют контакты 4-й и с 10-го по 13-й, по- этому их использование в других целях в присутствии платы расширения невозможно. Для программирования сетевого взаимодействия служит библиотека Ethernet из стан- дартного дистрибутива. При использовании этой библиотеки необходимо указывать МАС-адрес платы (уникальный идентификатор любого сетевого устройства). В более новых версиях платы Ethernet Shield ее МАС-адрес можно найти на наклейке на плате. Если такой наклейки нет, то просто введите любую подходящую цифробуквенную комбинацию, — главное, чтобы в вашей сети не было устройств с совпадающими МАС-адресами. Плата Ethernet Shield также оборудована слотом для карты памяти формата MicroSD, на которой можно хранить ресурсы, раздаваемые по сети. Для взаимодействия с SD-кар- той может быть использована библиотека sdfatlib. Последняя версия платы Ethernet Shield Rev3 полностью совместима с Arduino Mega2560.
Arduino и аналоговые датчики Итак, с учетом сказанного, для отправки данных в облачные сервисы мы задейст- вуем плату Arduino с подключенной к ней платой Ethernet Shield, выступающей в качестве веб-клиента, и создадим на этой основе простой пример получения на- шим устройством IP-адреса по DHCP. Подключается Ethernet Shield к плате Arduino так же просто, как и любой другой шилд, — просто состыкуйте их вместе. Соединив Ethernet Shield с платой Arduino, подключим плату Arduino к USB-порту компьютера, а к Ethernet Shield подсоединим сетевой кабель (рис. 4.8). Совет Следует учесть, что установка других шилдов поверх Ethernet Shield весьма затрудни- тельна. Это связано с большими размерами разъема RJ-45, служащего для подклю- чения сетевого кабеля, поэтому если вы хотите использовать другие шилды, то лучше их размещать между Arduino и Ethernet Shield. Рис. 4.8. Соединение плат Ethernet Shield Rev3 и Arduino Пример получения ЕР-адреса по DHCP представлен в листинге 4.2. // Получение IP-адреса по DHCP // МАС-адрес Ethernet Shield (можно увидеть на наклейке на плате) или // произвольный, но уникальный в сети #include <Ethernet.h> #include <SPI.h> byte mac[] = {0x00, OxAA, OxBB, OxCC, OxDE, 0x02}; void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); } // запуск Ethernet-соединения if (Ethernet.begin(mac) ==0) {
jg Глава 4 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() {;} Пример назначения статического ЕР-адреса представлен в листинге 4.3. // Получение статического IP-адреса // МАС-адрес Ethernet Shield (можно увидеть на наклейке на плате) или // произвольный, но уникальный в сети #include <Ethernet.h> #include <SPI.h> byte mac[] = {0x00, OxAA, 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(1000); Serial.println(Ethernet.locallP()); } void loop() {;} Получив доступ в Интернет, можно отправлять данные с платы Arduino в облачные сервисы. В следующем разделе мы рассмотрим пример такой отправки данных — на сайт «Народный мониторинг».
Arduino и аналоговые датчики 37_ 4.3.1. Отправка данных на сайт «Народный мониторинг» Сайт «Народный мониторинг» (http://www.narodrnon.ru)— проект по сбору и отображению на карте мира показаний температуры, давления, влажности и т. п. практически в реальном времени по фактическому их состоянию (а не на основе прогнозов) от различных датчиков среды, установленных как на улице для публич- ного доступа, так и в помещении для приватного, а также с веб-камер для частного или публичного доступа. Передавать показания датчиков на сайт narodmon.ru можно посредством протоколов TCP/UDP или HTTP GET/POST. Минимальный интервал передачи показаний датчика— 5 минут (если передавать чаще, то воз- можна блокировка). Чтобы стать участником проекта, необходимо зарегистрироваться: заходим на сайт http://www.narodmon.ru, выбираем команду меню Вход | Стать участником про- екта и в открывшуюся форму (рис. 4.9) вводим адрес электронной почты, куда будут нам отправлены логин и пароль для входа в профиль. Рис. 4.9. Регистрация на сайте «Народный мониторинг» Теперь настроим передачу и отображение показаний нашего, подключенного к Arduino, датчика температуры LM335 (см. разд. 4.2). Для добавления датчика на карту необходимо выполнить следующие действия: 1. Подключить устройство мониторинга (в нашем случае Arduino) к источнику питания и к сети Интернет (с помощью платы Ethernet Shield). 2. Настроить передачу показаний на сайт narodmon.ru с интервалом 5-15 минут (напомню, если чаще, то возможна блокировка).
38 Глава 4 3. Авторизоваться на сайте narodmon.ru, используя свой логин (e-mail или номер мобильного телефона) и пароль, полученные при регистрации. 4. В разделе Мои Датчики добавить устройство, введя его уникальный алфавитно- цифровой код (МАС-адрес). Добавление возможно только после успешной передачи показаний на сервер и верно указанного МАС-адреса. 5. Выбрать тип данных нашего датчика: температура. Если у нас подключены к Arduino еще несколько датчиков: влажности, давления и др., то выбираем все актуальные. 6. Установить доступ к показаниям для каждого датчика: публичный (виден всем) или приватный (только вам). 7. Указать названия для устройства и подключенных к нему датчиков. 8. Выполнить привязку к карте устройства мониторинга, указав полный адрес его размещения или геокоординаты, щелкнув для этого по строке с адресом в поле Устройство раздела Мои Датчики. 9. Уточнить свое местоположение, переместив маркер своего устройства на карте и щелкнув на опции Переместить в его всплывающем окне. Что ж, приступим к реализации перечисленных действий. И прежде всего подклю- чим датчик температуры LM335 к плате Arduino с Ethernet Shield (рис. 4.10). Рис. 4.10. Схема подключения датчика температуры LM335 к плате Arduino, состыкованной с Ethernet Shield/W5100 Далее загрузим на плату Arduino рекомендованный пример подключения к сервису narodmon.ru от student-proger.ru, изменив его под свои требования (сетевые параметры и датчики). Содержимое скетча представлено в листинге 4.4. #include <SPI.h> #include <Ethernet.h>
Arduino и аналоговые датчики 39 byte mac[] = { 0x94, OxDE, 0x80, ОхЗА, 0x90, OxC9 }; // МАС-адрес Arduino const unsigned long postinglnterval = 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 }; IPAddress server(94,19,113,221); // IP-адрес сервера //IPAddress server(91,122,49,168); // IP-адрес сервера EthernetClient client; unsigned long lastConnectionTime =0; // время последней передачи данных boolean lastConnected = false; // состояние подключения char replyBuffer[160]; void setup() { Serial.begin(9600); // Ethernet connection: Ethernet.begin(mac,ip,sdns,gateway,subnet); // секунда для инициализации Ethernet delay(1000); // первое соединение через 15 секунд после запуска lastConnectionTime = millis()-postingInterval+15000; void loop () { // если не подключены, и прошло определенное время, то делаем* замер, // переподключаемся и отправляем данные if (!client.connected() && (millis() - lastConnectionTime > postinglnterval)) { // формирование HTTP-запроса memset(replyBuffer, 0, sizeof(replyBuffer)); strcpy(replyBuffer,"ID="); // конвертируем МАС-адрес 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) + »0f;
40 Глава 4 if (Ь2>9) c2[0]=(char)(b2-10)+'Af; else c2[0] = (char)(b2) + '0'; cl[l]=l\Ol; c2[l]='\0'; strcat(replyBuffer, cl); strcat(replyBuffer,c2); } strcat(replyBuffer,"&"); strcat(replyBuffer,"3351C4BA0200003B"); strcat(replyBuffer,"="); 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,'\0•); // отправляем запрос 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.printIn("Host: narodmon.ru"); client.print-In("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)
Arduino и аналоговые датчики41 int i-0; do } while (buf[i]!='\0f); return i; } // функция int to string void itos(int n, char bufp[3]) // { char buf[3] = {'0\ f0\f\0'}; int i - 1; while (n > 0) { buf[i] - (n % 10)+48; i—; n /- 10; } for (i-0; i<3; bufp[i]-buf[i]; Для передачи данных на сайт «Народный мониторинг» мы используем резервный протокол передачи 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(кол-во байт в строке данных ниже)\г\п \г\п ID=MAC&macl=valuel&.. .&macN=valueN[&time=UnixTime] [&name=NAME] [&lat=LAT] [&lng=L NG] Скетч запускает Ethernet-соединение, плата получает IP-адрес в Сети, один раз в 5 минут считываются данные с датчика температуры, формируется строка с дан- ными для отправки на сервер «Народный мониторинг», и данные отправляются с использованием протокола HTTP POST. Электронный архив Скетч, соответствующий листингу 4.4, можно найти в файле arduino_scetches\_04\ _04_04.ino сопровождающего книгу электронного архива (см. приложение). Теперь авторизуемся на сайте, используя логин и пароль, пришедшие на нашу электронную почту, выбираем команду меню Датчики | Мои Датчики | Добавить устройство и вводим МАС-адрес нашего устройства. Если данные уже были от- правлены на сайт, устройство будет добавлено (рис. 4.11).
42 Глава 4 Рис. 4.11. Добавление устройства на сайте «Народный мониторинг» Затем выбираем тип данных для нашего датчика (температура), устанавливаем доступ к показаниям (приватный), указываем название устройства и выполняем привязку к карте устройства мониторинга, указав полный адрес щелчком на строке с адресом. После чего выбираем опцию показать на карте (см. рис, 4.11) и, в слу- чае необходимости, корректируем положение на карте с помощью плавающего меню (рис. 4.12). Рис. 4.12. Добавление устройства на карту сайта «Народный мониторинг»
Arduino и аналоговые датчики 43 Через некоторое время мы можем посмотреть временной график изменения данных датчика на нашем устройстве. Для этого выбираем команду меню Профиль | Мои Датчики и значок графика для выбранного датчика. На графике (рис. 4.13) пред- ставлено изменение переданных данных датчика во времени. 19 18 17 16 15 14 13 12 i /V h 08:00 09:00 10:00 11:00 12:00 13:00 14:00 15:00 Рис. 4.13. Временной график переданных показаний на сайте «Народный мониторинг» 4.3.2. Чтение данных с фоторезистора Рассмотрим теперь еще один аналоговый датчик— фоторезистор (рис. 4.14). Чаще всего с помощью фоторезисторов осуществляют измерение освещенности. Дело в том, что в темноте сопротивление фоторезистора весьма велико, но когда на него попадает свет, это сопротивление падает пропорционально освещенности. Для схемы измерения освещенности (рис. 4.15) необходимо собрать делитель на- пряжения, в котором верхнее плечо будет представлено фоторезистором, а ниж- Рис. 4.14. Фоторезистор
44 Глава 4 Рис. 4.15. Графическая схема подключения фоторезистора к Arduino нее — обычным резистором достаточно большого номинала (мы применим здесь резистор 10 кОм). Среднее же плечо делителя подключается к аналоговому входу АО Arduino. Скетч, который измеряет напряжение на аналоговом входе и отправляет его в по- следовательный порт, представлен в листинге 4.5. // Получение данных с фоторезистора и отправка в последовательный порт int light; void setup() { Serial.begin(9600) ; void loopO { light = analogRead(O); Serial.printIn(light); delay(100);
Arduino и аналоговые датчики 45 При уменьшении освещенности фоторезистора (можно просто затенить его рукой) сопротивление его будет возрастать, что приведет к уменьшению напряжения на аналоговом входе. 4.3.3. Отправка данных в сервис ThingSpeak Сервис ThingSpeak (https://thingspeak.com)— открытая платформа данных для проектов Internet of Things, включающая в себя сбор данных с датчиков в реальном времени, обработку этих данных, их визуализацию и использование в приложениях и плагинах. Чтобы начать работу с сервисом ThingSpeak, необходимо зарегистрироваться, нажав на кнопку GetStarted Now в стартовом окне сервиса. В открывшемся окне регистрации заполняем требуемые поля формы (рис. 4.16), нажимаем на кнопку Create Account и сразу попадаем в свой аккаунт (рис. 4.17). User 18 Email Time Zone PWMWOffl vOfiitfIIUH$Ofi vtetor.pcfcn victor.petin@gmail.com (GMT+03:00) Moscow $ j Рис. 4.16. Форма регистрации ThingSpeak Create a channel — it can be for a device, app, or anything that can «end data to • Агёиапо Tutorial ♦ NeMumo Rus Tuiona! Рис. 4.17. Успешная регистрация в сервисе ThingSpeak
4Q Глава 4 Здесь нам надо создать канал (Channel), в котором будут храниться наши данные. Каждый канал включает в себя восемь полей для любого типа данных, три поля местоположения и одно поле состояния. Таким образом, один канал мы можем использовать для отправки и хранения данных с одного устройства, имеющего не более восьми датчиков. Для создания канала нажимаем на кнопку New Channel, заполняем поля, как пока- зано на рис. 4.18, и сохраняем канал, нажав на кнопку Save Channel. Все — канал Склад создан (рис. 4.19). Как можно видеть на рис. 4.18, мы в качестве датчика задействовали в создаваемом канале фоторезистор, прописав его в поле Field 1. Рис. 4.18. Заполнение полей канала ThingSpeak Отправка данных в канал осуществляется с использованием протокола HTTP POST: URL: http://api.thingspeak.com/update Content Type: application/x-vww-form-urlencoded. Content: key=<Your API Key>&fieldl=<data fieldl> Для проверки возможности отправки данных в канал ThingSpeak мы воспользуемся дополнением Poster браузера Mozilla Firefox — удобным инструментом разработ- чика, позволяющим отправлять HTTP-запросы. На рис. 4.20 показано, как мы эмулируем отправку нескольких значений с датчика, прописанного в поле Field 1 (т. е. с фоторезистора), а рис. 4.21 демонстрирует гра- фик канала, отображающий поступившие данные.
Arduino и аналоговые датчики 47 Рис. 4.19. Канал ThingSpeak создан Рис. 4.20. Отправка данных в ThingSpeak через HTTP POST с помощью дополнения Poster браузера Mozilla Firefox
48 Глава 4 Рис. 4.21. Отображение поступивших данных на графике в канале А сейчас мы осуществим отправку в ThingSpeak данных с реальных датчиков, под- ключенных к плате Arduino, состыкованной с Ethernet Shield. Для этого подключим к ней датчик температуры LM335 и фоторезистор по схеме, приведенной на рис. 4.22, и отредактируем наш канал Склад, добавив поле Field 2 для датчика температуры LM335 (рис. 4.23). Скетч для отправки данных двух этих аналоговых датчиков в канал ThingSpeak представлен в листинге 4.6. Рис. 4.22. Схема подключения датчиков температуры и освещенности (фоторезистора) к Arduino
Arduino и аналоговые датчики Ptrtsfte? ты г Fim ffei FJ#f .«a Рис. 4.23. Добавление нового поля (Field 2) в канал Склад сервиса ThingSpeak #include <SPI.h> #include <Ethernet.h> // уникальный MAC-адрес платы Arduino byte mac[] - { 0xD4, 0x28, 0xB2, OxFF, OxAO, OxAl }; // 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 }; // ThingSpeak Settings char thingSpeakAddress[] = "api.thingspeak.com"; String writeAPIKey = "P8VDU06MDIMC3MAM"; // Интервал отправки данных на сервер - 16 сек const int updateThingSpeaklnterval = 16 * 1000; // служебные переменные long lastConnectionTime = 0; boolean lastConnected = false; int failedCounter = 0;
50 Глава 4 11 Инициализация Arduino Ethernet client EthernetClient client; void setup() { // Запуск последовательного порта Serial.begin(9600) ; // Запуск Ethernet на Arduino startEthernet(); void loopO { // Чтение данных из АО и А1 String analogValueO = String(analogRead(АО), DEC); double temp335=analogRead(Al)*5.0/1024*100-273.15; String analogValuel = String(temp335); // печать запроса в последовательный порт if (client.available()) { char с = client.read(); Serial.print(c); // Разъединение с ThingSpeak if (!client.connected() && lastConnected) { Serial.println("...disconnected"); Serial.println(); client.stop(); // отправка данных в канал ThingSpeak if(!client.connected() && (millisO - lastConnectionTime > updateThingSpeakInterval)) { updateThingSpeak("fieldl="+analogValueO+"&field2*="+analogValuel); Serial.printIn(analogValueO); Serial.println(analogValuel); } // При кол-ве неуспешных попыток >10 - перезапуск интернет-соединения if (failedCounter > 10 ) {startEthernet();} lastConnected = client.connected(); } // отправка данных в канал ThingSpeak void updateThingSpeak(String tsData)
Arduino и аналоговые датчики51 if (client.connect(thingSpeakAddress, 80)) { client.print("POST /update HTTP/1.l\n"); client.print("Host: api.thingspeak.com\n"); client.print("Connection: close\n"); client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+"\n"); client.print("Content-Type: application/x-www-form-urlencoded\n"); client.print("Content-Length: "); client.print(tsData.length()); client.print("\n\n"); client.print(tsData); lastConnectionTime = millis(); if (client.connected()) { Serial.println("Connecting to ThingSpeak..."); Serial.println(); failedCounter = 0; } . else { failedCounter++; Serial.println("Connection to ThingSpeak failed ("+String(failedCounter, DEC)+")") Serial.printlnO ; else { // увеличение счетчика неуспешных попыток отправки данных failedCounter++; Serial.println("Connection to ThingSpeak Failed ("+String(failedCounter, DEC)+")"); Serial.println(); lastConnectionTime = millisO; // Перезапуск интернет-соединения void startEthernet() { client.stop(); Serial.printIn("Connecting Arduino to network...") Serial.println(); delay(lOOO); Ethernet.begin(mac,ip,sdns,gateway,subnet);
52 Глава 4 delay(1000); Serial.print("My IP address: "); for (byte thisByte = 0; thisByte < 4; thisByte++) { // печать IP-адреса Serial.print(Ethernet.locallPO [thisByte], DEC); Serial.print(".If) ; } Serial.println(); delay(1000); Электронный архив Скетч, соответствующий листингу 4.6, можно найти в файле arduino_scetches\_04\ _04_06.ino сопровождающего книгу электронного архива (см. приложение). Загружаем этот скетч в плату Arduino и через некоторое время наблюдаем в окне сервиса ThingSpeak графики, построенные на основе отправленных в наш канал значений температуры и освещенности (рис. 4.24). Рис. 4.24. Отображение поступивших из платы Arduino данных на графиках в канале сервиса ThingSpeak
Arduino и аналоговые датчики 53 4.4. Arduino и инфракрасные датчики расстояния SHARP Для измерения расстояния до объекта используются аналоговые оптические датчи- ки, основанные на методе триангуляции. Самые распространенные из них — это инфракрасные (Infra-Red, IR) датчики расстояния с выходным аналоговым напря- жением, производимые фирмой Sharp (рис. 4.25). В датчиках Sharp установлен инфракрасный (IR) светодиод (LED), излучающий через фокусирующую линзу узкий световой луч в инфракрасном диапазоне. Отра- женный от объекта луч направляется через другую линзу на позиционно- чувствительный фотоэлемент (Position-Sensitive Detector, PSD). Угол отражения луча от объекта, а соответственно, и место на элементе PSD, куда попадает отра- женный луч, зависят от расстояния до объекта (рис. 4.26). А проводимость элемен- та PSD зависит от того, в какое место на нем попадает отраженный луч. Проводи- мость эта преобразуется в напряжение, оцифровывая которое аналого-цифровым преобразователем микроконтроллера, можно вычислить расстояние до объекта. U1 P8D Рис. 4.25. Инфракрасный датчик расстояния Sharp Рис. 4.26. Путь светового луча инфракрасного измерителя расстояния при различных расстояниях до объекта Выход датчика расстояния Sharp обратно пропорциональный— с увеличением расстояния его значение медленно уменьшается (рис. 4.27). Датчики, в зависимости от их типа, имеют границы измерения, в пределах которых их выход может быть признан надежным. Измерение максимального реального расстояния ограничивают два фактора: уменьшение интенсивности отраженного света и невозможность PSD регистрировать незначительные изменения местоположения отраженного луча. Так, при измерении расстояния до сильно удаленных объектов выход датчика оста-
54 Глава 4 ется приблизительно таким же, как и при измерении минимальных расстояний. Дело в том, что минимально измеряемое датчиками Sharp расстояние ограничено их особенностью, проявляющейся в резком падении выходного напряжения при малых расстояних до объекта (в зависимости от типа датчика: от 4-х до 20 см). По существу, это означает, что одному значению выходного напряжения соответству- ют два расстояния: очень близкое и очень далекое. Для предотвращения возникно- вения такой проблемы следует избегать слишком близкого приближения датчиков к объекту. В целом график зависимости напряжения от расстояния хоть и не является линей- ным, но в пределах допустимых расстояний график обратной величины выход- U -► d Рис. 4.27. График зависимости напряжения U от расстояния d для датчиков Sharp %х) * 0.0001831Х - 0.0030927 200 250 300 350 400 460 50 100 150 500 ADC Рис. 4.28. График зависимости выходного напряжения датчика GP2Y0A21YK от расстояния до объекта
Arduino и аналоговые датчики 55^ ного напряжения и расстояния к линейности приближается достаточно близко, и с его помощью довольно просто получить формулу преобразования напряжения в расстояние. Для нахождения такой формулы необходимо точки этого графика ввести в какую-либо программу обработки табличных данных и из них создать но- вый график, а на основе точек этого графика автоматически вычислить линию тренда. На рис. 4.28 приведен график связи исправленной обратной величины вы- ходного напряжения инфракрасного датчика GP2Y0A21YK с расстоянием вместе с линейной линией тренда. Выходное напряжение для упрощения формулы уже переведено в 10-битное значение аналого-цифрового преобразователя с опорным напряжением +5 В. 4.4.1. Подключение датчиков Sharp к Arduino Работать с сенсором Sharp очень просто — достаточно подключить к нему питание и завести его вывод Vo на аналоговый вход Arduino (рис. 4.29). Значение получае- мой функции anaiogRead представляет собой целое число в диапазоне от 0 до 1023. Таким образом, чтобы узнать напряжение на выходе сенсора, необходимо значение на аналоговом входе Arduino умножить на 0,0048828125 (5 В / 1024). А расстояние мы вычисляем по формуле: distance = volts x 0,0001831 - 0,003097 Содержимое скетча, выдающего расстояние, измеряемое датчиком Sharp, в после- довательный порт, представлено в листинге 4.7. Рис. 4.29. Подключение к Arduino инфракрасного датчика расстояния Sharp GP2Y0A21YK
56 Глава 4 int IRpin =0; // аналоговый пин для подключения выхода Vo сенсора void setup() { Serial.begin(9600); // старт последовательного порта void loop () { // 5V/1024 - 0.0048828125 // считываем значение сенсора и переводим в напряжение float volts = analogRead(IRpin)*0.0048828125; //ив расстояние в см float distance-32*pow(volts,-1.10); Serial.print(distance); // выдаем в порт значение delay(100); При чтении данных на каждой итерации цикла иногда для одного и того же рас- стояния приходят разные значения сигнала. Дело в том, что датчик передает сигнал на аналоговый порт с некоторой амплитудой, и когда итерация в момент считыва- ния данных приходится на провал, измеренное значение оказывается отличным от реального. В листинге 4.8 представлен код скетча, осуществляющего сглаживание значений, получаемых с датчика расстояния. const int IRpin = АО; // аналоговый пин для подключения выхода Vo сенсора int value1; // для хранения аналогового значения void setup() { Serial.begin(9600); // Запуск последовательного порта void loop() { Serial.println(irRead(), DEC); // получаем сглаженное значение и переводим в напряжение float volts = analogRead(IRpin)*0.0048828125; //ив расстояние в см float distance=32*pow(volts,-1.10); Serial.print(distance); // выдаем в порт значение delay(200);
Arduino и аналоговые датчики 57_ II Усреднение нескольких значений для сглаживания int irReadO { int averaging =0; // переменная для суммирования данных // Получение 5 значений for (int i=0; i<5; i++) { valuel - analogRead(IRpin); averaging = averaging + valuel; delay(55); // Ожидание 55 ms перед каждым чтением } valuel = averaging /5; // усреднить значения return(valuel); Электронный архив Скетч, соответствующий листингу 4.8, можно найти в файле arduino_scetches\_04\ _04_08.ino сопровождающего книгу электронного архива (см. приложение). Точность измерений показаний датчика впрямую зависит от напряжения питания АЦП — естественно, для лучшего результата необходимо питать АЦП от отдель- ного источника калиброванного стабилизированного напряжения. 4.4.2. Подсчет количества посетителей магазина Создадим пример отправки в сервис Twitter данных о количестве посетителей мага- зина за определенный промежуток времени. Упростим задачу, предполагая, что вход осуществляется через неширокую дверь, а для входа и выхода посетителей служат разные двери. На входе поставим инфракрасный датчик Sharp GP2Y0A21YK0F с диапазоном из- мерений 20-150 см таким образом, чтобы при проходе человека показания имели значения от 10 до 50 см, а при отсутствии людей в просвете двери — 80 см. Каждые 10 минут данные о посещаемости будут отправляться в Twitter. Сначала напишем код обнаружения прохода человека через дверной проем (лис- тинг 4.9). const int IRpin = АО; // аналоговый пин для подключения выхода Vo сенсора int valuel; // для хранения аналогового значения unsigned long timevisitors; // время прохода int count_visitors=0; // переменная подсчета посетителей void setup() { Serial.begin(9600); // Запуск последовательного порта
58 Глава 4 void loop () { // получаем сглаженное значение и переводим в напряжение valuel=irRead(); //Serial.println(valuel, DEC); if(valuel>50) // фиксация прохода { timevisitors=millis (); while(irRead()>50) ; if (millis()-timevisitors>300) // > минимального времени прохода { Serial, print In ("passage! ! ! ") ; count_visitors=count_visitors+l; // увеличение счетчика Serial.print("count_visitors="); Serial.printIn(count_visitors); delay(200); } // Усреднение нескольких значений для сглаживания int irRead() { int averaging =0; // переменная для суммирования данных // Получение 5 значений for (int i=0; i<5; i++) { valuel = analogRead(IRpin); averaging = averaging + valuel; delay(55); // Ожидание 55 ms перед каждым чтением } valuel = averaging / 5; // усреднить значения return(valuel); Электронный архив Скетч, соответствующий листингу 4.9, можно найти в файле arduino_scetches\ _04\_04_09.ino сопровождающего книгу электронного архива (см. приложение). Итак, датчик обнаруживает попадание человека в дверной проем. Теперь мы ожи- даем завершения его прохода через проем, и если это время больше минимального времени прохода (взмах руки, пролет постороннего предмета и пр. мы отсекаем), то инкрементируем счетчик посетителей и выводим данные в последовательный порт (рис. 4.30). Нам осталось добавить отправку в Twitter полученных данных с периодичностью в 10 минут — этим мы в следующих разделах и займемся.
Arduino и аналоговые датчики 59 passage!!! count_visitors*l passage!!! Gunt_visitors«2 passage!!! CQunt_visitors»3 passage!!! count_visitors»4 passage!!! count visitors=*5 Рис. 4.30. Вывод в последовательный порт данных о проходе посетителей 4.4.3. Приложение ThingTweet сервиса ThingSpeak Приложение ThingTweet сервиса ThingSpeak позволяет вашим устройствам послать сообщение в ваш профиль в Twitter, используя API ThingSpeak. При этом сервис ThingSpeak действует для Twitter в качестве прокси-сервера — чтобы ваши устрой- ства отправляли сообщения в Twitter без необходимости реализовывать открытую аутентификацию (OAuth). Что ж, авторизуемся в сервисе ThingSpeak и выберем пункт меню Apps — откроет- ся окно выбора приложений (рис. 4.31). ThingTweet ThingHTTP TweetContro! React TalkBack TrmeControf Рис. 4.31. Окно выбора приложения в сервисе ThingSpeak
60 Глава 4 Рис. 4.32. Окно перехода в аккаунт Twitter Выбираем здесь приложение ThingTweet и попадаем на страницу со ссылкой пере- хода в ваш аккаунт Twitter (рис. 4.32). В следующем окне (уже на странице Twitter) необходимо разрешить приложению ThingTweet доступ к данным вашего аккаунта Twitter, нажав на кнопку Авторизо- вать (рис. 4.33). Рис. 4.33. Предоставление приложению ThingTweet доступа к вашему аккаунту Twitter После того, как вы предоставите приложению ThingTweet доступ к данным вашего аккаунта в Twitter (рис. 4.34), Twitter перенаправит вас обратно в ThingSpeak, где приложение ThingTweet сгенерирует ключ API (рис. 4.35). Теперь, когда вы станете посылать HTTP POST с ключом ThingTweet API (API Key), ваше сообщение будет передано в Twitter.
Ardumo и аналоговые датчики 61 сЛ » Authorizstion Рис. 4.34. Доступ приложению к вашему аккаунту Twitter предоставлен Accoii Рис. 4.35. Генерация API-ключей для перенаправления данных в Twitter 4.4.4. Отправка данных о количестве посетителей в Twitter из Arduino Продолжим создание примера из разд. 4.4.2. Нам сейчас необходимо добавить в него отправку с периодичностью в 10 минут данных приложению ThingSpeak, которое перенаправит их в Twitter. Для этого один раз в 10 минут мы станем отправлять с нашей платы Arduino, состыкованной с Ethernet Shield, в сервис ThingSpeak запрос HTTP POST следующего содержания: POST /apps/thingtweet/1/statuses/update HTTP/1.1 Host: api.thingspeak.com Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: <length>api_key=<thingtweet_api_key>&status=<message>
(№ Глава 4 где: □ <iength> — количество символов в сообщении; □ <thingtweet_api_key>— полученный API-ключ JUPP0TQ752M2AOEP (см. рис. 4.35); □ <message>— сообщение. Итак, загружаем в нашу плату Arduino скетч, представленный в листинге 4.10. #include <SPI.h> #include <Ethernet.h> byte mac[] « {0x00, OxAA, OxBB, OxCC, OxDE, 0x02}; byte ip[] - { 192, 168, 0, 97 }; byte sdns[] - { 192, 168, 1, 1 }; byte gateway[] « { 192, 168, 0, 28 }; byte subnet[] = { 255, 255, 255, 0 }; const int IRpin = АО; // аналоговый пин для подключения выхода Vo сенсора int value1; // для хранения аналогового значения unsigned long timevisitors; int count_visitors=0; unsigned long timel0minute=500000; // ThingSpeak Settings char thingSpeakAddress[] = "api.thingspeak.com"; String thingtweetAPIKey - "JUPP0TQ752M2AOEP"; // служебные переменные long lastConnectionTime =0; boolean lastConnected = false; int failedCounter = 0; // инициализация Arduino Ethernet Client EthernetClient client; void setup() { Serial.begin(9600); // Запуск последовательного порта startEthernet(); delay(1000); void loop() { valuel^irRead(); if(valuel>50) { timevisitors-rnillis ();
Arduino и аналоговые датчики 63^ while(irRead()>50) ; if (millis()-timevisitors>300) { Serial.println("passage!!!"); count_yisitors=count_yisitors+l; Serial.print("count_visitors-"); Serial.println(count_yisitors); delay(200); if(millis()-timel0minute>600000) { String message^'last 10 minute "+String(count_visitors)+" visitors"; updateTwitterStatus(message); timelOminute=millis () ; } // печать ответа от сервера в монитор while (client.available()) { char с = client.read(); Serial.print(с); } // отключение от ThingSpeak if (!client.connected() && lastConnected) { Serial.println("...disconnected"); Serial.println(); client.stop(); } // рестарт сетевого соединения if (failedCounter > 3 ) {startEthernet();} lastConnected = client.connected(); // Усреднение нескольких значений для сглаживания int irReadO { int averaging =0; // переменная для суммирования данных // Получение 5 значений for (int i=0; i<5; valuel = analogRead(IRpin); averaging = averaging + valuel; delay(55); // Ожидание 55 ms перед каждым чтением
64 Глава 4 valuel = averaging / 5; // усреднить значения return(value1); void startEthernet() { client.stop(); Serial.println("Connecting Arduino to network..."); Serial.println(); delay(1000); Ethernet.begin (mac, ip, sdnsf gateway, subnet); Serial.println(Ethernet.locallPO); // Connect to network amd obtain an IP address using DHCP Ethernet.begin(mac, ip, sdns, gateway, subnet); Serial.println(Ethernet.locallPO); delay(lOOO); void updateTwitterStatus(String tsData) { if (client.connect(thingSpeakAddress, 80)) { // данные HTTP POST D tsData = "api_key="+thingtweetAPIKey+"&status="+tsData; client.print("POST /apps/thingtweet/1/statuses/update HTTP/1.l\n"); client.print("Host: api.thingspeak.com\n"); client.print("Connection: close\n"); client.print("Content-Type: application/x-www-form-urlencoded\n"); client.print("Content-Length: "); client.print(tsData.length()); client.print("\n\n"); client.print(tsData); lastConnectionTime = millis (); if (client.connected()) { Serial.println("Connecting to ThingSpeak..."); Serial.println(); count_visitors=0; failedCounter = 0;
Arduino и аналоговые датчики 65 else failedCounter++; Serial. Serial.println(); failedCounter++; Serial.println("Connection to ThingSpeak failed ("+String(failedCounter, DEC)+")"); else failedCounter++; Serial.println("Connection to ThingSpeak Failed ("+String(failedCounter, DEC)+")"); Serial.printlnO ; lastConnectionTime = millis(); Электронный архив Скетч, соответствующий листингу 4.10, можно найти в файле arduino_scetches\_04\ _04_io.ino сопровождающего книгу электронного архива (см. приложение). connecting то iningbpe; КГГРЛ 1 200 ОК Server nginx/1.7.5 Date: Wed, 08 Apr 2015 05:39:10 GMT Content-Type, text/htel; charset-utf-8 Transfer-Encoding: chunked Connection: close Vary: Accept-Encoding Status: 200 OK X-Fraie-Options. ALLOWALL Access-Control-AUow-Origin: ♦ Access-Control-AUov-Methods: GET, POST, PUT, OPTIONS, DELETE, PATCH Access-Control-Allov-Headers: origin, content-type, X-Requested-With Ac cess-Control-Max-Age: 1800 ETag- "c4ca4238a0b923820dcc509a6f75849b" Cache-Control: nax-age-G, private, must-revalidate Set-Cookie- request_«ethod«POST; path»/ X-Request-Id: flaf63e2-7cl9-44b3-9d07-a976444d2b0c 1 1 0 .disconnected )assage!!! count_visitors"l passage!!! count_visitors»2 jassagel! I count_visitors«3 passage!!! count_vmtors-4 lassage!!! count_visitors-5 jassage!!! count visitors-6 Рис. 4.36. Отображение процесса подсчета посетителей и отправки данных в мониторе последовательного порта
66 Глава 4 Здесь при загрузке программы мы прежде всего устанавливаем настройки сети для платы Ethernet Shield, после чего в основном цикле программы ведем по срабаты- ванию инфракрасного датчика подсчет посетителей в переменной countvisitors и по прошествии 10 минут (miiiis()-timeiOminute>io*6O*iooo) отправляем серверу api.thingspeak.com HTTP POST С сообщением "last 10 minute xx visitors.". Затем обнуляем счетчик посетителей countvisitors и опять ждем 10 минут для отправки следующих данных. После трех неудачных попыток соединения с сервером пере- подключаем Ethernet Shield к Сети. На рис. 4.36 показано отображение в мониторе последовательного порта Arduino IDE процесса подсчета посетителей и отправки данных в ThingSpeak, а на рис. 4.37 — публикация этих сообщений в Twitter. I Ip ' ;■/; Tvs*:dvr. UvC iUSF ri«'tpS VtWiLttfГОШ i:;c 7 ущнлй Шттщз Рис. 4.37. Публикация отправляемых из Arduino данных в Twitter 4.5. Arduino и датчики переменного тока SCT В этом разделе мы рассмотрим важную практическую задачу — измерение объема потребляемой электроэнергии. И воспользуемся для этого датчиками переменного тока серии SCT — например, SCT-013 100А (рис. 4.38). Этот датчик предназначен для измерения переменного тока до 100 А. Датчик явля- ется безинвазивным, т. е. для его подключения не надо делать разрыва в сети — достаточно поместить силовой провод электросети внутрь контура датчика. Для удобства пользования контур сделан разъемным — чтобы открыть чувствительный элемент датчика, нужно потянуть за ручку-фиксатор. В качестве чувствительного элемента в датчике SCT-013 используются две одинаковые ферритовые скобы.
Arduino и аналоговые датчики 67 Итак, раскройте контур датчика, поместите между ферритовыми скобами силовой провод (обязательно один провод— фазовый) и защелкните ручку-фиксатор (рис. 4.39). Рис. 4.38. Датчик переменного тока SCT-013 Рис. 4.39. Размещение силового провода электросети в чувствительный контур датчика SCT-013
68 Глава 4 Уровень выходного сигнала датчика прямо пропорционален протекающему через силовой провод току. Как уже отмечалось, датчик позволяет измерить ток до 100 А. Нанесенное на датчик обозначение 100А : 50mA показывает соотношение входного и выходного сигнала: 100 А сети равняется 50 мА на выходе, т. е. датчик просто уменьшает значение тока в силовой сети в 2000 раз. 4.5.1. Подключение датчика SCT-013 Sharp к Arduino Подключить датчик SCT-013 напрямую к плате Arduino невозможно, т. к. у него выходной сигнал токовый. А плата Arduino имеет только аналоговые входы напряжения, которые измеряют 0-5 В постоянного тока, поэтому необходимо пре- образовать токовый выход датчика в опорный сигнал напряжения, а затем масшта- бировать опорное напряжение в диапазоне 0-5 В. Соответствующая схема подклю- чения датчика SCT-013 Sharp к плате Arduino представлена на рис. 4.40. SCT-013 100A Рис. 4.40. Схема подключения датчика SCT-013 к плате Arduino Делитель напряжения в этой схеме (два резистора по 10 кОм) устанавливает точку 0 для тока в положении 2,5 В, чтобы измерять и положительный, и отрицательный ток, при этом напряжение на нагрузочном резисторе на пике тока должно быть равно половине аналогового опорного напряжения Arduino (2,5 В) (рис. 4.41). Для получения значений тока и мощности воспользуемся библиотекой EmonLib. Скетч, который измеряет значения тока и мощности и отправляет их в последова- тельный порт, представлен в листинге 4.11.
Arduino и аналоговые датчики ст. Voltage Current 75 mA -75 mA Рис. 4.41. Пояснение к схеме подключения датчика SCT-013 к плате Arduino Электронный архив Скетч, соответствующий листингу 4.11, можно найти в файле arduino_scetches\_04\_04_11.ino сопровождающего книгу электронного архива (см. приложение). II подключить библиотеку tinclude "EmonLib.h" // создать объект EnergyMonitor emonl; void setup() { Serial.begin(9600); // пин A3, калибровочный коэффициент emonl*voltage(3, 234.26, 1.7); // пин A3, калибровочный коэффициент emonl.current(3, 111.1); void loop() { // количество выборок, time-out emonl.calcVI(20,2000); // мощность float realPower = emonl.realPower; // значение тока float Irms - emonl.Irms; // отправить в последовательный порт Serial.print("P=");Serial.print(realPower); Serial.print(" I=");Serial.printIn(Irms);
70 Глава 4 Результат вывода значений в последовательный порт при включенном и выклю- ченном приборе представлен на рис. 4.42. Как видим, при нулевом потреблении здесь выдаются ненулевые значения тока. 3iy проблему можно решить более точной подстройкой делителя напряжения, попробовать, например, установить вместо резисторов потенциометры. Р-526.50 Р-522.26 Р-525.98 Р-519.92 Р-523.46 Р-523,16 Р-520.28 Р-526.79 Р«529.30 Р-520.56 Р-533.95 Р-524.53 Р-525.03 Р-32.00 Р»0.08 Р-0.23 Р-0.04 •0.14 Р-0.00 Р«0.00 P--0.G6 1-10.47 1=10.45 1«10.47 1-10.42 1-10.48 1-10.45 1-10.43 1-10.49 1-10.50 1-10.44 1-10.58 1-10.48 1-10.46 1-2.60 1-0.32 1-0.26 1-0.32 1-0.23 1-0.30 1-0.29 1-0.34 Рис. 4.42. Вывод данных в монитор последовательного порта Однако нас интересуют не мощность, напряжение и ток, а потребляемая электро- энергия в киловатт-часах (кВт-ч). Изменим наш скетч так, чтобы считать потреб- ляемый ток нарастающим итогом (листинг 4.12). Электронный архив Скетч, соответствующий листингу 4.12, можно найти в файле arduino_scetches\J)4\ _04J2.ino сопровождающего книгу электронного архива (см. приложение). /1 пин подключения счетчика A3 int currentPin = 3; double kilos = Q; int peakPower = 0; void setup() { Serial.begin(9600); Serial.println("Running");
Arduino и аналоговые датчики 71_ void loop () { int current = 0; int maxCurrent = 0; int minCurrent = 1000; // 200 выборок для получения мин. и макс, значения тока for (int i=0 ; i<=200 current = analogRead(currentPin); if(current >= maxCurrent) maxCurrent = current; else if(current <= minCurrent) minCurrent = current; } if (maxCurrent <= 517) { maxCurrent = 516; } double RMSCurrent » ((maxCurrent - 516)*0.707)/11.8337; // потребленная мощность в ваттах int RMSPower = 220*RMSCurrent; if (RMSPower > peakPower) { peakPower = RMSPower; } // подсчет в киловатт-час kilos * kilos + (RMSPower * (2.05/60/60/1000)); delay (2000); Serial.print(RMSCurrent); Serial.printIn("A"); Serial.print(kilos); Serial.println("kWh"); Результат вывода полученных значений в последовательный порт представлен на рис. 4.43. 4.5.2. Отправка данных в сервис ThingSpeak Теперь рассмотрим отправку данных в сервис ThingSpeak. Ранее мы отправляли данные в сервис ThingSpeak по протоколу HTTP без использования сторонних биб- лиотек. В этом разделе мы воспользуемся библиотекой ThingSpeak, которая очень сильно упростит наш код. Рассмотрим установку библиотеки ThingSpeak в среде Arduino ШЕ версии 1.6.5 и выше. Для установки библиотеки выбираем пункт меню Эскиз | Include library | Manage libraries, находим в поиске библиотеку ThingSpeak и нажимаем кнопку Install (рис. 4.44).
72 Глава 4 2.09А O.OOkWh 2.21А O.OOkWh 2. ISA O.OOkWh 2. ISA O.OlkWh O.OOA OlkWh OOA OlkWh OOA OlkWh OOA OlkWh OOA OlkWh OOA OlkWh OOA OlkWh OOA OlkWh OOA OlkWh O.OOA Рис. 4.43. Вывод данных в монитор последовательного порта Рис. 4.44. Установка библиотеки ThingSpeak
Arduino и аналоговые датчики 73 Рис. 4.45. Библиотека ThingSpeak установлена После скачивания и установки библиотека появится в списке Файл | Образцы (рис. 4.45). Теперь создадим в ThingSpeak новый канал Electricity (рис. 4.46). Загружаем на плату Arduino. скетч из листинга 4.13, внеся в него свои данные: unsigned long myChannelNumber = 12345; const char * myWriteAPIKey = и**************************... и соединяемся с сервисом ThingSpeak через Ethernet Shield. Отправку значений по- требляемой электроэнергии нарастающим итогом производим каждые 2 минуты.
74 Глава 4 Рис. 4.46. Создание канала Electricity // подключение библиотеки #include "ThingSpeak.h" // Use wired ethernet shield #include <SPI.h> #include <Ethernet.h> byte mac[] = { OxDE, OxAD, OxBE, OxEF, OxFE, OxED}; EthernetClient client; // 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 }; // данные канала unsigned long myChannelNumber = 314294; const char * myWriteAPIKey = "8YTRJ3NX1RJTAJU3"; unsigned long mi11is1=0; // пин подключения счетчика A3 int currentPin = 3; j
Arduino и аналоговые датчики 75^ double kilos =* 0.03; int peakPower - 0; void setup() { // запуск Ethernet Ethernet.begin(mac,ip,sdns,gateway,subnet); // секунда для инициализации Ethernet delay(1000); // инициализация ThingSpeak ThingSpeak.begin(client); // запуск последовательного порта Serial.begin(9600); Serial.println("Running"); void loop() { int current = 0; int maxCurrent = 0; int minCurrent = 1000; // 200 выборок для получения мин. и макс, значения тока for (int i=0 ; i<=200 current = analogRead(currentPin); if(current >= maxCurrent) maxCurrent = current; else if(current <= minCurrent) minCurrent = current; } if (maxCurrent <= 517) { maxCurrent =* 516; } double RMSCurrent = ((maxCurrent - 516)*0.707)/11.8337; // потребленная мощность в ваттах int RMSPower - 220*RMSCurrent; if (RMSPower > peakPower) { peakPower = RMSPower; } // подсчет в киловатт-часах kilos = kilos + (RMSPower * (2.05/60/60/1000)); delay (2000); Serial.print(RMSCurrent); Serial.println("A"); Serial.print((float)kilos); Serial.println("kWh");
76 Глава 4 if(millis()-millisl>30*1000) { // отправка данных в сервис ThingSpeak ThingSpeak.writeField(myChamelNumber, 1, (float)kilos, myWriteAPIKey); Serial.println("SEND ") ; Электронный архив Скетч, соответствующий листингу 4.13, можно найти в файле arduino_scetches\_04\ _04j3.ino сопровождающего книгу электронного архива (см. приложение). Далее заходим на сайт ThingSpeak и на канале Electricity видим график потребле- ния электроэнергии (рис. 4.47). Рис. 4.47. Отображение поступающих данных на канале в сервисе ThingSpeak 4.6. Arduino и счетчик расхода воды Рассмотрим подключение к плате Arduino счетчика учета воды. В последнее время выпускают счетчики воды, снабженные импульсными выходами. Цена импульсных счетчиков не сильно отличается от простых счетчиков той же модели. Если вам не удобно добираться к счетчику для снятия показаний, можно этот процесс авто- матизировать.
Arduino и аналоговые датчики 77 4.6.1. Счетчик воды Бетар СГВ-15Д К очередной поверке я приобрел дистанционный счетчик воды Бетар СГВ-15Д (рис. 4.48). Этот счетчик как раз и предназначен для автоматизированных систем учета энергоресурсов. Рис. 4.48. Счетчик воды Бетар СГВ-15Д Дистанционный выходной сигнал имеет следующие параметры импульсов: □ цена деления одного импульса, м3 — 0,01; П ток, мА — от 0,1 до 50; □ напряжение, В — от 0,5 до 18. Назначение выводов импульсного выхода представлено в табл. 4.1. Таблица 4.1. Назначение выводов импульсного выхода счетчика СГВ-НЩ Цвет изоляции провода Черный (минусовое напряжение) Синий Красный Желтый (минусовое напряжение) Назначение Объемный расход (съем показаний) Объемный расход (съем показаний) Сигнал воздействия внешнего магнитного поля Сигнал воздействия внешнего магнитного поля Внутри счетчика провод подключен к геркону, и при проходе через счетчик оче- редных восьми литров геркон замыкается, а при проходе еще двух — размыкается. Как раз момент замыкания мы и будем ловить.
78 Глава 4 4.6.2. Подключение счетчика к плате Arduino Подключим счетчик СГВ-15Д к плате Arduino (рис. 4.49) и напишем скетч получе- ния данных о расходе воды с выводом их в последовательный порт и сохранением текущих показаний в памяти EEPROM (листинг 4.14). Рис. 4.49. Схема соединений счетчика воды Бетар СГВ-15Д к Arduino ■ Ilutrmw С14 // подключение библиотеки #include <EEPROM.h> // начальные показания unsigned int dataBetarl5D=0; void setup() { // начальная установка значений в EEPROM при первом запуске if(get_param2_EEPROM(0)==0xffff) savej?aram2_EEPROM(0, dataBetarl5D); // запуск последовательного порта Serial.begin(9600); // получение показаний из EEPROM dataBetarl5D=get_param2_EEPRQM(0); // вывод показаний текущих Serial.print ("dataBetarl5D="); Serial.println(dataBetarl5D);
Arduino и аналоговые датчики 79 // запускаем прерывание attachlnterrupt(0,addDataBetarl5D,RISING); void loop() {;} // получить значения параметра из ЕЕPROM int getj?aram2_EEPROM(int addr) { int retval=((EEPROM.read(addr)«8)+EEPROM.read{addr+l)); return retval; } // сохранить значения параметра в EEPROM void save_param2_EEPROM(int addr, int val) { EEPROM.write (addr,highByte (val)) ; EEPRQM.write(addr+1,lowByte(val)); } // прерывание - добавить 10 л void addDataBetarl5D() { detachlnterrupt(0) ; dataBetarl5D= dataBetarl5D+10; // сохранить в EEPROM save_j?aram2_EEPROM (0, dataBetarl5D); attachlnterrupt(0, addDataBetarl5D, RISING); 4.6.3. Отправка данных о расходе воды в «облако» Рассмотрим здесь отправку полученных данных в сервис ThingSpeak, для чего соз- дадим в ThingSpeak новый канал WaterConsumption (рис. 4.50). Загружаем на плату Arduino скетч из листинга 4.15, внеся в него свои данные: unsigned long myChannelNuniber = 12345; const char * myWriteAPIKey = »**•••***•**•***•**•**•**••»; и соединяемся с сервисом ThingSpeak через Ethernet Shield. Отправку значений расхода воды нарастающим итогом производим только при получении данных о следующем расходе. // подключение библиотеки #include "ThingSpeak.h" // Use wired ethernet shield #include <SPI.h> #include <Ethernet.h> byte mac[] = { OxDE, OxAD, OxBE, OxEF, OxFE, OxED}; EthernetClient client; // IP-адрес, назначаемый Ethernet Shield: byte ip[] - { 192, 168, 0, 119 };
80 Глава 4 WaterConsumption Рис. 4.50. Создание канала WaterConsumption // IP-адрес, dns сервера: byte sdns[] = { 192, 168, 1, 1 }; // адрес шлюза: byte gateway[] = { 192, 168, 0, 28 }; // маска: byte subnet[] - { 255, 255, 255, 0 }; // данные канала unsigned long myChannelNumber = 324829; const char * myWriteAPIKey = "CT4U51S33J4V5OWC"; // подключение библиотеки #include <EEPROM.h> // начальные показания unsigned int dataBetarl5D=0; unsigned int dataBetarl5Dpr=0; void setup() { // запуск Ethernet Ethernet.begin(mac,ip,sdns,gateway,subnet); // секунда для инициализации Ethernet delay(1000);
Arduino и аналоговые датчики 81_ I/ инициализация ThingSpeak ThingSpeak.begin(client); // запуск последовательного порта Serial.begin(9600); // начальная установка значений в EEPROM при первом запуске if(get_param2_EEPROM(0)==0xffff) save_param2_EEPROM(0, dataBetarl5D); // получение показаний из EEPROM dataBetarl5D=get_param2_EEPROM(0); dataBetarl5Dpr=dataBetarl5D; // вывод показаний текущих Serial.print ("dataBetarl5D="); Serial.println(dataBetarl5D); // запускаем прерывание attachlnterrupt(0,addDataBetarl5D,RISING); Serial.printIn("Running"); void loop() { if(dataBetarl5Dpr!=dataBetarl5D) { // отправка данных в сервис ThingSpeak ThingSpeak.writeField(myChannelNumber, 1, (float)dataBetarl5D, myWriteAPIKey); dataBetarl5Dpr=dataBetarl5D; // получить значения параметра из EEPROM int get_param2_EEPRQM(int addr) { int retval=((EEPROM.read(addr)«8)+EEPROM.read(addr+1)); return retval; } // сохранить значения параметра в EEPROM void save_param2_EEPROM(int addr,int val) { EEPROM.write(addr,highByte(val)); EEPROM.write(addr+1,lowByte(val)); } // прерывание - добавить 10 л void addDataBetarl5D() { detachlnterrupt(0); dataBetarl5D= dataBetarl5D+10; // сохранить в EEPRQM save_param2_EEPROM(0, dataBetarl5D); attachlnterrupt(0, addDataBetarl5D, RISING); } Электронный архив Скетч, соответствующий листингу 4.15, можно найти в файле arduino__scetches\_04\_04_15.ino сопровождающего книгу электронного архива (см. приложение).
ГЛАВА 5 Использование Arduino в качестве контроллера исполнительных устройств Концепция Internet of Things (Интернет вещей) предполагает не только удаленное получение данных о состоянии объектов, но и удаленное управление исполнитель- ными устройствами. Исполнительные устройства Исполнительные устройства — это элементы автоматики, создающие управляющее воздействие на объект управления. Они изменяют положение или состояние регули- рующего органа объекта управления таким образом, чтобы управляемый параметр соответствовал заданному значению. Исполнительное устройство, или механизм (actuator), преобразует электрическую энергию в механическую для воздействия на управляемый процесс. В качестве исполнительных механизмов могут быть задействованы световые и звуко- вые устройства, электромагнитные клапаны, электродвигатели постоянного (DC) и пе- ременного (АС) тока, сервоприводы, релейные системы и многое другое. Плата Arduino, имеющая доступ к сети с помощью, например, платы Ethernet Shield, вполне способна выступать в роли контроллера удаленных исполнительных устройств. В этой главе мы рассмотрим использование платы Arduino для органи- зации веб-сервера, получающего команды управления по HTTP и преобразующего их в команды управления исполнительными устройствами, подключенными к циф- ровым выводам Arduino. 5.1. Arduino и электромагнитное реле 5.1.1. Электромагнитное реле Реле (от фр. relais) — электрическое или электронное устройство (ключ), предна- значенное для замыкания и размыкания различных участков электрических цепей. Изобретение реле стало великим открытием, перевернувшим мир. Произошло это в далеком 1831 году. Позже, в 1937 году, Сэмюэл Морзе изобрел коммуникационное реле и применил его в телеграфном аппарате. Сегодня электрические, пневматиче-
84 Глава 5 ские и механические реле используются весьма широко и выпускаются в огромном количестве самых разнообразных их видов. Наиболее распространенными являются электромагнитные реле — электромехани- ческие устройства, замыкающие и/или размыкающие контакты внешней электриче- ской цепи при подаче в обмотку реле управляющего электрического тока. Этот ток порождает магнитное поле, вызывающее перемещение ферромагнитного якоря ре- ле, механически связанного с электрическими контактами внешней электрической цепи. Последующее перемещение контактов коммутирует эту цепь. К реле можно подключить лампочку, вентилятор, электромагнитный клапан для управления поливом и программно управлять этими устройствами изменением состояния на цифровых выводах Arduino. 5.1.2. Устройство и принцип работы электромагнитного реле Рассмотрим устройство электромагнитного реле на примере широко используемого в связке с Arduino реле SRD-05VDC фирмы SONGLE (рис. 5.1). Это реле управля- ется напряжением 5 вольт и способно коммутировать до 10 ампер постоянного тока напряжением 30 В и переменного тока напряжением 250 В. Рис. 5.1. Реле SRD-05VDC Рис. 5.2. Схема электромагнитного реле Реле имеет две раздельных цепи, никак не связанные между собой: цепь управле- ния, представленную контактами А1 и А2, и управляемую цепь с контактами 1, 2 иЗ (рис. 5.2). Между контактами А1 и А2 расположен металлический сердечник, при протекании тока по обмотке которого к нему притягивается подвижный якорь 2. Контакты 1 и 3 закреплены неподвижно. Стоит отметить, что якорь под- пружинен, и пока мы не пропустим ток через обмотку сердечника, якорь будет удерживаться прижатым к контакту 3. При подаче в обмотку сердечника управ- ляющего тока, сердечник, как уже говорилось, превращается в электромагнит, и якорь прижимается к контакту 1. При обесточивании обмотки сердечника пружина снова возвращает якорь к контакту 3.
Использование Arduino в качестве контроллера исполнительных устройств 85 5.1.3. Подключение реле к Arduino При подключении реле к Arduino возникает одна немаловажная проблема — кон- такт микроконтроллера не может обеспечить мощность, необходимую для нор- мальной работы катушки реле. Поэтому нам необходимо усилить управляющий ток— что решается включением транзистора в схему управления реле. Удобнее всего для усиления применять n-p-n-транзистор, включенный по схеме с общим эмиттером (ОЭ), — как показано на рис. 5.3. При таком способе можно подключать нагрузку с напряжением питания большим, чем питание микроконтроллера. Рези- стор на базе транзистора — ограничительный. Его. номинал может варьироваться в широких пределах (1-10 кОм)— в любом случае транзистор будет работать в режиме насыщения. В этой схеме может быть применен любой n-p-n-транзистор, поскольку коэффици- ент его усиления практически не имеет значения — достаточно подобрать транзи- стор таким образом, чтобы он соответствовал нужному нам току коллектора и напряжению коллектор-эмиттер (напряжение, которым запитывается нагрузка). На основании личного опыта могу порекомендовать для этой схемы транзистор С945. О +12 V К Arduino ыт. (cms, С4вш аналогичные) Рис. 5.3. Схема подключения реле к Arduino (р-канальное управление) Для включения реле, подключенного по схеме с ОЭ, на вывод Arduino необходимо подать 1, для выключения — 0. Скетч, обеспечивающий работу схемы с реле, при- веден в листинге 5.1. int relayPin void setup() 10; // подключение Arduino к выводу D10
86 Глава 5 pinMode(relayPin, OUTPUT); // настроить вывод как выход (OUTPUT) // the loop function runs over and over again forever void loopO { digitalWrite(relayPin, HIGH); // включить реле delay(5000); digitalWrite(relayPin, LOW); // выключить реле delay(5000); Существуют и готовые модули для Arduino, со- держащие сразу несколько реле с необходимой обвязкой (рис. 5.4). Однако в таких модулях обычно используется n-канальное управление (рис. 5.5), при котором реле включается пода- чей на вывод Arduino низкого уровня. Рис. 5.4. Модуль из 4 реле 5V signal LED2 R2_ w b LED1 - 1LJ3 Reli"|——/ 2 Рис. 5.5. Схема подключения реле к Arduino (n-канальное управление)
Использование Arduino в качестве контроллера исполнительных устройств 87 5.2. Arduino и твердотельное реле Твердотельные реле (Solid State Relay, SSR) применяют в промышленном оборудо- вании — там, где нужны большая надежность и малые габариты (рис. 5.6). Во всех твердотельных оптоэлектронных реле коммутация цепей нагрузки осуществляется бесконтактно — за счет управления встроенными полупроводниковыми элемента- ми. Как правило, это тиристоры или симисторы (для коммутации переменного то- ка) и транзисторы (для постоянного тока). Такая конструкция дает твердотельным реле ряд преимуществ перед обычными электромагнитными — ведь как и в обычных реле, в твердотельных существует гальваническая развязка между напряжением катушки и напряжением на силовых контактах. Только в электромеханических реле это достигается за счет разнесения в пространстве, а в твердотельных — за счет оптической развязки, поскольку на входе реле установлен оптрон. Рис. 5.6. Твердотельное реле Твердотельные реле потребляют и теряют гораздо меньше энергии при работе, имеют меньшие габариты, высокое быстродействие, гораздо более длительный срок службы и все это — абсолютно бесшумно! Но есть у них и серьезный недоста- ток — высокая цена. Для подключения твердотельного реле к Arduino минусовой контакт управляющей сети подсоединяется к «земле», а плюсовой контакт— к цифровому выводу Arduino. Выходного тока контакта Arduino для срабатывания твердотельного реле вполне достаточно.
8№ Глава 5 5.3. Arduino и диммер 5.3.1. Диммер Переключение нагрузки переменного тока с помощью Arduino довольно просто: используется либо механическое реле, либо твердотельное реле с оптически изоли- рованным симистором. Становится сложнее, если необходимо, используя Arduino, плавно уменьшать (диммировать) яркость лампы переменного тока: просто ограни- чивать ток симистором не представляется возможным из-за необходимости в мощ- ном симисторе и, как следствие, необходимости рассеивания большого количества тепла. Неэффективно это также и с точки зрения использования энергии. Правиль- ный способ реализации этой задачи — применение регулирования фазы: симистор полностью открыт, но только в одной части синусоидальной волны переменного тока. Пояснение Диммером называется устройство, обычно используемое для регулировки яркости свечения ламп накаливания или светодиодов. Можно, конечно, и просто открывать симистор с помощью Arduino на некоторое количество микросекунд, но проблема здесь в том, что невозможно заранее пред- сказать, в какой части синусоидальной волны симистор откроется и, следовательно, какой уровень затемнения обеспечит. То есть, в синусоидальной волне нам необхо- димо иметь точку отсчета. Найти ее способен детектор пересечения нуля — схема, которая сообщает Arduino (или другому микроконтроллеру), когда синусоидальная волна проходит через нуль и, следовательно, фиксирует на этой синусоидальной волне определенную точку. Открытие симистора на некоторое количество микро- секунд, начиная от пересечения нуля, как раз и даст нам предсказуемый уровень затемнения. Сделать такую схему несложно: пересечение нуля берется непосредственно из вы- прямленного сетевого переменного тока, что и дает сигнал каждый раз, когда волна проходит через нуль. Поскольку синусоида сначала проходит двухфазное выпрям- ление, сигнал пересечения нуля подается независимо от того, вверх или вниз идет синусоидальная волна. Этот сигнал и может быть использован для вызова преры- вания Arduino. Схема диммера изображена на рис. 5.7. Сетевое напряжение 220 В через два рези- стора по 30 кОм идет к мостовому выпрямителю, который выдает двухфазный вы- прямленный сигнал на оптрон 4N25. Светодиод в этом оптроне при низком уровне работает на частоте 100 Гц, а на коллектор выходит сигнал высокого уровня с час- тотой 100 Гц в соответствии с синусоидальной волной. Сигнал с 4N25 подается на прерывающий вывод Arduino (или другого микропроцессора). Программа прерыва- ний дает сигнал определенной длины на один из портов ввода/вывода. Сигнал с порта ввода/вывода уходит в нашу схему и открывает светодиод в симисторном оптроне МОС3021, который запускает оптотиристор.
Использование Arduino в качестве контроллера исполнительных устройств 89 Для затемнения реально пригодны только обычные лампы накаливания. Впрочем, наша схема также будет работать и с галогенными лампами, но это сократит срок их службы. А вот с компактными люминесцентными лампами (КЛЛ) схема рабо- тать не будет — если только они не выполнены специально с возможностью дим- мирования. ♦Vcc Выход детектора нуля Вход сигнала диммирования от МК Рис. 5.7. Схема реализации диммера 5.3.2. Подключение диммера к Arduino Подключим к плате Arduino диммер (рис. 5.8), приобретенный мной на сайте http://carduino.ru. Схема соединений показана на рис. 5.9: выход детектора нуля подсоединен к цифровому входу D2 платы Arduino — им мы воспользуемся для вызова прерывания, а цифровой вход D4 служит в качестве входа диммирования сигнала микроконтроллером. Рис. 5.8. Диммер
90 Глава 5 +5В GND; D4J D2| — Вид с обратной стороны Рис. 5.9. Подключение диммера к Arduino 5.3.3. Скетч управления диммером Напишем теперь скетч управления яркостью подключенной к диммеру лампы по- средством отправки команд в последовательный порт Arduino. В листинге 5.2 при- веден пример такого скетча, взятый у разработчика диммера, примененного в разд. 5.3.2. В скетче используется библиотека Cyberlib.h, которую можно найти на сайте http://cyber-place.ru. Библиотека представляет набор макросов для низкоуровневой работы с портами Arduino, что дает существенный прирост скорости записи/чтения цифровых портов по сравнению со встроенными функциями Arduino, а также уменьшает размер используемой памяти. #include <CyberLib.h> // Библиотека от Cyber-Place.ru volatile uint8_t tic, Dimmerl=255; uint8__t data; void setup() { D4__Out; // настраиваем порт на выход D4_Low; // установить на выходе низкий уровень сигнала // настраиваем порт на вход для отслеживания прохождения сигнала // через ноль D2_In; // настроить срабатывание прерывания interrupt0 на pin 2 на // низкий уровень attachlnterrupt(0, detect_up, LOW); StartTimerl(halfcycle, 40); // время для одного разряда ШИМ StopTimerl(); // остановить таймер UART_Init(57600); // инициализация порта
Использование Arduino в качестве контроллера исполнительных устройств 91_ IV обработчики прерываний void halfcycle() // прерывания таймера { tic++; // счетчик if (Diirmerl < tic ) D4_High; // управляем выходом void detect_up() // обработка внешнего прерывания: сработает по переднему // фронту { tic=0; // обнулить счетчик ResumeTimerl(); // запустить таймер // перепрограммировать прерывание на другой обработчик attachlnterrupt(0, detect_down, HIGH); void detectjdown() // обработка внешнего прерывания: сработает по заднему // фронту StopTimerl(); // остановить таймер D4_Low; // логический ноль на выходы tic=0; // обнулить счетчик // перепрограммировать прерывание на другой обработчик attachlnterrupt(0f detect_up, LOW); void loop() { Start if (UART_ReadByte(data)) { if(data>47 && data<59) { data=225-(data-48)*25; Dimmerl=data; End Электронный архив Скетч, соответствующий листингу 5.2, можно найти в файле arduino_scetches\J)5\ _05_02.ino, а библиотеку Cyberlib.h — в папке arduinoJibraries\Cybertib сопровождаю- щего книгу электронного архива.
92 Глава 5 5.4. Arduino и сервоприводы Сервопривод (он же «серва», servo, рулевая машинка)— устройство, обеспечи- вающее преобразование сигнала в строго соответствующее этому сигналу переме- щение (как правило — поворот) исполнительного устройства. Представляет собой прямоугольную коробку с мотором, схемой, редуктором и выходным валом, кото- рый может поворачиваться на строго фиксированный угол, определяемый входным сигналом. Как правило, этот угол имеет предел в 60 градусов, а иногда ив 180. Бы- вают сервоприводы и постоянного вращения. На вал сервопривода надевается рычаг в форме круга, крестовины или перекладин- ки для передачи вращающего движения на рабочий орган. Выполнив поворот, вал остается в том же положении, пока не придет иной управляющий сигнал. Смысл сервопривода заключен в гарантированном выполнении заданной команды — если внешняя сила не позволит выполнить поворот на нужный угол, сервопривод все равно закончит движение по окончании действия мешающего внешнего воздейст- вия. Воспрепятствовать этому может лишь разрушение сервопривода, снятие внешнего управляющего сигнала или пропадание напряжения питания. Большинство сервоприводов внешне похожи друг на друга (рис. 5.10)— как пра- вило, это прямоугольный корпус (внутри которого прячутся мотор, шестерни и управляющая схема) с крепежными ушками по бокам и выходным валом, располо- женным на верхней крышке. К валу, как уже отмечалось, крепится сменный (иду- щий в комплекте) передаточный элемент в виде диска с отверстиями по кругу, кре- стовины с отверстиями на концах всех его перекладин или рычага, насаженного на выходной вал либо своим центром, либо одним из концов. Чаще всего этот смен- ный элемент белого цвета. Иногда сервопривод имеет форму цилиндра — тогда его верхняя часть при работе поворачивается вокруг своей оси. Некоторые сервоприводы вместо выходного вала оснащаются шкивом (катушкой). На такой шкив наматывается (или с него сматы- вается) тросик, с помощью которого управляют каким-то внешним приспособлени- ем — например, парусом в моделях судов или яхт. штор Рис. 5.10. Сервопривод
Использование Arduino в качестве контроллера исполнительных устройств 93^ 5.4.1. Принципы управления сервоприводами Сервопривод — электрическое исполнительное устройство, подключаемое с по- мощью трех проводов к устройству управляющему (контроллеру) и источнику пи- тания. По способу управления сервоприводы подразделяются на аналоговые и цифровые. Аналоговые управляются аналоговым сигналом — буквально частотой, параметры которой задаются с помощью широтно-импульсной модуляции (ШИМ). Цифровые сервоприводы управляются цифровым сигналом, представляющим собой кодовые команды, передаваемые по последовательному интерфейсу. Аналоговые сервопри- воды намного дешевле цифровых. Управление сервоприводом осуществляется с помощью импульсов переменной длительности, посылаемых по сигнальному проводу. Параметрами этих импульсов являются минимальная длительность, максимальная длительность и частота повто- рения. Угол поворота сервопривода определяется длительностью посылаемого на него импульса (это и называется широтно-импульсной модуляцией). Так, импульс в 1,5 миллисекунды (1,5 мс) диктует мотору поворот на 90 градусов, что и соответ- ствует его нейтральному положению. Ожидает сервопривод импульса каждые 20 мс. Нейтральное положение сервопривода определяется как положение, в котором сер- вопривод обладает одинаковым потенциалом вращения в обоих направлениях. Важно отметить, что различные сервоприводы обладают разными ограничениями в своем вращении, но они все имеют нейтральное положение, и это положение все- гда находится в районе длительности импульса в 1,5 мс. Когда сервопривод получает команду на перемещение, его управляющий орган пе- ремещается в это положение и удерживает его. Если внешняя сила действует на сервопривод, когда он удерживает заданное положение, сервопривод будет сопро- тивляться перемещению из этого положения. Максимальная величина силы, кото- рую может выдерживать сервопривод, характеризует вращающий момент серво- привода. Однако сервопривод не навсегда сохраняет свое положение — импульсы позиционирования должны повторяться, информируя сервопривод о необходимо- сти сохранения положения. Когда импульс, посылаемый на сервопривод, оказывается короче 1,5 мс, сервопри- вод поворачивает выходной вал на несколько градусов против часовой стрелки и удерживает это положение. Если же приходит импульс шире, чем 1,5 мс, выходной вал поворачивается на несколько градусов в противоположном направлении. Ми- нимальная и максимальная ширина импульса, который управляет сервоприводом, является свойством конкретного сервопривода. Различные марки, и даже различ- ные сервоприводы одной марки, обладают различным минимумом и максимумом. Как правило, ширина минимального импульса составляет примерно 1 мс, а ширина максимального — 2 мс. Различаются сервоприводы и габаритами. Существуют так называемые стандарт- ные сервоприводы. Их габариты и вес в общем модельном ряду соответствуют не- которым средним значениям. Они самые дешевые— в пределах 10-20 долларов.
94 Глава 5 При уменьшении или увеличении размеров сервопривода в сторону от стандартных значений цена сервопривода возрастает пропорционально величине этих отклоне- ний. Как и самые маленькие (микросервы), так и самые большие супермощные сер- воприводы, — это самые дорогие устройства, цена их может доходить до сотен долларов. Сервоприводы различаются также материалом шестеренок. Самые дешевые серво- приводы оснащены шестернями из пластмассы. Более дорогие — с одной выходной шестерней из металла. Самые дорогие — с металлическими шестернями. Соответ- ственно виду материала изменяется нагрузочная способность сервопривода. Самый слабый сервопривод — с пластиковыми шестернями, самый мощный — с металли- ческими. Различия сервоприводов определяются и типом подшипников. Наиболее дешевые не имеют подшипников вовсе: пластмассовые шестерни на пластмассовых валах крутятся в отверстиях пластмассовых пластин, соединяющих шестерни в единый редуктор, — это самые недолговечные сервоприводы. Более дорогие и, соответст- венно, более долговечные сервоприводы имеют металлическую — обычно, латун- ную — втулку на выходном валу. Сервы подороже имеют на выходном валу, на который приходится самая большая нагрузка, настоящий подшипник: шариковый или роликовый. Шариковый — дешевле, роликовый — компактнее и легче. В еще более дорогих сервоприводах на всех (металлических!) шестернях стоят подшип- ники. Это — самые долговечные и надежные устройства. Сервоприводы различаются и по толщине. Она может сильно варьироваться при одинаковых размерах по высоте и длине. Чем меньше толщина, тем выше цена, по- скольку в узком корпусе труднее разместить шестерни. Наконец, сервоприводы различаются по фирме-производителю. Наиболее раскру- ченные бренды продают самые дорогие сервоприводы. При этом в их ассортименте будут как дорогие, так и дешевые сервоприводы, но даже самый простенький и де- шевый стандартный сервопривод крупного бренда стоит дороже, а иногда и суще- ственно дороже, чем аналогичный сервопривод с наклейкой менее раскрученного имени и, тем более, с именем никому не известной фирмы. Очень мощные и очень дорогие сервоприводы могут иметь любую внешнюю фор- му, определяемую назначением сервопривода. Так, сервоприводы для андроидов (человекоподобных роботов) могут быть шаровидными или дисковидными. Но обычно сервопривод — это все-таки черный параллелепипед с белой фитюлькой на верхней крышке. Сервоприводы применяются в основном в промышленности (станки с числовым программным управлением и т. п.). В них установлены, как правило, мощные дви- гатели, в том числе и шаговые, что позволяет использовать их в автоматических манипуляторах (в промышленных роботах). Сервоприводы для моделирования имеют гораздо более худшие характеристики, чем промышленные. Основным их параметром является момент сил, приложенных к «качалке» на заданном расстоянии от оси. Обычно такой момент измеряется в кг/см. Самые слабые сервоприводы тянут 1-2 кг/см. Самые мощные непромыт-
Использование Arduino в качестве контроллера исполнительных устройств 95^ ленные сервоприводы — более 100 кг/см. Момент этот также зависит от питающе- го напряжения. Немаловажным параметром является и скорость вращения вала сервопривода, как правило, измеряемая в сек/60°. Скорость сервопривода обычно важна, если он при- меняется совместно с гироскопом или акселерометром (например, в моделях верто- летов). 5.4.2. Управление сервоприводом с помощью Arduino Для управления сервоприводом в Arduino имеется стандартная библиотека Servo. Однако на платах, отличных от Mega, задействование этой библиотеки отключает возможность использования функции anaiogwrite () (ШИМ) на контактах 9 и 10 (вне зависимости, подключены к этим контактам сервы или нет). В то же время на платах Mega без влияния на функциональность ШИМ могут использоваться до 12 сервоприводов, но дальнейшее увеличение количества сервомашинок до 23-х отключит ШИМ на контактах 11 и 12. Рис. 5.11. Подключение сервопривода Подключается сервопривод к плате Arduino тремя проводами (рис. 5.11): Vcc (пи- тание), Gnd («земля») и S (сигнальный). Красный провод (питание) может быть подключен на плате Arduino к выводу +5 В. Черный или коричневый про- вод («земля») подключается к выводу Arduino GND, оранжевый, желтый или белый сигнальный провод подключается к цифровому выводу контроллера Arduino. Сле- дует отметить, что мощные сервоприводы могут создавать большую нагрузку — в этом случае их следует записывать отдельно (не через выход +5 В Arduino). To же самое верно и для случая подключения сразу нескольких сервоприводов. Итак, подключаем сервопривод к Arduino по схеме, показанной на рис. 5.12, и за- гружаем скетч, представленный в листинге 5.3.
9(5 Глава 5 #include <Servo.h> // подключение библиотеки Servo Servo myservo; // создание экземпляра объекта Servo int pos =0; // переменная для хранения текущей позиции сервопривода void setup() myservo.attach(9); // подключает переменную servo к выходу 9 void loop() for(pos =0; pos <= 180; pos +=1) // вращение в одну сторону с шагом 1 myservo.write(pos); // переместить в новую позицию delay(15); // пауза 15 ms для перемещения сервы for(pos = 180; pos>=0; pos-=l) // вращение в одну сторону с шагом 1 myservo.write(pos delay(15); Рис. 5.12. Схема подключения сервопривода
Использование Arduino в качестве контроллера исполнительных устройств 97_ 5.5. Arduino и библиотека Tiny Webserver Библиотека TinyWebServer является небольшой и расширяемой реализацией HTTP- сервера, предназначенного для работы в ограниченном количестве пространства памяти плат Arduino. Для подключения к сети он использует плату Ethernet Shield/W5100, состыкованную с платой Arduino в обычном порядке. С помощью библиотеки TinyWebServer логика работы контроллера теперь может быть полностью отделена от отображения страниц. При этом Arduino не обязатель- но формировать страницы полностью — веб-страницы, изображения и другой кон- тент может быть скопирован пользователем вручную на SD-карту или загружен через сервер HTTP. Файлы библиотеки TinyWebServer можно скачать со страницы: https://github.com/ ovidiucp/TinyWebServer. Работа библиотеки TinyWebServer зависит от внешней библиотеки Flash версии 5.0, файлы которой можно скачать со страницы: http://arduiniana.org/libraries/flash/. При использовании новых версий Arduino IDE (новее, чем 1.5) нербходимо изменить файл Flash.h, включив в него сразу после ♦include <AVR / pgmspace. h> следующие строки: #if ARDUINO >= 150 typedef char prog_char attribute (( progmem )); tendif Для использования библиотеки TinyWebServer необходимо в скетч включить сле- дующие строки: jfinclude <Ethernet.h> iinclude <Flash.h> iinclude <SD.h> Hnclude <TinyWebServer.h> Функционал библиотеки TinyWebServer осуществляет класс TinyWebServer. Метод конструктора принимает два аргумента: первый— список обработчиков, когда клиентом HTTP запрашиваются определенные адреса, второй — список имен заго- ловков HTTP, для которых необходима реализация обработчиков. В листинге 5.4 представлен пример реализации библиотеки TinyWebServer с одним обработчиком. // МАС-адрес сетевой платы static uint8_t mac[] = { OxDE, OxAD, OxBE, OxEF, OxFE, OxED }; // обработчик для страницы "/" (вывод на страницу "Hello World!") boolean index_handler(TinyWebServer& web_server) { web_server.send_error_code(200); web_server « F("<htmlxbody><hl>Hello World! </hlx/bodyx/html>\n" ); return true;
9(5 Глава 5 I/ список заголовков и привязанных к ним обработчиков TinyWebServer::PathHandler handlers[] = { // Register the indexjiandler for GET requests on / {"/", TinyWebServer::GET, &index_handler }, {NULL}, // The array has to be NULL terminated this way }; // создать веб-сервер TinyWebServer web = TinyWebServer(handlers, NULL); void setup() { Serial.begin(115200); EthernetDHCP.begin(mac); web.beginO; } void loopO { web.processO ; Здесь в цикле loop о для отслеживания HTTP-запросов мы должны вызвать метод веб-сервера process (). При отсутствии запросов этот метод осуществляет возврат, а при поступлении запроса он блокирует выполнение цикла, пока запрос не будет обработан. 5.5.1. Использование файлов с SD-карты для формирования веб-страниц На плате Ethernet Shield/W5100 размещен слот для флеш-карты формата MicroSD, на которую пользователем могут быть записаны те или иные файлы. TinyWebServer позволяет задействовать эти файлы для формирования веб-страниц, что избавляет нас от необходимости использовать для этого память Arduino. В листинге 5.5 представлен код обработчика для выдачи веб-сервером страницы, содержимое которой находится в файле на SD-карте. boolean file__handler(TinyWebServer& web_server) { char* filename = TinyWebServer: :get_file_fromj?ath(web_server.get_path()); if (!filename) { webjserver. send_error__code (404); web_server « "Could not parse URL"; } else { TinyWebServer: :MimeType mime_type = TinyWebServer::get mime_type_from_filename (filename);
Использование Arduino в качестве контроллера исполнительных устройств web_server. send_error_code (mime_type, 200); if (file.open(filename, O_READ)) { web_server.send_file(file); file.close(); } else { web_server « "Could not find file: " « filename « "\n"; } free(filename); } return true; Список имен заголовков для этого обработчика следующий: TinyWebServer::PathHandler handlers[] = { {"/" "*", TinyWebServer::GET, Sfilejiandler }, {NULL}, } Запись "/" п*и указывает, что обработчик вызывается для любого адреса (URL), следующего после "/". При запросе /contentl на веб-страницу будет выводиться содержимое файла contenti либо сообщение Could not find file:contentl при его от- сутствии на SD-карте. 5.5.2. Включение/выключение реле с веб-страницы Напишем скетч для удаленного включения/выключения нескольких реле, подсо- единенных к плате Arduino, состыкованной с Ethernet Shield. Для этого создадим на Arduino веб-сервер, используя библиотеку TinyWebServer. Прежде всего подключим к цифровым выводам Arduino три реле. Контакты микро- контроллера не могут обеспечить мощность, необходимую для нормальной работы катушек реле. Поэтому нужно усилить ток — добавить n-p-n-транзистор, включен- ный по схеме с ОЭ, согласно схеме, приведенной на рис. 5.3. В этом случае выдача высокого уровня на контакт Arduino приведет к включению реле, подача низкого уровня — к его выключению. Для того чтобы наш проект выглядел современно, мы воспользуемся технологией AJAX, которая позволяет отправлять данные на сервер и получать данные с сервера без перезагрузки страницы. Технология AJAX В нормальных веб-приложениях пользователи заполняют поля форм и нажимают кнопку Submit (Подтвердить). После этого форма передается на сервер полностью, сервер обрабатывает сценарий (обычно РНР или Java, возможно, CGI-процесс или что-то в этом роде), а потом передает назад всю новую страницу. Эта страница может быть HTML-страницей с новой формой с некоторыми заполненными данными, либо страницей подтверждения, либо страницей с какими-то выбранными вариантами, за- висящими от введенных в оригинальную форму данных. Естественно, пока сценарий или программа на сервере не обработается и не возвратится новая форма, пользова-
100 Глава 5 тели должны ждать. Их экраны очистятся и будут перерисовываться по мере поступ- ления новых данных от сервера. Вот где проявляется низкая интерактивность — поль- зователи не получают немедленной обратной реакции и определенно чувствуют себя не так, как при работе с настольными приложениями. Технология AJAX по существу помещает технологию JavaScript и объект XMLHttpRequest между вашей веб-формой и сервером. Когда пользователи заполня- ют формы, данные передаются в некий JavaScript-код, а не прямо на сервер. Вместо этого JavaScript-код собирает данные формы и сам передает запрос на сервер. Пока это происходит, форма на экране пользователя не мелькает, не мигает, не исчезает и не блокируется. Другими словами, код JavaScript передает запрос в фоновом режи- ме — пользователь даже не замечает, что происходит запрос на сервер. Более того, запрос передается асинхронно, а это означает, что ваш JavaScript-код (и пользова- тель) не ожидает ответа сервера. То есть, пользователи могут продолжать вводить данные, прокручивать страницу и работать с приложением. Когда же сервер передает данные обратно в ваш JavaScript-код (все еще находящий- ся в вашей веб-форме), тот решает, что делать с данными. Он может обновить поля формы «на лету», придавая свойство немедленности вашему приложению, — пользо- ватели получают новые данные без подтверждения или обновления их форм. JavaScript-код может даже получить данные, выполнить какие-либо вычисления и пе- редать еще один запрос, и все это без вмешательства пользователя! В этом заключа- ется мощь XMLHttpRequest — он может общаться с сервером по своему желанию, а пользователь даже не догадывается о том, что происходит на самом деле. В резуль- тате мы получаем в веб-форме динамичность, чувствительность и высокую интерак- тивность настольного приложения вместе со всеми возможностями Интернета. 5.5.3. Веб-страница для управления реле Создадим HTML-страницу для удаленного изменения статуса трех реле с исполь- зованием технологии AJAX. Веб-страница представляет собой форму, на которой расположены три элемента radio, — каждый такой элемент показывает статус од- ного из реле: ON — включено, OFF — выключено (рис. 5.13). Добавим в форму еще один элемент input, в который станем передавать ответ сер- вера на ajax-запрос веб-страницы на изменения статуса реле. HTML-код формы представлен в листинге 5.6. Set Arduino Relay Status RELAY! OFF •• ON RELAY2 OFF ■♦ ON RELAY3 OFF ♦ ON Рис. 5.13. Веб-страница для удаленного включения/выключения реле, подключенных к Arduino
Использование Arduino в качестве контроллера исполнительных устройств 101 <form name=forml action^1return false;f> RELAYl<br> OFF<input type=radio name=relayl value=0 checked onclick="SetArduinoOutput(1,0);"> <input type=radio name=relayl value=l onclick="SetArduinoOutput(1,1);">ON <br>RELAY2<br> OFF<input type=radio name:ssrelay2 value=0 checked onclick="SetArduinoOutput (2,0); "> <input type=radio name=relay2 value=l onclick="SetArduinoOutput(2,1);">ON <br>RELAY3<br> OFF<input type^radio name=relay3 value=0 checked onclick="SetArduinoOutput(3,0);"> <input type=radio name=relay3 value^l onclick="SetArduinoOutput(ЗД);">ON <brxbr><brxbr> <input type=text name="resl" id="resl" value="result"/> </form> При изменении значение элемента radio (с on на off или наоборот) вызывается js-функция SetArduinoOutput о, которая создает объект XMLHttpRequest для от- правки данных на сервер и получения ответа с сервера с использованием AJAX. В ЛИСТИНГе 5.7 Представлен КОД jS-фуНКЦИИ SetArduinoOutput (). <script> function SetArduinoOutput(pin,value) { nocache - "&nocache=" + Math.randomO * 1000000; var request = new XMLHttpRequest(); request.onreadystatechange = function 0 { if (this.readyState — 4) { if (this.status — 200) { if (this.responseXML != null) { // разбор XML ответа сервера document.getElementById("resl").value = this.responseXML.getElementsByTagName('messagef)[0] childNodes[0].nodeValue;
102 Глава 5 request.open("GET", "setrelay"+"&pin="+pin.toString () +l'&value=" +value.toString()+nocache, true); request.send(null); } </script> Код запрашиваемой страницы должен находиться в файле RELAYS, расположенном на SD-карте. Эта страница подгружается при URL-запросе /relays к TinyWebServer на Arduino. Вот список имен заголовков HTTP: TinyWebServer::PathHandler handlers[] = { {"/", TinyWebServer::GET, &index_handler }, {"/setrelay" "*", TinyWebServer::GET, &set_relays }f {"/" "*", TinyWebServer::GET, &file_handler }, {NULL}, }; При обращении по URL http://<ipArduino>/reiays вызывается обработчик file handier о, который выведет на страницу содержимое файла RELAYS с SD-карты. Код обработчика представлен в листинге 5.8. boolean file_handler(TinyWebServer& web_server) { if (!has_f ilesystem) { web_server.send_error_code(500); web_server « F("Internal Server Error"); return true; } char* filename = TinyWebServer: :get__file__from_path(web_server.get__path() ); if (! filename) { web_server. sendee rror__code (400); web_server « F("Bad Requestl"); return true; } send__file__name (web_server, filename); free(filename); return true; } void send_file_name(TinyWebServer& web_server, const char* filename) { TinyWebServer: :MimeType mime_type = TinyWebServer: :getjnime_type__from_filename(filename);
Использование Arduino в качестве контроллера исполнительных устройств 103 if (file.open(&root, filename, OJREAD)) { web_server.send_error_code(200); web_server. send_content_type (mime_type); web_server. end__headers (); Serial « F("Read file "); Serial.println(filename); web_server. send_file (file) ; file.close (); else web__server. send__error_code (404); web_server.send_content_type("text/plain"); web_server.end_headers(); Serial « F("Could not find file: "); Serial.println(filename); web__server « F("404 - ERROR ") « filename « "\n"; Данные на сервер страница отправляет методом GET no URL http://<ipArduino>/ setreiay. При поступлении на TinyWebServer этого запроса вызывается обработчик setreiays (), который должен обработать полученные методом GET данные, выде- лить номер реле и значение для него, включить (или выключить) реле и отправить серверу в формате XML ответ следующего содержания: <xml version - "1.0" ?>" <inputs> <message>relay X on(off) </message> </inputs> Содержимое обработчика setreiays () представлено в листинге 5.9. // включение/выключение реле по запросу boolean set_relays(TinyWebServer& web_server) { char* filename = TinyWebServer: :get_file_from_j)ath(web_server.get_path() ); String strl(filename); Serial.printIn(strl); // установка реле digitalWrite(pinrelays[convertl(strl,13,14)-1],convertl(strl,21,22)); if(!filename) { web server.send error code(400);
104 Глава 5 web_server « F("Bad Requestl"); return true; } web_server. send_error_code (200); web_server.send_content_type("text/xml"); web_server.end_headers(); webjserver « F("<?xml version = \"1.0\" ?>"); web_server « F("<inputs>"); web_server « F("<message>relay ")«strl.substring(13,14); if(convertl(strl,21,22)>0) web_server « F(" on"); else web_server « F(" off"); web_server « F("</message>"); web_server « F("</inputs>"); return true; } // выделение нужных значений из GET-данных int convert1(String strstr,int startl,int endl) { char *strint=new char[2]; String str3; str3=strstr.substring(start1,endl);str3.toCharArray(strint, 2); return atoi(strint); При этом индексная страница на сервере (рис. 5.14) представляет собой меню для выбора страницы включения/выключения реле Set relays (/relays) или управления сервоприводами Set servos (/servos) — эту опцию мы рассмотрим в следующем разделе. При поступлении запроса индексной страницы вызывается обработчик indexJiandler () (ЛИСТИНГ 5.10). // главная страница boolean index_handler(TinyWebServer& web_server) { webjserver.send_error_code(200); web_server.send_content_type("text/html"); web_server.endjieaders(); web_server « F("<htmlxbody><hl>Menu</hl>") ; web_server « F("<a href=f /relaysf>Set relays</axbr>") ; web_server « F("<br>"); web_server « F("<a href=f/servos1>Set servos</a><br>"); web_server « F return true;
Использование Arduino в качестве контроллера исполнительных устройств 105 Menu Set relays Set servos Рис. 5.14. Индексная страница нашего TinyWebServer Электронный архив Скетч, соответствующий листингам, описывающим управление реле из веб-страницы, созданной с использованием технологии AJAX, можно найти в файле arduino_ scetches\J)5\J)5_1214.ino сопровождающего книгу электронного архива. 5.5.4. Веб-страница для управления сервоприводом Добавим на наш TinyWebServer страницу управления сервоприводом (рис. 5.15). С помощью HTML-элемента range (ползунок) мы станем задавать угол поворота сервопривода, а в элемент input— передавать ответ сервера на ajax-запрос веб- страницы по изменению угла поворота сервопривода. HTML-код такой формы поедставлен в листинге 5.11. Set Arduino Relay Status RELAYl Sevol*"" [servo 1 set 130 Рис. 5.15. Веб-страница для удаленного управления сервоприводами, подключенными к Arduino <form name=forml action=freturn false;f> ServoKinput type=range name=servol min=0 max=180 step=l value=90 onchange=MSetArduino0utput(1,this.value);"> <br>
106 Глава 5 Servo2<input type=range names:sservo2 min=O max=180 step=l value=90 onchange="SetArduinoOutput(2,this.value);"> <brxbrxbrxbr> <input type=text name=resl id=resl value="result"> </form> При щелчке мышью по линии движения ползунка (элемент range) или по его от- пусканию по завершении передвижения вызывается js-функция setArduinoOutputo, которая создает объект XMLHttpRequest для отправки данных на сервер и получе- ния ответа с сервера с использованием AJAX. В листинге 5.12 представлен код jS-фуНКЦИИ SetArduinoOutput (). <script> function SetArduinoOutput(pin, value) { var valuel="fl; if(value<10) valuel=valuel+flOO"+value; else if(value<100) valuel=valuel+"O"+value; else valuel=valuel+value; nocache = "&nocache=" + Math.random() * 1000000; var request = new XMLHttpRequest(); request.onreadystatechange - function() { if (this.readyState — 4) { if (this.status — 200) { if (this.responseXML != null) { // разбор XML ответа сервера document.getElementByld("res1").value - this.responseXML.getElementsByTagName('message') [0].childNodes[0].nodeValue; request.open("GET", "setservof4fl&pin-"+pin+"&value="+valuel+nocachef true); request.send(null); } </script> Код запрашиваемой страницы находится в файле SERVOS, расположенном на SD-карте. Эта страница подгружается при URL запросе /servos к TinyWebServer на
Использование Arduino в качестве контроллера исполнительных устройств 707 Arduino. Добавляем этот запрос и обработчик запроса к списку имен заголовков HTTP: TinyWebServer::PathHandler handlers[] = { {"/", TinyWebServer::GET, &indexjiandler }, {"/setservo" "*", TinyWebServer::GET, &set__servos }, {"/setrelay" "*", TinyWebServer::GET, &set_relays }, {"/" "*", TinyWebServer::GET, &file_handler }, {NULL}, }; При обращении по URL http://<ipArduino>/servos вызывается обработчик f ilehandier (), который выведет на страницу содержимое файла SERVOS с SD- карты. С кодом этого обработчика мы уже знакомы (см. листинг 5.8). Данные на сервер страница отправляет методом GET no URL http://<ipArduino>/ setservo. При поступлении на TinyWebServer этого запроса вызывается обработчик setservos (), который должен обработать полученные методом GET данные, выде- лить номер сервопривода и угол поворота, выдать команду поворота для сервопри- вода и отправить серверу в формате XML ответ следующего содержания: <xml version = "1.0" ?>" <inputs> <message>servo X set XXX </message> </inputs> Далее для управления сервоприводом используем библиотеку Arduino Servo: 1. Подключаем библиотеку Servo: #include <Servo.h> 2. Создаем экземпляры объектов: Servo myservol; Servo myservo2; 3. Подключаем переменные myservol и myservo2 к выводам Arduino: myservol.attach(2); myservo2.attach(3); 4. Поворачиваем сервоприводы на угол, равный значению ползунка на веб-стра- нице: myservol.write(convert1(strl,21,24f4)); myservo2.write(convert1(strl,21,24,4)); Содержимое обработчика set_servos () представлено в листинге 5.13. // управление поворотом сервопривода по запросу boolean set__servos (TinyWebServer & web_server)
108Глава 5 char* filename * TinyWebServer: :get_file_fromjpath(web_server.getj?ath()); String strl(filename); Serial.printIn(strl); if({filename) { web_server. send_error_code (400); web__server « F("Bad Requestl"); return true; } if (convertl(strl,13,14,2)—1) myservol.write(convert1(strl,21,24,4)); // поворот серво 1 else if (convertl(strl,13,14,2)—2) myservo2.write(convertl(strl,21,24,4)); // поворот серво 2 else I/ ответ серверу web_server.send_error_code(200); web_server.send_content_type("text/xml"); web_server.end_headers (); web_server « F("<?xml version - \"1.0\" ?>"); web_server « F("<inputs>"); web^server « F("<message>servo fl)«strl.substring(13,14); web_server « F(" set ")«convertl(strl,21,24,4); web_server « F(lf</message>fl); web_server « F("</inputs>"); return true; } // выделение нужных значений из GET-данных int convertl(String strstr,int startl,int endl, int kol) { char *strint=new char[kol]; String str3; strS^strstr.substring(start1,endl);str3.toCharArray(strint,kol); return atoi(strint); Электронный архив Скетч, соответствующий листингам, описывающим управление сервоприводами из веб-страницы, созданной с использованием технологии AJAX, можно найти в файле arduino_scetches\_05\_05jl517.ino сопровождающего книгу электронного архива. В следующих главах мы еще вернемся к использованию библиотеки TinyWebServer для удаленного доступа к показаниям датчиков Arduino. Вернемся и к удаленному управлению исполнительными устройствами, подключенными к Arduino, но уже с использованием платы GPS/GPRS Shield.
ГЛАВА 6 Arduino и устройства 12С В главе 4 мы рассмотрели работу плат Arduino с аналоговыми датчиками, но может ли Arduino общаться с более сложными устройствами? Разумеется! — Arduino спо- собен реализовать имеющиеся возможности, взаимодействуя через различные ин- терфейсы со множеством внешних компонентов. Чтобы упростить обмен данными между микроконтроллером и огромным количеством всевозможных модулей, соз- дан ряд интегральных схем (ИС), реализующих стандартизированные цифровые протоколы связи. В этой главе мы рассмотрим работу Arduino с устройствами 12С. 6.1. Обзор протокола I2C Разработанная фирмой Philips шина I2C (Inter-Integrated Circuit) — это двунаправ- ленная асинхронная шина с последовательной передачей данных и возможностью адресации до 128 устройств. Физически шина 12С содержит две сигнальные линии, одна из которых (SCL) предназначена для передачи тактового сигнала, а вторая (SDA) — для обмена данными. Для управления линиями применяются выходные каскады с открытым коллектором, поэтому линии шины должны быть подтянуты к источнику питания +5 В через резисторы сопротивлением 1-10 кОм (в зависимо- сти от физической длины линий и скорости передачи данных). Длина соединитель- ных линий в стандартном режиме может достигать двух метров, скорость переда- чи— до 100 Кбит/с. Суммарная емкость линий не должна превышать 400 пФ, входная емкость на каждую ИС должна находиться в пределах 5-10 пФ. Отличительные особенности протокола: □ двунаправленный обмен по обеим линиям; □ высокая скорость обмена — до 100 Кбит/с и выше; □ возможность адресации до 128 устройств; □ простота программной реализации Master-абонента; О временная независимость процесса передачи. Все абоненты шины делятся на два класса: Master и Slave. Устройство Master гене- рирует тактовый сигнал (SCL) и, как следствие, является ведущим. Оно может
110 Глава 6 самостоятельно выходить на шину и адресовать любое Slave-устройство с целью передачи или приема информации. Все Slave-устройства «слушают» шину на пред- мет обнаружения собственного адреса и, распознав его, выполняют предписывае- мую операцию. Кроме того, возможен так называемый Multi Master— режим, когда на шине установлено несколько Master-абонентов, которые либо совместно разделяют общие Slave-устройства, либо попеременно являются то Master-уст- ройствами— когда сами инициируют обмен информацией, то Slave-устрой- ствами— когда находятся в режиме ожидания обращения от другого Master- устройства. Режим Multi Master требует арбитража и распознавания конфликтов. Естественно, он сложнее в реализации (имеется в виду программная реализация) и, как следствие, реже используется в реальных изделиях. В начальный момент времени — в режиме ожидания — обе линии, SCL и SDA, на- ходятся в состоянии логической единицы (транзистор выходного каскада с ОК за- крыт). В режиме передачи (рис. 6.1) бит данных SDA стробируется положительным импульсом SCL. Смена информации на линии SDA производится при нулевом состоянии линии SCL. Slave-устройство может «придерживать» линию SCL в нуле- вом состоянии — например, на время обработки очередного принятого байта, при этом Master-устройство обязано дождаться освобождения линии SCL, прежде чем продолжить передачу информации. Для синхронизации пакетов шины 12С различают два условия: Start и.Stop, ограни- чивающих начало и конец информационного пакета (рис. 6.2). Для кодирования SCL SDA Данные фиксированы; ! Данные фиксированы Смена данных Рис. 6.1. Диаграмма процесса передачи данных по шине I2C Рис. 6.2. Диаграмма START/STOP условия шины I2C
Arduino и устройства I2С 111 этих условий используется изменение состояния линии SCL, что недопустимо при передаче данных. Start-условие образуется при отрицательном перепаде линии SDA, когда линия SCL находится в единичном состоянии, и, наоборот, Stop- условие образуется при положительном перепаде линии SDA при единичном со- стоянии линии SCL. Передача данных начинается по первому положительному импульсу на линии SCL (рис. 6.3), которым стробируется старший бит первого информационного байта. Каждый информационный байт (8 битов) содержит 9 тактовых периодов линии SCL. В девятом такте устройство-получатель выдает подтверждение (АСК) — от- рицательный импульс, свидетельствующий о «взаимопонимании» передатчика и получателя. Сразу отметим, что любой абонент шины — как Master, так и Slave — может в разные моменты времени быть как передатчиком, так и получателем, и в соответствии с режимом обязан либо принимать, либо выдавать сигнал АСК, отсутствие которого интерпретируется как ошибка. SCL SDA передатчик SDA получатель Старт-условие АСК Подтверждение Рис. 6.3. Диаграмма подтверждения приема байта на шине I2C Временная диаграмма сигналов SCL и SDA шины 12С показана на рис. 6.4 (здесь S обозначает Start-условие, а Р — Stop-условие). Значения временных характеристик шины приведены в табл. 6.1. SCL SDA _ _ _ j / P W;STA I \\ i t "■ | ! с i L- •■ i\ \ ! «и— / V 1— tf tsU;STA 1 u l\ 1 tsu JF tmiDkl tsU;OAT j |tHO^TA ! STO -- г p Рис. 6.4. Временная диаграмма работы шины 12С
112 Глава 6 Таблица Параметр Частота сигнала SCL Свободная шина Фиксация START-условия Длительность LOW полупериода SCL Длительность HIGH полупериода SCL Готовность повторного START-условия Удержание данных Готовность данных Фронт сигналов SCL и SDA Спад сигналов SCL и SDA Готовность STOP-условия 6.1. Значения временных характеристик шины 1С Обозначение fSCL tBUF tHD.ST t|_OW thllGH tsU;STA tHD.DAT tsU.DAT tr tf tsU.STO min 0 4.7 4.0 4.7 4.0 4.7 0 250 - - 4.0 max 100 - - - - - - - 1000 300 - Единица кГц МКС МКС МКС МКС МКС МКС НС МКС Передача Передавав (п байтов* АСК) а) Передача от «Master» к «Slave» 1 I А] Данные И Данные) Чтение 6} Чтение из «Slave» Принимаемые данные (п байтов+АСК) От «Master» к «Slave» От «Slave» к «Master» «Start»-yonoBne «Stop^-условие Бит подтверждения (АСК) Отсутствие подтверждения Передача или чтение Повторный «Start» в) Комбинированный формат — передача/чтение Передача или чтение Рис. 6.5. Формат операций чтения/записи Чтобы начать операцию обмена, устройство Master выдает на шину Start-условие, за которым следует байт с адресом Slave-устройства (рис. 6.5), состоящий из семи- битового адреса устройства (занимает биты 1-7) и однобитового флага операции R/W (бит 0), определяющего направление обмена, причем 0 означает передачу от Master к Slave (рис. 6.5, а), а 1 — чтение из Slave (рис. 6.5, б). Все биты передаются по шине 12С в порядке старший-младший, т. е. первым передается 7-й бит, послед- ним 0-й. За адресом могут следовать один или более информационных байтов
Arduino и устройства I2С 1J3_ (в направлении, определенном флагом R/W), биты которых стробируются сигналом SCL из Master-устройства. При совершении операции чтения Master-абонент должен сопровождать прочитан- ный байт сигналом АСК, если необходимо прочитать следующий байт, и не выда- вать сигнала АСК, если собирается закончить чтение пакета. Допускается и многократное возобновление Slave-адреса в одном цикле передачи, т. е. передача повторного Start-условия без предварительного Stop-условия. Такой принцип широко применяется в управлении 12С абонентами, когда выдача нового Start-условия служит для синхронизации начала нового пакета данных, сопровож- даемого, например, новым управляющим словом, уточняющим адресацию пакета. Логическая реализация протоколов на шине 12С не нормируется документами фир- мы Philips, содержащими формальные описания шины, и может быть произвольной для каждой конкретной ИС. Преимущества интерфейса 12С: □ необходим всего один микроконтроллер для управления набором устройств; □ используется всего два проводника для подключения многих устройств; □ возможна одновременная работа нескольких ведущих (master) устройств, под- ключенных к одной шине 1С; □ стандарт предусматривает «горячее» подключение и отключение устройств в процессе работы системы; □ фильтр, встроенный в микросхемы, реализующие интерфейс, подавляет вспле- ски, обеспечивая целостность данных. Недостатки интерфейса 12С: □ ограничение на емкость линии — 400 пФ; □ несмотря на простоту протокола, программирование контроллера 12С затруднено из-за обилия на шине возможных нештатных ситуаций. По этой причине боль- шинство систем используют PC с единственным ведущим (master) устройством и распространенные драйверы поддерживают только монопольный режим об- мена по 12С; □ трудность локализации неисправности, если одно из подключенных устройств ошибочно устанавливает на шине состояние низкого уровня. 6.2. Arduino и библиотека Wire Библиотека Wire позволяет Arduino взаимодействовать с различными устройствами по интерфейсу I2C/TWL На платах Arduino версии R3 (с «распиновкой» 1.0) линии SDA (данные) и SCL (тактовые импульсы), связанные с этим интерфейсом, распо- ложены на разъеме возле контакта AREF. В Arduino Due реализовано два интер- фейса I2C/TWI: линии одного из них (SDA1 и SCL1) расположены возле вывода AREF, линии второго— на выводах 20 и 21. Расположение выводов I2C/TWI для различных плат Arduino показано в табл. 6.2.
114 Глава 6 Таблица 6.2. Расположение выводов I2C/TWI для различных плат Arduino Плата Arduino Uno, Ethernet Mega2560 Leonardo Due Выводы I2C/TWI A4 (SDA), A5 (SCL) 20 (SDA), 21 (SCL) 2 (SDA), 3 (SCL) 20 (SDA), 21 (SCL), SDA1, SCL1 Начиная с версии языка Arduino 1.0, библиотека Wire наследует функции класса stream, что позволяет ей быть совместимой с другими библиотеками, осуществ- ляющими запись и чтение данных. Поэтому методы send () и receive () были в ней заменены методами read () и write (). Библиотека Wire использует следующие методы: О void begin()/void begin (uint8_t address);void begin(int address); Описание: инициализация библиотеки Wire и подключение к шине 12С в каче- стве Master или Slave. Вызывается только один раз. Параметр: address — 7-битный адрес устройства (если оно работает в режиме Slave). Если параметр не указан, то контроллер подключается к шине в роли Master. Возвращаемое значение: нет. □ uint8_t requestFrom(uint8_t address, uint8_t quantity); Описание: используется мастером для запроса байта от ведомого устройства (Slave). Байты могут быть получены с помощью методов available () и read (). Параметры: • address — 7-битный адрес устройства для запроса байтов данных; • quantity — количество запрошенных байтов. Возвращаемое значение: число считанных байтов. □ void beginTransmission(uint8_t address); Описание: начало передачи 12С для ведомого устройства (Slave) с заданным адресом, с последующими вызовом метода write () для добавления последова- тельности байтов в очередь предназначенных для передачи и выполнением самой передачи данных методом endTransmission (). Параметр: address — 7-битный адрес устройства для передачи. Возвращаемое значение: нет. □ uint8__t endTransmission (void); Описание: завершает передачу данных для ведомого устройства (Slave), кото- рое было начато методом beginTransmission о, и фактически осуществляет пе- редачу байтов, которые были поставлены в очередь методом write ().
Arduino и устройства I2С ff5. Параметры: нет. Возвращаемое значение: байт, который указывает статус передачи: • 0 — успех; • 1 — данных слишком много, и они не помещаются в буфер передачи (размер буфера задается определением #def ine buffer_length 32); • 2 — получили NACK на передачу адреса; • 3 — получили NACK на передачу данных; • 4 — другая ошибка. □ size_t write (uint8_t data) ;size__t write (const uint8__t *data, size_t quantity); Вызов: • Wire. write (value); • Wire.write(string); • Wire.write(data, length); Описание: записывает данные от ведомого устройства (Slave) в ответ на запрос мастера (Master), или записывает очередь байтов для передачи от мастера к ведомому устройству (в промежутках между вызовами методов beginTransmission() И endTransmission()). Параметры: • value — значение для отправки как единичный байт; • string — строка для отправки как последовательность байтов; • data — массив байтов для отправки; • length — число байтов для передачи. Возвращаемое значение: число записанных байтов. □ int available (void); Описание: возвращает количество байтов, доступных для получения. Этот метод должно быть вызван на мастере (Master) после вызова requestFromO или ведомым устройством (Slave) внутри обработчика onReceive (). Параметры: нет. Возвращаемое значение: число байтов, доступных для чтения. □ int read (void); Описание: считывает байт, который был передан от ведомого устройства (Slave) к мастеру (Master) после вызова requestFromO или был передан от Master к Slave. Параметры: нет. Возвращаемое значение: следующий полученный байт. Пример использования этого метода приведен в листинге 6.1.
116 Глава 6 #include <Wire.h> void setup() { Wire.begin(); // подключение к шине 12С Serial.begin(9600); // запуск последовательного порта } void loop() { Wire.requestFrom(2, 6); // запрос 6-го байта от // устройства с адресом 2 while(Wire.available()) // пока есть, что читать { char с = Wire.readO; // получаем байт (как символ) Serial.print(с); // печатает в порт } delay(500); П void onReceive( void (^function)(int) ); Описание: регистрирует функцию, которая вызывается, когда ведомое устрой- ство (Slave) получает данные от мастера (Master). Параметр: function — функция, которая вызывается, когда Slave получает дан- ные. Обработчик должен принимать один параметр int (число байтов, считан- ных от мастера) и ничего не возвращать. Возвращаемое значение: нет. П void onRequest( void (^function)(void) ); Описание: регистрирует функцию, которая вызывается, когда мастер запраши- вает данные из этого ведомого устройства. Параметр: function — функция, которая будет вызываться. Возвращаемое значение: нет. 6.3. Arduino и датчик освещенности ВН1750 на шине I2C В главе 4 для измерения уровня освещенности мы использовали фоторезистор. Но если необходимо знать величину освещенности в физических единицах (люксах), он не удобен, поскольку тогда нам пришлось бы делать для такого датчика измери- тельную схему и калибровать полученные с него данные. Для получения точных величин освещенности в люксах удобнее использовать датчик ВН1750, который посредством цифрового интерфейса сможет выдавать нам готовые значения.
Arduino и устройства I2С 117_ Датчик ВН1750 обладает следующими характеристиками: □ цифровой интерфейс: 12С; □ высокое разрешение: до 0,5 Лк; □ малый потребляемый ток и наличие функции «спящего» режима; □ фильтрация световых шумов: 50/60 Гц; □ малая зависимость от источника света (лампа накаливания, светодиод и т. д.); □ малое влияние инфракрасного излучения; □ возможность выбрать два адреса микросхемы для 12С интерфейса (можно под- ключить одновременно два таких датчика к одной шине); □ не требует калибровки, что максимально удобно для применения в любых про* ектах; □ малые габариты; □ напряжение питания: 2,4-3,6 В; □ ток потреблений: 120 мкА; □ ток потребления в спящем режиме: 0,01 мкА; □ измеряемая длина волны: 560 нм; □ точность в режиме высокого разрешения: 1 Лк; □ точность в режиме низкого разрешения: 4 Лк; □ период измерения в режиме высокого разрешения: 120 мс; □ период измерения в режиме низкого разрешения: 16 мс; □ 16-битный АЦП. Для использования с платой Arduino датчик выпускается в виде модуля (рис. 6.6). Рис. 6.6. Модуль датчика ВН1750
118 Глава 6 Итак, подключим модуль датчика ВН1750 к плате Arduino (рис. 6.7) и напишем скетч получения значений освещенности в люксах. Для работы с модулем мы вос- пользуемся библиотекой ВН1750, которая является «оберткой» для библиотеки Wire. Содержимое скетча представлено в листинге 6.2. Рис. 6.7. Схема соединения модуля ВН1750 с платой Arduino UNO // подключение библиотек #include <Wire.h> #include <BH1750.h> BH1750 lightMeter; void setup() { Serial.begin(9600); // запуск последовательного порта lightMeter.begin(); // подключение к 12С Serial.println("Running..."); } void loop() { uintl6_t lux = lightMeter.readLightLevel(); // получение значения Serial.print("Light: "); Serial.print(lux); Serial.println(" lx"); delay(1000);
Arduino и устройства I2С 119 i -ight: 302 Xx -ight: 303 Xx Running... -ight: 305 Xx 313 Xx 303 Xx 47 Xx 43 Xx 317 Xx 311 Xx 310 Xx 311 Xx 310 Xx 310 Xx 312 Xx 309 Xx 308 Xx 308 Xx 307 Xx 309 Xx 295 Xx 33 Xx 25 Xx 320 Xx -ight: 316 Xx -ight: -ight: -ight: -ight: .ight: -ight: .ight: -ight: -ight: -ight: -ight: .ight: -ight: -ight: -ight: -ight: -ight: -ight: Рис. 6.8. Вывод показаний модуля ВН1750 в монитор последовательного порта Arduino IDE На рис. 6.8 показан вывод показаний модуля ВН1750 в монитор последовательного порта Arduino IDE. 6.4. Arduino и сервис Xively Для отображения информации с датчиков Arduino служит и облачный сервис Xively (https://xively.com), также реализующий возможности концепции Internet of Things. Чтобы пользоваться этим сервисом, сначала необходимо в нем зарегистрировать- ся, — на главной странице сервиса (рис. 6.9) нажимаем кнопку GET STARTED и в открывшейся форме регистрации (рис. 6.10) заполняем все необходимые поля. Зарегистрировавшись, мы можем войти в свой профиль и в разделе DEVELOP (рис. 6.11) добавить новое устройство, нажав на кнопку + Add Device. Откроется форма (рис. 6.12), в поля которой мы вводим название (здесь: Zheleznovodsk), опи- сание нового устройства (здесь: Zheleznovodsk sanatoriy), выбираем вид доступа к нему (приватный или публичный) и нажимаем кнопку Add Device, в результате чего попадаем в Xively Workbench — центр, объединяющий все датчики добавлен- ного нами устройства. Здесь отображается информация об устройстве, последние запросы, текущие значения каналов, ключей API, триггеров и многое другое.
120 Глава 6 Рис. 6.9. Главная страница сервиса Xively Рис. 6.10. Форма регистрации сервиса Xively
Arduino и устройства I2С 121 xively о Development Devices Prototype e*fm<wnt 'es^rcft я*ог<> 4* Arid Device Рис. 6.11. Добавление нового устройства в Xively Рис. 6.12. Форма для ввода данных нового устройства в Xively
122 Глава 6 ВАЛ. Отправка данных в сервис Xively Чтобы начать отправку данных из Arduino в Xively, необходимо добавить канал для каждого потока данных— например, для значений каждого подключенного к Arduino датчика. Для добавления канала в окне Xively Workbench (рис. 6.13) нажимаем кнопку Add Channel и в поля открывшейся формы вводим данные для нового канала, завершив ввод нажатием кнопки Save Channel. Как можно видеть, мы создали канал для отображения данных с нашего датчика ВН1750. Ch8firKriS last uixtafefS 3 minute* ago ff Graphs R0C|U69t LO£ II Pause DSLETt channel Ugnti «04 33*0400 aft channel Ughfi H0426»0400 Kit channel Llghti ti 04-25 *040o|j i f j PUT feed ПО2 38'-О4ОО^ (MIT enamel Ughti ю 54 48 *0400 API Keys Auto-generated Zheieznovodsk device key for feed 99H65348 x82!xX5skP«z3TJEVAFcBxX1GzSk0fcl3a)7}EvsTveuZNC8t LOCatiOn / рипйКем REAO.UPOAT£,CREATE,oaETg Рис. 6.13. Добавление нового канала для устройства в Xively Теперь приступим к написанию скетча на Arduino. Но прежде всего нам необходи- мо скачать и установить предназначенные для работы с Arduino библиотеки Xively (https://github.com/xively/xively_arduino/archive/master.zip) и HTTPClient (https:// github.com/amcewen/HttpClient/archive/master.zip). Для отправки данных в канал нам также понадобятся значения API key (x821xX5skPez3TJEVAFcBxXlGzSk0Pd3Cu7jEvsTveuZNC8t), feed (991165348) и sensorlD (BH1750), найти которые можно на странице устройства Zheleznovodsk в окне Xively Workbench (см. рис. 6.13). Отправку данных мы станем делать раз в минуту. Содержимое скетча представлено в листинге 6.3. // Подключение библиотек #include <SPI.h> #include <Ethernet.h>
Arduino и устройства I2С iinclude <HttpClient.h> tinclude <Xively.h> // Mac address нашей платы Ethernet Shield byte arduinojnac [ ] = { OxDE, OxED, OxBA, OxFE, OxFE, OxED }; // Настройки сети IPAddress arduino__ip ( 192, 168, 0, 120); IPAddress dns__ip ( 192, 168, 1, 1) ; IPAddress gateway_ip ( 192, 168, 0, 28); IPAddress subnet_mask(255, 255, 255, 0); // Your Xively key to let you upload data char xivelyKey[] - "x821xX5skPez3TJEVAFcBxXlGzSk0Pd3Cu7jEvsTveuZNC8t"; // Подключение библиотек для датчика ВН1750 iinclude <Wire.h> iinclude <BH1750.h> BH1750 lightMeter; // Данные для канала char sensorld[] = "BH1750"; XivelyDatastream datastreams [] = { XivelyDatastream(sensorId, strlen(sensorld), DATASTREAM_FLOAT), ); // Направить поток данных в канал feed XivelyFeed feed(991165348, datastreams, 1 /* количество каналов */); EthernetClient client; XivelyClient xivelyclient(client); void setup () { // подключение последовательного порта Serial.begin(9600); // запуск датчика ВН1750 lightMeter.begin(); Serial.printIn("Starting single datastream upload to Xively..."); Serial.println(); // Подключение к сети Ethernet .begin (arduinojmc, arduino_ip, dns_ip, gateway_ip, subnet_mask) ; Serial.println(Ethernet.locallP()); void loop() { // получение данных с ВН1750 uintl6__t lux = lightMeter.readLightLeveK) ; datastreams[0].setFloat(lux);
124 Глава б Serial.print("BH1750 sensor value "); Serial.println(datastreams[0].getFloat()); Serial.println("Uploading it to Xively"); // Получение ответа от Xively int ret = xivelyclient.put(feed, xivelyKey); Serial.print("xivelyclient.put returned "); Serial.println(ret); // задержка ,60 сек delay(60000); Итак, устанавливаем в разъемы платы Arduino Uno плату Ethernet Shield, подклю- чаем Ethernet Shield к сети, подключаем датчик ВН1750 и загружаем на плату Arduino скетч из листинга 6.3. Затем открываем монитор последовательного порта Arduino IDE и наблюдаем процесс отправки данных датчика ВН1750 в сервис Xively (рис. 6.14). Star Starting single datastream upload to Xively. 192.168.0.120 BH1750 sensor value 342.00 Uploading it to Xively xivelyclient.put returned 200 BH1750 sensor value 80.00 Uploading it to Xively xivelyclient.put returned 200 BH1750 sensor value 343.00 Uploading it to Xively xivelyclient.put returned 200 BH1750 sensor value 179.00 Uploading it to Xively xivelyclient.put returned 200 Рис. 6.14. Контроль из монитора последовательного порта процесса отправки данных в сервис Xively Через некоторое время мы можем зайти в свой профиль в Xively, выбрать устрой- ство и канал ВН1750 и увидеть графическое отображение отправленных из Arduino данных (рис. 6.15).
Arduino и устройства I2С 125 ЗН1750 1 /Э.00 Рис. 6.15. Графическое отображение поступающих в канал данных Электронный архив Скетч, соответствующий листингу 6.3, можно найти в файле arduino_scetches\_06\ _06_03.ino сопровождающего книгу электронного архива. 6.4.2. Получение данных из сервиса Xively Мы можем не только отправлять данные в сервис Xively, но и получать из него данные того или иного канала. Для этого подключим другую плату Arduino с Ethernet Shield на борту к сети и настроим для нее получение данных из канала ВН1750. Содержимое скетча пред- ставлено в листинге 6.4. // Подключение библиотек Ifinclude <SPI.h> iinclude <Ethernet.h> iinclude <HttpClient.h> tinclude <Xively.h> // Mac address нашей платы Ethernet Shield byte'arduino_mac[] = { OxDE, OxED, OxBA, OxFE, OxFE, OxED }; // Настройки сети IPAddress arduino_ip ( 192, 168, 0, 120);
126 Глава 6 IPAddress dnsJLp ( 192, 168, 1, 1); IPAddress gateway_ip ( 192, 168, 0, 28); IPAddress subnet_mask(255, 255, 255, 0); // Your Xively key to let you upload data char xivelyKey[] - "x821xX5skPez3TJEVAFcBxXlGzSk0Pd3Cu7jEvsTveuZNC8t"; // Данные для канала char sensorld[] = "BH1750"; XivelyDatastream datastreains [ ] = { XivelyDatastream (sensorId, strlen(sensorId), DATASTREAM_FLOAT), >; // Направить поток данных в канал feed XivelyFeed feed(991165348, datastreams, 1 /* количество каналов */); EthernetClient client; XivelyClient xivelyclient(client); void setup() { // подключение последовательного порта Serial.begin(9600); Serial.println("Starting single datastream upload to Xively..."); Serial.println(); // Подключение к сети Ethernet.begin (arduinojmc, arduino_ip, dns_ip, gateway_ip, subnet_mask) ; Serial.println(Ethernet.locallP()); void loop() { // Получение ответа от Xively int ret = xivelyclient.get(feed, xivelyKey); Serial.print("xivelyclient.get returned "); Serial.printIn(ret); // если есть данные - обработать и вывести if (ret > 0) { Serial.println("Datastream is..."); Serial.printIn(feed[0]); Serial.print("Light is: "); Serial.println(feed[0].getFloat()); } // задержка 60 сек delay(60000UL);
Arduino и устройства I2С 127 Загрузим в плату Arduino, предназначенную для получения данных, скетч из лис- тинга 6.4, откроем монитор последовательного порта Arduino ШЕ и увидим про- цесс получения данных из канала ВН1750 сервиса Xively (рис. 6.16). Reading from Xively example 192.168.0.122 xivelyclient.get returned 200 Datastream is... { "id" : "BH175011, "currentjralue" : "279.00" } Light is: 279.00 xivelyclient.get returned 200 Datastream is... { "id" : "BH175Q", "current_value" : "45.00" } Light is: 45.00 xivelyclient.get returned 200 Datastream is... { "id" : "BH1750", "current_value" : "294.00" } Light is: 294.00 xivelyclient.get returned 200 Datastream is... { "id" : "BH1750", "current_value" : "293.00" } Light is: 293.00 Рис. 6.16. Вывод в последовательный порт данных, полученных из сервиса Xively Электронный архив Скетч, соответствующий листингу 6.4, можно найти в файле arduino_scetches\_06\ _06_04.ino сопровождающего книгу электронного архива. В следующем разделе мы рассмотрим отправку и получение данных для несколь- ких каналов сервиса Xively. 6.5. Arduino и датчик влажности и температуры SHT21 на шине I2C Познакомимся с еще одним полезным датчиком, работающим по протоколу 12С, — датчиком SHT21 (рис. 6.17). По заявлению производителя (фирма Sensirion), это самый маленький в мире датчик влажности и температуры. Датчик обладает сле- дующими отличительными особенностями: □ миниатюрный размер: 3x3x1,1 мм— это, как уже отмечено, самый маленький датчик влажности в мире;
128 Глава 6 П напряжение питания: 2,1-3,6 В; □ всего 6 ножек по бокам корпуса (несмотря на миниатюрный размер, микросхему вполне можно запаять обычным паяльником); □ диапазон измерения температуры: от -40 до +125 °С с разрешением 14 бит (LSB = 0,01°C); □ диапазон измерения влажности: от 0%RH до 100%RH с разрешением 12 бит (LSB = 0,04%RH); □ потребление в режиме измерения — 300 цА, в спящем режиме — 0,15 цА; □ встроенный детектор разряда батареи выставляет флаг, если напряжение пита- ния опускается ниже 2,25 В; □ встроенный нагреватель для самодиагностики датчиков. Рис. 6.17. Датчик влажности и температуры SHT21 Если требуется получить высокую точность и стабильность показаний (в особенно- сти температуры), то при разводке платы и работе с датчиком следует придержи- ваться ряда правил. Это касается не только SHT21, но и любых датчиков темпера- туры/влажности, от которых требуется высокая точность. Дело в том, что показа- ния датчика могут оказаться ложными, если сам датчик и/или воздух вокруг него нагреваются в процессе работы. Причин для этого может быть несколько: □ саморазогрев датчика из-за непрерывной работы. Действительно, если мы по- стоянно заставляем датчик измерять температуру или влажность, пересчитывать их и выдавать данные в линию, то он будет выделять тепло. А из-за маленького размера корпуса (напомню, SHT21 — самый маленький датчик влажности в ми- ре) он скоро начнет нагреваться. Решение этой проблемы напрашивается само собой — опрашивайте датчик как можно реже. Хорошо, если отношение времени работы ко времени простоя будет около 10%. Так, SHT21 требуется 70 мс для измерения температуры и 25 мс для измерения влажности. В сумме: 95 мс. Получается, что для того чтобы датчик не разогревался, нам надо проводить замеры не чаще чем раз в 1 секунду. Учитывая, что температура и влажность обычно изменяются медленно, увели- чив задержку между опросами, мы ничего не потеряем; □ влияние источников тепла, расположенных в непосредственной близости от датчика. Передавать датчику свое тепло могут как различные силовые элемен-
Arduino и устройства I2С 129 ты, особенно если они работают в линейном режиме и сильно нагреваются, так и мощные контроллеры, работающие на высокой частоте. Большая часть такого тепла передается через медную фольгу на текстолите (печатный монтаж), по- этому рекомендуется размещать датчик как можно дальше от источников тепла и делать информационные дорожки к нему потоньше. При промышленном производстве в плате вокруг датчика делают прорези, отделяя его от остальной платы; □ передача тепла посредством конвекции. Проще говоря, горячий воздух от тех же силовых элементов может попасть в область действия датчика и привести к изменению его показаний. Способ борьбы один —- отгородить датчик от разо- гретого воздуха перегородками. Впрочем, если наше устройство не замуровано в корпус, то этой напасти можно не бояться; □ солнечный свет тоже очень сильно влияет на показания термометра. Кстати, де- лать «крышу» над датчиком, если он стоит на открытом воздухе, нужно не толь- ко для защиты от солнца, но и от дождя. Если устройство находится в корпусе, то датчик надо располагать так, чтобы кон- такт с воздухом из окружающей среды был наибольшим. Самый хороший вари- ант — когда внешний воздух свободно проходит около датчика, а от нагретого воз- духа из корпуса датчик защищен перегородкой. Для работы с Arduino датчик выпускается в виде модуля (рис. 6.18) с преобразова- телем питания от 5 В. Рис. 6.18. Модуль датчика SHT21 Схема подключения модуля датчика SHT21 к плате Arduino показана на рис. 6.19. Для работы с модулем можно использовать библиотеку SHT2x. В листинге 6.5 представлен пример считывания с датчика SHT21 данных влажности и температу- ры и вывод их в монитор последовательного порта. iinclude <Wire.h> tinclude <SHT2x.h> void setup ()
130Глава 6 Wire.begin(); Serial.begin(9600); } void loop() { Serial.print("Humidity(%RH): "); Serial.print(SHT2x.GetHumidity()); Serial.print(" Temperature(С): "); Serial.printIn(SHT2x.GetTemperature()); delay(1000); Рис. 6.19. Схема подключения модуля датчика SHT21 к плате Arduino 6.6. Arduino и сервис Xively (продолжение) 6.6.1. Отправка мультиданных в сервис Xively Добавим в схему, приведенную на рис. 6.7, датчик SHT21 и настроим дополни- тельно к отправке в сервис Xively данных освещенности (от датчика ВН1750) также и отправку данных влажности и температуры. Для этого в сервисе Xively для наше- го устройства Zheleznovodsk добавим еще два канала: SHT-H — для отправки зна- чений влажности и SHT-T — для отправки значений температуры (рис. 6.20).
Arduino и устройства I2С 131 Рис. 6.20. Создание дополнительных каналов для отправки в сервис Xively данных от датчика SHT21 Изменим соответственно и скетч из листинга 6.3, добавив в него отправку данных в несколько каналов устройства Xively. Измененный скетч представлен в листин- ге 6.6. Загрузим его в плату Arduino и увидим в сервисе Xively графическое ото- бражение поступающих с датчиков ВН1750 и SH21 данных (рис. 6.21). // Подключение библиотек tinclude <SPI.h> if include <Ethernet.h> tinclude <HttpClient.h> iinclude <Xively.h> // Mac address нашей платы Ethernet Shield byte arduino_mac[] = { OxDE, OxED, OxBA, OxFE, OxFE, OxED }; // Настройки сети IPAddress arduino__ip ( 192, 168, 0, 120); IPAddress dns_ip ( 192, 168, 1, 1);
132 Глава 6 IPAddress gateway_ip ( 192, 168, 0, 28); IPAddress subnet_mask(255, 255, 255, 0) ; // Your Xively key to let you upload data char xivelyKey[] = nx821xX5skPez3TJEVAFcBxXlGzSk0Pd3Cu7jEvsTveuZNC8t"; // Подключение библиотек для датчика ВН1750 #include <Wire.h> #include <BH1750.h> BH1750 lightMeter; // Подключение библиотеки для датчика SHT21 #include <SHT2x.h> // Данные для каналов char sensorld[] = "ВН1750"; char sensorldl[] = "SHT21-H"; char sensorld2] = " SHT21-T"; XivelyDatastream datastreams [] = { XivelyDatastream(sensorId, strlen(sensorld), DATASTREAM_FLOAT), XivelyDatastream(sensorldl, strlen(sensorldl), DATASTREAM_FLOAT), XivelyDatastream (sensorld2, strlen(sensorld2), DATASTREAM_FLOAT), }; // Направить поток данных в канал feed XivelyFeed feed(991165348, datastreams, 3 /* количество каналов */); EthernetClient client; XivelyClient xivelyclient(client); void setup() { // подключение последовательного порта Serial.begin(9600); // запуск датчика ВН1750 lightMeter.begin(); Serial.println("Starting single datastream upload to Xively..."); Serial.println(); // Подключение к сети Ethernet.begin(arduino_mac,arduino_ip,dns_ip,gateway_ip,subnet_mask); Serial.println(Ethernet.locallP()); void loop() { // получение данных с ВН1750 uintl6_t lux = lightMeter.readLightLevel(); datastreams[0].setFloat(lux); datastreams[1].setFloat(SHT2x.GetHumidity()); datastreams[2].setFloat(SHT2x.GetTemperature()
Arduino и устройства 12С 133 Serial.printIn("Uploading it to Xively"); // Получение ответа от Xively int ret = xivelyclient.put(feed, xivelyKey); Serial.print("xivelyclient.put returned "); Serial.printIn(ret); // задержка 60 сек delay(60000); put feed ?6 oo-26 «<жю put feed is«936*O4O0 put feed «r&8 45*0*00 put feed ъьтьь+ъюо put feed »s/05*040o APIIfey* Auto-generated Zheleznovodsk device key for feed 991165348 Triggers provide 'push* с«реШ1«в by sending HTTP POST requests to e URL of your choice when a condition ha* been sattefted What happens in the "Develop" stage? And what happens next? Reed the full story on Develop, Deploy and Manage her» How do I connect a device, app, or service to this feed? Рис. 6.21. Графическое отображение поступающих в канал данных Электронный архив Скетч, соответствующий листингу 6.6, можно найти в файле arduino_scetches\_06\ _06_06.ino сопровождающего книгу электронного архива. 6.6.2. Получение мультиданных из сервиса Xively Изменим скетч из листинга 6.4 для получения данных из нескольких созданных нами каналов: ВН1750, SHT21-H и SHT21-T. Содержимое скетча представлено в листинге 6.7.
134 Глава 6 /I Подключение библиотек #include <SPI.h> tinclude <Ethernet.h> #include <HttpClient.h> #include <Xively.h> // Mac address нашей платы Ethernet Shield byte arduinojnac[] = { OxDE, OxED, OxBA, OxFE, OxFE, OxED }; // Настройки сети IPAddress arduino_ip ( 192, 168, 0, 120); IPAddress dns_ip ( 192, 168, 1, 1); IPAddress gateway_ip ( 192, 168, 0, 28); IPAddress subnet_mask(255, 255, 255, 0); // Your Xively key to let you upload data char xivelyKey[] = "x821xX5skPez3TJEVAFcBxXlGzSk0Pd3Cu7jEvsTveuZNC8t"; // Данные для каналов char sensorldU = "BH1750"; char sensorldl[] = "SHT21-H"; char sensorld2] » " SHT21-T"; XivelyDatastream datastreams[] = { XivelyDatastream (sensor Id, strlen(sensorld), DATASTREAM_FLOAT), XivelyDatastream (sensorldl, strlen (sensorldl), DATASTREAM_FLOAT), XivelyDatastream(sensorld2, strlen(sensorld2), DATASTREAM_JTLOAT), }; // Направить поток данных в канал feed XivelyFeed feed(991165348, datastreams, 3 /* количество каналов */); EthernetClient client; XivelyClient xivelyclient(client); void setup() { // подключение последовательного порта Serial.begin(9600); Serial.println("Starting single datastream upload to Xively..."); Serial.println(); // Подключение к сети Ethernet.begin (arduinojmc, arduino_ip, dns_ip, gateway__ip, subnetjmask); Serial.println(Ethernet.locallPO); void loopO { // Получение ответа от Xively int ret = xivelyclient.get(feed, xivelyKey);
Arduino и устройства 12С 135 Serial. print ("xivelyclient. get returned "); Serial, print In (ret) ; // если есть данные - обработать и вывести if (ret > 0) { Serial.println("Datastream is..."); Serial.printIn(feed[0]); Serial.print("Light is: "); Serial.printIn(feed[0].getFloat()) ; Serial.print("Humidity is: "); Serial.printIn(feed[1].getFloat()); Serial.print("Temp is: "); Serial.printIn(feed[2].getFloat()); } // задержка 60 сек delay(60000UL); Загружаем в плату Arduino скетч из листинга 6.7, открываем монитор последова- тельного порта Arduino IDE и наблюдаем процесс получения данных из трех кана- лов сервиса Xively (рис. 6.22). Temp is: 22.03 xivelyclient.get returned 200 Datastream is... Light is: 153.00 Humidity is: 43.43 Temp is: 21.99 xivelyclient.get returned 200 Datastream is... Light is: 152.00 Humidity is: 43.22 Гетр is: 22.01 xivelyclient.get returned 200 Datastream is... Light is: 150.00 Humidity is: 43.34 Гетр is: 22.13 xivelyclient.get returned 200 Datastream is... ght is: 142.00 Humidity is: 42.52 Гетр is: 22.04 Рис. 6.22. Вывод в последовательный порт данных, полученных из сервиса Xively
136 Глава 6 Электронный архив Скетч, соответствующий листингу 6.7, можно найти в файле arduino_scetches\_06\ _06_07.ino сопровождающего книгу электронного архива. 6.7. Arduino и часы реального времени на шине I2C Познакомимся с еще одним 12С-устройством, весьма часто необходимым при соз- дании систем на Arduino, — микросхемой часов реального времени (RTC). Допус- тим, ваша плата Arduino собирает данные с подсоединенных к ней датчиков и ведет запись данных на внешний накопитель — например, на SD-карту. Чтобы анализи- ровать находящиеся на карте данные, необходимо записывать их вместе с времен- ной меткой, — тут и пригодится микросхема часов реального времени. Ж SDA УОС GN0 Рис. 6.23. Модуль RTC на микросхеме DS1307 Подключаемая к микроконтроллеру при помощи шины 12С, микросхема Dallas DS1307 (рис. 6.23) представляет собой часы реального времени с календарем и до- полнительной памятью nvSRAM (56 байтов). Количество дней в месяце она спо- собна с учетом високосных лет рассчитать до 2100 года. В микросхеме DS1307 имеется встроенная схема, определяющая аварийное отключение питания и авто- матически подключающая резервную батарейку. При этом отсчет времени продол- жается, и после восстановления питания часы показывают правильное время. Име- ется в этой микросхеме и программируемый генератор прямоугольных импульсов, позволяющий вырабатывать одну из четырех частот (1 Гц, 4096 Гц, 8192 Гц или 32 768 Гц). Часы подключаются по протоколу 12С всего двумя проводами — через выводы SCL и SDA интерфейса 12С. Выводы, через которые подключаются часы к шине питания, необходимо дополнительно подтянуть с помощью резисторов 2кОм. Контакты SCL и SDA на разных платах Arduino расположены на различных вы- водах: □ Uno, Nano — на выводах А4 (SDA) и А5 (SCL); □ Mega2560 — на выводах 20 (SDA) и 21 (SCL); □ Leonardo — на выводах 2 (SDA) и 3 (SCL).
Arduino и устройства I2С 137^ Вывод SDA часов подключается к выводу SDA контроллера, а вывод SDL часов — соответственно, к выводу SDL контроллера. Схема подключения микросхемы часов реального времени DS1307 и жидкокри- сталлического (LCD) индикатора WH1602 к плате Arduino показана на рис. 6.24. Рис. 6.24. Схема подключения к Arduino модуля часов реального времени DS1307 и жидкокристаллического (LCD) индикатора WH1602 Напишем скетч для вывода даты и времени, получаемых с микросхемы часов ре- ального времени DS1307, на экран LCD-индикатора WH1602 (листинг 6.8). При написании скетча мы воспользуемся библиотекой Time, которая является «оберт- кой» для библиотеки DS1307, и библиотекой Wire, предназначенной для работы с 12С-устройствами. Для работы с LCD-индикатора нам пригодится также библио- тека LiquidCrystal. // подключение библиотек для RTC tinclude <Wire.h> tinclude <Time.h> ♦include <DS1307RTC.h> // подключение библиотеки для led tinclude <LiquidCrystal.h> // инициализация с указанием контактов подключения LiquidCrystal lcd(9, 8, 7, 6, 5, 4);
138 Глава 6 void setup() { led.begin(16, 2); // установить размерность дисплея } void loop () { tmElements_t tm; if (RTC.read(tm)) // получение времени { print2digits (tm.Hour, 0,0) ; led.print(': ') ; print2digits (tm.Minute, 3,0); led.print(•:f); print2digits(tm.Second,6,0); print2digits(tm.Day,0,l); lcd.printC/1); print2digits (tm.Month, 3,1); lcd.print(f/M ; led.print(tmYearToCalendar(tm.Year)); } else { if (RTC.chipPresent()) { led.clear(); led.setCursor(0, 0); lcd.print("DS1307 is stopped"); } else { led.clear(); led.setCursor(0, 0); lcd.print("DS1307 read error"); } delay(9000); } delay(1000); } // процедура вывода на дисплей с добавлением до двух цифр void print2digits(int number,int col, int str) { led.setCursor(col, str); if (number >= 0 && number < 10) Ucd.printrO");} led.print(number);
Arduino и устройства I2С 739 При запуске скетча на экране дисплея мы увидим неверное время и неверную дату. Дело в том, что при отсутствии питания значение времени в микросхеме DS1307 сбрасывается на 00:00:00 01/01/2000. Чтобы при отключении питания время не сбрасывалось, предусмотрено аварийное питание модуля от батарейки 3 В. Для установки времени в библиотеке имеется функция rtc. write (tmEiementsj: tm). Добавим в наш скетч возможность установки данных RTC по последовательному порту отправкой в модуль строки вида: dd/mm/YYYY hh:mm:ss. Содержимое скетча показано в листинге 6.9. // подключение библиотек для RTC I include <Wire.h> ^include <Time.h> ♦include <DS1307RTC.h> // подключение библиотеки для led tinclude <LiquidCrystal.h> // инициализация с указанием контактов подключения LiquidCrystal lcd(9, 8, 7, 6, 5, 4);' // строка, собираемая из данных, приходящих в последовательный порт String inputString = ""; boolean stringComplete = false; // флаг комплектности строки void setup () { Serial.begin(9600); // запустить последовательный порт led.begin(16, 2); // установить размерность дисплея void loop () { tmElements t tm; // ожидание конца строки для анализа поступившего запроса: if (stringComplete) { tm.Day=(int(inputString[0])-48)*10+(int(inputString[1])-48); tm.Month=(int(inputString[3])-48)*10+(int(inputString[4})-48); tm.Year=CalendarYrToTm((int(inputString[6])- 48)*1000+(int(inputString[7])-48)*100+ (int(inputString[8])-48)*10+(int(inputString[9])-48)); tm.Hour=(int(inputString[11])-48)*10+(int(inputString[12])-48); tm.Minute=(int(inputString[14])-48)*10+(int(inputString[15])-48); tm.Second^(int(inputString[17])-48)*10+(int(inputString[18])-48); RTC.write(tm); // записать время в RTC
140 Глава 6 // очистить строку inputString = ""; stringComplete = false; } if (RTC.read(tm)) { print2digits(tm.Hour, 0,0); lcd.print(f:f); print2digits(tm.Minute,3,0); lcd.printC:1); print2digits (tm.Second, 6,0); print2digits(tm.Day,0,1); led.print('/'); print2digits (tm.Month, 3,1); led. print (V); led.print(tmYearToCalendar(tm.Year)); } else { if (RTC.chipPresentO) { led.clear(); led.setCursor(0, 0); led.print("DS1307 is stopped"); } else { led.clear(); led.setCursor(0, 0); led.print("DS1307 read error"); } delay(9000); } delay(1000); } // процедура вывода на дисплей с добавлением до двух цифр void print2digits(int number,int col, int str) { led.setCursor(col, str); if (number >= 0 && number < 10) Ucd.printrO");} led.print(number); } // получение данных по последовательному порту void serialEvent() { while (Serial.available())
Arduino и устройства 12С 141 { // получить очередной байт: char inChar = (char)Serial.read(); // добавить в строку inputString += inChar; // /n - конец передачи if (inChar == 'Xn1) {stringComplete = true;} Теперь установим время из монитора последовательного порта отправкой в модуль строки dd/mm/YYYY hh:mm:ss и увидим на экране дисплея отображение верных даты и времени. Электронный архив Скетчи, соответствующие листингам 6.8 и 6.9, можно найти в файлах arduino_ scetches\_06\_06_08.ino и _06_09.ino сопровождающего книгу электронного архива. 6.8. Arduino и SD-карта: чтение и запись данных Если вашим Arduino-проектам не хватает памяти (а объем энергонезависимой па- мяти EEPROM в платах Arduino совсем небольшой), можно использовать внешние носители. И одним из самых простых по подключению к платам Arduino является накопитель на SD-карте: мы можем подсоединиться к SD-карте напрямую, а можем и использовать соответствующие модули. Итак, подсоединим модуль SD Card к плате Arduino и напишем пример сохранения на SD-карте данных от датчика ВН1750. Для анализа данных освещенности потре- буется знать и время производства замеров, поэтому мы задействуем и модуль часов реального времени (RTC). Схема, соответствующая нашим пожеланиям, показана на рис. 6.25. Рис. 6.26. Схема подключения к Arduino модулей SD Card и DS1307
142 Глава 6 При написании скетча мы воспользуемся библиотекой SD для работы с SD-картой, а также библиотеками Time и DS1307 для работы с модулем RTC. Содержимое скетча показано в листинге 6.10: каждые 5 минут мы считываем данные с датчика ВН1750 и заносим время измерения и данные в файл вида d-m-Y. В начале суток создаем новый файл на новый день. // подключение библиотек для RTC #include <Wire.h> #include <Time.h> #include <DS1307RTC.h> // подключение библиотеки для SD #include <SD.h> File myFile; String sfilename; char filename[20]; const int LM335=A0; // для подключения LM335 tmElements_t tm; unsigned long millisl=0; // Подключение библиотек для датчика ВН1750 #include <Wire.h> #include <BH1750.h> BH1750 lightMeter; void setup() { // запуск датчика ВН1750 lightMeter.begin(); void loop() { // проверка, прошло 5 минут? if (millis() -millisl>5*60*00O) { millisl=*nillis (); // получить имя файла для текущего дня sf ilename=get^f ile__name (); sfilename.toCharArray(filename,20); // открыть файл или создать myFile = SD.open(filename, FILE_WRITE); // получить данные ВН1750 uintl6_t lux = lightMeter.readLightLevel();
Arduino и устройства I2С 143 // получить время Н:т // создать запись для файла record=get_time(); record+=" "; record+=String(lux); myFile.printIn(record); myFile.close(); } // получение времени дня String get_time () { String timel; RTC.read(tm) ; if (tm.Hour()<10) timel="0"+String(tm.Hour(),DEC); else timel=String(tm.Hour(),DEC); if(tm.Minute()<10) timel+=":O"+String(tm.Minute(),DEC); else timel+=lf: "+String (tm.Minute (), DEC) ; return timel; Электронный архив Скетч, соответствующий листингу 6.10, можно найти в файле arduino_scetches\J)6\ _06_10.ino сопровождающего книгу электронного архива.
ГЛАВА 7 Arduino и 1-Wire В этой главе мы рассмотрим примеры использования Arduino в связке с устройст- вами, основанными на протоколе 1-Wire. 7.1. Технология 1-Wire l-Wire (от англ. — единственный провод) — зарегистрированная торговая марка корпорации Dallas Semiconductor для системотехники шины устройств связи Dallas Semiconductor. Протокол обеспечивает низкоскоростной интерфейс для данных — обычно 16,4 Кбит/с (максимум 125 Кбит/с в режиме overdrive). Для связи с устрой- ством необходимо лишь два провода: на данные и заземление. Дело в том, что ин- тегральная схема включает конденсатор емкостью 800 пФ для питания от линии данных (так называемое питание от паразитного источника). При этом электро- питание схемы осуществляется за счет конденсатора, который заряжается в период наличия высокого уровня напряжения на линии данных. Здесь следует учитывать, что связь с устройствами, использующими паразитное питание, возможна только на коротких линиях, на длинных же линиях приходится задействовать дополни- тельный провод питания. Протокол регламентирован разработчиками для применения в четырех основных сферах-приложениях: □ приборы в специальных корпусах MicroCAN для решения проблем идентифика- ции, переноса или преобразования информации (технология iButton); □ программирование встроенной памяти интегральных компонентов; □ идентификация элементов оборудования и защита доступа к ресурсам электрон- ной аппаратуры; □ системы автоматизации (технология сетей 1-Wire). Первое из этих направлений широко известно на мировом рынке и уже давно поль- зуется заслуженной популярностью. Второе— с успехом обеспечивает возмож- ность легкой перестройки функций полупроводниковых компонентов, производи- мых фирмой Dallas Semiconductor и имеющих малое количество внешних выводов.
146 Глава 7 Третье — позволяет обеспечить недорогую, но достаточно эффективную иденти- фикацию и надежную защиту самого разнообразного оборудования. Что касается четвертого применения, то реализация локальных распределенных систем на базе шины 1-Wire является на сегодня де-факто наиболее оптимальным решением для большинства практических задач автоматизации. В настоящее время Dallas Semiconductor поставляет широкую номенклатуру однопроводных компонентов различных функциональных назначений для реализации самых разнообразных сетевых приложений. Поэтому имеется огромное число конкретных примеров использования интерфейса 1-Wire для целей автоматизации в самых различных областях, и все больше разработчиков проявляют интерес к этой технологии. Так в чем же особенность этого сетевого стандарта? Ведь в качестве среды для пе- редачи информации по однопроводной линии чаще всего возможно использование обычного телефонного кабеля и, следовательно, скорость обмена в этом случае не велика. Однако если внимательно проанализировать большинство объектов, тре- бующих автоматизации, то больше чем для 60% из них предельная скорость об- служивания в 16,3 Кбит/с будет более чем удовлетворительной. А вот и другие преимущества технологии 1-Wire: □ простое и оригинальное решение адресуемости абонентов; □ несложный протокол; □ простая структура линии связи; □ малое потребление компонентов; □ легкое изменение конфигурации сети; □ значительная протяженность линий связи; □ исключительная дешевизна всей технологии в целом. Все эти преимущества отражают очевидную рациональность и высокую эффектив- ность технологии 1-Wire при решении задач комплексной автоматизации в самых различных областях деятельности. Сеть 1-Wire представляет собой информационную сеть, использующую для осуще- ствления цифровой связи одну линию данных (data) и один возвратный (или зем- ляной) провод (ret). Таким образом, для реализации среды обмена этой сети могут быть применены доступные кабели, содержащие неэкранированную витую пару той или иной категории и даже обычный телефонный провод. Такие кабели при их прокладке не требуют наличия какого-либо специального оборудования, а ограни- чение максимальной длины однопроводной линии регламентировано разработчи- ками на уровне 300 м. Основой архитектуры сетей 1-Wire является топология общей шины, когда каждое из устройств подключено непосредственно к единой магистрали, без каких-либо каскадных соединений или ветвлений. При этом в качестве базовой используется структура сети с одним ведущим (или мастером) и многочисленными ведомыми. Впрочем, существует и ряд специфических приемов организации работы однопро- водных систем в режиме мультимастера.
Arduino u 1-Wire 147 Конфигурация любой сети 1-Wire может произвольно меняться в процессе ее рабо- ты, не создавая помех дальнейшей эксплуатации и работоспособности всей систе- мы в целом, если при этих изменениях соблюдаются основные принципы организа- ции однопроводной шины. Эта возможность достигается благодаря присутствию в протоколе интерфейса 1-Wire специальной команды поиска ведомых устройств (поиск ПЗУ), которая позволяет быстро определить новых участников информаци- онного обмена. Благодаря наличию в составе любого устройства, снабженного ин- терфейсом 1-Wire, индивидуального уникального адреса (отсутствие совпадения адресов для компонентов, когда-либо выпускаемых Dallas Semiconductor, гаранти- руется самой фирмой-производителем), такая сеть имеет практически неограни- ченное адресное пространство. При этом каждый из однопроводных компонентов сразу готов к использованию в составе сети 1-Wire без каких-либо, дополнительных аппаратно-программных модификаций. Однопроводные компоненты представляют собой самотактируемые полупроводни- ковые устройства, в основе обмена информацией между которыми лежит управле- ние длительностью импульсных сигналов в однопроводной среде и их измерение. Передача сигналов для интерфейса 1-Wire — асинхронная и полудуплексная, а вся информация, циркулирующая в сети, воспринимается абонентами либо как коман- ды, либо как данные. Команды сети генерируются мастером и обеспечивают раз- личные варианты поиска и адресации ведомых устройств, определяют активность на линии даже без непосредственной адресации отдельных компонентов, управля- ют обменом данными в сети. Стандартная скорость работы сети 1-Wire, изначально нормированная на уровне 16,3 Кбит/с, была выбрана, во-первых, исходя из обеспечения максимальной на- дежности передачи данных на большие расстояния, и, во-вторых, с учетом быстро- действия наиболее широко распространенных типов универсальных микрокон- троллеров, которые в основном должны использоваться при реализации ведущих устройств шины 1-Wire. Эта скорость обмена может быть снижена до любой воз- можной благодаря введению принудительной задержки между передачей в линию отдельных битов данных (растягиванию временных слотов протокола). Увеличение скорости обмена в сети 1-Wire выше значения 16,3 Кбит/с приводит к сбоям и ошибкам при работе на магистрали 1-Wire длиной более 1 м. Однако если длина линии 1-Wire не превышает 0,5 м, то скорость обмена может быть значительно уве- личена за счет перехода на специальный режим ускоренной передачи — overdrive (до 125 Кбит/с), который допускается для отдельных типов однопроводных компо- нентов. Как правило, такой режим обмена аппаратно реализован для однопровод- ных компонентов, имеющих большой объем встроенной памяти и предназначен- ных для эксплуатации на небольшой, но качественной и не перегруженной другими устройствами линии 1-Wire. Типичным примером таких компонентов являются микросхемы семейства iButton. При реализации интерфейса 1-Wire используются стандартные КМОПЛГТЛ логиче- ские уровни сигналов, а питание большинства однопроводных компонентов может осуществляться от внешнего источника с рабочим напряжением в диапазоне от 2,8 до 6,0 В. Причем, такой источник может быть расположен либо непосредственно
148 Глава 7 возле компонента (например, батарея в составе микросхем iButton), либо энергия от него может поступать по отдельной линии магистрали 1-Wire. Альтернативой при- менению внешнего питания служит так называемый механизм паразитного пита- ния, действие которого заключается в использовании каждым из ведомых компо- нентов линии 1-Wire электрической энергии импульсов, передаваемых по шине данных, аккумулируемой затем специальной, встроенной в микросхему, емкостью. Кроме того, отдельные однопроводные компоненты сетей 1-Wire могут использо- вать особый режим питания по шине данных, когда энергия к приемнику поступает непосредственно от мастера по шине data магистрали, при этом обмен информаци- ей в сети принудительно прекращается. 7.2. Применение 1-Wire О признании шины 1-Wire в качестве международного стандарта и серьезности от- ношения к этому интерфейсу со стороны маститых разработчиков и производите- лей электроники говорят многочисленные факты. Например, нет практически ни одного универсального микроконтроллера, в литературе по применению которого не обсуждались бы способы организации на его базе мастера линии 1-Wire. Рационально использование технологии 1-Wire при построении систем автоматиза- ции контроля и управления для разнообразного рассредоточенного оборудования, когда не требуется высокая скорость при обслуживании, но необходима сущест- венная гибкость и наращиваемость при невысоких затратах на реализацию. Приве- дем некоторые примеры активного применения устройств 1-Wire: □ автоматизация; □ метеостанции; □ многоточечные системы контроля температуры— применяются при монито- ринге микроклимата самых различных объектов, при ревизии любых операций по переработке и хранению пищи и медикаментов, для контроля температуры во многих областях промышленного производства, в холодильной технике и т. п.; П технология «Умный дом» (Home Automation) — комплекс автоматики, который управляет инженерными системами жилища (освещением, отоплением, венти- ляцией, кондиционированием, энергоснабжением, водоснабжением, электро- приводами, оборудованием пожарных и охранных систем и прочим); □ идентификация и защита электронных изделий— например, маркирование и защита картриджей для принтеров и копировальных аппаратов, а также любых требующих этого электронных изделий; □ менеджмент автономных источников энергии — строгая и полная идентифика- ция источников энергии, сохранение в памяти встроенного в батарею электрон- ного устройства особенностей ее изготовления и индивидуальных технических характеристик, наиболее полный мониторинг их основных эксплуатационных параметров на протяжении всего срока службы, а также формирование коррект-
Arduino u 1-Wire 149 ного управляющего воздействия, связанного с восстановлением заряда обслу- живаемого аккумулятора; □ ограничения и сопряжение с промышленными и глобальными сетями. Русскоязычную информацию об однопроводных компонентах, наиболее подходя- щих для организации сетей 1-Wire, можно посмотреть в сети Интернет по адресу http://www.elin.ru/l-Wire/?topic=component. Полные списки всех однопроводных устройств и приспособлений для их поддержки можно получить на интернет-сайте компании-производителя Dallas Semiconductor: http://www.maxim-ic.com. Устройства 1-Wire достаточно широко представлены в российских интернет- магазинах по приемлемым, достаточно низким, ценам. 7.3. Интерфейс 1-Wire Интерфейс 1-Wire, как уже отмечалось ранее, разработан фирмой Dallas Semi- conductor (ныне MAXIM) в конце 1990-х годов. Этот интерфейс интересен тем, что для двустороннего обмена по нему требуется всего одна линия, причем на эту линию можно повесить сразу несколько устройств. Правда, потребуются также общий провод («земля») и— но не всегда— провод питания. Протокол очень прост и легко реализуется на микроконтроллере программно. На рис. 7.1 представ- лена блок-схема аппаратной реализации 1-Wire. Микроконтроллер 4,7К Шина 1-Wire DQ Rx= ПРИЕМ Тх= ПЕРЕДАЧА УСТРОЙСТВО!-Wire Г 100 п V MOSFET Рис. 7.1. Блок-схема аппаратной реализации 1-Wire Вывод DQ устройства представляет собой вход КМОП-логического элемента, ко- торый может быть зашунтирован (замкнут на общий провод) полевым транзисто- ром. Сопротивление канала этого транзистора в открытом состоянии— около 100 Ом. Когда транзистор заперт, имеется небольшой ток утечки (примерно 5 мкА) на общий провод. Шина 1-Wire должна быть «подтянута» отдельным резистором к напряжению пи- тания (может быть от 3 до 5 В — нужно уточнять по характеристикам подключав-
150 Глава 7 мого устройства). Сопротивление этого резистора 4,7 К, однако это значение под- ходит лишь для весьма коротких линий. Если шина используется для подключения устройств на большее расстояние, то сопротивление подтягивающего резистора необходимо уменьшить (это сопротивление зависит от величины максимального втекающего тока линии DQ конкретного устройства 1-Wire). Примечательный момент— как уже отмечалось, некоторые устройства 1-Wire могут использовать так называемое паразитное/фантомное питание (Parasite power)— при котором питание устройства осуществляется от линии данных за счет встроенного конденсатора, который заряжается в период наличия высокого уровня напряжения на линии данных. Здесь следует учитывать, что связь с устрой- ствами, использующими паразитное питание, допустима только на коротких лини- ях. На длинных линиях могут присутствовать непонятные побочные эффекты. По- этому, если возможно, такого типа питания устройств следует избегать. 7.3.1. Обмен информацией по шине 1-Wire Рассмотрим, как происходит обмен информацией по шине 1-Wire. □ Передача информации возможна только выдачей низкого уровня в линию, т. е. замыканием ее на общий провод. В высокий логический уровень линия вернется сама из-за наличия подтягивающего резистора (теперь становится понятно, что наличие внешнего подтягивающего резистора— обязательное условие работы 1-Wire). □ Обмен происходит по инициативе ведущего устройства (обычно — микрокон- троллера). □ Обмен информацией начинается с подачи импульса сброса (reset pulse) на ли- нию. □ Устройства 1-Wire предусматривают «горячее» подключение. □ При подключении устройство 1-Wire выдает в линию DQ импульс присутствия (presence pulse). Этот же импульс выдается при обнаружении сигнала reset. □ Обмен информацией ведется так называемыми тайм-слотами — один слот со- держит один бит информации. □ Данные передаются побайтно — бит за битом, начиная с младшего байта. Дос- товерность данных (проверка отсутствия искажений) гарантируется путем под- счета циклической контрольной суммы (CRC). Микроконтроллер (МК) формирует импульс reset, переводя в низкий логический уровень шину 1-Wire и удерживая ее не менее 480 микросекунд. Затем МК «отпус- кает» шину, и напряжение возвращается к высокому логическому уровню — время «отпускания» зависит от емкости линии и сопротивления подтягивающего резисто- ра. Протокол 1-Wire ограничивает это время диапазоном от 15 до 60 микросекунд, что и влияет на выбор подтягивающего резистора (на время возврата линии к высо- кому уровню большее влияние оказывает емкость линии, но, чаще всего, мы изме- нить ее не можем). Обнаружив импульс reset, ведомое устройство формирует от-
Arduino u 1-Wire 151 ветный импульс presence. Для этого устройство «прижимает» линию DQ к «земле» и удерживает ее в таком состоянии от 60 до 240 микросекунд. Затем устройство так же «отпускает» шину. После этого устройству еще дается время для завершения внутренних процедур инициализации. Таким образом, МК должен приступить к любому обмену с устройством не ранее, чем через 480 микросекунд после завер- шения импульса reset. Соответственно, процедура инициализации, с которой на- чинается обмен данными между устройствами, длится минимум 960 микросекунд (рис. 7.2). GND МК передает импульс RESET Шина 1-Wire 480 jiS минимум Время реакции 15-60 |is Г МК находится в состоянии приема 480 jus минимум Устройство передает импульс PRESENCE 60-240 us * МК удерживает низкий уровень Устройство удерживает низкий уровень Уровень в линии обеспечивает резистор "подтяжки" Рис. 7.2. Процедура инициализации Теперь рассмотрим процедуры обмена битами информации, которые осуществ- ляются определенными тайм-слотами— жестко лимитированными по времени последовательностями смены уровней сигнала в линии 1-Wire (рис. 7.3). Различают 4 типа тайм-слотов: □ передача «1» от МК; □ передача «0» от МК; □ прием «1» от устройства; □ прием «0» от устройства. Тайм-слот всегда начинает микроконтроллер, «прижимая» шину к «земле». Дли- тельность тайм-слота находится в пределах от 60 до 120 микросекунд. Между тайм-слотами всегда должен быть интервал не менее 1 микросекунды (оп- ределяется параметрами ведомого устройства). Тайм-слоты передачи отличаются от тайм-слотов приема поведением микроконтроллера: □ при передаче МК только формирует сигналы; □ при приеме МК еще и опрашивает уровень сигнала в линии 1-Wire.
152 Глава 7 Начало тайм-слота Начало тайм-слота Шина 1-Wire GND- Шина 1-Wire GND- > 1 Тайм-слот передачи "О" 60|lis<Tx"0"<120 15|is 15 jus 30 Тайм-слот передачи "1" < TREC < оо > 1 JLlS 15 jus 15 30 Тайм-слот приема Устройство передает "О" Устройство передает "Г us < TREC < оо 15 -:< Зона ввода значения в МК 45 us > 1 JulS Зона ввода значения в МК 15 Рис. 7.3. Процедура обмена битами информации Тайм-слот передачи «О» заключается просто в «прижимании» шины 1-Wire к «зем- ле» в течение всей длительности тайм-слота. Передача «1» осуществляется путем «отпускания» шины 1-Wire со стороны МК не ранее чем через 1 микросекунду по- сле начала тайм-слота, но не позже чем через 15 микросекунд. Ведомое устройство опрашивает уровень в шине 1-Wire в течение временного интервала (показанного на рис. 7.3 в виде серого прямоугольника), т. е. начиная с 15-й микросекунды от начала тайм-слота и заканчивая 60-й микросекундой его от начала (для большинст- ва устройств — около 30-й микросекунды от начала тайм-слота). Заштрихованная на рис. 7.3 область — это область «нарастания» уровня в шине 1-Wire, которая зависит от емкости линии и сопротивления подтягивающего рези- стора. Тайм-слоты приема информации отличаются тем, что МК формирует только начало тайм-слота (так же, как при передаче «1»), а затем управление уровнем ши- ны 1-Wire берет на себя устройство, а МК осуществляет ввод этого уровня так же в определенной зоне временных интервалов. Зона эта, как видно из рис. 7.3, довольно мала. Поскольку заштрихованная область— область неопределенности, то для ввода микроконтроллеру остается даже не промежуток, а скорее конкретный мо-
Arduino и 1-Wire 153_ мент, когда он должен ввести уровень сигнала из линии. Этот момент времени — 14-я или 15-я микросекунда от начала тайм-слота. Резюмируем: □ микроконтроллер начинает тайм-слот, «прижимая» шину 1-Wire к логическому «О» в течение 1 микросекунды; □ последующий уровень зависит от типа тайм-слота: для приема и передачи «1» уровень должен стать высоким, а для передачи «О» — оставаться низким вплоть до конца тайм-слота, т. е. от 60 до 120 микросекунд; □ принимая данные, МК должен считывать уровень в шине 1-Wire в промежутке от 13-й до 15-й микросекунды тайм-слота; □ микроконтроллер должен обеспечить интервал между тайм-слотами не менее 1 микросекунды (лучше — больше, максимальное значение не ограничено). Для достижения требуемых временных интервалов надо следовать простым пра- вилам: □ все сигналы, которые должен формировать МК, следует формировать по прин- ципу необходимого минимума длительности (т. е. немного больше, чем указан- ная минимальная длительность); □ от устройства следует ожидать сигналов по принципу наихудшего (т. е. ориен- тироваться на самые худшие варианты временных параметров сигнала). 7.3.2. Протокол обмена информацией 1-Wire Каждое устройство 1-Wire обладает уникальным идентификационным 64-битным номером, программируемым на этапе производства микросхемы: □ первые 8 битов — номер серии устройства (список некоторых кодов семейств 1-Wire-устройств приведен в табл. 7.1); □ следующие 48 битов — уникальный серийный номер; □ последние 8 битов — CRC-код предыдущих 56 битов информации. Фирма-производитель гарантирует, что не найдется двух микросхем с одинаковым идентификационным номером. Нетрудно посчитать, что устройств одного типа может быть выпущено 281 474 976 710 655 (десятичное представление OxFFFFFFFFFFFF — 48 битов, или 6 байтов идентификационного номера). Предположим, что на шине 1-Wire имеется более одного устройства. В этом случае перед микроконтроллером встают две проблемы: определение количества имею- щихся устройств и выбор (адресация) одного конкретного из них для обмена дан- ными. Номера некоторых устройств наносятся прямо на корпус микросхем (напри- мер, для ключей-таблеток — iButton), а номера других можно определить при по- мощи специальных программ или устройств. Итак, пусть мы знаем номера всех устройств 1-Wire на шине. Алгоритм работы с ними следующий: 1. Микроконтроллер посылает импульс reset, и все имеющиеся устройства выда- ют PRESENCE.
154 Глава 7 2. Микроконтроллер посылает в шину команду, которую принимают все устройст- ва. Определено несколько общих команд для всех типов устройств 1-Wire, есть так же и команды, уникальные для отдельных типов устройств. 3. После того, как микроконтроллер выдаст команду read rom, от устройства по- ступит 8 байтов его собственного уникального адреса — микроконтроллер дол- жен их принять. Любая процедура обмена данными с устройством должна быть завершена полностью либо прервана посылкой сигнала reset. 4. Если отправлена команда match rom, to после нее микроконтроллер должен пе- редать 8 байтов адреса конкретного устройства, с которым будет осуществлять- ся последующий обмен данными. 5. Приняв эту команду, каждое устройство сравнивает передаваемый адрес со сво- им собственным. Все устройства, адрес которых не совпал, прекращают анализ и выдачу сигналов в линии 1-Wire, а опознавшее адрес устройство продолжает работу. Теперь все данные, передаваемые МК, будут попадать только к этому «адресованному» устройству. 6. Если устройство на шине единственное — можно ускорить процесс взаимодей- ствия с ним при помощи команды skip rom. Получив эту команду, устройство сразу считает адрес совпавшим, хотя никакого адреса за этой командой не сле- дует. Некоторые процедуры не требуют приема от устройства никаких данных, в этом случае команду skip rom можно использовать для передачи какой-то ин- формации сразу всем устройствам— например, для одновременного запуска цикла измерения температуры несколькими датчиками-термостатами типа DS18S20. Общие команды для всех типов устройств 1-Wire представлены в табл. 7.1. Таблица 7.1. Общие команды для всех типов устройств 1-Wire Команда SEARCH ROM READ ROM MATCH ROM SKIP ROM Значение байта OxFO 0x33 0x55 OxCC Описание Поиск адресов — используется при универсальном алгоритме определения количества и адресов подключенных устройств Чтение адреса устройства — используется для определения адреса единственного устройства на шине Выбор адреса — используется для обращения к конкретному адресу устройства из многих подключенных Игнорировать адрес — используется для обращения к единст- венному устройству на шине, при этом адрес устройства игно- рируется (можно обращаться к неизвестному устройству) Прием и передача байтов всегда начинается с младшего бита. Порядок следования байтов при передаче и приеме адреса устройства так же ведется от младшего к старшему. Порядок передачи другой информации зависит от конкретного.уст- ройства.
Шито и 1-Wire Алгоритм поиска устройств 1-Wire следующий: 1. Поиск начинается с импульса reset от ведущего устройства и принятия PRESENCE ОТ ВеДОМЫХ. 2. Затем посылается 1 байт команды: • Oxfo — осуществляется поиск всех устройств на линии; • Охес— поиск среди устройств, находящихся в состоянии тревоги (alarm state). 3. Устройства отправляют первый бит своего уникального номера. Если несколько устройств передают свой бит одновременно, результирующий бит на линии по- лучится как результат операции логического И (and). 4. Следующий бит, который отправляют устройства, — это дополнение первого бита (если первый бит был 1, то будет 0 и наоборот: если был 0 — теперь бу- дет 1). На основании этих двух битов ведущее устройство может сделать вывод о первом бите устройств на линии. 5. Далее микроконтроллер отправляет принятый бит назад. И теперь продолжат работу только те ведомые устройства, у которых этот бит установлен. Если же устройство такого бита не имеет, оно должно перейти в режим ожидания до сле- дующего сигнала reset. 6. Такая «двубитная передача» повторяется для всех следующих 63 битов ROM. 7. Все устройства на линии, кроме одного, перейдут в состояние ожидания, а код ROM этого единственного устройства будет известен. 7.4. Arduino и цифровой датчик температуры DS18B20 7.4.1. Цифровой датчик температуры DS18B20 DS18B20 (рис. 7.4)— цифровой термометр с программируемым разрешением от 9 до 12 битов, способный сохранять данные замеров в памяти EEPROM прибора. DS18B20 обменивается данными по шине 1-Wire и при этом может быть как един- ственным устройством на линии, так и работать в группе. Все процессы на шине управляются центральным микропроцессором. Диапазон измерений датчика: от -55 до +125 °С с точностью 0,5°С в диапазоне от-10 до +85 °С. В дополнение DS18B20 может питаться напряжением линии дан- ных (так называемое питание от паразитного источника) при отсутствии внешне- го источника напряжения. Каждый датчик типа DS18B20 имеет уникальный 64-битный последовательный код, который позволяет общаться с множеством датчиков DS18B20, установленных на одной шине. Первые 8 битов — код серии (для DS18B20 — 28h), затем 48 битов уникального номера и в конце 8 битов CRC-кода. Такой принцип позволяет ис-
156 Глава 7 Рис. 7.4. Цифровой датчик температуры DS18B20 пользовать один микропроцессор, чтобы контролировать множество датчиков DS18B20, распределенных по большому участку. Характеристики датчика DS18S20: □ интерфейс 1-Wire; □ измеряемая температура: от -55 до +125 °С; □ точность 0,5 °С в диапазоне от -10 до +85 °С; □ температура считывается 9-ю битами данных; □ время на конвертацию температуры — 750 мс (максимальное). Данные о температуре хранятся в оперативной памяти датчика (рис. 7.5). Память состоит из оперативной ROM и энергонезависимой EEPROM: □ первые два байта — содержат данные об измеренной температуре; □ третий и четвертый байты хранят верхний (тн) и нижний (tl) пределы темпера- туры; □ пятый и шестой — не задействованы; □ седьмой и восьмой— байты-счетчики. Они могут использоваться для более точного измерения температуры; □ девятый байт хранит CRC-код предыдущих восьми. Кроме общих для всех типов 1-Wire-устройств команд, представленных в табл. 7.1, датчик может выполнять следующие команды: □ Alarm search [ECh] — операция этой команды идентична операции поиска адре- сов [FOh], за исключением того, что в данном случае ответят только те датчики,
Arduino u 1-Wire 157 byteO byte I byte 2 byte3 byte 4 byte 5 byte 6 byte 7 byte 8 SCRATCHPAD (Power-up State) Temperature LSB (5Oh) 1 Temperature MSB (05h) J TH Register or User Byte 1* TL Register or User Byte 2* Configuration Register* Reserved (FFh) Reserved (OCh) Reserved (lOh) CRC* EEPROM Щ w 4* fe 4k lb Тн Register or User Byte I TL Register or User Byte 2 Configuration Register *Co ит от значений, сохраненного в EEPROM Рис. 7.5. Карта памяти DS18B20 у которых при последнем измерении температура вышла за установленные пре- делы (выше тн или ниже tl); □ convert т [44h] — конвертировать температуру. Датчик произведет измерение и запись данных о текущей температуре. Если ведущее устройство будет за этой командой слать тайм-слоты чтения, то пока конвертация не закончена, DS18S20 будет выдавать в линию «О», а после завершения конвертации «1»; □ write Scratchpad [4Eh] — запись в память. Эта команда позволяет записать 3 байта в память датчика. Первый байт запишется в тн, второй — в tl, а третий байт запишется в пятый байт памяти — это байт конфигурации; О Read Scratchpad [BEh] — чтение памяти. Команда позволяет нам считать память датчика. В ответ на эту команду датчик вернет 9 байтов своей памяти, начиная с 0-го байта temperature lsb и заканчивая восьмым — CRC; П copy scratchpad [48h] — копировать память. Датчик скопирует содержимое ОЗУ — тн и tl в EEPROM. Для получения от датчика данных о температуре необходимо выдать следующую последовательность команд: 1. Произвести reset и поиск устройств на линии 1-Wire. 2. Выдать команду 0x44, чтобы запустить конвертацию температуры датчиком. 3. Подождать не менее 750 мс. 4. Выдать команду Охве, чтобы считать ОЗУ датчика (данные о температуре будут в первых двух байтах). Датчик может запитываться двумя способами: внешним питанием (три провода) или паразитным (питание от шины, два провода). Схема подключения к Arduino датчика, запитанного от внешнего источника, представлена на рис. 7.6.
158 Глава 7 DS18B20 Arduino GND DQ VOD 1 . 3 л И*" T \ __,__, _____ Rx Тх D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D13 G АО А1 А2 A3 А4 А5 А6 А7 +3.3V ND — ____ — — — — — Рис. 7.6. Подключение к Arduino датчика DS18B20 7.4.2. Использование библиотеки OneWire для получения данных температуры с датчика DS18B20 Для работы с датчиками по интерфейсу 1-Wire можно использовать библиотеку OneWire. Электронный архив Библиотеку OneWire вы найдете в папке arduino_libraries\OneWife сопровождающего книгу электронного архива. Скетч получения данных с датчика температуры DS18B20 и вывода данных в по- следовательный порт с помощью библиотеки OneWire представлен в листинге 7.1. #include <0neWire.h> OneWire ds(10); // линия 1-Wire будет на pin 10 void setup(void) { Serial.begin(9600); void loop(void) { byte i;
Arduino u 1-Wire 159 byte present = 0; byte data[12]; byte addr[8]; if ( !ds.search(addr)) { //Serial.print("No more addresses.\n"); ds.reset_search(); return; } if ( OneWire::crc8( addr, 7) != addr[7]) { Serial.print("CRC is not valid!\n"); return; if ( addr[0] != 0x28) { Serial, print ("Device is not a DS18B20 family deviceAn"); return; ds.reset (); ds.select(addr); ds.write(0x4 4,1); // запускаем конвертацию delay(750); // ждем 750 мс present = ds.reset (); ds. select (addr); ds.write(OxBE); // считываем ОЗУ датчика for ( i =» 0; i < 9; i++) { // обрабатываем 9 байтов data[i] = ds.readO; // высчитываем температуру :) int HighByte, LowByte, TReading, Tc_100; LowByte = data[0]; HighByte « data[l]; TReading = (HighByte « 8) + LowByte; Serial.print(Temp/16); Serial.print("."); Serial.print(((Temp%16)*100)/16); Serial. println (); Вывод показаний датчика температуры DS18B20 в последовательный порт показан на рис. 7.7.
160 Глава 7 Т - 19 43 Т - 19.43 Т - 19.43 Т - 19 43 Т « 19 43 Т - 19.50 • 19.43 Т - 19.50 Т - 19.50 Т - 19.50 Т - 19 50 Т - 19.50 Т - 19 50 Т - 19 50 Т - 19.50 Рис. 7.7. Вывод показаний датчика DS18B20 в последовательный порт В главе 8 мы рассмотрим использование датчика DS18B20 в проекте сервера Internet of Thing, собирающего данные с Ethernet-модулей различных датчиков, подключенных к плате Arduino.
ГЛАВА 8 Сервер для сбора данных с Ethernet-модулей датчиков, установленных на Arduino В этой главе мы создадим веб-сервер для сбора и отображения данных с Ethernet- модулей датчиков, сопряженных с платами Arduino. Каждый модуль представляет собой плату Arduino, состыкованную с платой Ethernet Shield, к которой подключе- ны несколько датчиков. Будут использованы следующие датчики: □ температуры DS18B20; □ влажности DHT11 (или DHT22); □ освещенности ВН1750; □ движения HC-SR501; □ звука FC-04. На каждом модуле установлен веб-сервер, отдающий показания в формате JSON при обращении к нему с центрального сервера (может быть использован любой компьютер). На центральном сервере можно посмотреть отображение собираемых с нескольких модулей данных в графическом и табличном виде. Датчик измерения освещенности ВН1750 мы рассмотрели в главе 6, датчик темпе- ратуры DS18B20 — в главе 7. Далее мы кратко познакомимся с другими датчиками, задействованными в этом проекте. 8.1. Датчики влажности DHT11 и DHT22 Датчики DHT11 (рис. 8.1) и DHT22 (рис. 8.2) не отличаются высоким быстродейст- вием и точностью, однако могут найти свое применение в радиолюбительских про- ектах из-за своей невысокой стоимости. Конструкция этих датчиков основана на емкостном датчике влажности и термисторе. Кроме того, они содержат в себе про- стенький АЦП для преобразования аналоговых значений влажности и температуры в их цифровое представление.
162 Датчики DHT имеют по 4 вывода стандарта 2,54 мм: □ 1—VCC (питание 3-5 В); □ 2 — DATA (вывод данных); □ 3 — не используется; □ 4 — GND («земля»). Глава 8 Рис. 8.1. Датчик влажности DHT11 Рис. 8.2. Датчик влажности DHT22 Протокол обмена — однопроводный, по структуре он весьма схож с протоколом датчика температуры DS18B20, но с важными оговорками: □ датчики DHT не умеют работать в «паразитном» режиме (питание по линии данных); □ каждый датчик температуры DS18B20 имеет персональный идентификатор, что дает возможность подключения нескольких таких датчиков к одному выводу Arduino. Однако у датчиков DHT такой возможности нет— один датчик ис- пользует строго один цифровой вывод. Общие характеристики датчиков: □ DHT11: • весьма низкая стоимость; • питание и I/O: 3-5 В; . • определение влажности: 20-80% с точностью 5%; • определение температуры 0-50 °С с точностью 2%; • частота опроса не более 1 Гц (не более одного раза в 1 сек.); • размеры 15,5x12x5,5 мм; □ DHT22: • низкая стоимость; • питание и I/O: 3-5 В;
Сервер для сбора данных с Ethernet-модулей датчиков, установленных на Arduino 163 • определение влажности: 0-100% с точностью 2-5 %; • определение температуры: от -40 до +125 °С с точностью ±0,5 °С; • частота опроса не более 0,5 Гц (не более одного раза в 2 сек.); • размеры 15,1x25x7,7 мм. Сенсор DHT22 имеет лучшие, чем DHT11 характеристики, но более высокую стои- мость. 8.1.1. Подключение датчиков DHT к Arduino Рекомендуемая схема подключения датчиков DHT к Arduino (рис. 8.3) содержит обязательный для однопроводных линий резистор-подтяжку к VCC и, в качестве опции, рекомендуется конденсатор (фильтр по питанию между VCC и GND). мси VDD VC 5K DATA IP 2P\n 4Pin DHT GND Рис. 8.З. Схема подключения к Arduino Если к вам в руки попали DHT11 или DHT22 на небольшой плате, можно подклю- чать их к Arduino напрямую — резистор и конденсатор там уже и так есть. 8.1.2. Библиотека DHT Для работы Arduino с датчиками DH11 и DH22 существует готовая библиотека (DHT), скачать которую можно со страницы: https://github.com/adafruit/DHT- sensor-library. Электронный архив Библиотеку DHT вы найдете в папке arduino_libraries\DHT сопровождающего книгу электронного архива. Скетч получения данных с датчика температуры и влажности DHT22 и вывода по- лученных данных в последовательный порт представлен в листинге 8.1. Для использования в этом скетче датчика DHT11 необходимо закомментировать строку: //#define DHTTYPE DHT22 // DHT 22 (АМ2302)
164 Глава 8 и раскомментировать: #define DHTTYPE DHT11 // DHT 11 Вывод показаний датчика температуры и влажности DHT22 в последовательный порт показан на рис. 8.4. DHT xx test Humidity, fJxmidity: Humidity: Humidity: iumidity: humidity: Humidity: Humidity: Humidity: Humidity: Humidity: Humidity: Humidity: Humidity: Humidity: Humidity: 32,70 * эг„70 i зг.то \ 32.70 1 32.60 i 32.60 1 32.60 i 32,60 i 32.60 i 32.60 4 32.60 1 за.«о < зг.во 1 32.S0 1 32-60 1 » T«m|»«ratut«: 25.70 1 Т#Ш|*#у#ДгУ1У# * Its ч> 70 к T«mjperature: £S.7O к Temperature: 25.70 I Temperature: 25.70 i T«mp«ratur«: 25,70 I T«m|>«rmtur«: 25» 70 к T*m|»«raturt: 2S«70 к T«mi>«ratur«: 2S.40 i Tampcratuc*: 25.40 к Temperature: 25.40 ft Temperature: 25.40 1 Temperature: 25.90 i Temperature: 25,90 t Temperature: £5.90 fc Temperature: 15.90 *c *C ♦C *c ♦c *c ♦c *c ♦c *c ♦c *c *c ♦c Рис. 8.4. Вывод данных с датчика в монитор последовательного порта #include "DHT.h" #define DHTPIN 2 // пин подключения //#define DHTTYPE DHT11 // DHT 11 #define DHTTYPE DHT22 // DHT 22 (AM2302) //#define DHTTYPE DHT21 // DHT 21 (AM2301) DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(9600) ; Serial.println("DHTxx test!"); dht.begin(); void loopO { // Reading temperature or humidity takes about 250 milliseconds! // Sensor readings may also be up to 2 seconds 'old1 // (its a very slow sensor)
Сервер для сбора данных с Ethemet-модупей датчиков, установленных на Arduino 165^ float h - dht.readHumidity(); float t = dht.readTemperature(); // check if returns are valid, if they are NaN (not a number) // then something went wrong! if (isnan(t) || isnan(h)) { Serial.println("Failed to read from DHT"); } else { Serial.print("Humidity: "); Serial.print(h); Serial.print(" %\t"); Serial.print("Temperature: "); Serial.print(t); Serial.println(" *C"); 8.2. Модуль датчика движения HC-SR501 HC-SR501 (рис. 8.5) — модуль, состоящий из РЖ-сенсора и схемы управления. Пояснение: PIR-sensor PIR-sensor переводится с английского как Pyroelectric (Passive) InfraRed sensor — пироэлектрический (пассивный) инфракрасный сенсор. Пироэлектричество— это свойство генерировать определенное электрическое поле при облучении материала инфракрасными (тепловыми) лучами. И поскольку тело человека излучает тепло, PIR- датчики позволяют обнаруживать движение людей в контролируемой зоне. Такие дат- чики малы по размеру, недороги, имеют низкое энергопотребление, просты в исполь- зовании и не изнашиваются. Рис. 8.5. Модуль датчика движения (PIR Motion sensor) HC-SR501 В модуле датчика движения HC-SR501 в качестве органов настройки используются два потенциометра и перемычка (рис. 8.6): П параметр Delay Time Adjust, регулируемый одним из потенциометров, опреде- ляет время, в течение которого при обнаружении движения на контакте OUT будет удерживаться высокий уровень (5-300 сек.);
166 Глава 8 О параметр Distance Adjust определяет чувствительность датчика— центр кон- тролируемой зоны: от 3 до 7 м; Совет Не стоит располагать PlR-датчики в местах, где температура меняется быстро. Это приведет к тому, что датчик не сможет обнаруживать появление человека в контроли- руемой зоне, а станет выдавать множество ложных срабатываний. □ режим работы модуля задается перемычкой, обеспечивающей установку одного из двух режимов: режима Н или режима L. На рис. 8.6 в модуле установлен ре- жим Н. В этом режиме при срабатывании датчика несколько раз подряд на его выходе (на OUT) остается высокий логический уровень. В режиме L при каж- дом срабатывании датчика на выходе модуля появляется отдельный импульс. VCCS12VDC =п \ ч_ _пл_п Рис. 8.6. Элементы настройки модуля датчика движения HC-SR501 Основные параметры модуля датчика движения HC-SR501 приведены в табл. 8.1. Таблица 8.1. Основные параметры модуля HC-SR501 Параметр Размеры, см Напряжение питания, В Ток на выводе OUT, мА Напряжение на выходе Дистанция обнаружения, м Угол обнаружения Длительность импульса при обнаружении, сек. Значение примерно 3,2x2,4x1,8 постоянное 4,5-20 <60 Высокие и низкие уровни 3,3 В в TTL-логике 3-7 (настраивается) до 120-140° (в зависимости от конкретного датчика и линзы) 5-200 (настраивается)
Сервер для сбора данных с Ethemet-модулей датчиков, установленных на Arduino 167_ Таблица 8.1 (окончание) Параметр Время блокировки до следую- щего замера, сек. Рабочая температура, °С Режим работы Значение 2,5 (но можно изменить заменой SMD-резисторов) от -20 до +80 L — одиночный захват, Н — повторяемые измерения Схема подключения модуля датчика движения HC-SR501 к плате Arduino показана на рис. 8.7. Рис. 8.7. Схема подключения модуля HC-SR501 к плате Arduino Итак, устанавливаем перемычку в режим работы L и подаем питание. Необходимо подождать примерно 20-40 сек. (для некоторых модулей и до 60 сек.) — в это вре- мя датчик калибруется. Теперь, как только датчик зафиксирует движение, на вход Arduino поступит высокий уровень, который будет держаться время, установленное потенциометром Delay Time Adjust. В листинге 8.2 приведен скетч для подсчета срабатываний PIR-датчика. int countjrciotion^O; // счетчик срабатываний void setup () { attachlnterrupt(0,motion,RISING); // запустить прерывания (pin D2)
168 Глава В void loop () // обработка прерывания ПК датчика движения void motion() { detachlnterrupt(0); countjnot ion++; attachlnterrupt(0,motion,RISING); 8.3. Модуль датчика звука FC-04 Датчик звука fC-04 (рис. 8.8) построен на основе микрофона и имеет регулировку чувствительности. Выход датчика цифровой— при превышении установленного звукового порога на выходе датчика устанавливается логическая единица. Рис. 8.8. Датчик звука FC-04 Датчик звука FC-04 измеряет интенсивность звука и предназначен для определения факта наличия звука, но он не может определить его уровень и звуковые частоты. Датчик можно применить, например, для голосовых выключателей, в том числе с расшифровкой кодовой последовательности звуков (например, три хлопка в ла- доши) определителя лая собаки, если она остается одна в квартире в течение рабо- чего дня, сигнализации о других посторонних звуках в квартире. Датчик звука FC-04 представляет собой печатную плату с установленными на ней микрофоном, микросхемой LM393, а также несколькими другими электронными компонентами. Основные характеристики датчика: □ напряжение питания звукового датчика: от +2,7 до +5,5 В; □ ток потребления сенсора звука: 1,4 мА; □ интерфейс или тип выходного сигнала датчика звука: цифровой TTL; □ цифровой выход сигнала: рабочее напряжение на выходе 5 В; □ подключается непосредственно к микроконтроллеру;
Сервер для сбора данных с Ethernet-модулей датчиков, установленных на Arduino f59 □ рабочая температура: от -30 до +85 °С; □ размеры модуля звука (длина х ширина х высота): 47x18,4x10 мм; □ вес модуля: 3 грамма; □ диаметр отверстия для монтажа датчика: 3 мм. Звуковой сенсор снабжен специальным штырьковым разъемом (типа «папа») для подключения к плате микроконтроллера Arduino. Для регулировки чувствитель- ности на плате имеется потенциометр. В листинге 8.3 представлен скетч для определения срабатывания датчика звука. При срабатывании зажигается светодиод, подключенный к выводу 13 Arduino. const int SensorPin =9; // номер pin для датчика const int ledPin = 13; // номер led pin // переменные, изменяемые в процессе работы: int SensorState =0; // переменная для чтения // состояния датчика void setup() { pinMode(ledPin, OUTPUT); // начальная установка led pin // как выхода (output) pinMode(SensorPin, INPUT); // установка pin датчика как входа (input) } void loop() { SensorState = digitalRead(SensorPin); // Чтение состояния датчика: if (SensorState == HIGH) // если на выходе 1 { digitalWrite(ledPin, HIGH); // включить светодиод delay(200); // Задержка 0.2 сек } else // иначе - выключить светодиод { digitalWrite(ledPin, LOW); delay(200); 8.4. Ethernet-модуль датчиков на Arduino Ethernet-модуль датчиков (рис. 8.9) состоит из платы Arduino, платы Ethernet Shield и пяти подключенных к ним датчиков: движения HC-SR501, температуры DS18B20, звука FC-04, освещенности ВН1750 и влажности DHT11.
170 Глава 8 HC-SR501 DS18B20 Рис. 8.9. Электрическая схема Ethernet-модуля датчиков На каждом модуле установлен простейший веб-сервер. Каждый модуль имеет уни- кальный IP-адрес и свой уникальный порт обращения. При обращении по HTTP к модулю он отдает в формате JSON следующие данные датчиков температуры, влажности, освещенности, количества срабатываний датчика движения и датчика звука после последнего обращения: {«meteo»: {«tempi»:«25.31»,«humidityl»:«35.00»,«luxl»:«10»,«soundl»:«0», «motionl»:«0»} } Содержимое скетча для Ethernet-модуля датчиков представлено в листинге 8.4. // подключение библиотек #include <SPI.h> #include <Ethernet.h> #include <OneWire.h> #include <Wire.h> #include <BH1750.h> // объекты для датчиков ВН1750, DHT11, DS18B20 BH1750 light1; tinclude "DHT.h" DHT dht(8, DHTTYPE); OneWire ds(7); // on pin 7
Сервер для сбора данных с Ethemet-модулей датчиков, установленных на Arduino 171 II датчик (для каждого датчика назначить уникальный ip-адрес и порт) byte mac[] » { ОхАА, ОхВВ, OxCC, OxDD, OxEEf OxFl }; byte ip[] - { 192, 168, 1, 121 }; EthernetServer server(10001); byte my_addr[8]={0x28,0x2A,0x78,0x65,5,0,0,0x10}; // переменные для подсчета срабатываний датчика движения и датчика звука int countjnotion^O; uintl6_t count_sound=0; void setup() { Serial.begin(9600); Serial.println("start"); Ethernet.begin(mac, ip); // запуск сервера server.begin(); Serial.print("server is at "); Serial.println(Ethernet.locallP()); Wire.beginO ; lightl.beginO; // прерывание для PIR-датчика attachlnterrupt(0,motion,RISING); void loop () { EthernetClient client = server.available(); if (client) { boolean currentLinelsBlank = true; while (client.connected()) { if (client.availableO) { char с = client.read(); // ожидание конца запроса if (с — f\nf && currentLinelsBlank) { // отправить стандартные header client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); // отправка JSON-данных client.print(f{'); // данные температуры client.print ('"'); client. print ("meteo"); client. print (f"f) ; client.println(":"); client.print (Ч1); int Temp^get^emp () ; client.print(f"f);client.print("tempi");client.print(f"f); client.print(":");
172 Глава 8 client.print(f"f)/client.print(Temp/16); client.print("."); client.print(((Temp%16)*100)/16)/client.print("")/client.print(f,•); // данные влажности float h = dht.readHumidity(); client.print(f"f);client.print("humidityl");client.print(f"f); client.print(":"); client.print(f"f);client.print(h)/client.print(f"f); client.print(',f); // данные bhl750 uintl6_t lux - lightl.readLightLevelO; client.print(f"f)/client.print("luxl")/client.print(•"')? client.print(":"); client.print(f"f)/client.print(lux)/client.print('"')/ client.print(',f)/ // sound client.print(f"f)/client.print("soundl")/client.print(f"f)/ client.print(":"); client.print(lllf)/client.print(count_sound)/client.print('"'); client.print(\ f)/ count_sound=0/ // датчик движения client.print(f"f)/client.print("motionl")/client.print('"'); client.print(":"); client.print(f"f)/client.print(count jnotion)/client.print(f"')/ client.printing1}")/ client.print("}ff)/ countjnotion=0/ break/ } if (c — f\nf) {currentLinelsBlank = true/} else if (c != f\rf) {currentLinelsBlank - false/} // пауза, чтобы данные ушли delay(1); // закрыть Ethernet-соединение client.stop()/ } // sound if(analogRead(A0)<500) {count_sound++/delay(1000)/} } // получение температуры датчика int get_temp()
Сервер для сбора данных с Ethernet-модулей датчиков, установленных на Arduino 173 byte i; byte present = 0; byte data[12]; byte addr[8]; int Temp; ds.reset(); ds. select (my_addr); ds.write(0x44f1); delay(lOOO); // пауза 750 мс present = ds.reset(); ds.select(my_addr); ds.write(OxBE); // команда чтения for ( i = 0; i < 9; i++) { data[i] = ds.read(); } Temp= (data [ 1 ] «8) +data [0] ; Temp=Temp; return Temp; // обработка прерывания ИК датчика движения void motion () { detachlnterrupt(0); count_mot ion++; attachlnterrupt(0,motion,RISING); Bee Ethernet-модули датчиков квартиры/дома соединены в единую локальную сеть. В этой же сети настроен описанный в следующем разделе сервер для сбора данных с устройств и представления данных в виде графиков и таблиц, а также для ото- бражения данных в виде виджетов на плане дома или квартиры. 8.5. Сервер сбора данных На сервере (Apache, mySQL, php) локальной сети для сбора данных установлен сайт, осуществляющий опрос Ethernet-модулей датчиков по сгоп каждые 5 минут. Данные собираются в базу данных mySQL, где также хранятся настройки всех модулей, задействованных в системе (рис. 8.10). Сайт написан на HTML5 с элементами canvas, что обеспечивает вывод виджетов на плане объекта. Отправка информации на сервер осуществляется без перезагрузки страницы (использована технология AJAX и библиотека xajax). Вид объектов с виджетами (средние значения температуры, влажности, освещенности) показан на рис. 8.11.
174 ГлаваS Рис. 8.10. Данные модулей в базе mySQL - is- % j ^ ** ' ' Рис. 8.11. Вид объектов с виджетами на плане дома
Сервер для сбора данных с Ethernet-модулей датчиков, установленных на Arduino 175 После авторизации (рис. 8.12) ссылки с виджетов становятся доступны в режиме администратора, позволяющем осуществлять просмотр данных с возможностью выбора объекта (квартира, дача, гараж), подобъекта (1 этаж ...), комнаты и даты считанных данных (рис. 8.13). 3/ % Рис. 8.12. Активация ссылок с виджетов в режиме администратора Рис. 8.13. Выбор настроек для просмотра данных, считанных с модулей Для температуры, влажности, освещенности строятся соответствующие графики (рис. 8.14). Для датчиков звука и датчиков движения— таблицы с количеством срабатываний между запросами (рис, 8.15). При построении графиков и таблиц ис- пользуется API Google Chart.
176 Глава 8 Дата-20144)5-04 8рем*-2256:37 23,0 20,0 Рис. 8.14. Данные в виде фафиков (представлены данные замеров температуры сдатчика DS18B20) Рис. 8.15. Данные в виде таблиц (представлены данные срабатывания датчика движения HC-SR501) Электронный архив Скетч, соответствующий листингу 8.4, можно найти в файле arduino_scetches\_08\ _08_04.ino, а файлы сайта и дамп базы данных сервера — в папке arduino_scetches\ _08\web сопровождающего книгу электронного архива.
ГЛАВА 9 Обмен данными с помощью платы GPRS/GSM Shield Плата Arduino GPRS/GSM Shield предоставляет нам возможность использовать для удаленного приема и передачи данных в проектах Arduino сеть мобильной GSM- связи. Осуществить это можно тремя способами: □ используя отправку/прием коротких текстовых сообщений (SMS); □ отправкой голосовых (аудио) команд на основе технологий CSD (стандартная технология передачи данных в сети GSM) и/или DTMF (двухтональный много- частотный аналоговый сигнал, используемый для набора телефонного номера); □ используя пакетную передачу данных на основе технологии GPRS. Рассмотрим один из вариантов платы GPRS/GSM Shield — Quad-Band GPRS Shield на основе чипа SEM900 (рис. 9.1). Основные характеристики GSM-модуля SIM900 платы Quad-Band GPRS Shield: □ четыре диапазона GSM: 850/9Q0/1800/1900 МГц; □ класс передачи данных: GPRS multi-slot class 10/8; Рис. 9.1. Плата SIM900 Quad-Band GPRS Shield
178 Глава 9 П соответствие стандарту GSM фазы 2/2+; □ класс мощности 4 (2 Вт в диапазонах 850/900 МГц); □ класс мощности 1 (1 Вт в диапазонах 1800/1900 МГц); □ управление АТ-командами (GSM 07.07,07.05 и фирменные АТ-команды SIMCom); □ аудиокодеки HR, FR, EFR, AMR, подавление эха; □ скорость передачи данных по технологии CSD: до 14,4 Кбит/с; □ РРР-стек; □ встроенный стек TCP/IP, UDP/EP; □ протоколы HTTP и FTP; О протокол защищенных сокетов SSL; □ декодирование DTMF-tohob; □ eMail — формирование и отправка электронных писем посредством АТ-команд; □ SMS Autorun — исполнение АТ-команд, полученных по SMS от определенного абонента; □ встроенная память для пользовательских данных: 2,5 Мбайт; □ MMS— формирование, дополнение пользовательскими файлами и отправка с помощью АТ-команд; □ AMR play — воспроизведение аудиофайлов в динамик или в сторону удаленно- го абонента; □ функция обнаружения глушения сигнала (Jamming Detection); □ FOTA — обновление прошивки модуля по беспроводному каналу; □ Easy Scan — получение информации об окружающих базовых станциях без под- ключения SIM-карты; □ PING — проверка доступности адреса в Интернете посредством обмена ICMP- пакетами. Особенности платы SIM9.Q0 Quad-Band GPRS Shield: □I совместимость с Arduino Mega; □ наличие слота для карт SD ( включение/отключение с помощью перемычки); □ гнездо наушников «два в одном»; □ программное и аппаратное обеспечение последовательного порта — может об- щаться с Arduino через последовательный порт программного обеспечения (D2/D3) или последовательный порт (D0/D1); О интерфейс FTDI; □ наличие слота батарейки для часов реального времени (RTC); □ 10 цифровых входов/выходов GPIO;
Обмен данными с помощью платы GPRS/GSM Shield 179 □ 2 выхода ШИМ; □ интерфейс 12С. Плату SIM900 Quad-Band GPRS Shield можно включить двумя способами: аппарат- ным (кратковременное нажатие кнопки PWRKEY) и программным (используется выход D7 Arduino). 9.1. Отправка и получение SMS-сообщений В этом примере мы каждые 30 минут будем с помощью платы GSM/GPRS Shield отправлять на определенный телефонный номер показания аналогового датчика температуры LM335, подсоединенного к выводу АО платы Arduino. Установим SIM-карту в соответствующий слот платы GSM/GPRS Shield, а саму плату GSM/GPRS Shield состыкуем с Arduino. С помощью джамперов соединим контакты для работы через SoftwareSerial-эмуляцию. Схема соединений представ- лена на рис. 9.2. Содержимое скетча для отправки SMS приведено в листинге 9.1. Рис. 9.2. Схема подключения модуля GSM/GPRS Shield и датчика LM335
180 Глава 9 // подключение библиотеки 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=l\r"); delay(100); // номер телефона получателя Sim900Serial.println("AT + CMGS = V") ; Sim900Serial.println(PHONE) ; Sim900Serial.println("\""); delay(100); // сообщение - данные температуры double val = analogRead(lm3.35) ; // чтение double voltage = val*5.0/1024; // перевод в вольты double temp = voltage*100 - 273.15; // в градусы Цельсия Sim900Serial.println(temp); delay(100); // ASCII код ctrl+z - окончание передачи Sim900Serial.println((char)26); delay(100); Sim900Serial.println();
Обмен данными с помощью платы GPRS/GSM Shield 181_ Электронный архив Скетч, соответствующий листингу 9.1, можно найти в файле arduino_scetches\_09\ _09_01.ino сопровождающего книгу электронного архива (см. приложение). Проверим работу скетча и, если все в порядке, изменим скетч таким образом, что- бы плата Arduino отправляла SMS-сообщение с данными температуры только при получении приходящего сообщения с текстом temp. Содержимое измененного скет- ча приведено в листинге 9.2. 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); Siin900Serial.print ("AT+CPBS=\"SM\"\r") ; delay(300); Sim900Serial.print("AT+CNMl=lf2f2flf0\r"); delay(500); void loop() { if (!Sim900Serial.available ()) return; char currSymb = Sim900Serial.read(); if (f\rf — currSymb) { if (isStringMessage) // текущая строка - sms-сообщение, { if (!currStr.compareTo("tempff)) // текст sms - temp { // отправить sms на приходящий номер Sim900Serial.print("AT+CMGF-lNr") ; delay(100); Sim900Serial.print ("AT + CMGS - \"lf);
182 Глава i Sim900Serial.print(phone); Sim900Serial. print In ("V") ; 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.printIn(currStr); isStringMessage = false; } else { if (currStr.startsWith(f4CMT")) { Serial.println(currStr); JI выделить из сообщения номер телефона phone=currStr.substring(7,19); Serial.println(phone); // если текущая строка начинается с "+СМТ", //то следующая строка является сообщением isStringMessage = true; currStr = ""; } else if C\n' != currSymb) { currStr += String(currSymb); Электронный архив Скетч, соответствующий листингу 9.2, можно найти в файле arduino_scetches\_09\ _09_02.ino сопровождающего книгу электронного архива (см. приложение). 9.2. Отправка данных на сайт «Народный мониторинг» С сервисом «Народный мониторинг» мы уже познакомились в главе 4, когда от- правляли ему данные с помощью платы Ethernet Shield. А сейчас мы рассмотрим пример отправки данных на сайт «Народный мониторинг» с использованием платы GPRS/GSM Shield.
Обмен данными с помощью платы GPRS/GSM Shield 183_ Итак, подключаем к Arduino плату GPRS/GSM Shield и датчик температуры LM335. В режиме отправки/получения данных GPRS чип SIM900 потребляет ток до 2 А, поэтому ему необходимо внешнее питание. Для отправки HTTP-данных по GPRS соединению необходимо выполнить отправку АТ-команд в следующей последовательности: 1. Первой отправляется команда at — ответ должен быть ок. 2. at+sapbr=i,i— установка GPRS-связи. 3. at+sapbr=3, l, "contype", "gprs" — настройка типа подключения (в данном слу- чае — GPRS). 4. AT+SAPBR=3,1,"APN", "intemet.beeline.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. Теперь пишем скетч отправки данных (листинг 9.3). idefine INTERVALSEND 60000 tdefine LM335 АО Hnclude <SoftwareSerial.h> SoftwareSerial GPRS(7, 8); int onModulePin= 9; char aux_str[150]; char aux; char data[512]; int data_size; uint8_t answer=0; unsigned long millissend=0; char apn[]="internet.beeline.ru"; char url[150]; String surl="http://narodmon.ru/post.php/?";
184 Глава $ void setup() { GPRS.begin(19200); // скорость для GPRS Serial.begin(9600); Serial.println("Starting..."); pinMode(onModulePin,OUTPUT); power_on(); delay(3000); // точка доступа APN sendATcommand(llAT+SAPBR=3,l/\"CONTYPE\"f\"GPRS\""f "OK", 2000); snprintf (aux_str, sizeof(aux_str), "AT+SAPBR-3,1,\"APN\",\"%s\"", apn); sendATcoinmand (aux_str, "OK", 2000); while (sendATcoinmand ("AT+SAPBR=1,1", "OK", 2000) — 0) { delay(2000); } delay(1000); } void loop() { // отправка раз в 10 минут if (millis()-millissend>INTERVALSEND ) { // Initializes HTTP service answer » sendATcoinmand("AT+HTTPINIT", "OK", 10000); if (answer = 1) { // Sets CID parameter answer = sendATcoinmand("AT+HTTPPARA=\"CID\",1", "OK", 5000); if (answer = 1) {// Sets url double val = analogRead(LM335); // чтение показаний LM335 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 - sendATcoinmand(aux_str, "OK", 5000); if (answer == 1) {// Starts GET action answer = sendATcoinmand ("AT+HTTPACTION=0", "+HTTPACTION: 0,200", 10000); if (answer = 1) { sprintf(aux_str, "AT+HTTPREAD");
Обмен данными с помощью платы GPRS/GSM Shield 185 sendATcoiranand(aux_str, "OK", 5000); } else { Serial.println("Error getting the url"); } } else { Serial, print In ("Error setting the url1');, } } else { Serial.println("Error setting the CID"); } }• else { Serial.printIn("Error initializating"); } sendATcoramand("AT+HTTPTERM", "OK", 5000); millissend=millis(); // отправка АТ-команд int8_t sendATcoramand(char* ATcoramand, char* expected_answer, unsigned int timeout) { uint8_t x=0, answer=0; char response[150]; unsigned long previous; mernset (response, f\0f, 150); // Initialize the string delay(100); while( GPRS.availableO > 0) GPRS.read(); // Clean the input buffer GPRS.println(ATcoramand); // Отправка АТ-команды x = 0; previous = raillis (); // this loop waits for the answer do{ if (GPRS.availableO != 0) { //if there are data in the UART input buffer, reads it and checks for the asnwer response[x] = GPRS.read();
186 Глава 9 // 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.println(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("AT", "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); Электронный архив Скетч, соответствующий листингу 9.3, можно найти в файле arduino_scetches\J)9\ _09_03.ino сопровождающего книгу электронного архива (см. приложение).
Обмен данными с помощью платы GPRS/GSM Shield 767 Загружаем скетч в плату Arduino и проверяем отправку данных на сайт. После от- правки данных можно добавить новое устройство в список устройств своего про- филя (рис. 9.3). Рис. 9.3. Подключение устройства на сайте «Народный мониторинг» 9.3. GPS-трекер на Arduino и GPRS/GSM Shield В этом разделе мы рассмотрим создание на базе Arduino и GPRS/GSM Shield GPS- трекера для автомобиля, велосипеда или пешехода. Наш трекер должен быть спо- собен: □ отправлять GPS-данные по GSM/GPRS на сайт в Интернете с сохранением их в базе данных; □ предоставлять пользователю возможность просматривать маршрут движения за определенный интервал времени на веб-странице с использованием сервиса Яндекс.Карты; □ показывать в реальном времени текущее положение пользователя на веб- странице с использованием сервиса Яндекс.Карты. Для получения GPS-данных мы воспользуемся модулем GPS-приемника V.KEL 16, позволяющим определять свое местоположение с помощью глобальной системы GPS. Глобальная система GPS GPS (от англ. Global Positioning System, система глобального позиционирования) — это система для определения местоположения объекта, основанная на группировке искусственных спутников Земли и наземных станций слежения, объединенных в об- щую сеть. С помощью GPS можно определить следующие параметры местонахожде- ния GPS-приемника:
188 Глава 9 • широту и долготу; • высоту над уровнем моря; • направление и скорость движения. Важными параметрами GPS-приемника являются «холодный» старт, «теплый» старт и «горячий» старт — это время, необходимое приемнику на определение позиции после включения. «Холодный» старт происходит, если GPS-приемник был длительное время (более ме- сяца) выключен. Во время «холодного» старта скачиваются так называемые альманах (параметры орбит всех спутников) и эфимерис (очень точные корректировки парамет- ров орбит и часов для каждого спутника). Время «холодного» старта порядка 5 минут. «Теплый» старт происходит, если приемник находился в выключенном состоянии по- рядка 30 минут и занимает до 1,5 минут. При этом происходит прием свежих данных эфимериса. «Горячий» старт происходит после непродолжительного отключения GPS- приемника и осуществляется очень быстро. Данные альманаха и эфимериса при «го- рячем» старте считаются свежими. Модуль GPS V.KEL 16 один из самых дешевых и простых. Назначение его выводов представлено на рис. 9.4. Рис. 9.4. Назначение выводов модуля GPS V.KEL 16
Обмен данными с помощью платы GPRS/GSM Shield 189 Основное, что можно делать с приемником V.KEL 16, — это считывать с него дан- ные по протоколу NMEA с вывода ТХ. Уровни — 5 В, скорость — 9600 бод. Для подключения модуля к плате Arduino мы используем ее программный UART на выводах 2 и 3. Чтение данных осуществляется с помощью библиотеки TinyGPS. Схема соединений для нашего GPS-трекера представлена на рис. 9.5. Общий вид GPS-трекера в сборе с литий-полимерной батареей показан на рис. 9.6. Рис. 9.5. Схема соединений GPS-трекера Данные с трекера мы будем отправлять на сайт в сети Интернет. При написании серверной части и веб-интерфейса предусмотрено получение и вывод результатов для нескольких модулей (id_avto=N) от 8-ми движущихся объектов, при этом для каждого из них должна быть выбрана своя уникальная комбинация переключате- лей. В схеме для этого предусмотрен переключатель на 3 позиции. Для получения страницы по определенному интернет-адресу (URL) нужно послать следующие команды:
190 Глава 9 //Открыть несущую (Carrier) AT+SAPBR=1,1 //тип подключения - GPRS AT+SAPBR=3,1,"CONTYPE","GPRS" //APN, для Билайна AT+SAPBR=3,1,"APN","internet.beeline.ru" //Инициализировать HTTP AT+HTTPINIT //Carrier ID для использования. AT+HTTPPARA="CID",1 //Собственно URL, после sprintf с координатами AT+HTTPPARA="URL", "http: /????????. ru/gps_tracker/gps_trackerl.php?id_avto=?N&la t=XXXXXlon=YYYYY" //Запросить данные методом GET AT+HTTPACTION=0 //дождаться ответа AT+HTTPREAD //остановить HTTP AT+HTTPTERM Рис. 9.6. GPS-трекер в сборе Скетч для этого проекта загружаем из файла arduino_scetches\_09\J$_04.ino сопрово- ждающего книгу электронного архива (см. приложение). Вот некоторые пояснения к нему. Чтобы не отправлять данные во время стоянки, отправка данных на сервер будет осуществляться только в том случае, если GPS-данные изменятся на значение, ука- занное в константе mincange.
Обмен данными с помощью платы GPRS/GSM Shield 191_ Интервал отправки данных — константа intervalsend (в м/сек). Наличие двух ак- тивных программных последовательных портов приводит к ошибкам получе- ния/отправки данных, поэтому приходится переключать состояние программных последовательных портов для работы с каждым шил дом: GPRS.end() ;gpsSerial.begin(9600); В процедуре setup о — выбор номера модуля для отправки данных на сервер (id_avto=) — считывается из положения трех переключателей. В веб-интерфейсе (рис. 9.7) предусмотрено отображение на Яндекс.Картах текуще- го (последнего переданного) положения либо маршруту за выбранный период. Те- кущее положение отображается меткой на карте, а во всплывающем у метки окне выводится время для этой метки (рис. 9.8). При построении маршрута по меткам строится траектория, и во всплывающем у каждой метки окне отображается время (рис. 9.9). Для быстрого построения страницы предусмотрена константа макси- мального количества меток — следующие метки подгружаются кнопками > и <. Интерфейс написан с использованием технологии AJAX (библиотека xajax). Файлы для сайта и дамп БД находятся в архиве arduino_scetches\_09\www.zip сопровождаю- щего книгу электронного архива (см. приложение). Рис. 9.7. Интерфейс сайта отображения данных трекера
192 Глава 9 Рис. 9.8. Метка на карте со всплывающим окном Рис. 9.9. Построение маршрута
ГЛАВА 10 Проект Blynk: управление Arduino с планшета Здесь мы рассмотрим, как управлять Arduino с планшета или смартфона, используя возможности проекта Blynk (http://www.blynk.cc), который в начале 2015 года успешно профинансировал ся на сайте Kickstarter почти на 500%. Проект Blynk позволяет установить в приложении на планшете/смартфоне различ- ные виджеты (кнопки, слайдеры, дисплеи, графики и пр.) и с их помощью управ- лять платой Arduino или получать с нее данные. Как можно видеть, проект Blynk работает через Интернет (рис. 10.1). Рис. 10.1. Архитектура проекта Blynk
194 Глава 10 10.1. Начало работы: тестовый пример Программное обеспечение Blynk Cloud, написанное на Java, использует простые IP-сокеты TCP и работает на сервере icloud.blink.cc. Приложения Blynk для iOS и Android подключаются к Blynk Cloud по умолчанию— каждому пользователю Blynk обеспечивается к нему свободный доступ. Для начала работы с проектом Blynk необходимо выполнить следующие шаги: 1. Скачать и установить бесплатное приложение Blynk: для Android— из Play Маркет, для iOS — из Арр Store. 2. Запустить скачанное приложение Blynk и зарегистрироваться в сервисе Blynk. 3. Настроить приложение для своего устройства, добавив на экран необходимые виджеты. 4. Скачать и установить Arduino-библиотеку, загрузить скетч примера на плату Arduino. 5. Запустить приложение на планшете, после чего можно будет управлять вывода- ми Arduino и отображать полученные данные. Итак, для скачивания приложения для Android заходим в Play Маркет и находим по поиску приложение Blynk (рис. 10.2). Скачиваем его, устанавливаем и создаем себе на сервисе учетную запись (аккаунт), указав адрес своей электронной почты и пароль. Войдя в аккаунт, для создания нового проекта нажимаем кнопку +, вводим имя проекта и выбираем тип устройства (рис. 10.3). Сервис поддерживает множество Blynk for Arduino,RPi and more Blynk.cc Оптимизировано для телефонов 68 л Инструменты Похожие Управление Arduino, Малина Pi, SparkCore и другие с смартфона в минуту? Рис. 10.2. Приложение Blynk в Play Маркет
Проект Blynk: управление Arduino с планшета 795 устройств, включая несколько плат Arduino, Raspberry Pi, ESP8266 и ряд других (список устройств создатели сервиса обещают пополнять). При выборе устройства автоматически генерируется уникальный ключ авторизации (AUTH TOKEN), ко- торый нам понадобится при написании скетча. В завершение нажимаем на кнопку Create — и проект создан. Рис. 10.3. Создание нового проекта в Blynk Теперь в проект можно добавлять виджеты для управления платой Arduino и полу- чения с нее данных. Для добавления виджетов нажимаем в окне проекта кнопку +. На момент подготовки книги выбор виджетов небольшой — явно меньше заявлен- ного на Kickstarter: камера, джойстики, графики для отображения данных там пока не присутствуют, но что выбрать, все же, есть (рис. 10.4). Чтобы воспользоваться виджетами, подготовим сначала схему: к плате Arduino с установленной на ней платой Ethernet Shield подключим RGB-светодиод, два обычных светодиода и фоторезистор (рис. 10.5). После чего согласно этой схеме в проект Blynk на экране планшета мы добавляем виджеты Button (рис. 10.6) — задаем переключатель switch 1 состояния вывода D8 Arduino, три слайдера для управления выводами R, G и В RGB-светодиода (рис. 10.7), таймер для включения вывода D12 (рис. 10.8) и виджет Value Display ря отображения показаний фоторезистора, подключенного к выводу Al Arduino (рис. 10.9). Общий вид проекта представлен на рис. 10.10.
196 Глава fO Рис. 10.4. Виджеты для проекта в Blynk Рис. 10.5. Схема подключения для примера Blynk
Проект Blynk: управление Arduino с планшета 197 Рис. 10.6. Подключение вйджета Button Рис. 10.7. Подключение виджета Slider
198 Глава 10 Рис. 10.8. Подключение виджета Timer Рис. 10.9. Подключение виджета Value Display
Проект Blynk: управление Arduino с планшета 199 Рис. 10.10. Общий вид нашего проекта Blynk Вернемся к нашей плате Arduino: 1. Скачиваем библиотеку Blynk по ссылке https://github.com/blynkkk/blynk- library/archive/vO.2.1.zip. 2. Распаковываем библиотеку и копируем ее в папку libraries Arduino ГОЕ. 3. Создаем скетч (листинг 10.1) на основе примера ArduinoJEthernetJVIanual.ino из библиотеки Blynk: • прописываем в нем настройки для нашей платы Arduino (IP, DNS, gateway, subnet, МАС-адрес платы); • прописываем ключ авторизации нашего проекта (AUTH TOKEN); • сервер: "cloud.blynk.ее"; • порт 8442 (облако cloud.blynk.ee использует два порта для обмена данными: 8443 — для мобильных устройств, 8442 — для контроллеров). 4. Загружаем скетч в нашу плату Arduino и открываем монитор последовательного порта. На рис. 10.11 показан процесс соединения Arduino с сервером cloud.blynk.ee.
200 Глава 10 иг 1(1.1 // подключение библиотек #define BLYNK_PRINT Serial #include <SPI.h> #include <Ethernet.h> #include <BlynkSimpleEthernet.h> // токен авторизации для проекта на планшете char auth[] = n16bcc28b557d4c45b3fd380f5cf8da66"; // МАС-адрес и настройки сети для Ethernet shield byte arduino_mac[] = { OxDE, OxED, OxBA, OxFE, OxFE, OxED }; IPAddress arduino_ip ( 192, 168, 0, 120); IPAddress dns_ip ( 192, 168, 1, Г) ; IPAddress gateway_ip ( 192, 168, 0, 28); IPAddress subnet_mask(255, 255, 255, 0); void setup() { Serial.begin(9600); Blynk.begin(auth, "cloud.blynk.ee", 8442, arduino_ip, dns_ip, gateway_ip, subnetjnask, arduinojnac) ; } void loopO { Blynk.run(); Электронный архив Скетч, соответствующий листингу 10.1, можно найти в файле arduino_scetches\JO\ __10_01.ino сопровождающего книгу электронного архива. IUJZ I4774] Ready! |0] Blynk vO.2.1 10] Using static IP 11300] My IP: 192.168.0.120 11301] Connecting to cloud.blynk.ee:8442 117313] Timeout 123313] Connecting to cloud.blynk.ee:8442 123755] Ready! Рис. 10.11. Процесс соединения с сервером cloud.blynk.ee
Проект BIynk: управление Arduino с планшета 201 Рис. 10.12. Управление выводами Arduino с экрана планшета Рис. 10.13. Монтажная плата соединения элементов для платы Arduino
202 Глава 10 Теперь запускаем на планшете наш проект на выполнение и с помощью слайдеров устанавливаем цвет свечения RGB-светодиода. Данные фоторезистора (вывод А1, виджет Value Display) обновляются раз в 10 секунд, виджет Button (switchl) рабо- тает как переключатель состояния светодиода, подключенного к выводу D8. Timer подает 1 на вывод D12 в 15.00 и 0 — в 15.30 (рис. 10.12). При этом на плате Arduino наблюдаем изменение состояния светодиодов (рис. 10.13). 10.2. Управление с планшета исполнительными устройствами, подключенными к Arduino С тестовым примером мы разобрались, надо двигаться дальше. Добавим к нашему проекту возможность управления со смартфона исполнительными устройствами, подключенными к Arduino. Если для управления реле достаточно использования виджета Button с опцией switch, то управлять сервоприводом подобным образом не получится. Рассмотрим, как это можно сделать. Чтобы обеспечить угол поворота сервопривода от 0 до 180 градусов, в наш проект на планшете добавляем виджет Slider, в качестве виртуального порта (PIN) для него выбираем Virtual V0 и задаем область значений в промежутке 0 до 180 (рис. 10.14). Рис. 10.14. Создание виджета Slider для виртуального порта V0
Проект Blynk: управление Arduino с планшета 203^ Для получения данных из облака с виртуального порта V0 (при изменении значе- ния на выводе V0) необходимо добавить функцию blynkwrite(O). В качестве параметра в эту функцию как раз и приходит значение виртуального порта V0. Вы- ведем его в последовательный порт: BLYNK_WRITE(O) int valVO=param.aslnt(); Serial.print("virtual pinO=");Serial.println(valVO); Добавим этот фрагмент в скетч из листинга 10.1 и загрузим в плату Arduino. Те- перь, меняя значение на слайдере в проекте на планшете, мы видим вывод этого значения в монитор последовательного порта (рис. 10.15). [0 My IP: 192.168.0.120 [1301] Connecting to cloud.blynk.ее:8442 [0] Blynk vO.2.1 [0] Using static IP [1300] My IP: 192.168,0.120 [1301] Connecting to cloud.blynk.ee:8442 [2393] Ready! virtual pm0«Q virtual pmG=15 virtual pmO=66 virtual pinO=75 virtual pmO=75 virtual pinO=75 virtual pmO=76 virtual pmO=97 virtual pmO=128 virtual pmO«132 virtual pinO=132 virtual pmO=132 virtual pm0=130 Рис. 10.15. Получение значений виртуального порта V0 на Arduino Соответственно, получаемое Arduino значение положения слайдера мы можем ис- пользовать для задания угла поворота сервопривода — подсоединяем сервопривод в выводу D9 платы Arduino (рис. 10.16) и загружаем в плату скетч из листинга 10.2. Теперь с помощью слайдера на планшете мы можем управлять поворотом подклю- ченного к плате Arduino сервопривода (см. рис. 10.16).
204 Глава 10 Рис. 10.16. Управляемый слайдером сервопривод добавлен к монтажной плате // подключение библиотек #define BLYNK_PRINT Serial #include <SPI.h> #include <Ethernet.h> #include <BlynkSimpleEthernet.h> #include <Servo.h> // создание экземпляра объекта Servo Servo servol; // токен авторизации для проекта на смартфоне char auth[] = fl16bcc28b557d4c45b3fd380f5cf8da66"; // МАС-адрес и настройки сети для Ethernet shield byte arduinojnac[] = { OxDE, OxED, OxBA, OxFE, OxFE, OxED }; IPAddress arduino_ip ( 192, 168, 0, 120); IPAddress dns_ip ( 192, 168, 1, 1); IPAddress gateway_ip ( 192, 168, 0, 28); IPAddress subnet mask(255, 255, 255, 0);
Проект Blynk: управление Arduino с планшета 205 BLYNK_WRITE(O) { int valVO=param. aslnt () ; Serial.print("virtual pinO=")/Serial.printIn(valVO); servol.write(valVO); // поворот сервопривода } void setup () { Serial.begin(9600) ; Blynk.begin(auth, "cloud.blynk.ee", 8442, arduino_ip, dns_ip, gateway_ip, subnet_mask, arduino_mac); servol.attach(9); // подключает переменную servo к выходу 9 } void loop () { Blynk. run(); Электронный архив Скетч, соответствующий листингу 10.2, можно найти в файле ardulno_scetches\_10\ __10_02.ino сопровождающего книгу электронного архива. 10.3. Отправка данных из Arduino на экран планшета Дополним наш проект возможностью отображения на экране планшета данных с любых датчиков, подключенных к плате Arduino. Воспользуемся для этого датчи- ком освещенности ВН1750, и станем отправлять с него данные в облако каждые 10 секунд. Чтобы организовать этот процесс, добавим в наш проект на планшете виджет Value Display. В качестве виртуального порта (PIN) выберем Virtual VI (рис. 10.17). Создадим новый скетч (листинг 10.3) на основе скетча из листинга 10.1, добавив в него процедуру получения Arduino данных с датчика ВН1750 и отправку этих данных в проект на планшете через облако cloud.blynk.ee. Для задания периодич- ности опроса датчика и отправки данных в облако мы воспользуемся библиотекой SimpleTimer. Отправку данных в виртуальный порт обеспечивает функция: Blynk. virtualWrite (pin, value) ;
206 Глава 10 Рис. 10.17. Создание виджета Value Display для виртуального порта V1 //. подключение библиотек #define BLYNK_PRINT Serial #include <SPI.h> #include <Ethernet.h> #include <BlynkSimpleEthernet.h> #include <Servo.h> #include <SimpleTimer.h> #include <BH1750.h> #include <Wire.h> // создание экземпляра объекта ВН1750 BH1750 light1; // создание экземпляра объекта Servo Servo servol; // создание экземпляра объекта SimpleTimer SimpleTimer timer; // токен авторизации для проекта на смартфоне char auth[] = n16bcc28b557d4c45b3fd380f5cf8da66"; // МАС-адрес и настройки сети для Ethernet shield byte arduino_mac[] = { OxDE, OxED, OxBA, OxFE, OxFE, OxED };
Проект BIynk: управление Arduino с планшета 207 IPAddress arduino__ip ( 192, 168, 0, 120); IPAddress dns_ip ( 192, 168, 1, 1); IPAddress gateway_ip ( 192, 168, 0, 28);IPAddress subnet_mask(255, 255, 255, 0); // получение значения с виртуального порта V0 BLYNK_WRITE(0) { int valVCMparam.aslnt(); Serial.print("virtual pinO=");Serial.println(valVO); servol.write(valVO); // поворот сервопривода void setup () { Serial.begin(9600); BIynk.begin(auth, "cloud.blynk.ee", 8442, arduino_ip, dns_ip, gateway_ip, subnet_mask,arduino_mac); servol.attach(9); // подключает переменную servo к выходу 9 lightl.begin(); // запуск датчика ВН1750 timer.setlnterval(10000, sendBH1750); void loop() { BIynk. run (); timer, run(); void sendBH1750() { // получить значение освещенности в 1х uintl6 t lux = 1ightl.readLightLevel(); Serial.println(lux); // отправка значения освещенности BIynk.virtualWrite(1, lux); Электронный архив Скетч, соответствующий листингу 10.3, можно найти в файле arduino_scetches\_10\ _10_03.ino, а библиотеку SimpleTimer — в папке arduinoJibraries\SimpleTimer сопрово- ждающего книгу электронного архива. Теперь на планшете в виджете Value Display каждые 10 секунд мы видим измене- ние данных с датчика ВН1750 (рис. 10.18). Для отображения данных с датчика, подключенного к плате Arduino, необязательно писать код отправки данных по таймеру — можно воспользоваться возможностями библиотеки BIynk (листинг 10.4).
208 Глава 10 Рис. 10.18. Получение на планшете данных с датчика ВН1750, подключенного к Arduino При создании виджета Value Display (BH1750) мы указывали время опроса 10 секунд (см. рис. 10.17). С помощью библиотеки Blynk мы также каждые 10 секунд отправляем данные в виртуальный порт VI при получении запроса из виджета: BLYNK_READ (1) { // получить значение освещенности в 1х uintl6_t lux = lightl.readLightLevel(); Serial.println(lux); // отправка значения освещенности Blynk.virtualWrite(1, lux);
Проект BIynk: управление Arduino с планшета 209 II подключение библиотек #define BLYNK_PRINT Serial linclude <SPI.h> #include <Ethernet.h> #include <BlynkSimpleEthernet.h> #include <Servo.h> Jfinclude <BH1750.h> +++++-#include <Wire.h> // создание экземпляра объекта ВН1750 BH1750 light1; // создание экземпляра объекта Servo Servo servol; // токен авторизации для проекта на планшете char auth[] = n16bcc28b557d4c45b3fd380f5cf8da66"; // МАС-адрес и настройки сети для Ethernet shield byte arduino_mac[] = { OxDE, OxED, OxBA, OxFE, OxFE, OxED }; IPAddress arduino_ip ( 192, 168, 0, 120); IPAddress dns_ip ( 192, 168, 1, 1); IPAddress gateway_ip ( 192, 168, 0, 28); IPAddress subnet_mask(255, 255, 255, 0); BLYNK_WRITE(O) { int valVO=param.asInt(); Serial.print("virtual pinCM");Serial.println(valVO); servol.write(valVO); // поворот сервопривода } // функция обработки запроса с выхода VI BLYNK_READ(1) { // получить значение освещенности в 1х uintl6_t lux = lightl.readLightLeveK) ; Serial.println(lux); // отправка значения освещенности BIynk.virtualWrite(l, lux); void setup() { Serial.begin(9600);
210 Глава 10 Blynk.begin(auth, "cloud.blynk.ee"/ 8442, arduino__ip, dns_ip, gateway_ip, subnet_mask, arduino_mac); servol.attach(9); // подключает переменную servo к выходу 9 lightl.beginO ; void loopO { Blynk. run (); Электронный архив Скетч, соответствующий листингу 10.4, можно найти в файле arduino_scetches\_10\ _10_04.ino сопровождающего книгу электронного архива. Мы рассмотрели здесь базовые возможности сервиса Blynk. Разработчики сервиса обещают добавлять в него новые возможности, поэтому периодически заходим на сайг http://blynk.ee и следим за новостями.
ГЛАВА 11 loT-платформа ThingWorx ThingWorx— ведущая технологическая платформа Интернета вещей. Платформа имеет встроенные средства для подключения устройств и источников данных раз- ного рода, создания приложений, анализа данных, организации совместной работы (рис. 11.1). При всех ее возможностях работа с платформой настолько проста, что на ней выполняются задания соревнований Интернета вещей JuniorSkills в возраст- ной категории 10+. Конструктор «вещей» позволяет создавать приложения макси- мально просто, часто даже без использования программирования, а создание веб- страниц приложений не требует программирование вообще. Рис. 11.1. Возможности платформы ThingWorx
212 Глава 11 11.1. Подключение к платформе ThingWorx Чтобы получить доступ для работы с платформой ThingWorx, сначала надо полу- чить доступ к ее курсам. Для этого переходим по ссылке: https://eliademy.com/ и регистрируемся. Затем по адресу: https://eliademy.com/app/a/courses/8a6be9c4ad/15 записываемся на бесплатный курс Разработка приложений интернета вещей (вводный курс) (рис. 11.2). Слушателям курса предоставляется доступ к платформе ThingWorx, где можно будет создать Mashup-приложение для отображения получаемых с устройств дан- ных и удаленного управления устройствами. 11ШвШшвШвШ Рис. 11.2. Курс Разработка приложений интернета вещей (вводный курс) 11.2. Мини-теплица на Arduino Теплицы предназначены для создания оптимального микроклимата, обеспечиваю- щего рост и развитие растений. Это может быть как большое промышленное со- оружение, так и небольшое место на подоконнике для выращивания любимого цветка. Но даже за самой крохотной теплицей на подоконнике нужен уход: осуще- ствлять полив растения, поддерживать нужную температуру, уровень освещенно- сти и т. п. Какие же функции будет выполнять наша умная теплица? По-минимуму: получать всю необходимую информацию об климатических параметрах нашей теп- лицы, т. е. осуществлять мониторинг:
loT-платформа ThingWorx 213^ О температуры воздуха (датчик LM35); □ влажности воздуха (датчик DHT11 или DHT22); □ температуры почвы (датчик DS18B20 герметичный); □ влажности почвы (датчик soilMoisture); □ освещенности (фоторезистор). Все эти данные будут отправляться на платформу ThingWorx. Итак, вставляем Ethernet W5100 Shield в плату Arduino UNO и подключаем датчики по схеме, представленной на рис. 11.3. Рис. 11.3. Схема соединений мини-теплицы Перед загрузкой основного скетча необходимо загрузить скетч для получения уни- кального номера датчика DS18В20 (листинг 11.1). // ThingWorx // получение уникального идентификатора DS18B20 // *•***•**• константы ******** idefine PIN DS18B20 16 // пин подключения ds!8b20
214 Глава 11 I/ dsl8b20 #include <OneWire.h> OneWire ds(PIN_DS18B20_l); // подключение onewire датчиков температуры void setup() { Serial.begin(9600); void loop() { // ***** получение показаний с датчиков get_id_dsl8b20(); // задержка delay(15000); void get_id_dsl8b20() { byte i; byte addrl[8]; if ( Ids.search(addrl)) { Serial.print("No more addresses.\n"); ds.reset_search(); } Serial.printC'R»"); //R=28 Not sure what this is for( i - 0; i < 8; i++) { Serial.print(addrl[i], HEX); Serial.print(" "); } Serial.println(); if ( OneWire::crc8( addrl, 7) !- addrl[7]) { Serial.print("CRC is not valid!\n"); } if ( addrl[0] != 0x28) { Serial.print("Device is not a DS18S20 family device.\nM); Электронный архив Скетч, соответствующий листингу 11.1, можно найти в файле arduino^scetchesXJIUI.OI.ino сопровождающего книгу электронного архива (см. приложение). Далее открываем монитор последовательного порта (рис. 11.4) — выделенное на иллюстрации значение и есть уникальный 64-битный идентификатор датчика DS18B20. Теперь загружаем в плату Arduino скетч из листинга 11.2. Перед этим в скетче не- обходимо внести изменения (вписать уникальный 64-битный номер своего датчика
Рис. 11.4. Получение уникального номера датчика DS18B20 температуры DS18B20). Для этого в строке 24 заменяем данные на 64-битное зна- чение вашего датчика: byte addr[2] [8] = { {0x28,0x90,0x57,,0x65,0x04, 0, 0,0хЕ4}, // *•**•**** константы ******** ^include "defines.h" // ********* подключение библиотек ********* // dsl8b20 tinclude <OneWire.h> // dht linclude "DHT.h" DHT dht(PIN_DHT, DHTTYPE); // тип датчика DHT11,DHT22 OneWire ds(PIN_DS18B20_l); // подключение onewire датчиков температуры // для DS18B20 byte addr[2][8]={ {0x28, 0x90, 0x57, 0x65, 0x4, 0x0, 0x0, 0xE4}, {0x28, ОхЕЗ, 0x4, 0x67, 0x5, 0x0, 0x0, 0x52} }; float fvalue; // переменная void setup() { Serial.begin(9600); // инициализация dht11 dht.beginO ; } void loopO { // ***** получение показаний с датчиков // dsl8b20 - 1 Serial.print("DATA dsl8b20 = "); Serial.println(get_temp(O)); // dhtll Serial.print("DATA dht 11= "); Serial.printIn(get_dht());
216 Глава 11 /I Im35 Serial.print("DATA Im35 = "); Serial.println(get_lm35()); // soilMoisture Serial.print("DATA soilMoisture % - "); Serial.println(get_soilMoisture()); // фоторезистор Serial.print("DATA photo % - ■') ; Serial.println(get_light()); // задержка delay(5000); Serial.printlnO ; } // получить показания с датчика температуры dsl8b20 // num= 0-воздуха, 1-почвы float get__temp (int num) { byte i; byte present = 0; byte data[12]; int Temp; float fTemp; ds.reset(); ds.select(addr[num]); ds.write(0x44,1); // start conversion, with parasite power on at the end delay(lOOO); // подождать 750 ms is enough, maybe not present = ds.reset(); ds.select(addr[num]); ds.write(OxBE); // Read Scratchpad for ( i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); } Temp= (data [ 1 ] «8) +data [0] ; Temp=Temp; //divide by 16 to get pure celcius readout fTemp-float(Temp/16)+float((Temp%16)*100)/16/100; return fTemp; } // получить показания с датчика DHT float get_dht(){ float fhumidity; fhumidity^dht.readHumidity(); if (isnan(fhumidity)) { return 1000.0; } return fhumidity;
loT-платформа ThingWorx 217 II получить показания с датчика SoilMoisture float get_soilMoisture(){ float percentSoilMoisture; percentSoilMoisture=map(analogRead(PIN_SOILMOISTURE),MIN_SOILMOISTURE, MAX_SOimOISTURE, 0,100) ; return percentSoilMoisture; } // получить показания освещенности float get_light () { int light; light=*map(analogRead(PIN_LIGHT),MIN_LIGHT,MAX_LIGHT,0,100); return float(light); }' // получить показания LM35 - датчик температуры float get_lm35 () { double val=analogRead(PIN_LM35); double voltage=val*5.00/1024; double temp=voltage*100-273; return float(temp); DATA USI8D20 - DATA dSl8b20 - 20.69 DATA dht 11- 39.00 DATA Iffl35 - 21.34 DATA SoilMoisture % - 42.00 DATA photo % - 74.00 DATA dsl8b20 «20.69 DATA dht 11« 39.00 . DATA Im35 - 21.34 DATA SoilMoisture % - 41.00 DATA photo % - 74.00 DATA dsl8b20 «20.56 DATA dht 11» 39.00 DATA Im35 «21.34 DATA SoilMoisture % - 41.00 DATA photo % » 75.00 DATA dsl8b20 «20.56 DATA dht 11» 39.00 DATA Im35 «21.34 DATA SoilMoisture % - 40.00 DATA photo % » 74.00 DATA dsl8b20 - 20.56 DATA dht 11- 39.00 DATA Ifn35 «21.34 DATA SoilMoisture % « 40.OG DATA photo % » 74.00 DATA dsl8b20 «20.56 DATA dht 11- 39.00 DATA Ifli35 «21.34 DATA SoilMoisture % - 40.00 DATA photo % ш 74.00 DATA ds!8b20 « Рис. 11.5. Получение данных мини-теплицы
218 Глава 11 Электронный архив Скетч, соответствующий листингу 11.2, можно найти в файле arduino_scetches\_11\_1i_02.ino сопровождающего книгу электронного архива (см. приложение). После загрузки скетча в плату открываем монитор последовательного порта, где мы должны увидеть вывод значений, считываемых с датчиков (рис. 11.5). 11.3. Создание «вещи» в ThingWorx и задание ее свойств Для создания в ThingWorx приложения Интернета вещей следует запустить конст- руктор приложений Composer. Для слушателей курса Разработка приложении интернета вещей (вводный курс) он находится по адресу http://tvsn.doud. thingworx.com/Thingworx/Composer. При обращении по этому адресу система запросит логин и пароль. Во время за- грузки системы появляется заставка (рис. 11.6), а затем открывается окно браузера Composer. Рис. 11.6. Загрузка конструктора приложений Composer
loT-платформа ThingWorx 219 Рис. 11.7. Создание в браузере Composer новой «вещи» Для создания новой «вещи» выбираем пункт Modeling | Things и нажимаем на кнопку New (рис. 11.7). В открывшемся после этого окне надо задать общую информацию (General Infor- mation) о создаваемой «вещи». Обязательно следует присвоить «вещи» наименова- ние (Name), дать ее краткое описание (Description) и задать шаблон. Для нашей «вещи» мы воспользуемся шаблоном «вещи общего вида» (GeneralThings) (рис. 11.8). General Information Search f?®sy?ts Рис. 11.8. Заполнение в Composer данных новой «вещи»
220 Глава 11 Закончив ввод, можно сохранить информацию и перейти к вводу следующего па- раметра (Done and Add), либо просто закончить работу (Done). Бели вы собирае- тесь выводить в приложении местоположение вашей теплицы на картах Google, добавьте для «вещи» свойство (Propetries) с типом данных (Base Type): Location (рис. 11.9). После задания всех свойств «вещи» сохраните данные кнопкой Save (рис. 11.10). • Properties Рис. 11.9. Добавление свойства о местоположении Location Рис. 11.10. Сохранение созданной «вещи»
loT-платформа ThingWorx 221 11.4. Изменение свойств «вещи» в ThingWorx Значения параметров (свойств) «вещи» не могут изменяться сами собой. Присвое- ние или изменение значений параметров (в том числе получение значений от ре- альной «физической» вещи через Интернет) производится с помощью т. н. служб (Service). Для создания новой службы надо перейти в раздел Services выбранной «вещи» и нажать кнопку Add My Service (рис. 11.11). - Services My 3*'fV!v«:* 1toq : Рис. 11.11. Добавление службы в Composer В открывшемся окне надо задать имя (Name) службы и дать ее краткое описание (Description) (рис. 11.12). В окне Script на языке программирования JavaScript записываются необходимые преобразования параметров. Для преобразований нужны какие-то входные дан- ные — в нашем случае это данные, которые будет отправлять ваша мини-теплица на Arduino. Эти данные необходимо добавить на вкладке Inputs/Outputs (рис. 11.13). Для добавления данных нажимаем кнопку Add и в открывшемся окне вводим дан- ные входного параметра: его наименование (Name), его описание (Description), тип (Base Type), а также, при необходимости, указываем, является ли он обязательным (Required) и имеет ли значение по умолчанию (Has Default Value) (рис. 11.14). После чего вводим все необходимые входные данные и сохраняем их кнопкой Save Entity (рис. 11.15).
222 Глава 11 е if &ШШ Рис. 11.12. Заполнение данных службы в Composer Services Рис. 11.13. Заполнение данных на вкладке Inputs/Outputs
loT-платформа ThingWorx 223 J- [ Inpm Parameter Рис. 11.14. Ввод данных для входных параметров ■ Services Script Оицмт г и т шзш Рис. 11.15. Ввод входных данных
224 Глава ft Далее в окне Script пишем скрипт для преобразования входных параметров (рис. 11.16): me. AirTemperature=parseFloat (ValAirTemperature) me.AirHumidity=parseFloat(ValAirHumidity) me.SoilTemperature=parseFloat(ValSoilTemperature) me.SoilMoisture=parseFloat(ValSoilMoisture) me.Light=parseFloat(ValLight) try { me.Location.latitude=ValLat; me.Location.longitude=ValLon; } catch(err) { me.Location.latitude=0.0; me.Location.longitude=0.0; } Services Script 1 n m '" ш Ш it 'ШШ M Ш Рис. 11.16. Ввод скрипта обработки данных в окне Script Закончив ввод или корректировку службы, надо сохранить ее, нажав кнопку Save Entity. Теперь можно проверить, как служба преобразовывает принимаемые данные. Для этого в списке сервисов нажимаем кнопку Test (рис. 11.17). Затем в открывшемся окне вводим данные для входных параметров и нажимаем кнопку Execute Service (рис. 11.18). Если ошибок нет, можем перейти в просмотр параметров «вещи» Properties и уви- деть, что свойствам «вещи» присвоены значения только что отправленных пара- метров (рис. 11.19). Теперь можно приступить и к созданию веб-страницы приложения.
loT-платформа ThingWorx 225 Services - Tsmpsatir} ■ S<?rvicet5 Рис. 11.17. Тестирование сервиса Рис. 11.18. Ввод тестовых данных
226 Глава 11 . Properties >• Рис. 11.19. Результат успешного тестирования 11.5. Создание веб-страницы для отображения принимаемых данных Веб-страница приложения создается в т. н. конструкторе машапов (Mashup Builder), и для этого не требуется знание программирования. Конструктор машапов автоматически вызывается при создании или работе с машапом в разделе Visualization. Для создания нового машапа нажимается значок с зеленым знаком New (рис. 11.20). В открывшимся окне надо выбрать тип машапа (в данном случае— страница (Page)) и формат вывода на экран: изменяющегося размера (Responsive) или ста- тичный (Static) (рис. 11.21). После задания этих значений (нажатия на кнопку Done) открывается собственно конструктор машапов (Mashup Builder) (рис. 11.22). Центральная зона окна — это макет будущей веб-страницы. В левой верхней части окна расположены графические элементы (Widgets), которые можно на веб- страницу добавить. Добавление графического элемента производится простым пе- ретаскиванием его из списка слева в нужное место на макете веб-страницы. Для некоторых графических элементов нужна «подложка», которой на панели Panel можно задать свой цвет, текстуру и пр. Если при перетаскивании графического элемента на макет появится сообщение, что нужно сначала создать панель, — под- твердите ее создание.
loT-платформа ThingWorx 227 Рис. 11.20. Создание нового машапа New Wasiiup Рис. 11.21. Выбор типа и формата вывода машапа Добавим на веб-страницу для отображения текущих значений датчиков три видже- та LedDisplay, два виджета Gauge (для отображения увлажненности почвы и осве- щенности в процентах) и пять виджетов Label (для надписей). Добавим и геогра- фическую метку для GoogleMaps — GoogleLocationPicker (рис. 11.23).
228 Глава 11 О fs Рис. 11.22. Окно конструктора машапов ции nnn ции и, и' Рис. 11.23. Добавление виджетов на веб-страницу
loT-платформа ThingWorx 229 Свойства выделенного на макете графического элемента появляются в левом ниж- нем окне, там же можно их и задавать (рис. 11.24). Можно также выбирать стили отображения выбранного виджета и создавать собственные стили (рис. 11.25). Рис. 11.24. Задание стилей отображения для виджетов Рис. 11.25. Выбор стилей отображения для виджетов
230 Глава 11 Рис. 11.26. Предварительный просмотр веб-страницы После сохранения машапа (кнопкой Save) можно посмотреть получившуюся стра- ницу — по нажатию на кнопку View Mushup машап откроется в новом окне как реальная веб-страница (рис. 11.26). Теперь необходимо сделать так, чтобы в виджетах отображались реальные данные с датчиков. Поэтому закрываем веб-страницу и продолжаем редактировать машап, добавив в него источники данных. Для этого в верхнем правом углу окна конструк- тора выбираем вкладку Data и нажимаем на кнопку + (рис. 11.27). Рис. 11.27. Добавление источников данных для машапа
ЬТ-платформа ThingWorx 231 Рис. 11.28. Добавление источника данных Things В открывшемся окне источник данных — Things (рис. 11.28). В качестве сервиса получения данных выбираем наш сервис GetProperties и под- тверждаем выбор кнопкой Done (рис. 11.29). С # Acid 0з*.а Рис. 11.29. Выбор сервиса GetProperties Теперь в конструкторе машапов перетягиваем на каждый из виджетов необхо- димые данные (рис. 11.30). В нижней средней части конструктора на вкладке Connections видна установленная связь данных (рис. 11.31).
232 Глава 11 Рис. 11.30. Привязка данных к виджетам перетягиванием Рис. 11.31. Привязка данных установлена
loT-платформа ThingWorx 233 С ПН u.uu Рис. 11.32. Машап сданными из сервиса Снова выбираем View Mushup и видим страницу с заполненными данными (рис. 11.32). Добавьте еще виджет AutoRefresh, измените Refreshlnterval на необходимый (в сек) — например, введите 30. И протяните связь от свойства Refresh вправо на службу GetProperties в области значений (Data). Уберите галочку со свойства Visible, чтобы скрыть кнопку. Сохраните результат и убедитесь, что значения обновляются автоматически каждые 30 секунд. 11.6. Отправка данных с Arduino в сервис ThingWorx Набор функций, к которым разработчики могут совершать запросы и получать от- веты, определяет REST API. Взаимодействие происходит по протоколу HTTP. Пре- имуществом такого подхода является широкое распространение протокола HTTP, поэтому REST API можно использовать практически из любого языка программи- рования. REST API ThingWorx предназначен для запросов к серверам ThingWorx. Для отправки данных с датчиков необходимо отправить следующие данные: POST /Thingworx/Things/<thingName>/Services/<serviceName>?appKey=<appKey> &method!=post&x-thingworx-session=true<parameters> HTTP/1.1 Host: tvsn.cloud.thingworx.com Content-Type: text/html
234 Глава ft Для создания ключа аррКеу выбираем в разделе Security пункт Applications Keys и нажимаем кнопку New (рис. 11.33). В открывшемся окне вводим данные и сохраняем их кнопкой Save (рис. 11.34). Ж -:ы^ Рис. 11.33. Создание ключа аррКеу Щ reformation Рис. 11.34. Ввод данных ключа аррКеу и их сохранение
loT-платформа ThingWorx 235 В поле keyld отражается ваш аррКеу: char аррКеуП = n87e241cc-4b5a-4080-ab6e--8aba62047c47lf; Другие параметры: // ThingWorx Thing name char thingName[] = "ThingGreenhouse_i00019_01"; // ThingWorx service char serviceName [] = "ServiceGreenhouse_01"; <parameters> - список параметров в формате &<name>=<value> Для выбора названий параметров открываем нашу «вещь», выбираем раздел Services, в нем находим имя нашего сервиса приема данных и вкладку Inputs/Outputs (рис. 11.35). Services ■■&*■■ и* ё. Ж 1>: rihoysfi 01 Щ Рис. 11.35. Список параметров Далее загружаем на плату Arduino скетч из листинга 11.3, изменив данные на свои. // •••*••••• константы ******** Hnclude "defines.h"
236 Глава 11 // ••••••••* подключение библиотек •*•*****• // dsl8b20 tinclude <OneWire.h> // dht #include "DHT.h" // Ethernet #include <SPI.h> #include <Ethernet.h> DHT dht(PIN_DHT, DHTTYPE); // тип датчика DHT11,DHT22 OneWire ds(PIN_DS18B20_l); // подключение onewire датчиков температуры // для DS18B20 byte addr[2][8]={ {0x28, 0x90, 0x57, 0x65, 0x4, 0x0, 0x0, 0xE4}, {0x28, ОхЕЗ, 0x4, 0x67, 0x5, 0x0, 0x0, 0x52} byte arduinojnac [] = { OxFF, OxFE, OxFB, OxFA, 0xF9, 0xF8 }; EthernetClient client; // если адрес статический // (установить #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,1/1}; // ThingWorx-сервер //char server[] = "thingworx-academic-staff.ptcmscloud.com"; char server[] = "tvsn.cloud.thingworx.com"; // ThingWorx App key //char appKey[j - n9bcf4e6c-ce7c-48c6-9b5e-59634f58066e"; char appKey[] = M87e241cc-4b5a-4080-ab6e-8aba62047c47"; // ThingWorx Thing name char thingName[] = "ThingGreenhouse_i00019_01"; // Интервал отправки данных unsigned long timeBetweenRefresh = 60000; // ThingWorx service char serviceName [] = "ServiceGreenhouse__01"; // Initialize Properties Names and Values Arrays //How many values you will be pushing to ThingWorx #define propertyCount 7 char* propertyNames[] - {"ValLat","ValLon", "ValAirTemperature", "ValAirHumidity", "ValSoilTemperature", "ValSoilMoisture", "ValLight",
loT-платформа ThingWorx 237 double propertyValues[propertyCount]; int digitValues[propertyCount]={4,4,2,2,2,2,2}; // last time you connected to the server, in milliseconds unsigned long lastConnectionTime = 0; // state of the connection last time through the main loop boolean lastConnected = false; float fvalue; // переменная void setup () { Serial.begin(9600); // инициализация dhtll dht.begin(); // установка сетевого соединения ethernet_begin(); print_ip(); void loop() { if (millisO - lastConnectionTime > timeBetweenRefresh) { // ***** получение показаний с датчиков // dsl8b20 - 1 propertyValues[2]=get_temp(0); // dhtll propertyValues[3]=get_dht(); // Im35 propertyValues[4]=get_lm35(); // soilMoisture propertyValues[5]=get_soilMoisture(); // фоторезистор propertyValues[6]=get_light(); propertyValues[0]=44.1365; propertyValues[1]=43.0278; updateValues(propertyValues, client, server, appKey, thingName, serviceName, propertyNames); Электронный архив Скетч, соответствующий листингу 11.3, можно найти в файле arduino_scetches\_11\J1_03.ino сопровождающего книгу электронного архива (см. приложение). Затем в мониторе последовательного порта проверяем наличие соединения и от- правку данных (рис. 11.36). Откройте созданный машап, и вы увидите в нем отправленные из Arduino данные (рис. 11.37).
238 Глава 11 onnected POST /Thingvorx/Things^hingGreenhouse_i«»19_01/Service5/Sem«^ 14ft Host tvsn cloud thingvorx cot Content-Type text/htil connected POST /mngwxAhings/nungGreenhouse_iGCm9_Gl/Service5/S9rv^ 14, Host tvsn cloud thingvorx со» itent-Type text/htnl mected РСЛТ /Thlno>oгxЯh^ngs/ThlngGгeвnhous6_lOOQ19_01/Sвгvlces/Seг¥lceGreenhouse_01'appKey»87e241cc-4b5a-4G8Q•ab6e-8aba62(M7c47toethod^o8t&^ 14Й Host tvsn cloud thingvorx coi "yntent Type text/html :onnected POST ^ingvorx/11iings/IbingGreenhouse_iOOQ19_01/Services/ServiceGreenhouse_01^ppKey«^e241cc-4b5a-408G-ab6e-8aba62G47c47teethod^o Ш Host tvsn cloud thingworx coi itent-Typ* text/ht«l connected , fWT ЯНгпд¥дд Host tvsn cloud.thingworx coi ".ontent-Type text/htnl :onnected (6T AhingvorxAhingsAhingGreenhouse_iOOG19_01/Services/ServiceGreenhouse_01'appKey-87e241cc-4bSa-408G ab6e-8aba62Q47c47&Bethod-post&x thingvorx-session-true<&ValLat-44 № i-to5t tvsn cloud.thingvorx coi Content Type text/Mil connected j POST mingvorx^hings/TlnngGreenhouse_i0Oai9_01/Service5/ServiceGreenhouse_01'>appKey-87e241cc-4b5a-4Cia) ay»-8aba62Q47c47ft!iethod-post&x thingvorx-sessxon-true<«iValLat-44 Ш Hst. tvsn.cloud.thingvorx coi »ntent-T>pe text/html с 4b5e-408Q-ab6e-8aba62e47c47&eethod-po8t&x-thingworx-6ession-true<&ValLat-44 1 Рис. 11.36. Данные соединения и отправки данных в мониторе последовательного порта Рис. 11.37. Отображение данных из Arduino в машапе
loT-платформа ThingWorx 239 11.7. Создание в ThingWorx потока данных и построение графиков Теперь рассмотрим, как в ThingWorx строить для поступивших данных графики. Для построения графика сначала создадим поток данных— в разделе DATA STORAGE выберем пункт Value Streams и нажмем кнопку New (рис. 11.38). В открывшемся окне выбираем пункт Value Stream (рис. 11.39). Ш -ей? Рис. 11.38. Создание нового потока данных Choose ValueStre&m Template Рис. 11.39. Выбор Value Stream
240 Глава 11 €*•■ - С? fl # General Inf on nation Рис. 11.40. Заполнение данных о ValueStream Затем добавляем информацию о Value Stream: имя Name, описание Description и шаблон Thing Template: ValueStream (рис. 11.40). Теперь переходим к нашей «вещи», для которой создается поток, — ThingGreen- house_i00019, и в поле Value Stream выбираем созданный поток: Greenhouse_ Ю0019 (рис. 11.41). General inforrriation Рис. 11.41. Привязка потока к «вещи»
loT-платформа ThingWorx 241 С 7*т Properties Ar Tfeftipe га til га Рис. 11.42. Выбор свойств, для которых будем выводить графики У тех свойств «вещи», для которых будем строить графики, ставим флажок Logged (рис. 11.42). Для показа графика с данными в машапе переходим в окно редактирования, на вкладке Data добавляем новые данные (рис. 11.43): источник — «вещь» Щ nan им и Рис. 11.43. Добавление данных в машап
242 Глава 11 Рис. 11.44. Выбор источника для отображения потока данных в машап Рис. 11.45. Добавление виджета Label Chart
1оТ-платформа ThingWorx 243 ThingGreenhouse_i00019, сервис— QueryPropertyHistory и завершаем добавле- ние нажатием кнопки Done (рис. 11.44). Затем на веб-страницу добавляем виджет Label Chart (рис. 11.45). В свойствах виджета устанавливаем значения параметров: □ XAxisField — timestamp; П ChartType — bar; □ DataFieldl—AirTemperature. Запускаем машап и видим на веб-странице график (рис. 11.46). Рис. 11.46. Отображение графика с данными на веб-странице 11.8. Создание на веб-странице кнопок для отправки команд управления актуаторами на Arduino В предшествующих разделах мы разобрались, как организовать удаленный мони- торинг данных с Arduino-устройства. Теперь рассмотрим вопрос организации управления Arduino-устройством из веб-приложения и организуем, например, воз- можность удаленно запускать помпу для полива растений. Откроем окно редактирования машапа и добавим виджет Checkbox. Пусть в со- стоянии «включено» необходимо производить полив, а в состоянии «выключе- но» — выключать его (рис. 11.47).
244 Глава 11 ^r^-^-M^\"^-4s^kdf>>^ Рис. 11.47. Добавление в машап виджета Checkbox Перейдем теперь к нашей «вещи» (ThingGreenhouse_J00019) и добавим новое свойство (Properties) Watering (рис. 11.4S): Watering=l— полив включен, Watering=O — полив выключен. Затем переходим в область Services и создаем новый сервис — Service_Greenhouse_ water_on (рис. 11.49). Properties ШшШш» Рис. 11.48. Добавление «вещи» свойства Watering
loT-платформа ThingWorx 245 ;•' Services ве^wafer on Рис. 11.49. Создание нового сервиса: Service_Greenhouse_water_on На вкладке Inputs/Outputs добавляем входную переменную ValWatering (тип boolean), которая будет принимать значение переключателя и устанавливать свой- ство Watering в 0 или в 1 (рис. 11.50). Services ouse .watw on # ^ Рис. 11.50. Добавление переменной ValWatering
246 Глава 11 циУ Рис. 11.51. Добавление источника данных Рис. 11.52. Добавление сервиса Service_Greenhouse_water_on в качестве источника данных Вернемся к редактированию машапа и на вкладку Data (рис. 11.51), добавим ис- точник данных — сервис Service_Greenhouse_water_oii (рис. 11.52). После чего делаем привязку для виджета Checkbox: □ свойства State ко входу (input) переменной ValWatering сервиса Service^ Greenhouse_water_on (рис. 11.53); □ события Changed к сервису Semce_Greenhouse_water_pn (рис. 11.54).
loT-платформа ThingWorx 247 -ей Рис. 11.53. Привязка свойства State ^??Щ$ГШ Рис. 11.54. Привязка события Changed Результат выполненных привязок показан на рис. 11.55. Теперь запускаем веб-приложение кнопкой View Mushup и видим, что при изме- нении статуса Checkbox изменяется и значение свойства Watering «вещи» Thing Greenhouse iOOO19 (рис. 11.56).
248 Глава 11 Рис. 11.55. Результат привязки *1 ППГ\ Рис. 11.56. Отображение флажка запуска помпы на веб-странице
loT-платформа ThingWorx 249 11.9. Создание скетча для получения Ardulno-устройством данных из ThingWorx Настало время подключить к Arduino-устройству помпу для полива. Схема соеди- нений мини-теплицы приобретает вид, представленный на рис. 11.57. Помпа управляется с Arduino через реле, и для подключения помпы необходимо внешнее питание. Рис. 11.57. Схема соединений мини-теплицы с добавленным устройством управления помпой Для взаимодействия с веб-страницей на ThingWorx необходимо делать постоянные запросы к серверу для получения значения параметра Watering (который меняет значение в соответствии с переключателем виджета Checkbox). Для получения зна- чения параметра «вещи» необходимо отправить следующие данные: POST /Thingworx/Things/<thingName>/Properties/<propertyName>?appKey= <appKey>&method==post&x-thingworx-session=true HTTP/1.1 Host: tvsn.cloud.thingworx.com Content-Type: text/csv В ответ мы получим: char server[] - "tvsn.cloud.thingworx.com"; // ThingWorx App key char appKey[] = "87e241cc-4b5a-4080-ab6e-8aba62047c47"; // ThingWorx Thing name char thingName[] = "ThingGreenhouse_i00019_01"; Процедура запроса значений датчика представлена в листинге 11.4.
250 Глава 11 /I запрос значения датчика int getValue(char param[]) { //build the String with the data that you will send //through REST calls to your TWX server char data[80];• int dat « 0; char inChar; String t = String(""); bool bTransferDone = false; bool bStartFile = false; int connectLoop = 0; int nEol = 0; int nQuotes = 0; strcpy (data, "?appKey=") ; strcat(data, appKey); strcat(data, "&method=get&Accept=text/csv"); // if you get a connection, report back via serial: if (client.connect(server, 80)) { client.print("GET /Thingworx/Things/"); client.print(thingName); client.print("/Properties/"); client.print(param); client.print(data); client.println(" HTTP/1.1"); client.print("Host: "); client.printIn(server); client.println("Content-Type: text/csv"); client.println(); while (client.connected()) { while (client.availableO) { inChar = client.read(); Serial.write(inChar); if (inChar — f\nf || inChar — f\rf) { nEol++; } else { nEol = 0; } if (nEol >= 4) { // \r\n\r\n - маркер начала и конца в ответе сервера bStartFile - IbStartFile; } if (bStartFile) { if (inChar — fIff) { nQuotes++;
loT-платформа ThingWorx 251 if (nQuotes >= 2) { if (isDigit(inChar) || inChar — '.') { bTransferDone = true; t += inChar; connectLoop = 0; } connectLoop++; if (connectLoop > 900) { client.stop(); } // this is a delay for the connectLoop timing delay(1); } client.stop(); lastConnectionTime2 = millis (); else { // kf you didn't get a connection to the server: Serial.println("the connection could not be established") client.stop(); } if (bTransferDone) { dat - t.tolnt()/10; } else { dat = 999; } return dat; Электронный архив Скетч, соответствующий листингу 11.4, можно найти в файле arduino_scetches\J1\_i1_04.ino сопровождающего книгу электронного архива (см. приложение). Анализируем ответ сервера и, в зависимости от приходящего значения параметра Watering, включаем или выключаем помпу. Для включения помпы необходимо на вывод Arduino (PIN_PUMP=9) подать логический 0. int water = getValue ("Watering") ; if (water > 998) Serial.println("GET parse error");
252 Глава 11 else { Serial.print("Received WATER= "); Serial.println(water); digitalWrite(PINJPUMP,1-water); } Процесс отправки запроса и получения ответа от сервера можно увидеть и в мони- торе последовательного порта Arduino (рис. 11.58). Host: tvsn.cloud.thingworx.com Content-Type: text/html HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Set-Cookie: JSESSI0NID=37F1136EEA7ADB12E65B71737626D0FA; Path=Ahingworx/; HttpOnly Expires: Wed, 10 Aug 2016 11:17:32 UTC Content-Disposition: attachment;filename=data.csv Content-Type: text/csv; charset=4JTF-8 Transfer-Encoding: chunked Date: Wed, 10 Aug 2016 11:16:32 GMT Connection: close d "Watering" 1 Received WATER- 1 HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Set-Cookie: JSESSI0NID-85497F4E17323G96E7777C8B510732A8; PathVThingvarx/j HttpOnly Expires: Wed, 10 Aug 2016 11:17:38 UTC Content-Disposition: attachment;filename*data.csv Content-Type: text/csv;charset»UTF-8 Transfer-Encoding: chunked Date: Wed, 10 Aug 2016 11:16:38 GOT Connection: close d Watering" 1 Рис. 11.58. Процесс отправки запроса и получения ответа в мониторе последовательного порта
ГЛАВА 12 Микрокомпьютер Raspberry Pi Raspberry Pi — это миниатюрный, размером с кредитную карту, компьютер стои- мостью порядка 25 долларов за базовую модель и 35 — за более продвинутую, сни- скавший огромную популярность и разошедшийся по миру в количестве более 4,5 миллионов штук (на начало 2015 года). Одним из основных преимуществ Raspberry Pi является соотношение качества про- дукта и его стоимости. Конечно, этот мини-ПК не столь мощный, как современные компьютеры, но он прекрасно подходит для изучения компьютера и основ работы с ним, для решения многих практических задач, для интернет-серфинга, а также для проигрывания видео- и прослушивания аудиофайлов. В первую очередь, Raspberry Pi отводится роль компьютера, предназначенного для изучения с его помощью базовых информационных технологий в школе. Позицио- нируется Raspberry Pi и как дешевое решение для начинающих разработчиков. С учетом удовлетворительной мощности этого устройства, низкого энергопотреб- ления и малой себестоимости его можно использовать для создания личного мини- сервера. Raspberry Pi — идеальный компьютер для постановки различных экспериментов. А применительно к статистическому управлению процессами (от англ. Statistical Process Control, SPC) — методу мониторинга производственных процессов с целью управления качеством продукции непосредственно в процессе производства, Raspberry Pi является первым доступным техническим решением такого размера, которое можно использовать повсеместно для программирования на многих языках и в качестве микроконтроллеров для управления роботизированными устройст- вами. Одна из главных и привлекательных особенностей Raspberry Pi — наличие на плате аппаратных портов ввода/вывода GPIO (General Purpose Input/Output, интерфейс ввода/вывода общего назначения), что открывает перспективы использования его в робототехнических проектах и устройствах «умного дома».
254 Глава 12 12.1. Технические характеристики и возможности Raspberry Pi Первые версии Raspberry Pi: модели «А», «В» (рис. 12.1), «А+» и «В+» — оснаще- ны процессором Broadcom BCM2835 архитектуры ARM 11 с тактовой частотой 700 МГц и модулем оперативной памяти на 256 (или 512) Мбайт, размещенным по технологии package-on-package непосредственно на процессоре. Модель «А» осна- щается одним портом USB 2.0, модель «В»— двумя такими портами, модель «В+» — четырьмя. У моделей «В» и «В+» также наличествует порт Ethernet. По- мимо основного ядра, процессор ВСМ2835 включает графическое ядро с поддерж- кой OpenGL ES 2.0, аппаратного ускорения и видео Full HD, а также ядро DSP (Digital Signal Processor, цифровой сигнальный процессор). RCA VIDEO AUDIO ...•■■ ш, usb UN Рис. 12.1. Схема Raspberry Pi, модель «В» Питание компьютера осуществляется через разъем MicroUSB, при этом сила тока должна составлять минимум 0,5-0,7 А. При меньших значениях компьютер все еще может включиться, но будет уходить в перезагрузку при запуске ресурсоемких за- дач. Следовательно, подключать плату лучше не через хаб, а напрямую к USB- порту компьютера или в розетку через специальный переходник. Никаких кнопок включения/выключения на плате Raspberry Pi нет. Если необходи- мо устройство запустить — подключаете USB-питание, для выключения — выдер- гиваете шнур. Остается надеяться, что в будущих ревизиях Raspberry Pi, возможно, добавят питание по Ethernet, поскольку это один из самых частых запросов от поль- зователей.
Микрокомпьютер Raspberry Pi 255 Версии «А» и «В» устройства оснащены слотом для карт памяти формата SD, вер- сии «А+» и «В+» — слотом для карт формата MicroSD. Без карты памяти Raspberry Pi не включается, поскольку именно на ней должна быть записана операционная система, — это все равно что пробовать запустить компьютер без жесткого диска. Поскольку собственной ОС во внутренней памяти (как, например, в телефонах) у Raspberry Pi не имеется, то из этого следует один положительный момент — устройство практически невозможно превратить в «кирпич»: после любого неудач- ного эксперимента достаточно перезаписать дистрибутив на карте памяти, и Raspberry Pi снова заработает как новенький. Для подключения дисплея на плате Raspberry Pi имеются сразу два интерфейса: RCA Video (композитный) и HDMI. Применяя соответствующие переходники, можно выйти и на более традиционные: VGA и DVI. HDMI поддерживает передачу как видео, так и звука, но если потребуется отдельный аудиоканал, то и он присут- ствует на плате в виде стандартного мини-джека 3,5 мм. Подключение микрофона также возможно, но для этого понадобится найти USB-устройство, совместимое с Raspberry Pi. Существующие сейчас модели Raspberry Pi не имеют модуля Wi-Fi, и для работы с ними в Интернете понадобится задействовать порт Ethernet. Поскольку физически на плате он скоммутирован через USB 2.0, то обеспечивает не гигабитную, а всего лишь 100-мегабитную скорость. Чипы процессора и графического ускорителя не оснащены даже простейшими ра- диаторами, и после нескольких часов работы компьютера становится очевидным, почему его разработчики остановились именно на этом решении: плата нагревается при работе совсем незначительно — она скорее теплая, чем горячая. Частота процессора, как уже упоминалось, составляет 700 МГц, и, в зависимости от дистрибьютора, его можно разогнать до 1000 МГц без потери гарантии (возможен выбор и более щадящих режимов). Чип памяти производства Samsung или Hynix напаян прямо поверх основного чипсета, так что увеличить RAM самостоятельно не получится. При покупке стоит обратить внимание на маркировку этой SoC (от англ. System-on-a-Chip, системы на кристалле): номер партии для «старых» версий модели «В» с 256 Мбайт RAM начинается с K4P2G, а у выпуска с 512 Мбайт памя- ти—с K4P4G. Видеоускоритель Broadcom VideoCore IV позволяет даже при таком слабом про- цессоре декодировать видео 1080р h.264 с битрейтом вплоть до 40 Мбит/с. Для ап- паратного ускорения MPEG-2 и VC-1 лицензии придется докупать отдельно. Плата оснащена индикаторами — пятью светодиодами: три из них демонстрируют активность и режим работы Ethernet, а еще два сигнализируют о наличии питания и работе с SD-картой. На рынке можно найти несколько корпусов как официальных производителей уст- ройства, так и сторонних, которые применяются для повышения защищенности компьютера и более удобной его транспортировки. К теперь — самое интересное: уточним набор низкоуровневых интерфейсов, кото- рые позволяют подключать к Raspberry Pi платы расширения, внешние контролле-
256 Глава 12 ры, датчики и прочие аксессуары. Во-первых, на плате имеются 15-штырьковые слоты CSI-2 — для подключения камеры и DSI — для подключения дисплея. Во-вторых, присутствует колодка на 26 (40— для версии «В+») линий вво- да/вывода общего назначения GPIO. На них же реализованы интерфейсы UART, консольный порт, шина SPI (Serial Peripheral Interface, последовательный перифе- рийный интерфейс), PC (Inter-Integrated Circuit, последовательная шина данных для связи интегральных схем) и FS (Integrated Inter-chip Sound, последовательная шина данных, служащая для соединения цифровых аудиоустройств). Использование GPIO — это как раз самое интересное и творческое применение Raspberry Pi. Впрочем, недостатков у Raspberry Pi тоже хватает. В нем, к примеру, нет собствен- ных часов реального времени (Real Time Clock, RTC), поэтому единственный спо- соб получения времени — это синхронизация с NTP-серверами. SoC, как уже упо- миналось, содержит в себе цифровой сигнальный процессор (DSP), но полного дос- тупа к его API до сих пор нет. Выводы GPIO никак не защищены от короткого замыкания, поэтому ошибка в монтаже может сгубить весь мини-ПК. Кроме того, Raspberry Pi способен обрабатывать только цифровые сигналы. Видеовыходы не могут одновременно выводить картинку. Аудиовхода вообще нет... В 2015 году выпущена новая версия— Raspberry Pi 2 Model В (рис. 12.2). Вместо процессора ВСМ2835 в ней установлен чип ВСМ2836. Отличается он от предшест- венника наличием четырех ядер ARM Cortex-A7 с набором инструкций ARMv7 — против ARMv6k у ВСМ2835. Тактовая частота этого процессора составляет 900 МГц — не слишком много по меркам современных решений Qualcomm и даже MediaTek, но для подавляющего большинства DIY-проектов (от англ. Do It Your- self, «Сделай сам») ее хватит с лихвой, тем более что, напомним, ядер на этот раз целых четыре. Объем оперативной памяти нового устройства увеличен с 512 Мбайт до 1 Гбайт. Видеоядро изменений не претерпело, и это по-прежнему Broadcom Рис. 12.2. Микрокомпьютер Raspberry Pi 2
Микрокомпьютер Raspberry Pi 257 VideoCore IV. Разработчики говорят о шестикратном приросте производительности в многопоточных тестах и о трехкратном — в однопоточных. Новая мощь может пригодиться во встроенных системах при обработке изображений— есть много энтузиастов, которым хочется создать компьютерное зрение на основе OpenCV. Примечательно, что на новую модель сохранилась демократичная цена в 35 долларов США. Raspberry Pi может стать в ваших руках и медиацентром, и управляющим центром «умного дома», и мозгом робота — тут уж все зависит от вашей фантазии и жела- ния. В Сети есть немало примеров, готовых проектов, сообществ пользователей и целых магазинов, посвященных Raspberry Pi. Есть даже официальный очень-очень скромный интернет-магазин The Pi Store (http://store.raspberrypi.com/projects) с небольшим количеством ПО, игр, руководств и собственным журналом. В этой книге мы рассмотрим использование микрокомпьютеров Raspberry Pi в про- ектах IoT (Интернет вещей). 12.2. Установка операционной системы Для того чтобы запустить Raspberry Pi, необходимо установить на него операцион- ную систему. В качестве таковой нам доступны три официальных дистрибутива Linux: □ Pidora — основанный на Fedora; О Archlinux — установка этого дистрибутива происходит практически вручную; □ Raspbian — основанный на Debian. Кроме этих трех операционных систем, на Raspberry Pi портировано очень много других. Поскольку операционная система устанавливается на SD-карту, чтобы за- пустить другую систему, достаточно вставить в устройство карту с этой системой. Мы в наших проектах будем ориентироваться на операционную систему Raspbian. Самый простой способ установить дистрибутив на Raspberry Pi— инструмент N0OBS от создателей Raspberry Pi, который позволяет при первой загрузке вы- брать для установки одну операционную систему из следующих: □ ArchLinux; О OpenElec; П Pidora; О RaspBMC; □ Raspbian; О Rise Os. Для установки дистрибутива на Raspberry Pi с помощью NOOBS потребуется карта формата SD (для моделей «А» и «В») или MicroSD емкостью 4 Гбайт или более. SD-карту необходимо отформатировать, в чем нам поможет программа SD Formatter 4.0, архив которой доступен для закачки по ссылке https:// www.sdcard.org/downloads/formatter_4/eula_windows/ (рис. 12.3).
258 Глава 12 Рис. 12.3. Страница загрузки программы SD Formatter 4.0 Итак, помещаем нашу карту в картридер компьютера, скачиваем программу, уста- навливаем ее на компьютер и запускаем. Выбираем нашу SD-карту, нажав кнопку Options, задаем параметр FORMAT SIZE ADJUSTMENT равным ON и формати- руем (рис. 12.4). Рис. 12.4. Окно программы SD Formatter 4.0 Далее скачиваем программное обеспечение NOOBS (http://downloads.raspberrypi.org/ noobs) и распаковываем ZIP-файл на нашу SD-карту. По завершении записи вынимаем SD-карту из картридера компьютера и вставляем ее в Raspberry Pi. Подключаем монитор (по HDMI или VGA), клавиатуру, а так- же — опционально — мышь и кабель Ethernet. Затем подаем питание через порт MicroUSB. При первой загрузке устройства нам будет продемонстрировано меню, предлагающее установить одну из нескольких операционных систем в свободное пространство на карте памяти (рис. 12.5). После установки операционной системы Raspberry Pi станет загружаться в обыч- ном режиме. Тем не менее, NOOBS остается на карте, поэтому, удерживая клавишу
Микрокомпьютер Raspberry Pi 259 ■ ARM Рис. 12.5. Меню NOOBS при первой загрузке Рис. 12.6. Редактирование файла config txt
260 Глава 12 <Shift> во время загрузки, можно вернуться к меню выбора. Это позволяет пере- ключиться на другую операционную систему или заново переписать установку текущей, а также предоставляет удобный инструмент для редактирования установ- ленной операционной системы— файл конфигурации config.txt (рис. 12.6) и даже веб-браузер, так что в случае проблем с установкой можно будет найти информа- цию в Сети на тематических форумах. 12.3. Первоначальная настройка ОС Raspbian 12.3.1. Меню конфигурации При первом запуске ОС Raspbian мы увидим на экране монитора, подключенного к Raspberry Pi, меню конфигурации (рис. 12.7). Рассмотрим некоторые пункты этого меню: □ Expand Filesystem— расширение раздела на все пространство флеш-нако- пителя (операция будет выполнена после перезагрузки); □ Change User Password — изменение пароля пользователя Pi; □ Enable Boot to Desktop — запуск графического режима при загрузке; Рис. 12.7. Меню конфигурации Raspbian □ Internationalisation Options — выбор языка и региональных настроек: • Change locale — изменение языка: устанавливаем два значения: en_GB.UTF-8 и ru JUJ.UTF-8; • Change Timezone — настройка часового пояса; • Change Keyboard Layout — изменение раскладки клавиатуры; □ Enable Camera — поддержка модуля камеры; □ Overclock— увеличение частоты процессора (разгон), можно разогнать до 1ГГц;
Микрокомпьютер Raspberry Pi 261 □ Advanced Options — дополнительные параметры: • Overscan— настройка режима overscan (вылета развертки): если у вас по краю изображения имеется широкая черная полоса, то необходимо выклю- чить этот режим (опция Disable); • Hostname — имя компьютера в сети (по умолчанию raspberrypi); • Memory split — количество памяти, выделяемое под видео (по умолчанию — 64 Мбайт); • SSH — включение ssh-сервера; • Update — обновление программы raspi-config; □ About raspi-config — о программе. Настроив все необходимые параметры, выбираем Finish — система запросит раз- решение на перезагрузку. Соглашаемся. Если вы позже захотите поменять какие- либо настройки, необходимо в консоли набрать команду: sudo raspi-config После продолжительной перезагрузки система выйдет на запрос логина и пароля: вводим логин пользователя Pi и пароль, который был введен при настройке. Для запуска графического режима набираем в консоли команду: startx и попадаем на рабочий стол Raspbian (рис. 12.8). i a Рис. 12.8. Рабочий стол Raspbian
262 Глава 12 12.3.2. Настройка сетевых параметров Скорее всего, вы не будете использовать Raspberry Pi для вывода информации на монитор — вам наверняка понадобится удаленный доступ к нему по ssh, поэтому сейчас следует настроить его сетевые параметры. Установку сетевого соединения для Raspberry Pi обеспечивает файл конфигурации /etc/network/interfaces, и если IP-адрес Raspberry Pi получает по DHCP, то ничего пра- вить в этом файле вам не придется. В случае же назначения Raspberry Pi статиче- ского IP-адреса, выполняем команду: sudo nano /etc/network/interfaces и дописываем в файл конфигурации /etc/network/interfaces следующие строки: iface ethO inet static address 192.168.0.117 netmask 255.255.255.0 gateway 192.168.0.28 auto ethO где: □ iface ethO inet static — указывает системе, что интерфейс (iface etho) нахо- дится в диапазоне адресов IPv4 (inet) со статическим IP-адресом (static); □ address 192.168. о. 117 — указывает, что IP-адрес (address) нашей сетевой карты 192.168.0.117; □ netmask 255.255.255.0— указывает, что наша маска подсети (netmask) имеет значение 255.255.255. о; □ gateway 192.168.0.28— указывает, что адрес шлюза (gateway) по умолчанию 192.168.0.1; □ auto ethO — указывает, что интерфейс ethO необходимо включать автоматиче- ски при загрузке системы с указанными здесь параметрами. Если требуется изменить адреса серверов DNS, выполняем команду: sudo gedit /etc/resolv.conf и вписываем в открывшийся файл конфигурации resolv.conf следующие строки: nameserver 192.168.1.1 nameserver 8.8.8.8 где: 192.168.1.1 и 8.8.8.8— адреса серверов DNS. Если нужно добавить больше адресов — каждый адрес следует начинать с новой строки и со слова nameserver. 12.3.3. Настройка доступа по Wi-Fi Далеко не всегда удобно вести к Raspberry Pi сетевой провод. Решить эту проблему можно с помощью адаптера Wi-Fi, подключаемого через USB. У меня в наличии имеется соответствующий адаптер (рис. 12.9), купленный в Китае за 7 долларов.
Микрокомпьютер Raspberry Pi 263 Позиционируется он в интернет-магазине как устройство, специально предназна- ченное для Raspberry Pi. Еще раз напомню, что при подключении адаптера Wi-Fi, как и любого другого внешнего устройства, запитывать Raspberry Pi следует от достаточно мощного бло- ка питания. Рис. 12.9. USB-адаптер Wi-Fi Итак, подключаем адаптер в USB-порт и проверяем, определит ли его система. Ре- зультат выполнения команды iwconfig (рис. 12.10) показывает, что наше устройст- во (wlanO) найдено. Рис. 12.10. Результат выполнения команды iwconfig
264 Глава 12 Теперь сканируем пространство на поиск доступных беспроводных сетей коман- дой: sudo iwlist wlanO scan и видим (рис. 12.11), что найдена точка доступа AndroidAP — в нашем случае это планшет Samsung Galaxy Tab 2, настроенный как точка доступа Wi-Fi. Рис. 12.12. Поиск доступных беспроводных сетей Теперь соединимся с точкой доступа по WPA-шифрованию. Соединение с таким шифрованием поддерживает утилита wpajpassphrase. С помощью этой утилиты, которая входит в состав пакета wpasupplicant, генерируем пароль на основе ключа доступа (для моей точки доступа AndroidAP — Icwt9634): wpajpassphrase AndroidAP Icwt9634 Утилита выдает сгенерированную строку psk (рис. 12.12). Далее блок, содержащий ssid сети (AndroidAP) и строку psk, вставляем в конец конфигурационного файла/etc/wpa_supplicant/wpa_supplicant.conf (рис. 12.13). Рис. 12.12. Генерирование строки psk
Микрокомпьютер Raspberry Pi 265 В завершение перезагружаем наш Raspberry Pi и наблюдаем на планшете Samsung подключение Raspberry Pi (устройство raspberrypi2) к нашей точке доступа (рис. 12.14). Рис. 12.13. Добавление данных в конфигурационный файл wpa.suppiicant conf Рис. 12.14. Подключение к точке доступа Wi-Fi 12.3.4. Подключение ЗС-модема Поскольку сотовая связь доступна практически на всей населенной территории РФ, бесспорное достоинство Зв-модема состоит в том, что в любой точке зоны охвата можно соединиться с Интернетом, пусть и на относительно малых скоростях. У меня как раз оказался в наличии ЗО-модем ZTE MF180 от «Билайн» (рис. 12.15), и хотя я и не нашел его в списке совместимого с Raspberry Pi оборудования
266 Глава 12 Рис. 12.15. Зв-модем ZTE MF180 от «Билайн» (http://elinux.org/RPi__VerifiedPeripherals)? однако подключить его и получить Ин- тернет на скорости 3G у меня получилось. Рассмотрим, как это удалось сделать. Итак, для подключения к Raspberry Pi no USB Зв-модема прежде всего необходимо установить пакеты ррр и sakis3g. Для установки пакета ррр выполним команду: sudo apt-get install ррр Затем скачиваем пакет sakis3g: sudo wget "http://www.sakis3g.org/versions/latest/armv4t/sakis3g.gz" Этот источник очень часто бывает недоступен, и, попав в такую ситуацию, можно обратиться к альтернативному: sudo wget "http://raspberry-at-home.com/files/sakis3g.tar.gz" Получив пакет, распаковываем его в . предварительно созданную папку /usr/bin/modem3g: sudo mkdir /usr/bin/modem3g sudo chmod 777 /usr/bin/modem3g sudo cp sakis3g.tar.gz /usr/bin/modem3g cd /usr/bin/modem3g sudo tar -zxvf sakis3g.tar.gz sudo chmod +x sakis3g Теперь можно запустить скрипт sakis3g, работающий в терминале: sudo ./sakis3g -interactive В открывшемся главном меню программы (рис. 12.16) выбираем подключение к сети 3G. Скрипт sakis3g считывает с модема настройки и предлагает выбор точ- ки доступа для подключения (рис. 12.17). Для моего тарифа приходится вводить свои параметры точки доступа: home.beeline.ru (рис. 12.18).
Микрокомпьютер Raspberry Pi 267 Рис. 12.16. Главное меню программы Sakis3G Рис. 12.17. Выбор точки доступа Рис. 12.18. Ввод параметров точки доступа
268 Глава 12 Затем вводим логин (рис. 12.19) и пароль — скрипт пытается подключиться к сети и выдает нам об этом соответствующее сообщение. Как можно видеть, подклю- читься к сети у нас получилось (рис. 12.20). Рис. 12.19. Ввод логина/пароля для точки доступа Рис. 12.20. Сообщение о подключении к точке доступа Рис. 12.21. Меню программы Sakiz3G
Микрокомпьютер Raspberry Pi 269 Рис. 12.22. Просмотр данных соединения Далее мы попадаем в меню скрипта (рис. 12.21), где можно посмотреть настройки соединения (рис. 12.22) или разорвать его. 12.4. Интерфейс GPIO Как уже отмечалось ранее, Raspbeny Pi несет на борту интерфейс, называемый GPIO (рис. 12.23),— набор портов ввода/вывода общего назначения (General Purpose Input/Output). В моделях «А» и «В» — это 26 линий, из которых для управ- ления доступны 17, в моделях «В+» — 40 линий, из которых доступны 26. |^| Рис. 12.23. Порты GPIO на плате Raspberry Pi
270 Глава 12 На этих линиях реализованы интерфейсы UART, консольный порт, SPI (Serial Peripheral Interface, последовательный периферийный интерфейс) и PC (Inter- Integrated Circuit, последовательная шина данных для связи интегральных схем). Расстояние между выводами — 2,54 мм. Выводы UART, SPI и 12С в случае необхо- димости могут быть настроены как обычные порты ввода/вывода. Назначение выводов GPIO (так называемая распиновка) представлено на рис. 12.24-12.26. Для плат «А» и «В» первой ревизии выводы 4, 9, 14, 17, 20, 25 обозначены как DNC (Do Not Connect), и подсоединять к ним что-либо не следу- ет — плата может сгореть. На новых ревизиях платы разведены, но не распаяны, еще четыре GPIO, дополнительно дающие интерфейсы PC и FS (Inter-Integrated Circuit, последовательная шина данных для связи интегральных схем). Первые 26 выводов GPIO платы «В+» полностью идентичны разъемам GPIO плат «А» и «В», осталь- ные 14 содержат 9 выводов GPIO общего назначения, которые могут быть сконфи- гурированы как вход или выход, 3 вывода GND и 2 вывода не задействованы. С помощью выводов GPIO к Raspberry Pi можно подключать датчики и внешние исполнительные устройства, что открывает интересные возможности творческого использования Raspberry Pi. ь?Ю ;!?. li: 12 вРЮ IB ! GHG 2 Г 33; 14.DNC I GP1C3 22 15:16 Gr\O 23 ; OHC; 3 7- ib;GP:Q 24 = SPiOM'.vO ?Л'22Хг*?Ю .?:у i 940 SCIK /3l 74 Sr-iC CtO & [ ОЫС. 2>; 26 SPiO Cr.l К ; Рис. 12.24. «Распиновка» портов GPIO плат «А» и «В» Revision 1 тжшшшш io UART nm j Рис. 12.25. «Распиновка» портов GPIO плат «А» и «В» Revision 2 При работе с портами GPIO следует помнить о некоторых их особенностях и со- блюдать определенные меры предосторожности, чтобы не повредить Raspberry Pi. Вот основные из них: □ максимальный суммарный ток обоих выводов 3,3 В равен 50 мА, и эти выводы могут использоваться для питания внешних устройств только в том случае, если их потребляемый ток меньше 50 мА;
Микрокомпьютер Raspberry Pi 271 Рис. 12.26. «Распиновка» портов GPIO плат «В+» и «В 2» П максимальный суммарный ток обоих выводов 5 В равен 300 мА, и эти выводы также могут использоваться для питания внешних устройств только в том слу- чае, если их потребляемый ток меньше 300 мА; О на GPIO нельзя подавать напряжение больше 3,3 В! Цифровые выводы GPIO имеют уровни напряжения 0-3,3 В и не совместимы с традиционными уровнями напряжения 0-5 В. Если подать на вывод GPIO логическую единицу, представ- ляющую собой 5 В (а не 3,3 В), — этот вывод может выйти из строя; □ выводы GPIO 14 и GPIO 15 по умолчанию выполняют альтернативную функцию и являются выводами UART (RXD и TXD), поэтому после включения на них присутствует высокий уровень 3,3 В, однако программно их можно переконфи- гурировать в обычные выводы. Все остальные выводы GPIO после включения Raspberry Pi выполняют основную функцию и работают как обычные цифровые; □ все настраиваемые выводы GPIO — кроме GPIO 0 (SDA) и GPIO I (SCL) — по умолчанию являются входами и поэтому имеют высокое входное сопротивле- ние, при этом подтяжка логического уровня у них не включена, так что после включения Raspberry Pi напряжение на них может «плавать»; □ выводы GPIO 0 (SDA) и GPIO I (SCL) по умолчанию «подтянуты» к питанию, поэтому после включения Raspberry Pi на них присутствует напряжение логиче- ской единицы (3,3 В); □ сигнал на любом из цифровых выводов может служить источником внешнего прерывания. Нужно помнить, что GPIO — это выводы, непосредственно подключенные к про- цессору Raspberry Pi, они являются инструментом для взаимодействия с ним. Поэтому неосторожное обращение с GPIO может привести к необратимым послед- ствиям для процессора.
272 , Глава 12 Работать с GPIO можно двумя способами: □ используя оболочку bash и файловую систему Raspbian; □ используя языки программирования. 12.4.1. Управление GPIO из оболочки bash ОС Raspbian представляет собой один из дистрибутивов Linux, а концепция Linux предполагает, что любой объект является файлом. Именно это позволяет выводить и считывать сигналы с GPIO обычными командами оболочки bash прямо в терми- нале. Вывод логической единицы при этом выглядит как команда записи "Г в файл, соответствующий нужному выводу: sudo su - echo "25" > /sys/class/gpio/export echo "25" > /sys/class/gpio/export echo "out" > /sys/class/gpio/gpio25/direction echo "1" > /sys/class/gpio/gpio25/value echo "0" > /sys/class/gpio/gpio25/value Для чтения входов надо использовать команду cat и путь к файлу: echo "24" > /sys/class/gpio/export echo "in" > /sys/class/gpio/gpioO/direction cat /sys/class/gpio/gpio24/value Все операции должны выполняться от имени пользователя root. 12.4.2. Управление GPIO командами языка Python Для работы с GPIO на языке Python требуется специальная библиотека RPi.GPIO. В новом дистрибутиве Raspbian она уже установлена, а если у вас дистрибутив ста- рый, то для установки библиотеки RPi.GPIO выполните команду: sudo apt-get install python-rpi.gpiо Чтобы использовать эту библиотеку, необходимо в программу на Python добавить строку импорта библиотеки RPi.GPIO: Import RPi.GPIO as GPIO При написании программы можно выбрать один из двух способов нумерации пор- тов GPIO: первый— GPIO.BOARD— использует систему нумерации портов на плате Raspberry Pi. Преимущество этой системы нумерации в том, что ваше обору- дование будет работать всегда, независимо от номера ревизии — вам не придется перемонтировать свой разъем или изменить имеющийся код. Вторая система нуме- рации — GPIO.BCM (номера ВСМ). Это более низкий уровень работы — с прямым обращением к номерам каналов на процессоре Broadcom. Выбор способа нумера- ции определяется соответствующими командами: GPIO.setmode(GPIO.BOARD) GPIO.setmode(GPIO.BCM)
Микрокомпьютер Raspberry Pi 273 Следующие команды устанавливают режим работы контакта на вход или выход: GPIO.setup(channel, GPIO.IN) GPIO.setup(channel, GPIO.OUT) Если входной канал ни к чему не подключен, его значение может «плыть». Сле- дующие команды устанавливают начальную «подтяжку» вывода к питанию или к «земле»: GPIO.setup(channel, GPIO.IN, GPIO.PUDJJP) GPIO.setup(channel, GPIO.IN, GPIO.PUD_DOWN) Для выходов out можно установить начальное значение 0 или 1: GPIO.setup(channel, GPIO.OUT, GPIO.LOW) GPIO.setup(channel, GPIO.OUT, GPIO.HIGH) Для чтения значения контакта GPIO, настроенного как вход in, служит следующая команда: GPIO.input(channel) Значение контакта, настроенного как выход оит, устанавливается следующей командой: GPIO.output(channel, state) В листинге 12.1 приведен пример использования команд работы с GPIO. import RPi.GPIO as GPIO #подключаем библиотеку GPIO.setmode(GPIO.ВСМ) #устанавливаем режим нумерации GPIO.setup(7, GPIO.OUT) #конфигурируем GPIO 7 как выход GPIO.setup(8, GPIO.IN) #конфигурируем GPIO 8 как вход GPIO.output(7, True) #выводим на GPIO 1- логическую "1" (3.3 V) GPIO.output(7, False) #выводим на GPIO 7 логический "О" signal = GPIO.input(8) #считываем с GPIO 8 в переменную signal GPIO.cleanup() #завершаем работу с GPIO Библиотека RPi.GPIO позволяет использовать контакты GPIO в качестве выходов ШИМ (сигналов широтно-импульсной модуляции). Для создания экземпляра ШИМ служит команда: р = GPIO.PWM(channel, frequency) где frequency — частота, Гц. Для старта ШИМ на контакте: p.start(dc) где dc — рабочий цикл ШИМ (0,0-100,0).
274 Глава 12 Для изменения частоты сигнала: р.ChangeFrequency(freq) где f req — частота сигнала, Гц. Для изменения рабочего цикла ШИМ: p.ChangeDutyCycle(dc) # where 0.0 <= dc <= 100.0 Останов выдачи сигнала ШИМ на контакте: p. stop () В листинге 12.2 представлен пример плавного включения/выключения светодиода, подключенного к контакту. import time import RPi.GPIO as GPIO GPIO.setmode(GPIO.BOARD) GPIO.setup(12, GPIO.OUT) p = GPIO.PWM(12, 50) # контакт 12 частота 50 Гц p.start(0) try: while 1: for dc in range(0, 101, 5): p.ChangeDutyCycle(dc) time.sleep(0.1) for dc in range(100, -1, -5): p.ChangeDutyCycle(dc) time.sleep(0.1) except Keyboardlnterrupt: pass p. stop () GPIO.cleanup() Функция ожидания события -■- изменения состояния на входе in — выглядит сле- дующим образом: GPIO.wait_for_edge(channel, GPIO.RISING) GPIO.wait_for_edge(channel, GPIO.FALLING) GPIO.wait_for_edge(channel, GPIO.BOTH) Эта функция прерывает выполнение программы до изменения состояния на входе GPIO. В отличие от нее функция add_event_detected () выполняется в цикле про- граммы, и для того, чтобы узнать об изменении состояния на контакте GPIO, необ- ходимо в цикле проверять наступление события eventdetected ():
Микрокомпьютер Raspberry Pi 275^ GPIO.add event detect(channel, GPIO.RISING if GPIO.event_detected(channel): print('Button pressed1) Каждый контакт GPIO может быть настроен на работу в режиме прерывания — в этом случае при наступлении события на контакте, управление передается функ- ции обработки прерывания. Функция обработки прерывания работает в отдельном потоке, не прерывая выполнения основной программы: def my_callback(channel): print(fобработка прерывания!f) GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback) В конце любой программы рекомендуется очистить все ресурсы, которые могли использоваться. Для такой очистки в конце скрипта надо предусмотреть команду: GPIO. cleanup () Для сброса одного контакта служит команда: GPIO.cleanup(channel) 12.5. Raspberry Pi и датчик температуры DS18B20 на шине 1-Wire 12.5.1. Подключение датчика DS18B20 к Raspberry Pi В главе 7 мы уже рассматривали датчик температуры DS18B20, работающий по однопроводному интерфейсу 1-Wire. Схема подключения датчика DS18B20 к контактам GPIO Raspberry Pi по протоколу 1-Wire приведена на рис. 12.27. Протокол 1-Wire позволяет подключить к одной шине и несколько датчиков DS18B20 (рис. 12.28). Рис. 12.27. Схема подключения датчика DS18B20 к Raspberry Pi по шине 1-Wire
276 Глава 12 Рис. 12.28. Схема подключения к Raspberry Pi нескольких датчиков DS18B20 Для использования с Raspberry Pi датчиков DS18B20 на шине 1-Wire необходимо загрузить два специальных модуля: wl-gpio и wl-term. Для этого набираем в тер- минале: sudo modprobe wl-gpio sudo modprobe wl-therm Первая строка здесь активирует протокол модуля 1-Wire на GPIO4, а вторая — за- гружает модуль, который, собственно, и читает температуру с шины 1-Wire. Чтобы модули автоматически загружались после перезагрузки или выключения Raspberry Pi, две эти строки нужно добавить в файл /etc/modules, отвечающий за автозагрузку модулей, для чего набираем в терминале: sudo nano /etc/modules и добавляем в конец открывшегося для редактирования файла две следующие строчки: wl-gpio wl-therm Через несколько секунд после подключения датчика в каталоге /sys/bus/w1 /devices появится вложенный каталог вида 28-хххххххххххх (рис. 12.29). Если этого не про- изошло, значит у вас установлена новая версия Raspbian, в которой по умолчанию отключена поддержка дерева устройств. Чтобы исправить ситуацию, открываем файл /boot/config.txt: sudo nano /boot/config.txt вписываем в конец файла следующую строку: dtoverlay=wl-gpio и перезагружаемся. Для каждого подключенного по шине 1-Wire датчика температуры создается свой такой каталог. Название каждого каталога — это уникальный серийный номер дат- чика DS18B20.
Микрокомпьютер Raspberry Pi 277 Locii Ы-мк P«i€£ Carrimamiir Session Options F Nam- ;a. Ж-000003 cAL&fcO; iii ^I_bu?_masted 14 05.201516:17 14 ;>5ЯН 516:1V Рис. 12.29. Каталог для датчика DS18B20 в папке /sys/bus/wi/devices Данные температуры хранятся в файле 28-000003b816b0/w1 -slave, содержимое кото- рого можно считать по команде: cat /sys/bus/wl/devices/28-OOOOO3b816bO/wl_slave Результат считывания показаний датчика DS18B20 приведен на рис. 12.30. Рис. 12.30. Содержимое файла с показаниями датчика DS18B20 Обратите внимание на присутствующий в считанной информации фрагмент: t= 16687. Это температура по шкале Цельсия, умноженная на 1000. То есть, реаль- но замеренная температура составляет 16687/1000 = 16,687 °С. Не надо обманы- ваться относительно трех знаков после запятой— абсолютная точность датчика всего 0,5 °С. Напишем на языке Python скрипт, считывающий и выводящий каждые три секунды данные температуры с датчика DS18B20 (листинг 12.3). #-*-coding:utf-8 -*- from time import sleep while 1: tfile=open('7sys/bus/wl/devices/28-000003b816b0/wl_slave")
278 ttext=tfile.read() tfile.closeO temp=ttext.split("\n")[1].split(" ")[9] temperature=float(temp[2:])/1000 print "temperature="+str(temperature) sleep(3) Запустим этот скрипт на выполнение: python listing_12_03.py и наблюдаем вывод показаний (рис. 12.31). Глава 12 Рис. 12.31. Работа скрипта, читающего показания датчика DS18B20 12.5.2. Отправка данных с датчика DA18B20 в сервис «Народный мониторинг» Как известно, для регистрации какого-либо датчика в сервисе «Народный монито- ринг» сначала необходимо отправить туда данные его замеров. Так что, прежде всего напишем скрипт, отправляющий данные с датчика в этот сервис. Для этого создаем файл listing_12_04.py, заносим в него код из листинга 12.4, запускаем наш скрипт на выполнение: python listing_12_04.py и наблюдаем отправку данных (рис. 12.32).
Микрокомпьютер Raspberry Pi 279 Рис. 12.32. Отправка данных в сервис «Народный мониторинг» из python-скрипта listing_i2_04.py t-*-coding:utf-8 -*- import socket from time import sleep i МАОадрес устройства. Заменить на свой! DEVICE_MAC = fb827eb83a32cf If идентификатор устройства sensor_id_i = '28ооооозь81бьо' # значения датчика, тип float/integer sensor_value_l = О while 1: tfile=open(Vsys/bus/wl/devices/28-000003b816bO/wl_slave") ttext=tfile.read() tfile.close() temp=ttext.split("\n")[1].split(" ")[9] temperature=float(temp[2:])/1000 print "temperature="+str(temperature) sensor_value_l=temperature # создание сокета sock = socket.socket() # обработчик исключений try: # подключаемся к сокету sock.connect((fnarodmon.ruf, 8283)) # пишем в сокет единичное значение датчика sock.send("#{}\n#{}#{}\n##".format(DEVICE_MAC, SENSOR_ID_1, sensor_value_l)) # пишем в сокет множественные значения датчиков # sock.send("#{}\n#{}#{}\n#{}#{}\n##".format(DEVICE_MAC, SENSOR_IDJL, sensor_value_l, SENSOR_ID_2, sensor_yalue_2) # читаем ответ data = sock.recv(1024) sock.close() print data
280 Глава 12 except socket.error, e: print(fERROR! Exception {}f.format(e)) sleep(600) Отправив данные, заходим в свой профиль на сайте http://www.narodmon.ru, выбираем пункт меню Датчики, нажимаем на кнопку Добавить датчик и в соот- ветствующее поле открывшегося окна вносим МАС-адрес нашего устройства (ис- пользуем МАС-адрес сетевой платы Raspberry Pi). Если данные были переданы успешно, наша плата появится в списке устройств (рис. 12.33). Рис. 12.33. Добавление датчика на сайт сервиса «Народный мониторинг» Рис. 12.34. График передачи показаний датчика температуры
Микрокомпьютер Raspberry Pi 281 Осталось настроить параметры датчика нашего устройства, и через некоторое вре- мя можно будет увидеть график его показаний (рис. 12.34). Электронный архив Скрипт, соответствующий листингу 12.4, можно найти в файле python\listing_12_04.py сопровождающего книгу электронного архива. 12.6. Raspberry Pi и датчик освещенности ВН1750 на шине I2C 12.6.1. Подключение датчика ВН1750 к Raspberry Pi В главе 6 мы уже рассматривали датчик освещенности ВН1750 на шине 12С — под- ключим его теперь к Raspberry Pi. Для работы с датчиками 12С на Raspberry Pi необходимо сначала настроить под- держку интерфейса 12С, который в нем отключен по умолчанию. Поэтому запуска- ем утилиту конфигурации raspi-config: sudo raspi-config и выбираем в главном меню пункт Advanced options, а в открывшемся окне (рис. 12.35) — вариант А712C, чем и включаем поддержку интерфейса 12С. Затем добавляем в файл /etc/modules, отвечающий за автозагрузку модулей, сле- дующие строки: i2c-bcm2708 i2c-dev Рис. 12.35. Настройка поддержки протокола I2C в меню конфигурации raspi-config
282 Глава 12 и устанавливаем утилиты python-smbus и i2c-tools: sudo apt-get install python-smbus sudo apt-get install i2c-tools Теперь подключаем к Raspberry Pi датчик освещенности ВН1750 (рис. 12.36) и про- веряем, видит ли Raspberry Pi наш датчик,— отдаем в терминале команду i2cdetect, которая содержится в утилите i2c-tools: i2cdetect -у 1 и видим «решетку адресов» (рис. 12.37) — адрес нашего датчика здесь: 0x23. Рис. 12.36. Схема подключения датчика ВН1750 к Raspberry Pi Рис. 12.37. «Решетка адресов» 12С-датчиков, подключенных к Raspberry Pi
Микрокомпьютер Raspberry Pi 283 12.6.2. Получение на Raspberry Pi данных с датчика ВН1750 Напишем на языке Python скрипт получения Raspberry Pi данных с датчика ВН1750 (листинг 12.5). #! /usr/bin/python import smbus import time # Установка констант по технической документации DEVICE = 0x23 # I2C адрес датчика P0WER_DOWN = 0x00 # Неактивное состояние P0WER_ON = 0x01 # Включение RESET = 0x07 # Сбросить значение регистра Не POWERJDOWN = 0x00 # # Запуск измерения с разрешением 4 1х. Время, как. правило, 16 мс. C0NTINUOUS_LOW_RES_MODE = 0x13 # Запуск измерения с разрешением 1 1х. Время, как правило, 120 мс C0NTINUOUS_HIGH_RES_MODE_l = 0x10 # Запуск измерения с разрешением 0.5 1х. Время, как правило, 120 мс C0NTINUOUS_HIGH_RES_MODE_2 = 0x11 i Запуск измерения с разрешением 1 1х. Время, как правило, 120 мс # Устройство автоматически устанавливается на Power Down после измерения. 0NE_TIME_HIGH_RES_MODE_l = 0x20 # Запуск измерения с разрешением 0.5 1х. Время, как правило, 120 мс f Устройство автоматически устанавливается на Power Down после измерения. 0NE_TIME_HIGH_RES_MODE_2 = 0x21 I Запуск измерения с разрешением 1 1х. Время, как правило, 120 мс # Устройство автоматически устанавливается на Power Down после измерения. 0NE_TIME_LOW_RES_MODE = 0x23 fbus = smbus.SMBus(0) # Rev 1 Pi uses 0 bus = smbus.SMBus(1) # Rev 2 Pi uses 1 def convertToNumber(data): # перевод данных датчика в числовое значение return ((data[l] + (256 * data[0])) / 1.2) def readLight(addr=DEVTCE): data = bus.read_i2c_block_data(addr,ONE_TIME_HIGH_RES_MODE_l) return convertToNumber(data)
284 Глава 12 def main(): while True: print "Light Level : " + str(readLight()) + " lx" time.sleep(0.5) i f name == "__jnain ": main() Запустим этот скрипт в терминале: python listing_ll_05.py и увидим там вывод показаний датчика ВН1750 (рис. 12.38). Рис. 12.38. Вывод показаний датчика ВН1750 Электронный архив Скрипт, соответствующий листингу 12.5, можно найти в файле python\listing_12_05.py сопровождающего книгу электронного архива. Теперь данные освещенности с датчика ВН1750 можно отправлять в облачный сер- вис— например, в тот же «Народный мониторинг», добавив в этот скрипт код отправки данных из листинга 12.4.
ГЛАВА 13 WeblOPi — веб-интерфейс и облако для Raspberry Pi Воспользуемся для доступа к портам GPIO фреймворком WeblOPi— сервисом Internet of Things, позволяющим контролировать состояние и управлять всеми пор- тами GPIO локально или удаленно, из браузера или любого приложения. Возможности WeblOPi: □ доступ к функционалу сервиса через основанный на HTTP интерфейс REST API (Representational State Transfer, передача состояния представления) и протокол ограниченного применения CoAP (Constrained Application Protocol) с поддерж- кой мультикаста (многоадресного вещания); П работа с портами GPIO, Serial, I2C, SPI, 1-Wire; lJ встроенная поддержка более чем 30 устройств, включая ЦАП, АЦП, датчики; 3 возможность работы с облачным сервисом Weaved; 0 совместимость с Python 2 и 3; 0 защита логином/паролем; П множество примеров. 13.1. Установка WeblOPi на ОС Raspbian Для установки фреймворка WeblOPi на ОС Raspbian необходимо скачать соот- ветствующий архив, извлечь содержащиеся в нем файлы и запустить сценарий установки, который автоматически загрузит и инсталлирует необходимые зависи- мости: wget http://webiopi.googlecode.com/files/WebIOPi-0.7.1.tar.gz tar xvzf WebIOPi-0.7.1.tar.gz cd WebIOPi-0.7.1 sudo ./setup.sh В процессе достаточно продолжительной установки вам будет предложено создать профиль в облачном сервисе Weaved (https://www.weaved.com) для доступа
286 Глава 13 WeblOPi Main Menu GPIO Header C^nlrdaiKl Debug tlw Raspberry Pi GPIO w^ GPIO List Control and Debug fbe Raspberry Pi GPIO ordered m a single column. Serial Monitor Use the browser to play with Serial irrfer&ces configured m WeblOPL Devices Monitor Control aod Debug devices and arenas wed to your Pi and configured in WeblOPi. Рис. 13.1. Стартовая страница WeblOPi 192.168.0.101:8000/app/gpio-header 3.3V GPIO 2 GPIO3 GPIO 4 GROUND GPIO 17 GPIO 27 GPIO 22 33V GPIO 10 GPIO 9 GPIO 11 GROUND 5.0V 5.0V GROUND UARTTX UARTRX GPIO 18 GROUND GPIO 23 GPIO 24 GROUND GPIO 25 GPIO 8 GPIO 7 Рис. 13.2. Страница управления выводами GPIO
WeblOPi — веб-интерфейс и облако для Raspberry Pi 287 к WeblOPi из сети Интернет (установка сервиса Weaved рассмотрена в разд. 13.7). Установленный WeblOPi лучше запускать как сервис: sudo /etc/init.d/webiopi start Если нужно, что бы WeblOPi стартовал автоматически при загрузке системы, выполните следующую команду: sudo update-rc.d webiopi defaults Теперь можно открыть веб-браузер на любом компьютере домашней сети, набрать адрес: http: //iprasp:8000 (где iprasp — IP-адрес Raspberry Pi) и авторизоваться — имя пользователя (логин): webiopi, пароль: raspberry. В результате в браузере от- кроется стартовая страница WeblOPi (рис. 13.1). На странице управления выводами GPIO (рис. 13.2), открывающейся по ссылке GPIO Header, можно задать режим работы любой ножки и установить значение на выходе. 13.2. Задание пользовательского пароля WeblOPi Сервер WeblOPi использует зашифрованный файл etc/webiopi/passwd, содержащий логин и пароль (по умолчанию логин: webiopi, пароль: raspberry). Чтобы изменить пароль, необходимо выполнить команду: webiopi-passwd и далее следовать инструкциям (рис. 13.3). Рис. 13.3. Изменение пароля WeblOPi После изменения пароля сервер необходимо перезагрузить: sudo /etc/init.d/webiopi restart Для снятия защиты при входе в WeblOPi необходимо либо ввести пустой пароль, либо удалить файл /etc/webiopi/passwd.
288 Глава 13 13.3. Настройка сервера WeblOPi Настраивается сервер WeblOPi внесением изменений в файл его конфигурации: /etc/webiopi/config. Синтаксис этого файла такой же, как и у прочих INI-файлов, — он содержит несколько разделов, содержащих пары «ключ = значение». □ Блок [нттр] позволяет включить или отключить HTTP, а также изменить значе- ние порта. В этом блоке можно изменить местоположение файла passwd, домаш- ней папки и название индексного файла HTML: [HTTP] enabled = true port = 8000 passwd-file = /etc/webiopi/passwd doc-root = /home/pi/webiopi/examples/scripts/macros welcome-file = index.html □ Блок [coap] позволяет включить или отключить сервер Со АР, а также изменить значение порта: [СОАР] enabled = true port = 5683 multicast = true □ Блок [gpio] позволяет установить пользовательские настройки и значения для портов GPIO при запуске WeblOPi. Например: [GPIO] 21 = IN 23 = OUT 0 24 = OUT 0 25 = OUT I □ Блок [-gpio] позволяет установить пользовательские настройки и значения для портов GPIO при перезагрузке WeblOPi. Например: [-GPIO] 21 = IN 23 = IN 24 = IN 25 = OUT 0 □ Блок [scripts] определяет список скриптов, выполняемых при запуске WeblOPi. Например: [SCRIPTS] myscript = /home/pi/webiopi/examples/scripts/macros/script.py □ Блок [rest] позволяет с помощью REST API (см. разд. 6.2.3) ограничить доступ get/post к некоторым портам: [REST] gpio-export = 21, 23, 24, 25
WeblOPi — веб-интерфейс и облако для Raspberry Pi 289 gpio-post-value = false gpio-post-function = false device-mapping = false □ Блок [devices] позволяет подключить устройства, поддерживаемые WeblOPi, к конкретным портам GPIO (список поддерживаемых WeblOPi устройств см. на странице: https://code.google.com/p/webiopi/wiki/DEVICES): usbO = Serial deviceittyUSBO baudrate:9600 adc = MCP3008 dac = MCP4922 chip:l gpioO = MCP23017 gpiol = MCP23017 slave:0x21 gpio2 = MCP23017 slave:0x22 pwmO = PCA9685 pwml = PCA9685 slave:0x41 □ Блок [routes] определяет список маршрутов переадресации. Это позволяет при использовании REST API скрыть в адресной строке значение порта доступа или другое назначение, т. е. придать адресам удобный вид: /bedroom/light = /GPIO/25/value /bedroom/temperature = /devices/temp2/sensor/temperature/c 13.4. Javascript-библиотека webiopi.js WeblOPi включает в себя HTTP-сервер, обеспечивающий как HTML-ресурсы, так и интерфейс REST API для управления выводами GPIO. При запуске сервера браузер сначала загружает HTML-файл с включенной Javascript-библиотекой webiopi.js, содержащей библиотеку jQuery для асинхронных вызовов к REST API. Этот метод очень эффективен, потому что не требует для обновления данных обновления стра- ницы. Расширить возможности WeblOPi можно путем загрузки пользовательского сценария Python, содержащего функции настройки выводов GPIO и созданного с использованием Arduino-подобного синтаксиса (рис. 13.4). HTTP REST API HTTP REST API Рис. 13.4. Схема WeblOPi
290 Глава 13 Для подключения библиотеки webiopijs на странице HTML в блок [header) поме- щаем следующий код: <script type="text/javascript" src="/webiopi. js"x/script> 13.4.1. Функции библиотеки webiopi.js Пояснение Здесь и далее webiopi о— возвращаемый объект WeblOPi. Функция WeblOPi.ready Функция webiopi. ready () регистрирует функцию обратного вызова при загрузке библиотеки webiopi.js. Синтаксис: WeblOPi. ready (callback) Параметр: callback — функция обратного вызова. Функция WeblOPi.setFunction Функция webiopi. setFunction () устанавливает назначение вывода GPIO. Синтаксис: □ WeblOPi.setFunction(gpio, func) □ WeblOPi.setFunction(gpio, func, callback) Параметры: О gpio — номер вывода GPIO; П func — назначение вывода: • in — вывод конфигурирован как вход; • оит — вывод конфигурирован как выход; • pwm — вывод конфигурирован как ШИМ-выход. □ callback — функция обратного вызова. Функция WeblOPi.digitalWrite Функция WeblOPi.digitalWrite о устанавливает цифровое значение вывода GPIO, сконфигурированного как выход (оит). Синтаксис: □ WeblOPi.digitalWrite (gpio, value) □ WeblOPi.digitalWrite(gpio, value, callback) Параметры: □ gpio — номер вывода GPIO; □ value — значение для вывода (0 или 1); □ callback — функция обратного вызова.
WeblOPi — веб-интерфейс и облако для Raspberry Pi Функция WeblOPi.digitalRead Функция WeblOPi.digitalRead о получает значение с вывода GPIO, сконфигуриро- ванного как вход (in). Синтаксис: П WeblOPi.digitalRead(gpio) □ WeblOPi.digitalRead(gpio, callback) Параметры: □ gpio — номер вывода GPIO; □ callback — функция обратного вызова. Возвращаемое значение: value (0 или 1). Функция WeblOPi.toggleValue Функция webiopi. toggievalue () переключает значение на выводе GPIO на проти- воположное. Синтаксис: WeblOPi. toggleValue (gpio) Параметр: gpio — номер вывода GPIO. Функция WeblOPi. call Mac ro Функция webiopi.caiiMacroо выполняет макрофункцию на сервере WeblOPi. Мак- рос может объявляться в скрипте Python, запускаемом при старте WeblOPi. Синтаксис: □ WeblOPi.caiiMacro (macro) О WeblOPi.caiiMacro(macro, args) 0 WeblOPi.caiiMacro(macro, args, callback) Параметры: □ macro — наименование макрофункции; □ args — массив передаваемых аргументов для макрофункции; Я callback — функция обратного вызова. Функция WeblOPi.outputSequence Функция WeblOPi.outputSequence о отправляет последовательность битов на выход GPIO. Синтаксис: О WeblOPi.outputSequence(gpio, period, sequence) Я WeblOPi.outputSequence(gpio, period, sequence, callback) Параметры: 0 gpio — вывод GPIO; 3 period — время отправки (миллисекунд) одного бита;
292 Глава П П sequence — последовательность битов; □ callback — функция обратного вызова. Пример: var sequence = "01010100110011001100101010"; // отправка последовательности на gpio 7 с периодом 100 мсек webiopi().outputSequence(7, 100, sequence, sequenceCallback); Функция WeblOPi.pulse Функция webiopi. pulse () отправляет импульс на выход GPIO. Синтаксис: □ WeblOPi.pulse(gpio) □ WeblOPi.pulse(gpio, callback) Параметры: □ gpio — вывод GPIO; □ callback — функция обратного вызова. Функция WeblOPi.puiseRatio Функция webiopi. puiseRatio () отправляет ШИМ-сигналы на выход GPIO. Синтаксис: □ WeblOPi.puiseRatio (gpio, ratio) □ WeblOPi.puiseRatio (gpio, ratio, callback) Параметры: □ gpio — вывод GPIO; □ ratio — значение для сигнала ШИМ (0,0-1,0); □ callback — функция обратного вызова. Функция WeblOPi.pulseAngle Функция webiopi.pulseAngle о отправляет ШИМ-сигналы на выход GPIO. Эта функция удобна при управлении сервоприводами для установки угла поворота рабочего органа от -45 до +45 градусов. Синтаксис: П WeblOPi.pulseAngle (gpio, angle) □ WeblOPi.pulseAngle(gpio, angle, callback) Параметры: □ gpio — вывод GPIO; □ angle — значение сигнала ШИМ (от -45 до +45); □ callback функция обратного вызова.
WeblOPi — веб-интерфейс и облако для Raspberry Pi 293 Функция WeblOPi.createButton Функция webiopi. createButton () возвращает объект — простую кнопку. Синтаксис: □ WeblOPi.createButton(id, label) П WeblOPi.createButton(id, label, mousedown) П WeblOPi.createButton(id, label, mousedown, mouseup) Параметры: □ id — идентификатор кнопки; П label — надпись на кнопке; □ mousedown — функция, вызываемая при событии mousedown (нажатие по кнопке); □ mouseup — функция, вызываемая при событии mouseup (отпускание кнопки). Примечание События mousedown И mouseup В ОСНОВНОМ ИСПОЛЬЗУЮТСЯ, КОГДЭ ИДвТ НЭЖаТИе НЭ КНОПКУ, перемещение ее, а потом мышь отпускается. Чтобы кнопка появилась на странице, ее необходимо добавить — например, так: button = webiopi().createButton("btl", "buttonl", fun_down, fun_up); $("#divl").append(button); Функция WeblOPi.createFunctionButton Функция webiopi. createFunctionButton о создает объект — кнопку, при нажатии на которую изменяется назначение вывода GPIO. Синтаксис: WeblOPi. createFunctionButton (gpio) Параметр: gpio— вывод, назначение которого изменяется (in, out), при этом на кнопке выводится соответствующая надпись (Ш, OUT). Функция WeblOPi.createGPIOButton Функция webiopi. createGPiOButton о создает объект — кнопку, при нажатии на которую изменяется значение (0 или 1) вывода GPIO. Синтаксис: WeblOPi. createGPiOButton (label, gpio) Параметры: П label — надпись на кнопке; D gpio — вывод, назначение которого изменяется (о, 1), при этом на кнопке выво- дится соответствующая надпись (0,1). Функция WeblOPi.createMacroButton Функция webiopi. createMacroButton о создает объект— кнопку, при нажатии на которую выполняется макрофункция на сервере (макрофункции прописываются в Python-скрипте, запускаемом при старте webiopi).
294 Глава 13 Синтаксис: WebIOPi.createMacroButton(id, label, macro, args) Параметры: □ id — идентификатор кнопки; □ label — надпись на кнопке; □ macro — название макрофункции на сервере; □ args — список параметров, передаваемых макрофункции. Функция WeblOPi.createSequenceButton Функция webiopi. createSequenceButton () создает объект — кнопку, при нажатии на которую на вывод GPIO отправляется последовательность битов. Синтаксис: WeblOPi.createSequenceButton (id, label, gpio, period, sequence) Параметры: □ id — идентификатор кнопки; □ label — надпись на кнопке; □ gpio — вывод для отправки последовательности битов; □ period — время отправки одного бита (мсек); □ sequence — последовательность битов в виде строки. Пример: button = webiopi().createSequenceButton("butl", "labell", 25, 100, "01010100110011001100101010"); $("#divl").append(button); Функция WeblOPi.createRatioSlider Функция WeblOPi.createRatioSlider о создает объект— шкалу (см. рис. 6.15), поло- жением указателя на которой регулируется значение ШИМ-сигнала на выводе GPIO. Синтаксис: WeblOPi.createRatioSlider (gpio, ratio) Параметры: □ gpio — вывод для отправки последовательности битов; □ ratio — начальное значение для ШИМ (0,0-1,0). Пример: button = webiopi().createRatioSlider(24, 1.0); $("#divl").append(button); Функция WeblOPi.createAngleSlider Функция webiopi. createAngiesiider () создает объект — шкалу, положением указа- теля которой регулируется значение ШИМ-сигнала, подаваемого на вывод GPIO при управлении сервоприводом для значений поворота угла рабочего органа от -45 до +45 градусов.
WeblOPi -— веб-интерфейс и облако для Raspberry Pi 295^ Синтаксис: WeblOPi. createAngleSlider (gpio, angle) Параметры: □ gpio — вывод для отправки последовательности битов; Я angle — начальное значение угла для сигнала ШИМ (от -45 до +45). Функция WeblOPi.setL.abel Функция WeblOPi. setLabei () изменяет надпись на кнопке. Синтаксис: WeblOPi. setLabei (id, label) Параметры: D id — идентификатор кнопки; 0 labie — новая надпись для кнопки. В листинге 13.1 представлен пример кода страницы для формирования элементов управления webiopi, а на рис. 13.5 — вид этой HTML-страницы. <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content = "height = device-height, width = 420, user-scalable = no" /> <title>WebIOPi I Demo</title> <script type="text/javascript" src="/webiopi.js"x/script> <script type="text/javascript"> webiopi().ready(function() { var content, button; content = $("#content"); button = webiopi().createFunctionButton(25); content.append(button); button = webiopi().createGPIOButton(7, "SWITCH"); content.append(button); button = webiopi().createSequenceButton("sos", "S.O.S 1", 25, 100, "01010100110011001100101010"); content.append(button); button = webiopi().createMacroButton("macro", "Print Time", "PrintTime"); content.append(button); button = webiopi().createAngleSlider(23, 30); content.append(button);
296 Глава 13 button = webiopi().createRatioSlider(24, 0.5); content.append(button); webiopi().refreshGPIO(true); </head> <body> <div id="content" align="center"x/div> </body> </html> Рис. 13.5. Вид HTML-страницы с элементами управления webiopi 13.5. Проект управления веб-камерой на сервоприводах Для создания своего проекта с использованием фреймворка WeblOPi необходимо реализовать следующие его компоненты: □ веб-интерфейс — HTML-страницу с использованием библиотеки webiopi.js; □ серверный скрипт на языке Python, запускаемый при старте webiopi для реализа- ции функционала веб-интерфейса; □ файл конфигурации с установкой начальных значений портов.
WeblOPi — веб-интерфейс и облако для Raspberry Pi 297 Подготовим проект управления из веб-интерфейса камерой, укрепленной на подве- се, снабженном сервоприводами. Из веб-интерфейса можно будет поворачивать камеру, а также делать снимки и отправлять их на электронную почту. Для проекта понадобятся следующие детали: □ подвес для камеры (рис. 13.6); □ сервоприводы TG9 (рис. 13.7) — 2 шт.; □ дополнительный блок питания 5 В; □ камера Raspberry Pi Camera Board (рис. 13.8). Рис. 13.6. Подвес для камеры с сервоприводами Рис. 13.7. Сервопривод TG9 Рис. 13.8. Камера Raspberry Pi Camera Board
298 Глава f3 Lipo -О- L7805 IN OUT GND Raspberry Pi GPIO \% +5V Servo GND| Vcc S Servo GND| Vcc S »3,3B GPIOO 5 GP1O1 GPIO4 9 GNP 11 GPIO17 13 GPIQ21 15 GPIO22 17 -K3.3B 19 GP1O10 21 GPIO9 23 GPIO11 25 GND »5 В »5B GND 6 GP1O14 GP1O15 10 GP1O18 12 GNO 14 GP1O23 16 GPIO24 18 GND 20 GPIQ25 22 GPIO6 24 GPIO7 26 21* Рис. 13.9. Электрическая схема проекта Для управления сервоприводами задействуем два вывода GPIO: GPIO23 и GPIO24. Электрическая схема проекта представлена на рис. 13.9. Сначала настроим в файле конфигурации config, который находится в папке /etc/webiopi/, необходимые параметры: путь к домашней папке и путь к скрипту, выполняемому при запуске webiopi: doc-root - /home/pi/webiopi/examples/servo-camera script = /home/pi/webiopi/examples/servo-camera/camera.py Поскольку камера Raspberry Pi Camera Board подключена напрямую к графическо- му процессору через CSI-разъем, CSI-разъем на плате, запись и кодирование видео происходят без использования процессорного времени. Установим для передачи потокового видео с этой камеры пакет MJPG-streamer: su pi https://svn.code.sf.net/p7mjpg-streamer/code/mjpg-streamer/ mjpg-streamer cd mjpg-streamer/mjpg-streamer make USE_LIBV4L2=true clean all sudo su make DESTDIR=/usr install cp -R www /var/ Напишем запускающий камеру sh-скрипт stream_start.sh (листинг 13.2), создав для него предварительно файл: sudo nano /usr/local/bin/stream_start.sh sudo chmod +x /usr/local/bin/stream start.sh
WeblOPi — веб-интерфейс и облако для Raspberry Pi 299 #! /bin/bash if [ -d /tmp/stream ];then echo "/tmp/stream already created" else mkdir /tmp/stream fi if [ -f /tmp/stream/pic.jpg ];then echo "raspistill already running" else raspistill -w 320 -h 240 -q 5 -o /home/pi/webiopi/examples/ servo-camera/pic.jpg -tl 100 -t 999999Э& fi mjpg_streamer -i "input_file.so -f /home/pi/webiopi/examples/servo-camera" -o "output_http.so -w /home/pi/webiopi/examples/servo-camera" Запуск скрипта осуществляется командой: /usr/local/bin/stream_start. sh Напишем на языке Python серверный скрипт camera.py (листинг 13.3), который бу- дет запускаться при запуске webiopi. В скрипте пропишем назначение контактов, макросы и выполним начальный запуск камеры потокового видео. Учтем при этом, что управляющие контакты сервоприводов подключены к выводам 16 (GPIO23) и 18 (GPIO24) GPIO. Плюс еще одна дополнительная опция — мигание светодиода, подключенного к выводу 22 (GPIO25). import webiopi import sys import time from subprocess import call GPIO = webiopi.GPIO SERVO1 =23 SERVO2 =24 LED1 =25 def camera_start () : return_code = call("/usr/share/webiopi/examples/servo-camera/ stream_start.sh", shell=True) def setup () : webiopi.debug("Blink script - Setup")
300 Глава 13 # Установка выводов GPIO GPIO.setFunction(SERV01, GPIO.PWM) GPIO.setFunction(SERVO1, GPIO.PWM) GPIO.setFunction(LED1, GPIO.OUT) GPI0.pwmWriteAngle(SERV01, 0) # set to 0 (neutral) GPIO.pwmWriteAngle(SERVO2, 0) # set to 0 (neutral) GPIO.digitalWrite(LED1, GPIO.HIGH) camera_start () # Цикл loop() def loop(): # Toggle LED each 5 seconds value = not GPIO.digitalRead(LEDl) GPIO.digitalWrite(LED1, value) webiopi.sleep(5) # Возврат выводов в начальное состояние def destroy(): webiopi.debug("Blink script - Destroy") # Reset GPIO functions GPIO.setFunction(SWITCH, GPIO.IN) GPIO.setFunction(SERVO, GPIO.IN) GPIO.setFunction(LEDO, GPIO.IN) GPIO.setFunction(LED1, GPIO.IN) Веб-интерфейс у нас будет достаточно простой: два слайдера управления подвесом камеры, кнопка для отправки фото на e-mail и картинка изображения с камеры (рис. 13.10). При изменении позиции слайдера подвес поворачивается в направле- Рис. 13.10. HTML-страница проекта управления подвесом для камеры
WeblOPi — веб-интерфейс и облако для Raspberry Pi 301 нии вверх-вниз и влево-вправо. Изображение с камеры постоянно обновляется запуском функции setTimeout (). Необходимо также запретить кэширование стра- ницы. Код HTML-страницы camera.html представлен в листинге 13.4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv = "cache-control" content = "max-age=0"> <meta http-equiv = "cache-control" content = "no-cache"> <meta http-equiv = "expires" content = "0"> <meta http-equiv = "expires" content = "Tue, 01 Jan 1970 1:00:00 GMT"> <meta http-equiv = "pragma" content = "no-cache"> <meta name="viewport" content = "height = device-height, width = 420, user-scalable = no" /> <title>WebIOPi camera</title> <script type="text/javascript" src="/webiopi.js"x/script> <script type="text/javascript"> function init() { var button; button = webiopiO.createButton("photo", "big photo", photo); $("#cam").append(button); button = webiopi().createAngleSlider(23, 30); $("#updown").append(button); button = webiopi().createAngleSlider(24, 0); $("#leftright").append(button); function photo() { $("#ph").html("); $("#ph").html(f<img src="pic.jpg">f); } function get_img() { document.getElementByld("imgl").src="http://192.168.0.101:8080/pic.jpg"; } webiopi().ready(init); </script> <style type="text/ess">
302 Глава 13 button { margin: 5px 5px 5px 5px; width: 150px; height: 50px; font-size: 12pt; font-weight: bold; color: black; } </style> </head> <body onload='setlnterval("get_img();",1000);' > <div style="float:left"> <div id="content" align="center"> <div id="cam"></div> <div id="vid"><img id="imgl" widtfr="320" height="240" src="http: //192.168.0.101:8080/pic. jpg"x/div> <div>down<span ids="updown"x/span>up</div> <div>left<span id="leftright"x/span>right</div> <div style-"float:right" id="ph"x/div> </body> </html> Электронный архив Коды листингов этого проекта вы найдете в папке python\servo-camera сопровождающе- го книгу электронного архива. 13.6. WeblOPi — подключение устройств Фреймворк WeblOPi позволяет использовать устройства типов Serial, I2C, SPI и 1-Wire прямо из интерфейса REST API, без написания макросов (список поддержи- ваемых датчиков имеется на странице: https://code.google.com/p/webiopi/wiki/ DEVICES). Включить поддержку устройства можно в блоке [device] файла конфигурации /etc/webiopi/config, раскомментировав строку с выбранным датчиком, который сле- дует подключить к выходам GPIO: [DEVICES] #temp0 - TMP102 #templ - ТМР102 slave:0x49 temp2 = DS18B20 #temp3 - DS18B20 slave:28-0000049bc218
WeblOPi — веб-интерфейс и облако для Raspberry Pi 303 Пример схемы подключения датчика температуры DS18B20 представлен на рис. 13.11. Выполнив необходимые монтажные манипуляции, открываем стартовую страницу WeblOPi (см. рис. 13.1), выбираем пункт Device Monitor и попадаем на страницу подключенных устройств (рис. 13.12). В нашем случае здесь отображен только дат- чик температуры DS18B20. Страница демонстрирует данные, получаемые с датчи- ка, с обновлением их каждые 5 секунд. DS18B20 Raspberry Pi GPIO GND OQ VDD 1 2 i r- 3 4,7k\ V L_ i 1 +3.3 В 3 GPIOO 5 GPIO1 > 7 GPIO4 1 9 GND 11 GPIO17 13 GPIO21 15 GPIO22 17 +3.3 В 19 GPIO10 21 GPIO9 23 GPIO11 25 GND ♦5 В 2 * +5 В 4 GND 6 GPIO14 8 GPIO15 10 GPIO18 12 GND 14 GPIO23 16 GPIO24 18 GND 20 GPIO25 22 GPIO8 24 GPIO7 26 i" Рис. 13.11. Схема подключения к GPIO датчика DS18B20 Devices Monitor temp2: Temperature: 19.56°C Рис. 13.12. Монитор подключенных устройств
304 Глава 13 13.7. Доступ к устройству из сервиса Weaved Сервис Weaved (https://www.weaved.com) позволяет подключиться к Raspberry Pi (и не только) из браузера, находясь в любой точке мира. Если вы не установили программное обеспечение для сервиса Weaved при установке WeblOPi, сейчас для этого самое время. 13.7.1. Установка сервиса Weaved Для установки сервиса сначала необходимо в нем зарегистрироваться. Сделать это можно на странице https://developer.weaved.com/portal/ (рис. 13.13), открываемой по нажатию кнопки Sign Up на главной странице сервиса. ?: https //developer, weaved com/portal/ sndex pkp | #Weaved Internet of Things for Everyone There is no cost to try out our products and services, we just need to know you' re a real jperson Full Name [ Email * [ ~~ZZ 1 _ IZZT-ZZ _i Password * [ Confirm Password * j ■ * Indicates required Click here if you already have a Weaved account Рис. 13.13. Регистрация в сервисе Weaved Зарегистрировавшись в сервисе, запускаем терминал нашего Raspberry Pi и скачи- ваем установщик программного обеспечения для сервиса Weaved: wget https://github.com/weaved/installer/raw/master/binaries/ weaved-nixinstaller_l.2.13.bin Делаем файл установщика исполняемым: chmod +x weaved-nixinstaller_l.2.13.bin Запускаем установку: ./weaved-nixinstaller 1.2.13.bin
WeblOPi — веб-интерфейс и облако для Raspberry Pi 305 Во время установки вам будет предложено выбрать вид доступа для связи с Rasp- berry Pi (рис. 13.14): □ SSH на порту 22; О Web (HTTP) на порту 80; □ WeblOPi на порту 8000; Я VNC на порту 5901 (tested with tightvncserver); □ пользовательский сервис TCP. Выбрать можно только один из предложенных. Если вы хотите использовать не- сколько видов доступа, необходимо запускать установку несколько раз, выбирая каждый раз новый вид доступа. Рис. 13.14. Выбор вида доступа к плате из сервиса Weaved: здесь выбрано подключение по Web (HTTP) Далее необходимо ввести данные для авторизации в сервисе Weaved: логин (адрес электронной почты) и пароль (рис. 13.15). После чего создать имя для устройства в сервисе Weaved (рис. 13.16). В завершение установки выдается информация по командам для запуска/остановки сервиса (рис. 13.17). Завершив установку, мы можем зайти в свой профиль в сервисе Weaved и увидеть список наших устройств (рис. 13.18).
306 Глава 13 Рис. 13.15. Ввод данных для авторизации в сервисе Weaved Рис. 13.16. Создание имени для устройства в сервисе Weaved
WeblOPi — веб-интерфейс и облако для Raspberry Pi 307 Рис. 13.17. Информация по командам запуска сервисов для доступа из Weaved Рис. 13.18. Список устройств в сервисе Weaved
308 Глава 13 13.7.2. Подключение к Raspberry Pi в сервисе Weaved Подключимся для начала к Raspberry Pi no WeblOPi. Этому подключению соответ- ствует устройство raspberry_pi_02 (см. рис. 13.18) — выбираем его и попадаем на страницу авторизации сервиса WeblOPi нашего Raspberry Pi (рис. 13.19). ; http$y/akfzcgdi.p6.weavedcom , Необходима авторизация Для доступа на сервер http$^/akfecgdi.p6.weaved.com: 443 требуется указать имя пользователя и пароль. Сообщение сервера: WeblOPi, Имя пользователя: webiopi Пароль: I ********* Вход Рис. 13.19. Страница доступа к WeblOPi из Weaved После авторизации— мы на главной странице WeblOPi нашего Raspberry Pi (рис. 13.20). WeblOPi Main Menu GPIO Header Control and Debug die Raspberry Pi GPIO with a display which looks like the physical header GPIO List Control and Debug the Raspberry Pi GPIO ordered in a single column. Serial Monitor Use the browser to play with Serial interfaces configured in WeblOPi. Devices Monitor Control and Debug devices and circuits wired to your J*i and configured ш WeblOPi. Рис. 13.20. Страница доступа к WeblOPi из Weaved Подключимся теперь к Raspberry Pi no Web. Этому подключению соответствует устройство raspberry_pi_02_http (см. рис. 13.18). Для такого подключения на Raspberry Pi необходимо установить веб-сервер:
WeblOPi — веб-интерфейс и облако для Raspberry Pi 309 sudo apt-get update sudo apt-get install apache2 Страница доступа из Weaved к веб-серверу на Raspberry Pi показана на рис. 13.21. It works! This is the default web page for this server The web server software is running but no content has been added, yet. Рис. 13.21. Страница доступа к веб-серверу на Raspberry Pi из Weaved
ГЛАВА 14 Проект Wyliodrin: управление удаленными устройствами из браузера Румынский онлайн-сервис Wyliodrin (https://www.wyliodrin.com/), основанный на графической среде программирования Blockly, предоставляет возможность графи- ческого программирования сенсоров/актуаторов на Intel Galileo, Intel Edison, Beagle Bone Black, Raspberry Pi, Arduino и еще целом ряде устройств (рис. 14.1). С по- мощью Wyliodrin можно программировать устройства, загружать в них программы и управлять этими устройствами прямо из браузера. Для программирование встраиваемых устройств необходимо, как правило, чтобы они были подключены к компьютеру. Однако при работе через Wyliodrin устройст- во должно быть подключено только к Интернету. А раз так, то и находиться оно может в любом месте, — вы можете запрограммировать его, просто войдя в свою учетную запись (аккаунт) Wyliodrin. Таким образом, если у вас есть, например, метеостанция или удаленные устройства автоматизации, вы можете программиро- вать их и управлять ими непосредственно из своего дома или офиса. Сервис позво- ляет также строить графики для отображения данных, получаемых с устройств. Программирование встраиваемых устройств обычно требует знания языков С или C++. Работая же через Wyliodrin, вы можете выбрать язык, который хорошо знаете и любите: от тех же C/C++ до Java, Pascal, Shell Script, Perl, PHP, Objective-C, C#, Python или JavaScript. И даже если вы не знаете никакого языка программирования, то сможете воспользоваться визуальной средой программирования, где построение программы осуществляется простым перетаскиванием блоков. Чтобы начать пользоваться сервисом, необходимо зарегистрироваться, после чего вы сможете выбрать тип учетной записи: бесплатный (использовать одно устройст- во и создать три приложения) или платный (от 3,9 до 50 долларов в месяц). Для владельцев плат Intel Galileo действует специальное предложение — годовая под- писка, позволяющая бесплатно использовать три платы и создать 15 приложений. Итак, регистрируемся в сервисе и попадаем в свой профиль. Сейчас наш профиль пуст — какая-либо информация о подключенных устройствах и созданных прило-
312 Глава 14 UmPi Uvllii YVvliotirm Рис. 14.1. Главная страница проекта Wyliodrin жениях в нем отсутствует. Так что, прежде всего нам надо добавить в него уст- ройство. 14.1. Добавление устройства в профиль Для добавления устройства нажимаем в окне профиля кнопку Add New Board и в открывшемся окне New Board (рис. 14.2) вводим название устройства (в поле Рис. 14.2. Добавление устройства
Проект Wyliodrin: управление удаленными устройствами из браузера ^ Name), выбираем плату, с которой собираемся работать (сейчас это Raspberry Pi), и нажимаем кнопку Next. В следующем окне (рис. 14.3) выбираем тип подклю- чения устройства к сети Интернет и нажимаем кнопку Submit — все, устройство добавлено в профиль (рис. 14.4). New Board ШМштШ €#й»«€йвв * itpftf© вш st#p a«d s'ust click *$;Лтйя Шг©1вм - Cilcfc см? *Us» Wireless* enter ifw WWi istwcwl rwros mi раззшегс!» лпй tli#fi click *5«1?тНв Рис. 14.3. Выбор настроек подключения устройства к Интернету Рис. 14.4. Профиль пользователя с добавленными устройствами 14.2. Запись образа Wyliodrin на SD-карту... Теперь необходимо настроить наше устройство, для чего следует прежде всего ска- чать и загрузить на карту памяти образ Wyliodrin для Raspberry Pi, выбрав из выпа- дающего меню опцию Download SD Card (рис. 14.5). Примечание Нам понадобится карта MicroSD емкостью минимум 4 Гбайт (рекомендуемый класс — не ниже 10).
314 Глава 14 Рис. 14.5. Закачка образа Wyliodrin для Raspberry Pi 14.2.1. ...в ОС Windows Для записи образа Wyliodrin на SD-карту в операционной системе Windows скачай- те и установите на компьютер программу Win32 Disk Imager (инсталлятор про- граммы находится в свободном доступе по ссылке http://win32-disk-imager.ru. uptodown.com/). Запустив установленную программу, выберите устройство (картридер), где нахо- дится ваша SD-карта (рис. 14.6), и, нажав на значок папки у поля Image File, ука- жите путь к файлу со скачанным и распакованным образом Wyliodrin (рис. 14.7). V '! Рис. 14.6. Выбор местонахождения SD-карты Вернувшись после этого в окно программы Win32 Disk Imager, нажмите кнопку Write— начнется процесс записи образа Wyliodrin на карту (рис. 14.8), по завер- шении которого нажмите кнопку Exit и закройте приложение. Теперь ваша карта MicroSD готова для использования на Raspberry Pi.
Проект Wyliodrin: управление удаленными устройствами из браузера 315 Рис. 14.7. Указание пути к файлу образа Рис. 14.8. Запись образа на SD-карту 14.2.2. ...в ОС Linux Для записи образа Wyliodrin на SD-карту в операционной системе Linux вставьте SD-карту в картридер — карта должна определиться в системе (в данном случае — под именем mmcblkO) (рис. 14.9). Рис. 14.9. Определение SD-карты в списке устройств /dev
316 Глава 14 Выполните в терминале команду: dd if=wyliodrin_raspberrypi_image_file of=/dev/device_name где wyliodrin_raspberrypi_image_file— путь К Скачанному И распакованному об- разу Wyliodrin, a /dev/device_name — путь к подключенному картридеру с SD- картой (например: /dev/mncbiko). Осталось только дождаться завершения процесса записи. 14.2.3. ...в Mac OS Для записи образа на SD-карту в операционной системе Mac OS X скачайте утили- ту PiWriter (http://sourceforge.net/projects/piwriter/), вставьте SD-карту в картри- дер, запустите утилиту и следуйте инструкциям на экране. 14.2.4. ...в ОС Raspbian Если вы опытный пользователь, то можете установить образ Wyliodrin сразу на SD-карту с операционной системой Raspbian. Для этого скачайте из репозитория архив https://github.com/Wyliodrin/wyliodriii-server-nodejs/tree/development, рас- пакуйте его на эту карту и запустите скрипт инсталляции: . /wyliodrin--serve г- raspberry-pi. sh Если используется беспроводное соединение, необходимо изменить файл /etc/ network/interfaces, записав в него код из листинга 14.1. auto lo iface lo inet loopback iface ethO inet dhep allow-hotplug wlanO iface wlanO inet manual #wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf wpa-roam /home/pi/wyliodrin-server-nodej s/conf/wireless/wireless.conf iface default inet dhep 14.3. Запись на SD-карту настроек Wyliodrin Для каждой новой платы система генерирует уникальный файл настроек wyljodrin.json — скачайте из своего профиля этот файл, выбрав из выпадающего ме- ню опцию Download wyliodrin.json (рис. 14.10), и запищите его на ту же карту MicroSD, куда уже был записан образ Wyliodrin (рис. 14.11).
Проект Wyliodrin: управление удаленными устройствами из браузера 317 Щ Applicat В Рис. 14.10. Закачка файла настроек wyliodrin json Рис. 14.11. Запись файла настроек на карту MicroSD 14.4. Подключение Raspberry Pi к Wyliodrin Вставьте подготовленную SD-карту в Raspberry Pi и загрузитесь с нее. Если плата получила доступ в Интернет, то после загрузки системы в профиле Wyliodrin ее статус изменится на Online (рис. 14.12). Из веб-интерфейса Wyliodrin можно произвести удаленную загрузку библиотек (опция Extra Libraries) и обновление (опция Update Image) системы (рис. 14.13), причем протекание этих процессов вам будет наглядно показано (рис. 14.14).
318 Глава 14 Рис 14.12. Подключение Raspberry Pi к Wyliodrin Рис. 14.13. Возможность удаленной загрузки библиотек и обновления системы Рис. 14.14. Процесс удаленной загрузки библиотек на плату Raspberry Pi
Проект Wyliodrin: управление удаленными устройствами из браузера ^ Так же удаленно (из браузера) вы можете запустить оболочку shell (рис. 14.15) и диспетчер задач (рис. 14.16), а также просто выключить Raspberry Pi. Ну вот, наша плата готова к программированию, и мы можем приступить к созда- нию приложений. Рис. 14.15. Удаленный запуск оболочки shell Рис. 14.16. Удаленный запуск диспетчера задач 14.5. Создание приложения в графической среде программирования Для создания нового приложения в окне профиля (см. рис. 14.13) нажмите кнопку Create new application, после чего в открывшемся окне New Project введите назва- ние нового приложения, его описание и выберите язык программирования.
320 Глава 14 В списке языков программирования Programming Language уже имеется несколь- ко готовых шаблонов приложений от Wyliodrin— выберите в качестве первого приложения: Led Blink-Visual Programming (рис. 14.17). Подтвердите свой выбор, и наше новое приложение создано (рис. 14.18). lie Рис. 14.17. Создание нового приложения 7Л Л Рис. 14.18. Список приложений профиля
Проект Wyliodrin: управление удаленными устройствами из браузера 321 Выбрав приложение в списке приложений (см. рис. 14.18), мы попадем в окно его редактирования (рис. 14.19)— здесь можно посмотреть, как выглядит код прило- жения на языках Python и JavaScript, внести в этот код какие-либо изменения, а также загрузить приложение на плату и запустить на выполнение. Рис. 14.19. Окно редактирования приложения Немного подредактируем наше приложение: изменим в визуальных блоках значе- ния pin на вывод 7 и увеличим задержки delay до 2000 мс (рис. 14.20). Ai?:£^-*%j*?i^ Рис. 14.20. Редактирование приложения
322 Глава 14 Теперь подключим к Raspberrry Pi светодиод согласно схеме, приведенной на рис. 14.21, и нажмем в окне приложения на надпись Stopped (выделена кружком на рис. 14.20). Система проверит код и, если все в порядке, осуществит загрузку приложения на плату и запуск его на выполнение (рис. 14.22). Рис. 14.21. Схема подключения светодиода к плате Raspberry Pi Рис. 14.22. Запуск приложения
Проект Wyliodrin: управление удаленными устройствами из браузера 323 В это время на плате Raspberry Pi мы можем наблюдать мигание светодиода, под- ключенного к выводу 7. Нажатие кнопки Stop в правом верхнем углу окна прило- жения (рис. 14.22) приведет к остановке приложения на плате. 14.6. Включение/выключение светодиода с веб-страницы Для управления светодиодом с веб-страницы создадим новый проект web_raspi и в визуальном редакторе впишем код, представленный на рис. 14.23. Запустим на Raspberry Pi веб-сервер (порт 5000). При попадании на главную страницу браузер выдает код: <br><a href=Vonf>On</a> <brxa href='/offf>Off</a> По нажатию на ссылку On светодиод, подключенный к выводу 7, зажигается, по нажатию на ссылку Off— гаснет. Рис. 14.23. Код приложения web_raspi в визуальном редакторе Теперь надо узнать адрес нашего веб-сервера, т. е. IP-адрес Raspberry Pi, — запус- тим для этого из браузера оболочку shell и выполним в ней команду ip addr show (рис. 14.24). Далее запускаем в Wyliodrin наше приложение web_raspi (рис. 14.25), набираем в браузере адрес http://ip_raspberry:5000 и управляем включением/выключением светодиода переходом по ссылкам (рис. 14.26).
324 Глава 14 Рис. 14.24. Получение IP-адреса Raspberry Pi из командной оболочки shell Рис. 14.25. Запуск приложения web_raspi Рис. 14.26. Веб-страница управления включением/выключением светодиода
Проект Wyliodrin: управление удаленными устройствами из браузера 325 14.7. Подключение платы Arduino к сервису Wyliodrin... Плату Arduino невозможно напрямую использовать для подключения к сервису Wyliodrin. Но программное обеспечение Wyliodrin позволяет использовать возмож- ности платы Arduino, подключенной к микрокомпьютеру Raspberry Pi. Рассмотрим здесь соответствующие примеры. 14.7.1. ...с помощью библиотеки Firmata Сначала загрузим на плату Arduino скетч StandartFirmata из Arduino-библиотеки Firmata (рис. 14.27), входящей в состав Arduino IDE. Библиотека Firmata реализует протокол Firmata, упрощающий общение с программами на компьютере. Рис. 14.27. Загрузка на плату Arduino скетча StandartFirmata из библиотеки Firmata Подсоединим теперь плату Arduino к нашему Raspberry Pi, создадим в своем про- филе Wyliodrin новый проект arduinol и выберем в качестве языка программиро- вания VisualProgramming. На следующем шаге выберем подключение платы Arduino: Connect an Arduino to the board (Raspberry Pi only) — как показано на рис. 14.28.
326 Глава 14 New Project рШ"*' ш -ш beard *'Rr*$pO€vry P? Рис. 14.28. Выбираем при создании проекта подключение платы Arduino Создав проект, зайдем в окно редактирования проекта и в визуальном редакторе впишем код мигания светодиодом на 13-м выводе Arduino с периодичностью 2 сек. (рис. 14.29). Узнать порт подключения платы Arduino к Raspberry Pi можно прямо из сервиса Wyliodrin, запустив оболочку shell и выполнив команду dmesg (рис. 14.30). Рис. 14.29. Программа в VisualProgramming
Проект Wyliodrin: управление удаленными устройствами из браузера 327 Рис. 14.30. Определение порта подключения Arduino с помощью оболочки shell Осталось запустить проект и наблюдать мигание светодиода на выводе 13 платы Arduino. Создадим новый проект (arduino2), для которого подключим к аналоговым входам Arduino аналоговый датчик температуры LM35 и фоторезистор (рис. 14.31), и рас- смотрим отображение получаемых данных в виде виджетов и графиков. Выберем для этого проекта тот же язык программирования — VisualProgramming и подключение платы Arduino: Connect an Arduino to the board (Raspberry Pi only)— как показано на рис. 14.28. Создав проект, заходим в режим редактирова- ния и создаем в визуальном редакторе код, приведенный на рис. 14.32. Запускаем проект на выполнение и наблюдаем вывод в монитор программы на сай- те Wyliodrin показаний датчика температуры LM35 и фоторезистора (рис. 14.33). Теперь добавим в браузере отображение температуры на виджете и показаний фо- торезистора на графике. Для этого в окне редактирования приложения arduino2 открываем вкладку Signals (рис. 14.34), выбираем элемент Send signal "..." with value 0 и добавляем его в цикл опроса данных аналоговых входов. Добавить следует
328 Глава 14 Рис. 14.31. Схема подключения к плате Arduino аналогового датчика температуры и фоторезистора тттшж Рис. 14.32. Программа в VisualProgramming для получения показаний сдатчиков
Проект Wyliodrin: управление удаленными устройствами из браузера 329 Рис. 14.33. Получение показаний с датчиков температуры и освещенности Рис. 14.34. Вкладка Signal два таких элемента: один — для фоторезистора, второй — для датчика температу- ры (рис. 14.35). При этом присваиваем каждому сигналу соответствующее имя: GraphPhoto — для отправляемых значений фоторезистора, VidgetTemp — для от- правляемых значений датчика температуры.
330 Глава 14 ^Р^У"^ '^Л' ттШ; Рис. 14.35. Элементы вкладки Signal (Send signal...) добавлены в программу Далее нажимаем в окне программы (см. рис. 14.34) на ссылку Dashboard и добав- ляем в окно из правого списка два элемента: виджет температуры Thermometer и график Spline Line (рис. 14.36). Добавленные элементы необходимо отредактиро- вать так, чтобы они отображали данные отправляемых нашей программой сигна- лов, — редактируем элементы (рис. 14.37 и 14.38) и запускаем программу. Рис. 14.36. Добавление элементов в окне Dashboard
Проект Wyliodrin: управление удаленными устройствами из браузера 331 Рис. 14.37. Изменение параметров элемента Thermometer Рис. 14.38. Изменение параметров элемента Spline Line
332 Глава 14 Рис. 14.39. Графическое отображение в браузере данных фоторезистора и датчика температуры Теперь в браузере мы можем увидеть графическое отображение температуры и график изменения во времени показаний фоторезистора (рис. 14.39). 14.7.2. ...без использования библиотеки Firmata Чтобы отправить в сервис Wyliodrin результат любого скетча, выполняемого на Arduino, надо чтобы плата Arduino по последовательному порту отправляла данные в Raspberry Pi, а скрипт, запущенный на Raspberry Pi, отправлял бы эти данные в сервис Wyliodrin. Допустим, мы собираемся отправлять в сервис Wyliodrin данные с датчиков, рабо- тающих по протоколу 12С, -— воспользуемся для этого датчиком освещенности ВН1750 и датчиком влажности и температуры SHT21, рассмотренными нами в гла- ве б. Данные с этих датчиков будут отправляться из Arduino в Raspberry Pi по по- следовательному порту, а скрипт на языке Python, запущенный на Raspberry Pi, станет принимать эти данные и отправлять в сервис Wyliodrin. Схема подключения датчиков ВН1750 и SHT21 к плате Arduino представлена на рис. 14.40. Загрузим на плату Arduino скетч из листинга 14.2. Arduino здесь получает данные с датчиков и отправляет эти данные в формате JSON по последовательному порту в Raspberry Pi.
Проект Wyliodrin: управление удаленными устройствами из браузера 333 Рис. 14.40. Схема подключения датчиков ВН1750 и SHT21 к плате Arduino // Подключение библиотек для датчика ВН1750 #include <Wire.h> #include <BH1750.h> BH1750 lightMeter; // Подключение библиотеки для датчика SHT21 #include <SHT2x.h> uintl6_t lux; float temp; float humidity; void setup() { // подключение последовательного порта Serial.begin(9600); // запуск датчика ВН1750 lightMeter.begin();
334 Глава 14 void loop() { // получение данных с ВН1750 lux = lightMeter.readLightLevel(); humidity=SHT2x.GetHumidity(); temp=SHT2x.GetTemperature(); Serial.print("{lux:");Serial.print(lux); Serial.print(",temp:");Serial.print(temp); Serial.print(",humidity:");Serial.print(humidity); Serial.printlnC1}") ; // задержка 10 сек delay(10000); Зайдем теперь в сервис Wyliodrin и создадим новое приложение: arduino3. Выбе- рем для него язык программирования Python и впишем в окне редактирования про- граммы (рис. 14.41) код, приведенный в листинге 14.3. Здесь мы считываем по по- следовательному порту из Arduino данные с датчиков ВН1750 и SHT21 в формате JSON и отправляем эти значения в виджеты Lux (Освещенность), Temp (Темпера- тура) и Humidity (Влажность). Рис. 14.41. Код приложения arduino3
Проект Wyliodrin: управление удаленными устройствами из браузера 335 from wyliodrin import * import json import serial def main(): initCommunication() print 'Hello from Wyliodrin\n' ser = serial.Serial(f/dev/ttyACMO', 9600, timeout=l) ser.open() try: while 1: responsel = ser.readline() if len(responsel)>0: print responsel 1 mil = responsel.find('luxf) +1+4 ml2 = responsel.find(',t') +1-1 m31 = responsel.find('humidity1) +1+9 m21 = responsel.find('temp1) +1+5 m22 = responsel.find(',h') +1-1 m31 = responsel.find('humidity') +1+9 m32 = responsel.find('}') +1-1 print(responsel[int(m21 - 1) : int(m22)]) try: lux=float (responsel[int(mil - 1) : int(ml2)]) humidity=float (responsel[int(m31 - 1) : int(m32)]) temp=float (responsel [int (m21 - 1) :. int(m22)]) humidity=float (responsel[int(m31 - 1) : int(m32)]) sendSignal('Lux', lux) sendSignal('Temp', temp) sendSignal('Humidity', humidity) except ValueError: print("ERROR") except Keyboardlnterrupt: ser.close() if name = "_main ": main() Теперь мы можем запустить приложение arduino3 в браузере в Wyliodrin и наблю- дать вывод данных с датчиков на виджеты и в монитор (рис. 14.42).
336 Глава 14 Рис. 14.42. Запуск приложения arduino3 14.8. Совместная работа Raspberry Pi и платы GrovePi Система Grove представляет собой набор готовых к использованию электронных устройств в виде модулей. Она включает базовую плату и различные модули со стандартными разъемами для подключения к ней. Базовая плата позволяет легко связать выводы популярных микроконтроллеров с контактами модулей Grove. Су- ществуют базовые платы для Arduino, Raspberry Pi, Intel Galileo, Intel Edison, mbed, LaunchPad и других микроконтроллеров и микрокомпьютеров. Большой выбор базовых плат и модулей Grove представлен в интернет-магазине Seeedstudio: https://www.seeedstudio.com/depot/s/grove.html?search_in__description=0. Для подключения к Raspberry Pi (рис. 14.43) используются платы расширения GrovePi и GrovePi+ (плата для подключения плат Raspberry Pi версий «А+» и «В+»). Плата GrovePi+ поддерживает подключение семи цифровых и трех аналоговых вы- водов, трех портов 12С, одного последовательного порта подключения к GrovePi и последовательного порта подключения к Raspberry Pi. Для работы Raspberry Pi с платой GrovePi необходимо установить соответствующее программное обеспечение. Для этого подключаемся по ssh к нашему Raspberry Pi и клонируем репозиторий GrovePi: git clone https://github.com/Dexterlnd/GrovePi
Проект Wyliodrin: управление удаленными устройствами из браузера 337 Рис. 14.43. Подключение платы GrovePi+ к Raspberry Pi Переходим в папку GrovePi/Script: cd GrovePi/Script Предоставлям файлу install.sh права на выполнение: sudo chmod +x install.sh И запускаем его: sudo ./install.sh Скрипт будет работать достаточно продолжительное время, связанное с закачкой из Интернета и установкой дополнительных пакетов (рис. 14.44). По завершении работы скрипта Raspberry Pi необходимо перезагрузить: sudo reboot После перезагрузки можно подключить GrovePi к Raspberry и использовать с ним устройства Grove. На странице http://www.seeedstudio.com/wiki/GrovePi+ можно найти ссылки на проекты с кодом по подключению некоторых да!чиков системы Grove (рис. 14.45). Работать с устройствами Grove через плату GrovePi в Wyliodrin весьма просто: под- соединим к контактам АО платы GrovePi датчик света Grove light (рис. 14.46), соз- дадим в Wyliodrin новое приложение arduino4 и выберем для него язык VisualProgramming, напишем программу вывода получаемых значений на график (рис. 14.47), запустим программу и увидим график получаемых с датчика Grove light значений (рис. 14.48).
338 Глава 14 Рис. 14.44. Установка программного обеспечения Supported Products Grove list • 1 Grove- Button # • 2 Light Sensor $ • 3 Buzzer # • 4 Sound Sensor й? • 5 Grove -Red LED & • 6 Grove -Blue LED d> • 7 Grave-Green LED $ • 8 LCDRGBBacWightiS» • 9 Rotary Angle Sensor $ • 10 Temperature Humidify Sensor dP • 11 Ultrasonic Ranger Sensor d? • 12 Relays See Also Designer's web ate De^enndustnesdF Download the pdf file about setting up the softerware Setting_Up_Sof{w3reJor_GrowPi pdf ijfi I Categories: Grove . Grove Stem Raspberry Pi Рис. 14.45. Ссылки на проекты с подключением датчиков Grove к плате GrovePi
Проект Wyliodrin: управление удаленными устройствами из браузера 339 \ Рис. 14.46. Датчик Grove light Рис. 14.47. Программа для вывода данных датчика Grove light на фафик щзтжт^шжшжщ Рис. 14.48. График получаемых с датчика Grove light значений
340 Глава 14 14.9. Обмен сообщениями между платами Raspberry Pi через сервис Wyliodrin В сервисе Wyliodrin существует возможность обмена сообщениями между платами. Чтобы исследовать эту возможность, добавим к нашему профилю еще одну плату Raspberry Pi (см. разд. 14.1) — и назовем ее Raspberry_pi_02. Запишем на нее об- раз, файл настроек wyliodrin.json и подключим плату к сети Интернет. Откроем свой профиль Wyliodrin и увидим, что она находится в статусе Online (рис. 14.49). Рис. 14.49. Добавление в профиль еще одной платы Raspberry Pi: Raspberry_pi_02 Наша новая плата будет принимать JSON-сообщения, отправляемые платой Raspberry_pi_01, к которой подключена плата Arduirio UNO с датчиками освещен- ности ВН1750 и влажности и температуры SHT21 (см. рис. 14.40). В плату Arduino загружен скетч из листинга 14.2, который каждые 10 секунд отправляет данные датчиков в формате JSON по последовательному порту в Raspberry_ pi_01. Эти данные плата Raspberry_pi_01 станет отправлять в плату Raspberry_pi_02 через Wyliodrin. Создадим новое приложение: arduino5_send_data? выберем для него язык про- граммирования Python и запишем в него код из листинга 14.4. from wyliodrin import * import json import serial def main(): initCommunication() print 'Hello from Wyliodrin\nf ser = serial.Serial(f/dev/ttyACMO', 9600, timeout=l) ser.open() try: while 1: responsel = ser.readline()
Проект Wyliodrin: управление удаленными устройствами из браузера 341 if len(response1)>0: print responsel sendMessage(fvictoruni_raspberry_pi_02@wyliodrin.com1, 'labell', json.dumps (responsel) ) except Keyboardlnterrupt: ser.close() if name_ main () main Функция sendMessage ('boardid1, 'label1, json. dumps (message)) отправляет СОоб- щение message с меткой label в плату boardid. Параметр boardid можно посмотреть, выбрав в настройках платы пункт BoardID (рис. 14.50). Рис. 14.50. Значение параметра boardid Теперь напишем приложение для платы Raspberry_pi_02, обеспечивающее получе- ние сообщений от платы Raspberry_pi_01: создаем новое приложение arduino6_ getmessage, выбираем для него язык программирования Python и заносим в при- ложение код из листинга 14.5. from wyliodrin import * import json def messagesReceiver(sender, label, error, message): print(message) def main(): openConnection(flabellf, messagesReceiver) if name = "_main ": main()
342 Глава 14 Теперь при запуске на плате Raspberryjpi 02 этого приложения мы увидим по- лучение сообщений, отправленных приложением из платы Raspberry_piJ)l (рис. 14.51). Яй Рис. 14.51. Получение платой Raspberry_pi_02 сообщений из платы Raspberry_pi_01 Использовать получаемые в сообщениях данные можно по своему усмотрению. Мы же просто выделим из них нужные значения и выведем их на виджеты (для темпе- ратуры и влажности) и график (освещенность) — как мы делали ърозд. 14Л. Изменим для этого приложение arduino6_getjmessage9 добавив в него парсинг значений из получаемого сообщения и вывод их на виджеты и график (рис. 14.52). Код приложения приведен в листинге 14.6. from wyliodrin import * ' import json def messagesReceiver(sender, label, error, message): print(message) mil = message.find(flux1) +1+4 ml2 = message.find(',tf) +1-1 m31 = message.find('humidity1) +1+9 m21 = message.find('temp') +1+5 m22 = message.find(f,hf) +1-1 m31 = message.find('humidity1) +1+9 m32 = message.find(f}f) +1-1 try: lux=float (message[int (mil - 1) : int(ml2)]) humidity=float (message[int(m31 - 1) : int(m32)])
Проект Wyliodrin: управление удаленными устройствами из браузера 343 temp=float (message[int(m21 - 1) : int(m22)]) humidity=float (message[int(m31 - 1) : int(m32)]i print (lux) print (temp) print (humidity) sendSignaH fLux?, lux) sendsignal ('Temp1, temp) sendSignal (f Humidity', humidity) except ValueError: print("ERROR") def main () : openConnection(flabel1', messagesReceiver) if name == main () WmlmF " main ii. Рис. 14.52. Вывод значений, получаемых платой Raspberry_pi_02 из платы Raspberry_pi_O1, на виджеты и график 14.10. Отправка данных в сервис Wyliodrin с мобильного устройства Сервис Wyliodrin позволяет плате Raspberry Pi получать данные с датчиков мо- бильного устройства (планшета или смартфона). Для этого необходимо скачать и установить на него из Play Маркет приложение Wyliodrin Sensors (рис. 14.53).
344 Глава 14 В приложении следует задать настройки: ID устройства и интервал передачи дан- ных (рис. 14.54) и выбрать список датчиков устройства для передачи данных (рис. 14.55). Рис. 14.53. Приложение Wyliodrin Sensors в Play Маркет Рис. 14.54. Задание ID устройства и интервала передачи данных В окне профиля платы Raspberry Pi из соответствующего выпадающего меню надо выбрать возможность получения мобильных сообщений: Enable Mobile Messages (рис. 14.56). Сделав это, создайте соединение между платой и мобильным прило- жением — просто нажмите кнопку Board ID в выпадающем меню, и QR-код со- единения отобразится на экране. Чтобы сканировать этот код, нажмите на большую красную кнопку Scan Token в мобильном приложении. Завершив сканирование QR-кода (рис. 14.57), мобильное устройство начнет посылать в сервис Wyliodrin данные, поступающие из выбранных датчиков.
Проект Wyliodrin: управление удаленными устройствами из браузера 345 Рис. 14.55. Выбор датчиков для передачи данных Рис. 14.56. Включение мобильных сообщений для платы Raspberry Pi
346 Глава 14 Рис. 14.57. Сканирование QR-кода в мобильном приложении Теперь создадим в Wyliodrin приложение arduino8 для платы Raspberry_pi_02 и выберем для него язык программирования VisualProgramming. Код для этого при- ложения представлен на рис. 14.58. Здесь мы получаем показания сенсора light с мобильного устройства и выводим данные на экран и в график. Запустив приложение, мы видим на графике показания датчика light мобильного устройства, передаваемые нашему приложению. arduinoS Рис. 14.58. Код приложения arduino8
Проект Wyliodrin: управление удаленными устройствами из браузера 347 Рис. 14.59. График и показания датчика light мобильного устройства, передаваемые нашему приложению
ГЛАВА 15 Wi-Fi-модуль ESP8266 С конца 2014 года на китайских торговых площадках появились Wi-Fi-модули ESP8266. Причем, как выяснилось, это не просто модули Wi-Fi, а полноценные 32-битные микроконтроллеры со своими наборами GPIO, в том числе поддержи- вающими шины SPI, UART и 12С. При этом сами модули состоят из минимального количества деталей: собственно чипа ESP8266, Flash-памяти и кварцевого генера- тора. Характеристики модулей представлены в табл. 15.1. Таблица 15.1. Характеристики модулей ESP8266 Частота Стандарт Мощность Поддерживаемые типы шифрования Поддерживаемые режимы работы Напряжение питания Потребление тока Количество доступных выводов GPIO Внешняя Flash-память RAM данных RAM инструкций Температурный режим Wi-Fi 2412-2484 МГц 802.11 b/g/n + 20дБ WEP, WPA, WPA2 Клиент (STA), точка доступа (АР), клиент+точка доступа (STA+AP) 1,7-3,6 В 70 мА (пиковое значение 240 мА) 4-10 512 Кбайт 80 Кбайт 32 Кбайт От -40 до +70 °С В настоящее время выпускается более 12 модификаций плат модулей ESP8266, различающихся количеством выводов и вариантами исполнения (рис. 15.1). Моду- ли продаются с загруженной прошивкой, которая образует мост Wi-Fi —► UART для подключения к другому микроконтроллеру, в том числе и к Arduino. Настройка со- единения и обмен данными осуществляются с помощью АТ-команд.
350 Глава 15 ESP-01 ESP-02 ESP-03ESP-04 ESP-05 ESP-06 ESP-07 ESP-08 ESP-09 ESP-10 ESP-11 Рис. 15.1. Модули ESP8266 Возможны два варианта работы с модулем: □ использование его совместно с микроконтроллером, который будет управлять модулем по UART; □ создание собственной прошивки для чипа ESP8266 и его применение как само- достаточного устройства. 15.1. Режим АТ-команд Рассмотрим работу с модулем ESP8266 в режиме АТ-команд, для чего подключим его к компьютеру через переходник USB-to-RS232. Назначение выводов модуля представлено на рис. 15.2. Для работы модуля требуется внешнее питание 3,3 В. Схема подключения весьма простая: □ вывод VCC — питание платы (+3,3 В); □ вывод GND — общий; □ выводы RX и ТХ — подключаем к конвертеру USB-to-RS232 (в режиме 3,3 В); □ вывод CHJPD (Chip enable) — подключаем к питанию платы (+3,3 В). Для отправки в модуль АТ-команд я использовал в Mac OS X программу CoolTerm, а в ОС Windows — программу Termite. Узнать скорость СОМ-порта для соедине- •RX -VCC -GPIO О •RESET -CH_PD -GPIO 2 -ТХ •GND Рис. 15.2. Назначение выводов модуля ESP8266 исполнения ESP-01
Wi-Fi-модуль ESP8266 351 ния с модулем можно только экспериментально, поскольку для различных проши- вок она может быть разной. Так, для моего модуля эта скорость оказалась равной 9600 бод. Кроме того, установить обмен удалось только после отключения и по- вторного подключения к питанию вывода CHJPD. После удачного подключения модуля к компьютеру набираем в терминале at и должны получить в ответ от модуля ок. Команда at+gmr выдает номер версии про- шивки модуля, команда at+rst — перезагружает модуль (рис. 15.3). OK AT+GMR D0180009Q2 DK AT+RST OK [System Ready, Vendor www ai-thinker com] Рис. 15.3. Отправка АТ-команд в модуль из программы Termite Набор доступных АТ-команд в новых версиях прошивки модулей ESP8266 посто- янно пополняется. В табл. 15.2 приведен полный список АТ-команд для комплекта средств разработки (SDK) 0.9.5 версии 021. Таблица 15.2. Полный список АТ-команд для SDK 0.9.5 версии 021 Команда AT AT+RST AT+GMR AT+GSLP ATE AT+RESTORE AT+UART Описание Проверка модуля. Если модуль успешно стартовал, то он отвечает ок Перезапуск модуля Отобразить версию прошивки Переход в режим пониженного энергопотребления Включить/выключить эхо Сбросить на заводские настройки Настройка последовательного интерфейса Выполнение AT AT+RST AT+GMR AT+GSLP=<BpeMH мс> ATO ATI AT+RESTORE AT+UART= baudrate, databits, stopbits, parity, flow control
352 Глава 15 Таблица 15.2 (продолжение) Команда AT+CWMODE AT+CWJAP AT+CWLAP AT+CWQAP AT+CWSAP AT+CWLIF AT+CWDHCP AT+CIPSTAMAC AT+CIPAPMAC АТ+ CIPSTA АТ+ CIPAP AT+CIPSTATUS AT+CIPSTART AT+CIPSEND AT+CIPCLOSE AT+CIFSR AT+CIPMUX AT+CIPSERVER Описание Переключение режима Wi-Fi. Для вступления в силу требуется пере- запуск модуля командой at+rst Подключение к АР (точке доступа) Отобразить список доступных АР Отключение от АР Установить параметры для режима АР Отобразить IP-адреса подключен- ных клиентов Установить режим DHCP Посмотреть/установить МАС-адрес в режиме station Посмотреть/установить МАС-адрес в режиме softAP Посмотреть/установить IP-адрес в режиме station Посмотреть/установить IP-адрес в режиме softAP Отобразить статус подключения. Возвращает ID соединения, тип соединения (TCP или UDP), IP-адрес, порт, тип связи (клиент, сервер) Установить подключение TCP или UDP Отправить данные Закрыть подключение TCP или UDP Отобразить IP-адрес, который получили от АР, и адрес softAP Выбрать режим одиночных или множественных подключений Запустить (перезапустить) сервер Выполнение AT+CWMODE? AT+CWMODE=1 (station) AT+CWMODE=2 (АР) AT+CWMODE=3 (station+AP) AT+CWJAP =<идентификатор сети>,<пароль> AT+CWJAP? AT+CWLAP AT+CWQAP AT+CWSAP= ^идентификатор сети>, <пароль>, <канал>, <тип шифрования> AT+CWLIF АТ+СЮОНСР=<режим>, <вкл> AT+CIPSTAMAC=<mac> AT+CIPSTAMAC? AT+CIPAPMAC=<mac> AT+CIPAPMAC? AT+ CIPSTA=<ip> AT+ CIPSTA? AT+ CIPAP=<ip> AT+ CIPAP? AT+CIPSTATUS AT+CIPSEND=? AT+CI PSEND=<,ryTHHa> AT+CI РЗЕШ=<идентификатор><длина>
Wi-Fi-модуль ESP8266 353 Таблица 15.2 (окончание) Команда AT+CIPSTO AT+CIPMODE AT+CIUPDATE AT+PING +IPD Описание Установить тайм-аут сервера Установить сквозной режим Обновление прошивки через обла- ко. Модуль должен находиться в режиме 1 или 3 и быть подклю- ченным к АР с доступом к Интернету Пинг по имени хоста или IP-адресу Получить данные из сети Выполнение Рис. 15.4. Программа AppStack ESP8266 Config
354 Глава 15 Легко настроить модуль ESP8266, не заморачиваясь с АТ-командами, можно с по- мощью программы AppStack ESP8266 Config, свободно доступной для закачки, например, с российского сайта поддержки платы по ссылке: http://esp8266.ru/ download/esp8266-utils/ESP8266 Config.zip. Внешний вид программы AppStack ESP8266 Config представлен на рис. 15.4. На- стройка модуля осуществляется с помощью графического интерфейса, при этом выполнение команд можно видеть в мониторе программы (рис. 15.5). Из командной строки монитора также можно посылать в модуль и АТ-команды. Обновление прошивок модуля ESP8266 возможно осуществлять через облако. Мо- дуль при этом должен находиться в режиме 1 или 3 и быть подключен к точке дос- тупа с выходом в Интернет. Для обновления прошивки надо переключить модуль в режим прошивки, «подтянув» GPIO0 на «минус» и выполнить команду: AT+CIUPDATE После прошивки эту «подтяжку» надо отключить. ! 1 i г 1 1 1 Ш щ Ш т ш ж 1 ■ ■ ■ щ 1 s щ Ш т щ ш т тшт т т ш т ив Ж Щ ■ш if 1 I т i 1 ш т т ш чит РЖ Ж 1 1 I I ж 1 » 1 тят йндря Ш ■ ш ш ш ш 1 ш т Щ т т т ш Ж Ippii» 1 mm Ш 1 1 ш т т i т ш Щ ш т I I ш 1 1 ( Hi Ш т 1 я т Ш 1 т т 1 Щ I 1 1 1 1 т 1 т 1 т 1 1 ! 1 Ж щ Щ i «да Ш Ш ■ 1 ЯШ штат 1 J щ \ 1 1 1 в § 1 1 ■ ш i Ж I т ■ I ш Ш Ж. 1 ■ 1 iflSS Йбё м Ж i i i 1 т ш в е s в ш нШ I ж т в в ш WBsl i ■ ■ шш ■ ■ 1 i I I s Яр m и ■ ж «ж ■ т ■ Р ж Ш ян as 1 т ш ж ■ш i 1 1 I щ » ш i 1 Яг i i 0 1 Ж в 1 а X и ЯР ! 1 1 lips мм i 1 I s я т ш I Рис. 15.5. Окно Serial Monitor программы AppStack ESP8266 Config
Wi-Fi-модуль ESP8266 35Ц Следуя этой инструкции, можно обновиться только до официальных версий. Есть и другой вариант обновления прошивки— вручную. Для этого можно воспользо- ваться программами ХТСОМ UTDL, ESP8266 Flasher, NodeMCU Flasher и рядом других, доступных для свободной закачки с российского сайта поддержки платы ESP8266 (http://esp8266.ru). 15.2. Отладочные платы NodeMCU Отладочные платы (development board) — например, NodeMCU (рис. 15.6), гораздо более удобны в использовании, а особенно — при изучении ESP8266. Они нена- много дороже, но имеют гораздо больше преимуществ по сравнению с обычными модулями ESP8266: □ встроенный интерфейс USB-UART, реализованный на хорошо известных преоб- разователях СР2102 или CH340G. Подключение к ПК происходит при помощи обычного кабеля microUSB; Я встроенный преобразователь напряжения +3,3 В, а само питание берется непо- средственно от USB-порта ПК; □ все выводы, доступные на ESP8266, выведены на две гребенки со стандартным шагом 2,54 мм; □ плата имеет на борту 4 Мбайт Flash-памяти, а использование прошивки NodeMCU позволяет реализовать встроенную файловую систему spiffs; □ встроенные микрокнопки Reset и Flash для перезагрузки и перепрошивки мо- дуля; О изначально в платах установлена прошивка NodeMCU. Рис. 15.6. Плата NodeMCU
356 Глава 15 15.3. Прошивка NodeMCU Прошивка NodeMCU способна интерпретировать команды языка Lua — скрипто- вого языка программирования, разработанного подразделением Tecgraf Католиче- ского университета Рио-де-Жанейро. Интерпретатор этого языка распространяется свободно, с открытыми исходными текстами на языке Си. Прошивка NodeMCU, кроме интерпретирования команд языка Lua, может также создавать файлы во Flash-памяти модуля ESP8266 и выполнять их. Роль запускаю- щего файла прошивки (autorun) исполняет при этом файл init.lua. С помощью lua- команд можно: □ подключаться к точке доступа Wi-Fi; □ выступать в роли точки доступа Wi-Fi; □ уходить в глубокий сон для снижения энергопотребления (недоступно для АТ- команд); □ привязать lua-функцию к кнопке на GPIO16 (недоступно для АТ-команд в стан- дартной прошивке, частично доступно в некоторых кастомных); □ включать/выключать светодиод на GPIO16 (недоступно для АТ-команд в стан- дартной прошивке, доступно в некоторых кастомных); □ перенаправлять вывод— в примерах использования прошивки есть Telnet- сервер (недоступно для АТ-команд); □ создавать, записывать, читать, выполнять, искать, удалять, выводить списком файлы Flash-памяти (недоступно для АТ-команд); □ в режиме startsmart автоматически находить открытую сеть Wi-Fi и подключать- ся к ней (недоступно для АТ-команд); □ выводить свой МАС-адрес (недоступно для АТ-команд в стандартной прошивке, доступно в некоторых кастомных); □ управлять пользовательским таймером (недоступно для АТ-команд); □ управлять таймером WatchDog (недоступно для АТ-команд в стандартной про- шивке, частично доступно в некоторых кастомных); □ управлять (запись, чтение, триггер) выводами GPIO1-GPIO5, GPIO10, GPIO12- GPIO15 (недоступно для АТ-команд); □ обеспечивать PWM (ШИМ) на выводах GPIO1-GPIO5, GPIO10, GPIO12- GPIO15 (недоступно для АТ-команд); □ использовать ТСРЛР-сокеты; □ обеспечивать режим веб-сервера; □ осуществлять адресацию, запись, чтение по шине 12С— (недоступно для АТ-команд); □ выполнять 10-битное преобразование АЦП на выводе TOUT (недоступно для АТ-команд).
WhFi-модуль ESP8266 3&7_ Чтобы воспользоваться прошивкой NodeMCU, надо скачать ее последнюю версию с сайта: https://github.com/nodemcu/nodemcu-firmware/tree/master/pre_build и прошить ее на плату, например, с помощью утилиты ESP8266 Flasher (рис. 15.7), которую можно скачать со страницы: http://esp8266.ru/downloads/esp8266-utils/ #wpfb-cat-3. Рис. 15.7. Прошивка модуля программой esp8266_flasher_win Затем со страницы http://esp8266.ru/esplorer-ide-esp8266 скачиваем комплект средств разработки (SDK) и запускаем ESPlorer (рис. 15.8). Средство ESPlorer отличается от других программ для ESP8266 тем, что: □ работает на множестве платформ; □ поддерживает несколько открытых файлов; □ обеспечивает подсветку кода языков Lua и Python; □ имеет режимы Undo/Redo; □ поддерживает цветовые темы редакторов: dark, Eclipse, ШЕА, Visual Studio; □ осуществляет автозавершение кода по нажатию комбинации клавиш <Ctrl>+ +<Space>; □ обеспечивает «умную» отправку файлов с ожиданием ответа; □ поддерживает несколько прошивок одновременно. Как уже было отмечено, обеспечивающий autorun скрипт init.lua автоматически стартует при перезагрузке. Создадим этот скрипт и внесем в него код для автома- тического подключения модуля в качестве клиента к беспроводной сети (лис- тинг 15.1), а для модуля установим режим client+ap.
358 Глава 15 Рис. 15.8. Окно программы ESPIorer wifi.setmode(3) print(f set mode=STATION (mode=f,wifi.getmode(), ')f) print(f MAC=f,wi fi.sta.getmac()) print('set wifi1) wifi config start wifi. sta. config ("dlirikdap", "") wifi config end Загрузим скрипт в модуль, нажав кнопку Save to ESP (см. рис. .15.8), переза- грузим модуль и убедимся, что он подключен в качестве клиента к беспроводной сети. 15.3.1. Запуск веб-сервера Теперь напишем скрипт создания прЪстейшего веб-сервера, чтобы при обращении к модулю по HTTP с него выдавалась информация. Создадим для этого файл server! .lua и запишем в него код, представленный в листинге 15.2.
WhFi-модуль ESP8266 359 port = 80 srv=net. createServer (net. TCP) srv: listen (port, function(conn) conn:send("HTTP/1.1 200 OK\nContent-Type: text/html\nRefresh: 5\n\n" .. "<!DOCTYPE HTML>" ., "<html><body>lf .. "<b>ESP8266</b></br>" .. "Node ChipID : " .. node.chipid() .. *'<br>" .. "Node MAC : " .. wifi.sta.getmacO .. "<br>" .. "Node Heap : " .. node.heapO .. "<br>" .. "Timer Ticks : " .. tmr.now() .. "<br>" .. "</htmlx/body>") conn:on("sent"ffunction(conn) conn:close() end) end Сохраним файл serveri.lua в модуле и запустим. Внимание! Для запуска сервера при загрузке модуля необходимо в конце нашего autorun-файла init.lua добавить строку: dofile(serverI.lua) А для проверки работы сервера подключимся к точке доступа модуля и наберем в браузере ее адрес: http://192.168.4.1 (рис. 15.9). ESP8266 Node ChipID: 10289131 . Node MAC: 18-FE-34-9C-FF-EB Node Heap: 17600 Timer Ticks: 461355948 Рис. 15.9. Обращение к серверу на ESP8266 15.3.2. Подключение к ESP8266 модулей датчиков средствами языка Lua Важный момент — в прошивке NodeMCU присутствуют модули датчиков, которые можно подключать к скриптам командой require о. Количество таких модулей по- стоянно увеличивается, и они доступны для просмотра и закачки на странице: https://github.com/nodemcu/nodemcu-firmware/tree/master/lua_modules.
360 Глава 15 В листинге 15.3 приведен пример скрипта для подключения модуля датчика темпе- ратуры DS18B20, получения и вывода его значений. — подключение модуля t = require(ndsl8b20") — GPIO карта модуля ESP-01 gpioO = 3 gpio2 = 4 t.setup(gpioO) addrs = t.addrs() if (addrs ~= nil) then print("Total DS18B20 sensors: "..table.getn(addrs); end — чтение температуры print("Temperature: "..t.read().."f C") — освободить память после использования t = nil dsl8b20 = nil package.loaded[ndsl8b20"]«nil Результат выполнения этого скрипта при подключении датчика температуры к вы- воду GPIO0 показан на рис. 15.10. Рис. 15.10. Получение и вывод значений датчика температуры DS18B20 с помощью модуля ESP8266
Wi-Fi-модуль ESP8266 361_ 15.4. Arduino IDE для ESP8266 Рассмотрим еще один способ программирования ESP8266 — из среды Arduino IDE. Для тех, кто знаком с программированием Arduino, такой способ работы очень понравится. Arduino IDE для ESP8266 позволяет создавать прошивки и прошивать их в ESP8266 точно так же, как вы это делаете с Arduino. К тому же, большая часть библиотек для Arduino, не использующих внутренние порты и прочие ее аппарат- ные возможности, после небольшой доработки отлично работают и на ESP- модулях. В настоящее время уже достаточно много библиотек адаптировано для использования с ESP8266. Чтобы установить Arduino IDE для ESP8266, сначала необходимо с официального сайта Arduino скачать Arduino IDE версии не ниже 1.6.5. Далее запускаем Arduino IDE, выбираем пункт меню Файл | Настройки, в поле Additional Boards Manager URLs ВВОДИМ: http://arduino.esp8266.com/stable/package_esp8266com_index.json И нажимаем кнопку ОК (рис. 15.11). I ' :Ъ*ЛМГЪ СЛЦХ<:бнс:^ Ш^Ъ\ f-Z\.J}f:b I'~- pf 'l-^ Рис. 15.11. Добавление в поле Additional Boards Manager URLs адреса для скачивания Arduino IDE для ESP8266 Затем выбираем пункт меню Инструменты | Плата | Boards Manager и ищем в списке плату ESP8266. Выбираем эту плату, а также ее версию и нажимаем кноп- ку Install (рис. 15.12)— запустится процесс скачивания и установки Arduino IDE для ESP8266 (рис. 15.13), который завершится выводом соответствующего сообще- ния (рис. 15.14), а в списке плат, открываемом по команде меню Инструменты | Плата, появятся платы ESP8266 (рис. 15.15).
362 Глава 15 Рис. 15.12. Выбор платы ESP8266 в окне Boards Manager Ш»;ШШ'1^№Щ|9§^^ Рис. 15.13. Процесс скачивания и установки Arduino IDE для ESP8266
Wi-Fi-модуль ESP8266 363 Рис. 15.14. Arduino IDE для ESP8266 установлена Рис. 15.15. Выбор плат ESP8266 в Arduino IDE для ESP8266
364 Глава 15 15.5. Подключение модулей ESP8266 к сети Интернет по Wi-Fi Чтобы модуль ESP8288 мог выходить в Интернет, необходимо подключить его по Wi-Fi к точке доступа, имеющей выход в Интернет. В составе Arduino IDE для ESP8266 имеется библиотека Wi-Fi ESP8266, очень схожая по функциям с библио- текой для обычного шилда Wi-Fi. Создадим скетч для подключения модуля ESP8266 к точке доступа Wi-Fi и отправ- ки данных в сервис data.sparkfun.com (листинг 15.4). Измените только в нем на свои следующие данные для подключения к точке доступа, а также и в сервисе data.sparkfim.com: const char* ssid = "my_j>oint"; const char* password « " myjpoint pass"; const char* host = "data.sparkfun.com"; const char* streamld - " "; const char* privateKey = " "; #include <ESP8266WiFi.h> const char* ssid = "myjpoint "; const char* password = "myjpoint pass "; const char* host = "data.sparkfun.com"; const char* streamld = " const char* privateKey = " void setup() { Serial.begin(115200); delay(10000); // подсоединение к точке доступа Wi-Fi Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(".");
Wi-Fi-модуль ESP8266 365 Serial, println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.locallP()); float value = 0; void loop () { delay(lOOOO) ; Serial.print("connecting to "); Serial.println(host); // создаем TCP-соединение WiFiClient clients- const int httpPort = 80; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); return; // создаем строку URL String url = "/input/"; url += streamld; url += "?private_key="; url += privateKey; url += "&battery="; value=3.3*analogRead(A0)/1024; url += valued- Serial .print("Requesting URL: "); Serial.println(url); // отправить данные на сервер client.print(String("GET ") + url + " HTTP/1.l\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); delay(10); // ответ сервера while(client.available()){ String line = client.readStringUntil(f\rf); Serial.print(line); } Serial.println(); Serial.println("closing connection");
366 Глава 15 Электронный архив Скетч, соответствующий листингу 15.4, можно найти в файле esp8266_scetches\J5\_15_O4.ino сопровождающего книгу электронного архива (см. приложение). Загрузив скетч на плату, запускаем монитор последовательного порта и наблюдаем процесс отправки данных с аналогового вывода АО в сервис data.sparkfun.com (рис. 15.16) каждые 10 секунд. rl d&M Ш1 Н> $м с|ЪГ д ";"<& сйыд'ц1пфыщ b х„ф1;1{1хуоа rdto # дг| dn ф#Дтпоп $ВДД fc og Connecting to MacBoolc-Pro-Victor WiFi connected IP address: 192.168.2.19 connecting to data.sparIcfun.com Requesting URL: / input/9blira53N68cI&0^JgK?privateJC€y»tt^^ HTTP/1.1 200 OK Access-Control-Allow-Origin: * Access-Control-Allow-Hethods: GET, POST, DELETE Acce s a-Cant rol-Al low-Headers: X-Requested-Hith, Phant;-Private*-Key Content-Type: text/plain X-Rate-Limit-Limit: 300 X-Rate-Limit-Renaming: 294 X-Rate-Limit-Reset: 1499763422.428 Date: Ttie, 11 Jul 2017 08:46:12 GHI Connection: close Transfer-Encoding: chunked Set-Cookie: SERVERID»; Expires*Thu, Ol-Jan-1970 00:QQ:01 GHI; path»/ Cache-control: private ответ сервера Рис. 15.16. Отображение в мониторе последовательного порта процесса отправки данных в сервис data.sparkfun.com 15.6. Метеостанция на ESP8266 Создадим на модуле ES8266 домашнюю метеостанцию. Мы воспользуемся при этом отладочной платой NodeMCU. В метеостанции будут задействованы всего два датчика: цифровой датчик температуры DS18B20 и датчик влажности DHT22, который, в отличие от самого популярного датчика влажности DHT11, измеряет весь диапазон относительной влажности воздуха (от 0 до 100%) и работает при отрицательных температурах (от -40 до 80 °С).
Wi-Fi-модуль ESP8266 367^ 15.6.1. Подключение датчика температуры DS18B20 Для подключения к модулю NodeMCU ESP8266 датчика температуры DS18B20 вывод 1-Wire датчика необходимо «подтянуть» к питанию резистором номиналом 4,7кОм(рис. 15.17). Рис. 15.17. Схема подключения датчика температуры DS18B20 к плате NodeMCU ESP8266 Считывание данных датчика DS18B20 мы будем осуществлять с помощью библио- теки One Wire, адаптированной для ESP8266 (должны быть внесены соответствую- щие изменения в файл OneWire.h). Содержимое скетча представлено в листин- ге 15.5. // константы tdefine DSD18B20PIN 5 // пин подключения контакта DATA (Dl, GPIO5) tdefine INTERVAL_GET_DATA 2000 // интервала измерений, мс // подключение библиотеки // http: //www.pjrc.com/teensy/td_libs_OneWire.htial #include <OneWire.h> // создание экземпляра OneWire OneWire ds(DSD18B20PIN); // переменная для интервала измерений - ' unsigned long millis_intl=0; void setup(void) { // запуск последовательного порта Serial.begin(9600);
368 Глава 15 void loop() { if (millis ()-millis_intl >= INTERVAL_GET_DATA) { // получение данных с DS18B20 float temp = get_data_dsl8b20(); // вывод в монитор последовательного порта if(temp<100) { Serial.print("temp=");Serial.println(temp); } // старт интервала отсчета millis_intl=millis(); // старт интервала отсчета millis_intl=millis(); float get_data_dsl8b20(void) { byte i; byte present = 0; byte type_s; byte data[12]; byte addr[8]; float fTemp; if ( !ds.search(addr)) { Serial.println("No more addresses.") Serial.println(); ds.reset_search(); delay(250); return 999; 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 999; } Serial.println(); // the first ROM byte indicates which chip switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); // or old DS1820
Wi-Fi-модуль ESP8266 369 type_s = 1; break; case 0x28: Serial, printing Chip = DS18B20"); type_s = 0; break; case 0x22: Serial, printing1 Chip = DS1822"); type_s = 0; break; default: Serial.println("Device is not a DS18x20 family device."); return 999; ds.reset(); ds.select(addr); // запустить конвертацию температуры датчиком ds.write(0x44, 1); delay(lOOO); // ждем 750 мс present = ds.reset(); ds.select(addr); ds.write(OxBE); // считываем ОЗУ датчика for ( i = 0; i < 9; i++) { data[i] = ds.read(); Serial.print(data[i], HEX); Serial.print(" "); } // перевод полученных данных в значение температуры intl6_t raw = (data[l] « 8) | data[0]; if (type_s) { raw = raw « 3; if (data[7] == 0x10) { raw = (raw & OxFFFO) + 12 - data[6]; } } else { byte cfg = (data[4] & 0x60); if (cfg = 0x00) raw = raw & -7; else if (cfg == 0x20) raw = raw & -3; else if (cfg == 0x40) raw = raw & -1; } fTemp = (float)raw / 16.0; return fTemp;
370 Глава 15 Электронный архив Скетч, соответствующий листингу 15.5, можно найти в файле esp8266_scetches\_15\_15J)5.ino сопровождающего книгу электронного архива (см. приложение). Загрузим этот скетч в модуль NodeMCU ESP8266, откроем монитор последова- тельного порта и увидим в нем вывод данных, получаемых с датчика DS18B20 (рис. 15.18). *6В 1 4В 46 7F FF С 10 FB tasrap«22.69 No more addresses» ROM * 28 FF 17 8E 73 16 5 DB Chip * DS18B20 6Б 1 4Б 46 7F FF С 10 FB ъешр~22.69 No шоге addresses. ROM - 28 FF 17 8E 73 16 5 DB Chip = DS18B20 6B 1 4B 46 7F FF С 10 FB terop=22.69 No sore addresses. ROM - 28 FF 17 8E 73 16 5 DB Chip - DS18B20 6B 1 4B 46 7F FF С 1Q FB teaap-22.69 No more addresses. ROM » 28 FF 17 8E 73 16 5 DB Chip » DS18B20 6B 1 4B 46 7F FF С 10 FB temp=22.69 No more addresses. Рис. 15.18. Вывод данных датчика температуры DS18B20 в монитор последовательного порта 15.6.2. Подключение датчика влажности DHT22 Схема подключения к модулю NodeMCU ESP8266 датчика влажности DHT22 представлена на рис. 15.19. Для считывания данных датчика DTH22 с помощью ESP8266 существует готовая библиотека DHT. Заметим, что эта библиотека предназначена именно для ESP8266, библиотека для Arduino не подходит. Содержимое скетча представлено в листин- ге 15.6.
Wi-Fi-модуль ESP8266 371 Рис. 15.19. Схема подключения датчика влажности DHT22 к плате NodeMCU ESP8266 // подключение библиотеки DTH tinclude "DHT.h" // константы tdefine DHTPIN 4 // пин (D2) подключения контакта DATA tdefine DHTTYPE DHT22 // датчик DHT 22 tdefine INTERVAL_GET_DATA 2000 // интервал измерений, мс // создание экземпляра объекта DHT DHT dht(DHTPIN, DHTTYPE); // переменная для интервала измерений unsigned long millis intl=0; void setup() { Serial.begin(9600); dht.begin(); // запуск последовательного порта // запуск DHT void loop () { if (millis ()-millis_intl >- INTERVAL_GETJDATA) { // получение данных с DHT22 int humidity = get_data_humidity(); // вьшод в монитор последовательного порта Serial.print (^humidity**11); Serial.printIn(humidity); // запуск отсчета интервала millis intl=millis();
372 Глава 15 int get_data_humidity () { int h = dht.readHumidity(); return h; Электронный архив Скетч, соответствующий листингу 15.6, можно найти в файле esp8266_scetches\J5\_15_O6.ino сопровождающего книгу электронного архива (см. приложение). Загрузим этот скетч в модуль NodeMCU ESP8266, откроем монитор последова- тельного порта и увидим вывод данных, получаемых с датчика DHT22 (рис. 15.20). '..:.; : ' " \ huiBidity*55 humidity=46 huiaidit;Y=58 humidiry=€l huroidity*62 humidity=62 humidit:y=61 hum.dit:y=61 humidity=62 humxdity=61 humidity=€l humidity=60 ■ 9500 Ыт Рис. 15.20. Вывод данных датчика влажности DHT22 в монитор последовательного порта 15.7. Отправка данных метеостанции в сервис ThingSpeak Теперь организуем отправку данных из метеостанции в сервис ThingSpeak. Для этого в сервисе ThingSpeak (https://thingspeak.com) создадим новый канал Meteo_ESP8266 (рис. 15.21). Для данных температуры и влажности в канале создадим два поля (рис. 15.22). Для отправки и записи данных в канал Meteo_ESP8266 необходимо знать ID канала и его API Key (рис. 15.23).
Wi-Fi-модуль ESP8266 373 Рис. 15.21. Создание нового канала Meteo_ESP8266 в сервисе ThingSpeak Рис. 15.22. Поля для записи данных в канал Meteo_ESP8266
374 Глава 15 Рис. 15.23. ID и API Key канала Meteo_ESP8266 Теперь загрузим на плату NodeMCU ESP8266 скетч из листинга 15.7. В нем необ- ходимо предварительно заменить данные SSID и пароля для вашей точки доступа Wi-Fi: // Wi-Fi Settings // wireless network name (SSID) const char* ssid = »************.». // Wi-Fi network password const char* password = »*********»; А также данные для своего канала на ThingSpeak: // ThingSpeak Settings const int channellD = 319811; // write API key for your ThingSpeak Channel String writeAPIKey = "CB09mVF9ERI9CCT"; // константы tdefine DSD18B20PIN 5 // пин подключения контакта DATA (Dl, GPIO5) tdefine DHTPIN 4 // пин подключения контакта DATA #define DHTTYPE DHT11 // датчик DHT 22 // подключение библиотеки // http://www.pjrc.com/teensy/td_libs_OneWire.html #include <OneWire.h> // создание экземпляра OneWire OneWire ds(DSD18B20PIN);
WhFhModynb ESP8266 375^ I/ подключение библиотеки DHT iinclude "DHT.h" // создание экземпляра объекта DHT DHT dht(DHTPIN,DHTTYPE) ; // подключение библиотеки Wi-Fi iinclude <ESP8266WiFi.h> // Wi-Fi Settings // wireless network name (SSID) const char* ssid = "MacBook-Pro-Victor"; // Wi-Fi network password const char* password = "19101966"; WiFiClient client; // ThingSpeak Settings const int channellD = 319811; String writeAPIKey = "CB09FMVF9ERI9CCT"; // write API key for your ThingSpeak Channel const char* server = "api.thingspeak.com"; const int postinglnterval = 20 * 1000; // post data every 20 seconds void setup(void) { // запуск последовательного порта Serial.begin(115200); WiFi.begin(ssidf password); while (WiFi.status() != WL_CONNECTED) { delay(500); } Serial.printIn(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.locallP()); void loopO { if (client.connect(server, 80)) { // Construct API request body String body = "field2="; int humidity = get_data_humidity(); body += String(humidity); float temp = get_data_dsl8b20(); if(temp<999) { body += "&fieldl="; body += String(temp);
376 Глава 15 client.print("POST /update HTTP/1.l\n"); client.print("Host: api.thingspeak.com\n"); client.print("Connection: close\n"); client.print("X-THINGSPEAKAPIKEY: " + writeAPIKey + "\n"); client.print("Content-Type: application/x-www-form-urlencoded\n"); client.print("Content-Length: "); client.print(body.length()); client.print("\n\n"); client.print(body); client.print("\n\n"); client.stop(); // wait and then post again delay(postinglnterval); float get_data_dsl8b20 (void) { byte i; byte present - 0; byte type_s; byte data[12]; byte addr[8]; float fTemp; if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.printlnO ; ds.reset_search(); delay(250); return 999; Serial.print("ROM ="); for( i - 0; i < 8; i++) { Serial.writeC '); Serial.print(addr[i], HEX); if (OneWire::crc8(addr, 7) !- addr[7]) { Serial.println("CRC is not valid!"); return 999; } Serial.printlnO ;
Wi-Fi-модуль ESP8266 377^ 11 the first ROM byte indicates which chip switch (addr[0]) { case 0x10: Serial.printlnC Chip - DS18S20"); // or old DS1820 type_s = 1; break; case 0x28: Serial.println(" Chip = DS18B20"); type_s = 0; break; case 0x22: Serial.printlnC1 Chip - DS1822") ; type_s = 0; break; default: Serial.printIn("Device is not a DS18x20 family device."); return 999; ds.reset (); ds.select(addr); // запустить конвертацию температуры датчиком ds.write(0x44, 1); delay(lOOO); // ждем 750 мс present = ds.reset(); ds.select(addr); ds.write(OxBE); // считываем ОЗУ датчика for ( i - 0; i < 9; i++) { data[i] = ds.readO; Serial.print(data[i], HEX); Serial.print(" "); } // перевод полученных данных в значение температуры intl6__t raw = (data[l] « 8) | data[0]; if (type^s) { raw = raw « 3; if (data[7] — 0x10) { raw = (raw & OxFFFO) + 12 - data[6]; } } else { byte cfg - (data[4] & 0x60); if (cfg — 0x00) raw = raw & ~7; else if (cfg — 0x20) raw = raw & -3; else if (cfg = 0x40) raw = raw & -1; } fTemp = (float)raw / 16.0;
378 Глава 15 return fTemp; int get_data_humidity () { int h = dht.readHumidity(); return h; Электронный архив Скетч, соответствующий листингу 15.7, можно найти в файле esp8266_scetches\_15\_i5_O7.ino сопровождающего книгу электронного архива (см. приложение). После загрузки скетча на плату начнется отправка данных температуры и влаж- ности воздуха в сервис ThingSpeak. Через некоторое время мы увидим в канале Meteo_ESP8266 в виде графиков данные, отправленные с платы NodeMCU (рис. 15.24). Рис. 15.24. Графики данных температуры и влажности на канале Meteo_ESP8266 сервиса ThingSpeak 15.8. Протокол MQTT — простой протокол для Интернета вещей Устройства в сетях IoT взаимодействуют друг с другом посредством различных интерфейсов и протоколов передачи данных. В предыдущих главах мы использова- ли протокол HTTP. В этой главе будет рассмотрен еще один протокол — наиболее популярный и одновременно простой протокол обмена для устройств Интернета вещей — MQTT (Message Queue Telemetry Transport). Основные особенности протокола MQTT: □ асинхронный протокол; □ компактные сообщения; □ работа в условиях нестабильной связи на линии передачи данных;
Wi-Fi-модуль ESP8266 379 □ поддержка нескольких уровней качества обслуживания (QoS); □ легкая интеграция новых устройств. Обмен сообщениями по протоколу MQTT осуществляется между клиентом (client), который может быть издателем или подписчиком (publisher/subscriber) сообщений, и брокером (broker) сообщений (например, Mosquitto MQTT). Издатель и подпис- чик не передают друг другу сообщения напрямую, не устанавливают прямой кон- такт и могут не знать о существовании друг друга. Издатель отправляет данные на MQTT-брокер, указывая в сообщении определенную тему— топик (topic). Под- писчики могут получать разные данные от множества издателей в зависимости от подписки на соответствующие топики. Топики представляют собой символы с кодировкой UTF-8. Иерархическая структу- ра топиков имеет формат «дерева», что упрощает их организацию и доступ к дан- ным. Топики состоят из одного или нескольких уровней, которые разделены между собой символом /: /home/living /living-rooml/temperature Устройства MQTT используют определенные типы сообщений для взаимодействия с брокером — далее представлены основные: □ Connect — установить соединение с брокером; □ Disconnect — разорвать соединение с брокером; □ Publish — опубликовать данные в топик на брокере; □ Subscribe — подписаться на топик на брокере; □ Unsubscribe — отписаться от топика. Схема простого взаимодействия между подписчиком, издателем и брокером пока- зана на рис. 15.25. Издатель -1. подключение- 7. подтверждение подключения Брокер -1. подключение- 2. подтверждение подключения 3. подписка- ■. публикация- Подписчик . публикация- Рис. 15.25. Схема простого взаимодействия по протоколу MQTT 15.9. Использование MQTT-сервера CloudMQTT Как уже было отмечено, отправка и получение сообщений при использовании про- токола MQTT осуществляется через специальный сервер — брокер, поэтому нам понадобится обзавестись в сети Интернет публичным брокером. В качестве броке- ра мы выберем сервис CloudMQTT (https://www.cloudmqtt.com/)— перейдите по этому адресу и создайте бесплатный аккаунт, нажав кнопку Control Panel
380 Глава 15 -штшмт Рис. 15.26. Регистрация в сервисе CloudMQTT (рис. 15.26). Для регистрации вам необходимо будет ввести адрес электронной поч- ты (в качестве логина) и пароль. Выполнив регистрацию, мы попадаем в панель управления, где и создаем брокер: вводим название, выбираем датацентр (Европа или США), тарифный план — бес- платный (Cute Cat) и сохраняем введенные данные, нажав кнопку Create (рис. 15.27). Брокеров можно создать несколько. . Рис. 15.27. Создание брокера в сервисе CloudMQTT
Wi-Fi-модуль ESP8266 381 CioudMQTT CloudMQl T instances Рис. 15.28. Переход к настройкам выбранного брокера На следующем шаге нажимаем в открывшемся окне кнопку Details (рис. 15.28) и попадаем в настройки (рис. 15.29). Нам необходимы следующие: П имя хоста: ml3.cloudmqtt.com; □ порт 18274 (для скетча Arduino ШЕ); П WebSockets порт 38274 (для мобильного приложения). CloudMQTT Console instance info MariageJJ«€fs ACLs Рис. 15.29. Настройки выбранного брокера
382 Глава 15 Здесь же находится менеджер пользователей (Manage Users), где можно создать пользователей для доступа к данным брокера и в следующем окне (рис. 15.30) на- значить им права (Read или Write). В поле Topic необходимо для всех топиков ввести #. Рис. 15.30. Создание пользователей для доступа к брокеру 15.10. Мобильное приложение loT Manager IoT Manager— это мобильное приложение для телефонов и планшетов, совме- щающее в себе табло для отображения данных с датчиков и пульт для управления исполнительными устройствами. Приложение это существует в версиях как для Android, так и для iOS, скачать которые можно в Google Маркет и AppStore соот- ветственно. IoT Manager предоставляет возможность очень гибкой настройки вид- жетов с помощью HTML5+CSS, причем все настройки производятся в устройствах, а не в приложении. Топики отправляются в JSON-формате и содержат в себе имена заголовков, значения и стили отображения. Итак, скачайте и установите мобильное приложение IoTManager и запустите его. Для настройки приложения выберите в его меню опцию Settings (рис. 15.31) и в открывшуюся форму внесите данные своего брокера (рис. 15.32): □ MQTT hostname — ml3. cloudmqtt. com; □ MQTT Websocket port — 38274 (см. рис. 15.29);
Wi-Fi-модуль ESP8266 383 Рис. 15.31. Основное меню приложения IoTManager Рис. 15.32. Окно настроек брокера
384 Глава 15 П MQTTusername — nodemcui; □ MQTT password. Теперь выберите в меню приложения опцию Dashboard, и вы увидите установлен- ное соединение (рис. 1533). Надпись No data не должна вас смущать— данные в топики еще не передавались. Рис. 15.33. Успешное подключение к брокеру 15.11. Отправка данных брокеру CloudMQTT для приложения loT Manager (тестовый пример) Для проверки работы брокера CloudMQTT загрузим на плату NodeMCU тестовый пример, который можно скачать со страницы: https://gist.github.com/4refr0nt/ 7d0ac08a5e530957b311. Этот скетч также находится в файле esp8266_scetches\ _15\_15J)8.ino сопровождающего книгу электронного архива (см. приложение). В скетч следует внести изменения: свои данные для точки доступа Wi-Fi, а также данные своего брокера: const char *ssid = "MacBook-Pro-Victor"; const char *pass = "*******•»; String mqttServerName = "ml3.cloudmqtt.com"; int mqttport = 18274; String mqttuser = "nodemcui"; String mqttpass = "******"; Кроме того, необходимо установить в Arduino IDE библиотеку PubSubClient.
Wi-Fi-модуль ESP8266 385 iPublish new status for /IoTaianager/devQ2-bedroQm/lightl, value: {"status" :"0"} publish new status for /IoTJaanager/devQ2~bedrooai/light2f value: {"status":"1"} publish new status for /IoTroanager/devQ2~be<iroom/ADC, value: {"status":"3я} publish new status for /IoTmaiiager/dev02-bedroom/light4P value: {"status":"!"} Publish new status for /IoTBanager/dev02-bedro0iR/red, value: {"status":"Q"} publish new status for /IoTaaanager/devQ2-bedrooia/greeni, value: {"status":"0"} publish new status for /IoTmanager/devG2-bedroom/blue, value: {"status":"Q"} Subscribe: Success |5et data from subscribed topic /IoTmanager «> HELLO pet data frost subscribed topic /IoTmanager »> devO2-bedroom publish config: Success ({"id":"0","page* Publish config: Success ({"id" Publish config: Success ({"id" publish config: Success ({"id" "page' "page' "page' "page1 "page' "page' "page* :"Bedroom","descr":"Bedroom light-0","widget":"toggle","topic":"/It :"Bedroom", "descr":"Bedroom light-1", "widget":"toggle", "topic": "/I< :"Bedroom", "descr*:"Bedroom light-2", "widget":"toggle", "topic":"/I< :"Bedroom","descr":"ADC","widget":"small-badge","topic":"/IoTmanagt :"BedrooiB1?, "descr": "KEY", "widget": "power-button", "topic" :"/IoTmana< : "Bedroom", "descr": "Bedroom RED", "widget": "range", "topic":"/IoTman* : "Bedroom", "descr":"Bedroom GREEN", "widget":"range", "topic": "/IoTiw : "Bedroom", "descr": "Bedroom BLUE", "widget" publish config: Success ({"id" Publish config: Success ({"id" Publish config: Success ({"id" Publish config: Success ({"id" Publish config: Success Publish new status for /IoTjBanager/devQ2-bedroom/lightQ, value: {"status":"Q"} Publish new status for /IoTmanager/dev02-bedrQ<offi/lightlr value: {"status" :"0"} Publish new status for /IoTmanager/dev02-bedraom/light2f value: {"status"*"1"} publish new status for /IoTmanager/dev02-bedroom/Alx:, value: {"status":"3"} Publish new status for /IoTmanager/dev02-bedrooJB/light4, value: {"status":"1"} Publish new status for /IoTmainager/dev02-bedroom/red, value: {"status":"0"} Publish new status for /IoIiaanager/devQ2-bedrcM3m/greenlf value: {"status":"0"} Publish new status for /IoTmanager/devQ2-bedroom/blue, value: {"status":"0"} Set data from subscribed topic /loTmanager/ids «> 3915c€ac-85b3-4ee0-afa8-3a5dc524a94c range","topic":"/IoTmai Рис. 15.34. Отправка и получение данных с платы NodeMCU Итак, загружаем скетч в плату NodeMCU и открываем монитор последовательного порта, где видим отправку данных брокеру с платы (рис. 15.34). Как только начнется отправка данных с платы NodeMCU брокеру, эти данные появятся в мобильном приложении IoT Manager (рис. 15.35). Мы можем также посмотреть и список тем, на которые подписано (subscribe) мо- бильное устройство (рис. 15.36). IoT Manager не только подписан на темы, но также выступает в роли publisher — публикует данные в темы. Это определяется значениями соответствующих слайде- ров и статусами их кнопок (см, рис. 15.35). Такие данные плата NodeMCU, подпи- санная в качестве subscriber на эти темы, может использовать для управления под- ключенными к ней устройствами.
386 Глава 15 Рис. 15.35. Получение данных с платы NodeMCU в мобильном приложении IoT Manager Рис. 15.36. Список тем (subscribe), на которые подписан IoT Manager
Wi-Fi-модуль ESP8266 387^ 15.12. Отправка данных метеостанции по MQTT в сервис CloudMQTT для приложения loT Manager Для отправки брокеру данных с метеостанции (от датчиков DHT22 и DS18B20) не- обходимо в скетч из предыдущего раздела внести некоторые правки. Прежде всего, устанавливаем количество виджетов для отображения по количеству датчиков: const int nWidgets = 2; String stat [nWidgets]; String sTopic '[nWidgets]; String color [nWidgets]; String style [nWidgets]; String badge [nWidgets]; String widget [nWidgets]; String descr [nWidgets]; String page [nWidgets]; String thing__config [nWidgets]; String id [nWidgets]; int pin [nWidgets]; float defaultVal [nWidgets]; bool inverted [nWidgets]; Далее в процедуре initvar о прописываем настройки для виджетов: для параметра раде[] (страница в lot Manager для отображения виджетов) устанавливаем SensorsNodemcu, параметр pin [ ] нам не нужен, т. к. данные датчиков мы будем получать программно, а не с пинов, тип для defauitval [ ] назначаем float. id [0] = "0"; page [0] = "SensorsNodemcu"; descr [0] = "DHT22"; widget[0] = "small-badge"; //pin [0] = A0; sTopic[0] = prefix + "/" + devicelD + "/DHT22"; badge [0] - "\"badge\":\"badge-calm\""; style [0] - "\"style\":\"font-size:150%;\""; id [1] = "1"; page [1] = " SensorsNodemcu "; descr [1] = "DS18b20"; widget[1] = "small-badge"; //pin [1] » A0; sTopic[l] = prefix + "/" + devicelD + "/DS18b20"; badge [1] = "\"badge\":\"badge-calm\""; style [1] = "\"style\":\"font-size:150%;\""; Параметры конфигурации отображения датчиков, которые необходимо направить брокеру, должны выглядеть так:
388 Глава 15 thing_config[0] = "{\"id\":\"fl + id[O] + "\"Л"раде\" :\"" + page[O]+"\",\"descr\":\"" + descr{0] + "\", \"widget\":\ff" + widget [0] + "\",\lftopic\":\"fl + sTopic[0] + "\"," + badge [0] + "," + style [0] + "}"; // DHT22 thing_config[l] = "{\"id\":\ffff + id[l] + "\",\"page\":\llff + page[l]+"\",\"descr\":\"" + descr[l] + "\",\"widget\":\"" + widget [1] + "\",\"topic\":\fMI + sTopic[l] + "\"," + badge [1] + "," + style [1] + "}"; // dsl8b20 Вносим изменения в функцию callback: void callback(const MQTT::Publish& sub) { Serial.print("Get data from subscribed topic "); Serial.print(sub.topic()); Serial.print(" => "); Serial.println(sub.payload_string()); if (sub.topic() = sTopic[0] + "/control") { // DHT22 } else if (sub.topic() — sTopic[l] + "/control") { // DS18B20 display only } else if (sub.topic() = prefix) { if (sub.payload_string() == "HELLO") { pubConfig(); Данные отправляем каждые 10 сек: if (client.connected()) { newtime - millis (); if (newtime - oldtime > 10000) { // 10 sec float x - get_data_humidity(); val = "{\"status\":\"" + String(x)+ "\"}"; client.publish(sTopic[0] + "/status", val ); // widget 0 x = get_data_dsl8b20(); val = "{\"status\":\"lf + String (x)+ "\"}"; client.publish(sTopic[l] + "/status", val ); // widget 1 oldtime = newtime; } client.loop(); } Функции получения данных с датчика DHT22: getdata humidity (): float get_data_humidity() { float h - dht.readHumidityO; return h;
Wi-Fi-модуль ESP8266 389_ И с датчика температуры DS18B20: get_data_dsi8b20 (): float get_data_dsl8b20 (void) { byte i; byte present = 0; byte type_s; byte data[12]; byte addr[8]; float fTeinp; if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.printlnO ; ds.reset_search(); delay(250); return 999; Serial.print("ROM -"); for( i = 0; i < 8; i++) { Serial.writeC '); Serial.print(addr[i], HEX); if (OneWire::crc8(addr, 7) !=addr[7]) { Serial.printIn("CRC is not valid!"); . return 999; } Serial.println(); switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); // or old DS1820 type_s = 1; breaks- case 0x28: Serial.println(" 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 999;
390 Глава 15 ds.reset (); ds.select(addr); // запустить конвертацию температуры датчиком ds.write(0x44, 1); delay(lOOO); // ждем 750 мс present = ds.reset(); ds.select(addr); ds.write(OxBE); // считываем ОЗУ датчика for ( i - 0; i < 9; i++) { data[i] = ds.read(); Serial.print(data[i], HEX); Serial.print(" "); } // перевод полученных данных в значение температуры intl6__t raw = (data[l] « 8) | data[0]; if (type_s) { raw = raw «3; if (data[7] — 0x10) { raw = (raw & OxFFFO) + 12 - data[6]; } } else { byte cfg = (data[4] & 0x60); if (cfg — 0x00) raw = raw & -7; else if (cfg — 0x20) raw = raw & -3; else if (cfg == 0x40) raw = raw & -1; } fTemp = (float)raw / 16.0; return fTemp; Электронный архив Полный скетч, соответствующий всем сделанным изменениям, можно найти в файле esp8266__scetches\__15\_15_09.ino сопровождающего книгу электронного архива (см. при- ложение). Итак, скачиваем полный скетч и загружаем его в плату NodeMCU, открываем мо- нитор последовательного порта и видим отправку данных с датчиков (рис. 15.38). Одновременно данные отображаются и на смартфоне в приложении IoT Manager (рис. 15.39).
Wi-Fi-модуль ESP8266 391 id Да< & 1д с|ЦГ д >;"с& с 8„$1г<1;1*уоа Г d jb # gr! dM ф#Ьуодп 1Щ1 § од 1 о;ф>Ыд ЮТТ cliem; started. free heap = 368S0 tonnecting via KiFi to MacBook-Pro-Victor».. ?iFi connect: Success IP acidresa: 192.168.2.19 Connecting to MQTT server ».. Connect to MCTT server: Success publish config: Succes publish config: Success fablish config: Success ?ublish new s Publish new stat Subscribe: Success : Success s C{"id":wOw,wpage™:"SjaarthouseNodemcuw,"deacr":"DHT22","widget"^small-badge","topic":"! s ({"id":wl", "page":"SroarthouseNoderacu", "deacr":"BS18b2G"» "widget":"small-badge", "topic"| g: Success | tatus for /Io^Banager/SffiarthQuseNode2scu/DHT22, value: {"status":"0"} ! tatus for /IolSaan,ager/SiBarthQuse!lodeiscu/DS18b2Q, value: {"status";"0я} Рис. 15.37. Отправка данных в мониторе последовательного порта Arduino IDE DHT22 DS18b20 Брокер 0* 44.00 19.99 Рис. 15.38. Отображение данных на смартфоне в приложении loT Manager
392 Глава 15 15.13. Создание на модуле ESP8266 пульта для управления квадрокоптером AR.Drone 2.0 На основе модуля Wi-Fi ESP8266 и модуля GY-521 на микросхеме MPU6050 (гиро- скоп-акселерометр) можно сделать бюджетный блок управления квадрокоптером AR.Drone 2.O. Parrot AR.Drone (рис. 15.39) — это радиоуправляемый квадрокоптер, то есть верто- лет с четырьмя несущими винтами, размещенными на выносных диагональных балках. Сам AR.Drone работает под управлением операционной системы Linux, а в качестве пульта ДУ к квадрокоптеру может выступать практически любой сенсор- ный смартфон или планшет на Android или iOS. Дистанция устойчивого управле- ния квадрокоптером по Wi-Fi — от 25 до 100 метров и зависит от помещения и по- годных условий, если полеты происходят на улице. Рис. 15.39. Квадрокоптер AR.Drone 2.0 15.13.1. Подключение модуля ESP8266 ESP-07 к квадрокоптеру по Wi-Fi При включении AR.Drone создает точку доступа SSIS «ardrone_XX_XX». Подклю- чение осуществляется без пароля. Попробуем подключиться к точке доступа AR.Dron с помощью АТ-команд. Для этого подключим плату ESP к СОМ-порту компьютера через переходник UART-USB и подадим на нее питание 3,3 В. Откроем Arduino IDE, монитор последовательного порта и начнем отправлять на плату ESP8266 АТ-команды (рис. 15.40). Квадрокоптер при этом должен быть включен. 15.13.2. Удаленное программирование квадрокоптера AR.Drone через Wi-Fi Связь с квадрокоптером AR.Drone осуществляется с помощью АТ-команд. Коман- ды отправляются на AR.Drone как UDP- или TCP-пакеты. Один пакет UDP должен содержать, по крайней мере, одну полную команду или более. В случае если пакет
Wi-Fi-модуль ESP8266 ___^_ 393 AT получить список сетей ок RI+CHLAE +CWLAP: (3, -MacBook-Pro-Victor",-56,"28:cf :da:dd:71:4a", 11) ок ^ подключиться к сети Al+aWOkP-"ardrene2_r060602",яп ОК ^p вывести данные о подключении +OWAP:wardrone2 060602" Щшштшттшшттттттшшштштшштт OK ^ ОТКЛЮЧИТЬСЯ AT+CWQAP ^тшштшшшшшшшшшшшттт ок ^^ вывести данные о подключении по this fun ^*U ПОДКЛЮЧИТЬСЯ AT+OMAP-nardrone2_060602",t"1 ^шш^ш^тшшшшяя^ ок ^ вывести данные о подключении АТ-ЮШР* ^шшшшшшшттшшшштттшшт +CWJAP: ОК Рис. 15.40. Обмен данными с квадрокоптером AR.Drone 2.0 содержит более одной команды, то для разделения команд используется сим- вол ОхОА. Строки кодируются в виде 8-битовых символов ASCII. Максимальная длина команды составляет 1024 символов. Между командами должна быть предусмотре- на задержка 30 мс. Синтаксис команды: AT * [имя команды] = [порядковый номер команды в виде строки] [, аргумент 1, аргумент 2 ...] Список основных АТ-команд для управления AR.Drone: □ at*ref — используется для взлета, посадки, сброса и аварийной остановки; □ at*pcmd — команда управления движением AR.Drone; □ at*ftrim — на горизонтальной плоскости; □ at*config — настройка параметров AR.Drone; □ at*led — устанавливает LED-анимации на AR.Drone; □ at*anim — установка полетной анимации на AR.Drone; □ at*comwdg — команда сброса watchdog (посылаем ее в квадрокоптер постоянно).
394 Глава 15 Для связи используются следующие порты: □ порт 5556: UDP — отправка команд на AR.Drone; О порт 5554: UDP — получение пакетов данных от AR.Drone; □ порт 5555 — получение потока видеопакетов из AR.Drone; □ Порт 5559: TCP — пакеты для критически важных данных, которые не могут быть потеряны, как правило, для конфигурации. Внимание! Клиент отключается от UDP-порта через 2 секунды после отправки последней коман- ды — поэтому, при отсутствии необходимых команд, необходимо постоянно посылать ему команды at*comwdg. 15.13.3. Получение навигационных данных от квадрокоптера AR. Drone Получение навигационных данных от AR.Drone осуществляется через порт 5554 — UDP. Пакет навигационных данных в режиме demo имеет длину 500 байтов. В слу- чае, если что-либо идет не так, то AR.Drone может присылать пакет длиной 32 и 24 байта. Если пакет имеет длину 24 байта, это означает, что порт 5554 находится в режиме BOOTSTRAP, и необходимо заново подсоединиться к порту, чтобы пере- вести его режим demo. AR.Drone может передавать клиенту навигационные данные в двух формах: □ сокращенной (или demo) — размер 500 байтов; □ полной. Чтобы получать demo-данные, надо отправить на порт 5554 сначала четыре байта 0x01, 0x00, 0x00, 0x00, а затем на порт 5556 команду: AT*CONFIG="+(seq++)+",\"general:navdata_demo\",\"TRUE\" где seq — порядковый номер команды. Структура пакета навигационных данных выглядит так. В начале пакета присутст- вуют 4 именованные величины: □ заголовок пакета: 32 бита; □ флаги состояния вертолета: 32 бита; □ порядковый номер последней команды, переданной вертолету клиентом: 32 бита; □ vision flag: 32 бита. Далее следуют: □ Заголовок опции navdata: 20-23 бита; Опция navdata имеет следующие поля: • battery = 24 бита — заряд батареи в процентах; • pitch = 28 битов — угол наклона по продольной оси;
WhFi'MQdynb ESP8266 395 • roll = 32 бита — угол наклона относительно поперечной оси; • yaw = 36 битов — угол поворота относительно вертикальной оси; • altitude = 40 битов — высота; • vx = 44 бита — скорость по оси X; • vy = 48 битов — скорость по оси Y; • vz = 52 бита — скорость по оси Z. На время отладки подсоединим к плате ESP8266 дисплей Nokia 5110 (схема соеди- нений приведена на рис. 15.41) и будем выводить на него и в монитор последова- тельного порта часть навигационных данных. Рис. 15.41. Схема подсоединения к ESP8266 дисплея Nokia 5110 Содержимое скетча представлено в листинге 15.8. #include <SPI.h> #include <Adafruit_GFX.h> #include <Adafruit_PCD8544.h> // ESP8266 Software SPI (slower updates, more flexible pin options) // pin 14 - Serial clock out (SCLK) // pin 13 - Serial data out (DIN) // pin 12 - Data/Command select (D/C)
396 Глава 15 // pin 15 - LCD chip select (CS) // pin 4 - LCD reset (RST) Adafruit_PCD8544 display - Adafruit_PCD8544(14, 13, 12, 15, 4); #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <IPAddress.h> #include <WiFiUdp.h> #include <stdio.h> #include <inttypes.h> const char* ssid = lfardrone2__060602"; const int navPort - 5554; const int atPort - 5556; const IPAddress drone(192, 168, 1, 1); byte pos; unsigned int sequence; unsigned int lastNav; unsigned int lastPacket; WiFiUDP Udp; WiFiUDP AT; String sendBuffer; char incoming[1024]; void setup(void) { Serial.begin(115200); Serial.printIn(""); Serial.println("Starting"); // initialize the LCD display.begin(); display.setContrast(50); display.display(>; // show splashscreen delay(2000); display.clearDisplay(); // clears the screen and buffer display.setTextSize(1); display.setTextColor(BLACK); // Turn on the blacklight and print a message, display.setCursor(0,0); display.print("WiFi connect ..."); display.displayO ; pos = 0; sequence = 1; // Connect to WiFi network WiFi .mode (WIFI_STA) ; WiFi.begin(ssid);
Wi-Fi-модуль ESP8266 397_ II Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(200); } Serial.println("Connected!"); Serial.println(WiFi.locallPO); display.clearDisplayO; display.setCursor(0,0); display.print("OK"); delay(3000); display.setCursor(0,20); display.print(WiFi.locallPO); display.display(); // pinMode(pinButton,INPUT); // Udp.begin(navPort); //Open port for navdata Udp.flushO; AT.begin(atPort); AT.flushO; String configg = "AT*CONFIG="; configg += String(sequence); configg += "Л"general:navdata_demo\",\"TRUE\"\r"; while(Udp.parsePacket() ==0) { delay(10); Udp.beginPacket(drone, navPort); Udp.write(0x01); Udp.endPacketO ; delay(10); sendPacket(configg); } Serial.println("Starting main loop"); //delay(3000); void loop (void) { if(Udp.parsePacket()) { int len = Udp.read(incoming, 1024); Serial.print("length=");Serial.println(len); if (len < 30) return; incoming[len] = 0; Serial.print("header=");printParamData(0,4);Serial.println(); Serial.print("state*5");printParamData(4,4);Serial.println(); Serial.print("pitch=");printParamData(28,1);Serial.println(); Serial.print("roll=");printParamData(32,l);Serial.println(); Serial.print("yaw=");printParamData(36f1);Serial.println(); Serial.print("altitude=");printParamData(4 0,1);Serial.println();
398 Глава 15 Serial.print("battery^");printParamData(24,l);Serial.println(); Serial.print("vx=");printParamData(44,l);Serial.printlnO; Serial.print("vy=");printParamData(52,1);Serial.println(); Serial. println ("********************************************"); // печать параметров на дисплей printdatalcd(); } // отправка пакета для поддержания соединения if(millis() - lastPacket > 1000) { String tmr - "AT*CQMWDG="; tmr += String (sequence); sendPacket(tmr); Serial.print("send=")/Serial.printIn(tmr); // отправка в порт 5554 void sendPacket(String &string) { char sendChar[string.length()+1]; string.toCharArray(sendChar, string.length()+1); sendChar[string.length()] = f\rf; AT.beginPacket(drone, atPort); AT.write(sendChar); AT.endPacketO ; sequence++; lastPacket = millisO; } // печать данных в последовательный порт void printParamData(int offset,int count) { for(int i=count;i>0;i—) { Serial.print(incoming[offset+i-1],HEX);Serial.print(" "); // данные на экране led void printdatalcd() { // status display.clearDisplay(); display.setCursor(0,0); display.print(incoming[4],HEX);display.print(" "); display.print(incoming[5],HEX);display.print(" "); display.print(incoming[6],HEX);display.print(" "); di splay.print(incoming[7],HEX);display.print(" "); // battery display.setCursor(0,20); display.print(incoming[24],DEC); display.print("%"); // altitude h display.setCursor(0,40);
Wi-Fi-модуль ESP8266 399^ display.print(incoming[40],HEX);display.print(" "); // vx display.print(incoming[40],HEX);display.print(" "); // vy display.print(incoming[40],HEX);display.print(" "); // vz display.print(incoming[40],HEX);display.print(" "); display.display(); } Электронный архив Скетч, соответствующий листингу 15.8, можно найти в файле esp8266_scetches\J5\ J5_i0.ino сопровождающего книгу электронного архива (см. приложение). Connected! 192.168.1.2 Starting main loop length-500 headex-55 66 77 88 atate-F 80 4 DO pitch-0 roll-0 yaw-0 altitude-0 battery-51 vx-0 vy-0 length-24 length-500 headex»SS 66 77 88 state-F 80 4 DO picch-0 roll-0 yaw-0 altitude-0 battery-51 •vk-0 vy-0 length-500 header-55 66 77 88 state-F 80 4 DO pitch-0 roll-0 yaw-0 altitude-Q battery-51 vx-0 vy-0 length-500 header-SS 66 77 88 atate-F 80 4 DO pitch-0 roll-0 yaw-0 Рис. 15.42. Вывод навигационных данных в последовательный порт
400 Глава 15 Загружаем этот скетч на модуль ESP8266 и наблюдаем вывод навигационных дан- ных в последовательный порт (рис. 15.42) и на экран дисплея. 15.13.4. Отправка команд взлета и посадки Теперь добавим в наш проект взлет и посадку квадрокоптера командами с пульта. Для взлета необходимо отправить команду: AT*REF=[Sequence number ], 290718208<LF> А для посадки: AT*REF=[Sequence number ], 290717696<LF> Перед взлетом необходимо отправить команду для горизонтальной калибровки, иначе AR.Drone не сможет стабилизироваться при полете:. AT * FTRIM=[Sequence number ]<LF> Добавляем к нашей схеме кнопку (рис. 15.43). Рис. 15.43. Схема подсоединения к ESP8266 дисплея Nokia 5110 и кнопки Добавим в скетч из предыдущего раздела переменные для работы с кнопкой: int pinButton=5; int lastButtonsl=0; int currentButtonsl=0; boolean onLand=true;
Wi-Fi-модуль ESP8266 401_ А также процедуру борьбы с дребезгом: // проверка на дребезг int debounce(int last,int pinl) { int current = digitalRead(pinl); // Считать состояние кнопки if (last != current) // если изменилось... { delay(5); // ждем 5 мс current = digitalRead(pinl); // считываем состояние кнопки return current; // возвращаем состояние"кнопки И обработку нажатий кнопки: // проверка нажатия кнопки currentButtonsl = debounce(lastButtonsl, pinButton); if (lastButtonsl == 0 && currentButtonsl ==1) // если нажатие. { // изменить состояние реле onLand=!onLand; // вывести в порт Serial.print("onLand=");Serial.println(onLand); if(onLand==false) { // takeoff String tmr="AT*FTRIM="; tmr += String (sequence1); sendPacket(tmr); delay(50); tmr = "AT*REF="; tmr += String(sequence); tmr += ",290718208"; sendPacket(tmr); } else { // landing String tmr = "AT*REF="; tmr += String(sequence); tmr += ",290717696"; sendPacket(tmr); lastButtonsl = currentButtonsl; Электронный архив Полный скетч, соответствующий всем сделанным изменениям, можно найти в файле esp8266_scetches\_15\_i5_11.ino сопровождающего книгу электронного архива (см. при- поженив).
402 Глава 15 Загружаем этот скетч в плату NodeMCU, включаем квадрокоптер AR.Drone 2.0 и проверяем работу кнопки. При нажатии — взлет, при следующем нажатии — по- садка и т. д. 15.13.5. Подключение гироскопа-акселерометра MPU6O50 для управления AR.Drone 2.0 Для управления квадрокоптерами применяются датчики определения их положения в пространстве. Микросхема MPU6050 содержит на борту как акселерометр, так и гироскоп, а помимо этого еще и температурный сенсор, и является главным эле- ментом модуля GY-531 (рис. 15.44). Кроме этой микросхемы на плате модуля рас- положена необходимая обвязка MPU6050, в том числе подтягивающие резисторы интерфейса 12С, а также стабилизатор напряжения на 3,3 вольта с малым падением напряжения (при питании уже в 3,3 вольта на выходе стабилизатора будет ровно 3 вольта) с фильтрующими конденсаторами. Рис. 15.44. Модуль GY-531 Подключение модуля GY-531 к микроконтроллеру осуществляется по протоколу 12С. Схема соединений представлена на рис. 15.45. Использование акселерометра и гироскопа позволяет определить отклонение по осям X и Y и «превратить» это отклонение в команды движения квадрокоптера по соответствующим осям. Перевод показаний, получаемых с датчика, в угол отклонения: uint8_t* data = i2cRead(0x3B,14); ассХ = ((data[0] « 8) | data[l]); accY - ((data[2] « 8) I data[3]); accZ = ((data[4] « 8) | data[5]);
Wi-Fi-модуль ESP8266 403 //tempRaw = ((data[б] « 8) I data[7]); gyroX = ((data[8] « 8) I data[9J); gyroY = ((data[10] « 8) | data[11]); gyroZ = ((data[12] « 8) | data[13]); /* Calculate the angls based on the different sensors and algorithm */ accYangle = (atan2(accX,accZ)+PI)*RADJTO_DEG; accXangle = (atan2(accY, accZ)+PI)*RAD_TO_DEG; double gyroXrate = (double)gyroX/131.0; double gyroYrate = -((double)gyroY/131.0); // Calculate gyro angle without any filter gyroXangle += gyroXrate*((double) (micros()-timer)/1000000) ; gyroYangle += gyroYrate*((double)(micros()-timer)/1000000); Шкшттеяттшт Рис. 15.45. Схема подсоединения к ESP8266 дисплея Nokia 5110, кнопки и модуля GY-531 Значения, получаемые при использовании комплементарного фильтра и фильтра Калмана: // значения при применении комплементарного фильтра compAngleX = (0.93*(compAngleX+(gyroXrate*(double)(micros()-timer)/1000000)))+ (0.07*accXangle); compAngleY = (0.93*(compAngleY+(gyroYrate*(double)(micros()-timer)/1000000)))+ (0.07*accYangle); // значения при применении фильтра Калмана kalAngleX = kalmanX.getAngle(accXangle, gyroXrate, (double)(micros()-timer)/1000000); kalAngleY = kalmanY.getAngle(accYangle, gyroYrate, (double)(micros()-timer)/1000000);
404 Глава 15 Команда, которую необходимо направлять квадрокоптеру AR.Drone для управле- ния полетом: AT*REF=[Sequence number ],[Flag bit-field],[Roll],[Pitch],[Gaz],[Yaw]<LF> Значения Roll и Pitch в интервале от -1 до 1 берем из таблицы const int floats [ ] — индекс соответствует углу отклонения, вычисляемому из данных дат- чика MU6050. Электронный архив Полный скетч управления квадрокоптером AR.Drone, соответствующий всем сделан- ным изменениям, можно найти в файле esp8266_scetches\_15\_15_12.ino сопровождаю- щего книгу электронного архива (см. приложение). Загружаем этот скетч в плату NodeMCU, включаем квадрокоптер AR.Drone 2.0 и проверяем работу пульта (рис. 15.46). Рис. 15.46. Пульт на ESP8266 и квадрокоптер ArDrone 2.0
Wi-Fi-модуль ESP8266 405 15.14. Печать курса валют на термопринтере Создадим проект IoT-принтера, который будет печатать курс валют на текущую дату, получая данные из сети Интернет с сайта cbr.ru. В этом проекте используется бюджетный термопринтер для Arduino (рис. 15.47), печатающий на термобумагу шириной 2,25 дюйма, которую можно приобрести в магазине канцелярских това- ров. Вам также понадобятся модуль часов реального времени (RTC) на микросхе- ме DS3231 и регулируемый источник питания от 5 до 9 В постоянного тока, кото- рый может обеспечить ток более 1,5 А. Рис. 15.47. Термопринтер для Arduino 15.14.1. Подключение термопринтера к модулю NodeMCU ESP8266 Общение термопринтера с микроконтроллером осуществляется по UART-соеди- нению. Для проведения начального теста принтера подключите его к блоку пита- ния, держа нажатой кнопку на верхней панели,— будет распечатана таблица шрифтов и некоторая дополнительная информация (рис. 15.48). Нужный нам пара- метр — скорость обмена по последовательному порту: 19200 бод. Подключим термопринтер к модулю NodeMCU ESP8266 по схеме, представленной на рис. 15.49, и загрузим на плату NodeMCU код из листинга 15.9. Обратите вни- мание: для программирования нам потребуется Arduino-библиотека Adafruit Thermal Printer.
406 Глава 15 Рис. 15.48. Распечатка тестовой страницы FF5V7A Рис. 15.49. Схема соединений для подключения термопринтера
Wi-Fi-модуль ESP8266 407 iinclude "Adafruit_Thermal. h" Adafruit_Thermal printer(&Serial); ■// Pass addr to printer constructor void setup () { // запуск последовательного порта Serial.begin(19200); // инициализация принтера printer.begin(); delay(3000); // настройки по умолчанию printer.wakeO ; printer.setDefault(); printer.printIn(); printer.printlnO ; delay(1000); printer.println("test "); printer.println("esp8266 iot"); printer.printIn("thermal printer"); } void loop() { Электронный архив Скетч, соответствующий листингу 15.13, можно найти в файле arduino_scetches\J5\ _15_i3.ino сопровождающего книгу электронного архива (см. приложение). После загрузки скетча начнется вывод данных на принтер (рис. 15.50). Рис. 15.50. Вывод данных из скетча на принтер
408 Глава 15 15.14.2. Подключение модуля DS3231 к модулю NodeMCU ESP8266 В нашем проекте необходимо знать реальное время, которое мы будем получать с помощью уже упомянутого ранее модуля часов реального времени (RTC) на мик- росхеме DS3231. Подключение модуля DS3231 к модулю NodeMCU ESP8266 осуществляется по протоколу 12С: подсоединяемся к контактам NodeMCU D3 (GPIO0) — SCL и D4 (GPIO2). Схема соединений представлена на рис. 15.51. Рис. 15.51. Схема подключения модуля DS3231 к модулю NodeMCU Загрузим на модуль NodeMCU скетч установки и получения текущего времени с RTC-модуля DS3231 (листинг 15.10). #include <Wire.h> int clockAddress = 0x68; // I2C адрес микросхемы byte second, minute, hour, dayOfWeek, day, dayOfMonth, month, year; #define DS3231_SCL 0 #define DS3231_SDA 2 void setup() { // запустить Wire Wire.begin(DS3231_SCL, DS3231_SDA); Serial.begin(9600) ; void loop() { if (Serial.available() > 0) { String str = Serial.readStringUntil(f\n'); if (str == "show time") { getDateDs3231(); // показать время
WJ-Fi-модуль ESP8266 40Ц String s = getTimeStr(); Serial.println(s) ; } if (str — "set time") { time_set (); // получить дату и время void getDateDs3231() { Wire.beginTransmission(clockAddress); Wire.write(byte(0x00)); Wire.endTransmission(); Wire.requestFrom(clockAddress, 7); second = bcdToDec(Wire.read() & 0x7f); minute = bcdToDec(Wire.read()); hour = bcdToDec(Wire.read() & 0x3f); dayOfWeek = bcdToDec(Wire.read()); dayOfMonth = bcdToDec(Wire.read()); day = dayOfMonth; month = bcdToDec(Wire.read()); year = bcdToDec(Wire.read()); } void setDateDsl307() { Wire.beginTransmission(clockAddress); Wire.write(byte(0x00)); Wire.write(decToBcd(second)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(hour)); Wire.write(decToBcd(dayOfWeek)); Wire.write(decToBcd(dayOfMonth)); Wire.write(decToBcd(month)); Wire.write(decToBcd(year)); Wire.endTransmission(); byte decToBcd(byte val) { return ( (val / 10 * 16) + (val % 10) ); } byte bcdToDec(byte val) { return ( (val / 16 * 10) + (val % 16) );
410 Глава 15 String getTimeStr() { String str = String(day) + "." + formatDigit(month, 2) + "." + formatDigit(year, 2) + " " + formatDigit(hour, 2) + ":" + formatDigit(minute, 2) + ":" + formatDigit(second, 2); return str; } String formatDigit(int i, int len) { String s = String(i); while (s.length() < len) { s « "0" + s; } return (s); void time_set () { Serial.println("Enter Year 2 last digits") while (Serial.available() <= 0); year = Serial.parselnt(); Serial.println(year); Serial.println("Month"); while (Serial.available() <= 0); month = Serial.parselnt(); Serial.println(month); Serial.println("Day"); while (Serial.available() <= 0); day = Serial.parselnt(); dayOfMonth = day; Serial.println(day); Serial.println("Day of Week"); while (Serial.availableO <= 0); dayOfWeek = Serial.parselnt(); Serial.println(dayOfWeek); Serial.println("Hour"); while (Serial.availableO <= 0) ; hour = Serial.parselnt(); Serial.println(hour); Serial.println("Minute"); while (Serial.available() <= 0); minute = Serial.parselnt(); Serial.println(minute); setDateDsl307(); Serial.println("Time recvd OK");
Wi-Fi-модуль ESP8266 411 Электронный архив Скетч, соответствующий листингу 15.4, можно найти в файле anduino_scetches\J5\J5_14.ino сопровождающего книгу электронного архива (см. приложение). Результат работы скетча, позволяющего установить время отправкой команд по последовательному порту, показан на рис. 15.52. Рис. 15.52. Установка времени через последовательный порт 15.14.3. Получение XML-файла с курсом валют с сайта cbr.ru Теперь нам необходимо получать актуальный курс валют из сети Интернет. По- лучить курсы валют в формате 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);
412 Глава 15 Затем создаем TCP-соединение с сервером cbr.ru: WiFiClient client; const int httpPort - 80; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); return; И формируем строку для запроса 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); 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\rf); Serial.print(line); delay(10); Электронный архив Полный скетч получения XML-файла с сайта Сбербанка, соответствующий всем при- веденным фрагментам, можно найти в файле arduino_scetches\_15\_15_15.ino сопровож- дающего книгу электронного архива (см. приложение). Загружаем этот скетч в плату NodeMCU и наблюдаем результат его работы в мони- торе последовательного порта (рис. 15.53).
Wi-Fi-модуль ESP8266 413 НрШГ|аП):пд1щш Connecting no MaeBook-Pro-Victor W1F1 connected IP address: 1 192.168,2.19 , 24.08.17 11:48:21 connecting to cbr.ru Requesting URL: /scripts/2CML_daily.asp'>date_req=24/0S/2017 HTTP/1.1 200 OK Server: nginx/1.11.10 Date: Thu, 24 Aug 2017 08:47:02 Gffi Content-Type: text/xml Content-Length: 5804 Connection: close Vary: Accept-Encodmg Cache-Control: private X-Powered-By: ASP.NET <?xml veraion^l.G" encoding=Mwindows-1251w ?> <ValCurs Date="24.08.2017w пазве*"Foreign Currency Market"> <Valute ID='fR01010tf> <NuaiCode>03 6</NumCode> <CharCode>AUD</CharCode> <Ыазве>Австралийский <Value>4€, € </Valute> <Valute 1О <Nui^:ode>94 4</NuraCDde > <CharCod€>A2N</CharCode> <No3Bi.nal>l</Nominal> <Ыаше>Азербайджанский ман <Value>35,0719</Value> Рис. 15.53. Результат получения XML-файла с сайта cbr.ru 15.14.4. Обработка данных курса валют и печать на принтер В предыдущем разделе мы разобрались с получением XML-файла с курсами валют. Теперь нам следует только извлечь из него необходимое значение и вывести его на печать. Работа со строками в Arduino достаточно проблемна, поэтому сдела- ем так: int k=0; while(client.available()){ line = client.readStringUntil(f\r'); if(k>0) k++; if(line.substring(11,14)=="840") k=l;
414 Глава 15 if (к—5) { if (dollar=line.substring(9,16)) ; // если курс изменился - выводим на печать else { dollar=line.substring(9,16); printer.println(); printer.printIn(getTimeStr()); printer.print("$= "); printer.print(dollar); printer.print(" rub"); printer.println(); delay(10 ); Электронный архив Полный скетч печати курса валют на принтере можно найти в файле arduino_scetches\ Jl5\_15_i6.ino сопровождающего книгу электронного архива (см. приложение). Загружаем этот скетч в плату NodeMCU и получаем вывод курса доллара на печать (рис. 15.54). Рис. 15.54. Вывод курса доллара с сайта cbr.ru на принтер
Wi-Fi-модуль ESP8266 415^ 15.15. Интернет-часы на модулях ESP8266 и ТМ1637 с синхронизацией по NTP Рассмотрим еще один проект, в котором будет задействован модуль ESP8266, — часы, но не простые, а интернет-часы, которые станут получать время по NTP (Network Time Protocol)— сетевому протоколу для синхронизации внутренних часов компьютера. Протокол NTP использует для своей работы протокол UDP. В качестве табло часов мы возьмем четырехразрядный индикатор от Robotdyn с разделителем типа «двоеточие» между вторым и третьим разрядами (рис. 15.55). Основное в индикаторе— микросхема ТМ1637, представляющая собой драйвер для отдельных 7-сегментных разрядов. При этом нам не потребуется программной реализации динамической индикации, поскольку все уже реализовано внутри мо- дуля. Модуль обеспечивает 8 градаций яркости и имеет двухпроводной интерфейс работы (CLK, DIO). Рис. 15.55. Четырехразрядный индикатор от Robotdyn Схема подключения модуля ТМ1637 к модулю NodeMCU ESP8266 представлена на рис. 15.56. Итак, загружаем на плату скетч из листинга 15.11 (обратите внимание: для про- граммирования нам потребовалась библиотека DigitalTube), поменяв на свои зна- чения данных для соединения по Wi-Fi. #define AP_SSID "MacBook-Pro-Victor" #define AP_PASS "19101966" И данные для своей временной зоны: #define TIMEZONE 3
416 Глава 15 Рис. 15.56. Схема соединений для подключения модуля ТМ1637 к плате NodeMCU ESP8266 #include <ESP8266WiFi.h> #include <WiFiUdp.h> #include "TM1637.h" #define TM1637_CLK 4 #define TM1637_DIO 5 TM1637 tml637(TM1637_CLK,TM1637_DIO); #define AP_SSID "MacBook-Pro-Victor" #define AP_PASS "19101966" #define TIMEZONE 3 unsigned int localPort = 2390; // local port to listen for UDP packets unsigned long ntp_time = 0; long t_correct = 0; unsigned long cur_ms = 0; unsigned long msl = 0; unsigned long ms2 = 100000.00UL; unsigned long t_cur =0; bool points = true; unsigned int err_count = 0; IPAddress timeServerIP; const char* ntpServerName = "time.nist.gov"; const int NTP_PACKET_SIZE =48; byte packetBuffer[ NTP_PACKET_SIZE]; WiFiUDP udp;
Wi'Fi-модуль ESP8266 417_ void setup() { Serial.begin(115200); Serial.println(""); Serial.println(""); Serial.print("Free Memory: ") ; // Соединение с WiFi Serial.println(ESP.getFreeHeap()); if ( ! ConnectWiFi (AP_SSID/AP_PASS) ) { Serial.println("Reset ESP8266 ..."); ESP.reset (); } delay(1000); // Инициализация дисплея tml637.init(); // Установка яркости дисплея tml637.set(5); // Инициализация UDP-соединения с NTP-сервером Serial.println("Starting UDP"); udp.begin(localPort); Serial.print("Local port: "); Serial.println(udp.localPort()); void loop(){ curjns = millis (); t_cur = curjns/1000; // Каждые 60 секунд считываем время в Интернете if( curjns < ms2 I| (curjns - ms2) > 60000 ){ err_count++; // Делаем три попытки синхронизации с Интернетом if ( GetNTPO ) { ms2 = curjns; err_count = 0; t_correct = ntp_time - t_cur; // Каждые 0.5 секунды выдаем время if ( curjns < msl | I (curjns - msl) > 500 ) { msl = curjns; ntp_time = t_cur + t_correct; DisplayTime (); points = !points; } // Если нет соединения с Интернетом, перезагружаемся if( err_count > 10 ){ Serial.println("NTP connect false");
418 Глава 15 Serial.println("Reset ESP8266 ..."); ESP. reset () ; } delay(100); } // Соединение с Wi-Fi bool ConnectWiFi(const char *ssid, const char *pass) { // Три попытки соединения по Wi-Fi for( int i=0; i<3; i++){ Serial.print("\nConnecting to: "); Serial.printIn(ssid); WiFi.begin(ssid,pass); delay(1000); // Максимум 12 раз проверка соединения for( int j=0; j<12; j++ ){ if (WiFi.status() == WL_CONNECTED) { Serial.print("\nWiFi connect true: "); Serial.print(WiFi.locallP()); Serial.print("/"); Serial.print(WiFi.subnetMask()) ; Serial.print("/"); Serial.println(WiFi.gatewaylPO); return true; } delay(1000); Serial.print(WiFi.status()); Serial.println("\nConnect WiFi failed ..."); return false; } // Выдача текущего времени на индикатор void DisplayTime(void){ uintl6_t m = ( ntp_time/60 )%60; uintl6_t h = ( ntp_time/3600 )%24; Serial.print("Time: "); Serial.print(h); Serial.print(":"); Serial.println(m); tml637.point(points); tml637.display(0,h/10); tinl637.display (l,h% 10) ; tml637.display(2fm/10) ; tml637.display (3fm% 10); } // Посылаем и парсим запрос к NTP-серверу bool GetNTP(void) { WiFi.hostByName(ntpServerName, timeServerIP);
Wi-Fi-модуль ESP8266 £79 sendNTPpacket (timeServerIP)" ; delay(1000); int cb = udp.parsePacket(); if (!cb) { Serial.println("No packet yet11); return false; } else { Serial.print("packet received, length^"); Serial.printIn(cb); // Читаем пакет в буфер udp.read(packetBuffer, NTP_PACKET_SIZE); // 4 байта, начиная с 40-го, содержат таймстамп времени - число секунд // от 01.01.1900 unsigned long highWord - word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // Конвертируем два слова в переменную long unsigned long secsSincel900 = highWord « 16 | lowWord; // Конвертируем в UNIX-таймстамп (число секунд от 01.01.1970 const unsigned long seventyYears = 2208988800UL; unsigned long epoch = secsSincel900 - seventyYears; // Делаем поправку на местную тайм-зону ntp_time - epoch + TIMEZONE*3600; Serial.print("Unix time = "); Serial.printIn(ntp_time) ; } return true; // Посылаем запрос NTP-серверу на заданный адрес unsigned long sendNTPpacket(IPAddressS address) { Serial.printIn("sending NTP packet..."); // Очистка буфера в 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Формируем строку зыпроса NTP-сервера packetBuffer[0] - 0Ы1100011; // LI, Version, Mode packetBuffer[1] =0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = OxEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] =49; packetBuffer[13] = Ox^E; packetBuffer[14] =49; packetBuffer[15] - 52;
420 Глава 15 // Посылаем запрос на NTP-сервер (123 порт) udp.beginPacket(address, 123); udp.write(packetBuffer, NTP_PACKET_SIZE); udp.endPacket(); Электронный архив Скетч, соответствующий листингу 15.11, можно найти в файле arduino_scetches\J5\ _15_i7.ino сопровождающего книгу электронного архива (см. приложение). После загрузки скетча мы можем наблюдать вывод данных времени на дисплей ТМ1637 (рис. 15.57). Рис. 15.57. Вывод данных времени на дисплей ТМ1637
Заключение Интернет вещей (Internet of Things, IoT) — это новое направление, которое сейчас стремительно развивается. Связанные с Интернетом вещи призваны сделать нашу жизнь еще более функциональной и удобной. Интернет вещей трансформирует привычные для нас объекты в совершенно новые инструменты, позволяющие со- бирать, агрегировать и анализировать значительные объемы информации об окру- жающей нас действительности. Устройства с постоянным подключением к Интер- нету могут следить практически за всеми измеримыми параметрами. Таким обра- зом, Интернет вещей предоставляет нам возможности наблюдения за любыми показателями окружающей среды в реальном времени. И, что самое важное,— возможность реализации функций анализа получаемых показателей и управления устройствами, их изменяющими. В 2016 году количество IoT-предметов во всем мире составило почти 5 миллиар- дов, и аналитики Juniper Research считают, что к 2020-му году эта цифра достигнет 25-38 миллиардов. В этой книге мы рассмотрели вопросы реализации идей Интернета вещей на самых известных и популярных платформах: Arduino и Raspberry Pi, а также на ставшем весьма популярным в последнее время Wi-Fi-модуле ESP8266. А практическое воплощение полученных при прочтении книги знаний поможет вам поучаствовать в построении мира Интернета вещей не только в качестве потреби- теля, но и разработчика. Желаю вам творческих успехов!
ПРИЛОЖЕНИЕ Описание электронного архива Электронный архив с материалами, сопровождающими книгу, можно скачать с FTP-сервера издательства по ссылке ftp://ftp.bhv.ru/9785977539517.zip, а также со страницы книги на сайте www.bhv.ru. В архиве находятся следующие папки: □ \arduino_scetches — исходники примеров и проектов глав 4-11 для Arduino IDE; □ \esp8266_scetches — исходники примеров и проектов главы 15 для Arduino IDE; □ \python — исходники примеров для главы 12; □ \arduinojibraries — библиотеки Arduino, используемые в примерах и проектах книги и не включенные в среду разработки Arduino IDE; О \esp8266Jibraries — библиотеки для ESP8266, используемые в примерах и проек- тах книги и не включенные в среду разработки Arduino IDE.
Предметный указатель м МАС-адрес 34,38,39,41,49 Master-устройство ПО Р PIR-sensor 165 R Raspberry Pi 253 Slave-устройство 110 Start-условие 111 Stop-условие 111 w Wi-Fi-модуль ESP8266 349 Автоматическая центровка и масштабирование схемы 25 Аналоговые оптические датчики 53 Аналоговый датчик 29 0 освещенности (фоторезистор) 43 0 температуры ■ LM335 31 » LM35 327 Аналого-цифровые преобразователи (АЦП) 30 Аппаратные порты ввода/вывода GPIO 253 Библиотека 0 Tiny Webserver 97 0 Wire 113 В Видеоускоритель Broadcom VideoCore IV 255 Виджет температуры в сервисе Wyliodrin 327 Виджеты для проекта в Blynk 195 Включение транзистора в схему управления реле 85 Вращающий момент сервопривода 93 График показаний фоторезистора в сервисе Wyliodrin 327
426 Предметный указатель Датчик 29 О влажности DHT11 161 О влажности DHT22 161 О влажности и температуры SHT21 в сервисе Wyliodrin 332 О влажности и температуры SHT21 нашинеПС 127 О движения HC-SR501 165 О звука FC-04 168 О освещенности ВН1750 205,281 О освещенности ВН 1750 в сервисе Wyliodrin 332 О освещенности ВН1750 на шине 12С 116 О света Grove light 337 О температуры DS18B20 275,303 О температуры LM335 183 О температуры LM35 в сервисе Wyliodrin 327 Диммер 88 Добавление О в библиотеку Fritzing новых компонентов 26 О устройства в сервис Wyliodrin 312 к Камера Raspberry Pi Camera Board 297 Карта памяти О формата MicroSD 255 О формата SD 255 м Меню конфигурации Raspberry Pi 260 Методы библиотеки Wire 114 Микросхема часов реального времени Dallas DS1307 136 Монитор последовательного порта 18 н Набор стандартных библиотек 18 Назначение выводов GPIO 270 Накопитель на SD-карте 141 Настройка 0 доступа к Raspberry Pi no Wi-Fi 262 0 сервера WeblOPi 288 0 сетевых параметров Raspberry Pi 262 Нейтральное положение сервопривода 93 Загрузка скетча 18 Загрузчик (bootloader) Arduino 18 Запись образа Wyliodrin на SD-карту 313 И Изменение пароля WeblOPi 287 Интерфейс GPIO (General Purpose Input/Output) 269 Инфракрасный датчик расстояния Sharp 53 0 GP2Y0A02YK29 Исполнительные устройства 83 Использование 0 в сервисе Wyliodrin платы Arduino, подключенной к Raspberry Pi 325 0 внешних носителей 141 0 технологии 1-Wire 148 Облачный сервис Xively 119 Обмен 0 информацией по шине 1-Wire 150 0 сообщениями между платами Raspberry Pi через сервис Wyliodrin 340 Обновление прошивок модуля ESP8266 354 Онлайн-сервис Wyliodrin 311 Оптрон 87 Отправка данных 0 в несколько каналов 131 0 в сервис ThingSpeak 46 0 в сервис Wyliodrin с мобильного устройства 343 0 из Arduino в Xively 122 0 на сайт «Народный мониторинг» с использованием платы GPRS/GS Shield 182 0 с Raspberry Pi в сервис «Народный мониторинг» 278 0 с платы Arduino в облачные сервисы 37 Отправка и получение SMS-сообщений с помощью платы GSM/GPRS Shield 179
Предметный указатель 427 п Пироэлектрический инфракрасный сенсор 165 Питание от паразитного источника 145 Плата О Arduino GPRS/GSM Shield 177 О Ethernet shield 33,83 0 SIM900 Quad-Band GPRS Shield 177 Платы расширения GrovePi и GrovePi+ 336 Подключение О ЗС-модема к Raspberry Pi 265,266 О Raspberry Pi к Wyliodrin 317 О датчика ВН1750 к плате Arduino 118 О датчика DS18B20 к контактам GPIO Raspberry Pi 275 О датчиков DHT к Arduino 163 О датчиков расстояния Sharp к Arduino 55 О диммера к Arduino 89 О к Raspberry Pi датчика ВН1750 281 О модуля SD Card 141 О твердотельного реле к Arduino 87 О электромагнитного реле к Arduino 85 Получение данных О из сервиса Xively 125 О из нескольких каналов 133 Приложение ThingTweet сервиса ThingSpeak 59 Пример отправки данных в Twitter 57 Принцип действия датчиков расстояния Sharp 53 Проект Blynk 193 Протокол 1-Wire 145 Процессор 0 ВСМ2836 256 0 Broadcom BCM2835 254 Прошивка NodeMCU модуля ESP8266 356 Работа с GPIO на языке Python 272 Регистрация в сервисе Wyliodrin 311 Режим АТ-команд модуля ESP8266 350 Сайт «Народный мониторинг» 41 Сглаживание значений, получаемых с датчика расстояния 56 Сенсор 29 Сервис 0 ThingSpeak 45 0 Twitter 57 0 Weaved304 Сервопривод 92 Симистор 87, 88 Система Grove 336 Скетч 17 Скорость вращения вала сервопривода 95 Слот для флеш-карты MicroSD 98 Создание 0 нового проекта в Blynk 194 0 приложения в среде программирования Wyliodrin 319 0 принципиальной схемы 25 Среда 0 программирования ■ Arduino IDE 13 ■ Blockly311 0 разработки Fritzing 21 Стабилитрон 31 Стандартные сервоприводы 93 Стартовая страница WeblOPi 287 Статистическое управление процессами 253 Страница управления выводами GPIO HaWebIOPi287 Схема 0 подключения к GPIO датчика температуры DS18B20 303 0 соединения элементов 21 Твердотельное реле 87 Техническая документация (Datasheet) 31 Технология 0 «Умный дом» 148 0 AJAX100 Тиристоры 87 Топология общей шины 146 Точка калибровки датчика 32 Угол поворота сервопривода 93 Управление 0 светодиодом с веб-страницы Wyliodrin 323 0 сервоприводом 93 0 сервоприводом из проекта Blynk 202
428 Предметный указатель Установка О Arduino IDE 14 О WeblOPi на ОС Raspbian 285 О дистрибутива ОС на Raspberry Pi 257 О драйверов Arduino IDE 15 О среды разработки Fritzing 21 Устройство электромагнитного реле 84 Учетная запись Wylipdrin 311 ш Шина I2C 109 Широтно-импульсная модуляция (ШИМ) 93 Электромагнитное реле 84 0 SRD-05VDC фирмы SONGLE 84 Файл настроек Wyliodrin 316 Фоторезистор 43,116 Фреймворк WeblOPi 285 Язык программирования Lua 356 Часы реального времени (RTC) 256