Автор: Петин В.А.
Теги: информационные технологии вычислительная техника обработка данных компьютерные технологии программирование электроника программное обеспечение издательство бхв-петербург
ISBN: 978-5-9775-6711-4
Год: 2021
Виктор Петин
Проекты
с
контроллера ДГ[|ШП0
4-е издание
Санкт-Петербург
« БХВ-Петербург»
2021
УДК 004
ББК 32.973.26
П29
Петин В. А.
П29 Проекты с использованием контроллера Arduino. — 4-е изд., перераб.
и доп. — СПб.: БХВ-Петербург, 2021. — 560 с: ил. — (Электроника)
ISBN 978-5-9775-6711-4
Рассмотрены основные платы Arduino и платы расширения (шилды),
добавляющие функциональность основной плате. Подробно описан язык и среда
программирования Arduino IDE. Приведены практические проекты с использованием
контроллеров семейства Arduino в области робототехники, погодных
метеостанций, "умного дома", вендинга, телевидения, беспроводной связи (bluetooth,
радиоуправление, связь с устройствами Android) и др. Все проекты сопровождаются
схемами и листингами. На сайте издательства размещен архив с исходными
кодами программ и библиотек, описаниями и спецификациями электронных
компонентов.
В четвертом издании рассмотрены новые платы Arduino MKR и Nano 33, новые
платы расширения, светодиодные матрицы, протокол MQTT, RFID-идентифика-
ция, GPS-трекер, ЯндексКарты и проекты в области нейронных сетей.
Для читателей, интересующихся современной электроникой
УДК 004
ББК 32.973.26
Группа подготовки издания:
Руководитель проекта Евгений Рыбаков
Зав. редакцией Екатерина Сависте
Компьютерная верстка Ольги Сергиенко
Дизайн обложки Марины Дамбиевой
Оформление обложки Карины Соловьевой
Подписано в печать 11.01.21.
Формат 70хЮ01/1в. Печать офсетная. Усл. печ. л. 45,15.
Тираж 1500 экз. Заказ № 007.
"БХВ-Петербург", 191036, Санкт-Петербург, Гончарная ул., 20.
Отпечатано с готового оригинал-макета
ООО "Принт-М", 142300, М.О., г. Чехов, ул. Полиграфистов, д. 1
ISBN 978-5-9775-6711-4 © ооо тав", 2021
©Оформление ООО "БХВ-Петербург", 2021
Оглавление
•••••••••••••••
XXDv/ДИЗЛОВИv •••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••*•••••••••••••
Для кого и о чем эта книга? 13
Структура книги 13
Благодарности 14
ЧАСТЬ I. ARDUINO — ОБЩИЙ ОБЗОР 15
1.1. Arduino — что это? 17
1.2. В чем преимущество Arduino? * 18
1.3. Новые тенденции и перспективы развития Arduino 18
Глава 2. Платы семейства Arduino и платы расширения для них..................... 20
2.1. Обзор плат семейства Arduino 20
2.2. Arduino Uno 21
2.3. Arduino Nano 22
2.4. Arduino Pro Mini 23
2.5. Arduino LilyPad 24
2.6. Arduino Mega2560 25
2.7. Arduino Leonardo 26
2.8. Arduino Due 27
2.9. Arduino Yun 28
2.10. Arduino MKR WiFi 1010 29
2.11. Arduino Nano 33 30
2.12. Платы расширения для Arduino 31
ЧАСТЬ П. СРЕДЫ РАЗРАБОТКИ И ЯЗЫК ПРОГРАММИРОВАНИЯ
Ш1АТ ARDUINO 33
Глава 3. Среда разработки Arduino IDE 35
3.1. Установка Arduino IDE в Windows 35
3.2. Установка Arduino IDE в Linux 36
3.3. Настройка среды Arduino IDE 37
Оглавление
Глава 4. Облачная среда разработки Arduino Create 41
4.1. Начало работы в среде Arduino Create , 41
4.2. Загрузка и выполнение пробного скетча 43
Глава 5. Программирование плат Arduino 45
5.1. Базовые знания 45
5.1.1. Цифровые выводы 45
5.1.2. Аналоговые входы 46
5.1.3. Широтно-импульсная модуляция 46
5.1.4. Память в Arduino 46
5.2. Струюура программы 48
5.2.1. Функции setupO и loopO 48
5.3. Синтаксис и операторы .....49
5.3.1. Управляющие операторы 49
5.3.1.1. Оператор //(условие) и операторы сравнения ==, /=, < , > 49
5.3.1.2. Оператор //.. .else 49
5.3.1.3. Оператор/or 50
5.3.1.4. Оператор switch 51
5.3.1.5. Оператор while 51
5.3.1.6. Оператор do...while 52
5.3.1.7. Оператор break 52
5.3.1.8. Оператор continue 52
5.3.1.9. Оператор return 53
5.3.2. Синтаксис 53
5.3.2.1.; (semicolon, точка с запятой) , 53
5.3.2.2. {} (curly braces, фигурные скобки) 53
5.3.2.3. Комментарии: //(single line comment, однострочный),
/* */ (multi-line comment, многострочный) 54
5.3.3. Арифметические операторы 54
5.3.3.1. = (assignment, оператор присваивания) 54
5.3.3.2. + (сложение), - (вычитание), * (умножение), /(деление) 55
5.3.3.3.% (modulo) 55
5.3.4. Операторы сравнения 55
5.3.5. Логические операторы 55
5.3.5.1. && (логическое И) 55
5.3.5.2. || (логическое ИЛИ) 55
5.3.5.3. / (логическое отрицание) 56
5.3.6. Унарные операторы 56
5.3.6.1. ++ (увеличение значения), /—(уменьшение значения) 56
5.3.6.2. +=,-=, *= ,/= 56
5.4. Данные 56
5.4.1. Типы данных 56
5.4.
5.4.
5.4.
5.4.
5.4.
5.4.
.1. boolean 56
.2. char '. 57
3.byte 4 57
A.int : 57
.5. unsigned int 58
.6. long 58
Оглавление
5.4.1.7. unsigned long 58
5.4.1.8. float 59
5.4.1.9. double 59
5.4.1.10. string — текстовые строки 59
5.4.1.11. Массивы ..60
5.4.1.12. void. 61
5.4.2. Константы 61
5.4.3. Переменные 62
5.4.3.1. Объявление переменных 62
5.4.3.2. Границы переменных 62
5.4.4. Преобразование типов данных 63
SAA.l.charO 63
5.4.4.2. byteO 63
5.4.4.3. intO 63
5.4.4.4. longO 63
5AA.5.floatO .'. 63
5.5. Функции 64
5.5.1. Цифровой ввод/вывод '. 64
5.5.1.1. ФункциярinMode 64
5.5.1.2. Функция digitalWriteO 64
5.5.1.3. Функция digitalReadO 65
5.5.2. Аналоговый ввод/вывод 66
5.5.2.1. Функция analogReadQ 66
5.5.2.2. Функция analogReferenceO 67
5.5.2.3. Функция analogWriteO 67
5.5.3. Дополнительные фунции ввода/вывода 68
5.5.3.1. Функция tone() 68
5.5.3.2. Функция поТопеО 69
5.5.3.3. Функция shiftOutO , 69
5.5.3.4. Функцияpulseln() 71
5.5.4. Работа со временем 72
5.5.4.1. Функция millisO 72
5.5.4.2. Функция microsO 72
5.5.4.3. Функция delayO 73
5.5.4.4. Функция delayMicrosecondsQ 74
5.5.5. Математические функции 74
5.5.5.1. Функция min(x,yx) 75
5.5.5.2. Функция max(x, у) 75
5.5.5.3. Функция absO 75
5.5.5.4. Функция constraint, a, b) 76
5.5.5.5. Футащя mapfvalue, fromLow, fromHigh, toLow, toHigh) 76
5.5.5.6. Функцияpow(basef exponent) 77
5.5.5.7. Функция sq(x) 77
5.5.5 8. Функция sqrt(x) 77
5.5.6. Тригонометрические функции 77
5.5.6.1. Функщя sin(rad) 78
5.5.6.2. Функция cos(rad) 78
5.5.6.3. Функция tan(rad) 78
Оглавление
5.5.7. Генераторы случайных значений 78
5.5.7.1. Функция randomSeed(seed) 78
5.5.7.2. Функция randomO 78
5.5.8. Операции с битами и байтами 79
5.5.8.1. Функция lowByteO 79
5.5.8.2. Функция highByteO 80
5.5.8.3. Функция bitReadO 80
5.5.8.4. Функция bitWriteO 80
5.5.8.5. Функция bitSetO 80
5.5.8.6. Функция bitClearO 81
5.5.8.7. Функция Ыф 81
5.5.9. Внешние прерывания 81
5.5.9.1. Функция attachlnterrupt 81
5.5.9.2. Функция detqchlnterrupt 82
5.6. Управление портами через регистры ATmega 83
ЧАСТЬ Ш. ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ ARDUINO 85
Глава 6. Проекты для изучения выводов Arduino 87
6.1. Цифровые выводы — «бегущий огонь» на светодиодах 87
6.1.1. Подключение светодиода к выводу Arduino 88
6.1.2. Подключение к плате Arduino 8 светодиодов 92
6.2. Цифровые входы — управляем светодиодами с помощью кнопок 97
6.2.1. Подключение кнопки к плате Arduino 97
6.2.2. Управление кнопками количеством горящих светодиодов 104
6.3. Аналоговые входы — светодиодный индикатор аналоговых значений 107
6.3.1. Подключение потенциометра к плате Arduino 109
6.3.2. Вывод показаний потенциометра на светодиодную шкалу 112
6.4. ШИМ — радуга на RGB-светодиоде 114
6.4.1. Подключение к плате Arduino RGB-светодиода 115
6.5. Светодиодные индикаторы 118
6.5.1. Подключение к плате Arduino семисегментного индикатора 118
6.6. Расширение цифровых выходов — микросхема 74НС595 122
6.6.1. Подключение к плате Arduino сдвигового регистра 74НС595 123
6.7. Расширение цифровых входов и выходов — микросхема МСР23017 128
6.8. Расширение аналоговых входов — мультиплексор CD4051 129
Глава 7. Использование библиотек в проектах Arduino 132
7.1. Установка библиотек 132
7.1.1. Установка библиотеки через Менеджер библиотек 133
7.1.2. Установка библиотеки из ZIP-архива 133
7.1.3. Установка библиотеки вручную 135
7.2. Подключение библиотеки 135
7.3. Создание собственной библиотеки 136
7.3.1. Создание заголовочного файла D5651.h 136
7.3.2. Создание файла реализации D5651.cpp 137
7.3.3. Создание файла keywords.txt 138
Оглавление
Глава 8. Arduino и последовательный порт UART 140
8.1. Библиотека Serial 140
8.1.1. Функция Serial.begin 140
8.1.2. Функция Serialprint 141
8.1.3. Функция Serialprintln 141
8.1.4. Функция Serialwrite 141
8.1.5. Функция Serial.available 142
8.1.6. Функция Serial.read 142
8.2. Использование UART для отладки программ 142
8.2.1. Подключение к плате Arduino нескольких кнопок 142
8.3. Использование UART для установки параметров 145
8.4. Библиотека SoftwareSerial * 149
8.5. Соединение по UART двух плат Arduino 150
Глава 9. Подключение датчиков к плате Arduino 153
9.1. Подключение аналоговых датчиков 153
9.1.1. Подключение к плате Arduino аналогового датчика температуры LM335 154
9.2. Подключение датчиков по протоколу 1-Wire 156
9.2.1. Подключение к плате Arduino цифрового датчика температуры DS18B20 157
9.3. Подключение датчиков влажности и температуры DHT 163
9.4. Подключение датчиков по протоколу 12С 167
9.4.1. Подключение к плате Arduino датчика интенсивности света ВН1750 169
Глава 10. Использование дисплеев в проектах Arduino...................................... 173
10.1. Символьные дисплеи на микроконтроллере HD44780 173
10.1.1. Функция beginO 176
10.1.2. Функция plearQ 176
10.
10.
10.
10.
10.
.3. Функция homeO 177
.4. Функция setCursorQ .....177
.5. Функция writeQ 177
.6. Функция printO 177
.7. Функция cursorQ 178
10.1.8. Функция noCursorO 178
10.1.9. Функция W/иЭД 178
10.1.10. Функция noBlinkO 178
10.1.11. Функция displayO 17$
10.1.12. Функция noDisplayO 179
10.1.13. Функция scrollDisplayLeftO 179
10.1.14. Функция scrollDisplayRightQ 179
10.
10.
10.
10.
10.
.15. Функция autoscrollO 179
.16. Функция noAutoscrollQ 180
Al^yHKumleftToRightO 180
.18. Функция rightToLeftO 180
.19. Функция createCharQ 180
10.2. Подключение дисплеев на контроллере HD44780 по протоколу 12С 181
10.2.1. Вывод на ЖК-дисплей данных с датчика, работающего по протоколу 12С 183
10.3. Графический дисплей Nokia 186
10.4. OLED-дисплеи 192
10.4.1. Электронные часы на OLED-дисплее 193
8 Оглавление
10.5. Дисплеи Nextion 197
10.5.1. Создание нового проекта для дисплея Nextion 198
10.5.2. Прошивка дисплея через UART 202
10.5.3. Прошивка дисплея с помощью карты microSD 203
10.5.4. Подключение дисплея Nextion к плате Arduino 203
10.6. Светодиодные матрицы 207
10.6.1. Четырехразрядная светодиодная матрица 207
10.6.2. Вывод на четырехразрядную светодиодную матрицу спрайтов и символов 210
10.6.3. Бегущая строка на четырехразрядной светодиодной матрице 213
10.6.4. Русификация «бегущей строки» на четырехразрядной
светодиодной матрице 215
10.6.5. Матрица 16x16 на светодиодах WS2812 218
10.6.6. Arduino-библиотека Adafruit Neopixel 220
10.6.7. Графический аудиоспектроанализатор на матрице 16*16
светодиодов\У82812 221
Глава 11. Подключение к Arduino исполнительных устройств .225
11.1. Подключение к плате Arduino электромагнитного или твердотельного реле 225
11.2. Подключение к плате Arduino электродвигателя постоянного тока 229
11.2.1. Управление двигателем с помощью транзистора 229
11.3. Управление двигателями с помощью драйвера 231
11.4. Подключение к плате Arduino сервопривода 234
11.4.1. Использование сервопривода в проекте звуковой сигнализации 237
11.5. Подключение к плате Arduino шагового двигателя 239
11.5.1. Управление дроблением шага и направлением вращения
шагового двигателя с платы Arduino 242
11.6. Подключение к плате Arduino бесколлекторного двигателя 245
Глава 12. Arduino и беспроводная связь 248
12.1.ИК-управление 248
12.1.1. Управление сервоприводом с помощью ИК-связи 251
12.2. Радиомодули для частоты 433 МГц 254
12.2.1. Управление светодиодом платы Arduino с другой такой же платы
по радиоканалу 433 МГц 254
12.3. Радиомодули NRF24L01 257
12.3.1. Организация связи между двумя платами Arduino с использованием
модулей NRF24L01 259
12.4. Использование Arduino с аппаратурой радиоуправления 264
12.4.1. Принципы формирования радиосигнала 266
12.4.2. Организация связи приемника с передатчиком 267
12.4.3. Разработка скетча для приема платой Arduino команд передатчика 268
12.5. Arduino и Bluetooth 271
Глава 13. Arduino и Интернет вещей 279
13.1. Подключение к Интернету с помощью платы расширения Ethernet shield 279
13.1.1. Получение IP-адреса по DHCP 280
13.1.2. Отправка данных на сайт «Народный мониторинг» через Ethernet shield 282
13.2. Подключение к Интернету с помощью платы расширения GSM/GPRS shield 289
13.2.1. Отправка и получение SMS-сообщений с помощью GSM/GPRS shield 291
13.2.2. Отправка данных на сайт «Народный мониторинг» через GSM/GPRS shield 295
Оглавление 9
13.3. Протокол MQTT , 299
13.3.1. Отправка данных по протоколу MQTT 300
13.3.2. Получение данных по протоколу MQTT 304
13.3.3. Android-приложение IoT MQTT Dashboard ._. 307
13.4. Плата Arduino MKR WiFi 1010 для проектов IoT 308
13.5. Отправка данных в облако Arduino IoT Cloud и получение их оттуда 312
Глава 14. RFED-идентификация 318
14.1. Считыватель RFIDRC522 , 318
14.2. Организация контроля доступа по RFID-меткам 321
14.3. Запись информации на RFID-метку 323
14.4. Проект «Говорящая фотография» 330
Глава 15. Специальные возможности отдельных плат Arduino 334
15.1. Использование Arduino Leonardo в качестве USB-устройства 334
15.1.1. Arduino Leonardo: имитация клавиатуры 335
15.1.2. Блокируем клавиатуру с наступлением темноты 337
15.1.3. Arduino Leonardo: имитация компьютерной мыши 337
15.2. Плата Arduino Esplora 340
15.2.1. Arduino Esplora: установка цветов RGB-светодиода 343
15.2.2. Arduino Esplora: создание игры 344
15.3. Плата Arduino LilyPad 362
15.4. Плата Arduino Yun 367
15.4.1. Плата расширения Arduino Yun shield 367
15.4.2. Arduino Yun shield: управляем веб-камерой 369
Глава 16. Взаимодействие Arduino с другими программируемыми
системами 372
16.1. Использование Arduino в проектах LEGO 372
16.1.1. Получение микрокомпьютером LEGO данных с датчика влажности
и температуры DHT11, подключенного к плате Arduino 373
16.2. Arduino в проектах ROS 376
16.2.1. Установка ROS \ 377
16.2.2. Узлы и темы в ROS 377
16.2.3. Пакет rosserial 378
16.2.4. Подготовка сообщения (publisher) на Arduino 379
16.2.5. Создание подписки (subscriber) на Arduino 383
16.2.6. Связь через ROS двух плат Arduino 385
16.3. Arduino и Raspberry pi 386
16.3.1. Установка WeblOPi на Raspberry Pi 387
16.3.2. Обмен данными по последовательному порту 389
16.3.3. Управление движущейся платформой на базе Arduino
по web-интерфейсу Raspberry Pi 390
Глава 17. Программирование в среде Arduino IDE других плат ••...••..•••••.••••••..398
17.1.ESP8266 — микроконтроллер с интерфейсом Wi-Fi 398
17.1 Л. Установка Arduino IDE для работы с ESP8266 399
17.1.2. Печать курса валют на термопринтере в проекте Интернета вещей 402
10 Оглавление
П.2. Z-Uno — плата для прототипирования устройств Z-Wave 409
17.2.1. Установка Arduino IDE для Z-Uno 411
17.2.2. Подключение к плате Z-Uno датчика влажности DHT11 414
ЧАСТЬ IV. ИНТЕРЕСНЫЕ ПРОЕКТЫ НА ARDUINO 417
Глава 18* Умная теплица 419
18.1. Мониторинг климатических параметров умной теплицы 420
18.2. Индикация показаний умной теплицы 425
18.3. Организация полива, обдува и освещения в умной теплице 431
18.4. Переносим функции мониторинга и управления теплицей на устройство
с ОС Android 440
18.5. Создаем собственное мобильное приложение для управления умной теплицей 447
18.6. Превращаем нашу умную теплицу в объект Интернета вещей 451
Глава 19. GPS-трекер и онлайн-сервис поиска стоянок . 461
19.1. Подключение GPS-модуля к плате Arduino '. 461
1?.2. Отправка данных по GPRS на сервер 464
19.3. Создание веб-страницы с использованием API Яндекс.Карт 472
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник,
разменный автомат 476
20.1. Купюроприемник ICT серий А7 и V7 476
20.1.1. Подключение купюроприемника ICT V7 к плате Arduino 480
20.1.2. Скетч для получения номинала принимаемой купюры 482
20.2. Монетоприемник СН-926 483
20.2.1. Настройка монетоприемника 484
20.2.2. Калибровка монетоприемника 485
20.3. Разменный автомат (хоппер) Cube Hopper MKII 485
20.3.1. Подключение хоппера к плате Arduino 487
20.3.2. Программирование хоппера 487
Глава 21. Создание управляющей платы для автомойки
самообслуживания 492
21.1. Блок приема денежных средств и блок индикации t 492
21.2. Выбор программ работы мойки 496
21.3. Отсчет времени выполнения программы. Реализация паузы 499
21.4. Режим администратора. Установка параметров 501
Глава 22. Arduino и интерфейс USB: управление роботами 503
22.1. Интерфейс USB 503
22.2. Плата расширения USB Host Shield 504
22.3. HID-устройства USB 505
22.4. Подключение HID-мыши USB 508
22.5. Управление роботом с помощью руля Defender 508
22.6. Управление роботом с помощью геймпада Defender 518
Оглавление tf.
Глава 23. Камера Pixy: реализация компьютерного зрения •.•.••••••.••.•••••••••••••.••525
23.1. Настройка камеры 526
23.2. Подключение камеры Pixy к плате Arduino 527
23.3. Организация слежения камерой за объектом 529
Глава 24. Проекты на плате Nano 33 BLE Sense ....................................532
24.1. Щчало работы с платой Nano 33 BLE Sense 533
24.2. Bluetooth Low Energy (BLE) 536
24.3. Отправка данных с датчиков платы Nano 33 BLE Sense no BLE 537
24.4. БиблиотекаТеп8огР1о>у Lite 540
24.5. Пример создания классификатора объектов с обучением 541
24.5.1. Сбор данных „ 542
24.5.2. Обучение модели 544
24.5.3. Скетч классификатора для запуска нейронной сети на плате
Nano 33 BLE Sense 549
••••••••••••••••••••••••••••
Приложение 1. Перечень использованных источи и ков...................................... 555
Приложение 2. Описание электронного архива .....................556
Предметный указатель ..............................................................................................557
Предисловие
Для кого и о чем эта книга?
Книга ориентирована на читателей, желающих быстро освоить темы
программирования плат Arduino и использования их для связи с внешними системами в
проектах автоматизации и робототехники.
В книге содержится описание языка программирования плат Arduino в среде
Arduino IDE и предлагается изучение основ работы с платами Arduino на
множестве реальных примеров и проектов их использования, имеющих практическое
значение и представляющих собой законченные решения, пригодные для включения
в ваши конструкции. Все проекты содержат электрические и (или) монтажные
схемы соединений и листинги соответствующих программ.
Все задействованные в проектах книги детали и компоненты нетрудно приобрести
в специализированных магазинах, кроме того, для удобства читателей на сайте
издательства «БХВ-Петербург» (https://bhv.ru/product-category/nabory-dlya-mejkerov/)
предлагаются наборы деталей и компонентов, с помощью которых вы сможете
быстро адаптироваться в мире Arduino и получить удовольствие, видя, как
оживают ваши творения!
Книга сопровождается электронным архивом, содержащим исходный код всех
рассмотренных примеров и проектов, используемые в проектах необходимые
библиотеки, а также техническую документацию на задействованные в проектах устройства
и датчики (см. приложение 2). Этот электронный архив можно скачать с FTP-
сервера издательства «БХВ-Петербург» по ссылке ftp://ftp.bhv.ru/9785977567114.zip,
а также со страницы книги на сайте www.bhv.ru.
Структура книги
Книга состоит из четырех частей и включает предисловие, двадцать четыре главы
и два приложения.
? Часть I содержит описание платформы Arduino, обзор плат семейства Arduino
и плат расширения для Arduino.
14 Предисловие
? В части II книги рассмотрены среда разработки Arduino IDE, новая облачная
среда разработки Arduino Create и язык программирования для плат Arduino.
D Часть III посвящена изучению возможностей платы Arduino, использованию
в связке с ней датчиков, дисплеев, исполнительных устройств, организации
беспроводного соединения плат Arduino, созданию устройств Интернета вещей.
Рассмотрено также взаимодействие Arduino с другими системами и
программирование в среде Arduino ШЕ других плат.
О Часть IV посвящена созданию конкретных устройств на основе платы Arduino.
? В приложениях приведены перечень использованных источников и описание
электронного архива, сопровождающего книгу.
Благодарности
Хочу поблагодарить родных и близких, которые с пониманием относились к
потраченному на книгу (за счет общения с ними) времени. Особая благодарность Богаче-
вой Марине Николаевне за поддержку и понимание.
Большая благодарность издательству «БХВ-Петербург», где поверили в
необходимость этой книги, и всем сотрудникам издательства, которые помогали мне в ее
создании.
Благодарю также всех читателей, купивших эту книгу, — надеюсь, она поможет
вам в разработке собственных проектов на основе Arduino.
ЧАСТЬ I
О0
Arduino — общий обзор
Глава 1. Введение в Arduino
Глава 2. Платы семейства Arduino и платы расширения для них
ГЛАВА 1
Введение в Arduino
1.1. Arduino — что это?
Появление первых микроконтроллеров ознаменовало начало новой эры в развитии
микропроцессорной техники. Сосредоточение в одном корпусе большинства
системных устройств сделало микроконтроллер подобным обычному компьютеру.
В отечественной литературе они даже назывались однокристальными микроЭВМ.
Соответственно и желание использовать микроконтроллеры как обычные
компьютеры возникло практически одновременно .с их появлением. Но желание это
сдерживалось многими факторами. Например, чтобы собрать устройство на
микроконтроллере, необходимо знать основы схемотехники, устройство и работу
конкретного процессора, уметь программировать на ассемблере и изготавливать электронную
технику. Потребуются также программаторы, отладчики и другие вспомогательные
устройства. В итоге без огромного объема знаний и дорогостоящего оборудования
не обойтись. Такая ситуация долго не позволяла многим любителям использовать
микроконтроллеры в своих проектах. Сейчас, с появлением устройств, дающих
возможность работать с микроконтроллерами без наличия серьезной материальной
базы и знания многих предметов, все изменилось. Примером такого устройства
может служить проект Arduino итальянских разработчиков.
Arduino и его клоны представляют собой наборы, состоящие из готового
электронного блока и программного обеспечения. Электронный блок здесь — это печатная
плата с установленным микроконтроллером и минимумом элементов, необходимых
для его работы. Фактически электронный блок Arduino является аналогом
материнской платы современного компьютера — на нем имеются разъемы для
подключения внешних устройств, а также разъем для связи с компьютером, по которому и
осуществляется программирование микроконтроллера. Особенности используемых
микроконтроллеров ATmega фирмы Atmel позволяют производить
программирование без применения специальных программаторов. Все, что нужно для создания
нового электронного устройства, — это плата Arduino, кабель связи и компьютер.
Второй частью проекта Arduino является программное обеспечение для создания
управляющих программ. Оно объединило в себе простейшую среду разработки и
язык программирования, представляющий собой вариант языка C/C++ для микро-
Часть I. Arduino — общий обзор
контроллеров. При этом в него добавлены элементы, позволяющие создавать
программы без изучения аппаратной части. Так что для работы с Arduino практически
достаточно знания только основ программирования на C/C++. Создано для Arduino
и множество библиотек, содержащих код, работающий с различными устройствами.
1.2. В чем преимущество Arduino?
Пользователь современного компьютера не задумывается о функционировании
отдельных частей ПК. Он просто запускает нужные программы и работает с ними.
Точно так же и Arduino позволяет пользователю сосредоточиться на разработке
проектов, а не на изучении устройства и принципов функционирования отдельных
элементов. Нет надобности и в создании законченных плат и модулей —
разработчик может использовать готовые платы расширения или просто напрямую
подключить к Arduino необходимые элементы. Все остальные усилия будут направлены на
разработку и отладку управляющей программы на языке высокого уровня. В итоге
доступ к разработке микропроцессорных устройств получили не только
профессионалы, но и просто любители что-то сделать своими руками. Наличие готовых
модулей и библиотек программ позволяет непрофессионалам в электронике
создавать готовые работающие устройства для решения своих задач. А варианты
использования Arduino ограничены только возможностями микроконтроллера и
имеющейся платы, ну и, конечно, фантазией разработчика.
1.3. Новые тенденции
и перспективы развития Arduino
Классический форм-фактор Arduino является знаковым, но он постепенно отмирает.
Uno-подобные платы, которые стали стандартом де-факто в мире любителей
радиоэлектроники, медленно уходят на пенсию.
В настоящее время внимание Arduino в большей степени направлено на Интернет
вещей (IoT). Сначала появилась серия плат MKR, предоставляющая различные
варианты подключения к сети и управления питанием, что побуждает людей
использовать их в качестве единого стандартного формата для проектов IoT. Платы MKR
повысили уровень стандартизации процесса проектирования, облегчая жизнь
разработчика, пытающегося продать свой конечный продукт на рынке.
Затем появилась серия Nano 33. Ее платы имеют практически те же размеры, что и
оригинал Nano, но несут на борту новые процессоры и отличаются низким
энергопотреблением. Это и плата Nano Every для обычных проектов на базе
мощного микроконтроллера Microchip ATmega4809 с микросхемой ATSAMD11 ARM
Cortex-MO и процессором для USB-to-serial связи, и Nano IoT на микросхеме
ATSAMD21 ARM Cortex-MO с поддержкой Wi-Fi и Bluetooth LE и с крипточипом
для безопасного хранения сертификатов и общих ключей, совместимая с новым
облаком Arduino IoT, и Nano 33 BLE — энергоэффективные модули для работы по
технологии Bluetooth BLE.
Глава 1. Введение в Arduino 19_
Эти новые Nano-платы могут быть совместимы с макетом, но больше
предназначены для поверхностного монтажа в виде модулей. Они на самом деле нацелены на
мелких производителей, которые изготовили прототипы на классических или
MKR-платах и хотят довести свой продукт до полномасштабного производства.
На выставке CES 2020 компания Arduino представила новое семейство мощных
устройств Arduino Portenta, разработанное для требовательных промышленных
приложений, обработки задач искусственного интеллекта и для робототехники.
Оно оборудовано широким спектром поддерживаемых соединений для
подключения периферийных устройств.
ГЛАВА 2
Платы семейства Arduino
и платы расширения для них
2.1. Обзор плат семейства Arduino
Основные версии плат Arduino представлены следующими моделями:
? Due — плата на базе 32-битного ARM микропроцессора Atmel SAM3X8E ARM
Cortex-M3;
? Leonardo — плата на микроконтроллере ATmega32U4;
? Uno — самая популярная версия базовой платформы Arduino;
? Duemilanove — плата на микроконтроллере ATmegal68 или ATmega328;
? Diecimila — версия базовой платформы Arduino USB;
? Nano — компактная плата, используемая как макет. Она подключается к
компьютеру при помощи кабеля USB Mini-B;
? Mega — версия серии плат Mega на базе микроконтроллера ATmegal280;
? Mega2560— плата на базе микроконтроллера ATmega2560 с использованием
микроконтроллера ATMega8U2 для последовательного соединения по USB-
порту;
? Mega ADK— версия платы Mega2560 с поддержкой интерфейса USB-host для
связи со смартфонами на Android и другими устройствами с интерфейсом USB;
? Arduino ВТ — плата с модулем Bluetooth для беспроводной связи и
программирования;
? LilyPad— плата, разработанная для носимых устройств (может зашиваться
в ткань);
? Fio— плата, разработанная для беспроводных применений. Содержит разъем
для радио ХВее, разъем для батареи Li-Po и встроенную схему подзарядки;
? Mini — самая маленькая плата Arduino;
? Pro — плата, разработанная для опытных пользователей (может являться
частью большего проекта);
Глава 2. Платы семейства Arduino и платы расширения для них 2?
? Pro Mini — как и плата Pro, разработана для опытных пользователей, которым
требуется низкая цена, меньшие размеры и дополнительная функциональность; ,
? Arduino Yun — плата на основе Arduino Leonardo, объединяющая в себе
достоинства двух платформ, поддерживаемых Свободным сообществом: Arduino
и Linux. Получившийся симбиоз предоставляет огромные возможности для
использования Интернета в своих проектах;
? Arduino MKR — серия плат, разработанная компанией Arduino, предоставляет
различные варианты подключения к сети и управления питанием, в большой
степени направлена на Интернет вещей (IoT);
? Arduino Nano 33 — серия плат Nano нового поколения. Платы имеют
практически те же размеры, что и оригинал, но отличаются новыми процессорами,
низким энергопотреблением и наличием беспроводных интерфейсов.
Рассмотрим более подробно некоторые из этих плат.
2.2. Arduino Uno
Плата Arduino Uno (рис. 2.1) построена на микроконтроллере ATmega328. В
отличие от всех предыдущих ее версий, использовавших для связи по USB
микроконтроллер FTDI USB, новая Arduino Uno использует с этой целью микроконтроллер
ATmega8U2.
Характеристики платы Arduino Uno представлены в табл. 2.1.
Рис. 2.1. Плата Arduino Uno
22
Часть I. Arduino — общий обзор
Таблица 2.1. Характеристики платы Arduino Uno
Микроконтроллер
Рабочее напряжение
Входное напряжение (рекомендуемое)
Входное напряжение (предельное)
Цифровые входы/выходы
Аналоговые входы
Постоянный ток через вход/выход
Постоянный ток для вывода 3,3 В
Флеш-память
ОЗУ
EEPROM
Тактовая частота
ATmega328
5В
7-12 В
6-20 В
14 F из которых могут использоваться как выходы
ШИМ)
6
40 мА
50 мА
32 Кбайт, при этом 0,5 Кбайт используются
для загрузчика
2 Кбайт
1 Кбайт
16 МГц
2.3. Arduino Nano
Плата Nano (рис. 2.2), построенная на микроконтроллере ATmega328 (Arduino Nano
3.0) или ATmegal68 (Arduino Nano 2jc), имеет небольшие размеры и может
использоваться в лабораторных работах.
Рис. 2.2. Плата Arduino Nano
Arduino Nano способна получать питание через подключение USB Mini-B или от
внешнего источника питания: нерегулируемого 6-20 В (вывод 30) или
регулируемого 5 В (вывод 27). Источник с самым высоким напряжением выбирается
автоматически.
Характеристики платы Arduino Nano представлены в табл. 2.2.
Глава 2. Платы семейства Arduino и платы расширения для них
23
Таблица 2.2. Характеристики платы Arduino Nano
Микроконтроллер
Рабочее напряжение
Входное напряжение (рекомендуемое)
Входное напряжение (предельное)
Цифровые входы/выходы
Аналоговые входы
Постоянный ток через вход/выход
Постоянный ток для вывода 3,3 В
Флеш-память
ОЗУ
EEPROM
Тактовая частота
ATmega168 или ATmega328
5В
7-12 В
6-20 В
14 F из которых могут использоваться как выходы
ШИМ)
6
40 мА
50 мА
16 Кбайт (ATmega168) или 32 Кбайт (ATmega328),
при этом 2 Кбайт используются для загрузчика
1 Кбайт (ATmega168) или 2 Кбайт (ATmega328)
512 байтов (ATmega168) или 1 Кбайт (ATmega328)
16 МГц
2.4. Arduino Pro Mini
Плата Arduino Pro Mini (рис. 2.3) построена на микроконтроллере ATmegal68.
Рис. 2.3. Плата Arduino Pro Mini
Характеристики платы Arduino Pro Mini представлены в табл. 2.3.
Таблица 2.3. Характеристики платы Atduino Pro Mini
Микроконтроллер
Рабочее напряжение
Входное напряжение
Цифровые входы/выходы
Аналоговые входы
АТтеда168
3,3 или 5 В (в зависимости от модели)
3,35-12 В (модель 3,3 В) или 5-12 В (модель 5 В)
14 F из которых могут использоваться как выходы
ШИМ)
6
24
Часть I. Arduino — общий обзор
Таблица 2.3 (окончание)
Постоянный ток через вход/выход
Флеш-память
ОЗУ
EEPROM
Тактовая частота
40 мА
16 Кбайт B — используются для загрузчика)
1 Кбайт
512 байтов
8 МГц (модель 3,3 В) или 16 МГц (модель 5 В)
Arduino Pro Mini может получать питание: через кабель FTDI, или от платы-
конвертера, или от регулируемого источника питания 3,3 или 5 В (зависит от
модели платформы) через вывод VCC, или от нерегулируемого источника через вывод
RAW.
Выводы питания:
? RAW — для подключения нерегулируемого напряжения;
? VCC — для подключения регулируемых 3,3 или 5 В;
? GND — выводы заземления.
2.5. Arduino LilyPad
Плата Arduino LilyPad (рис. 2.4) разработана так, чтобы ее можно было зашить
в ткань одежды вместе со встроенными источниками питания, датчиками,
проводами и приводами.
Рис. 2.4. Плата Arduino LilyPad
Характеристики платы Arduino LilyPad представлены в табл. 2.4.
Таблица 2.4. Характеристики платы Arduino LilyPad
Микроконтроллер
Рабочее напряжение
Входное напряжение
ATmega168 или ATmega328
2,7-5,5 В
2,7-5,5 В
Глава 2. Платы семейства Arduino и платы расширения для них
25
Таблица 2.4. Характеристики платы Arduino LilyPad
Цифровые входы/выходы
Аналоговые входы
Постоянный ток
через вход/выход
Флеш-память
ОЗУ
EEPROM
Тактовая частота
14 F из которых могут использоваться как выходы ШИМ)
6
40 мА
16 Кбайт (ATmega168) или 32 Кбайт (ATmega328),
при этом 2 Кбайт используются для загрузчика
1 Кбайт (ATmega168) или 2 Кбайт (ATmega323)
512 байтов (ATmega168) или 1 Кбайт (ATmega328)
16 МГц
2.6. Arduino Mega2560
Плата Arduino Mega2560 (рис. 2.5) построена на микроконтроллере ATmega2560.
Рис. 2.5. Плата Arduino Mega2560
Характеристики платы Arduino Mega2560 представлены в табл. 2.5.
Таблица 2.5. Характеристики платы Arduino Mega2560
Микроконтроллер
Рабочее напряжение
Входное напряжение
(рекомендуемое)
АТтеда2560
5В
7-12 В
26
Часть /. Arduino — общий обзор
Таблица 2.5 (окончание)
Входное напряжение (предельное)
Цифровые входы/выходы
Аналоговые входы
Постоянный ток через вход/выход
Постоянный ток для вывода 3,3 В
Флеш-память
ОЗУ
EEPROM
Тактовая частота
6-20 В
54 A4 из которых могут использоваться
как выходы ШИМ)
16
40 мА
50 мА
256 Кбайт, из которых 8 Кбайт используются
для загрузчика
8 Кбайт
4 Кбайт
16 МГц
2.7. Arduino Leonardo
Плата Arduino Leonardo (рис. 2.6) построена на базе микроконтроллера ATmega32U4,
имеющего, в отличие от всех других микропроцессоров, встроенную поддержку
для USB-соединения.
Характеристики платы Arduino Leonardo представлены в табл. 2.6.
Рис. 2.6. Плата Arduino Leonardo
Глава 2. Платы семейства Arduino и платы расширения для них
27
Таблица 2.6. Характеристики платы Arduino Leonardo
Микроконтроллер
Рабочее напряжение
Входное напряжение
(рекомендуемое)
Входное напряжение (предельное)
Цифровые входы/выходы
Аналоговые входы
Постоянный ток через вход/выход
Постоянный ток для вывода 3,3 В
Флеш-память
ОЗУ
EEPROM
Тактовая частота
ATmega32U4
5В
7-12 В
6-20 В
20 G из которых могут использоваться как выходы
ШИМ)
12
40 мА
50 мА
32 Кбайт, из которых 4 Кбайт используются для
загрузчика
2 Кбайт
1 Кбайт
16 МГц
2.8. Arduino Due
Arduino Due (рис. 2.7) представляет собой первую плату Arduino на основе
32-битного микроконтроллера с ARM-ядром — процессора Atmel SAM3X8E ARM
Cortex-M3.
В отличие от других плат Arduino, максимальное рабочее напряжение, которое
выдерживают входы/выходы Arduino Due, составляет 3,3 В.
Рис. 2.7. Плата Arduino Due
28
Часть I. Arduino — общий обзор
Характеристики платы Arduino Due представлены в табл. 2.7.
Таблица 2.7. Характеристики платы Arduino Due
Микроконтроллер
Рабочее напряжение
Входное напряжение
(рекомендуемое)
Входное напряжение (предельное)
Цифровые входы/выходы
Аналоговые входы
Аналоговые выходы
Постоянный ток через вход/выход
Постоянный ток для вывода 3,3 В
Постоянный ток для вывода 5 В
Флеш-память
ОЗУ
Тактовая частота
AT91SAM3X8E
3,3 В
7-12 В
6-20 В
54 A2 из которых могут использоваться как выходы
ШИМ)
12
2(ЦАП)
50 мА
800 мА
800 мА
512 Кбайт
96 Кбайт (два банка: 64 и 32 Кбайт)
84 МГц
2.9. Arduino Yun
Arduino Yun (рис. 2.8) — это плата на основе Arduino Leonardo, объединяющая
в себе, как уже упоминалось ранее, достоинства двух платформ, поддерживаемых
Свободным сообществом: Arduino и Linux. Получившийся симбиоз предоставляет
огромные возможности для использования Интернета в своих проектах.
Arduino-часть платы содержит микроконтроллер ATmega32U4, работающий на
частоте 16 МГц. «Распиновка» Arduino Yun аналогична Arduino Leonardo, поэтому
вместе с Arduino Yun вы можете использовать большинство плат расширения
Arduino.
Linux-часть платы Arduino Yun использует микрокомпьютер Atheros AR9331,
работающий под управлением операционной системы Linino — специально
подготовленной версии OpenWRT (популярного дистрибутива Linux для встраиваемых
систем).
Микрокомпьютер Atheros AR9331 работает на частоте 400 МГц, имеет 64 Мбайт
оперативной и 16 Мбайт флеш-памяти, встроенные интерфейсы Wi-Fi и Ethernet,
USB-host и слот для карты microSD. Linino содержит в себе пакетный менеджер
opkg, который позволяет устанавливать большое количество Linux-приложений,
а также интерпретатор языка Python 2.7, с помощью которого вы можете писать для
Linino свои приложения.
Глава 2. Платы семейства Arduino и платы расширения для них 29
Рис. 2.8. Плата Arduino Yun
Память для Linux-приложений может быть расширена с помощью съемного
носителя (карты microSD или USB-флешки).
2.10. Arduino MKR WiFi 1010
Arduino MKR WiFi 1010 (рис. 2.9) -— это платформа из семейства MKR для
разработчиков с минимальным опытом работы в сети, желающих создавать проекты IoT.
Плата состоит из трех основных блоков:
? микроконтроллера ATSAMD21G18 с тактовой частотой 48 МГц и
вычислительным ядром Cortex-M0+. Благодаря своей 32-битной архитектуре контроллер
справляется с ресурсоемкими математическими вычислениями, обрабатывает
аналоговые сигналы с большой точностью и воспроизводит музыку через
встроенный ЦАП;
? модуля беспроводной связи NINA-W10 от компании u-blox со встроенным
чипом ESP32. Модуль обеспечивает беспроводной обмен данными в диапазоне
2,4 ГГц по протоколам Wi-Fi и Bluetooth. Регулировка выходной мощности
позволяет достичь оптимального соотношения между дальностью связи,
скоростью передачи данных и энергопотреблением;
? крипточипа ЕСС508 для защиты передаваемых данных с использованием
шифрования SHA-256. Крипточип дает возможность выполнять HTTPS-запросы без
нагрузки на основной процессор.
Поскольку платформа выполнена на архитектуре ARM Cortex-M0+, «родное»
напряжение ее выводов — 3,3 В. То есть выходы для логической единицы выдают
30 Часть I. Arduino —- общий обзор
Рис. 2.9. Плата Arduino MKRWiFi 1010
3,3 В и рассчитаны принимать напряжение не более этого. Большее напряжение
повредит микроконтроллер.
2.11. Arduino Nano 33
Arduino Nano 33 — серия плат Nano нового поколения. Платы, как уже отмечалось
ранее, имеют практически те же размеры, что и оригинал, но отличаются новыми
процессорами, низким энергопотреблением и наличием беспроводных
интерфейсов. К настоящему моменту выпущено четыре платы этой серии (рис. 2.10): Arduino
Nano Every, Nano 33 IoT, Nano 33 BLE и Nano 33 BLE Sense.
Рис. 2.10. Семейство Arduino Nano 33:
Nano Every, Nano 33 IoT, Nano 33 BLE, Nano 33 BLE Sense (слева направо)
Глава 2. Платы семейства Arduino и платы расширения для них 31_
П В отличие от оригинальной платы Arduino Nano, несущей на борту 8-битный
микроконтроллер Microchip ATmega328P, плата Arduino Nano Every построена
на основе гораздо более мощного микроконтроллера Microchip ATmega4809
с микросхемой ATSAMD11 ARM Cortex МО и процессором для USB-to-serial
связи.
? Плата Arduino Nano 33 IoT основана на микросхеме ATSAMD21 ARM Cortex-
МО с поддержкой Wi-Fi и Bluetooth LE, предоставляемой встроенным
микроконтроллером Espressif ESP32 в форме модуля NINA-W102 u-blox. Плата также
оснащена 9-осевым инерциальным измерительным устройством (Inertial
measurement unit, IMU), крипточипом для безопасного хранения сертификатов и
общих ключей и совместима с новым облаком Arduino IoT.
? В отличие от Nano Every и Nano 33. IoT, плата Arduino Nano 33 BLE не основана
на процессоре с микрочипом. Вместо этого она оснащена модулем u-blox NINA-
В306, который, в свою очередь, построен на базе платформы Nordic nRF52840
архитектуры ARM Cortex-M4F. Плата Nano 33 BLE также несет на борту
9-осевой IMU.
? Плата Nano 33 BLE Sense построена на том же модуле u-blox NINA-B306, но —
в дополнение к 9-осевой IMU — поставляется с гораздо большим набором
датчиков: давления, влажности, температуры и света, а также датчиком жестов и
встроенным микрофоном.
2.12. Платы расширения для Arduino
Большую популярность плата Arduino приобрела не только из-за низкой стоимости,
легкости разработки и программирования, но главным образом благодаря наличию
плат расширения (так называемых шилдов\ добавляющих Arduino дополнительную
функциональность. Шилды (кроме маленьких модулей и платы LilyPad)
подключаются к Arduino с помощью имеющихся на них штыревых разъемов (рис. 2.11).
Существует множество различных по функциональности шилдов— от
простейших, предназначенных для макетирования, до сложных, представляющих собой
отдельные многофункциональные устройства.
Далее приведено краткое описание некоторых шилдов:
? Ethernet Shield — обеспечивает подключение к Интернету;
? ХВее Shield — обеспечивает при помощи модуля Maxstream Xbee Zigbee
беспроводную связь нескольких устройств Arduino;
? MicroSD Shield — обеспечивает запись данных на карты microSD;
? МРЗ Shield — плата для воспроизведения звука в форматах Ogg Vorbis, MP3,
ААС, WMA и MIDI и записи звука в формате Ogg Vorbis;
? Motor Shield — обеспечивает управление двигателями постоянного тока;
? GSM/GPRS Shield— позволяет отправлять SMS-сообщения, делать
телефонные звонки, обмениваться данными по GPRS;
32 Часть I. Arduino — общий обзор
Рис. 2.11. Модульная структура установки плат расширения для Arduino
? Cosmo WiFi Connect — обеспечивает организацию беспроводной сети
стандарта ЕЕЕЕ 802.1 lb/g.
Существуют также шилды: Video Overlay Shield — для наложения текста на
аналоговое видео, EasyVR Arduino Shield— многоцелевой модуль распознавания
речи, Music Shield — профессиональный аудиокодек и др.
Количество плат расширения (шилдов) постоянно растет. Ознакомиться с их
списком можно на официальном сайте проекта Arduino по адресу: http://www.
arduino.cc/playground/Main/SimilarBoards#goShie.
ЧАСТЬ II
00
Среды разработки
и язык программирования
плат Arduino
Глава 3. Среда разработки Arduino IDE
Глава 4. Облачная среда разработки Arduino Create
Глава 5. Программирование плат Arduino
ГЛАВА 3
Среда разработки Arduino IDE
Разработка собственных приложений на базе плат, совместимых с архитектурой
Arduino, осуществляется в бесплатной среде разработки Arduino IDE. Среда
предназначена для написания, компиляции и загрузки собственных программ в память
микроконтроллера, установленного на плате Arduino-совместимого устройства.
Основу среды разработки составляет язык Processing/Wiring— это фактически
обычный язык C++, дополненный простыми и понятными функциями для
управления вводом/выводом на контактах. Существуют версии среды для операционных
систем Windows, macOS и Linux.
Последнюю версию среды Arduino A.8.13) и бета-версию Arduino (с
экспериментальными возможностями) можно скачать со страницы загрузки официального
сайта: http://arduino.cc/en/Main/Software.
Примечание
В главе 4 вашему вниманию представлена новая облачная среда разработки Arduino
Create.
3.1. Установка Arduino IDE в Windows
Отправляемся на страницу http://arduino.cc/en/Main/Software (рис. 3.1), выбираем
версию для операционной системы Windows и скачиваем архивный файл. Он
занимает чуть более 80 Мбайт и содержит все необходимое, в том числе и драйверы. По
окончании загрузки распаковываем скачанный файл в удобное для себя место.
Теперь необходимо установить драйверы. Подключаем плату Arduino к
компьютеру. На ней должен загореться индикатор питания — зеленый светодиод. Windows
начинает попытку установки драйвера, которая заканчивается сообщением:
Программное обеспечение драйвера не было установлено.
Открываем Диспетчер устройств. В составе устройств находим значок Arduino
Uno — устройство отмечено восклицательным знаком. Щелкаем правой кнопкой
мыши на значке Arduino Uno и в открывшемся окне выбираем пункт Обновить
драйверы и далее пункт Выполнить поиск драйверов на этом компьютере.
Указываем путь к драйверу — ту папку на компьютере, куда распаковывали скачанный
36^ Часть II. Среды разработки и язык программирования плат Arduino
архив. Пусть это будет папка drivers каталога установки Arduino. Игнорируем все
предупреждения Windows и получаем в результате сообщение: Обновление
программного обеспечения для данного устройства завершено успешно. В
заголовке окна будет указан и СОМ-порт, на который установлено устройство.
Осталось установить и запустить среду разработки Arduino IDE.
Рис. 3.1. Страница загрузки официального сайта Arduino
3.2. Установка Arduino IDE в Linux
В Linux Ubuntu среда Arduino DDE устанавливается просто — она находится в репо-
зитории стандартных приложений Linux. Выбираем Arduino IDE из списка
доступных программ в меню Ubuntu: Приложения | Центр приложений Ubuntu |
Загрузить приложение. В списке разделов выбираем Инструменты разработчика,
в списке следующего уровня— Все приложения и в следующем открывшемся
списке— Arduino IDE (рис. 3.2). Щелкаем левой кнопкой мыши на значке этой
программы— справа от нее появляется кнопка Установить, нажимаем на эту
кнопку, и среда устанавливается автоматически.
Глава 3. Среда разработки Arduino IDE
37
Рис. 3.2. Выбор программы из центра приложений Ubuntu
3.3. Настройка среды Arduino IDE
Среда разработки Arduino (рис. 3.3) состоит из:
О редактора программного кода;
? области сообщений;
? окна вывода текста;
? панели инструментов с кнопками часто используемых команд;
О нескольких меню.
Примечание
Все примеры работы с Arduino IDE в этом издании книги показаны в наиболее
распространенной версии среды — 1.8.5.
Программа, написанная в среде Arduino, носит название скетч. Скетч пишется
в текстовом редакторе, который имеет цветовую подсветку создаваемого
программного кода. Во время сохранения и экспорта проекта в области сообщений
появляются пояснения и информация об ошибках. Окно вывода текста показывает
сообщения Arduino, включающие полные отчеты об ошибках и другую
информацию. Кнопки панели инструментов позволяют проверить и записать программу,
создать, открыть и сохранить скетч, открыть мониторинг последовательной шины.
Разрабатываемым скетчам дополнительная функциональность может быть
добавлена с помощью библиотек, представляющих собой специальным образом
оформленный программный код, реализующий некоторый функционал, который можно
подключить к создаваемому проекту. Специализированных библиотек существует
множество. Обычно библиотеки пишутся так, чтобы упростить решение той или
38 Часть II. Среды разработки и язык программирования плат Arduino
Рис. 3.3. Arduino IDE — среда разработки
иной задачи и скрыть от разработчика детали программно-аппаратной реализации.
Среда Arduino IDE поставляется с набором стандартных библиотек: Serial,
EEPROM, SPI, Wire и др. Они находятся в подкаталоге libraries каталога установки
Arduino. Необходимые библиотеки могут быть также загружены с различных
ресурсов (см. главу 7). Пацка загруженной библиотеки копируется в каталог
стандартных библиотек (подкаталог libraries каталога установки Arduino). Внутри
каталога с именем библиотеки находятся файлы *.срр, *.h. Многие библиотеки
снабжаются примерами, расположенными в папке examples каталога установки Arduino.
Если библиотека установлена правильно, то она появляется в меню Скетч | Import
Library. Выбор библиотеки в меню приведет к добавлению в исходный код строки:
#include <имя библиотеки.h>
Эта директива подключает заголовочный файл с описанием объектов, функций
и констант библиотеки, которые теперь могут быть использованы в проекте. Среда
Arduino будет компилировать создаваемый проект вместе с указанной библиотекой.
Электронный архив
Необходимые для работы с проектами книги подгружаемые библиотеки размещены
в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2).
Глава 3. Среда разработки Arduino IDE 39
Рис. 3.4. Arduino IDE — выбор платы
Перед загрузкой скетча требуется задать необходимые параметры: в меню Сервис |
Плата (Tools | Board) выбрать используемую плату (рис. 3.4) и в меню Сервис |
Последовательный порт (Tools | Serial Port) — задействованный
последовательный порт (рис. 3.5).
Современные платы Arduino перед загрузкой перезагружаются автоматически. На
старых платах необходимо нажать кнопку перезагрузки. На большинстве плат во
время процесса загрузки будут мигать светодиоды RX и ТХ.
При загрузке скетча используется загрузчик (bootloader) Arduino — небольшая
программа, загружаемая в микроконтроллер на плате. Она позволяет загружать
программный код без использования дополнительных аппаратных средств. Работа
загрузчика распознается по миганию светодиода на цифровом выводе D13.
Монитор последовательного порта (Serial Monitor) отображает данные, посылаемые
в плату Arduino (через порт USB или порт последовательной шины). Для отправки
данных необходимо ввести в соответствующее поле текст и нажать кнопку
Послать (Send) или клавишу <Enter> (рис. 3.6). Предварительно следует из
выпадающего списка выбрать скорость передачи, соответствующую значению serial.begin
в скетче. На macOS или ОС Linux при подключении мониторинга
последовательной шины плата Arduino будет перезагружена (скетч начнется сначала).
40 Часть II. Среды разработки и язык программирования плат Arduino
Рис. 3.5. Arduino IDE — выбор последовательного порта
Рис. 3.6. Arduino IDE — монитор последовательного порта
ГЛАВА 4
Облачная среда разработки
Arduino Create
Arduino Create — это новая платформа, призванная заменить существующую среду
разработки Arduino IDE (см. главу 3). Как пишут сами создатели платформы: «Это
важный шаг в экосистеме Arduino, и мы надеемся изменить способ взаимодействия
с вашими проектами и сообществом».
Arduino Create сочетает в себе новый Arduino Web Editor (облачный редактор
Arduino), инструменты для быстрого старта, доступ к Arduino-магазину и форуму,
а также Project Hub, базирующийся на ресурсе Hackster.io, и сетевой облачный
сервис Arduino Cloud.
Основная идея новой платформы состоит в том, что разработчик теперь имеет
возможность писать код и загружать скетчи к любой плате Arduino непосредственно
из браузера с помощью облачного редактора Arduino Web Editor — без
необходимости что-либо устанавливать на свой компьютер. При использовании новой
платформы папка со скетчами Sketchbook будет храниться в облаке Arduino и станет
доступна с любого устройства.
Возможности Arduino Create покрывают практически всю область разработки: вы
сможете создавать код прямо у себя в браузере и отправлять его на свою плату
Arduino, читать документацию и описание лучших способов работы с Arduino,
общаться с коллегами, исследовать проекты других разработчиков.
4.1. Начало работы в среде Arduino Create
Итак, заходим на сайт Arduino Create: https://create.arduino.cc/ (рис. 4.1). Сначала
там необходимо зарегистрироваться (кнопка SIGN Ш). На странице регистрации
заполняем форму и нажимаем на кнопку CREATE ACCOUNT (рис. 4.2).
Активация профиля осуществляется при переходе по ссылке в письме, пришедшем на
указанную вами почту.
Войдя в профиль, мы можем работать на сайте. Выбираем пункт Arduino Web
Editor. Для дальнейшей работы необходимо установить плагин arduino-create-agent
(рис. 4.3). Этот плагин позволит портам вашего компьютера общаться с
веб-редактором в браузере, загружать скетчи из браузера в .платы, подключенные к USB
или к сети, использовать другие облачные сервисы.
42
Часть II. Среды разработки и язык программирования плат Arduino
Рис. 4.1. Стартовая страница сервиса Arduino Create
Рис. 4.2. Форма регистрации сервиса Arduino Create
Глава 4. Облачная среда разработки Arduino Create 43
Рис. 4.3. Форма загрузки плагина сервиса Arduino Create
4.2. Загрузка и выполнение пробного скетча
После установки плагина (рис. 4.4) выберем пример Blynk (Examples | Basics |
Biynk) и загрузим его в свою плату Arduino (рис. 4.5). Не забываем также выбрать
тип платы Arduino и порт подключения (рис. 4.6).
Рис. 4.4. Плагин arduino-create-agent установлен
44
Часть II. Среды разработки и язык программирования плат Arduino
Рис. 4.5. Загрузка примера BIynk в плату Arduino
Рис. 4.6. Выбор типа платы и порта подключения
ГЛАВА 5
Программирование плат Arduino
Материал этой главы основан ца переводе с официального сайта проекта Arduino
(http://arduino.cc) и представлен по лицензии Creative Commons Attribution-
ShareAlike 3.0 License (http://creativecommons.Org/licenses/by-sa/3.0/deed.ru).
5.1. Базовые знания
5.1.1. Цифровые выводы
Выводы плат Arduino могут работать и как входы, и как выходы. Аналоговые
входы Arduino (на микроконтроллере ATmega) могут конфигурироваться и работать
так же, как и цифровые порты ввода/вывода.
Выводы Arduino настроены как порты ввода, поэтому для них не требуется
декларации в функции pinMode (). Сконфигурированные порты ввода находятся в высо-
коимпедансном состоянии. Это означает, что порт ввода дает слищком малую
нагрузку на схему, в которую он включен. Для перевода порта ввода из одного
состояния в другое необходимо малое значение тока. Если к выводу ничего не
подключено, то значения на нем будут принимать случайные величины, наводимые
электрическими помехами. Поэтому если на порт ввода не поступает сигнал, то
рекомендуется задать порту какое-либо известное состояние. Это делается
добавлением подтягивающих резисторов 10 кОм, подключающих вход либо к питанию
+5 В, либо к земле.
Микроконтроллер ATmega имеет программируемые встроенные подтягивающие
резисторы 20 кОм. Программирование этих резисторов осуществляется так:
pinMode(pin, INPUT); // назначить выводу порт ввода
digitalWrite(pin, HIGH); // включить подтягивающий резистор
Выводы, сконфигурированные как порты вывода, находятся в низкоимпедансном
состоянии. Эти выводы могут пропускать через себя весьма большой ток. Так,
выводы микросхемы ATmega могут быть источником тока до 40 мА, однако такого
значения тока все же недостаточно для большинства реле, соленоидов и
двигателей.
46^ Часть //. Среды разработки и язык программирования плат Arduino
Короткие замыкания выводов Arduino или попытки подключить энергоемкие
устройства могут повредить выходные транзисторы вывода или весь микроконтроллер
ATmega.
5.1.2. Аналоговые входы
Микроконтроллеры ATmega, используемые в Arduino, содержат шестиканальный
аналого-цифровой преобразователь (АЦП). Разрешение преобразователя составляет
10 битов, что позволяет на выходе получать значения от 0 до 1023. Аналоговые
входы могут использоваться как цифровые выводы портов ввода/вывода, при этом
они имеют номера от 14 до 19:
pinModeA4,OUTPUT);
digitalWriteA4, HIGH);
Для вывода, работавшего ранее как цифровой порт вывода, команда anaiogRead
будет работать некорректно. В этом случае рекомендуется сконфигурировать его
как аналоговый вход.
5.1.3. Широтно-импульсная модуляция
Широтно-импульсная модуляция (ШИМ)— это операция получения
изменяющегося аналогового значения посредством цифровых устройств. Подавая на выход
сигнал, состоящий из высоких и низких уровней, мы моделируем напряжение между
максимальным значением E В) и минимальным @ В). Длительность включения
максимального значения называется шириной импульса. Для получения различных
аналоговых величин ширину импульса изменяют. В результате на выходе будет
получена величина напряжения, равная площади под импульсами (рис. 5.1).
Вызов функции anaiogwrite () с масштабом 0-255 означает, что значение
anaiogwriteB55) будет соответствовать 5 В A00%-ный рабочий цикл —
постоянное включение 5 В), а значение anaiogwrite A27) — 2,5 В E0%-ный рабочий цикл).
5.1.4. Память в Arduino
В микроконтроллерах ATmegal68, ATmega328, ATmegal280, ATmega2560,
используемых на платформах Arduino, существует три вида памяти:
? флеш-память — используется для хранения скетчей;
? ОЗУ (статическая оперативная память) — служит для хранения и работы пере-
. менных;
? EEPROM (энергонезависимая память) — применяется для хранения постоянной
информации.
Флеш-память и EEPROM являются энергонезависимыми видами памяти (данные
сохраняются при отключении питания). ОЗУ представляет собой энергозависимую
память.
Глава 5. Программирование плат Arduino
47
1
_- _ _ _ __
90%
10%
50%
II И J
Эквивалентное постоянное напряжение |
Эквивалентное постоянное напряжение |
¦; тс зт л
ц
Эквив;
алентн
юепо
стоян^
юена
пряжение ]
о
Рис. 5.1. Широтно-импульсная модуляция
Микроконтроллер ATmegal68 имеет:
? 16 Кбайт флеш-памяти B Кбайт используются для хранения загрузчика);
? 1024 байта ОЗУ;
? 512 байтов EEPROM.
Для ATmega328 эти показатели следующие:
? 32 Кбайт флеш-памяти B Кбайт используются для хранения загрузчика);
? 2 Кбайт ОЗУ;
? 1024 байта EEPROM.
48^ Часть II. Среды разработки и язык программирования ллат Arduino
Для ATmegal280 эти показатели следующие:
? 128 Кбайт флеш-памяти B Кбайт используются для хранения загрузчика);
? 8 Кбайт ОЗУ;
? 4096 байтов EEPROM.
Для ATmega2560 эти показатели следующие:
? 256 Кбайт флеш-памяти B Кбайт используются для хранения загрузчика);
? 16 Кбайт ОЗУ;
? 9182 байта EEPROM.
При отсутствии свободного места в ОЗУ могут произойти сбои программы.
5.2. Структура программы
Arduino программируется на языке Wiring, которого на самом деле не существует,
как не существует и компилятора Wiring, — написанные на Wiring программы
преобразуются в программу на языке C/C++ и затем компилируются компилятором
AVR-GCC. Фактически используется специализированный для микроконтроллеров
AVR вариант C/C++.
5.2.1. Функции setupf) и 1оор()
Базовая структура программы для Arduino состоит по меньшей мере из двух
обязательных частей: функций setup () и loop (). Перед функцией setup () идет
объявление переменных, подключение библиотек. Функция setup о запускается один раз
после каждого включения питания или сброса платы Arduino. Она используется для
инициализации переменных, установки режима работы портов и прочих
подготовительных для основного цикла программы действий. Функция setup ()
обязательно должна быть включена в программу, даже если не выполняет никаких действий.
Функция loop () в бесконечном цикле выполняет основную работу программы —
последовательно исполняет команды, которые описаны в ее теле.
Пример простейшей программы представлен в листинге 5.1.
void setup()
{
Serial.begin(9600);
}
void loop()
{
Serial.println (inillis ()) ;
delayA000);
Глава 5. Программирование плат Arduino
5.3. Синтаксис и операторы
5.3.1. Управляющие операторы
5.3.1.1. Оператор /У (условие) и операторы сравнения ==, /=,<,>
Оператор if. используется в сочетании с операторами сравнения. Он проверяет,
достигнута ли истинность условия — например, превышает ли входное значение
заданное число. Формат оператора if следующий:
if (someVariabJe > 50){
// выполнять действия
}
Здесь программа проверяет, больше ли значение somevariabie чем 50 или нет. Если
да, то выполняются определенные действия. Говоря иначе, если выражение в
круглых скобках истинно, выполняются операторы внутри фигурных скобок. Если нет,
программа пропускает этот код.
Выражения, которые вычисляются внутри круглых скобок, могут состоять из
одного или нескольких операторов.
Операторы сравнения:
? х == у (х равно у);
О х != у (х не равно у);
? х < у (х меньше чем у);
? х > у (х больше чем у);
? х <= у (х меньше чем или равно у);
? х >= у (х больше чем или равно у).
5.3.1.2. Оператор if.. .else
Конструкция if.. .else предоставляет больший контроль над процессом
выполнения кода, чем базовый оператор if, — она позволяет сделать выбор «либо, либо».
Например:
if (pinInput=HIGH)
{doFunlO;}
else
{doFun2();}
В отличие от одиночного оператора if, оператор if.. .else дает возможность
осуществлять сразу несколько взаимоисключающих проверок. Каждая проверка
позволяет переходить к следующему за ней оператору не раньше, чем получит
логический результат истина. Когда проверка с результатом истина найдена,
запускается вложенный в нее блок операторов, и затем программа игнорирует все
следующие строки в конструкции if.. .else. Если ни одна из проверок не получила
результат истина, по умолчанию выполняется блок операторов в else, если по-
50 Часть II. Среды разработки и язык программирования плат Arduino
следний присутствует, и устанавливается действие по умолчанию. Конструкция
else...if может быть использована как с заключительным else, так и без него,
и наоборот. Допускается неограниченное число таких переходов else...if
(листинг 5.2).
if (pinAnaloglnput < 100)
{doFunlO;}
else if (pinAnaloglnput >= 150)
{doFun2();}
else
{doFun3();>
Другой способ создания переходов со взаимоисключающими проверками
использует оператор switch case (см. далее).
5.3.1.3. Оператор for
Конструкция for служит для повторения блока операторов, заключенных в
фигурные скобки. Она имеет счетчик приращений, обычно использующийся для
определения количества повторений и завершения цикла. Оператор for подходит для
любых повторяющихся действий и часто применяется в сочетании с массивами
коллекций данных/выводов.
Заголовок цикла for состоит из трех частей:
for (initialization; condition; increment) {операторы, выполняющиеся в цикле}
Инициализация (initialization) выполняется самой первой и один раз. Каждый раз
в цикле проверяется условие (condition), и если оно верно, выполняется блок
операторов и приращение (increment), затем условие проверяется вновь. Когда
логическое значение условия становится ложным, цикл завершается. В листинге 5.3
приведен пример затемнения светодиода с использованием ШИМ-вывода.
// Затемнение светодиода с использованием ШИМ-вывода
int PWMpin = 10; // Светодиод последовательно с R=470 Ом на 10 выводе
void setup()
{;}
void loop ()
{
for (int i=0;.i <= 255; i
{
analogWrite(PWMpin, i);
delayA0);
Глава 5. Программирование плат Arduino 51_
5.3.1.4. Оператор switch
Конструкция switch.. .case управляет процессом выполнения программы, позволяя
программисту задавать альтернативный код, который будет выполняться при
разных условиях. Оператор switch сравнивает значение переменной со значением,
определенным в операторах case. Когда найден оператор case, значение которого
равно значению переменной, выполняется программный код, записанный в этом
операторе. Ключевое слово break является командой выхода из оператора case и
обычно используется в конце каждого case. Без оператора break оператор switch
будет продолжать вычислять следующие выражения, пока не достигнет break или
конца оператора switch. Синтаксис команды switch.. .case представлен в
листинге 5.4.
switch (var)
{
case label1:
// код для выполнения
break;
case Iabel2:
// код для выполнения
break;
case Iabel3:
// код для выполнения
break;
default:
// код для выполнения
break;
Параметры:
? var — переменная, которая вычисляется для сравнения с вариантами в case;
? label — значение, с которым сравнивается значение переменной.
5.3.1.5. Оператор while
Оператор while будет вычислять в цикле непрерывно и бесконечно до тех пор,
пока выражение в круглых скобках не станет равно логическому ложно. Что-то
должно изменять значение проверяемой переменной, иначе выход из цикла while
никогда не будет достигнут. Это изменение может происходить как в программном
коде, например, при увеличении переменной, так и во внешних условиях,
например, при тестировании датчика. Синтаксис команды следующий:
while(выражение)
{
// операторы
52 Часть II. Среды разработки и язык программирования плат Arduino
Пример использования оператора while представлен в листинге 5.5.
var i=0;
while($i<100)
{
// операторы
5.3.1.6. Оператор do...while
Цикл do работает так же, как и цикл while, за исключением того, что условие
проверяется в конце цикла. Таким образом, цикл do будет всегда выполняться хотя бы
один раз. Пример использования оператора do ... while представлен в листинге 5.6.
do {
delayE0); // подождать, пока датчики стабилизируются
х = readSensors(); // проверить датчики
} while (х < 100);
5.3.1.7. Оператор break
Оператор break используется для принудительного выхода из циклов do, for или
while, не дожидаясь завершения цикла по условию. Он также применяется для
выхода из оператора switch. Пример приведен в листинге 5.7.
for (х = 0; х < 255; х ++)
{
digitalWrite(PWMpin, x);
sens = analogRead(sensorPin);
if (sens > threshold)
{ // выходим из цикла, если есть сигнал с датчика
х = 0;
break;
}
delayE0);
5.3.1.8. Оператор continue
Оператор continue пропускает оставшиеся операторы в текущем шаге цикла.
Вместо них выполняется проверка условного выражения цикла, которая происходит
при каждой следующей итерации. Пример приведен в листинге 5.8.
Глава 5. Программирование плат Arduino 53
for (x = 0; х < 255; х ++)
{
if (х > 40 && х < 120)
{ // если истина, то прыгаем сразу на следующую итерацию цикла
continue;
}
digitalWrite(PWMpin, x);
delayE0);
5.3.1.9. Оператор return
Оператор return прекращает вычисления в функции и возвращает значение из
прерванной функции в вызывающую, если это нужно. Пример возврата значения из
функции в зависимости от значения на входе аналогового входа представлен в
листинге 5.9.
int checkSensor()
{
if (analogRead(O) > 200)
return 1;
else{
return 0;
5.3.2. Синтаксис
5.3.2.1.; (semicolon, точка с запятой)
Точка с запятой ; — используется для обозначения конца оператора.
int a = 13;
5.3.2.2. О (curly braces, фигурные скобки)
Фигурные скобки {} — важный элемент языка программирования С. Открывающая
скобка { должна всегда сопровождаться закрывающей скобкой }. Это условие
известно как парность (симметричность) фигурных скобок.
Основные способы использования фигурных скобок:
? функции:
• void Название Функции (тип данных аргумента) { оператор(ы) };
54 Часть II. Среды разработки и язык программирования плат Arduino
? циклы:
• while (логическое выражение){ оператор(ы)};
• do { оператор(ы)} while (логическое выражение);
• for (инициализация; условие окончания цикла; приращения цикла)
{ оператор (ы)} ;.
? условные операторы:
• if (логическое выражение) {оператор(ы)}.
5.3.2.3. Комментарии: //(single line comment, однострочный),
/* V (multi-line comment, многострочный)
Комментарии — это строки в программе, которые используются для
информирования вас самих или других о том, как работает программа. Они игнорируются
компилятором и не занимают места в памяти микроконтроллера.
Есть два способа пометить строку как комментарий:
? однострочный комментарий — // ;
? многострочный комментарий — /* ... */ .
Пример приведен в листинге 5.10.
х = 5; // Это комментарий в одной строке. Все после двойного
// слеша - комментарий до конца строки
/* это многострочный комментарий - используйте его для закомментирования
целых кусков кода */
5.3.3. Арифметические операторы
5.3.3.1. = (assignment, оператор присваивания)
Присваивает переменной слева от оператора значение переменной или выражения,
находящееся справа (листинг 5.11).
int sensVal; // объявление переменной типа integer
senVal=analogRead@); // присваивание переменной sensVal значение,
// считанное с аналогового входа 0
Переменная слева от оператора присваивания (±) должна быть способна сохранить
присваиваемое значение. Если оно выходит за диапазон допустимых значений, то
сохраненное значение будет не верно. Необходимо различать оператор
присваивания (=) и оператор сравнения (==) — двойной знак равенства, который
осуществляет проверку на равенство.
Глава 5. Программирование плат Arduino 55_
5.3.3.2. + (сложение), - (вычитание), * (умножение), /(деление)
Операторы +, -, * и / возвращают результат выполнения соответствующих
арифметических действий над двумя операндами. Возвращаемый результат будет зависеть
от типа данных операндов — например, 9/4 возвратит 2, т. к. операнды 9 и 4
имеют тип int. Также надо следить за тем, чтобы результат не вышел за диапазон
допустимых значений для используемого типа данных. Так, например, сложение I
с переменной типа int и значением 32 767 возвратит -32 768. Если операнды
имеют разные типы, то для вычислений будет использован тип с более «широким»
диапазоном. Если один из операндов имеет тип float или double, то для
вычислений будет использована арифметика «с плавающей запятой».
5.3.3.3. % (modulo)
Возвращает остаток от деления одного целого (int) операнда на другой. Примеры:
х = 9 % 5; // х имеет значение 4
х=5%5; // х имеет значение О
Нельзя применить к типу float.
5.3.4. Операторы сравнения
Операторы сравнения:
? х == у (х равно у);
? х ! = у (х не равно у);
? х < у (х меньше чем у);
? х > у (х больше чем у);
? х <= у (х меньше чем или равно у);
? х >= у (х больше чем или равно у).
5.3.5. Логические операторы
Логические операторы чаще всего используются в проверке условия оператора if.
5.3.5.1. && (логическое И)
Истина, если оба операнда истина (true). Пример:
if (digitalReadB) = HIGH && digitalReadC) == HIGH)
Serial.println("ok");
5.3.5.2. || (логическое ИЛИ)
Истина, если хотя бы один операнд истина. Пример:
if (digitalReadB) = || digitalReadC) == HIGH)
Serial.println("ok");
56^ Часть II. Среды разработки и язык программирования плат Arduino
5.3.5.3. / (логическое отрицание)
Истина, если операнд false, и наоборот. Пример:
if (!(digitalReadB)== HIGH))
Serial.println("ok");
5.3.6. Унарные операторы
5.3.6.1. ++ (увеличение значения), /— (уменьшение значения)
Унарные (имеющие один операнд) операторы ++ и — соответственно увеличивают
и уменьшают значение переменной (листинг 5.12).
х++; // увеличивает значение х на единицу и возвращает старое значение х
++х; // увеличивает значение х на единицу и возвращает новое значение х
х— ; // уменьшает значение х на единицу и возвращает старое значение х
—х ; // уменьшает значение х на единицу и возвращает новое значение х
5.3.6.2. +=,-=,*=, /=
Короткий способ записи арифметических действий над переменной и одним
операндом (листинг 5.13).
х += у; // эквивалент записи х = х + у;
х -= у; // эквивалент записи х = х - у;
х *= у; // эквивалент записи х = х * у;
х /= у; // эквивалент записи х = х / у;
5.4. Данные
5.4.1. Типы данных
Компилятор Arduino определяет следующие типы данных:
boolean, char, byte, int, unsigned int, long, unsigned 'long, float, double, string,
массив (array), void.
Рассмотрим эти типы данных более подробно.
5.4.1.1. boolean
Логический (булевый) тип данных — boolean. Может принимать одно из двух
значений: true или false. Данные типа boolean занимают в памяти один байт.
Глава 5. Программирование плат Arduino 57_
5.4.1.2. char
Переменная типа char занимает 1 байт памяти и может хранить один алфавитно-
цифровой символ (литеру). При объявлений литеры используются одиночные
кавычки: fAf (двойные кавычки используются при объявлении строки символов —
ТИП string: "ABC").
Символ хранится в памяти как число, соответствующее коду символа в таблицу
кодировки символов ASCII. Так как символ хранится как число, в памяти над ним
возможно производить арифметические действия (например, 'A' + i будет 66, т. к.
ASCII код для fAf — 65).
Тип char знаковый тип, т. е. число (код), хранящийся в памяти, может принимать
значения от -128 до 127. Если необходима знаковая однобайтовая переменная,
используйте ТИП byte.
Пример:
char myChar = 'A1;
char myChar =65; // Варианты эквивалентны
5.4.1.3. byte
Хранит 8-битовое числовое значение без десятичной точки. Имеет диапазон от О
до 255. Пример:
byte someVariable=150; // объявление переменной someVariable,
// имеющей тип byte
5.4.1.4. int
Тип данных int (от англ. integer — целое число) — один из наиболее часто
используемых типов данных для хранения чисел. int занимает 2 байта памяти и может
хранить числа от -32 768 до 32 767.
Для размещения отрицательных значений int использует так называемый
дополнительный код представления числа. Старший бит указывает на отрицательный
знак числа, остальные биты инвертируются с добавлением 1.
Arduino-компилятор сам заботится о размещении в памяти и представлении
отрицательных чисел, поэтому арифметические действия над целыми числами
производятся как обычно.
Когда переменная типа int вследствие арифметической операции достигает своего
максимального значения, она «перескакивает» на самое минимальное значение,
и наоборот (листинг 5.14).
int х;
х = -32,768;
х = х - 1; //х теперь равно 32,161
58 Часть II. Среды разработки и язык программирования плат Arduino
х = 32,767;
х = х + 1; // х теперь равно -32,768
5.4.1.5. unsigned int
Тип данных unsigned int — беззнаковое целое число, так же, как и тип int
(знаковое), занимает в памяти 2 байта. Но, в отличие от int, тип unsigned int может
хранить только положительные целые числа в диапазоне от 0 до 65 535.
Отличие кроется в том, как unsigned int использует старший бит, иногда
называемый знаковым битом. Если старший бит равен 1, то для типа int компилятор
Arduino считает, что это число отрицательное, а остальные 15 битов несут
информацию о модуле целого числа в дополнительном коде представления числа, в то
время как unsigned int использует все 16 битов для хранения модуля числа.
Когда переменная типа unsigned int вследствие арифметической операции
достигает своего максимального значения, она «перескакивает» на самое минимальное
значение, и наоборот (листинг 5.15).
unsigned int x;
х = 0;
х = х - 1; //х теперь равна 65535
х = х + 1; // х теперь 0
5.4.1.6. long
Тип данных long используется для хранения целых чисел в расширенном диапазоне
от -2 147 483 648 до 2 147 483 647. long занимает 4 байта в памяти. Пример:
long varl = -178000;
5.4.1.7. unsigned long
unsigned long используется для хранения положительных целых чисел в диапазоне
от 0 до 4 294 967 295 и занимает 32 бита D байта) в памяти. Пример вывода в
миллисекундах (мс) с начала выполнения программы приведен в листинге 5.16.
void loop()
{
Serial.print("Time: ");
time = millis ();
// выводит время, прошедшее с момента начала выполнения программы
Serial.println(time);
functionl();
Глава 5. Программирование плат Arduino
5.4.1.8. float
Тип данных float служит для хранения чисел с плавающей запятой. Этот тип часто
используется для операций с данными, считываемыми с аналоговых входов.
Диапазон значений: от -3,4028235Е+38 до 3,402823 5Е+3 8. Переменная типа float
занимает 32 бита D байта) в памяти.
Тип float имеет точность 6-7 знаков (имеются в виду все знаки, а не только
мантисса). Обычно для увеличения точности используют другой тип — double, но на
платформе Arduino double и float имеют одинаковую точность.
5.4.1.9. double
Тип данных double, в отличие от большинства языков программирования, на
платформе Arduino имеет ту же точность, что и тип float, и занимает также 4 байта
памяти.
Тип double поддерживается в Arduino для совместимости кода с другими
платформами.
5.4.1.10. string — текстовые строки
Текстовые строки в Arduino объявляются как массив (array) типа char (символов,
литер), оканчивающийся символом «конца строки». Возможны следующие
варианты объявления текстовых строк:
? объявить массив символов без присваивания значений;
? объявить массив символов и присвоить значения всем элементам, кроме
последнего, — компилятор Arduino автоматически добавит символ конца строки;
? явно объявить завершающий символ;
? инициализировать массив строковой константой в двойных кавычках.
Компилятор автоматически задаст требуемый размер на массив, равный количеству
символов плюс завершающий символ;
? инициализировать массив с явным заданием размера и присвоением строковой
константы;
? инициализировать массив с явным заданием дополнительного размера (с
запасом), фактически превышающего размер строковой константы при начальном
присвоении.
В листинге 5.17 приведены варианты объявления и присвоения строк.
char Svtrl[15];
char Str2[8] = {faf,fr1, fdf, fuf
char Str3[8] *= {faf ,'r', fdf, fuf
char Str4[ ] = "arduino";
char#Str5[8] = "arduino";
char Str6[15] = "arduino";
60 Часть II. Среды разработки и язык программирования плат Arduino
Обычно строки оканчиваются нулевым символом (код 0 в ASCII). Это позволяет
функциям (таким как Serial.print о) выявлять окончание строки. В противном
случае могут считаться байты памяти, не принадлежащие переменной.
Массив символов, выделяемый под строку, должен иметь один дополнительный
элемент для символа конца строки. Если объявить строку без символа окончания
строки, то это приведет к некорректной работе функций, оперирующих строками.
Строки всегда объявляются внутри двойных кавычек: "Abe".
При работе с большими объемами текстовой информации бывает удобно
использовать массивы строк. Так как строки сами по себе массивы, массив строк будет
двумерным массивом.
В примере, приведенном в листинге 5.18, символ звездочки после объявления типа
char* указывает на то, что мы имеем дело с массивом указателей. Это необходимо
для задания двумерного массива.
char* myStrings[]={"string 1", "string 2", "string 3","string 4",
"string 5","string 6"};
void setup()
{Serial.begin(9600);}
void loopO
{
for (int i = 0; i < 6; i++){
Serial.println(myStrings[i]);
delayE00);
5.4.1.11. Массивы
Массивы (arrays) — именованный набор однотипных переменных с доступом
к отдельным элементам по их индексу. Существует несколько вариантов
объявления массива:
? массив может быть объявлен без непосредственной инициализации элементов
массива:
int mylnts[6];
П массив может быть объявлен без явного задания размера. Компилятор сам
подсчитает фактическое количество элементов и создаст в памяти массив
необходимого размера:
int myPins[] = {2, 4, 8, 3, 6};
О при объявлении массива размер может быть задан явно, одновременно с
инициализацией элементов массива. При создании массива типа char необходим
дополнительный элемент массива для нулевого символа:
Глава 5. Программирование плат Arduino 61_
int mySensVals[6] = {2, 4, -8, 3, 2};
char message[6] = "hello";
Индексация массива начинается с 0. Присваивание значения элементу массива
происходит следующим образом:
mySensVals[0] = 10;
Получение значения массива:
х = mySensVals[4];
Чаще всего для перебора элементов цикла применяется цикл for, счетчик цикла
используется как индекс для доступа к каждому элементу массива. Например, для
вывода массива через последовательный порт (serial) можно задать следующий
код:
int i;
for (i = 0; i < 5; i = i + 1)
{ Serial.println(myPins[i]); }
5.4.1.12. void
Ключевое слово void используется при объявлении функций, если функция не
возвращает никакого значения при ее вызове.
5.4.2. Константы
Константы — предопределенные значения. Они используются, чтобы делать
программы более легкими для чтения. Объявление констант (а также базовых макросов
и функций) можно посмотреть в файле \hardware\arduino\cores\arduino\wiring.h.
Рассмотрим некоторые константы:
? true/false— это булевы константы, определяющие логические уровни, false
легко определяется как 0 (ноль), a true — как 1, но может быть и чем-то другим,
отличным от нуля. Поэтому -1, 2 и 200 — это все тоже определяется как true.
#define true 0x1
#define false 0x0
? high/low — уровни сигналов порта high и low:
tdefine HIGH 0x1
#define LOW 0x0
? input/output — настройка цифровых портов на ввод (input) и вывод (output)
сигналов:
#define INPUT 0x0
#define OUTPUT 0x1
Цифровые порты могут использоваться на ввод или вывод сигналов. Изменение
порта с ввода на вывод производится при помощи функции pinMode ():
pinModeA3, OUTPUT); // 13 вывод будет выходом
pinModeA2, INPUT); // 12 - входом
62_ Часть II. Среды разработки и язык программирования плат Arduino
В программе можно создавать собственные константы:
#define LEFT 0x95
tdefine MESS_LEFT "поворот влево"
5.4.3. Переменные
Переменные •*— это способ именовать и хранить числовые значения для
последующего использования их программой. Переменные представляют собой значения,
которые могут последовательно меняться, в отличие от констант, чье значение
никогда не меняется. Переменные нужно декларировать (объявлять). Следующий код
объявляет переменную inputvariabie, а затем присваивает ей значение, полученное
от 2-го аналогового порта:
int inputVariable=O;
inputVariable=analogReadB);
Переменные могут быть названы любыми именами, которые не являются
ключевыми словами языка программирования Arduino.
5.4.3.1. Объявление переменных
Все переменные должны быть задекларированы до того, как они могут
использоваться. Объявление переменной означает определение типа ее значения: int, long,
float и т. д., задание уникального имени переменной, и дополнительно ей можно
присвоить начальное значение. Все это следует делать только один раз в
программе, но значение может меняться в любое время при использовании арифметических
или других разных операций.
Следующий пример показывает, что объявленная переменная inputvariabie имеет
тип int, и ее начальное значение равно нулю. Это называется простым
присваиванием.
int inputvariabie = 0;
Переменная может быть объявлена в разных местах программы, и то, где это
сделано, определяет, какие части программы могут использовать переменную.
5.4.3.2. Границы переменных
Переменные могут быть объявлены в начале программы перед void setup (),
локально внутри функций и иногда в блоке выражений, таком как цикл for. Место,
где объявлена переменная, определяет ее границы (область видимости), т. е.
возможность некотррых частей программы ее использовать.
? Глобальные переменные таковы, что их могут видеть и использовать любые
функции и выражения программы. Такие переменные декларируются в начале
программы перед функцией setup ().
? Локальные переменные определяются внутри функций или таких частей, как
цикл for. Они видимы и могут использоваться только внутри функции, в кото-
Глава 5. Программирование плат Arduino 63^
рой объявлены. Таким образом, может существовать несколько переменных
с одинаковыми именами в разных частях одной программы, которые содержат
разные значения. Уверенность, что только одна функция имеет доступ к ее
переменной, упрощает программу и уменьшает потенциальную опасность
возникновения ошибок.
5.4.4. Преобразование типов данных
5AAA.char()
char () приводит значение к типу char.
Синтаксис:
char(х);
где х — переменная любого типа.
5.4.4.2. byteO
byte () приводит значение к типу byte.
Синтаксис:
byte(x);
где х — переменная любого типа.
5.4.4.3. int()
int () приводит значение к типу int.
Синтаксис:
int(x) ;
где х — переменная любого типа.
5.4.4.4. longO
long () приводит значение к типу long.
Синтаксис:
long(x);
где х — переменная любого типа.
5.4.4.5. floatO
float () приводит значение к типу float.
Синтаксис:
long(x);
где х — переменная любого типа.
64 Часть II. Среды разработки и язык программирования плат Arduino
5.5. Функции
5.5.1. Цифровой ввод/вывод
Рассмотрим функции цифрового ввода/вывода:
? pinMode ();
? digitaiwriteО;
? digitalRead().
5.5.1.1. Функция pinMode
Устанавливает режим работы заданного входа/выхода (pin) как входа или как
выхода.
Синтаксис:
pinMode(pin, mdde);
Параметры:
? pin — номер входа/выхода (pin), который вы хотите установить;
? mode — режим. Одно из двух значений: input или output, устанавливается на
вход или выход соответственно.
Пример:
int ledPin = 13; // Светодиод, подключенный к входу/выходу 13
void setup()
{
pinMode(ledPin, OUTPUT); // устанавливает режим работы - выход
5.5.1.2. Функция digitalWriteQ
Подает high или low значение на цифровой вход/выход (pin).
Если вход/выход (pin) был установлен в режим выход (output) функцией pinMode (),
то для значения high напряжение на соответствующем входе/выходе (pin) будет 5 В
C,3 В для плат 3,3 В) и О В (земля) для low.
Если вход/выход (pin) был установлен в режим вход (input), to функция
digitaiwrite со значением high будет активировать внутренний нагрузочный
резистор 20 кОм. Подача low, в свою очередь, отключает этот резистор. Нагрузочного
резистора достаточно, чтобы светодиод, подключенный ко входу, светил тускло.
Если вдруг светодиод работает, но очень тускло, возможно, необходимо установить
режим ВЫХОД (OUTPUT) функцией pinMode ().
Синтаксис:
digitaiwrite(pin, value);
Глава 5. Программирование плат Arduino
Параметры:
? pin — номер входа/выхода (pin);
? value — значение high или low.
Пример представлен в листинге 5.19.
int ledPin =13; // Светодиод, подключенный ко входу/выходу 13
void setup()
{
pinMode(ledPin, OUTPUT); // устанавливает режим работы - выход
}
void loop()
{
digitalWrite(ledPin:, HIGH); // включает светодиод
delayA000); // ждет секунду
digitalWrite(ledPin, LOW); // выключает светодиод
delay(lOOO); // ждет секунду
} '
5.5.1.3. Функция digitalReadQ
Функция считывает значение с заданного входа: high или low.
Синтаксис:
digitalRead(pin) ;
Параметр: pin — номер входа/выхода (pin), который вы хотите считать.
Пример представлен в листинге 5.20.
int ledPin =13; // Светодиод, подключенный ко входу/выходу 13
int inPin =7; // кнопка на входе 7
int val = 0; // переменная для хранения значения
void setup()
{
pinMode(ledPin, OUTPUT); // устанавливает режим работы - выход для 13
pinMode(inPin, INPUT); // устанавливает режим работы - вход для 7
}
void loop ()
{
val = digitalRead(inPin); // считываем значение со входа
digitalWrite(ledPin, val); // устанавливаем значение на светодиоде
// равным значению входа кнопки
Часть II. Среды разработки и язык программирования плат Arduino
Замечание
Если вход не подключен, то digitaiRead может возвращать значения high или low
случайным образом. Аналоговые входы (analog pins) могут быть использованы как
цифровые входы/выходы (digital pins). Обращение к ним идет по номерам от 14 (для
аналогового входа 0) до 19 (для аналогового входа 5).
5.5.2. Аналоговый ввод/вывод
Рассмотрим функции аналогового ввода/вывода:
? analogRead();
? analogReference();
О analogWrite().
5.5.2.1. Функция analogReadf)
Функция считывает значение с указанного аналогового входа. Большинство плат
Arduino имеют 6 каналов (8 каналов у плат Mini и Nano, 16 — у Mega) с 10-битным
аналого-цифровым преобразователем (АЦП). Напряжение, поданное на аналоговый
вход (обычно от 0 до 5 В), будет преобразовано в значение от 0 до 1023 — это
1024 шага с разрешением 0,0049 В. Разброс напряжения и шаг может быть изменен
функцией analogRef erence о. Считывание значения с аналогового входа занимает
примерно 100 мкс @,0001 с), т. е. максимальная частота считывания
приблизительно 10 000 раз в секунду.
Синтаксис:
analogRead(pin);
Параметр: pin — номер порта аналогового входа, с которого будет производиться
считывание: 0..5 для большинства плат, 0..7 для Mini и Nano и 0..15 для Mega.
Возвращаемое значение int @ to 1023).
Замечание
Если аналоговый вход не подключен, то значения, возвращаемые функцией
analogRead (), могут принимать случайные значения.
Пример представлен в листинге 5.21.
int analogPin =3; // номер порта, к которому подключен потенциометр
int val =0; // переменная для хранения считываемого значения
void- setup ()
{
Serial.begin(9600); // установка связи, по serial
Глава 5. Программирование плат Arduino 67
void loop()
{
val = analogRead(analogPin); // считываем значение
Serial.println(val); // выводим полученное значение
}
5.5.2.2. Функция analogReferenceQ
Функция определяет опорное напряжение, относительно которого происходят
аналоговые измерения. Функция anaiogReado возвращает значение с разрешением
8 битов A024) пропорционально входному напряжению на аналоговом входе и
в зависимости от опорного напряжения.
Возможные настройки:
? default — стандартное опорное напряжение 5 В (на платформах с напряжением
питания 5 В) или 3,3 В (на платформах с напряжением питания 3,3 В);
? internal— встроенное опорное напряжение 1,1 В на микроконтроллерах
ATmegal68 и ATmega328 и 2,56 В на ATmega8;
? external — внешний источник опорного напряжения, подключенный к выводу
AREF.
Синтаксис:
analogReference(type);
Параметр: type — определяет используемое опорное напряжение (default, internal
или external).
Внешнее напряжение рекомендуется подключать к выводу AREF через резистор
5 кОм.
Рекомендуемой настройкой для вывода AREF является external. При этом
происходит отключение обоих внутренних источников, и внешнее напряжение будет
* являться опорным для АЦП.
5.5.2.3. Функция analogWriteQ
Выдает аналоговую величину (ШИМ-волну) на порт входа/выхода. Функция может
быть полезна для управления яркостью подключенного светодиода или скоростью
вращения электродвигателя. После вызова anaiogwrite () на выходе будет
генерироваться постоянная прямоугольная «волна» с заданной шириной импульса до
следующего вызова analogWrite (ИЛИ вызова digitalWrite, ИЛИ digitalRead на ТОМ же
порту входа/выхода). Частота ШИМ-сигнала приблизительно 490 Гц.
На большинстве плат Arduino (на базе микроконтроллера ATmegal68 или
ATmega328) ШИМ поддерживают порты 3, 5, 6, 9, 10 и 11, на плате Arduino
Mega — порты с 2 по 13. На более ранних версиях плат Arduino anaiogwrite ()
работает только на портах 9, 10 и 11.
Для вызова anaiogwrite о нет необходимости устанавливать тип входа/выхода
функцией pinMode (). Функция anaiogwrite () никак не связана с аналоговыми
входами И С функцией analogRead ().
(№ Часть II. Среды разработки и язык программирования плат Arduino
Синтаксис:
analogWrite(pin, value);
Параметры:
? pin — порт входа/выхода, на который подается ШИМ-сигнал;
? value — период рабочего цикла: значение между 0 (полностью выключено)
и 255 (сигнал подан постоянно).
Замечание
Период ШИМ-сигнала на портах входа/выхода 5 и 6 будет несколько длиннее. Это
связано с тем, что таймер для этих выходов также задействован функциями miliis ()
и delay (). Такой эффект более заметен при установке коротких периодов ШИМ-
сигнала @-10).
Пример задания яркости светодиода пропорционально значению, снимаемому
с потенциометра, представлен в листинге 5.22.
int ledPin =9; // Светодиод подключен к выходу 9
int analogPin =3; // потенциометр подключен к выходу 3
int val =0; // переменная для хранения значения
void setup()
{
pinModededPin, OUTPUT); // установка порта на выход
}
void loop ()
{
val = analogRead(analogPin); // считываем значение с порта,
// подключенного к потенциометру
analogWrite(ledPin, val / 4); // analogRead возвращает значения от 0
// до 1023f analogWrite должно быть
//в диапазоне от 0 до 255
5.5.3. Дополнительные фунции ввода/вывода
5.5.3.1. Функция toneQ
Генерирует на порту входа/выхода сигнал— прямоугольную «волну» заданной
частоты и с 50%-ным рабочим циклом. Длительность может быть задана
параметром, в противном случае сигнал генерируется до тех пор, пока не будет вызвана
функция потопе (). К порту входа/выхода может быть подключен пьезо- или иной
динамик для воспроизведения сигнала.
Воспроизводиться одновременно может только один сигнал. Если сигнал уже
воспроизводится на одном порту, то вызов tone () с номером другого порта в качестве
Глава 5. Программирование плат Arduino
параметра ни к чему не приведет, если же tone (} будет вызвана с тем же номером
порта, то будет установлена новая частота сигнала.
Использование функции tone о помешает использовать ШИМ на портах
входа/выхода 3 и 11 (кроме платы Arduino Mega).
Синтаксис:
tone(pin, frequency);
tone(pin, frequency, duration);
Параметры:
? pin — номер порта входа/выхода, на котором будет генерироваться сигнал;
? frequency — частота сигнала в герцах;
? duration — длительность сигнала в миллисекундах.
5.5.3.2. Функция noTonef)
Останавливает сигнал, генерируемый на порту входа/выхода, вызовом функции
tone (). Если сигнал не генерировался, то вызов потопе о ни к чему не приводит.
Замечание
Если необходимы сигналы на разных портах, то следует сначала остановить один
сигнал функцией потопе (), а лишь затем создавать новый сигнал на другом порту
функцией топе ().
Синтаксис:
поТопе (pin) ;
Параметр: pin — номер порта входа/выхода, на котором прекращается сигнал.
5.5.3.3. Функция shiftOutQ
Выводит байт информации на порт входа/выхода последовательно (побитно).
Вывод может осуществляться как с первого (левого), так и с последнего (правого)
бита. Каждый бит последовательно подается на заданный порт, после чего на
синхронизирующий порт входа/выхода подается сигнал, информирующий о
доступности к считыванию бита.
Такой способ передачи данных называется последовательным протоколом с
синхронизацией. Он часто используется для взаимодействия микроконтроллеров с
датчиками и сенсорами, а также другими микроконтроллерами. Последовательная
передача с синхронизацией позволяет устройствам связываться на максимальной
скорости. Смотрите также документацию (на англ. языке) по протоколу
последовательного периферийного интерфейса (SPI, Serial Peripheral Interface Protocol).
Синтаксис:
shiftout(dataPin, clockPin, bitOrder, value);
70^ Часть II. Среды разработки и язык программирования плат Arduino
Параметры:
? dataPin — номер порта входа/выхода, на который выводятся биты (int);
? clockPin — номер порта, по которому производится синхронизация (int);
? bitorder— используемая последовательность вывода битов, msbfirst (Most
Significant Bit First) — слева или lsbfirst (Least Significant Bit First) — справа;
? value — значение (байт) для вывода (byte).
Замечание
Порт вывода (dataPin) и синхронизирующий порт (clockPin) должны быть
предварительно сконфигурированы как порты вывода с помощью функции pinMode ().
Текущая реализация функции sniftouto может выводить только один байт (8
битов) информации, поэтому необходимо произвести несколько действий, чтобы
вывести значения больше 255. Пример вывода приведен в листинге 5.23.
// Вывод будет MSBFIRST с первого (левого) бита
int data = 500;
// выводим старший байт
shiftOut(dataPin, clock, MSBFIRST, (data » 8)); * %
// выводим младший бит
shiftOut(dataPin, clock, LSBFIRST, data);
// выводим старший бит
shiftOut(dataPin, clock, LSBFIRST, (data » 8));
Пример вывода счетчика от 0 до 255 на сдвиговый регистр с последовательным
вводом 74НС595 представлен в листинге 5.24.
// Порт, подключенный к ST_CP 74HC595
int latchPin = 8;
// Порт, подключенный к SH_CP 74HC595
int clockPin = 12;
// Порт, подключенный к DS 74HC595
int dataPin = 11;
void setup()
{
// устанавливаем режим порта выхода
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
Глава 5. Программирование плат Arduino 71_
void loop ()
{
for (int j = 0; j < 256; j++)
{
// устанавливаем LOW на latchPin, пока не окончена передача байта
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, j);
// устанавливаем HIGH на latchPin, чтобы проинформировать регистр, что
// передача окончена.
digitalWrite(latchPin, HIGH);
delayA000);
5.5.3.4. Функция pulselnQ
Считывает длину сигнала на заданном порту (high или low). Например, если задано
считывание high функцией puisein (), функция ожидает, пока на заданном порту не
появится high. Когда high получен, включается таймер, который будет остановлен,
когда на порту входа/выхода будет low. Функция puiseino возвращает длину
сигнала в микросекундах. Функция возвращает 0, если в течение заданного времени
(тайм-аута) не был зафиксирован сигнал на порту.
Возможны некоторые погрешности в измерении длинных сигналов. Функция
может измерять сигналы длиной от 1.0 мкс до 3 мин.
Синтаксис:
pulseln(pin, value);
pulseln(pin, value, timeout);
Параметры:
? pin — номер порта входа/выхода, на котором будет ожидаться сигнал;
? value — тип ожидаемого сигнала: high или low;
? timeout — время ожидания сигнала (тайм-аут) в секундах (unsigned long).
Возвращаемые значения: длина сигнала в микросекундах или 0, если сигнал не
получен до истечения тайм-аута (тип unsigned long).
Пример использования функции представлен в листинге 5.25.
int pin = 7;
unsigned long duration;
void setup()
{
pinMode(pin, INPUT);
72^ Часть II. Среды разработки и язык программирования плат Arduino
void loop()
{
duration = pulseln(pin, HIGH);
5.5.4. Работа со временем
5.5.4.1. Функция millisQ
Возвращает количество миллисекунд с момента начала выполнения текущей
программы на плате Arduino. Это количество сбрасывается* на ноль вследствие
переполнения значения приблизительно через 50 дней.
Параметров нет.
Возвращаемое значение — количество миллисекунд с момента начала выполнения
программы (ТИП unsigned long).
Пример использования функции представлен в листинге 5.26.
unsigned long time;
void setup()
{
Serial.begin(9600);
}
void loopO
{
Serial.print("Time: ");
time = millisO;
// выводит количество миллисекунд с момента начала выполнения программы
Serial.println(time);
// ждет секунду перед следующей итерацией цикла.
delayA000);
5.5.4.2. Функция microsQ
Возвращает количество микросекунд с момента начала выполнения на плате
Arduino текущей программы. Значение переполняется и сбрасывается на ноль
приблизительно через 70 мин. На платах Arduino с 16 МГц (Duemilanove и Nano)
функция micros () имеет разрешение 4 с (возвращаемое значение всегда кратно 4).
На платах с 8 МГц (Arduino Lilypad) разрешение функции — 8 с.
Параметров нет.
Возвращаемое значение — количество микросекунд с момента начала выполнения
программы (unsigned long).
Глава 5. Программирование плат Arduino 73_
Пример использования функции представлен в листинге 5.27.
unsigned long time;
void setup ()
{
Serial.begin(9600);
}
void loop()
{
Serial.print("Time: ");
time = micros();
// выводит количество микросекунд с момента начала выполнения
// программы
Serial.printIn(time);
// ждет секунду перед следующей итерацией цикла.
delayA000);
5.5.4.3. Функция delayO
Останавливает выполнение программы на заданное в параметре количество
миллисекунд A000 мс в 1 с).
Синтаксис:
delay (ms);
Параметр: ms — количество миллисекунд, на которое приостанавливается
выполнение программы ( ТИП unsigned long).
Пример использования функции представлен в листинге 5.28.
int ledPin = 13; // светодиод подключен на порт 13
void setup()
{
pinMode(ledPin, OUTPUT); // устанавливается режим порта - выход
}
void loop()
{
digitalWrite(ledPin, HIGH); // включаем светодиод
delayA000); // ожидаем секунду
digitalWrite(ledPin, LOW); // выключаем светодиод
delayA000); // ожидаем секунду
74 Часть II. Среды разработки и язык программирования плат Arduino
Не рекомендуется использовать эту функцию для событий длиннее 10 мс, т. к. во
время останова не могут быть произведены манипуляции с портами, не могут быть
считаны сенсоры или произведены математические операции. В качестве
альтернативного подхода возможно контролирование времени выполнения тех или иных
функций с помощью minis (). При использовании функции delay () работа
прерываний не останавливается, продолжается запись последовательно (serial)
передаваемых данных на RX-порт, ШИМ-сигнал (anaiogwrite) на портах продолжает
генерироваться.
5.5.4.4. Функция delayMicrosecondsQ
Останавливает выполнение программы на заданное в параметре количество
микросекунд A 000 000 мкс в 1 с).
В существующих версиях Arduino максимальная пауза, воспроизводимая
корректно,— 16 383. Возможно, это будет изменено в следующих версиях Arduino. Для
остановки выполнения программы более чем на несколько тысяч микросекунд
рекомендуется использовать функцию delay ().
Синтаксис:
delayMicroseconds(us);
Параметр: us — количество Микросекунд, на которое приостанавливается
выполнение программы (unsigned int).
Пример использования функции представлен в листинге 5.29.
int outPin =8; // цифровой порт входа/выхода 8
void setup()
{
pinMode(outPin, OUTPUT); // устанавливается режим порта - выход
}
void loop ()
{
digitalWrite(outPin, HIGH); // подаем HIGH на выход
delayE0); // ожидаем 50 мкс
digitalWrite(outPin, LOW); // устанавливаем LOW на выходе
delayE0); // ожидаем 50 мкс
5.5.5. Математические функции
В языке представлены следующие математические функции:
min () ? max () ? abs (), constrain (), map (), pow (), sq (), sqrt ().'
Глава 5. Программирование плат Arduino 75^
5.5.5.1. Функция min(x,yx)
Возвращает наименьшее из двух значений.
Параметры:
? х — первое число, любой тип;
? у — второе число, любой тип.
Возвращаемое значение — возвращает меньшее из двух сравниваемых значений.
Пример использования функции:
sensVal = min(sensVal, 100);
// проверяем, если sensVal больше 100, то senseVal будет присвоено 100
5.5.5.2. Функция тах(х, у)
Возвращает большее из двух значений.
Параметры:
? х — первое число, любой тип;
? у — второе число, любой тип.
Возвращаемое значение — возвращает большее из двух сравниваемых значений.
Пример использования функции:
sensVal = max(sensVal, 20);
// проверяем, если sensVal меньше 20, то senseVal будет присвоено 20
Функция max о зачастую используется для задания нижней границы значений
переменной. Функцией min () ограничивают верхнюю границу переменной. В силу
специфики реализации функции шах о следует избегать использования других
функций в качестве параметров. Например:
max(а—, 0); // может привести к некорректным результатам
а—;
max(а, 0); // так корректно
5.5.5.3. Функция abs()
Возвращает модуль числа.
Параметр: х — число.
Возвращаемые значения:
? х — если х больше или равен 0;
? -х — если х меньше 0.
В силу специфики реализации функции abs () следует избегать использования
других функций в качестве параметров:
abs (а++); // может привести к некорректным результатам
а++;
abs(а, 0); // так корректно
76^ Часть II. Среды разработки и язык программирования плат Arduino
5.5.5.4. Функция constrainfx, a, Ь)
Функция проверяет и, если надо, задает новое значение так, чтобы оно было в
области допустимых значений, заданной параметрами.
Параметры:
? х — проверяемое значение, любой тип;
? а — нижняя граница области допустимых значений, любой тип;
? ь — верхняя граница области допустимых значений, любой тип.
Возвращаемое значение:
Ох — если х входит в область допустимых значений [а. .ь];
? а — если х меньше а;
? ь — если х больше ь.
Пример:
sensVal * constrain(sensVal, 10, 150);
// ограничиваем значения sensVal диапазоном от 10 до 150
5.5.5.5. Функция mapfvalue, fromLow, fromHigh, toLow, toHigh)
Функция пропорционально переносит значение (value) из текущего диапазона
значений (fromLow ... fromHigh) в новый диапазон (toLow ... toHigh), заданный
параметрами.
Функция шар () не ограничивает значение рамками диапазона, как это делает
функция constrain (). Функция constrain () может быть использована до или после
вызова шар (), если необходимо ограничить допустимые значения заданным
диапазоном.
Обратите внимание, что «нижняя граница» может быть как меньше, так и больше
«верхней границы». Это может быть использовано, чтобы «перевернуть» диапазон:
у - тар(х, 1, 50, 50, 1);
Возможно использование отрицательных значений:
у - тар(х, 1, 50, 50, -100);
Функция тар о оперирует целыми числами. При пропорциональном переносе
дробная часть не округляется по правилам, а просто отбрасывается.
Параметры:
? value — значение для переноса;
? fromLow — нижняя граница текущего диапазона;
? fromHigh — верхняя граница текущего диапазона;
? toLow — нижняя граница нового диапазона, в который переносится значение;
? toHigh — верхняя граница нового диапазона.
Возвращаемое значение — значение в новом диапазоне.
Глава 5. Программирование плат Arduino 77_
Пример использования функции представлен в листинге 5.30.
// Переносим значение с аналогового входа
// (возможные значения от 0 до 1023) в 8 бит @..255)
void setup()
{;}
void loop ()
{
int val = analogRead(O);
val = map(val, 0, 1023, 0, 255);
analogWrite(9, val);
5.5.5.6. Функция powfbase, exponent)
Вычисляет значение, возведенное в заданную степень. Функция pow () может
возводить и в дробную степень.
Параметры:
? base — ЧИСЛО (ТИП float);
?I exponent — степень, в которую будет возводиться число (тип float).
Возвращаемое значение — результат возведения в степень, число (тип double).
5.5.5.7. Функция sq(x)
Функция возвращает квадрат числа, заданного параметром.
Параметр: х — число, любой тип.
Возвращаемое значение — квадрат числа.
5.5.5.8. Функция sqrt(x)
Функция вычисляет квадратный корень числа, заданного параметром.
Параметры: х — число, любой тип.
Возвращаемое значение — квадратный корень числа (тип double).
5.5.6. Тригонометрические функции
В языке представлены следующие тригонометрические функции:
? sin();
? cos о;
? tan ().
78^ Часть II. Среды разработки и язык программирования плат Arduino
5.5.6.1. Функция sin(rad)
Возвращает синус угла, заданного в радианах в передаваемом параметре. Результат
функции всегда в диапазоне -1... 1.
Параметр: rad — угол в радианах (float).
Возвращаемое значение: синус угла (тип double).
5.5.6.2. Функция cos(rad)
Возвращает косинус угла, заданного в радианах в передаваемом параметре.
Результат функции всегда находится в диапазоне -1... 1.
Параметр: rad — угол в радианах (тип float).
Возвращаемое значение: косинус угла (тип double).
5.5.6.3. Функция tan(rad)
Возвращает тангенс угла, заданного в радианах в передаваемом параметре.
Результат функции в диапазоне от минус бесконечности до плюс бесконечности.
Параметр: rad — угол в радианах (тип float).
Возвращаемое значение: тангенс угла (тип double).
5.5.7. Генераторы случайных значений
Функции формирования случайных чисел:
? randomSeed();
? random ().
5.5.7.1. Функция randomSeed(seed)
Функция randomSeed о инициализирует генератор псевдослучайных чисел.
Генерируемая последовательность случайных чисел очень длинная, и всегда одна и та же.
Точка в этой последовательности, с которой начинается генерация чисел, зависит
от параметра seed.
Параметр: seed — параметр, задающий начало выдачи псевдослучайных значений
на последовательности (тип int, long).
5.5.7.2. Функция randomQ
Функция random () возвращает псевдослучайное число.
Синтаксис:
random (max);
random(min, max);
Глава 5. Программирование плат Arduino 79_
Параметры:
? min — нижняя граница случайных значений, включительно (опционально);
? шах — верхняя граница случайных значений, включительно.
Возвращаемое значение: случайное число между min и max - 1 (тип long).
Если при каждом запуске программы необходимо получать разные
последовательности значений, генерируемых функцией randomo, то необходимо
инициализировать генератор псевдослучайных чисел со случайным параметром. Например,
можно использовать значение, отдаваемое функцией anaiogReadO с неподключенного
порта входа/выхода. В некоторых случаях необходимо получать одинаковую
последовательность при каждом запуске программы на Arduino. Тогда
инициализировать генератор псевдослучайных чисел следует вызовом функции randomseed ()
с фиксированным параметром.
Пример использования функции представлен в листинге 5.31.
long randNumber;
void setup()
{
Serial.begin(9600);
}
void loop()
{
// выводим случайное число из диапазона 0..299
randNumber = randomC00);
Serial.println(randNumber);
// выводим случайное число из диапазона 0..19
randNumber = randomA0, 20);
Serial.println(randNumber);
delayE0);
5.5.8. Операции с битами и байтами
Функции — операции с битами и байтами:
lowByte(), highByte(), bitRead(), bitWrite(), bitSet(), bitClear(), bit().
5.5.8.1. Функция lowByteQ
Извлекает младший (самый правый) байт переменной (например, типа word).
Синтаксис:
lowByte(x);
Параметр: х — величина любого типа.
Возвращает байт.
8? Часть II. Среды разработки и язык программирования плат Arduino
5.5.8.2. Функция highByteQ
Извлекает старший (крайний левый) байт слова (или второй младший байт
большего типа данных).
Синтаксис:
highByte(x);
Параметр: х — величина любого типа.
Возвращает байт.
5.5.8.3. Функция bitReadQ
Читает определенный бит переменной.
Синтаксис:
bitRead<x, n);
Параметры:
? х — число, из которого необходимо прочитать;
? п — указывает бит, который необходимо прочитать, начиная с 0 для младшего
(правого) бита.
Возвращает: значение бита @ или 1).
5.5.8.4. Функция bitWriteQ
Записывает бит числовой переменной.
Синтаксис:
bitWrite(x, n, b) ;
Параметры:
? х — числовая переменная, в которую необходимо записать;
? п — номер бита, который необходимо записать, начиная с 0 для младшего
(левого) бита;
П ь — значение, которое необходимо записать в бит @ или 1).
5.5.8.5. Функция bitSetf)
Устанавливает (записывает 1) бит числовой переменной.
Синтаксис:
bitSet(x, n)
Параметры:
? х — числовая переменная, которую необходимо записать;
? п— номер бита, который необходимо установить, начиная с 0 для младшего
(левого) бита.
Глава 5. Программирование плат Arduino 81_
5.5.8.6. Функция bitClearQ
Сбрасывает (записывает 0) бит числовой переменной.
Синтаксис:
bitClear(x, п);
Параметры:
? х — числовая переменная, которую необходимо записать;
On— номер бита, который необходимо установить, начиная с 0 для младшего
(левого) бита.
5.5.8.7. Функция bit()
Вычисляет значение указанного бита (бит 0 — это 1, бит 1 — это 2, бит 2 — это 4
и т. д.).
Синтаксис:
bit (n) ;
Параметр: п — номер бита, который необходимо вычислить.
Возвращает: значение бита.
5.5.9. Внешние прерывания
Прерывание (англ. interrupt)— сигнал, сообщающий процессору о наступлении
какого-либо события. При этом выполнение текущей последовательности команд
приостанавливается и управление передается обработчику прерывания, который
выполняет работу по обработке события и возвращает управление в прерванный
код. Arduino также предоставляет свои функции для работы с прерываниями.
Их всего две:
П attachlnterrupt();
? detachlnterrupt().
5.5.9.1. Функция attachlnterrupt
Задает функцию обработки внешнего прерывания, т. е. функцию, которая будет
вызвана по внешнему прерыванию. Если до этого была задана другая функция, то
назначается новая. Вычисляет значение указанного бита (бит 0— это 1, бит 1 —
это 2, бит 2 — это 4 и т. д.).
Синтаксис:
attachlnterrupt(interrupt, function, mode);
Параметры:
? interrupt — номер прерывания:
• о — на цифровом порту 2;
• 1 — на цифровом порту 3;
82 Часть II. Среды разработки и язык программирования плат Arduino
• 2 — на цифровом порту 21 (для Arduino Mega);
• з — на цифровом порту 21 (для Arduino Mega);
• 4 — на цифровом порту 21 (для Arduino Mega);
• 5 — на цифровом порту 21 (для Arduino Mega);
? function— функция, вызываемая прерыванием (должна быть без параметров
и не возвращать значений);
? mode— задает режим обработки прерывания, допустимо использование
следующих констанст:
• low — вызывает прерывание, когда на порту low;
• change — прерывание вызывается при смене значения на порту с low на high
и наоборот;
• rising — прерывание вызывается только при смене значения на порту с low
на high;
• falling — прерывание вызывается только при смене значения на порту с high
на low.
Возвращаемого значения нет.
Внутри функции обработки прерывания не работает функция delay о, значения,
возвращаемые функцией minis о, не изменяются. Возможна потеря данных,
передаваемых по последовательному соединению (Serial data) в момент выполнения
функции обработки прерывания. Переменные, изменяемые в функции, должны
быть объявлены как volatile.
5.5.9.2. Функция detachlnterrupt
Выключает обработку внешнего прерывания.
Синтаксис:
detachlnterrupt(interrupt);
Параметр: interrupt — номер прерывания @ или 1), для Arduino Mega еще 2, 3, 4
или 5.
Возвращаемого значения нет.
В листинге S.32 приведен пример использования прерывания 0 при наступлении
события change на порту 2. При этом светодиод на выводе 13 Arduino при каждом
прерывании меняет статус (горит либо гаснет).
int pin = 13;
volatile int state - LOW;
Глава 5. Программирование плат Arduino 83
void setup()
pinMode(pin, OUTPUT);
attachInterrupt(O, blink, CHANGE);
}
void loopO
digitalWrite(pin, state);
// функция обработки прерывания
void blink()
state = !state;
5.6. Управление портами
через регистры ATmega
Использование встроенных функций Arduino для работы с выводами очень удобно.
Однако за удобство приходится платить быстродействием. В большинстве
программ это не принципиально, но иногда имеет решающее значение. В таких
случаях необходимо управлять портами Arduino напрямую через регистры ATmega. При
этом мы не только увеличиваем быстродействие, но еще и уменьшаем размер
программы.
Рассмотрим таблицу соответствия выводов Arduino портам микроконтроллера
ATmega 168 (рис. 5.2).
Что мы видим:
? portd — цифровые выводы Arduino от D0-D7;
? portb — цифровые выводы Arduino от D8-D13;
? portc — аналоговые выводы Arduino A0-A5 (А6-А7 доступны в Arduino Mini,
Nano).
Для установки выводов и чтения записи данных используются следующие команды:
? ddrd, ddrb, ddrc — для установки назначения выводов (направления передачи
данных) соответствующих портов @ — input, 1 — output);
? portd, portb, portc — регистр установки данных на выводах соответствующего
порта;
? pind, pinb, pinc — считывание данных всех контактов соответствующего порта.
Используя эти команды, можно заменить стандартные функции Arduino для
управления выводами. Например:
84
Часть II. Среды разработки и язык программирования плат Arduino
// pinModeA3,INPUT)
DDRB = DDRB & B11011111
// pinModeE,OUTPUT)
DDRD = DDRD | B00100000
// digitalWriteG,HIGH)
PORTB= PORTB | B10000000
// digitalReadA0,HIGH)
PINB = (PINB & B00000100)»2
Arduino:
сброс
цифровой вывод 0 (RX)
цифровой вывод 1(ТХ)
цифровой вывод 2
цифровой вывод 3 (PWM)
цифровой вывод 4
VCC
OND
Кварцевый резонатор
Кварцевый резонатор
цифровой вывод 5 (PWM)
цифровой вывод 6 (PWM)
цифровой вывод 7
цифровой вывод 8
Atnwgai68 Pin Mapping
(PCIMTIpVRXO)POOC
<PONT16V1NTO)P02C
(рс^пвдхгелкп) роз с
(PCINT20/XCK/TO)P04C
vocc
GNDC
(PCtNT67XTAl1/TOSC1) РввС
(PC«NT7/XTAl2m>SC2)PB7C
^Рм№|Т|НЮ0|Шм1| РО5С.
fPQMT22yOCOA/AINOi РОв?!
(PC1KT23/AIN1)PO7C
(РС1НТ0ЛХКОЯСР1)РВ0С
rv-
1
1
i
1
§
г
1
I
il
it
*t
«1
M
ш
m
m
m
m
ш
m
*
ш
n
ft
fl
If
ЗPC4(AOC^SOA^a^Л¦12)
3143 (AOC3^CIHT11)
DPC2(A0C2FC!NTtO)
ЗРС1(АОС1Л»С1НТ9)
3PCO(AOC(VPCtMTS)
3Af«F
3JM0C
3Pe5<SCK/PaKT5)
3P84(KKSOAaCINT4)
ЗРвг<88ЮС1»РС1НТ2)
Цифровые выводы 11,12 и 13 (выводы одкроосемы
Atmega168 Ns 17. 18 и 19) используются портом CSP дли
подключения MISO, MOSI, SCK
. Избегайте низкоомной
нагрузки на этих выводах при использовании портом CSP
Arduino:
аналоговый вывод 5
аналоговый вывод 4
аналоговый вывод 3
аналоговый вывод 2
аналоговый вывод 1
аналоговый вывод 0
GNO
аналоговый опорный сигнал
VCC
цифровой вывод 13
цифровой вывод 12
цифровой вывод 11 (PWM)
цифровой вывод 10 (PWM)
цифровой вывод 9 (PWM)
Рис. 5.2. Соответствие выводов Arduino портам микроконтроллера АТтеда
Команда anaiogwrite () выдает ШИМ-волну на порт входа/выхода. Частота ШИМ-
сигнала приблизительно 490 Гц. Если вам хочется иметь ШИМ с большим
разрешением или другой частотой, чем позволяет стандартная функция anaiogwrite о,
или вы желаете организовать ШИМ на других вводах, можно написать замену
функции anaiogwrite (), используя прямой вывод на порты:
int PWM_tiine=32;
for (int k=0;k<PWM_time) PORTA=B00000001;
for (int k=0;k<256-PWM_time) PORTA=B00000000;
Теперь можно переходить к изучению Arduino на практических примерах. Этому
будут посвящены остальные главы книги.
ЧАСТЬ III
Практическое применение
Arduino
Глава 6. Проекты для изучения выводов Arduino
Глава 7. Использование библиотек в проектах Arduino
Глава 8. Arduino и последовательный порт UART
Глава 9. Подключение датчиков к плате Arduino
Глава 10. Использование дисплеев в проектах Arduino
Глава 11. Подключение к Arduino исполнительных устройств
Глава 12. Arduino и беспроводная связь
Глава 13. Arduino и Интернет вещей
Глава 14. RFID-идентификация
Глава 15. Специальные возможности отдельных плат Arduino
Глава 16. Взаимодействие Arduino с другими программируемыми системами
Глава 17. Программирование в среде Arduino IDE других плат
ГЛАВА 6
Проекты
для изучения выводов Arduino
Платы Arduino позволяют использовать большую часть своих контактов
ввода/вывода для связи с устройствами во внешних схемах. Прежде всего, эти
контакты могут служить цифровыми вводами и выводами. В то же время часть контактов
Arduino могут действовать и как аналоговые входы. Многие из имеющихся
контактов, кроме того, также мультиплексированы — способны выступать в роли
различных коммуникационных интерфейсов, последовательных интерфейсов, широтно-
импульсных модуляторов и обработчиков внешних прерываний. В этой главе мы
рассмотрим использование контактов Arduino на примере простых и не очень
проектов.
6.1. Цифровые выводы —
«бегущий огонь» на светодиодах
Первое, с чего можно начать знакомство с платформой Arduino, — это ее цифровые
выводы. Цифровые выводы, имеющиеся на платах Arduino, позволяют подключать
к ним другие микросхемы, а также различные датчики и приводы. Изучение
возможностей использования цифровых выводов Arduino позволит вам организовать
с ее помощью решение многих практически полезных задач.
Цифровые сигналы имеют только два отдельных значения: высокий (high, 1) и
низкий (low, 0) уровни. Вы можете задействовать цифровые сигналы в случаях, когда
вход или выход будут принимать одно из этих двух значений. Например, одной из
ситуаций, в которых вы можете использовать цифровой сигнал, является
включение и выключение светодиода.
Поскольку цифровые выводы Arduino могут выступать в роли как входов, так и
выходов, сначала необходимо их настроить. Для настройки цифровых выводов
в Arduino используется встроенная функция pimMode (), которая имеет следующий
синтаксис:
pinMode (pin, mode)
Часть III. Практическое применение Arduino
где:
? pin — номер вывода Arduino;
? mode — устанавливаемый режим для вывода pin:
• input — pin в режиме входа;
• output — pin в режиме выхода;
• inputpullup — в этом режиме к выводу подключается внутренний
подтягивающий резистор 20 кОм, чтобы привести уровень на выводе к значению
HIGH, если к нему ничего не подключено.
6.1.1. Подключение светодиода к выводу Arduino
Рассмотрим простейший пример— подключение к выводу Arduino светодиода.
Для него нам понадобятся следующие компоненты:
? плата Arduino Uno;
? кабель USB;
? плата прототипирования (монтажная плата);
? красный светодиод;
? резистор 220 Ом;
? соединительные провода типа «папа-папа» (далее в тексте — ПП) — 3 шт.
Рис. 6.1. Монтажная схема подключения светодиода
В представленной на рис. 6Л монтажной схеме этого проекта для подключения
светодиода к цифровому выводу мы применили ограничительный резистор
номиналом 220 Ом. Разберемся, как подобрать такой резистор, и как будет влиять
номинал резистора на яркость светодиода. Самым главным уравнением для любого
Глава 6. Проекты для изучения выводов Arduino 89^
инженера-электрика является закон Ома— он определяет отношения между
напряжением, током и сопротивлением в цепи. Закон Ома записывается следующим
образом:
где: V— напряжение в вольтах, /— ток в амперах, R — сопротивление в омах.
В электрической схеме каждый компонент имеет какое-то собственное
сопротивление, что вызывает при прохождении через него тока некоторое снижение его
напряжения, называемое падением напряжения. Светодиоды также вызывают
определенное падение напряжения на них и предназначены для работы при
определенном значении тока: чем больше ток через светодиод, тем ярче светодиод светится, и
так до предельного значения. Для наиболее распространенных типов светодиодов
максимальный ток составляет 20 мА. Обычное значение падения напряжения для
светодиода— около 2 В. Учитывая, что напряжение питания, равное 5 В, должно
упасть на светодиоде и резисторе, оставшиеся 3 В должны упасть на резисторе.
Зная максимальное значение прямого тока через светодиод B0 мА), можно найти
номинал резистора:
R=V/I= 3/0,02 =150 Ом.
Таким образом, при протекании тока величиной 20 мА через светодиод и резистор
сопротивлением 150 Ом светодиод станет светиться на полную мощность, а по
мере увеличения значения сопротивления ток будет уменьшаться и свечение
светодиода снижаться. И хотя сопротивление взятого нами в проект резистора B20 Ом)
превышает теоретически рассчитанное значение 150 Ом, однако оно все же
позволяет светодиоду светиться достаточно ярко. Кроме того, резисторы этого номинала
очень распространены.
Теперь приступим к написанию программы (скетча), которая обеспечит мигание
светодиода, подключенного к цифровому выводу Arduino D5.
В процедуре setup () настроим режим работы вывода (пина) 5 на выход (output):
void setup() {
pinModeE,OUTPUT);
}
В процедуре loop () нам необходимо зажечь светодиод — подать high A) на
цифровой вывод D5, подождать некоторое время, затем потушить его — подать low @) на
цифровой вывод D5, опять подождать некоторое время, и т. д. по кругу.
Для выполнения операции «подождать некоторое время» мы воспользуемся
встроенной в Arduino функцией delay (). Эта функция просто останавливает выполнение
программы на заданное в параметре количество миллисекунд (напомню: в 1 с
1000 мс). Например:
delayB000); // останавливает выполнение программы на 2000 мс B с)
Полный код скетча приведен в листинге 6.1.
90 Часть III. Практическое применение Arduino
void setup() {
// настроить выводы D5 Arduino как OUTPUT
pinModeE, OUTPUT);
void loop() {
// включить светодиод (установить D5 HIGH)
digitalWriteE, HIGH);
// пауза 1000 мс A с)
delayA000);
// выключить светодиод (установить D5 LOW)
digitalWriteE, LOW);
// пауза 1000 мс A с)
delayA000);
Загрузим этот скетч в плату Arduino— мы должны наблюдать
включение/выключение светодиода с периодичностью 2 с.
Допустим, вы хотите изменить вывод (пин) Arduino для подключения светодиода
или время паузы в функции delay о. Можно просто внести изменения в каждую
строку скетча, содержащую изменяемые параметры. Но это не совсем удобно,
и в больших программах займет очень много времени. Есть и другой вариант —
использовать константы и переменные. Константа и переменная — это места
хранения данных. Они имеют имя, значение и тип. Например, следующее объявление
(оно называется декларацией):
int pin_ledl = 5;
создает переменную с именем piniedi, значением 5 и типом int.
После этого мы получаем в программе возможность обратиться к ней следующим
образом:
const int pin_ledl =5;
Декларация:
const int pin_led2 = 6;
создает константу с именем pin_ied2, значением б и типом int.
Константы можно определить и иначе:
#define PIN_LED2 6
В этом случае не надо указывать тип переменной.
Таким образом, в программе возникает возможность обратиться к той или иной
переменной или константе через ее имя с целью работы с ее значением. Например,
в утверждении:
pinMode(pin_ledl, OUTPUT);
Глава 6. Проекты для изучения выводов Arduino
уже подразумевается значение вывода E), которое будет передаваться в функцию
pinMode (). Преимущество переменных и констант заключается в том, что
определение значения вывода осуществляется однажды, а потом можно использовать его
многократно.
Константа, в отличие от переменной, не может изменять свое значение — оно
предопределено при декларации константы, а значение переменной можно менять
в программе. Внесем изменения в предыдущий скетч (см: листинг 6.1), используя
константу и переменную, и получим скетч, представленный в листинге 6.2.
// константа пина Arduino для подключения светодиода
#define PIN_LED 5
// переменная для паузы (тип unsigned long)
unsigned long pause=1000;
void setup () {
// настроить вывод Arduino как OUTPUT
pinMode(PIN_LED, OUTPUT);
void loopO {
// включить светодиод
digitalWrite(PIN_LED, HIGH);
// пауза
delay(pause);
// выключить светодиод
digitalWrite(PIN_LED, LOW);
// пауза
delay(pause);
Загрузим этот скетч в плату Arduino и убедимся, что он работает. В чем его
преимущество перед скетчем из листинга 6.1? Если вам понадобится поменять вывод
(пин) для подключения светодиода, то внести изменения надо будет только в одну
строку:
#define PIN_LED 5
Если понадобится поменять длительность паузы, внести изменения нужно будет
тоже только в одну строку:
unsigned long pause=1000;
Вы можете поэкспериментировать со скетчем, меняя пин подключения светодиода
и значение переменной pause, определяющей частоту его мигания.
Часть III. Практическое применение Arduino
6.1.2. Подключение к плате Arduino 8 светодиодов
Рассмотрим теперь более сложный пример: подключим к плате Arduino 8
светодиодов и создадим из них «бегущий огонь». Для этого нам понадобятся следующие
компоненты:
? плата Arduino Uno;
? кабель USB;
? плата прототипирования (монтажная плата);
? красный светодиод — 8 шт.;
? резистор 220 Ом — 8 шт.;
? соединительные провода ПП — 17 шт.
Монтажная схема этого проекта приведена на рис. 6.2.
Рис. 6.2. Монтажная схема подключения светодиодов для проекта «бегущий огонь»
Приступим к написанию скетча. Прежде всего в процедуре setup о настроим
режим работы пинов Arduino, к которым подключены светодиоды, как output
(выходы):
pinModeA2,OUTPUT);
pinModeA1,OUTPUT);
pinModeA0/OUTPUT);
pinMode(9,OUTPUT);
Глава 6. Проекты для изучения выводов Arduino 93^
pinMode (8, OUTPUT) ;
pinModeG,OUTPUT);
pinModeF,OUTPUT);
pinModeE,OUTPUT);
И в начале программы все светодиоды потушены:
digitalWriteA2,LOW);
digitalWriteA1,LOW);
digitalWriteA0,LOW);
digitalWrite(9,LOW);
digitalWrite(8,LOW);
digitalWriteG,LOW);
digitalWriteF,LOW);
digitalWriteE,LOW);
В основном цикле программы — loop () — нам необходимо зажечь первый свето-
диод, подождать некоторое время, затем выключить его и зажечь второй светодирд,
подождать некоторое время, выключить второй светодиод и зажечь третий, и т. д.
по кругу. Для выполнения операции «подождать некоторое время», как и в
предыдущем примере, мы воспользуемся встроенной в Arduino функцией delay о. Эта
функция просто останавливает выполнение программы на заданное в параметре
количество миллисекунд.
Соответственно внесем в функцию loop () следующий код:
void loop() {
digitalWriteA2,HIGH);
delayA000);
digitalWriteA2,LOW);
digitalWriteA1,HIGH);
delayA000);
digitalWriteA1,LOW);
digitalWriteA0,HIGH);
delayA000);
digitalWriteA0,LOW);
digitalWrite(9,HIGH);
delayA000);
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
delayA000);
digitalWrite(8,LOW);
digitalWriteG,HIGH);
delayA000);
digitalWriteG,LOW);
digitalWriteF,HIGH);
delayA000);
digitalWriteF,LOW);
digitalWriteE,HIGH);
94 Часть III. Практическое применение Arduino
delayA000);
digitalWriteE,LOW);
}
Полный код получившегося скетча приведен в листинге 6.3.
void setup() {
// настроить выводы Arduino 12,11,10,9,8,7, 6,5
// как OUTPUT
pinModeA2,OUTPUT);
pinModeA1,OUTPUT);
pinModeA0,OUTPUT);
pinMode(9,OUTPUT);
pinMode(8,OUTPUT);
pinModeG,OUTPUT);
pinModeF,OUTPUT);
pinModeE,OUTPUT);
// все светодиоды потушить
digitalWriteA2,LOW);
digitalWrite(ll,LOW);
digitalWriteA0,LOW);
digitalWrite(9,LOW);
digitalWrite(8,LOW);
digitalWriteG,LOW);'
digitalWriteF,LOW);
digitalWriteE,LOW);
void I6op() {
digitalWriteA2,HIGH);
delayA000);
digitalWriteA2,LOW);
digitalWriteA1,HIGH);
delayA000);
digitalWriteA1,LOW);
digitalWriteA0,HIGH);
delayA000);
digitalWriteA0,LOW);
digitalWrite(9,HIGH);
delayA000);
digitalWrite(9,LOW);
digitalWrite(8,HIGH);
delayA000) ;
digitalWrite(8,LOW);
digitalWriteG,HIGH);
delayA000);
Глава 6. Проекты для изучения выводов Arduino
digitalWriteG,LOW);
digitalWriteF,HIGH);
delayA000);
digitalWriteF,LOW);
digitalWriteE,HIGH);
delayA000);
digitalWriteE,LOW);
Загрузим этот скетч в плату Arduino — мы должны наблюдать бегущий по свето-
диодам «огонь» сначала в одну сторону, а затем в обратную.
Основной недостаток нашего скетча — он слишком громоздкий. И даже
объявление каждого вывода с помощью переменных не исправит положения. К счастью,
есть способ значительно упростить этот скетч, воспользовавшись массивами.
Массив — это набор переменных, доступ к которым осуществляется через их индекс.
Рассмотрим варианты создания (объявления) массива:
? объявление массива без его инициализации:
int pin_leds[8];
? можно объявить массив без непосредственного указания размера. Компилятор
подсчитает количество элементов и создаст массив соответствующего размера:
int pinJLeds t] = {5,6,7,8,9,10,11,12};
? можно одновременно инициализировать и указать размер создаваемого массива:
int pin_leds [8] = {5,6,7,8,9,10,11,12};
? объявление массива типа char:
char message[8] = "Arduino";
Учтите, что в таком случае необходимо предусмотреть еще один элемент для
хранения обязательного null-символа:
Теперь рассмотрим, как осуществляется доступ к элементам массива. Индексация
в массивах начинается с нуля. То есть первый элемент массива будет иметь
порядковый номер 0. Таким образом:
pin_leds[0] = 5;
pin_leds[l] = 6;
Как работать с массивами? Очень удобный метод работы с массивами— циклы.
При этом счетчик цикла используется для индексации каждого элемента массива.
Например, для создания массива с номерами пинов, задаваемыми командой
pinMode (), необходимо выполнить следующий код:
int i;
for (i = 0; i < 8; i = i + 1) {
pinMode (pin_leds [ i ], OUTPUT) ;
Часть III. Практическое применение Arduino
Внесем соответствующие изменения в предыдущий скетч (см. листинг 6.3),
используя массивы, и получим скетч, представленный в листинге 6.4.
В нем кроме массивов мы предусмотрели для позиции горящего светодиода
переменную pos, которая после каждой паузы станет увеличиваться на 1, а при
достижении значения 8 будет обнуляться:
pos=(pos+l)%8;
При этом мы запускаем цикл for для массива pin_ieds[i] с пинами подключения
светодиодов, в котором для всех элементов массива с индексом, не равным
значению переменной pos, выполняем команду:
digitalWrite(pin_leds[i],LOW);
а для элемента массива с индексом, равным значению переменной pos, команду:
digitalWrite (pin_leds [i], HIGH);
// массив, элементы которого - пины
// подключения светодиодов
int pin_leds [8] = {12,11,10,9,8,7,6,5};
// позиция горящего светодиода
int pos=0;
// переменная для паузы (тип unsigned long)
unsigned long pause=1000;
void setup() {
// настроить выводы Arduino как OUTPUT
for (int i = 0; i < 8; i = i + 1) {
pinMode(pin_leds [i],OUTPUT);
}
// все светодиоды потушить
for (int i = 0; i < 8; i = i + 1) {
digitalWrite(pin_leds [i],LOW);
void loopO {
// все светодиоды потушить
for (int i = 0; i < 8; i = i + 1) {
// зажечь светодиод, если он =pos
if(i==pos)
digitalWrite(pin_leds [i],HIGH);
// все остальные потушить
else
digitalWrite (pin_leds [i], LOW) ;
Глава 6. Проекты для изучения выводов Arduino 97
// пауза
delay(pause);
// изменить позицию горящего светодиода
pos=(pos+l)%8;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\6\_06_04
сопровождающего книгу электронного архива. Напоминаю, что этот электронный архив можно
скачать с FTP-сервера издательства «БХВ-Петербург» по ссылке ftp://ftp.bhv.ru/
9785977567114.zip, а также со страницы книги на сайте www.bhv.ru (см. приложение 2).
Загрузим этот скетч в плату Arduino и убедимся в его работоспособности.
Метод расположения пинов в пределах массива очень удобен и позволяет
переставлять их как угодно без переподключения светодиодов. Вы можете
самостоятельно поэкспериментировать с расположением элементов массива.
6.2. Цифровые входы — управляем
светодиодами с помощью кнопок
Рассмотрим еще одну функцию цифровых выводов. В предыдущем разделе мы
использовали их в качестве выходов, генерируя цифровой сигнал для включения или
выключения светодиодов. Сейчас мы попробуем сконфигурировать выводы
Arduino в качестве входов. Это позволит подключить к Arduino, например,
переключатели и кнопки для взаимодействия с внешними устройствами в режиме
реального времени. И в этом разделе вы научитесь определять программное действие
по нажатию кнопки.
Установка режима того или иного вывода (на вход или на выход) осуществляется
С ПОМОЩЬЮ фуНКЦИИ pinMode () Г »
pinModeB,INPUT); // вывод D2 установлен как выход
6.2.1. Подключение кнопки к плате Arduino
Чтобы подключить к Arduino нормально разомкнутую кнопку, можно пойти самым
простым путем: один свободный проводник кнопки соединить с питанием или
«землей», а другой — с цифровым выводом Arduino (рис. 6.3). Но это
неправильно — все то время, когда кнопка не замкнута, на цифровом выводе Arduino могут
появляться электромагнитные наводки, и из-за этого возможны ложные
срабатывания.
Чтобы избежать наводок, цифровой вывод обычно подключают через достаточно
большой резистор E-10 кОм) либо к питанию, либо к «земле». В первом случае это
называется схемой с подтягивающим резистором (рис. 6.4), во втором — схемой со
стягивающим резистором (рис. 6.5). Резисторы в обеих схемах используются для
98
Часть III. Практическое применение Arduino
Рис. 6.3. Монтажная схема подключения кнопки к выводу Arduino
+5 В
Рис. 6.4. Монтажная {вверху) и принципиальная {внизу) схемы подключения кнопки к Arduino:
схема с подтягивающим резистором
Глава 6. Проекты для изучения выводов Arduino 99
+5 В
ЮкОм
Рис. 6.5. Монтажная (вверху) и принципиальная (внизу) схемы подключения кнопки к Arduino:
схема со стягивающим резистором
установки «значения по умолчанию» из входного контакта: в схеме с
подтягивающим резистором это high, в схеме со стягивающим резистором — low.
Но вот любопытный момент. Ранее мы утверждали, что схема, показанная на
рис. 6.3, неверная, но это только в том случае, если мы используем такой режим
установки:
pinMode B, INPUT) ; // вывод D2 установлен как выход
Однако все выводььвнутри платы Arduino подсоединены к шине питания 5 В через
резисторы сопротивлением порядка 20-50 кОм. И эти резисторы можно
программно подключать к выводам или отключать от них. Программное включение
резисторов осуществляется так:
pinMode C, INPUT_PULLUP); // внутренний подтягивающий резистор 20 кОм подключен
И схема подключения кнопки, показанная на рис. 6.3, уже оказывается верной!
Теперь напишем программу (листинг 6.5), устанавливающую состояние светодио-
да, подключенного к выводу 13 (находится на плате Arduino), в зависимости от
состояния кнопки (кнопка нажата — светодиод горит, кнопка отпущена — светодиод
потушен).
100 Часть III. Практическое применение Arduino
В процедуре setup () устанавливаем режимы выводов, а в процедуре loop () —
считываем состояние кнопки в переменную buttonstate и передаем его на светодиод.
Для схемы с подтягивающим резистором состояние переменной buttonstate
инвертируем, т. к. в этом случае при нажатой кнопке состояние сигнала низкое, а
светодиод светится при высоком. Для схемы со стягивающим резистором состояние
переменной buttonstate инвертировать не надо.
const int LED=13; // Контакт 13 для подключения светодиода
const int BUTTON=2; // Контакт 2 для подключения кнопки
boolean buttonstate; // переменная статуса кнопки buttonstate
void setup() {
// определяем вывод LED (светодиод) как выход
pinMode(LED, OUTPUT);
// определяем вывод BUTTON (кнопка) как вход
pinMode(BUTTON, INPUT_PULLUP);
void loop () {
// считываем состояние BUTTON входа (кнопки) и записываем в buttonstate
buttonstate = digitalRead(BUTTON);
// инверсия переменной buttonstate
// для схемы с подтягивающим резистором
buttonstate = ! buttonstate;
// записываем состояние из buttonstate на выход LED (светодиод)
digitalWrite(LED, buttonstate);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\6\_06_05
сопровождающего книгу электронного архива (см. приложение 2).
Загрузим этот скетч в плату Arduino — вы должны наблюдать включение
светодиода на выводе 13 при нажатии кнопки и выключение его при ее отпускании.
Насколько удобно держать кнопку постоянно нажатой для свечения светодиода?
Гораздо удобнее иметь возможность нажать кнопку один раз, чтобы включить
светодиод и, нажав ее еще раз, выключить. Загрузим в плату Arduino скетч
переключения состояния светодиода при нажатии кнопки (листинг 6.6). Для отладки
воспользуемся выводом данных в последовательный порт.
const int LED=13; // Контакт 13 для подключения светодиода
const int BUTTON=2; // Контакт 2 для подключения кнопки
boolean buttonstate; // переменная статуса кнопки buttonstate
Глава 6. Проекты для изучения выводов Arduino 101
boolean buttonStatePrevKLOW; // переменная статуса кнопки предыдущая
boolean ledState=LOW; // переменная статуса светодиода
void setup() {
// запуск последовательного порта
Serial.begin(9600);
// определяем вывод LED (светодиод) как выход
pinMode(LED, OUTPUT);
// определяем вывод BUTTON (кнопка) как вход
pinMode(BUTTON, INPUT^PULLUP);
// начальное состояние светодиода
digitalWrite(LED, ledState);
void loop () {
// считываем состояние BUTTON входа (кнопки)
buttonState = digitalRead(BUTTON);
// если нажатие с LOW на HIGH
if (buttonState == HIGH && buttonStatePrev==LOW) {
ledState = ! ledState;
// записываем состояние из ledState на выход LED (светодиод)
digitalWrite(LED, ledState);
Serial.println(ledState);
}
buttonStatePrev = buttonState;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\6\JNJN
сопровождающего книгу электронного архива (см. приложение 2).
Нажимаем на кнопку и видим, что в последовательном порту при однократном
нажатии кнопки происходит несколько изменений ее состояния (рис. 6.6) и
соответственно несколько переключений светодиода.
Почему же так происходит? Дело в том, что кнопки представляют собой
механические устройства с системой пружинного контакта, подверженной явлению,
называемому дребезгом,— в процессе нажатия кнопки контакт, особенно в начале
нажатия, несколько раз замыкается и размыкается. То есть, когда вы нажимаете
на кнопку, сигнал не просто меняется от низкого до высокого — он в течение
нескольких миллисекунд меняет значение от одного до другого, прежде чем
установится значение low. Графики, приведенные на рис. 6.7, иллюстрируют отличие
ожидаемого явления от реального.
Нажатие кнопки происходит примерно за 25 мс. Вы могли бы предположить, что
можете сразу узнать о состоянии кнопки, считав значение со входа контакта, как
показано на левом графике. Однако кнопка фактически движется вверх-вниз, пока
значение не установится, как показано на правом графике. Теперь, зная, как ведет
102
Часть III. Практическое применение Arduino
При одном нажатии кнопки
Рис. 6.6. Вывод данных отладки в монитор последовательного порта
Идеальное нажатие кнопки Реальное нажатие кнопки
Кнопка нажата Кнопка нажата
Рис. 6.7. Дребезг при нажатии кнопки
себя кнопка, вы можете написать программу, которая обеспечит нормальное снятие
показаний с кнопки, подверженной дребезгу, — она считывает состояние кнопки и
ожидает некоторое время, после чего считывает состояние снова, чтобы убедиться,
что первоначальное состояние не изменилось. Эта логика программы может быть
выражена следующим образом:
1. Сохраняем предыдущее состояние кнопки и текущее состояние кнопки (при
инициализации low).
Глава 6. Проекты для изучения выводов Arduino 103
2. Считываем текущее состояние кнопки.
3. Если текущее состояние кнопки отличается от предыдущего ее состояния, ждем
5 мс, потому что кнопка, возможно, изменила состояние.
4. По истечении 5 мс считываем состояние кнопки и используем его в качестве
текущего.
5. Если предыдущее состояние кнопки было low, а текущее high, переключаем
состояние светодиода.
6. Устанавливаем предыдущее состояние кнопки для ее текущего состояния.
7. Возврат к шагу 2.
Составляем скетч по приведенному алгоритму (листинг 6.7), загружаем его в плату
Arduino и проверяем работоспособность. Как можно видеть, однократное нажатие
кнопки приводит к однократному изменению состояния светодиода.
const int LED=13; // Контакт 13 для подключения светодиода
const int BUTTON=2; // Контакт 2 для подключения кнопки
boolean lastButton = LOW; // Переменная для сохранения предыдущего
// состояния кнопки
boolean currentButton = LOW; // Переменная для сохранения текущего
// состояния кнопки
boolean ledOn = false; // Текущее состояние светодиода
(включен/выключен)
void setup () {
// запуск последовательного 'порта
Serial.begin(9600);
pinMode (LED, OUTPUT); // Сконфигурировать контакт светодиода как
выход
pinMode (BUTTON, INPUT); // Сконфигурировать контакт кнопки как вход
void loop() {
currentButton = debounce(lastButton);
if (lastButton == LOW && currentButton = HIGH) // если нажатие...
{
ledOn = IledOn; // инвертировать значение состояния светодиода
Serial.printIn(ledOn);
}
lastButton = currentButton;
digitalWrite(LED, ledOn); // изменить статус состояния светодиода
104 Часть III. Практическое применение Arduino
// Функция сглаживания дребезга
// Принимает в качестве аргумента предыдущее состояние кнопки,
// выдает фактическое.
boolean debounce(boolean last) {
boolean current = digitalRead(BUTTON); // Считать состояние кнопки
if (last != current) ' // если изменилось...
{
delayE); . // ждем 5 мс
current = digitalRead(BUTTON); // считываем состояние кнопки
return current; // возвращаем состояние кнопки
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\6\_06_07
сопровождающего книгу электронного архива (см. приложение 2).
6.2.2. Управление кнопками количеством горящих
светодиодов
Создадим еще один проект с использованием кнопок — будем управлять с их
помощью количеством горящих светодиодов. Для этого нам понадобятся следующие
компоненты:
? плата Arduino Uno;
? кабель USB;
? плата прототипирования (монтажная плата);
? соединительные провода 1111 — 12 шт.;
? резисторы 220 Ом — 8 шт.;
О светодиоды — 8 шт;
? кнопки — 2 шт.;
? резисторы 10 кОм — 2 шт.
В представленной на рис. 6.8 монтажной схеме этого проекта восемь
подключенных к плате Arduino светодиодов расположены в ряд. При нажатии одной кнопки
добавляем горящий светодиод, при нажатии другой — убираем.
Весь основной цикл программы мы постоянно опрашиваем кнопки, ожидая их
нажатия. После нажатия кнопки следует реакция— изменение переменной counti
(количества зажженных светодиодов). Обратите внимание, что это число не может
быть меньше о и больше значения countleds. Функция changecounti о возвращает
измененное состояние counti:
int change_countl(int but) {
if (but=0) // добавить
return min(count1+1,COUNT LEDS);
Глава 6. Проекты для изучения выводов Arduino
105
else // снять
return max(count1-1,0);
После изменения значения counti нам необходимо установить новые состояния для
светодиодов, чтобы они соответствовали новому значению counti, — нужно зажечь
светодиоды с о до counti и потушить светодиоды с counti до последнего
(count_leds=8). Для этого вызываем функцию setiedso, передавая ей в качестве
аргумента значение counti:
void setleds(int cnt) {
// включение светодиодов от 0 до counti
for(int i=0;i<cnt;i++)
digitalWrite(pinleds[i],HIGH);
// включение светодиодов от 0 до cnt
for(int i=cnt;i<COUNT_LEDS;i++)
digitalWrite(pinleds[i],LOW);
Рис. 6.8. Монтажная схема подключения светодиодов и кнопок
106 Часть III. Практическое применение Arduino
Для устранения дребезга кнопок используем функцию debounce () из листинга 6.7.
Создадим в Arduino ШЕ новый скетч, занесем в него код из листинга 6.8 и загрузим
скетч в плату Arduino. Напомним, что в настройках Arduino IDE необходимо
выбрать тип платы (Arduino UNO) и порт подключения платы.
// количество кнопок
#define COUNT_BUTTONS 2
// количество светодиодов
#define COUNTJLEDS 8
// Выводы Arduino для подключения
// список светодиодов
int pinleds[8]={4,5,6,1,8,Ъ,10,11};
// список кнопок
int pinbuttons[2]={2,3};
// список сохранения предыдущих состояний кнопок
int lastbuttons[2]={0,0};
// список сохранения текущих состояний кнопок
int currentbuttons[2]={0,0};
// переменные - количество горящих светодиодов
int count1=0;
void setup() {
// настроить выводы Arduino для светодиодов как выходы
for(int i=0;i<COUNT_LEDS;i++) {
pinMode(pinleds[i], OUTPUT);
}
// установить число светодиодов @)
setleds(O);
// the loop function runs over and over again forever
void loop() {
// проверка нажатия кнопок выбора программ
for(int i=0;i<COUNT_BUTTONS;i++) {
currentbuttons[i] = debounce(lastbuttons[i],pinbuttons[i]);
// если нажатие...
if (lastbuttons[i] == 0 && currentbuttons[i] = 1) {
// реакция на нажатие - изменение count1
countl=change_countl(i);
// обновление состояния
setleds(count1);
Глава 6. Проекты для изучения выводов Arduino 107
lastbuttons[i] = currentbuttons[i];
// изменение количества светодиодов
int change_countl(int but) {
if (but=0) // добавить
return min(count1+1,COUNT_LEDS);
else // снять
return max(count1-1,0);
// (включение-выключение светодиодов)
void setleds (irit cnt) {
// включение светодиодов от 0 до count1
for(int i=0;i<cnt;i++)
digitalWrite(pinleds[i],HIGH);
// включение светодиодов от 0 до cnt
for(int i=cnt;i<COUNT_LEDS;i++)
digitalWrite(pinleds[i],LOW);
}
/* Функция сглаживания дребезга
* Принимает в качестве аргумента предыдущее состояние кнопки
* и выдает фактическое.
V
int debounce(int last,int pinl) {
int current = digitalRead(pinl); // Считать состояние кнопки
// если изменилось...
if (last != current) {
delayE); // ждем 5 мс
current = digitalRead(pinl); // считываем состояние кнопки
return current; // возвращаем состояние кнопки
Электронный архив
Полный вариант рассмотренного скетча находится в папке examplesW^oe^oe
сопровождающего книгу электронного архива (см. приложение 2).
6.3. Аналоговые входы —
светодиодный индикатор аналоговых значений
В предыдущих разделах мы познакомились с цифровыми выводами Arduino,
которые могут работать в режиме входов — для считывания внешних цифровых
сигналов, и выходов— для выдачи цифровых данных. Но цифровые данные имеют
только два состояния: high и low. В то же время мир вокруг нас является аналого-
108
Часть III. Практическое применение Arduino
вым — большинство наблюдаемых явлений в окружающем нас мире чаще всего
имеет аналоговый характер. Мир предполагает бесконечное число возможных
состояний, будь то цвет солнечного света, или температура океана, или концентрация
загрязняющих веществ в воздухе.
Графики на рис. 6.9 показывают, как аналоговые и цифровые сигналы отличаются
друг от друга. Слева — прямоугольная волна, значения которой варьируются
только между двумя значениями: 0 и'5 В. Точно так же, как и в случае с кнопкой,
которую вы использовали в предыдущем разделе, этот сигнал — только high или low.
Справа — часть косинусоидальной волны. Несмотря на то что ее границы все еще
О и 5 В, сигнал имеет бесконечное число значений между этими двумя
напряжениями.
10
А 6
Time(s)
10
Рис. 6.9. График значений для цифровых (слева) и аналоговых (справа) сигналов
Компьютерная система никогда не сможет осуществлять измерение аналогового
значения с его бесконечным числом десятичных разрядов, потому что память и
производительность компьютера небеспредельны. Если это так, то как вы можете
соединить интерфейс цифрового Arduino с аналоговым реальным миром? Ответ
прост— с помощью аналого-цифрового преобразователя (АЦП), который может
преобразовать аналоговые значения в цифровые представления с конечной
точностью.
Каждый из аналоговых контактов Arduino (для Arduino Uno это А0-А5) содержит
10-разрядный АЦП для аналоговых преобразований. 10-разрядный здесь
означает, что АЦП может разделить аналоговый сигнал на 210 различных значений
B10 = 1024)— от 0 до 1023. Максимальное напряжение E В) задает опорное
напряжение— его значение соответствует значению 1023 АЦП. При напряжении на
контакте 0 В АЦП возвращает значение 0. Напряжение 2,5 В возвращает
значение 512 (половина из 1023), и т. д.
Глава 6. Проекты для изучения выводов Arduino 109
6.3.1. Подключение потенциометра к плате Arduino
Самый простой аналоговый датчик, с которого вы можете получить данные, — это
потенциометр. Потенциометры являются переменными делителями напряжения
и часто выглядят как ручки. Они присутствуют в стереосистемах, звуковых
колонках, термостатах и в других изделиях, бывают разных размеров и форм, но все
имеют три вывода.
В представленной на рис. 6.10 монтажной схеме этого проекта один из крайних
выводов потенциометра подключен на «землю», а другой крайний вывод — к шине
+5 В. Средний вывод потенциометра подключен к аналоговому входу АО платы
Arduino.
Рис. 6.10. Монтажная схема подключения потенциометра к плате Arduino
Для считывания данных с аналогового порта в Arduino есть функция anaiogRead (),
которая возвращает аналоговое значение с аналогового входа Arduino, например:
int val=analogRead(AO);
Загрузим в плату Arduino скетч из листинга 6.9, обеспечивающий вывод в монитор
последовательного порта значений с потенциометра, подключенного к аналоговому
входу АО.
// пин подключения среднего вывода потенциометра
tele fine PIN_ANALOG АО
// переменная для сохранения значения потенциометра
int val;
void setup() {
// запуск последовательного порта
Serial.begin(9600);
110 Часть III. Практическое применение Artiuino
void loop() {
// считать значение с аналогового порта
val=analogRead(PIN_ANALOG);
// вывести последовательный порт
Serial.print("val^");
Serial.println(val);
delayC00);
Загрузив скетч в плату, откроем монитор последовательного порта и покрутим
ручку потенциометра— значения будут меняться в промежутке от 0 до 1023
(рис. 6.11).
val-398
val-398
val-398
val-398
val«39€
val-398
val-399
val«399
val-398
val-350
val-l€5
val-117
val-102
val-29
val-0
val-0
val-194
val-328
val-424
val-646
val-917
val-1023
val-1023
val-1023
val-1023
val-1023
val-1023
val-1023
val-1023
Рис. 6.11. Вывод данных с аналогового входа в монитор последовательного порта
Проблемы не возникнет и в том случае, если мы захотим получить с потенциометра
реальные значения сопротивления в омах, — просто составим пропорцию:
1023 — ЮкОм,
val — X кОм.
Тогда
X = val х 10/1023.
Глава 6. Проекты для изучения выводов Arduino 111
В Arduino IDE для таких преобразований имеется встроенная функция тар ():
тар (value, fromLow, fromHigh, toLow, toHigh)
Функция пропорционально переносит значение value из текущего диапазона
значений fromLow . . . fromHigh В НОВЫЙ диапазон toLow .. . toHigh.
Обратите внимание, что «нижняя граница» может быть как меньше, так и больше
«верхней границы». Этим можно воспользоваться, чтобы «перевернуть» диапазон:
у = map(x, 1, 50, 50, 1);
Возможно использование и отрицательных значений:
у = шар(х, 1, 50, 50, -100);
Функция тар () оперирует целыми числами. При пропорциональном переносе
дробная часть не округляется по правилам, а просто отбрасывается.
Внесем изменения в предыдущий скетч (см. листинг 6.9), чтобы в монитор
выводились не только показания аналогового входа АО, но и чтобы мы могли видеть
выставляемые значения потенциометра в омах, и получим скетч, представленный
в листинге 6.10.
Загружаем в плату Arduino этот скетч и смотрим вывод показаний потенциометра
в омах (рис. 6.12).
// пин подключения среднего вывода потенциометра
#define PIN_ANALOG АО
// переменная для сохранения значения потенциометра
int val;
unsigned int valQm;
void setup() {
// запуск последовательного порта
Serial.begin(9600);
}
void loop() {
// считать значение с аналогового порта
val=analogRead(PIN_ANALOG);
// переводим в Ом
valQm=map(val,0,1023,0,10000);
// вывести последовательный порт
Serial.print("val=");
Serial.print(valOm) ;
Serial.println(" Qm");
delayC00);
112 Часть III. Практическое применение Arduino
val-10000 On
val-10000 Ob
val*10QOO Om
val«9266 On
val~7849 On
val-7028 On
val-6402 On
val-5503 On
val-4017 On
val-2482 On
val-1104 On
val-0 On
val-Q On
val-0 On
val«0 On
val-0 On
val«0 On
val-1221 On
va1-2932 On
val-4467 On
val-5522 On
val-6304 On
val-6285 On
val-6471 On
val-6510 On
val-6510 On
val-6510 On
val-6510 On
Om
Рис. 6.12. Вывод показаний потенциометра в монитор последовательного порта в омах
6.3.2. Вывод показаний потенциометра
на светодиодную шкалу
Теперь визуализируем аналоговые данные потенциометра с помощью
светодиодной шкалы, состоящей из 10 светодиодов. Для этого нам понадобятся следующие
компоненты:
? плата Arduino Uno;
? кабель USB;
? плата прототипирования;
? 10-разрядная линейная светодиодная шкала;
? резистор 220 Ом — 10 шт.;
? соединительные провода ПП — 15 шт.
В представленной на рис. 6.13 монтажной схеме этого проекта для подключения
светодиодной шкалы к Arduino мы задействуем 10 цифровых выводов: D3-D12.
Каждый из светодиодов шкалы выводом анода соединен с цифровым выводом
Arduino, а катодом— с «землей» через последовательно включенный ограничи-
Глава 6. Проекты для изучения выводов Arduino
113
вающий резистор 220 Ом. Аналоговые данные потенциометра @-1023)
масштабируем в данные шкалы @-10) с помощью функции тар () и зажигаем на ней
соответствующее количество светодиодов (листинг 6.11).
Рис. 6.13. Монтажная схема подключения к Arduino
индикатора показаний потенциометра на светодиодах
// Аналоговый вход АО для подключения потенциометра
const int POT=0;
// переменная для хранения значения потенциометра
int valpot = 0;
// список контактов подключения светодиодов
const int pinsled[10]={4,5,6,7,8,9,10,11,12,13};
// переменная для хранения значения шкалы
int countleds = 0;
void setup() {
// запуск последовательного порта
Serial.begin(9600);
for(int i=0;i<10;i++) {
// Сконфигурировать контакты подсоединения шкалы как выходы
pinMode(pinsled[i],OUTPUT);
digitalWrite(pinsled[i],LOW);
114 Часть III. Практическое применение Arduino
void loop () {
// чтение данных потенциометра
valpot = analogRead(POT);
// масштабируем значение к интервалу 0-10
countled=map(valpot,0,1023,0,10);
Serial.print("countled =");
Serial.println(countled);
// зажигаем количество светодиодов на шкале, равное countled
.for(int i=0;i<10;i++) {
if(i<countleds) // зажигаем светодиод шкалы
digitalWrite(pinsled[i]fHIGH);
else // гасим светодиод шкалы
digitalWrite(pinsled[i],LOW);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\6\_06_11
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем скетч в плату Arduino и, поворачивая ручку потенциометра, следим
за показаниями шкалы из светодиодов. Данные для отладки выводим в монитор
последовательного порта.
6.4. ШИМ — радуга на RGB-светодиоде
Arduino не может на цифровой выход выдавать произвольное напряжение:
выдается либо +5 В (high), либо 0 В (low). Но уровнем напряжения управляется многое,
например: яркость светодиода, скорость вращения мотора или звук пьезоизлучате-
ля. Решение этой проблемы обеспечивает широтно-импулъсная модуляция (ШИМ) —
процедура получения изменяющегося аналогового значения с использованием
цифровых сигналов.
Работу с помощью ШИМ на Arduino обеспечивают «особые» цифровые выводы,
называемые PWM (Pulse-width modulation, широтно-импульсная модуляция) и
обозначенные на плате волнистой линией примерно такого вида ~. На платах Arduino
Nano и Arduino Uno ШИМ поддерживают выводы 3, 5, 6, 9-11, на плате Mega —
выводы 2-13.
Принцип организации ШИМ основан на том, что цифровой сигнал на выходе
постоянно переключается между максимальным и минимальным значениями.
Длительность включения максимального значения называется шириной импульса. При
этом отношение ширины импульса к периоду его следования (скваэюность) можно
изменять (рис. 6Л 4). Если скважность равняется 100%, то все время на цифровом
выходе Arduino будет напряжение логической единицы E В). Если задать
скважность 50%, то половину времени на выходе будет логическая единица, а
половину— логический ноль и среднее напряжение будет равняться 2,5 В. И так далее.
Глава 6. Проекты для изучения выводов Arduino
115
Таким образом, с помощью задания скважности можно менять среднее напряжение
на выходе ШИМ.
Выводы Arduino с функцией широтно-импульсной модуляции работают на частоте
около 500 Гц. Глаз не замечает мерцания более 50 Гц, поэтому нам кажется, что
светодиод, на который подается ШИМ-сигнал, не мерцает, а лишь горит в
неполную силу — пропорционально скважности этого сигнала.
Широтно-Импульсиая модуляция
0% рабочего цикла - analogWrite(O)
5v
0v
5v
Ov
5v
Ov
Sv
Ov
5v
Ov
2$% рабочего цикла - anatogWrtteF4)
fUUUUU
50% рабочего цикла - anaiogWHte(i27)
ППЛ-П-Ш
75% рабочего цикла - anatogWrtteA91)
ппппгц
100% рабочего цикла - analogWrtt0B55)
Красный .
Общий
1234
Рис. 6.14. Принцип работы
широтно-импульсной модуляции (ШИМ)
Рис. 6.15. Контакты
RGB-светодиода
Посмотрим, как на основе ШИМ управлять яркостью светодиода. Создадим для
этого проект генерации любого цвета, воспользовавшись специальным светодио-
дом RGB.
Аббревиатура RGB расшифровывается как Red, Green, Blue (красный, зеленый,
синий)— из этих цветов можно получить любой цвет путем смешения исходных.
Светодиод RGB отличается от обычного тем, что содержит три небольших
кристалла: R, G и В, с помощью которых можно синтезировать любой цвет или
оттенок, в зависимости от подаваемых на них напряжений. RGB-светодиод имеет 4
вывода (рис. 6.15).
6.4.1. Подключение к плате Arduino RGB-светодиода
Подключим RGB-светодиод к плате Arduino и заставим его переливаться всеми
цветами радуги. В представленной на рис. 6.16 монтажной схеме этого проекта
присутствует и потенциометр, с помощью которого мы сможем регулировать
скорость изменения этих цветов.
116
Часть III. Практическое применение Arduino
аг^^
Рис. 6.16. Монтажная схема подключения RGB-светодиода для свечения всеми цветами радуги
Список семи основных цветов радуги с разложением их по компонентам R, G и В
представлен в табл. 6.1.
Таблица 6.1. Семь основных цветов радуги с разложением по компонентам R, G и В
Цвет
Красный
Оранжевый
Желтый
Зеленый
Голубой
Синий
Фиолетовый
R
255
255
255
0
0
0
255
G
0
125
255
255
255
0
0
В
0
0
0
0
255
255
255
Наш светодиод должен переливаться от красного цвета до фиолетового, проходя
через все семь основных цветов. Алгоритм вычисления любого промежуточного
цвета радуги следующий:
1. Примем за начальную точку отсчета красный цвет B55, 0, 0).
2. Будем постепенно увеличивать значение зеленой составляющей G, пока не
достигнем значения оранжевого B55, 125, 0), а затем и желтого цвета B55,255, 0).
3. Постепенно уменьшим значение красной составляющей R до значения зеленого
цвета @, 255, 0).
Глава 6. Проекты для изучения выводов Arduino 117
4. Постепенно увеличим значение синей составляющей В до значения голубого
цвета @, 255, 255).
5. Постепенно уменьшим количество зеленой составляющей G до значения синего
цвета @, 0,255).
6. Постепенно увеличим количество красной составляющей R до значения
фиолетового цвета B55, 0,255).
7. Выдерживаем небольшую паузу и переходим к шагу 1.
Содержимое скетча, реализующего этот алгоритм, приведено в листинге 6.12.
// пауза перед каждым изменением цвета радуги
tdefine MAX_PAUSE 30
#define MINJPAUSE 1
// пин подключения среднего вывода потенциометра
const int PIN_POT=A0;
// вывод красной ноги RGB-светодиода
const int RED=11;
// вывод зеленой ноги RGB-светодиода
const int GREEN=10;
// вывод синей ноги RGB-светодиода.
const int BLUE=9;
// переменная для хранения значения потенциометра
int pot;
// переменная для хранения R-составляющей цвета
int red;
// переменная для хранения G-составляющей цвета
int green;
// переменная для хранения В-составляющей цвета
int blue;
void setup()
void loop () {
//от красного к желтому
red=2 55;green=0;blue=0;
for(green=0;green<=255;green++)
setRGB(red,green,blue);
//от желтого к зеленому
for(red=255;red>=0;red—)
setRGB(red,green,blue);
//от зеленого к голубому
for(blue=0;blue<=255;blue++)
setRGB(red,green,blue);
118
Часть III. Практическое применение Arduino
//от голубого к синему
for(green=255;green>=0;green—)
setRGB(red,green,blue);
//от синего к фиолетовому
for(red=0;red<=255;red++)
setRGB(red,green,blue);
delayB000);
}
// функция установки цвета RGB-светодиода
void setRGB(int r,int g,int b) {
analogWrite(RED,r);
analogWrite(GREEN,g);
analogWrite(BLUE,b);
pot=analogRead(PIN_POT);
delay(шар(pot,0,1023, MIN_PAUSE, MAX_PAUSE)
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\6\_06_12
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем скетч в плату и наблюдаем свечение RGB-светодиода всеми цветами
радуги. Скорость изменения цветов регулируем с помощью потенциометра.
6.5. Светодиодные индикаторы
Светодиодный индикатор представляет собой группу светодиодов, расположенных
в определенном порядке и объединенных конструктивно. Рассмотрим один из
самых распространенных светодиодных индикаторов— светодиодный семисег-
ментный индикатор.
В светодиодных семисегментных индикаторах контакты промаркированы метками
от а до g (и дополнительно DP — для отображения десятичной точки). У них также
имеется один общий вывод, который определяет тип подключения индикатора:
схема с общим анодом (ОА) или с общим катодом (ОК). Зажигая одновременно
несколько светодиодов, можно формировать на индикаторе символы цифр.
Назначение контактов светодиодного семисегментного индикатора D5651 с общим катодом
показано на рис. 6.17.
6.5.1. Подключение к плате Arduino
семисегментного индикатора
Создадим проект вывода на семисегментный индикатор цифр от 0 до 9. Для этого
нам понадобятся следующие компоненты:
? плата Arduino Uno;
D кабель USB;
Глава 6. Проекты для изучения выводов Arduino
119
Ю 9,8
12 3 4 5
Рис. 6.17. Назначение контактов индикатора D5651 с общим катодом
? плата прототипирования;
? семисегментный индикатор D5651;
? резистор 220 Ом — 8 шт.;
? соединительные провода ПП— 15 шт.
Монтажная схема подключения семисегментного индикатора D5651 к плате Arduino
показана на рис. 6.18.
При создании скетча для хранения информации о каждой цифре будем
использовать 1 байт, который состоит из 8 битов (каждый бит: 0 или 1). Данные для
представления каждой цифры приведены в табл. 6.2.
Рис. 6.18. Монтажная схема подключения семисегментного индикатора D5651 к плате Arduino
120
Часть III. Практическое применение Arduino
Цифра
0
1
2
3
4
5
6
7
8
9
а
бит 7
1
0
1
1
0
1
.1
1
1
1
b
бит б
1
1
1
1
1
0
0
1
1
1
Таблица
Сегменты
с
бит 5
1
1
0
1
1
1
1
1
1
1
d
бит 4
1
0
1
1
0
1
1
0
1
1
6.2. Значения битов для каждой цифры
индикатора
е
битЗ
1
0
1
0
0
0
1
0
1
0
f
бит 2
1
0
0
0
1
1
1
0
1
1
g
бит1
0
0
1
1
1
1
1
0
1
1
DP
битО
0
0
0
0
0
0
0
0
0
0
Число
в двоичной
форме
В11111100
В01100000
В11011010
В11110010
В01100110
В10110110
В10111110
В11100000
В11111110
В11110110
Организуем массив для описания 10 цифр (от 0 до 9):
// значения для вывода цифр 0-9
byte numbers[10] = { В11111100, // 0
В01100000, // 1
B11011010, // 2
B11110010, // 3
B01100110, // 4
B10110110, // 5
B10111110, // 6
B11100000, // 7
B11111110, // 8
B11100110 // 9
Теперь напишем подпрограмму setNumber (), отвечающую за вывод значений на
контакты Arduino для индикации цифры. Воспользуемся при этом Arduino-функ-
цией bitReadO, которая возвращает состояние указанного бита числа A илиО).
Нумерация начинается с младшего значащего бита (крайнего правого) с номером 0:
x=bitRead(B01001000,б); // х=1 - шестой бит, начиная с нулевого (крайнего справа)
А вот и сама подпрограмма:
void setNumber (int num) {
// пройти по всем битам
for(int i=0;i<7;i++) {
if(bitRead(numbers[num],7-i)==HIGH) // зажечь сегмент
digitalWrite(pins[i],HIGH);
Глава 6. Проекты для изучения выводов Arduino 121
else // потушить сегмент
digitalWrite(pins[i],LOW);
Каждую секунду (реализуем это с помощью delay (ЮОО)) мы будем выводить на
индикатор новое число от 0 до 9 (листинг 6.13).
// список выводов Arduino для подключения к разрядам а-д
// семисегментного индикатора
int pins[7]={11,10,9,8,7,6,5,4};
// значения для вывода цифр 0-9
byte numbers[10] = { В11111100, // 0
В01100000, // 1
B11011010, // 2
B11110010, // 3
B01100110, // 4
B10110110, // 5
B10111110, // 6
B11100000, // 7
B11111110, // 8
B11100110 // 9
};
// переменная для хранения значения текущей цифры
int number=0;
void setup() {
// Сконфигурировать контакты как выходы
for(int i=0;i<7;i++)
pinMode(pins[i],OUTPUT);
void loop () {
setNumber(number);
delayA000);
// следующая цифра
number=(number+l)%10;
// функция вывода цифры на семисегментный индикатор
void setNumber(int num) {
for(int i=0;i<7;i++) {
if(bitRead(numbers[num],7-i)==HIGH) // зажечь сегмент
digitalWrite(pins[i],HIGH);
122
Часть III. Практическое применение Arduino
else // потушить сегмент
digitalWrite(pins[i]fLOW);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\6\_06_i3
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем скетч в плату Arduino и смотрим на изменение цифр, выводимых на
светодиодный индикатор.
6.6. Расширение цифровых выходов —
микросхема 74НС595
Плата Arduino Uno имеет 20 выводов, которые можно задействовать в разработке,
но бывают проекты, для которых существующих выводов недостаточно. Например,
в очень простом проекте из предыдущего раздела мы использовали уже 13
выводов, а более сложные проекты потребуют еще большего их количества. Конечно
можно обратиться к плате Arduino Mega, но это не всегда рационально, к тому же
могут быть задуманы проекты, для реализации которых не хватит и выводов
Arduino Mega. Что же делать в такой ситуации? Использовать внешние
микросхемы, имеющие функционал по расширению выводов, — например, сдвиговый
регистр 74НС595 (рис. 6.19). Это восьмиразрядный сдвиговый регистр с
последовательным вводом, последовательным или параллельным выводом информации,
с триггером-защелкой и тремя состояниями на выходе.
Распиновка контактов сдвигового регистра 74НС595 показана на рис. 6.20, а
назначение этих контактов представлено в табл. 6.3.
74НС595
Q1
Q2
Q3
Q4
Q5
Q6
Q7
GND
VCC
Q0
DS
ОЕ
ST_CP
SH_CP
MR
Q7'
16
¦MM
15
14
13
мша
12
— 10
Рис. 6.19. Сдвиговый регистр 74НС595
Рис. 6.20. Распиновка контактов
сдвигового регистра 74НС595
Глава 6. Проекты для изучения выводов Arduino 123
Таблица 6.3. Назначение контактов микросхемы 74НС595
Контакт
Vcc
Q0...Q7 .
DS
ОЕ
ST.CP
SH_CP
MR
Q71
GND
Назначение
Питание B-6 В)
Параллельные выходы
Вход для последовательных данных
Вход для переключения состояния выходов из высокоомного в рабочее
(активация при получении LOW)
Синхронизация («защелкивание») выходов
Вход для тактовых импульсов
Сброс значений регистра (активация при получении low)
Выход для последовательного соединения регистров
«Земля»
Данные к микросхеме передаются последовательно по входу DS. Биты следуют
в регистр друг за другом, считывание битов происходит при поступлении
синхроимпульса SHCP. После поступления всех битов во внутренние ячейки 74НС595
необходимо передать их на выводы Q0...Q7 («защелкнуть»). «Защелкивание»
происходит при поступлении синхроимпульса ST_CP.
Используя всего три выхода Arduino, можно управлять 8 выходами сдвигового
регистра. Передал 8 битов — получил 8 выходных состояний на выходах регистра.
Поступающие на DS данные при переполнении 8 внутренних ячеек
проталкиваются на выход Q7'. А если микросхемы соединить последовательно друг за другом
(Q7' — к выводу DS следующего сдвигового регистра 74НС595 и т. д.), то
количество контролируемых выходов можно наращивать до любого разумного предела,
поскольку при каскадном включении 74НС595 (при необходимости получения 16,
24 и т. д. выходов) данные от первого регистра передаются к следующему.
6.6.1. Подключение к плате Arduino
сдвигового регистра 74НС595
Рассмотрим подключение к плате Arduino сдвигового регистра 74НС595 и
реализацию «бегущего огня» на 8 светодиодах. Для этого нам понадобятся следующие
компоненты:
? плата Arduino Uno;
? кабель USB;
? плата прототипирования;
? микросхема 74НС5951;
? светодиоды — 8 шт.;
124
Часть III. Практическое применение Arduino
? резисторы 220 Ом — 8 шт.;
? соединительные провода ПП — 25.
Монтажная схема подключения 8 светодиодов к плате Arduino с использованием
сдвигового регистра 74НС595 показана на рис. 6.21.
Рис. 6.21. Монтажная схема подключения 8 светодиодов к плате Arduino с использованием
сдвигового регистра 74НС595
На Arduino для подключения к сдвиговому регистру 74НС595 мы задействуем три
следующих выхода (табл. 6.4).
Таблица 6.4. Подключение Arduino к сдвиговому регистру 74НС595
Контакты
Arduino Uno
D7
D6
D5
Контакты 74НС595
DS
ST_CP
SH_CP
Данные, которые нам необходимо отправлять в сдвиговый регистр (нулевой бит мы
отправляем первым, и он попадает на выход Q7 сдвигового регистра), приведены
в табл. 6.5.
Глава 6. Проекты для изучения выводов Arduino 125
Таблица 6,5. Данные, отправляемые в сдвиговый регистр
Номер зажигаемого светодиода
0
1
2
3
4
5
6
7
Двоичные данные
В00000001
воооооою
воооооюо
вооооюоо
воооюооо
В00100000
В01000000
В1000000
Создадим в скетче массив с данными, которые будем отправлять в сдвиговый
регистр:
// массив хранения значений шкалы 0-7-
byte numbers[8] = { В00000001, // 0
В000000Ю, // 1
ВОООООЮО, // 2
B00001000, // 3
ВОООЮООО, // 4
B00100000, // 5-
B01000000, // 6
B10000000 // 7
};
И переменную, указывающую на текущие данные:
int pos=0;
А также направление изменения pos — переменную dir A или -1):
int dir=l;
Каждую секунду будем изменять значение pos (от 0 до 8 и обратно), выбирать
новые значения из массива numbers и отправлять в сдвиговый регистр:
delayA000);
pos=pos+dir;
send_data_74hc595(number[pos]);
if(pos==8)
dir=-l;
if (pos=0)
dir=l;
Теперь напишем процедуру отправки последовательных данных в сдвиговый
регистр — send_data_74hc595 о. Прежде всего выставляем на D5 (вывод SH_CP
сдвигового регистра) низкий уровень low. На D7 выставляем значение бита, начиная с
126 Часть III. Практическое применение Arduino
младшего, затем выставляем на D5 высокий уровень high. Для получения значения
бита используем Arduino-функцию bitRead(x,n), где п— номер бита @-7)
в байте х, начиная с младшего:
digitalWriteE, LOW) ;
digitalWriteG, bitRead(x,0));
digitalWriteE, HIGH);
Значение выставленного бита записывается во внутреннюю ячейку сдвигового
регистра. Повторяем операцию для следующих битов:
for(int i=0;i<8;i++) {
digitalWriteE/ LOW);
digitalWriteG, bitRead(x,i));
digitalWriteE, HIGH);
}
После отправки 8 битов необходимо значения «защелкнуть» на выходах Q0...Q7:
digitalWriteF, HIGH);
digitalWriteF, LOW);
Таким образом, весь код процедуры send_data_74hc595 () выглядит так:
void send_data_74hc595 (byte value) {
for(int i=0;i<8;i++) {.
digitalWriteE, LOW);
digitalWriteG, bitRead(value,i));
digitalWi;ite E, HIGH) ;
}
digitalWriteF, HIGH);
digitalWriteF, LOW);
}
Полный код скетча приведен в листинге 6.14. Загружаем скетч в плату Arduino и
проверяем его работу.
// константы подключения пинов
const int data_pin =7;
const int shjpin =5;
const int st_pin = 6;
// массив хранения значений шкалы 0-7
byte numbers[8]
= { B00000001,
B00000010,
B00000100,
B000010O0,
B00010000,
BOO1OOOOO,
// 0
// 1
// 2
// 3
// 4
// 5
Глава 6. Проекты для изучения выводов Arduino 127
В01000000, // б
В10000000 // 7
};
// текущее значение 0-7
int pos = 0;
// текущее направление движения значения 1 или -1
int dir = 1;
void setup () {
// запуск последовательного порта
Serial.begin(9600);
// Сконфигурировать контакты подсоединения 74НС595
pinMode(data_pin,OUTPUT);
pinMode(sh_pin,OUTPUT);
pinMode(stjpin,OUTPUT);
digitalWrite(st_pin, LOW);
void loopO {
// изменить текущее значение
pos=pos+dir;
// отправить данные в сдвиговый регистр
send_data_74hc595(numbers[pos]);
// для отладки
Serial.print("pos=");Serial.print(pos);
Serial.print(" dir=")/Serial.print(dir);
Serial.print(" value=");Serial.println(numbers[pos]);
// при крайних позициях поменять направление
if(pos=7)
dir=-l;
if(pos==0)
dir=l;
// пауза 1 с
delayA000);
}
// процедура отправки данных
//в сдвиговый регистр
void send_data_74hc595(byte value) {
// последовательная отправка байта
for(int i=0;i<8;i++) {
digitalWrite(sh_pin, LOW);
digitalWrite(data_pinf bitRead(value,i));
digitalWrite(sh_pin, HIGH);
}
// защелкиваем
digitalWrite(st_pin, HIGH);
digitalWrite(st_pinf LOW);
128
Часть III. Практическое применение Arduino
Электронный архив
Полный вариант рассмотренного скетча находится в папке
ждающего книгу электронного архива (см. приложение 2).
^U
сопрово6.7. Расширение цифровых входов и выходов —
микросхема МСР23017
В предыдущем разделе мы познакомились с расширителем выводов — сдвиговым
регистром 74НС595. Есть и другие способы расширить количество цифровых
контактов платы Arduino. Так, микросхема МСР23017 (рис. 6.22) добавляет Arduino
16 портов, которые можно настроить как на вход, так и на выход. Микросхема
использует популярную двухпроводную шину 12С.
GPBO
GPB1
GPB2
GPB3
GPB4
GPB5
GPB6
GPB7
Vdd
Vss
NC
SCL
SDA
NC
• 1
2
3
4
5
6
7
8
9
10
11
12
13
14
К
I
?
SE
28
27
26
25
24
23
22
21
20
19
18
17
16
15
" л щ
«1 "*• **
"Г -^ ¦ ¦ jfcr
¦П ^g.r,. m
2—**
2—^
2*—
2**—
GPA7
GPA6
GPA5
GPA4
GPA3
GPA2
GPA1
GPA0
INTA
1NTB
RESET
А2
А1
АО
Рис. 6.22. Выводы микросхемы МСР23017
Адрес микросхемы МСР23017 для протокола 12С можно установить комбинацией
сигналов на цифровых входах А0-А2 (рис. 6.23), что позволяет подключить к плате
Arduino одновременно 8 микросхем МСР23017 — соответственно 16x8= 128
контактов.
Рис. 6.23. Установка адреса микросхемы МСР23017
Глава 6. Проекты для изучения выводов Arduino 129^
Микросхема МСР23017 имеет два банка портов: A (GPA0-GPA7) и В (GPB0-GPAB),
каждый из которых можно настроить на ввод или на вывод. В листинге 6.15
показан пример настройки банков выводов А и В.
// подключение библиотеки Wire.h
#include <Wire.h>
byte input=0;
void setup()
{
Serial.begin(9600) ;
Wire.begin@,2); // запуск 12С
Wire.beginTransmission@x20); // i2c - адрес (А0-0,А1-0,А2-0)
Wire.write@x00); // IODIRA register
Wire.write@x00); // настроить PORT А как output
Wire. endTransmission ();
void loop()
{
// чтение данных из PORT В
Wire.beginTransmission@x20);
Wire.write @x13) ;
Wire. endTransmission ();
Wire, request From @x20, 1) ;
input=Wire. read ();
// записать полученные данные в PORT A
Wire.beginTransmission@x20) ;
Wire.write@x12); // address PORT A
Wire.write(input); // PORT A
Wire.endTransmission ();
delayA00); // пауза
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\6\_06_15
сопровождающего книгу электронного архива (см. приложение 2).
6.8. Расширение аналоговых входов —
мультиплексор CD4051
Если вашим проектам окажется недостаточно имеющихся в наличии на платах
Arduino аналоговых входов, можно воспользоваться мультиплексором CD4051
(рис. 6.24).
130
Часть III. Практическое применение Arduino
т
ilillL
•
1
т
л
т
Рис. 6.24. Мультиплексор CD4051
Микросхема CD4051 представляет собой 8-канальный аналоговый мультиплексор/
демультиплексор, имеющий 8 входов (уО-у7) и один выход z (рис. 6.25). Выбор
считываемого входа осуществляется подачей цифровых сигналов на выходы sO-s2.
Таким образом, для подключения к плате Arduino 8 дополнительных аналоговых
датчиков необходимо задействовать три цифровых выхода модуля и один
аналоговый вход.
4051
в режиме мультиплексора
у4 —
уб-
Z —
У7-
у5-
Е-
Vee-
gnd-
-1
-2
-3
-4
-5
-6
-7
-8
4051
16-
15-
14-
13-
12-
11-
10-
9-
Vcc
У2 .
у1
уо
уз
sO
s1
s2
Аналоговые
входы
Выбор
аналогового
входа
(установка
с 3 контактов
Arduino)
с выбранного
аналогового
' входа
(к аналоговому
входу Arduino)
Назначение контактов
Логическая схема
работы
Рис. 6.25. Контакты мультиплексора CD4051
В листинге 6.16 представлен скетч циклического опроса 8 аналоговых датчиков,
подключенных к 8 входам мультиплексора и — через вход z — к аналоговому
входу АО платы Arduino.
// список пинов для подключения к sO, si, s2 мультиплексора
// D5, D7, D8
int pins[J={14, 13, 15};
// Массив двоичных чисел, определяющих номер выбранного входа/выхода
// микросхемы 4051, с 1 по 8.
int bin [] = { В000, В001, ВОЮ, ВОН, В100, В101, В110, Bill } ;
Глава 6. Проекты для изучения выводов Arduino 131
// служебные переменные
int row;
int rO = 0;
int rl = 0;
int r2 = 0;
int avalue =0;
void setup (void) {
// входы подключения к мультиплексору как OUTPUT
for(int i=0;i<3;i++) {
pinMode(pins[i],OUTPUT);
}
// запуск последовательного порта
Serial.begin(9600);
void loop (void) {
for(int i=Q;i<8;i++) {
// выбор входа мультиплексора
row = bin [i] ;
rO = row & 0x01 ;
rl = (row » 1) & 0x01 ;
r2 = (row » 2) & 0x01 ;
digitalWrite (pins[i]/ rO) ;
digitalWrite (pins[i], rl) ;
digitalWrite (pins [ i], r2) ;
// получение данных с АО
avalue= analogRead(AO);
// вывод в монитор последовательного порта
Serial.print("analog input =");Serial.print(i);
Serial.println(" = "); Serial.println(avalue);
}
// пауза
delayB000);
Электронный архив
Полный вариант рассмотренного скетча находится в папке вхат^ввХб^Об^б
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 7
Использование библиотек
в проектах Arduino
Возможности среды программирования Arduino могут быть существенно
расширены за счет использования библиотек. Библиотеки расширяют функциональность
программ и несут в себе дополнительные функции — например, для работы с
аппаратными средствами, по обработке данных и т. д. Ряд библиотек устанавливается
автоматически вместе со средой разработки, однако вы также можете скачивать
дополнительные библиотеки или создавать собственные. Использование библиотек
существенно упрощает работу над проектами, потому что дает возможность
сосредоточиться на основной логике программы, не тратя время на множество мелочей,
Сегодня огромное количество библиотек выложено в Интернете, где их можно
легко скачать, причем совершенно бесплатно.
Электронный архив
Необходимые для работы с проектами книги подгружаемые библиотеки размещены
в каталоге libraries сопровождающего книгу электронного архива (см. приложение 2).
7.1. Установка библиотек
Среда разработки Arduino IDE поставляется вместе с набором стандартных
библиотек. Функционал стандартных библиотек включает в себя функции базовых видов
коммуникации и поддерживает наиболее распространенные устройства.
Стандартные библиотеки располагаются в папке libraries каталога установки Arduino. Список
всех установленных библиотек, в том числе и базовых, можно посмотреть
в Arduino IDE по команде Эскиз | Include Library (рис. 7.1).
Если в этом списке нет необходимой библиотеки, ее нужно установить. Сделать это
можно тремя способами:
? через Менеджер библиотек (Manage libraries);
? импортированием ZDP-архива библиотеки;
? вручную.
Установленная библиотека появится в списке библиотек Arduino IDE, и ее можно
будет использовать в своих скетчах. Обратите внимание: примеры добавлен-
Глава 7. Использование библиотек в проектах Arduino 133
Рис. 7.1. Список установленных библиотек в Arduino IDE
ной библиотеки появятся в меню Файл | Образцы только после перезагрузки
Arduino IDE.
7.1.1. Установка библиотеки
через Менеджер библиотек
Эта возможность появилась в Arduino IDE, начиная с версии 1.6.2,—
соответствующее меню открывается командой Эскиз | Include Library | Manage Libraries.
В появившемся списке (рис. 7.2) ищем нужную библиотеку, выбираем
необходимую версию и нажимаем кнопку Install.
Время загрузки зависит, как правило, от скорости интернет-соединения. По
завершении загрузки рядом с названием библиотеки должна появиться надпись
INSTALLED (рис. 7.3). После этого Менеджер библиотек можно закрыть.
7.1.2. Установка библиотеки из ZIP-архива
Многие библиотеки в Интернете предлагаются для установки из ZIP-архивов. Для
подключения таких библиотек необходимо их сначала скачать на компьютер. Затем
в Arduino IDE выполнить команду меню Эскиз | Include Library | Add /ZIP
library, в открывшемся окне выбрать путь к скачанному ZIP-архиву и нажать
кнопку Open (рис. 7.4) — ZIP-архив библиотеки будет распакован в папку libraries
134
Часть III. Практическое применение Arduino
Рис. 7.2. Поиск библиотеки в Менеджере библиотек
Рис. 7.3. Библиотека установлена
Глава 7. Использование библиотек в проектах Arduino
135
Рис. 7.4. Установка библиотеки из ZIP-архива
каталога установки Arduino, а название библиотеки появится в списке
установленных библиотек.
7.1.3. Установка библиотеки вручную
Для ручной установки библиотеки необходимо скачать и распаковать ее ZIP-архив.
Название распакованной папки является названием библиотеки. Внутри этой папки
находятся: файл с расширением срр, файл с расширением h, текстовый файл
keywords.txt, папка examples с примерами и другие файлы, требуемые библиотеке.
Распакованную папку необходимо переместить в папку libraries, расположение
которой зависит от используемой вами операционной системы:
? для Windows по умолчанию это Мои floicyMeHTbiWduinoMibraries;
О для macOS: -/Документы/Arduino/libraries;
? в Linux это будет папка libraries с вашими скетчами.
После перезапуска Arduino IDE добавленная библиотека станет доступна для
подключения ее к своим программам через меню Эскиз | Include Library.
7.2. Подключение библиотеки
Для того чтобы подключить библиотеку, нужно написать всего одну строку в
начале скетча:
#include <name_library.h>
136 Часть III. Практическое применение Arduino
например:
#include < LiquidCrystal.h>
Некоторые библиотеки при работе используют методы и функции других
библиотек — тогда нужно подключать обе библиотеки: сначала подключается та, методы
и функции которой использует вторая, например:
// Подключение библиотеки Wire для работы с шиной I2C
#include <Wire.h>
// Подключение библиотеки LiquidCrystal_I2C
#include <LiquidCrystal_I2C.h>
Для работы с большинством библиотек нужно создать объект (экземпляр класса
библиотеки), через который будут доступны их функции и методы, например:
LiquidCrystal_I2C led@x27,20,4);
Здесь led— это объект библиотеки LiquidCrystai_i2c, через него и обращаются
к функциям и методам библиотеки.
7.3. Создание собственной библиотеки
Научимся создавать собственные библиотеки. В разд. 6.5 мы рассматривали работу
со светодиодным индикатором D5651. Создадим библиотеку, которая будет
упрощать вывод цифр на этот индикатор. Назовем ее D5651.
Библиотека должна иметь как минимум два файла:
? заголовочный файл (с расширением h);
? файл с исходным кодом (с расширением срр).
В первом файле содержится описание самого класса, переменные и константы.
А второй файл содержит программный код методов.
7.3.1. Создание заголовочного файла D5651.h
Все содержимое h-файла необходимо заключить в конструкцию, исключающую
повторное подключение библиотеки:
#ifndef Button_h // если библиотека Button не подключена
#define Button_h // тогда подключаем ее
#endif
Внутри конструкции необходимо включить файл Arduino.h, содержащий
стандартные константы и переменные языка Arduino. В обычных программах он
добавляется автоматически, а для библиотеки должен быть указан явно, поэтому следует
написать:
#include "Arduino.h"
Глава 7. Использование библиотек в проектах Arduino 137^
Необходимо также добавить описание класса. Класс — это набор функций и
переменных, объединенных в одном месте. Функции и переменные могут быть
публичными (public), что означает общий доступ к ним всех, кто использует библиотеку,
или частными (private), что означает доступ к ним только внутри класса.
Конструктор имеет то же имя, что и класс, но не имеет типа возвращаемого значения:
class D5651
{
public:
D5651(byte *pins);
void setNumber«(int num) ;
private:
byte *pinsS;
};
Содержимое создаваемого файла D5651.h приведено в листинге 7.1.
iifndef D5651_h
idefine D5651_h
iinclude "Arduino.h"
class D5651
{
public:
D5651(byte *pins);
void setNumber(int num);
private:
byte *pinsS;
};
tendif
7.3.2. Создание файла реализации D5651.cpp
В начале кода этого файла находится директива #inciude:
tinclude <D5651.h>
Она разрешает доступ к характеристикам, содержащимся в головном файле
библиотеки D5651.h.
За ней следует конструктор. Он используется для создания экземпляра
создаваемого класса:
D5651::D5651(byte *pins) {
for(int i=0;i<8;i++) {
pinsS= pins;
138 Часть III. Практическое применение Arduina
for(int i=0;i<
pinMode(pinsS[i], OUTPUT); // определяем вывод как вход
Далее прописана реализация метода. Код D5651:: означает, что функция принадле
жит классу D5651.
Содержимое файла D5651.cpp приведено в листинге 7.2.
#include <D5651.h>
// описание конструктора класса D5651
D5651::D5651(byte *pins) {
for(int i=0;i<8;i
pinsS= pins;
for(int i=0;i
pinMode(pinsS[i], OUTPUT); // определяем вывод как вход
// вывод цифры
void D5651::setNumber(int num) {
byte numbers[10] = { B11111100, // 0
В01100000,
B11O11O1O,
B1111OO1O,
BO11OO11O,
B1O11O11O,
B1O11111O,
B111OOOOO,
B1111111O,
B111OO11O
//
//
//
//
//
//
//
//
//
1
2
3
4
5
6
7
8
9
for(int i=0;i<7;i++) {
if(bitRead(numbers[num],7-i)=fHIGH) // зажечь сегмент
digitalWrite(pinsS[i],HIGH);
else // потушить сегмент
digitalWrite(pinsS[i],LOW);
7.3.3. Создание файла keywords.txt
Для того чтобы Arduino ШЕ выделяла цветом новые типы и методы нашей
библиотеки, необходимо создать файл keywords.txt:
Глава 7. Использование библиотек в проектах Arduino 139
D5651 KEYW0RD1
setNumber KEYW0RD2
Каждая строка этого файла содержит ключевое слово, табуляцию (не пробелы)
и тип ключевого слова: keywordi определяет классы, keyword2 — методы.
Электронный архив
ZIP-архив с файлами библиотеки D5651 находится в папке examp/es\7
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 8
00
Arduino
и последовательный порт UART
Протокол обмена через последовательный порт UART предполагает двусторонний
обмен данными между двумя устройствами. При этом оба устройства являются
равноправными — то есть явно выраженного деления устройств на главное и
подчиненное не предполагается. Для организации обмена данными используются всего
две линии: по одной данные передаются от первого устройства ко второму, а по
другой — в обратном направлении. На микроконтроллере при этом задействуются
два контакта (пина). Обозначаются они соответственно: ТХ — передающий
и RX — принимающий. Линии передачи соединяют ТХ первого устройства с RX
второго и RX первого устройства с ТХ второго.
Arduino Uno имеет один аппаратный последовательный порт, подключенный к
порту USB. Arduino Mega имеет три дополнительных последовательных порта.
8.1. Библиотека Serial
Для работы с аппаратными UART-контроллерами в Arduino существует
встроенный класс serial. Он предназначен для управления обменом данными через UART.
Рассмотрим основные функции класса serial.
8.1.1. Функция Serial.begin
Синтаксис функции:
Serial.begin(speed)
Функция разрешает работу порта UART и — через параметр speed — задает
скорость обмена в бодах (бит/с).
Для задания скорости передачи данных рекомендуется использовать стандартные
значения: 4800,9600, 19 200, 38 400, 57 600, 115 200 бод. Например:
Serial.begin(9600); // инициализация порта, скорость 9600 бод
Глава 8. Arduino и последовательный порт UART 141_
8.1.2. Функция Serial.print
Синтаксис функции: Serial.print (val), Serial.print (val, format)
Функция передает данные через последовательный порт как ASCII-текст и может
принимать различные типы данных. Так, целые числа выводятся
соответствующими им символами ASCII, а вещественные — с помощью двух ASCII-символов: для
целой и дробной частей. Байты передаются как символ с соответствующим
номером. Символы и строки отсылаются как есть.
Параметры функции:
? val — данные для передачи через последовательное соединение;
? format — базис для целых чисел или количество знаков после запятой для
вещественных:
• byte — выводит число в виде байта;
• bin — выводит число в двоичном формате;
• ост — выводит число в восьмеричном формате;
• dec — выводит число в шестнадцатеричном формате;
• hex — выводит число в десятичном формате.
8.1.3. Функция Serial.println
Синтаксис функции:
Serial .println ()
Serial. println (val)
Serial.println (val, format)
Функция выводит данные через последовательный порт UART в виде ASCII-
символов с добавлением символов переноса строки (\г, код 13) и (\п, код 10),
чтобы следующее сообщение отображалось с новой строки. В остальном она
аналогична функции print ().
Параметры функции:
? val — данные для передачи через последовательное соединение;
? format — базис для целых чисел или количество знаков после запятой для
вещественных.
8.1.4. Функция Serial.write
Синтаксис функции:
Serial. write (val)
Функция выводит двоичные данные через последовательный порт UART и
возвращает количество переданных байтов.
142 Часть III. Практическое применение Aftiuk
Параметр функции: vai— данные для передачи через последовательное соеди
нение.
8.1.5. Функция Serial.available
Синтаксис функции:
Serial.available()
Функция возвращает количество байтов, принятых последовательным портом и
записанных в буфер. Буфер последовательного порта может хранить до 64 байтов
В случае пустого буфера возвращает 0. Пример:
п* Serial, available(); // в п - число принятых байтов
8.1.6. Функция Serial.read
Синтаксис функции:
Serial.read()
Функция возвращает очередной байт из буфера последовательного порта. Если
буфер пуст — возвращает число 1 (Oxffff). Пример:
char var= Serial.read(); // чтение байта из буфера
8.2. Использование UART
для отладки программ
Среда Arduino ГОЕ не содержит отладчика, что создает проблемы в поиске ошибок
кода программы. А, как известно, без ошибок программы сразу не пишутся.
Формальные ошибки выявляются при компиляции, а с алгоритмическими и
вычислительными сложнее. И основная функция отладки — увидеть состояние программы
и узнать значение переменных. Это можно сделать, передав нужную информацию
на компьютер через последовательный интерфейс. Среда Arduino ГОЕ включает
монитор последовательного порта, позволяющий получать и посылать данные
обмена с платой.
8.2.1. Подключение к плате Arduino
нескольких кнопок
Рассмотрим, как использовать отладочную информацию в проекте подключения
к плате Arduino нескольких кнопок. Для этого нам понадобятся следующие
компоненты:
? плата Arduino Uno;
? кабель USB;
Глава 8. Arduino и последовательный порт UART 143_
О плата прототипирования;
О кнопка — 6 шт.;
? резисторы 10 кОм — 6 шт.;
О соединительные провода.
В представленной на рис. 8.1 монтажной схеме этого проекта шесть кнопок
подключены к выводам контроллера Arduino. При определении нажатия мы будем
выводить в последовательный порт номер нажатой кнопки и контакт (пин) ее
подключения.
Создадим в Arduino IDE новый скетч, занесем в него код из листинга 8.1, загрузим
скетч в плату Arduino и откроем монитор последовательного порта. При нажатии
на кнопку в порт должна выводиться информация о номере нажатой кнопки и
контакте (пине) ее подключения (рис. 8.2). Если при нажатии кнопки такая
информация не выводится или выводится неверная, ищем ошибку или в подключении, или
в коде программы.
// кнопки выбора режима
int pinButtons[]={5,6,7,8,9,10};
int lastButtons[]={0,0,0,0,0,0,0,0};
int currentButtons[]={0,0,0,0,0,0,0,0};
int countButtons=6;
void setup(void) {
// запуск последовательного порта
Serial.begin(9600);
void loop(void) {
// проверка нажатия кнопок
for(int i=0;i<countButtons;i++) {
currentButtons[i] = debounce(lastButtons[i],pinButtons[i]);
if (lastButtons[i] == 0 && currentButtons[i] == 1) { // если нажатие.
// вывод номера нажатой кнопки и пина подключения
Serial.print("button=");Serial.print(i);
Serial.print(" pin - ");Serial.println(pinButtons[i]);
}
lastButtons[i] = currentButtons[i1;
// Функция сглаживания дребезга
// Принимает в качестве аргумента предыдущее состояние кнопки,
// выдает фактическое
int debounce(int last,int pinl)
{
int current = digitalRead(pinl); // Считать состояние кнопки
144
Часть III. Практическое применение Arduino
Рис. 8.1. Монтажная схема подключения шести кнопок
Рис. 8.2. Вывод отладочной информации в монитор последовательного порта
Глава 8. Arduino и последовательный порт UART 145
if (last != current) // если изменилось...
{
delayE); // ждем 5 мс
current = digitalRead(pinl); // считываем состояние кнопки
return current; // возвращаем состояние кнопки
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\8\_08_01
сопровождающего книгу электронного архива (см. приложение 2).
8.3. Использование UART
для установки параметров
При написании скетчей часто используют начальную установку параметров. Но
если необходимо внести в скетч изменения, приходится его потом заново
компилировать и загружать в плату, что не всегда удобно или даже возможно. Поэтому
нужно предусмотреть интерфейс для установки параметров без необходимости
вносить изменения в программу. Один из вариантов — получение параметров
программы по последовательному порту и хранение их в памяти EEPROM.
Микроконтроллеры ATmega имеют на борту энергонезависимую память EEPROM, не поте-
ряющую записанные в нее данные даже после отключения питания. 512 байтов
такой памяти несут ATmega8 и ATmegal68, 1024 байта— ATmega328, 4096
байтов — Arduino Mega. Память типа EEPROM допускает несколько десятков тысяч
циклов записи и стирания данных. Для работы с этой памятью в составе Arduino
IDE имеется удобная библиотека EEPROM. Библиотека содержит две функции:
чтения и записи в память данных.
Функция eeprom. read считывает байт из энергонезависимой памяти EEPROM. Если
байт до этого никогда не перезаписывался — вернет значение 255.
Синтаксис функции:
EEPROM. read (address)
Параметр: address— порядковый номер ячейки памяти для чтения от 0 до 512
(или 1024) (int);
Возвращаемое значение — байт, хранимый в ячейке памяти.
Функция eeprom.write записывает байт в энергонезависимую память.
Синтаксис функции:
EEPROM.write(address, value)
Параметры:
? address — порядковый номер ячейки памяти для записи — от 0 до 511 (int);
? value — байт для записи — от 0 до 255 (byte).
Возвращаемого значения нет.
146 Часть III. Практическое применение Arduino
Теперь рассмотрим получение данных платой Arduino по последовательному порту.
Мы уже знаем, что функция serial.available о позволяет проверить, можно ли
прочитать данные из последовательного порта. Arduino имеет 64-байтовый буфер
последовательного порта. Функция вызывается без параметров и возвращает
количество доступных для чтения байтов.
if(Serial.available()) {
// выполнить, если имеются данные
}
Итак, напишем скетч — шаблон для получения и установки параметров по
последовательному порту. Данные будем отправлять в формате:
<байт начала передачи><параметр>=<значение><0айт конца передачи>
Например:
*<параметр>=<значение>$
Функция seriaiEvent () вызывается, если в буфере последовательного порта есть
какие-либо данные.
Побайтно получаемые данные записываем в строку inputstring. При получении
байта конца передачи устанавливаем признак конца получаемых данных:
stringComplete = true;
И начинаем парсинг полученных данных и запись данных для параметра в
соответствующие ячейки EEPROM. Для записи числа int необходимо использовать два
байта памяти EEPROM:
void save_param2_EEPR0M(int addr,int val) {
EEPROM.write(addrfhighByte(val));
EEPROM.write(addr+1,lowByte(val));
}
Содержимое скетча представлено в листинге 8.2.
// подключение библиотеки EEPRQM
#include <EEPROM.h>
// данные, пришедшие из последовательного порта
String inputstring = "";
// строка пришла
boolean stringComplete = false;
//*** данные от компа
// команда
int params[]={1,2,3,4,5};
int tekparam;
Глава 8. Arduino и последовательный порт UART 147_
II данные
int paramsdata[5] = {0,О,О, 0,0};
int tekparamsdata;
// адреса в EEPROM для параметров
int addrEEPRQM[] = {0,2, 4,6,8};
void setup () {
// запуск последовательного порта
Serial.begin(9600);
// резервирование 30 bytes для inputString:
inputString.reserveC0);
// загрузка параметров программы из EEPROM
void loop () {
// проверка прихода строки из последовательного порта
if (stringComplete) {
Serial.println(inputString);
// парсинг строки
if(parse_string()) {
set_param(); // установка параметра
}
// очистить строку
inputString = "";
stringComplete = false;
// при наличии данных в буфере последовательного порта
void serialEvent() {
boolean flagl=false;
while (Serial.available() && flagl==false) {
// получить байт:
char inChar = (char)Serial.read();
// если байт конца передачи
if (inChar == f$f) {
stringComplete = true;
flagl=true;
}
else
// добавить в inputString:
inputString += inChar;
// парсинг получаемых данных
boolean parse_string() {
148 Часть III. Практическое применение Arduino
int sl,s2;
int lengthl==inputString. length () ;
Serial.print("str=");Serial.println(inputString);
Serial.print("lengthl=");Serial.println(lengthl);
if(inputString.charAt(O)!='*')
return false;
if(inputString.charAt(lengthl-1)!=f;f)
return false;
//
for(int i=l;i<lengthl;i++) {
if(inputString.charAt(i)==';f)
{sl=i;break;}
}
tekparam=inputString.substringA,si).tolnt();
// action
for(int i=sl+l;i<lengthl;i++) {
if(inputString.charAt(i)==f; ')
{s2=i;break;}
}
tekparamsdata=inputString.substring(s1+1,s2).tolnt();
Serial.print("tekparam=");Serial.printIn(tekparam);
Serial.print("tekparamsdata=");Serial.printIn(tekparamsdata);
return true;
}
// установка параметра
void set_param() {
if(tekparam>=0 && tekparam<5) {
paramsdata[tekparam]=tekparamsdata;
save_param2_EEPROM(addrEEPROM[tekparain],tekparamsdata);
Serial.println("param set!!!");
}
else {
Serial.printIn("Wrong param!!!");
// сохранить значения параметра в EEPROM
void save_j>aram2_EEPR0M(int addr,int val) {
EEPROM.write(addr,highByte(val));
EEPROM.write(addr+1,lowByte(val)); .
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\8\J)8JJ
сопровождающего книгу электронного архива (см. приложение 2).
Глава 8. Arduino и последовательный порт UART 149^
Загрузим этот скетч в плату Arduino и попробуем отправлять в монитор
последовательного порта команды установки параметров. При этом выводим в него и
отладочную информацию (рис. 8.3).
1*2;1342;
!atr-*2;1342;
;lengthl-8
tekpara»«2
: teiparaaedata«1342
pare» set!!!
Рис. 8.З. Отправка параметров из последовательного порта в Arduino
8.4. Библиотека SoftwareSerial
Библиотека SoftwareSerial дает возможность реализовать последовательный
интерфейс на любых цифровых выводах Arduino с помощью программных средств,
дублирующих функциональность UART (отсюда и название SoftwareSerial).
Библиотека позволяет программно создавать несколько последовательных портов,
работающих на скорости до 115 200 бод.
При использовании нескольких последовательных портов в каждый момент
времени только один из них может получать данные.
На платах Arduino Mega и Arduino Mega2560 некоторые выводы не поддерживают
прерывания, возникающие при изменении уровня сигнала. В силу этого, на этих
платах в качестве вывода RX могут использоваться только следующие выводы:
10, И, 12, 13, 14, 15, 50, 51, 52, 53, А8 F2), А9 F3), А10 F4), АН F5), А12 F6),
А13F7),А14F8),А15F9).
На Arduino Leonardo некоторые выводы также не поддерживают прерывания,
возникающие при изменении уровня сигнала. Поэтому на ней в качестве вывода RX
150
Часть III. Практическое применение Arduino
могут использоваться только следующие выводы: 8, 9, 10, 11, 14 (MISO), 15 (SCK),
16(MOSI).
8.5. Соединение по UART двух плат Arduino
Соединим две платы Arduino и установим связь между ними по программному
последовательному порту UART. Монтажная схема этого проекта показана на
рис. 8.4.
Рис. 8.4. Монтажная схема соединения двух плат Arduino
по программному последовательному порту
Загрузим на каждую плату Arduino скетч из листинга 8.3, который поможет нам из
монитора последовательного порта Arduino ШЕ отправлять данные в другую плату
Arduino, подключим каждую плату по USB к компьютеру и проверим обмен
сообщениями: на рис. 8.5 показан процесс отправки данных из одной платы Arduino
в другую, а на рис. 8.6 — прием этих данных другой платой.
// подключение библиотеки SoftwareSerial
#include <SoftwareSerial.h>
// создание экземпляра SoftwareSerial
// на RX-8, TX-9
SoftwareSerial mySerial(8, 9);
void setup()
{
// Инициализируем последовательный порт
Serial.begin(9600) ;
Serial.println("I'm ready!");
Глава 8. Arduino и последовательный порт UART
151
Рис. 8.5. Отправка данных из одной платы Arduino в другую
Рис. 8.6. Прием платой Arduino данных, посланных в нее из другой платы
152 Часть III. Практическое применение Arduino
// устанавливаем скорость передачи данных
// для последовательного порта, созданного
// библиотекой SoftwareSerial
mySerial.begin(9600);
mySerial.println("Hello, world?");
void loopO {
// получаем по Software - отправляем в монитор
if (mySerial.available())
Serial.write(mySerial.read());
// пишем в монитор (аппаратный) - отправляем по Software
if (Serial.available())
mySerial.write(Serial.read());
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\8\_08_03
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 9
Подключение датчиков
к плате Arduino
Датчик, или сенсор, — это устройство, с помощью которого мы измеряем значение
какого-либо технологического параметра. Датчики позволяют определять, что
происходит во внешней среде, и действовать на основе этой информации. Датчики,
наверное, можно назвать органами чувств системы. Любой датчик состоит из
чувствительного элемента и преобразовательной системы, выполняющей
преобразование входного воздействия любой физической величины в сигнал, удобный для
дальнейшего использования.
9.1. Подключение аналоговых датчиков
Самый простой тип датчиков — аналоговые датчики. Это первичные
преобразователи. Такой тип датчиков применяется в системах непрерывного измерения и
регулирования. Принцип действия аналоговых датчиков состоит в том, что при
изменении измеряемого параметра происходит соответствующее изменение его
выходного сигнала. Выходное напряжение может принимать значения от О В до напряжения
питания, хотя обычно рабочий диапазон напряжений более узкий.
Примеры датчиков:
? акселерометры — для обнаружения наклона (используются в смартфонах и
планшетах);
? магнитометры — для обнаружения магнитных полей (используются при
создании цифровых компасов);
? инфракрасные датчики — для определения расстояния до объекта;
? датчики температуры — для определения температуры;
Q фоторезисторы — для измерения освещенности.
Между измеряемой датчиком величиной и возвращаемым напряжением
устанавливается определенная зависимость. Например, чем больше величина, тем больше
напряжение, или наоборот, чем больше величина, тем напряжение меньше.
154 Часть III. Практическое применение Arduino
9.1.1. Подключение к плате Arduino
аналогового датчика температуры LM335
Рассмотрим работу с аналоговыми датчиками температуры на примере датчика
LM335 — недорогого температурного чувствительного элемента с диапазоном от
-40 до +100°С и точностью в 1°С ( рис. 9.1). По принципу действия датчик LM335
представляет собой стабилитрон, у которого напряжение стабилизации зависит от
температуры. При повышении температуры на один градус Кельвина напряжение
стабилизации увеличивается на 10 мВ. Типовая схема включения (соответствует
типовой схеме включения стабилитрона) показана на рис. 9.2.
/\
—V- (GND)
ч
V+
ADJ
Рис. 9.1. Датчик температуры LM335 Рис. 9.2. Типовая схема включения
датчика LM335
При взгляде на эту схему сразу можно спросить, каково же сопротивление
резистора R1 и какое напряжение питания должно быть при такой схеме включения? Ответ
содержится в технической документации (Data Sheet), где сказано, что нормальная
работа изделия гарантируется в диапазоне токов 0,45...5,00 мА при сопротивлении
резистора R1 2,2 кОм. Следует заметить, что предел в 5 мА превышать не следует,
поскольку датчик будет перегреваться и измерять при этом собственную
температуру.
Электронный архив
Техническая документация производителей (Data Sheet) практически на все
компоненты и устройства, задействованные в проектах этой книги, находится в каталоге
datasheets сопровождающего книгу электронного архива (см. приложение 2).
Согласно документации датчик проградуирован по абсолютной шкале Кельвина.
При температуре -273,15°С, а это абсолютный ноль по Кельвину, рассматриваемый
датчик должен показать нулевое напряжение. При увеличении температуры на
каждый градус выходное напряжение стабилитрона будет возрастать на целых 10 мВ,
или на 0,010 В.
Температура 25°С — единственная точка калибровки сенсора. При этой
температуре на выходе датчика должно быть: 298,15 х 0,010 = 2,9815 В. Для калибровки
датчика используется схема, представленная на рис. 9.3.
Глава 9. Подключение датчиков к плате Arduino 155
¦Опит
Выход 10 мВ^К
LM335
Рис. 9.3. Схема калибровки датчика LM335
Итак, подключаем датчик температуры LM335 по схеме, представленной на
рис. 9.4, и пишем скетч (листинг 9.1) считывания данных с датчика и вывода
показаний в последовательный порт (рис. 9.5). .
int lm335=0; // подключение датчика к аналоговому входу АО
void setup ()
{
Serial.begin(9600) ;
}
void loop ()
{
double val = analogRead(lm335); // чтение
double voltage = val*5.0/1024; // перевод в значение в вольтах
double temp = voltage*100 - 273.15; // в градусы Цельсия
Serial.print(" temp = ");
Serial.printIn(temp);
delayA000);
Рис. 9.4. Монтажная схема подключения датчика LM335 к плате Arduino
156
Часть III. Практическое применение Arduino
tei/
teup
te«p
teip
teip
teip
teip
teip
teip
temp
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
teip
- 25.68
- 26.17
- 25.68
- 25.68
- 25 68
- 26 17
- 25 68
- 25.68
- 25.68
- 25.68
- 25.19
« 26 17
- 26.65
- 27.14
- 26.65
- 27 63
- 28.12
- 28 61
- 29.10
- 30 07
- 31.05
- 30.07
- 29 10
- 28.61
- 28 12
- 27.63
- 27.14
- 26.65
- 26.17
Рис. 9.5. Вывод результатов измерения данных датчиком LM335
в монитор последовательного порта
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\9\J>9JI
сопровождающего книгу электронного архива (см. приложение 2).
9.2. Подключение датчиков
по протоколу 1-Wire
Интерфейс 1-Wire разработан фирмой Dallas Semiconductor (ныне MAXIM) в конце
1990-х гг. Этот интерфейс интересен тем, что для двустороннего обмена требуется
всего одна линия. Правда, еще понадобится общий провод («земля») и провод
питания (не всегда). Причем на эту одну линию можно «повесить» несколько
устройств. Протокол очень прост и легко реализуется на микроконтроллере
программно.
Для взаимодействия Arduino с устройствами 1-Wire необходимо установить
библиотеку One Wire.
Электронный архив
Библиотека OneWire размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
Глава 9. Подключение датчиков к плате Arduino
157
9.2.1. Подключение к плате Arduino
цифрового датчика температуры DS18B20
Рассмотрим подключение к Arduino цифровых датчиков температуры DS18B20,
работающих по протоколу 1-Wire.
DS18B20 (рис. 9.6)— цифровой термометр с программируемым разрешением от 9
до 12 битов, которое может сохраняться в памяти EEPROM прибора. DS18B20
обменивается данными по шине 1-Wire и при этом может быть как единственным
устройством на линии, так и работать в группе. Все процессы на шине управляются
центральным микропроцессором.
(BOTTOM VIEW)
ТО-92
(DS18B20)
Рис. 9.6. Датчик DS18B20
Диапазон измерений датчика: от -55 до +125°С, с точностью 0,5°С в диапазоне от
-10 до +85°С. Датчик может запитываться двумя способами: внешним питанием
(три провода) или паразитным (питание от шины, 2 провода). Монтажная схема
подключения нескольких (в нашем случае — двух) датчиков температуры DS18B20
от внешнего питания к Arduino представлена на рис. 9.7.
Каждый датчик типа DS18B20 имеет уникальный 64-битный последовательный
код, который позволяет общаться с множеством датчиков DS18B20, установленных
на одной шине. Первые 8 битов — код серии (для DS18B20 — 28h), затем 48 битов
уникального номера и в конце 8 битов CRC-кода. Такой принцип позволяет
использовать один микропроцессор, чтобы контролировать множество датчиков
DS18B20, распределенных по большому участку.
Скетч для получения датчиков DS18B20, подключенных к шине 1-Wire, и вывода
их уникальных идентификаторов в последовательный порт представлен в
листинге 9.2.
158
Часть III. Практическое применение Arduino
Рис. 9.7. Монтажная схема подключения нескольких датчиков DS18B20 к плате Arduino
// Подключение библиотеки OneWire
#include «OneWire.h>
// пин подключения датчиков
OneWire ds(8);
void setup(void) {
// запуск последовательного порта
Serial.begin(9600) ;
void loop(void) {
byte i;
byte type_s;
byte addr[8];
// поиск устройств
if ( !ds.search(addr)) {
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delayB50);
return;
Глава 9. Подключение датчиков к плате Arduino 159
II вывод уникального номера
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' f);
Serial.print(addr[i], HEX);
if (OneWire::crc8(addr, 7) !=addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial. println () ;
// определение типа датчика
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20");
type_s = 1;
break;
case 0x28:
Serial.printIn(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s =0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\9\_09_02
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем этот скетч в плату Arduino, запускаем монитор последовательного порта
и наблюдаем вывод в последовательный порт данных уникального идентификатора
для каждого датчика (ррс. 9.8).
Данные о температуре хранятся в оперативной памяти датчика (рис. 9.9). Память
состоит из оперативной ROM и энергонезависимой EEPROM:
О первые два байта содержат данные об измеренной температуре;
П третий и четвертый байты хранят верхний (тн) и нижний (tl) пределы
температуры;
? пятый и шестой — не используются;
160
Часть III. Практическое применение Arduino
П седьмой и восьмой— байты-счетчики. Они могут использоваться для более
точного измерения температуры;
? девятый байт хранит CRC-код предыдущих восьми.
Рис. 9.8. Вывод идентификаторов двух датчиков DS18B2Q в монитор последовательного порта
SCRATCHPAD (Power-up State)
byte 0
bytel
byte 2
byte3
byte 4
byte 5
byte 6
byte 7
byte 8
Temperature LSB E0h) 1 ^^
Temperature MSB @5h) J v" '
Th Register or User Byte 1 ¦
TL Register or User Byte 2*
Configuration Register41
Reserved (FFh)
Reserved (OCh)
Reserved (lOh)
CRC*
EEPROM
M Bi
<« >
TH Register or User Byte 1
Tl Register or User Byte 2
Configuration Register
"Состояние после вилку
зависит от значений, сохраненного в EEPROM
Рис. 9.9. Карта памяти датчика DS18B20
Последовательность команд для получения от датчика данных о температуре
должна быть такой:
1. Произвести reset и поиск устройств на линии 1-Wire.
2. Выдать команду 0x44, чтобы запустить конвертацию температуры датчиком.
Глава 9. Подключение датчиков кллате Arduino 161_
3. Подождать не менее 750 мс.
4. Выдать команду Охве, чтобы считать ОЗУ датчика (данные о температуре будут
в первых двух байтах).
Скетч получения данных с датчиков температуры DS18B20 и вывода данных в
последовательный порт представлен в листинге 9.3.
// Подключение библиотеки OneWire
tinclude <OneWire.h>
// пин подключения датчиков
OneWire ds(8);
void setup (void) {
// запуск последовательного порта
Serial.begin(9600);
void loop (void) {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float temperature;
// поиск устройств
if ( !ds.search(addr)) {
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delayB50);
return;
// вывод уникального номера
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(f f);
Serial.print(addr[i], HEX);
if (OneWire::crc8(addr, 7) !=addr[7]) {
Serial.println("CRC is not valid!");
return;
162 Част» Ш. Практическое пришенениеАп}^
Serial-print in О ;
//
switch
case Qxlt):
Serlal.printlnC Chip = DS18S20-1 ;
typejs = 1;
breaks
case 0x28:
Serial-println Г Oiip = Ш18В20-);
types = 0;
break;
case 0x22:
Serial.primtln I* Chip = В&1Ш22т);
type_s = 0;
break;
defaailt:
Serial, printlm I "Device is n*ot а Ш1Вж20 family tteryice'.
return;
I
// сброс иины
ds. reset О;
// яидг^яятнидр™^ алреса |уникашьного немэра;)
ds.selectCaddrl;
ds.write!0x44, 1);
// пауза > 750 шве
// сброс ни
present: — ds. reset О;
// иыегашяезте адреса Сушшшньюоро номера)
ds. select faddrj;
// комацда чтения памяти дщатчика
ds.Mrite(OxBE) ;
Serial, print Cw Data = m}s
Serial.printCpxesent, ШХ1);
Serial-print!" "I;
// чтение памяти датчика, 9 байт
for С i = 0; i < 9; inn-J f
datafi] = ds.readO;
Serial .print Idatalil, EEXD;
Serial.printr "»;
}
Serial.print Iя* CRG="|;
Serial.printCQneHire::crc8|datar 8b JBEX1;
Serial.println О ;
Подключение датчиков к плжпеАпкшю 163
// перевод тъмтах в зшадогаие температуры
tenperature= ((float) |Kiuit)dataI©l 1 UCintJdatalU) « 8И * 0.0625 hi- 0.03125;
Serial, prints" Temperature = "Э;
Serial.i
ЭЛЕКТРОННЫМ ARXMB
Полный вариант раоснклренного сверча камодится в палое ежаячр18я«_09_вЗ
ясвэммивго вни^^ дпмгпиунноур авмива нзи. прияояввние 2ж»
Загр\ ~жаем этот сжетя в плату Aiduina, запускаем монитор последовательного порп
н наблюдаем вывод показаний датчиков температуры DS1SB20 в
ныи порт (рис 9.10).
iOS1SB20bi
9.3. Подключение датчиков влажности
и температуры DHT
Датчики DHT11 и DHT22 (рис. 9.11) состоят из емжосттюго,
термистора. Кроме тога, дагчижи содержат чип, который преобразует
сигнал в цифровой. В процессе производства
| DHT, могут получать разные параметры, и чтобы
вильны м и. производитель калибрует каждый дагак DHT в i
164 Часть III. Практическое применение Arduino
а поправочный коэффициент сохраняется в памяти и вызывается при считывании
данных.
Общие характеристики датчиков:
? DHT11:
• очень низкая стоимость;
• питание и I/O: 3-5 В;
• определение влажности 20-80% с точностью 5%;
• определение температуры 0...50°С с точностью 2%;
• частота опроса не более 1 Гц (не более одного раза в 1 с);
• размеры 15,5x12x5,5 мм;
? DHT22:
• низкая стоимость;
• питание и I/O: 3-5 В;
• определение влажности 0-100% с точностью 2-5%;
• определение температуры -4О...+125°С с точностью ±0,5°С;
• частота опроса не более 0,5 Гц (не более одного раза в 2 с);
• размеры 15,1x25x7,7 мм.
Сенсор DHT22 имеет лучшие, чем у DHT11, характеристики, но более высокую
стоимость.
Рис. 9.11. Датчики DHT11 (слева) и DHT22 (справа)
Преимущество этих датчиков— небольшие размеры, низкое энергопотребление,
высокая дальность передачи (до 20 м), к недостаткам можно отнести относительно
невысокую точность измерений.
Датчики имеют 4 вывода стандарта 2,54 мм:
? 1— VCC (гаггание 3-5 В);
? 2 — DATA (вывод данных);
? 3 — не используется;
? 4 — GND («земля»).
Глава 9. Подключение датчиков к плате Arduino 165^
Протокол обмена— однопроводный, по структуре весьма похожий на протокол
датчиков DS18В20, но с различиями:
? DHT не умеет работать в «паразитном» режиме (при питании по линии данных);
О каждый DS18B20 имеет персональный идентификатор, что дает возможность
подключения нескольких таких датчиков к одному контакту (пину) Arduino.
Однако у DHT такой возможности нет— один датчик будет использовать строго
один цифровой пин.
Чтобы начать получать данные с датчика, микроконтроллер должен отправить
датчику запрос и дождаться от него ответа, что датчик готов передавать информацию.
Происходит это следующим образом. Когда микроконтроллер собрался принимать
данные, он должен притянуть линию данных к нулю на 18 мс, после чего отпустить
ее обратно к 1. При этом микроконтроллер переходит в режим ожидания и следит
за тем, что происходит с линией данных. Через 20-40 мкс, если все в порядке,
датчик отвечает притягиванием уже со своей стороны линии данных к нулю на 80 мкс
и отпускает ее на 80 мкс. Таким образом датчик дает понять микроконтроллеру, что
с ним все в порядке и он начинает передачу данных. Данные передаются побитно.
Перед передачей каждого нового бита датчик притягивает линию данных к нулю на
50 мкс, после чего отпускает ее к 1. В зависимости от того, на сколько микросекунд
датчик отпускает линию к 1, микроконтроллер распознает, какой бит был передан:
если длительность временного промежутка до следующего притягивания к нулю
26-28 мкс, то передан 0, если 70 мкс — передана 1.
Количество передаваемой информации — 40 битов E байтов). Первый и второй
байты содержат целую и дробную части информации о влажности, третий и
четвертый байты содержат целую и дробную части информации о температуре, пятый
байт — контрольная сумма, которая представляет собой последние 8 битов от
сложения предыдущих 4 байтов.
После передачи пакета данных датчик переходит в спящий режим до следующего
запроса со стороны микроконтроллера.
Монтажная схема подключения датчика DHT22 к плате Arduino показана на
рис. 9.12.
Для считывания данных датчика DTH22 с помощью Arduino существует готовая
библиотека DHT, которую необходимо импортировать в Arduino IDE.
Электронный архив
Библиотека DHT размещена в каталоге libraries сопровождающего книгу электронного
архива (см. приложение 2).
Итак, загружаем в плату Arduino скетч получения данных с датчика DHT22 и
вывода их в последовательный порт Arduino (листинг 9.4), запускаем монитор
последовательного порта и наблюдаем вывод в него значений влажности и температуры
(рис. 9.13).
166
Часть III. Практическое применение Arduino
•шйшашшяадмшшмю^^
Рис 9.12. Монтажная схема подключения датчика DHT22 к плате AnJuino
Рис 9.13. Вывод данных влажности и температуры с датчика DHT22
Гпава 9. Подключение датчиков к плате Алклпо 167
II подключение библиотеки ЕГГН
¦include "DHT.h"
// пин подключения контакта DATA
tdefine DHTPIN 10
// тип датчика - DHT 22
¦define DHTTYPE DHT22
// создание экземпляра объекта DHT
DHT dht (DHTPIN, DHTTYPE) ;
void setup () {
// запуск последовательного порта
Serial.begin (9600);
// запуск DHT
dht.begin();
void loop() {
// получение ^нш« с датчика
int h = dht.readHumidityO;
int t = dht.readTenperatureO;
Serial. print ("Humidity^");
Serial .print (h);
Seria 1. print (" Temperature=") ;
Ser ial. print In (t) ;
// пауза (измерения не чаще одного раза в 2 с)
delayB000);
Электронным архив
Полный вариант рассмотренного скетча находится в папке examples№\J)9jD4
сопровождающего книгу электронного архива (см. приложение 2).
9.4. Подключение датчиков по протоколу 12С
Последовательный протокол обмена данными t*C использует для передачи данных
две двунаправленные линии связи:
? SDA (Serial Data) — шина последовательных данных;
? SCL (Serial Clock) — шина тактирования (синхронизации).
Задействуются также две линии для питания. Шины SDA и SCL подтягиваются
к шине питания через резисторы.
При работе по протоколу 12С в сети должно присутствовать хотя бы одно ведущее
устройство (master), которое инициализирует передачу данных и генерирует <
168 Часть III. Практическое применение Arduino
налы синхронизации, а также ведомые устройства (slave), которые передают
данные по запросу ведущего. У каждого ведомого устройства есть уникальный адрес,
по которому ведущий и обращается к нему. К одной шине 12С может быть подклю
чено до 127 устройств, в том числе несколько ведущих.
Arduino использует для работы по интерфейсу 12С два контакта. Каждая версия
Arduino имеет свои выводы 12С (табл. 9.1).
Таблица 9.1. Контакты 12С для разных плат Arduino
Плата Arduino
Arduino Uno, Nano
Arduino Mega
Arduino Leonardo
Arduino Due
Вывод SDA
4
20
2
20
Вывод SCL
5
21
3
21
Для обмена данными с устройствами по шине 12С в Arduino есть стандартная
библиотека Wire.
Подключим к плате Arduino несколько датчиков, работающих по протоколу 12С, и
загрузим в плату Arduino скетч поиска устройств, подключенных к шине 12С
загрузим в плату Arduino скетч поиска устройств, подключенных к шине 1С
(листинг 9.5). Этот скетч сканирует шину 12С и выводит в последовательный порт
Arduino таблицу с адресами подключенных устройств.
#include "Wire.h"
void setup() {
Wire.begin();
Serial.begin(9600); // запуск последовательного порта
void loop () {
int devices;
byte err, add;
Serial.println("Start scan I2C bus...");
devices =0;
Serial.print(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E OF");
for(add = 0; addr<= 127; addr++ ) {
if((addr% 0x10) = 0) {
Serial. println ()' ;
if(addr< 16)
Serial.print('0f) ;
Serial.print(addr, 16);
Serial.print(" ") ;
Глава 9. Подключение датчиков к плате Arduino 169
Wire.beginTransmission(addr);err = Wire.endTransmission();
if (err == 0) {
if (addr<16)
Serial.print(");
Serial.print(addr, HEX);
.devices**;
}
else {
Serial.print ("—");
}
Serial.print(" ");
delayA);
}
Serial .println () ;
if (nDevices = 0)
Serial.printIn("No I2C devices found\n");
delayB500) ;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\9\_09_Q5
сопровождающего книгу электронного архива (см. приложение 2).
9.4.1. Подключение к плате Arduino датчика
интенсивности света ВН1750
Рассмотрим подключение к плате Arduino датчика интенсивности света — модуля
GY-302 на базе микросхемы ВН1750 (рис. 9.14), работающего по протоколу 12С.
Рис. 9.14. Модуль GY-302 на базе микросхемы ВН1750
170 Часть III. Практическое применение Arduh
Измерение освещенности является важным параметром при создании приложении
домашней автоматики. Освещенность измеряют в люксах Aх). Люкс равен
освещенности поверхности площадью 1 м2 при световом потоке падающего на нее
излучения, равном 1 люмену (лм). Модуль GY-302 на базе чипа ВН1750 представляет
собой высокоточный цифровой датчик интенсивности света, выдающий значение
в люксах.
Модуль имеет S выводов:
П VCC — питание 5 В;
? GND — «жиля»;
? SDA—данные 12С;
? SCL— синхронизация 12С;
П ADDR — выбор адреса для протокола 12С.
Разберемся с возможными адресами датчика BH17S0. Существуют два варианта
подключения датчика BH17S0 к шине 12С (рис. 9.15).
Рис. 9l15u Монтажные ооемы подключения датчика ВН1750 к Arduino
Загруженный на плату Aidoino скетч из листинга 9.S будет сканировать шину 12С и
выводить в последовательный порт Anhiino адрес подключенного устройства. Как
показано на рис. 9.16, модуль BH17S0 может иметь— в зависимости от уровня
сигнала на входе ADDR — два адреса @x23 и 0х5с). Это значит, что к одной плате
Aiduino можно подсоединить одновременно два датчика ВН1750.
Для работы Aiduino с датчиками BH17S0 написано несколько библиотек, мы здесь
воспользуемся одной из них— BH17S0FVI (ее можно скачать по ссылке:
https^/g^HlM»m/enjoyKwermg/BH1750FV1). Эта библиотека поддерживает все
режимы датчика ВЫ 1750, позволяет производить измерения освещенности с
несколькими параметрами чувствительности @,45-3,68) и разрешающей способности
Глава 9. Подключение датчиков if плате Arduino
171
AOOR-HSGH
Until
Рис 9.16. Адреса датчика ВН1750
Рис 9.17. Пример вывода данных с датчика ВН1750 в монитор последовательного порта Arduino
при различных режимах измерении
172 Часть III. Практическое применение Arduino
@,5-4 1х), а также в режиме энергосбережения. К библиотеке прилагается пример
(BH1750FVI_Demo) вывода в последовательный порт Arduino данных с датчика
ВН1750 при различных режимах измерения (рис. 9.17).
Электронный архив
Библиотека BH1750FVI размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
В следующих главах мы рассмотрим и другие датчики, работающие по
протоколу 12С.
ГЛАВА 10
Использование дисплеев
в проектах Arduino
Данные, получаемые с датчиков, в предыдущей главе мы выводили в монитор по:
следовательного порта Arduino. Смотреть на показания датчиков через
последовательный порт не всегда приемлемо — и нам необходимы более удобные устройства
для отображения данных. Электронные устройства, предназначенные для
визуального отображения цифровой, цифро-буквенной или графической информации,
называются дисплеями. И в этой главе мы рассмотрим работу Arduino с различными
дисплеями.
10.1. Символьные дисплеи
на микроконтроллере HD44780
Жидкокристаллические (ЖК) дисплеи на основе микроконтроллера HD44780
наиболее часто используются в проектах Arduino. Такой дисплей представляет собой
модуль, состоящий из микроконтроллера HD44780 и непосредственно самого ЖК-
дисплея. Микроконтроллер принимает команды й отрисовывает на ЖК-дисплее
соответствующие символы.
Существует огромное количество разновидностей таких ЖК-модулей: они могут
содержать 1, 2 или 4 строки с различным числом символов в строке, быть с
подсветкой или без оной, а также с различным цветом подсветки. Объединяет их всех
наличие контроллера HD44780, знание команд которого позволит без проблем
использовать в своих проектах ту или иную модификацию этого модуля.
ЖК-дисплеи Winstar WH1602 (рис. 10.1) на контроллере HD44780 имеют 16
выводов, назначение которых представлено в табл. 10.1.
Таблица,10.1. Назначение выводов дисплея WH1602
№ вывода
1
2
3
Название
Vss
Vdd
Vo
Функция
Общий (GND)
Напряжение питания C или 5 В)
Контрастность
174 Часпт* Ш. Праюпичесюое пршленение Агвиюо
г 10,1 (окончание)
RS
R/W
6
DBO
DB1
9
10
11 \
DB2 Л
DB3 Jl
DB4 Л
тинвшныхЗ
ШШЯЯ ДЭНИпК «1
•«ядмисЧ
12 DB5
13 DB6 1Ьти»дамиых6
14 DB7
15 ' LHH Напряжение ncwsenn(^
16 ! LED- НапрюемвподсвелиН
mi. i
в этом модуж организованы подача шпаннж, настрои-
1раствостнн1юдсветжа(рнс. 10^).
ЖК-джшкя ^Kfinsiar нсобжздрш внсошнн источник питания 4у5—5,5 В.
- и LED- служат для вкшоч^па no^caeivH. Питание к подсветке под-
номинального тока с помощью внешнего резистора R.
Номина шюде должно составлять 3,5 В, а ток— 40 мА. Исходя из
R=E-3 Д>0,04 = 37 Ом.
•зуется делитель
10-20 кОм. Перед выводом
необходимо убедиться, что уцявяякяцее контрастностью напряжение
Глава 1О. Использование дисплеев в проектах Апкшю 175
+ 5В
находится в рабочем давшазове. Для этого с помощью потенциометра добейте
чтобы верхний рад <
Если после подачи питания верхний рад
угольниками, можно приступать к подключеншо ЖК-дисплея к опте Апкшю. Дня
управления ЖК-дисплеем необходимо 6 или 10 выводов
HD4478G—в зависимости от тогот выбран 4-или S-бнтныи режим обмена,
ми. Для сокращения требуемого числа выводе» микроконтроллера HD447801
работать и в 4-битном режиме. В этом случае на его выводы DB4-DB7
будут передаваться старшие четыре бита гумдгах/гамаиди а затем -
тыре бита. Выводы DB0-DB3 останутся незздействованншт.
Монтажная схема подключения ЖК-дисплея к шаге Апкшю предст
рис. 103.
Дня работы с ЖК-дисплеями на контроллере HD447S0 в Ankrino IDE
встроенная библиотека LiqmdCiystaL Чтобы с ней работать, необходимо ее
подключить:
finclucie
И Создать ЗКЭеМПЛЯр объекта LiqeidCrystai:
LiqtiidCrystal lcdC5r 1. Ъш 9. W, 11>;
Объект ТИПа LiquidCrysital ПрИСОЗДаН
? пин подключения контакта RS A2);
? пин подключения контакта Е A1);
? пин подключения контактаD4EX
? пин подключения контакта D5 D);
О пин подключения контакта D6 (ЗХ
? пнн подключения контакта D7 B)и
176 Часть III. Практическое применение Arduino
+ 5В
Рис. 10.3. Монтажная схема подключения ЖК-дисплея Winstar WH1602 к плате Arduino
Библиотека LiquidCrystal содержит много примеров, позволяющих разобраться в ее
работе. Кратко познакомимся с функциями этой библиотеки.
10.1.1. Функция beginf)
Синтаксис функции:
led.begin(cols, rows)
Функция определяет размерность индикатора (количество символов в ширину и
высоту).
Параметры:
? led — переменная типа LiquidCrystal;
? cols — количество символов в строке;
? rows — количество строк.
10.1.2. Функция clearf)
Синтаксис функции:
led. clear ()
Глава 10. Использование дисплеев в проектах Arduino 177_
Функция очищает экран жидкокристаллического индикатора и располагает курсор
в его верхнем левом углу.
Параметр: led — переменная типа LiquidCrystai.
10.1.3. Функция home()
Синтаксис функции:
led.home ()
Функция располагает курсор в верхнем левом углу жидкокристаллического
индикатора. Используется для определения начального положения при выводе
последовательного текста на экран индикатора. Чтобы еще и очистить экран индикатора,
ИСПОЛЬЗуЙТе ВМеСТО ЭТОЙ фуНКЦИИ фуНКЦИЮ clear ().
Параметр: led — переменная типа LiquidCrystai.
10.1.4. Функция setCursorf)
Синтаксис функции:
lcd.setCursor(col, row)
Функция позиционирует курсор жидкокристаллического индикатора, т. е.
устанавливает положение, в котором на его экран будет выведен последующий текст.
Параметры:
? led — переменная типа LiquidCrystai;
? col — номер знако-места в ряду (начиная с 0 для первого знако-места);
? row — номер ряда (начиная с 0 для первого ряда).
10.1.5. Функция writef)
Синтаксис функции:
led.write(data)
Функция записывает символ в жидкокристаллический индикатор.
Параметры:
? led — переменная типа LiquidCrystai;
? data — символ, записываемый в индикатор.
10.1.6. Функция printf)
Синтаксис функции print ():.
led.print(data)
led.print(data, BASE)
Функция печатает текст на жидкокристаллическом индикаторе.
178 Часпш. Ш. Праяпючесжое приыенение AjrkMK
LiquidCrystai;
Д81 печати (ТИП char, byte, lust, long НИИ string);
>)— основание, по которому печатаются числа: bin дм дао-
2\ dec дм десятичных (основание 10), ост дм восьмеричных
SX hex дяя пюстнздцпернчшга (основание 16).
10.1.7. Функция cursorQ
led. cursor t)
Функция выводит на экран жцуумр» ¦И1ммим«»ясж«гп ицдикагора курсор — подчер-
кивание зиако-месга в позиции, в которую будет записан следующий <
Параметр: icd-
10.1.8. Функция noCursorQ
Синтаксис функции:
led. noCtirsor (J
Функция скрывает курсор с
Параметр: led—переменная типа
10.1.9. Функция ЫткО
Синтаксис функции:
icd.blinkC)
Функция выводит на экран жцдоокрктжшшчесхюго ицци^аюра мигающий курсор.
Если она используется в комбинации с функцией cursor(>т результат будет
зависеть от конкретного нццшсатора.
Параметр: led—переменная типа
10.1.10. Функция noBlinkO
Синтаксис функции:
led.noBlinkil
курсор на экране мц^ущкрт птии'нч ымп шщика-
Параметр: led—переменная тнв
Пива 10. Испольэовэшю дисплеев в щюежпыж А/пЛшпо 179
10.1.11. Функция (MsplayO
Синтаксис функции:
led. display О
Функция включает жцщщкжрнсплянческнй нццжагпр после того, как ов быя
выключен функцией nooispiayo. Эта фушцш восстанавлшает текст (н курсора
шгарый был на дисплее.
Параметр: led—переменная типа
10.1.12. Функция noDisplayO
Синтаксис фушщии:
led. noDisplay { }
Функция выключает *|wi'>KP"gTai*IM''rfi'Jt™ nrtu^i»*iO|> без потерн огображягмпй
на нем информации.
Параметр: led—переменная типа Liqaddctystai.
10.1.13. Функция scmllDisplayLettO
Синтаксис функции:
icd.scrollMsplayljefft A
а экране ицднкашра (текст и курсор) на одно
Парамеф: led—переменная типа li<
10.1.14. Функция scrollDisplayRightO
Синтаксис функции:
led. scxoIJLMsplayfllgibt: С }
Функция прокручивает информацию на экране ицдакагора (текст и курсор) на одно
Параметр: led—переменная типа
10.1.15. Функция autoscroHQ
Icd.aotoscxoilС)
ч^рнкция включает автюматичеез^ю шшрошарушялу лцхшна жцдтлцинс!'
дшеатора и заставаяет кжтгдий вывод симвеша на экрош ицдикатора
предыдущие символы на одно знако-место. Если те^тцее нащювленне вывода сим-
водов слева направо (значение по умодчанмо)—экран нвдикатора прокручивается
180 Часть III. Практическое применение Arduino
влево, если текущее направление вывода символов справа налево — экран
индикатора прокручивается вправо. Это производит на экране жидкокристаллического
индикатора эффект вывода каждого нового символа в одно и то же знако-место.
Параметр: led — переменная типа LiquidCrystai.
10.1.16. Функция noAutoscrollQ
Синтаксис функции:
lcd.noAutoscroll()
Функция выключает автоматическую прокрутку экрана жидкокристаллического
индикатора.
Параметр: led — переменная типа LiquidCrystai.
10.1.17. Функция leftToRight()
СиНТаКСИС фуНКЦИИ lef tToRight ():
led.leftTorRight()
Функция устанавливает направление вывода символов на экран
жидкокристаллического индикатора слева направо (значение по умолчанию). Это означает, что
последующие символы, выводимые на экран индикатора, пойдут слева направо, но
не повлияют на выведенный ранее текст.
Параметр: led — переменная типа LiquidCrystai.
10.1.18. Функция rightToLeftO
Синтаксис функции:
led. rightToLeftO
Функция устанавливает направление вывода символов на экран
жидкокристаллического индикатора справа налево (значение по умолчанию — слева направо). Это
означает, что последующие символы, выводимые на экран индикатора, пойдут
справа налево, но не повлияют на выведенный ранее текст.
Параметр: led — переменная типа LiquidCrystai.
10.1.19. Функция createCharQ
Синтаксис функции:
lcd.createChar(num, data)
Функция создает пользовательский символ (глиф) для использования на
жидкокристаллическом дисплее. Поддерживаются до восьми символов 5x8 пикселов
(нумерация с 0 до 7). Создание каждого пользовательского символа определяется
массивом из восьми байтов — один байт для каждой строки. Пять младших значащих
Глава 10. Использование дисплеев в проектах Arduino
181
битов каждого байта определяют пикселы в этой строке. Чтобы вывести
пользовательский символ на экран, используйте функцию write () с номером символа в
качестве параметра.
Параметры:
? led — переменная типа LiquidCrystal;
? num — номер создаваемого символа @ to 7);
? data — данные символьных пикселов.
10.2. Подключение дисплеев
на контроллере HD44780 по протоколу 12С
К сожалению, стандартная схема подключения ЖК-дисплеев на контроллере
HD44780 не всегда удобна, т. к. занимает как минимум 6 цифровых выходов платы
Arduino. Использование конвертера 12С (рис. 10.4) позволяет задействовать для
подключения такого дисплея к плате Arduino только два вывода.
Рис. 10.4. Подключение конвертера I2C к ЖК-дисплею Winstar
Монтажная схема подключения ЖК-дисплея с конвертером 12С к плате Arduino
представлена на рис. 10.5.
Для определения 12С-адреса дисплея загрузим в плату Arduino скетч из листинга 9.5
и запустим монитор последовательного порта (рис. 10.6).
Чтобы работать с ЖК-дисплеем WH1602 по протоколу 12С, необходимо установить
библиотеку LiquidCrystal_I2C, которую можно скачать из репозитория Arduino, Для
этого в меню Arduino IDE выбираем команду Эскиз | Include library | Manage
Libraries. Далее в строке поиска набираем i2c led, находим библиотеку
LiquidCrystal_I2C и нажимаем на кнопку Install (рис. 10.7).
182 Часть III. Практическое применение Ardumo
+5В
Рис 1Л5. Монтажная схема подключения ЖК-дисплея с конвертером!^ к плате Anluino
Рис 10.6. Поиск 12С-устроиств, подключенных к АгаЧлпо
Глава 10. Использование дисплеев в проектах Arduino 183
Рис 10.7. Поиск библиотек UquidCfystal_l2C
10.2.1. Вывод на ЖК-дисплей данных с датчика,
работающего по протоколу I2C
Рассмотрим пример вывода на ЖК-дисплей данных с датчика атмосферного
давления и температуры ВМР280, работающего по протоколу 12С. Этот датчик может
измерять атмосферное давление и температуру с очень высокой точностью. Так,
точность измерения барометрического давления этим датчиком составляет ±1 гПа,
а температуры— ±1,0°С. Поскольку давление изменяется с высотой, датчик
ВМР280 также можно использовать и как высотомер с точностыо±1 м.
Обратите внимание, что в представленной на рис. 10.8 монтажной схеме этого
проекта питание датчика ВМР280 берется с выхода Arduino 33 В. Подключение его
к напряжению 5 В приведет к выходу датчика из строя!!!
Дня работы датчика ВМР280 с Arduino необходимо установить библиотеку
ВМР280, которую можно скачать со страницы: https://gitbeb.coiii/adafoHt/Adafriiit
ВМР280 Library
Электронный архив
Библиотека Adafruit_BMP280JJbfary размещена в каталоге fbraries сопровождающего
кнму электронного архива (см. приложение 2).
С помощью созданного для этого проекта скетча (листинг 10.1) мы будем получать
с датчика данные с периодичностью 5 с и выводить их как в фиксированные
позиции ЖК-дисплея, так и в монитор последовательного порта.
184
Часть III. Практическое применение Arduino
Рис. 10.8. Монтажная схема подключения к плате Arduino ЖК-дисплея с конвертером I2C
и датчика ВМР280
// подключение библиотеки Wire
#include "Wire.h"
#include <SPI.h>
// подключение библиотеки LiquidCrystal_I2C
#include <LiquidCrystal_I2C.h>
// создание экземпляра объекта для дисплея 16x2
LiquidCrystal_JE2C lcd@x27, 16, 2) ;
// подключение библиотек для датчика ВМР280
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
¦// создание экземпляра объекта - подключение по I2C
Adafruit_BMP280 myBMP280;
// для периода опроса датчика
unsigned long millisl=0;
int val;
void setup() {
// запуск последовательного порта на скорости 9600 бод
Serial.begin(9600);
// запуск ВМР280
myBMP280.begin();
Глава 10. Использование дисплеев в проектах Arduino 185
II инициализация дисплея
lcd.initO ;
// включить подсветку
led.backlight();
//
led.setCursor@,0);
lcd.print("P=");
led.setCursor(8,0);
lcd.print("T=");
void loop () {
// раз в 5 с
if (millis()-millisl>=5000) {
// данные атмосферного давления с ВМР280
int val=(int)myBMP280.readPressure();
Serial.print("Pressure: ") ;
Serial.print(val);
Serial, printing Pa");
led.setCursorB,0);
led.print(val);
led.print("Pa");
// данные температуры с ВМР280
int val=(int)myBMP28 0.readTemperature();
Serial.print("Temperature: ");
Serial.print(val);
Serial.printIn(" *C");
led.setCursorA0,0);
led.print(val);
led.print("*C");
// начать отсчет 5 с заново
millisl=millis ();
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\10\_10_01
сопровождающего книгу электронного архива (см. приложение 2).
При компиляции скетча может произойти ошибка из-за отсутствия библиотеки
Adafruit Unified Sensor. В этом случае необходимо доустановить эту библиотеку. Ее
можно найти в репозитории Arduino. Для этого в Arduino IDE выбираем пункт
Эскиз | Include library | Manage Libraries, находим библиотеку Adafruit Unified
Sensor и нажимаем на кнопку Install.
186
Часть III. Практическое применение Arduino
10.3. Графический дисплей Nokia
Символьные дисплеи, которые мы рассматривали в предыдущих разделах, имеют
большие возможности в плане вывода символьной информации. С их помощью
можно выводить текстовые сообщения, значения различных параметров, показания
датчиков. Но что если нам требуется еще больший уровень информативности —
с отображением графиков, картинок или текстовых сообщений с использованием
разных шрифтов?
Поможет нам в этом деле графический дисплей— например, Nokia5110. Этот
дисплей широко распространен среди любителей Arduino. Дисплей монохромный и
имеет разрешение 84x48 точек. Как правило, дисплеи NokiaSl 10 поставляются на
плате в паре с контроллером PCD8544 и штыревым разъемом. В продаже можно
найти два варианта исполнения модулей дисплея: на синей плате (рис. 10.9, слева)
и на красной (рис. 10.9, справа). Оба варианта модуля имеют по восемь выводов:
П RST —сброс (Reset);
? СЕ — выбор устройства (Chip Select);
? DC — выбор режима (Data/Command select);
? Din — данные (Data In);
? SCLK — тактирующий сигнал (Clock);
П VCC — питание 33 B;
О BL (LIGHT) — подсветка;
П GND — «земля».
Щ:Г0ШШЩШшШш \
Рис. 10.9. Дисплеи Nokia5110: слева—на синем плате; справа—на фасной
Питание контроллера PCD8S44 должно лежать в пределах 2,7-3,3 В (максимум
33 В — при подаче S В дисплей может выйти из строя). Сигнальные же выводы
толерантны к напряжению 5 В и подключаются к любым цифровым выводам
Arduino.
Глава 10. Использование дисплеев в проектах Ardumo 187
При использовании синего модуля подсветка дисплея активизируется подачей
сигнала высокого уровня на вывод BL, а при использовании красного — подачей
сигнала низкого уровня на вывод LIGHT.
Монтажная схема подключения дисплея Nokia5110 к плате Arduino показана на
рис. 10.10.
Рис 10.10. Монтажная схема подключения дисплея Nakia5110 к плате Апкнпо
Для управления дисплеем Nokia5110 потребуется библиотека Adaftnit GFX
Library, которую можно скачать по адресу: fcttps^/gMiebxora/adbifnMt/Adafnut-
GFX-Library/arcluvc/nMsterjdp. Установите эту библиотеку и включите в скетч
следующие строки:
tinclode <Ad&fruit_GFX.h>
finclude <Adafruit_PCD8544.h>
// Nokia 5110
// pin 1 - Serial clock out (SCUt)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Ccraoand select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - UCD reset (RST)
Adafruit_PCD8544 display = Mafruit_PCD8544 G, 6, 5, 4, 3);
Электронный архив
Библиотека Adafln?jGFX_Ubrary размещена в каталоге Sbrahes сопровождающего
книгу электронного архива (см. приложение 2).
188 Часть III. Практическое применение Arduino
В листинге 10.2 показан простой скетч вывода текста на экран дисплея Nokia5110.
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
// Nokia 5110
// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Coiranand select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544G, 6, 5, 4, 3);
void setup() {
// инициализация и очистка дисплея
display.begin();
display.clearDisplay();
display.display();
display.setContrastE0); // установка контраста
delayA000);
display.setTextSizeA); // установка размера шрифта
display.setTextColor(BLACK); // установка цвета текста
display.setCursor@,0); // установка позиции курсора
display.println("Hello, world!");
display.display();
void loop() {
Загрузите этот скетч в плату Arduino, и вы увидите вывод на экран текста Hello,
world!
Теперь попробуем поработать с графикой — выведем на экран простейшие
геометрические фигуры (листинг 10.3).
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
// Nokia 5110
// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
Глава 10. Использование дисплеев в проектах Arduino
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544 G, 6, 5, 4, 3);
void setup () {
// инициализация и очистка дисплея
display.begin();
display.clearDisplay();
display.display();
display.setContrastE0); // установка контраста
delayA000);
void loop () {
// пиксел
display.clearDisplay();
display.drawPixelA0, 10f BLACK);
display.display();
delayA000);
// линия
display.clearDisplay();
display.drawLine@, 0, 50, 30, BLACK);
display.display();
delayA000);
// прямоугольник
display.clearDisplay();
display.drawRect@, 0, 10, 10, BLACK);
display.display();
delayA000);
// прямоугольник залитый
display.clearDisplay();
display.fillRect@, 0, 10, 10, BLACK);
display.display();
delayA000);
// треугольник
display.clearDisplay();
display.drawTriangle@, 0, 40, 40, 30, 20, BLACK);
display.display();
delayA000);
// окружность в центре
display.clearDisplay();
display.drawCircle(display.width()/2,
display.heigtit()/2, 10, BLACK);
display.display();
delayA000);
190 Часть Ш. Цракипуюшю щшш&ювжю Antoho
Электронный архив
Полный вариант рассмотренного светча наяурпся в лапше ехатрЛеяМО(_10_аз сопрово-
яфцэкхцого янму элбкпюнного арнива Сем. лрютиввмив 2V.
Библиотека Adafimk GFX Libf«y позволяет выводил» на экран дисплея и
растровые июбражениж. Для начала веобходщю создать саму мциинку— в черно-белом
формате с расширением bmp и размером 84x8 пикселов. А затем получить НЕХ-код
этой щциинки— например, в программе GLCD Took— и вставить ого в скетч
Aiduino (листинг 10.4). Загрузите этот скетч в плату АпЬшю, и вы уввдите на
экране растровое изображение (рис. 10.11).
Рве 10.11. Двупрстиая i
# include <MafruitjG?X.n>
#indiade <Mafr3iit_BCDB544.n
// Nokia 5110
// pin 1 - Serial clock out
// pin 6 - Serial data ©ait ЩШ)
// pie 5 - Data/OaramaiMi select
// pin 4 - LCD chip select fCS)
// pin 3 - ILCB reset (K$T$
i^dafoiit_roD©S44 display = Adafruit_PCDB544 f 1, 6. 5, 4, 3);
canst unsigned char ЖХЭЖМ imglOO = f
Oxff, Qxff, Oxffr ®x?f0 0xff# !Qxff# 0xffr Qxff# Oxff, Qxff, 0x80,
Oxff# Qxff, Oxff# 0xe©, Qxff# 0xfc# 0xlf# Qxff# Qxff, Qxff, 0x80#
Oxff, Oxff# Qxff, 0xe0# 0xffr ©xfc, Qxlf, Oxffr Qxff# Qxff, 0x80,
Oxff, Oxff, Qxf?. 0xe0# ©xff, 0xfcr Oxlf, Oxff, Oxffr Qxff, Qx80#
Oxff, Qxff, QxffF Qxe©, Qxff# 0xfc# (Dxlf, 0xffr Qxff, Qxff, Qx80#
Qxffr Dxff, Qxffr ©xel# ©xff, Oxfc, Qxlf, Qxlf, Oxff# Qxff, 0x80,
Qxff, Oxff, Oxff# 0xel# Oxff, ©xf®, ©xlf# Oxff, Oxff# Qxff# 0x80,
Oxff, Oxff, Oxff, Oxcl, Oxff, ©xf8, Qx3f, Qxff, Oxff, Qxff, 0x80,
Oxff, Oxff, Qxff, Oxcl, ©xff, ©xfB, Qx3f, Oxff, Oxff, Qxff, 0x80,
Oxff, Oxff, Oxff, Oxcl, Oxff, OxfB, 0x3f, Oxff, Qxff, Qxff, 0x80,
Oxff, Oxff, Oxff, Oxcl, Oxff, QxfB, Qx3f, Qxff, Qxff, Qxff, 0x80,
Gxff, Oxff, Oxff, ОхсЗ, Qxff, QxfO, Qx3f, Qxff, Qxff, Qxff, 0x80,
Oxff, Oxff, Oxff, 0x83, 0x3, QxfO, 0x20, 0x78, Qx3f, 0x83, 0x80,
Oxff, Oxff, Oxff, 0x80,-0x1, OxfO, 0x40, 0x38, Qx3f, 0x83, 0x80,
Oxff, Oxff, Oxff, 0x80, 0x0, QxfO, QxQ, 0x38, Qxlf, 0x7, 0x80,
Oxff, Oxff, Oxff, 0x80, 0x0, OxfO, QxQ, 0x18, Qxlf, 0x7, 0x80,
Oxff, Qxff, Oxff, 0x80, 0x0, QxfO, 0x10, Qxlc, Qxle, Qxf, 0x80,
Dxff, Oxff, 0x3, 0x81, OxcO, 0x60, 0x78, Qxlc, Qxlc, Qxlf, 0x80,
Oxff, Oxfc, 0x3, 0x3, OxeO, 0x60, 0x78, Qx3c, Qxlc, Qxlf, 0x80,
Гпава 10. Испапьэовамюдшятвеве проектах АйФжю 191
Oxff# OxfQ, 0x3, 0x7, ОжеО, 0x60, Qxf8, ОхЗс, 0x18, ©x3f, 0x80,
Cxit, ОхсО, 0x3, 0x7, ОхеО, QxeO, Qxf8, ОхЗе, 0x8, 0x3f, 0x60,
Oxff, 0x60, 0x3, 0x7, OxeO, QxeO, Qxf8, ОхЗе, QxQ, Qx7f, 19x80,
Oxff, 0x0, 0x3, 0x7, ©xc©, OxeO, 0xf8, ОхЗе, 0x0, Oxff, 0x80,
Oxfe, 0x0, 0x3, 0x7, QxcO, Qxd, Qxf8, ОхЗе, 0x0, ©xff, 0x80,
Oxfe, 0x0,0x6, 0x3, Oxl, Oxd, OxfO, 0x7e, Oxl, Qxff, 0x80,
Oxfe, 0x0, 0x6, QxO, Oxl, Oxcl, OxfO, 0x7f, Oxl, Oxff, 0x80,
OxfS, QxO, 0x6, 0x0, 0x3, Oxcl, OxfO, 0x7f, 0x3, Oxff, 0x80,
OxfO, 0x0, Oxle, 0x0, 0x7, Oxcl, OxfO, 0x7f, 0x7, Oxff, 0x80,
OxfO, 0x0, 0x7e, 0x10, Oxf, 0x81, OxfO, 0x7f, 0x7, Oxff, 0x80,
OxeO, Oxl, Oxfe, 0x18, Oxlf, ОхсЗ, OxfO, Oxff, 0x8f, Oxff, 0x80,
OxeO, Oxl, Oxff, Oxff, Qxff, Oxff, ©xff, Qxff, Oxff, Oxff, 0x80,
OxeO, 0x3, Oxfe, 0x0, 0x0, 0x0, 0x0, 0x0, ©xlf, Oxff, 0x80,
OxeO, 0x3, Oxfe, 0x0, 0x0, 0x0, 0x0, 0x0, Oxlf, Oxff, 0x80,
OxcO, 0x7, Oxfe, 0x0, QxO, QxQ, OxQ, 0x0, 0x3f, Qxff, 0x80,
OxcO, 0x7, Oxff, Oxff, Qxff, Oxff, Oxff, Oxff, Qxff, Oxff, 0x80,
OxcO, 0x7, Oxff, Oxfe, QxO, 0x7f, Qxff, Qxff, Qxff, Oxff, 0x80,
OxcO, 0x7, Oxff, Oxfe, 0x0, ©xff, Oxff, Oxff, Qxff, Oxff, 0x80,
OxcO, 0x7, Oxff, ©xfB, 0x0, Oxff, Oxff, Oxff, Oxff, Qxff, 0x80,
OxeO, 0x3, Oxff, 0xf8, 0x0, Oxff, Oxff, Qxff, Oxff, Oxff, 0x80,
OxeO, 0x3, Oxff, 0xf8, 0x0, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80,
OxeO, Qxl, Oxff, OxfO, OxQ, Qxff, Qxff, Qxff, Oxff, Oxff, 0x80,
OxeO, 0x0, Oxff, OxeO, Qxl, Qxff, Qxff, Oxff, Dxff, Oxff, 0x80,
OxfO, 0x0, 0x7f, 0x80, Oxl, Oxff, Qxff, Oxff, Oxff, Oxff, 0x80,
OxfO, 0x0, 0x4, 0x0, 0x3, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80,
OxfS, 0x0, Ox©, 0x0, 0x3, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80,
Oxfe, 0x0, 0x0, 0x0, 0x7, Oxff, Oxff, Oxff, Oxff, Oxff, 0x80,
Oxfe, QxO, 0x0, 0x0, 0x7, Qxff, Oxff, Oxff, ©xff, Oxff, 0x80,
Oxfe, 0x0, 0x0, 0x0, Oxf, Oxff, Oxff, Oxff, Qxff, Oxff, 0x80
void setup О {
// инициализадия и ичжтка дасплея
display. begin О ;
display - clearBisplay О ;
display, display О ;
// установка контраста
display. setCantrast: {50};
delay A000);
// отрисовка изображения
display.drawBitJaapiO, 0, iiaglO, 84, 44, ВШЖ);
display.display О ;
void loop<0 {
192
Часть III. Практическое применение Arduino
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\10\_10_04
сопровождающего книгу электронного архива (см. приложение 2).
10.4. OLED-дисплеи
В последнее время в проектах Arduino все чаще используют не простые ЖК-инди-
каторы, а OLED-дисплеи, несмотря на то, что они дороже. Но, в отличие от ЖК-
индикаторов, где пикселы подсвечиваются, в OLED-дисплеях они сами излучают
свет— изображение получается более контрастным и насыщенным, с хорошими
углами обзора. К тому же OLED-дисплеи обладают незначительным
энергопотреблением.
Для использования в Arduino-проектах удобно применять OLED-дисплеи,
выполненные в виде модуля на микросхеме SSD1306 с необходимой обвязкой. Эти
модули работают на интерфейсе 12С. Монтажная схема подключения модуля OLED-
дисплея к плате Arduino показана на рис. 10.12.
Рис. 10.12. Монтажная схема подключения к плате Arduino OLED-дисплея 128x32
Сначала определим адрес нашего дисплея на шине 12С. Для этого загрузим в плату
Arduino скетч из листинга 9.5 и запустим монитор последовательного порта.
Результат работы скетча показан на рис. 10.13— найдено устройство с адресом
ОхЗС.
Для работы с OLED-дисплеем 128x32 имеется несколько библиотек. Самая
известная— Adafruit SSD1306. Есть также и библиотека OLEDI2C, которая благодаря
Глава 10. Использование дисплеев в проектах Arduino
усилиям энтузиастов поддерживает использование русского шрифта. Для
подключение русского шрифта включите в скетч команду:
extern uint8_t RusFont[];
Затем в нужном месте скетча выберите шрифт:
display. setFont (RusFont) ;
К сожалению, в скетче Arduino мы не можем набирать слова русскими буквами,
поэтому вводим нужный текст в английской раскладке:
// текст "Издательство БХВ"
display.print ("Bplfntkmcndj <{D", CENTER, 40);
Рис. 10.13. Адрес OLED-дисплея 128x32 найден
Электронный архив
Библиотека OLEDJ2C размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
10.4.1. Электронные часы на OLED-дисплее
В этом примере мы воспользуемся OLED-дисплеем, чтобы создать макет
электронных часов. Датчиком точного времени нам послужит модуль DS3231 на
микросхеме DS3231 (рис. 10.14)— он представляет собой недорогую плату с чрезвычайно
точными часами реального времени (RTC), с календарем, дополнительной памятью
NW SRAM E6 байтов) и возможностью температурной компенсации кварцевого
генератора и кристалла. Количество дней в месяце рассчитывается с учетом
високосных лет до 2100 г.
194
Часть III. Практическое применение Arduino
Рис. 10.14. Модуль датчика точного времени DS3231
Модуль несет на себе литиевую батарею, которая поддерживает бесперебойную
работу даже при отключении источника питания. Микросхема подключается
к плате Arduino при помощи шины 12С.
Монтажная схема подключения к плате Arduino модуля датчика точного времени
и OLED-дисплея показана на рис. 10.15.
Рис. 10.15. Монтажная схема подключения к плате Arduino
модуля датчика точного времени и OLED-дисплея
Глава 10. Использование дисплеев в проектах Arduino 795
В скетче для этого проекта (листинг 10.5) мы получаем время с микросхемы
DS3231, форматируем его и выводим на дисплей (рис. 10.16). При этом
используются два вида шрифтов:
0 smaiiFont — для вывода времени и даты;
0 RusFont — для вывода дня недели.
Рис. 10.16. Макет электронных часов в сборе
// подключение библиотек
finclude <Wire.h>
tinclude <Time.h>
iinclude <DS1307RTC.h>
iinclude <OLED_I2C.h>
OLED display(SDA, SCL, 8); //
extern uint8_t SmallFontf]; // шрифт small
extern uint8_t RusFont []; // шрифт RusFont
tmElements_t tm;
String strl=IMI;
// дни недели
char wday[7] [12] = { {"Gjytltkmybr"},
{" Dnjhybe "},{" Chtlf "},
{" Xtndthu "},{" Gznybwf "},
196 Часть III. Практическое применение Artiu'm
{" Ce,,jnf "},{"Djcrhtctymt"}
void setup() {
display.begin();
void loop() {
if (RTC.read(tm)) {
// Стираем все с экрана
display.clrScr();
// Выбираем шрифт'
display.setFont(SmallFont);
// строка время
strl="";
strl=strl+ printf2 (tm.Hour);
strl=strl+":";
strl=strl+ printf2 (tm.Minute);
strl=strl+":ff;
strl=strl+ printf2 (tm.Second);
display.print(strl, CENTER, 10);
// строка дата
strl="";
strl=strl+ printf2 (tm.Day);
strl=strl+"/";
strl=strl+ printf2 (tm.Month);
strl=strl+'7";
strl=strl+String(tmYearToCalendar(tm.Year));
display.print(strl, CENTER, 22);
display.setFont(RusFont);
// строка день недели
display.print(wday[tm.Wday], CENTER, 34);
// Обновляем информацию на дисплее
display.update();
delayA000);
// вывод с добавлением до двух цифр
String printf2(int nn) {
String snn="";
if (nn >= 0 && nn < 10)
{snn=";}
snn=str+String(nn);
return snn;
}
Глава 10. Использование дисплеев в проектах Arduino 197_
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\10\_10_05
сопровождающего книгу электронного архива (см. приложение 2).
10.5. Дисплеи Nextion
К этому моменту мы уже рассмотрели подключение к Arduino различных дисплеев:
символьных, графических монохромных Nokia5110, а также современных OLED-
дисплеев. Однако чем сложнее дисплей, тем больше вычислительных ресурсов
платы Arduino он использует.
В этом плане весьма интересен дисплей Nextion, который представляет собой
полноценный компьютер с процессором, видеокартой и экраном, причем он выделяет
весь свой вычислительный ресурс на обработку графики и позволяет записывать
в него свои программы. На модулях дисплеев Nextion имеется разъем UART и
выводы GPIO, что дает возможность использовать дисплеи Nextion как совместно
с Arduino — подключая дисплей к Arduino по шине UART (обмен с помощью
унифицированных команд), так и отдельно— подключая кнопки, светодиоды, реле
и пр. напрямую к выводам GPIO дисплея). Через имеющийся у дисплея Nextion
разъем для карт памяти micro-SD в него можно загружать программы.
Для работы с дисплеями Nextion необходимо установить программу Nextion Editor,
которая позволяет создавать интерфейс пользователя с использованием различных
библиотечных элементов: кнопок, слайдеров, картинок, графики, текста и т. п.,
а также прописывать алгоритмы поведения дисплея для различных событий
элементов, формирующих этот интерфейс.
Скачать программу Nextion Editor можно со страницы загрузки официального
сайта: https://nextion.itead.cc/resources/download/. Версия там имеется только для
операционной системы Windows.
Итак, скачиваем, распаковываем, устанавливаем и запускаем программу Nextion
Editor. Перед нами откроется графическое окно разработки (рис. 10.17):
1. Главное меню.
2. Меню управления выравниванием и порядком элементов.
3. Библиотека элементов.
4. Область отображения.
5. Список страниц проекта.
6. Библиотека изображений/Библиотека шрифтов.
7. Окно вывода результатов компиляции.
8. Окно для ввода кода, выполняемого при возникновении события.
9. Зона редактирования атрибутов выбранного элемента.
198 Часть III. Практическое применение Arduino
Рис. 10.17. Элементы окна программы Nextion Editor
10.5.1. Создание нового проекта
для дисплея Nextion
Командой меню File | New создадим новый проект, введем название будущего
проекта и нажмем на кнопку Сохранить — откроется окно Setting с тремя вкладками:
Device, DISPLAY и project:
? на вкладке Device выберем линейку и модель дисплея (рис. 10.18);
? на вкладке DISPLAY — ориентацию дисплея и кодировку (рис. 10.19). Для
поддержки кириллицы необходимо выбрать кодировку iso-8859-5;
? на вкладке project можно установить пароль доступа к проекту.
Приступим теперь к добавлению элементов. Изначально в окне списка страниц
присутствует одна страница — page, название которой можно изменить. У каждого
элемента, а также у страницы, имеются свойства (атрибуты), которые также можно
изменять в окне редактирования атрибутов выбранного элемента.
Установим для страницы фон, предварительно добавив изображение в области 6
окна программы (библиотека изображений), нажав на кнопку +. Теперь можно
определить нужный фон, выбрав для страницы page атрибут sta, равный image,
и нужное изображение из списка в поле pic (рис. 10.20).
Затем добавим шрифты, которые наверняка пригодятся для надписей на экране.
Шрифты можно сгенерировать генератором шрифтов. Выполняем команду меню
Tools | Font Generator и в открывшемся окне выбираем параметры шрифта
(рис. 10.21), после чего сохраняем сделанный выбор, нажав на кнопку Generare
font.
Fnaea 10. Использование дисплеев в проектах Arduino 199
Рис. 10.18. Выбор модели дисплея
Рис. 10.19. Выбор ориентации дисплея и кодировки
200
Часть III. Практическое применение Arduino
Рис. 10.20. Добавление фона для страницы
Рис. 10.21. Генерация шрифта
Гпава 10. Использование дисплеев в проектах Arduino
201
Рис. 10.22. Шрифты проекта
Сгенерированный шрифт можно добавить в проект. Для этого в библиотеке
шрифтов нажимаем на кнопку + и указываем путь к шрифту. Теперь добавленный шрифт
можно использовать в проекте (рис. 10.22).
Электронный архив
Иллюстрации и шрифты, использованные в этом проекте, находятся в папке \examples\
10\пехИоп_10__1 сопровождающего книгу электронного архива (см. приложение 2).
Элементы интерфейса добавляются на экран из библиотеки элементов,
местоположение элемента на экране устанавливаем, перемещая его с помощью мыши, для
активного элемента редактируем его атрибуты (рис. 10.23).
Б
I - л,-
Рис. 10.23. Редактирование атрибутов элемента
202
Часть III. Практическое применение Arduino
Установив соответствующий флажок, задаем отправку команд выбранного события
для UART (Touch Press или Touch Release), в поле кода можно добавить код для
этого события (рис. 10.24).
Рис. 10.24. События для элемента
Перед прошивкой модуля необходимо проект скомпилировать, выполнив команду
меню Compile. Если ошибок нет, можно приступать к прошивке модуля.
Дисплеи Nextion поддерживают два вида прошивки:
? через последовательный порт UART;
? с помощью карты microSD.
10.5.2. Прошивка дисплея через UART
Для прошивки дисплея через UART понадобится адаптер USB-Serial. Схема
подключения Nextion к адаптеру USB-Serial показана на рис. 10.25.
Для загрузки прошивки выбираем пункт меню Upload и в открывшемся окне
нажимаем на кнопку Go. Процесс прошивки будет отображаться в окошке программы
(рис. 10.26) и на дисплейном модуле. По окончании прошивки загружаемый проект
начнет выполняться и отображаться на дисплейном модуле. Надо отметить, что
прошивка через UART занимает весьма долгое время.
Глава 10. Использование дисплеев в проектах Arduino
203
^4iM; '
Рис. 10.25. Схема подключения дисплея Nextion к адаптеру USB-Serial
Рис. 10.26. Загрузка прошивки в дисплей Nextion через последовательный порт
10.5.3. Прошивка дисплея с помощью карты microSD
Подключите к компьютеру карту microSD и скопируйте на нее файл с именем
проекта. Извлеките карту из компьютера и вставьте ее в соответствующий разъем
дисплея. Подключите на дисплей питание и дождитесь окончания прошивки.
Извлеките карту. После выполнения всех этих действий загружаемый проект начнет
выполняться и отображаться на дисплейном модуле.
10.5.4. Подключение дисплея Nextion к плате Arduino
Рассмотрим подключение дисплея Nextion к плате Arduino и организацию их
двустороннего взаимодействия. Взаимодействие это происходит по
последовательному порту. Монтажная схема подключения дисплея Nextion к плате Arduino
показана на рис. 10.27.
Для взаимодействия с дисплеем Nextion мы воспользуемся Arduino-библиотекой
Nextion. При этом со стороны Arduino задействуем программный
последовательный порт Software на пинах 2 (RX) и 3 (ТХ).
204 Часть III. Практическое применение Arduino
Рис. 10.27. Монтажная схема подключения дисплея Nextion к плате Arduino
Электронный архив
Библиотека Nextion размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
Содержимое скетча получения данных из дисплея Nextion при событиях Touch
Press и Touch Release созданной ранее прошивки для дисплея Nextion представлено
в листинге 10.6.
// подключение библиотеки для работы с Software Serial
#include <SoftwareSerial.h>
// подключение библиотеки для работы с Nextion
#include <Nextion.h>
// Nextion TX к пин 2, RX к пин 3 Arduino
SoftwareSerial nextionB, 3);
// создание объекта Nextion к порту на скорости 9600 бод
Nextion myNextion(nextion, 9600);
void setup() {
// запуск последовательного порта
Serial.begin(9600);
// инициализация Nextion
myNextion.init();
Глава 10. Использование дисплеев в проектах Arduino 205
void loop () {
// ожидание сообщения от Nextion
String message = myNextion.listen();
if (message != ""H
// при получении сообщения -
// вывести его в последовательный порт
Serial.println(message);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\10\_10_06
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем этот скетч в плату Arduino и видим в последовательном порту
подключение данных из Nextion при назначенных для элементов событиях Touch Press
и Touch Release (рис. 10.28).
Рис. 10.28. Получение данных от дисплея Nextion по последовательному порту
Разберем формат полученной строки:
65 0 2 1 ffff fffff fffff
Здесь:
? 65 — первый байт: произошло событие TouchEvent;
? о — номер страницы;
206 Часть III. Практическое применение Arduino
? 2 — номер элемента на странице;
? 1 — событие Touch Press @ — Touch Release).
Теперь рассмотрим отправку команд на дисплей Nextion (выбор страницы,
установка атрибутов элементов, переключение кнопок, получение атрибутов элементов
и пр.). В библиотеке Nextion имеются методы для отправки команд на дисплей
Nextion — например:
? sendcommand () — отправить команду;
? setComponentText () — установить текст компонента;
? buttononof f () — нажать/отжать кнопку;
? buttonToggie () — переключение переключателя;
? updateProgressBar () — изменить компонент ProgressBar;
? getcomponentText () — получить текст компонента.
Содержимое скетча отправки команд на дисплей Nextion представлено в
листинге 10.7.
// подключение библиотеки для работы с Software Serial
#include <SoftwareSerial.h>
// подключение библиотеки для работы с Nextion
#include <Nextion.h>
// Nextion TX к пин 2, RX к пин 3 Arduino
SoftwareSerial nextionBf 3);
// создание объекта Nextion к порту на скорости 9600 бод
Nextion myNextion(nextion, 9600);
// служебные переменные
char buf[10];
void setup() {
// запуск последовательного порта
Serial.begin(9600);
// инициализация Nextion
myNextion.init();
void loop() {
// изменение текста на компоненте t0
myNextion.setComponentText("tO", "Smartf4String(millis()));
delayB000);
// изменение размера кнопки ЬО
myNextion.sendCommand( "bO.font=l");
Глава 10. Использование дисплеев в проектах Arduino 207
delayB000);
myNextion.sendCommand( "ЬО.font=0");
delayB000);
// изменение позиции слайдера
String s="hO.val="+String(random@,100));
Serial.println(s);
s.toCharArray(buf, 10);
myNextion.sendCommand(buf);
delayB000);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\10\_10_07
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем скетч на плату Arduino и видим на дисплее изменение атрибутов
компонентов.
10.6. Светодиодные матрицы
Познакомимся с еще одним типом устройств, которые можно использовать для
визуализации проектов Arduino.
Если скомпоновать светодиоды не в виде цифры или шкалы, а в виде сетки, то
получится графический индикатор, на котором можно отобразить не только число,
но и какое-либо изображение. Такая сетка называется матричным индикатором,
а в случае использования светодиодов — светодиодной матрицей.
10.6.1. Четырехразрядная светодиодная матрица
Разрешение матричного индикатора — это количество точек по горизонтали и
вертикали. Самые распространенные индикаторы имеют разрешение 8x8 точек. Схема
соединений светодиодов в матрице показана на рис. 10.29.
Для создания изображения на такой матрице с использованием динамической
индикации необходимо задействовать 16 контактов Arduino! К счастью, разработаны
специализированные микросхемы для управления индикаторами— например,
МАХ721, которая позволяет управлять матрицей по трем проводам. Если требуется
светодиодная матрица с большим разрешением, то ее составляют из нескольких
индикаторов 8><8.
Монтажная схема подключения четырехразрядной светодиодной матрицы 4x8x8
показана на рис. 10.36. Для ее питания необходимо использовать внешний
источник 5 В.
При программировании матрицы мы подключим библиотеку Max72xxPanel.
Дополнительно надо установить и библиотеку Adafruit-GFX-Library, необходимую
для вывода на дисплей графических примитивов.
208
Часть III. Практическое применение Arduino
Rl
R2
R3
R4
R5
R6
R7
R8
а
С1 С2 СЗ С4 С5 С6 С7 С8
Рис. 10.29. Схема соединения светодиодов в матрице 8x8
Рис. 10.30. Монтажная схема подключения матрицы 4x8x8 к плате Arduino
Электронный архив
Библиотеки Max72xxPanel и Adafruit-GFX-Library размещены в каталоге libraries
сопровождающего книгу электронного архива (см. приложение 2).
Глава 10. Использование дисплеев в проектах Anduino 209
В листинге 10.8 представлен скетч для вывода точки и гашения точки на матрицу
в произвольные позиции:
? получаем произвольные позиции координат и зажигаем светодиоды:
matrix.drawPixei (x, у, HIGH);
? или гасим светодиод в матрице:
matrix.drawPixei(x, у, LOW);
О после включения и выключения пикселов с помощью функции drawPixei ()
необходимо вызвать функцию write ().
// подключение библиотек
tinclude <SPI.h>
iinclude <Adafruit__GFX.h>
iinclude <Max72xxPanel.h>
// пин CS
int pinCS = 10;
// количество матриц по горизонтали
int numberOfHorizontal = 4;
// количество матриц по вертикали
int numberOfVertical = 1;
// создание объекта
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontal, numberOfVertical);
// координаты х,у
int x, y;
void setup () {
// яркость от 0 до 15
matrix.setlntensity(8);
void loopO {
x=random@,32);
y=random@,8);
// зажигаем пиксел
matrix.drawPixei(x, y, HIGH);
// вывод всех пикселов на матрицы
matrix.write(); у
delayA0);
x=random@,32);
y=random@,8);
// гасим пиксел
matrix.drawPixei(xf y, LOW);
210 Часть III. Практическое применение Ardumo
// вывод всех пикселов на матрицы
matrix.write();
Загружаем скетч в плату и наблюдаем за меняющимся заполнением экрана.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\W\_10_08
сопровождающего книгу электронного архива (см. приложение 2).
10.6.2. Вывод на четырехразрядную
светодиодную матрицу спрайтов и символов
Попробуем вывести на экран маленькую картинку — спрайт. Для создания
изображения спрайта воспользуемся массивом из восьми байтов. Каждый байт
массива будет отвечать за строку матрицы, а каждый бит в байте — за точку в строке:
const byte spritel[8] = {
0В00111100,
0B01000010,
0B10100101,
0B10000001,
0B10100101,
0B10011001,
0B01000010,
0B00111100
};
Осталось загрузить в плату Arduino скетч из листинга 10.9 (попиксельный вывод
картинки из массива).
// подключение библиотек
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
// пин CS
int pinCS = 10;
// количество матриц по горизонтали
int numberOfHorizontal = 4;
// количество матриц по вертикали
int numberOfVertical = 1;
// создание объекта
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontal, numberOfVertical);
// изображение
const byte spritel[8] = {
ObOOllllOO,
ObOlOOOOlO,
Глава 10. Использование дисплеев в проектах Arduino 211
0Ы0100101,
0Ы0000001,
0Ы0100101,
0Ы0011001,
оьоюооою,
ObOOllllOO
void setup () {
// яркость от 0 до 15
matrix.setIntensityF);
// очистка экрана
matrix.fillScreen(LOW);
for ( int у = 0; у < 8; y++ ) {
for ( int x = 0; x < 8; x++ ) {
// зажигаем х-й пиксел в у-й строке
matrix.drawPixel (х, у, spritel[y] & A«х));
// вывод всех пикселов на матрицу
matrix.write();
void loop() {;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\1C\_10_09
сопровождающего книгу электронного архива (см. приложение 2).
После загрузки скетча на экране видим изображение, но оно повернуто на 90
градусов! А причина в том, что одноразрядные матрицы в нашей сборке стоят
неправильно (рис. 10.31).
Нас выручит имеющаяся в библиотеке Max72xxPanel функция setRotation (),
которая задает ориентацию изображения на матрице:
matrix.setRotation@,1);
Здесь первый параметр — это индекс матрицы, а второй — количество поворотов
на 90 градусов.
На матрицу можно вывести любой символ — например, букву или цифру. Для
этого необходимо для нужных символов создать соответствующие изображения.
К счастью, в библиотеке Adafruit-GFX-Library помимо функций для работы с
графикой и текстом имеется и база латинских букв в верхнем и нижнем регистрах,
а также все знаки препинания и прочие служебные символы. Символы имеют
размер 5x8. Отобразить символ на матрице можно с помощью функции drawchar ():
drawChar( х, у, символ, цвет, фон, размер);
212 Часть III. Практическое применение Arduino
Как должно быть
@,0)
Как в сборке
Рис. 10.31. Схемы соединения матриц
В листинге 10.10 приведен скетч вывода текста на нашу 4-разрядную
светодиодную матрицу.
// подключение библиотек
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
// пин CS
int pinCS =10;
// количество матриц по горизонтали
int nuinberOfHorizontal = 4;
// количество матриц по вертикали
int numberOfVertical = 1;
// создание объекта
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontal, numberOfVertical);
// текст для вывода
String text = "Ok95!";
void setup() {
// яркость от 0 до 15
matrix.setIntensityG);
void loopO {
// очистить экран
matrix.fillScreen(LOW);
Глава 10. Использование дисплеев в проектах Arduino
213
for ( int i = 0 ; i < text.length(); i++ ) {
// поворот на 90 градусов
matrix.setRotation( i, 1 );
// вывод символов
matrix.drawChar(i*6, 0, text[i], HIGH, LOW, 1);
}
// вывод на матрицу
matrix.write();
delayA000);
После загрузки скетча на экране видим текст!
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\iO\_1O__W
сопровождающего книгу электронного архива (см. приложение 2).
10.6.3. Бегущая строка
на четырехразрядной светодиодной матрице
Создадим на 4-разрядной светодиодной матрице «бегущую строку». Схема
соединений показана на рис. 10.32. Потенциометром мы воспользуемся для
регулирования скорости «бега».
I-5B
Рис. 10.32. Монтажная схема соединения для «бегущей строки»
на 4-разрядной светодиодной матрице
214 Часть III. Практическое применение Arduino
Приступим к написанию скетча (листинг 10.11):
? строка для вывода будет храниться в переменной text:
String text = "Arduino BHV ";
? размер матрицы по горизонтали — 32 позиции. Длина «бегущей строки» равна
длине строки, умноженной на 6 E — ширина символа + 1 интервал между
символами);
? переменная offset — координата начала строки. Начиная с этой координаты,
выводим символы на матрицу:
• крайнее левое положение:
offset=0-text.length() * 6;
• по достижении крайнего правого положения устанавливаем of f set=32;
? количество матриц по горизонтали берем с запасом, чтобы не происходило
сбоев с выводом:
int numberOfHorizontal = 15;
? скорость движения регулируем потенциометром.
// подключение библиотек
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
// пин CS
int pinCS = 10;
// количество матриц по горизонтали (берем с запасом! !!)
int numberOfHorizontal = 15;
// количество матриц по вертикали
int numberOfVertical = 1;
// создание объекта
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontal,
numberOfVertical);
// строка для вывода
String text = "Arduino BHV";
// текущее смещение от 0
int offset=32;
// максимальное значение скорости
int maxspeedl^lOO;
// минимальное значение скорости
int minspeedl=1000;
void setup() {
// яркость от 0 до 15
matrix.setIntensityG);
Глава 10. Использование дисплеев в проектах Arduino 215
void loop () {
// очистка экрана
matrix.fillScreen(LOW);
// вывод строки с позиции offset
for ( int i = 0 ; i < text.length(); i++ ) {
matrix.setRotation( i, 1 );
if(i*6+offset>(-6) && i*6+offset<32) {
matrix.drawChar(i*6+offset, 0, text[i], HIGH, LOW, 1);
matrix.write();
// задержка (скорость)
int speedl=(analogRead(АО),0,1023,minspeedl,maxspeedl);
delay(speedl);
// изменение смещения
offset=offset-1;
//в начало - позиция 32
if(offset+text.length()*6==0) {
offset=32;
Загружаем скетч на плату Arduino и наблюдаем «бегущую строку», скорость ее
«бега» регулируем потенциометром.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\W\_W_ii
сопровождающего книгу электронного архива (см. приложение 2).
10.6.4. Русификация «бегущей строки»
на четырехразрядной светодиодной матрице
В разд. 10.6.3 мы создали на 4-разрядной светодиодной матрице «бегущую
строку». Однако, если в эту строку вставить русские буквы, мы получим в ней крако-
зябры. Это происходит из-за того, что в графической библиотеке Adafruit_GFX нет
русского шрифта. Следовательно, его необходимо туда добавить. Для этого надо
заменить в файле glcdfont.c из библиотеки Adafruit GFX определенные символы на
русские в нужной кодировке.
Электронный архив
Напомню, что библиотека Adafruit GFX размещена в каталоге libraries
сопровождающего книгу электронного архива (см. приложение 2).
Однако и здесь есть проблема. Шрифт в файле glcdfont.c рассчитан на однобайтную
кодировку букв, a Arduino IDE использует для русских букв двухбайтовую UTF-8.
Тем не менее в русской кодировке UTF-8 прослеживается определенная законо-
216 Часть III. Практическое применение Arduino
мерность, которая позволяет сделать преобразование из UTF-8 в однобайтовую
русскую кодировку Windows-1251.
В листинге 10.12 показана функция utf8rus(), которая получает исходную строку,
символы с кодами ОхОО-Oxbf пропускает без изменения в выходную строку, а в
оставшихся кодах отбирает русские буквы и перекодирует их.
String utf8rus(String source)
{
int i,k;
String target;
unsigned char n;
char m[2] = { '01, f\0' };
k = source.length(); i = 0;
while (i < k) {
n = source[i]; i++;
if (n >= OxCO) {
switch (n) {
case OxDO: {
n = source[i]; i++;
if (n == 0x81) { n = 0xA8; break; }
if (n >= 0x90 && n <= OxBF) n = n + 0x2F;
break;
}
case OxDl: {
n = source[i]; i++;
if (n == 0x91) { n = 0xB8; break; }
if (n >= 0x80 && n <= 0x8F) n = n + 0x6F;
break;
m[0] = n; target = target + String(m);
}
return target;
Теперь скетч для «бегущей строки» на 4-разрядной светодиодной матрице примет
вид, приведенный в листинге 10.13.
// подключение библиотек
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
Глава 10. Использование дисплеев в проектах Arduino 217
II пин CS
int pinCS = 10;
// количество матриц по горизонтали
int numberOfHorizontal = 15;
// количество матриц по вертикали
int numberOfVertical = 1;
// создание объекта
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontal, numberOfVertical);
It строка для вывода
String text = "Ардуино проекты БХВ";
// текущее смещение от 0
int offset=32;
// максимальное значение скорости
int maxspeedl=100;
// минимальное значение скорости
int minspeedl=1000;
void setup () {
// яркость от 0 до 15
matrix.setIntensityG);
void loop () {
String textnew=utf8rus(text);
// очистка экрана
matrix.fillScreen(LOW);
// вывод строки с позиции offset
for ( int i = 0 ; i < textnew.length(); i++ ) {
matrix.setRotation( i, 1 );
if(i*6+offset>(-6) && i*6+offset<32) {
matrix.drawChar(i*6+offset, 0, textnew[i], HIGH, LOW, 1);
matrix.write();
// задержка (скорость)
int speedl=(analogRead(АО),0,1023,minspeedl,maxspeedl);
delay(speedl);
// изменение смещения
offset=offset-l;
//в начало - позиция 32
if(offset+text.length()*6==0)
offset=32;
String utf8rus(String source)
{
int i,k;
String target;
218 Часть III. Практическое применение Arduino
unsigned char n;
char m[2] = { fOf, f\Of };
к = source.length(); i = 0;
while (i < k) {
n = source[i]; i++;
if (n >= OxCO) {
switch (n) {
case OxDO: {
n = source[i]; i++;
if (n = 0x81) { n = 0xA8; break; }
if (n >= 0x90 && n <= OxBF) n = n + 0x2F;
break;
}
case OxDl: {
n = source[i]; i++;
if (n == 0x91) { n = 0xB8; break; }
if (n >= 0x80 && n <= 0x8F) n = n + 0x6F;
break;
m[0] = n; target = target + String(m);
}
return target;
Загружаем скетч в плату Arduino и наблюдаем русифицированную «бегущую
строку», скорость ее «бега » регулируем потенциометром.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\10\_10_i2
сопровождающего книгу электронного архива (см. приложение 2).
10.6.5. Матрица 16x16 на светодиодах WS2812
Матрица на светодиодах WS2812 представляет собой светодиодную ленту из
последовательно соединенных между собой 256 светодиодов, которые расположены
в виде матрицы 16x16. В чем отличие светодиодных лент WS2812 от других
светодиодных лент? Лента WS2812 состоит из адресных светодиодов, а каждый такой
светодиод состоит из RGB-светодиода и контроллера! Благодаря такой начинке
у нас есть возможность управлять цветом любого светодиода ленты и создавать
потрясающие эффекты.
Для управления светодиодами ленты используется специальный протокол. На вход
первого в цепочке светодиода WS2812 подается сигнал из прямоугольных импуль-
Глава 10. Использование дисплеев в проектах Arduino
219
сов частотой 400 или 800 КГц. Импульсы, в зависимости от скважности, кодируют
О или 1 для одного бита информации. Длинный E0 мс) низкий уровень
означает RESET или старт новой последовательности. Первая микросхема считывает
24 бита, в которых закодирован RGB-сигнал по трем каналам светодиодов, а
остальные импульсы пропускает на выходную шину. Следующие 24 бита достаются
второй микросхеме, и т. д. Всего каскадом может объединяться 1024 микросхемы,
информация в которых может обновляться 30 раз в секунду. Схема подключения
платы Arduino для управления лентой показана на рис. 10.33.
+5ВЗА
Рис. 10.33. Монтажная схема подключения ленты WS2812 к плате Arduino
При этом необходимо обратить внимание на следующие моменты:
0 цифровой вход ленты идет напрямую на вход микроконтроллера, поэтому
между ним и управляющим пином Arduino нужен токоограничиваюший резистор
с номиналом 200-500 Ом. Без него возможно выгорание первого светодиода
ленты;
Я если между лентой и контроллером (Arduino) большое расстояние, т. е.
соединяющие их провода длиннее 10-15 см, то сигнальный провод и «землю» нужно
скрутить для защиты от наводок. Поскольку протокол связи у ленты достаточно
скоростной (800 кГц), на него сильно влияют внешние наводки, а экранирование
«земляной» скруткой поможет этого избежать;
? питание — один светодиод при максимальной яркости потребляет ток 20 мА.
В одном светодиоде три цвета — итого 60 мА на диод. Вы вряд ли будете
зажигать на полную яркость белого цвета все светодиоды, но Ъ-А А матрица может
потреблять запросто.
220 Часть III. Практическое применение Arduino
10.6.6. Arduino-библиотека Adafruit Neopixel
Самые популярные библиотеки для работы с лентами WS2812: FastLED и Adafruit
NeoPixel. Библиотека FastLED поддерживает все версии Arduino и множество
протоколов передачи данных. Язык программирования, на котором она написана, —
чистый С.
Библиотека Adafruit NeoPixel разработки компании Adafruit работает медленнее,
обладает меньшими возможностями, но содержит в себе лишь самое нужное.
Написана она на С, языке ассемблера и немного на Wiring и поддерживает всю
линейку Arduino.
Воспользуемся для нашего следующего проекта — постепенного заполнения
матрицы одним цветом — библиотекой Adafruit NeoPixel. Итак, установим библиотеку
Adafruit NeoPixel и загрузим скетч (листинг 10.14).
Электронный архив
Библиотека Adafruit NeoPixel размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
// подключение библиотеки
#include <Adafruit_NeoPixel.h>
// пин подключения
#define PIN 6
// Parameter 1 = number of pixels in strip
Arduino pin number (most are valid)
pixel type flags, add together as needed:
800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
400 KHz (classic fvlf (not v2) FLORA pixels, WS2811 drivers)
Pixels are wired for GRB bitstream (most NeoPixel products)
Pixels are wired for RGB bitstream (vl FLORA pixels, not v2)
AdafruitJSIeoPixel strip = Adafruit_NeoPixel B56, PIN, NEO_GRB + NEO_KHZ800) ;
// цвета
int colors[6][3]-{{150,0,0},{150,150,0},
{0,150,0},{0,150,150},
{0,0,150},{150,0,150},
};
// текущий цвет
int color=0;
void setup() {
Serial.begin(9600);
strip.begin();
strip, show();
//
//
//
//
//
//
Parameter 2
Parameter 3
NEO_
NEO_
NEO_
NEO
KHZ800
KHZ400
_GRB
RGB
Глава 10. Использование дисплеев в проектах Arduino 221
void loop () {
// заполнение цветом с 0 по 255 светодиод
for (int i = 0; i < 256; i++){
strip.setPixelColor(i,colors[color][0],colors[color][1],colors[color][2]);
// вывести на ленту
strip.show();
// задержка
delayE0) ;
}
// стирание цвета
for (int i = 255; i >=0; i—) {
strip.setPixelColor(i,0,0,0);
// вывести на ленту
strip.show();
// задержка
delayE0);
}
// выбираем другой цвет
color=(color+1)% б;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\10\_i0_13
сопровождающего книгу электронного архива (см. приложение 2).
10.6.7. Графический аудиоспектроанализатор
на матрице 16x16 светодиодов WS2812
Создадим на плате Arduino и семиполосном фильтре MSGEQ7 для графического
эквалайзера проект аудиоспектроанализатора с визуализацией на матрице 16x16
светодиодов WS2812. Восьмивыводной чип MSGEQ7 способен из входного
аудиосигнала выделить частотные полосы 63, 160, 400 Гц; 1, 2,5, 6,25 и 16 кГц
(рис. 10.34).
Управляется фильтр MSGEQ7 по двум цифровым входам: Reset и Strobe. После
стартового импульса Reset достаточно подать семь стробирующих импульсов на
линию Strobe, и в результате после каждого стробирующего импульса на выходе
чостотноя хороктеристико
63 №0 400 Ю00 2500 6250 16000
Рис. 10.34. Частотная харрактеристика MSGEQ7 — семиполосный эквалайзер
222
Часть III. Практическое применение Arduino
set 1
RESET
«J j _n игигигитл_ги
STROBE
OUTPUT
63 Hz 160 Hz 400 Hz 1kHz 2.5 kHz 6.25 kHz 16kHz 63 Hz 160 Hz
Рис. 10.35. Диафамма длительности импульсов микросхеммы MSGEQ7
Out будет появляться напряжение, пропорциональное содержанию одной из семи
частотных полос в аудиосигнале (рис^ 10.35).
Монтажная схема соединений для графического аудиоспектроанализатора показана
на рис. 10.36.
5В4А
1 1
1\
J
lOOnF
Рис. 10.36. Монтажная схема соединений для фафического аудиоспектроанализатора
Глава 10. Использование дисплеев в проектах Arduino 223^
Приступим к написанию скетча. Уровень сигнала для 7 частот будем собирать
в массиве arri [7], предварительно масштабируя для диапазона 0-16. После
получения значений выводим данные на ленту (колонки 1-15, по 2 колонки на одну
частоту). При этом цвет пиксела зависит от уровня сигнала (зеленый, желтый,
красный). Содержимое скетча показано в листинге 10.15.
// подключение библиотеки
#include <Adafruit_NeoPixel. h>
// пин подключения ленты
tdefine PIN 6
Adafruit_NeoPixel strip = AdafruitJNeoPixelB56, PIN, NEO_GRB + NEOJKHZ800);
// цвета для разных уровней
int colors[16] [3]={{0,200, 0}, {0,200,0},
{0,150,0},{0,150,0},
{150,150,0},{150,150,0},
{200,200,0},{200,200,0},
{150,0,0},{150,0,0},
{150,0,0},{150,0,0},
{200,0,0},{200,0,0},
{200,0,0},{200,0,0}
tdefine msg7RESET 12
idefine msg7Strobe 11
idefine msg7DCout 0
int arrl[7] = {0,0,0,0,0,0,Ob-
void setup () {
Serial.begin(9600) ;
pinMode(msg7RESET, OUTPUT);
pinMode(msg7Strobe, OUTPUT);
strip.begin();
strip.show();
void loopO {
// осуществляем сброс MSGEQ7
digitalWrite(msg7RESET, HIGH);
delayMicrosecondsA);
digitalWrite(msg7RESET, LOW);
delayMicrosecondsG2);
224 Часть III. Практическое применение Arduino
// семь частот - семь стробирующих импульсов
for (int x = 0; х < 7; х++){
digitalWrite(msg7Strobe, LOW);
// ждем установления значения 36 мкс
delayMicrosecondsC6);
// считываем значение с аналогового входа
// преобразовываем диапазон 0-1024 к диапазону 0-16
arrl[x] = map(analogRead(AO), 5, 1023, 0, 16);
setVals(x,arrl[x]);
delayMicrosecondsA600);
digitalWrite(msg7Strobe, HIGH);
delayMicroseconds C6);
}
// вывести на ленту
strip.show();
//в последовательный порт для контроля
for(int i=0;i<7;i++)
{Serial.print(" ")/Serial.print(arrl[i]);}
Serial.println();
//// вывести пикселы для 1 частоты B колонки)
// колонки 2-15
void setVals(int i,int valuel)
{
for(int j=0;j<16;j++)
{
if(valuel>=j)
{
strip.setPixelColor(A5-j)+(i*2+2)*16, colors[j][0],colors!j][1],
colors[j][2]);
strip.setPixelColor(j+(i*2+l)*16,colors[j][0],colors[j][1],
colors[j][2]);
}
else // без цвета
{
strip.setPixelColor(A5-j)+(i*2+2)*16,0,0,0);
strip.setPixelColor(j+(i*2+l)*16, 0,0,0);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\W\_W_14
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 11
Подключение к Arduino
исполнительных устройств
Исполнительные устройства — это элементы автоматики, создающие
управляющее воздействие на объект управления. Они изменяют положение или состояние
регулирующего органа объекта управления таким образом, чтобы управляемый
параметр соответствовал заданному значению. Исполнительное устройство или
механизм (actuator) преобразует электрическую энергию в механическую или в
физическую величину для воздействия на управляемый процесс.
Это могут быть световые и звуковые устройства, электромагнитные клапаны,
моторы постоянного (DC) или переменного (АС) тока, сервоприводы, релейные
системы и многое другое.
Рассмотрим работу Arduino с некоторыми исполнительными устройствами на
примерах.
11.1. Подключение к плате Arduino
электромагнитного или твердотельного реле
Реле— электрическое или электронное устройство (ключ), предназначенное для
замыкания и размыкания различных участков электрических цепей. Изобрели
собственно реле в далеком 1831 г. А уже в 1837 г. американский изобретатель Сэмюэл
Морзе создал основанный на реле электромагнитный телеграфный аппарат.
Сегодня реле широко используются практически во всех областях техники, существует
огромное количество самых разнообразных их видов.
Наиболее распространенными являются электромагнитные реле.
Электромагнитное реле — электромеханическое устройство, замыкающее и (или) размыкающее
механические электрические контакты при подаче в обмотку реле электрического
тока, порождающего магнитное поле, которое вызывает перемещение
ферромагнитного якоря реле, связанного механически с контактами, и последующее
перемещение контактов коммутирует внешнюю электрическую цепь.
Рассмотрим устройство реле на примере широко используемого совместно с
платами Arduino реле фирмы SONGLE SRD-05VDC (рис. 11.1). Это реле управляется
226 • Часть III. Практическое применение Arduino
напряжением 5 В и способно коммутировать постоянные токи до 10 А при
напряжении 30 В и переменные токи до 10 А при напряжении 250 В.
Реле имеет две раздельные цепи: цепь управления, представленную контактами А1
и А2, и управляемую цепь с контактами 1, 2 и 3 (рис. 11.2). Эти цепи электрически
никак между собой не связаны. При протекании тока по обмотке катушки,
включенной между контактами А1 и А2, металлический сердечник, размещенный
внутри этой обмотки, намагничивается, и к нему притягивается подвижный якорь,
соединенный с контактом 2. Контакты 1 и 3 неподвижны. Стоит отметить, что якорь
подпружинен, и пока мы не пропустим ток через обмотку сердечника, якорь будет
удерживаться прижатым к контакту 1. При подаче тока сердечник, как уже
говорилось, превращается в электромагнит и притягивает якорь к контакту 3. При обесто-
чивании пружина снова возвращает якорь к контакту 1.
Рис. 11.1. Электромагнитное реле SRD-05VDC
АД! 3l J1
А2| |2
Рис. 11.2. Схема электромагнитного реле SRD-05VDC
С подключением реле к плате Arduino связана проблема — вывод платы не может
обеспечить мощность, необходимую для нормальной работы катушки реле.
Поэтому необходимо усилить ток — для чего следует включить в схему транзистор. Для
усиления тока удобнее применять и-/?-и-транзистор, включенный по схеме с общим
эмиттером (ОЭ), — как показано на рис. 11.3. При таком способе можно
подключать нагрузку с напряжением питания большим, чем питание микроконтроллера.
Резистор на базе транзистора— ограничительный, его номинал может
варьироваться в широких пределах A-10 кОм),— в любом случае транзистор будет
работать в режиме насыщения. Транзистор можно взять любой, лишь бы он был
и-р-и-тйпа. Коэффициент его усиления практически не имеет значения. Выбирается
транзистор по току коллектора (нужный нам ток) и напряжению «коллектор —
эмиттер» (напряжение, которым запитывается нагрузка). Я, как правило, использую
транзисторы С945.
Для включения реле, подключенного по схеме с ОЭ, на вывод Arduino необходимо
подать 1, для выключения — 0 (листинг 11.1).
Глава 11. Подключение к Arduino исполнительных устройств
227
1.5 кОт
п
f
#12 V
ЙИМ1
к Arduino
НРН. (С945, С458
или )
Рис. 11.3. Схема подключения электромагнитного реле к плате Arduino (р-канальное управление)
int relayPin =10;
void setup ()
// подключение Arduino к выводу D10
pinMode(relayPin, OUTPUT); // настроить вывод как выход (OUTPUT)
// the loop function runs over and over again forever
void loop() -
{
digitalWrite(relayPin, HIGH); // включить реле
delayE000);
digitalWrite(relayPin, LOW); // выключить реле
delayE000);
Дпя подключения к плате Arduino можно использовать готовые модули,
содержащие сразу несколько реле с необходимой обвязкой (рис. 11.4). Но в таких модулях
обычно применяется я-канальное управление (рис. 11.5). При таком управлении
i реле включается цодачей на вывод Arduino низкого уровня.
! Твердотельные реле (Solid State Relay, SSR) применяются в промышленном обору-
I довании— там, где нужна большая надежность и малые габариты (рис. 11.6). Во
всех твердотельных оптоэлектронных реле коммутация цепей нагрузки
осуществляется бесконтактно— за счет управления встроенными полупроводниковыми
элементами. Как правило, это тиристоры или симисторы (для коммутации пере-
228
Часть III. Практическое применение Arduim
Рис. 11.4. Модуль из 4 реле
5V
signal
Рис. 11.5. Схема подключения электромагнитного реле к плате Arduino (п-канальное управление)
Рис. 11.6. Твердотельное реле
Глава 11. Подключение к Arduino исполнительных устройств 229
менного тока) и транзисторы (для коммутации постоянного тока). Такой способ
управления дает ряд преимуществ перед обычными электромагнитными реле.
Так же как и в обычных реле, в твердотельных существует гальваническая развязка
между напряжением катушки и напряжением на силовых контактах. Только в
электромеханических реле это достигается за счет разнесения катушки и силовых
контактов в пространстве, а в твердотельных — за счет использования оптрона,
обеспечивающего оптическую развязку.
Твердотельные реле при работе потребляют и теряют гораздо меньше энергии,
имеют меньшие габариты, высокое быстродействие, гораздо более длительный
срок службы — и все этоабсолютно бесшумно! Но есть у них и минусы — высокая
цена.
Для подключения твердотельного реле к плате Arduino минусовой контакт
управляющей сети подсоединяется к «земле», а плюсовой— к цифровому выводу
Arduino. Выходного тока контакта Arduino для срабатывания твердотельного реле
вполне достаточно.
К реле можно подключить лампочку, вентилятор или, например, электромагнитный
клапан для полива растений в теплице и программно управлять этими
устройствами изменением состояния на цифровых выводах Arduino.
11.2. Подключение к плате Arduino
электродвигателя постоянного тока
11.2.1. Управление двигателем с помощью транзистора
Электродвигатели постоянного тока применяются в роботах на колесных или
гусеничных платформах. И начнем мы с самого простого способа управления ими —
с помощью транзистора.
Выводы Arduino, сконфигурированные как output, находятся в низкоимпедансном
состоянии, могут отдавать в нагрузку 40 мА и не в состоянии обеспечить питание
мощной нагрузки и большого напряжения. Одним из способов управления мощной
нагрузкой является использование полевых MOSFET-транзисторов. MOSFET-
транзистор — это ключ для управления большими токами при помощи небольшого
напряжения (в отличие от биполярных транзисторов, управляемых током).
Рассмотрим управление с выхода Arduino мощной нагрузкой—
электродвигателем — с помощью MOSFET-транзистора. Для этого проекта нам понадобятся
следующие компоненты:
0 плата Arduino Uno;
0 кабель USB;
? плата прототипирования;
а транзистор MOSFETIRF540;
0 диод 1N4007;
230
Часть III. Практическое применение Arduino
П потенциометр 10 кОм;
? электродвигатель постоянного тока (DC) с редуктором;
? блок питания 5 В 2 А;
? соединительные провода разных типов (согласно схеме).
В представленной на рис. 11.7 монтажной схеме этого проекта для управления
скоростью двигателя с платы Arduino мы воспользуемся ШИМ, обеспечивающей
получение изменяющегося аналогового значения напряжения соответствующей
обработкой цифровых сигналов. Регулирование скорости двигателя будет
осуществляться с помощью потенциометра.
1
Рис. 11.7. Монтажная схема подключения электродвигателя к плате Arduino
При наличии в схеме индуктивной нагрузки (электродвигатель, электромагнитный
клапан и т. п.) рекомендуется защищать MOSFET-транзистор от напряжения
самоиндукции с помощью защитного диода. Управление электродвигателем при
помощи ШИМ без защитного диода может вызвать такие проблемы, как нагрев
транзистора или его полный выход из строя, замедление вращения двигателя, потеря
мощности и пр. Если же нагрузка в схеме активная: светодиод, галогенная лампа,
нагревательный элемент и т. п., то защитный диод не обязателен.
Содержимое скетча управления скоростью электродвигателя с платы Arduino
показано в листинге 11.2. Загружаем этот скетч в плату Arduino и поворотом ручки
потенциометра изменяем скорость вращения двигателя.
Гпава 11. Подключение к Arduino исполнительных устройств 231
II Выход для подключения MOSFET
const int MOTOR=9;
// Аналоговый вход АО для подключения потенциометра
const int POT=0;
// переменная для хранения значения потенциометра
int valpot = 0;
// переменная для хранения скорости двигателя
mt speedMotor = 0;
void setup () {
// выход управления двигателем как OUTPUT
pinMode(MOTOR,OUTPUT);
}
void loopO {
// чтение данных потенциометра
valpot = analogRead(POT);
// масштабируем значение к интервалу 0-255
speedMotor=map(valpot,0,1023,0,255);
// устанавливаем новое значение ШИМ
analogWrite(MOTOR,speedMotor);
// пауза
delayA00);
}
Электронный архив
Полный вариант рассмотренного скетча находится в папке examplesW1\J\1_O2
сопровождающего книгу электронного архива (см. приложение 2).
11.3. Управление двигателями
с помощью драйвера
Для управления электродвигателями с платы Arduino разработаны
специализированные микросхемы— так называемые драйверы двигателей. Наиболее
распространенным в среде пользователей Arduino является модуль драйвера L298 (рис. 11.8),
Рис. 11.8. Модуль
драйвера L298
232
Часть III. Практическое применение Arduino
который позволяет управлять двумя двигателями постоянного тока и обеспечивает
максимальную нагрузку до 2 А на каждый двигатель. Напряжение питания
двигателей при этом может находиться в диапазоне от 5 до 35 В.
Чередованием разноименных сигналов (высокий логический уровень или низкий)
на парах выводов IN1-IN2 и IN3-IN4 задается направление вращения двигателей
Выводы ENA (привязан к IN1 и IN2) и ENB (привязан к IN3 и IN4) отвечают за
раздельное управление каналами. Для регулировки скорости двигателей на выводы
ENA и ENB подается ШИМ-сигнал.
В представленной на рис. 11.9 монтажной схеме проекта управления двумя
двигателями с помощью модуля драйвера двигателей L298N направление вращения
каждого двигателя и его скорость регулируются потенциометрами: первый
потенциометр устанавливает направление движения и скорость для первого двигателя,
второй— для второго. Среднее положение потенциометров— нулевая скорость.
Осуществляется это следующим программным блоком:
// чтение данных потенциометра
valpotl = analogRead(POTl);
// масштабируем значение к интервалу -255 - 255
speedMotorl=map(valpotl,0,1023,-255,255);
if(speedMotorl<512) {
digitalWrite(INI,HIGH);
digitalWrite(IN2,LOW);
}
else {
digitalWrite(INI, LOW);
digitalWrite(IN2 HIGH,);
}
analogWrite(ENA,speedMotorl);
Рис. 11.9. Монтажная схема подключения электродвигателей к плате Arduino
с помощью модуля драйвера двигателей L298N
Fnaea 11. Подключение к Arduino исполнительных устройств 233
Содержимое скетча для управления скоростью двигателей с платы Arduino
показано в листинге 11.3. Загружаем этот скетч в плату Arduino и поворотами ручек
потенциометров изменяем скорость и направление вращения для каждого двигателя.
Что любопытно — два двигателя как раз и позволяют создать движущуюся
платформу.
// Контакты подключения к модулю драйвера L298
const int ENA=10;
const int IN1=9;
const int IN2=8;
const int ENB=5;
const int IN3=7;
const int IN4=6;
// Аналоговые входы для подключения потенциометров
const int POT1=0;
const int POT2=1;
// переменные для хранения значений потенциометров
int valpotl = 0;
int valpot2 = 0;
// переменные для хранения скоростей двигателей
int speedMotorl = 0;
int speedMotor2 = 0;
void setup () {
// выходы как OUTPUT
pinMode(ENA,OUTPUT);
pinMode(INI,OUTPUT);
pinMode(IN2,OUTPUT);
pinMode(ENB,OUTPUT);
pinMode(IN3,OUTPUT);
pinMode(IN4,OUTPUT);
void loop() {
// чтение данных потенциометра 1
valpotl = analogRead(POTl);
// масштабируем значение к интервалу -255 - 255
speedMotorl=map (valpotl, 0,1023, -255,255) ;
if(speedMotorl<512) {
digitalWrite(INI,HIGH);
digitalWrite(IN2,LOW);
}
else {
digitalWrite(INI, LOW);
234 Часть III. Практическое применение Arduina
digitalWrite(IN2 HIGH,);
}
// чтение данных потенциометра 2
valpotl = analogRead(POT2);
// масштабируем значение к интервалу -255 - 255
speedMotor2=roap(valpot2,0,1023,-255, 255);
if(speedMotor2<512) {
digitalWrite(IN3,HIGH);
digitalWrite(IN4,LOW);
}
else {
digitalWrite(IN3, LOW);
digitalWrite(IN4 HIGH,);
}
analogWrite(ENB,speedMotor2);
// пауза
delayA00);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\11\_11_03
сопровождающего книгу электронного архива (см. приложение 2).
11.4. Подключение к плате Arduino
сервопривода
Сервопривод это устройство, которое обеспечивает преобразование сигнала
в строго соответствующее этому сигналу перемещение (поворот) исполнительного
устройства. Представляет он собой прямоугольную коробку с мотором, схемой и
редуктором внутри, а также выходным валом, который должен поворачиваться на
строго фиксированный угол, определяемый входным сигналом. Существует очень
много видов сервоприводов, которые различаются габаритами, материалом
шестеренок (пластмасса, металл), способом управления (аналоговые и цифровые),
скоростью вращения вала, крутящим моментом, диапазоном поворота A20, 180°,
непрерывного вращения) и пр.
Сервопривод управляется с помощью импульсов переменной длительности — угол
поворота его выходного вала определяется длительностью импульса, подаваемого
по сигнальному проводу (как можно видеть, широтно-импульсная модуляция
задействована и здесь). Сервопривод ожидает импульса каждые 20 мс. Длительность
импульса определяет, в какое положение должен повернуться вал. Например,
импульс в 1,5 мс диктует приводу поворот в положение 90° (нейтральное положение).
Когда сервопривод получает команду на перемещение, его управляющий орган
перемещается в это положение и удерживает его. Если внешняя сила действует на
сервопривод, когда он удерживает заданное положение, сервопривод будет сопро-
Fnaea 11. Подключение к Arduino исполнительных устройств
235
тивляться перемещению из этого положения. Максимальная величина силы,
которую может выдерживать сервопривод, характеризует вращающий момент
сервопривода. Однако сервопривод не навсегда удерживает свое положение — импульсы
позиционирования должны повторяться, информируя сервопривод о сохранении
положения.
Рис. 11.10. Комплект сервопривода MG995
Рассмотрим подключение к плате Arduino популярного сервопривода MG995
(рис. 11.10). Для этого нам понадобятся три провода (рис. 11.11):
? красный провод— питание (внешний стабилизированный источник питания
4,8-7,2 В);
? черный провод — к выводу Arduino GND;
О синий — сигнальный, подключается к цифровому ШИМ-выводу платы Arduino.
Для управления сервоприводами с помощью Arduino в Arduino ГОЕ имеется
стандартная библиотека Servo, поддерживающая функции для установки настроек
сервопривода — необходимого угла поворота и считывания состояния.
В листинге 11.4 представлен скетч вращения сервопривода от 0 до 120° с шагом 1°,
а затем в обратную сторону. После загрузки этого скетча в плату Arduino вал
сервопривода медленно вращается сначала в одну, затем в другую сторону.
// подключение библиотеки Servo
^include <Servo.h>
// создать объект servo
Servo servol;
236 Часть III. Практическое применение Arduino
// пин для подключения сервопривода
const int pin_servo=9;
// макс, значение угла поворота
const int angle_max=120;
// для хранения текущей позиции сервопривода
int angle = 0;
// для хранения направления 1 или -1
dir=l;
void setup() {
// подключить управление сервоприводом к пину pin_servo
servol.attach(pin_servo);
void loop() {
for(;;) {
// команда установки положения сервопривода
servol.write(angle);
// время на перемещение сервопривода
delayA5);
//
if(angle==0)
dir=l;
else if (angle=angle_max)
dir=-l;
angle=angle+dir;
4.8 - 7.2 В
Рис. 11.11. Монтажная схема подключения сервопривода к плате Arduino
Fnaea 11. Подключение KArduino исполнительных устройств 237^
11.4.1. Использование сервопривода
в проекте звуковой сигнализации
Сервоприводы очень часто применяются в робототехнике, где вообще характерно
использование различных двигателей, сервоприводов и датчиков, и здесь мы
рассмотрим, как с помощью сервопривода можно оснастить робота звуковой
сигнализацией о наличии препятствий на пути его движения.
Датчик расстояния — модуль НС SR-04 — находится на вращающейся в
горизонтальной плоскости платформе робота (вращение платформы как раз и
осуществляется с помощью сервопривода) и измеряет расстояние до преграды. При
обнаружении объекта, находящегося на расстоянии менее 1 м от модуля, платформа
останавливается и подает звуковой сигнал на динамик до тех пор, пока объект не удалится
на большее расстояние.
Для этого проекта (рис. 11.12) нам понадобятся следующие компоненты:
? плата Arduino Uno;
О ультразвуковой модуль НС SR-04;
? сервопривод;
CJ платформа для крепления сервопривода и модуля НС SR-04;
О динамик 8 Ом;
? резистор 500 Ом;
? транзистор КТ503е;
? источник внешнего питания 5 В (для питания сервопривода);
? соединительные провода.
Рис. 11.12. Монтажная схема подключения к плате Arduino сервопривода,
ультразвукового модуля НС SR-04 и динамика
238 Часть III. Практическое применение Arduim
Содержимое скетча, обеспечивающего работу этого проекта, показано в
листинге 11.5. Сервопривод вращает платформу с датчиком от 0 до 180° и обратно. На
каждом шаге система проверяет показания модуля расстояния НС SR-04. Если
объект нарушает границу (значение distdetect, равное 100 см), на динамик подается
звуковой сигнал:
tone (PIN_SPEAKER, FREQ) ;
Далее система ждет, пока объект не выйдет из «зоны поражения», после чего
отключает динамик и продолжает вращение платформы.
// константы для выводов
#define PIN_TRIG 12
#define PIN_ECHO 13
#define PIN_SERVO 9
#define PIN_SPEAKER 8
// расстояние обнаружения, см
#define DISTJDETECT 100
// частота звукового сигнала
tdefine FREQ 546
// подключение библиотеки для НС SR04
#include "Ultrasonic.h"
// создание объекта Ultrasonic
// Trig - 12, Echo - 13
Ultrasonic ultrasonic(PINJTRIG, PIN_ECHO);
// переменная для хранения измеренного расстояния
float dist_cm=0;
// подключение библиотеки для серво
#include <Servo.h>
// создание объекта Servo
Servo myservo;
// переменная для хранения позиции сервопривода
int pos =0;
// переменная направления перемещения сервопривода
int dir=l;
void setup() {
// запуск последовательного порта
Serial.begin(9600);
// запуск серво на выходе PIN_SERVO
myservo.attach(PINJSERVO);
void loop() {
// вычисление следующей позиции сервопривода
pos=pos+dir;
Глава 11. Подключение KArduino исполнительных устройств 239
II установить сервопривод в позицию pos
myservo.write(pos);
// при достижении крайних позиций изменить
// направление dir
if(pos==180)
dir=-l;
else if(pos==0)
else ;
// получить данные с дальномера
dist_cm = ultrasonic.Ranging(CM);
Serial.printIn(dist_cm);
hi обнаружение объекта в зоне
if (dist_cm>0 && dist_cm<DIST_DETECT) {
// звуковой сигнал
tone(PIN_SPEAKERf FREQ);
}
// пока в зоне обнаружения
while (dist_cm>0 && dist_cm<DIST_DETECT)
{
dist_cm = ultrasonic.Ranging(CM);
Serial.printIn(dist_cm);
}
// отключить звуковой сигнал
noTone (PINJSPEAKER) ;
// пауза перед сменой позиции сервопривода
delayE0);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\1i\_11JM
сопровождающего книгу электронного архива (см. приложение 2).
11.5. Подключение к плате Arduino
шагового двигателя
Шаговые двигатели представляют собой электромеханические устройстэа, задачей
которых является преобразование электрических импульсов в перемещение вала
двигателя на определенный угол.
Достоинствами шаговых двигателей по сравнению с обычными являются:
? высокая точность позиционирования и повторяемости — качественные шаговые
двигатели имеют точность не хуже 2,5% от величины шага, при этом ошибка не
накапливается при последующих шагах;
? шаговый двигатель может быстро стартовать, останавливаться и выполнять
реверс;
240 Часть III. Практическое применение Arduino
П четкая взаимосвязь угла поворота ротора от количества входных импульсов
(в штатных режимах работы) позволяет выполнять позиционирование без
применения обратной связи;
? шаговые двигатели обеспечивают получение сверхнизких скоростей вращения
вала без использования редуктора;
? шаговые двигатели работают в широком диапазоне скоростей, поскольку
скорость напрямую зависит от количества входных импульсов.
Шаговые двигатели применяются там, где требуется высокая точность
перемещений,— например, в принтерах, факсах и копировальных машинах, в станках
с ЧПУ, в ЗО-принтерах.
Минимально возможный угол перемещения шагового двигателя называется шагом,
Управление шаговым двигателем сводится к задаче отработать определенное число
шагов в нужном направлении и с нужной скоростью.
Для управления шаговыми двигателями используют специальные устройства —
драйверы шаговых двигателей.
Популярный драйвер шагового двигателя А4988 (рис. 11.13) работает от
напряжения 8-35 В и может обеспечить ток до 1 А на фазу без радиатора (и до 2 А с
радиатором). Он имеет защиту от перегрузки и перегрева. Одним из параметров шаговых
двигателей является количество шагов на один полный оборот C60°). Например,
для шаговых двигателей Nema 17 (рис. 11.14)— это 200 шагов на оборот, т.е.
1 шаг равен 1,8°. Драйвер А4988 позволяет увеличить это значение за счет
управления промежуточными шагами и имеет пять режимов микрошага: 1 (полный), V2,
74, V8 и Лб шага.
Назначение контактов (выводов) драйвера А4988 приведено на рис. 11.15:
? ENABLE — включение/выключение драйвера;
? MSI, MS2, MS3 — контакты для установки микрошага;
Рис. 11.13. Драйвер шаговых двигателей А4988 Рис. 11.14. Шаговый двигатель Nema 17
Глава 11. Подключение кАгди'то исполнительных устройств
241
О RESET — сброс микросхемы;
? STEP— генерация импульсов для движения двигателей (каждый импульс —
шаг), с его помощью можно регулировать скорость двигателя;
? DIR — установка направления вращения;
? VMOT — питание для двигателя (8-35 В);
? GND — общий;
? 2В, 2 А, 1 А, 1В — подключение обмоток двигателя;
? VDD — питание микросхемы C,5-5 В).
А4988
3LE
MS1
MS2
MS3
С RESET
SLEEP
—*STEP
Рис. 11.15. Выводы драйвера А4988
Значение микрошага устанавливается комбинацией сигналов на входах MSI, MS2
и MS3. Есть пять вариантов дробления шага (табл. 11.1).
MS1
0
1
0
1
1
Таблица 11.1
MS2
0
0
1
1
1
. Комбинация значений для выбора микрошага
MS3
0
0
0
0
1
Дробление шага
1
1/2
1/4
1/8
1/16
Для работы в режиме микрошага необходим слабый ток. На модуле А4988
ограничение тока осуществляется с помощью находящегося на плате потенциометра.
Драйвер очень чувствителен к скачкам напряжения по питанию двигателя, поэтому
производитель рекомендует устанавливать для сглаживания таких скачков
электролитический конденсатор большой емкости. Имейте также в виду, что
подключение или отключение шагового двигателя при включенном драйвере может
привести к выходу двигателя из строя.
242
Часть III. Практическое применение Arduino
11.5.1. Управление дроблением шага
и направлением вращения шагового двигателя
с платы Arduino
Создадим проект управления дроблением шага и направлением вращения шагового
двигателя с платы Arduino. Для этого нам понадобятся следующие компоненты:
? плата Arduino Uno;
? драйвер А4988;
? шаговый двигатель Nema 17;
? потенциометр 10 кОм;
? кнопка;
? переключатель 2-позиционный;
? резистор 10 кОм — 3 шт.;
? провода разных типов (согласно схеме).
Монтажная схема этого проекта представлена на рис. 11.16.
Рис. 11.16. Монтажная схема подключения компонентов для управления дроблением шага
и направлением вращения шагового двигателя
Содержимое скетча, обеспечивающего работу этого проекта, показано в
листинге 11.6. Нажатие на кнопку включает/выключает двигатель подачей сигнала
low/high на вход ENABLE драйвера А4988. С помощью переключателя мы
выбираем направление вращения двигателя (сигнал с переключателя подается напрямую
Глава 11. Подключение к Arduino исполнительных устройств 243
на вход DIR драйвера А4988), а с помощью потенциометра — один из режимов
микрошага: 1, V2, V4, V8, Vi6.
// пины для подключения контактов STEP, DIR
const int STEP 3
int DIR 2
// для регулировки скорости - пин потенциометра
tdefine POT АО
// для кнопки
tdefine BUTTON 9
// для включения/выключения
fdefine EN 8
// количество шагов на 1 оборот
idefine ROUND 200
// скорость двигателя
tdefine SPEED 10
// массив пинов для MS1,MS2,MS3
int pins_steps[]={7,6,5};
int steps[5][3]={"
{0,0,0}, // 1
{1,0,0}, // 1/2
{0,1,0}, // 1/4
{1,1,0}, // 1/8
{1,1,1} // 1/16
// для кнопки
int prevB=0;
int tekB=0;
boolean movement=false;
void setup() {
// режим для выводов STEP и DIR как
pinModeSTEP, OUTPUT);
pinMode(DIR, OUTPUT);
// начальные значения
digitalWrite(STEP, 1);
digitalWrite(DIR, 0);
// режим для enable
pinMode(EN, OUTPUT);
244 Часть III. Практическое применение Arduino
//не разрешать
digitalWrite(EN, 1);
// для MS1,MS2,MS3
for(int i=0;i<3;i++) {
pinMode(pins_steps[i], OUTPUT);
void loop() {
// получить режим микрошага
digitalWrite(DIR, 1);
int mode=map(analogRead(POT),0,1024,0,5);
// установить
for(int i=0;i<3;i++) {
digitalWrite(pins_steps[i], steps[mode][i]);
}
// сделать 1 оборот
if (movement===true) {
digitalWrite(STEP, 1) ;
delay(SPEED);
digitalWrite(STEP, 0);
delay(SPEED);
}
// проверка нажатия кнопки
tekB = debounce(prevB, BUTTON);
if (prevB = 0 && tekB ==1) {
movement=! movement ;
digitalWrite (EN, Imovement) ;
}
prevB = tekB;
}
// проверка на дребезг
int debounce(int prev,int pin) {
int tek = digitalRead(pin);
if (prev != tek) {
delayE);
tek = digitalRead(pin);
return tek;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\11\_ii_06
сопровождающего книгу электронного архива (см. приложение 2).
Глава 11. Подключение к Arduino исполнительных устройств
245
11.6. Подключение к плате Arduino
бесколлекторного двигателя
Бесколлекторные двигатели (рис. 11.17) используются в различных
радиоуправляемых летающих моделях. По сравнению с коллекторными бесколлекторные
двигатели эффективно работают в более широком диапазоне оборотов и имеют более
высокий КПД. Конструкция двигателя при этом проще— в ней нет щеточного
узла, который работает постоянно в режиме трения, создает искры и в итоге
провоцирует потерю энергии. Бесколлекторные двигатели питаются трехфазным
переменным током, поэтому для их работы необходим специальный контроллер
(регулятор скорости), преобразующий постоянный ток от аккумуляторных батарей
в переменный (рис. 11.18).
Рис. 11.17. Бесколлекторный двигатель
Рис. 11.18. Регулятор ESC для бесколлекторного двигателя
Регулятор ESC, обеспечивающий работу бесколлекторного двигателя, имеет три
разъема для подключения собственно двигателя, два провода для подключения
питания (обычно это литий-полимерная батарея) и 3-контактный разъем для под-
246 Часть III. Практическое применение Arduino
ключения к управляющему устройству (например, к плате Arduino). При этом для
управления задействуются два контакта: черный — GND и белый — управляющий,
а третий (красный — 5 В) можно использовать для питания платы.
Регулятор последовательно переключает обмотки бесколлекторного двигателя
с определенной частотой. Управляя частотой переключения обмоток, мы
управляем скоростью вращения ротора. При программировании используется библиотека
Servo:
#include <Servo.h>
Servo motor;
// Инициализация мотора
motor.attach(motor__pin, js_position, max_position);
где:
? motorpin — контакт (пин) подключения;
? j sjposition — начальная позиция A500);
? max^position — максимальное значение B300).
Диапазон значений, подаваемых на регулятор, должен находиться в интервале 800-
2300.
Содержимое скетча, обеспечивающего управление скоростью бесколлекторного
двигателя с платы Arduino вращением потенциометра, показано в листинге 11.7.
#include <Servo.h>
Servo motor;
// пин подключения мотора
int motor_pin = 6;
// Начальная позиция, всегда 1.5 мс для регуляторов бесколлекторных двигателей
int jsjposition = 1500;
// Максимальное значение ШИМ 2.3 мс
int max_position = 2300;
// Минимальное значение ШИМ 0.8 мс
int minjposition = 800;
void setup() {
// Инициализация мотора
motor.attach(motor_pin, js_position, maxjposition);
// Начальная установка регулятора в нулевое положение
motor.writeMicroseconds(jsjposition);
delayG00);
Глава 11. Подключение кАгбшпо исполнительных устройств 247
void loop () {
// Считывание положения потенциометра
js_position = analogRead(АО);
// Преобразование положения потенциометра
js_position = map(js_position, О, 1023, 800, 2300);
motor.writeMicroseconds(js_position);
// Задержка 20 мс
delayB0);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\i1\__H_07
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 12
Arduino и беспроводная связь
Беспроводная передача данных (беспроводная связь) — связь, которая
осуществляется в обход проводов по радиоканалу. В мире Arduino существует множество
устройств беспроводной связи. Здесь мы рассмотрим некоторые из них.
12.1. ИК-управление
Устройства инфракрасного (ИК) диапазона волн часто применяются в
робототехнике, поскольку на сравнительно недорогих ИК-приемопередатчиках можно
организовать вполне полноценный обмен данными. Самое простое их применение —
использование ИК-пульта для управления роботом. При этом пульт служит в
качестве передатчика.
Для приема сигнала с пульта используется специальный ИК-приемник — датчик,
воспринимающий инфракрасный сигнал только на определенной частоте C0, 33,
36, 38, 40 кГц) и игнорирующий посторонние световые шумы от ламп освещения и
солнца.
В своих проектах мы можем задействовать любой пульт и соответствующий по
частоте приемник, а можно приобрести и комплект (рис. 12.1).
Рис. 12.1. Комплект в составе ИК-пульта и ИК-приемника
Глава 12. Arduino и беспроводная связь
249
Рис. 12.2. Монтажная схема подключения ИК-приемника к плате Arduino
Монтажная схема подключения ИК-приемника к плате Arduino показана на
рис. 12.2.
Библиотека для работы с ИК-приемником, поставляемая в составе Arduino IDE,
не содержит примеров. Чтобы посмотреть и попробовать примеры работы с ИК-
приемником, необходимо установить расширенную библиотеку. Но сначала
необходимо удалить встроенную библиотеку. Для этого заходим в каталог установки
Arduino IDE и из каталога libraries удаляем папку RobotlRRemote. Затем с сайта
https://github.com/z3tO/Arduino-IRremote скачиваем архив, содержащий
обновленную библиотеку IRemote, и устанавливаем ее в Arduino IDE командой меню
Эскиз | Include library | Add ZIP library.
Электронный архив
Библиотека IRemote размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
После установки расширенной библиотеки в Arduino ГОЕ появятся примеры.
Выберем пример IRRecvDemo (рис. 12.3) и загрузим его скетч в плату Arduino,
предварительно поменяв контакт подключения приемника на D2, как показано на схеме
подключения (см. рис. 12.2). Содержимое исправленного скетча показано в
листинге 12.1.
// подключение библиотеки
linclude <IRremote.h>
// пин подключения приемника
int RECV_PIN = 2;
// создаем объект ИК-приемника
IRrecv irrecv(RECVJPIN);
// создаем структуру результата приема данных
decode results results;
250
Часть III. Практическое применение Arduino
void setup()
{
// запустить последовательный порт
Serial.begin(9600);
// запустить приемник
irrecv.enableIRIn();
void loop() {
// если данные получены
if (irrecv.decode(&results)) {
// вывод кода в последовательный порт
Serial.println(results.value, HEX);
irrecv.resume(); // ждать следующее нажатие
Рис. 12.3. Пример IRRecvDemo в списке библиотек Arduino IDE
Глава 12. Arduino и беспроводная связь
251
Загрузив этот скетч в плату Arduino, мы можем получить коды клавиш (табл. 12.1),
которыми воспользуемся в дальнейшем в примере управления сервоприводом
с ИК-пульта (см. разд. 12.1.1). Возможно, для вашего пульта будут актуальны
другие коды.
Таблица 12.1. Коды клавиш пульта для управления
Кнопка пульта
—>
ок
t
i
*
Код
FF22DD
FFC23D
FF02FD
FF629D .
FFA857
FF42BD
Действие
Вращение влево
Вращение вправо
Стоп
В крайнее левое
В крайнее правое
В среднее положение
12.1.1. Управление сервоприводом
с помощью ИК-связи
Итак, подключим к плате Arduino ИК-приемник и сервопривод (монтажная схема
этого проекта представлена на рис. 12.4) и напишем скетч (листинге 12.2),
предусматривающий, что коды, отправляемые ИК-пультом, принимаются ИК-датчиком
и анализируются скетчем на совпадение с кодами из таблицы. При совпадении
вызываются соответствующие подпрограммы вращения вала сервопривода.
Загружаем этот скетч в плату Arduino и управляем движением сервопривода с
помощью пульта.
Рис. 12.4. Монтажная схема подключения ИК-приемника и сервопривода к плате Arduino
252 Часть III. Практическое применение Arduino
// Константы для кодов пульта
#define KOD_POS0 0xFF629D
#define KOD_POS180 0xFFA857
#define KOD_LEFT 0xFF22DD
#define KOD_RIGHT 0xFFC23D
#define KOD_STOP 0xFF02FD
#define KOD_POS90 0xFF42BD
// подключение библиотеки IRremote
#include <IRremote.h>
// пин подключения приемника
const int RECV_PIN = 2;
// создаем объект ИК-приемника
IRrecv irrecv(RECV_PIN);
// создаем структуру результата приема данных
decode_resuits results;
// подключение библиотеки Servo
#include <Servo.h>
// создать объект servo
Servo servol;
// пин для подключения сервопривода
const int pin_servo=9;
// для хранения текущей позиции сервопривода
int angle = 0;
// для хранения направления 1 или -1
int dir=l;
// движение 1, останов 0
int go=l;
void setup() {
// подключить управление сервоприводом к пину pin_servo
servol.attach(pin_servo);
// запустить приемник
irrecv.enablelRIn();
void loopO {
if (irrecv.decode(&results)) {
// проверка кода и выбор действия
switch(results.value) {
case KOD POSO:
Глава 12. Arduino и беспроводная связь 253
go=0;angle=O;go_pos(angle);
break;
case KOD_POS180:
go=180;angle=0;go_pos(angle);
break;
case KOD_POS90:
go=90;angle=0;gojpos(angle);
break;
case KOD_LEFT:
dir=-l;go=l;
break;
case KOD_RIGHT:
dir=l;go=l;
break;
case KOD_STOP:
go=0;
break;
default:
break;
}
// ждать следующее нажатие
irrecv.resume();
}
// если серво движется
if(go==l) {
angle=angle+dir;
go_pos(angle);
//в крайних позициях - стоп
if(angle==0 || angle==180)
go=0;
// установить в позицию
void go_pos(int ang) {
// команда установки положения сервопривода
servol.write(ang);
// время на перемещение сервопривода
delayA5);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\12\_i2_02
сопровождающего книгу электронного архива (см. приложение 2).
254 Часть III. Практическое применение Arduino
12.2. Радиомодули для частоты 433 МГц
Еще одним широко распространенным среди разработчиков способом организации
беспроводной связи в проектах Arduino является использование радиомодулей,
работающих на частоте 433,920 МГц. Частота 433,920 МГц выделена для работы
маломощных цифровых передатчиков, например: радиобрелоков
автосигнализации, брелоков управления шлагбаумами, радиолюстрами, радиорозетками,
радиомоделями.
Радиомодули передатчика FS1000A (рис. 12.5) и приемника MX-RM-5V (рис. 12.6)
позволяют организовать радиосвязь на расстоянии до 100 м. Данные при этом
передаются только в одном направлении. Для полноценной работы к модулю
передатчика необходимо припаять антенну. Рекомендуемая длина антенны для
передатчиков с частотой 433 МГц равна 17 см.
DATA
+5B
3-12B /
DATA
Рис. 12.5. Модуль радиопередатчика FS1000A Рис. 12.6. Модуль радиоприемника MX-RM-5V
12.2.1. Управление светодиодом платы Arduino
с другой такой же платы по радиоканалу 433 МГц
Подсоединим приемник к первой плате Arduino, передатчик — ко второй и
попробуем управлять включением/выключением светодиода на второй плате Arduino
нажатием кнопок, подсоединенных к первой плате Arduino. При программировании
подключим библиотеку RCSwitch.
Электронный архив
Библиотека RCSwitch размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
Содержимое скетча для первой платы Arduino (с двумя кнопками и передатчиком
FS1000A) показано в листинге 12.3.
Глава 12. Arduino и беспроводная связь 255
11 подключение библиотеки
tinclude <RCSwitch.h>
// создание объекта
RCSwitch mySwitch = RCSwitch () ;
// пины для подключения кнопок
int pinButtons []={ 10,11} ;
// для сохранения предыдущих состояний кнопок
int lastButtons [ ] = {0, 0} ;
// для сохранения текущих состояний кнопок
int currentButtons [ ] = {0,0};
void setup () {
// активировать передатчик
// пин подключения вывода Data 12
mySwitch.enableTransmitA2);
void loop () {
// проверка нажатия кнопок выбора программ
for(int i=0;i<2;i++)
{
// борьба с дребезгом
currentButtons [i] = debounce(lastButtons [i],pinButtons [i]);
if (lastButtons [i] — 0 && currentButtons [i] == 1) // если нажатие.
{
doButtons(i);
}
lastButtons[i] = currentButtons[i];
// обработка нажатия клавиш
void doButtons(int but)
{
switch(but)
{
case 0: mySwitch.send(B0100, 4);
break;
case 1: mySwitch.send(BOlOO, 4);
break;
default:
break;
256 Часть III. Практическое применение Arduino
I/ Функция сглаживания дребезга
// Принимает в качестве аргумента предыдущее состояние кнопки
//и выдает фактическое.
int debounce(int last,int pinl) {
int current = digitalRead(pinl); // Считать состояние кнопки
if (last != current) // если изменилось...
{
delayE); // ждем 5 мс
current = digitalRead(pinl); // считываем состояние кнопки
return current; // возвращаем состояние кнопки
В цикле loop о ждем нажатия кнопки и с помощью функции mySwitch.sendo
отправляем сообщение по радиоканалу. В параметрах функции указываются
сообщение для отправки и размер сообщения в битах.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\12\_12JK
сопровождающего книгу электронного архива (см. приложение 2).
Содержимое скетча для второй платы Arduino (с приемником MX-RM-5V)
показано в листинге 12.4.
// подключение библиотеки
#include <RCSwitch.h>
// создание объекта
RCSwitch mySwitch = RCSwitch();
// пин для подключения светодиода
int pinLed=13;
void setup() {
// вывод светодиода как OUTPUT
pinMode(pinLed, OUTPUT );
// инициализация приемника
// Используется прерывание 0 (вывод 2)
mySwitch.enableReceive@);
void loop() {
if (mySwitch.available()) {
int value = mySwitch.getReceivedValue();
if (value — B1000)
digitalWrite(pinLed, HIGH); // включить
Гпава 12. Arduino и беспроводная связь 257
else if (value == В0100)
digitalWrite(pinLed, LOW); // выключить
mySwitch.resetAvailable();
Электронный архив*
Полный вариант рассмотренного скетча находится в папке examples\12\_12_04
сопровождающего книгу электронного архива (см. приложение 2).
Приемник MX-RM-5V критичен даже к небольшим пульсациям на шине питания.
Если Arduino управляет устройствами, вносящими даже небольшие, но постоянные
пульсации в шину питания, то приемник расценивает эти пульсации как сигнал.
Влияние пульсаций на приемник можно снизить установкой на шине питания
приемника сглаживающего конденсатора или использованием для приемника
отдельного стабилизированного источника питания.
12.3. Радиомодули NRF24L01
Еще одним — очень популярным и бюджетным — вариантом соединения двух
Arduino-устройств по радиоканалу является использование беспроводных модулей
NRF24L01 (рис. 12.7). Малое энергопотребление, достойный радиус действия,
высокая скорость передачи и низкая цена— вот основные качества радиомодуля
NRF24L01.
Рис. 12.7. Радиомодуль NRF24L01
Радиомодуль NRF24L01 представляет собой полудуплексное устройство: в один
момент времени оно может либо передавать, либо принимать информацию. Чтобы
обеспечить двустороннюю связь, нужно постоянно переключаться с одного режима
на другой. Модуль передает данные на частоте от 2,4 до 2,525 ГТц — в
зависимости от выбранного канала, которых в NRF24L01 доступно 126. Используется
модуляция GFSK. Модуль подключается к Arduino по интерфейсу SPI. Один модуль
способен поддерживать связь сразу с шестью приемниками или передатчиками,
т.е. можно объединить сразу семь устройств в общую радиосеть на частоте
258
Часть III. Практическое применение Arduino
2,4 ГТц. Максимальная скорость обмена данными между модулями составляет
2Мбит/с. Дальность передачи— до 100 м. Если вам нужно большее расстояние
передачи, можно использовать модуль с внешней антенной (рис. 12.8), при этом
расстояние передачи может составить до 1000 м со скоростью 250 Кбит/с (или
500 м со скоростью до 2 Мбит/с).
Рис. 12.8. Радиомодуль NRF24L01 с внешней антенной
Как уже отмечалось, радиомодуль NRF24L01 подключается к плате Arduino при
помощи SPI-интерфейса. При этом, в зависимости от используемой библиотеки,
может задействоваться и дополнительный выход прерывания IRQ. Но в нашем
примере мы обойдемся без него. Схема соединения контактов радиомодуля
NRF24L01 и платы Arduino выглядит следующим образом (табл. 12.2).
Таблица 12.2. Схема
Радиомодуль NRF24L01
Arduino Uno
соединения контактов радиомодуля NRF24L01
GND
GND
VCC
+3,3 В
СЕ
9
CSN
10
MOSI
11
и платы Arduino
MISO
12
SCK
13
Монтажная схема подключения радиомодуля NRF24L01 к плате Arduino показана
на рис. 12.9. Питание модуля— 3,3 В, но выводы модуля толерантны и к 5 В. На
многих платах Arduino имеется встроенный стабилизатор напряжения на 3,3 В,
но он, однако, не обладает достаточной мощностью для правильной работы
NRF24L01. Особенно эта проблема актуальна для Arduino Mega. В связи с этим для
питания радиомодулей NRF24L01 рекомендуется использовать внешние
стабилизаторы.
Глава 12. Arduino и беспроводная связь
259
Рис. 12.9. Монтажная схема подключения радиомодуля NRF24L01 к плате Arduino
12.3.1. Организация связи между двумя платами Arduino
с использованием модулей NRF24L01
Установим связь между двумя платами Arduino с использованием модулей
NRF24L01. При этом к первой плате подсоединим датчик влажности и
температуры DHT11 (монтажная схема соединений для этой платы показана на рис. 12.10).
Каждые 30 с отправляем данные этого датчика по радиоканалу, кроме того, каждые
5 с проверяем соединение— отправляем данные и ждем ответа. При отсутст-
Рис. 12.10. Монтажная схема подключения модуля NRF24L01 и датчика DHT11 к плате Arduino
260 Часть III. Практическое применение Arduino
вии ответа сигнализируем светодиодом на выходе 13 о проблемах с
соединением.
Для взаимодействия Arduino с модулями NRF24L01 подключим библиотеку RF24.
Электронный архив
Библиотека RF24 размещена в каталоге libraries сопровождающего книгу электронного
архива (см. приложение 2).
Содержимое скетча для первой платы Arduino показано в листинге 12.5.
// пауза отправки данных для контроля связи
#define PAUSE_SEND_STATUS 5000
// максимальное время ожидания ответа от NRF2401
#define TIME_WAIT_STATUS 500
// пауза отправки данных текущих температуры и влажности
#define PAUSE_SEND_DATA 30000
// идентификатор канала
#define ID 0x357340
// номер канала
#define CHANNEL 5
// нулевой байт
#define TEMP 56 // температура текущая
#define HUMIDITY 57 // влажность текущая
#define STAT 59 // проверка статуса сети
// Подключаем библиотеку для работы с шиной SPI
#include <SPI.h>
// Подключаем файл настроек из библиотеки RF24
#include <nRF24L01.h>
// Подключаем библиотеку для работы с NRF24L01
#include <RF24.h>
// Создаем объект radio для работы с библиотекой
// RF24, указывая номера выводов nRF24L01+ (CE, CSN)
RF24 radio(9, 10);
// Создаем массив для приема данных
int data[2];
// подключение библиотеки DTH
#include "DHT.h"
// создание экземпляра объекта DHT
DHT dhtD, DHT11);
unsigned long millissendstatus=0;
unsigned long millissenddata=0;
unsigned long millisgetstatus=0;
Глава 12. Anduino и беспроводная связь 261
I/O - передаем, 1 - получаем
int mode=0;
void setup () {
Serial.begin(9600);
// Инициируем работу NRF24L01+
radio.begin();
// Указываем канал передачи данных (от 0 до 127),
// 5 - значит, передача данных осуществляется на частоте 2,405 ГГц
// (на одном канале может быть только 1 приемник и до б передатчиков)
radio.setChannel(CHANNEL);
// Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS)
radio.setDataRate (RF24_1MBPS);
// Указываем мощность передатчика (RF24_PA_MIN=-18dBm,
// RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm)
radio.setPALevel (RF24_PA_HIGH);
// Открываем для передачи данных с идентификатором ID
radio.openWritingPipe (ID);
Serial.println("start radio");
// запуск DHT
dht.beginO ;
Serial.println("ready");
void loopO {
// отправляем данные radio
if(mode==0) {
// отправка данных влажности и температуры
if (millis () -millissenddata>PAUSE_SEND_DATA) {
// получение данных с датчика
int h = dht.readHumidity();
Serial.print("Humidity=");
Serial.print(h);
data[0] = HUMIDITY;
data[l] = h;
// отправляем данные из массива data
radio.write(&data, sizeof(data));
delayA00);
int t = dht.readTemperature();
Serial.print(" Temperature=");
Serial.println(t);
data[0] = TEMP;
data[l] = t;
// отправляем данные из массива data
radio.write(&data, sizeof(data));
millissenddata=millis();
millissendstatus=millis();
262 Часть III. Практическое применение Arduino
I/ отправка для ответа - статус сети
if (millis () -millissendstatus>PAUSE_SEND_STATUS) {
data[0] = STAT;
datafl] = 1;
Serial.printIn("send");
// отправляем данные из массива data
radio.write(&data, sizeof(data));
delayA00);
Serial.printIn("ok") ;
millissendstatus=millis();
radio.openReadingPipeA, ID);
radio.startListening();
mode=l;
millisgetstatus=millis ();
delayA00);
// получаем данные radio
else {
if(radio.available()) {
radio, read (&data,sizeof(data));
Serial.print("get data=");
Serial.print(data[0]);
Serial.print(" ") ;
Serial.println(data[1]);
mode=0;
radio.stopListening();
delayA00);
radio.openWritingPipe (ID);
}
if (millis () -millisgetstatus>TIME_WAIT_STATUS)
mode=0;
Serial.print("status - NO");
Serial.println();
radio.stopListening();
radio.openWritingPipe (ID);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examplesKn^njOS
сопровождающего книгу электронного архива (см. приложение 2).
Вторая плата Arduino, получая по радиоканалу данные температуры и влажности,
выводит их в последовательный порт. Если полученные данные — это запрос
статуса, то отправляет ответ.
Глава 12. Arduino и беспроводная связь 263
Содержимое скетча для второй платы Arduino показано в листинге 12.6.
// идентификатор канала
idefine ID 0x357340
// номер канала
fdefine CHANNEL 5
// нулевой байт
idefine TEMP 56
idefine HUMIDITY 57
tdefine STAT 59
// Подключаем библиотеку для работы с шиной SPI
iinclude <SPI.h>
// Подключаем файл настроек из библиотеки RF24
tinclude <nRF24L01.h>
// Подключаем библиотеку для работы с NRF24L01
iinclude <RF24.h>
// Создаем объект radio для работы с библиотекой
// RF24, указывая номера выводов NRF24L01+ (СЕ, CSN)
RF24 radio (9, 10);
// Создаем массив для приема данных
int data[2];
void setup () {
// Запуск последовательного порта
Serial.begin(9600);
Serial.begin(9600);
// Инициируем работу NRF24L01+
radio.begin();
// Указываем канал передачи данных (от 0 до 127),
// 5 - значит, передача данных осуществляется на частоте 2,405 ГГц
// (на одном канале может быть только 1 приемник и до 6 передатчиков)
radio.setChannel(CHANNEL);
// Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS)
radio.setDataRate (RF24_1MBPS);
// Указываем мощность передатчика (RF24_PA_MIN=-18dBm,
// RF24_PA_LOW=-12dBm, RF24_PA_HIGH=~6dBm, RF24_PA_MAX=0dBm)
radio.setPALevel (RF24_PA_HIGH);
// Открываем для приема данных с идентификатором ID
radio.openReadingPipe A, ID);
Serial.println("start radio");
// Включаем приемник, начинаем прослушивать
radio.startListening ();
264 Часть III. Практическое применение Arduino
void loop () {
// Если в буфере имеются принятые данные
if(radio.available()) {
// Читаем данные в массив data и указываем, сколько байтов читать
radio.read(&data, sizeof(data));
// проверка dataO
switch(data[0]) {
case TEMP: // температура текущая
Serial.print("Temperatura tek=");
Serial.println(data[1]) ;
break;
case HUMIDITY: // влажность текущая
Serial.print("Humidity tek=");
Serial.println(data[l]);
break;
case STAT: // проверка статуса сети
Serial.print("status=");
Serial.println(data[1]);
radio.stopListening ();
//на отправку
delayA50);
radio.openWritingPipe (ID);
// отправить
radio.write(&data, sizeof(data));
//на получение
radio.openReadingPipe (lf ID);
// Включаем приемник, начинаем прослушивать
radio.startListening ();
break;
default:
break;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\12\_i2_06
сопровождающего книгу электронного архива (см. приложение 2).
12.4. Использование Arduino
с аппаратурой радиоуправления
Аппаратура радиоуправления используется для управления движущимися
моделями и состоит из передатчика, который находится у пилота, и размещенных на
модели приемника и исполнительных механизмов. Для управления исполнительными
Глава 12. Arduino и беспроводная связь
265
механизмами нередко задействуются платы Arduino, которые должны получать
команды от приемника и обрабатывать их в соответствии с заложенными в их
программу алгоритмами.
По конструкции органов управления, на которые, собственно, и воздействуют
пальцы пилота, передатчики делятся на джойстиковые (рис. 12.11) и пистолетного
типа. В первых — которые и используются в основном для управления летающими
моделями — установлены, как правило, два двухкоординатных джойстика.
Рис. 12.11. Передатчик НК-Т6А
Для управления движущимися моделями требуется выполнение одновременно
нескольких функций. Поэтому передатчики радиоуправления делают
многоканальными. Так, для авто- и судомоделей требуются два канала: управление
направлением движения и оборотами двигателя. Для полноценного управления самолетом
нужно не менее четырех, а вертолетом — пяти каналов.
Для самолетов на два двухкоординатных джойстика выводятся функции
управления рулем высоты, направления, элеронами и «газом» (оборотами) двигателя.
Конкретная раскладка функций по джойстикам бывает двух типов:
? Mode 1 (рис. 12.12): слева — руль высоты (по вертикали) и руль направления (по
горизонтали), справа — «газ» (по вертикали) и крен (по горизонтали);
? а также Mode 2 (рис. 12.13): слева— «газ» (по вертикали) и руль направления
(по горизонтали), справа — руль высоты (по вертикали) и крен (по горизонтали).
Есть еще типы раскладок Mode 3 и 4, но они мало распространены.
266
Часть III. Практическое применение Arduino
вверх
холостой
ход
Рис. 12.12. Раскладка Mode 1
холостой вверх
ход
Рис. 12.13. Раскладка Mode 2
12.4.1. Принципы формирования радиосигнала
Для того чтобы излучаемый передатчиком радиосигнал мог переносить полезную
информацию, он подвергается модуляции. То есть управляющий сигнал изменяет
параметры несущей радиочастоты. На практике нашли применение управление
амплитудой и частотой несущей, обозначаемые буквами AM (Amplitude Modulation,
амплитудная модуляция) и FM (Frequency Modulation, частотная модуляция).
В радиоуправлении используется только дискретная двухуровневая модуляция.
В варианте AM несущая имеет либо максимальный, либо Нулевой уровень. В
варианте FM излучается сигнал постоянной амплитуды либо с частотой F, либо с чуть
смещенной частотой F + df. Сигнал FM-передатчика напоминает сумму сигналов
двух АМ-передатчиков, работающих в противофазе на частотах F и F + df
соответственно. Из этого можно понять, даже не углубляясь в тонкости обработки
радиосигнала в приемнике, что в одинаковых помеховых условиях FM-сигнал имеет
принципиально большую помехозащищенность, чем АМ-сигнал. АМ-аппаратура,
как правило, дешевле, однако разница не очень велика. В настоящее время
использование АМ-аппаратуры оправдано только для тех случаев, когда расстояние до
модели относительно невелико. Как правило, это справедливо для автомоделей,
судомоделей и комнатных авиамоделей. Вообще, летать с использованием
АМ-аппаратуры можно лишь с большой опаской и вдали от промышленных центров.
Модуляция позволяет наложить на излучаемую несущую полезную информацию.
Однако в радиоуправлении используется только многоканальная передача
информации. Для этого все каналы уплотняются в один посредством кодирования. Сейчас
Глава 12. Arduino и беспроводная связь
267
для этого используется только импульсно-фазовая модуляция, обозначаемая
буквами PPM (Pulse Phase Modulation) и импульсно-кодовая модуляция, обозначаемая
буквами PCM (Pulse Code Modulation).
На рис. 12.14 приведен типовой РРМ-сигнал пятиканальной аппаратуры, имеющий
фиксированную длину периода Т = 20 мс. Это означает, что информация о
положениях ручек управления на передатчике попадает на модель 50 раз в секунду, что
определяет быстродействие аппаратуры управления. Как правило, этого хватает,
поскольку скорость реакции пилота на поведение модели намного меньше. Все
каналы пронумерованы и передаются по порядку номеров. Значение сигнала в канале
определяется величиной временного промежутка между первым и вторым
импульсом — для первого канала, между вторым и третьим — для второго канала и т. д.
Диапазон изменения величины временного промежутка при движении джойстика
(ручки управления) из одного крайнего положения в другое определен от 1 до 2 мс.
Значение 1,5 мс соответствует среднему (нейтральному) положению джойстика.
Продолжительность межканального импульса составляет около 0,3 мс. Такая
структура РРМ-сигнала является стандартной для всех производителей аппаратуры
радиоуправления.
„ 0.3 мс
. 2
КАНАЛЫ
3 4
Т=20мс
Рис. 12.14. Типовой РРМ-сигнал пятиканальной аппаратуры
12.4.2. Организация связи приемника с передатчиком
Рассмотрим организацию связи приемника НК-Т6А (рис. 12.15), установленного на
управляемой модели в нашем проекте, с передатчиком управляющего сигнала.
Как можно видеть, число каналов управления у этого приемника — шесть.
Для начала необходимо связать между собой передатчик и приемник в следующем
порядке:
1. Установить в передатчик батарею.
2. Вставить шнур для кодирования (показан на рис. 12.15, вверху) в контакты ВАТ
приемника.
268
Часть III. Практическое применение Arduino
Рис. 12.15. Приемник НК-Т6А (внизу); шнур с разъемом для кодирования приемника (вверху)
3. Соединить батарею питания приемника с одним из портов канала — если свето-
диоды на приемнике и передатчике вспыхивают одновременно, значит,
приемник успешно включен.
4. Зажать (нажать и удерживать) кнопку поиска частоты на передатчике и
включить питание — если светодиоды на приемнике не мигают, а просто горят, то
связь установлена.
5. Отпустить кнопку на передатчике, отсоединить шнур на приемнике.
6. Установить сервомашинку в какой-нибудь из каналов и проверить
работоспособность— при движении джойстиков на передатчике сервомашинка должна
вращаться.
Теперь можно подключить приемник к Arduino и разработать скетч для приема
команд с передатчика.
12.4.3. Разработка скетча
для приема платой Arduino команд передатчика
Для считывания платой Arduino данных, поступающих с передатчика на приемник,
подключаем сигнальные контакты приемника на выводы Dll, D10, D9, D8 платы
Arduino. He забываем подать на приемник питание 5 В. Диапазон изменения
величины временного промежутка при движении джойстика из одного крайнего
положения в другое определен величиной от 1 до 2 мс. Для определения длительности
сигнала, поступающего на входы, мы воспользуемся функцией puiseino.
Напомним, что функция считывает длину сигнала на заданном порту (high или low).
Например, если задано считывание high, функция puiseino ожидает, пока на
заданном порту не появится high. Когда high получено, включается таймер, который
Гпава 12. Arduino и беспроводная связь " 269
будет остановлен, когда на порту входа/выхода появится low. Длину сигнала
функция puiseino возвращает в микросекундах. Если же в течение заданного времени
(тайм-аута) сигнал на порту зафиксирован не был, функция возвращает 0.
Синтаксис функции puisein ():
pulseln(pin, value)
pulseln(pin, value, timeout)
Параметры:
? pin — номер порта входа/выхода, на котором будет ожидаться сигнал;
? value — тип ожидаемого сигнала (high или low);
? timeout— время ожидания сигнала (тайм-аут) в микросекундах; по
умолчанию — одна секунда.
Возвращаемое значение: длина сигнала в микросекундах или 0, если сигнал не
получен до истечения тайм-аута.
Выбираем поочередно порт для 1, 2, 3 и 4-го каналов, параметр vaiue=HiGH,
timeout=2 мс. Получаемое значение сигнала: от 1 до 2 мс. Данные, полученные
с передатчика, выводим в последовательный порт (рис. 12.16). Как можно видеть,
при перемещении джойстиков передатчика изменяется значение считываемого
сигнала.
Рис. 12.16. Вывод данных, полученных платой Arduino с передатчика, в монитор последовательного
порта
Содержимое скетча, обеспечивающего прием платой Arduino команд передатчика,
приведено в листинге 12.7.
// передатчик - НК-Т6А
// приемник -
// приемник :
270 Часть III. Практическое применение Arduino
// Chi - Rudder (руль направления, рыскание, YAW)
// Ch2 - Elevator (тангаж, PITCH)
// Ch3 - Throttle (газ)
// Ch4 - Aileron (элероны, ROLL)
unsigned long ChlValue,Ch2Value,Ch3Value,Ch4Value;
unsigned long lastl,Iast2,last3,last4;
int pinChl=ll;
int pinCh2=10;
int pinCh3=9;
int pinCh4=8;
void setup() {
Serial.begin(9600);
Serial.println("Ready");
pinMode (pinChl, INPUT); // connect Rx channel 1
pinMode (pinCh2, INPUT); // connect Rx channel 2
pinMode (pinCh3, INPUT); // connect Rx channel 3
pinMode (pinCh4, INPUT); // connect Rx channel 4
lastl = pulseln (pinChl, HIGH); //read RC channel 1
Iast2 = pulseln (pinCh2, HIGH); //read RC channel 2
Iast3 = pulseln (pinCh3, HIGH); //read RC channel 3
Iast4 = pulseln (pinCh4, HIGH); //read RC channel 4
void loop(){
//
ChlValue = pulseln (pinChl, HIGH, 20000); //read RC channel 1
if (ChlValue — 0) {ChlValue = lastl;}
else {lastl = ChlValue;}
Serial.print (" Chi: ");Serial.print (ChlValue);
//
Ch2Value = pulseln (pinCh2, HIGH, 20000); //read RC channel 2
if (Ch2Value = 0) {Ch2Value = Iast2;}
else {Iast2 - Ch2Value;}
Serial.print(и Ch2: ")/Serial.print (Ch2Value);
//
Ch3Value » pulseln (pinCh3, HIGH, 20000); //read RC channel 3
if (Ch3Value = 0) {Ch3Value = Iast3;}
else {Iast3 = Ch3Value;}
Serial.print(я Ch3: ")/Serial.print (Ch3Value);
//
Ch4Value = pulseln (pinCh4, HIGH, 20000); //read RC channel 4
if (Ch4Value = 0) {Ch4Value = Iast4;}
else {Iast4 = Ch4Value;}
Serial.print(lf Ch4: ");Serial.print (Ch4Value) ;
Serial.printIn("");
Глава 12. Arduino и беспроводная связь 271
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\12\__i2JO
сопровождающего книгу электронного архива (см. приложение 2).
12.5. Arduino и Bluetooth
Беспроводной интерфейс Bluetooth является одним из самых популярных
интерфейсов, которые любители программирования Arduino выбирают для связи
создаваемого ими устройства с мобильным приложением. Связь, как правило,
осуществляется с помощью подключаемых к плате Arduino Bluetooth-модулей НС-05 или
НС-06 — недорогих и широко распространенных.
Bluetooth-модуль общается с платой Arduino по последовательному порту и
работает в двух режимах:
? отправки/получения по Bluetooth данных, поступающих на него по
последовательному порту;
? в режиме программирования модуля отправкой АТ-команд.
Для входа в режим программирования необходимо подать на контакт KEY модуля
(рис. 12.17) сигнал высокого уровня 3,3 В. На некоторых модулях контакт KEY
отсутствует, вместо него имеется контакт EN. В этом случае для входа в режим
программирования необходимо подать сигнал высокого уровня на контакт 34
(рис. 12.18).
Рис. 12.17. Bluetooth-модуль НС-05 Рис. 12.18. Bluetooth-модуль НС-05
с контактом KEY без контакта KEY:
подключение для входа в режим программирования
Рассмотрим настройку модуля в режиме программирования отправкой АТ-команд
по последовательному порту. Подключим модуль НС-05 к плате Arduino по схеме
соединений, показанной на рис. 12.19. На контакт KEY модуля (или вывод 34-й пла-
272 Часть Hi Практическое применение Arduino
ты) подадим 3,3 В. АТ-команды будем отправлять с монитора последовательного
порта Arduino IDE.
При программировании подключаем Arduino-библиотеку SoftwareSerial.
Содержимое скетча показано в листинге 12.8. Скорость UART-модуля в режиме
программирования 38 400 бод, но может и отличаться, в этом случае ее следует подобрать.
Рис. 12.19. Монтажная схема подключения модуля НС-05 к плате Arduino
для режима отправки АТ-команд
#include <SoftwareSerial.h>
// указываем пины гх и tx соответственно
SoftwareSerial mySerialB, 3);
void setup() {
pinModeB,INPUT);
pinModeC,OUTPUT);
Serial.begin(9600);
mySerial.beginC8400);
Глава 12. Arduino и беспроводная связь
273
Serial.println("start prg");
void loopO {
if (mySerial.availableO ) {
char с = mySerial.read(); // читаем из software-порта
Serial.print(с); // пишем в hardware-порт
}
if (Serial.available()) {
char с = Serial.read(); // читаем из hardware-порта
mySerial.write(с); // пишем в software-порт
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\12\_12__08
сопровождающего книгу электронного архива (см. приложение 2).
Загрузив этот скетч в плату, откроем монитор последовательного порта Arduino
IDE и начнем отправлять АТ-команды (рис. 12.20).
Вот список основных АТ-команд:
П at — тестовая команда.
Параметров нет.
Ответ модуля: ок
¦ШАМЕ-МЕТЕО (yt-зноби
+ROLE? (Г7опуиить роль)
& U д р у!? / п Q г - у ч щ г ь гщозые
ATvCLAbS=:793u (устанош-ггь CLASS
Рис. 12.20. Отправка АТ-команд в модуль НС-05
274 Часть III. Практическое применение Arduino
? at+version? — получить версию прошивки модуля.
Параметров нет.
Ответ модуля:+VERSION: <Param>
где <Param> — версия прошивки Bluetooth-модуля.
? at+reset — сброс настроек.
Параметров нет.
Ответ модуля: ок
? at+orgl — установка пользовательских настроек модуля.
Параметров нет.
Ответ модуля: ок
? AT+ADDR? — ПОЛуЧИТЬ адрес МОДУЛЯ.
Параметров нет.
Ответ модуля: +ADDR: <Param>
где <Param> — адрес Bluetooth-модуля NAP: UAP : LAP.
? AT+NAME? ПОЛуЧИТЬ ИМЯ МОДуЛЯ.
Параметров нет.
Ответ МОДУЛЯ: +NAME:<Param>
где <Param> — имя Bluetooth-модуля.
? AT+NAME=<Param> — установить новое имя модуля.
Параметр: <Param> — имя Bluetooth-модуля.
Ответ модуля: +NAME:<Param>
ок (или fail)
? at+pswd? — получить пин-код доступа к Bluetooth-модулю.
Параметров нет.
Ответ модуля: + PSWD:<Param>
где <Param> — пин-код. По умолчанию 1234.
? AT+PSWD=<Param> — установить код доступа к Bluetooth-модулю.
Параметр: <Param> — код доступа к модулю.
Ответ модуля: ок (или fail)
? AT+CLASS=<Param> — установить режим работы модуля Bluetooth-модуля.
Параметр: <Рагаш> — класс. В документации модуля не приведены возможные
значения этого параметра. По умолчанию он установлен в 0. Если
предполагается использовать модуль в режиме master, значение не надо изменять. Если
использовать модуль в режиме slave, при значении параметра, равном 0, он не-
Глава 12. Arduino и беспроводная связь
видим для устройств с операционной системой Android. Для видимости
необходимо установить значение параметра, равное 7936.
Ответ модуля: ок
П AT+CLASS? — получить класс модуля.
Параметров нет.
Ответ модуля: +CLASS:<Param>
где <Param> — класс модуля.
? at+role? — получить режим работы модуля.
Параметров нет.
Ответ МОДУЛЯ: +ROLE:<Param>
где <Param> — режим работы модуля Bluetooth-модуля:
• о — slave. В этом режиме другой мастер может подключиться к модулю;
• 1 — master. В этом режиме модуль может сам подключиться к какому-нибудь
Bluetooth-устройству;
• 2 — slave-loop. Модуль отправляет обратно все байты, которые ему прислали.
AT+ROLE=<Param> — установить режим работы Bluetooth-модуля.
Параметр: <Param> — режим работы Bluetooth-модуля:
• о — slave;
• 1 — master;
• 2 — slave.
Ответ модуля: ок
? AT+UART=<Parami>, <Param2>, <Param3> — установить модуль для последовательно-
го порта.
Параметры:
• <Parami> — скорость обмена (9600, 19 200, 38 400, 57 600, 115 200);
• <Param2> — СТОП-бит:
D о — нет;
D 1 — есть;
<РагашЗ> — бит паритета:
п о — нет;
D 1 — есть.
Ответ модуля: ок (или fail)
? at+uart? — получить параметры обмена модуля.
Параметров нет.
276 Часть III. Практическое применение Arduino
Ответ модуля: +UART: <Paraml>, <Param2>, <Param3>
где:
• <Parami> — скорость обмена (9600, 19 200, 38 400, 57 600, 115 200);
• <Param2> — СТОП-бит;
• <Param3> — бит паритета.
? AT+CMODE=<Param> — установить режим подключения Bluetooth-модуля.
Параметр: <Param> — режим подключения Bluetooth-модуля:
• о— модуль может подключаться только к определенному командой
AT + BIND Bluetooth-устройству;
• l — модуль может подключаться к любому Bluetooth-устройству;
• 2 — режим slave-loop.
Ответ модуля: ок
? AT+CMODE? — получить режим подключения модуля.
Параметров нет.
Ответ МОДУЛЯ: +CMODE:<Param>
где <Param> — режим подключения Bluetooth-модуля:
• о — модуль может подключаться только к определенному командой
AT + BIND Bluetooth-устройству;
• l — модуль может подключаться к любому Bluetooth-устройству;
• 2 — режим slave-loop.
? AT+iNQ — запуск поиска Bluetooth-устройств.
Параметров нет.
Ответ модуля — список найденных устройств..
? AT+BiND=<Param> — привязать Bluetooth-модуль к другому модулю.
Параметр: <Param> — адрес авторизованного Bluetooth-модуля.
Ответ модуля: ок (или fail)
? at+bind? — получить адрес устройства, привязанного к Bluetooth-модулю.
Параметров нет.
Ответ модуля: <Param> — адрес устройства, привязанного к Bluetooth-модулю.
? AT+LiNK=<Param> — соединиться с Bluetooth-устройством.
Параметр: <Param> — адрес Bluetooth-устройства.
Ответ модуля: ок (или fail)
Глава 12. Arduino и беспроводная связь
277
После программирования модуля отсоединим контакт KEY модуля (или вывод 34)
от 3,3 В и попробуем подсоединиться к модулю со смартфона (или планшета) на
операционной системе Android (рис. 12.21-12.23).
Подключившись, можно организовать обмен данными между телефоном и платой
Arduino.
Рис. 12.21. Модуль НС-05 (устройство МЕТЕО найдено)
ШяШШШШ
>*?/Э '-^Й*'?'5''*Й.;^ч?С:i';'!-*!"!--, 1
Ы^У"ЖМг'%^
Рис. 12.22. Запрос на соединение с найденным устройством
278
Часть III. Практическое применение Arduino
SM-T2.ll
МЕТЕО
Рис. 12.23. Подключение к модулю НС-05 (устройству МЕТЕО)
с телефона Android состоялось
ГЛАВА 13
Arduino и Интернет вещей
Интернет вещей (Internet of Things, IoT) — это широкая сеть объектов, связанных
через Интернет и способных обмениваться данными. Интернет вещей предполагает
оснащение каждого устройства, будь то пылесос, холодильник или стиральная
машина, модулем подключения к Интернету с возможностью взаимодействия его
с домашним компьютером или смартфоном домовладельца. В этой главе мы
рассмотрим организацию доступа Arduino к сети Интернет с дальнейшей отправкой
данных в известные облачные сервисы и получением их оттуда.
13.1. Подключение к Интернету
с помощью платы расширения Ethernet shield
Самый распространенный метод обеспечить доступ платы Arduino к сети
Интернет— использование платы Ethernet shield (рис. 13.1). Ethernet shield— это плата
расширения, которая устанавливается на плату Arduino сверху. Она дает ей
возможность выступать в роли сетевого устройства и общаться по проводной сети
с аналогичными устройствами, с обычными компьютерами, принтерами, сервисами
в Интернете и прочими сетевыми ресурсами. Последняя версия платы Ethernet
Shield Rev3 полностью совместима с Arduino Mega2560.
Плата Ethernet shield основана на микросхеме Wiznet W5100, которая поддерживает
как TCP-, так и UDP-протоколы. Одновременно открытыми могут быть до четырех
подключений.
Плата обладает стандартным Ethernet-портом для подключения к сети с помощью
патч-корда витой пары и набором контактов для подключения к Arduino. Для
общения между собой Ethernet shield и Arduino задействуют контакты 4-й и с 10-го
по 13-й, поэтому их использование в других целях в присутствии платы
расширения невозможно.
Для программирования сетевого взаимодействия подключается библиотека Ethernet
из стандартного дистрибутива. При использовании этой библиотеки необходимо
указывать МАС-адрес платы (уникальный идентификатор любого сетевого
устройства). В более новых версиях Ethernet-шилда МАС-адрес можно увидеть на наклей-
280 Часть III. Практическое применение Arduino
ке на плате. Если такой наклейки нет, то просто введите любую похожую
комбинацию, — главное, чтобы в вашей сети не было устройств с совпадающими МАС-
адресами.
На плате размещен слот для карты памяти формата microSD, которая может быть
использована для хранения ресурсов, раздаваемых по сети. Для взаимодействия
с такой картой следует подключить, например, библиотеку sdfatlib.
Для отправки данных в облачные сервисы в примерах этого раздела мы
воспользуемся веб-клиентом на основе платы Arduino с установленной на нее платой
расширения Ethernet shield.
Рис. 13.1. Плата Ethernet shield Rev3
13.1.1. Получение IP-адреса по DHCP
Соединим Ethernet shield с платой Arduino и создадим простой пример получения
ими IP-адреса по DHCP. Соединяется Ethernet shield с платой Arduino так же
просто, как и любой другой шилд, — просто состыкуйте их вместе. Следует учесть,
что установка других шилдов поверх Ethernet shield весьма затруднительна. Это
связано с большими размерами имеющегося на плате Ethernet shield разъема RJ-45,
служащего для подключения сетевого кабеля, поэтому, если вы хотите
использовать совместно с Arduino еще и другие шилды, лучше их размещать между Arduino
и Ethernet shield.
Итак, подключим плату Arduino к USB-порту компьютера, a Ethernet shield
подсоединим с помощью сетевого кабеля к маршрутизатору, имеющему выход в Интернет
(рис. 13.2).
Скетч, обеспечивающий получение IP-адреса по DHCP, представлен в
листинге 13.1, а пример назначения статического IP-адреса — в листинге 13.2.
Глава 13. Arduino и Интернет вещей 281
Рис. 13.2. Подключение к плате Arduino платы расширения Ethernet shield Rev3
i
// Получение IP-адреса по DHCP
// МАС-адрес Ethernet shield (можно увидеть на наклейке на плате) или
// произвольный уникальный в сети
iinclude <Ethernet.h>
If 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) {
Serial.println("Failed to configure Ethernet using DHCP");
for (;;)
// печать в последовательный порт полученного по DHCP адреса
Serial.print("My IP address: ");
for (byte thisByte = 0; thisByte < 4; thisByte++) {
Serial.print(Ethernet.locallPO [thisByte], DEC);
Serial.print(".");
}
Serial.println();
void loop () {;}
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\13\_13__01
сопровождающего книгу электронного архива (см. приложение 2).
282 Часть III. Практическое применение Arduino
I/ Получение статического 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);
delayA000);
Serial.println(Ethernet.locallP());
}
void loop() {;}
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\13\_13_02
сопровождающего книгу электронного архива (см. приложение 2).
13.1.2. Отправка данных
на сайт «Народный мониторинг» через Ethernet shield
Получив доступ в Интернет, мы можем отправлять данные с платы Arduino в
облачные сервисы. Рассмотрим пример отправки данных на сайт «Народный
мониторинг».
«Народный мониторинг» (http://www.narodmon.ru) — это проект по сбору и
отображению на карте мира показаний температуры, атмосферного давления,
влажности и т. п. практически в режиме реального времени по фактическому их состоянию
(а не на основе прогнозов), получаемых от различных датчиков среды,
установленных как на улице для публичного доступа, так и в помещении для приватного,
а также от веб-камер для частного или публичного доступа. Передавать показания
датчиков на сайт «Народный мониторинг» можно посредством протоколов TCP/UDP
Глава 13. Arduino и Интернет вещей 283
или HTTP GET/POST. Минимальный интервал передачи показаний датчика —
5 мин (если передавать чаще, то возможна блокировка).
Чтобы стать участником проекта, необходимо зарегистрироваться. Для этого
заходим на сайт http://www.narodmon.ru и выбираем пункт меню Вход | Стать
участником проекта. В регистрационной форме (рис. 13.3) вводим адрес электронной
почты, на который будут отправлены логин и пароль для входа в профиль.
Рис. 13.3. Регистрация на сайте «Народный мониторинг»
Подключим к плате Arduino с установленной на нее платой расширения Ethernet
shield датчик температуры LM335 (рис. 13.4) и настроим передачу показаний этого
датчика на сайт «Народный мониторинг» и отображение их на его карте мира.
Рис. 13.4. Монтажная схема подключения датчика температуры LM335 к плате Arduino
с установленной на ней платой Ethernet shield W5100
284 Часть III. Практическое применение Arduino
Для добавления датчика на карту необходимо выполнить следующие действия:
1. Подключить устройство мониторинга (в нашем случае — плату Arduino с
датчиком LM335) к источнику питания и к сети Интернет (через Ethernet shield).
2. Настроить передачу показаний на сайт «Народный мониторинг» с интервалом
5-15 мин (если чаще, то возможна блокировка).
3. Авторизоваться на сайте «Народный мониторинг», используя свой логин (e-mail
или номер мобильного телефона) и пароль, полученные при регистрации.
4. В разделе сайта Мои Датчики добавить устройство, введя его уникальный
алфавитно-цифровой код (МАС-адрес). Имейте при этом в виду, что добавление
возможно только после успешной передачи показаний на сервер и при верно
указанном МАС-адресе.
5. Выбрать тип данных для каждого из датчиков: температура, влажность,
давление и пр.
6. Установить доступ к показаниям для каждого датчика: публичный (виден всем)
или приватный (только вам).
7. Указать названия для устройства мониторинга и подключенных к нему
датчиков.
8. Выполнить привязку устройства мониторинга к карте, указав полный адрес
его размещения или геокоординаты и щелкнув на строке с адресом в графе
УСТРОЙСТВО раздела сайта Мои Датчики (уточнить местоположение
можно, щелкнув на карте на маркере своего устройства и переместив в нужное место
появившееся всплывающее окно).
Для создания скетча (листинг 13.3) мы возьмем за основу рекомендованный
ресурсом student-proger.ru пример подключения к сервису «Народный мониторинг»
и изменим его под свои требования (сетевые параметры) и датчики.
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0x94, OxDE, 0x80, ОхЗА, 0x90, 0xC9 }; //МАС-адрес 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 };
Глава 13. Arduino и Интернет вещей 285
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
delayA000);
// первое соединение через 15 с после запуска
lastConnectionTime = millis()-postinglnterval+l5000;
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=*nac[k]/16;
int b2=*nac[k]%16;
char cl[2],c2[2];
if (bl>9) cl[0]=(char)(bl-10)+'Af;
else cl[0] = (char)(bl) + '0';
if (b2>9) c2[0]=(char)(b2-10)+'A';
else c2[0] = (char)(b2) + f0f;
cl[l]='\0';
c2[l]='\0f;
strcat(replyBuffer,cl);
strcat(replyBuffer,c2);
}
strcat(replyBuffer,"&");
strcat(replyBuffer,351C4BA0200003B");
strcat(replyBuffer,"=");
286 Часть III. Практическое применение Arduino
char temp[3];
double tmpd=(analogRead(АО)*5.0/1024)П00-273.15;
int tmpi=int (tmpd);
itos(tmpi, temp);
strcat(replyBuffer,temp);
strcat(replyBuffer,f\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.println("Host: narodmon.ru");
client.println("Content-Type: application/x-www-form-urlencoded");
client.print("Content-Length: ");
client.println(len(replyBuffer));
client.println();
client.println(replyBuffer);
client.println();
lastConnectionTime = millisO;
}
else
{
client.stop();
// размер данных
int len(char *buf)
{
int i=0;
do
} while (buf[i]!='\0f);
return i;
// функция int to string
void itos(int n, char bufp[3]) //
char buf[3] = {'0\ f0\ f\0f};
Глава 13. Arduino и Интернет вещей 287
int i = 1;
while (n > 0)
{
buf[i] = (n % 10)+48;
i—;
n /= 10;
}
for (i=0; i<3;
bufp[i]=buf[i];
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\i3\_i3_03
сопровождающего книгу электронного архива (см. приложение 2).
Для передачи данных на сайт «Народный мониторинг» мы здесь используем
резервный протокол передачи HTTP POST/GET на URL http://narodmon.ru/postphp.
HTTP-заголовки для POST следующие:
POST http://narocinon.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=LNG]
После загрузки в плату Arduino этот скетч запускает Ethernet-соединение, плата
получает IP-адрес в Сети, один раз в 5 мин считываются данные с датчика
температуры, формируется строка с данными для отправки на сервер сайта «Народный
мониторинг» и данные отправляются с использованием протокола HTTP POST.
Теперь авторизуемся на сайте, используя логин и пароль, пришедшие на
электронную почту. Выбираем пункт меню Датчики | Мои Датчики | Добавить
устройство и вводим МАС-адрес нашего устройства. Если данные уже были отправлены на
сайт, устройство будет добавлено (рис. 13.5).
Затем выбираем тип данных нашего датчика (температура), устанавливаем доступ
к показаниям (приватный), указываем название устройства мониторинга и
выполняем привязку его к карте, указав полный адрес и щелкнув на строке с адресом.
Выбираем опцию Показать на карте (см. рис. 13.5) и в случае необходимости
корректируем положение всплывающего окна (рис. 13.6).
Через некоторое время мы можем посмотреть временной график изменения данных
датчика на нашем устройстве. Для этого выбираем пункт меню Профиль | Мои
Датчики и значок графика для выбранного датчика. Как можно видеть, на графике
представлено изменение данных датчика во времени (рис. 13.7).
288
Часть III. Практическое применение Arduino
" ' ' ' ' ¦¦ \
— — . _.__ — —; _ . _ .. „._ . ••*'¦-\ i
Рис. 13.5. Добавление устройства на сайте «Народный мониторинг»
Рис. 13.6. Всплывающее окно нашего устройства на карте сайта «Народный мониторинг»
Гпава 13. Arduino и Интернет вещей 289
Рис. 13.7. Временной график переданных на сайт «Народный мониторинг» показаний датчика
13.2. Подключение к Интернету
с помощью платы расширения GSM/GPRS shield
Плата расширения GSM/GPRS shield предоставляет возможность использовать в
Arduino-проектах для удаленного приема и передачи данных сеть мобильной GSM-
связи. GSM/GPRS shield позволяет осуществить это следующими способами:
? прием/отправка SMS;
? передача аудио (голос, CSD, DTMF);
D связь по GPRS.
Рассмотрим один из вариантов этого шилда — SIM900 Quad-Band GPRS shield на
основе микросхемы GSM-модуля SIM900 (рис. 13.8).
Основные характеристики GSM-модуля SIM900:
? четыре диапазона GSM: 850, 900, 1800, 1900 МГц;
? класс передачи данных GPRS multi-slot class 10/8;
? соответствие стандарту GSM фазы 2/2+;
? класс мощности 4 B Вт в диапазонах 850,900 МГц);
? класс мощности 1 A Вт в диапазонах 1800, 1900 МГц);
? управление АТ-командами (GSM 07.07, 07.05 и фирменные АТ-команды
SIMCom);
0 аудиокодеки HR, FR, EFR, AMR, подавление эха;
? С8Бдо14,4Кб1Гг/с;
290 Часть III. Практическое применение Arduino
Рис. 13.8. SIM900 Quad-Band GPRS shield
? РРР-стек;
? встроенный стек TCP/IP, UDP/IP;
? протоколы HTTP и FTP;
? протокол защищенных сокетов SSL;
? декодирование DTMF-tohob;
? e-Mail — формирование и отправка электронных писем посредством АТ-команд;
? SMS Autorun — исполнение АТ-команд, полученных по SMS от определенного
абонента;
? 2,5 Mb user memory — встроенная память для пользовательских данных;
? MMS — формирование, дополнение пользовательскими файлами и отправка с
помощью АТ-команд;
? AMR play — воспроизведение аудиофайлов в динамик или в сторону
удаленного абонента;
? Jamming Detection — функция обнаружения глушения сигнала;
? FOTA — обновление прошивки модуля по беспроводному каналу;
? Easy Scan — получение информации об окружающих базовых станциях без
подключения SIM-карты;
? PING — проверка доступности адреса в Интернете посредством обмена ICMP-
пакетами.
Особенности шилда SIM900 Quad-Band GPRS shield:
? совместимость с Arduino Mega;
? слот для карт SD (включение/отключение при помощи перемычки);
Fnaea 13. Arduino и Интернет вещей
291
О гнездо наушников «два в одном»;
? программное и аппаратное обеспечение последовательного порта — может
общаться с Arduino через последовательный порт программного обеспечения
(D2/D3) или последовательный порт (D0/D1);
? интерфейс FTDI;
О слот батарейки для RTC;
? 10 цифровых входов/выходов GPIO;
G два ШИМ-выхода;
0 интерфейс 12С.
Рассматриваемый шилд имеет два способа включения: аппаратный
(кратковременное нажатие кнопки PWRKEY) и программный (используется выход D7 Arduino).
13.2.1. Отправка и получение SMS-сообщений
с помощью GSM/GPRS shield
В этом примере мы каждые 30 мин будем отправлять на определенный телефонный
номер SMS-сообщение с показаниями аналогового датчика температуры LM335,
подсоединенного к выводу АО платы Arduino (рис. 13.9). Установим SIM-карту
Рис. 13.9. Монтажная схема подключения к плате Arduino модуля GSM/GPRS shield и датчика LM335
292 Часть III. Практическое применение Arduino
в слот GSM/GPRS shield, а сам GSM/GPRS shield — на плату Arduino. С помощью
джамперов соединим контакты для работы через SoftwareSerial-эмуляцию.
Содержимое скетча для отправки SMS показано в листинге 13.4.
// подключение библиотеки SoftwareSerial
#include <SoftwareSerial.h>
// номер телефона для отправки sms (поменяйте на свой)
#define PHONE "+79034461752"
// Выводы для SoftwareSerial (у вас могут быть 7,8)
SoftwareSerial Sim900SerialB, 3);
const int lm335=A0; // для подключения LM335
unsigned long millisl;
void setup()
{
Sim900SerialA9200); // активация последовательного соединения
}
void loop()
{
if (millis()-millisl>30*60*1000) // прошло 30 мин?
{
SendTextMessage(); // отправить sms
millisl=millis ();
// подпрограмма отправки sms
void SendTextMessage()
{
// АТ-команда установки text mode
Sim900Serial.print("AT+CMGF=l\r");
delayA00);
// номер телефона получателя
Sim900Serial.println("AT + CMGS = \"");
Sim900Serial.println(PHONE);
Sim900Serial.println("\"");
delayA00);
// сообщение - данные температуры
double val = analogRead(lm335); // чтение
double voltage = val*5.0/1024; // перевод в вольты
double temp = voltage*100 - 273.15; // в градусы Цельсия
Sim900Serial.println(temp);
delayA00);
// ASCII код ctrl+z - окончание передачи
Sim900Serial.println((charJ6);
Гпава 13. Arduino и Интернет вещей 293
delayA00);
Sim900Serial. println ();
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\13\_i3_04
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем этот скетч в плату Arduino, проверяем его работу и, если все в порядке,
изменяем скетч таким образом, чтобы Arduino отправляла SMS-сообщение с
данными температуры только при получении приходящего сообщения с текстом
"temp" (ЛИСТИНГ 13.5).
tinclude <SoftwareSerial.h>
SoftwareSerial Sim900Serial B, 3) ;
String currStr = ""; //
String phone = ""; //
// True, если текущая строка является sms-сообщением
boolean isStringMessage = false;
void setup ()
{
Serial.beginA9200);
Sim900Serial.beginA9200);
// Настраиваем прием сообщений с других устройств
Sim900Serial.print("AT+CMGF=l\r");
delayC00);
Sim900Serial.print("AT+IFC=1, l\r");
delayC00);
Sim900Serial. print ("AT+CPBS=\ffSM\if\r") ;
delayC00);
Sim900Serial.print("AT+CNMI=l/2f2/lf0\r");
delayE00);
void loop ()
{
if (!Sim900Serial.available())
return;
char currSymb = Sim900Serial.read();
if (»\ri == currSynib)
{
if (isStringMessage) // текущая строка - sms-сообщение,
{
if (!currStr.compareTo("temp")) // текст sms - temp
294 . Часть III. Практическое применение Arduino
// отправить sms на приходящий номер
Sim900Serial.print("AT+CMGF=l\r");
delayA00);
Sim900Serial.print("AT + CMGS = \"");
Sim900Serial.print(phone);
Siin900Serial.println("\"ff) ;
delayA00);
double val - analogRead(AO); // чтение
double voltage = val*5.0/1024; // перевод в вольты
double temp = voltage*100 - 273.15; // в градусы Цельсия
Serial.printIn(temp);
Sim900Serial.println(temp);
delayA00);
Sim900Serial.println((charJ6);
delayA00);
Sim900Serial.println();
}
Serial.println(currStr);
isStringMessage = false;
}
else
{
if (currStr.startsWith("+CMTff)) {
Serial.println(currStr);
// выделить из сообщения номер телефона
phone^currStr.substringG,19);
Serial.println(phone);
//если текущая строка начинается с "+СМТ",
//то следующая строка является сообщением
isStringMessage = true;
currStr = "";
}
else if (f\nf != currSymb)
{
currStr += String(currSymb);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\13\_13_05
сопровождающего книгу электронного архива (см. приложение 2).
Глава 13. Arduino и Интернет вещей 295
13.2.2. Отправка данных на сайт
«Народный мониторинг» через GSM/GPRS shield
В этом примере для отправки данных на сайт «Народный мониторинг» мы
воспользуемся возможностями платы расширения GSM/GPRS shield.
Итак, устанавливаем на плату Arduino GSM/GPRS shield и подключаем к ней
датчик— все, как показано на рис. 13.9. В режиме отправки/получения данных GPRS
модуль SIM900 потребляет ток до 2 А, поэтому ему понадобится внешнее питание.
Для отправки HTTP-данных по GPRS-соединению необходимо выполнить
отправку АТ-команд в следующей последовательности:
1. Первой отправляется команда at — ответ должен быть ок.
2. at+sapbr=i, 1 — установка GPRS-связи.
3. at+sapbr=3, I, "contype", "gprs" — настройка типа подключения: GPRS.
4. AT+SAPBR=3,1, "APN", "internet.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. Дождаться ответа.
11. AT+HTTPREAD ПОЛуЧИТЬ ОТВвТ.
12. at+httpterm — остановить HTTP.
Содержимое скетча отправки данных представлено в листинге 13.6.
tdefine INTERVALSEND 60000
tdefine LM335 АО
iinclude <SoftwareSerial. h>
SoftwareSerial GPRS G, 8) ;
int onModulePin= 9;
char aux_str [150];
char aux;
char data [512];
int data_size;
uint8_t answer=0;
unsigned long millissend=O;
296 Часть III. Практическое применение Arduino
char apn[]="internet.beeline.ru";
char url[150];
String surl="http://narodmon.ru/post.php/?";
void setup()
{
GPRS.beginA9200); // скорость для GPRS
Serial.begin(9600);
Serial.printIn("Starting...");
pinMode(onModulePin,OUTPUT);
power_on();
delayC000);
// точка доступа APN
sendATcoramand ("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", "OK", 2000) ;
snprintf (aux_str, sizeof (aux_str), "AT+SAPBR=3, 1, \"APN\", \"%s\ff", apn) ;
sendATcoramand(aux_strf "OK", 2000);
while (sendATcoramand("AT+SAPBR=1,1", "OK", 2000) == 0)
{
delayB000);
}
delayA000);
void loopO
{
// отправка раз в 10 мин
if (millis() -millissend>INTERVALSEND )
{
// Initializes HTTP service
answer = sendATcoramand("AT+HTTPINIT", "OK", 10000);
if (answer = 1)
{
// Sets CID parameter
answer = sendATcoramand("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 = sendATcoramand(aux_str, "OK", 5000);
if (answer = 1)
{// Starts GET action
answer = sendATcoramand("AT+HTTPACTION=0", "+HTTPACTION:0,200", 10000);
Глава 13. Arduino и Интернет вещей 297
if (answer = 1)
{
sprintf(aux_str, "AT+HTTPREAD");
sendATcoramand(aux_str, "OK", 5000);
}
else
{
Serial.println("Error getting the url");
}
}
else
{
Serial.println("Error setting the url");
}
}
else
{
Serial.println("Error setting the CID");
}
}
else
{
Serial.println("Error initializating");
}
sendATcoramanci ("AT+HTTPTERM", "OK", 5000);
millissend=millis();
// отправка АТ-команд
int8_t sendATcoramand(char* ATcommand, char* expected_answer, unsigned int timeout)
{
uint8_t x=0, answer=0;
char response[150];
unsigned long previous;
memset(response, 'NO1, 150); // Initialize the string
delayA00);
while ( GPRS.available () > 0) GPRS.readO; // Clean the input buffer
GPRS.printIn(ATcoramand); // Отправка АТ-команды
x = 0;
previous = raillisO;
// this loop waits for the answer
do{
if(GPRS.available() != 0)
{
// if there are data in the UART input buffer, reads it and checks for
the asnwer
response [x] = GPRS.readO;
298 Часть III. Практическое применение Ardu'm
// check if the desired answer is in the response of the module
if (strstr(response, expected_answer) != NULL)
{
answer = 1;
// время ожидания ответа
while((answer == 0) && ((millisO - 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);
delayA000);
digitalWrite(onModulePin,HIGH);
delayB000);
digitalWrite(onModulePin,LOW);
delayC000);
answer = sendATcommand(ffAT", "OK", 2000);
if (answer = 0)
{
digitalWrite(onModulePin,LOW);
delayA000);
digitalWrite(onModulePin,HIGH);
delayB000);
digitalWrite(onModulePin,LOW);
delayC000);
digitalWrite(onModulePin,HIGH);
delayC000);
digitalWrite(onModulePin,LOW);*/
// время ожидания ответа
while(answer — 0)
{
// Send AT every two seconds and wait for the answer
answer = sendATcommand("AT", "OK", 2000);
Глава 13. Arduino и Интернет вещей
299
Электронный архив
Полный вариант рассмотренного скетча находится в папке examplesU3^13^06
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем скетч в плату Arduino и проверяем отправку данных на сайт. После
отправки данных можно добавить новое устройство в список устройств своего
профиля на сайте «Народный мониторинг» (рис. 13.10).
Рис. 13.10. Добавление нового устройства на сайте «Народный мониторинг»
13.3. Протокол MQTT
В предыдущих разделах этой главы мы использовали для отправки/получения
данных протокол HTTP. Рассмотрим еще один протокол взаимодействия устройств
IoT — MQTT (Message Queue Telemetry Transport).
Этот протокол обладает рядом преимуществ по отношению к другим протоколам:
? низкое потребление трафика;
? соединение между клиентом и сервером всегда открыто;
? не нагружает интернет-канал;
П отсутствие задержек в передаче данных;
П удобная система подписок на темы (топики);
Все это дает возможности мониторинга и управления в режиме реального времени.
Обмен сообщениями в протоколе MQTT осуществляется между клиентом (client),
который может быть издателем (publisher) или подписчиком (subscriber)
сообщений, и брокером (broker) сообщений (например, Mosquitto MQTT). Издатель и
подписчик не передают друг другу сообщения напрямую, не устанавливают прямой
300
Часть III. Практическое применение Arduino
контакт и могут не знать о существовании друг друга. Издатель отправляет данные
на брокер MQTT, указывая в сообщении определенную тему — топик (topic).
Подписчики могут получать разные данные от множества издателей в зависимости от
подписки на соответствующие топики.
Топики представляют собой символы с кодировкой UTF-8. Иерархическая
структура топиков имеет формат «дерева», что упрощает их организацию и доступ к
данным. Топики состоят из одного или нескольких уровней, которые разделены между
собой символом «/»:
/home/living/living-roonu/tenperature
Устройства MQTT используют определенные типы сообщений для взаимодействия
с брокером — далее представлены основные:
? connect — установить соединение с брокером;
? Disconnect — разорвать соединение с брокером;
? Publish — опубликовать данные в топик на брокере;
? subscribe — подписаться на топик на брокере;
? unsubscribe — отписаться от топика.
Схема взаимодействия между подписчиком, издателем и брокером показана на
рис. 13.11.
Издатель
-1. подключена
JL. подтверждение
подключения
3. публикация
Брокер
•1. подключение-
2. подтверждение
подключения
3. подписка-
%. публикация-
Подписчик
Рис. 13.11. Схема взаимодействия по протоколу MQTT
Однако протокол MQTT требует наличия своего собственного сервера брокера. Тут
есть два выхода: либо создавать свой сервер, либо использовать сторонние
сервисы — например, удобный сервис www.cloudmqtt.com, у которого есть бесплатный
тарифный план (Cute Cat).
После регистрации на этом сервисе, выбора тарифного плана и местоположения
сервера (EU или USA) создается устройство, в котором можно посмотреть ваши
данные: адрес сервера, имя и пароль пользователя, порты подключения и ключ API
key (рис. 13.12).
13.3.1. Отправка данных по протоколу MQTT
Настроим отправку брокеру данных температуры и относительной влажности
воздуха с датчика DHT11. Подключение платы Arduino к сети Интернет реализуем
через Ethernet shield (см. разд. 13.2). Монтажная схема подключения для отправки
данных с датчика DHT11 брокеру MQTT показана на рис. 13.13.
Fnaea 13. Arduino и Интернет вещей
301
о -л4 о=- г-, с?
Рис. 13.12. Данные для взаимодействия с брокером MQTT на сервисе www.cloudmqttcom
Рис. 13.13. Схема подключений для отправки данных с датчика DHT11 брокеру MQTT
302 Часть III. Практическое применение Articling
Содержимое скетча показано в листинге 13.7. При написании скетча мы
воспользуемся библиотекой PubSubClient. С периодичностью 10 с получаем данные с датчика
DHT11 И отправляем на сервер В темы meteo/humidity И /meteo/temperature.
Электронный архив
Библиотека PubSubClient размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
Замените в скетче переменные ip, sdns, gateway, subnet на данные для своей сети.
Если ваша плата получает IP-адрес по DHCP, обратитесь к листингу 13.1.
// Получение статического 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, 28 };
// маска:
byte subnet[] = { 255, 255, 255, 0 };
EthernetClient ethclient;
#include <PubSubClient.h>
// данные mqtt
#define mqtt_server lfm24. cloudmqtt. com"
tdefine mqtt_port 18532
#define mqtt_user "cbadnzof"
tdefine mqtt_pass "j63Z6DzKgogS"
// создание pubsub клиента
PubSubClient client;
// список тем отправки
tdefine topich "/meteo/humidity"
tdefine topict "/meteo/temperature"
tinclude <SimpleDHT.h>
SimpleDHTll dhtll(8);
byte temperature = 0;
byte humidity =0;
Глава 13. Arduino и Интернет вещей 303
II периодичность отправки
unsigned long millist=0;
void setup () {
Serial.begin(9600) ;
// запуск Ethernet-соединения
Ethemet.begin(mac, ip, sdns, gateway, subnet);
delayA000);
Serial.println(Ethernet.locallP());
client.setClient(ethclient);
client.setServer(mqtt_server, mqttjport);
reconnect();
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
if (millis()-millist>10000) {
dht11.read(&temperature, &humidityf NULL);
Serial.print((int)temperature); Serial.print(" *C, ");
Serial.print ((int)humidity); Serial.println(" Hfl);
publishData ((int) temperature, (int)humidity);
//
millist=millis();
// переподключение к mqtt
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...$");
// Attempt to connect
if (client.connect("Arduino+WiFi", mqtt_user, mqtt_pass)) {
Serial.println("Connected to MQTT server$");
}
else {
Serial.println("Could not connect to MQTT server");
Serial.println(" try again in 5 seconds$");
// Wait 5 seconds before retrying
delayE000);
304 Часть III. Практическое применение Arduino
I/ отправка данных в темы брокера
void publishData(int t, int h) {
client.publish(topich, String(h).c_str(), true);
delayE00);
client.publish(topict, String(t).c_str(), true);
delayE00);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\13\_13_07
сопровождающего книгу электронного архива (см. приложение 2).
Загрузив скетч в плату Arduino, заходим в профиль созданного нами устройства на
сайте www.doudmqtt.com и в пункте WEBSOCKET UI видим приходящие в темы
данные (рис. 13.14).
ВШ^Ш^^Ш^^^^^}^^&Щ0Щ
Рис. 13.14. Получение данных на брокере
13.3.2. Получение данных по протоколу MQTT
В разд. 13.3.1 мы рассмотрели отправку показаний температуры и
относительной влажности с датчика DHT11 на брокер MQTT, расположенный по адресу
www.cloudmqtt.com. Рассмотрим теперь получение данных по протоколу MQTT
для управления исполнительными устройствами, подключенными к модулю Relay
shield. Монтажная схема подключения показана на рис. 13.15.
Отправить необходимые команды для управления исполнительными устройствами
можно из вашего профиля на сайте www.cloudmqtt.com, выбрав пункт меню
WEBSOCKET UI и темы: meteo/relayl и /meteo/relay2 (рис. 13.16).
Глава 13. Arduino и Интернет вещей
305
Рис. 13.15. Монтажная схема подключения для управления исполнительными устройствами
по протоколу MQTT
Рис. 13.16. Отправка команд управления из профиля cloudmqtt.com
Чтобы получать команды управления от сервера (брокера), наше устройство при
подключении к брокеру должно подписаться на эти темы:
client.subscribe("/meteo/relayl");
client.subscribe("/meteo/relay2");
306
Часть III. Практическое применение Arduino
Для обработки сообщений от брокера необходимо назначить функцию обратного
вызова callback, которая формирует строку команд управления, отправляемую по
последовательному порту на Arduino:
void callback(char* topic, byte* payload, unsigned int length) {
String ss(topic);
int value=0;
Serial.print(topic);
Serial.print("=")/
for (int i = 0; i < length; i++) {
char receivedChar = (char)payload[i];
if (receivedChar = '0')
{Serial.print(");value=0;}
if (receivedChar = flf)
{Serial.print(");value=l;}
}
if(ss.indexOf("/meteo/relayl")!=-l) {
digitalWrite(pinRelayl,value);Serial.print(" relayl- ok");
}
else if(ss.indexOf(f7meteo/relay2")!=-l) {
digitalWrite(pinRelay2,value);Serial.print(" relay2- ok");
}
Serial.println();
Рис. 13.17. Получение команд от брокера
Глава 13. Arduino и Интернет вещей
307
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\13\_13__08
сопровождающего книгу электронного архива (см. приложение 2).
Загрузив скетч в плату Arduino, открываем монитор последовательного порта и при
отправке команд на сайте www.cloudmqtt.com в темы /meteo/relayl и /meteo/relay2
видим получение сообщений от брокера и установку новых значений для реле
(рис. 13.17).
13.3.3. Android-приложение loT MQTT Dashboard
Более удобный вариант обмена данными по протоколу MQTT— использование
Android-приложения IoT MQTT Dashboard, которое можно задействовать в
качестве пульта, а также для отображения информации, например, с датчиков домашней
метеостанции. Приложение представляет собой готовый MQTT-клиент с
небольшим количеством очень удобных виджетов.
Итак, скачиваем это приложение на смартфон. Сначала создаем новое соединение и
прописываем в нем данные из нашего профиля cloudmqtt (рис. 13.18).
my home meieo
; m24,c;ioudrnqti com ;.
] 18532 :'
Рис. 13.18. Создание соединения
Выбираем созданное соединение и на вкладке PUBLISH создаем виджеты (switch)
для отправки данных в темы /meteo/relayl и /meteo/relay2 (рис. 13.19).
Вкя
а б
Рис. 13.19. Создание виджетов для отправки сообщений в темы
308
Часть III. Практическое применение Arduino
Android-приложение IoT MQTT Dashboard позволяет также настроить отображение
данных, которые отправляются брокеру. Для этого на вкладке SUBSCRIBE надо
создать виджеты для отображения температуры и влажности и подписаться на
топики /meteo/humidity, /meteo/temperature (рис. 13.20). В результате на экране
смартфона мы получим табло с отображением этих данных (рис. 13.21)
Рис. 13.20. Создание виджетов для получения
данных температуры и влажности
из соответствующих топиков
Рис. 13.21. Отображение данных температуры
и влажности на экране смартфона
13.4. Плата Arduino MKR WiFi 1010
для проектов IoT
Плата Arduino MKR WiFi 1010 предназначена, как утверждают ее разработчики,
для тех, кому нужно практичное, компактное и недорогое решение, сочетающее
в себе функционал Wi-Fi и невысокие требования к знаниям в сетевых технологиях.
Она основана на однокристальной системе (SoC) Atmel ATSAMD21G18 с
вычислительном ядром ARM CortexMO, которая является частью семейства SmartConnect
беспроводных устройств Atmel, созданных специально для проектов в области
Интернета вещей.
Чип ATSAMW25 состоит из трех главных блоков:
? 32-битного ARM-микроконтроллера ATSAMD21G18 с низким
энергопотреблением;
? модуля беспроводной связи NINA-W1Q от компании u-blox со встроенным
чипом ESP32. Модуль обеспечивает беспроводной обмен данными в диапазоне
2,4 ГГц по протоколам Wi-Fi и Bluetooth;
? крипточипа ЕСС508 для защиты передаваемых данных.
Плата включает в себя схему зарядки Li-Po, которая позволяет Arduino MKR WiFi 1010
работать от батареи или от внешнего источника 5 В, заряжая батарею Li-Po во
время работы от внешнего источника питания. Переключение с одного источника на
другой осуществляется автоматически.
Модуль Wi-Fi платы MKR WiFi 1010 поддерживает сертификат SHA-256.
Глава 13. Arduino и Интернет вещей
309
Хорошая 32-битная вычислительная мощность, богатый набор интерфейсов
ввода/вывода, маломощный Wi-Fi с крипточипом для безопасной связи и простота
использования программного обеспечения Arduino IDE для разработки кода и
программирования— все эти функции делают плату MKR WiFi 1010
предпочтительным выбором для новых проектов IoT с батарейным питанием в компактном форм-
факторе.
Рассмотрим процесс программирования этой платы. В среде программирования
Arduino IDE необходимо установить поддержку для Arduino SAMD C2bit ARM
Cortex-M0+). Для этого заходим в Менеджер плат (Инструменты | Плата |
Менеджер плат), находим Arduino SAMD и нажимаем на кнопку Установка
(рис. 13.22 и 13.23).
Рис. 13.22. Находим Arduino SAMD в Менеджере плат и нажимаем на кнопку Установка
После этого в меню Инструменты Arduino IDE появится плата Arduino MKR 1000
(рис. 13.24).
Примечание
Как можно видеть на рис. 13.23, установка поддержки для Arduino SAMD в Arduino IDE
обеспечивает поддержку всех плат Arduino MKR. Поэтому не стоит удивляться, что
в меню Инструменты Arduino IDE все они определяются как Arduino MKR1000.
Одной из основных особенностей MKR WiFi 1010 является возможность доступа
к сети Wi-Fi. Для этого необходимо установить библиотеку WiFi 101. Установим ее
с помощью Менеджера библиотек, выполнив команду меню Скетч | Подключить
библиотеку | Управление библиотеками,— находим библиотеку WiFi 101 и
нажимаем на кнопку Установка (рис. 13.25).
Теперь загрузим в плату Arduino MKR WiFi 1010 пример из библиотеки ScanNetworks
(WiFilOl | ScanNetworks) для сканирования точек доступа Wi-Fi (рис. 13.26).
310
Часть III. Практическое применение Arduino
Рис. 13.23. Установка поддержки для Arduino SAMD в Arduino IDE
Рис. 13.24. Выбор платы Arduino MKR1000
Глава 13. Arduino и Интернет вещей
311
v 1С: ^^
' * ... .% ..
Рис. 13.25. Установка библиотеки WiFM01
Рис. 13.26. Сканирование точек доступа W-iFi
312 Часть Ш. Практическое применение Arduino
А затем подключимся к точке доступа Wi-Fi, загрузив пример из библиотеки
ConnectWithWPA (WiFilOl | ConnectWithWPA) и установив в скетче значения
SSID и пароль (рис. 13.27).
Рис. 13.27. Пример подключения к точке доступа Wi-Fi
13.5. Отправка данных в облако
Arduino loT Cloud и получение их оттуда
В феврале 2019 г. компания Arduino объявила, что бета-версия их собственного
облачного сервиса Arduino IoT становится общедоступной. С запуском Arduino IoT
Cloud компания Arduino предоставляет миллионам своих пользователей полный
комплексный подход к Интернету вещей, который включает аппаратное
обеспечение, встроенное ПО, облачные сервисы.
Arduino IoT Cloud — это способ Arduino демократизировать разработку IoT,
позволяющий каждому легко создавать приложения для Интернета вещей. Это дает
возможность устройствам на основе IoT обмениваться данными между собой и
облаком, где может выполняться дальнейшая их обработка, и использовать эти данные
для решения конкретных проблем. Платформа позволяет общаться через
множество протоколов, в том числе HTTP REST API, MQTT, инструменты командной
строки, Javascript и веб-сокеты. Arduino IoT Cloud имеет также инструменты, которые
позволяют автоматически генерировать эскиз/код для вашего устройства, что по-
Глава 13. Arduino и Интернет вещей
313
могает сократить время разработки с часов до минут. Поддерживая типичный
открытый исходный код и другие клоны Arduino, Arduino IoT Cloud позволяет
подключать к платформе различные устройства, в том числе и платы на основе Linux.
Рассмотрим пример создания проекта, взаимодействующего с облаком IoT Arduino
в части отправки и получения данных, для чего соберем схему, показанную на
рис. 13.28.
Но прежде всего в Arduino IoT Cloud необходимо зарегистрироваться, перейдя
в браузере по адресу: https://create.arduino.cc/io/ (рис. 13.29).
11
Рис. 13.28. Монтажная схема для взаимодействия с Arduino IoT Cloud
я
Рис. 13.29. Страница регистрации в сервисе Arduino IoT Cloud
314 . Часть III. Практическое применение Arduino
Зарегистрировавшись и войдя в профиль, на следующей странице мы нажимаем
кнопку Add new thing, которая позволяет нам настроить новое устройство IoT
(новую «вещь») на облачной платформе, присвоив ей имя и выбрав используемую
нами плату (рис. 13.30). При этом потребуется сначала сконфигурировать плату,
выполнив процедуру начала работы.
Рис. 13.30. Добавление нового устройства
Затем добавляем свойство «вещи» (рис. 13.31). В нашем случае — это значение
потенциометра.
Рис. 13.31. Добавление свойства «вещи» (для потенциометра)
Глава 13. Arduino и Интернет вещей 315
Рис. 13.32. Добавление переключателя ON/OFF для отправки данных из облака на плату
Для управления светодиодом с веб-страницы (отправки данных из облака на плату)
создадим элемент — переключатель ON/OFF (рис. 13.32).
Теперь переходим в Web editor для создания скетча — шаблон скетча там уже
создан. Добавляем данные для подключения к точке доступа Wi-Fi, получение данных
потенциометра и обработку данных из облака при использовании переключателя.
Здесь же мы можем загрузить скетч в плату или сохранить на компьютере.
Содержимое скетча показано в листинге 13.8.
1. // Подключение библиотек
iinclude <WiFil01.h>
Itinclude "thingProperties. h"
// служебные переменные
unsigned long lastConnectionTime = 0;
const unsigned long postinglnterval = 2000;
// статус светодиода
int led_status=2;
void setup () {
// Открытие последовательного порта
Serial.begin(9600);
delayA500);
316
Часть III. Практическое применение Arduino
I/ пин подключения светодиода
pinModeF,OUTPUT);
// инициализировать свойства initProperties();
initProperties();
// подключение к облаку Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
//
setDebugMessageLevelB);
ArduinoCloud.printDebuglnfо();
void loop() {
ArduinoCloud.update();
// отправка по интервалу
if (millisO - lastConnectionTime > postinglnterval) {
Pot=map(analogRead(AO),0,1023,0,10000) ;
Serial.println(Pot);
lastConnectionTime=mLllis ();
}
// изменение состояния светодиода
if (led_status=l) {
digitalWriteF,HIGH);
}
else if(led_status==0) {
digitalWriteF,LOW);
void onLedChange() {
if (led == true)
led_status =1;
else
led_status = 0;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examplesM3^13^09
сопровождающего книгу электронного архива (см. приложение 2).
В профиле созданной «вещи» на вкладке Dashboard мы можем видеть наши вид-
жеты с данными потенциометра и переключателем для изменения состояния
светодиода (рис. 13.33).
Глава 13. Arduino и Интернет вещей 317
Рис. 13.33. Веб-страница созданной «вещи»
ГЛАВА 14
RFID-идентификация
14.1. Считыватель RFID RC522
RFED— это технология автоматической бесконтактной идентификации объектов
при помощи радиочастотного канала связи. Любая RFID-система состоит из:
? RFID-метки;
? считывателя информации (RFID-ридера);
? микроконтроллера или компьютера для дальнейшей обработки информации.
Идентификация объектов производится по уникальному цифровому коду, который
считывается из памяти электронной метки, прикрепленной к объекту
идентификации.
Считыватель содержит в своем составе передатчик и антенну и посылает в эфир
электромагнитные сигналы определенной частоты. RFID-метки «отвечают» на
запрос считывателя собственным сигналом, который содержит информацию об
идентификационном номере метки и данные об объекте, им оснащенной. Этот сигнал
улавливается антенной считывателя, информация расшифровывается и передается
для дальнейшей обработки.
Считыватель RC522 представляет собой RFID-модуль, работающий на частоте
13,56 МГц с SPI-интерфейсом. В комплекте к модулю идут две RFID-метки: в виде
карты и брелока. В RFID-метках, работающих на указанной частоте, реализована
криптографическая защита, что уберегает от копирования и подделки.
Монтажная схема подключения RFID-модуля RC522 к плате Arduino показана на
рис. 14.1. Обратите внимание, что питание модуля осуществляется напряжением
3,3 В!
Для взаимодействия Arduino с модулем RC522 мы применим Arduino-библиотеку
MFRC522.
Электронный архив
Библиотека MFRC522 размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
Глава 14. RFlD-идентификация 319
Рис. 14.1. Монтажная схема подключения RF ID-модул я RC522 к плате Arduino
Установим библиотеку и напишем скетч вывода UID-метки и ее типа в
последовательный порт (листинг 14.1).
// Подключение библиотек
tinclude <SPI.h>
finclude <MFRC522.h>
// константы подключения контактов SS и RST
tdefine RST_PIN 9
fdefine SS_PIN 10
// Инициализация MFRC522
MFRC522 mfrc522(SS_PIN, RST_PIN) ; // Create MFRC522 instance.
void setup () {
Serial.begin(9600); // инициализация последовательного порта
SPI.beginO; // инициализация SPI
mfrc522.PCD Init(); // инициализация MFRC522
void loop() {
if ( ! mfrc522.PICC_IsNewCardPresent())
return;
320
Часть III. Практическое применение Arduino
/I чтение карты
if ( ! mfrc522.PICC_ReadCardSerial())
return;
// показать результат чтения UID и тип метки
Serial.print(F("Card UID:"));
dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
Serial.println();
Serial.print(F("PICC type: "));
byte piccType = infrc522.PICC_GetType(mfrc522.uid.sak);
Serial.println(mfrc522.PICC_GetTypeName(piccType));
delayB000) ;
}
// Вывод результата чтения данных в НЕХ-виде
void dump_byte_array(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
Загрузите скетч в плату Arduino. При поднесении меток (брелоков и карт) к модулю
RFID-считывателя RC522 в монитор последовательного порта выводится UID
(уникальный идентификатор) и тип метки (рис. 14.2).
Рис. 14.2. Вывод в монитор последовательного порта уникальныого идентификатора и типа метки
Глава 14. RFID-идентификация 321
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\U\_i4_0i
сопровождающего книгу электронного архива (см. приложение 2).
14.2. Организация контроля доступа
по RFID-меткам
Создадим проект организации доступа по RFID-меткам. Arduino будет отправлять
сигнал на срабатывание реле (например, для открытия электромеханического
замка). Доступ осуществляется только для меток из списка. Монтажная схема
подключения RFID-модуля RC522 к плате Arduino показана на рис. 14.3.
Рис. 14.3. Схема соединений для организации доступа с помощью RFID-меток
Приступим к написанию скетча. Уникальные идентификаторы карт или брелоков,
по которым доступен вход, запишем в массив uidok:
byte uidok[] [4] = {
{0xllf0x22f0x33,0x44}f
{0x11,0x22,0x33,0x45}
};
Пин для подключения реле:.
tdefine RELAY RC522 PIN 4
322 Часть III. Практическое применение Arduino
В цикле будем считывать данные с поднесенной карты или брелока, затем сверять
UID карты со списком разрешенных UTO и, если карта присутствует в списке,
посылать на реле сигнал срабатывания (уровень low).
Содержимое скетча приведено в листинге 14.2.
# // подключение библиотек
#include <LiquidCrystal.h>
#include <SPI.h>
#include <MFRC522.h>
// пин для подключения реле
#define RELAY_RC522_PIN 2
// пин для подключения динамика
#define SPEAKER_PIN АО
// уровни для включения/выключения реле
¦define RELAY_ON О
#define RELAY_OFF 1
// Инициализация MFRC522
// константы подключения контактов SS и RST
tdefine RST_PIN 3
#define SS_PIN 10
// Создание экземпляра MFRC522
MFRC522 mfrc522(SS_PIN, RST_PIN) ;
// создаем экземпляр объекта дисплея
LiquidCrystal lcd(8f9,4,5,6,7);
// массив разрешенных uid
byte uidok[][4]={
{OxEO, 0х2А, 0x87, OxlB},
{0xD9, OxFA, 0x90f 0x55}f
{0x36, OxAE, 0x59, 0xA5 }
void setup() {
// инициализация дисплея
led.beginA6,2);
// очистить
led.clear();
// инициализация SPI
SPI.begin();
// инициализация MFRC522
mfrc522.PCD_Init();
// сконфигурировать вывод реле как OUTPUT
pinMode(RELAY RC522 PIN,OUTPUT);
Глава 14. RFlD-идентификация 323
//и выключить
digitalWrite(RELAY_RC522_PINf RELAY_OFF);
// сконфигурировать вывод динамика
pinMode(SPEAKER_PIN, OUTPUT);
void loop () {
if (mf rc522. PICC_IsNewCardPresent ()) {
// чтение карты
if ( mfrc522.PICC_ReadCardSerial()) {
// показать результат чтения UID
if(compare_uid(mfrc522.uid.uidByte/ mfrc522.uid.size)) {
lcd.setCursorD,1);
led.print("OK !!!");
tone(SPEAKER_PIN,494,300);
delayE00);
tone(SPEAKER_PIN,440,200);
// включить реле
digitalWrite (RELAY_RC522_PIN, RELAYJDN) ;
delayD000) ;
digitalWrite(RELAY_RC522_PIN, RELAY_OFF);
} else {
led.setCursorD,1);
led.print("NO !!!");
tone(SPEAKER_PIN, 293, 300) ;
delayE00) ;
tone(SPEAKER_PIN,329,500);
delayA000);
Загрузим этот скетч в плату Arduino и проверим работу ограничения доступа с
помощью RFID.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examplesU4\_UJJ
сопровождающего книгу электронного архива (см. приложение 2).
14.3. Запись информации на RFID-метку
Ъразд. 14.1 и 14.2 мы создали скетчи для считывания UID (уникального
идентификатора) RFID-меток, работающих на частоте 13,56 МГц, что позволяет
использовать такие метки для организации систем контроля доступа. Но каждая метка,
кроме UDD, имеет память, в которую можно записывать данные и из которой счи-
324 Часть III. Практическое применение Arduino
Рис. 14.4. Метки Mirafe Ultralight
тывать их. Рассмотрим самые простые работающие на частоте 13,56 МГц метки
Mirafe Ultralight, выпускаемые в виде наклеек (рис. 14.4).
Эти метки имеют 64 байта памяти, организованные в 16 блоков по 4 байта. Чтобы
посмотреть содержимое памяти (дамп памяти) метки, соберем схему,
представленную на рис. 14.1, и загрузим в плату Arduino скетч из листинга 14.3,
осуществляющий чтение и вывод в последовательный порт дампа памяти метки.
// Подключение библиотек
#include <SPI.h>
#include <MFRC522.h>
// константы подключения контактов SS и RST
#define RST_PIN 9
#define SS_PIN 10
// Инициализация MFRC522
MFRC522 mfrc522(SS_PIN, RST_PIN) ;
void setup() {
Serial.begin(9600); // инициализация последовательного порта
SPI.beginO; // инициализация SPI
mfrc522.PCD_Init(); // инициализация MFRC522-
ShowReaderDetails(); // данные ридера
Serial.println(F("Scan PICC to see UID, type, and data blocks..."));
void loopO {
// Ожидание прикладывания новой RFID-метки:
if ( ! mfrc522.PICC_IsNewCardPresent())
return;
// чтение карты
if ( ! mfrc522.PICC_ReadCardSerial())
return;
// показать результат чтения UID и тип метки
// Вывод дампа памяти метки
mfrc522.PICC_DumpToSerial (& (mfrc522.uid)) ;
Глава 14. RFID-идентификация 325
void ShowReaderDetails() {
// Версия по для MFRC522
byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
Serial.print(F("MFRC522 Software Version: Ox"));
Serial.print(v, HEX);
if (v = 0x91)
Serial.print(F(" = vl.O"));
else if (v = 0x92)
Serial.print(F(" = v2.0"));
else
Serial.print(F(" (unknown)"));
Serial.println("ff);
// Если 0x00 или OxFF, ошибка подключения
if ((V == 0x00) || (v = OxFF)) {
Serial.printIn(F("WARNING: Communication failure, is the MFRC522 properly
connected?"));
Загрузив скетч в плату Arduino, откроем монитор последовательного порта и при
поднесении меток к считывателю увидим вывод дампа памяти метки Ultralight
(рис. 14.5).
Рис. 14.5. Вывод в монитор последовательного порта дампа памяти RFID-метки Mirafe Ultralight
326
Часть III. Практическое применение Arduino
Электронный архив
Полный вариант рассмотренного скетча находится в папке ехатр/евМ^и^З
сопровождающего книгу электронного архива (см. приложение 2).
Структура данных меток Mifare Ultralight приведена на рис. 14.6:
? В байтах SN0-SN7 — хранится UID метки;
? LockO, Lockl — блокировка страниц данных, например:
• Охоооо — страницы 4-7 доступны для записи;
• Oxffoo — блокированы страницы 4-11;
• Oxfffo — блокированы страницы 4-15;
? ОТРО-ОТРЗ — однократно записываемые данные;
? DataO-Data47 — для записи данных.
Рис. 14.6. Структура данных меток Mifare Ultralight
Запись данных на метку и считывание данных с метки производятся поблочно. Как
уже отмечалось ранее, размер блока меток Ultralight— 4 байта. Составим скетч
отправки в метку по последовательному порту строки вида:
*хх;уу;#
где:
? хх — номер страницы;
П уу — данные для первых двух байтов страницы хх.
Гпава 14. RFlD-идентификация 327
После получения и парсинга строки записываем данные в нужный блок.
Скетч получения данных из метки по последовательному порту и запись данных на
метку представлены в листинге 14.4.
// Подключение библиотек
iinclude <SPI.h>
iinclude <MFRC522.h>
// константы подключения контактов SS и RST
fdefine RSTJPIN 9
idefine SS_PIN 10
// Инициализация MFRC522
MFRC522 mfrc522(SS_PIN, RST_PIN) ;
// последовательный порт Arduino
String inputStringO = "";
boolean stringCompleteO = false;
unsigned int page_serial;
unsigned int data_serial;
void setup () {
Serial.begin(9600); // инициализация последовательного порта
SPI.begin(); // -инициализация SPI
mfrc522.PCD_Init(); // инициализация MFRC522
ShowReaderDetails(); // данные ридера
Serial.println(F("Scan PICC to see UID, type, and data blocks..."));
inputStringO.reserveB00);
void loop() {
//
if (stringCompleteO) {
Serial.println(inputStringO);
if(!parse_stringO())
{Serial.print("ERROR1");Serial.println(inputStringO);}
else {
page_serial=max(minA5,page_serial),7);
data_serial=minA000,data_serial);
}
// clear the string:
inputStringO = "";
stringCompleteO = false;
}
// Ожидание прикладывания новой RFID-метки:
if (mfrc522.PICC_IsNewCardPresent().) {
// чтение карты
if (mfrc522.PICC ReadCardSerial()) {
328 Часть ///. Практическое применение Arduino
if(data_serial>0 && page_serial>0) {
byte buf[] = {0x00, 0x00, 0x00, 0x00};
buf[0]=highByte(data_serial);
buf[1]=lowByte(data_serial);
//Запись на карту на страницы 8,9 или 10-4 байта
Serial.println(mfrc522.GetStatusCodeName(mfrc522.MIFARE_
Ultralight_Write(page_serial, buf, 4)));
// Вьюод дампа данных
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
delayB000);
// SerialEvent
void serialEvent() {
while (Serial.available()) {
// получить очередной байт:
char inChar = (char)Serial.read()
// /n - конец передачи
if (inChar == f#f)
stringCompleteO = true;
else
// добавить в строку
inputStringO += inChar;
// парсинг строки последовательного порта Serial
boolean parse_stringO() {
int sl,s2;
int lengthl=inputStringO.length();
if(inputStringO.charAt(O)!='*')
return false;
if(inputStringO.charAt(lengthl-1)!=';')
return false;
//
for(int i=l;i<lengthl;i++)
{if(inputStringO.charAt(i)==f;f)
{sl=i;break;}
}
page_serial=inputStringO.substringA,si).tolnt();
// action
for(int i=sl+l;i<lengthl;i++)
{if(inputStringO.charAt(i)—f;')
{s2=i;break;}
Глава 14. RFID-идентификация 329
data_serial=inputStringO.substring(sl+1,s2).tolnt();
return true;
}
void ShowReaderDetails() {
// Версия по для MFRC522
byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
Serial.print(F(WMFRC522 Software Version: Ox"));
Serial.print(v, HEX);
if (V = 0x91)
Serial.print(F(" = vl.O"));
else if (v == 0x92)
Serial.print(F(" = v2.0"));
else
Serial.print(F(" (unknown)"));
Serial.println("");
// Если 0x00 или OxFF, ошибка подключения
if ((v == 0x00) M (v == OxFF)) {
Serial.printIn(F("WARNING: Communication failure, is the MFRC522 properly
connected?"));
g^yyg^^
Рис. 14.7. Запись данных в память RFID-метки Mirafe Ultralight
330
Часть III. Практическое применение Arduino
Загружаем скетч в плату Arduino и проверяем его работу: отправляем строки из
монитора последовательного порта и видим изменение данных в памяти метки
(рис: 14.7).
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\14\_14_04
сопровождающего книгу электронного архива (см. приложение 2).
Л АЛ. Проект «Говорящая фотография»
Используем для проекта три фотографии характерных объектов. Приклеим к
каждой фотографии с обратной стороны метку-наклейку Ultralight. При поднесении
к фотографии (в районе метки) RFro-считывателя RC522 модуль DFPlayer Mini
будет воспроизводить предварительно записанный для каждой фотографии МРЗ-файл
с текстом.
Схема соединений проекта показана на рис. 14.8.
Рис. 14.8. Схема соединений проекта «Говорящая фотография»
Прежде всего необходимо записать на SD-карту музыкальные файлы:
1. Подключим SD-карту через картридер к компьютеру и отформатируем ее в
файловой системе FAT 16 или FAT32.
2. Создадим в корневом каталоге карты папку с названием трЗ.
3. Запишем в эту папку в качестве звуковых описаний для каждой фотографии
соответствующие МРЗ-композиции и дадим им имена: 0001 .трЗ, 0002.трЗ и
ОООЗ.трЗ.
Глава 14. RFlD-идентификация 337
С помощью скетча из листинга 14.4 запишем на 15-ю страницу каждой из трех
меток UltraLight следующие данные:
?I *15,1;# — для первой метки;
? *15;2;# — для второй метки;
? *15;3;# — для третьей метки.
А теперь напишем скетч получения данных из метки (байты 0 и 1 со страницы 15)
и воспроизведения соответствующих МРЗ-файлов на модуле DFPlayer Mini
(листинг 14.5).
// Подключение библиотек
tinclude <SPI.h>
tinclude <MFRC522.h>
// константы подключения контактов SS и RST
tdefine RST_PIN 9
tdefine SS_PIN 10
// Инициализация MFRC522
MFRC522 mfrc522(SS_PIN, RST_PIN);
// Подключение библиотек
tinclude <SoftwareSerial.h>
#include <DFPlayer_Mini_Mp3.h>
// Создание объекта подключения по SoftwsreSerial
SoftwareSerial mySerialB, 3); // RX, TX
void setup() {
Serial.begin(9600); // инициализация последовательного порта
SPI.beginO; // инициализация SPI
mfrc522.PCD_Init(); // инициализация MFRC522
ShowReaderDetails(); // данные ридера
// запуск Software Serial
mySerial.begin (9600);
mp3_set_serial (mySerial);
void loop() {
//
if (mf rc522. PICC_IsNewCardPresent ())
// Select one of the cards
if (mfrc522.PICC_ReadCardSerial() ]
int teksongl=getDataLabelA5);
if (teksongl—Oxffff) {
Serial.println("error");
332 Часть III. Практическое применение Arduino
else if(teksongl>0) {
teksong=teksongl;
mp3_play(teksong);
}
Serial.println(teksongl);
// данные карты
void ShowReaderDetails() {
// Версия по для MFRC522
byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
Serial.print(F("MFRC522 Software Version: Ox"));
Serial.print(v, HEX);
if (v = 0x91)
Serial.print(F(" = vl.O"));
else if (v == 0x92)
Serial.print(F(" = v2.0"));
else
Serial.print(F(" (unknown)")) ;
Serial.println("");
// Если 0x00 или OxFF, ошибка подключения
if ((v == 0x00) || (v == OxFF)) {
Serial.println(F("WARNING: Communication failure, is the MFRC522 properly
connected?"));
// получение данных 15 страница байты 0 и 1
unsigned int getDataLabel(int pagel) {
byte status;
byte byteCount;
byte bufferl[4];
byte i;
int page;
int offset;
unsigned int res=0;
// Read pages
byteCount = sizeof(bufferl);
page=pagel;
status = mfrc522.MIFARE_Read(page, bufferl, SbyteCount);
if (status != 1) {
Serial.print(F("ltflFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return Oxffff;
Глава 14. RFID-идентификация 333
11 data
res= (buf ferl [0] «8) +buf ferl [1] ;
return res;
Загружаем скетч в плату Arduino и проверяем его работу. Теперь каждая ваша
фотография сможет рассказать о себе интересную историю.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\14\_U_05
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 15
Специальные возможности
отдельных плат Arduino
Существует несколько версий плат Arduino, специально разработанных для
определенных задач. Рассмотрим их использование на конкретных примерах.
15.1. Использование Arduino Leonardo
в качестве USB-устройства
Возможно, наиболее важным моментом для любой платы Arduino является ее
способность быть запрограммированной через последовательный порт USB. Это
позволяет программировать Arduino без специального оборудования — такого,
например, как программатор. В случае Arduino программатор уже встроен в плату.
К тому же эта возможность обеспечивает прямое подключение к интегрированному
универсальному синхронному/асинхронному приемнику и передатчику ATmega
(USART). Используя этот интерфейс, вы можете обмениваться данными между
платой Arduino и компьютером.
У разных плат Arduino возможности последовательного соединения различны —
как с точки зрения аппаратной реализации адаптеров USB-to-serial, так и с точки
зрения программной поддержки тех или иных функций.
Для начала необходимо понять разницу между последовательным портом и USB.
Микроконтроллеры ATmega328, которыми укомплектованы Arduino Uno, имеют
один аппаратный последовательный порт. Он включает выводы ТХ (передача)
и RX (получение), к которым можно получить доступ на цифровых выводах 0 и 1.
Плата Arduino оборудована загрузчиком, который позволяет программировать ее
по последовательному интерфейсу. Это те выводы, которые
«мультиплексированы» (т. е. выполняют более одной функции), — они служат и для линий
приема/передачи кабеля USB. Но последовательный порт и порт USB несовместимы.
Устранение этой проблемы на Arduino осуществляется двумя способами. Первый
способ— добавление вторичной микросхемы-преобразователя, что применяется,
например, на платах Arduino Uno. Второй — использование
микроконтроллера, имеющего встроенный USB (например, микроконтроллер 32U4 в Arduino
Leonardo).
Глава 15. Специальные возможности отдельных плат Arduino
335
Плата Arduino Leonardo была первой платой, имеющей только одну микросхему —
микроконтроллер 32U4, — которая выполняет функции и программируемого
пользователем микроконтроллера, и интерфейса USB. То есть Arduino Leonardo (и
подобные платы Arduino) укомплектованы микроконтроллером, в который прямая
передача USB уже встроена. В результате плата может более легко использоваться
для эмуляции (имитации) USB-устройств, таких как клавиатура, мышь или
джойстик. При этом обычный порт USART на ATmega не мультиплексирован с
выводами интерфейса USB, поэтому связь с главным компьютером и вторичным
последовательным устройством (таким как модуль GPS) может происходить одновременно.
15.1.1. Arduino Leonardo: имитация клавиатуры
Для плат Arduino с прямой поддержкой USB в Arduino IDE, начиная с версии 1.01,
включены два класса, обеспечивающие поддержку мыши и клавиатуры. Функции
клавиатуры позволяют плате Arduino (Leonardo, Micro или Due) отправлять
нажатия клавиш на подключенный компьютер. Вот список этих функций:
? Keyboard.begin () — запускает эмуляцию клавиатуры;
? Keyboard, end () — завершает эмуляцию клавиатуры;
? Keyboard.press о — имитация нажатия и удерживания функциональных клавиш
клавиатуры;
? Keyboard.print о — отправляет последовательность кодов нажатых клавиш на
компьютер;
? Keyboard, print in о — отправляет последовательность кодов нажатых клавиш на
компьютер с добавлением кодов новой строки и возврата каретки;
? Keyboard, release о — завершает имитацию удерживания для функциональной
клавиши клавиатуры;
? Keyboard.reieaseAii о — завершает имитацию нажатия и удерживания всех
нажатых функциональных клавиш клавиатуры;
? Keyboard, write о — отправляет коды нажатия и отпускания клавиш на
компьютер.
Поддерживается также эмуляция клавиш-модификаторов (табл. 15.1).
Таблица 15.1. Список клавиш-модификаторов объекта Keyboard
Ключ
KEY_LEBT_CTRL
KEY_LEFT_SHIFT
KEY_LEFT_ALT
KEY_LEFT_GUI
KEY_RIGHT_CTRL
Шестнадцатеричное значение
0x80
0x81
0x82
0x83
0x84
Десятичное значение
128
129
130
131
132
336
Часть III. Практическое применение Arduino
Таблица 15.1 (окончание)
Ключ
KEY_RIGHT_SHIFT
KEY_RIGHT_ALT
KEY_RIGHT_GUI
KEY_UP_ARROW
KEY_DOWN_ARROW
KEY_LEFT_ARROW
KEY_RIGHT_ARROW
Key Backspace
Key_Tab
Key Return
KEY_ESC
Key Insert
Key Delete
KEY_PAGE_UP
KEY_PAGE_DOWN
KEY_HOME
Key End
KEY_CAPS_LOCK
Key_Fl
Key_F2
Key_F3
Key_F4
Key_F5
Key_F6
Key_F7
Key_F8
Key_F9
Key_F10
Key_Fll
Key_F12
Шестнадцатеричное значение
0x85
0x86
0x87
OxDA
0xD9
0xD8
0xD7
0xB2
ОхВЗ
OxBO
OxBl
OxDl
0xD4
0xD3
0xD6
0xD2
0xD5
OxCl
0xC2
ОхСЗ
0xC4
0xC5
0xC6
0xC7
0xC8
0xC9
OxCA
OxCB
OxCC
OxCD
Десятичное значение
133
134
135
218
217
216
215
178
179
176
177
209
212
211
214
210
213
193
194
195
196
197
198
199
200
201
202
203
204
205
Глава 15. Специальные возможности отдельных плат Arduino 337_
15.1.2. Блокируем клавиатуру с наступлением темноты
Создадим простой пример использования объекта Keyboard — например, реализуем
блокировку клавиатуры компьютера при наступлении темноты. Для этого
подсоединим к аналоговому входу АО платы Arduino Leonardo фоторезистор и при
наступлении темноты будем отправлять на компьютер комбинацию клавиш,
блокирующую компьютер (для Windows — это комбинация <Windows>+<L>). Содержимое
скетча представлено в листинге 15.1.
const int LIGHT =A0; // Датчик освещенности на вывод 1
const int THRESHOLD =200; // Значение с датчика освещенности
// для блокировки компьютера
void setup {)
{
Keyboard.begin();
}
void loopO
{
int brightness = analogRead(LIGHT); // Чтение данных датчика
if (brightness < THRESHOLD)
{
Keyboard.press(KEY_LEFT_GUI);
Keyboard.press('1');
delayA00);
Keyboard.releaseAll();
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\15\_15JI
сопровождающего книгу электронного архива (см. приложение 2).
15.1.3. Arduino Leonardo:
имитация компьютерной мыши
Функции мыши позволяют плате Arduino Leonardo управлять положением мыши на
подключенном компьютере. Вот список этих функций:
? Mouse. begin () — запускается эмуляция мыши на подключенном компьютере;
? Mouse. click () — эмулирует нажатие и отпускание кнопки мыши:
• mouseleft (по умолчанию) — левая кнопка;
• mouseright — правая кнопка;
• mouse_middle — средняя кнопка;
338
Часть III. Практическое применение Arduino
? Mouse. end () — завершается эмуляция мыши на подключенном компьютере;
? Mouse.move о — перемещение курсора на подключенном компьютере
(относительно текущего положения курсора);
? Mouse.press о — эмуляция нажатия и постоянного удерживания кнопки мыши,
нажатие отменяется функцией Mouse. release ():
• mouseleft (по умолчанию) — левая кнопка;
• mouseright — правая кнопка; | i
• mouse_middle — средняя кнопка;
? Mouse. release () — отмена нажатия и постоянного
удерживания кнопки мыши;
? Mouse.isPressedO — проверяет текущее состояние
кнопок мыши.
Используя двухосевой джойстик (рис. 15.1) и
несколько кнопок, с помощью Arduino Leonardo можно
сделать свою собственную мышь! Джойстик будет
контролировать местоположение указателя мыши, а
кнопки — выполнять функции левой, средней и
правой ее кнопок.
Рис. 15.1. Двухосевой джойстик
Монтажная схема эмулятора компьютерной мыши на
Arduino Leonardo представлена на рис. 15.2.
Рис. 15.2. Монтажная схема подключения эмулятора компьютерной мыши
Глава 15. Специальные возможности отдельных плат Arduino ЗЗЦ
Содержимое скетча для эмулятора компьютерной мыши представлено в
листинге 15.2.
const int LEFT_BUTTON=4; // Вход для левой кнопки мыши
const int MIDDLEJ3UTTON=3; // Вход для средней кнопки мыши
const int RIGHT_BUTTON =2; // Вход для правой кнопки мыши
const int X_AXIS=0; // Аналоговый вход для оси х джойстика
const int Y_AXIS=1; // Аналоговый вход для оси у джойстика
void setup ()
{
Mouse.begin();
}
void loop ()
{
int xVal=readJoystick(X_AXIS); // Получить отклонение
// джойстика по оси х
int yVal=readJoystick(Y_AXIS); // Получить отклонение
// джойстика по оси у
Mouse.move(xVal, yVal, 0); // Перемещаем мышь
readButton(LEFT_BUTTON/MOUSE_LEFT); // Чтение состояния левой кнопки
readButton(MIDDLE__BUTTONfMOUSE_MIDDLE); // Чтение состояния средней
readButton(RIGHT_BUTTON, MOUSE_RIGHT); // Чтение состояния правой
delayE);
}
// Чтение значения джойстика, масштабирование
int readJoystick(int axis)
{
int val = analogRead(axis); // Чтение аналогового значения
val = map(val, 0, 1023, -10, 10); // Масштабирование значения
if (val <= 2 && val >= -2) // Убрать дрейф мыши
return 0;
else // Вернуть значение
return val;
}
// Чтение состояния кнопок и отправка команд мыши
void readButton(int pin, char mouseCommand)
{
// Если кнопка нажата, эмулируем нажатие, если она еще не была нажата
if (dfgitalRead(pin) — LOW)
{
if (!Mouse.isPressed(mouseCommand))
340
Часть III. Практическое применение Arduino
Mouse.press (mouseCoinmand);
}
}
// Отпустить нажатие мыши
else
{
if (Mouse.isPressed(mouseConimand))
{
Mouse, release (mouseCoinmand) ;
Функция readJoystickO создана для считывания значений джойстика и
масштабирования их. Каждая ось джойстика имеет ряд значений: от 0 до 1024, полученных
от входа аналого-цифрового преобразователя (АЦП). Значения от 0 до 1023
масштабируем к значениям от -10 до 10.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\15\_15JJ
сопровождающего книгу электронного архива (см. приложение 2).
15.2. Плата Ardumo Esplora
Плата Arduino Esplora спроектирована на основе Arduino Leonardo и отличается
от всех предыдущих плат Arduino наличием множества встроенных и готовых
к использованию датчиков. Дизайн платы Arduino Esplora напоминает дизайн
обычного геймпада с аналоговым джойстиком слева и четырьмя кнопками справа
(рис. 15.3).
Рис. 15.3. Плата Arduino Esplora
Глава 15. Специальные возможности отдельных плат Arduino
341
Arduino Esplora обладает следующими встроенными средствами ввода и вывода
(рис. 15.4):
1. Аналоговый джойстик с кнопкой.
2. Четыре кнопки.
3. Линейный потенциометр.
4. Микрофон.
5. Датчик освещенности.
6. Датчик температуры.
7. Трехосевой акселерометр.
8. Зуммер для генерации звукового сигнала прямоугольной формы.
9. RGB-светодиод.
10. Два Tinkerkit-входа для подключения Tinkerkit-модулей датчиков с 3-пиновыми
разъемами.
11. Два Tinkerkit-выхода для подключения Tinkerkit-модулей приводов с
3-пиновыми разъемами.
12. Разъем подключения TFT-дисплея, считывающего устройства SD-карты или
других устройств, использующих протокол SPI.
On led
lied
Txled
I IRxled
11 Ю
Output 1U
Unkerkit
Connectors
ATMEGA32U4
8 Buzzer-
sensor)
Ж 4 Switch
1 Analog .-*-
with central
button
12 ICD
4
Microphone
connector (TFT)
6 Temperature
I Sensor
linear
Potentiometer
9
RGB led
^3Axis
7 Accelerator
Рис. 15.4. Средства ввода и вывода платы Arduino Esplora
Как и на плате Leonardo, в Esplora используется AVR-микроконтроллер ATmega32U4
с кварцевым резонатором 16 МГц. Arduino Esplora может определяться как обычная
клавиатура или мышь и с помощью библиотек Keyboard и Mouse может быть
запрограммирована на управление этими устройствами ввода.
342 Часть ///. Практическое применение Arduino
Чтобы упростить написание программ для платы Esplora, существует специальная
библиотека Esplora, которая содержит методы для считывания данных с датчиков
и отправки информации на встроенные устройства вывода, а также
высокоуровневые методы, возвращающие уже обработанные данные, — например, градусы по
Фаренгейту или Цельсию, вычисленные по показаниям датчика температуры. Эта
библиотека обеспечивает простой доступ к устройствам вывода — например, при
отправке значений RGB-светодиоду.
В примерах работы с Esplora в Arduino IDE (рис. 15.5) показаны основные функции
входов и выходов устройства — с их помощью удобно экспериментировать с
платой Arduino Esplora и познавать ее возможности:
? EsploraBlink — мерцание встроенного RGB-светодиода.
? EsploraAccelerometer — считывание показаний акселерометра;
? EsploraJoystickMouse — управление курсором компьютера с помощью
джойстика;
? EsploraLedShow — световое шоу с использованием джойстика и слайдера;
? EsploraLedShow2 — изменение цвета встроенного RGB-светодиода с
использованием микрофона, потенциометра и датчика освещенности;
? EsploraLightCalibrator — определение освещенности;
Рис. 15.5. Примеры библиотеки Esplora
Глава 15. Специальные возможности отдельных плат Arduino 343
? EsploraMusic — немного музыки в исполнении Arduino Esplora;
? EspIoraSoundSensor — обработка сигнала со встроенного микрофона;
? EsploraTemperatureSensor — считывание показаний температурного датчика и
расчет температуры в градусах Фаренгейта и Цельсия.
Внимательно изучаем эти примеры, а затем приступаем к написанию своих
программ.
15.2.1. Arduino Esplora:
установка цветов RGB-светодиода
Напишем скетч для установки цвета RGB-светодиода с помощью трех кнопок:
SWITCH2, SWITCH3, SWITCH4. Если нажата кнопка SWITCH2 — горит красный
светодиод, не нажата — красный светодиод потушен. Если нажата кнопка
SWITCH3 — горит зеленый светодиод, не нажата — зеленый светодиод потушен.
Если нажата кнопка SWITCH4 — горит синий светодиод, не нажата — синий
светодиод потушен.
Сначала подключаем библиотеку Esplora:
iinclude <Esplora.h>
Создадим переменные для значений красного, зеленого и синего цветов
RGB-светодиода:
int red, green, blue;
В цикле loop () проверяем данные с кнопок и устанавливаем значения для
соответствующих переменных: red, green, blue:
if (Esplora.readButton(SWITCH_2) = HIGH)
red = 255;
else
red = 0;
if (Esplora.readButton(SWITCH_3) — HIGH)
green = 255;
else
green = 0;
if (Esplora.readButton(SWITCH_4) — HIGH)
blue = 255;
else
blue = 0;
И устанавливаем цвета RGB-светодиода:
Esplora.writeRGB(red, green, blue);
Полное содержимое скетча показано в листинге 15.3. Загружаем его в плату
Arduino и управляем цветами RGB-светодиода нажатием на кнопки SWITCH2,
SWITCH3, SWITCH4.
344 Часть III. Практическое применение Ardumo
// Подключение библиотеки Esplora.
#include <Esplora.h>
// Переменные для значений красного, зеленого и синего цветов RGB-светодиода
int red, green, blue;
void setup() {
void loop() {
// получение данных с кнопок
if (Esplora.readButton(SWITCH_2) == LOW) //нажата
red = 255;
else
red = 0;
if (Esplora.readButton(SWITCH_3) == LOW) //нажата
green = 255;
else
green = 0;
if (Esplora.readButton(SWITCH_4) == LOW) //нажата
blue = 255;
else
blue = 0;
// Устанавливаем цвета RGB-светодиода:
Esplora.writeRGB(red, green, blue);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examp/esW5W5_03
сопровождающего книгу электронного архива (см. приложение 2).
15.2.2. Arduino Esplora: создание игры
Рассмотрим применение Arduino Esplora с TFT-дисплеем в качестве игровой
консоли и создадим для этого игру «Змейка» (рис. 15.6).
Змейка на экране дисплея будет представлять собой линейку из множества
квадратов размером 8x8, соединенных между собой. Данные о звеньях мы станем
сохранять в массиве, каждый из элементов которого — координаты х и у левого верхнего
угла каждого звена:
// структура для описания координаты одного звена 8x8
struct Pos {
int x;
int у;
Глава 15. Специальные возможности отдельных плат Arduino
345
II массив всех звеньев змейки
Pos snake[40]={{40,0},{32,0},{24,0},{16,0},{8,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0f0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0Ы0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0}
};
Переменная — указатель на хвост змейки (размер змейки):
int offsetsnake=6;
Переменные для направления движения змейки и коэффициент для фактического
смещения:
// перемещение по осям х и у и коэффициент (шаг)
int dX=l; // -1, 0, 1
int dY=0; // -1, 0, 1
int kXY=8;
И переменные для скорости — времени, после которого происходит очередное
изменение положения змейки:
// скорость
int speedsnake=1000;
unsigned long millissnake=0;
Рис. 15.6. Игра «Змейка»
346 Часть III. Практическое применение Arduino
Кнопки SWITCH1, SWITCH2, SWITCH3, SWITCH4 будут использоваться для
изменения направления змейки, которое описано в процедуре setdir ():
// получение смещения по осям х и у
// получение данных с кнопок
if (Esplora.readButton(SWITCH_l) — LOW) //нажата
setdir@,1);
else if (Esplora.readButton(SWITCH_2) — LOW) //нажата
setdir (-1, Ob-
else if (Esplora.readButton(SWITCHJ3) = LOW) //нажата
setdir@,-1);
else if (Esplora.readButton(SWITCH_4) — LOW) //нажата
setdir A, Ob-
else
// установить новое направление движения
void setdir(int x,int y) {
int xl,yl;
xl=x;yl=y;
if((dX+x)—0 && abs(x)>0)
{yl=y;xl=dX;}
if((dY+y)=0 && abs(y)>0)
{xl=x;yl=dY;}
// установить
dX=xl;dY=yl;
}
Полное содержимое скетча показано в листинге 15.4. Загрузим скетч в плату
Arduino Esplora и проверим управление змейкой с помощью кнопок.
// Подключение библиотеки для работы с TFT
#include <TFT.h>
#include <SPI.h>
// Подключение библиотек для работы с Esplora
#include <Esplora.h>
// структура для описания координаты одного звена 8x8
struct Pos {
int x;
int у;
};
// массив всех звеньев змейки
Pos snake[40] = {{40,0Ы32,0},{24,0},{16,0},{8,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
Глава 15. Специальные возможности отдельных плат Arduino
347
{0,0}, {0,0}, {0,0},{p,0},-{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0f0}f{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0}
};
int offsetsnake=6;
// перемещение по осям х и у и коэффициент (шаг)
int dX=l; // -1, 0, 1
int dY=0; // -1, 0, 1
int kXY=8;
// скорость
int speedsnake=1000;
unsigned long millissnake=0;
void setup () {
//
Serial.begin(9600);
//
EsploraTFT. begin () ;
// очищаем экран - черный цвет
EsploraTFT.background@,0,0);
// пауза
delayA000);
void loop () {
// получение смещения по осям х и у
// получение данных с кнопок
if (Esplora.readButton(SWITCHJL) == LOW) //нажата
setdir@,l);
else if (Esplora.readButton(SWITCH_2) == LOW) //нажата
setdir(-1,0);
else if (Esplora.readButton(SWITCH_3) = LOW) //нажата
setdir@,-1);
else if (Esplora.readButton(SWITCH_4) == LOW) //нажата
setdirA,0);
else
//// изменение положения змейки
if (millis()-millissnake>=speedsnake) {
// стереть предыдущее
EsploraTFT.fill@, 0, 0);
for (int i=0;i<offsetsnake;i++) {.
EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8);
348 Часть III. Практическое применение Arduino
//// новая позиция для змейки
// остальные
for(int i=offsetsnake-l;i>0;i—) {
snake[i].x=snake[i-l].x;
snake[i].y=snake[i-l].y;
}
// первая
snake[0].x=snake[0].x+dX*kXY;
snake[0].y=snake[0].y+dY*kXY;
// нарисовать новое
EsploraTFT.fillB55, 0, 0) ;
for(int i=0;i<offsetsnake;i++) {
EsploraTFT.rect(snake[i].x, snake[i].у, 8, 8);
}
millissnake=millis();
// установить новое направление движения
void setdir(int x,int у) {
int xl,yl;
xl=x;yl=y;
if((dX+x)—0 && abs(x)>0)
{yl=y;xl=dX;}
if((dY+y)==0 && abs(y)>0)
{xl=x;yl=dY;}
// установить
dX=xl;dY=yl;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\i5\_i5_04
сопровождающего книгу электронного архива (см. приложение 2).
Добавим в скетч генерирование корма для змейки. Нам необходим массив для
хранения координат корма с максимальным количеством 10:
// массив для корма
Pos food[10]-{{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0}
};
int counterfood=0;
Через время speedf ood генерируем корм и отображаем его на экране:
//// появление корма
if(millis()-millisfood>=speedfood && counterfood<10) {
// генерация случайных х и у
int xf=random@,20)*8;
int уf=randomB,15)* 8;
Глава 15. Специальные возможности отдельных плат Arduino ; 349
// проверка отсутствия в списке корма
for(int i=0;i<10;i++) {
if(food[i].x==xf && food[i].y==yf)
;
else if(food[i].x==0 && food[i].y==0){
//не попадает на змейку
if(nosnake(xf,yf)) {
// добавить в массив и на экран
addfood(xf,yf, i);
// звук
Esplora.toneB62,200) ;
counterfood++;
i=10;
millisfood=*millis () ;
}
В процедуре nosnake () проверяем отсутствие сгенерированного значения
координат в базе — не попадает ли корм на змейку, заносим данные в массив food и
выводим красный квадрат на дисплей:
// проверка непопадания корма на змейку
boolean nosnake(int x,int у) {
boolean ok=true;
for(int i=0;i<40;i++) {
if (snake [i] .x==x && snake[i] .y=y)
ok=false;
}
return ok;
}
// добавить корм в массив и вывести
void addfood(int x,int у, int pos) {
food[pos].x=x;
food[pos].y=y;
EsploraTFT.filMO, 0, 255);
EsploraTFT.rect(x, y, 8, 8);
}
В цикле после изменения положения змейки проверяем, не съела ли змейка корм —
не произошло ли совпадение ее головы с координатами всех позиций корма:
// проверка — съела змейка корм?
boolean atefood(int x,int у) {
boolean ok=false;
for(int i=0;i<10;i++) {
if(food[i],x==x && food[i].y==y) {
food[ij.x=0;food[i].y=0;
350
Часть III. Практическое применение Arduino
counterfood—;
ok=true;
Serial.printIn(i);
return ok;
}
Полное содержимое скетча показано в листинге 15.5. Загрузим скетч в плату
Arduino Efcplora и проверим его работу.
// Подключение библиотеки для работы с TFT
#include <TFT.h>
#include <SPI.h>
// Подключение библиотек для работы с Esplora
#include <Esplora.h>
// структура для описания координаты одного звена 8x8
struct Pos {
int x;
int у;
};
// массив всех звеньев змейки
Pos snake[40]={{40,16},{32,16},{24,16},{16,16},{8,16},
{0,16},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0}
};
int offsetsnake=6;
// массив для корма
Pos food[10]={{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0}
};
int counterfood=0;
// перемещение по осям х и у и коэффициент
int dX=l; // -1, 0, 1
int dY=0; // -1, 0, 1
int kXY=8;
// скорость
int speedsnake=300;
unsigned long millissnake=0;
Глава 15. Специальные возможности отдельных плат Arduino 357
// время появления нового корма
unsigned long speedfood=5000;
unsigned long millisfood=0;
// массив символов для вывода времени на экран
char printout [4] ;
void setup () {
//
Serial.begin(9600);
//
EsploraTFT.beginO ;
// очищаем экран - черный цвет
EsploraTFT.background@,0,0);
// пауза
EsploraTFT.fillB55, 255, 0);
EsploraTFT.rect@, 16, 160, 128);
void loop () {
// получение смещения по осям х и у
// получение данных с кнопок
if (Esplora.readButton(SWITCH_l) = LOW) //нажата
setdir@,l);
else if (Esplora.readButton(SWITCH_2) == LOW) //нажата
setdir(-l,0);
else if (Esplora.readButton(SWITCH_3) == LOW) //нажата
setdir@,-l);
else if (Esplora.readButton(SWITCH_4) == LOW) //нажата
setdir(l,0);
else
;
//// изменение положения змейки
if (millis() -millissnake>=speedsnake) {
// стереть предыдущее
EsploraTFT.fillB55, 255, 0);
for(int i=0;i<offsetsnake;i++) {
EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8);
}
//// новая позиция для змейки
// остальные
for(int i=offsetsnake-l;i>0;i—) {
snake[i].x=snake[i-l].x;
snake[i],y=snake[i-l].y;
}
// первая
snake[0].x=snake[0].x+dX*kXY;
snake[0].y=snake[0].y+dY*kXY;
352 Часть III. Практическое применение Arduino
// нарисовать новое
EsploraTFT.fillB55, 0, 0);
for(int i=0;i<offsetsnake;i++) {
EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8);
}
// проверка - съела змейка корм?
if(atefood(snake[0].x,snake[0].y)) {
Esplora.toneD94,200);
delayB00);
Esplora.toneC49,200);
offsetsnake++;
}
// новый отсчет millissnake
millissnake=millis();
}
//// появление корма
if (millis()-millisfood>=speedfood && counterfood<10) {
// генерация случайных х и у
int xf=random@,20)*8;
int yf=randomB,15)*8;
// проверка отсутствия в списке корма
for(int i=0;i<10;i++) {
if (food[i] .x=xf && food[ij .y==yf)
r
else if(food[i].x==0 && food[i].y==0){
//не попадает на змейку
if(nosnake(xf,yf)) {
// добавить в массив и на экран
addfood(xf,yf,i);
// звук
Esplora.toneB62,200);
counterfood++;
i=10;
millisfood=millis() ;
// установить новое направление движения
void setdir(int x,int у) {
int xl,yl;
xl=x;yl=y;
if((dX+x)==0 && abs(x)>0)
{yl=y;xl=dX;}
if((dY+y)==0 && abs(y)>0)
{xl=x;yl=dY;}
Глава 15. Специальные возможности отдельных плат Arduino 353
II установить
dX=xl;dY=yl;
}
// добавить корм в массив и вывести
void addfood(int x,int у, int pos) {
food[pos].x=x;
food[pos].y=y;
EsploraTFT.fill@, 0, 255);
EsploraTFT.rect(x, y, 8, 8) ;
}
// проверка непопадания корма на змейку
boolean nosnake(int x,int у) '{
boolean ok=true;
for(int i=0;i<40;i++) {
if(snake[i].x==x && snake[i].y==y)
ok=false;
}
return ok;
}
// проверка — съела змейка корм?
boolean atefood(int x,int у) {
boolean ok=false;
for(int i=0;i<10;i++) {
if(food[i].x==x && foodfi].y==y) {
food[i].x=0;food[i].y=0;
counterfood—;
ok=true;
Serial.printIn(i);
return ok;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\1&_15JM
сопровождающего книгу электронного архива (см. приложение 2).
Далее реализуем проверку выхода змейки за пределы экрана или на себя — в этом
случае заканчиваем игру:
// проверка выхода из границ
boolean outborder(int x,int у) {
boolean ok=false;
if(x<0 || x>152 || y<16 || y>120) {
ok=true;
}
return ok;
354 Часть III. Практическое применение Arduino
I/ проверка — не съела ли себя
boolean outsnake(int x,int у) {
boolean ok=false;
for(int i=l;i<40;i++) {
if(x==snake[i].x && y==snake[i].y) {
ok=true;
return ok;
}
А также реализуем табло для вывода времени игры, суммы набранных очков,
текущей длины змейки и количества корма на площадке:
// табло
void tabloO {
// очистить
EsploraTFT.filMO, 0, 0) ;
EsploraTFT.rect@, 0, 100, 16);
// текст
// цвет текста
EsploraTFT.strokeB55,255, 0);
// шрифт для текста
//EsploraTFT.setTextSizeA);
// выводим текст
• // корма на поле
String s = String(counterfood);
s.toCharArray(printout,4);
EsploraTFT.text(printout,20,2);
EsploraTFT.strokeB55,255,0);
// длина змейки
s = String(offsetsnake);
s.tbCharArray(printout,4);
EsploraTFT.text(printout,40,2);
EsploraTFT.strokeB55,255,0);
// сумма очков
s = String(sum) ;
s.toCharArray(printout,4);
EsploraTFT.text(printout,70,2);
EsploraTFT.strokeB55,255,0);
void settime() {
// очистить
EsploraTFT.fill@, 0, 0);
EsploraTFT.rectA00, 0, 60, 16);
// вывод времени
String s = String(seconds/60);
s.toCharArray(printout,4);
Глава 15. Специальные возможности отдельных плат Arduino 355
if(seconds/60<l0) {
EsploraTFT.text(",110,2);
EsploraTFT.text(printout,116,2);
}
else {
EsploraTFT.text(printout,110,2);
}
EsploraTFT.text(":",122,2);
s = String(seconds%60);
s.toCharArray(printout,4);
if(seconds%60<10) {
EsploraTFT.text(",128,2);
EsploraTFT.text(printout,134,2);
}
else {
EsploraTFT. text (printout, 128,2);
}
EsploraTFT.strokeB55,255,0);
Полное содержимое скетча показано в листинге 15.6. Загрузим скетч в плату
Arduino Esplora и проверим его работу. При желании вы можете внести в игру
«Змейка» собственные изменения.
// Подключение библиотеки для работы с TFT
iinclude <TFT.h>
tinclude <SPI.h>
// Подключение библиотек для работы с Esplora
iinclude <Esplora.h>
// структура для .описания координаты одного звена 8x8
struct Pos {
int x;
int у;
};
// массив всех звеньев змейки
Pos snake[40]={{40,16},{32,16},{24,16},{16,16},{8,16},
{0,16},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0}
356 Часть III. Практическое применение Arduino
int offsetsnake=6;
// массив для корма
Pos food[10]={{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0}
>;
int counterfood=0;
// перемещение по осям х и у и коэффициент
int dX=l; // -1, 0, 1
int dY=0; // -1, 0, 1
int kXY=8;
// скорость
int speedsnake=300;
unsigned long millissnake=0;
// время появления нового корма
unsigned long speedfood=5000;
unsigned long millisfood=0;
// массив символов для вывода времени на экран
char printout[4];
// сумма набранных очков
int sum=100;
// время игры - секунд
unsigned long seconds=0;
unsigned long millisseconds=0;
void setup(){
//
Serial.begin(9600);
//
EsploraTFT.begin();
// очищаем экран - черный цвет
EsploraTFT.background@,0,0);
// пауза
EsploraTFT.fillB55, 255, 0) ;
EsploraTFT.rect@, 16, 160, 128);
tablo();
void loop(){
// отсчет времени
if (millis()-millisseconds>=1000) {
seconds++;
settime ();
millisseconds=mLllis();
}
// получение смещения по осям х и у
// получение данных с кнопок
if (Esplora.readButton(SWITCH_l) = LOW) //нажата
setdir@,l);
Глава 15. Специальные возможности отдельных плат Arduino 357
else if (Esplora.readButton(SWITCH_2) == LOW) //нажата
setdir(-1,0);
else if (Esplora.readButton(SWITCH_3) == LOW) //нажата
setdir@,-1);
else if (Esplora.readButton(SWITCH_4) == LOW) //нажата
setdirA,0);
else
//// изменение положения змейки
if(millis()-millissnake>=speedsnake) {
// стереть предыдущее
EsploraTFT.fillB55, 255, 0) ;
for(int i=0;i<offsetsnake;i++) {
EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8);
}
//// новая позиция для змейки
// остальные
for(int i=offsetsnake-l;i>0;i—) {
snake[i].x=snake[i-1].x;
snake[i].y=snake[i-1].у;
}
// первая
snake[0].x=snake[0].x+dX*kXY;
snake[0].y=snake[0].y+dY*kXY;
// нарисовать новое
EsploraTFT.fillB55, 0, 0);
for(int i=0;i<offsetsnake;i++) {
EsploraTFT.rect(snake[i].x, snake[i].y, 8, 8);
}
// проверка - съела змейка корм?
if(atefood(snake[0].x,snake[0],y)) {
Esplora.toneD94,200);
delayB00);
Esplora.toneC49,200);
setsumC0+offsetsnake);
tablo();
offsetsnake++;
}
// проверка выхода из границ
if(outborder(snake[0].x,snake[0].y)) {
endgame();
newgame();
tablo();
}
// проверка — не съела ли себя
if(outsnake(snake[0].x,snake[0].y)) {
endgame();
358 Часть III. Практическое применение Arduino
newgame () ;
tablo();
}
// новый отсчет millissnake
millissnake=millis();
}
//// появление корма
if(millis()-millisfood>=speedfood && counterfood<l0) {
// генерация случайных х и у
int xf=random@,20) *8 ;
int yf=randomB,15)*8;
// проверка отсутствия в списке корма
for(int i=0;i<10;i++) {
if(food[i].x==xf && food[i].y==yf)
r
else if(food[i].x==0 && food[i].y==0){
//не попадает на змейку
if(nosnake(xf,yf)) {
// добавить в массив и на экран
addfood(xf,yf,i);
setsum(-5*counterfood);
tablo();
// звук
Esplora.toneB62,200);
counte r food++;
tablo();
millisfood^millis();
// установить новое направление движения
void setdir(int x,int y) {
int xl,yl;
xl=x;yl=y;
if((dX+x)==0 && abs(x)>0)
{yl=y;xl=dX;}
if((dY+y)=0 && abs(y)>0)
{xl=x;yl=dY;}
// установить
dX=xl;dY=yl;
}
// добавить корм в массив и вывести
void addfood(int x,int y, int pos) {
food[pos].x=x;
Глава 15. Специальные возможности отдельных плат Arduino 359
food[pos].y=y;
EsploraTFT.filMO, 0, 255);
EsploraTFT.rect(x, у, 8, 8);
}
// проверка непопадания корма на змейку-
boolean nosnake(int x,int у) {
boolean ok=true;
for(int i=0;i<40;i++) {
if (snake [i] ,x=x && snake[i] .y=y)
ok=false;
}
return ok;
}
// проверка — съела змейка корм?
boolean atefood(int x,int у) {
boolean ok=false;
for(int i=0;i<10;i++) {
if (food[i] .x==x && food[i] .y=y) {
food[i].x=0;food[i].y=0;
counterfood—;
ok=true;
Serial.printIn(i);
return ok;
}
// проверка выхода из границ
boolean outborder(int x,int y) {
boolean ok=false;
if(x<0 || x>152 || y<16 || y>120) {
ok=true;
}
return ok;
}
// проверка — не съела ли себя
boolean outsnake(int x,int у) {
boolean ok=false;
for(int i=l;i<40;i++) {
if (x==snake[i] .x && y=snake[i] .y) {
ok=true;
return ok;
}
// табло
void tabloO {
360 Часть III. Практическое применение Arduino
I/ очистить
EsploraTFT.filMO, 0, 0) ;
EsploraTFT.rect@, 0, 100, 16);
// текст
// цвет текста
EsploraTFT.strokeB55,255,0);
// шрифт для текста
//EsploraTFT.setTextSizeA);
// выводим текст
// корма на поле
String s = String(counterfood);
s.toCharArray(printout,4);
EsploraTFT.text(printout,20,2);
EsploraTFT.strokeB55,255,0) ;
// длина змейки
s = String(offsetsnake);
s.toCharArray(printout,4);
EsploraTFT.text(printout,40,2);
EsploraTFT.strokeB55,255,0) ;
// сумма очков
s = String(sum);
s.toCharArray(printout,4);
EsploraTFT.text(printout,70,2);
EsploraTFT.strokeB55,255,0) ;
}
// подсчет количества очков
void endgame() {
// очистить экран
EsploraTFT.background@,0,0);
EsploraTFT.fillB55, 255, 0) ;
// цвет текста
EsploraTFT.strokeB55,255, 0);
EsploraTFT.text("GAME END",50,40);
// сумма очков
EsploraTFT.text("sum =",50,70);
String s = String(sum);
s.toCharArray(printout,4);
EsploraTFT.text(printout,86,70);
// ожидаем нажатия кнопки
while(Esplora.readButton(SWITCH_1)==HIGH &&
Esplora.readButton(SWITCH_2)==HIGH & &
Esplora.readButton(SWITCH_3)==HIGH & &
Esplora.readButton(SWITCH_4)==HIGH )
// начать заново
void newgame() {
Глава 15. Специальные возможности отдельных плат Arduino 361
// очистить экран
EsploraTFT.background@,0,0);
EsploraTFT.fillB55, 255, 0);
EsploraTFT.rect@, 16, 160, 128);
// массив snake
for(int i=0;i<1
food[i].x=0;
food[i],y=0;
}
counterfood=0;
// массив food
for(int i=0;i<4
snake[i].x=0;
snake[i].y=0;
}
snake[0].x=40;snake[0].y=16;•
snake[1].x=32;snake[1 ].y=16;
snake[2].x=24;snake[2].y=16;
snake[3].x=16;snake[3].y=16;
snake[4].x=8;snake[4].y=16;
snake[5].x=0;snake[5].y=16;
offsetsnake=6;
// направление
dX=l;
dY=0;
//
sum=100;
seconds=0;
}
// подсчет количества очков
void setsum(int add) {
sum=sum+add;
void settiine () {
// очистить
EsploraTFT.fill@, 0, 0);
EsploraTFT.rectA00, 0, 60, 16);
// вывод времени
String s = String(seconds/60);
s.toCharArray(printout,4);
if(seconds/60<10) {
EsploraTFT.text(", 110,2) ;
EsploraTFT.text(printout,116,2);
}
else {
EsploraTFT.text(printout,110,2);
362 Часть III. Практическое применение Arduino
EsploraTFT.text(":",122,2);
s = String(seconds%60);
s.toCharArray(printout, 4);
if(seconds%60<10) {
EsploraTFT.text(",128,2) ;
EsploraTFT.text(printout,134,2);
else {
EsploraTFT. text (printout, 128,2) ;
EsploraTFT.strokeB55,255,0);
}
Электронный архив
Полный вариант рассмотренного скетча находится в папке examplesWS^ISjoe
сопровождающего книгу электронного архива (см. приложение 2).
15.3. Плата Arduino LilyPad
Плата Arduino LilyPad была разработана и создана дизайнером Leah Buechley
совместно со SparkFun для использования с предметами одежды и текстиля. Arduino
LilyPad можно пришивать к ткани и с помощью токопроводящих нитей подключать
питание, датчики или исполнительные устройства. Электронная схема, собранная
на ткани, включая саму плату Arduino LilyPad, не боится стирки — ее можно
стирать вручную, естественно, предварительно отключив питание.
Печатная плата LilyPad Arduino имеет форму круга диаметром около 50 мм. Плата
выполнена на микроконтроллерах ATmegal68V или ATmega328V. Напряжение
питания платы — в интервале от 2,7 до 5,5 В. При отрицательном питании или
большем чем 5,5 В плата может выйти из строя.
Существуют три варианта этой платы:
? LilyPad Arduino 328 (рис. 15.7) — на базе микроконтроллера ATmega328;
? LilyPad Arduino USB (рис. 15.8) — на базе микроконтроллера ATmega32U4.
Этот вариант отличается наличием USB-порта для связи с компьютером и
разъема для литиевой батареи;
? LilyPad Simple Snap (рис. 15.9)— благодаря специальным контактам из кнопок
может отстегиваться от схемы, содержит встроенный литиевый аккумулятор.
Рассмотрим плату LilyPad Arduino 328 (см. рис. 15.7), построенную на базе
микроконтроллера ATmega328. Плата имеет 22 контакта (рис. 15.10). Контакты + и -
предназначены для питания платы. Остальные контакты аналогичны контактам
Arduino Uno. Также на плате присутствуют штырьковые контакты для
подключения переходника USB-Serial, необходимого для загрузки скетчей из компьютера.
Глава 15. Специальные возможности отдельных плат Arduino 363
Рис. 15.7. Плата LilyPad Arduino 328
Рис. 15.8. Плата LilyPad Arduino USB
364 Часть III. Практическое применение Arduino
Рис. 15.9. Плата LilyPad Simple Snap
Контакты для FTDI USB
Питание датчиков
-GND—"
Питание датчиков
Светодиод .
Индикатор ^ •*
питания Тестовый
светодиод
для PIN 13
Рис. 15.10. Контакты и разъемы платы LilyPad Arduino 328
Глава 15. Специальные возможности отдельных плат Arduino
365
Технические характеристики платы LilyPad Arduino 328:
? микроконтроллер: ATmega328V;
? количество цифровых контактов: 14 F из которых могут использоваться как
выходы ШИМ);
? количество аналоговых контактов: 6;
О рабочее и входное напряжение: 2,7-5,5 В;
? флеш-память: 16 Кбайт B Кбайт используются для загрузчика);
? ОЗУ: 1 Кбайт;
Для подключения платы LilyPad Arduino 328 к компьютеру требуется
преобразователь USB-Serial (рис. 15.11).
Рис. 15.11. Монтажная схема подключения LilyPad Arduino 328 к преобразователю USB-Serial
Для загрузки скетчей из Arduino ШЕ на плату LilyPad Arduino 328 необходимо
в меню Инструменты выбрать порт подключения платы LilyPad и ее тип —
LilyPad Arduino (рис. 15.12).
На дешевых переходниках USB-Serial отсутствует контакт DTR, который
соединяется с выводом RESET Arduino и сбрасывает микроконтроллер перед загрузкой
в него новой программы. Если такого контакта нет, то при загрузке скетча на плату
LilyPad Arduino происходит ошибка (рис. 15.13).
В таких случаях необходимо после нажатия кнопки Загрузить — когда
компиляция скетча завершится и появится надпись Загружаем — нажать и отпустить на
плате Arduino кнопку сброса.
366
Часть III. Практическое применение Arduino
; Ф5ЙЛ i\pims,? TfC^tfS ?ЙШ»
&&-*ПА1 f ;i;M'>Uib
ikrOViUC Г'С О* РГО Г^:;
Рис. 15.12. Настройки Arduino IDE для LilyPad Arduino 328
Рис. 15.13. Ошибка
при загрузке скетча
на плату LilyPad Arduino
Глава 15. Специальные возможности отдельных плат Arduino 367
15.4. Плата Arduino Yun
Одной из самых слабых сторон платформы Arduino до недавнего времени являлось
отсутствие связи. Плата Arduino Yun решает эту проблему, потому что
представляет собой плату Arduino со встроенным модулем Wi-Fi. Кроме того, Yun несет на
борту второй микропроцессор, на котором работает облегченная версия Linux
с предустановленным языком программирования Python. Кроме Python вы можете
также установить Ruby, PHP или Node.
О Arduino-часть платы содержит микроконтроллер ATmega32U4, работающий на
частоте 16 МГц. «Распиновка» Arduino Yun аналогична Arduino Leonardo,
поэтому вместе с Arduino Yun вы можете использовать большинство плат
расширения Arduino.
? Linux-часть платы Arduino Yun использует микрокомпьютер Atheros AR9331,
работающий под управлением операционной системы Linino — специально
подготовленной версии OpenWRT (популярного дистрибутива Linux для
встраиваемых систем).
На Arduino Yun можно создать какое-либо устройство Интернета вещей или даже
«поднять» небольшой сайт и использовать его как главное устройство «умного дома».
15.4.1. Плата расширения Arduino Yun shield
Недостатком платы Arduino Yun является ее высокая цена. Эта проблема решается
использованием платы расширения Arduino Yun shield (рис. 15.14), которая
добавляет любой вашей плате Arduino функционал Linux-части Arduino Yun. В чем
отличие «полноценной» Arduino Yun от Arduino Yun shield? И Arduino Yun, и Yun
Shield имеют одинаковый процессор, размер памяти и объем оперативной памяти
для системы Linux. В принципе, плата расширения Yun Shield, состыкованная
Рис. 15.14. Плата расширения Arduino Yun shield, состыкованная с платой Arduino
368 Часть III. Практическое применение Arduino
с платой Arduino Leonardo, — это и есть Arduino Yun, но обладание платой Yun
Shield даст вам большую гибкость, потому что она может использоваться и с
другими платами Arduino: Arduino Uno, Duemilanove и Mega.
Рассмотрим работу с платой расширения Arduino Yun shield — состыкуем ее с
платой Arduino и подадим питание. Подключиться к плате можно как по Ethernet, так и
по Wi-Fi. Плата создает точку доступа Ышпо-лхкххх (рис. 15.15), к которой можно
подключиться с компьютера или планшета.
Рис. 15.15. Точка доступа платы Arduino Yun shield
Эта точка доступа имеет IP-адрес 192.168.240.1. Для входа в веб-интерфейс в
браузере набираем адрес: http://192.168.240.1 и на странице авторизации вводим
пароль: iduino. Если необходим выход в Интернет, можно подсоединиться к сети
Wi-Fi, имеющей доступ в Интернет (рис. 15.16).
Рис. 15.16. Настройки подключения к Интернету по Wi-Fi с помощью платы Arduino Yun shield
Глава 15. Специальные возможности отдельных плат Arduino 369
После перезагрузки плата Arduino с установленной на ней платой расширения
Arduino Yun shield будет находиться в сети Wi-Fi с доступом в Интернет.
Все основные модули шилда Yun: Wi-Fi, Ethernet, USB-хост — подключены к
процессору AR9331. Работать с этими устройствами, запускать скрипты и
взаимодействовать с различными веб-службами позволяет библиотека Bridge. Существует
несколько вспомогательных классов, предназначенных для этого взаимодействия.
15.4.2. Arduino Yun shield: управляем веб-камерой
В этом проекте мы подключим к плате Arduino Yun shield веб-камеру и организуем
создание снимков при срабатывании датчика движения, подключенного к плате
Arduino.
Итак, сначала подключим веб-камеру в USB-разъем Arduino Yun shield и
соединимся с Arduino Yun shield no ssh (рис. 15.17).
Рис. 15.17. Подключение к плате Arduino Yun shield no ssh
Теперь выполним в терминале команды:
П обновление:
opkg update
? установка UVC-драйвера:
opkg install kmod-video-uvc
? установка утилиты fswebcam:
opkg install fswebcam
370
Часть III. Практическое применение Arduino
Для проверки камеры попробуем сделать тестовый снимок (рис. 15.18):
fswebcam test.png
Затем подключим к плате Arduino датчик движения HC-SR501 (рис. 15.19).
ъ I
Рис. 15.18. Создание снимка с веб-камеры утилитой fswebcam
ife-:^-
Рис. 15.19. Монтажная схема подключения к плате Arduino датчика движения HC-SR501
Методы класса Process библиотеки Bridge позволяют плате Arduino запускать на
плате Yun shield linux-процессы. И в скетче (листинг 15.7) после обнаружения
движения датчиком HC-SR501 мы формируем на основании даты имя файла и
запускаем соответствующие linux-процессы.
Глава 15. Специальные еозможности отдельных плат Arduino 371_
Далее с полученными картинками можно делать что угодно — например,
отправлять их в какой-либо облачный сервис.
// Подключение библиотек Bridge
tinclude <Bridge.h>
iinclude <Process.h>
// process
Process picture;
// имя файла картинки
String filename;
// пин подключения HC-SR501
int pin_HCSR501 = 4;
// путь сохранения картинки
String path = "/root/imgs/";
void setup () {
// Bridge
Bridge. begin ();'
void loop (void) {
// датчик сработал
if (digitalRead(pin_HCSR501) == true) {
// формирование имени файла
filename = "";
// запуск процесса в linux (получение даты)
picture.runShellCommand("date +%s");
while(picture.running());
// получение данных из linux
while (picture.available()>0) {
char с = picture.read();
filename += c;
}
filename.trim ();
filename += ".png";
// запуск процесса в linux (получение картинки с камеры)
picture.runShellCommand("fswebcam " + path + filename + " -r 640x320")
while(picture.running());
delayE000);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\i5\_i5_07
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 16
Взаимодействие Arduino
с другими программируемыми
системами
16.1. Использование Arduino в проектах LEGO
LEGO Mindstorms — конструктор (набор сопрягаемых деталей и электронных
блоков) для создания программируемого робота— впервые был представлен
компанией LEGO в 1998 г. В 2013 г. вышла 3-я модель серии — LEGO Mindstorms EV3.
Наборы LEGO Mindstorms комплектуются стандартными деталями LEGO (балки,
оси, колеса, шестерни, сервомоторы), а также сенсорами, двигателями и
программируемым блоком. Программируемый блок (рис. 16.1) оснащен процессором Sitara
AM 1808 (ARM9) частотой 300 МГц от Texas Instruments, несет на борту 64 Мбайт
оперативной памяти, 16 Мбайт флеш-памятй и слот для карт памяти microSDHC
объемом до 32 Гбайт. В наличии имеются USB-xoct и модуль связи Bluetooth,
возможно подключение к сети Wi-Fi через USB-донгл, поддерживаются устройства
Рис. 16.1. Программируемый блок (микрокомпьютер) конструктора LEGO Mindstorm EV3
Глава 16. Взаимодействие Arduino с другими программируемыми системами 373
Apple. Блок оснащен монохромным LCD-дисплеем с разрешением 178x128, а для
подключения датчиков на нем имеются 4 порта ввода и 4 порта вывода команд.
Тем не менее очень часто в проектах с использованием конструктора LEGO
Mindstorm EV3 не хватает возможностей его стандартных датчиков, или для
подключения необходимых датчиков недостаточно имеющихся у микрокомпьютера
LEGO 4 портов. В такой ситуации допустимо задействовать возможности
платформы Arduino.
Каждый порт микрокомпьютера LEGO Mindstorm EV3 поддерживает целый ряд
различных протоколов — в основном это сделано для совместимости с датчиками
NXT и датчиками сторонних производителей. Так, в каждом порту
микрокомпьютера имеется канал аналого-цифрового преобразователя и реализована поддержка
протоколов 12С и UART.
Способность микрокомпьютера LEGO работать по протоколу 12С позволяет
подключить к каждому из его портов до 127 подчиненных устройств. И здесь мы
рассмотрим способ превратить плату Arduino в 12С-датчик для этого
микрокомпьютера. К плате Arduino может быть подключено множество датчиков разных типов,
и Arduino будет отправлять данные по протоколу 12С на микрокомпьютер LEGO,
выступая в роли своеобразного конвертера: получая запрос (по номеру датчика) из
микрокомпьютера LEGO на значение этого датчика и отправляя полученное
значение в микрокомпьютер LEGO.
16.1.1. Получение микрокомпьютером LEGO
данных с датчика влажности и температуры DHT11,
подключенного к плате Arduino
Итак, подключим к плате Arduino датчик влажности и температуры DHT11 и
выведем его показания на экран микрокомпьютера LEGO.
Схема подключения платы Arduino (справа) к порту датчиков микрокомпьютера
LEGO (слева) приведена на рис. 16.2 (для лучшего понимания коннектор для
подключения датчиков LEGO к порту микрокомпьютера LEGO показан в увеличенном
виде).
Программное обеспечение для сопряжения микрокомпьютера LEGO и платы Arduino
состоит из двух частей: первая часть — программа для среды LEGO Mindstorm EV3,
вторая часть — скетч, выполняемый на Arduino.
Для создания программы в среде LEGO Mindstorm необходимо скачать блоки
Dexter Industries EV3 (Dexter.ev3b) и импортировать их в ПО LEGO Mindstorms
EV3 командой меню среды LEGO Mindstorm Инструменты | Мастер импорта
блоков. А затем сформировать программу, которая отсылает на плату Arduino
по протоколу 12С числа 1 и 2 и выводит приходящие в ответ данные на экран
(рис. 16.3).
Электронный архив
Файл Dexter.ev3b размещен в папке examples\16\ сопровождающего книгу электронного
архива (см. приложение 2).
374
Часть Ш. Практическое применение Arduino
6-SDA_Blue
5-SCl_Yel!ow ,
4-4 3V_Green
3-GND_Red
2-GND_Black
1-ANA White
I I I I
i j^5
EV3
—
""""""
—
АО RX
' A1 TX
A2
A3 02
A4 *03
A5 04
*05
RES + *06
ViN 07
5V 08
3,3V *D9
AREF *010
GNO *D11
GNO 012
GNO 013
Рис. 16.2. Схема подключения платы Arduino к порту датчиков микрокомпьютера LEGO
Рис. 16.3. Программа в среде LEGO Mindstorm EV3
Примечание
Изучение программирования в среде LEGO Mindstorm не укладывается в рамки этой
книги.
В скетче для Arduino (листинг 16.1) плата Arduino, получив запрос от
микрокомпьютера LEGO, запрашивает значение либо влажности, либо температуры с
датчика DHT11 и отправляет 1 байт данных на микрокомпьютер LEGO. Результат
работы объединенной системы «Arduino — LEGO» представлен на рис. 16.4.
#include "DHT.h"
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
tdefine DHTPIN 17
#define DHTTYPE DHT11 // DHT 11
DHT dht(DHTPIN, DHTTYPE);
int data;
int val,flag=O;
Глава 16. Взаимодействие Arduino с другими программируемыми системами 375
void setup () {
Serial.begin(9600);
Wire.begin(SLAVE_ADDRESS);
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
dht.begin();
Serial.println("Ready!");
void loopO {
if(flag==l) {
Serial.print("val=");Serial.println(val);
flag=0;
if(val==l)
data = dht.readHumidity();
else
data = dht.readTemperature();
void receiveData(int byteCount) {
while(Wire.available()>0) {
val=Wire.read();
flag=l;
// callback for sending data
void sendData () {
Wire.write(data);
Рис. 16.4. Результат работы объединенной системы «Arduino — LEGO»
376 Часть III. Практическое применение Arduino
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\16\_16_01
сопровождающего книгу электронного архива (см. приложение 2).
16.2. Arduino в проектах ROS
ROS (Robot Operating System, операционная система для роботов) — это структура
программной системы (фреймворк), предоставляющая функционал для
распределенной работы по программированию роботов. Система ROS (под названием
Switchyard) была первоначально разработана в 2007 г. в Лаборатории
искусственного интеллекта Стэнфордского университета.
При разработке робота обычно приходится реализовывать свою архитектуру, свой
протокол обмена сообщениями, драйвер пульта управления, логику навигации и пр.
И даже если имеется возможность использовать для этих задач различные готовые
библиотеки, то все равно остается серьезная проблема — объединить их для робота
в единую систему. Разработчики ROS позиционируют свою систему именно как
операционную — для программ взаимодействия и управления роботом ROS играет
роль операционной системы, предоставляя программам управления свои
интерфейсы, библиотеки и готовые приложения. ROS работает под уже готовой ОС (Ubuntu
Linux), в которой реализует свой дополнительный слой абстракции— конкретно
для управления роботами. ROS обеспечивает стандартные службы операционной
системы, такие как аппаратная абстракция, низкоуровневый контроль устройств,
реализация часто используемых функций, передача сообщений между процессами
и управление пакетами.
ROS развивается в двух направлениях: в качестве уже описанной здесь
операционной системы и в виде поддерживаемых пользователями пакетов (ros-pkg),
организованных в наборы (стеки), реализующие различные функции робототехники. Так,
ROS содержит вспомогательные библиотеки и приложения для роботов:
преобразование систем координат, утилиты для визуализации данных и распознавания
объектов, стек навигации и многое другое. Реализованы для ROS и драйверы,
позволяющие единым образом работать со многими устройствами: джойстиками,
устройствами GPS, камерами, лазерными дальномерами и пр.
ROS основана на архитектуре графов, где обработка данных происходит в узлах,
которые могут получать и передавать между собой сообщения (структурированные
данные). Комбинируя готовые узлы ROS и по необходимости дописывая
собственные, можно существенно сократить время разработки и позволить себе
сконцентрироваться только на тех задачах, которые действительно нужно решить.
К настоящему времени под управлением ROS работает уже много роботов. Вот
неполный их список: PR2, TurtleBot, PR1, HERB, STAIR I и II, Nao, Husky A200,
iRobot Create, LEGO Mindstorms NXT.
ROS выпускается в соответствии с условиями лицензии BSD и с открытым
исходным кодом. Она бесплатна для использования как в исследовательских, так и в
Глава 16. Взаимодействие Arduino с другими программируемыми системами 377
коммерческих целях. Пакеты из ros-pkg распространяются на условиях различных
открытых лицензий.
16.2.1. Установка ROS
Шаги по установке ROS Kinetic Kame под Ubuntu Linux расписаны на официальном
сайте системы: http://www.ros.org/wiki/fuerte^nstallation/Ubuntu. Рассмотрим ее
установку на компьютер с операционной системой Ubuntu Xenial A6.04 LTS).
1. Добавляем адрес сервера ROS, чтобы менеджер пакетов знал, откуда брать
пакеты ROS:
sudo sh -с 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc)
main" > /etc/apt/sources.list.d/ros-latest.list1
2. Получаем ключ:
sudo apt-key adv —keyserver fhkp: //keyserver.ubuntu.com: 80' —recv-ключ
C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
3. Обновляем список пакетов — тем самым сервер ROS.org будет проиндексирован:
sudo apt-get update
4. Отдаем команду установки ROS Fuerte (рекомендованная конфигурация
Desktop-Full):
sudo apt-get install ros-kinetic-desktop-full
Разработчики ROS стремятся интегрировать в систему лучшие открытые робото-
технические библиотеки, сохраняя при этом модульность системы, чтобы
пользователь мог установить только те модули, которые ему действительно необходимы.
Некоторые библиотеки вынесены из ROS и устанавливаются в ОС стандартным
образом, что позволяет использовать эти библиотеки и без ROS:
1. Установим необходимый нам пакет rosseriai:
sudo apt-get install ros-kinetic-ros-comm
2. Отдельно необходимо установить также пакеты rosinstaii и rosdep:
sudo apt-get install python-rosinstaii python-rosdep
3. В начале новой сессии bash необходимо прописать установку переменных
окружения ROS:
echo "source /opt/ros/kinetic/setup.bash" » ~/.bashrc . ~/.bashrc
На этом установка ROS завершена.
16.2.2. Узлы и темы в ROS
Узел— это исполняемый файл пакета ROS. Узлы ROS используют клиентские
библиотеки ROS для связи с другими узлами. Клиентские библиотеки ROS
позволяют реализовывать узлы ROS на различных языках программирования, например:
378 Часть III. Практическое применение Arduino
? Rospy — клиентская библиотека для Python;
? Roscpp — клиентская библиотека для C++;
? Rosjava — клиентская библиотека для Java.
Узлы могут публиковать сообщения по теме (publisher), а также подписаться на
тему для приема сообщений (subscriber). Сообщения — тип данных, используемых
для публикации или подписки на тему. Типы сообщений описываются в файлах
сообщений msg — простых текстовых файлах с полем типа и полем имени в строке.
Вот список типов полей, которые можно использовать:
int8, intl6, int32, int64, float32, float64, string, time, duration, other msg files,
variable-length array[], fixed-length array[C].
Файлы msg служат для генерации исходного кода для сообщений на разных языках
и хранятся в подкаталоге msg каталога пакета.
Узлы могут также предоставлять или использовать службы (Service). Службы
позволяют узлам послать запрос и получить ответ.
Файлы служб srv — такие же простые текстовые файлы, как и файлы msg, но они
состоят из двух частей: запроса и ответа. Эти две части, разделяются линией: —.
Вот пример файла srv:
int64 A
int64 В
int64 Sum
Здесь айв — запрос, a sum — ответ.
Файлы srv хранятся в подкаталоге srv каталога пакета.
16.2.3. Пакет rosserial
Библиотека rosserial устанавливает соединение точка-точка (point-to-point
connection) через последовательный порт с недорогими контроллерами (типа
Arduino) так, что вы можете посылать сообщения ROS туда и обратно.
Библиотека rosserial состоит из общего Р2Р-протокола, библиотеки для работы
с Arduino и узлов для ПК. Библиотека rosserial для работы с Arduino находится
в каталоге проекта serial (в каталоге serial_arduino\libraries). Для работы нам
понадобится и библиотека roslib, поэтому копируем каталог rosjib в библиотечный
каталог libraries Arduino ШЕ (рис. 16.5).
Электронный архив
Библиотека rosjib размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
Глава 16. Взаимодействие Arduino с другими программируемыми системами 379
Рис. 16.5. Подключение библиотеки rosjib
16.2.4. Подготовка сообщения (publisher) на Arduino
Создадим скетч для Arduino, демонстрирующий создание узла ROS, публикующего
сообщения в тему. Для этого соединим плату Arduino с подключенным к ней
датчиком температуры DS18B20 по последовательному порту (в рассматриваемом
случае это порт /dev/ttyusBO) с компьютером, на котором запущена ROS, и будем
отправлять в ROS значения температуры с датчика, используя библиотеки OneWire
и roslib.
Работу с датчиком температуры, работающим по протоколу 1-Wire, мы подробно
рассмотрели в предыдущих главах (см. например, главы 11 и 72), поэтому здесь
остановимся на работе библиотеки ros lib.
В каждую программу ROS для Arduino необходимо включить заголовочный файл
ros.h и файлы заголовков для всех типов сообщений, которые мы будем
использовать, — в нашем случае это std_msgs/Float32.h:
#include <ros.h>
tinclude <std_msgs/Float32.h>
Далее нам необходимо создать экземпляр объекта узла seriainode, что позволит
нашей программе выступать в качестве подписчика (subscriber) либо публиковать
сообщения (publisher):
ros::NodeHandle nh;
Создаем экземпляр publisher для нашего узла seriainode, публикующий
сообщения типа stdjnsgs: :Float32 В тему temperature:
stdjnsgs::Float32 float32_msg;
ros::Publisher chatter("temperature", &float32_msg);
380 Часть III. Практическое применение Arduino
В подпрограмме setup о необходимо инициализировать узел и объявить о роли
узла chatter В качестве publisher:
nh.initNode ();
nh.advertise(chatter);
В цикле loop () после считывания данных с датчика температуры публикуем
сообщение в тему и вызываем ros:: spinOnce (), где обрабатываются все функции
обратного вызова соединения.
chatter.publish( &float32_msg );
nh.spinOnce();
Код этого скетча представлен в листинге 16.2.
#include <OneWire.h>
OneWire dsA0); // линия 1-Wire будет на pin 10
#include <ros.h>
tinclude <std_msgs/Float32.h>
ros::NodeHandle nh;
std_msgs::Float32 float32_msg;
ros::Publisher chatter("temperature", &fIoat32_msg);
void setup(void)
{
nh.initNode();
nh.advertise(chatter);
}
void loop(void)
{
byte i;
byte present =0;
byte data[12];
byte addr[8];
if ( Ids.search(addr)) {
ds.reset_search();
return;
}
ds.reset();
ds.select(addr);
ds.write@x44,1); // запускаем конвертацию
delayA000); // скорее всего, достаточно 750 ms
present = ds.reset();
ds.select(addr);
ds.write(OxBE); // считываем ОЗУ датчика
J
Глава 16. Взаимодействие Arduino с другими программируемыми системами 381
for ( i - 0; i < 9; i++) { // обрабатываем 9 байтов
data[i] = ds.read();
}
Serial.print(" CRC=");
Serial.print( OneWire::crc8( data, 8), HEX);
Serial.println();
// высчитываем температуру
int HighByte, LowByte, Temp;
float Tempfl,Tempf2;
LowByte = data[0];
HighByte = data[l];
Temp = (HighByte « 8) + LowByte;
Tempfl=Temp/16;
Tempf2=(Temp%16)*100/16;
float32_msg.data=Tempfl+Tempf2/100;
// публикуем сообщение
chatter.publish( &float32_msg );
nh.spinOnce();
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\16\_16_02
сопровождающего книгу электронного архива (см. приложение 2).
Теперь проверим работу этого скетча. Первое, что необходимо выполнить, — это
команду roscore. Команда rosnode отображает информацию об узлах ROS, которые
работают в настоящий момент. Команда rosnode list выдает список этих активных
узлов. В терминале увидим:
/rosout
Соответственно, есть только один работающий узел: rosout. Этот узел работает
всегда, т. к. он собирает и логирует отладочные сообщения узлов.
Команда rosrun позволяет назначить имя пакета, чтобы непосредственно запустить
его узел:
$ rosrun [package_name] [node_name]
Запускаем узел seriainode.py пакета rosseriai^python, который соединяет нашу
Arduino с остальной частью. ROS. Необходимо выставить используемый
последовательный порт:
rosrun rosserial_python serial_node.py /dev/ttyUSBO
В терминале набираем:
$ rosnode list
И смотрим список активных узлов:
/rosout
/serial node
382 Часть III. Практическое применение Arduino
Утилита rxgraph, являющаяся частью пакета rxtoois, позволяет визуально показать
узлы и темы, запущенные в настоящий момент. Набираем в терминале:
$ rxgraph
Результат показан на рис. 16.6.
Рис. 16.6. Утилита rxgraph демонстрирует список активных узлов и тем
Утилита rostopic позволяет получить информацию о темах ROS. Команда rostopic
echo показывает данные, опубликованные в теме. Набираем в терминале:
$ rostopic echo /temperature
и видим постоянно поступающие с Arduino данные датчика температуры (рис. 16.7).
Рис. 16.7. Публикация сообщений из Arduino в тему temperature
Глава 16. Взаимодействие Arduino с другими программируемыми системами 383
16.2.5. Создание подписки (subscriber) на Arduino
Теперь рассмотрим пример использования Arduino в качестве узла subscriber для
приема сообщений. В э^ом примере мы будем зажигать/гасить светодиод,
подключенный к выводу 13 Arduino, получая сообщения из ROS.
Включаем заголовочный файл ros.h и файл заголовков для всех типов
используемых сообщений, — в нашем случае это std_msgs/Empty.h (для пустых сообщений):
#include <ros.h>
#include <std_msgs/Empty.h>
Далее необходимо создать экземпляр объекта узла serial jiode, что позволит нашей
программе выступать в качестве подписчика (subscriber) либо публиковать
сообщения (publisher):
ros:: NodeHandle nh;
Создаем экземпляр subscriber для нашего узла, публикующий пустые сообщения
типа stdjnsgs: :Float32 В тему toggle_led:
ros::Subscriber<std_msgs::Erapty> sub("toggle_led", &messageCb );
Создаем для нашего узла функцию обратного вызова messagecb. Эта функция
должна постоянно получать сообщение в качестве аргумента. Для нашей функции
обратного вызова messagecb назначим тип сообщения stdjnsgs::Empty. По
получении сообщения функция инвертирует значение сигнала на выводе 13 Arduino, при
этом зажигая/гася светодиод.
void messageCb( const stdjnsgs::Empty& togglejnsg){
digitalWriteA3, HIGH-digitalReadA3)); // blink the led
}
В подпрограмме setup о необходимо инициализировать узел и объявить о роли
узла в качестве подписчика на сообщения:
nh.initNode ();
nh. subscribe (sub) ;
И наконец, в цикле loop () вызываем ros:: spinOnce (), где обрабатываются все
функции обратного вызова соединения:
nh. spinOnce () ;
Код этого скетча представлен в листинге 16.3.
tinclude <ros.h>
Hnclude <stdjnsgs/Empty.h>
ros::NodeHandle nh;
void messageCb( const stdjnsgs::Empty& togglejnsg){
digitalWriteA3, HIGH-digitalReadA3)); // blink the led
384 Часть III. Практическое применение Arduino
ros::Subscriber<std_msgs::Empty> sub("toggle_led", &messageCb );
void setup()
{
pinModeA3, OUTPUT);
nh.initNode();
nh.subscribe(sub);
}
void loop()
{
nh.spinOnce();
delayA);
}
Запускаем узел serial node, py пакета rosseriai_python, который соединяет нашу
Arduino с остальной частью ROS. Необходимо выставить задействованный
последовательный порт (здесь использована другая плата Arduino, подключенная к порту
ttyACMO):
rosrun rosserial_python serial_node.py /dev/ttyACMO
Переходим на компьютер с запущенной ROS и проверяем список активных узлов:
$ rosnode list
Смотрим результат:
/rosout
/serial_node
Наш узел запущен как подписчик на сообщения по теме toggieied, но никаких
сообщений он пока не получил. Связь по темам осуществляется путем отправки
сообщений ROS между узлами. Для общения издатель (publisher) и абонент
(subscriber) должны отправлять и получать сообщения одинакового типа. Это
означает, что тип темы определяется типом сообщений, которые в ней публикуются.
Тип сообщения, отправляемого в тему, может быть определен с помощью команды
rostopic type:
$ rostopic type toggle_led
Результат:
std_msgs/Empty
Теперь используем rostopic с сообщениями — rostopic pub публикует данные
в тему:
rostopic pub [topic] [msg_type] [args]
Отправим единичное сообщение:
rostopic pub toggle_led std_msgs/Empty —once
Светодиод должен изменить значение на противоположное.
Глава 16. Взаимодействие Arduino с другими программируемыми системами 385^
Для отправки сообщения в цикле (-г) с определенной частотой введем команду:
rostopic pub toggle_led std_msgs/Empty -r 1
Эта команда публикует сообщение с частотой 1 Гц в тему toggie_ied. Светодиод
будет мигать с частотой 2 раза в секунду.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examplesW6W6_03
сопровождающего книгу электронного архива (см. приложение 2).
16.2.6. Связь через ROS двух плат Arduino
Теперь создадим пример передачи сообщений через ROS между двумя платами
Arduino. На одной плате Arduino, соединенной с ROS, находится датчик
температуры DS18B20 (см. разд. 16.2.4). Подключим к ROS по другому последовательному
порту вторую плату Arduino, к которой подключен дисплей WH0802 — на него мы
и будем выводить показания температуры с датчика, расположенного на первой
плате Arduino. Скетч для публикации показаний температуры у нас уже есть. Скетч
для получения сообщений с показаниями температуры, публикуемыми в тему
temperature, представлен в листинге 16.4.
// подключить библиотеку LiquidCrystal
tinclude <LiquidCrystal.h>
// создание экземпляра объекта LiquidCrystal
LiquidCrystal ledA2, 11, 5, 4, 3, 2);
// rosserial
tinclude <ros.h>
tinclude <std_msgs/Empty.h>
tinclude <stdjnsgs/Float32.h>
ros::NodeHandle nh;
void messageCb( const stdjcnsgs:: Float32& toggle_msg) {
digitalWriteA3r HIGH-digitalReadA3)); // blink the led
led.setCursor@, 0);
led.print("Temp=");
led.setCursor@, 1);
led.print(togglejmsg.data);}
ros:: Subscriber<std_msgs:: Float32> sub ("temperature11, SmessageCb );
void setup.() {
led.begin(8, 2);
pinModeA3, OUTPUT);
nh.initNode();
nh.subscribe(sub);
386 Часть III. Практическое применение Arduino
void loop () {
nh.spinOnce();
delayA000);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\16\_16JL
сопровождающего книгу электронного архива (см. приложение 2).
Теперь посмотрим, как реализовать в ROS передачу. Запустить два узла
serial__node с одним именем не получится. Но одна из особенностей ROS состоит
в том, что вы можете переназначить имена (Names) узлов из командной строки:
$ rosrun rosserial_python serial_node.py /dev/ttyUSBO name:=seriall
$ rosrun rosserial_python serial_node.py /dev/ttyACMO name:=serial2
Посмотрим список активных узлов командой rosnodeiist:
/rosout
/seriall
/serial2
А командой rxgraph посмотрим узлы и темы (рис. 16.8). При этом показания
температуры отображаются на дисплее WH0802.
Рис. 16.8. Утилита rxgraph — список активных узлов и тем
16.3. Arduino и Raspberry pi
Arduino и Raspberry Pi — совершенно разные устройства. Raspberry Pi — это
аппаратная платформа. Arduino — микрокомпьютер. Они не являются конкурентами и
служат для выполнения разных задач.
Гпава 16. Взаимодействие Arduino с другими программируемыми системами 387
Arduino идеален для аппаратных проектов, которые основаны на считывании
информации с различных датчиков и чипов и совершении простых действий в
качестве реакции на полученные сигналы. Raspberry Pi можно использовать с той же
целью, но простота выполняемых процессов не оправдывает мощность и сложность
применяемой системы.
В то же время мощность Arduino не позволяет производить сложные
вычислительные операции, а работа с Интернетом требует подключения дополнительных
модулей и написания программ для них.
Поэтому оптимальным выбором является использование обоих устройств в
тандеме — на Arduino могут выполняться простые операции, a Raspberry Pi позволяет
контролировать процессы на одном или нескольких Arduino и легко
взаимодействовать с Интернетом.
Существует Немало вариантов соединения Arduino и Raspberry Pi, обеспечивающих
вам клиентский доступ к настройкам и коду через Pi, в то время как Arduino
контролирует управление рабочими органами и собирает информацию с сенсоров: по
USB, по локальной сети или в виде простого подключения портов ввода/вывода
Arduino к Raspberry Pi. Мы рассмотрим здесь вариант соединения по
последовательному порту.
16.3.1. Установка WeblOPi на Raspberry Pi
На стороне Raspberry Pi мы воспользуемся фреймворком WeblOPi, позволяющим
контролировать состояние и управлять всеми портами GPIO локально или
удаленно из браузера или любого приложения.
Возможности WeblOPi:
? REST API через HTTP и СоАР с поддержкой мультикаста;
П работа с GPIO, Serial, I2C, SPI, 1-Wire;
? встроенная поддержка более чем 30 устройств, включая ЦАП, АЦП, датчики;
? совместимость с Python 2 и 3;
? защита логином/паролем;
Я множество примеров.
Чтобы установить фреймворк WeblOPi на Raspbian, его необходимо сначала
скачать, а затем извлечь. Следующий сценарий установки автоматически загрузит
и инсталлирует необходимые зависимости:
wget http://sourceforge.net/projects/webiopi/files/WebIOPi-0.7.1.tar.gz
tar xvzf WebIOPi-0.7.1.tar.gz
cd WebIOPi-0.7.1
wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi-
pi2bplus. patch
patch -pi -i webiopi-pi2bplus.patch
sudo ./setup.sh
Звв . Часть III. Практическое применение Arduino
После достаточно продолжительной установки WeblOPi будет готов к запуску.
Лучше запускать его как сервис:
sudo /etc/init.d/webiopi start
Теперь можно открыть веб-браузер на любом компьютере в домашней сети и
набрать адрес: http://iprasp:8000, где iprasp — ПР-адрес Raspberry Pi. Имя
пользователя — webiopi, пароль — raspberry.
В результате в браузере откроется стартовая страница WeblOPi (рис. 16.9). Перейдя
по ссылке GPIO Header, вы попадете на страницу управления выводами GRI0
(рис. 6.10), где можно задать режим работы любого вывода и установить значение
на выходе.
WeblOPi Main Menu
GPIO Header
Coi^aiidDetagtteRaspbercy Pi GPIO wife ^
GPIO List
Control and Debug tfae Raspberry К GPIO ordered n a siogje column.
Serial Monitor
Use die browser to play wife Serial intofeces configured io WebfOPL
Devices Monitor
Control and Debug devices and circuits wired to your Pi and configured ki WeblOPi.
Рис. 16.9. Стартовая страница WeblOPi
WeblOPi включает в себя HTTP-сервер, обеспечивающий ресурсы HTML, и
интерфейс REST API для управления выводами GRIO. Браузер сначала загружает HTML-
файл с включенной Javascript библиотекой webiopi.js, включающей jquery для
асинхронных вызовов к REST API. Этот метод очень эффективен, потому что не
требует для обновления данных обновления страницы.
Настроить сервер WeblOPi можно путем редактирования его файла конфигурации
/etc/webiopi/config:
sudo nano /etc/webiopi/config
В файле конфигурации сервера WeblOPi нас интересуют:
О блок [нттр], который позволяет включить или отключить HTTP, а также
изменить значение порта. Здесь же можно изменить местоположение файла passwd,
домашней папки и название индексного файла HTML:
Глава 16. Взаимодействие Arduino с другими программируемыми системами
389
О 192.168A101:8000/app/gpJo-header
3JV
GPIO2
G«O3
СРЮ 4
GROUND
GPTO17
GHO27
GPIO22
3.3V
GPIO10
GPIO9
СЯРЮ11
GROUND
5.0V
GROUND
UARTTX
tJARTRX
СРЮ18
GROUND
СРЮ 23
GPIO24
GROUND
GP1O25
€ЯЮ9
GPK> 7
Рис. 16.10. Страница управления выводами GRIO
[HTTP] '
enabled = true
port = 8000
passwd-file = /etc/webiopi/passwd
doc-root = /home/pi/webiopi/examples/scripts/macros
welcome-file = index.html
D а также блок [scripts] , который определяет список скриптов, выполняемых при
запуске WeblOPi. Например:
[SCRIPTS]
myscript = /home/pi/webiopi/examples/scripts/macros/script.py
16.3.2. Обмен данными по последовательному порту
Соединим Arduino и Raspberry Pi по последовательному порту, для чего на Arduino
Mega воспользуемся портом Serial 1. Подключение Arduino к LFSB-порту Raspberry
Pi выполняется через переходник USB-UART (рис. 16.11).
Пусть наша связка «Arduino — Raspberry P»i установлена на платформе робота.
В этом примере мы будем отправлять на Raspberry Pi данные с подключенных
к плате Arduino Mega датчика GPS (широту и долготу) и фоторезистора. Формат
отправки данных:
? о=хх@ — данные фоторезистора @-100);
? з=ууууууу@ — данные lat GPS (широта);
? 4=zzzzzzzz@ — данные Ion GPS (долгота).
Получение данных с Raspberry Pi:
? l;ххх;ххх$ — движение вперед со скоростью ххх @-255);
? 2; ххх;ххх $ — движение назад со скоростью ххх @-255);
390
Часть III. Практическое применение Arduino
Рис. 16.11. Монтажная схема соединений Arduino Mega и Raspberry Pi
? 3; ххх; ххх $ — остановка;
? 4; ххх; ххх $ — движение в л ево;
? 5; ххх;ххх$ — движение вправо;
? 11; ххх; ххх$ — подсветка светодиодов в зависимости от освещенности;
? 12; ххх;ххх$ — зажечь/погасить светодиоды.
Схема соединения всех элементов показана на рис. 6.12.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\16\_16jO5
сопровождающего книгу электронного архива (см. приложение 2).
16.3.3. Управление движущейся платформой
на базе Arduino по web-интерфейсу Raspberry Pi
Сначала настроим в. файле конфигурации config, который находится в папке
/etc/webiopi/, необходимые параметры: путь к домашней папке и путь к скрипту
camboti .py, выполняемому при запуске WeblOPi (мы напишем его чуть позже):
Глава 16. Взаимодействие Arduino с другими программируемыми системами
391
I
i
О.
392 Часть III. Практическое применение Arduino
doc-root = /home/pi/webiopi/examples/malina
script = /home/pi/webiopi/examples/malina/cambotl.py
Теперь напишем на python серверный скрипт camboti.py, который будет
выполняться при запуске WeblOPi. Этот скрипт запускает прослушку по последовательному
порту и исполнение макросов на веб-странице. Содержимое скрипта показано
в листинге 16.5.
# Imports
import webiopi
from webiopi.devices.serial import Serial
import sys
from subprocess import call
import time
serial = Serial("ttyUSBO", 9600)
sensors = [0 for a in rangeF)]
# Retrieve GPIO lib
GPIO = webiopi.GPIO
I #
# Macro definition part #
: л.
@webiopi.macro
def go_forward():
serial.writeString("l;255;255$")
@webiopi.macro
def go_backward():
serial.writeString(;255;255$")
0webiopi.macro
def turn_left():
serial. writeString (" 4; 2*55; 0$ ")
@webiopi.macro
def turn_right():
serial.writeString(;0;255$")
@webiopi.macro
def stop():
serial.writeString(;0;0$")
Gwebiopi.macro
def getSensor(channel):
percent = sensors[int(channel)]
return "%.2f" % percent
Глава 16. Взаимодействие Arduino с другими программируемыми системами 393
@webiopi .macro
def headlighton() :
serial.writeString(2;1;1$")
@webiopi. macro
def headlightoff () :
serial.writeString(2;0;0$")
@webiopi .macro
def autoheadlighton():
serial.writeString(1;1;1$")
@webiopi.macro
def autoheadlightoff():
serial.writeString(1;0;0$")
def loop () :
if (serial.available() > 0):
data = serial.readString()
lines = data.split("@")
count = len(lines)
lines = lines[0:count-1]
for pair in lines:
cv = pair.split("=")
channel = int(cv[0])
value = int(cv[l])
sensors[channel] = value
webiopi.sleepA)
# при загрузке WebIOPi
def setup():
stop()
webiopi.sleepE)
Электронный архив
Файл скрипта cambottpy находится в папке examples\16\ сопровождающего книгу
электронного архива (см. приложение 2),
В файле конфигурации config настроим путь к HTML-файлу, выполняемому при
запуске WeblOPi:
welcome-file = indexl.html
Открываемая веб-страница содержит кнопки управления движущейся платформой
и поля для отображения данных, поступающих с нее (данные фоторезистора и
датчика GPS).
394 Часть III. Практическое применение Arduino
Содержимое HTML-файла показано в листинге 16.6.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv = "cache-control" content = "max-age=0">
<meta http-equiv = "cache-control" content = "no-cache">
<meta http-equiv = "expires" content = ">
<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>CamBot</title>
<script src="jquery-3.3.1 .min. js"x/script>
<script type="text/javascript" src="/webiopi.js"x/script>
<script type="text/javascript">
function init() {
var button;
button = webiopi().createButton("bt_up", "/\\", go_forward);
$("#up").append(button);
button = webiopi().createButton("bt_leftf\ "<", turn_left);
$("#middle").append(button);
button = webiopi().createButton("bt_stop", "v"f stop);
$("#middle").append(button);
button = webiopi(),createButton("bt_right", ">", turn_right);
$("#middle").append(button);
button = webiopi().createButton("bt_down", "\\/", go_backward) ;
$("#down").append(button);
setlnterval(updateUI, 1000);
setlnterval(koordToServer, 30000);
function go_forward() {
webiopi().callMacro("go_forward");
Глава 16. Взаимодействие Arduino с другими программируемыми системами 395
function go_backward() {
webiopi().callMacro("go_backward");
function turn_right() {
webiopi().callMacro("turn_right");
function turn_left() {
webiopi().callMacro("turn_left");
function stopO {
webiopi().callMacro("stop");
function hi() {
var pi;
if(document.getElementByld("headlight").checked)
{webiopi().callMacro("headlighton");pl=l;}
else
{webiopi().callMacro("headlightoff");pl=0;}
function autohl() {
if(document.getElementByld("autoheadlight").checked)
{webiopi().callMacro("autoheadlighton");}
else
{webiopi().callMacro("autoheadlightoff");}
function koordToServer() {
$.ajax({
type: 'GET1,
url: f http://xxxxxxx.ru/department/getKoords.php',
cache: false,
data: {"bot": 1,
"lat": document.getElementByld(flsensor3").innerText,
"Ion": document.getElementByld("sensor4").innerText},
success: function (data) {
;//alert(data);
396 Часть III. Практическое применение Arduino
function updateUI() {
// call getSensor macro«for Arduino analog channel 0-3
webiopi().callMacro("getSensor", 0, sensorCallback);
webiopi().callMacro("getSensor", 1, sensorCallback);
webiopi().callMacro("getSensor", 2, sensorCallback);
webiopi().callMacro("getSensor", 3, sensorCallback);
webiopi().callMacro("getSensor", 4, sensorCallback);
// callback function used to display sensor data
function sensorCallback(macroName, channel, data) {
// use jQuery to change spans content
if(channel<3)
{$("#sensor"+channel).text(data);}
else
{$("#sensor"+channel).text(data/1000000);}
webiopi().ready(init);
function get__img() {
document.getElementById(",imglft).src="http://192.168.0.100:8000/img.jpg";
</script>
<style type="text/css">
button {
margin: 5px 5px 5px 5px;
width: 50px;
height: 50px;
font-size: 24pt;
font-weight: bold;
color: black;
}
</style>
</head>
<body>
<div id="content" align="center">
<img width=20" height=40"
src="http://192.168.0.100:9090/?action=stream">
<div id="up"x/div>
<div id="middle"x/div>
<div id="down"x/div>
Глава 16. Взаимодействие Arduino с другими программируемыми системами
397
<div align="center">
<div>Lighting: <span id="sensorO"x/span>
<div>Sensor center: <span id="sensorl"x/span> cm</div>
<div>Sensor right: <span id="sensor2"></span> on</div>
<div>GPS lat: <span id="sensor3"></span>
<div>GPS Ion: <span id=lfsensor4"x/span>
<form id=llforml">
</form>
<div align="center">
Headlights<input type^'checkbox" id="headlight"
onchange="hl();"><br>
auto headlights<input type=:"checkbox" id="autoheadlight"
onchange="autohl();">
</body>
</html>
Вид страницы показан на рис. 16.13.
Электронный архив
Файл index1.html находится в папке examp!es\16\ сопровождающего книгу электронного
архива (см. приложение 2).
Lighting: 56 %
Sensor center: cm
Sensor right: cm
GPS lat: 43.018442
GPS Ion: 44Л37259
Headlights 0
auto headlights ?
Рис. 16.13. Вид веб-страницы для управления движущейся платформой из WeblOPi
ГЛАВА 17
Программирование
в среде Arduino IDE других плат
Начиная с версии 1.6.5, Arduino IDE предоставила официальную поддержку для
добавления сторонних плат. Это позволяет программировать в знакомой среде и на
понятном Arduino языке Arduino-несовместимые платы и соответственно
использовать их в своих проектах.
17.1. ESP8266 — микроконтроллер
с интерфейсом Wi-Fi
С конца 2014 г. на китайских торговых площадках появились модули Wi-Fi ESP8266.
Причем, как выяснилось, это не просто модули Wi-Fi, а полноценные 32-битные
микроконтроллеры со своими наборами GPIO, в том числе поддерживающими
шины SPI, UART и 12С. При этом сами модули состоят из минимального количества
деталей: собственно микросхемы ESP8266, флеш-памяти и кварцевого генератора.
Характеристики этих модулей представлены в табл. 17.1.
В настоящее время выпускается более 12 модификаций плат модулей ESP8266,
различающихся количеством выводов и вариантами исполнения. Модули
продаются с загруженной прошивкой, которая образует мост Wi-Fi —> UART для
подключения к другому микроконтроллеру, в том числе и к Arduino. Настройка соединения и
обмен данными осуществляются с помощью АТ-команд.
Возможны два варианта работы с модулем ESP8266:
О использование его совместно с платой Arduino, которая- будет управлять
модулем по UART;
? создание собственной прошивки для модуля ESP8266 и его применение как
самодостаточного устройства.
Таблица 17.1. Характеристики модулей ESP8266
Частота
Стандарт
Мощность
Wi-Fi 2412-2484 МГц
802.11 b/g/n
+ 20дБ
Глава 17. Программирование в среде Arduino IDE других плат
399
Таблица 17.1 (окончание)
Поддерживаемые типы шифрования
Поддерживаемые режимы работы
Напряжение питания
Потребление тока
Количество доступных выводов GPIO
Внешняя флеш-память
RAM данных
RAM инструкций
Температурный режим
WEP, WPA, WPA2
Клиент (STA), точка доступа (АР),
клиент + точка доступа (STA + АР)
1,7-3,6 В
70 мА (пиковое значение 240 мА)
4-10
512 Кбайт
80 Кбайт
32 Кбайт
От-40до70°С
Один из недостатков плат ESP8266— малое количество контактов, что сильно
ограничивает их применение в больших проектах. Эта проблема решена в новой
линейке контроллеров ESP— ESP32, которые отличаются большей
производительностью, большим объемом оперативной памяти, имеют поддержку не только
Wi-Fi, но и Bluetooth, а также несут на борту большее количество выводов.
Подробно ознакомиться с описанием микроконтроллера ESP32 можно,, например, по
этой ссылке: http://micpic.ru/home/proekty-na-esp32/194-opisanie-mikrokontrollera-
esp32.html.
17.1.1. Установка Arduino IDE для работы с ESP8266
Arduino IDE позволяет создавать для ESP8266 прошивки и прошивать их в ESP8266
точно так же, как вы это делаете с Arduino. К тому же большая часть библиотек для
Arduino, не использующих внутренние порты и прочие аппаратные возможности
плат Arduino, после небольшой доработки отлично работают и на ESP-модулях.
В настоящее время для использования с ESP8266 адаптировано уже достаточно
много библиотек.
Рассмотрим установку Arduino ШЕ для работы с ESP8266.
Сначала необходимо скачать с официального сайта Arduino среду разработки
Arduino IDE версии не ниже 1.6.5 и установить ее на компьютер (см. главу J). Затем
запускаем Arduino IDE, выполняем команду меню Файл | Настройки (рис. 17.1)
и в поле Additional Boards Manager URLs вводим:
http://arduino.esp8266.com/stable/package_esp8266com_index.json
Нажимаем кнопку ОК.
Теперь выполняем команду меню Инструменты | Плата | BoardsManager и в
списке ищем плату ESP8266. Выбираем этот пункт и версию и нажимаем на кнопку
Install (рис. 17.2)— запустится процесс скачивания и установки Arduino IDE для
ESP8266 (рис. 17.3).
400
Часть III. Практическое применение Arduino
ора: -С|*с:?-«|-шае
&aife Code гФФи
Рис. 17.1. Добавление в поле Additional Boards Manager URLs адреса для скачивания Arduino IDE
для работы с ESP8266
Рис. 17.2. Выбор платы ESP8266 в окне Boards Manager
Глава 17. Программирование в среде Arduino IDE других плат
401
Рис. 17.3. Процесс скачивания и установки Arduino IDE для ESP8266
По завершении этого процесса рядом с наименованием платы ESP8266 возникнет
надпись INSTALLED (рис. 17.4), а в списке плат, открываемом по команде меню
Инструменты | Плата, появятся платы ESP8266 (рис. 17.5).
:i; п-Л^Г
Рис. 17.4. Arduino IDE для ESP8266 установлена
402
Часть III. Практическое применение Arduino
Рис. 17.5. Выбор плат ESP8266 в Arduino IDE для ESP8266
17.1.2. Печать курса валют на термопринтере
в проекте Интернета вещей
Наличие у модулей ESP8266 интерфейса Wi-Fi позволяет использовать их в
проектах Интернета вещей (IoT). Создадим на ESP8266 проект IoT-принтера, который
будет печатать курс валют на текущую дату, получая через Интернет данные с
сайта cbr.ru. В качестве принтера в этом проекте мы воспользуемся бюджетным
термопринтером, выпускаемым специально для Arduino (рис. 17.6).
Принтер использует термобумагу 2,25 дюйма, которую можно приобрести в
магазине канцелярских товаров. Вам также понадобится регулируемый источник
питания от 5 до 9 В постоянного тока, который может обеспечить ток более 1,5 А.
Общение с принтера с платой Arduino мы организуем с помощью UART-соеди-
нения.
Глава 17. Программирование в среде Arduino IDE других плат
403
Рис. 17.6. Термопринтер для Arduino
Прежде всего, необходимо провести начальный тест принтера. Подключите
принтер к блоку питания, держа нажатой кнопку на его верхней панели, — будет
распечатана таблица шрифтов и некоторая дополнительная информация (рис. 17.7).
Нужный нам параметр — скорость обмена по последовательному порту (Baudrate):
19 200 бод.
Рис. 17.7. Распечатка тестовой страницы
Подключим теперь термопринтер к модулю ESP8266 (в проекте использована
отладочная плата NodeMCU — удобная платформа на основе модуля ESP8266) по
схеме, представленной на рис. 17.8, и загрузим на плату NodeMCU код из
листинга 17.1 (для программирования нам потребуется Arduino-библиотека для принтера
404 Часть III. Практическое применение Arduino
Adafruit Thermal). В результате мы увидим вывод на принтер тестовых данных
(рис. 17.9).
Электронный архив
Библиотека Adafruit Thermal размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2),
+ 5V2A
Рис. 17.8. Монтажная схема подключения термопринтера к отладочной плате NodeMCU ESP8266
Рис. 17.9. Вывод тестовых данных из скетча на принтер
Глава 17. Программирование в среде Arduino IDE других плат 405
tinclude "AdafruitJThermal.h"
AdafruitJThermal printer(&Serial); // Pass addr to printer constructor
void setup() {
// запуск последовательного порта
Serial.beginA9200);
// инициализация принтера
printer.begin();
delayC000);
// настройки по умолчанию
printer.wake();
printer.setDefault();
printer.printIn();
printer.println();
delay(lOOO);
printer.println("test ");
printer.println(flesp8266 iot") ;
printer.printIn("thermal printer");
}
void loop() {
Нашему проекту для правильной работы необходимо знать реальное время, для
получения которого мы воспользуемся модулем часов реального времени (RTC) на
микросхеме DS3231. Подключение модуля DS3231 к модулю NodeMCU ESP8266
осуществляется по протоколу 12С: соединяем контакты NodeMCU D3 (GPIO0) и D4
(GPIO2) соответственно с контактами SCL и SDA модуля DS3231 (рис. 17.10).
Теперь нам необходимо получать из Интернета актуальный курс валют. Курсы
валют в формате XML доступны на сайте Сбербанка по адресу: vnvw.cbr.ru/
scripts/XML_daily.asp?date_req=<data>, где <data> — дата в формате dd/mm/yyyy.
Если параметр datereq в запросе отсутствует, то вы получите данные на
последнюю зарегистрированную дату.
Чтобы делать запросы по адресу получения XML-файла, сначала мы устанавливаем
соединение с точкой доступа для подключения к Интернету:
WiFi.mode (WIFI_STA) ;
WiFi.begin(ssid, password);
Затем создаем TCP-соединение с сервером cbr.ru:
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
406 Часть III. Практическое применение Arduino
h - Н
h - I
L. — I
u— l
H
H
H
H
H
и
H
—
H
H
H
H
I -
i : i -
Рис. 17.10. Схема подключения модуля DS3231 к модулю NodeMCU ESP8266
Формируем строку для запроса XML-файла:
String url = "/scripts/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);
Глава 17. Программирование в среде Arduino IDE других плат 407
return str;
}
Отправляем данные на сервер:
client.print(String("GET ") + url + " HTTP/l.l\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
delayA0);
И выводим в последовательный порт ответ сервера:
String line;
while(client.available()){
line = client.readStringUntil('\rf);
Serial.print(line);
delayA0);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\i7\_i7JJ
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем этот скетч в плату NodeMCU и видим результат его работы в мониторе
последовательного порта (рис. 17.11).
Работа со строками в Arduino достаточно проблемна, поэтому внесем в наш скетч
следующие изменения:
int k=0;
while (client.available ()) {
line = client.readStringUntil('\rf);
if(k>0) k++;
if(line.substringA1,14)=="840")
k=l;
if(k==5) {
if(dollar==line.substring(9,16)) ; // если курс изменился - выводим
на печать
else {
dollar=line.substring(9,16);
printer.println();
printer.println(getTimeStr());
printer.print("$= ");
printer.print(dollar);
printer.print(" rub");
printer.printlnO ;
delayA0);
408
Часть III. Практическое применение Arduino
Рис. 17.11. Результат получения XML-файла с сайта cbr.ru в мониторе последовательного порта
Рис. 17.12. Вывод курса доллара с сайта cbr.ru на принтер
Глава 17. Программирование в среде Arduino IDE других плат 409
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\i7\_17_03
сопровождающего книгу электронного архива (см. приложение 2).
Загружаем этот скетч в плату NodeMCU и видим, как на печать выводится курс
доллара (рис. 17.12).
17.2. Z-Uno — плата для прототипирования
устройств Z-Wave
Z-Wave — это распространенный протокол радиопередачи данных,
предназначенный для домашней автоматизации. Передача данных осуществляется на частотах
869,0 МГц (Россия), 868,42 МГц (Европа, страны СЕРТ, Китай, Сингапур, ОАЭ,
ЮАР), 908,42 МГц (США, Мексика), 921,42 МГц (Австралия, Бразилия, Новая
Зеландия), 919,8 МГц (Гонконг), 865,2 МГц (Индия), 868,2 МГц (Малайзия), 951-956
и 922-926 МГц (Япония). Модуляция FSK (частотная). Скорость передачи: 42, 100
и 9,6 Кбит/с (для совместимости со старыми устройствами). Скважность не более
1%. Предельная мощность передачи — 1 мВт.
Протокол Z-Wave весьма популярен, и существует огромное множество
совместимых устройств. Однако все, кто когда-либо автоматизировал свое жилище,
сталкивались с тем, что чего-то все-таки не хватает. Совсем недавно для облегчения
разработки устройств Z-Wave было создано устройство Z-Uno (рис. 17.13). Более
правильно назвать Z-Uno платформой, а не устройством, т. к. устройств на этой
маленькой плате можно сделать много. Разработчик устройства — компания
Z-Wave.me.
Рис. 17.13. Плата Z-Uno
410 Часть III. Практическое применение Arduino
Z-Uno — это Arduino в мире Z-Wave. На этой плате вы можете собрать все ваши
устройства. Код пишется на языке С в стиле Arduino прямо в среде Arduino IDE,
Эта же среда используется и для загрузки кода в плату по USB (есть также
возможность залить новый код по радио через контроллеры Z-Wave — так называемая
перепрошивка ОТА). Код управляет всеми выводами платы, как в Arduino.
Привычный набор функций Arduino дополнен специфическими для работы с сетью
Z-Wave— получения и отправки команд. Все сложности Z-Wave скрыты «под
капотом» Z-Uno. Основное отличие Z-Uno от плат Arduino — наличие
радиопередатчика Z-Wave и полная поддержка сетей этого стандарта.
В России продаются более сотни совместимых с Z-Wave устройств — различных
датчиков и контроллеров, а всего в мире реализуется свыше 1400 наименований от
более чем четырехсот производителей. Сеть Z-Wave представляет собой
самоорганизующуюся ячеистую mesh-сеть. То есть при отсутствии получателя сигнала
в зоне прямой видимости сигнал к нему пойдет через соседние радиоузлы сети до
тех пор, пока не будет найден получатель. Каждое устройство перед началом
работы должно быть добавлено в сеть. Сеть Z-Wave может содержать до 232 устройств,
каждое из которых имеет свой уникальный 8-битный идентификатор (ГО).
Технические характеристики платы Z-Uno:
? 28 Кбайт флеш-памяти для скетчей;
? 4 Кбайт RAM;
? Z-Wave радиотрансивер на каналах 9,6, 40 и 100 Кбит/с;
? 22 вывода GPIO (некоторые перекрываются с другими функциями);
? 4 вывода АЦП;
? 5 выводов ШИМ;
? 2 вывода UART;
П вход USB (в режиме serial);
? 64 Кбайт EEPROM;
? вывод SPI (режимы master или slave);
? 4 ИК-контроллера и один ИК-приемник с функцией обучения;
? по одному контроллеру TRIAC/ZEROX для диммирования;
? одно прерывание;
? 2 таймера A6 МГц или от внешнего источника);
? вывод 12С (программный на «ногах» GPIO);
? вывод 1-Wire (программный на «ногах» GPIO);
? 8x6 сканер кнопок (в том числе в режиме глубокого Сна);
? 2 сервисных светодиода, одна сервисная кнопка;
? один пользовательский светодиод (как контакт 13 у Arduino).
Назначение контактов платы Z-Uno показано на рис. 17.14.
Глава 17. Программирование в среде Arduino IDE других плат 411
Рис. 17.14. Назначение контактов платы Z-Uno
17.2.1. Установка Arduino IDE для Z-Uno
Пользовательские скетчи заливаются в Z-Uno из Arduino ГОЕ. Для работы в Arduino
IDE с Z-Uno необходимо установить соответствующий пакет, который содержит
компилятор, загрузчик, библиотеки и Н-файлы проекта Z-Uno. Это делается из
Менеджера плат (Board Manager), появившегося в Arduino ГОЕ, начиная с
версии 1.6.5.
Итак, запускаем Arduino ГОЕ версии не ниже 1.6.5. Выполняем команду меню
Файл | Настройки, в поле Additional Boards Manager URLs добавляем адрес:
z-uno. z-wave. me/ files /z-uno/package_z -wave .me_index. j son
и нажимаем кнопку OK (рис. 17.15).
Перезапускаем Arduino IDE. Выполняем команду меню Инструменты | Плата |
Boards Manager, находим в списке плат Z-Uno by Z-WANE>ME и нажимаем
кнопку Install (рис. 17.16).
После загрузки Плата Z-WANE>ME Z-Uno появится в списке плат (рис. 17.17).
Пункт меню Записать Загрузчик (см. рис. 17.17) позволяет обновить загрузчик
скетча Z-Uno и стек Z-Wave до самой последней версии, входящей в пакет Z-Uno.
Также в меню появится флажок для включения шифрования (класс команд
Security), компактной отправки пакетов (класс команд Multicommand) и рабочей
частоты Frequency (RU, EU, USA). Эти функции не поддерживаются некоторыми
412
Часть III. Практическое применение Arduino
Рис. 17.15. Добавление в поле Additional Boards Manager URLs адреса
для скачивания пакета поддержки проекта Z-Uno
Рис. 17.16. Процесс скачивания и установки пакета поддержки проекта Z-Uno
Глава 17. Программирование в среде Arduino IDE других плат 413
Рис. 17.17. Выбор платы Z-Uno в Arduino IDE
Рис. 17.18. Примеры использования платы Z-Uno в Arduino IDE
414 Часть III. Практическое применение Arduino
контроллерами. В меню Файл | Образцы появятся примеры, специфичные для
Z-Uno (рис. 17.18). С них и можно начать изучение возможностей Z-Uno.
17.2.2. Подключение к плате Z-Uno
датчика влажности DHT11
Рассмотрим проект подключения датчика DHT11 к плате Z-Uno и отправку
значений влажности и температуры в каналы Multilevel Sensor. Схема соединений
показана на рис. 17.19. Содержимое скетча приведено в листинге 17.2 (для
программирования используется библиотека ZUNODHT).
Рис. 17.19. Монтажная схема подключения к плате Z-Uno датчика DHT11
Листинг 1Т.2
// добавить библиотеку
#include "ZUNO_DHT.h"
// пин подключения data DHT11
#define DHTPIN 9
DHT dht(DHTPIN, DHT11);
int humidity; // переменная для данных влажности
int temperature; // переменная для данных температуры
// установить каналы для отправки
ZUNO_SETUP_CHANNELS(
ZUNO_SENSOR_MULTILEVEL_TEMPEI^TURE (getterTemperature),
ZUNO_SENSOR_MULTILEVEL_HUMIDITY(getterHumidity)
Глава 17. Программирование в среде Arduino IDE других плат 415
void setup () {
dht. begin ();
Serial.begin();
Serial.println("start");
void loop() {
// получение данных с датчика
humidity = dht.readHumidity();
temperature = dht.readTemperature();
Serial.print("Humidity = ");
Serial.print(humidity);
Serial.print(" % ");
Serial.print("Temperature = ");
Serial.print(temperature);
Serial.println(" *C");
// отправка данных в каналы
zunoSendReportA);
zunoSendReportB);
// пауза 30 секунд
delayC0000);
}
byte getterTemperature() {
return temperature;
}
byte getterHumidity() {
return humidity;
В окне канала Z-Wave данные температуры и влажности после добавления
устройств будут выглядеть следующим образом (рис. 17.20).
Рис. 17.20. Отображение данных в окне канала Z-Wave
ЧАСТЬ IV
Интересные проекты
на Arduino
Глава 18. Умная теплица
Глава 19. GPS-трекер и онлайн-сервис поиска стоянок
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник,
разменный автомат
Глава 21. Создание управляющей платы для автомойки самообслуживания
Глава 22. Arduino и интерфейс USB: управление роботами
Глава 23. Камера Pixy: реализация компьютерного зрения
Глава 24. Проекты на плате Nano 33 BLE Sense
ГЛАВА 18
Умная теплица
О0
Теплицы предназначены для обеспечения оптимального микроклимата,
способствующего росту и развитию растений. Это могут быть и большие промышленные
сооружения, и небольшое место на подоконнике для выращивания любимого
цветка. Но даже за самой крохотной теплицей на подоконнике нужен уход:
осуществлять полив, поддерживать нужную температуру, уровень освещенности и т. п.
Многие с удовольствием занялись бы подобным хозяйством, вот только ни сил, ни
времени на это нет. И только мечта подсказывает: вот бы иметь такую
конструкцию, которая была бы настолько умной, что делала бы все сама. Такая теплица
окажется востребованной теми, кто не хочет тратить много времени на уход за
растениями, а также не имеет для этого возможности в случае длительного
отсутствия — командировок, отпуска и т. п.
Назовем такую теплицу «умной» и приступим к ее созданию. Какие же функции
будет выполнять наша теплица?
Прежде всего, нам потребуется оперативно получать всю необходимую
информацию о климатических параметрах нашей теплицы: температуре и влажности
воздуха, температуре и увлажненности почвы, а также освещенности внутри теплицы,
т. е. осуществлять мониторинг климатических параметров теплицы.
Какую проблему решит функция мониторинга? Прежде всего — устранит
беспокойство насчет того, все ли в порядке с растениями во время нашего отсутствия:
есть ли вода в системе, не выключалось ли электричество, может ли система
вентиляции обеспечить нужную температуру, если в помещении стало слишком жарко,
и т. п.
Выводить данные мониторинга можно на дисплей при самой теплице, или
оповещать нас о критических значениях климатических параметров с помощью
«тревожных» светодиодов, или пересылать нам данные через Интернет на смартфон
или планшет.
Следующая функция — обеспечение автономности теплицы: при снижении
уровня увлажненности почвы в теплице ниже определенного значения — включить
полив, при снижении в ней температуры— включить обогрев, при превышении-
420
Часть IV. Интересные проекты на Arduino
температуры — включить вентиляцию, освещенность в теплице тоже необходимо
регулировать по определенному циклу.
К функции автономности тесно примыкает и следующая функция — необходимо
реализовать возможность управления теплицей: осуществлять полив, обогрев,
вентиляцию, регулировать освещенность растений. Управление можно организовать
с помощью автоматики или удаленно — через Интернет со смартфона или
планшета (рис. 18.1).
Попив, свет,
вентилятор
Network
Данные с датчиков §*--
t, h, освещенность
Данные с датчиков
t, h, освещенность
Полив, свет,
вентилятор
Рис. 18.1. Схема взаимодействия коипонентов умной теплицы
18.1. Мониторинг климатических параметров
умной теплицы
Начнем наш проект с реализации функции мониторинга параметров умной
теплицы и обеспечим получение следующих данных об окружающей среде внутри нее:
? температура воздуха;
? влажность воздуха;
О увлажненность почвы;
? освещенность цветка.
Для реализации функции мониторинга нам понадобятся следующие компоненты:
? плата Arduino Uno;
? кабель USB;
? плата прототипирования;
Глава 18. Умная теплица 421
? соединительные провода—15 шт.;
? фоторезистор;
? резистор ЮкОм;
? датчик температуры ТМРЗ6;
? датчик температуры и влажности воздуха DHT11;
П модуль влажности почвы.
Наборы компонентов «Для мейкеров»
Многие из упомянутых в этом и других проектах компонентов имеются в наборах
электроники «Для мейкеров», предлагаемых издательством «БХВ-Петербург» (см. https://
bhv.ru/product-category/nabory4llya-mejkerov/).
Познакомимся с датчиками, которые обеспечат функции мониторинга параметров
нашего проекта.
Датчик температуры и влажности воздуха DHT11 мы рассматривали в главе 9
(см. разд. PJ).
С помощью фоторезистора (рис. 18.2) осуществляется измерение освещенности:
в темноте сопротивление фоторезистора весьма велико, но когда на него попадает
свет, это сопротивление падает пропорционально его освещенности.
Pin1 Pin 2 Pln3
DC voltage Analog eND
¦2J-5.5V Voltage
Output
Рис. 18.2. Фоторезистор Рис. 18.3. Аналоговый датчик температуры ТМР36
Аналоговый датчик температуры ТМР36 (рис. 18.3) позволяет легко преобразовать
выходной уровень напряжения в показания температуры в градусах Цельсия.
Каждые 10 мВ соответствуют 1°С. Формула для преобразования выходного
напряжения в температуру:
Т,°С = [(Vout, мВ - 500] / 10.
422 Часть IV. Интересные проекты на Arduino
Модуль влажности почвы (рис. 18.4) предназначен для определения влажности
земли, в которую погружен. Он позволяет узнать о недостаточном или избыточном
поливе ваших домашних или садовых растений. Модуль состоит из двух частей:
контактного щупа YL-28 и датчика YL-38, соединенных между собой двумя
проводами. Между двумя электродами щупа YL-28 создается небольшое напряжение.
Если почва сухая, то сопротивление велико и ток будет меньше. Если земля
влажная — сопротивление меньше, ток — чуть больше. По итоговому аналоговому
сигналу можно судить о степени влажности.
Рис. 18.4. Модуль влажности почвы
Монтажная схема этого проекта представлена на рис. 18.5, а его начальный общий
вид — на рис. 18.6.
Рис. 18.5. Монтажная схема подключения к плате Arduino датчиков
для мониторинга параметров проекта умной теплицы
Глава 18. Умная теплица
423
Рис. 18.6. Проект умной теплицы: подключение датчиков
Содержимое скетча, обеспечивающего работу этого проекта, приведено в
листинге 18.1. Фоторезистор, датчик температуры ТМР36 и модуль влажности почвы —
обычные аналоговые датчики. Аналоговые значения датчика ТМР36 мы
преобразовываем в показания температуры в градусах Цельсия. Для работы с датчиком
температуры и влажности воздуха DHT11 подключается Arduino-библиотека DHT.
Данные с датчиков снимаются с интервалом 5 с и значения выводятся (пока!) в
последовательный порт Arduino.
Электронный архив
Библиотека DHT размещена в каталоге libraries сопровождающего книгу электронного
архива (см. приложение 2).
Создадим в Arduino ШЕ новый скетч, занесем в него код из листинга 18.1 и
загрузим этот скетч в плату Arduino.
// подключение библиотеки DHT
#include "DHT.h"
// тип датчика DHT
#define DHTTYPE DHT11
// контакт подключения входа данных модуля DHT11
int pinDHTll=9;
424 Часть IV. Интересные проекты на Arduino
// контакт подключения аналогового выхода.модуля влажности почвы
int pinSoilMoisture=AO;
// контакт подключения аналогового выхода датчика температуры ТМРЗб
int pinTMP36=Al;
// контакт подключения аналогового выхода фоторезистора
int pinPhotoresistor=A2;
// создание экземпляра объекта DHT
DHT dht(pinDHTll, DHTTYPE);
void setup()
{
// запуск последовательного порта
Serial.begin(9600);
dht.beginO ;
void loop ()
{
// получение данных с DHT11
float h = dht.readHumidity();
if (isnan(h))
{
Serial.println("Failed to read from DHT");
}
else
{
Serial.print("HumidityDHTll= "); Serial.print(h)/Serial.println(" %")
}
// получение значения с аналогового вывода модуля влажности почвы
int valO=analogRead(pinSoilMoisture);
Serial.print("SoilMoisture= "); Serial.printIn(valO);
// получение значения с аналогового вывода датчика температуры ТМР36
int vall=analogRead(pinTMP36);
// перевод в мВ
int mV=vall*1000/1024;
// перевод в градусы Цельсия
int t=(mV-500)/10;
Serial.print("TempTMP36= "); Serial.print(h)/Serial.println(" C");
// получение значения с аналогового вывода фоторезистора
int val2=analogRead(pinPhotoresistor);
Serial.print("Light= "); Serial.println(val2);
// пауза 5 с
Serial.println( );
delayE000);
Глава 18. Умная теплица 425
Электронный архив
Полный вариант рассмотренного скетча находится в папке examplesU8\_18_0i
сопровождающего книгу электронного архива (см. приложение 2).
Загрузив скетч в плату, открываем монитор последовательного порта и наблюдаем
вывод в него показаний наших датчиков (рис. 18.7).
HumiaityuHiii» ja.uu %
SoilMoisHumidityDHTll» 38.00 %
SoilMoisture» 531
ГетрТМРЗб- 23 С
Light» 589
HumidityDHTll- 38.00 %
SoilMoisture» 530
ГетрТМРЗб» 23 С
Light- 586
HumidityDHTll- 38.00 %
SoilMoisture- 530
ТегарТМРЗб» 23 С
Light- 607
HumidityDKTll» 38.00 %
SoilMoisture» 530
ГетрТМРЗб» 23 С
Light» 598
HuiidityDHTll- 38.00 %
SoilMoisture» 531
ГетрТМРЗб» 23 С
Light- 668
HumidityDKTll» 38.00 %
SoilMoisture» 530
ТетрТМРЗб» 23 С
Light- 621
HumidityDKTll- 38.00%
SoilMoisture» 530
ГетрТМРЗб- 23 С
Light- 576
•
Рис. 18.7. Вывод показаний наших датчиков в монитор последовательного порта Arduino
18.2. Индикация показаний умной теплицы
Смотреть на показания датчиков через монитор последовательного порта не всегда
приемлемо, поэтому мы создадим более удобную систему индикации показаний.
Для этого мы, во-первых, реализуем вывод данных с датчиков на дисплей, а во-
вторых, подключим светодиоды, которые будут сигнализировать о наступлении
неблагоприятных климатических условий, требующих нашего вмешательства
(например, о понижении увлажненности почвы, слишком высокой температуре,
недостаточной освещенности).
426
Часть IV. Интересные проекты на Arduino
Дополнительно к компонентам, использовавшимся в разд. 75.7, нам понадобятся
также:
? светодиод красный — Зшт.;
? резистор 220 Ом — 3 шт.;
? ЖК-дисплей Nokia5110.
Выбор двухцветного графического ЖК-дисплея Nokia5110 (рис. 18.8) обусловлен
его дешевизной и умеренным энергопотреблением, позволяющим подключать этот
дисплей к плате Arduino без дополнительного питания (см. также разд. 10.3).
Рис. 18.8. ЖК-дисплей Nokia5110
Монтажная схема развития нашего проекта с учетом дополнительных компонентов
(светодиодов и ЖК-дисплея) представлена на рис. 18.9.
Приступим к написанию скетча и определим условия, при которых необходимо
сигнализировать светодиодами о наступлении неблагоприятных климатических
параметров:
? температура воздуха — выше tempdetect;
? увлажненность почвы — ниже moisturedetect;
? освещенность — ниже lightdetect.
Значения для констант temp_detect, moisture_detect и light_detect необходимо
определить самостоятельно. При наступлении неблагоприятного параметра будет
Глава 18. Умная теплица
427
Рис. 18.9. Монтажная схема подключения к плате Arduino датчиков, светодиодов и ЖК-дисплея
для проекта умной теплицы
загораться соответствующий светодиод, сигнализирующий нам, что необходимо
предпринять какие-то действия:
О включить полив почвы;
О включить лампу освещения;
? включить вентилятор.
Контакты (пины) Arduino для подключения светодиодов определены константами
I?D_TEMP, LED_MOISTURE И LED__LIGHT.
Текущие значения температуры и влажности воздуха, увлажненности почвы и
освещенности будут выводиться на дисплей Nokia5110. Для работы с дисплеем
подключаются Arduino-библиотеки Adafruit_GFX и Adafruit_PCD8544.
Электронный архив
Библиотеки Adafruit_GFX и Adafruit_PCD8544 размещены в каталоге libraries
сопровождающего книгу электронного архива (см. приложение 2).
Создадим в Arduino ГОЕ новый скетч, занесем в него код из листинга 18.2 и
загрузим этот скетч в плату Arduino.
// подключение библиотек для nokia5110
#include <Adafruit_GFX.h>
#include <Adafruit PCD8544.h>
428
Часть IV. Интересные проекты на Arduino
/I подключение библиотеки DHT
#include "DHT.h"
// тип датчика DHT
#define DHTTYPE DHT11
// контакт подключения входа данных модуля DHT11
int pinDHTll=9;
// контакт подключения аналогового выхода модуля влажности почвы
int pinSoilMoisture=AO;
// контакт подключения аналогового выхода датчика температуры ТМР36
int pinTMP36-Al;
// контакт подключения аналогового выхода фоторезистора
int pinPhotoresistors=A2;
// пины светодиодов индикации
#define LED_TEMP 5
#define LED_MOISTURE 6
#define LED_LIGHT 7
// значения для условий
#define TEMPJDETECT 30
#define MOISTUREJDETECT 500
#define LIGHT_DETECT 250
// создание экземпляра объекта DHT
DHT dht(pinDHTll, DHTTYPE);
// Nokia 5110
// pin 13 - Serial clock out (SCLK)
// pin 12 - Serial data out (DIN)
// pin 11 - Data/Command select (D/C)
// pin 10 - LCD chip select (CS)
// pin 8 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544A3, 12, 11, 10, 8);
void setup()
{
// запуск последовательного порта
Serial.begin(9600);
//
pinMode (LEDJTEMP, OUTPUT) ,-digitalWrite (LED_TEMP, LOW) ;
pinMode (IJSDJtolSTURE, OUTPUT) ;digitalWrite (LED_MOISTORE, LOW) ;
pinMode (LED_LIGHT,OUTPUT) ;digitalWrite (LED_LIGHT, LOW) ;
//
dht.beginO;
// инициализация дисплея
display.begin();
// установить контраст фона экрана
display.setContrastF0);
display.clearDisplay(); // очистить экран
display.setTextSize(l); // размер шрифта
display.setTextColor(BLACK); // цвет
Глава 18. Умная теплица . 429
I/ заставка
display.setCursorA5,15);
display.print("Home Flower");
display.display();
delayB000);
void loop()
{
display.clearDisplay();
display.setCursorE, 0);
display.print("Home Flower");
// получение данных с DHT11
float h = dht.readHumidity();
display.setCursorE,10);
if (isnan(h))
{
Serial.println("Failed to read from DHT");
display.print("airH= error");
}
else
{
Serial.print("HumidityDHTll= "); Serial.print(h);Serial.println(" %");
display.print("airH=");display.print(h);display.print("%");
}
// получение значения с аналогового вывода модуля влажности почвы
display.setCursorE,20);
int valO=analogRead(pinSoilMoisture);
Serial.print("SoilMoisture= "); Serial.println(valO);
display.print("soilM=");display.print(valO);
// получение значения с аналогового вывода датчика температуры ТМРЗб
display.setCursorE,30);
int vall=analogRead(pinTMP36);
// перевод в мВ
int mV= vall*1000/1024;
// перевод в градусы Цельсия
int t=(mV-500)/10+75;//t=23;
Serial.print("ТетрТМРЗб- "); Serial.print(t);Serial.println(" C");
display.print("airT=");display.print(t);display.print(" C");
// получение значения с аналогового вывода фоторезистора
display.setCursorE,40);
int val2=analogRead(pinPhotoresistor);
Serial.print("Light= "); Serial.println(val2);
display.print("Light=");display.print(val2);
// обновить
display.display();
430 Часть IV. Интересные проекты на Arduino
//// проверка условий
// увлажненность почвы
if(valO > MOISTURE_DETECT)
digitalWrite(LED_MOISTURE,HIGH);
else
digitalWrite(LED_MOISTORE,LOW);
// температура воздуха
if(t > TEMP_DETECT)
digitalWrite(LED_TEMP,HIGH);
else
digitalWrite (LEDJTEMP, LOW) ;
// освещенность
if(val2 < LIGHT_DETECT)
digitalWrite(LED_LIGHT,HIGH);
else
digitalWrite(LED_LIGHT,LOW);
// пауза 5 с
Serial.println();
delayE000);
HumidityDHTii- 38.00 %
SoilMoisHumidityDHTll- 38.00 %
SoilMoisture- 531
ТешрТМРЗб- 23 С
Light- 589
HumidityDHTll- 38.00 %
SoilMoisture- 530
ГеирТМРЗб- 23 С
Light- 586
HumidityDHTll- 38.00 %
SoilMoisture- 530
ГеирТМРЗб- 23 С
Light- 607
HumidityDKTll» 38.00 %
SoilMoisture- 530
ГешрТМРЗб- 23 С
Light- 598
HumidityDKTll- 38.00 %
SoilMoisture- 531
ТешрТМРЗб- 23 С
Light- 668
HumidityDHTll- 38.00 %
SoilMoisture- 530
ГешрТМРЗб- 23 С
Light- 621
HumidityDHTll- 38.00 %
SoilMoisture- 530
ТеярТМРЗб- 23 С
Light- 576
Рис. 18.10. Вывод показаний датчиков в монитор последовательного порта Arduino
Глава 18. Умная теплица 431_
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\18\_18__02
сопровождающего книгу электронного архива (см. приложение 2).
После загрузки скетча в плату показания наших датчиков выводятся не только
в монитор последовательного порта (рис. 18.10), но и на дисплей (рис. 18.11), а
также о наступлении неблагоприятных климатических условий сигнализируют све-
тодиоды.
Рис. 18.11. Вывод показаний датчиков на дисплей Nokia5110
18.3. Организация полива, обдува и освещения
в умной теплице
Добавим нашей умной теплице функции управления — организуем полив цветка,
его обдув и освещение. Выполняться эти операции будут по нажатию
соответствующих кнопок.
Дополнительно к компонентам, использовавшимся в предыдущих разделах, нам
понадобятся также:
? плата расширения Relay shield на 4 реле;
? вентилятор 12 В;
? мембранный насос 12 В;
? лампа освещения;
432
Часть IV. Интересные проекты на Arduino
? кнопки — 3 шт.;
? резистор 10 кОм — 3 шт.
Для полива почвы мы воспользуемся мембранным вакуумным насосом (рис. 18.12) —
он способен всасывать воду из емкости и подавать ее в нужное место. Рабочее
напряжение насоса — 12 В, потребляемый рабочий ток — 0,5-0,7 А, расход воды —
1,5 л/мин. К насосу необходимо прикрепить шланги требуемой длины.
Рис. 18.12. Мембранный вакуумный насос
При превышении внутри теплицы установленных значений температуры воздуха
мы будем производить обдув цветка с помощью вентилятора. Вентилятор можно
взять любой, работающий от 12 В,— например, из старого системного блока
(рис. 18.13).
Рис. 18.13. Вентилятор 12 В
Искусственные источники света для эффективного выращивания растений должны
излучать спектр, аналогичный тому, который получают растения в естественной
среде. Если полной аналогии достичь сложно, то освещение должно удовлетворять
Глава 18. Умная теплица
433
хотя бы минимальным потребностям. Чтобы обеспечить наиболее комфортные для
развития растений условия, подбираются специальные лампы, оказывающие на них
различное влияние. Рекомендуется использовать следующие лампы:
? светодиодные фитолампы;
? энергосберегающие лампы дневного спектра;
? люминесцентные.
Насос, вентилятор и лампу подключать напрямую к Arduino нельзя! И нам
придется обеспечить управление ими через реле. Можно воспользоваться, например,
платой расширения Relay shield (рис. 18.14), которая содержит 4 реле с необходимой
обвязкой.
Рис. 18.14. Плата расширения Relay shield
Монтажная схема развития нашего проекта с учетом дополнительных компонентов
представлена на рис. 18.15.
Допишем код скетча с учетом сделанных в схеме дополнений. Для этого создадим
переменные типа Boolean (true— включено, false— выключено) для состояния
трех реле:
? насос — statusjpump;
? лампа — status__lamp;
? вентилятор — statusfun.
В цикле loop о отслеживаем нажатие кнопок с проверкой на дребезг (процедура
debounce ()) и при нажатии кнопки изменяем статус соответствующей переменной,
отправляя команду для изменения статуса соответствующего реле на
противоположное:
434
Часть IV. Интересные проекты на Arduino
I ^ "<l? Hi « ft
l:
"• 220 Б
Рис. 18.15. Монтажная схема развития проекта умной теплицы:
мониторинг параметров и ручное управление
? включение/выключение насоса (полив почвы);
? включение/выключение освещения;
О включение/выключение вентилятора.
Создадим в Arduino IDE новый скетч, занесем в него код из листинга 18.3 и
загрузим этот скетч в плату Arduino.
// подключение библиотек для nokia5110
#include <Adafruit_GFX.h>
#include <Adafruit PCD8544.h>
Глава 18. Умная теплица 435
II подключение библиотеки DHT
#include "DHT.h"
// тип датчика DHT
#define DHTTYPE DHT11
// контакт подключения входа данных модуля DHT11
int pinDHTll=9;
// контакт подключения аналогового выхода модуля влажности почвы
int pinSoilMoisture=AO;
// контакт подключения аналогового выхода датчика температуры ТМРЗб
int pinTMP3 6=А1;
// контакт подключения аналогового выхода фоторезистора
int pinPhotoresistor=A2;
// пины светодиодов индикации
#define LEDJTEMP 5
#define LED_MOISTURE 6
#define LED_LIGHT 7
// значения для условий
#define TEMP_DETECT 30
#define MOISTURE_DETECT 500
#define LIGHT_DETECT 250
// кнопки
#define COUNT_BUTTONS 3
int pinButtons[]={A4,A5,A6};
int lastButtons[] = {0,0,0,0};
int currentButtons[] = {0,0,0,0};
// реле
int pinRelays[]={2,3,4};
// статусы полива, освещения, вентилятора
boolean statusRelays[]={false,false,false};
// создание экземпляра объекта DHT
DHT dht(pinDHTll, DHTTYPE);
// Nokia 5110
// pin 13 - Serial clock out* (SCLK)
// pin 12 - Serial data out (DIN)
// pin 11 - Data/Command select (D/C)
// pin 10 - LCD chip select (CS)
// pin 8 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544A3, 12, 11, 10, 8);
unsigned long millisupdate=0;
436 Часть IV. Интересные проекты на Arduino
void setup()
{
// запуск последовательного порта
Serial.begin(9600);
//
pinMode (LED_TEMP, OUTPUT);digitalWrite (LEDJTEMP, LOW) ;
pinMode (LED_MOISTURE,OUTPUT) /digitalWrite (LED_MOISTORE, LOW) ;
pinMode (LED_LIGHT, OUTPUT) ;digitalWrite (LED_LIGHT,LOW) ;
//
dht,begin();
// инициализация дисплея
display.begin();
// установить контраст фона экрана
display.setContrastF0);
display.clearDisplay(); // очистить экран
display.setTextSize(l); // размер шрифта
display.setTextColor(BLACK); // цвет
// заставка
display.setCursorA5,15);
display.print("Home Flower");
display.display();
delayB000);
void loopO
{
// каждые 5 с - получение показаний датчиков
//и вывод на дисплей
if (millis()-millisupdate>5000)
{
millisupdate=millis();
display.clearDisplay();
display.setCursorE,0) ;
display.print("Home Flower");
// получение данных с DHT11
float h = dht.readHumidity();
display.setCursorE,10);
if (isnan(h))
{
Serial.println("Failed to read from DHT");
display.print("airH= error");
}
else
{
Serial.print("HumidityDHTll= "); Serial.print(h);Serial.println(" %");
display.print("airH=");display.print(h);display.print("%");
Глава 18. Умная теплица 437
// получение значения с аналогового вывода модуля влажности почвы
display.setCursorE,20);
int valO=analogRead(pinSoilMoisture);
Serial.print("SoilMoisture= "); Serial.println(valO);
display.print("soilM=");display.print(valO);
// получение значения с аналогового вывода датчика температуры ТМРЗб
display.setCursorE,30);
int vall=analogRead(pinTMP36);
// перевод в мВ
int mV= vall*1000/1024;
// перевод в градусы Цельсия
int t=(mV-500)/10+75;//t=23;
Serial.print("ТетрТМРЗ6= "); Serial.print(t);Serial.println(" C");
display.print ("airT=");display.print (t) /display.print (" C") ;
// получение значения с аналогового вывода фоторезистора
display.setCursorE,40);
int val2=analogRead(pinPhotoresistor);
Serial.print("Light= "); Serial.println(val2);
display.print("Light=");display.print(val2);
// обновить
display.display();
// вывод состояния полива, лампы, вентилятора
Serial.print("pump - "); Serial.println(statusRelays[2]);
Serial.print("fun - "); Serial.println(statusRelays[1]);
Serial.print("lamp - "); Serial.println(statusRelays[0]);
//// проверка условий
// увлажненность почвы
if(valO > MOISTURE_DETECT)
digitalWrite(LED_MOISTORE,HIGH);
else
digitalWrite(LED_MOISTORE,LOW);
// температура воздуха
if (t > TEMP_DETECT)
digitalWrite(LED_TEMP,HIGH);
else
digitalWrite (LEDJTEMP, LOW) ;
// освещенность
if(val2 < LIGHT_DETECT)
digitalWrite (LED__LIGHT,HIGH) ;
else
digitalWrite (LED_LIGHT, LOW) ;
// пауза 5 с
Serial.println();
}
// проверка нажатия кнопок выбора программ
for(int i=0;i<COUNT BUTTONS;i
438 Часть IV. Интересные проекты на Arduino
{
currentButtons[i] = debounce(lastButtons[i],pinButtons[i]);
if (lastButtons[i] == 0 && currentButtons[i] ==-1) // если нажатие...
{
doButtons(i);
}
lastButtons[i] = currentButtons[i];
// при нажатии кнопок
void doButtons(int but)
{
// изменить статус
statusRelays[but]=!statusRelays[but];
// изменить состояние реле
digitalWrite(pinRelays[but],statusRelays[but]);
/* Функция сглаживания дребезга
* Принимает в качестве аргумента предыдущее состояние кнопки
* и вьщает фактическое.
*/
int debounce(int last,int pinl)
{
int currents digitalRead(pinl); // Считать состояние кнопки
if (last != current) // если изменилось...
{
delayE); // ждем 5 мс
current = digitalRead(pinl); // считываем состояние кнопки
return current; // возвращаем состояние кнопки
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\i8\__W_03
сопровождающего книгу электронного архива (см. приложение 2).
После загрузки скетча в плату мы можем управлять включением/выключением
насоса, лампы и вентилятора с помощью кнопок. В монитор последовательного порта
выводятся показания датчиков и установленные нами состояния реле: полив,
вентиляция, освещение (рис. 18.16), на дисплей— показания датчиков. Общий вид
проекта с учетом добавленных компонентов приведен на рис. 18.17.
ГеирТМРЗб= 25 С
Light= 362
pump - О
fun - О
lamp - О
HumidityDHTll= 35.00 %
SoilMoisture= 474
ГеярТМРЗб= 25 С
Light= 362
pump - О
fun - О
lamp - О
HufflidityDHTll= 35.00 %
SoilMoisture= 459
ГешрТМР36= 25 С
Light= 362
pump - 0
fun - 1
lamp - 1 •
HuinidityDHTll= 35.00 %
SoilMoistjure= 447
TempTMP36= 25 С
Light= 361
pump - 0
fun - 0
lamp - 1
HumidityDHTll= 35.00 %
SoilMoisture= 446
TempTMP36= 25 С
Light= 366
pump - 0
fun - 1
lamp - 1
i
00
I
Q>
Рис. 18.16. Вывод показаний датчиков и состояний реле
в монитор последовательного порта Arduino
Рис. 18.17. Проект «Домашний цветок»: подключение реле, насоса и лампы
со
440
Часть IV. Интересные проекты на Arduino
18.4. Переносим функции мониторинга
и управления теплицей на устройство
с ОС Android
Перенесем функции мониторинга и управления теплицей на смартфон (или
планшет) с операционной системой Android. Во-первых, это очень удобно, во-вторых,
мы сможем исключить из системы ряд деталей, а именно — дисплей и кнопки. Эти
функции возьмет на себя смартфон/планшет. Связь Arduino со смартфоном будет
осуществляться по Bluetooth, и нам понадобится Bluetooth-модуль НС-05,
позволяющий наладить двунаправленную радиосвязь по протоколу Bluetooth (этот
модуль мы уже рассматривали ъразд. 12.5).
Подключение Bluetooth-модуля к плате Arduino осуществляется по
последовательному порту. Аппаратный последовательный порт Arduino у нас занят — через него
осуществляется отладка программы, поэтому для связи с Bluetooth-модулем мы
воспользуемся программным последовательным портом. В качестве контактов
программного последовательного интерфейса мы задействуем цифровые выводы 17
и 18, которые освободятся после удаления из системы кнопок.
Монтажная схема развития нашего проекта с учетом сделанных изменений
представлена на рис. 18.18. Заметьте, что питание Bluetooth-модуля НС-05 — 3,3 В!
Теперь нам надо удалить из предыдущего скетча фрагменты кода, связанные с
выводом данных на дисплей и обработкой нажатий клавиш, и добавить отправку
данных в Bluetooth-модуль НС-05 по SoftwareSerial, а также получение и обработку
данных, поступающих по SoftwareSerial, для команд включения/выключения
насоса, вентилятора и лампы.
Формат команд отправки данных мониторинга в SoftwareSerial представлен
в табл. 18.1, а формат команд управления из SoftwareSerial — в табл. 18.2.
Таблица 18.1. Команды отправки данных мониторинга в SoftwareSerial
Команда
aH=<data>\r\n
SM=<data>\r\n
aT=<data>\r\n
Ph=<data>\r\n
PM=<data>\r\n
FN=<data>\r\n
LM=<data>\r\n
Описание
Данные влажности с датчика DHT11
Данные увлажненности ПОЧВЫ SoilMoisture
Данные температуры с датчика ТМР36
Данные освещенности — с фоторезистора
Состояние реле включения/выключения A/0) насоса
Состояние реле включения/выключения A/0) вентилятора
Состояние реле включения/выключения A/0) лампы
Глава 18. Умная теплица
441
Таблица 18.2. Команды управления из SoftwareSerial
Команда
РМ=1#
РМ=0#
FN=1#
FN=0#
LM=1#
LM=0#
Описание
Включение насоса
Выключение насоса
Включение вентилятора
Выключение вентилятора
Включение лампы
Выключение лампы
" 2.20 S
Рис. 18.18. Монтажная схема развития проекта умной теплицы:
мониторинг параметров, обеспечение комфортных условий и связь по Bluetooth
442 Часть IV. Интересные проекты на Arduino
Создадим в Arduino ШЕ новый скетч, занесем в него код из листинга 18.4 и
загрузим этот скетч в плату Arduino.
// подключение библиотеки SoftwareSerial
#include <SoftwareSerial.h>
// подключение библиотеки DHT
#include "DHT.h"
// тип датчика DHT
#define DHTTYPE DHT11
// контакты подключения bluetooth-модуля НС-05
int pinBlRx=17;
int pinBlTx=18;
// контакт подключения входа данных модуля DHT11
int pinDHTll=9;
// контакт подключения аналогового выхода модуля влажности почвы
int pinSoilMoisture=AO;
// контакт подключения аналогового выхода датчика температуры ТМР36
int pinTMP36=Al;
// контакт подключения аналогового выхода фоторезистора
int pinPhotoresistor=A2;
// пины светодиодов индикации
#define LED_TEMP 5
#define LED_MOISTURE 6
#define LED_LIGHT 7
// значения для условий
#define TEMP_DETECT 30
#define MOISTURE_DETECT 500
#define LIGHT_DETECT 250
// реле
int pinRelays[]={2,3,4};
// статусы полива, освещения, вентилятора
boolean statusRelays[]={false,false,false};
// создание экземпляра объекта SoftwareSerial
SoftwareSerial HC05Serial(pinBlRx,pinBlTx);
// создание экземпляра объекта DHT
DHT dht(pinDHTll, DHTTYPE);
unsigned long millisupdate=O;
// для получения данных из SoftwareSerial
String inputStringO = "";
Глава 18. Умная теплица 443
II признак конца полученной строки
boolean stringCompleteO = false;
void setup ()
{
// запуск последовательного порта
Serial.begin(9600);
//
pinMode (LEDJTEMP, OUTPUT) ; digitalWrite (LED_TEMP, LOW) ;
pinMode(LED_MOISTURE,OUTPUT)/digitalWrite(LED_MOISTURE,LOW);
pinMode(LED_LIGHT,OUTPUT)/digitalWrite(LED_LIGHT,LOW);
// инициализация dht
dht.begin()/
// запуск SoftwareSerial
HC05Serial.begin(9600)/
// резервирование 50 bytes для the inputString:
inputStringO.reserveE0)/
void loop()
{
// ожидание конца строки для анализа поступившего запроса:
serialEventO()/
if (stringCompleteO)
{
Serial.println(inputStringO)/
parse_stringO(inputStringO);
// очистить :
inputStringO = ""/
stringCompleteO = false/
}
// каждые 5 с - получение показаний датчиков
//и вывод на дисплей
if (millis()-millisupdate>5000)
{
millisupdate^millis () /
// получение данных с DHT11
float h = dht.readHumidityO/
if (isnan(h))
{
Serial.println("Failed to read from DHT")/
HC05Serial.println("Hl=101")/ •
delayA0)/
}
else
{
^ Serial.print("HumidityDHTll= ")/ Serial.print(h)/Serial.println(" %")/
444 Часть IV. Интересные проекты на Arduino
HC05Serial.print("аН=");HC05Serial.print(h);HC05Serial.println();
delayA0);
// получение значения с аналогового вывода модуля влажности почвы
int valO=analogRead(pinSoilMoisture);
Serial.print("SoilMoisture= "); Serial.println(valO);
HC05Serial.print("SM=");HC05Serial.print(h);HC05Serial.println();
delayA0);
// получение значения с аналогового вывода датчика температуры ТМРЗб
int vall=analogRead(pinTMP36);
// перевод в мВ
int mV= vall*1000/1024;
// перевод в градусы Цельсия
int t=(mV-500)/10+75;//t=23;
Serial.print("TempTMP36= "); Serial.print(t);Serial.printIn(" C");
HC05Serial.print("aT=");HC05Serial.print(t);HC05Serial.println();
delayA0);
// получение значения с аналогового вывода фоторезистора
int val2=analogRead(pinPhotoresistor);
Serial.print("Light= "); Serial.println(val2);
HC05Serial.print("Ph=");HC05Serial.print(val2);HC05Serial.printIn();
delayA0);
// обновить
// вывод состояние полива, лампы, вентилятора
Serial.print("pump - "); Serial.println(statusRelays[2]);
Serial.print("fun - "); Serial.println(statusRelays[1]);
Serial.print("lamp - "); Serial.println(statusRelays[0]);
HC05Serial.print("PM=");HC05Serial.print(statusRelays[2]);
HC05Serial.print(" ");
delayA0);
HC05Serial.print("FN=");HC05Serial.print(statusRelays[1]);
HC05Serial.print(" ");
delay(lO);
HC05Serial.print("LM=");HC05Serial.print(statusRelays[0]);
HC05Serial. printing1 ");
delayA0);
//// проверка условий
// увлажненность почвы
if(valO > MOISTURE_DETECT)
digitalWrite(LED_MOISTURE,HIGH);
else
digitalWrite(LED_MOISTURE,LOW);
// температура воздуха
if(t > TEMP_DETECT)
digitalWrite(LED_TEMP,HIGH);
else
digitalWrite (LEDJTEMP, LOW);
Глава 18. Умная теплица 445
// освещенность
if(val2 < LIGHT_DETECT)
digitalWrite(LED_LIGHTfHIGH);
else
digitalWrite(LED_LIGHT,LOW);
// пауза 5 с
Serial.println();
// SerialEvent для НС05
void serialEventO() {
while (HC05Serial.available()) {
// получить очередной байт:
char inChar = (char)HC05Serial.read()
// добавить в строку
inputStringO += inChar;
// /n - конец передачи
if (inChar — •#') {
stringCompleteO = true;
// парсинг строки из android
void parse_stringO(String inputString)
{
// длина строки
int lengthl=inputString.length();
if(lengthl!=5)
{Serial.printIn("ERROR1"); return;}
if(inputString.charAtB)!='=')
{Serial.printIn("ERROR2"); return;}
if(inputString.charAtD)!='#')
{Serial.println("ERROR3"); return;}
String paraml=inputString.substring@,2);
int param2=inputString.substringC,4).tolnt();
Serial.print("paraml=");Serial.println(paraml);
Serial.print("param2=");Serial.println(param2);
if (paraml="PM")
doCoinmand B, min (param2,1));
else if (paraml=="FNlf)
doCommand A, min (param2, 1));
else if(paraml=="LM")
doCommand @, min (param2, 1));
// исполнение команды от смартфона
void doCommand(int relay, int statusl)
446
Часть IV. Интересные проекты на Arduino
aH-34 5М-449 aT-24 Ph-222 РН-1 FH-0 LU-0 аН-ЗО SU-443 aT-24 Ph-239 РИ-1 FH-0 LM-0
вН-33 SM-446 aT-24 Ph-370 PU-1 FH-0 LU-0
аН-32 5М-446 aT-24 Ph-287 PU-1 FH-0 LU-0
вН-32 SU-440 aT-24 Ph-268 РИ-1 FH-0 LU-0
aH-34 SU-449 aT-24 Ph-404 PU-1 FH-0 LU-0
aH-31 SU-447 aT-24 Ph-392 PU-1 FH-Q LU-0
aH-33 SU-446 aT-24 Ph-310 PU-1 FH-0 LU-0
aH-30 SU-448 aT-24 Ph-366 PU-1 FH-0 LU-0
aH-34 SU-447 aT-24 Ph-261 PU-1 FH-0 LU-0
aH-33 SU-448 aT-24 Ph-309 PU-1 FH-0 LU-0
aH-33 SU-44Q aT-24 Ph-414 PU-1 FH-0 LU-0
aH-31 SU-440 aT-24 Ph-353 PU-1 FH-0 LU-0
32 SU-446 aT-24 Ph-394 PU-1 FH-0 LU-0
Рис. 18.19. Получение в приложение Bluetooth Terminal, установленное на планшете,
данных мониторинга с платы Arduino
aH-35 SM-44Q aT-24 Ph-334 PM-1 FH-0 LM-0 aH=35 SM-440 aT-24 Ph-333 PM-1 FN-0 LM-i
aH«35 SM-440 aT-24 Ph-334 PM-1 FH-0 LM-0
aH-35 SM-440 aT-24 Ph-334 PM-1 FH-0 LM-0
FH-1#
aH-35 SM-440 aT-24 Ph-334 PM-1 FH-1 LM-0
aH-35 SM-440 aT-24 Ph-333 PM-1 FH-1 LM-0
PM*Q#
aH-35 SM-440 aT-24 Ph-334 PM-0 FH-1 LM-Q
aH-35 SM-440 aT-24 Ph-333 PM-0 FH-1 LM-0
aH-35 SM-440 aT-24 Ph-334 PM-0 FH-1 LM-1
LM=O#
aH-35 SM-440 aT-24 Ph-334 PM-0 FH-1 LM-0
Рис. 18.20. Отправка
из приложения Bluetooth
Terminal, установленного
на планшете,
команд управления
на плату Arduino
Глава 18. Умная теплица 447
I/ изменить статус
statusRelays[relay]=statusl;
// изменить состояние реле
digitalWrite(pinRelays[relay],statusRelays[relay]);
Получать на смартфон/планшет данные и отправлять с него команды мы будем
(пока!) из приложения Bluetooth Terminal, которое скачаем из Google Play.
Установим его на смартфон/планшет, подключимся из Bluetooth Terminal к нашему
Bluetooth-модулю и увидим на смартфоне/планшете отправленные с платы Arduino
данные (рис. 18.19). Из этого же приложения мы отправляем на плату Arduino
команды управления: включения/выключения насоса, вентилятора и лампы
(рис. 18.20).
18.5. Создаем собственное мобильное
приложение для управления умной теплицей
Использовать приложение Bluetooth Terminal не очень удобно — хорошо бы
создать для этого собственное полноценное приложение. Глубоко вникать в вопросы
программирования для операционной системы Android не входит в наши планы,
поэтому нам нужна простая и понятная система создания кода для Android —
наподобие системы Sctratch для Arduino. К счастью, подобный визуальный редактор
есть— это Арр Invertor 2, онлайн-редактор визуального программирования для
Android, доступ к которому можно получить на странице: http://ai2.appinventoi\
mit.edu.
После авторизации (можно использовать профиль Google) или регистрации
попадаем в свой профиль программы, где можем создать новый проект (рис. 18.21).
Рис. 18.21. Создание проекта в своем профиле Арр Invertor 2
448 Часть IV. Интересные проекты на Arduino
Сначала в панели Designer создаем интерфейс нашего приложения (рис. 18.22),
перетаскивая на экран необходимые компоненты. Кроме визуальных компонентов
необходимо добавить три невизуальных:
? Bluetooth client — из раздела Connectivity;
? Clock— из раздела Sensors (для получения данных из Bluetooth с
периодичностью, установленной в Clock);
? Notifer — из раздела Userlnterface.
Рис. 18.22. Создание интерфейса приложения в панели Designer
Затем переходим в раздел Block, где создаем код:
? для инициализации Bluetooth-соединения и создания Bluetooth-клиента;
? для отправки сообщений при изменении состояния флажков для насоса,
вентилятора и лампы;
? для получения по таймеру сообщений, поступающих по Bluetooth из Arduino.
После чего создаем Арр-приложение (рис. 18.23) и загружаем его на
смартфон/планшет.
Теперь нам надо внести небольшие изменения в наш скетч (см. листинг 18.4),
заменив разделитель с пробела на символ * при отправке данных с Arduino на Android.
Электронный архив
Код этого скетча находится в папке examples\18\_18jO5 сопровождающего книгу
электронного архива (см. приложение 2).
Глава 18. Умная теплица
449
Рис. 18.23. Генерация Арр-приложения
Загружаем этот скетч в плату Arduino и запускаем на смартфоне/планшете наше
приложение (рис. 18.24). Затем соединяемся из него по Bluetooth с платой Arduino
(рис. 18.25) и получаем возможность наблюдать за состоянием датчиков нашей
теплицы и отправлять команды управления поливом, обдувом и освещением
(рис. 18.26).
У {j/1 «Ж В € Н N ОС ? Ь
Массе дл« ттлшэ
; Вентилятор
Рис. 18.24. Приложение запущено на планшете
Электронный архив
Разработанное приложение и файл проекта находятся в папке exampfes\18\Android
сопровождающего книгу электронного архива (см. приложение 2).
450
Часть IV. Интересные проекты на Arduino
Рис. 18.25. Подключение приложения по Bluetooth к плате Arduino
Рис. 18.26. Приложение в работе: получение данных
с датчиков и отправка команд управления
Глава 18. Умная теплица 451
18.6. Превращаем нашу умную теплицу
в объект Интернета вещей
Теперь мы превратим нашу умную теплицу в объект Интернета вещей (IoT) — это
позволит мониторить данные теплицы из любой точки мира, где у нас будет доступ
к Интернету. Для этого необходимо организовать отправку этих данных на
публичный интернет-сервер— например, на сайт «Народный мониторинг» (http://
narodmon.ru).
Сайт «Народный мониторинг» — геоинформационный сервис, позволяющий
отображать на карте мира и контролировать (на ПК, смартфонах и других гаджетах)
показания датчиков своих участников (температуры, влажности, атмосферного
давления, скорости и направления ветра, радиации, энергопотребления и многих
других), а также трансляций частных и городских веб-камер для публичного или
частного (приватного) просмотра (см. также главу 13).
Дополнительно к компонентам, использовавшимся в предыдущих разделах этой
главы, нам понадобится только один модуль — Ethernet shield W5100, который мы
уже рассматривали в разд. 13.1.
В скетч из предыдущего раздела мы внесем лишь незначительные изменения. При
включении Arduino добавим запуск Ethernet и получение IP-адреса Ethernet-
шилдом W5100. Процедура еthemet_begin () получает IP-адрес либо с помощью
DHCP, либо назначает плате статический адрес (в зависимости от значения
константы DHCP) (листинг 18.5).
byte arduinojnac[] = { 0x35, 0x75, 0x02, OxFF, OxFF, 0x01 };
String MAC=5-75-02-FF-FF-01";
EthernetClient client;
ttdefine DHCP 1 // 0-dhcp, 1 - manual
// если адрес статический
// (установить #define DHCP 1)
int mip[4]={192,168,0,121};
int mmask[4]={255,255,255,0};
int mgateway[4]={192,168,0,28};
int mdns[4]={192,168,l,l};
// запустить ethernet
void ethernet_begin()
{
if(DHCP==0)
{
if(Ethernet.begin(arduino_mac)==0)
Serial.printIn("dhcp - error");
else
Serial.println("dhcp - ok");
452 Часть IV. Интересные проекты на Arduino
else
{
IPAddress arduino_ip(mip[0] ,mip[l] ,mip[2] fmip[3]);
IPAddress dns_ip(mdns [0] ,mdns [1] ,mdns [2] ,mdns [3]);
IPAddress gateway_ip(mgateway[0],mgateway[1],mgateway[2],mgateway[3]);
IPAddress subnet_mask(ramask[O],mmask[l],mmask[2],ramask[3]);
Ethernet.begin(arduino_mac, arduino_ip, dns_ip, gateway_ip, subnetjnask) ;
Для загрузки данных на сервер «Народного мониторинга» необходимо отправить
их методом GET на адрес:
http://narodmon.ru/get?ID=MAC&macl=valuel&...&macN
При каждом опросе датчиков формируем строку, но отправляем данные один раз
в 5 мин.
Итак, создадим в Arduino IDE новый скетч, занесем в него код из листинга 18.6
и загрузим этот скетч в плату Arduino.
// подключение библиотеки SoftwareSerial
#include <SoftwareSerial.h>
// подключение библиотеки DHT ,
tinclude "DHT.h"
// тип датчика DHT
#define DHTTYPE DHT11
// контакты подключения bluetooth-модуля HC-05
int pinBlRx=17;
int pinBlTx=18;
// контакт подключения входа данных модуля DHT11
int pinDHTll=9;
// контакт подключения аналогового выхода модуля влажности почвы
int pinSoilMoisture=AO;
// контакт подключения аналогового выхода датчика температуры ТМРЗб
int pinTMP3 6=A1 ;
// контакт подключения аналогового выхода фоторезйстора
int pinPhotoresistor=A2;
// пины светодиодов индикации
#define LEDJTEMP 5
#define LED_MOISTURE 6
tdefine LED_LIGHT 7
// значения для условий
#define TEMP DETECT 30
Глава 18. Умная теплица 453
#define MOISTUREJDETECT 500
tdefine LIGHT_DETECT 250
// реле
int pinRelays[]={2,3,4};
// статусы полива, освещения, вентилятора
boolean statusRelays[]={false,false,false};
// создание экземпляра объекта SoftwareSerial
SoftwareSerial HC05Serial(pinBlRx,pinBlTx);
// создание экземпляра объекта DHT
DHT dht(pinDHTll, DHTTYPE);
// для получения данных из SoftwareSerial
String inputStringO = "";
// признак конца полученной строки
boolean stringCompleteO = false;
// Ethernet
#include <SPI.h>
tinclude <Ethernet.h>
byte arduinojnac[] = { 0x35, 0x75, 0x02, OxFF, OxFF, 0x01 };
String MAC=5-75-02-FF-FF-01";
EthernetClient client;
#define DHCP 1 // 0-dhcp, 1 - manual
// если адрес статический
// (установить #define DHCP 1)
int mip[4]={192,168,0,121};
int mmask[4] = {255,255,255,0};
int mgateway[4]={192,168,0,28};
int mdns[4]={192,168,l,l};
// IoT-сервер
char server[] = "narodmon.ru";
String strNarodmon="";
unsigned long millisupdatel=O;
unsigned long millisupdate2=0;
void setup()
{
// запуск последовательного порта
Serial.begin(9600);
//
pinMode (LED_TEMP, OUTPUT) ;digitalWrite (LED_TEMP, LOW) ;
pinMode (LED_MOISTURE,OUTPUT) ;digitalWrite (LEDJ1OISTORE, LOW) ;
pinMode (LED_LIGHT, OUTPUT) ;digitalWrite (LED_LIGHT, LOW);
454 Часть IV. Интересные проекты на Arduino
// инициализация dht
dht.begin();
// запуск SoftwareSerial
HC05Serial.begin(9600);
// резервирование 50 bytes для the inputString:
inputStringO.reserveE0);
// установка сетевого соединения
ethernet_begin();
print_ip () ;
void loop()
{
// ожидание конца строки для анализа поступившего запроса:
serialEventO();
if (stringCompleteO)
{
Serial.println(inputStringO);
parse_stringO(inputStringO);
// очистить :
inputStringO = "";
stringCompleteO = false;
}
// каждые 5 с - получение показаний датчиков
//и вывод в software serial на экран телефона
if(millis()-millisupdatel>5000)
{
millisupdatel^millis();
s t rNa rodmon=" ";
// получение данных с DHT11
float h = -dht.readHumidity();
if (isnan(h))
{
Serial.println("Failed to read from DHT");
HC05Serial.println("Hl=101");
delayA0);
}
else
{
Serial.print("HumidityDHTll= "); Serial.print(h);Serial.println(" %");
HC05Serial.print("aH=");HC05Serial.print(h);HC05Serial.print("*");
strNarodmon=strNarodmon+"&Hl=f4St'ring (h) ;
delayA0);
}
// получение значения с аналогового вывода модуля влажности почвы
int valO=analogRead(pinSoilMoisture);
Serial.print("SoilMoisture= "); Serial.println(valO);
Глава 18. Умная теплица 455
HC05Serial.print("SM=");HC05Serial.print(valO);HC05Serial.print("*");
strNarodmon=strNarodmon+"&H2="+String(map(valO, 0,1024,0,100));
delayA0);
// получение значения с аналогового вывода датчика температуры ТМР36
int vall=analogRead(pinTMP36);
// перевод в мВ
int mV= vall*1000/1024;
// перевод в градусы Цельсия
int t=(mV-500)/10+75;
Serial.print("ТетрТМРЗ6= "); Serial.print(t)/Serial.println(" C");
HC05Serial.print("aT=");HC05Serial.print(t);HC05Serial.print("*");
strNarodmon=strNarodmon+"&Tl=="+String (t);
delayA0);
// получение значения с аналогового вывода фоторезистора
int val2=analogRead(pinPhotoresistor);
Serial.print("Light= "); Serial.println(val2);
HC05Serial.print("Ph=");HC05Serial.print(val2);HC05Serial.print("*");
strNarodmon=strNarodmon+"&Ll="+String(val2);
delayA0);
// обновить
// вывод состояния полива, лампы, вентилятора
Serial.print("pump - "); Serial.println(statusRelays[2]);
Serial.print("fun - "); Serial.println(statusRelays[1]);
Serial.print("lamp - "); Serial.println(statusRelays[0]);
HC05Serial.print("PM=");HC05Serial.print(statusRelays[2]);
HC05Serial.print("*");
delayA0);
HC05Serial.print("FN=");HC05Serial.print(statusRelays[1]);
HC05Serial.print("*");
delayA0);
HC05Serial.print("LM=");HC05Serial.print(statusRelays[0]);
delayA0);
//// проверка условий
// увлажненность почвы
if(valO > MOISTURE_DETECT)
digitalWrite(LED_MOISTURE,HIGH);
else
digitalWrite(LED_MOISTORE,LOW);
// температура воздуха
if(t > TEMP_DETECT)
digitalWrite(LED_TEMP,HIGH);
else
digitalWrite(LED_TEMP,LOW);
// освещенность
if(val2 < LIGHT_DETECT)
digitalWrite(LED_LIGHT,HIGH);
456 Часть IV. Интересные проекты на Arduino
else
digitalWrite (LED_LIGHT, LOW) ;
Serial.println();
}
if (millis()-millisupdate2>5*60000)
{
millisupdate2=millis();
if (client.connect(server, 80))
{
client.print("GET /get?ID=");
client.print(MAC);
client.print(strNarodmon);
client.println(" HTTP/1.1");
client.print("Host: ");
client.printIn(server);
client.println("Connection: close");
client.println();
client.println();
client,, stop ();
client.flush() ;
}
else
Serial.println("error send narodmon");
Serial.println(strNarodmon);
// SerialEvent для НС05
void serialEventO() {
while (HC05Serial.available()) {
// получить очередной байт:
char inChar = (char)HC05Serial.read();
// добавить в строку
inputStringO += inChar;
// /n - конец передачи
if (inChar — f#f) {
stringCompleteO = true;
// парсинг строки из android
void parse_stringO(String inputString)
{
// длина строки
int lengthl=inputString.length();
Глава 18. Умная теплица 457
if(lengthl!=5)
{Serial.printIn("ERR0R1"); return;}
if(inputString.charAtB)!=f=f)
{Serial.printIn("ERROR2"); return;}
if(inputString.charAtD)! ='#f)
{Serial.println("ERROR3"); return;}
String paraml=inputString.substring@,2);
int param2=inputString.substringC,4).tolnt();
Serial.print (ffparaml="); Serial.println (paraml);
Serial.print("param2=");Serial.printIn(param2);
if(paraml=="PM")
doCoiranand B, min (param2,1));
else if(paraml=="FN")
doCommand A, min (param2,1));
else if(paraml=="LM")
doCommand @, min (param2,1));
// исполнение команды от смартфона
void doCommand(int relay, int statusl)
{
// изменить статус
statusRelays[relay]=statusl;
// изменить состояние реле
digitalWrite(pinRelays[relay],statusRelays[relay]);
// запустить ethernet
void ethernet_begin()
{
if(DHCP==0)
{
if(Ethernet.begin(arduinojnac)==0)
Serial.println("dhcp - error");
else
Serial.println("dhcp - ok");
}
else
{
IPAddress arduino_ip (mip [0],mip [ 1 ],mip [2],mip [3]);
IPAddress dns_ip (mdns [0],mdns [ 1 ] ,mdns [2] ,mdns [3]) ;
IPAddres s gateway_ip(mgateway[0],mgateway[1],mgateway[2], mgateway[3]);
IPAddress subnet_mask(mmask[O],mmask[l],rnmask[2],mmask[3]);
Ethemet.begin(arduinojnac, arduino_ip, dns_ip, gateway_ip, subnetjnask);
458 Часть IV. Интересные проекты на Arduino
// вывести ip-адрес
void print_ip()
{
Serial.print("My IP address: ");
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.locallP0 [thisByte], DEC);
Serial.printC1.") ;
}
Serial.println();
Serial.print("My SUBNET: ") ;
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.subnetMaskO [thisByte], DEC);
Serial.print(".");
}
Serial.println();
Serial.print("My GATEWAYIP: ");
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.gatewayIP()[thisByte], DEC);
Serial.print(".");
}
Serial.println();
Serial.print("My DNS: ") ;
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.dnsServerlPO [thisByte], DEC);
Serial.print(".");
}
Serial.println();
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\18\_18_07
сопровождающего книгу электронного архива (см. приложение 2).
После загрузки скетча в плату и отправки данных необходимо зарегистрироваться
в сервисе «Народный мониторинг» и настроить визуализацию наших данных, а
затем — добавить наше устройство на карту «Народного мониторинга». Для этого
вводим МАС-адрес устройства:
String MAC=5-75-02-FF-FF-01";
и нажимаем на кнопку ОК (рис. 18.27).
Далее выбираем пункт меню Датчики | Настройка датчиков и триггеров, где
изменяем названия датчиков и адрес местонахождения устройства (рис. 18.28). Более
Глава 18. Умная теплица 459
Рис. 18.27. Добавление устройства на карту сервиса «Народный мониторинг»
Рис. 18.28. Установка названий для датчиков и адреса устройства
460 Часть IV. Интересные проекты на Arduino
точно положение устройства на карте можно подстроить с помощью пункта меню
Подвинуть по карте.
Теперь вы можете увидеть на карте всплывающее окно с последними показаниями
датчиков своей умной теплицы (рис. 18.29) и следить за ними из любого места, где
есть доступ к сети Интернет.
Рис. 18.29. Всплывающее окно с данными нашей теплицы
на карте сайта «Народный мониторинг»
ГЛАВА 19
GPS-трекер
и онлайн-сервис поиска стоянок
В этой главе на основе модуля GPS-приемника, позволяющего определять наше
местоположение с помощью глобальной системы GPS, мы создадим проект он-
лайн-сервиса поиска стоянок, опирающегося на сервис Яндекс.Карты.
19.1. Подключение GPS-модуля
к плате Arduino
GPS (Global Positioning System) — это система, позволяющая с точностью до 100 м
определить местоположение (координаты) объекта, то есть его широту, долготу и
высоту над уровнем моря, а также направление и скорость его движения. Кроме
того, с помощью GPS можно заффиксировать время с точностью до 1 не. GPS
состоит из совокупности определенного количества искусственных спутников Земли
(спутниковой системы NAVSTAR) и наземных станций слежения, объединенных
в общую сеть. В качестве абонентского оборудования служат индивидуальные
GPS-приемники, способные принимать сигналы со спутников и по принятой
информации вычислять свое местоположение. В нашем проекте мы воспользуемся
GPS-приемником (трекером) V.KEL VK16E (рис. 19.1).
Рис. 19.1. GPS-приемник V.KEL VK16E
462 Часть IV. Интересные проекты на Arduino
Так называемый холодный старт происходит, когда GPS-приемник был выключен
длительное время, перемещался в выключенном состоянии на значительное
расстояние, или его часы не совпадают с данными спутника. При холодном старте со
спутников скачивается соответствующая информация, называемая альманахом.
Время обновления альманаха — от 5 до 15 мин в зависимости от условий приема и
количества видимых спутников. Необходимое условие— приемник в это время
должен быть неподвижен. Теплый старт происходит, когда приемник был
выключен более 30 мин. При этом прозводится прием уточняющих данных, занимающий
0,5-1,5 мин. Горячий старт происходит, когда приемник был отключен
непродолжительное время. Данные на приемнике считаются свежими, и приемник просто
находит спутники (опираясь на данные альманаха).
Для проверки работоспособности подключим, используя адаптер USB-TTL, модуль
по последовательному порту к компьютеру с ОС Windows и запустим программу
MiniGPS_v1.7.1.exe. Программа показывает количество найденных приемником
спутников и, в случае их достаточного числа, демонстрирует наше
местоположение: географические широту и долготу. Мигание расположенного на модуле
зеленого светодиода сигнализирует о достаточном для определения положения
количестве спутников.
Теперь подключим GPS-приемник к плате Arduino (рис. 19.2) и напишем скетч,
выводящий данные о его местоположении: географические широту и долготу, а также
текущую дату и время по Гринвичу — в монитор последовательного порта Arduino
(рис. 19.3).
При написании скетча (листинг 19.1) используются библиотеки SoftwareSerial и
TinyGPS, позволяющие выделять нужные данные из всего потока, передаваемого
приемником.
Rx
Рис. 19.2. Монтажная схема подключения GPS-приемника к плате Arduino
Глава 19. GPS-трекер и онлайн-сервис поиска стоянок 463
Рис. 19.3. Получение данных с GPS-модуля
Электронный архив
Библиотека TinyGPS размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
II подключение библиотек
#include <SoftwareSerial.h>
tinclude <TinyGPS.h>
// создание экземпляров объектов
TinyGPS gps;
SoftwareSerial gpsSerialE, 6);
bool newdata = false;
unsigned long start;
long lat, Ion;
unsigned long time, date;
void setup() {
gpsSerial.begin(9600); // скорость обмена с GPS-приемником
Serial.begin(9600);
Serial.println("Waiting data of GPS...");
}
void loop() {
// задержка в секунду между обновлениями координат
if (millisO - start > 1000) {'
newdata = readgps();
if (newdata) {
start = millis0;
gps.get_position(&lat, &lon);
464 Часть IV. Интересные проекты на Arduino
gps.getjdatetime(&date, &time);
Serial.print("Lat: "); Serial.print(lat);
Serial.print(" Long: "); Serial.print(Ion);
Serial.print(" Date: "); Serial.print(date);
Serial.print(" Time: "); Serial.printIn(time);
}
// проверка наличия данных
bool readgps() {
while (gpsSerial.available()) {
int b = gpsSerial.read();
//в TinyGPS есть ошибка: не обрабатываются данные с \г и \п
if C\r' !- b) {
if (gps.encode(b))
return true; ,
return false;
}
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\19\_19J)i
сопровождающего книгу электронного архива (см. приложение 2).
19.2. Отправка данных по GPRS на сервер
Arduino GPRS/GSM Shield предоставляет возможность использовать в Arduino-
проектах сеть мобильной связи GSM для удаленного приема и передачи данных.
Рассмотрим один из вариантов этого шилда — SIM900 Quad-Band GPRS shield на
основе чипа SIM900 (рис. 19.4).
Общение с платой производится через serial-соединение с помощью набора
АТ-команд. Используя имеющиеся на плате перемычки, возможно установить
задействуемые для коммуникации контакты: аппаратные 0-1, 2-3 (на некоторых
платах) или 7-8 для работы через SoftwareSerial.
Плату GSM GPRS SIM900 Shield можно выключить двумя способами:
? аппаратным (нажатием кнопки PWRKEY);
? программным.
Для чего нужен программный сброс? Иногда при обмене по GPRS возникают
ситуации, после которых модуль может зависнуть..Виной этому могут быть
некорректные данные, пришедшие по сети и загнавшие в ступор SIM900, или помехи на
линии обмена модуля и контроллера, или еще какие-нибудь неведомые проблемы.
Производитель чипа предлагает в таких случаях перезагружать модуль с помощью
Глава 19. GPS-трекер и онлайн-сервис поиска стоянок
465
Рис. 19.4. GPS/GPRS shield: слева — вид сю стороны чипа SIM900;
справа — вид со стороны монтажных выводов
VBAT
NRESET
STATUS
(OUTPUT)
M*v20u$
Тур 60uS
Min 12S
Рис. 19.5. Программный сброс для GPS GPRS shield
специальной последовательности импульсов, подаваемых на вход PWRKEY
(рис. 19.5).
Однако это не всегда помогает, и самым правильным способом перезагрузки
модуля является полное снятие с него питания, выдержка некоторой паузы (хотя бы
секунду — на всякий случай) и повторная подача питания. Для перезагрузки
модуля на плате необходимо предусмотреть реле или транзисторный ключ,
управляемый контроллером.
По факту программный сброс через D9 не работал, поэтому пришлось
подключаться перемычкой и управлять сбросом с цифрового выхода D4 платы Arduino. Схема
соединений для этого случая показана на рис. 19.6.
466 Часть IV. Интересные проекты на Arduino
12В ЗА
Рис. 19.6. Монтажная схема подключения GPS/GPRS shield к плате Arduino
Рассмотрим управление модулем GSM/GPRS shield с пбмощью АТ-команд. Для
этого установим модуль на плату Arduino и подключим ее к компьютеру. Arduino-
скетч отправки и получения данных между компьютером и модулем GSM/GPRS
shield через плату Arduino приведен в листинге 19.2.
// подключение библиотеки
#include <SoftwareSerial.h>
// создание объекта
SoftwareSerial grsG, 8); // RX, TX
// скорость обмена
#define GSMbaud 19200
String strl;
char buff[100];
void setup() {
Serial.begin(9600) ;
gsm. begin(GSMbaud);
Serial.println("Start");
Глава 19. GPS-трекер и онлайн-сервис поиска стоянок 467
void loop() {
if (Serial.available()) {
strl = Serial.readStringUntil(f\nf);
strl.toCharArray(buffer, hh.length() + 1);
gsm. write(buffer);
gsm.board.write(f\nf);
}
if (gsm. available()) {
Serial.write(gprs.read());
Данные с GPS-трекера мы будем отправлять на сервер по адресу PHP-скрипта,
обрабатывающего GET-данные и записывающего их в базу данных:
http://freeparkovka.ru/getkoords,php&id=xxx&lat=yyyyyyy&lon=zzzzzzzzz
Для отправки данных нужно послать следующие АТ-команды:
AT+SAPBR=1,1 // Открыть несущую (Carrier)
// Тип подключения - GPRS
AT+SAPBR=3,1,"CONTYPE","GPRS"
// APN, для Билайна - internet
AT+SAPBR=3,1,"APN","internet.beeline.ru"
// Инициализировать HTTP
AT+HTTPINIT
// Carrier ID для использования.
AT+HTTPPARA="CID",1
// Отправить данные методом GET
AT+HTTPPARA="URL","http:/freeparkovka.ru/gps_trackerl.php?id=l&lat=XXXXXlon=YYY
YY"
AT+HTTPACTION=0
// Дождаться ответа
AT+HTTPREAD
// Остановить HTTP
AT+HTTPTERM
Пробуем отправить эту последовательность из монитора последовательного порта
(рис. 19.7).
Теперь напишем скетч (листинг 19.3). Функция sendATcoinmand () отправляет At-коман-
ды и возвращает True в случае ожидаемого ответа и False при получении любого
другого.
boolean sendATcommand(char* ATcommand, char* expected_answer, unsigned int
timeout)
{
uint8_t x=0;
boolean answer=false;
468 Часть IV. Интересные проекты на Arduino
char response[150];
unsigned long previous;
memset(response, f\0f, 150); // Initialize the string
delayA00);
while( GPRSSerial.available() > 0)
GPRSSerial.read(); // очистить буфер данных
Serial.println(ATcoramand);
GPRSSerial.println(ATcoiranand); // Send the AT command
x = 0;
previous = millisO;
// ждем ответ
do{
if(GPRSSerial.available() != 0)
response[x] = GPRSSerial.read();
// сравнение на совпадение
if (strstr(response, expected_answer) != NULL)
{
answer = true;
// контролировать время ожидания
while((answer == false) && ((millisO - previous) < timeout));
Serial.println(response);
return answer;
s^^^^^^^^^^^KgUE:mm
bftfiCi
I ~ :'~.h:
шФпг:
Рис. 19.7. Отправка АТ-команд на GPRS shield из последовательного порта
Глава 19. GPS-трекер и онлайн-сервис поиска стоянок 469
За отправку группы АТ-команд отвечают функции:
? iniGPRS () — инициализация GPRS и подключение к сети оператора;
? sendkoords () — инициализация HTTP и отправка данных серверу;
? resetGPRS () — программный сброс;
? onof f gprs () — перезагрузка модуля выключением/включением питания.
Содержимое основной части скетча показано в листинге 19.4.
// подключение библиотеки SoftwareSerial
tinclude <SoftwareSerial.h>
//Подключение дисплея lsdl602 i2c
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//Подключение библиотеки для gps
#include <TinyGPS.h>
// Создание объектов библиотек
TinyGPS gps;
SoftwareSerial SerialGpsE, 6);
SoftwareSerial GPRSSerialG, 8); // RX, TX
//Служебные переменные
unsigned long startGPS;
bool newDataGps=false;
unsigned long millisGPRS;
unsigned long millisGPS;
float lat=44.029678;
float lon=43.072151;
// кол-во ошибок
int errorl=0;
int error2=0;
int error3=0;
void setup() {
GPRSSerial.beginA9200);
Serial.begin(9600);
delayC000);
Serial.printIn("iniGPRS - start ") ;
while(!iniGPRS()) {
error2++;
if(error2>3) {
while(!resetGPRS()) {
errorl++;
470 Часть IV. Интересные проекты на Arduino
if(errorl>3) {
onoffGPRS() ;
errorl=0;
error2=0;
Serial.printIn("iniGPRS - ok ");
void loop() {
// получение каждые 5 с
if (millisO-millisGPS >= 3000)
GPRSSerial.endO;
SerialGps.begin(9600);
getGPS();
millisGPS=millis() ;
// отправка каждые 10 с
if (millisO-millisGPRS >= 10000)
SerialGps.end();
GPRSSerial.beginA9200);
if(!sendkoords()) {
if(error3>3) {
while(!iniGPRS()) {
error2++;
if(error2>3) {
while (IresetGPRSO) {
errorl++;
if(errorl>3) {
onoffGPRS() ;
errorl=0;
error2=0;
}
}
error3=0;
millisGPRS=millis();
Глава 19. GPS-трекер и онлайн-сервис поиска стоянок
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\19\_19_04 сопрово-
ждающего книгу электронного архива (см. приложение 2).
На стороне сервера данные принимает РНР-скригтг getkoords.php. Содержимое этого РНР-
скрипта показано в листинге 19.5. Скрипт получает данные и записывает их в
таблицу базы данных users (рис. 19.8).
Рис. 19.8. Запись в таблицу базы данных
<?php .
$location="localhost";
$user="bhx20666_parking";
$pass="****************";
$db_name="bhx20666j?arking";
//
if (! $db=imysqli_connect ($location/ $userf $pass, $db_name))
{echo "connect error";}
else
mysqli_query($db/"SET CHARACTER SET futf8ffl);
$queryO=" SELECT * FROM Users WHERE id=".$_POST[iduser]." ";
$rezO=mysqli_query($db,$queryO);
472 Часть IV. Интересные проекты на Arduino
$rowO=mysqli_fetch_assoc ($rezO);
$str=$rowO[lat].";".$rowO[lon]."; ff.$row0[last_time].";";
echo $str;
19.3. Создание веб-страницы
с использованием API Яндекс.Карт
Теперь остается купить хостинг, доменное имя и написать код страницы для
отображения текущего местоположения GPS-трекера.
JavaScript API поможет встроить на сайт или в приложение карту поиска по
топонимам и организациям с возможностью строить маршруты и смотреть панорамы,
а также с другими функциями, доступными на Яндекс.Картах.
С помощью JavaScript API вы можете настроить нужную логику взаимодействия
пользователя с картой и определить, как эта карта будет выглядеть. Чтобы задать
внешний вид объектов на карте, можно выбрать стандартные элементы или создать
собственный макет.
Пользоваться API Яндекс.Карт можно бесплатно, если соблюдать условия:
? все данные должны отображаться на карте, размещенной на общедоступном
сайте или в приложении. Сохранять или изменять данные нельзя, но можно
кэшировать запросы к геокодеру и маршрутизатору на срок до 30 дней;
? бесплатный API нельзя использовать для мониторинга транспорта и в закрытых
системах;
? общее число запросов к геокодеру, маршрутизатору и панорамам в сутки не
должно превышать 25 тыс.
Также есть другие ограничения на бесплатное использование. Подробнее о них
можно прочитать в документации.
Для использования API Яндекс.Карт на своем сайте необходимо получить API-
ключ (рис. 19.9).
Для использования на странице API необходимо подключить библиотеку—
разместить в заголовке страницы следующий код:
<script src="https://api-maps.yandex.ru/2.l/?apikey=75e85ef2-7142-428b-8bd0-
785b0ba84f55&lang==ru_RU" type="text/javascript"></script>
Теперь мы можем использовать возможности библиотеки, создавать карту и
размещать на ней объекты (рис. 19.10).
Код javascript создания карты:
myMap = new ymaps.MapC'map", {
center: [44.036578, 43.074971],
zoom: 12
Глава 19. GPS-трекер и онлайн-сервис поиска стоянок 473
Рис. 19.9. Ключи API
Рис. 19.10. Страница с картой на сайте
474 Часть IV. Интересные проекты на Arduino
Создается коллекция объектов:
myGeoObjects = new ymaps.GeoObjectCollection({}, {
preset: "islands#blueCircleIcon",
strokeWidth: 4,
geodesic: true
});
в которую заносим метки для всех автостоянок— данные берем из базы mysql
(рис. 19.11). Код создания метки, координат, содержимого балуна формируется
PHP-скриптом. Скриптом формируется и список всех автостоянок в таблице.
Рис. 19.11. Данные об автостоянках в базе данных
Также создается метка для нашего GPS-трекера (РНР-код):
<?php
$queryl="SELECT * FROM Users WHERE id=l ";
$rezl=mysqli_query ($db, $queryl);
$rowl=mysqli_fetch_assoc ($rezl);
$str="AvtoPlacemark = new ymaps.Placemark([".$rowl[lat].",".$rowl[Ion]."],
{balloonContentBody: 'Последние показания <br>".$rowl[last_time]."',
hintContent: f".$rowl[last_time]."f},
{iconLayout: f default#image',
iconlmageHref: f iconavto.jpgf,
iconlmageSize: [40, 40],
iconlmageOffset: [-20, -20]});";
echo $str;
Глава 19. GPS-трекер и онлайн-сервис поиска стоянок 475
Для обновления информации о положении GPS-трекера, изменении информации
и свободных местах на стоянках, отправки запроса бронирования используется
технология Ajax:
<script src="js/jquery-3.3.1.min.js"x/script>
<script type="text/javascript">
function getKoordsAvto() {
$.ajax({
type: fPOSTf,
url: 'getkoords.php',
cache: false,
data: {"iduser": 1 },
success: function (data) {
var arr=data.split(";");
AvtoPlacemark.geometry.setCoordinates([arr[0],arr[l]]);
setTimeout(getKoordsAvto,10000);
</script>
При нажатии кнопки Забронировать отправляется запрос на сервер для
перенаправления запроса на автостоянки и на карте строится маршрут (рис. 19.12).
Рис. 19.12. Построение маршрута
ГЛАВА 20
Проекты для вендинга:
купюроприемник, монетоприемник,
разменный автомат
Продажа товаров и услуг с помощью автоматизированных систем (торговых
автоматов) называется вендингом. Вендинг получил широкое распространение в мире
как удобный и не очень требовательный способ вести торговлю или оказывать
услуги. На рынке представлен большой выбор торговых автоматов. Но если вас не
устраивает цена, или вы желаете добавить функционала действующему автомату,
или решили собрать что-то новенькое — Arduino в качестве микроконтроллера для
управления отдельными блоками устройства вам в этом поможет.
Рассмотрим работу Arduino с купюроприемником, монетоприемником и хоппером.
Купюроприемник (он же банкнотник, кугаорник, валидатор, биллакцептор) —
устройство, предназначенное для приема наличных платежей банкнотами. Купюро-
приемники осуществляют прием купюр, распознавание номинала и (при наличии
механизма укладки и кассеты) хранение принятых купюр. Монетоприемник —
устройство, предназначенное для приема платежей монетами или жетонами. Хоппер —
устройство для выдачи сдачи монетами.
Купюроприемники, монетоприемники и хопперы устанавливают в платежные
терминалы, развлекательные, лотерейные и игровые автоматы, а также в вендинговые
(торговые) автоматы.
20.1. Купюроприемник ЮТ серий А7 и V7
Купюроприемники ICT серий А7 и V7 (MDB-версия) по-настоящему проверены
временем — на российском рынке эта модель появилась еще в 2003 г. и с успехом
эксплуатируется до сих пор как в индустрии игорного бизнеса, так и в вендинге и
системах моментальных платежей (рис. 20.1). Модель поставляется с механизмом
укладки на 200, 400 и 800 купюр и предоставляет возможность быстрой замены
микропрограммы с помощью ПК.
Основные возможности:
? осуществляет прием купюры, поданной в любом направлении;
? уровень распознавания купюр — более 96%;
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник... 477
Рис. 20.1. Купюроприемник
ICTV7
? время операции — 3 с (включая время укладки);
? обеспечивает работу по протоколу PULSE, RS 232, MDB;
? имеет контейнер укладчика на 300 купюр;
? напряжение питания — 12 В;
? позволяет обновлять микропрограмму в Flash Rom;
П имеется модель с горизонтальным механизмом укладки.
Немаловажный факт — в Интернете можно приобрести работающие б/у
экземпляры по цене до 1000 рублей (лично я приобрел два у разных продавцоз).
Для настройки купюроприемник имеет три блока переключателей: первый и второй
блоки переключателей находятся с боковой стороны купюроприемника (рис. 20.2),
третий блок спрятан: разворачиваем купюроприемник к себе лицевой стороной и
кассетой вверх, над лицевой панелью находим пластиковую крышку — чтобы она
открылась, достаточно потянуть ее немного вверх, — вы увидите плату и, поискав,
найдете и колодку с четырьмя переключателями (рис. 20.3).
Каждый переключатель (в просторечии «дип») имеет два положения: on — вниз и
off— вверх. Рассмотрим назначение переключателей:
? первый блок:
• sw 1-5 — настройка приема по номиналам купюр;
• sw 6 — качество приема. Если установить HighAcceptance, то
купюроприемник принимает даже помятые купюры;
478
Часть IV. Интересные проекты на Arduino
• sw7 — отключает прием inhibit (сигнал, устанавливающий блокировку
приема купюр);
• sw 8 — настройка уровня сигнала inhibit;
? второй блок:
• sw 1-2 — настройка количества импульсов;
• sw 3-4 — настройка длины импульса и длины паузы.
Сводная таблица настройки переключателей первого и второго блоков
представлена в табл. 20.1;
Рис. 20.2. Купюроприемник ICT V7: слева — вид спереди; справа — вид сбоку;
вверху — увеличенное изображение первого (слева) и второго (справа) блоков переключателей
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник... 479
О третий блок (который под крышкой):
• SW 1 ПОЛЯРНОСТЬ ИМПуЛЬСа High (on) ИЛИ Low (off);
• sw 2 — протокол pulse (on) или rs232 (off);
• sw 3-4 — не используются.
Чтобы любые изменения вступили в силу, купюроприемник надо перезагрузить.
Рис. 20.3. Купюроприемник ICT V7, вид спереди: слева — крышка закрыта; справа — крышка открыта;
вверху — увеличенное изображение третьего блока переключателей
480
Часть IV. Интересные проекты на Arduino
Таблица 20.1. Таблица настройки переключателей первого и второго блоков
Функция
Reject Ruble 10
Accept Ruble 10
Reject Ruble 50
Accept Ruble 50
Reject Ruble 100
.Accept Ruble 100
Reject Ruble 500
Accept Ruble 500
Reject Ruble 1000
Accept Ruble 1000
High Acceptance
High Security
Harness disable
Harness enable
Inhibit Active High
Inhibit Active Low
1 pulse/Ruble 10
2 pulse/Ruble 10
5 pulse/Ruble 10
20 pulse/Ruble 10
50 ms on/50 ms off
60 ms on/300 ms off
30ms.on/50msoff
150 ms on/150 ms off
Переключатели первого блока
1
on
off
2
on
off
3
on
off
4
on
off
5
on
off
6
on
off
7
on
off
8
on
off
Переключатели
второго блока
1
off
on
off
on
2
off
off
on
on
3
off
on
off
on
4
off
off
on
on
20.1.1. Подключение купюроприемника ICT V7
к плате Arduino
Купюроприемник оснащен кабелем для подключения к автомату, на конце кабеля
имеется разъем 3x3 (рис. 20.4). Назначение интересующих нас выводов следующее:
? красный — 12 В;
? оранжевый — GND;
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник...
481
П желтый — inhibit*;
? зеленый — inhibit-;
? синий — signal+;
? фиОЛеТОВЫЙ SIGNAL-.
Рис. 20.4. Кабель подключения купюроприемника ICT V7
Подключаем купюроприемник к плате Arduino по протоколу pulse. Схема
подключения приведена на рис. 20.5, а установка переключателей — в табл. 20.2. Такое их
положение определяет режим pulse с полярностью High, 1 импульс на 10 рублей
E— на 50 рублей, 10— на 100 рублей), длительность импульса 50 мс, качество
приема низкое, отсутствие сигнала блокировки купюроприемника и прием купюр
номиналом 10, 50 и 100 рублей с отторжением 500- и 1000-рублевых купюр.
Таблица 20.2. Таблица установки переключателей
Первый блок
1
off
2
off
3
off
4
on
5
on
6
off
7
off
8
off
Второй блок
1
off
2
off
3
off
4
off
Третий блок
1
on
2
on
3
off
4
off
+12 V
ICV7
красный
+12В
оранжевый
GND
синий
SIGNAL+
—
ММ
R1 -
I1 i
<- i i
4,7К
—
Arduino
ТХХ АО
D2 А1
D3 А2
D4 A3
D5 А4
D6 А5
D7 А6
D8 А7
по
иу
D10
D11 +З.ЗВ
D12
D13 +5В
GND
1
±
—
—
-
-
Рис. 20.5. Схема подключения купюроприемника ICT V7 к плате Arduino
482 Часть IV. Интересные проекты на Arduino
20.1.2. Скетч для получения
номинала принимаемой купюры
Выход D2 платы Arduino подсоединен к выходу signal* купюроприемника и
установлен в режим получения данных (input). Через резистор 4,7 кОм (см. рис. 20.5)
он подтянут к питанию +5 В, и на нем находится уровень high. После получения
купюры купюроприемник посылает импульсы продолжительностью 50 мс на
выход signal+, устанавливая на входе D2 уровень low и вызывая процедуру обработки
прерывания, где инкрементируется счетчик количества импульсов. В основном
цикле программы (листинг 20.1) проверяется время, прошедшее после получения
первого импульса, и если оно превысило 1000 мс, выводится номинал полученной
купюры (на основе количества импульсов), а счетчик обнуляется до поступления
первого импульса при приеме новой купюры.
const int moneyPin=2; // подключение SIGNAL+
int money=0; // номинал принятой купюры
unsigned long timeAllPulse=2000; // макс, время приема купюры
unsigned long timeCount=0;
void setup()
{
Serial.begin(9600);
pinMode(moneyPin,INPUT);
attachlnterrupt@,count_pulse,FALLING);
Serial.printIn("ready");
void loop()
{
// прошло максимальное время приема купюры? - вывести номинал
if (money>0 && (millis () -timeCount) >timeAllPulse)
{
Serial.print("money=");
Serial.printInA0*money);
money=0;
// обработка прерывания - получить кол-во импульсов
//
void countjpulse ()
{
detachlnterrupt@);
money++;
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник... 483
if (money==l)
timeCount=:rtiillis ();
attachlnterrupt @, count_pulse, FALLING) ;
}
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\20\_20JI
сопровождающего книгу электронного архива (см. приложение 2).
20.2. Монетоприемник СН-926
Монетоприемник — это устройство для приема монет (жетонов), которые
используются во всех видах торговых автоматов, сенсорных киосках, платежных
терминалах, автономных устройствах услуг. Их цель — принять и распознать
металлические деньги (монеты, жетоны). Монетоприемники можно разделить на четыре
вида:
? монетоприемники эталонного типа (компараторы) — принимающие монеты или
жетоны только одного типа;
? программируемые монетоприемники— способные распознавать монеты
различных номиналов;
? монетоприемники-селекторы;
О монетоприемники с функцией выдачи сдачи.
Программируемые монетоприемники используются во всех торговых и платежных
терминалах. Для игровых или развлекательных автоматов достаточно компаратор-
ных монетников (эталонного типа). В зависимости от наличия свободного места
внутри самого аппарата, монетоприемники устанавливаются сбоку (пристраивается
дополнительный бокс) или за фасадной панелью автомата. Монета (жетон)
попадает в монетоприемник, проверяется там на предмет подлинности (в современных
устройствах сверяются до 24 параметров), и далее, в случае одобрения, аппарат
получает команду выдать товар или произвести какую-либо операцию. Новые модели
монетоприемников благодаря встроенным оптическим датчикам исключают такие
распространенные виды мошенничества, как монета (жетон) на нитке. Выбор
монетоприемников как дополнительного оборудования достаточно широк, что дает
возможность исходя из конкретных задач подобрать оптимальную модель.
Рассмотрим программируемый монетоприемник СН-926 (рис. 20.6), который
можно приобрести на ЕЬау по достаточно приемлемой цене (дешевле 1000 рублей). Он
может принять до 6 видов различных монет диаметром от 15 до 32 мм и толщиной
от 1,2 до 3,8 мм. Рабочее напряжение— 12 В. Выходной сигнал— импульсный.
Частота импульсов устанавливается с помощью трехпозиционного переключателя:
fast — 20 мс, medium — 50 мс, slow — 100 мс.
484 Часть IV. Интересные проекты на Arduino
Рис. 20.6. Монетоприемник СН-926
20.2.1. Настройка монетоприемника
Рассмотрим процесс программирования (настройки) монетоприемника СН-926:
1. Включить питание, установить переключатель 1 в позицию NC.
2. Переключателем 2 выбрать нужную скорость обмена (fast, medium, slow).
3. Нажать одновременно кнопки ADD и MINUS и удерживать их более 3 с,
отпустить — на индикаторе появится А.
4. Нажать и отпустить кнопку SET — на индикаторе появится Е.
5. Кнопками ADD и MINUS установить количество разных монет для приема: от 1
до 6 (я установил 5 — для настройки монетоприемника на прием 50 копеек, 1,2,
5 и 10 рублей).
6. Нажать кнопку SET более 3 с — на индикаторе появится HI (количество
экземпляров первой монеты для калибровки).
7. Кнопками ADD и MINUS установить значение Н для первой монеты.
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник... 485
8. Нажать кнопку SET более 3 с — на индикаторе появится Р1 (количество
выдаваемых импульсов при успешном приеме первой монеты) — выбирается от 1
до 50.
9. Кнопками ADD, MINUS установить значение импульсов для первой монеты
(я выбрал 1 — для первой, 2 — для второй, 3 — для третьей, 4 — для
четвертой, 5 — для пятой);
10. Нажать кнопку SET более 3 с — на индикаторе появится F1 (точность
опознания первой монеты) — выбирается от 1 до 30 (я выбрал 10).
11. Кнопками ADD и MINUS установить значение F для первой монеты.
12. Нажать кнопку SET более 3 с.
13. Повторить шаги 6-12 для других выбранных монет. По окончании на
индикаторе появится А.
14. Нажать и отпустить кнопку SET — на индикаторе появится Е.
Теперь выключаем/включаем монетоприемник и проводим его калибровку.
20.2.2. Калибровка монетоприемника
Процесс калибровки монетоприемника СН-926 заключается в следующем:
1. Нажать кнопку SET более 3 с — на индикаторе появится А1.
2. Начинаем опускать в монетоприемник монеты номинала 1 в количестве HI.
3. По загрузке последней монеты на индикаторе начинает мигать А1.
4. Нажать кнопку SET — на индикаторе появится А2.
5. Повторить загрузку монет для номиналов 2-5.
6. Нажать кнопку SET более 3 с.
После включения/выключения монетоприемник готов к приему монет. Мы можем
опускать в него монеты— на индикаторе высвечивается количество импульсов.
Если монеты какого-либо номинала не проходят, повторяем настройку сначала.
20.3. Разменный автомат (хоппер)
Cube Hopper MK II
Хоппер Cube Hopper MK II (рис. 20.7) при внесении купюры через
купюроприемник осуществляет ее размен на монеты, а также хранит и выдает сдачу монетами
одного номинала — это один из самых распространенных хопперов, он разработан
всемирно известной компанией Suzo, известнейшим игроком на рынке
развлекательного оборудования. Модель Cube Hopper MK II специально предназначена для
игровой и вендинговой индустрии, выполнена из износостойкого пластика и
обладает высокой надежностью.
486 Часть IV. Интересные проекты на Arduino
Характеристики хоппера Cube Hopper MKII:
О количество номиналов: 1;
? есть варианты под монеты достоинством 1, 2, 5 и 10 рублей;
? скорость выдачи монет: 7 монет/с;
? размер монет: 18-31 мм;
? толщина монет: 1,5-3,20 мм;
? питание: 12 В постоянного тока (DC) ±10% или 24 В постоянного тока от -25
до+10%;
О температура окружающей среды: от 0 до 50°С;
? вместимость: 450 монет диаметром 24 мм (опционально в устройство
допускается установить до трех расширителей держателя монет, что дает возможность
загружать в его бункер более 1200 монет (жетонов) диаметром 24 мм);
? современное электронное управление оптическими датчиками выдачи;
? работает в двух протоколах: ccTalk или параллельный;
? имеет квадратный форм-фактор — выдача монет (жетонов) может быть
осуществлена с 4 различных сторон в зависимости от необходимости.
Рис. 20.7. Хоппер Cube Hopper MK II
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник... 487
20.3.1. Подключение хоппера к плате Arduino
Для подключения к плате Arduino используются следующие контакты на разъеме
хоппера:
? pin 6 — выход оптического сенсора;
? pin 8 —+12 В;
? pin 9 — «земдя».
При подаче на pin 8 напряжения +12 В хоппер начинает выдавать монеты. Выдав
каждую монету, хоппер подает на pin 6 отрицательный импульс длительностью
35 мс. При подключении ко входу платы Arduino pin 6 хоппера подтягивается
резистором 10 кОм к контакту +5 В. Монтажная схема соединений разменного автомата
в составе купюроприемника и хоппера показана на рис. 20.8.
20.3.2. Программирование хоппера
Как уже отмечалось, при внесении купюры через купюроприемник хоппер
производит размен ее на монеты. Если в нем недостаточно для этого монет, прием денег
купюроприемником блокируется. Содержимое скетча, обеспечивающего эту
функциональность, представлено в листинге 20.2. Загружаем скетч в плату Arduino и
проверяем его работу.
// пин включения/выключения купюроприемника
#define PIN_KUP_ON 12
// пин включения/выключения хоппера
#define PIN_HOPPER_ON 11
// пин сигнала хоппера
#define PIN_HOPPER_S 4
// пин сигнала хоппера
#define PIN_BLOCK 9
#define KUP_ON 0
#define KUP_OFF 1
#define HOPPER_ON 1
#define HOPPER_OFF 0
// время ожидания монеты в хоппере (хоппер пустой)
#define TIME_WAIT_HOPPER 5000
// для хоппера поправка
#define TIME1_MAX 200
// адреса EEPROM для хранения
// блокировано?
#define ADDR_BLOCK 27
// для EEPROM
tinclude <EEPROM.h>
488
Часть IV. Интересные проекты на Arduino
I
I
о.
ё
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник... 489
II купюроприемник
const int moneyPin2=2;
int pulse2=0;
// макс, время ожидания импульса после приема купюры
unsigned long timeAHPulse2=500;
unsigned long timeCount2=0;
unsigned int sum=0;
// параметры номинала монеты - 10 рублей
unsigned int nominal=10;
// блокировка приема
int block=0;
void setup() {
Serial.begin(9600);
block=EEPRQM.read(ADDRJBLOCK);
pinMode(PIN_KUP_ON, OUTPUT);
// проверка отсутствия монет
if(digitalRead(PIN_BLOCK)==0 && block==l)
digitalWrite(PIN_KUP_ON,KUP_OFF);
else
digitalWrite(PIN_KUP_ON,KUP_ON) ;
pinMode(PIN_HOPPER_ON,OUTPUT);
digitalWrite(PIN_HOPPER_ON,HOPPER_OFF);
attachlnterrupt@,count_pulse2,FALLING);
void loop() {
// прошло максимальное время ожидания импульса приема купюры?
if(pulse2>0 && (millis()-timeCount2)>timeAHPulse2 ) {
sum=sum+pulse2* 10;
Serial.print("sumpulse2=");Serial.println(pulse2*10);
i f(sum>=nominal) {
Serial.print("sum=");Serial.println(sum);
// блокировка купюроприемника
digitalWrite(PIN_KUP_ON,KUP_OFF);
detachlnterrupt@);
// выдача монет
if(exchange(sum)) { // успешно
digitalWrite(PIN_KUP_ON,KUP_ON);
attachlnterrupt@,count_pulse2f FALLING);
}
else {
if (digitalRead (PIN_BLOCK) =1) {
digitalWrite (PIN_KUP_ONfKUP_ON) ;
attachlnterrupt@,count_pulse2, FALLING);
490 Часть IV. Интересные проекты на Arduino
Ыоск-1;
}
Serial.print("sum=");Serial.println(sum) ;
EEPRQM.write(ADDR_BLOCK,block) ;
// обработка прерывания купюроприемника - получить кол-во импульсов
void countjpulse2() {
detachlnterrupt@);
pulse2++;
if(pulse2==l)
timeCount2=-millis ();
delayA0);
attachlnterrupt@,count_pulse2,FALLING);
//attachlnterrupt(lf count_pulse2,CHANGE);
}
// выдача размена
boolean exchange (int summa) {
boolean lastSignal=HIGH;
boolean currentsignal=HIGH;
unsigned long millisl=0;
int count;
unsigned int timel=0;
timel=TIMEl_MAX;
count=sum/nominal;
int pulse3=0;
unsigned long millis2=millis();
digitalWrite(PIN_HOPPER_ONf HOPPER_ON);
while(pulse3<count) {
currentSignal=debounce(lastSignal,PIN_HOPPER_S);
if(lastSignal==HIGH && currentSignal==LOW) {
pulse3++;
Serial.println(pulse3);
millisl=millis();
//delayD0);
}
lastSignal=currentSignal;
if (millis () -millisl> TIME_WAIT_HOPPER)
break;
}
delay (timel) ;
digitalWrite(PIN_HOPPER_ON,HOPPER_OFF);
delayA000);
Глава 20. Проекты для вендинга: купюроприемник, монетоприемник... 491
sum=sum-pulse3*nominal ;
if(pulse3<count)
return false;
else
return true;
/* Функция сглаживания дребезга
* Принимает в качестве аргумента предыдущее состояние кнопки
* и выдает фактическое.
V
int debounce(int last,int pinl)
{
int current = digitalRead(pinl); // Считать состояние кнопки
if (last != current) // если изменилось...
{
delayE); // ждем 5 мс
current = digitalRead(pinl); // считываем состояние кнопки
return current; // возвращаем состояние кнопки
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\20\_20JJ
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 21
Создание управляющей платы
для автомойки самообслуживания
В коммерческих проектах для включения какого-нибудь устройства на
определенное время, зависящее от поступившей оплаты, — например, в популярных
автомойках самообслуживания, также используются купюроприемники и
монетоприемники, рассмотренные нами в главе 20. Автоматика мойки самообслуживания
состоит из блока приема денежных средств (купюроприемник, монетоприемник),
блока отображения информации, нескольких кнопок и нескольких реле времени
обратного счета с различными временами отсчета в зависимости от выбранной
кнопки запуска, к которым подключается оборудование для выполнения
определенных функций— например: мойка водой под давлением, активная пена, воск,
осмос (ополаскиватель). Рассмотрим создание на Arduino контроллера
(управляющей платы) автомойки самообслуживания.
21.1. Блок приема денежных средств
и блок индикации
К плате Arduino по схеме, показанной на рис. 21.1, подключены купюроприемник и
монетоприемник. Вывод информации о принятых средствах осуществляется на
четырехразрядную матрицу 8><8 (см.разд. 10.6).
Получаемые денежные средства накапливаются в переменной sum. Для вывода
суммы на дисплей D-разрядную матрицу 8><8) необходимо создать массивы для
изображения цифр и других дополнительных символов:
byte figure[25][10]={
{8,8, //0
В00111110,
В01111111,
В01100011,
В01100011,
В01100011,
В01100011,
В01111111,
В00111110},
Глава 21. Создание управляющей платы для автомойки самообслуживания
493
I
>s
О
I
§
Я
I
I
>s
s
i
i
494
Часть IV. Интересные проекты на Arduino
{8,8,
воооооооо,
воооооооо,
воооооооо,
воооооооо,
воооооооо,
воооооооо,
воооооооо,
ВОООООООО},
{8,8,
В11100111,
В11000011,
В10000001,
В00011000,
В00100100,
В11111111,
В11111111,
В01100110},
{8,8,
В11100000,
В10100000,
В10100000,
В10101110,
В10101010,
В00001010,
В00001010,
В00001010},
//пустота
{8,8,
В01100011,
В01100011,
BOiiioon,
В01101011,
В01100111,
В01100011,
В01100011,
В01100011},
//для мигания
//прогр. пауза
//буква N
Для работы с дисплеем D-разрядной матрицей 8><8) используем библиотеку
MaxMatrix:
#include <SPI.h>
#include <MaxMatrix.h>
MaxMatrix m(ll,10,13,4);
// инициализация матриц
m.init ();
m.setlntensityA5);
Глава 21. Создание управляющей платы для автомойки самообслуживания 495
и создаем функцию вывода цифр на разряды дисплея:
// показать цифры на матрицах
void view_figure(unsigned int num,int mode)
{
int numl,num2,num3,num4;
numl=num/1000;
num2=(num-numl*1000)/100;
num3=(num-numl*1000-num2*100)/10;
num4=(num-numl*1000-num2*100-num3*10)/1;
m.writeSpriteB4, 0, figure[num4]);
if(num3==0 && nunKlO)
m.writeSpriteA6, 0, figure[10]);
else
m.writeSpriteA6, 0, figure[num3]);
if(num2==0 && nuirKlOO)
m.writeSprite(8, 0, figure[10]);
else
m.writeSprite (8, 0, figure [num2]);
if(numl==0 && num<1000)
m.writeSprite@, 0, figure[10]);
else
m.writeSprite@, 0, figure[numl]);
if (numl=0)
m.writeSprite@, 0, figure[mode]);
Электронный архив
Библиотека MaxMatrix размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
При приеме монет и купюр считаем в процедурах прерывания импульсы и
переводим их в сумму. А в основном цикле loop () выводим накапливаемую сумму на
дисплей:
// обработка прерывания купюроприемника - получить кол-во импульсов
void count_pulse2()
{
detachlnterruptA);
pulse2++;
if(pulse2==l)
timeCount2=millis();
delayA0);
attachlnterruptA,count_pulse2,FALLING);
496 Часть IV. Интересные проекты на Arduino
void loop () {
// прошло максимальное время приема купюры?
if(pulse2>0 && (itiillis()-timeCount2)>timeAHPulse2)
{
sum=sum+nominals2 [min (pulse2,15) ] ;
pulse2=0;
view_figure(sum, 10) ;
21.2. Выбор программ работы мойки
Для выбора программ мойки служит блок кнопок и реле для включения выбранных
функций. Мы воспользуемся антивандальными кнопками с подсветкой (рис. 21.2).
Блок кнопок состоит из 6 кнопок: выбор программ (кнопки 1-5) и кнопка для
установки паузы. Схема подключения компонентов показана на рис. 21.3.
Рис. 21.2. Антивандальная кнопка с лампочкой на 12 В
В цикле loop о постоянно идет процесс проверки нажатия кнопок с учетом
возможности «дребезга»:
int pinButtons2[]={14,15,16f17,18,19}; // 14 - пауза
int lastButtons2[] = {0,0,0, 0,0,0,0,0};
int currentButtons2[]={0,0,0,0,0,0,0,0};
void loopO {
§
I
I
Рис. 21.3. Схема подключения кнопок с подсветкой и реле
498 Часть IV. Интересные проекты на Arduino
// проверка нажатия кнопок выбора программ
for(int i=0;i<COUNT_BUTTONS;i
currentButtons2[i] = debounce(lastButtons2[i],pinButtons2[i]);
// если нажатие...
if (lastButtons2[i] = 0 && currentButtons2[i] — 1)
{
doButtons(i);
}
lastButtons2[i] = currentButtons2[i];
// обработка клавиш выбора программ
void doButtons(int but)
{
if(sum<l) return;
if (but—0)
{
RUN1.prg=8;RUN1.stopprg=l;
RUNl.millispausel=*nillis ();
RUN1.speedmoney=500;
}
else
{
RUN1.prg=but;RUN1.stopprg=0;
RUN1.speedmoney=60000/(unsigned long)params[but];
millisttt^millis();
}
setledsrelays(RUNl.prg);
view_figure(sum,10);
}
Определив нажатие кнопки, запускаем необходимые для выбранной программы
реле. Список состояний реле берем из массива relays (о — включить, 1 —
выключить). Поскольку выводы подсветки кнопок включены параллельно управляющим
контактам реле, одновременно загораются и нужные кнопки:
int pinRelays2[] = {12,8,7, 6,5,4};
byte relays[9][б]={{1,1,1,1,1,1},
{0,1,1,1,1,1}, {1,0,1,1,1,1}, {1,1, 0,1,1,1},
{1,1,1,0,1,1},{1,1,1,1,0,1},
{1,1,1,1,1,1},{0,0,0,0,0,0},
{1,1,1,1,1,0}};
// установка подсветки кнопок включения реле
void setledsrelays(byte valuel)
Глава 21. Создание управляющей платы для автомойки самообслуживания 499
int w=(int) valuel;
for(int j=0;j<=COUNT_LEDS;j++)
digitalWrite (pinRelays2 [ j ], relays [w] [j ]);
21.3. Отсчет времени выполнения программы.
Реализация паузы
Все параметры выполнения выбранной программы содержатся в переменной runi:
struct RUN // структура
{
int modeadmin; // режим работы/установка параметров
int prg; // номер выполняемой программы
int stopprg; // выключена программа - пауза
long millispausel; // начало паузы
int view; // для мигания при паузе
unsigned long speedmoney; // скорость ухода денег
};
RUN RUNl={0, 0, 0,0,0,500} ;
При выборе программы переменная runi заполняется параметрами этой
программы. Параметры хранятся в памяти EEPROM.
В цикле loop о выполняется декремент баланса на одну единицу каждые
runi . speedmoney мс. Если нажата кнопка паузы, происходит отсчет максимального
времени паузы, а при его превышении возобновляется последняя программа. Если
во время паузы происходит выбор программы, начинается ее выполнение. Во время
паузы на дисплее мигает значение баланса. Содержимое цикла loop о показано
в листинге 21.1.
void loop ()
{
// проверка нажатия кнопок выбора программ
for(int i=0;i<COUNTBUTTONS;i
currentButtons2[i] - debounce(lastButtons2[i],pinButtons2[i]);
if (lastButtons2[i] = 0 && currentButtons2[i] == 1) // если нажатие...
{
doButtons(i);
lastButtons2[i] = currentButtons2[i];
}
// режим пользователя
if (millis()-millisttt>=RUNl.speedmoney)
500 Часть IV. Интересные проекты на Arduino
millisttt=millis();
// идет программа
if(RUNl.prg>0 && RUNl.stopprg<l)
{
sum=sum-l;
view_f igure (sum, 10);
if(sum<l)
{sum=0;RUNl.prg=0; '
RUN1.speedmoney=1000;
setledsrelays@);
//view_figure(sum,11);
delay(MILLISBOUNCE);
pulse2=0;pulsel=0;
m.init () ;
m.setlntensityA5);
view_figure(sum,11);
// пауза
else if (RUNl.prg>0 && RUNl.stopprg=l)
{
RUNl.view=8-RUNl.view;
if(RUNl.view==0)
view_figurel@) ;
else
view_f igure (sum, 10);
millisppp=params[0];millisppp=millisppp*1000;
if (millis () -RUNl .millispausel>millisppp)
{
sum=0;RUNl.prg=0;
RUNl.speedmoney=500;
view_f igure(sum,11);
setledsrelays@);
}
else if(RUNl.prg==0 && RUNl.stopprg==2)
{
if(millis()-RUNl.millispausel>millisppp)
{
sum=0;RUNl.prg=0;
RUNl.speedmoney=500;
view_figure(sum, 11);
setledsrelays@);
Serial.print("*53;0;$");
Глава 21. Создание управляющей платы для автомойки самообслуживания 501
else ;
}
// прошло максимальное время приема купюры?
if(pulse2>0 && (millis()-tiitieCount2)>timeAHPulse2)
{
if(sum==0)
RUN1.stopprg=2;
suin=sum+nominals2 [min (pulse2/15) j ;
pulse2=0;
view_figure(sum,10) ;
RUN1 .millispausel=inillis () ;
millisppp=params[0];millisppp==millisppp*1000;
// прошло максимальное время приема монеты?
if(pulsel>0 && (millis()-timeCountl)>timeAllPulsel)
{
if(sum==0)
RUNl.stopprg=2;
sum=sum+nominalsl [min(pulsel, 15) ] ;
pulse1=0;
view_figure(sum,10);
RUN1.millispausel^millis();
millisppp=params[0];millisppp=millisppp*1000;
}
// первоначальный ввод денег
if(sum>0 && RUNl.prg==0)
{
view_figure(sum,10) ;
setledsrelays@);
21.4. Режим администратора.
Установка лараметров
Режим администратора позволяет установить «стоимость» каждой программы
и длительность паузы. Для выбора режима администратора необходимо на контакт
Arduino D9 подать логическую единицу. Можно осуществлять это с помощью
переключателя.
Для выбора следующего параметра, увеличения и уменьшения значения параметра,
а также сохранения параметра используются кнопки. Данные сохраняются в
EEPROM:
// Выставляемые настройки
// 0 - пауза секунд до выключения
// 1 - стоимость 1 мин'О};
502 Часть IV. Интересные проекты на Arduino
unsigned int params[]={600,100,100,100,200,200,200,200,200};
unsigned int paramsmin[]={60,50,50,50,50,50,50,50,50};
unsigned int paramsmax[]={1200,1500,1500,1500,1500,1500,1500,1500,1500};
int paramsstep[]={30,5,5,5,5,5,5,5,5};
int tekparam=0;
// обработка нажатия кнопок настройки
void setOptions(int but)
{
switch(but)
{
case 0: // переход/выход в режим программирования
// загрузка значений параметров из EEPROM
for(int i=0;i<COUNT_BUTTONS;i++)
params[i]=get_param_EEPROM(i);
view_figurelB);
delayB000);
view_f igure(params[tekparam],tekparam+12);
break;
case 1: // следующий параметр
tekparam=(tekparam+1)%COUNT_BUTTONS;
view_figure(params[tekparam],tekparam+12);
break;
case 2: // уменьшить значение параметра
params [tekparam] =params [tekparam] -paramsstep [tekparam];
params [tekparam] =max (params [tekparam], paramsmin [tekparam]);
view_f igure (params [tekparam], tekparam+12) ;
break;
case 3: // увеличить значение параметра
params [tekparam] =params [tekparam] +paramsstep [tekparam];
params [tekparam] =min (params [tekparam], paramsmax [tekparam]);
view_f igure (params [tekparam], tekparam+12);
break;
case 4: // сохранить изменение параметра
save_param_EEPRQM (tekparam, params [tekparam]);
view_figurelA);
delayB000);
view_figure(params[tekparam],tekparam+12);
break;
default:
break;
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\21\_21_0i
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 22
Arduino и интерфейс USB:
управление роботами
22.1. Интерфейс USB
Последовательный интерфейс USB используется для подключения периферийных
устройств. Соответственно, существуют понятия «главное устройство» — хост (он
управляет обменом данными через интерфейс и выступает инициатором обмена)
и «периферийное устройство» — клиент (в процессе обмена данными он
«подчиняется» хосту). Логика работы хоста и клиента принципиально различна, поэтому
нельзя напрямую соединять устройства «хост— хост» и «клиент— клиент».
Имеются специальные устройства — хабы, которые подключаются в качестве клиента
к одному хосту и в то же время выступают хостом для других периферийных
устройств. Хабы также применяются для «разветвления» шины USB.
Физически интерфейс USB (до версии 2.0) использует 4 провода (рис. 22.1):
? «земля» (GND);
О +5 В (VBUS);
? D-, D+— линии приема/передачи данных (обозначения D+ и D- условны,
с электрическими потенциалами это никак не связано).
Спецификация USB 1.0 определяла два типа разъемов: А — на стороне
контроллера или концентратора USB и В — на стороне периферийного устройства.
Впоследствии были разработаны миниатюрные разъемы для применения USB в переносных
У5» Standard В
Standard А ' #*
ii «^, ф
Рис. 22.1. Назначение контактов USB 1.0 и USB 2.0
504 Часть IV. Интересные проекты на Arduino
и мобильных устройствах, получившие название Mini-USB. Версия миниатюрных
разъемов, называемых Micro-USB, была представлена USB Implemented Forum
4 января 2007 г.
Примечание
Поскольку платы Arduino не несут на борту новомодных USB-разъемов стандартов
USB 3 и Туре-С, они здесь и не рассматриваются.
Благодаря встроенным линиям питания USB позволяет подключать периферийные
устройства без собственного источника питания (максимальная сила тока,
потребляемого устройством по линиям питания шины USB, не должна превышать 500 мА,
yUSB 3.0 — 900 мА).
Стандарт USB поддерживает концепцию plug-and-play. Эта концепция
подразумевает, что пользователю достаточно «воткнуть» устройство в соответствующий порт
компьютера. Далее его операционная система автоматически определит тип
подключенного устройства, найдет подходящий для этого устройства драйвер,
сконфигурирует устройство и т. д. Для того чтобы это все работало, стандартом USB
предусмотрены некие общие требования для всех устройств:
? каждое устройство содержит дескриптор (описание) устройства;
? есть общий для всех USB-устройств механизм, который позволяет ОС прочитать
дескриптор устройства для того, чтобы идентифицировать устройство и узнать
его характеристики;
? есть общий для всех USB-устройств механизм, который позволяет ОС
выполнить первичную конфигурацию устройства (например, присвоить устройству
новый адрес).
22.2. Плата расширения USB Host Shield
Очень соблазнительно иметь возможность подключать к Arduino USB-устройства,
которых великое множество. Плата расширения USB Host Shield 2.0 (рис. 22.2)
позволяет платам Arduino выступать в роли родительского USB-устройства для
практически любой имеющейся USB-периферии. С этой платой открывается масса
новых возможностей для реализации интересных проектов.
В настоящее время платой USB Host Shield 2.0 поддерживаются следующие классы
устройств:
? НЮ-устройства — такие как клавиатуры, мыши, джойстики и др.;
? игровые устройства: Sony PlayStation 3, Nintendo Wii, Xbox 360;
? USB-преобразователи: FTDI, PL-2303, ACM, а также некоторые аппараты и
GPS-приемники;
П Android-устройства;
? цифровые фотоаппараты: Canon (EOS, PowerShot), Nikon и др.
Для программирования платы расширения USB Host Shield используется
специальная библиотека USB_Host, скачать которую можно со страницы https://github.com/
felis/USB Host Shield 2.0.
Глава 22. Arduino и интерфейс USB: управление роботами
505
Рис. 22.2. Плата расширения USB Host Shield 2.0
Электронный архив
Библиотека USBJHost размещена в каталоге libraries сопровождающего книгу
электронного архива (см. приложение 2).
Спецификацию и примеры использования библиотеки USBHost можно найти на
сайте Circuits@Home по адресу: http://www.circuitsathome.com/arduino_usb_
host_shieldjprojects.
22.3. HID-устройства USB
HID (Human Interface Device) — устройство, подключаемое к вычислительной
технике с тем, чтобы с ней мог работать человек. Говоря проще, HID — это устройство
ввода информации. Устройства ввода необходимы для непосредственного участия
человека в работе компьютера: для введения исходных данных для вычислений,
для выбора параметров действия, для редактирования имеющихся данных и
результатов и т. п.
НЮ-устройства ввода различаются по типу вводимой информации:
? для текстовой информации— это преимущественно клавиатуры. Они служат
для управления техническими и механическими устройствами (компьютер,
калькулятор, кнопочный телефон). Каждой клавише устройства соответствует
один или несколько определенных символов. Количество действий,
выполняемых с клавиатуры, можно увеличить с помощью сочетаний (комбинаций)
клавиш. В клавиатурах такого типа клавиши сопровождаются наклейками с
изображением символов или действий, соответствующих нажатию;
? для звуковой информации— это микрофон. Электроакустические приборы,
преобразующие звуковые колебания в колебания электрического тока,
используются во многих устройствах (телефоны и магнитофоны, приборы звукозаписи
и видеозаписи на радио и телевидении, устройства радиосвязи);
506 Часть IV. Интересные проекты на Arduino
? для графической информации:
• сканер — устройство для считывания плоского изображения и представления
его в растровой электронной форме;
• цифровая камера — устройство (фотоаппарат), использующее массив
полупроводниковых светочувствительных элементов (матрицу), на которую
изображение фокусируется с помощью системы линз объектива. Полученное
изображение сохраняется в электронном виде в памяти самой камеры или же
на дополнительном цифровом носителе;
• веб-камера — цифровая видео- или фотокамера, способная в режиме
реального времени фиксировать изображения, предназначенные для дальнейшей
передачи по сети Интернет как в потоковом режиме, так и за определенные
промежутки времени;
• тата захвата (тюнер) — электронное устройство для преобразования
аналогового видеосигнала в цифровой видеопоток. Используется для захвата
телесигнала, сигнала с камер видеонаблюдения и др.
HID-устройства управления различаются по функционалу:
? относительное позиционирование (обрабатывают информацию о перемещении):
• мышь — манипулятор, преобразующий механические движения в движение
курсора на экране. Различают механические, оптические, гироскопические,
сенсорные мыши;
• трекбол — манипулятор, чей принцип работы сходен с шариковой
механической мышью и аналогичен мыши по принципу действия и по функциям.
Однако пользователь не передвигает мышь, а управляет с помощью ладони
или пальцев непосредственно шариком, закрепленным на специальном
держателе с датчиками;
• трекпойнт — миниатюрный тензометрический джойстик, применяемый
в ноутбуках для замены мыши. Трекпойнт считывает направление и силу
давления пальца пользователя;
• тачпад — сенсорная панель, применяемая в основном в портативных
компьютерах (ноутбуках). В отличие от трекпойнта, считывающего давление
пальца, тачпад считывает емкостные характеристики при соприкосновении
пальца с поверхностью емкостных датчиков. Поэтому управление тачпадом
с помощью непроводящих предметов (ручка, карандаш, стилус) достаточно
проблематично;
• джойстик — устройство ввода информации, которое представляет собой
качающуюся в двух плоскостях ручку, боковое давление которой считывается
датчиками в основании устройства. Используется как игровой гаджет, а
также как средство управления (например, роботизированной техникой на
производстве);
? абсолютное позиционирование (высчитывают абсолютные координаты на
плоскости, в качестве которой выступает устройство):
Глава 22. Arduino и интерфейс USB: управление роботами 507
• графический планшет — устройство для ввода графики (отдельных линий и
рисунков) от руки непосредственно в компьютер. Состоит из пера и плоского
планшета, чувствительного к нажатию пера;
• тачскрин (сенсорный экран)— устройство ввода информации,
представляющее собой экран, реагирующий на прикосновения к нему (используется
в современных смартфонах, платежных и информационных терминалах).
Отдельно хочется выделить специальные НТО-устройства для компьютерных игр:
? игровые мыши — отличаются от обычных компьютерных мышей высокой
чувствительностью, настраиваемым весом, большим количеством
программируемых кнопок;
? кейпады— специальные игровые клавиатуры-приставки, в которых кнопки
скомбинированы для максимального удобства игрока (в современные модели
встраивается мини-джойстик);
? руль и педали — манипуляторы для игр жанра «автогонки» (рейсинг);
? джойстики — используются для игр жанра «авиасимуляторы»;
? геймпады— специальные игровые манипуляторы, используемые в аркадных
жанрах (перешли с игровых консолей);
? танцевальные платформы— специальные платформы с датчиками давления.
Управление производится с помощью ног. Используются для игр жанра
«танцевальные аркады»;
? музыкальные инструменты (гитары, барабаны) — специальные манипуляторы
в форме музыкальных инструментов с кнопками и датчиками давления.
Используются для игр жанра «музыкальные аркады».
Операционные системы, как правило, имеют встроенные драйверы НТО-класса, так
что у разработчиков отпадает необходимость в трудоемкой разработке
собственного драйвера для нового устройства. Чтобы определить устройство как HID,
необходимо поддержать ряд структур, описывающих HID-интерфейс, а также написать
алгоритм обмена по interrupt-каналу (каналу прерываний) передачи данных. Во
многих отношениях устройства НТО не имеют никаких особенных отличий от
других USB-устройств. Однако кроме требований, которые относятся ко всем USB-
устройствам, устройства НТО выдвигают ряд дополнительных требований:
? НТО-устройство должно иметь interrupt in — конечную точку для выдачи
данных в хост, interrupt Out — конечная точка для получения периодических
данных от хоста, является опциональной и может не использоваться;
? НТО-уСТрОЙСТВО ДОЛЖНО содержать дескриптор класса Device Class Descriptor И
ОДИН ИЛИ более Дескрипторов репорта HID Report Descriptor;
? НТО-устройство должно поддерживать специфический для класса управляющий
запрос GetReport, а также опционально поддерживать дополнительный запрос
Set_Report;
508
Часть IV. Интересные проекты на Arduino
П для передачи interrupt in (данные из устройства в хост) устройство должно
положить данные репорта в FIFO соответствующей конечной точки и разрешить
передачу;
? для передачи interrupt Out (данные из хоста в устройство) устройство должно
разрешить соответствующую конечную точку out, а затем, после прихода
пакета, забрать данные из FIFO.
22.4. Подключение HID-мыши USB
В библиотеке USBHost 2.0 имеется пример для подключения к Arduino HID-мыши
USB — USBHIDBootMouse.pde. Загружаем его и смотрим в мониторе
последовательного порта результат работы скетча (рис. 22.3).
Рис. 22.3. Скетч для подключения HID-мыши USB
22.5. Управление роботом
с помощью руля Defender
В этом проекте мы будем управлять роботом с помощью игрового манипулятора —
руля Defender Forsage Drift GT (рис. 22.4). Для беспроводной передачи
управляющих команд от манипулятора к роботу воспользуемся беспроводным радиомодулем
NRF24L01, работу с которым мы рассмотрели в главе 12 (см. разд. 12.3).
Руль подсоединяется к плате Arduino через USB Host Shield. Для отправки роботу
управляющих команд от руля подсоединяем к этой плате радиомодуль 2>4 ГГц
Глава 22. Arduino и интерфейс USB: управление роботами
509
Рис. 22.4. Руль Defender Forsage Drift GT
L293
Рис. 22.5. Электрическая схема блока робота
510
Часть IV. Интересные проекты на Ardumo
NRF24L01. Блок робота выполнен в виде гусеничной платформы. К плате Arduino,
установленной на роботе, подсоединяется такой же радиомодуль 2,4 ГГц NRF24L01,
назначение которого — прием команд, управляющих роботом. Электрическая
схема блока робота представлена на рис. 22.5. В качестве драйвера двигателей здесь
используется микросхема L293.
Загружаем в плату Arduino скетч USBJHIDJDesc.pde (листинг 22.1), входящий в
примеры библиотеки USBHost, подсоединяем к Arduino через USB Host Shield наш
руль И получаем Descriptor Report Нф-устрОЙСТВа (рис. 22.6).
Рис. 22.6. Получение Descriptor Report HID-устройства
Usage Page Gen Desktop Ctrls(Ol)
Usage Game Pad
Collection Application
Collection Logical
Report Size@8)
Report Count@4)
Logical Min(OO)
Logical Max(FFOO)
Physical Min(OO)
Physical Max(FFOO)
Usage X
Usage Y
Глава 22. Arduino и интерфейс USB: управление роботами 511
Usage Z
Usage Z
Usage Rz
Input @0000010)
Report Size@4)
Report Count@1)
Logical Max@7)
Physical MaxCB01)
UnitA4)
Usage Hat Switch
Input@1000010)
Unit@0)
Report Size@1)
Report Count @C)
Logical Max @1)
Physical Max@1)
Usage Page Button @9)
Usage Min@1)
Usage Max @C)
Input@0000010)
Usage Page Undef@0)
Report Size@8)
Report CQunt@2)
Logical Max@1)
Physical Max@1)
Usage
Input@0000010)
End Collection
Collection Logical
Report Size@8)
Report Count@4)
Physical Max(FFOO)
Logical Max(FFOO)
Usage
Output@0000010)
End Collection
End Collection
Для создания своего кода возьмем код примера USBHIDJoystick.pde, входящего
в библиотеку USBHost и реализующего функционал джойстика, и перепишем
файлы hidjoystickrptparser.h (листинг 22.2) и hidjoystickrptparser.cpp (листинг 22.3) для
сохранения данных в структуре. Затем добавим отправку данных руля по
радиоканалу с помощью библиотеки для радиомодуля NRF24L01 (листинг 22.4). Отправку
производим каждые 300 мс.
512 Часть IV. Интересные проекты на Arduino
#if !defined ( HIDJOYSTICKRPTPARSER_H_)
#define HIDJOYSTICKRPTPARSER_H_
#include <inttypes.h>
# include <avr/pgmspace.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include lfusb_ch9.h"
#include "Usb.h"
#if defined(ARDUINO) && ARDUINO >=100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif
tinclude "printhex.h"
#include "hexdump.h"
#include "message.h"
#include "confdescparser.h"
#include "hid.h"
struct GamePadEJventData
{
uint8_t X, Y, Zl, Z2, Rz;
};
class JoystickEvents
{
public:
virtual void OnGamePadChanged(const GamePadEventData *evt)
virtual void OnHatSwitch(uint8_t hat);
virtual void OnButtonUp(uint8_t but_id);
virtual void OnButtonDn(uint8_t but_id);
uint8_t X;
uint8_t Y;
uint8_t Zl;
uint8_t Z2;
uint8_t Rz;
#define RPT_GEMEPAD_LEN 5
class JoystickReportParser : public HIDReportParser
{
JoystickEvents *joyEvents;
Глава 22. Arduino и интерфейс USB: управление роботами 513_
uint8_t oldPad [RPT_GEMEPAD_LEN] ;
uint8_t oldHat;
uintl6_t oldButtons;
public:
JoystickReportParser(JoystickEvents *evt);
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
#endif // HIDJOYSTICKRPTPARSER_H_
Электронный архив
Полный вариант рассмотренного скетча (файл hidjoystickrptparser.h) находится в папке
examples\22\J22JJ сопровождающего книгу электронного архива (см. приложение 2).
#include "hidjoystickrptparser.h"
JoystickReportParser::JoystickReportParser(JoystickEvents *evt) :
joyEvents(evt),
oldHat(OxDE),
oldButtons@)
{
for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i
oldPad[i] = OxD;
void JoystickReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len,
uint8_t *buf)
{
bool match = true;
// Checking if there are changes in report since the method was last called
for (uint8__t i=0; i<RPT_GEMEPAD_LEN;
if (buf[i] != oldPad[i])
{
match = false;
break;
// Calling Game Pad event handler
if (!match && joyEvents)
{
joyEvents->OnGamePadChanged((const GamePadEventData*)buf);
514 Часть IV. Интересные проекты на Arduino
for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i];
}
uint8_t hat = (buf[5] & OxF);
// Calling Hat Switch event handler
if (hat != oldHat && joyEvents)
{
joyEvents->OnHatSwitch(hat);
oldHat = hat;
uintl6_t buttons = @x0000 | buf[6]);
buttons «= 4;
buttons |= (buf[5] » 4);
uintl6_t changes = (buttons A oldButtons);
// Calling Button Event Handler for every button changed
if (changes)
for (uint8_t i=0; KOxOC;
{
uintl6_t mask = @x0001 « i);
if (((mask & changes) > 0) && joyEvents)
if ((buttons & mask) > 0)
j oyEvents->OnButtonDn(i+1);
else
j oyEvents->OnButtonUp(i+1);
}
oldButtons = buttons;
void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt)
{
X=evt->X;
Y=evt->Y;
Zl=evt->Z1;
Z2=evt->Z2;
Rz=evt->Rz;
void JoystickEvents::OnHatSwitch(uint8_t hat)
{
Serial.print("Hat Switch: ");
PrintHex<uint8 t>(hat);
Глава 22. Arduino и интерфейс USB: управление роботами
Serial.printIn("");
}
void JoystickEvents::0nButtonUp(uint8_t but_id)
{
Serial.print("Up: ");
Serial.println(but_id, DEC);
}
void JoystickEvents::0nButtonDn(uint8_t but_id)
{
Serial.print("Dn: ");
Serial.println(but_id, DEC);
Электронный архив
Полный вариант рассмотренного скетча (файл hidjoystickrptparser.cpp) находится в папке
examples\22\_22JK сопровождающего книгу электронного архива (см. приложение 2).
#include <avr/pgmspace.h>
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
# include <avr/pgmspace.h>
#include <address.h>
#include <hid.h>
#include <hiduniversal.h>
#include "hidjoystickrptparser.h"
#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
JoystickEvents JoyEvents;
JoystickReportParser Joy(&JoyEvents) ,
tinclude <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
516 Часть IV. Интересные проекты на Arduino
#include <MirfHardwareSpiDriver.h>
#define MAX_BUFF 32 // Буфер приема-передачи
void setup()
{
Serial.begin( 115200 );
Serial.println("Start");
if (Usb.InitO = -1)
Serial.println("OSC did not start.");
delay( 200 );
if (!Hid.SetReportParser@, &Joy))
ErrorMessage<uint8_t>(PSTR("SetReportParser"), 1 );
Mirf.spi = SMirfHardwareSpi;
Mirf.init();
Mirf.setRADDR((byte *)"defender"); // Здесь задаем адрес
Mirf.payload = MAX_BUFF; // Здесь задаем буфер
Mirf.channel = 10;
// Это канал приема-передачи - должен
// быть одинаковым у устройств.
Mirf .configO ;
Serial.println("Start.. ");
}
char buff[MAX_BUFF];
int c_count = 0;
void loopO
{
Usb.TaskO;
buf f [0] =raap (JoyEvents.X, 0,255,1,100) ;
buff[1]=map(JoyEvents.Y,0,255,1,100);;
buff[2]=map(JoyEvents.Zl,0,255,1,100);
buff[3]=map(JoyEvents.Z2,0,255,1,100);
buff[4]=JoyEvents.Rz+1;
buff[5]=0;
Mirf.setTADDR((byte *)"automobilel"); // Адрес!
Serial.print(">");
Mirf.send((uint8_t *)buff);
while(Mirf.isSending()){
}
Serial .println (buff)";
delayC00 );
Электронный архив
Полный вариант рассмотренного скетча (файл J22jL.'mo) находится в папке
examplesV2\J22JL сопровождающего книгу электронного архива (см. приложение 2).
Глава 22. Arduino и интерфейс USB." управление роботами 517_
Теперь необходимо написать скетч приема данных и отправки команд двигателям
робота. Первый байт из буфера данных: влево @-50)— вправо E1-100), второй
байт: вперед E1-100)— назад A-50). Надо только правильно перевести байты
в данные для микросхемы L293. Полученный скетч представлен в листинге 22.5.
tinclude <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
ttdefine MAX_BUFF 32 // Буфер приема-передачи
void setup(){
Serial.begin(9600);
Mirf.spi = &MirfHardwareSpi;
Mirf.initO;
Mirf.setRADDR((byte *)"automobilel"); // Здесь задаем адрес
Mirf.payload = MAX_BUFF; // Здесь задаем буфер
Mirf.channel = 10;
// Это канал приема-передачи - должен
// быть одинаковым у устройств.
Mirf .configO ;
// настраиваем выводы для моторов
pinModeC, OUTPUT);
pinModeD, OUTPUT);
pinModeE, OUTPUT);
pinModeF, OUTPUT);
Serial.println("Start..");
char buff[MAX_BUFF];
void loop(){
delayA0);
//receiving
if(Mirf.dataReady()) {
Mirf.getData((uint8_t *)buff);
int fbl=buff[0];
int lr=buff[l];
gol2(fbl,lrl);
}
delayA00);
518 Часть IV. Интересные проекты на Arduino
/I
void gol2(int fbfint lr)
{
// вперед-назад
if(fb>50)
{digitalWriteC,HIGH);digitalWriteD,LOW);
digitalWriteEfHIGH);digitalWriteFrLOW);}
else if(fb<50)
{digitalWriteC,LOW);digitalWriteD,HIGH);
digitalWrite E, LOW) /digitalWrite F,HIGH).;}
else
{digitalWriteC,LOW)/digitalWriteD,LOW);
digitalWriteE,LOW)/digitalWriteF, LOW);}
// влево-вправо
int lrl=map(absE0-lr),1,50,1,255);
int fbl==map(absE0-fb) ,1,50,1,255);
if(lr<50)
{int left=minB55,max@,fbl-lrl/2));
int right=^ninB55,fbl+lrl/2) }
else
{int right=minB55,max@,fbl-lrl/2));
int left=minB55,fbl+lrl/2))
analogWrite(9, left);
analogWriteA0, right);
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\22\j22JM
сопровождающего книгу электронного архива (см. приложение 2).
22.6. Управление роботом
с помощью геймпада Defender
Робот iRobot Create (рис. 22.7) — программируемый робот. Он разработан в 2007 г.
компанией iRobot на базе платформы робота-пылесоса Roomba. Электронный
интерфейс робота имеет 7 разъемов mini-DIN и разъем DB-25 для обмена данными,
электронные датчики и световые индикаторы. Программный интерфейс робота
позволяет управлять его поведением: считывать информацию с сенсоров при помощи
серии команд, включать команды режима, команды привода, звуковые команды,
демонстрационные команды и команды опроса сенсоров. Эти команды можно
посылать на последовательный порт робота с компьютера или платы Arduino.
Скачать описание открытого интерфейса робота можно по ссылке: http://
www.irobot.com/filelibrary/pdfs/hrd/create/Create%20Open%20Interface v2.pdf.
Глава 22. Arduino и интерфейс USB: управление роботами
519
?Ш
Рис. 22.7. Робот jRobot Create
Электронный архив
Этот же файл под именем Create Open Interface_y2.pdf содержится в папке datasheets
сопровождающего книгу электронного архива (см. приложение 2).
Для подсоединения робота к плате Arduino используем его 25-контактный разъем
DB-25 с распаянным согласно данным табл. 22.1 переходником (рис. 22.8).
Рис. 22.8. Переходник для подключения робота к плате Arduino
520 Часть IV. Интересные проекты на Arduino
Таблица 22.1. Соединение платы Arduino и робота iRobot Create
iRobot Create
1(Rx)
2(Tx)
14 (GND)
8 (+5 B)
Arduino
4
3
GND
Vin
В этом проекте также задействованы плата расширения USB Host Shield и
беспроводной геймпад Defender Scorpion RS3 (рис. 22.9), подключаемый к плате как HID-
устройство. Беспроводной геймпад имеет два аналоговых джойстика, 12 кнопок, D-
pad и индикатор заряда батарей. На геймпаде может быть включен режим
вибрации. Если геймпад не используется в течение продолжительного времени, он
автоматически выключается. Совместим этот геймпад с ПК и Sony PlayStation 3.
Интерфейс — Bluetooth.
Рис. 22.9. Беспроводной геймпад Defender Scorpion RS3
Итак, устанавливаем на плату Arduino шилд USB Host Shield. К USB-входу шилда
подсоединяем USB-ресивер геймпада (рис. 22.10) и соединяем плату Arduino с
роботом iRobot Create через переходник (см. рис. 22.8) проводами, распаянными
согласно табл. 22.1.
В библиотеке USBJHost содержится пример для беспроводного джойстика PS3.
Чтобы пример заработал с геймпадом Defender Scorpion RS3, необходимо
исправить заголовочный файл PS3Enums.h, входящий в эту библиотеку. Исправления
касаются значения для кнопок геймпада в массиве buttons [ ].
Глава 22. Arduino и интерфейс USB: управление роботами 521
Рис. 22.10. Подключение USB-ресивера геймпада к USB-входу шилда
Электронный архив
Исправленный файл PS3Enums.h находится в папке libraries\USB_Host сопровождающего
книгу электронного архива (см. приложение 2).
Выберем следующее назначение кнопок и джойстиков геймпада:
? правый джойстик — для управления движением;
? кнопка Start/10 — для перевода робота iRobot Create в режим fiill (полное
управление);
? кнопка Select/9 — для перевода iRobot Create в пассивный режим;
? кнопки R1 и R2 — для проигрывания мелодий iRobot Create;
? кнопки LI, L2 — для установки светодиодов iRobot Create;
О кнопка 4 (квадрат) — выполнение скрипта движения по квадрату.
Скетч для Arduino, представленный в листинге 22.6, отслеживает состояние кнопок
и джойстиков и выполняет отправку команд на iRobot Create.
iinclude <SoftwareSerial.h>
SoftwareSerial mySerialD,3);
#include <PS3USB.h>
USB Usb;
PS3USB PS3(&Usb);
Button Btarr[16]={UP, RIGHT, DOWN, LEFT, SELECT, START, L3, R3, L2, R2, LI, Rl,
TRIANGLE, CIRCLE, CROSS, SQUARE};
AnalogHat Joyarr[4]={LeftHatX,LeftHatY,RightHatX,RightHatY};
522 Часть IV. Интересные проекты на Arduino
boolean printAngle;
uint8_t state = 0;
int status_buttons[16] = {0,0,0,0,0,0,0, 0,0,0,0, 0,0,0,0,0};
long millisjDuttons[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
long millis_buttonsl[16]={500, 500, 500, 500; 2000, 2000, 2000, 2000, 2000,
2000, 2000, 2000, 2000, 2000, 2000, 2000};
int status_joys[4]={0,0,0,0};
int millis_joys[4]={0,0,0,0};
int map_joys[4]={2000,-500,2000,-500};
int dHatLeft=0;
int dHatRight=0;
void setup()
{
Serial.beginA15200) ;
if (Usb.InitO — -1)
{
Serial.print(F("\r\n OSC did not start"));
whileA); //halt
}
Serial.print (F(lf\r\nPS3 USB Library Started"));
my'Serial. begin E7600) ;
}
void loopO
{
Usb.TaskO;
// joys
for(int i=0;i<4;i++)
{
if((PS3.getAnalogHat(Joyarr[i]) != status_joys[i]) &&
(millis()-millis_joys[i]>200))
{
millis_joys[i]=millis();status_joys[i]=PS3.getAnalogHat(Joyarr[i]);
int hat=map(PS3.getAnalogHat(Joyarr[i]),0,255,map_joys[i]*
(-l),map_joys[i]);
if(i<2) dHatLeft=l;
else dHatRight=l;
if(dHatLeft>0)
{dHatLeft=0;}
if(dHatRight>0)
{dHatRight=0;
go_irobot(status_joys[3],status_joys[2]);}
Глава 22. Arduino и интерфейс USB: управление роботами 523
II buttons
for(int i=0;i
if(PS3.getButtonPress(Btarr[i]) && status_buttons[i]==0)
millis_buttons[i]=millis();status_buttons[i]=l;
put_actions(i);
}
else
{if(millis()-millis_buttons[i]>millis_buttonsl[i]) status_buttons[i]=0;}
// действия по нажатии кнопки
void put_actions(int btnl)
{
switch(btnl)
{
case 4: mySerial.writeA28);
break;
// start
case 5: mySerial.writeA32);
break;
// led
case 8: mySerial.write((intI39); mySerial.write((int)8);
mySerial.write((intJ55)/mySerial.write((intJ55);
break;
case 10: mySerial.writeA39);mySerial.writeD);
mySerial.write((byteH);mySerial.writeB55);
break;
// music 6
case 9: mySerial.writeA41);mySerial.writeF);
break;
// 40 см и останов
case 12: mySerial.writeA52);mySerial.writeA3);mySerial.writeA37) ;
mySerial.writeA);mySerial.writeD4);mySerial.writeA28);
mySerial.write((byteH);mySerial.write((intI56);
mySerial.write((intI) ;mySerial.write((intI44);
mySerial.writeA37);mySerial.write((byteH);mySerial.write((byte)O);
mySerial.write((byteH);mySerial.write((byte)O);mySerial.writeA53);
break;
// music 5
case 11: mySerial.writeA41);mySerial.writeE);
break;
case 13: mySerial.writeA52);mySerial.writeA7);mySerial.writeA37) ;
mySerial.writeA);mySerial.writeD4);mySerial.writeA28);
mySerial.write((byteH);mySerial.write((intI56);
mySerial.write((intI);mySerial.write((intI44);
524 Часть IV. Интересные проекты на Arduino
mySerial.writeA37) ;mySerial.writeA) ;mySerial.writeD4);
mySerial.write((byte)O);mySerial.write(l);mySerial.write((intI57);
mySerial.write((byteH);mySerial.write(90);
mySerial.writeA53);mySerial.writeA53);
break;
default:
break;
// отправка команд для движения робота
void go_irobot(int vl,int rl)
{
int v2,r2,lfl,rtl;
if(vl<128 && rl<128)
{lfl=vl+abs(rl~128)/2;rtl=max@fvl-abs(rl-128)/2);}
else if(vl<128 && rl>=128)
{lfl=max@,vl-abs(rl-128)/2);rtl=vl+abs(rl-128)/2;}
else if(vl>=128 && rl<128)
{Ifl=vl-abs(rl-128)/2;rtl=rainB55,vl+abs(rl-128)/2);}
else if(vl>=128 && rl>=128)
{Ifl=minB55,vl+abs(rl-128)/2);rtl=vl-abs(rl-128)/2;}
else
lfl=raap(lfl,0,255,250,-250);
rtl^map (rtl,0,255,250,-250);
mySerial.writeA45);
mySerial.write(highByte(rtl));mySerial.write(lowByte(rtl));
mySerial.write(highByte(If1));mySerial.write(lowByte(If1));
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\22\_22J>6
сопровождающего книгу электронного архива (см. приложение 2).
Для загрузки скетча в плату Arduino предварительно скопируйте его на своем
компьютере в папку libraries\USB_Host\examples, откройте в Arduino IDE и нажмите на
кнопку Загрузить.
ГЛАВА 23
Камера Pixy:
реализация компьютерного зрения
Камера Pixy (рис. 23.1) — это популярная система машинного зрения для Arduino и
Raspberry Pi. В отличие от большинства камер, Pixy самостоятельно выполняет
обработку изображения, освобождая мощности микроконтроллера для других задач.
Встроенные в ее прошивку алгоритмы способны обнаруживать и отслеживать
множество объектов одновременно.
Рис. 23.1. Камера PixyCam
В частности, для обнаружения объектов Pixy использует алгоритм цветовой
фильтрации на основе оттенков. Поэтому объект должен иметь четкий цветовой оттенок.
Камера может одновременно распознавать объекты семи цветовых оттенков,
которые можно запрограммировать. Обмен данными с микроконтроллерами
осуществляется по одному из интерфейсов: I2C, SPI, UART или через аналоговые выходы.
Pixy может находить сотни объектов за кадр. Она использует алгоритм связанных
компонентов, чтобы определить, где один объект начинается, а другой заканчива-
526 Часть IV. Интересные проекты на Arduino
ется. Затем Pixy компилирует размеры и местоположение каждого объекта и
передает их через один из своих интерфейсов (например, SPI).
23.1. Настройка камеры
В качестве утилиты настройки для Pixy используется PixyMon — она работает как
в ОС Windows, так и в Mac OS и в Linux. Версию для Windows можно скачать по
ссылке: http://cmucam.Org/attachments/download/1246/pixymonwindows-2.0.9.exe.
Скачав и установив утилиту PixyMon, подсоединим камеру Pixy к компьютеру
с помощью USB-кабеля и запустим утилиту.
Для настройки камеры на определенные цвета выбираем в меню пункт Action | Set
Signature<X>... и на изображении выделяем с помощью мыши участок нужного
цвета. Так же поступаем и для настройки камеры на следующие шесть сигнатур.
После этого на экране видим выделение объектов для всех настроенных сигнатур
(рис. 23.2).
Рис. 23.2. Определение объектов запрограммированных сигнатур в утилите PixyMon
Глава 23. Камера Pixy: реализация компьютерного зрения 527
Рис. 23.3. Тонкая настройка сигнатур в программе PixyMon
Для каждой сигнатуры в меню File | Configure можно установить и более тонкие
настройки (рис. 23.3).
23.2. Подключение камеры Pixy
к плате Arduino
Подключение камеры Pixy к плате Arduino выполняется с помощью входящего
в комплект камеры переходника, который подсоединяется к контактам ISCP платы
Arduino (рис. 23.4). Общение камеры с платой Arduino при этом осуществляется по
интерфейсу SPI.
Для программирования камеры используется библиотека Pixy. Установим библиог
теку в Arduino IDE и запустим из этой библиотеки пример hello_world. Как можно
видеть, в монитор последовательного порта с камеры Pixy выводятся данные об
обнаруженных объектах (рис. 23.5).
Электронный архив
Библиотека Pixy размещена в каталоге libraries сопровождающего книгу электронного
архива (см. приложение 2).
528
Часть IV. Интересные проекты на Arduino
Рис. 23.4. Подключение камеры Pixy к плате Arduino
Рис. 23.5. Вывод в монитор последовательного порта данных,
приходящих в Arduino с камеры Pixy
Глава 23. Камера Pixy: реализация компьютерного зрения 529_
23.3. Организация слежения камерой
за объектом
В этом проекте мы организуем слежение камерой Pixy, укрепленной на подвесе из
двух сервоприводов, за объектом определенного цвета. Система ищет объект с
цветом заданной сигнатуры и с максимальными размерами, определяет удаление его
центра от центра камеры и дает команды на сервомоторы для смещения подвеса.
Монтажная схема этого проекта представлена на рис. 23.6, а содержимое скетча,
обеспечивающего ее работу, — в листинге 23.1. Загружаем скетч в плату Arduino и
проверяем работу системы.
fntzmg
Рис. 23.6. Монтажная схема подключения к плате Arduino камеры Pixy,
укрепленной на подвесе из двух сервоприводов
// подключение библиотек
#include <SPI.h>
#include <Pixy.h>
#include <Servo.h>
// создание объектов
Pixy pixy;
Servo servoX;
Servo servoY;
530
Часть IV. Интересные проекты на Arduino
void setup()
{
Serial.begin(9600);
Serial.print("Starting..An")
servoX.attach(9);
servoY.attachA0);
// запуск pixy
pixy.initO ;
void loop О
0;
static int i
int j;
uintl6_t blocks;
char buf[32];
// получить данные с камеры
blocks = pixy.getBlocks();
// если блоки найдены
if (blocks)
// анализируем 1 .из каждых 50 кадров
if (i%50—0)
sprintf(buf, "Detected %d:\n", blocks);
Serial.print(buf);
for (j=0; j<blocks; j++)
sprintf(buf, " block %d: ", j);
// если объект сигнатуры 1
int maxlength=0;
int maxlengthx=0;
int maxlengthy=0;
int centerx=0;
int centery=0;
if(pixy.blocks[j].signature==l) {
Serial.print(pixy.blocksfj].signature);Serial.print(" ");
Serial.print(pixy.blocks[j].x);Serial.print(" ");
Serial.print(pixy.blocks[j].y);Serial.print(" ");
Serial.print(pixy.blocks[j].width);Serial.print(" ");
Serial.print(pixy.blocks[j}.height);Serial.printIn(" ");
// вычисляем максимальный объект
if(maxlength<pixy.blocks[j].width || maxlength<pixy.blocks[j].height) {
maxlength=max(pixy.blocks[j].width,pixy.blocks[j].height);
Глава 23. Камера Pixy: реализация компьютерного зрения 531
maxlengthx=pixy.blocks[j].width;
maxlengthy^pixy.blocks[j].height;
centerx=pixy.blocks[j].x+pixy.blocks[j].width/2;
centery=pixy.blocks[j],y+pixy.blocks[j].height/2;
}
// поворот сервоприводов
servoX.write(map(centerx,0+50,320-50,0,180));
servoY.write(map(centery,0+50,240-50,0,180));
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples№3\_23JI
сопровождающего книгу электронного архива (см. приложение 2).
ГЛАВА 24
Проекты
на плате Nano 33 BLE Sense
Arduino Nano 33 BLE Sense (рис. 24.1) — компактная платформа для разработки на
чипе u-blox NJNA-B306, который включает в себя 32гбитный микроконтроллер
Nordic nRF52840 на архитектуре ARM Cortex-M4 с тактовой частотой 64 МГц,
1 МБайт флеш-памяти и 256 КБайт оперативной памяти. Чип NINA-B306
обеспечивает связь Bluetooth v5.0 в диапазоне 2,4 ГГц и поддерживает
энергосберегающий протокол Bluetooth Low Energy (BLE).
На плате расположено несколько датчиков:
? 9-осевой IMU-сенсор (инерциальное измерительное устройство) на чипе LSM9DS1,
включающий в себя акселерометр, компас и магнитометр;
? датчик температуры и относительной влажность воздуха HTS221;
? датчик атмосферного давления LPS22HB;
ХП датчик Avago APDS-9960, который позволяет распознавать базовые жесты
(взмах руки влево или вправо, вверх-вниз и вперед-назад), а также цвета через
интенсивность каналов RGB и уровень освещенности;
? встроенный цифровой микрофон MP34DT05, который можно использовать для
распознавания коротких голосовых команд или записи звука.
Назначение контактов платы Arduino Nano 33 BLE Sense показано на рис. 24.2.
Рис. 24.1. Плата Arduino Nano 33 BLE Sense
Глава 24. Проекты на плате Nano 33 BLE Sense 533
ARDUINO SYMBOL
Рис. 24.2. Назначение контактов платы Arduino Nano 33 BLE Sense
24.1. Начало работы
с платой Nano 33 BLE Sense
Чтобы осуществлять программирование платы Nano 33 BLE Sense в среде Arduino
IDE, необходимо установить для нее поддержку.
Для этого командой меню Инструменты | Плата | Менеджер плат заходим в
Менеджер плат, находим плату типа nano зз ые, нажимаем кнопку Установка
(рис. 24.3) и подтверждаем установку программного обеспечения в открывшемся
окне Безопасность Windows (рис. 24.4).
После установки программного обеспечения и драйверов (рис. 24.5) в списке плат
среды Arduino IDE появится плата Arduino Nano 33 BLE и обнаружится
подключение к порту (рис. 24.6).
Теперь на плату необходимо загрузить любой скетч — например, Blink, и
проверить ее работоспособность.
Кроме того, для работы с датчиками, установленными на плате, необходимо
установить через Менеджер библиотек (Скетч | Подключить библиотеку | Управлять
библиотеками) следующие библиотеки:
? HTS221 — для датчика температуры и влажности;
О LPS22HB — для барометрического датчика;
534 Часть IV. Интересные проекты на Arduino
О APDS9960 — для датчика жестов, освещенности, цвета и приближения;
? LSM9DS1 —для DVfU-датчика (акселерометр, гироскоп, магнитометр);
? PDM — для микрофона;
? ArduinoBLE — для передачи данных по Bluetooth BLE.
Рис. 24.3. Поиск платы типа nano 33 Ые
Рис. 24.4. Установка поддержки для Arduino Nano 33 BLE Sense в Arduino IDE
Глава 24. Проекты на плате Nano 33 BLE Sense
535
Рис. 24.5. Завершение
установки ПО
и драйверов
Рис. 24.6. Плата Arduino Nano 33 BLE готова к работе
536 Часть IV. Интересные проекты на Arduino
Электронный архив
Библиотеки HTS221, LPS22HB, APDS9960, LSM9DS1, RDM и ArduinoBLE размещены в
каталоге libraries сопровождающего книгу электронного архива (см. приложение 2).
Загрузите примеры из этих библиотек на плату и проверьте их работу.
24.2. Bluetooth Low Energy (BLE)
Bluetooth Low Energy (BLE) является частью спецификации Bluetooth 4.0, которая
также включает протокол классического Bluetooth и протокол высокоскоростного
Bluetooth (Classic Bluetooth and Bluetooth High Speed Protocols). По сравнению
с классическим Bluetooth BLE требует меньшей мощности при сохранении
аналогичного диапазона связи. Дело, в том, что BLE — это технология, которая всегда
отключена и передает только короткие объемы данных, когда это необходимо. Это
значительно снижает энергопотребление, что делает технологию BLE идеальной
для использования в случаях, когда требуется постоянное долговременное
соединение с низкой скоростью передачи данных.
В BLE есть два основных понятия:
? GAP, Generic Access Profile — общий профиль доступа;
? GATT, Generic Attribute Protocol — протокол общих атрибутов.
Общий профиль доступа (GAP) ответствен за подключение и распространение
информации о наличии устройства BLE. Он отвечает за видимость устройства во
внешнем мире, а также играет важную роль в определении того, как устройство
взаимодействует с другими устройствами.
На основе BLE функционируют два вида устройств; периферийные и центральные.
Процесс обеспечения видимости устройств (advertising process) заключается в том,
что периферийное устройство каждые 2 с отправляет в окружающую среду данные
о своем существовании. Если эти данные получит центральное устройство, оно
отправит запрос на сканирование. В ответ периферийное устройство пришлет данные
результата сканирования.
Используя общий протокол данных (протокол атрибутов GATT), два устройства
BLE обмениваются данными друг с другом на основе таких понятий, как сервис
(service) и характеристика (characteristic). Протокол GrATT сохраняет все сервисы
и характеристики в справочной таблице с использованием 16-битных
идентификаторов* Сервис может иметь много характеристик.
Уникальность каждого сервиса обеспечивается универсальным уникальным
идентификатором (UUID), который может иметь размер 16 битов— для официальных
адаптированных сервисов или 128 битов — для пользовательских сервисов.
Характеристики содержат одну точку данных и схожи с сервисами, при этом каждая
характеристика имеет свой уникальный идентификатор (UUID), который отличает
ее от другой характеристики.
Глава 24. Проекты на плате Nano 33 BLE Sense 537
Согласно спецификации Special Interest Group (SIG) для устройств BLE1 любое
устройство BLE, которое официально приняло UUID от SIG, должно использовать
идентификатор, указанный им в своих приложениях.
24.3. Отправка данных
с датчиков платы Nano 33 BLE Sense no BLE
Рассмотрим отправку данных с датчиков HTS221 (относительной влажности
воздуха и температуры) и LPS22HB (барометрический датчик) платы Nano 33 BLE Sense
по BLE. Используем для этого библиотеку ArduinoBLE (листинг 24.1).
Сначала определяем BLE сервиса (uuid — 0x1815 Automation IO):
BLEService meteoBLEsense(815");
и характеристики для температуры, влажности и атмосферного давления:
BLEIntCharacteristic meteoTemperatureChar(A6E", BLERead | BLENotify);
BLEUnsignedlntCharacteristic meteoHumidityChar(A6F", BLERead | BLENotify);
BLEUnsignedlntCharacteristic meteoPressureChar(AA3", BLERead I BLENotify);
Данные UUID для сервиса и характеристик берем в спецификации SIG для
характеристик и сервисов.
После чего отправляем данные замеров с периодичностью 1 раз в 3 с.
// подключение библиотек
#include <ArduinoBLE.h>
Hnclude <Arduino_HTS221.h>
¦include <Arduino_LPS22HB.h>
// определение BLE сервиса (uuid - 0x1815 Automation 10 )
BLEService meteoBLEsense(815");
// характеристики сервиса
BLEIntCharacteristic meteoTemperatureChar(A6E", BLERead I BLENotify);
BLEUnsignedlntCharacteristic meteoHumidityChar(A6F", BLERead | BLENotify);
BLEUnsignedlntCharacteristic meteoPressureChar(AA3", BLERead | BLENotify);
// служебные переменные
float temperature;
float humidity;
float pressure;
unsigned long millissend;
void setup() {
// запуск последовательного порта
Serial.begin(9600);
1 Для характеристик см.: https://www.bluetooth.com/speciflcations/gatt/characteristics/, для
сервисов — https://www.bluetooth.com/speciflcations/gatt/services/.
538 Часть IV. Интересные проекты на Arduino
while (!Serial);
// запуск датчика влажности и температуры
if (!HTS.begin()) {
Serial.println("Failed to initialize humidity temperature sensor!");
while A);
}
// запуск барометра
if (!BARO.begin()) {
Serial.println("Failed to initialize pressure sensor!");
while A);
pinMode(LED_BUILTIN, OUTPUT);
// запуск BLE
if (!BLE.begin()) {
Serial.println("BLE failed to Initiate");
delayE00);
while A);
// чтение данных с датчиков
temperature = HTS.readTemperature();
humidity = HTS.readHumidity();
pressure = BARO.readPressureO;
BLE.setLocalName("ArduinoMeteoBLEsense");
BLE.setAdvertisedService (meteoBLEsense);
meteoBLEsense.addCharacteristic(meteoTemperatureChar);
meteoBLEsense.addCharacteristic(meteoHumidityChar);
meteoBLEsense.addCharacteristic(meteoPressureChar);
BLE.addService(meteoBLEsense);
meteoTemperatureChar.writeValue(temperature*100);
meteoHumidityChar.writeValue(humidity*100);
meteoPressureChar.writeValue(pressure*7.5);
// advertising process
BLE.advertise();
Serial.println("Bluetooth device is now active, waiting
for connections...");
void loopO {
- // подключение центрального устройства
BLEDevice central = BLE.central();
if. (central) {
Serial.print("Connected to central: ");
Serial.println(central.address());
digitalWrite(LED_BUILTIN, HIGH);
Глава 24. Проекты на плате Nano 33 BLE Sense
539
while (central.connected()) {
if (millis()-millissend>=3000) {
temperature = HTS.readTemperature();
humidity = HTS.readHumidity();
pressure = BARO.readPressureO;
meteoTemperatureChar.writeValue(temperature*100);
meteoHumidityChar.writeValue(humidity*100);
meteoPressureChar.writeValue(pressure*7.5);
Serial.println("Meteo BLEsense data:");
Serial.print("t=")/Serial.print(temperature);Serial.print(" °C");
Serial.print (" h=") /Serial.print (humidity);Serial.print (" %") ;
Serial.print(" p=")/Serial.print(pressure);Serial.print(" kPa");
Serial.println(" ");
Serial.println("");
//
millissend=mLllis();
digitalWrite(LED_BUILTIN, LOW);
Serial.print("Disconnected from central: ");
Serial.println(central.address());
В качестве центрального устройства мы используем смартфон на ОС Android
с установленным приложением nrfConnect (рис. 24.7).
i% Mi Smart Band 4
Й8? Е8-07:2F:ID-.2/4:^0
ЫЯ BONDED
0x1300
Рис. 24.7. (Часть 1 из 2) Получение данных из периферийного устройства (nrfConnect)
540 Часть IV. Интересные проекты на Arduino
Рис. 24.7. (Часть 2 из 2)
Электронный архив
Полный вариант рассмотренного скетча находится в папке *xampte&\24\j>4j)i
сопровождающего книгу электронного архива (см. приложение 2).
24.4. EM6nHOTeicaTensorFlow Lite
TensorFlow — открытая программная библиотека для машинного обучения,
разработанная компанией Google для решения задач построения и тренировки
нейронной сети с целью автоматического нахождения и классификации образов, достигая
качества человеческого восприятия. Ее вариант TensorFlow Lite — это облегченное
решение TensorFlow для мобильных и встроенных устройств.
Специалисты компании Arduino совместно с командой TensorFlow Lite разработали
библиотеку TensorFlow Lite Micro для Arduino Nano 33 BLE Sense. Эта библиотека
доступна в Arduino Library Manager (Скетч | Подключить библиотеку |
Управлять библиотеками). Установите ее, как показано на рис. 24.8.
Глава 24. Проекты на плате Nano 33 BLE Sense 541
Рис. 24.8. Установка библиотеки Tensorflow Lite
Электронный архив
Библиотека TensorFlow Lite Micro размещена в каталоге libraries сопровождающего
книгу электронного архива (см. приложение 2).
В библиотеке TensorFlow Lite Micro содержатся примеры на предварительно
обученных моделях:
? micro_speech — распознавание речи с помощью встроенного микрофона;
О magicwand — распознавание жестов с использованием встроенного IMU;
О persondetection — обнаружение человека с помощью внешней камеры ArduCam.
Загрузите й плату и проверьте в действии пример micro_speech. При произнесении
слова «yes» светодиод горит пару секунд зеленым цветом, при произнесении слова
«по» светодиод горит пару секунд красным цветом. Предварительно обученная
нейронная сеть работает на плате Nano 33 BLE Sense.
24.5. Пример создания
классификатора объектов с обучением
В этом проекте мы создадим классификатор объектов с использованием нейронной
сети, запущенной на плате Arduino Nano 33 BLE Sense. Для этого воспользуемся
библиотекой TensorFlow Lite Micro и датчиком цвета APDS9960, расположенным
на плате.
Классификацию объектов мы проведем по цвету — например, определим фрукты
разного цвета: зеленое яблоко, банан, апельсин, огурец, помидор. Проект состоит
из следующих этапов: сбор данных, обучение и развертывание классификаторов.
542 Часть IV. Интересные проекты на Arduino
24.5.1. Сбор данных
Соберем данные для обучения нашей модели в TensorFlow, предлагая устройству
наши фрукты и овощи в качестве объектов разного цвета.
Загрузите в плату Arduino Nano 33 BLE Sense скетч из листинга 24.2, с помощью
которого будут получены цветовые данные объектов.
// подключение библиотек
#include <Arduino_APDS9960.h>
void setup() {
// запуск последовательного порта
Serial.begin(9600);
while (!Serial) {};
// инициализация датчика APDS9960
if (!APDS.begin()) {
Serial.println("Error initializing APDS9960 sensor.");
}
// заголовок
Serial.println("Red,Green,Blue");
void loopO {
int r, g, b, c, p;
float sum;
// ожидание данных датчика
while (!APDS.colorAvailable() I I !APDS.proximityAvailable()) {}
// чтение данных с датчика
APDS.readColor(r, g, b, с);
sum = r + g + b;
p = APDS.readProximity() ;
// если объект находится близко и достаточно хорошо освещен
if (р == 0 && с > 10 && sum > 0) {
float redRatio = г / sum;
float greenRatio = g / sum;
float blueRatio = b / sum;
// вывод в CSV-формате
Serial.print(redRatio/ 3);
Serial.print(\ ');
Serial.print(greenRatio, 3);
Глава 24. Проекты на плате Nano 33 BLE Sense 543
Serial.print(',f); •
Serial.print(blueRatio, 3);
Serial.println();
Здесь для каждого объекта, который мы хотим классифицировать, собираются
некоторые данные о его цвете. Перемещайте плату с датчиком вдоль и вокруг
поверхности каждого объекта, чтобы захватить все возможные вариации его цвета.
Датчик цвета отправляет данные о цвете объекта в формате журнала CSV в
последовательный порт (рис. 24.9). Выводимые в монитор данные (включая первую
строку: Red, Green, Blue) сохраняем в файлы *.csv.
Выполнив описанную операцию для всех объектов, получим в результате
соответствующее количество файлов: banana.csv, greenapple.csv, orange.csv, tomato.csv,
cucumber.csv.
Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\24\_24JJ
сопровождающего книгу электронного архива (см. приложение 2).
Рис. 24.9. Отправка данных цвета объекта в монитор последовательного порта
544 Часть IV. Интересные проекты на Arduino
24.5.2. Обучение модели
Для обучения нейронной сети воспользуемся Google Colab — бесплатным
облачным сервисом на основе Jupyter Notebook. Google Colab предоставляет все
необходимое для машинного обучения прямо в браузере и дает бесплатный доступ к
невероятно быстрым процессорам нейронных сетей GPU и TPU. С помощью Google
Colab вы можете легко обучить свою модель за считанные секунды.
В Colab предустановлена библиотека Tensorflow и практически все необходимые
для работы python-библиотеки. Если какой-то пакет отсутствует, он с легкостью
устанавливается на ходу через pip или apt-get.
Чтобы начать работать с Colab, сначала необходимо войти в свою учетную запись
Google, а затем перейти по этой ссылке: https://colab.research.google.com
(рис. 24.10).
Рис. 24.10. Вход в Google Colab: создание нового ноутбука
Затем устанавливаем необходимые пакеты, набрав в Поле выполнения кода
соответствующие команды (рис. 24.11).
После чего можно загрузить необходимые данные — CSV-файлы, полученные
в разд. 24.5.1 (рис. 24.12).
Теперь можно приступать к обучению нейронной сети. Выполнение кода,
осуществляющего анализ CSV-файлов и преобразование их в формат, который будет
использоваться для обучения подключенной нейронной сети, показано на рис. 24.13.
Результат такого анализа и преобразования показан на рис. 24.14.
Глава 24. Проекты на плате Nano 33 BLE Sense 545
Рис. 24.11. Установка необходимых пакетов
Рис. 24.12. Загрузка файлов с данными
546 Часть IV. Интересные проекты на Arduino
Рис. 24.13. Анализ CSV-файлов и преобразование их в формат,
который будет использоваться для обучения подключенной нейронной сети
Рис. 24.14. Преобразование файлов с данными к необходимому формату
Глава 24. Проекты на плате Nano 33 BLE Sense 547
Рис. 24.15. Создание и обучение модели TensorFlow с помощью высокоуровневого API Keras
Далее создаем и обучаем модель TensorFlow с помощью высокоуровневого API
Keras (рис. 24.15).
Поместим наши тестовые данные в модель (рис. 24.16) и подготовим прогнозы
(рис. 24.17).
Преобразуем модель в формат TFlite (рис. 21.18).
Создадим постоянный байтовый массив, который содержит модель TFlite, и
импортируем его как файл model.h (рис. 24.19).
Рис. 24.16. Помещение тестовых данных в модель
548
Часть IV. Интересные проекты на Arduino
Рис. 24.17. Прогнозы при загрузке тестовых данных в модель
Рис. 24.18. Преобразование модели в формат TFIite
Рис. 24.19. Создание файла model.h
Глава 24. Проекты на плате Nano 33 BLE Sense
549
Осталось щелкнуть на файле model.h двойным щелчком для его скачивания на
компьютер.
Электронный архив
Файл RrojectsArduino_glava24.ipynb для среды Google Colab находится в папке examples\24
сопровождающего книгу электронного архива (см. приложение 2).
24.5.3. Скетч классификатора для запуска
нейронной сети на плате Nano 33 BLE Sense
Создадим скетч классификатора (листинг 24.3), при этом скопировав в папку
скетча файл model.h, который содержит модель TFlite (Tensorflow lite) (рис. 24.20).
iorfK:>rt si
Рис. 24.20. Добавление в скетч файла model.h
// Подключение библиотек
// Arduino_TensorFlowLite - Version: 0.alpha.precompiled
#include <TensorFlowLite.h>
550 Часть IV. Интересные проекты на Arduino
#include <tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h>
#include <tensorflow/lite/experimental/micro/itiicro_error_reporter.h>
#include <tensorflow/lite/experimental/micro/micro_interpreter.h>
#include <tensorflow/lite/schema/schema_generated.h>
#include <tensorflow/lite/version.h>
#include <Arduino_APDS9960.h>
#include "model.h"
// глобальные переменные, используемые в TensorFlow Lite (Micro)
tflite::MicroErrorReporter tflErrorReporter;
tflite::ops::micro::A110psResolver tflOpsResolver;
const tflite::Model* tflModel = nullptr;
tflite::MicroInterpreter* tfllnterpreter = nullptr;
TfLiteTensor* tfllnputTensor = nullptr;
TfLiteTensor* tflOutputTensor = nullptr;
// Буфер памяти для tensorflow lite
constexpr int tensorArenaSize = 8 * 1024;
byte tensorArena[tensorArenaSize];
// массив для сопоставления индекса объектов с именем
const char* CLASSES[] = {
"Banana",
"Cucumber",
"GreenApple",
"Orange",
"Tomato"
#define NUM_CLASSES (sizeof(CLASSES) / sizeof(CLASSES[0]))
void setup() {
Serial.begin(9600);
while (!Serial) {};
Serial.println("Object classification using RGB color sensor");
Serial, print In (" ");
Serial.println("Arduino Nano 33 BLE Sense running TensorFlow Lite Micro")
Serial.printIn(ии);
if (!APDS.begin()) {
Serial.println("Error initializing APDS9960 sensor.");
// получите представление TFL массива байтов модели
tflModel = tflite::GetModel(model);
Глава 24. Проекты на плате Nano 33 BLE Sense 551_
if (tflModel->version() != TFLITE_SCHEMA_VERSION) {
Serial.printIn("Model schema mismatch!");
while A);
// Создание интерпретатора для запуска модели
tfllnterpreter = new tflite::Microlnterpreter(tflModel, tflOpsResolver,
tensorArena, tensorArenaSize, &tflErrorReporter)
// Выделите память для входных и выходных тензоров модели
tflInterpreter->AllocateTensors();
// Получить указатели для входных и выходных тензоров модели
tfllnputTensor = tfllnterpreter->input@);
tflOutputTensor = tfllnterpreter->output@);
void loop() {
int r, g, b, p, c;
float sum;
// пока есть данные с датчика
while (!APDS.colorAvailableО I I !APDS.proximityAvailable()) {}
// чтение данных
APDS.readColor(r, g, b, c);
p = APDS.readProximity();
sum = r + g + b;
// если объект находится близко и достаточно хорошо освещен
if (р == 0 && с > 10 && sum > 0) {
// normalize
float redRatio = г / sum;
float greenRatio = g / sum;
float blueRatio = b / sum;
// входящие данные для tensorflow
tflInputTensor->data.f[0] = redRatio;
tflInputTensor->data.f[1] = greenRatio;
tflInputTensor->data.f[2] = blueRatio;
// запуск сети
TfLiteStatus invokeStatus = tfllnterpreter->lnvoke();
if (invokeStatus != kTfLiteOk) {
Serial.println("Invoke failed!");
while A);
return;
552 Часть IV. Интересные проекты на Arduino
// вывести результаты
for (int i - 0;' i < NUM_CLASSES; i++) {
Serial.print(CLASSES[i]);
Serial.print(" ")/
Serial.print(int(tflOutputTensor->data.f[i] * 100));
Serial.print("%\n")/
}
Serial.println();
// ожидание данных датчика
while (!APDS.proximityAvailable() I I (APDS * readProximity() — 0)) {}
Загружаем скетч в плату и проверяем работу классификатора объектов (рис. 24.21).
Электронный архив
Полный вариант рассмотренного скетча находится в папке ехатр1е$\24\т24„03
сопровождающего книгу электронного архива (см. приложение 2).
.. ®э«в^Шв;1
Рис. 24.21. Работа классификатора объектов
ПРИЛОЖЕНИЯ
Приложение 1. Перечень использованных источников
Приложение 2. Описание электронного архива
ПРИЛОЖЕНИЕ 1
Перечень
использованных источников
? http://www.arduino.cc — официальная документация проекта Arduino;
? http://www.cxem.net — авторские материалы с сайта «Паяльник»;
? http://www.playarduino.ru — авторские материалы с сайта PlayArduino;
? Петин В. А. Лекции по Arduino для школ Казахстана (будут распространяться
только на DVD в школах Казахстана).
ПРИЛОЖЕНИЕ 2
Описание электронного архива
Электронный архив с материалами, сопровождающими книгу, можно скачать
с FTP-сервера издательства «БХВ-Петербург» по ссылке ftp://ftp.bhv.ru/
9785977567114.zip, а также со страницы книги на сайте www.bhv.ru.
В архиве находятся следующие папки:
? \examples — исходники примеров и проектов глав 7-24 для Arduino IDE;
? Mibrariee — библиотеки Arduino, используемые в примерах и проектах книги и не
включенные в среду разработки Arduino IDE;
? \datasheets— документация производителей (data sheet) на рассматриваемые
в книге микросхемы и модули.
Предметный указатель
Android-приложение IoT MQTT Dashboard 307
API Яндекс.Карт 472
Applnvertor2 447
Arduino Due 27,28
Arduino GPRS/GSM Shield 464
Arduino Leonardo 21,26-28,149,367
Arduino LilyPad 24,25
Arduino Mega 145,149
Arduino Mega2560 25,26,149
Arduino MKR 21
Arduino MKR WiFi 29,308,309
Arduino Nano 22,23
Arduino Nano 33 21,30,31
Arduino Nano Every 30,31
Arduino Pro Mini 23,24
Arduino Uno 21,22
ArduinoYun21,28
В
Bluetooth-модуль HC-05 271,273,277,440,
442,452
Cosmo WiFi Connect Shield 32
EasyVR Arduino Shield 32
Ethernet Shield 31
GPS-приемник V.KEL VK16E 461
GSM/GPRS Shield 31
H
LEGO Mindstorms 372
LilyPad Arduino 328,364
M
МАС-адрес устройства 279,281,282,284,285,
287,458
MicroSD Shield 31
Motor Shield 31
MP3 Shield 31
Music Shield 32
N
Nano 33 BLE Sense 30,31
О
OLED-дисплеи 192
Raspberry Pi 3$6-390
RGB-светодиод 115,342-344
Robot Operating System (ROS) 376
Video Overlay Shield 32
w
Wi-Fi модуль ESP8266 398-406
Wi-Fi/Bluetooth модуль ESP32 399
X
XBee Shield 31
НТО-интерфейс 507
НТО-устройства 504-507,510
ZIP-архив библиотеки 133
558
Предметный указатель
Адаптер USB-Serial 202, 334
Амплитудная модуляция 266
Аналоговые
0 входы Arduino 45,107
0 датчики 153
° температуры LM335 154,283,284,291,292,
295,296
¦ температуры ТМР36 421,423,424,428,429,
435,437,440,442,444,452,455
Аналого-цифровой преобразователь (АЦП 46
Аппаратные UART-контроллеры 140
Аппаратура радиоуправления 264
Арифметические операторы 54
Базовая структура программы для Arduino 48
Бесколлекторные двигатели 245,246
Беспроводная передача данных 248
Беспроводной геймпад Defender Scorpion RS3 520
Беспроводной интерфейс Bluetooth 271
Беспроводной радиомодуль NRF24L01 257-259,
508,510,511
Библиотека
0 Adafruit SSD1306 192
0 Adafruit Thermal Printer 404
0 Adafruit Unified Sensor 185
0 Adafruit_GFX_Library 187,190
0 BH1750FVI170,172
0 BMP280 183
0 DHT165,423
0 Esplora 342, 343,344
0 Ethernet 279
0 IRRemote249
0 Keyboard 341
0 LiquidCrystal 175,176
0 LiquidCrystalJ2C 181
0 Mouse 341
0 NRF24L01 511
0 OLEDJ2C192
0 OneWirel56
0 Pixy 527
0 RCSwitch254
0 RF24 260
0 rosjib 378,379
0 rosserial378
0 sdfatlib280
0 Serial 140
0 Servo 235,246
0 SoftwareSerial 149,272
0 USB_Host 504,505, 508,510,511,520
0 Wire 168
0 ZUNO_DHT414
Библиотеки Arduino 37,38,132
В
Веб-камера 369
Вентилятор 432
Графический дисплей Nokia5110 186
Датчик 153,154,157
0 AvagoAPDS-9960 532
0 атмосферного давления LPS22HB 532
0 атмосферного давления и температуры ВМР280
183
0 влажности и температуры DHT11 259,373,374,
414,421,423,424,428,429,435,436,440,442,
443,452,454
0 движения HC-SR501 310-312,370,371,535,544
0 расстояния НС SR-04 237
0 температуры и относительной влажности
воздуха HTS221 532
0 точного времени DS3231 193,194
Дисплей 173,175,197
0 Nextion 197,203,206
0 WH0802 385,386
Драйверы двигателей 231
0 L293 510,517
0 L298 231,233
0 шагового двигателя А4988 240
Дребезг 101,102
Дробление шага шагового двигателя 242
ж
Жидкокристаллические дисплеи 173
ЖК-дисплей Nokia5110 426,427,431
ЖК-индикаторы 192
Заголовочный файл библиотеки 136
и
Игра «Змейка» 344
Издатель (publisher) 378,379,383,384
ИК-приемник 248,249,251,252
ИК-приемопередатчик 248
ИК-пульт248,251
Интернет вещей 279,* 367,402,451
Интерфейс
0 I2C192
0 SPI527
0 USB503
Искусственные источники света 432
Исполнительное устройство 225
Предметный указатель
559
К
Камера Pixy 472, 525,527-529
Клиент 503
Конвертор I2C 181
Контроллер PCD8544 186
Купюроприемник 476-480,492
л
Логические операторы 55
Люминесцентные лампы 433
м
Мембранный вакуумный насос 432
Менеджер библиотек 132,133
Микрокомпьютер Atheros AR9331 28, 367
Микроконтроллер
0 ATmega45
¦ ATmegal280 20
¦ ATmegal68 20,22-25
¦ ATmegal68V 362
¦ ATmega2560 20,25
о ATmega328 20-25,334,362
¦ ATmega328V 362,365
¦ ATmega32U4 20,26,28,334,335,341,362,367
0 ATSAMD21G18 29
0 ESP32 399
0 HD44780 173,175
0 Microchip ATmega328P 31
0 Microchip ATmega4809 18
Микропроцессор Atmel SAM3X8E ARM Cortex-M3
20
Микросхема
0 DS3231 193,405,406
0 ESP8266 398
0 L293 510,517
0 MCP23017 128
0 SIM900 289
0 WiznetW5100 279
Модуль
0 влажности почвы 422
0 часов реального времени DS3231 405
Монетоприемник 476,483,484,492
Монитор последовательного порта 39
Мультиплексор CD4051 129,130
н
Назначение статического IP-адреса 280,302
Настройка контрастности 174,175
Нормально разомкнутая кнопка 97
Облачная среда разработки Arduino Create 35
Операторы сравнения 49,55
Основные АТ-команды 273
Отладочная
0 информация Arduino 142,149
0 плата NodeMCU 403,407,409
п
Передатчик
0 FS1000A254
0 НК-Т6А265,268,269
Переменные 62,82
Плата Arduino 181,188,190,192,205,207
0 Esplora 340-344,346, 350,355
0 Leonardo 334,335,337,338,340,368
0 LilyPad362
0 Mega 389-391
0 Nano 33 BLE Sense 532-534,540-542,550
0 Yun367
Плата
0 GSM GPRS SIM900 Shield 464
0 LilyPad Arduino USB 363
0 LilyPad Simple Snap 364
0 Z-Uno 409-414
Плата расширения
0 Arduino Yun shield 367-369
0 Ethernet shield 279-284
0 Ethernet shield W5100 451
0 GSM/GPRS Shield 289,292,295
0 Relay shield 431,433
0 USB Host Shield 504,505, 508,510,520
Платы расширения (шилды) 31
Подключение
0 библиотек 135
0 русского шрифта 193
Подписчик (subscriber) 379,383
Подтягивающий резистор 97-100
Поиск устройств, подключенных к шине I2C 168
Получение IP-адреса по DHCP 280,281,302
Последовательный интерфейс USB 503
Последовательный порт
0 UART 140,141,150
0 USB334
Потенциометр 109,115,175
Преобразователь USB-Serial 365
Приемник
0 НК-Т6А267,268
0 MX-RM-5V256,257
Приложение Bluetooth Terminal 446,447
Программа Nextion Editor 197
Программатор 334
Протокол
0 1-Wire 156,157,379
0 Bluetooth 440
0 Bluetooth Low Energy (BLE) 532,536
0 I2C 167-169,172,181,183,373
0 MQTT 300,304,305,307
0 MQTT (Message Queue Telemetry Transport) 299
0 радиопередачи данных Z-Wave 409-411,415
560
Предметный указатель
Процессор
О Atmel SAM3X8E ARM Cortex-M3 27
О SitaraAM1808(ARM9K72
Радиоканал 433,920 МГц 254
Радиомодуль
0 передатчика FS1000A 254
0 приемника MX-RM-5V 254
Разменный автомат (хоппер) 476,485,486
Реле 225,226
Робот iRobot Create 518-520
Руль Defender F.orsage Drift GT 508,509
Сайт «Народный мониторинг» 282-284, 287-289,
295,299,300,301, 304-306,451
Светодиодная матрица 207
Светодиодные фитолампы 433
Светодиодный индикатор 118
0 D5651 118,136
Сдвиговый регистр 74НС595 122-124
Сенсор 153
Сервис Arduino IoT Cloud 312,313,316
Сервопривод 234,238,251
0 MG995 235
Символьные дисплеи 173,186
Система GPS 461
Скетч 37
Создание библиотек 136
Среда
0 Arduino Create 41^43
0 разработки Arduino IDE 35,37
Стягивающий резистор 97,99,100
Схема с общим эмиттером 226
Файл
0 keywords.txt 135,138
0 реализации библиотеки 137
Фоторезистор 337,421,423,424,428,429,435,437,
440,442,444,452,455
Фреймворк WeblOPi 387
Функции 48, 53,64, 78, 79
0 клавиатуры 335
0 мыши 337
х
Хост 503, 507, 508
ц
Цифровой датчик
0 влажности и температуры DHT 163
0 интенсивности света ВН1750 169
0 температуры DS18B20 157
Цифровой микрофон MP34DT05 532
Цифровые
0 входы Arduino 97
0 выводы Arduino 87
0 порты ввода/вывода 45
Частотная модуляция 266
ш
Шаговые двигатели 239,240
0 Nema 17 240
Широтно-импульсная модуляция (ШИМ) 46,114
Твердотельные реле 227,229
Термопринтер 402,403
Типы данных 56
Узлы ROS 381
Унарные операторы 56
Управляющие операторы 49
Установка драйверов Arduino 35
Утилита PixyMon 526, 527
Электродвигатели постоянного тока 229
Электромагнитное реле 225,226
Электронные часы 193,195
Эмулятор компьютерной мыши 338, 339
Энергонезависимая память EEPROM 145-147,148
Энергосберегающие лампы дневного спектра 433
Язык Processing/Wiring 35