Text
                    Валерий Яценков
Здоровье, спорт
и окружающая среда
проектах
Санкт-Петербург
« БХВ-Петербу рг»
2020


УДК 004+61+796 ББК 32.973.26+28.708 Я92 Яценков В. С. Я92 Здоровье, спорт и окружающая среда в проектах Arduino. — СПб.: БХВ-Петербург, 2020. — 336 с: ил. — (Электроника) ISBN 978-5-9775-4068-1 Описаны новые проекты на платформах Arduino и ESP32/8266 и увлекательные опыты по исследованию человеческого организма и окружающей среды с исполь- зованием самых современных и доступных сенсоров и модулей профессионально- го уровня. Каждый проект начинается с описания основ изучаемого явления и завершается опытами и заданиями для самостоятельной работы. Рассказано, как выбрать плату Arduino, создать домашнюю лабораторию, измерять частоту пульса и содержание кислорода в крови, проверять гальваническую реакцию кожи, сни- мать электрокардиограмму и регистрировать мышечные токи, контролировать чистоту окружающего воздуха и измерять интенсивность ультрафиолета в разных диапазонах, обрабатывать данные и работать с онлайновым сервисом визуализа- ции Adafruit 10. На сайте издательства помещен архив файлов с исходными кода- ми программ и цветными иллюстрациями. Для широкого круга любителей электроники, школьников, студентов и преподавателей Группа подготовки издания: Руководитель проекта Евгений Рыбаков Зав. редакцией Екатерина Сависте Компьютерная верстка Ольги Сергиенко Дизайн серии Марины Дамбиевой Оформление обложки Карины Соловьевой УДК 004+61+796 ББК 32.973.26+28.708 Подписано в печать 11 11 19 Формат 70x1001Лб Печать офсетная Уел печ л 27,09 Тираж 1000 экз Заказ № 4441 "БХВ-Петербург", 191036, Санкт-Петербург, Гончарная ул , 20 Отпечатано в ОАО «Можайский полиграфический комбинат» 143200, Россия, г Можайск, ул Мира, 93. www.oaompk га, тел (495) 745-84-28, (49638) 20-685 ISBN 978-5-9775-4068-1 © °°о "БХВ", 2020 © Оформление ООО "БХВ-Петербург", 2020
Оглавление Глава 1. Ознакомительная 1 1.1. О чем расскажет эта книга? 1 1.2. Электрическая безопасность — это важно! 4 1.3. Обратная связь 4 ЧАСТЬ I. НЕОБХОДИМОЕ ОБОРУДОВАНИЕ И ПРОГРАММЫ 5 Глава 2. Платформы Arduino и ESP8266 7 2.1. Платы контроллеров Arduino 7 2.1.1. Arduino Nano 8 2.1.2. Arduino Mini 9 2.1.3. Arduino UnoR3 10 2.1.4. Arduino Mega 2560 R3 11 2.2. Однокристальная система ESP8266 12 2.2.1. Основные технические характеристики микросхемы ESP8266 12 2.2.2. Модули и платы ESP8266 13 2.2.3. Особенности эксплуатации ESP8266 15 2.3. Среда разработки Arduino IDE 16 2.3.1. Установка Arduino IDE 16 Установка для ОС Windows 16 Установка альтернативных версий IDE 16 Установка для ОС Linux 16 Установка для macOS 17 2.3.2. Установка библиотек Arduino 18 Автоматическая установка библиотеки 18 Установка библиотеки вручную 18 2.3.3. Установка расширения ESP8266 для Arduino IDE 19 2.3.4. Особенности программирования ESP8266 19 Порты и прерывания 19 Организация задержек 20 Поддержка интерфейсов 12С и SPI 20
Оглавление Глава 3. Интерфейсы обмена данными 21 3.1. Согласование логических уровней 22 3.2. Последовательный интерфейс UART 23 3.2.1. Конвертер интерфейсов USB-UART 24 3.2.2. Встроенный класс Serial 26 Проблемы и ошибки при работе с последовательным портом 27 3.2.3. Программные порты SoftwareSerial 27 3.2.4. Терминал последовательного порта Termite 28 3.3. Последовательная шина 12С 29 3.3.1. Библиотека Wire 30 3.4. Последовательная шина 1-Wire 33 3.4.1. Библиотека One Wire 34 3.5. Последовательный интерфейс SPI 36 3.5.1. Библиотека SPI 37 3.6. Подключение по Bluetooth 39 3.6.1. Модули Bluetooth НС-06 и НС-05 40 Если модуль не отвечает на команду AT 42 Настройка модуля НС-05 42 3.6.2. Настройка подключения Bluetooth в Windows 10 43 Адаптер USB-Bluetooth 44 Включение адаптера Bluetooth и добавление устройства 45 3.6.3. Утилита Bluetooth Serial Terminal 48 Глава 4. Подключение Arduino к сети Интернет 50 4.1. Подключение к проводной сети Ethernet 50 4.1.1. Модуль Ethernet ENC28J60 51 4.1.2. Шилд Ethernet для Arduino Uno и Arduino Mega 55 4.2. Беспроводное подключение по Wi-Fi 58 4.2.1. Подключение контроллера ESP8266 к сети Wi-Fi 59 4.2.2. Сетевой шилд Dragino Yun.. 61 Питание шилда Dragino Yun 62 Функции кнопки сброса Dragino Yun 62 Добавление платы Dragino Yun в Arduino IDE 62 Подключение шилда к компьютеру для настройки 63 Определение типа базовой платы 65 Загрузка скетча через сеть из Arduino IDE 66 Подключение к Wi-Fi и вывод сообщений в консоль Linux 67 Глава 5. Визуализация данных 70 5.1. Построение графиков на компьютере 70 5.1.1. Встроенный плоттер Arduino IDE 71 5.1.2. Графопостроитель Serial Port Plotter 73 5.1.3. Графопостроитель FlexiPlot 75 Дополнительные настройки рабочего окна графика 77 Встроенный терминал 78
Оглавление Рисование столбчатых диаграмм 78 Динамические диаграммы 80 5.1.4. Arduino плюс Excel — сбор и хранение данных 81 Установка расширения на компьютер 82 Запуск расширения 82 Рабочее окно и органы управления 83 Формат строки данных Arduino 84 Команды настройки и передачи данных 85 Специальные команды и управление 85 Рабочая книга Excel 87 Прочие команды 87 Демонстрационный скетч PLX-DAQ 88 5.2. Онлайновая приборная панель Adafruit 10 91 5.2.1. Учетная запись и потоки данных 92 Получение главного ключа 92 Создание групп и потоков 93 Настройка групп и потоков 95 5.2.2. Создание приборной панели 96 5.2.3. Установка библиотек 100 5.2.4. Подключение к сервису Adafruit 10 по Wi-Fi 101 5.2.5. Подключение к сервису Adafruit 10 по Ethernet 104 5.3. Дисплейные модули в проектах Arduino 107 5.3.1. Графические библиотеки Arduino 108 Графическое ядро Adafruit GFX 109 Система координат дисплея 109 Цвет пиксела 110 Графические примитивы 111 Поворот экрана 114 5.3.2. Дисплейный модуль OLED 128^64 115 Подключение OLED-дисплея к плате Arduino 116 Библиотека OLED-дисплея 117 5.3.3. Дисплейные модули TFT SPI 128х 160 и 240^320 119 Подключение к плате Arduino дисплея TFT SPI 128x160 121 Назначение быводов дисплея TFT SPI 128x160 121 Пример кода с библиотекой Adafruit ST7735 122 Подключение к плате Arduino дисплея TFT SPI 240x320 123 Назначение выводов дисплея TFT SPI 240x320 124 ' Пример кода с библиотекой Adafruit ILI9341 124 5.3.4. Универсальный дисплейный шилд 125 ЧАСТЬ П. ТЕОРИЯ И ПРАКТИКА 127 Глава 6. Аналоговый оптический пульсометр 129 6.1. Принцип действия оптического пульсометра 129 6.2. Погрешности измерения ЧСС оптическим методом 132
_W Оглавление 6.3. Простой оптический сенсор 133 6.4. Пульсометре OLED-дисплеем 138 6.5. Пульсометр с цветным TFT-дисплеем 141 6.6. Задания для самостоятельной работы 145 6.7. Опыты с пульсометром 145 6.7.1. Опыте наложением жгута 145 6.7.2. Опыт с реакцией капилляров на температуру 146 6.7.3. Опыт с частотой и глубиной дыхания (рефлекс Геринга) 146 6.7.4. Рефлекс Ортнера 146 6.7.5. Клиностатический рефлекс Даниелополу 146 6.7.6. Ортостатический рефлекс Превеля 146 6.7.7. Опыте физической нагрузкой 147 6.8. Информация для любознательных 147 Глава 7. Шагомер на акселерометре ADXL335 148 7.1. Интегральный аналоговый акселерометр ADXL335 148 7.2. Подключение ADXL335 к плате Arduino Uno 149 7.3. Подключение шагомера к плоттеру FlexiPlot no Bluetooth 152 7.4. Простой шагомер с OLED-дисплеем 157 7.4.1. Определение средней длины шага 158 7.4.2. Определение расхода калорий 158 7.5. Задания для самостоятельной работы 161 Глава 8. Бесконтактное измерение температуры тела 162 8.1. Принцип действия и устройство инфракрасного пирометра 163 8.2. Подключение сенсора MLX90615 к плате Arduino 164 8.2.1. Проверка работоспособности сенсора 165 8.3. Особенности бесконтактного измерения температуры 166 8.4. Пирометре OLED-дисплеем и настройкойКИ 168 8.5. Задания для самостоятельной работы 172 Глава 9. Измеритель интенсивности ультрафиолетового излучения 173 9.1. Диапазоны и свойства ультрафиолетового излучения 173 9.2. Устройство и принцип работы сенсора VEML6075 175 9.3. Индекс УФ-излучения 177 9.4. Измеритель интенсивности УФ-излучения с OLED-дисплеем 178 9.4.1. Задания для самостоятельной работы 182 9.5. Онлайн-мониторинг солнечной активности 182 9.6. Опыты с измерителем УФ-излучения 188 9.6.1. Опыт с измерением УФ-проницаемости оконных стекол 189 9.6.2. Опыте измерением УФ-проницаемости пластиков 190 9.6.3. Опыт с отражением УФ-излучения от песка и воды 190 9.6.4. Опыт с проверкой качества солнцезащитных очков 190 9.6.5. Опыт с проверкой качества солнцезащитных кремов 191
Оглавление VH_ Глава 10. Измерение электрической активности кожи 192 10.1. Что такое электрическая активность кожи? 192 10.2. Модули измерителя ЭАК 193 10.3. Самодельные контакты сенсора ЭАК 194 10.4. Подключение модуля измерителя ЭАК к плате Arduino Uno R3 196 10.4.1. Электрическая безопасность — это важно! 196 10.4.2. Подключение к аналоговому порту 196 Пример чтения графика ЭАК 199 10.4.3. Подключение к шине SPI 201 Нужен ли TFT-дисплей для измерителя ЭАК? 204 10.5. Опыты с измерителем ЭАК 205 10.5.1. Опыт с глубоким дыханием 205 10.5.2. Опыт с мускульным напряжением 205 10.5.3. Опыт с воздействием температуры 205 10.5.4. Опыт с расположением электродов 206 10.5.5. Опыт с эффектом расслабления 206 10.5.6. Опыт с воздействием боли 206 10.5.7. Опыт с воздействием страха 206 10.5.8. Опыт с адаптацией и восстановлением 206 10.5.9. Опыт со словами и ассоциациями 207 10.5.10. Опыт с тревожным ожиданием 207 10.5.11. Опыт с тревожной реакцией 207 10.5.12. Опыт с мыслительным усилием 208 10.5.13. Опыте загадыванием числа 208 10.5.14. Опыт с обусловленным откликом 208 Глава 11. Цифровой пульсоксиметр 209 11.1. Принцип работы и устройство сенсора МАХЗ 0102 210 11.1.1. Устройство микросхемы МАХ30102 212 11.1.2. Основные технические характеристики пульсоксиметра МАХЗ 0102 213 11.2. Подключение МАХ30102 к плате Arduino Uno 214 11.2.1. Установка библиотеки пульсоксиметра 215 11.2.2. Проверка и настройка пульсоксиметра 215 11.2.3. Встроенный датчик приближения 218 11.3. Измеритель частоты пульса и сатурации крови 220 Глава 12. Датчик общего качества воздуха 224 12.1. Устройство и характеристики сенсора CCS811 224 12.1.1. Основные технические характеристики датчика качества воздуха CCS811 226 12.1.2. Внимание: особенности эксплуатации сенсора 227 12.2. Модуль расширения CCS811 228 12.2.1. Назначение выводов модуля 228 12.2.2. Установка библиотеки Arduino 229 12.3. Подключение и проверка модуля 229
VIII Оглавление 12.4. Монитор качества воздуха с OLED-дисплеем 231 12.4.1. Опыты с измерителем качества воздуха 234 12.4.2. Задание для самостоятельной работы над проектом 234 12.5. Онлайн-мониторинг качества воздуха 235 12.5.1. Проблема совместимости ESP8266 и CCS811 237 12.5.2. Задание для самостоятельной работы 241 Глава 13. Измерение пыльности и дымности воздуха 242 13.1. Датчик пыли SHARP GP2Y1014AU0F 243 13.1.1. Основные технические характеристики датчика пыли GP2Y1014AU0F 244 13.1.2. Воздушный поток через датчик 245 13.1.3. Управление подсветкой 245 13.1.4. Назначение выводов датчика пыли 246 13.1.5. Монтаж датчика пыли 246 13.2. Подключение датчика пыли к плате Arduino 247 13.3. Демонстрационный скетч и калибровка датчика 248 13.3.1. Начальное напряжение и калибровка 251 13.4. Определение наличия дыма в воздухе 251 13.4.1. Построение диаграммы в таблице Excel 254 13.4.2. Задания для самостоятельной работы 260 Глава 14. Шагомер на цифровом акселерометре LIS2DS12 261 14.1. Назначение и функции акселерометра LIS2DS12 262 14.1.1. Основные технические характеристики акселерометра LIS2DS12 262 14.1.2. Встроенные функции акселерометра LIS2DS12 262 14.2. Модуль акселерометра LIS2DS12 263 14.2.1. Назначение выводов модуля 264 14.3. Подключение и проверка модуля 264 14.4. Шагомер с OLED-дисплеем 268 14.5. Задания для самостоятельной работы 272 Глава 15. Трехточечный электрокардиограф 273 15.1. Фазы кардиограммы 274 15.2. Назначение и расположение электродов 275 15.3. Модуль электрокардиографа AD8232 276 15.3.1. Назначение выводов модуля ЭКГ 277 15.3.2. Электрическая безопасность — это важно! 279 15.3.3. Подключение кардиографа к Arduino Uno 279 15.4. Кардиомонитор с цветным TFT-дисплеем 283 15.5. Задания для самостоятельной работы 287 Глава 16. Измеритель скорости пульсовой волны 288 16.1. Схема и макет измерительного устройства 290 16.2. Измерение скорости пульсовой волны 296 16.3. Задания для самостоятельной работы 297
Оглавление IX_ Глава 17. Измерение биопотенциала мышц 298 17.1. Изготовление и подключение электродов для миографии 299 17.2. Измерение биопотенциала бицепса 300 17.3. Миография в прикладных проектах 303 17.3.1. Переменный волнообразный сигнал 304 17.3.2. Нестабильный сигнал с помехами 304 17.3.3. Необходимость значительных аппаратных и вычислительных ресурсов 304 ПРИЛОЖЕНИЯ 307 Приложение 1. Содержимое электронного архива 309 Приложение 2. Источники питания для проектов Arduino 312 П2.1. Автономное питание макетов иустройств 313 112.1.1. Источник питания на одной батарее ААА '. 314 П2.1.2. Заряжаемый источник питания на литий-полимерной батарее 315 Модуль повышающего преобразователя 316 Модуль зарядного устройства Li-Po 316 Литий-полимерный аккумулятор 317 Схема подключения и монтаж 318 Приложение 3. Коэффициенты излучения поверхности различных материалов 320 Предметный указатель 323
ГЛАВА 1 Ознакомительная Уважаемые читатели! Эта книга посвящена, пожалуй, самым ценным для нас объектам исследований — человеческому организму и окружающей среде, в которой он обитает. Сегодня можно без труда и по доступной цене приобрести современные интеграль- ные сенсоры, которые совсем недавно применялись только в сложном профессио- нальном оборудовании. Достаточно подключить эти сенсоры к плате Arduino или ESP8266 — и можно проводить увлекательные и безопасные опыты с измерением параметров человеческого организма и окружающей среды! Мы постарались подготовить для вас книгу, которая станет полным руководством по разработке любительских проектов: начиная от выбора подходящей платы Arduino и заканчивая средствами визуализации результатов измерений. Если вы начинающий любитель или разработчик, то материал глав первой части книги по- служит вам настольным справочником при работе над различными проектами. Опытные же разработчики найдут во второй части книги полезные примеры ис- пользования современных сенсороб и советы по решению проблем. При подготовке описаний проектов автор намеренно оставлял читателям простран- ство для самостоятельного творчества и размышлений. Большинство описаний до- полнено заданиями для самостоятельной работы и перечнем опытов. 1.1. О чем расскажет эта книга? Первая часть книги — подготовительная. Опытные пользователи могут пропустить отдельные главы этой части и обращаться к ним по мере необходимости. ♦ Во второй главе мы знакомим читателя с наиболее популярными платами плат- форм Arduino и ESP8266 и рассказываем, как установить среду разработки Arduino IDE и добавить в нее различные библиотеки и расширения. ♦ В третьей главе мы рассказываем о различных протоколах и шинах обмена данными. Вы будете подключать к плате контроллера сенсоры и модули расши- рения, которые используют разные шины данных: I2C, SPI, 1-Wire. Следует
2 Глава 1 знать, как работают эти шины и как реализовать обмен данными в коде про- граммы. Отдельно говорится о настройке беспроводного соединения с компью- тером по Bluetooth. ♦ В четвертой главе мы говорим о различных способах подключения плат Arduino и ESP8266 к сети Интернет для передачи данных на облачный сервер или в другие онлайновые сервисы. ♦ В пятой главе рассказано о том, как простыми средствами визуализировать дан- ные. Это важный этап работы над проектом! На самом деле исследования и опыты не заканчиваются после получения данных от сенсора. Сами по себе эти данные ничего не значат до тех пор, пока они не обработаны и не представлены в доступном для человека виде. Зачастую получателем данных является непод- готовленный пользователь, и ему нужно показать понятные графики, шкалы и числа. Вторая часть книги содержит описание теоретических основ предметов измере- ний, практических проектов и опытов с макетами измерительных устройств. ♦ В главе 6 рассказано о физических принципах измерения частоты пульса опти- ческим методом и приведено описание простого пульсометра на основе анало- гового сенсора. Читатель изготовит макет портативного пульсометра с OLED- дисплеем, а также более продвинутый пульсометр с цветным дисплеем. ♦ В главе 7 на примере простого аналогового шагомера рассказано о том, как раз- рабатываются устройства мониторинга. Читатель научится анализировать «сы- рые» результаты измерений и на их основе создавать программу для обработки полученных данных. В результате получится простой и надежный шагомер с OLED-дисплеем. ♦ В главе 8 мы изучаем физические принципы бесконтактного измерения темпера- туры и создаем простой бесконтактный термометр-пирометр для дистанционно- го измерения температуры тела и окружающих предметов. ♦ В главе 9 мы продолжаем заниматься измерением интенсивности оптических излучений. Мы обсудим, какое влияние на человеческий организм оказывает ультрафиолетовое излучение с различной длиной волны, и построим измеритель интенсивности излучения в диапазонах А и В. Затем мы подключим измеритель к сети Интернет и создадим онлайновую приборную панель для дистанционного мониторинга интенсивности излучения. ♦ В главе 10 мы изучаем измерение электрической активности кожи и учимся расшифровывать результаты. Это очень увлекательная тема — ведь именно из- меритель электрической активности кожи лежит в основе знаменитого и слегка таинственного «детектора лжи». Описание проекта дополнено большим переч- нем опытов — включая эксперименты, которые придуманы профессиональными психологами. При наличии определенного навыка исследователь-любитель сможет по форме графика на дисплее компьютера угадывать слова, предметы и события, о которых думает подопытный. ♦ В главе 11 мы возвращаемся к теме оптической пульсометрии, но теперь будем измерять уровень насыщения крови кислородом. Как обычно, перед началом
Ознакомительная работы с макетом познакомимся с физическими принципами исследуемого яв- ления. В отличие от проекта из главы 6, в этом проекте использован современ- ный интегральный сенсор для профессионального оборудования. ♦ В главе 12 рассказано об измерении общего качества воздуха и углеродного эквивалента. Это универсальные параметры, которые характеризуют общий уровень загрязненности воздуха органическими примесями и степень вреда окружающей среде из-за парникового эффекта. Прибор, макет которого мы по- строим, незаменим для контроля безопасности вдыхаемого воздуха, особенно в производственных помещениях и вблизи химических предприятий. Для этого проекта также предусмотрено подключение к сети Интернет и удаленный мони- торинг через онлайн-панель. ♦ В главе 13 мы продолжаем исследовать качество воздуха и приступаем к работе над проектом измерителя концентрации частиц пыли и дыма в окружающем нас пространстве. В описании этого проекта вновь приведен пример разработки прошивки устройства на основе анализа «сырых» данных. ♦ В главе 14 мы возвращаемся к проекту шагомера, но за основу берем современ- ный интегральный акселерометр со встроенным сигнальным процессором. Этот сенсор оснащен встроенными функциями цифровой обработки сигнала и под- счета количества шагов. Внешнему контроллеру достаточно лишь прочитать готовое значение из регистра счетчика и отобразить его на дисплее. Проект на- глядно демонстрирует возможности современных интегральных сенсоров. ♦ В главе 15 мы изучаем электрокардиографию. Благодаря наличию специальной микросхемы электрокардиографа, теперь можно даже в домашних условиях из- готовить простой кардиомонитор на основе контроллера Arduino и недорогого модуля расширения. ♦ В главе 16 мы объединяем измеритель частоты пульса из главы 6 с кардиомони- тором из главы 15 и получаем измеритель скорости пульсовой волны. Это важ- ный параметр, характеризующий состояние сердечно-сосудистой системы чело- века. Обычно для измерений применяется сложное лабораторное оборудование, но мы наглядно продемонстрируем, что базовые измерения можно выполнить даже в домашних условиях при помощи платформы Arduino и модулей расши- рения. ♦ В главе 17 мы изучаем технологию измерения биологических потенциалов, воз- никающих при работе мышц человеческого тела. В качестве измерительного устройства мы используем модуль электрокардиографа, с которым работали в главе 15. Несмотря на кажущуюся простоту проекта, вычислительные требова- ния к проекту лежат на пределе возможностей платформы Arduino, поэтому мы можем выполнить только простые измерения, а для дальнейшего развития про- екта необходимо перейти на более мощную платформу. Исходные коды программ (листинги), приведенные в книге, можно найти в сопро- вождающем ее электронном архиве (см. приложение 7). Электронный архив выло- жен на FTP-сервер издательства «БХВ-Петербург» по адресу: ftp://ftp.bhv.ru/ 9785977540681.zip. Ссылка на архив доступна и со страницы книги на сайте www.bhv.ru.
4^ Глава 1 В приложении 2 приведены данные об источниках питания для проектов Arduino, а в приложении 3 — таблица коэффициентов излучения поверхности различных материалов. 1.2. Электрическая безопасность — это важно! Все устройства и опыты, о которых рассказано в книге, абсолютно безопасны для здоровья. Напряжение питания всех устройств не превышает 5 вольт. Поэтому работать с макетами устройств могут даже школьники младшего возраста. Тем не менее при работе с устройствами и макетами, подключенными к сетевому источнику питания, в том числе при подключении к стационарному компьютеру по USB, существует некоторая опасность поражения электрическим током. Это может случиться при определенном стечении обстоятельств, связанных с неисправностью заземления в здании или повреждением изоляции в источнике питания. Еще опаснее ситуация, когда из-за ошибок монтажа электропроводки линия «фазы» в розетке оказывается подключенной к заземляющему выводу розетки, а устройст- во защитного отключения в домашнем электрощитке отсутствует. В этом случае на корпусе компьютера и на общем проводе макета может присутствовать полное напряжение 220 вольт относительно заземленных предметов. Работая над проектами из этой книги, вы будете подключать к своему телу измери- тельные электроды, которые обеспечивают очень хороший контакт с кожей. Осо- бенно важно, что, экспериментируя с электрокардиографом, вы будете подключать электроды непосредственно в области сердца. В такой ситуации нельзя полагаться на исправность заземления и правильность монтажа электросети в квартире или лаборатории! Необходимо обеспечить надежную гальваническую развязку между макетом устройства и компьютером. Разумеется, если вы подключаете макет уст- ройства к ноутбуку с батарейным питанием, дополнительная развязка не нужна. Но если вы работаете на настольном компьютере с сетевым питанием, то для обмена данными с компьютером используйте беспроводное соединение по Bluetooth, a устройство питайте от батарейного источника питания. Итак, вот основные правила электробезопасности при работе с устройствами, электроды которых подключаются непосредственно к телу человека: 1. Организуйте беспроводное соединение по Bluetooth. 2. Используйте автономное питание от батарейного источника. 3. Перед подключением провода USB для записи прошивки в контроллер Arduino отключите электроды от тела! 1.3. Обратная связь Автор и редакторы издательства будут признательны за ваши отзывы, советы и замечания по содержанию этой книги. Мы обязательно учтем их при подготовке следующих изданий. Пишите по адресу mail@bhv.ru или непосредственно автору по адресу valeriy.yatsenkov@gmail.com.
ЧАСТЬ I Необходимое оборудование и программы Глава 2. Платформы Arduino и ESP8266 Глава 3. Интерфейсы обмена данными Глава 4. Подключение Arduino к сети Интернет Глава 5. Визуализация данных
ГЛАВА 2 Платформы Arduino и ESP8266 Как вы думаете, почему относительно несложные и маломощные микроконтрол- лерные платы Arduino и ESP8266 приобрели невероятную всемирную популяр- ность? Разумеется, низкая цена имеет свое значение. Но все-таки основная причина попу- лярности состоит в том, что центральная плата — мы будем называть ее «контрол- лер» — является универсальным вычислителем, к которому можно без труда под- ключить модули расширения, которые выполняют различную работу. Некоторые модули расширения устроены сложнее, чем контроллер. Но даже в этом случае начинающему разработчику достаточно потратить несколько минут на со- единение модуля с контроллером, чтобы получить работающее устройство. Затем можно приступать к увлекательным экспериментам, попутно изучая принцип рабо- ты различных сенсоров и прочих периферийных устройств. Если собрать вместе платы, модули, описания, исходные коды, язык и среду про- граммирования, то получится техническая платформа. На основе платформы раз- работчики создают свои проекты и могут быть уверены в совместимости модулей и программ внутри одной платформы. Среди начинающих разработчиков особенно популярны две платформы: Arduino на основе микроконтроллеров Atmel и ESP8266 на основе системы на чипе ESP8266 со встроенным блоком Wi-Fi. Эти платформы во многом взаимно совместимы на уровне исходного кода и модулей расширения. О работе с современными модулями расширения рассказано в следующих главах книги. А сейчас приглашаем новых пользователей Arduino ближе познакомиться со средой разработки Arduino IDE и аппаратной частью платформ Arduino и ESP8266. 2.1. Платы контроллеров Arduino Для большинства любительских проектов начального и среднего уровня, включая проекты из этой книги, достаточно приобрести одну из трех недорогих плат: Arduino Nano, Arduino Uno или Arduino Mini. Все три платы реализованы на микро- контроллере ATmega328. При использовании любой из этих плат нет необходимо-
Часть I. Необходимое оборудование и программы сти вносить изменения в исходные коды программ или в схему устройства — дос- таточно подключить соединительные провода к выводам контроллера с нужными наименованиями в соответствии со схемой проекта. Если ресурсов микроконтроллера ATmega328 не хватает для вашего проекта, вос- пользуйтесь платой Arduino Mega 2560 R3, созданной на основе более мощного микроконтроллера ATmega2560. В этом случае могут потребоваться незначитель- ные изменения исходного кода скетчей. Схемы расположения выводов всех упомянутых в книге плат несложно найти в Интернете, выполнив в справочной системе соответствующий запрос. 2.1.1. Arduino Nano Контроллер Arduino Nano (рис. 2.1)— это «рабочая лошадка» любителей электро- ники. С обратной стороны платы установлены линейный стабилизатор +5 В и кон- вертер USB-UART. Микросхема конвертера содержит встроенный стабилизатор +3,3 В. Этим напряжением можно питать внешние трехвольтовые модули с током потребления до 50 мА. Преимуществами этой версии являются компактность и возможность установки непосредственно в беспаечную макетную плату. Рис. 2.1. Плата Arduino Nano Основные технические характеристики платы Arduino Nano ♦ Контроллер: ATmega328P ♦ Рабочее напряжение: 5 В ♦ Внешнее питание: 7... 12 В ♦ Тактовая частота: 16 МГц ♦ Цифровые порты: 14 (из них 6 ШИМ) ♦ Аналоговые входы: 8(10 битов АЦП) ♦ Предельный ток порта: 40 мА ♦ Память программ: 32 Кбайт (бутлоадер 0,5 Кбайт)
Глава 2. Платформы Arduino и ESP8266 ♦ Память SRAM (ОЗУ): 2 Кбайт ♦ Память EEPROM: 1 Кбайт ♦ Размеры: 45x18 мм ♦ Вес: 5 г Внимание! Внешнее нерегулируемое напряжение питания в диапазоне +7...+12 В следует пода- вать только на вход VIN! При этом на выводах 5V и 3.3V появятся соответствующие стабилизированные напряжения, которые можно использовать для питания внешних элементов схемы с суммарным потребляемым током до 50 мА. Стабилизированное внешнее напряжение +5 В можно подавать напрямую на вывод 5V. 2.1.2. Arduino Mini Arduino Mini (рис. 2.2) — это вариант платы с минимальным количеством внешних компонентов. Она не содержит конвертер USB-UART, поэтому для соединения с компьютером и программирования понадобится качественный внешний конвер- тер (см. разд. 3.2.1 и 4.1.1). Официальная плата выпускается в двух вариантах рабо- чего напряжения и тактовой частоты: 5 В (16 МГц) и 3,3 В (8 МГц). От рабочего напряжения зависит микросхема стабилизатора, установленная на плате. Китайские производители выпускают несколько вариантов плат, которые различаются распо- ложением выводов. Плату Arduino Mini удобно монтировать непосредственно на поверхность печатной платы готового устройства. В сочетании с низкой ценой это делает плату незаме- нимым компонентом многих любительских и мелкосерийных проектов. Рис. 2.2. Плата Arduino Pro Mini Основные технические характеристики платы Arduino Mini ♦ Контроллер: ATmega328P ♦ Рабочее напряжение: 5 В / 3,3 В ♦ Внешнее питание: 7... 12 В (RAW) ♦ Тактовая частота: 16 МГц / 8 МГц ♦ Цифровые порты: 14 (из них 6 ШИМ)
Часть I. Необходимое оборудование и программы ♦ Аналоговые входы: 6(10 битов АЦП) ♦ Предельный ток порта: 40 мА ♦ Память программ: 32 Кбайт (бутлоадер 0,5 Кбайт) ♦ Память SRAM (ОЗУ): 2 Кбайт ♦ Память EEPROM: 1 Кбайт ♦ Размеры: 33,6x17,8 мм ♦ Вес: 3,8 г Внимание! Внешнее напряжение питания в диапазоне +7...+12 В следует подавать только на вход RAW! Вывод VCC подключен непосредственно к линии питания микроконтрол- лера. Допускается подавать на него только стабилизированное напряжение +5 В или +3,3 В — в зависимости от модификации платы. Будьте внимательны при покупке платы и подключении внешнего конвертера USB-UART. 2.1.3. Arduino Uno R3 Плата Arduino Uno R3 (рис. 2.3) является третьей версией (Revision 3) самой попу- лярной платы Arduino Uno. Основное отличие платы Arduino Uno от Nano заключа- ется в монтажном факторе. Если Nano вставляют в макетную плату, то Uno сама является макетной платой. Для нее выпускают множество расширений (шилдов), которые совпадают по форме и вставляются в разъемы поверх основной платы. Кроме того, на плате Uno есть дополнительный разъем для внешнего источника питания напряжением 7... 12 В, электролитические конденсаторы в цепи питания и более сложная схема коммутации питания с автоматическим переключением между источниками. На плате установлен самовосстанавливающийся полимерный предо- хранитель, дополнительно защищающий порт USB компьютера от перегрузки. Рис. 2.3. Плата Arduino Uno R3
Глава 2. Платформы Arduino и ESP8266 11_ Основные технические характеристики платы Arduino Uno ♦ Контроллер: ATmega328P ♦ Рабочее напряжение: 5 В ♦ Внешнее питание: 7... 12 В ♦ Тактовая частота: 16 МГц ♦ Цифровые порты: 14 (из них 6 ШИМ) ♦ Аналоговые входы: 6(10 битов АЦП) ♦ Предельный ток порта: 40 мА ♦ Память программ: 32 Кбайт (бутлоадер 0,5 Кбайт) ♦ Память SRAM (ОЗУ): 2 Кбайт ♦ Память EEPROM: 1 Кбайт ♦ Размеры: 68,6x53,4 мм ♦ Вес: 25 г 2.1.4. Arduino Меда 2560 R3 Плата Arduino Mega 2560 R3 (рис. 2.4) реализована на микроконтроллере ATmega2560. По сравнению с предыдущими платами, Arduino Mega 2560 имеет больше цифровых и аналоговых портов, два аппаратных последовательных порта, увеличенный объем памяти. На плате установлен самовосстанавливающийся поли- мерный предохранитель, дополнительно защищающий порт USB компьютера от перегрузки. Благодаря большому количеству портов, к базовой плате можно под- ключать быстродействующие цветные дисплеи с параллельной восьмибитной ши- ной, при этом остается достаточно выводов для работы с другими периферийными устройствами. Разводка выводов платы выполнена так, чтобы к ней можно было подключить большинство модулей расширения, предназначенных для Arduino Uno R3. Рис. 2.4. Плата Arduino Меда 2560
t2 Часть I. Необходимое оборудование и программы Основные технические характеристики платы Arduino Mega 2560 ♦ Контроллер: ATmega2560 ♦ Рабочее напряжение: 5 В ♦ Внешнее питание: 7...12 В ♦ Тактовая частота: 16 МГц ♦ Цифровые порты: 54 (из них 15 ШИМ) ♦ Аналоговые входы: 16 ♦ Предельный ток порта: 40 мА ♦ Память программ: 256 Кбайт (бутлоадер 8 Кбайт) ♦ Память SRAM (ОЗУ): 8 Кбайт ♦ Память EEPROM: 4 Кбайт ♦ Размеры: 101,5x53,3 мм ♦ Вес: 37 г 2.2. Однокристальная система ESP8266 Однокристальная система, или система на кристалле (SoC, System-on-Chip), — это микросхема, объединяющая на одном кристалле несколько модулей с принципи- ально различными функциями и выполняющая задачи целого устройства. Как пра- вило, такая система содержит микропроцессорное ядро, встроенную память, внут- ренние шины данных и специфические функциональные модули. Микросхема ESP8266 является примером SoC, потому что состоит из микропро- цессора и функционального модуля Wi-Fi, выполненных на одном кристалле. Та- ким образом, на одной микросхеме можно выполнить законченное устройство, подключаемое к беспроводной сети Интернет. Изначально SoC ESP8266 разрабатывалась как микросхема для модулей Wi-Fi, подключаемых к другим микроконтроллерам. На практике оказалось, что возмож- ности встроенного процессора настолько велики, что в большинстве случаев позво- ляют обойтись вообще без внешнего микроконтроллера. Кроме разработки про- грамм в привычной среде Arduino IDE, для ESP8266 можно писать программы на языках Lua, MicroPython и Smart-JS и даже запускать их в среде простой операци- онной системы. 2.2.1. Основные технические характеристики микросхемы ESP8266 ♦ Процессор: одноядерный Tensilica L106 с тактовой частотой до 160 МГц ♦ Поддерживаемые стандарты WI-FI: 802.11 b / g / n ♦ Поддерживаемы типы шифрования: WEP, WPA, WPA2
Глава 2. Платформы Arduino и ESP8266 13_ ♦ Поддерживаемые режимы работы: Клиент (STA), Точка доступа (АР), Кли- ент+Точка доступа (STA+AP) ♦ Количество одновременных соединений TCP: 5 ♦ Напряжение питания: 1,7...3,6 В ♦ Потребляемый ток: до 215 мА (в зависимости от режима работы) ♦ Количество GPIO: 17 (количество доступных зависит от модификации модуля) ♦ Интерфейсы: ADC 10 битов, I2C, UART, SPI, PWM ♦ Внешняя Flash-память: от 512 Кбайт до 16 Мбайт ♦ Объем памяти данных (EEPROM): 80 Кбайт ♦ Объем памяти команд (RAM): 64 Кбайт 2.2.2. Модули и платы ESP8266 Микросхема ESP8266 выполнена в малогабаритном корпусе и в любительской практике используется только в виде готовых модулей с необходимыми внешними компонентами схемы (рис. 2.5). Но даже в таком виде модули редко применяются в любительских проектах, потому что их неудобно подключать к макетной плате. ESP-01 ESP-02 ESP-03 ESP-04 ESP-05 ESP-06 ESP-07 ESP-08 ESP-09 ESP-10 ESP-11 - ESP-12 ESP-13 ESP-14 Рис. 2.5. Стандартные модули на основе ESP8266 Производители оборудования для разработчиков-любителей обычно устанавлива- ют стандартный модуль ESP-12 на материнскую плату, оснащенную разъемами, стабилизатором питания, конвертером USB-UART и прочими вспомогательными компонентами. Сейчас на рынке представлено бесчисленное множество конструк-
14 Часть I. Необходимое оборудование и программы ций плат ESP8266, и начинающему разработчику сложно выбрать оптимальный вариант. Мы рекомендуем приобрести одну из двух наиболее удобных и популярных плат: WeMos D1 (рис. 2.6) или NodeMCU (рис. 2.7). Плата WeMos D1 по форме и расположению выводов максимально совместима с платой Arduino Uno R3, поэтому к ней можно подключить большинство модулей расширения Arduino. Рис. 2.6. Плата WeMos D1 Рис. 2.7. Плата NodeMGU
Глава 2. Платформы Arduino и ESP8266 75 Плата NodeMCU изначально была разработана для открытого проекта NodeMCU, но, благодаря удачной конструкции, стала очень популярной среди любителей. Эта плата предназначена для установки в беспаечную макетную плату и тоже содержит все необходимое для автономной работы. 2.2.3. Особенности эксплуатации ESP8266 При разработке устройств на основе ESP8266 — особенно при переносе готовых проектов с платформы Arduino— необходимо учитывать некоторые специфиче- ские особенности микросхемы. ♦ Максимальная нагрузка на порт. В отличие от плат Arduino, допускающих нагрузку на порт до 40 мА, что позволяет не задумываясь подключать к ним малогабаритные сверхъяркие светодиоды и прочую подобную нагрузку, порты ESP8266 выдерживают ток не более 14 мА, поэтому их можно перегрузить даже обычным светодиодом. Следует тщательно ограничивать нагрузку на порты плат ESP8266 или применять ключевые транзисторы. ♦ Согласование логических уровней. Согласно спецификации производителя, только линии UART (Tx, Rx) допускают работу с напряжениями пятивольтовой логики. Подача на остальные выводы логических уровней, превышающих на- пряжение питания микросхемы, с большой вероятностью выведет ее из строя. При совместном использовании модулей с разным напряжением питания необ- ходимо применять согласование логических уровней (см. разд. 4.1). ♦ Режим программирования. Для перевода микросхемы в режим записи про- шивки необходимо установить низкий уровень на входе GPIO0 и кратковре- менно подать низкий уровень на вход сброса RESET (либо держать вывод GPIO0 соединенным с общим проводом в момент включения питания). Микро- схема перейдет в режим программирования и коротко мигнет встроенным све- тодиодом, подключенным к выводу GPIO2. После этого можно вернуть высо- кий уровень на вход GPIO0. На большинстве плат, включая WeMos D1 и NodeMCU, смонтирована схема из двух транзисторов для автоматического пе- рехода в режим программирования по сигналам DTR и RTS от конвертера USB- UART. Если на вашей плате такой схемы нет, или вы используете стандартный модуль ESP-jcjc (см. рис. 2.5), то вам придется вручную переводить микросхему в режим записи. ♦ Температурный режим. В режиме максимальной мощности пиковый потреб- ляемый ток может достигать 240 мА, а корпус микросхемы в условиях недоста- точного отведения тепла — нагреваться до 80 °С. Несмотря на то, что микросхема может работать при температуре до +125 °С, перегрев модуля может привести к росту погрешности синтезатора частоты трансмиттера Wi-Fi, а циклические тепловые перегрузки ускоряют выход модуля из строя из-за нарушения пайки. ♦ Требования к монтажу. Микросхема чувствительна к наводкам сигнала на ли- нии портов от собственной антенны Wi-Fi. Длинные соединительные проводни- ки между платой на основе ESP8266 и внешними устройствами могут привести
16_ Часть I. Необходимое оборудование и программы к нестабильной работе, что выражается в зависании и самопроизвольной переза- грузке микросхемы. 2.3. Среда разработки Arduino IDE Важную роль в успехе платформы Arduino сыграла интегрированная среда разра- ботки Arduino IDE (Integrated Development Environment). По аналогии с аппаратной частью, среда Arduino IDE тоже устроена по модульному принципу — в среду раз- работки легко добавляются описания новых контроллеров и библиотеки сторонних разработчиков. Основные библиотеки встроены в среду по умолчанию. Для про- граммирования применяется адаптированный вариант языка Processing. Среда состоит из редактора исходного кода с подсветкой синтаксиса, компилятора AVR-GCC, средства загрузки прошивок AVRdude, монитора последовательного порта и плоттера для рисования графиков. Пользователь может оставаться в среде Arduino IDE в течение всего цикла разработки — от первой буквы кода до отладки готового устройства. 2.3.1. Установка Arduino IDE Скачайте свежую версию Arduino IDE для своей операционной системы с сайта разработчика http://www.arduino.cc/en/Main/Software. Установка для ОС Windows Пользователям Windows для первой установки на компьютер рекомендуется вы- брать вариант Windows Installer. Кроме автоматической распаковки, он создаст нужные записи в реестре, ассоциирует файлы, имеющие расширение ino, с редакто- ром Arduino IDE, а также создаст специальный рабочий каталог для хранения фай- ла конфигурации и служебных файлов. Установка альтернативных версий IDE Установщик Windows Installer проверяет наличие других версий Arduino IDE и предлагает их удалить. Поэтому для установки старой версии (или нескольких раз- ных версий) необходимо скачать ZIP-архив, а не установщик, и развернуть его в отдельный каталог. Затем можно создать на рабочем столе ярлыки для запуска с указанием номера версии. При совместной работе над сложными проектами или тестировании чужих проек- тов рекомендуется использовать одинаковые версии IDE. При использовании раз- личающихся версий IDE возможна ситуация, когда скомпилированные прошивки будут отличаться по размеру, быстродействию или наличию скрытых ошибок. Установка для ОС Linux Раньше способ установки Arduino IDE зависел от версии Linux, а для пользователей Raspberry Pi вообще существовала отдельная инструкция. Новые сборки IDE со-
Глава 2. Платформы Arduino и ESP8266 17_ держат все необходимые скрипты для автоматической установки среды независимо от версии ОС. Вам нужно лишь правильно определить тип сборки ОС Linux, кото- рую вы используете: 32bit, 64bit или ARM — и скачать подходящую версию уста- новочного пакета по адресу: http://www,arduino.cc/en/Main/Software. Версия ука- зана в названии файла. Распакуйте архив в любой удобный вам каталог. Программа будет запускаться на выполнение из этого каталога. В процессе распаковки будет создан каталог с име- нем ardulno-1.8.x. Найдите в программе файл install.sh и щелкните на нем правой кнопкой мыши. В контекстном меню выберите пункт Run in Terminal. После короткого процесса установки на рабочем столе появится новый значок. Если в контекстном меню нет опции запуска скрипта, откройте терминал и перей- дите в каталог arduino-1.8.x (в нашем примере — версия IDE 1.8.7): cd arduino-1.8.7 ./install.sh Теперь среда Arduino IDE готова к запуску. Может случиться так, что при попытке записи прошивки в плату вы получаете сообщение об ошибке: Error opening serial port... Это означает, что нужно задать разрешения для работы с портом. Подключи- те свою плату к компьютеру. Введите в терминале команду: Is -I /dev/tty* В ответ вы получите строку наподобие такой: crw-rw 1 root dialout 188, Feb 16 13:22 ttyUSBl Строк может быть несколько, но нас интересуют только те, в которых содержится слово dialout. Они могут содержать как текст ttyUSBx, так и ttyACMx, где х — это номер порта, к которому подключена плата. Дата и время в строке указывают на время, когда вы подключили плату. Запомните наименование и номер порта и ука- жите его в настройках Arduino IDE. Теперь надо включить нового пользователя (себя) в группу dialout: sudo usermod -a -G dialout <ваше имя пользователя> Изменения начнут действовать только после выхода из системы и повторного вхо- да. Далее вы сможете загружать прошивки как обычно. Разумеется, для большинства версий Linux среду Arduino IDE можно установить из репозитория. Но при этом будет установлена далеко не самая последняя версия программы. Кроме того, вы будете лишены возможности выбора версии в случае особых требований к проекту. Установка для macOS Скачайте архив нужной версии Arduino IDE со страницы загрузки. Если вы исполь- зуете браузер Safari, то архив будет развернут автоматически. При использовании иного браузера архив придется развернуть самостоятельно. Скопируйте приложе- ние Arduino в каталог Applications (Программы). Значок Arduino появится в панели запуска программ LaunchPad. Вы можете также скопировать приложение в любой другой каталог и запускать оттуда.
Часть I. Необходимое оборудование и программы 2.3.2. Установка библиотек Arduino Библиотека Arduino — это набор стандартных функций для решения определенных прикладных задач. Как правило, это массово востребованные задачи: работа с дат- чиками, дисплеями, микросхемами внешней памяти, поддержка протоколов обме- на. Чтобы не тратить зря время и силы на повторное написание уже существующих программ, имеет смысл воспользоваться готовыми решениями. Обычно они много- кратно испытаны и отлажены членами творческого сообщества Arduino. Библиоте- ка может содержать примеры использования. Многие библиотеки написаны специалистами компаний, выпускающих электрон- ные модули и компоненты. Наиболее универсальные и востребованные библиотеки входят в состав среды Arduino IDE. Но рано или поздно вы столкнетесь с необхо- димостью добавить библиотеки, которых нет в стандартном наборе. Автоматическая установка библиотеки Библиотека может присутствовать во встроенном списке среды Arduino IDE, но требовать установку. Поэтому, прежде всего, обратимся к встроенному списку биб- лиотек. Перейдите в пункт меню Скетч | Подключить библиотеку | Управлять библиотеками и внимательно изучите список или воспользуйтесь поиском. Поиск работает по фрагменту слова из названия или описания библиотеки. Найдя нужную библиотеку, выделите ее в списке и нажмите кнопку Установка. Установленные библиотеки помечаются словом INSTALLED возле заголовка. Если библиотека отсутствует во встроенном списке, то разработчики обычно рас- пространяют ее в виде ZIP-архива. Скачайте архив библиотеки и не распаковывай- те его. Если имя архива содержит в названии фрагмент -master, удалите этот фраг- мент. Откройте пункт меню Скетч | Подключить библиотеку | Добавить ZIP-биб- лиотеку. Выберите архив библиотеки в диалоговом окне. Архив будет автоматиче- ски распакован в каталог libraries внутри вашего рабочего каталога Arduino IDE. Те- перь снова откройте меню Скетч | Подключить библиотеку. Название новой биб- лиотеки должно появиться в списке библиотек с пометкой INSTALLED. Использование библиотеки можно начинать сразу после установки. Установка библиотеки вручную При автоматической установке библиотеки разворачиваются в каталог My Documents\ Arduino\libraries\ (Windows) или Documents/Arduino/libraries/ (macOS, Linux) и доступны для всех версий Arduino IDE. Но библиотеки, как и обычные программы, иногда страдают несовместимостью с отдельными версиями IDE. Если установлено не- сколько версий Arduino IDE, а библиотеку надо установить только для одной из них, потребуется ручная установка. Закройте Arduino IDE. Распакуйте архив с библиотекой. Если каталог библиотеки содержит в названии фрагмент -master, удалите этот фрагмент. Откройте каталог, в который вы раньше установили нужную версию IDE. Найдите каталог libraries и
Глава 2. Платформы Arduino и ESP8266 19_ откройте его. Внутри должны находиться некоторые каталоги стандартных биб- лиотек. Поместите туда же каталог с вашей библиотекой. Запустите Arduino IDE и убедитесь, что новая библиотека появилась в списке. 2.3.3. Установка расширения ESP8266 для Arduino IDE Выберите пункт меню Файл | Настройки и вставьте в поле Дополнительные ссылки для Менеджера плат строку ссылки: http://arduino.esp8266.com/staging/package_esp8266com_index.json Если в поле для дополнительных ссылок уже есть другая запись, отделите ее запя- той. Теперь перейдите в меню Инструменты | Плата | Менеджер плат и дожди- тесь, пока менеджер плат соединится с ресурсами по указанной ссылке и обновит список плат. Затем найдите в списке плату esp8266 by ESP8266 Community (обыч- но в конце списка) и нажмите кнопку Установка. Теперь вы можете работать с платой на основе ESP8266 точно так же, как с любой платой Arduino. Обратите внимание, что в меню Файл | Примеры появился раздел с примерами для ESP8266. Кроме этого, автоматически установлена специальная библиотека ESP8266wiFi для поддержки функций беспроводного соединения. Расширение среды Arduino IDE, которое вы установили, представляет собой обертку (wrapper) для набора официальных функций API SDK, предоставляемых производителем микросхемы ESP8266. Когда в вашей программе совершается лю- бое действие, например запись логического уровня в порт ввода/вывода, на самом деле компилятор не генерирует собственный оригинальный код, а обращается к готовой функции API SDK и передает ей нужные параметры. Заслуга разработчи- ков расширения ESP8266 состоит в том, что они проделали за нас всю самую слож- ную работу, переведя обращения к API SDK на простой и понятный язык Processing для Arduino IDE. 2.3.4. Особенности программирования ESP8266 Простые программы, наподобие программ управления портами GPIO, будут рабо- тать на ESP8266 точно так же, как на оборудовании Arduino. Но если вы не будете учитывать аппаратные особенности ESP8266 при разработке более сложных про- грамм, то обязательно наткнетесь на «подводные камни», которые могут доставить много проблем. Нельзя забывать, что в микросхеме ESP8266, кроме процессорной части, имеется блок Wi-Fi, который «живет своей жизнью», занимает ресурсы про- цессора и требует отдельного внимания. В этом разделе мы уточним только те особенности программирования ESP8266, которые имеют прямое отношение к проектам из этой книги. Порты и прерывания Формально, вы можете обратиться в программе к любому из портов GPIO0 — GPIO16, но для свободного пользования доступны не все порты, т. к. часть выводов
Часть I. Необходимое оборудование и программы занята для служебных нужд. Количество линий портов, выведенных на внешние контакты платы, зависит от конструкции модуля, но некоторые порты заняты все- гда, либо их не рекомендуется использовать. В частности, порты GPIO1 и GPIO3 заняты под линии порта UART Тх и Rx. По этим линиям производится запись про- шивки, а также обмен последовательными данными с внешними устройствами. К выводу GPIO2 по умолчанию подключен встроенный светодиод большинства модулей. Однако в модуле ESP-01 светодиод подключен к порту GPIO1, поэтому невозможно одновременно управлять встроенным светодиодом и использовать этот последовательный порт. Порт GPIO0 служит для управления режимом программи- рования. Порт GPIO15 определяет режим загрузки с карты памяти SD и по умолча- нию в большинстве случаев соединен на плате с общим проводом. Порт GPIO16 (часто обозначаемый как DEEPSLEEP) используется для вывода микросхемы из режима пониженного энергопотребления. В таком случае он должен быть соединен с выводом RESET микросхемы. Во многих модулях это соединение выполнено на печатной плате, поэтому крайне нежелательно использовать GPIO16 для своих це- лей. Таким образом, не рекомендуется задействовать порты GPIOO, GPIO1, GPIO2, GPIO3, GPIO15 и GPIO16 для каких-либо иных целей, кроме назначенных по умол- чанию. Прерывания поддерживаются функциями attachinterrupt и detachinterrupt и мо- гут быть назначены на любой GPIO, кроме GPIO16. Организация задержек Функции delay () и deiayMicroseconds () работают аналогично одноименным функ- циям Arduino, при этом работа модуля Wi-Fi и стека TCP/IP не прерывается. По- этому функцию delay () иногда используют для того, чтобы приостановить выпол- нение скетча и дать возможность отработать модулю Wi-Fi. Специальные функции блока Wi-Fi и стека ТСРЛР обрабатывают события только в конце каждого цикла loop () вашего скетча либо во время задержки delay (). Если внутри цикла loop () есть фрагменты, которые выполняются дольше 50 миллисекунд, необходимо использовать функцию delay о, чтобы сохранить работоспособность стека Wi-Fi. Функция deiayMicroseconds () блокирует выполнение других задач, включая Wi-Fi, поэтому не рекомендуется использовать ее для организации задержек более 20 миллисекунд, — иначе сработает сторожевой таймер и перезагрузит микро- схему. Поддержка интерфейсов 12С и SPI Для интерфейса 12С (библиотека wire— см. разд. 3.3.1) реализован только режим ведущего с частотой до 450 кГц. Для всех модулей, кроме ESP-01, по умолчанию используются выводы 4 (SDA) и 5 (SCL). Выводы могут быть переназначены при ПОМОЩИ функции Wire.pins (int sda, int scl). Например: Wire.pins (3, 7). Библиотека spi (см. разд. 3.4.1) поддерживается почти полностью, за исключением полярности тактовых импульсов Clock Polarity (CPOL). Поэтому режимы spi_mode2 и spi_mode3 не работают. Но практически во всех любительских проектах они и не требуются.
ГЛАВА 3 Интерфейсы обмена данными Платформа Arduino привлекает разработчиков обширным выбором периферийных модулей и устройств, которые можно подключить к плате контроллера. При этом плата контроллера Arduino сама является периферийным устройством по отноше- нию к настольному компьютеру, планшету или смартфону. В общем случае, контроллер отправляет в периферийное устройство команды и данные, а устройство выполняет заданные действия и может вернуть ответные данные. Например, контроллер посылает в термометр команду выполнить измере- ние. Термометр выполняет команду и возвращает байты данных с числовым значе- нием температуры. Общение между устройством и контроллером происходит по согласованным пра- вилам, которые описывают параметры сигналов и логический порядок следования данных. Набор этих правил называется протоколом обмена данными. Реализация протокола на физическом уровне часто называется интерфейсом обмена. Следует понимать различие между интерфейсом обмена и форматом данных. Ин- терфейс — это способ передачи сигнала, согласованный на физическом уровне, а формат данных— это способ организации данных. Например, приемник GPS за- действует последовательный интерфейс UART. Используя аппаратный протокол в виде чередования логических уровней заданной длительности и амплитуды, он передает непрерывный поток форматированных текстовых данных, содержащих координаты и точное время. В этой главе говорится о базовых интерфейсах: I2C, 1-Wire, SPI и UART, которые применяются для внутреннего обмена данными в большинстве микроконтроллер- ных платформ, включая Arduino. Практически все современные микроконтроллеры оснащены аппаратной поддерж- кой основных интерфейсов. В среду разработки Arduino IDE встроены специальные библиотеки для них, которые не требуют установки.
22_ Часть I. Необходимое оборудование и программы 3.1. Согласование логических уровней Цифровые микросхемы оперируют логическими уровнями «ноль» (низкий уровень) и «единица» (высокий уровень). В зависимости от напряжения питания различают- ся и напряжения логических уровней ноля и единицы на выходах микросхем. У микросхем с пятивольтовым питанием напряжение логического ноля лежит в пределах 0...0,5 В, а напряжение логической единицы— в пределах 2,4...5 В. У микросхем с трехвольтовым питанием напряжение логического ноля также ле- жит в пределах 0...0,5 В, но напряжение логической единицы лежит в диапазоне 2,4...3,3 В. Все популярные платы Arduino питаются напряжением 5 В. Но многие совре- менные периферийные модули (сенсоры, дисплеи) питаются напряжением 3,3 В и работают с трехвольтовыми логическими уровнями. Что может произойти, если соединить выводы микросхем с разным рабочим на- пряжением? ♦ Выход трехвольтовой микросхемы соединяется с входом пятивольтовой. В этом случае схема будет нормально работать. Напряжения на выходе низко- вольтной части вполне достаточно, чтобы вход пятивольтовой микросхемы на- дежно определял уровень логической единицы. Рабочий диапазон логического нуля в любом случае совпадает. ♦ Выход пятивольтовой микросхемы соединяется с входом трехвольтовой. В этом случае уровень логической единицы на входе трехвольтовой микросхемы может превысить ее напряжение питания. Это с большой вероятностью приве- дет к перегрузке и выходу из строя низковольтной микросхемы! Существуют низковольтные микросхемы со встроенной защитой, устойчивые к превышению входного напряжения. В описании таких микросхем или модулей на их основе встречается текст «TTL tolerant» или «5V tolerant». Если вы не уверены в наличии такой защиты в вашей микросхеме, лучше применить согласование ло- гических уровней. Если сигнал передается в одном направлении — от высоковольтного выхода к низ- ковольтному входу, то для защиты от перенапряжения достаточно включить после- довательно в разрыв соединительной линии резистор сопротивлением 1 кОм. Сложнее обеспечить согласование уровней на двунаправленной линии — например, при обмене данными по шине 12С. В этом случае вам потребуется двунаправленный преобразователь уровней (рис. 3.1), выполненный на транзисторах или на специ- альной микросхеме. Для того чтобы преобразователь работал правильно, на него необходимо подавать оба питающих напряжения. При поиске в зарубежных интер- нет-магазинах ИСПОЛЬЗуЙте ключевые СЛОВа logic level converter ИЛИ logic level shifter.
Глава 3. Интерфейсы обмена данными 23 Рис. 3.1. Двунаправленные преобразователи логических уровней 3.2. Последовательный интерфейс UART UART (Universal Asynchronous Receiver-Transmitter, универсальный асинхронный приемопередатчик)— это самый старый, простой и популярный способ обмена данными в любительской электронике. Он используется при записи прошивок в отладочные платы Arduino, при обмене данными между микроконтроллерами и внешними модулями, при настройке модулей при помощи настольного компьютера и во многих других случаях. Строго говоря, UART — это общее название целого семейства последовательных протоколов, которые различаются по рабочему напряжению логических уровней и физическому носителю сигнала. Примернр десять лет назад в каждом компьютере был последовательный порт COM (Communication port) RS-232 для подключения периферийных устройств. Сейчас компьютеры с таким портом можно найти только в промышленном оборудовании, потому что RS-232 работает с логическими уров- нями +12 и -12 В. Инфракрасный порт IrDA тоже работает по протоколу семейства UART, но в качестве носителя сигнала используется оптический канал. Наибольшее распространение получила разновидность UART, работающая со стандартными уровнями трехвольтовой или пятивольтовой логики и позволяющая соединять устройства между собой напрямую. Практически все современные мик- роконтроллеры содержат встроенный аппаратный модуль UART или поддержива- ют его программную эмуляцию. Поэтому, если говорят об интерфейсе UART, по умолчанию подразумевается именно вариант со стандартными логическими уров- нями для прямого подключения к микроконтроллерам.
24 Часть I. Необходимое оборудование и программы Данные передаются по одному биту в заданный промежуток времени. Передача начинается со стартового бита и заканчивается стоповым битом и битом четно- сти. Скорость передачи измеряется в бодах (битах в секунду), иногда она называ- ется битрейт (bitrate, битовая скорость). Существуют общепринятые скорости пе- редачи: 300, 600, 1200, 2400, 4800, 9600, 19 200, 38 400, 57 600, 115 200, 230 400, 460 800, 921 600 бод. Наиболее часто используются скорости 9600, 19 200, 57 600 и 200бод. Поскольку вместе с битами данных передаются старт-стоповые биты и бит четности, пропускная способность отличается от скорости обмена. Например, при скорости обмена 115 200 битов в секунду фактическая скорость передачи данных составит всего 92 600 бит/сек. Эту особенность следует учитывать при проектировании уст- ройств, критичных к скорости передачи данных. Обмен данными происходит по двум линиям: прием Rx (RXD) и передача Тх (TXD). Устройства, которые обмениваются данными, полностью равноправны. Ли- ния передачи одного устройства является линией приема для другого, и наоборот. Поэтому выводы устройств необходимо соединять перекрестно: Rx—►Тх, Тх—>Rx. Если предполагается передавать данные только в одном направлении, достаточно соединить выход Тх передающего устройства со входом Rx принимающего. 3.2.1. Конвертер интерфейсов USB-UART Многие электронные устройства приходится подключать к компьютеру для про- граммирования, настройки или просмотра потока данных. При этом используется обычный разъем USB. Но далеко не всегда устройство поддерживает работу по протоколу USB. Этот протокол весьма сложен для программирования как на сторо- не компьютерных приложений, так и на стороне прошивки устройства. Намного чаще используется программно-аппаратная эмуляция последовательного порта об- мена данными. Некоторые устройства, особенно отладочные платы, содержат встроенные конвертеры интерфейсов USB-UART в виде специальной микросхемы, но часто применяются внешние преобразователи. При подключении конвертера USB-UART к компьютеру в системе появляется вир- туальный последовательный порт. Программы работают с ним, как с обычным аппаратным портом, хотя фактически данные транслируются через порт USB. В свою очередь, микроконтроллер устройства также обменивается данными с мик- росхемой конвертера, как с обычным последовательным портом. Таким образом, конвертер «прозрачен» для последовательного потока данных в обе стороны. В продаже доступно большое количество недорогих конвертеров USB-UART, но почти все они построены на базе одного из трех чипов: FTDI (FT232), WCH (CH340G) или Prolific (PL2303). Микросхема конвертера может быть установлена на плате устройства либо оформлена в виде внешнего модуля (рис. 3.2). В любом случае, на компьютер необходимо установить драйвер соответствующей микро- схемы, который можно скачать на сайте ее производителя. Старайтесь найти плату конвертера, на разъем которой от микросхемы выведены линии и RTS, и DTR (как минимум, только DTR). Дело в том, что для записи про-
Глава 3. Интерфейсы обмена данными 25 шивки в микроконтроллеры Atmel непосредственно перед началом записи необхо- димо подать импульс на вывод сброса микроконтроллера. Прршожение Arduino IDE формирует этот импульс автоматически на линиях DTR и RTS. Если микросхема конвертера уже установлена на плату Arduino или ESP8266, то проблема с автома- тическим сбросом не возникает. Если же вы используете внешний модуль конвер- тера, у которого отсутствует вывод DTR, придется либо дорабатывать его плату, либо каждый раз непосредственно перед началом загрузки прошивки вручную на- жимать кнопку RESET на плате контроллера, ловя нужный момент. Рис. 3.2. Варианты модулей конвертера USB-UART Все микросхемы конвертеров могут вырабатывать напряжение питания +3,3 В для питания внешних потребителей током до 50 мА. Удобно, если это напряжение вы- ведено на разъем. В таком случае при настройке или отладке маломощных трех- вольтовых устройств можно обойтись без дополнительного источника питания. В некоторых конвертерах предусмотрена возможность переключения напряжения логических уровней выходного каскада при помощи перемычки или переключате- ля. Благодаря этой опции, можно подключать конвертер к микросхемам трехволь- товой логики без преобразователя уровней. Из числа конвертеров, изображенных на рис. 3.2, лучше всего подойдут варианты Ь, с и d. Вариант f выглядит подходящим, но изготовлен на поддельной микросхе- ме-клоне FT232 и работает очень нестабильно. Вариант а не оснащен выводом сброса, а вариант е рассчитан только на логические уровни трехвольтовых микро- схем.
Часть I. Необходимое оборудование и программы 3.2.2. Встроенный класс Serial В состав среды разработки Arduino IDE входит класс serial для работы с аппарат- ным портом UART. Этот класс вы будете постоянно использовать для вывода отла- дочных сообщений и данных в терминал последовательного порта. Мы рассмотрим использование основных методов класса при работе с платами контроллеров Arduino Uno/Nano и ESP8266. В листинге 3.1 приведен простой пример использования класса Serial для переда- чи и получения текстовых данных. void setup() { // Инициализация порта на скорости 9600 бод Serial.begin(9600); // Вывод в порт без перевода строки Serial.print("Hello, ") ; // Вывод в порт с переводом строки Serial.println("World!"); // Вывод числа в десятичном формате Serial.println(125, DEC); // Вывод числа в шестнадцатеричном формате Serial.println(125, HEX); void loop () { String s; char c; // Пока в буфере есть данные, считываем их посимвольно //и добавляем в строку while (Serial.available()>0) { с = Serial.read(); s = s + с; } // Когда данные в буфере закончились, // выводим строку обратно в порт Serial.print(s); Скетч выводит строки и числа в последовательный порт, а затем ожидает ввод строки через порт. Полученные данные считываются из буфера порта и собираются в строку. Когда буфер опустел (метод serial.available о вернул ноль), полученная строка выводится обратно в порт. Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1).
Глава 3. Интерфейсы обмена данными 27_ Проблемы и ошибки при работе с последовательным портом Начинающие разработчики обычно забывают, что буферы приемника и передатчи- ка последовательного порта микроконтроллера имеют весьма небольшую ем- кость. Буферы хранятся в оперативной памяти микроконтроллера. По умолчанию объем буферов приема и передачи контроллера Arduino на основе ATmega328 — всего 64 байта. Объем буфера можно увеличить, изменив значения настроечных констант serialtxbuffer и serialrxbuffer в файле конфигурации \hardware\ arduino\avr\cores\arduino\HardwareSerial.h. Но в этом случае уменьшится объем свобод- ной памяти для хранения переменных. Скорость обмена должна быть достаточной для передачи массива данных от источ- ника. Некоторые периферийные устройства генерируют плотный поток данных. Например, приемник GPS с частотой обновления координат 10 раз в секунду не может работать на скорости меньше 57 600 бод, иначе он не успеет передать тек- стовые навигационные данные в промежутке между измерениями. При отправке данных в порт вы должны позаботиться о том, чтобы исходящая порция данных не превышала размер буфера передатчика. При переполнении буфера приемника старые данные вытесняются из памяти. Ваша программа должна успевать считывать и обрабатывать поступающие данные по мере поступления, иначе старые данные будут утеряны. Поэтому рекомендуется считывать содержимое буфера полностью, и только после этого обрабатывать по- лученные данные. В любом случае вы должны помнить, что передача данных через последовательный порт происходит «порциями», объем которых не должен превышать объем буфера. Ваша программа должна вовремя опорожнять буфер приемника и не переполнять буфер передатчика. К сожалению, невозможно дать готовые рецепты на все случаи жизни. Вам придется самостоятельно выполнять оценочные расчеты для каждого нового проекта. 3.2.3. Программные порты SoftwareSerial Единственный аппаратный последовательный порт контроллеров Arduino Uno/Nano занят адаптером USB-UART для записи прошивок и обмена данными с компьютером. Если нужен еще один последовательный порт для подключения модуля или устройства, придется эмулировать работу этого порта при помощи про- граммы. В среду разработки Arduino IDE встроена библиотека SoftwareSerial, которая по- зволяет создать на разных выводах несколько программных портов, работающих на скорости до 115 200 бод. Но эта библиотека не позволяет передавать и принимать данные через несколько портов одновременно. Если для вашего проекта критически важна возможность одновременной работы нескольких портов, воспользуйтесь библиотекой Aitsoftserial (https://www. pjrc.com/teensy/td_libs_AltSoftSerial.html). В целом работа с библиотекой SoftwareSerial ничем не отличается от работы с методами класса serial. Нужно лишь в явном виде подключить библиотеку и
Часть I. Необходимое оборудование и программы предварительно создать объект последовательного порта с номерами выводов RX иТХ: #include <SoftwareSerial.h> // подключение библиотеки SoftwareSerial mySerial(2, 3); // 2 - RX, 3 - ТХ void setup() { mySerial.begin(115200); // инициализация порта } 3.2.4. Терминал последовательного порта Termite В среду разработки Arduino IDE встроен монитор последовательного порта, но у него скромный набор функций. Многие периферийные устройства и модули пе- ред началом эксплуатации нуждаются в настройке через последовательный порт. Приложение Termite идеально подходит для подключения к устройствам, поддер- живающим обмен командами через COM/UART: приемники GPS, модемы, модули Bluetooth и т. д. Скачайте самораспаковывающийся архив программы по адресу http://www. compuphase.com/software_termite.htm. При установке поставьте в списке компо- нентов флажок для шрифта GNU Unifont. Этот шрифт отображает небуквенные служебные символы, если они встречаются в потоке данных. Эта опция может при- годиться в будущем для тестирования и отладки проектов. При работе с дополнительными модулями потребуется проверить и изменить сле- дующие настройки терминала Termite (рис. 3.3): ♦ номер последовательного порта — это порт, который появляется в системе при подключении адаптера USB-COM. При подключении одного и того же устрой- ства к разным разъемам USB номер порта может меняться; Рис. 3.3. Окно настроек программы терминала Termite
Глава 3. Интерфейсы обмена данными 29 скорость обмена с устройством — для каждого устройства определена своя скорость обмена, указанная в исходном коде прошивки, инструкции или описа- нии; присоединение символов конца строки и перевода каретки: <LF> и <CR>. Не- которые устройства требуют наличия этих символов в конце команды, некото- рые — нет. Несоблюдение условия по наличию или отсутствию символов <LF> и <CR> может привести к невозможности передачи команд или к неправильной реакции устройства; шрифт — если нужно отображать спецсимволы, выберите в поле Font опцию unifont. 3.3. Последовательная шина 1С Последовательная шина I2C (IIC, Inter-Integrated Circuit) разработана в 1980 году компанией Philips для простого 8-битного обмена данными между интегральными микросхемами внутри одного устройства. В любительских устройствах по этой шине могут также подключаться различные датчики, вынесенные на небольшое расстояние от основной платы. К шине 12С обязательно подключено ведущее устройство (master) и одно или не- сколько ведомых (slave). У каждого ведомого есть свой адрес на шине. Способ задания адреса зависит от ведомой микросхемы. У некоторых микросхем, например у трехвыводных датчиков температуры, адрес фиксированный и указан в доку- ментации. У более сложных микросхем адрес можно задавать комбинацией пере- мычек на выводах, соединяя их с «землей» или шиной питания. Разработчикам доступно до 112 свободных адресов для подключения ведомых на одну шину (рис. 3.4). Ведущий Ведомый 1 Ведомый 2 Ведомый N SCL SDA Адрес 1 SCL SDA Адрес 2 SCL SDA Рис. 3.4. Схема подключения шины I2C Для обмена данными используются две линии: тактирование — SCL и данные — SDA. Обмен начинается с того, что ведущее устройство дает команду START и пе- редает по линии SDA адрес ведомого. Ведомый, распознав свой адрес, дает в ответ сигнал подтверждения готовности. Далее ведущий передает ведомому устройству команды или данные и может получать данные в ответ. Например, микроконтрол-
Часть I. Необходимое оборудование и программы лер передает команду измерить температуру и получает в ответ измеренное зна- чение. В большинстве устройств используется одна из стандартных скоростей: 100 Кбит/с или 400 Кбит/с. Логические уровни стандартные, трех- или пятивольтовые — в зависимости от рабочего напряжения схемы. Преобразование интерфейса 12С в какой-либо другой встречается редко и обычно не требуется в любительской практике. Микроконтроллеры имеют аппаратную ли- бо программную поддержку 12С. Все, что от вас требуется, — правильно соединить выводы микросхем или модулей и не ошибиться с адресом устройства. Учитывайте особенности и ограничения шины 12С: ♦ логические уровни обязательно должны быть согласованы при помощи двуна- правленных преобразователей; ♦ двунаправленными являются обе линии: SCL и SDA; ♦ при неустойчивой работе шины могут понадобиться подтягивающие резисторы сопротивлением около 1 кОм, подключенные к линиям SCL и SDA и к шине питания; ♦ шина чувствительна к помехам и емкости соединительных проводов, поэтому плохо работает на линиях, длиннее 30 см; ♦ в любительских устройствах старайтесь использовать скорость 100 Кбит/с. В контроллерах Arduino на базе ATmega328 линии SCL и SDA совмещены с выво- дами А5 и А4. На платах Arduino UNO R3 эти выводы продублированы с другой стороны платы и снабжены подписями: SCL и SDA. 3.3.1. Библиотека Wire Для работы с шиной 12С предназначена встроенная в среду Arduino IDE библиотека wire. Библиотека позволяет контроллеру Arduino работать ведущим или ведомым устройством. Если в аргументе метода begin о указать 7-битовый адрес, то кон- троллер будет ведомым. По умолчанию аргумент не указывают, и контроллер оста- ется ведущим устройством. Для передачи данных в ведомое устройство инициализируют сеанс передачи ме- тодом beginTransmissionO, затем передают данные методом write о и закрывают сеанс методом endTransmission (). Для чтения данных из устройства сначала запрашивают данные методом requestFrom(address,quantity). Аргументами метода являются адрес ведомого уст- ройства и количество байтов, которые необходимо прочитать. Затем при помощи метода read о полученные байты поочередно считываются из буфера приемника. Наличие доступных для чтения байтов проверяется при помощи метода available (): Wire.requestFrom(2, 6);// Запрашиваем 6 байтов по адресу 2 while(Wire.available())// ведомый может передать меньше, чем ждали
Глава 3. Интерфейсы обмена данными 31_ byte с = Wire.read();// читаем байт из буфера Serial.print(с, HEX);// выводим байт на печать } Дело в том, что устройство не обязательно может вернуть столько байтов данных, сколько у него запрашивали. Метод setciock () позволяет установить скорость шины. По умолчанию в устройст- вах Arduino шина работает на скорости 100 кГц. Другое популярное значение ско- рости — 400 кГц. Некоторые ведомые могут работать на скорости 1000 и 3400 кГц, но в проектах Arduino редко встречаются такие устройства. В целом, макеты схем на беспаечных платах с большим количеством проводов и контактов плохо подхо- дят для работы на большой скорости. Не увеличивайте скорость шины без необходимости! В качестве примера использования библиотеки wire рассмотрим скетч для работы с расширителем ТСА9548А шины 12С (подробнее об этой микросхеме см. здесь: http://reedpaper.com/archives/1108). Исходный код скетча приведен в листинге 3.2. #include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); for (byte i = 0; i < 8; i++) { // Записываем номер порта в регистр конфигурации Wire.beginTransmission(0x70); // адрес микросхемы 0x70 Wire.write(i); Wire.endTransmission() ; // Читаем номер активного порта из регистра Wire.requestFrom(0x70, 1); byte j = Wire.read(); Serial.println(j); delay(300); void loopO
32 Часть I. Необходимое оборудование и программы В этом скетче контроллер Arduino по очереди записьгоает номера портов в регистр конфигурации, а затем читает значение из регистра. Весьма часто случается так, что вы не знаете точно, по какому адресу доступно периферийное устройство. В этом случае вам пригодится скетч сканера шины 12С (листинг 3.3). // Ref- Nick Gammon http: //www.gammon, com. au/forum/?id=10896 // I2C Scanner #include <Wire.h> void setup() { Serial.begin (9600); Serial.println (); Serial.println ("I2C scanner. Scanning ..."); byte count = 0; Wire.beginO ; for (byte i = 8; i < 120; i++) { Wire.beginTransmission (i); if (Wire.endTransmission () ==0) { Serial.print ("Found address: "); Serial.print (i, DEC); Serial.print (" (Ox"); Serial.print (i, HEX); Serial.println (")"); count++; delay (1); Serial.println ("Done."); Serial.print ("Found "); Serial.print (count, DEC); Serial.println (" device(s)."); void loop() {} Сканер последовательно перебирает все 112 возможных адресов шины и пытается установить сеанс передачи данных по каждому из этих адресов. Если устройство отвечает, текущее значение адреса выводится на экран.
Глава 3. Интерфейсы обмена данными 33 Имейте в виду, что одно ведомое устройство может занимать на шине 12С несколько адресов— если каждому регистру микросхемы присвоен собственный адрес. На- пример, микросхема цифрового барометра ВМР180 занимает отдельные адреса для регистров конфигурации, калибровки, давления и температуры. 3.4. Последовательная шина 1-Wire Для связи между устройствами по протоколу 1-Wire требуется всего два провода: сигнальный и общий (рис. 3.5). Питание периферийного устройства осуществляет- ся по линии сигнала. Устройство содержит конденсатор емкостью 800 пФ, который заряжается при высоком логическом уровне на линии сигнала за счет подтягиваю- щего резистора с номиналом 4,7 кОм. Для некоторых устройств номинал резистора может быть иным. Но такая технология паразитного питания (parasite power) рабо- тает только на коротких линиях. Для питания компонентов, вынесенных на боль- шое расстояние, используют отдельную линию. Vcc Vcc линия данных Ведущий Ведомый 1 х X Рис. 3.5. Подключение устройств к шине 1-Wire В электронных системах шина 1-Wire обычно используется для подключения недо- рогих внешних датчиков и средств идентификации. Пример— всем известные «таблетки» iButton для домофона. Часто по шине 1-Wire подключается специаль- ная микросхема, устанавливаемая в батареях ноутбуков и смартфонов для проверки подлинности батареи и мониторинга ее температуры. В принтерах по шине 1-Wire распознается тип и состояние картриджей с тонером. Преимущество протокола 1-Wire заключается в широких возможностях адресации и гибкости системы. Каждое устройство имеет 64-битовый серийный номер, со- стоящий из трех частей: 8-битовый код семейства, уникальный 48-битовый номер и 8-битовая контрольная сумма. Уникальность номеров устройств гарантируется об- ладателем торговой марки— компанией Dallas Semiconductor (с 2001 года — Maxim Integrated). Устройства самотактируются. Информация кодируется длитель- ностью импульсов. Все импульсы несут в себе либо данные, либо номер адресуе-
34 Часть I. Необходимое оборудование и программы мого компонента. На шине присутствует одно ведущее устройство, остальные ве- домые. Ведущий имеет возможность перед началом работы опросить шину и опре- делить перечень подключенных ведомых. Стандартная скорость передачи данных составляет 15,4 Кбит/с. В режиме Overdrive скорость может достигать 125 Кбит/с на линиях длиной менее 50 см. 3.4.1. Библиотека OneWire Библиотеку OneWire, используемую для организации работы по шине 1-Wire, можно установить при помощи менеджера библиотек Arduino. При разработке проекта необходимо учитывать особенности работы периферийных устройств 1-Wire. На- пример, термометры DS 18x20 выполняют измерение температуры с высоким раз- решением в течение 750 мс. Все это время надо поддерживать на шине высокий логический уровень. Передача данных одновременно с питанием устройства не от- личается идеальной надежностью, особенно если к шине подключено несколько устройств. Поэтому после считывания данных по шине 1-Wire принято проверять контрольную сумму. В качестве простого примера использования библиотеки OneWire рассмотрим скетч считывания данных из ключа iButton DS1990A (листинг 3.4). Такие ключи часто используют в обычных домофонах и прочих системах контроля доступа. Наверняка у вас найдется под рукой хотя бы один такой ключ. Не бойтесь — вы не испортите его своими экспериментами. Схема подключения ключа к плате Arduino Uno показана на рис. 3.6. В нашем слу- чае для питания ключа нужно использовать подтягивающий резистор с номиналом 2,2 кОм. Рис. 3.6. Схема подключения ключа DS1990A к контроллеру Arduino Uno
Глава 3. Интерфейсы обмена данными 35 #include <OneWire.h> // Создаем объект шины 1-Wire на выводе D10 OneWi re ibutton(10); void setup(void) { Serial.begin(9600); void loop(void) { byte i; byte data[8]; // Массив байтов ответа ключа // Ищем устройство на шине // Если ни одного устройства нет, // досрочно повторяем цикл 1оор() if ( !ibutton.search(data)) { ibutton.reset_search(); return; // Выводим в порт ID ключа, // при этом добавляем ведущие ноли в строку вывода Serial.print("ID: ") ; for ( i = 6; i > 0; i—) { if (data[i] = 0) Serial.print("00"); if (data[i] <= 16 && data[i] > 0) { Serial.print("0"); Serial.print(data[i], HEX); } if (data[i] > 16) Serial.print(data[i], HEX) // Проверяем контрольную сумму if ( OneWire::crc8( data, 7) != data[7]) { Serial.println("CRC is not valid!"); return; // Если первый байт ответа устройства не равен 0x01, // значит, это не ключ DS1990A if ( data[0] != 0x01) { Serial.println("Device is not a DS1990A family device."); return;
36^ Часть I. Необходимое оборудование и программы Serial.println(); ibutton.reset(); delay(lOOO); Скетч непрерывно проверяет шину 1-Wire на наличие подключенного устройства. Ответ устройства помещается в массив. Первый байт — это идентификатор типа устройства. Следующие шесть байтов— уникальный номер ключа (button ID). Ключи iButton обозначаются идентификатором 0x01. Если на шине действительно ключ, выводим следующие шесть байтов в обратном порядке, как они выгравиро- ваны на корпусе ключа. Метод serial.print (data, hex) выводит числа в шестнадцатеричном формате, но без ведущего ноля. Например, число of будет напечатано как f, а число оо — как о. Это сбивает с толку и затрудняет чтение последовательности чисел. Поэтому в скетче при помощи строк кода: if (data[i] <= 16 && data[i] > =0) { Serial.print("0"); } в нужных случаях принудительно добавляются ведущие ноли к шестнадцатеричным числам, попадающим в диапазон от 0 (00) до 16 (0F). 3.5. Последовательный интерфейс SPI Четырехпроводной интерфейс SPI (Serial Peripheral Interface) предназначен для не- сложного, но скоростного сопряжения микроконтроллеров с периферийными уст- ройствами. При помощи SPI подключают компактные матричные дисплеи, микро- схемы и карты памяти, бесконтактные считыватели карт и прочие устройства, тре- бующие передачи относительно больших объемов данных за короткое время. Многие современные микроконтроллеры имеют аппаратную поддержку SPI и кро- ме обмена данными допускают загрузку прошивок по этому протоколу. В SPI используется четыре цифровых линии: ♦ MOSI (SDI, SI, DI) — выход ведущего, вход ведомого (Master Out Slave In); ♦ MISO (SDO, SO, DO) — вход ведущего, выход ведомого (Master In Slave Out); ♦ SCLK (SCK, CLK)— выход тактовых импульсов для тактирования ведомых устройств; ♦ SS или CS — выбор ведомой микросхемы (Slave Select или Chip Select). SPI— это полноценный дуплексный интерфейс. Данные могут одновременно передаваться в двух направлениях: от ведущего к ведомому по линии MOSI и от ведомого к ведущему по линии MISO. В любом случае ведущий выбирает ведомое устройство при помощи сигнала SS и тактирует передачу данных по шине. Скорость передачи данных определяется частотой тактовых импульсов ведущего, может достигать 50 Мбит/с и технически ограничивается возможностями самого
Глава 3. Интерфейсы обмена данными 37 медленного устройства на шине. Например, в библиотеке Arduino SPI по умолча- нию задана частота тактовых импульсов, равная V4 от тактовой частоты контролле- ра: 16: 4 = 4 МГц. Следовательно, скорость по умолчанию— 4 Мбит/с. Это на- много больше, чем скорость других интерфейсов. Как правило, такой скорости дос- таточно для большинства любительских конструкций. Интерфейс SPI может работать в четырех разных режимах. Они различаются ак- тивным уровнем тактового импульса и порядком передачи битов в байте. По умол- чанию активен положительный тактовый импульс (захват данных по переходу из О в 1)— первым передается старший бит. Это наиболее распространенный режим spimodeo. При разработке собственных проектов следует уточнить спецификацию периферийных устройств. Стандартные библиотеки SPI позволяют менять режим перед обращением к конкретному устройству. Поскольку для каждого ведомого нужен отдельный сигнал SS, то приходится выде- лять под каждый из них отдельный вывод микроконтроллера. Это главный недос- таток интерфейса SPI, особенно в случае использования маломощных контролле- ров с небольшим числом выводов. Под интерфейс занято минимум четыре вывода, и каждое следующее устройство занимает еще один вывод. Но для современных микроконтроллеров, у которых бывает более двух десятков портов ввода/вывода, эта проблема менее актуальна. Интерфейс SPI предназначен для коммутации на небольших расстояниях внутри одного устройства. Следует соединять между собой одноименные выводы ведуще- го и ведомого (рис. 3.7). Ведущий MOSI MISO SCLK SS df I II II ,w Ведомый MOSI MISO SCLK SS Рис. 3.7. Схема соединений по интерфейсу SPI 3.5.1. Библиотека SPI Библиотека spi включена в состав среды разработки Arduino IDE и не требует установки. На сегодняшний день практически все модули расширения для кон- троллеров Arduino, работающие с интерфейсом SPI, снабжены собственными биб- лиотеками. Эти библиотеки являются «обертками» для библиотеки SPI, предостав- ляют пользователю простой доступ к функциям устройства и позволяют не думать о том, как там внутри работает SPI. Тем не менее иногда приходится работать с устройством напрямую через интерфейс SPI. Поэтому будет полезно ознакомить- ся с библиотекой spi хотя бы в общих чертах.
38^ Часть I. Необходимое оборудование и программы Библиотека spi поддерживает работу аппаратного блока микроконтроллера только в режиме ведущего. Поэтому стандартный вывод 55 обязательно должен быть на- строен в режим выхода и никогда не переключаться в режим входа, иначе аппарат- ный блок интерфейса SPI автоматически переключится в режим ведомого, и библио- тека spi не будет работать. По умолчанию вывод 55 переключается в режим вывода при инициализации командой begin (). Даже если вы используете для выбора ведо- мых другие выводы, 55 все равно должен оставаться в режиме выхода. Приступая к работе с периферийным устройством, мы должны задать в явном виде частоту тактовых импульсов SCLK, режим работы шины mode и порядок следова- ния байтов. Все эти параметры описаны в руководстве к устройству, с которым вы работаете. К одной шине SPI могут быть подключены устройства с разными режимами. По- этому рекомендуется указывать параметры шины непосредственно перед началом обмена с конкретным устройством. Это не замедляет, а, наоборот, ускоряет работу библиотеки. Контроллер передает и принимает байты через интерфейс SPI. Назначение и ин- терпретация этих байтов: адрес, команда, данные — полностью зависит от ведомо- го устройства. Например, вы можете передать подряд три байта: адрес регистра, байт конфигурации для записи в этот регистр и команду для устройства, а в ответ получить два байта как результат выполнения команды. В качестве примера рассмотрим скетч из листинга 3.5 для обмена данными с неким условным устройством. Линия выбора устройства подключена к выводу D7. #include <SPI.h> // Вывод для выбора ведомого устройства const int slaveSelect = 7; void setup() { // Переключаем вывод в режим выхода pinMode(slaveSelect, OUTPUT); digitalWrite(slaveSelect, HIGH); // Инициализируем библиотеку SPI.begin(); void loop() { // Начинаем сеанс обмена с устройством, // частота шины - 4 МГц, младший байт идет первым, режим MODE0 SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)) // Выбираем ведомое устройство digitalWrite(slaveSelect, LOW); // Передаем в устройство некоторые данные SPI.transfer(0x78); SPI.transfer(OxFF);
Глава 3. Интерфейсы обмена данными 3£ // Шина SPI может одновременно работать на передачу и прием // Передаем в устройство некоторую команду и получаем ответ int result8 = SPI.transfer(0x45); // Передаем в устройство два байта (слово) и получаем ответ int resultl6 = SPI.transferl6(0xFE25); // Отключаем ведомое устройство от шины digitalWrite(slaveSelect, HIGH); // Закрываем сеанс обмена, освобождаем шину SPI.endTransaction(); // Теперь шина может работать с другим устройством } В этом исходном коде использован алгоритм, рекомендованный для работы с об- новленной библиотекой spi. Вы можете встретить старые варианты программ, в которых не используется в явном виде метод beginTransaction () и объект настро- ек spisettingso. Старые скетчи компилируются без ошибок, но для будущей со- вместимости и ускорения работы библиотеки рекомендую использовать в вашем коде новый вариант. Явное указание начала и окончания сеанса работы с шиной и управление выбором ведомого именно внутри сеанса избавит вас от трудноопределяемых ошибок, свя- занных с конфликтами устройств на шине. Это хороший стиль программирования. 3.6. Подключение по Bluetooth Использование модуля (адаптера) Bluetooth— это простой и недорогой способ организовать беспроводное подключение контроллера Arduino к настольному ком- пьютеру, ноутбуку или мобильному гаджету. Стандартные модули Bluetooth обес- печивают устойчивую связь в помещении на расстоянии около 10-12 метров. В целом, пользоваться модулем Bluetooth очень просто. Вы соединяете модуль с платой контроллера Arduino по линиям последовательного порта RX/TX, а ком- пьютер, оснащенный собственным адаптером Bluetooth, создает виртуальный по- следовательный порт. С точки зрения программирования контроллера, это подклю- чение абсолютно идентично соединению проводом с СОМ-портом компьютера. В таких случаях говорят, что адаптер создает прозрачный канал последовательного порта. На самом деле, адаптеры Bluetooth могут выполнять и другие функции, кроме трансляции данных последовательного порта. В зависимости от прошивки и режи- ма работы адаптер Bluetooth может работать в беспроводных наушниках, клавиату- ре и других устройствах. Но в этой книге мы говорим только о подключении стан- дартных модулей Bluetooth для передачи данных. Устройства Bluetooth делятся на ведущие (master) и ведомые (slave). Ведущее устройство дает команду установить связь и спрашивает, в каком режиме работает ведомое устройство. Обычно в качестве ведущего устройства выступает компью- тер, смартфон или планшет. Некоторые модули Bluetooth могут работать в режиме ведущего, но в проектах Arduino редко применяется эта возможность.
40 Часть I. Необходимое оборудование и программы Перед началом эксплуатации модуль необходимо настроить: задать имя устройст- ва, пин-код и скорость передачи данных. Для некоторых модулей необходимо так- же задать режим работы ведомый/ведущий. Для настройки модуля Bluetooth вам потребуется адаптер последовательного порта USB-UART (см. разд. 3.2.1). Модуль Bluetooth может находиться в одном из трех режимов: ♦ настройка (режим команд, АТ-режим)— в этом режиме модуль получает от управляющего контроллера команды по линии RX и отвечает по линии ТХ. Команды начинаются с префикса AT, который исторически унаследован от пер- вых модемов. В режиме настройки обмен по радиоканалу не происходит; ♦ ожидание подключения — модуль виден в эфире под своим именем и ожидает подключение по радиоканалу по инициативе ведущего устройства; ♦ подключение установлено— модуль соединен с ведущим устройством по радиоканалу и работает в режиме прозрачного последовательного порта в обе стороны. Для перевода модуля со старой прошивкой в режим настройки необходимо нажать кнопку на плате модуля в момент подачи питания или соединить перемычкой два вывода платы. Такие модули еще встречаются в продаже. Современные модули могут совмещать режимы команд и ожидания подключения. Если соединение не установлено, они принимают и выполняют АТ-команды. Как только ведущее устройство передало требование установить связь по радиоканалу, модуль перестает воспринимать АТ-команды и любые данные прозрачно трансли- рует в радиоканал. 3.6.1. Модули Bluetooth НС-06 и НС-05 НС-06— это самый популярный и недорогой Arduino совместимый модуль Bluetooth (рис. 3.8). В продаже встречаются визуально идентичные модули НС-05, которые иногда продаются под видом НС-06. Также существуют разные версии w- I Рис. 3.8. Модуль Bluetooth НС-06
Глава 3. Интерфейсы обмена данными 41_ прошивки модуля, которые различаются синтаксисом команд управления и спосо- бом включения режима настройки. У начинающих любителей все проблемы с мо- дулем Bluetooth возникают именно на этапе настройки и подключения. Если вы начинающий любитель, то не спешите покупать новые модули НМ-10 и АТ- 09 класса Bluetooth Low Energy (BLE). Эти модули обладают большими возможно- стями, но работают иначе, чем популярные модули НС-05 и НС-06. Вы не сможете использовать модули НМ-10 и АТ-09 для простой передачи данных через последо- вательный порт без дополнительной сложной настройки и специальных приложений. Кроме того, модули BLE работают не со всеми мобильными гаджетами. Сначала мы разберемся с настройкой стандартного модуля НС-06 с новой прошив- кой. Сразу после включения питания этот модуль готов принимать АТ-команды и сохраняет эту возможность до момента соединения с ведущим устройством. Для перехода в режим настройки не требуется соединять какие-либо выводы или нажи- мать кнопки на плате. 1. Подключите модуль НС-06 к конвертеру USB-UART. Не забывайте, что линии данных надо подключать перекрестно: RX->TX, TX-^RX. 2. Если плата конвертера поддерживает переключение логических уровней, уста- новите напряжение уровней трехвольтовой логики. 3. Запустите на компьютере программу Termite (см. разд. 3.2.4). Выберите номер нужного порта, задайте скорость 9600 бод и опцию Append nothing. Нажмите кнопку ОК. 4. В строке ввода терминала наберите латинскими буквами команду at и нажмите клавишу <Enter>. Если скорость совпадает, и модуль готов к приему команд, он ответит ОК. Если модуль не отвечает, попробуйте скорости 19 200, 57 600 и 115 200. Пока вы не добились от модуля ответа ОК, нет смысла вводить другие команды. 5. Введите команду AT+NAMEArduino (без пробелов). Эта команда задает модулю имя Arduino, под которым он будет виден в эфире среди других устройств. Модуль должен ответить OKsetname. 6. Введите команду at+pin****, где вместо звездочек подставьте четырехзначный цифровой пин-код (пароль). Этот пароль понадобится для привязки модуля к компьютеру. 7. Введите команду at+bauds. Эта команда задает скорость 115 200 бод. Я рекомен- дую установить большую скорость обмена, чтобы иметь запас по скорости на случай передачи длинных блоков данных. Но вы можете оставить скорость по умолчанию 9600 бод или задать другую скорость. 8. После смены скорости снова войдите в настройки терминала и выберите новую скорость обмена. Вернитесь в терминал и снова отправьте в модуль команду at. Если модуль ответил ОК на новой скорости — настройка завершена, и модуль готов к работе с контроллером Arduino.
42 Часть I. Необходимое оборудование и программы А Не забывайте указывать в скетче Arduino именно ту скорость обмена, которую зада- ли в настройках модуля! Если модуль не отвечает на команду AT... Если попытки получить ответ модуля на разных скоростях обмена не помогли, попробуйте поочередно указать в настройках терминала режимы Append CR, Append LF и Append CR+LF и снова попытайтесь получить ответ ОК на команду at на скоростях 9600 и 115 200 бод. Если и эти манипуляции не помогают — модуль нуждается в принудительном пе- реключении в режим команд. Внимательно посмотрите на рис. 3.9. На нем изобра- жен модуль Bluetooth без платы расширения и отмечено расположение специально- го управляющего вывода KEY для версий НС-06 и НС-05. Чтобы перевести модуль в режим команд, соедините вывод KEY(26) с выводом питания +3,3V и подайте питание. Затем снова попробуйте соединиться на скорости 9600 и 115 200 бод. ТХ(1) ТХ(1) K£Y(34) RX<2) RX(2) LED2(32) LED1{31) |LED(24) ♦3.3V(12> GND<13) | GND{13) НС-06 НС-05 Рис. З.9. Расположение выводов управления режимом в модулях НС-06 и НС-05 Настройка модуля НС-05 Иногда соединение вывода 26 с шиной питания не помогает перевести модуль в режим команд. Значит, вы стали обладателем модуля НС-05, который может ра- ботать как в режиме ведомого, так и в режиме ведущего. Система команд этого мо- дуля намного обширнее и отличается по синтаксису от НС-06. 1. Попробуйте перевести модуль в режим команд, соединив вывод KEY(34) с вы- водом +3,3V и подав питание. Важные нюансы! Модуль НС-05 в режиме команд работает только на фиксированной скорости 38 400 бод. Команда обязательно должна завершаться символами возврата каретки и перевода строки (CR+LF).
Глава 3. Интерфейсы обмена данными 43 Скорость обмена, которую вы задаете в настройках, имеет значение только в обыч- ном режиме. 2. Войдя в режим команд, первым делом назначьте модуль ведомым устройством КОМаНДОЙ AT+ROLE=0. 3. Назначьте ИМЯ МОДУЛЯ КОМаНДОЙ AT+NAME=Arduino. 4. Установите пин-код командой at+pswd=****, где вместо звездочек укажите циф- ровой код. 5. Установите скорость обмена командой at+uart=ii52OO,o, о. Второй и третий па- раметр после запятой — настройки стоп-бита и бита четности. Не меняйте эти параметры. 6. На этом настройка модуля НС-05 для использования в большинстве проектов Arduino завершена. Можно отключить перемычку от вывода 34. 3.6.2. Настройка подключения Bluetooth в Windows 10 На первый взгляд, настройка обмена данными по Bluetooth между платой контрол- лера Arduino и компьютером под управлением ОС Windows 10 не составляет осо- бого труда. Но на самом деле иногда требуется немного магии. Подготовим плату Arduino к обмену данными по Bluetooth. Будем считать, что вы уже настроили модуль Bluetooth, как сказано в разд. 3.5.1 или 3.5.2. Скорость соединения: 115200 бод, имя устройства: Arduino. Подключите модуль Bluetooth к плате Arduino следующим образом: Arduino 5V GND D2 D3 Bluetooth vcc GND TXD RXD Загрузите в контроллер Arduino простой скетч из листинга 3.6. # include <SoftwareSerial.h> SoftwareSerial mySerial(2, 3); // RX, TX void setup() { mySerial.begin(115200);
44 Часть I. Необходимое оборудование и программы void loop() { mySerial.println(analogRead(АО)); delay(500); В этом скетче мы подключаем библиотеку softwareSerial, создаем виртуальный последовательный порт на выводах D2 (RX) и D3 (ТХ) и скоростью обмена 115200 бод (которую задали раньше в настройках модуля Bluetooth), а затем с ин- тервалом 500 мс отправляем в этот порт случайные данные, прочитанные с анало- гового входа АО. А Перед настройкой подключения к компьютеру отключите от модуля Bluetooth провод, идущий к выводу D3 (ТХ) платы Arduino! Модули НС-05, НС-06 и некоторые другие нестабильно устанавливают связь, если в это время на их вход поступают данные. Даже если устройство нормально отобра- жается как связанное, с ним все равно не получится установить связь. Оставим плату Arduino с включенным модулем Bluetooth работать вблизи компью- тера, с которым будет устанавливаться соединение. Переходим к настройке под- ключения Bluetooth на компьютере. Адаптер USB-Bluetooth Если вы пользуетесь ноутбуком, то в нем уже есть встроенный модуль Bluetooth. Для связи с обычным настольным компьютером потребуется адаптер USB- Bluetooth. Постарайтесь приобрести адаптер, совместимый с протоколом Bluetooth 4.0, иначе вы не сможете установить связь между компьютером и некоторыми со- временными беспроводными устройствами. Один из самых недорогих и миниа- тюрных адаптеров Bluetooth изображен на рис. 3.10. Такие адаптеры продаются под различными торговыми марками. Рис. 3.10. Миниатюрный адаптер USB-Bluetooth 4.0 Не путайте адаптеры Bluetooth и специальные адаптеры для подключения беспро- водных клавиатур и компьютерных мышей. Визуально такие адаптеры выглядят одинаково, но не совместимы по протоколу обмена данными.
Глава 3. Интерфейсы обмена данными 45 Включение адаптера Bluetooth и добавление устройства Вставьте адаптер Bluetooth в гнездо USB. Для большинства адаптеров Windows 10 автоматически загрузит и установит нужный драйвер. В редких случаях может потребоваться установка драйвера с диска из комплекта поставки адаптера. Чтобы включить Bluetooth, нажмите мышью на значок уведомлений в правом ниж- нем углу экрана. Найдите плитку со значком Bluetooth (рис. 3.11) и нажмите на нее. Рис. 3.11. Включение Bluetooth в Windows 10 Затем нажмите на плитку Соединиться (рис. 3.12), после чего выберите ссылку Поиск устройств других типов— откроется окно управления подключенными устройствами (рис. 3.13). Нажмите в этом окне на строку Добавление Bluetooth или другого устройства. Рис. 3.12. Выбор настройки соединений в Windows 10
46 Часть I. Необходимое оборудование и программы Рис. 3.13. Панель управления подключенными устройствами Windows 10 В окне выбора типа добавляемого устройства (рис. 3.14) выберите опцию Bluetooth. Компьютер выполнит поиск доступных устройств Bluetooth, находящихся в ра- диусе действия. Выберите в списке устройство с именем Arduino. Через несколько Рис. 3.14. Выбор типа добавляемого устройства Windows 10
Глава 3. Интерфейсы обмена данными 47 Рис. 3.15. Ввод PIN-кода устройства для привязки к компьютеру секунд появится окно ввода PIN-кода (рис. 3.15). Введите пароль, который вы зада- ли при настройке модуля, и нажмите кнопку Подключиться. Операционная система создаст виртуальные СОМ-порты, и в панели управления (см. рис. 3.13) в списке Другие устройства появится новое устройство с именем Arduino и пометкой Сопряжено. Теперь надо определить номер виртуального порта, по которому будут доступны данные, поступающие из устройства Arduino. Для этого в панели управления уст- ройствами (справа) выберите строку меню Другие параметры Bluetooth — откро- ется окно дополнительных параметров (рис. 3.16). На вкладке СОМ-порты найди- те строку, которая содержит имя вашего устройства1 и пометку Исходящий. Это и есть виртуальный последовательный порт Bluetooth, через который приложения на вашем компьютере будут получать данные. Запомните номер этого порта. Запустите любую программу терминала последовательного порта (например, Termite). Попробуйте открыть последовательный порт Bluetooth (номер которого вы только что запомнили) на скорости 115 200 бод. Если все работает правильно, терминал сообщит о том, что порт открыт, а светодиод на плате модуля Bluetooth перестанет мигать и либо станет постоянно гореть, либо погаснет (зависит от вер- сии прошивки модуля). Теперь восстановите подключение линий ТХ и RX к плате контроллера Arduino. В окне терминала немедленно начнут отображаться случайные значения, которые контроллер считывает с вывода АО и отправляет в последовательный порт. Иногда случается так, что вы все сделали правильно, но ни одна программа терми- нала не может установить связь с Arduino. Это проблема, которую отмечают мно- 1 В вашем случае имя устройства может отличаться от показанного на рисунке — оно зависит от клас- са адаптера и имени, которое вы задали при настройке.
48 Часть I. Необходимое оборудование и программы гие пользователи. Вероятно, причина неполадки заключается в том, что PIN-код модуля не сохранился в системе после привязки устройства. В таком| случае попро- буйте установить из Магазина приложений Windows утилиту Bluetooth Serial Terminal. Рис. 3.16. Окно дополнительных параметров Bluetooth 3.6.3. Утилита Bluetooth Serial Terminal Утилита Bluetooth Serial Terminal — это простое приложение Windows 10, которое специально предназначено для работы по протоколу Bluetooth с устройствами Arduino. Для установки утилиты перейдите в Магазин приложений Windows (пункт Windows Store в списке приложений Windows 10). В строке поиска введите назва- ние Bluetooth Serial Terminal. Установите приложение и запустите его (рис. 3.17). В раскрывающемся списке найдите устройство Arduino и нажмите кнопку Connect. Если приложение запросит PIN-код устройства, введите его. После этого будет установлена связь с устройством Arduino. Если даже утилита не помогла установить работающую связь с устройством, удалите устройство из системы в па- нели управления устройствами (см. рис. 3.13), а затем найдите и привяжите заново. Не забудьте отключить передачу потока данных от платы на время регистрации уст- ройства в системе.
Глава 3. Интерфейсы обмена данными 49 Рис. 3.17. Окно утилиты Bluetooth Serial Terminal для Windows 10
ГЛАВА 4 Подключение Arduino к сети Интернет Протоколы нижнего уровня, о которых мы говорили в главе 3, позволяют контрол- леру обмениваться данными с модулями расширения, периферийными устройства- ми, компьютерами и смартфонами. Такой обмен данными работает надежно и бы- стро, но действует локально, в пределах шаговой доступности. Ситуация принципиально изменилась, когда появилась возможность подключить к сети Интернет миллионы сенсоров, контроллеров и прочих устройств. Такие уст- ройства называются подключенными устройствами (connected device), а вместе они образуют Интернет вещей (Internet of Things, IoT). Теперь мы можем получать, хранить и исследовать результаты измерений, независимо от расположения датчи- ков — достаточно иметь доступ к Интернету. В этой книге мы говорим об исследовании состояния окружающей среды и челове- ческого организма. Очевидно, что подключение по сети Интернет подходит не для всех проектов. Например, нет необходимости передавать в режиме реального вре- мени результаты измерения кислотности почвы или проводимости кожи человека. Но для подключения по сети Интернет нет альтернативы, если требуется дистанци- онный мониторинг состава воздуха, уровня жесткого ультрафиолета и прочих кри- тически важных параметров окружающей среды. Даже динамичные наборы дан- ных — например, кардиограмма или пульсограмма — могут быть переданы по сети специалистам для анализа. При этом обмен данными между сенсорами, модулями и контроллером по-прежнему происходит по стандартным протоколам нижнего уровня. В этой главе мы расскажем о способах подключения контроллеров Arduino и ESP8266 к сети Интернет для получения и передачи данных, а в главе 5 приведем примеры отображения данных на облачной приборной панели Adafruit 10. 4.1. Подключение к проводной сети Ethernet Несмотря на популярность и удобство мобильных беспроводных устройств, под- ключение к проводной сети Ethernet имеет свои преимущества:
Глава 4. Подключение Arduino к сети Интернет 51 ♦ можно питать устройство по сетевому кабелю (Power over Ethernet, PoE); ♦ высокая скорость передачи данных; ♦ качество связи не зависит от наличия помех и расстояния до маршрутизатора. Мы рассмотрим способы подключения платы Arduino к проводной сети Ethernet при помощи двух популярных и недорогих модулей. 4.1.1. Модуль Ethernet ENC28J60 Модуль на основе микросхемы ENC28J60 выпускается в нескольких вариантах. Для использования совместно с контроллером Arduino Uno рекомендую приобре- сти версию платы, изображенную на рис. 4.1. У этой платы есть важные преимуще- ства перед другими вариантами: ♦ встроенный стабилизатор питания +3,3 вольта (расположен с обратной стороны платы); Рис. 4.1. Модуль расширения Ethernet на микросхеме ENC28J60 ♦ совместимость по монтажным отверстиям с платой Arduino Uno. Она удобно монтируется на нейлоновых стойках высотой 12 мм (рис. 4.2); ♦ низкая цена. Модуль обменивается данными с контроллером по универсальному протоколу SPI с тактовой частотой до 20 МГц и может быть подключен к любому контроллеру с аппаратной или программной поддержкой SPI. Микроконтроллер читает данные из буфера приемника микросхемы ENC28J60 и записывает данные в буфер пере- датчика. Всю остальную работу по организации сетевого обмена выполняет микро- схема модуля. Номинальный рабочий ток микросхемы — 170 мА (однако при работе микросхема может потреблять пиковый ток до 250 мА\ Многие платы контроллеров Arduino вообще не имеют отдельного источника напряжения +3,3 вольта и получают это напряжение от стабилизатора, встроенного в конвертер USB-UART с максималь- ным током до 100 мА. Поэтому желательно, чтобы модуль Ethernet имел собствен- ный стабилизатор питания.
52 Часть I. Необходимое оборудование и программы Рис. 4.2. Монтаж модуля расширения Ethernet на плату Arduino Uno Микросхема модуля совместима с логическими уровнями пятивольтовой и трех- вольтовой логики без дополнительного согласования. Схема подключения выводов модуля к плате Arduino такова: Arduino 5V GND D13(SCK) D12(MISO) D11 (MOSI) D10 (SS) ENC28J60 5V GND SCK SO SI CS Для работы с модулем ENC28J60 можно использовать библиотеки EtherCard и EtherEncLib, но самым обширным набором функций обладает библиотека uiPEthemet. Для установки этой библиотеки перейдите в менеджер библиотек Arduino IDE и введите в поле поиска строку uiPEthemet. Установите найденную библиотеку. Подключите сетевой кабель Ethernet к разъему модуля. Для проверки функциони- рования модуля и правильности подключения загрузите простой демонстрацион- ный скетч из листинга 4.1. Этот скетч создает TCP-клиент, подключается к серверу
Глава 4. Подключение Arduino к сети Интернет 53^ и скачивает с него текстовый файл. Содержимое файла выводится в монитор порта Arduino IDE. #include <SPI.h> #include <UIPEthernet.h> // Задаем МАС-адрес устройства в сети byte mac[] = {ОхАЕ, 0хВ2, 0x26, 0хЕ4, 0x4А, 0х5С}; // МАС-адрес EthernetClient client; // Создаем объект ТСР-клиента void setup() { SPI.begin(); Serial.begin(115200); Serial.printIn("Start connection..."); if (Ethernet.begin(mac) ==0) { Serial.println("DHCP Error!"); // Если роутер не выдал IP-адрес while (1); // Останавливаем программу } else { Serial.print("Connected with IP = "); IPAddress ip = Ethernet.locallP(); Serial.println(ip); // Выводим в терминал IP-адрес устройства } if (!client.connected()) { // Проверяем, не установлено ли уже соединение if (client.connect("reedpaper.com", 80)) { Serial.println("Connected to server."); } else { Serial.println("Can't connect to server"); while (1); // Если не удалось подключиться, останавливаем программу else { Serial.print("Already connected!"); Serial.println("Send request to server..."); // Отправляем на сервер стандартный GET-запрос //на получение содержимого файла test.txt //и разрываем соединение с сервером после получения файла client.print("GET /files/test.txt HTTP/1.l\r\n");
54 Часть I. Необходимое оборудование и программы client.print ("Host: www.reedpaper.com\r\n") ; client.print("Connection: close\r\n\r\n"); // Ждем, пока от сервера не поступит // хотя бы первый символ ответа while (client.available() < 1) { Serial.println("."); delay(500); void loopO { while (client.available()) { char chr = client.read(); Serial.print(chr); Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). Приведенный в листинге 4.1 скетч использует несколько базовых функций библио- теки uiPEthernet. С полным перечнем ее функций и подробным описанием этой библиотеки можно ознакомиться по адресу http://mypractic.ru/arduino-biblioteka- uipethernet-h-ethernet-h. В начале скетча мы задаем МАС-адрес модуля. Это обязательный параметр. Вы можете задать любой адрес, но в локальной сети не должно быть второго устройст- ва с таким же адресом. Дополнительно можно вручную задать IP-адрес модуля, адрес DNS, адрес сетевого шлюза и маску подсети. Но мы не будем указывать необязательные параметры, и маршрутизатор вашей локальной сети присвоит их автоматически. После создания клиента пробуем получить IP-адрес от роутера методом Ethernet, begin (mac). Метод возвращает 0 при неудаче или 1 при успешном соеди- нении. Далее выводим в терминал IP-адрес модуля и проверяем, не установлено ли уже соединение с сервером. Если во время работы скетча вы нажмете кнопку сброса на плате Arduino, а в буфе- ре модуля останутся данные, то будет считаться, что соединение активно, пока вы не очистите буфер. Наконец, скетч отправляет стандартный GET-запрос на сервер reedpaper.com, где я заранее выложил текстовый файл test.txt. Сервер отвечает не мгновенно, поэтому необходимо подождать, пока в буфере приема не появится хотя бы один символ. Ожидание для наглядности реализовано в блоке setup о при помощи оператора цикла while (client.available () < l), но можно просто проверять наличие данных
Глава 4. Подключение Arduino к сети Интернет 55_ в буфере в главном цикле loop (). Содержимое текстового файла посимвольно вы- водится в последовательный порт. Итак, мы испытали модуль в качестве TCP-клиента. Модуль также может работать в качестве ТСР-сервера, UDP-клиента и UDP-сервера, однако подробное рассмот- рение этих режимов выходит за рамки книги. Некоторые примеры использования модуля будут приведены далее в описании проектов. 4.1.2. Шилд Ethernet для Arduino Uno и Arduino Mega Шилд Ethernet W5100 (рис. 4.3) для плат Arduino Uno и Arduino Mega совместим со стандартной встроенной библиотекой Ethernet среды Arduino IDE и очень популя- рен среди любителей и разработчиков. Рис. 4.3. Шилд Ethernet W5100 для плат Arduino Uno и Arduino Mega Этот шилд обладает особенностями, о которых вам следует знать заранее: ♦ на многих платах китайского производства установлена резисторная сборка с неправильным сопротивлением. Поэтому шилд может неустойчиво рабо- тать — или вообще не работать — с некоторыми сетевыми коммутаторами или маршрутизаторами D-Link, а также с соединительными проводами Ethernet низ- кого качества или длиннее 25 метров; ♦ ошибку китайских производителей можно легко исправить. Но для этого надо обладать некоторым опытом работы с SMD-компонентами и иметь под рукой
56 Часть I. Необходимое оборудование и программы паяльную станцию. Подробное описание способа выявления этого брака и дора- ботки платы приведено по адресу http://reedpaper.com/archives/1086; ♦ стандартная библиотека Ethernet медленно работает в некоторых программах. Впрочем, в простых проектах начального уровня вы это вряд ли заметите; ♦ микросхема W5100 при интенсивной работе более получаса подряд может силь- но нагреваться. Не помещайте готовое устройство в герметичный корпус! Но у шилда Ethernet W5100 есть и преимущества: ♦ подключается простой установкой в разъемы, не нужны соединительные про- вода; ♦ на плате установлен слот для карты MicroSD. Это удобно при запуске миниа- тюрного веб-сервера или для ведения лога данных. Шилд Ethernet W5100 соединяется с платой Arduino по протоколу SPI. Для под- ключения задействованы стандартные выводы шины SPI: D13 (SCK), D12 (MISO), Dll (MOSI), D10 (CS-Ethernet), D4 (CS-SD). Это означает, что при подключении других модулей «поверх» шилда Ethernet вы не должны задействовать выводы D10 и D4, которые заняты под сигнал CS для микросхемы Ethernet и карты SD соответ- ственно. Установите шилд Ethernet W5100 на плату Arduino. Возьмите карту MicroSD, под- ключите ее к стационарному компьютеру или ноутбуку и отформатируйте в форма- те FAT321. Вставьте отформатированную карту памяти в слот шилда. Загрузите в плату Arduino скетч из листинга 4.2. Этот скетч создает ТСР-клиент, подключается к серверу и скачивает с него текстовый файл. Содержимое файла со- храняется в файл на SD-карте и выводится в монитор порта. Таким образом, при помощи одного проверочного скетча мы протестируем работу всех узлов модуля. #include <SPI.h> #include <Ethernet.h> #include <SD.h> // Библиотека для работы с SD-картой // Задаем МАС-адрес устройства в сети byte mac[] = {ОхАЕ, 0хВ2, 0x26, 0хЕ4, 0x4А, 0х5С}; // МАС-адрес const int chipSelect =4; // Вывод D4 для выбора SD-карты (CS-SD) EthernetClient client; // Создаем объект ТСР-клиента 1 Карту можно отформатировать как стандартными средствами операционной системы компьютера, так и при помощи специальной утилиты SD Card Formatter (https://www.sdcard.org/downloads/ formatter_3). Рекомендую использовать эту утилиту во всех сложных случаях — если карта отформа- тирована в неизвестном формате, она выглядит неисправной или отображается неправильное значе- ние емкости.
Глава 4. Подключение Arduino к сети Интернет 57^ void setup() { Ethernet.init(10); // Назначаем вывод D10 для шилда Ethernet Serial.begin(115200); Serial.print("Initializing SD card..."); // Проверяем, удалось ли инициализировать карту памяти if (!SD.begin(chipSelect)) { Serial.println("Card failed, or not present"); // Если карта недоступна, зацикливаем программу навсегда while (1); } Serial.println("card initialized."); Serial.println("Start connection..."); if (Ethernet.begin(mac) ==0) { Serial.println("DHCP Error!"); // Если роутер-не выдал IP-адрес while (1); // Останавливаем программу } else { Serial.print("Connected with IP = "); IPAddress ip = Ethernet.locallP(); Serial.println(ip); // Выводим в терминал IP-адрес устройства } if (!client.connected()) { // Проверяем, не установлено ли уже соединение if (client.connect (flreedpaper.com", 80)) { Serial.println("Connected to server."); } else { Serial.println("Can't connect to server"); while (1); // Если не удалось подключиться, останавливаем программу else { Serial.print("Already connected!"); Serial.println("Send request to server..."); // Отправляем на сервер стандартный HTTP-запрос //на получение содержимого файла test.txt //и разрываем связь с сервером после получения файла client.print("GET /files/test.txt HTTP/1.l\r\n"); client.print("Host: www.reedpaper.com\r\n"); client.print("Connection: close\r\n\r\n"); // Ждем, пока от сервера не поступит хотя бы первый символ ответа while (client.available() < 1) { Serial.println(".");
58^ Часть I. Необходимое оборудование и программы delay(500); void loop() { // Открываем файл лога для записи File dataFile = SD.open("datalog.txt", FILE_WRITE); while (client.available()) { char chr = client.read(); // Если файл доступен, записываем в него символ if (dataFile) { dataFile.print(chr); } Serial.print(chr); // Выводим символ в порт } dataFile.close(); // Закрываем файл Если ответ сервера успешно получен и выведен в монитор, можете извлечь карту памяти из гнезда и прочитать на компьютере содержимое файла datalog.txt. А Если предполагается использовать карту памяти, то команда инициализации вывода шины SPI Ethernet.init (Ю); должна присутствовать в скетче в явном виде, хотя в примерах Arduino IDE сказано, что это не обязательно. Без явной инициализации вывода D10 шилд может зависать, если карта памяти вставлена в слот. 4.2. Беспроводное подключение по Wi-Fi Беспроводное подключение к сети Интернет по Wi-Fi с точки зрения программиро- вания в Arduino IDE почти не отличается от проводного подключения к Ethernet. Но аппаратная часть устроена иначе. К сожалению, российские читатели не могут по доступной цене приобрести фир- менные платы Arduino MKR1000 и Arduino Yun Rev2. Эти платы не отгружаются в Россию из официального магазина Arduino. Но для простых проектов онлайн- мониторинга вполне достаточно плат китайского производства, которые можно заказать в любом интернет-магазине для разработчиков-любителей. С появлением платформы ESP8266 использование простых Wi-Fi-шилдов для плат Arduino потеряло смысл. При разработке проектов малой и средней сложности на- много проще и разумнее использовать независимый контроллер ESP8266, который программируется в среде Arduino IDE, почти полностью совместим со стандартны- ми библиотеками Arduino и уже имеет встроенный модуль Wi-Fi при существенно меньших габаритах и стоимости. Если периферийных ресурсов контроллера ESP8266 (см. разд. 2.2) недостаточно для проекта, можно воспользоваться специальным шил дом Wi-Fi/Linux для платы Arduino Uno. В этой главе мы рассмотрим оба варианта подключения по Wi-Fi.
Глава 4. Подключение Arduino к сети Интернет 59 4.2.1. Подключение контроллера ESP8266 к сети Wi-Fi Если вы еще не установили расширение ESP8266 для среды Arduino IDE (см. разд. 2.3.3), сделайте это сейчас. Подключите плату контроллера ESP8266 к компьютеру. В меню Инструменты | Плата выберите плату NodeMCU 1.0. Активация выбранной платы может занять несколько секунд. В меню Инструмен- ты | Порт выберите последовательный порт компьютера, к которому подключен контроллер. Загрузите в плату контроллера пробный скетч из листинга 4.3. Не забудьте перед компиляцией подставить в исходный код имя и пароль своей сети Wi-Fi. #include <ESP8266WiFi.h> const char* ssid = "********"; // имя вашей сети Wi-Fi const char* password = "********"; // Пароль вашей сети Wi-Fi WiFiClient client; // Создаем объект TCP-клиента void setup() { Serial.begin(115200); delay(100); // Пауза для запуска последовательного порта Serial.println("Start connection.. .") ; Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); // ESP8266 как клиент сети WiFi.begin(ssid, password); // Инициализируем соединение while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); Serial.println(""); Serial.println("WiFi connected"); Serial.print("IP address: ") ; Serial.println(WiFi.locallPO); if (client.connect("reedpaper.com", 80)) { Serial.println("Connected to server."); } else { Serial.println("Can't connect to server");
(Ю Часть I. Необходимое оборудование и программы while (1); // Если не удалось подключиться, останавливаем программу } Serial.println("Send request to server..."); // Отправляем на сервер стандартный HTTP-запрос //на получение содержимого файла test.txt //и разрываем связь с сервером после получения файла client.print("GET /files/test.txt HTTP/1.l\r\n"); client.print("Host: www.reedpaper.com\r\n"); client.print("Connection: close\r\n\r\n"); // Ждем, пока от сервера не поступит // хотя бы первый символ ответа while (client.available() < 1) { Serial.println("."); delay(500); void loopO { // Выводим ответ сервера в последовательный порт while (client.available()) { char chr = client.read(); Serial.print(chr); Если вы внимательно сравните этот код с кодом из листингов 4.1 и 4.2, то обнару- жите, что главные различия заключаются только в используемых библиотеках. Кроме этого, для подключения к сети Wi-Fi требуется имя сети и пароль, но не используется МАС-адрес платы, потому что он жестко записан в микросхему ESP8266 на фабрике. После команды serial.begin о необходимо сделать паузу 10... 100 миллисекунд для инициализации последовательного порта. Это особенность системы ESP8266. ESP8266 может работать как клиент сети Wi-Fi, как точка доступа и в смешанном режиме. В нашем примере командой wiFi.mode(wiFiSTA) мы переводим контрол- лер в режим клиента. После того, как установлено и проверено физическое соединение с сетью Wi-Fi, далее мы работаем с программным сетевым клиентом1 client и пользуемся его ме- тодами для отправки и приема данных. Набор стандартных методов библиотеки Wi-Fi практически не отличается от методов встроенной библиотеки Ethernet и 1 Не путайте режим клиента Wi-Fi микросхемы ESP8266 и объект сетевого клиента в программе.
Глава 4. Подключение Arduino к сети Интернет 61_ других сетевых библиотек. Поэтому с момента подключения к сети можно больше не думать о протоколе физического уровня. 4.2.2. Сетевой шилд Dragino Yun Сетевой шилд Dragino Yun (рис. 4.4) представляет собой выпускаемый в Китае клон фирменной платы Arduino Yun. Функционально этот клон даже превосходит исходную плату и доступен для заказа из России. Шилд полностью совместим по разъемам с платами Arduino Due, Leonardo, Zero, 101, Uno R3, Mega2560 R3 и может быть подключен к другим платам Arduino при помощи соединительных проводов. Рис. 4.4. Сетевой шилд Dragino Yun v.2.4 Плата содержит разъем Ethernet, USB-хост и слот для карты памяти формата MicroSD. Если установлено соединение с сетью, вы можете выгружать скетчи из Arduino IDE в плату через Wi-Fi. При этом также поддерживается обычная загрузка скетчей в плату Arduino через USB. Для связи между контроллером Arduino и мо- дулем Atheros AR9331 задействован порт seriaii и специальная библиотека Bridge. По сути, Dragino Yun — это отдельный микрокомпьютер с ОС Linux, веб-интер- фейсом, доступом по SSH и возможностью запускать скрипты на языке Python. Обратите внимание на идеологию работы сетевого модуля шилда. Несмотря на на- личие полноценной операционной системы, он работает только как средство ком- муникации между сетью и платой Arduino. При помощи этого модуля вы можете загружать скетчи в плату Arduino через Wi-Fi или Ethernet и передавать по сети данные. Вы не можете обращаться к выводам шилда средствами ОС Linux или про- граммировать работу шилда при помощи Arduino IDE. Разумеется, если у вас есть достаточный опыт работы с Linux, вы можете загружать в шилд собственные скрипты на языке Python или Lua, которые будут взаимодействовать с сетью или контроллером Arduino. Но все равно ОС Linux может использовать для аппаратной коммуникации только порты UART, SPI и выводы управления светодиодами на плате шилда.
Часть I. Необходимое оборудование и программы В этой главе мы расскажем о первом включении и настройке шилда Dragino Yun «из коробки» и приведем простые примеры работы с сетевым подключением. Под- робное руководство по работе с шилдом, включая обновление и восстановление прошивки операционной системы, а также использование функций Linux, приведе- но в книге «От Arduino до Omega. Платформы для мейкеров шаг за шагом»1. Питание шилда Dragino Yun Шилд Dragino Yun не имеет отдельного разъема питания и получает питание от базовой платы контроллера Arduino Uno R3. По питанию цепи разделены на две линии: питание совмещенного контроллера USB-хоста + слот для карты памяти MicroSD и питание процессорной части шилда. Чтобы избежать перегрева встроен- ного стабилизатора базовой платы, процессорная часть шилда питается от собст- венного импульсного преобразователя, вход которого соединен непосредственно с разъемом питания базовой платы. Поэтому шилд Dragino Yun невозможно питать напряжением 5 В от USB-порта компьютера. Следует подавать на разъем питания базовой платы питание 7..Л 5 В от отдельного источника. Контроллер USB-хоста питается напряжением 5 В, которое поступает со стабили- затора базовой платы. Этим напряжением питаются также все внешние устройства, подключенные к USB-хосту Dragino Yun. Функции кнопки сброса Dragino Yun Кнопка сброса расположена возле разъема USB-хоста. Кратковременное (менее 5 секунд) нажатие на эту кнопку приводит к перезагрузке модуля Wi-Fi. Нажатие на кнопку сброса дольше пяти, но менее 30 секунд, приводит к сбросу на- строек Wi-Fi. После этого Dragino Yun вновь запускает открытую беспроводную точку доступа с именем Dragino-*******. Эта функция кнопки сброса удобна в случае, когда шилд оказался в зоне действия новой беспроводной сети и не может к ней подключиться. Если проводное подключение через разъем Ethernet недоступ- но, то спасти положение может только сброс сетевых настроек. Длительное (более 30 секунд) нажатие на кнопку сброса приводит к сбросу всех настроек Linux до начального состояния (factory reset), в котором шилд находится сразу после покупки или перепрошивки. При этом удаляются все ранее установ- ленные файлы и сетевые настройки. Применяйте такой сброс только в крайнем случае! Добавление платы Dragino Yun в Arduino IDE Для корректной работы платы шилда Dragino Yun, подключенного к платам Uno, Leonardo и Mega2560, необходимо добавить специальное описание в перечень плат Arduino IDE. Откройте пункт меню Файл | Настройки и вставьте ссылку http: //www. dragino. com/downloads/downloads/YunShield/package_dragino_yun_test 1 Cm. http://www.bhv.ru/books/book.php?id=198923.
Глава 4. Подключение Arduino к сети Интернет 63^ index, json в поле Дополнительные ссылки для Менеджера плат. Если в этом поле уже есть ссылки, их надо разделить запятой. Теперь перейдите к менеджеру плат и дождитесь, пока он соединится с ресурсом по указанной ссылке и обновит список плат. Затем найдите в списке менеджера строку с названием Dragino Yun by Dragino Technology (рис. 4.5) и нажмите кнопку Установка. После этих мани- пуляций в списке Инструменты | Плата появится раздел Dragino Yun. Рис. 4.5. Установка набора плат Dragino Yun в среде Arduino IDE Начинающие разработчики могут спросить, почему мы добавляем новые платы, а не воспользуемся готовым пунктом Arduino Yun из стандартного пакета Arduino IDE? Дело в том, что мы используем универсальный шилд, который может под- ключаться к разным платам Arduino, содержащим различные микроконтроллеры. При помощи Arduino IDE мы программируем не шилд, а плату контроллера. Шилд используется только в качестве средства сетевой коммуникации. Поэтому компиля- тор Arduino IDE должен «знать», для какого контроллера компилировать скетч. Пе- речень из трех плат: Leonardo, Uno и Mega2560 — фактически перекрывает все не- обходимые варианты контроллеров. Например, если вы вдруг захотите подключить шилд Dragino Yun к плате Arduino Nano, вам следует выбрать в списке плат пункт Arduino Uno — Dragino Yun, потому что в платах Nano и Uno используется один и тот же процессор ATmega328. Иными словами, ключевое значение имеет не назва- ние платы, а применяемый в ней процессор. Подключение шилда к компьютеру для настройки При первом включении ненастроенный шилд работает в режиме открытой точки доступа Wi-Fi.
64 Часть I. Необходимое оборудование и программы Подключите шилд к базовой плате Arduino и подайте питание от источника посто- янного тока 7... 15 В. Шилд должен мигнуть всеми светодиодами. А Если светодиоды хаотично мерцают или горят вполнакала, у вас проблемы с источ- ником питания. Учтите, что шилд не начинает работать сразу после включения. За- грузка ОС Linux занимает примерно 90 секунд. Когда загорится синий светодиод WLAN, устройство готово к работе. Теперь нужно подключиться к шилду по Wi-Fi при помощи ноутбука, планшета или смартфона. Найдите открытую точку доступа с именем Dragino-******* и подключитесь к ней. В браузере введите адрес веб-интерфейса: 192.168.240.1 (рекомендуется использовать браузеры Chrome или Firefox). Пароль доступа к панели управления по умолчанию: dragino. После входа в веб-интерфейс нажмите кнопку SYSTEM. На этой странице вы мо- жете настроить следующие параметры: ♦ YUN NAME — имя, под которым устройство будет видно в локальной сети; ♦ PASSWORD — общий пароль для доступа ко всем сервисам, требующим авто- ризации. По умолчанию dragino; ♦ TIMEZONE — часовой пояс вашего географического положения; ♦ CONFIGURE A WIRELESS NETWORK— если опция выбрана, то после на- стройки подключения к вашему роутеру Wi-Fi и перезагрузки шилд перейдет в режим клиента и подключится к вашей беспроводной сети; ♦ DETECTED WIRELESS NETWORK — список доступных беспроводных се- тей. Выберите в нем ваш домашний роутер Wi-Fi, к которому будет подключен шилд; ♦ WIRELESS NAME, SECURITY — заполняются автоматически после выбора точки доступа; ♦ PASSWORD — пароль вашего роутера Wi-Fi; ♦ REST API ACCESS— шилд поддерживает так называемый REST API— специальный стандарт обмена данными с платой Arduino через адресную строку браузера. Например, в строке браузера можно в явном виде указать номер выво- да платы Arduino и логический уровень. Шилд расшифрует адресную строку, преобразует ее в команду для платы Arduino и передаст через последовательный порт. Если вы работаете только внутри домашней сети, то можно установить режим без пароля: OPEN. Для открытых сетей и критичных приложений реко- мендуется оставить режим доступа с паролем: WITH PASSWORD. Закончив настройки на этой вкладке, нажмите кнопку CONFIGURE & RESTART. Дождитесь перезагрузки шилда и включения синего светодиода WLAN на плате. После настройки подключения Wi-Fi и перезагрузки шилд перестанет работать в режиме беспроводной точки. Надо определить новый IP-адрес устройства в вашей локальной сети одним из следующих способов:
Глава 4. Подключение Arduino к сети Интернет 65^ ♦ войдите в административную панель вашего маршрутизатора Wi-Fi и найдите там IP-адрес шилда в списке подключенных устройств; ♦ запустите Arduino IDE и подождите около минуты, пока идет поиск шилда в се- ти. Затем перейдите в меню Инструменты | Порт и найдите сетевой порт в спи- ске (рис. 4.6). Рис. 4.6. Определение IP-адреса шилда и задание сетевого порта Arduino IDE Если шилд не получает IP-адрес при соединении по Wi-Fi, сбросьте сетевые настройки нажатием на кнопку сброса дольше пяти, но меньше тридцати секунд, снова перейдите на страницу SYSTEM и проверьте правильность настройки под- ключения к Wi-Fi. Определив новый IP-адрес, подключитесь к веб-интерфейсу шилда для продолже- ния работы. Определение типа базовой платы Нажмите кнопку SENSORS на главной странице веб-интерфейса. Шилд может ав- томатически определять тип процессора, установленного на базовой плате (рис. 4.7), и обычно делает это правильно. Убедитесь, что плата контроллера опре- делена верно. Если по каким-либо причинам автоматическое определение не срабо- тало, тип процессора и платы можно задать вручную из небольшого списка. Если установлен флажок UPLOAD BUTLOADER, то вместе с кодом прошивки в процессор базовой платы Arduino будет записан бутлоадер (начальный загруз- чик). Это может быть полезно, если бутлоадер не был записан раньше или повреж- ден, а также если плата не определяется правильно. В остальных случаях запись бутлоадера не требуется, и флажок можно снять. На этом основные настройки шилда завершены.
Часть I. Необходимое оборудование и программы Загрузка скетча через сеть из Arduino IDE Запустите Arduino IDE, выберите правильный тип базовой платы, подключенной к шилду. В списке портов выберите сетевой порт (см. рис. 4.6). Обычным путем отправьте скетч на загрузку в плату. Перед началом прошивки будет запрошен па- роль ДОСТупа. По умолчанию: dragino. При помощи веб-интерфейса вы можете загрузить скомпилированный код прошив- ки (файл с расширением hex). Чтобы получить этот файл, выберите в меню Arduino IDE пункт Скетч | Экспорт бинарного файла. После завершения компиляции скетча выберите пункт Скетч | Показать папку скетча. В ней будут находиться два варианта файла с расширением hex: с бутлоадером и без бутлоадера. Для за- грузки в стандартную плату Arduino бутлоадер не нужен. Полученный бинарный файл вы можете загрузить в плату с любого компьютера, имеющего сетевое под- ключение к шилду (рис. 4.7). ШЧ.ОДО SKI: ГСП Рис. 4.7. Определение типа процессора и загрузка бинарных файлов в плату Arduino Далее мы будем считать, что ваш шилд подключен к плате контроллера Arduino Uno. Не подключайте плату контроллера к компьютеру проводом USB! Запустите среду разработки Arduino IDE. Откройте базовый пример мигания свето- диодом: Файл | Примеры | Basics | Blink. Выберите плату Arduino Uno — Dragino Yun и сетевой порт, как на рис. 4.6. На- жмите кнопку загрузки в плату в Arduino IDE. По запросу введите пароль к шилду,
Глава 4. Подключение Arduino к сети Интернет 67_ и прошивка будет загружена в плату через беспроводное соединение Wi-Fi. После загрузки скетча светодиод на плате контроллера начнет мигать. Подключение к Wi-Fi и вывод сообщений в консоль Linux Если контроллер Arduino подключен к USB-порту компьютера через конвертер USB-UART, то данные отправляются в последовательный порт при помощи встро- енной библиотеки Serial. Но шилд Dragino Yun занимает стандартный последовательный порт Arduino RX0/TX0 под обмен данными с ОС Linux сетевого модуля. Для вывода отладочных и служебных сообщений будет логично воспользоваться консолью Linux и библио- текой Console. В качестве окна консоли для получения и отправки символьных данных можно ис- пользовать стандартный монитор порта Arduino IDE. Когда установлено соедине- ние Arduino IDE с сетевым портом, монитор порта автоматически превращается в терминал Telnet. Но встроенный монитор в режиме консоли работает очень не- стабильно и медленно, из-за чего буфер консоли может переполняться и терять части больших сообщений. Мы воспользуемся более надежным инструментом— универсальной утилитой PuTTY, которую можно скачать по адресу www.putty.org, и научимся работать с консолью на примере скетча из листинга 4.4. Откройте в Arduino IDE файл исходного кода. Мы уже указали имя сети и пароль Wi-Fi в настройках шилда Dragino Yun, поэтому в исходном коде скетча ничего не надо менять. Загрузите скетч в плату контроллера через сетевой порт. Запустите программу PuTTY. В поле Host address введите IP-адрес вашего шилда Dragino Yun. Номер порта 22 не меняйте. Ниже должна быть выбрана опция Connection type — SSH. Нажмите кнопку Connect, введите имя пользователя root и пароль по умолчанию dragino или новый пароль, который вы задали при на- стройке шилда. Введите в окно терминала PuTTY команду telnet locaihost 6571 (рис. 4.8). Теперь все сообщения, отправленные в консоль контроллером Arduino, отобразятся в окне терминала PuTTY. Для отключения от порта Telnet нажмите комбинацию клавиш <Ctrl>+<C>, а затем клавишу <Е>. #include <Bridge.h> // Библиотека Bridge #include <BridgeClient.h> // Библиотека http-клиента Bridge #include <Console.h> // Библиотека онлайн-консоли BridgeClient client; // Объект сетевого подключения void setup() { Bridge.begin(); // Активируем соединение Bridge Console.begin(); // Запускаем консоль только ПОСЛЕ Bridge
Часть I. Необходимое оборудование и программы while (!Console); // Ждем окончание запуска консоли Linux Console.println("Done!"); // Подключаемся к серверу по заданному адресу, порт 80 (HTTP) if (client.connect("reedpaper.com", 80)) { Console.println("Connected to server."); } else { Console.println("Can't connect to server"); while (1); // Если не удалось подключиться, останавливаем программу } Console.println("Send request to server..."); // Отправляем на сервер стандартный HTTP-запрос //на получение содержимого файла test.txt //и разрываем связь с сервером после получения файла client.print("GET /files/test.txt HTTP/1.l\r\n"); client.print("Host: www.reedpaper.com\r\n"); client.print("Connection: close\r\n\r\n"); void loopO { // Выводим ответ сервера в консоль while (client.available()) { char chr = client.read(); Console.print(chr); login as: root root8l92.168.1.159's password: BusyBox vl.19.4 {2015-01-06 10:25:28 CST) built-in shell {ash) Enter 'help* for a list of built-in commands. I _ \l _ \ / \ / l_ J \ ! I/ _ \ I I I I l_) I /_\| I I I! \! I I i I ! l_l I _ < / \ l_l II II l\ I M ! I /\_\ W_/ \_\ i !_l \_l\ / W i F i, Linux, M С U, Embedded Model: Dragxno v2 Version: Dragino-v2 conaaon-2.0.7 Build Tue Nov 24 19:39:50 CST 2015 www.dragino.com root9dragino-15e324:~# telnet localhost €57l| Рис. 4.8. Подключение к консоли Linux no Telnet
Глава 4. Подключение Arduino к сети Интернет 69_ В начале скетча мы подключаем библиотеку Bridge, которая обеспечивает комму- никацию по последовательному порту между контроллером Arduino и сетевым шилдом. Мы также воспользуемся библиотекой Bridgeciient, которая обслуживает объект подключения к сети Интернет. В предыдущих примерах этого раздела мы уже создавали объект сетевого клиента при помощи других библиотек. Библиотека Console позволяет выводить строки символов в консоль Linux при помощи стандартных методов, идентичных библиотеке serial. Далее мы активируем соединение Bridge и запускаем консоль Linux командами: Bridge.begin() ; Console.begin(); Команды должны следовать именно в таком порядке! Остальная часть скетча идентична листингам 4.1-4.3. Различие лишь в том, что вместо команды serial, print о применяется команда console, print о. Контроллер соединяется с сервером по протоколу HTTP, передает серверу GET-запрос на ска- чивание файла и выводит в консоль ответ сервера и содержимое файла. Итак, мы научились подключать контроллер Arduino к сети Интернет по проводно- му и беспроводному каналам. Мы убедились, что, независимо от оборудования, в простых проектах после создания сетевого клиента можно забыть про аппарат- ную часть и дальше использовать стандартные методы работы с сетью. Эти знания пригодятся нам при работе над проектами сетевого мониторинга и онлайновой приборной панели.
ГЛАВА 5 Визуализация данных Наглядное отображение данных — это очень важная часть проекта! Схемы и про- шивки спрятаны «под капотом» устройства, а пользователь видит только готовые цифры и графики на дисплее. Поэтому разработчики стараются, чтобы результаты измерений отображались наглядно и красиво. Изучите эту главу, чтобы уверенно использовать различные дисплеи и плоттеры в своих проектах. Общая задача всех устройств, о которых рассказано в книге, — выполнять измере- ния и генерировать поток данных. Но сами по себе эти данные бесполезны, если мы не можем их обработать и истолковать. Некоторые данные— например, статистику интенсивности солнечного излуче- ния, — можно накапливать в течение заданного периода времени, а потом на осно- вании этих данных построить наглядный график. Другие данные — например, час- тота пульса или температура тела, — обычно востребованы в режиме реального времени. В любом случае, результаты измерений должны быть показаны в доступ- ной для человеческого понимания форме. Быстро меняющиеся параметры мы будем отображать в виде графика, а результаты периодических измерений выводить в числовом виде. Иногда для удобства отладки и проведения наглядных экспериментов совмещают оба типа данных на одном дисплее. Например, в опытах с измерением частоты пульса полезно следить не только за числовым значением частоты пульса, но и за графиком уровня насыще- ния крови кислородом. 5.1. Построение графиков на компьютере Среди инструментов, которые строят графики на основе ранее сохраненных дан- ных, пользователям наиболее известны встроенные графопостроители Microsoft Excel и пакета MATLAB. Эти программы также обладают средствами анализа и обработки данных. Но при аппаратном мониторинге физических параметров часто требуется построение графика в реальном времени, синхронно с поступающим по- током данных. Раньше эту работу выполняли специальные электромеханические устройства — графопостроители. Они рисовали график на движущейся бумажной
Глава 5. Визуализация данных 71_ ленте или вращающемся барабане. Даже сегодня многие врачи получают и иссле- дуют кардиограмму на бумажной ленте. На смену механическим графопостроителям пришли специальные программы с выводом графиков на экран дисплея. Эти программы обладают множеством по- лезных функций — таких, как цифровая фильтрация и обработка сигнала в режиме реального времени. Но большинство профессиональных программ-графопост- роителей предназначены для работы со специальным оборудованием в условиях научной лаборатории или производственного предприятия. И стоят они очень до- рого. Для работы с любительскими проектами Arduino разработано много простых бес- платных и условно бесплатных программ, которые получают данные через после- довательный порт и отображают легкочитаемые графики в режиме реального вре- мени. В этой главе мы познакомимся с тремя такими популярными программами: встроенным плоттером Arduino IDE и графопостроителями Serial Port Plotter и FlexiPlot. 5.1.1. Встроенный плоттер Arduino IDE Среда разработки Arduino IDE оснащена простым встроенным средством построе- ния графиков. Это инструмент Serial plotter, который в русской версии имеет длин- ное название: Плоттер по последовательному соединению. Для удобства мы будем далее называть этот инструмент просто «плоттер». Окно плоттера можно вызвать из меню Инструменты или комбинацией клавиш <Ctrl>+<Shift>+<L>. Плоттер предельно прост и не имеет никаких настроек, кроме скорости соединения. Плоттер может строить графики одновременно по несколь- ким величинам (несколько кривых). Формально количество величин нигде не огра- ничено в явном виде, но на практике график, состоящий более чем из трех линий, трудно читается визуально. Данные передаются в плоттер в виде текстовой строки определенного формата. Нельзя вставлять в строку никакие другие символы, кроме цифр. Значения в виде десятичных чисел разделяют пробелом или символом табуляции \t. Строка долж- на завершаться символом перевода строки. Каждый символ перевода строки явля- ется для плоттера командой отрисовать очередные точки на графике. Плоттер имеет неотключаемое автоматическое масштабирование значений по оси Y. Это достоинство и одновременно недостаток. Наличие автомасштабирования полезно для несложных проектов, но мешает и раздражает, если приходится на- блюдать несколько разных сигналов, когда значения меняются в широком диапазо- не, а график при этом сам по себе увеличивается и уменьшается. Масштабирование по оси X не предусмотрено. График сдвигается настолько быст- ро, насколько часто поступают новые данные. Загрузите в плату Arduino простой демонстрационный скетч из листинга 5.1.
72 Часть /. Необходимое оборудование и программы #define DEG_TO_RAD 0.01745329 void setup() { Serial.begin(115200); void loopO { for (float angle = 0; angle < 360; angle++) { Serial.print(angle/100); Serial.print(" "); Serial.print(sin(DEG_TO_RAD * angle)*10) ; Serial.print(" "); Serial.println(cos(DEG_TO_RAD * angle)); delay(10); Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). В этом скетче мы строим в окне плоттера синусоиду, косинусоиду и график изме- нения аргумента тригонометрических функций. Два первых значения мы выводим Рис. 5.1. Окно встроенного плоттера Arduino IDE
Глава 5. Визуализация данных 73_ в порт командой print о, а последнее значение— командой printino, которая автоматически добавляет символ перевода строки. Если открыть окно монитора последовательного порта, то мы увидим поток обычных числовых данных. Откры- вать одновременно окна монитора и плоттера нельзя — с последовательным пор- том может общаться только один инструмент. Откройте окно плоттера. В нем должна сразу же начаться прорисовка трех графи- ков (рис. 5.1). Если ничего не происходит, проверьте настройку скорости соедине- ния в правом нижнем углу окна плоттера. К достоинствам встроенного плоттера можно отнести простоту использования, простой и очевидный формат данных. К недостаткам — отсутствие настроек, неот- ключаемое автомасштабирование, отсутствие легенды графика (подписей к кри- вым), невозможность сохранить данные в файл или отобразить ранее сохраненные данные. 5.1.2. Графопостроитель Serial Port Plotter Программа Serial Port Plotter не требует установки. Исполняемый файл для опера- ционных систем Windows и Linux можно скачать по адресу https://github.com/ CieNTi/serialjport^^plotter/releases. На момент подготовки книги была доступна версия 1.3.0 от 8 сентября 2018 г. Извлеките каталог с файлами из архива и сохра- ните в любом удобном месте. Автоматическая проверка обновлений в программе пока не предусмотрена, поэтому я рекомендую регулярно проверять наличие новых версий. Формат пакета данных немного отличается от формата встроенного плоттера Arduino: пакет обязательно должен начинаться с символа $ и заканчиваться симво- лом ;, значения внутри пакета разделяются пробелами, символ перевода строки не нужен. Каждому значению соответствует свой канал данных, к которому привязан график. Причем новый канал может появиться в пакете данных в любой момент— про- грамма это распознает и начнет рисовать еще один график. Программа не ограни- чивает количество каналов, но для окраски линий графика доступен только цикли- чески повторяющийся набор из 14 цветов. Загрузите в плату Arduino скетч из листинга 5.2 (это слегка доработанный скетч из листинга 5.1). #define DEG_TO_RAD 0.01745329 void setup() { Serial.begin(115200); void loop() { for (float angle = 0; angle < 360; angle++)
_74 Часть I. Необходимое оборудование и программы { Serial.print("$") ; Serial.print(angle/100); Serial.print(" "); Serial.print(sin(DEG_TO_RAD * angle)*10); Serial.print(" "); Serial.print(cos(DEG_TO_RAD * angle)); Serial.print(";"); delay(10); Запустите программу. В меню PORT CONTROLS (слева от панели графопострои- теля) выберите номер порта, к которому подключена плата, и задайте скорость 115200. Нажмите кнопку с изображением треугольника ► в верхней строке меню, чтобы подключиться к порту и запустить отрисовку графика (рис. 5.2). Рис. 5.2. Окно программы Serial Port Plotter (из-за ограничений типографской технологии рисунок дан в негативе) Если линии графика не умещаются в панели, или, наоборот, график отображается слишком мелко, нажмите кнопку Autoscale Yaxis (автоматический масштаб по оси Y) — график будет автоматически отмасштабирован к размерам окна. Масштаб по оси X можно изменять вращением колесика мыши.
Глава 5. Визуализация данных 7Ь_ Если параметры сигнала известны заранее, или требуется ручная корректировка масштаба, воспользуйтесь панелью настройки PLOT CONTROLS. Видимость линий графика можно выключать и включать двойным щелчком на имени канала в левой панели. Если вы забыли, какие каналы выключены, можно вернуть их все на экран нажатием кнопки Reset All Visible. Под панелью графопостроителя расположено окно текстового терминала, в кото- ром отображается поток входных данных. Терминал можно скрыть кнопкой Hide TextBox. Легенда графика (подписи к линиям) расположена в правом верхнем углу. Подписи можно редактировать двойным щелчком на имени канала в легенде. Разрешено ис- пользовать символы кириллицы. Все поступающие данные сохраняются в буфере до тех пор, пока хватает памяти компьютера. Благодаря этому, график можно «прокрутить» обратно, просто про- таскивая мышью вправо. Это очень удобная опция для детального изучения графи- ка в определенном интервале времени. Данные из буфера можно сохранить в CSV- файл, если нажать значок с изображением листа бумаги в верхнем меню. Изображение графика можно сохранить в графическом файле формата PNG. Все файлы пока сохраняются непосредственно в главный каталог программы, диало- говое окно сохранения файла не выводится. Возможно, это окно будет добавлено в новой версии программы. 5.1.3. Графопостроитель FlexiPlot Графопостроитель FlexiPlot находится в процессе разработки, но уже сейчас обла- дает большим количеством настроек и функций. Скачайте архив файлов програм- мы по адресу https://github.com/xcoderl23/FlexiPlot/releases. Программа не требу- ет установки. Распакуйте архив в удобное место. FlexiPlot позволяет открыть несколько рабочих окон графопостроителя (Chart), и в каждом окне можно независимо и одновременно строить до 256 графиков. Каж- дому окну присвоено уникальное имя (индекс окна). Этот индекс необходимо ука- зать в пакете данных, чтобы программа поняла, в какое окно направить пакет. FlexiPlot может рисовать не только обычные графики в ортогональной системе ко- ординат— предусмотрены функции рисования столбчатых диаграмм различного вида и свободный графопостроитель по заданным точкам. Пакет данных для рисования графика заключен в фигурные скобки, данные разде- ляются символом вертикальной черты |. Формат пакета имеет следующий вид: {Index | Name_l I Colour_l | Value_l I Name_2 | Colour_2 I Value_2} где: ♦ index — имя окна, в которое отправлен пакет; ♦ Namel — подпись первой кривой в легенде графика; ♦ Coiouri — цвет первой кривой графика в формате r, G, в (например, 255, о, о);
76^ Часть I. Необходимое оборудование и программы ♦ vaiuel — текущее значение для первой кривой графика; ♦ Name_2 — подпись второй кривой в легенде графика; ♦ Coiour_2 — цвет второй кривой графика в формате r, G, в; ♦ vaiue_2 — текущее значение для второй кривой графика, и т. д. — для каждой величины, которая должна быть прорисована в окне с соот- ветствующим индексом. Пакет должен завершаться символом перевода строки. Такой объемный пакет данных позволяет очень гибко настраивать отображение графиков. Например, можно на ходу менять цвет линии графика в зависимости от величины отображаемого параметра. Но большая длина пакета вынуждает исполь- зовать высокую скорость передачи данных в порт (115 200 бод) и выдерэюивать паузу не менее 5 мс меэюду пакетами, чтобы избежать переполнения буфера порта и потерю данных. Загрузите в плату Arduino демонстрационный скетч из листинга 5.3. Этот скетч от- правляет текущее значение аргумента angle в окно ро, а значения тригонометриче- ских функций sin о и cos о — в окно pi. j #define DEG_TO_RAD 0.01745329 void setup() { Serial.begin(115200); void loop() { for (float angle =0; angle < 360; angle++) { // Пакет данных для окна Р0 Serial.print("{P0|Angle|0,0,255Iй); Serial.print(angle); Serial.println("}"); // Пакет данных для окна PI Serial.print("{PI|Sin|255,0,0|"); Serial.print(sin(DEG_TO_RAD * angle)*10); Serial.print("|Cos|0,255, 0|") ; Serial.print(cos(DEG_TO_RAD * angle)); Serial.println("}") ; 1. Запустите программу FlexiPlot. Настройте номер последовательного порта (оп- ция Port) и установите скорость обмена 115200 бод (опция Baudrate).
Глава 5. Визуализация данных 77_ 2. Выберите пункт меню Graph | Add Line Chart или нажмите кнопку графиче- ского меню с изображением графика — на экране появится рабочее окно гра- фопостроителя, которое надо настроить. Растяните это окно на всю ширину окна программы и на половину его высоты. 3. Перейдите на вкладку Settings и введите в поле Title название окна— напри- мер, Аргумент функций. 4. В поле Buffer введите значение юоо — это размер буфера. С такой настройкой буфер будет хранить 1000 выборок. Вновь поступающие значения вытесняют устаревшие данные. 5. В поле Refresh Rate введите значение ю — это интервал между обновлениями изображения в миллисекундах. Чем меньше его значение, тем плавнее движет- ся график, но выше нагрузка на процессор компьютера. 6. Уберите флажок Auto Scaling Y (автомасштабирование по оси Y). В нашем случае мы заранее знаем, что отображаемое значение изменяется в диапазоне от о до 360, поэтому можем настроить масштаб вручную. Для этого в поле Min Y введите о, а в поле Max Y — 400. 7. Добавьте еще одно рабочее окно и расположите его под предыдущим окном. Введите заголовок окна— например, значения функций. Значения Buffer и Refresh Rate скопируйте из настроек первого окна, чтобы графики прорисовы- вались синхронно. 8. Уберите флажок Auto Scaling Y. В поле Min Y введите -ю, в поле Max Y — ю. 9. Для сохранения всех настроек и расположения рабочих окон нажмите кнопку с изображением дискеты или выберите пункт меню File | Save. 10. Вернитесь к вкладкам Chart. Выберите пункт меню Serial | Connect. Плата Arduino перезагрузится и начнется прорисовка графиков (рис. 5.3). Если этого не произошло, проверьте настройку номера и скорости порта, а также настройки рабочих окон. При большой нагрузке на процессор компьютера может искажаться прорисовка гра- фиков. В ответственных случаях лучше не запускать на компьютере одновременно с FlexiPlot какие-либо ресурсоемкие программы. Дополнительные настройки рабочего окна графика Вы можете также задать следующие дополнительные настройки: ♦ Date Format— формат меток реального времени по оси X (часы:минуты: секунды). Можно оставить только нужную метку или полностью убрать метки времени; ♦ Auto Filling — автоматическая заливка цветом областей под кривой графика; ♦ Auto Fill Opacity — интенсивность цвета заливки. По умолчанию — 20%.
78 Часть I. Необходимое оборудование и программы Рис. 5.3. Рабочее окно программы FlexiPlot с демонстрационными графиками Встроенный терминал В программе имеется встроенный терминал последовательного порта, доступный в меню Serial | Terminal. Это обычный терминал, который позволяет отправлять символы и шестнадцатеричные числа в плату Arduino и отображать поступающие данные. Опция Filter Plotting Packets отсекает пакеты данных и пропускает только символы, не входящие в пакеты. Эта опция позволяет отправлять в графопострои- тель отладочные сообщения в интервале между пакетами данных. Рисование столбчатых диаграмм FlexiPlot может в режиме реального времени рисовать наглядные столбчатые диа- граммы по данным, поступающим от платы контроллера Arduino. Каждый новый пакет полностью обновляет диаграмму. Формат пакетов данных для диаграммы представлен в двух вариантах: с автомати- ческим выбором цвета столбцов и с явным указанием цвета. Пример пакета данных с автоматическим выбором цвета имеет следующий вид: {P0|Night;Morning;Day;Evening|Inside|12 15 17 14lOutside|8 15 23 19}
Глава 5. Визуализация данных 79 Сначала, как обычно, идет индекс (имя) рабочего окна. Далее через точку с запятой задаются имена групп столбцов. Их может быть сколь угодно много. В нашем при- мере это четыре группы: ночь, утро, день и вечер. Допустим, мы измеряем темпера- туру внутри помещения (inside) и снаружи (outside) четыре раза в сутки (т. е. по- лучаем по четыре группы значений для каждого типа замеров). Соответственно, после названия величины типа замера в пакете следуют четыре значения, разделен- ные пробелами. Затем идет название следующей величины и ее значения. Этот шаблон повторяется нужное количество раз. В строке пакета нельзя использовать кириллицу и специальные символы. Воспользуемся встроенным инструментом отладки FlexiPlot — Packet Injector — который позволяет имитировать получение пакетов через последовательный порт. Благодаря этому инструменту мы можем экспериментировать с содержимым паке- тов и вариантами прорисовки диаграммы без программирования контроллера Arduino. 1. Выберите пункт меню Graph | Add Bar Graph — чтобы открыть новое окно рисования столбчатых диаграмм. 2. Выберите пункт меню Tools | Debug Tools — чтобы запустить инструмент от- ладки. Введите в поле Packet пример пакета данных с автоматическим выбором цвета и нажмите клавишу <Enter>. В рабочем окне должна появиться диаграмма (рис. 5.4). Если ничего не произошло, проверьте правильность ввода пакета данных. Чтобы повторить отправку пакета, выделите нужную строку в поле History. Рис. 5.4. Пример построения столбчатой диаграммы из четырех групп с автовыбором цвета
J30 Часть I. Необходимое оборудование и программы 3. Перейдите на вкладку Settings в рабочем окне. В вашем распоряжении богатый выбор настроек внешнего вида диаграммы: • Name of X Axis и Name Of Y Axis — подписи осей координат. Можно ис- пользовать кириллицу; • Bar Chart Type — выбор типа диаграммы: обычная (Normal), с наложением столбцов (Stacked), с наложением в процентах (Percent), горизонтальная (Horizontal), горизонтальная с наложением (Horizontal Stacked), горизон- тальная в процентах (Horizontal Percent); • Animation— адимация при прорисовке диаграммы: без анимации (No Animation), анимация осевой разметки (Grid/Axis Animation), анимация столбцов (Series Animation), анимация всех элементов (All Animations); • Theme — выбор темы оформления диаграммы; • Anti-Aliasing — сглаживание изображения; • Legend — настройка отображения, расположения и шрифта текста легенды диаграммы; • Labels — настройка отображения и расположения текстовых меток на диа- грамме. По умолчанию числовое значение величины (@value) отображается в середине столбца; • Scaling— управление автоматическим масштабированием. Если диапазон значений известен заранее, можно задать минимальное и максимальное зна- чение в полях Min и Мах. Попробуйте менять параметры настроек и наблюдайте за изменениями на вкладке Chart. Выберите вариант настройки, который вам больше нравится. Цвет столбцов в формате r,g,b можно указать непосредственно в пакете. Для этого после названия величины надо вставить в пакет значение цвета: {P0|Night;Morning;Day;Evening|Inside|255,0,0|12 15 17 14|Outside|0,255,0| 8 15 23 19} В этом примере параметр inside будет отображен красными столбцами, а параметр Outside — зелеными. Динамические диаграммы Программа FlexiPlot не очень хорошо справляется с прорисовкой быстро меняю- щихся диаграмм. Плавность прорисовки столбцов зависит от быстродействия и загруженности процессора компьютера. Тем не менее мы можем успешно отобра- жать плавно меняющиеся параметры, изменять цвет столбцов в зависимости от величины параметра, изменять подписи столбцов и групп. Для этого достаточно сформировать нужный пакет данных в скетче Arduino. Загрузите в плату Arduino скетч примера из листинга 5.4.
Глава 5. Визуализация данных 81 int i, j; void setup() { Serial.begin(115200); void loop() { for (i = 0; i < 255; i = i + 5) { j = 255 - i; Serial.println((String)"{P0IS|dl|" + i + ",0," + j +"I" + i + ff|d2| 0,255,0 Г + j + "}"); delay(100); } for (int i = 255; i > 0; i = i - 5) { j = 255 - i; Serial.println((String)"{P0|S|dlГ + i + ",0," + j +"I" + i + (l|d2| 0,255,0 Г + j + "}"); delay(100); В этом скетче мы рисуем диаграмму из двух столбцов, высота которых плавно из- меняется в противоположных направлениях от 0 до 255 и обратно. При этом цвет первого столбца плавно меняется в зависимости от текущего значения параметра. Эффект достигается подстановкой переменных значений в компонент цвета в паке- те данных. В настройках графика отключите анимацию, отображение легенды и автомасшта- бирование. Задайте диапазон значений Min/Max от о до зоо. Попробуйте менять тип диаграммы Bar Chart Type и выберите наиболее подходящий для ваших задач. 5.1.4. Arduino плюс Excel — сбор и хранение данных Несмотря на широкое распространение облачных технологий и развитие систем обработки данных, в научных исследованиях и на производстве до сих пор часто применяется сбор, хранение и обмен данными в виде файлов Microsoft Excel. Если контроллер Arduino или другой прибор подключен к компьютеру через последова- тельный порт, можно без труда организовать автоматическое заполнение таблицы Excel, причем с поддержкой различных команд со стороны контроллера: заполне- ние ячеек, чтение ячеек, выбор рабочего листа таблицы, прокрутка листа и многое другое. Компания Parallax Software разработала специальное расширение (plugin) PLX- DAQ для автоматического заполнения таблиц Excel данными, которые поступают
82 Часть I. Необходимое оборудование и программы от приборов через последовательный порт. Несколько лет назад официальная под- держка этого расширения была прекращена. Но энтузиасты платформы Arduino не просто продолжили его поддержку, а выпустили в 2016 году новую версию расши- рения, которая совместима с последними 64-битовыми версиями MS Office и Windows 10. На официальном форуме Arduino создана специальная тема, посвященная этому расширению. Она расположена по адресу http://forum.arduino.cc/index.php? topic=437398.0. В первое сообщение темы разработчик регулярно добавляет ссылки на самую свежую версию расширения. На момент работы над книгой была доступ- на версия PLX-DAQ 2.11. Расширение не требует установки и представляет собой файл Excel с присоединен- ным макросом на языке VBA (Visual Basic for Applications). Пользователь открыва- ет файл, разрешает выполнение макросов и открывает последовательный порт, че- рез который поступают данные из контроллера Arduino. Строка сообщения Arduino содержит команды и данные. Макрос расширения счи- тывает строку из последовательного порта, выполняет команды и сохраняет данные в ячейки таблицы. Макрос может отправить данные из таблицы Excel в Arduino в ответ на запрос контроллера. Установка расширения на компьютер Скачайте архив с самой новой версией расширения. Распакуйте его в удобное место. Архив состоит из следующих файлов: ♦ PLX-DAQ-v2.11.xlsm— исходный шаблон файла Excel с макросом. Вы можете скопировать этот файл в другой каталог и переименовать или сохранить под другим именем; ♦ PLX-DAQ-v2-DefaultSketch.ino— демонстрационный скетч Arduino, который со- держит почти все возможные команды; ♦ Beginners Guide to PLX DAQ v2 (revi).doc — руководство пользователя; ♦ PLX-DAQ-v2-AutoGrapher-RandomValue.ino— демонстрационный скетч с генерато- ром случайных чисел и рисованием графика в реальном времени; ♦ PLX-DAQ-v2-AutoGrapher-RandomValue.xlsm — файл Excel с примером данных для демонстрационного скетча. Запуск расширения Откройте файл шаблона. Для запуска расширения необходимо разрешить выполне- ние макросов (рис. 5.5). Нажмите кнопку Параметры и в открывшемся окне на- строек выберите опцию Разрешить это содержимое. Если макрос не запустился автоматически, нажмите кнопку с надписью Open PLX DAQ UI в верхней части шаблона. Готовый файл Excel со встроенным макросом PLX-DAQ (файл DustSensorTestxIsm) можно найти в сопровождающем книгу электронном архиве (см. приложение 1).
Глава 5. Визуализация данных 83 Рис. 5.5. Запрос системы безопасности на разрешение запуска макросов По соображениям безопасности не рекомендуется глобально разрешать выполне- ние произвольных макросов в общих настройках Excel. Лучше потратить несколько секунд на включение макросов по запросу. Рабочее окно и органы управления После запуска макроса нажмите на кнопку Display direct debug, чтобы открыть поле, в которое выводятся поступающие данные и команды (рис. 5.6). Рис. 5.6. Окно макроса PLX-DAQ ♦ Port — номер порта, к которому подключен контроллер Arduino; ♦ Baud — скорость соединения, бод; ♦ Connect — установить соединение с портом; ♦ Pause logging / Resume logging — приостановить запись данных; ♦ Reset Timer — сбросить таймер макроса. Таймер используется для подстановки меток времени в таблицу и измерения продолжительности работы макроса Excel; ♦ Clear Columns — удаляет все данные из столбцов таблицы. Заголовки столбцов сохраняются;
84 Часть I. Необходимое оборудование и программы ♦ Display / Hide direct debug — показывает или прячет текстовое поле в правой части окна. В текстовом поле отображаются поступающие команды; ♦ Sheet name to post to — отображает список доступных листов текущей книги Excel. Данные будут сохраняться в лист, который выбран в списке. В документе такой лист обозначен опцией ActiveSheet. После добавления, удаления или пе- реименования листов обязательно нажмите кнопку Load для обновления списка; ♦ Controller Messages — отображает последнее сообщение, поступившее от кон- троллера. Обычно сообщения меняются очень часто, поэтому их удобнее на- блюдать в окне Direct Debug Window; ♦ Reset on Connect — обычно при подключении к порту происходит автоматиче- ский сброс контроллера. Эта опция позволяет отключить автоматический сброс, если нельзя прерывать работу контроллера; ♦ Custom Checkbox 1/2/3— пользовательские опции для управления работой контроллера. Arduino может задать подписи к флажкам в окне макроса, читать состояние флажков и выполнять определенные действия в зависимости от их наличия; ♦ Log incoming data? — запись входящего потока данных от контроллера в окно отладки. Уберите этот флажок, если возникают проблемы с быстродействием макроса; ♦ Log outgoing data? — запись исходящего потока данных из макроса в контрол- лер. Уберите этот флажок, если возникают проблемы с быстродействием мак- роса; ♦ Log system messages? — запись системной информации Excel (например, сооб- щений об ошибках). Уберите этот флажок, если возникают проблемы с быстро- действием макроса; ♦ Add timestamp? — добавление метки времени к каждой записи лога. Полезно для отладки; ♦ кнопка => — увеличивает размер окна отладки; ♦ кнопка <= — уменьшает размер окна отладки; ♦ Clear — удаляет все записи в окне отладки. А Не перемещайте окно макроса во время записи данных. Это может привести к сбою работы Excel и потере данных. Формат строки данных Arduino Строка команд выводится в порт командой serial.printinо. Для правильного об- мена данными между Arduino и макросом расширения строка должна иметь строго определенный формат. Вот пример стандартной строки: Serial.printin( (String) "DATA,DATE,TIME," +millis() );
Глава 5. Визуализация данных 85^ Команды строки данных можно условно разделить на основные группы: ♦ настройка и передача данных — команды для форматирования листа и пере- дачи данных; ♦ специальные команды и управление— команды для переключения между листами и использования управляющих полей Custom Checkbox для Arduino; ♦ рабочая книга Excel — команды для управления процессом записи данных или сохранения рабочей книги; ♦ прочие команды — дополнительные команды, которые не имеют важного при- кладного значения. Рассмотрим подробнее эти группы команд. Команды настройки и передачи данных ♦ clearsheet— полностью очищает рабочий лист (включая загловки столбцов!). Эта команда должна быть первой в любом скетче. Пример: Serial.printIn("CLEARSHEET"); ♦ cleardata — очищает только данные (начиная со второй строки таблицы). Пример: Serial, print In ("CLEARDATA") ; ♦ label — устанавливает заголовки столбцов в первой строке таблицы. Пример: Serial.println("LABEL, Temperature, Humidity, Lightness"); ♦ data— самая главная и важная команда. Служит для передачи данных из Arduino в активный лист книги Excel. Вы можете передавать произвольные дан- ные, но должны разделить данные запятыми и обеспечить совпадение количест- ва столбцов данных и количества заголовков. Зарезервированные слова date, time и timer распознаются макросом и заменяются на соответствующие значения: слово date — на текущую системную дату компью- тера (например, 15.09.2018), слово time— на текущее системное время (например, 15:32:17), слово timer— на продолжительность текущего сеанса работы макроса в секундах (например, 1458). В строку можно добавить ключевое слово autoscrollxx. Распознав это слово, мак- рос автоматически прокручивает текущий лист так, чтобы в нижней части таблицы всегда были пустые строки. Число хх указывает, сколько строк с данными следуют выше последней строки с данными, — например, autoscroll_20. Специальные команды и управление ♦ cell, set — вводит произвольное значение в указанную ячейку таблицы. Можно работать как с активным листом (ActiveSheet), так и с любым другим листом. Пример ДЛЯ активного ЛИСТа: Serial .println ("CELL, SET, C9,myValue") ; Эта команда вводит значение myvalue в ячейку С9 активного листа.
Часть I. Необходимое оборудование и программы Пример для произвольного листа: Serial.println ("CELL, SET, ONSHEET,mySheet,C, 9,myValue") ; Эта команда вводит значение myvaiue в ячейку сэ листа с названием mysheet. Внимание! При высоких скоростях обмена могут возникнуть проблемы с обработкой команды set — макрос не будет успевать ее выполнить. В таком случае уменьшите скорость передачи данных или введите небольшую задержку перед командой. Обычно доста- точно задержки в диапазоне 3-100 мс (например, delay (Ю)). cell, get — извлекает данные из указанной ячейки и передает их в Arduino. На- пример, можно заранее сохранить в таблицу последовательность значений тем- пературы и времени, а термостат на основе Arduino будет поочередно считывать значения и выдерживать указанную температуру в течение заданного проме- жутка времени. Аналогичным образом можно управлять различными техноло- гическими процессами — от координатного станка до инкубатора. Контроллер Arduino должен не только отправить команду запроса, но и прочитать строку ответа. Тип данных ответа может быть integer (целое число) или string (строка). Вы должны быть уверены, что макрос отправит именно строку, если Arduino ждет строку, и целое число, если Arduino ждет число. Используйте для чтения ответа одну из следующих команд: Serial.readStringUntil(10); Serial.readStringUntil(10).tolnt(); Serial.readStringUntil(10).toFloat(); Число io в коде ASCII означает конец строки, поэтому следует использовать только это число. Пример кода Arduino: int myData; Serial.println("CELL,GET,C9"); // команда чтения из ячейки С9 myData = Serial.readStringUntil(10).tolnt(); // получение ответа Пример чтения содержимого ячейки С9 из произвольного листа mysheet: Serial.println("CELL,GET,FROMSHEET,mySheet,C,9"); Внимание! При высоких скоростях обмена могут возникнуть проблемы с обработкой команды get — макрос не будет успевать ее выполнить. В таком случае уменьшите скорость передачи данных или введите небольшую задержку перед командой. Обычно доста- точно задержки в диапазоне 3-100 мс (например, delay (Ю)). row — вы можете явно задать значение указателя строки, с которой будете рабо- тать. Например, когда записаны 20 строк данных, вы можете сбросить указатель до значения 2 и начать сначала заполнение строк. Примеры команд: Serial.println("ROW,SET,2"); Serial.println("ROW,GET"); int myRow = Serial.readStringUntil(10).tolnt();
Глава 5. Визуализация данных 87_ ♦ customboxi / custombox2 / custombox3 — вы можете задать подпись к опции, снять или установить флажок и прочитать состояние опции (булево значение false / true). Примеры: Serial.println("CUSTOMBOXI,LABEL,LED Light"); Serial.println("CUSTOMBOXI,GET"); boolean myV=CheckValue = Serial.readStringUntil(10).tolnt(); ♦ clearrange — очищает заданный диапазон строк (range) активного листа. Пример: Serial, println ("CLEARRANGE, В ДО, D, 20") ; Ф resettimer — сбрасывает счетчик продолжительности работы расширения. Пример: Serial.println("RESETTIMER"); Рабочая книга Excel ♦ PAUSELOGGING / RESUMELOGGING / STOPLOGGING Пауза ЗаПИСИ ДаННЫХ / ВОЗОбнОВ- ление записи / прекращение записи. Разумеется, расширение продолжит «слу- шать» и выполнять поступающие команды, даже если запись данных в ячейки приостановлена или прекращена. Пример: Serial.println("PAUSELOGGING"); ♦ saveworkbook — сохраняет рабочую книгу Excel под текущим именем. Команда полезна, если вы записываете данные в течение длительного времени и хотите периодически сохранять файл с данными. ♦ saveworkbookas— сохраняет рабочую книгу Excel под заданным именем. По умолчанию новый файл сохраняется в тот же каталог, где находился исходный файл, но вы можете задать новый каталог в строке имени файла. Пример сохранения в текущий каталог: Serial.println("SAVEWORKBOOKAS,MyNewWorkbookName"); Пример сохранения в подкаталог с именем mySubfolder: Serial.println("SAVEWORKBOOKAS,mySubfolder\Workbookname"); ♦ forceexcelquit — опасная команда! Немедленно прекращает работу Excel! Обя- зательно сохраните рабочую книгу перед отправкой этой команды. Пример: Serial.println("FORCEEXCELQUIT"); Прочие команды ♦ веер— всего лишь заставляет компьютер издать короткий звуковой сигнал встроенным звукоизлучателем материнской платы или корпуса. Полезно, если надо привлечь внимание пользователя, когда достигнуто определенное значение величины, которую вы измеряете. Пример: Serial.println ("ВЕЕР") ;
88 Часть I. Необходимое оборудование и программы ♦ msg — помещает заданный текст в метку сообщения Controller Message в окне расширения. Пример: Serial.println("MSG,Put your text here"); ♦ done— принудительно передает содержимое буфера последовательного порта со стороны Excel. ♦ getrandom — передает случайное число из Excel в Arduino. Это полезная коман- да, потому что Arduino не может самостоятельно генерировать случайные числа. Функции random о в Arduino требуется инициализация генератора случайных чисел начальным значением при помощи функции randomseed(value). Если на- чальное значение будет повторяться, то и вся последовательность полученных псевдослучайных чисел тоже будет повторяться. Обычно генератор случайных чисел Arduino инициализируют случайным значением, прочитанным с «висяще- го в воздухе» аналогового входа. Но если все входы заняты, начальное значение можно получить из Excel. Пример: Serial.println("GETRANDOM,-31313,32323"); int rndseed = Serial.readStringUntil(10).tolnt(); randomSeed(rndseed); Serial.println( (String) "1st number: " + random(0, 50)); Serial.println( (String) "2nd number: " + random(0, 50)); Serial.println( (String) "3rd number: " + random(0, 50)); Демонстрационный скетч PLX-DAQ Демонстрационный скетч, приведенный в листинге 5.5, основан на коде скетча из комплекта поставки расширения PLX-DAQ v.2.11. Скетч содержит почти все дос- тупные команды для работы с таблицей Excel. Загрузите скетч в плату Arduino. Откройте исходный шаблон файла Excel из ком- плекта поставки расширения. В поле Port введите номер последовательного порта, к которому подключена плата. Остальные настройки не меняйте. Нажмите кнопку Display direct debug в окне расширения. Затем нажмите кнопку Connect. Если все работает правильно, контроллер перезагрузится, и в окне отладки побегут строки команд и служебных сообщений, а таблица будет заполняться значениями. Обратите внимание, что изменились подписи к флажкам. Поставьте флажок Quit at 450. Как только значение счетчика скетча достигнет 450 (или уже превыси- ло 450 на момент установки флажка), Excel сохранит файл под новым именем и прекратит работу. Откройте сохраненный файл и посмотрите содержимое листов. Во втором листе с именем Further list должна быть заполнена ячейка G11.
Глава 5. Визуализация данных 89 int i = 0; void setup() { // последовательный порт на скорости 9600 Serial.begin(9600); //Serial.println("CLEARDATA"); // очистка листа со строки 2 Serial.println("CLEARSHEET"); // очистка листа со строки 1 // определяем пять столбцов с именами "Date", "Time", "Timer", "Counter" и "millis" Serial.println("LABEL,Date,Time,Timer,Counter,millis") ; // задаем подписи к трем флажкам (только латинские символы) Serial.println("CUSTOMBOXl,LABEL,Stop logging at 250?"); Serial.println("CUSTOMBOX2,LABEL,Resume log at 350?"); Serial.printIn("CUSTOMBOX3,LABEL,Quit at 450?"); // ставим флажки в первое и второе поля Serial.println("CUSTOMBOXl,SET,1"); Serial.println("CUSTOMBOX2,SET,l"); Serial.println("CUSTOMBOX3,SET,0"); void loop() { // выводим в таблицу данные и команду прокрутки Serial.println( (String) "DATA,DATE,TIME,TIMER," + i++ + "," + millis() + ",AUTOSCROLL_20" // альтернативный способ вывода строки по частям /* Serial.print("DATA,DATE,TIME,TIMER,"); Serial.print(i++); Serial.print(","); Serial.println(millis()); Serial.printC1,") ; Serial.println("SCROLLDATA_20"); */ // стираем некоторые ячейки (прямоугольник от В10 до D20) if (i == 100) Serial.println("ClearRange,B,10,D,20"); // звуковой сигнал, если i==150 if (i == 150) Serial.println("BEEP"); // читаем целое число из ячейки Е4 //в листе с заданным именем, если i==200 if (i == 200)
_90 | Часть I. Необходимое оборудование и программы // запрашиваем данные из листа Serial.println("CELL,GET,FROMSHEET,Further sheet,E,4"); // короткий вариант для чтения из текущего листа // Serial.println("CELL,GET,E4"); // получаем ответ Excel int readvalue = Serial.readStringUntil(10).tolnt(); // выводим значение в окно отладки Serial.println( (String) "Value of cell E4 is: " + readvalue); // проверяем значение CUSTOMBOX1 // если флажок установлен, приостанавливаем запись if (i == 250) { Serial.printIn("CUSTOMBOX1,GET"); int stoplogging = Serial.readStringUntil(10).tolnt(); // выводим сообщение в окно отладки Serial.println( (String) "Value of stoplogging/checkbox is: " + stoplogging); if (stoplogging) Serial.printIn("PAUSELOGGING"); // запрашиваем случайное число из компьютера, если i==300 if (i == 300) { Serial.println("GETRANDOM,-4321,12345"); // случайное число от -4321 до 12345 int rndseed = Serial.readStringUntil(10).tolnt(); // выводим сообщение в окно отладки Serial.println( (String) "Got random value f" + rndseed + "f from Excel" // теперь возобновляем запись, если i==350 и стоит флажок CUSTOMBOX2 if (i == 350) { Serial.println("CUSTOMBOX2,GET"); int resumelogging = Serial.readStringUntil(10).tolnt(); if (resumelogging) Serial.println("RESUMELOGGING"); // запись в заданную ячейку G10 текущего листа //и ячейку G11 произвольного листа if (i == 400)
Глава 5. Визуализация данных 91 I/ активный лист по умолчанию Serial.println("CELL,SET,G10,400 test 1 string"); // лист с именем "Further sheet" Serial.println("CELL,SET,ONSHEET,Further sheet,G,11,400 test 2"); // если i>=450 и установлен флажок CUSTOMBOX3 // сохраняем файл под другим именем и закрываем Excel if (i >= 450) Serial.println("CUSTOMBOX3,GET"); if (Serial.readStringUntil(10).tolnt()) { Serial.println("SAVEWORKBOOKAS,450-Lines-File"); Serial.println("FORCEEXCELQUIT"); else Serial.println("No forced Excel quit requested!"); 5.2. Онлайновая приборная панель Adafruit 10 Как быть, если вы хотите дистанционно наблюдать за показаниями приборов из любой точки мира? Для решения этой задачи разработаны специальные облачные сервисы — онлайновые приборные панели (online dashboard). Ваше устройство по сети Интернет соединяется с сервером онлайновых панелей и передает ему данные в стандартном формате. Сервер может выполнять предварительную обработку дан- ных, но чаще хранит данные в исходном «сыром» виде (raw data). Для просмотра данных вы обращаетесь к серверу через браузер — как при посеще- нии обычного сайта. Сервер формирует приборную панель, состоящую из видже- тов: графиков, стрелочных индикаторов, сигнальных лампочек — и отправляет эту панель в окно браузера. Приборная панель обычно обновляется при поступлении новых данных на сервер. На сегодняшний день пользователям доступен широкий выбор среди качественных и мощных приборных панелей, но есть проблема — большинство из сервисов тре- буют оплату с первого дня или предоставляют короткий пробный период с урезан- ным набором бесплатных функций. Такие сервисы плохо подходят для любителей, которые занимаются домашними проектами в свободное время. На мой взгляд, на сегодняшний день наиболее удачный компромисс между бес- платными и платными услугами предлагает компания Adafruit Industry, разрабо- тавшая сервис приборной панели Adafruit IO. Давайте научимся им пользоваться.
J92 Часть I. Необходимое оборудование и программы 5.2.1. Учетная запись и потоки данных Зарегистрируйте учетную запись на сайте www.adafruit.com. Эта учетная запись будет действительна для всех сервисов Adafruit. Учтите, что логин учетной записи будет задействован в атрибутах приборной панели и входит в состав URL, а также отображается на форуме. Перейдите по адресу io.adafruit.com и выберите бесплатный тариф. Этот тариф действует без ограничения срока, а его параметров достаточно для простых проек- тов: ♦ 10 потоков данных (подключенных источников); ♦ 5 приборных панелей; ♦ 30 входящих значений данных в минуту; ♦ 30 дней хранения данных на сервере. Получение главного ключа Нажмите на ссылку View AIO Key в левой части экрана. Откроется окно, в котором вы можете скопировать или заново сгенерировать главный ключ и посмотреть при- меры кода (рис. 5.7). Сохраните главный ключ в надежном месте. Это пароль, при помощи которого ваши устройства получают доступ к приборным панелям и данным. Если зло- Рис. 5.7. Получение главного ключа
Глава 5. Визуализация данных 93_ умышленник завладеет главным ключом, он получит доступ ко всем вашим при- борным панелям и данным наравне с вами. А После перегенерации ключа вам придется вручную изменить код прошивки у всех подключенных устройств. Создание групп и потоков Каждое подключенное устройство генерирует поток данных (feed). Созданные по- токи можно объединять в группы (group). Поток должен принадлежать хотя бы к одной группе. В учетной записи всегда есть группа по умолчанию default, к ко- торой автоматически добавляются потоки, не связанные с другими группами. Допустим, вы разместили датчики температуры и влажности на кухне и в спальне. Соответственно, вы создаете две группы с именами: kitchen (кухня) и bedroom (спальня). К группе kitchen вы привязываете потоки данных от кухонных датчиков kit-temp И kit-hum, а К группе bedroom — ПОТОКИ данных ОТ датчиков bedroom-temp И bedroom-hum. Старайтесь с самого начала придерживаться правил присвоения имен группам и потокам: ♦ только латинские символы, цифры и тире; ♦ понятные человеку названия. Нажмите ссылку Feeds (Потоки) в левой части экрана, затем выберите пункт Create a new Group (Создать новую группу) в раскрывающемся списке Actions (Действия). Введите имя kitchen и описание группы (рис. 5.8) и нажмите кнопку Create (Создать). Аналогичным способом создайте группу bedroom. Рис. 5.8. Создание новой группы потоков Нажмите ссылку Feeds в левой части экрана, затем выберите пункт Create a new Feed (Создать новый поток) в раскрывающемся списке Actions (Действия). Введите имя kitchen-temp и описание потока (рис. 5.9). В поле Add to groups удалите при-
94 Часть I. Необходимое оборудование и программы вязку к группе Default. Щелкните на пустом поле или начните вводить в него пер- вые буквы названия группы kitchen. Выберите имя группы из списка и нажмите кнопку Create. Аналогичным способом создайте потоки kitchen-hum, bedroom-temp И bedroom-hum. Новые группы и потоки сразу после создания появляются в списке (рис. 5.10). По- токи автоматически получают индивидуальные ключи, которые составлены из Рис. 5.9. Создание нового потока Рис. 5.10. Список действующих групп и потоков
Глава 5. Визуализация данных 95^ имени группы и имени потока. Если главный ключ АЮ служит для доступа к сер- вису в целом, то индивидуальный ключ указывает серверу, какому потоку принад- лежат данные и в какую группу их направить. Вы можете изменить индивидуаль- ный ключ группы или потока, но имейте в виду, что после этого вам придется из- менить настройки прошивок всех подключенных устройств, которые работают с этой группой или потоком. Настройка групп и потоков По щелчку на имени группы или потока открывается экран просмотра и настроек. В правой части экрана появляются ссылки на опции настроек. Кратко укажем их назначение: ♦ Feed Info (Group Info) — настройка имени и ключа потока (группы), просмотр URL, по которому должно обращаться внешнее устройство; ♦ Privacy — настройка приватности потока. По умолчанию только владелец учет- ной записи может видеть данные потока и приборные панели, для которых по- ток поставляет данные. Если вы сделаете поток публичным, то любой желаю- щий сможет видеть данные и использовать их; ♦ Sharing— отправка личного приглашения другому пользователю Adafruit 10. В зависимости от настройки доступа, гость может либо только получать данные из потока, либо получать и отправлять данные; Маленькая хитрость... Если вам не хватает бесплатных потоков, создайте две учетных записи с разными адресами электронной почты и обменяйтесь приглашениями между ними. ♦ Feed History — по умолчанию все данные потока хранятся 30 дней. Вы можете отключить сохранение данных, и приборная панель будет отображать только последнее поступившее значение; ♦ Notifications— настройка аварийных уведомлений. Вы можете получить уве- домление по электронной почте, если данные потока не поступали на сервер в течение заданного времени; ♦ Disable Feed — поток отключается от сервера, перестает принимать данные и не учитывается счетчиком потоков. Вы не сможете включить поток обратно! Единственное, что вы можете сделать с отключенным потоком, — скачать со- храненные данные, пока не истек срок хранения; ♦ License — настройка лицензии на право пользования данными. Эта настройка имеет смысл, если вы сделали поток публичным или пригласили других пользо- вателей. После создания и настройки групп и потоков можно приступать к настройке при- борных панелей, которые будут наглядно отображать поступающие данные.
Часть I. Необходимое оборудование и программы 5.2.2. Создание приборной панели Щелкните на ссылку Dashboards (Приборные панели) в левой части экрана и вы- берите пункт Create a new Dashboard (Создать новую приборную панель) в рас- крывающемся списке Actions. Откроется пустое рабочее поле на черном фоне. Справа вверху расположены кнопки управления: — редактирование макета приборной панели; — добавление нового блока (виджета) на панель; — удаление текущей приборной панели; — просмотр главного ключа АЮ; — настройка приватности приборной панели; — развернуть панель на весь экран. Нажмите кнопку добавления нового блока. Откроется окно выбора блока (рис. 5.11). На момент работы над книгой были доступны следующие блоки: 1. Переключатель ON/OFF (включено/выключено). Приборная панель может передавать в устройство состояние переключателя. 2. Кнопка. Работает как обычная механическая кнопка без фиксации. Приборная панель может передавать в устройство состояние кнопки. 3. Слайдер (ползунковый регулятор). Приборная панель передает в устройство числовое значение, пропорциональное положению движка. 4. Индикатор. Работает аналогично обычному стрелочному индикатору. Угол от- клонения указателя пропорционален входному значению. 5. Текстовый блок. Отображает текст, полученный в потоке, или отправляет строку в устройство. 6. Монитор потока. Отображает в реальном времени данные, поступающие от нескольких потоков (не более пяти). 7. Изображение. Отображает изображение в кодировке base64. Для отправки изо- бражения в устройство перетащите его на блок в панели приборов. 8. График. Отображает двумерный график изменения значений одного или не- скольких потоков. 9. Указатель цвета. Применяется для просмотра или отправки в устройство цве- та в шестнадцатеричном формате #rrggbb. 10. Карта. Применяется для отображения на карте координатных данных о пере- мещении устройства. 11. Пульт дистанционного управления. Имитирует работу пульта Mini Remote Control производства компании Adafruit.
Глава 5. Визуализация данных 97 Рис. 5.11. Окно выбора блока (виджета) 12. Значок. Вы можете передать в потоке имя значка, и он отобразится на панели. Полный перечень значков находится по адресу https://io.adafruit.com/icons- faq. 13. Световой индикатор. Отображает один из двух заранее настроенных цветов в зависимости от того, превышает ли входное значение заданный порог. 14. Цифровая клавиатура. Возвращает в устройство код нажатой клавиши. Детальное знакомство со всеми блоками выходит за рамки этой книги. В качестве примера мы создадим простую приборную панель для мониторинга двух потоков данных: температуры и влажности воздуха в спальне. 1. В окне выбора блока нажмите на значок (4) с изображением индикатора — от- кроется окно выбора потока данных. Вы можете выбрать только один поток. Пусть это будет поток bedroom-temp. После нажатия кнопки Next step (Следую- щий шаг) появится окно настроек блока (рис. 5.12). 2. В поле Block Title введите название индикатора, которое будет отображено на приборной панели. 3. В поля Gauge Min Value и Gauge Max Value введите соответственно мини- мальное и максимальное значение шкалы индикатора. Пусть это будут значе- ния о и 50.
98 Часть I. Необходимое оборудование и программы шяшшшшшшвшшштшшяшш Рис. 5.12. Настройка блока индикатора 4. Поле Gauge Width оставьте без изменений. 5. В поле Gauge Label введите подпись единицы измерений — градусы Цельсия. Подсказка: откройте текстовый редактор MS Word, введите на страницу доку- мента четыре цифры: 2103 (код Юникод) и сразу после этого нажмите комби- нацию клавиш <Alt>+<X>. Введенный код превратится в символ градусов Цельсия: °С. Скопируйте этот символ в буфер обмена и вставьте в поле Gauge Label. 6. В поля Low Warning Value и High Warning Value введите соответственно ми- нимальное и максимальное значение, при которых указатель индикатора будет менять цвет. Если полученное значение потока превышает максимальное значе- ние шкалы, индикатор автоматически становится красным. 7. Попробуйте вводить в поле Test Value пробные значения и наблюдайте, как меняются показания индикатора. Затем нажмите кнопку Create block. 8. Снова нажмите на кнопку добавления блока и выберите значок (8) с изображе- нием графика — откроется окно добавления потоков. В нашем случае вы може- те выбрать несколько потоков для отображения на графике. После нажатия кнопки Next step появится новое окно настроек (рис. 5.13).
Глава 5. Визуализация данных 99 Рис. 5.13. Настройка параметров блока графика 9. Введите в поле Block Title имя графика. В поле Show History (показывать ис- торию) выберите период, за который надо отобразить данные на графике. В по- ле Х-Axis Label введите подпись для оси X, а в поле Y-Axis Label — подпись для оси Y. В поля Y-Axis Minimum и Y-Axis Maximum можно ввести макси- мальное и минимальное значение данных потока, но мы оставим эти поля пус- тыми и предоставим серверу возможность автоматически выбрать масштаб по оси Y. Нажмите кнопку Create block, и виджет графика появится на приборной панели. 10. Для просмотра поступающих данных в текстовом виде добавим панель терми- нала. Выберите значок (6) с изображением текста. В качестве источника дан- ных укажите ПОТОКИ bedroom-temp И bedroom-hum. Остальные наСТрОЙКИ МОЖНО не менять. Нажмите кнопку Create block. Теперь у нас есть три блока, которые размещены вертикально один под другим. Но такое расположение блоков нас не устраивает. Нажмите кнопку с изображением шестеренки. Теперь блоки можно перемещать и редактировать. Расположите блоки по своему усмотрению (например, как показано на рис. 5.14) и нажмите кнопку Save. Итак, у нас настроены потоки данных, и готова приборная панель. Осталось подго- товить устройство на базе Arduino, которое подключится к сети Интернет и будет отправлять данные на сервер Adafruit 10.
100 Часть I. Необходимое оборудование и программы Рис. 5.14. Редактирование расположения блоков на панели 5.2.3. Установка библиотек Запустите среду разработки Arduino IDE и перейдите в менеджер библиотек: Скетч | Подключить библиотеку | Управлять библиотеками. При помощи строки поиска менеджера библиотек найдите и установите следующие библиотеки: ♦ Adafruit IO Arduino — взаимодействие с сервисом Adafruit 10; ♦ Adafruit MQTT Library — поддержка протокола MQTT; ♦ Adafruit Unified Sensor— универсальный драйвер для работы с сенсорами (датчиками); ♦ DHT Sensor Library (by Adafruit) — библиотека для работы с датчиками темпе- ратуры и влажности DHT11 и DHT22. Датчик DHT11 мы и будем использовать в демонстрационном примере далее. Библиотека Adafruit io Library предназначена для работы с платами на основе ESP8266 и фирменными платами Ethernet собственного производства Adafruit. По- этому библиотека Adafruit ю подойдет для работы с любой платой ESP8266, но для работы со стандартными Ethernet-шилдами Arduino придется использовать встроен- ную библиотеку Arduino Ethernet (см. разд. 5.2.5).
Глава 5. Визуализация данных 101_ 5.2.4. Подключение к сервису Adafruit 10 по Wi-Fi Для реализации демонстрационного примера нам потребуется плата на основе ESP8266 — например, NodeMCU. О настройке среды разработки Arduino IDE для работы с платформой ESP8266 рассказано в разд. 2.3.3 и 4.2.1. Источником данных послужит популярный сенсор температуры и влажности DHT11 (рис. 5.15). Подключите вывод сенсора OUT к выводу D1, вывод «плюс» — к выводу +3,3 вольта, вывод «минус» — к выводу GND платы ESP8266. Рис. 5.15. Сенсор (датчик) температуры и влажности DHT11 Откройте в Arduino IDE скетч из листинга 5.6. Внесите изменения в строки, выде- ленные полужирным шрифтом, — вместо звездочек необходимо подставить ваше имя пользователя в сервисе Adafruit IO, ваш главный ключ сервиса, имя и пароль вашей домашней сети Wi-Fi. Загрузите исправленный скетч в плату контроллера и откройте монитор последова- тельного порта на скорости 115 200 бод. Если настройки заданы правильно, в окне монитора через несколько секунд появится сообщение об успешном подключении. Откройте в браузере страницу своей первой приборной панели. Круговой индика- тор отобразит температуру, в блоке графика начнется построение линии уровня влажности, а в окне терминала отобразятся входящие значения потоков (рис. 5.16). Если этого не происходит, проверьте совпадение имен потоков в панели и в скетче. Имена потоков должны быть заданы полностью, включая имя группы (если вы ее создали). // Библиотека сенсоров DHTxx #include "DHT.h" // Библиотека Adafruit 10 для WiFi #include "AdafruitIO_WiFi.h" #define DHTPIN 5 // Вывод для подключения датчика (Dl) #define DHTTYPE DHT11 // Тип датчика - DHT11 // Имя пользователя сервиса Adafruit IO #define IO USERNAME ••********•*•» // Главный ключ сервиса Adafruit IO #define IO KEY и***************************************!'
102 Часть I. Необходимое оборудование и программы // Имя вашей сети WiFi #de£ine WIFIJSSID »•*******" // Пароль вашей сети WiFi #define WIFI PASS "***•****" // Конструктор подключения к Adafruit 10 AdafruitIO_WiFi io(IOJJSERNAME, IO_KEY, WIFI_SSID, WIFI_PASS) ; // Конструктор объекта сенсора DHT dht(DHTPIN/ DHTTYPE); // Объявляем объекты потоков с их ключами AdafruitIO_Feed *bedroom_temp = io.feed("bedroom.bedroom-temp"); AdafruitIO_Feed *bedroom_hum = io.feed("bedroom.bedroom-hum"); void setup() { Serial.begin(115200); // Инициализируем сенсор DHT11 dht.begin(); Serial.print("Connecting to Adafruit IO"); // Подключаемся к io.adafruit.com io.connect(); // Ожидаем подключение while (io.status() < AIO_CONNECTED) { Serial.print("."); delay(500); // Отладочное сообщение о подключении в монитор порта Serial.println(); Serial.println(io.statusText()); void loop() { // Вызов метода io.run(); требуется в КАВДОМ скетче //и должен быть первой строкой цикла 1оор() // Вызов поддерживает соединение с io.adafruit.com //и обрабатывает входящие данные. io.run(); // Читаем из сенсора показания температуры и влажности float h = dht.readHumidity(); float t = dht.readTemperature();
Глава 5. Визуализация данных 103 II Отправляем данные в потоки if (!isnan(t)) bedroom_temp->save(t); if (!isnan(h)) bedroom_hum->save(h); // Adafruit 10 ограничивает частоту поступления данных. // Датчику DHT11 тоже требуется интервал между измерениями. // Поэтому делаем паузу 5 секунд между отправками данных, delay(5000); Рис. 5.16. Приборная панель с поступающими данными потоков Скетч примера требует некоторых пояснений. Так, в строках: AdafruitIO_Feed *bedroom_temp = io.feed("bedroom.bedroom-temp"); AdafruitIO_Feed *bedroom_hum = io.feed("bedroom.bedroom-hum"); мы создаем объекты потоков, к которым будем обращаться для передачи данных. В одном скетче можно обращаться к любому количеству потоков в пределах учет- ной записи. В строках: if (! isnan (t)) bedroom_temp->save (t) ; if (!isnan(h)) bedroom hum->save(h);
104 Часть I. Необходимое оборудование и программы производится проверка того, является ли числом значение, полученное от сенсора DHT11. Дело в том, что у сенсора DHT11 своеобразный формат представления вы- ходных данных, и периодически случаются сбои передачи данных, когда библиоте- ка dht не может истолковать результат как число. В таких случаях библиотека воз- вращает значение nan (NaN, Not a Number). Передавать значение пап в панель — дурной тон программирования. При получении нечислового значения круговой ин- дикатор сбрасывается в ноль, а разрыв графика заменяется горизонтальным отрез- ком. Такое поведение панели выглядит непрофессионально и раздражает пользова- теля. Всегда проверяйте данные на соответствие заданному формату перед отправ- кой в поток! В нашем случае мы выполняем проверку при помощи метода isnano в однострочном условном операторе if (). 5.2.5. Подключение к сервису Adafruit 10 по Ethernet Для подключения к сервису Adafruit 10 по проводному соединению Ethernet вос- пользуемся стандартным шилдом Arduino W5100 (см. раз. 4.1.2). Установите шилд Arduino W5100 в разъем платы Arduino Uno R3. Источни- ком данных послужит популярный сенсор температуры и влажности DHT11 (см. рис. 5.15). Подключите вывод сенсора OUT к выводу D1, вывод «плюс» — к выводу +3,3 вольта, а вывод «минус» — к выводу GND платы контроллера. Под- ключите провод Ethernet к сетевому разъему шилда. В среде разработки Arduino IDE откройте скетч из листинга 5.7. Подставьте в скетч имя пользователя Adafruit 10 и главный ключ (подлежащие исправлению строки в листинге выделены полужирным шрифтом). Загрузите скетч в плату контроллера и откройте монитор последовательного порта. Если настройки скетча заданы правильно, в окне монитора будет выведено сооб- щение о том, что установлено соединение с MQTT-сервером, а в текстовом блоке приборной панели появятся новые строки данных. #include <SPI.h> #include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" #include <Ethernet.h> #include <EthernetClient.h> #include <Dns.h> #include <Dhcp.h> // Библиотека сенсоров DHTxx #include "DHT.h" // Задаем МАС-адрес шилда Arduino Ethernet byte mac[] = {OxDE, OxAD, OxBE, OxEF, OxFE, OxED}-;
Глава 5. Визуализация данных 105 II Настройки доступа к Adafruit 10 по протоколу MQTT #define AIO_SERVER "io.adafruit.com" #define AIO_SERVERPORT 1883 #define AIOJJSERNAME "******•*" #define AIO KEY #define DHTPIN 2 // Вьюод для подключения датчика (Dl) #define DHTTYPE DHT11 // Тип датчика - DHT11 // Создаем сетевого клиента EthernetClient client; // Создаем клиента MQTT-подключения Adafruit_MQTT_Client mqtt (&client, AIO_SERVER, AIO_SERVERPORT, AIOJJSERNAME, AIO_KEY); // Необходимая строка, ничего не меняйте #define halt(s) { Serial.println(F( s )); while(1); } // Объявляем потоки в виде <username>/feeds/<feedname> Adafruit_MQTT_Publish temperature = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/bedroom.bedroom-temp"); Adafruit_MQTT_Publish humidity = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/bedroom.bedroom-hum"); // Объявляем хотя бы один поток входящих данных от сервера Adafruit_MQTT_Subscfibe income = Adafruit_MQTT_Subscribe(&mqtt, AIOJJSERNAME "/feeds/onoff"); // Конструктор объекта сенсора DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(115200); // Инициализируем сенсор DHT11 dht.begin(); // Инициализируем клиента Ethernet Serial.print(F("\nlnit the Client...")); Ethernet.begin (mac); delay(1000); // Задержка для инициализации // Подписка на входящие данные MQTT // ОБЯЗАТЕЛЬНО для нормальной работы библиотеки mqtt.subscribe(&income);
106 Часть I. Необходимое оборудование и программы void loop () { // Устанавливаем подключение с сервером, // проверяем наличие подключения в каждом цикле 1оор(), // при необходимости восстанавливаем подключение MQTT_connect(); // Проверяем наличие входящих данных от сервера // ОБЯЗАТЕЛЬНО для нормальной работы библиотеки Adafruit_MQTT_Subscribe *subscription; while ((subscription = mqtt.readSubscription(lOOO))) { if (subscription == &income) { Serial.print(F("Got: ") ) ; Serial.println((char *)income.lastread); // Читаем из сенсора показания температуры и влажности float h = dht.readHumidity(); float t = dht.readTernperature (); // Публикуем данные в потоки if (!isnan(t)) temperature.publish(t); if (!isnan(h)) humidity.publish(h); // Пингуем сервер для поддержания активного соединения // Если сервер не отвечает, объявляем соединение разорванным //и попытаемся восстановить его в следующем цикле 1оор() if (! mqtt.pingO) { mqtt.disconnect(); } delay(5000) ; // Функция для соединения с сервером MQTT, проверки наличия соединения //и повторного соединения при необходимости void MQTT_connect() { int8_t ret; // Если уже подключено - ничего не делаем if (mqtt.connected()) { return; Serial.print("Connecting to MQTT... "); // При наличии соединения возвращается 0 while ((ret = mqtt.connect()) != 0) {
Глава 5. Визуализация данных 107 // Если возвращен не О, выводим текст ошибки //и повторяем попытку через 5 секунд Serial.printIn(mqtt.connectErrorString(ret)); Serial.println("Retrying MQTT connection in 5 seconds..."); mqtt.disconnect(); delay(5000); } Serial.println("MQTT Connected!"); В целом этот скетч работает аналогично скетчу из листинга 5.6, но есть важные нюансы. У библиотеки Adaf ruit mqtt есть особенность, которая доставила немало трудностей начинающим разработчикам. Протокол MQTT позволяет устройству работать в обе стороны — как передавать данные на сервер (publication, публика- ция), так и получать данные от сервера (subscription, подписка). Разумеется, для общения с сервером MQTT необходимо авторизовать устройство при помощи главного ключа. Но библиотека Adaf ruit mqtt передает главный ключ и авторизует устройство только в момент оформления подписки на входящие данные. Даже если вы не собираетесь получать данные или команды от сервера, вам все равно придется создать в скетче объект входящего потока и подписаться на него. Можно не создавать реальный поток для подписки в панели Adafruit IO. Достаточ- но создать фиктивный поток и подписку в скетче. В скетче примера эту работу выполняют строки: Adafruit_MQTT_Subscribe income = Adafruit_MQTT_Subscribe(&mqtt, AIOJJSERNAME "/feeds/onoff"); mqtt.subscribe(&income); MQTT_connect(); Последовательность действий должна быть именно такой: создали ссылку на канал подписки, подписались на канал, подключились командой MQTTconnect (). Далее нужно регулярно выполнять чтение из канала подписки. 5.3. Дисплейные модули в проектах Arduino Персональный компьютер обладает большими возможностями для обработки и отображения данных, но для портативных устройств нужны малогабаритные дис- плеи. Ассортимент миниатюрных и недорогих дисплеев весьма обширен. Радиолю- бители уже давно используют в своих проектах различные жидкокристаллические дисплеи— в основном, от мобильных телефонов. Но постепенно предпочтения разработчиков-любителей сосредоточились на трех основных типах дисплеев (рис. 5.17): монохромные строковые дисплеи (а), монохромные OLED-дисплеи на органических светодиодах (б) и цветные графические TFT-дисплеи (в). В этой книге мы не будем говорить о монохромных строковых дисплеях. Такие дисплеи еще применяются в любительских проектах, но имеют существенные не-
108 Часть I. Необходимое оборудование и программы достатки: они громоздкие, тяжелые, с большим энергопотреблением, подключают- ся по параллельной шине данных или через дополнительный адаптер 12С, не могут отображать даже простейшую графику. Эти устаревшие дисплеи плохо подходят для наших проектов. Современные компактные графические дисплеи стоят немно- го дороже, но зато работают с полноценной растровой (пиксельной) графикой и текстом. Рис. 5.17. Основные типы дисплеев для Arduino: монохромные строковые дисплеи (а), монохромные OLED-дисплеи на органических светодиодах (б) и цветные графические TFT-дисплеи (в) Графический дисплей состоит из пиксельной матрицы, встроенной памяти для хра- нения изображения и специальной микросхемы, которая управляет переносом изо- бражения из памяти в матрицу. Эту микросхему называют драйвером, или кон- троллером. Не путайте ее с программным драйвером компьютера или платой кон- троллера Arduino. В дальнейшем для этой микросхемы мы будем использовать термин «драйвер дисплея». Любой дисплей бесполезен, если контроллер Arduino не подготовил исходные дан- ные: изображение или текст. Причем, в большинстве графических дисплеев симво- лы текста тоже являются изображениями и должны быть сформированы на стороне контроллера Arduino1. 5.3.1. Графические библиотеки Arduino Подготовка графических элементов и текста — сложная задача для маломощных микроконтроллеров. В скетчах Arduino применяются готовые графические биб- лиотеки, которые разработаны профессиональными программистами и тщательно оптимизированы. Компания Adafruit — производитель модулей и наборов для технического творче- ства— разработала набор библиотек для популярных дисплеев. Эти библиотеки стали фактическим стандартом у начинающих любителей. При желании и наличии некоторого опыта вы можете воспользоваться более мощной библиотекой utft, но в скетчах для проектов из этой книги применяются простые и хорошо документи- рованные библиотеки Adafruit. 1 Некоторые дисплеи оснащены постоянной памятью с записанным в нее шрифтом и позволяют ото- бражать по усмотрению пользователя как готовый набор символов, так и пользовательские шрифты.
Глава 5. Визуализация данных 109_ Графические библиотеки Adafruit состоят из двух частей: Ф универсальное графическое ядро Adafruit GFX, которое выполняет все необ- ходимые математические вычисления для рисования графических примитивов (точки, линии, окружности, символы шрифтов и т д); ♦ библиотека драйвера дисплея. Эта надстройка над графическим ядром переда- ет команды настройки дисплея, взаимодействует с графическим ядром и загру- жает в дисплей графические данные по нужному протоколу и в нужной форме. А Иногда в дисплеях, которые внешне выглядят абсолютно одинаково, разные фабри- ки устанавливают различные микросхемы драйвера (контроллера). Эта ситуация может вызывать замешательство у неопытных любителей, которые не могут понять, почему не работает даже простейший проект. В таком случае надо уточнить, какие варианты драйвера могут применяться в дисплее, и попробовать использовать в скетче другую библиотеку. Графическое ядро Adafruit GFX Графическое ядро загружается и устанавливается в среду Arduino IDE один раз и для всех дисплеев, а выбор библиотеки драйвера зависит от того, какая микросхема драйвера использована в дисплее. Для установки графического ядра скачайте архивный файл по адресу: https:// github.com/adafruit/Adafruit-GFX-Library/archive/master.zip. Распакуйте архив. В наименовании каталога Arduino-GFX-Library-Master удалите фраг- мент -Master. Перенесите каталог с файлами библиотеки в каталог библиотек среды Arduino IDE (см. разд. 2.3.2). На этом установка графического ядра завершена. Перед началом работы с функциями графической библиотеки вы должны создать объект дисплея. Синтаксис конструктора объекта зависит от того, какой дисплей используется. В примерах этого раздела мы будем считать, что вы уже создали объ- ект С именем display. Практические примеры создания объектов дисплея и работы с ними приведены в раза. 5.3.2 и 5.3.3. Система координат дисплея Любое изображение на экране дисплея состоит из отдельных элементов — пиксе- лов. Каждый пиксел в отдельности определяется параметрами координат и цвета. Прямоугольная система координат дисплея похожа на привычную картезианскую систему координат с вертикальной и горизонтальной осями. Но есть важное разли- чие — начало системы координат дисплея располагается слева вверху (рис. 5.18). Координаты по оси X отсчитываются как обычно — слева направо, а координаты по оси Y отсчитываются в обратном направлении — сверху вниз. Такая система координат применяется во всех компьютерных дисплеях со времен первых монито- ров на электронно-лучевых трубках, которые прорисовывают изображение слева направо и сверху вниз.
110 Часть I. Необходимое оборудование и программы li 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 г 1 Г 2 3 4 5 I иксел на (0, • 7 м 0) > У i I 8 9 10 11 12 13 14 15 Пиксел на i Пиксел на 6,13) 16 17 18 ! 18,6) ... 19 и. L SH 1 > 20 1 21 22 23 > i I Рис. 5.18. Система координат графических дисплеев Координаты каждого пиксела в изображении всегда строго заданы и постоянны. Физические размеры изображения зависят от плотности дисплея— количества пикселов, которые умещаются на квадратном дюйме поверхности дисплея. Чем меньше размер отдельных пикселов, тем меньше зернистость и лучше качество изображения. Цвет пиксела Цвет пиксела определяется 16-разрядным числом. Старшие пять битов задают ин- тенсивность красного цвета, средние шесть битов — интенсивность зеленого цвета1 и младшие пять битов — интенсивность синего цвета (рис. 5.19). MSB LSB 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 О 5 битов красного (0-31) 6 битов зеленого 5 битов синего (0-63) (0-31) Рис. 5.19. Цветовая схема пиксела в библиотеке ядра Adafruit GFX В различных дисплеях разрядность цветовых составляющих может быть как боль- ше, так и меньше, чем принято в библиотеке Adafruit gfx. Но на платформе Arduino удобнее работать именно с 16-разрядными числами — все значения цвето- вых составляющих будут приведены к нужной разрядности. «Лишний» разряд прикрепили к зеленой составляющей, потому что человеческий глаз наиболее чувствителен к изменениям интенсивности именно зеленого цвета.
Глава 5. Визуализация данных 111 Для работы с основными цветами в библиотеке ядра назначены ключевые слова: #define BLACK 0x0000 // черный #define BLUE OxOOlF // синий tdefine RED 0xF800 // красный #define GREEN 0x07E0 // зеленый #define CYAN 0x07FF // зеленовато-голубой (циан) #define MAGENTA 0xF81F // пурпурный (малиновый) #define YELLOW OxFFEO // желтый #define WHITE OxFFFF // белый Вы можете по своему усмотрению использовать любой из 65 536 цветов, но стан- дартные ключевые слова упрощают написание и понимание кода. Монохромные дисплеи работают лишь с двумя градациями цвета: 1 (включено) и о (выключено). Дня светоизлучающего дисплея (например, OLED) единице соответ- ствует светящийся пиксел. Для светоотражающего монохромного ЖК-дисплея единице соответствует темный пиксел. Графические примитивы Библиотека графического ядра Adaf ruit gfx предназначена для рисования базовых изображений — графических примитивов, из которых можно составить произволь- ное изображение. Поддерживаются следующие примитивы: ♦ Точка — одиночный пиксел с заданными координатами и цветом. Синтаксис: void drawPixel(uintl6_t x, uintl6_t у, uintl6_t color); Пример: display. drawPixel (15, 48, YELLOW); Ф Линия — рисование линии заданного цвета по начальной и конечной точке. Синтаксис: void drawLine(uintl6_t x0, uintl6_t y0, uintl6_t xl, uintl6_t yl, uintl6_t color); Пример: display. drawLine (23, 45, 150, 10, MAGENTA); Для рисования вертикальных и горизонтальных линий можно использовать быстрые оптимизированные функции, в которых не выполняются вычисления углов: void drawFastVLine(uintl6_t x0, uintl6_t y0, uintl6_t length, uintl6_t color); // быстрая вертикальная линия void drawFastHLine(uint8_t xO, uint8_t yO, uint8_t length, uintl6_t color); // быстрая горизонтальная линия ♦ Прямоугольник— рисование и заливка прямоугольника заданного цвета по координатам верхней левой точки, ширине и высоте. Синтаксис: void drawRect (uintl6_t x0, uintl6_t y0, uintl6_t w, uintl6_t h, uintl6_t color); // Прямоугольник без заливки void fillRect(uintl6_t xO, uintl6_t yO, uintl6_t w, uintl6_t h, uintl6_t color); // Прямоугольник с заливкой
112 Часть I. Необходимое оборудование и программы Примеры: display.drawRect(20, 20, 110, 70, 0xFF2C12); display.fillRect(45, 70, 30, 40, GREEN); ♦ Окружность — рисование и заливка окружности заданного цвета по координа- там центра и радиусу. Синтаксис: void drawCircle(uintl6_t x0, uintl6_t y0, uintl6_t r, uintl6_t color); void fillCircle(uintl6_t xO, uintl6_t yO, uintl6_t r, uintl6_t color); Примеры: display.drawCircle(35, 60, 20, 0x00B098); display.fillCircle(23, 10, 10, WHITE); ♦ Скругленный прямоугольник — рисование и заливка заданным цветом по ко- ординатам верхней левой точки, ширине, высоте и радиусу скругления углов. Небольшая хитрость: поскольку окружность рисуется относительно централь- ной точки, ее диаметр всегда получается нечетным. Если вам необходима окружность с четным диаметром, используйте функцию рисования скругленно- го прямоугольника, но задайте в нем одинаковое четное значение ширины и вы- соты, а радиус скругления сделайте равным половине этого значения. Синтаксис: void drawRoundRect(uintl6_t x0, uintl6_t y0, uintl6_t w, uintl6_t h, uintl6_t radius, uintl6_t color); void fillRoundRect(uintl6_t xO, uintl6_t yO, uintl6_t w, uintl6_t h, uintl6_t radius, uintl6_t color); Примеры: display.drawRoundRect(16, 20, 30, 50, 8, BLUE); display.fillRoundRect(32, 92, 100, 100, 15, 0x4517CC); ♦ Треугольник — рисование и заливка заданным цветом треугольника по коор- динатам трех точек. Точки можно определять в любом порядке. Синтаксис: void drawTriangle(uintl6_t xO, uintl6_t yO, uintl6_t xl, uintl6_t yl, uintl6_t x2, uintl6_t y2, uintl6_t color); void fillTriangle(uintl6_t xO, uintl6_t yO, uintl6_t xl, uintl6_t yl, uintl6_t x2, uintl6_t y2, uintl6_t color); Примеры: display.drawTriangle(0, 0, 30, 10, 18, 40, WHITE); display.fillTriangle(9, 2, 18, 9, 6, 13, YELLOW); ♦ Символы и текст — вывод одиночных символов и строки текста по заданным координатам и с заданным цветом. В библиотеке для экономии памяти по умол- чанию применяется только один шрифт. Знакоместо шрифта имеет размеры 5x8 пикселов (рис. 5.20), но его можно масштабировать, указав относительный
Глава 5. Визуализация данных 113 размер шрифта— значения 1, 2 или з. Например, размеру шрифта size = 2 соответствует знакоместо 10x16 пикселов. При увеличении размера символы начинают выглядеть как бы состоящими из квадратиков, но это плата за сохра- нение свободной памяти микроконтроллера. Одиночный символ выводится на дисплей при помощи функции drawChar о, в ар- гументах которой следует указать координаты верхнего левого угла знакоместа (см. рис. 5.20), символ, цвет символа, цвет фона, размер шрифта). Синтаксис: void drawChar(uintl6_t x, uintl6_t у, char с, uintl6_t color, uintl6__t bg, uint8_t size) ; Пример: display.drawChar (10, 10, fAf, YELLOW, RED, 1) ; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Рис. 5.20. Стандартное знакоместо библиотеки Adaf ruit GFX При выводе текста координаты верхнего левого угла строки, размер шрифта и цвет необходимо задать отдельными командами, а затем вывести на экран стро- ку командой print (). Параметры текста сохраняются для последующих строк до тех пор, пока не будут заданы новые параметры. Это позволяет сократить и упростить программу. Синтаксис: void setCursor(uintl6_t x0, uintl6_t y0); void setTextColor(uintl6_t color); void setTextColor(uintl6_t color, uintl6_t backgroundcolor); void setTextSize(uint8_t size); void setTextWrap(boolean w); Пример: display.setCursor(10, 10); display.setTextColor(GREEN); // только цвет текста
114 Часть I. Необходимое оборудование и программы display.setTextColor(YELLOW, RED); // желтый текст на красном фоне display.setTextSize(2); // допустимые значения 1, 2 и 3 display.setTextWrap(1); // разрешить разрыв строки с переносом display.println("Hello world!"); // печать строки display.print(OxABCDEF, HEX); // печать шестнадцатеричного числа Затем вы можете использовать обычные команды print () и println () для выво- да текста на экран, как это делали раньше для вывода в последовательный порт. ♦ Растровое изображение (bitmap)— вывод на экран монохромного битового изображения (значки или спрайты для мини-анимации). Блок двоичных данных должен быть приготовлен заранее и сохранен в памяти программ директивой PROGMEM. Использование этой директивы может вызвать затруднение у неопытных разра- ботчиков и требует дополнительного изучения. Ознакомьтесь с описанием ди- рективы progmem по адресу http://arduino.cc/en/Reference/PROGMEM. Простой онлайн-сервис для генерации байтового массива из файла изображения доступен по адресу http://javl.github.io/image2cpp/. После конвертации скопи- руйте байтовый массив и вставьте его в исходный код своего скетча. Синтаксис: void drawBitmap(intl6_t x, intl6_t у, uint8_t *bitmap, intl6_t w, intl6_t h, uintl6_t color); Здесь: х и у — координаты левого верхнего угла изображения, w и h — ширина и высота изображения в пикселах, *bitmap— содержимое изображения в виде блока двоичных данных, color — цвет, которым будет нарисовано изображение. Пример: display.drawBitmap(20, 30, 128, 128, myPic, WHITE); ♦ Очистка (заливка) дисплея — полная заливка экрана заданным цветом. Синтаксис: void fillScreen(uintl6_t color); Пример: display. fillScreen (BLACK) ; Поворот экрана Мы не можем произвольно вращать изображение или текст на экране дисплея. Но, в зависимости от наших потребностей, мы можем выбрать портретную или ланд- шафтную ориентацию. Обычно ориентацию дисплея задают один раз в блоке setup () при ПОМОЩИ команды setRotation (rotation). Параметр rotation может принимать значение о, 1, 2 или з. Разные производители по-разному монтируют дисплей на плате, поэтому на некоторых дисплеях изобра- жение может оказаться перевернутым вверх ногами. В этом случае вам придется самостоятельно подобрать подходящее положение дисплея опытным путем. После поворота на 90 градусов ширина и высота дисплея (оси X и Y) меняются местами. Логическое начало координат всегда остается в левом верхнем углу экра- на, но физически это будет другой угол дисплея. Текущую ширину и высоту ДИСПЛеЯ МОЖНО ВЫЯСНИТЬ Программно При ПОМОЩИ фуНКЦИЙ width () И height (), например:
Глава 5. Визуализация данных 115 uintl6_t w = display.width(); uintl6_t h = display.height(); На этом мы заканчиваем изучение теоретической части библиотек и переходим к практическим примерам подключения и использования самых популярных и не- дорогих вариантов графических дисплеев. 5.3.2. Дисплейный модуль OLED 128x64 Аббревиатура OLED расшифровывается как Organic Light Emitting Diode — орга- нический светоизлучающий диод, изготовленный из трех слоев полимерного мате- риала. Два внешних слоя являются электродами, а промежуточный органический слой способен излучать видимый свет при подаче напряжения на электроды. Каж- дый пиксел дисплея — это отдельный органический светодиод. К достоинствам OLED-дисплеев относятся широкие углы обзора, высокая контра- стность и яркость, отсутствие инерции переключения. Но в то же время качествен- ные цветные OLED-дисплеи стоят заметно дороже, чем жидкокристаллические. Поэтому цветные органические дисплеи обычно применяются в дорогих смартфо- нах и телевизорах. У разработчиков-любителей большой популярностью пользуются миниатюрные монохромные OLED-дисплеи с разрешением 128x64 пиксела и интерфейсом 12С (рис. 5.21). Рис. 5.21. Монохромный OLED-дисплей 128x64 При самостоятельной покупке OLED-дисплея учитывайте следующие важные нюансы: ♦ цвет свечения — в продаже представлены дисплеи с белым, синим, зеленым и красным цветом свечения пикселов, а также комбинированные, у которых цвет свечения верхней полосы отличается от основного поля. Комбинированные дис- плеи подходят не для всех проектов;
116 Часть I. Необходимое оборудование и программы ♦ интерфейс— некоторые OLED-дисплеи оснащены интерфейсом SPI, который в нашем случае менее удобен в подключении и использовании; ♦ разводка выводов — в некоторых вариантах конструкции дисплея выводы рас- положены иначе, чем показано на рис. 5.21 ив иллюстрациях к проектам этой книги. Перед сборкой макета схемы внимательно проверьте разводку выводов дисплея; В некоторых экземплярах могут быть даже перепутаны подписи к выводам питания! ♦ выцветание пикселов — в недорогих OLED-дисплеях органические светодиоды имеют относительно небольшой ресурс и быстро теряют яркость в случае дли- тельного свечения. Поэтому не рекомендуется делать на таких дисплеях посто- янно работающие индикаторы (часы, термометры). Желательно предусмотреть такой режим работы устройства, при котором дисплей включается по запросу пользователя на нужное время. Подключение OLED-дисплея к плате Arduino Схема подключения OLED-дисплея к плате Arduino Uno R3 изображена на рис. 5.22— выводы дисплея с маркировкой SDA и SCL электрически соединены с выводами А4 и А5 платы Arduino Uno R3 соответственно (для подключения к другим вариантам плат воспользуйтесь соответствующими инструкциями, имею- SCL GND +5V Рис. 5.22. Схема подключения дисплея OLED 128x64 к плате Arduino Uno R3
Глава 5. Визуализация данных 117_ щимися в Интернете). Дисплей оснащен встроенным стабилизатором питания 3,3 вольта, а его входы SDA и SCL совместимы с уровнями пятивольтовой логики без промежуточного согласования. Дисплей может занимать один из двух адресов на шине 12С: Охзс или Охза Иногда нужный адрес написан на обратной стороне платы дисплея. Если вы не знаете адрес дисплея, просканируйте шину 12С. Для этого загрузите в плату скетч сканера шины 12С из каталога l2C_scanner сопровождающего книгу электронного архива (см. приложение 1\ откройте монитор порта и определите адрес дисплея: I2C scanner. Scanning ... Found address: 60 (ОхЗС) Done. Found 1 device(s). В нашем случае обнаружено ведомое устройство по адресу Охзс. Запомните этот адрес. Библиотека OLED-дисплея Скачайте архив библиотеки по адресу https://github.com/adafruit/Adafruit_SSD1306. В дисплее применяется микросхема драйвера SSD1306, и это отражено в названии библиотеки. Распакуйте и установите библиотеку в каталог с остальными библио- теками (см. разд. 2.3.2). Ак Убедитесь, что установлена библиотека графического ядра Arduino gfk. При необхо- /?\ димости вернитесь к разд. 5.3.1 и установите эту обязательную общую библиотеку. Библиотека Adafruit_ssDi306 может работать с различными дисплеями на чипе SSD1306, поэтому для новой версии библиотеки необходимо в явном виде указать разрешение дисплея, адрес на шине 12С и наличие вывода сброса. В старой версии требовалось редактировать исходный файл заголовка библиотеки, что вызывало затруднения у начинающих пользователей. Теперь настройка стала проще — дос- таточно указать параметры непосредственно в скетче. Откройте скетч примера в меню Файл | Примеры | Adafruit SSD13061 ssdl306_128x64_12c.bi Обратите внимание на следующие строки скетча, в которых задано разрешение дисплея: #define SCREEN_WIDTH 128 tdefine SCREEN_HEIGHT 64 Эти параметры должны быть обязательно заданы в любом скетче OLED-дисплея. Найдите в скетче строку: #define OLED_RESET 4 и исправьте параметр 4 на -1, потому что в нашем дисплее нет отдельной линии сброса и незачем зря занимать вывод D4 Arduino.
118 Часть I. Необходимое оборудование и программы Конструктор объекта OLED-дисплея должен вызываться с полным набором ранее объявленных аргументов: Adafruit_SSDl306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); Далее, найдите в скетче строку: display.begin(SSD1306_SWITCHCAPVCC, 0x3D); Если у вашего дисплея адрес Охзс (а это наверняка так), то исправьте адрес во вто- ром аргументе функции: display.begin(SSD1306_SWITCHCAPVCC, ОхЗС); Загрузите скетч в плату контроллера. Если все сделано правильно, вы увидите на экране демонстрацию всех возможностей графической библиотеки, включая про- стейшую анимацию. В качестве шаблона для будущих проектов с OLED-дисплеем вы можете использо- вать скетч из листинга 5.8. Попробуйте самостоятельно подставлять в него различ- ные функции рисования графических примитивов. #include <Adafruit_GFX.h> // графическое ядро #include <Adafruit_SSD1306.h> // библиотека OLED-дисплея #define SCREEN_WIDTH 128 // Ширина дисплея в пикселах #define SCREEN_HEIGHT 64 // Высота дисплея в пикселах #define OLED_RESET -1 //В нашем дисплее нет линии сброса // Создаем объект дисплея Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void setup() { // Активируем OLED-дисплей oled.begin(SSD1306_SWITCHCAPVCC, ОхЗС); oled.clearDisplay(); // очистка памяти дисплея oled.display(); // вывод из памяти на экран // Устанавливаем размер и цвет текста oled.setTextSize(l); oled.setTextColor(WHITE); // Рисуем прямоугольник oled.drawRect(10, 10, 108, 44, WHITE); // Задаем начальную позицию текста oled.setCursor(25, 28); // Отправляем текст на печать oled.print("Hello, World!");
Глава 5. Визуализация данных 119 // Отображаем содержимое памяти на экране oled.display(); void loop () { В этом скетче мы подключаем необходимые библиотеки, создаем объект дисплея с именем oled, активируем его с адресом Охзс и очищаем память дисплея. Важная особенность! Память OLED-дисплея состоит из двух страниц. Вы последовательно формируете и отправляете в дисплей графические примитивы и текст. Графическая информация загружается в буферную память и не отображается на экране. Закончив формиро- вать изображение в буферной памяти, вы должны перенести его на экран командой display о. Такое переключение страниц позволяет устранить мерцание изображе- ния при загрузке данных в «медленный» дисплей — готовые страницы переключа- ются мгновенно. Команду display о выполняют каждый раз, когда изображение из- менилось, и пора его обновить. После начальной очистки дисплея устанавливаем размер и цвет текста. Напомню, что дисплей монохромный, поэтому поддерживаются только два цвета: white и black. Затем рисуем прямоугольник, печатаем текст и выводим готовое изображе- ние на экран командой display (). 5.3.3. Дисплейные модули TFT SPI 128x160 и 240x320 Малогабаритные дисплейные модули на основе TFT-матрицы выдают качествен- ные изображения с яркими и сочными цветами и обладают высоким быстродейст- вием при невысокой стоимости. Вычислительных ресурсов и памяти маломощных контроллеров Arduino вполне достаточно для работы с такими изображениями в проектах средней сложности. Неудивительно, что подобные дисплейные модули с разрешением 128x160 или 240x320 пикселов широко применяются в любитель- ских проектах. В проектах нашей книги мы будем использовать самый недорогой и простой в экс- плуатации дисплейный модуль с интерфейсом SPI и TFT-матрицей 128x160 пиксе- лов (рис. 5.23). В проектах со сложным графическим интерфейсом, для которых требуется более высокое разрешение экрана, можно применить TFT SPI с разреше- нием 240x320 пикселов (рис. 5.24). В матрицах, изготовленных по технологии TFT (Thin Film Transistor, тонкопленоч- ный транзистор), состоянием каждого пиксела управляет отдельный транзистор. Конструктивно матрица дисплея представляет собой «бутерброд» из двух слоев прозрачной поляризующей пленки, между которыми находится жидкокристалличе- ский слой и стеклянная основа с тонкопленочными управляющими транзисторами. Позади матрицы располагается источник подсветки белого цвета. Проходя через первую пленку, свет становится поляризованным. Плоскости поля- ризации первой и второй пленки повернуты на 90 градусов относительно друг дру-
120 Часть I. Необходимое оборудование и программы Рис. 5.23. Модуль полноцветного дисплея TFT 128x160 с интерфейсом SPI Рис. 5.24. Модуль полноцветного дисплея TFT 240x320 с интерфейсом SPI га, поэтому вторая пленка не пропускает поляризованный свет (вспомним школь- ный курс физики). Но угол поляризации света может меняться при прохождении через слой жидких кристаллов. В зависимости от напряжения, приложенного к мо- лекулам ЖК-слоя, поляризацию света можно плавно менять от полного поглоще- ния до полного пропускания вторым фильтром. Соответственно, будет меняться яркость свечения пиксела. В цветных матрицах к структуре TFT добавляются три светофильтра: красный, зе- леный и синий, а каждый пиксел состоит из трех расположенных рядом независимо управляемых субпикселов — по одному на каждый цвет. Визуально три субпиксела сливаются в один пиксел с цветом, который получается сложением трех цветовых составляющих. К недостаткам TFT-дисплеев относится потребность в задней подсветке, которая потребляет много электрической энергии, ограниченные углы обзора, и невысокая контрастность изображения у недорогих матриц. Но при этом даже недорогие TFT-
Глава 5. Визуализация данных 121 дисплеи демонстрируют удивительно высокое качество изображения для своей це- новой категории. Пикселы TFT-матриц не подвержены выгоранию, и срок службы дисплея зависит только от исправности источника подсветки. Подключение к плате Arduino дисплея TFT SPI 128x160 При подключении модуля TFT-дисплея к плате Arduino (рис. 5.25) требуется согла- сование между пятивольтовыми логическими уровнями Arduino и трехвольтовыми логическими уровнями дисплея. А Без согласования логических уровней дисплей не будет работать и может выйти из строя! О способах согласования уровней рассказано в разд. 3.1. В нашем случае достаточ- но четырех резисторов с сопротивлением 1,0..Л,5 кОм. Линия RST (Reset) не нуж- дается в согласовании. Рис. 5.25. Схема подключения дисплея TFT SPI 128x160 к плате Arduino Uno R3 Назначение выводов дисплея TFT SPI 128x160 В исходном коде примеров для графических библиотек не оптимально использо- ваны дефицитные выводы портов платы Arduino. Но мы с легкостью освободим порт D8, если вход сброса дисплея RST соединим с выводом RES платы контрол- лера. ♦ RST — вход сброса контроллера дисплея. Подключается к линии сброса Arduino, чтобы не занимать вывод GPIO;
122 Часть /. Необходимое оборудование и программы ♦ CS — вход выбора ведомого устройства. Подключается к порту D10 (SS, SPI Slave Select) Arduino; ♦ D/C — вход управления режимом дисплея Data / Command (Прием данных / Прием команд). Может быть подключен к любому свободному порту GPIO. В нашем случае подключен к порту D9; ♦ DIN — вход данных SPI. Подключается к порту Dll (SPI MOSI); ♦ CLK — вход тактовых импульсов SPI. Подключается к порту D13 (SPI SCLK); ♦ VCC — питающее напряжение +5 вольт. Для питания напряжением 3,3 вольта необходимо замкнуть перемычку Л на плате; ♦ BL — управление подсветкой дисплея. Высокий уровень включает подсветку. Можно соединить напрямую с входом питания VCC; ♦ GND — общий провод. Соединяется с любым выводом GND платы Arduino. Пример кода с библиотекой Adafruit ST7735 Скачайте графическую библиотеку Adafruit ST7735 по адресу https://github.com/ adafruit/Adafruit-ST7735-Library и установите ее (см. разд. 2.3.2). Откройте демонстрационный пример графической библиотеки в меню Файл | Примеры | Adafruit ST7735 Library | graphicstest. Приведите назначение выводов платы Arduino в соответствие со схемой, приведен- ной на рис. 5.25. Для этого внесите небольшое изменение в скетч примера (показа- но полужирным шрифтом): #define TFT_RST О Загрузите скетч в плату контроллера. Если вы правильно подключили модуль дис- плея и верно указали номера выводов платы Arduino, к которым подключены выво- ды дисплея CS, RST и D/C, на экране дисплея начнется отрисовка графических примеров. В качестве шаблона для будущих проектов с дисплеем TFT 128x160 можно исполь- зовать скетч из листинга 5.9. Попробуйте самостоятельно подставлять в него раз- личные функции рисования графических примитивов. Обратите внимание, что константы цвета содержат префикс ST7735_, потому что для разных микросхем контроллера дисплея требуется разный формат данных цвета. #include <Adafruit_GFX.h> // Графическое ядро #include <Adafruit_ST7735.h> // Библиотека драйвера ST7735 #include <SPI.h> #define TPTjCS 10 // выбор ведомого устройства SPI #define TFTJRST 0 // вход сброса дисплея (Arduino RES) #define TFT DC 9 // вход режима данные/команда дисплея
Глава 5. Визуализация данных 123 II Создаем объект дисплея tft Adafruit ST7735 tft = Adafruit ST7735(TFT CS, TFT DC, TFT RST); void setup() { tft.initR(INITR_BLACKTAB); // Инициализация чипа ST7735 tft.setRotation(l); // Горизонтальное положение дисплея //tft.setRotation(3); // Горизонтальное перевернутое на 180 градусов tft.fillScreen(ST7735_BLACK); // Очистка дисплея tft.setTextSize(l); // Размер текста tft.setTextColor(ST7735_GREEN); // Текст зеленого цвета // Рисуем прямоугольник линиями белого цвета tft.drawRect(10, 10f 108, 44, ST7735_WHITE); // Задаем начальную позицию текста tft.setCursor(25, 28); // Отправляем текст на печать tft.print("Hello, World!"); Подключение к плате Arduino дисплея TFT SPI 240x320 Схема подключения к плате Arduino дисплея TFT SPI 240x320 (рис. 5.26) имеет небольшие, но важные отличия от схемы, показанной на рис. 5.25. Резисторы для согласования логических уровней должны иметь сопротивление 1,5...2,0 кОм. С резисторами 1,0 кОм многие экземпляры дисплея на чипе ILI9341 не работают * 1 Рис. 5.26. Схема подключения дисплея TFT SPI 240x320 к плате Arduino Uno R3
124 Часть I. Необходимое оборудование и программы (не перезагружаются и не стартуют). Светодиод подсветки подключается к внеш- нему источнику +3,3 вольта через балластный резистор с сопротивлением 15...30 Ом. Назначение выводов дисплея TFT SPI 240x320 ♦ SDO(MISO)— выход данных SPI. Подключается к порту D12 (SPI MISO) Arduino; ♦ LED— подсветка дисплея. Соединяется с источником питания +3,3 вольта че- рез балластный резистор 15...30 Ом; ♦ SCK — вход тактовых импульсов SPI. Подключается к порту D13 (SPI SCLK); ♦ SDI(MOSI) — вход данных SPI. Подключается к порту Dll (SPI MOSI); ♦ D/C — вход управления режимом дисплея Data / Command (Прием данных / Прием команд). Может быть подключен к любому свободному порту GPIO. В нашем случае подключен к порту D10; ♦ RESET— вход сброса контроллера дисплея. Подключается к линии сброса Arduino, чтобы не занимать вывод GPIO; ♦ CS— вход выбора ведомого устройства. Подключается к порту D9 (SS, SPI Slave Select); ♦ GND — общий провод. Соединяется с любым выводом GND платы Arduino; ♦ VCC — питающее напряжение +5 вольт. Для питания напряжением +3,3 вольта необходимо замкнуть перемычку Л на плате. Пример кода с библиотекой Ada fruit ILI9341 Скачайте графическую библиотеку Adafruit ST7735 по адресу https://github.com/ adafruit/Adafruit_ILI9341 и установите ее (см. разд. 2.3.2). Откройте файл демонстрационного скетча библиотеки в меню Файл | Примеры | Adafruit ILI93411 graphicstest. Загрузите скетч в плату контроллера. Если вы правильно подключили модуль дис- плея и верно указали в скетче номера выводов Arduino, к которым подключены выводы дисплея D/C и CS, на экране дисплея начнется отрисовка графических примеров. В качестве шаблона для будущих проектов с дисплеем TFT 240x320 вы можете ис- пользовать скетч из листинга 5.10. Попробуйте самостоятельно подставлять в него различные функции рисования графических примитивов. Обратите внимание, что константы цвета содержат префикс 1Ы9341_, потому что для разных микросхем контроллера дисплея требуется разный формат данных цвета. #include "SPI.h" #include "Adafruit_GFX.h" // Графическое ядро #include "Adafruit ILI9341.h" // Библиотека драйвера ILI9341
Глава 5. Визуализация данных 125 #define TFTJDC 9 // вход режима данные/команда дисплея tdefine TFT_CS 10 // выбор ведомого устройства SPI // Создаем объект дисплея tft Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); void setup() { tft.begin(); // Инициализация чипа ILI9341 tft.setRotation(3); // Горизонтальное положение дисплея //tft.setRotation(1); // Горизонтальное перевернутое на 180 градусов tft.fillScreen(ILI9341_BLACK); // Очистка дисплея tft.setTextSize(1); // Размер текста tft.setTextColor(ILI9341_GREEN); // Текст зеленого цвета // Рисуем прямоугольник линиями белого цвета tft.drawRect(10, 10, 108, 44, ILI9341_WHITE); // Задаем начальную позицию текста tft.setCursor(25, 28); // Отправляем текст на печать tft.print("Hello, World!"); void loop() { 5.3.4. Универсальный дисплейный шилд Специально для работы над проектами из этой книги я разработал несложный дис- плейный шилд— расширение для платы Arduino Uno R3 (рис. 5.27). Шилд позво- Рис. 5.27. Универсальный дисплейный шилд для Arduino Uno R3
126 Часть I. Необходимое оборудование и программы ляет быстро и надежно подключить к этой плате любой из трех популярных дис- плеев, о которых говорится в разд. 5.3.2 и 5.3.3. Благодаря применению сквозных линейных разъемов, все выводы платы Arduino Uno R3 можно использовать для подключения других компонентов. Шилд может изготовить даже начинающий радиолюбитель, имеющий минималь- ные навыки работы с печатными платами. Принципиальная электрическая схема и чертеж печатной платы шилда в формате DipTrace, а также подробное описание конструкции шилда и цветные иллюстрации размещены на сайте по адресу http://reedpaper.com/archives/1035.
ЧАСТЬ II Теория и практика Глава 6. Аналоговый оптический пульсометр Глава 7. Шагомер на акселерометре ADXL335 Глава 8. Бесконтактное измерение температуры тела Глава 9. Измеритель интенсивности ультрафиолетового излучения Глава 10. Измерение электрической активности кожи Глава 11. Цифровой пульсоксиметр Глава 12. Датчик общего качества воздуха Глава 13. Измерение пыльности и дымности воздуха Глава 14. Шагомер на цифровом акселерометре LIS2DS12 Глава 15. Трехточечный электрокардиограф Глава 16. Измеритель скорости пульсовой волны Глава 17. Измерение биопотенциала мышц
ГЛАВА 6 Аналоговый оптический пульсометр В этой главе мы научимся использовать встроенный плоттер Arduino IDE для по- строения графика аналогового сигнала и создадим наш первый биометрический проект — измеритель частоты сердечных сокращений (пульсометр). Измерители частоты пульса за минувшее десятилетие стали миниатюрными и не- дорогими. Они широко применяются в «умных часах», фитнес-браслетах, спортив- ных тренажерах и профессиональной медицинской аппаратуре. 6.1. Принцип действия оптического пульсометра Частота сердечных сокращений в минуту (ЧСС), в быту называемая пульсом, — важнейший показатель физиологического состояния организма. Организм человека и животных реагирует резким учащением пульса на физическую нагрузку, опас- ность или стресс. При наличии сердечно-сосудистых заболеваний превышение до- пустимой частоты пульса может быть смертельно опасно. Резкое снижение частоты сердцебиения тоже сигнализирует об опасном состоянии организма. С древних времен знахари и эскулапы для подсчета частоты пульса прижимали па- лец к запястью или сонной артерии пациента и засекали определенный интервал времени. Когда изобрели электрокардиограф, ЧСС стали определять по кардио- грамме, измеряя интервал RR между соседними пиками кардиограммы и пересчи- тывая его в ЧСС по формуле ЧСС = 60/RR. Это очень точный метод, но для снятия кардиограммы требуется специальное оборудование1, которое сложно взять на про- бежку в парке. Существуют мобильные двухконтактные электрокардиографы в ви- де нагрудного пояса. Но это дорогое оборудование для профессиональных спорт- сменов. Современный массово доступный способ измерения ЧСС называется оптической плетизмографией и основан на зависимости поглощения света сеткой капилляров кожи и подкожного слоя от наполнения капилляров кровью. 1 Проект простого электрокардиографа описан в главе 15.
130 Часть II. Теория и практика Гемоглобин человеческой крови наиболее эффективно отражает красный свет (поэтому кровь ярко-красная). Для измерения поглощения нужно использовать так называемый инверсный (обратный) цвет спектра. В данном случае инверсный крас- ному — это зеленый цвет. Кровь человека наиболее интенсивно поглощает свето- вое излучение в диапазоне 500...600 нм. На практике в качестве источника света обычно используют зеленый светодиод с длиной волны 525 нм. Что такое обратный цвет спектра? Цвет предмета, который мы видим, соответствует отраженной части спектра. На- пример, мы видим кровь красной, потому что она отражает красную часть спектра и поглощает световые волны остального спектра. Если замкнуть цветовую линию ви- димого спектра в круг, то максимум поглощения будет находиться на круге строго напротив максимума отражения. Такие цвета называются обратными, инверсными, или негативными. Например, на негативе цветной фотографии небо желтое, потому что желтый цвет — обратный для голубого цвета. Человеческие ткани по-разному поглощают излучение зеленого цвета (рис. 6.1). Кости и сухожилия в основном отражают свет, поглощая лишь небольшую его часть. Вены и артерии немного лучше поглощают зеленый свет, но наиболее выра- женной поглощающей способностью обладает сеть капилляров. Свет проникает через тонкие стенки капилляров и поглощается гемоглобином крови. При этом свет практически не проникает сквозь толстые стенки вен и артерий. Поэтому наполне- ние вен и артерий почти не влияет на степень поглощения зеленого света. В момент сердечного толчка расширенные и наполненные кровью капилляры по- глощают зеленый свет намного сильнее, чем в промежутке между толчками сердца. График поглощения зеленого света в капиллярах в зависимости от сердечных со- кращений показан в верхней части рис. 6.1. А СТЕПЕНЬ ПОГЛОЩЕНИЯ ЗЕЛЕНОГО СВЕТА ВРЕМЯ Рис. 6.1. Зависимость поглощения зеленого света от степени наполнения кровеносной системы и типа тканей организма
Глава 6. Аналоговый оптический пульсометр 131 Почему измеряют степень поглощения зеленого света, а не степень отражения крас- ного? По сравнению с зеленым светом, зависимость отражения красного света от наполнения капилляров выражена меньше. Поэтому в простых пульсометрах чаще измеряют отражение зеленого света. Красный и инфракрасный свет применяется в биологических датчиках с более слож- ной конструкцией, которые, кроме частоты пульса, измеряют уровень насыщения крови кислородом. Мы обсудим этот вопрос в главе 16. Степень поглощения зеленого света можно измерять как через отражение, так и на просвет. На практике в мобильных устройствах редко применяют просвечивание, потому что для просвечивания насквозь запястья или пальца нужен мощный источ- Зеленые: свегодиодь? Ш Рис. 6.2. Пульсометр браслета Xiaomi Mi Band 2 &*'[0 Рис. б.З. Профессиональный медицинский пульсоксиметр с просвечивающим сенсором-клипсой
132 Часть II. Теория и практика ник света, который быстро разряжает батарею. Легче всего просвечивать мочку уха, но капилляры мочки уха чувствительны к сдавливанию. Это снижает чувстви- тельность прибора. В бытовых устройствах оптический датчик обычно размещается на запястье в виде браслета (рис. 6.2) и работает на отраженном свете. В медицинском оборудовании чаще используют клипсу для пальца (рис. 6.3). Датчик медицинской клипсы рабо- тает на просвет. 6.2. Погрешности измерения ЧСС оптическим методом Считается, что оптические датчики достаточно точно измеряют ЧСС при ходьбе или беге. Но при повышении частоты пульса более 150 ударов в минуту наполне- ние периферийных капилляров конечностей возрастает настолько, что они не успе- вают опорожняться, и датчик перестает надежно воспринимать пульсацию крово- тока. Эксперименты спортивных медиков показали, что при интенсивной нагрузке точность измерения ЧСС электрокардиографом составляет не менее 91%, а точ- ность показаний оптического датчика — только 85%. При работе над книгой я провел собственный эксперимент, одновременно измеряя частоту пульса во время интенсивного бега при помощи фитнес-браслета Xiaomi MiBand 2 и контактного кардиопульсометра беговой дорожки. При частоте пульса до 130 уд/мин показания обоих приборов приблизительно совпадали. При даль- нейшем росте частоты пульса браслет начал искажать показания. Когда контактный пульсометр беговой дорожки показывал частоту пульса 150 уд/мин, показания браслета колебались в районе 138... 142 уд/мин. Иными словами, оптический сенсор браслета начал занижать показания из-за пропуска отдельных пульсаций кровотока. Для бытовых занятий спортом эта погрешность не критична, но в профессиональ- ном спорте часто используют кардиопульсометры в виде нагрудного пояса с кон- тактами, которые соприкасаются с кожей в районе груди и регистрируют электри- ческие импульсы сердечных сокращений. Точность нагрудных кардиопульсомет- ров не зависит от частоты сердечных сокращений. На работу оптических сенсоров негативно влияют кости и сухожилия, которые в области запястья расположены близко к коже, а также татуировки и шрамы. Сен- соры, помещаемые на подушечку пальца, меньше подвержены влиянию анатомиче- ских факторов и работают надежнее. На точность работы оптического пульсометра также влияет общая наполняемость капилляров кровью, которая зависит от физической нагрузки, артериального давле- ния, температуры окружающей среды, приема сосудорасширяющих препаратов и некоторых других факторов.
Глава 6. Аналоговый оптический пульсометр 133_ 6.3. Простой оптический сенсор В наших первых проектах мы используем простой аналоговый оптический сенсор (рис. 6.4). Этот сенсор был представлен на краудфандинговой площадке Kickstarter и успешно собрал необходимые средства для начала массового производства. Офи- циальный сайт проекта находится по адресу http://www.pulsesensor.com. Рис. 6.4. Простой аналоговый пульсометр В центр небольшой платы сенсора помещен яркий зеленый светодиод (а). Рядом расположен ключевой элемент конструкции— фотоприемник, настроенный на спектр излучения светодиода (б). Световое излучение, отраженное от кожи и под- кожных капилляров, попадает на фотоприемник. Чем сильнее капилляры наполне- ны кровью, тем сильнее они поглощают зеленый свет и тем меньше света отража- ется в фотоприемник. Сигнал с фотоприемника поступает на операционный усили- тель и фильтр низкой частоты. Усиленный и очищенный от шума аналоговый сигнал передается на выход датчика. Считывание и обработку аналогового сигнала сенсора может выполнять любое устройство, оснащенное входом аналого-цифрового преобразователя (АЦП). Схема подключения сенсора к плате Arduino Uno показана на рис. 6.5. Сигнал с выхода сенсора подается на аналоговый вход АО. При подключении сенсора к плате NodeMCU выход сенсора также подключается к аналоговому входу АО, поэтому вносить изменения в скетчи не требуется. Перед началом опытов установите библиотеку сенсора. В данном случае скачивать файлы с внешних источников не потребуется. Перейдите в меню поиска Скетч | Подключить библиотеку | Управлять библиотеками. В строке поиска менедже- ра библиотек введите строку PuiseSensor (рис. 6.6) и нажмите кнопку Установка. Однако для проверки пульсометра библиотека сенсора нам не понадобится. Загру- зите в плату контроллера простейший скетч из листинга 6.1.
134 Часть II. Теория и практика АО GND 5V G + S Рис. 6.5. Схема подключения аналогового пульсометра к плате Arduino Uno Рис. 6.6. Установка библиотеки пульсометра в Arduino IDE
Глава 6. Аналоговый оптический пульсометр 135 int Signal; // Входной сигнал в диапазоне 0...1023 int Threshold = 550; // Пороговое значение для обнаружения пульса void setup() { pinMode(LED_BUILTIN, OUTPUT); // Встроеннный светодиод платы должен // мигать Serial.begin(9600); // Настраиваем void loop () { Signal = analogRead(O); // Читаем оцифрованное значение с аналогового // входа Serial.println(Signal); // Выводим полученное значение в плоттер порта if (Signal > Threshold) { // Если уровень сигнала // превышает порог, digitalWrite(LED_BUILTIN, HIGH); // зажигаем встроенный светодиод } else { digitalWrite(LED_BUILTIN, LOW); // Если нет, то гасим светодиод delay(10); // Задержка, чтобы отсчеты не шли слишком часто Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). Приложите сенсор оптической зоной, на которой изображено сердечко, к подушеч- ке пальца. Сенсор следует располагать так, чтобы он прилегал к коже без зазора, но не сдавливал подкожные капилляры. Сила прижатия должна быть постоянной. Не следует прижимать палец к сенсору, лежащему на столе или зажимать его между пальцами! Человек физически не способен сохранять постоянное усилие прижима. Малейшие колебания плотности прилегания будут резко отражаться на показаниях сенсора. Зафиксируйте сенсор на пальце при помощи текстильной ленты «липучки» или кусочка лейкопластыря (рис. 6.7). Не двигайте руку и не напрягайте мышцы руки во время измерений. Запустите встроенный плоттер среды разработки Arduino IDE. Если скетч работает правильно, и данные поступают в последовательный порт, то плоттер начнет рисо- вать график изменения напряжения на входе АО. После прорисовки одного экрана плоттер автоматически настроит масштаб по оси X, и мы получим максимально наглядный график (рис. 6.8). При необходимости подберите положение сенсора и силу прижатия для наблюдения максимально выраженных пульсаций.
136 Часть II. Теория и практика Рис. 6.7. Размещение сенсора на подушечке пальца -— г-~» ■■ — -Ч. Рис. 6.8. График пульсаций кровотока, отображаемый в окне плоттера Arduino IDE Наверное, вы уже видели подобный график в кино, когда главный герой лежит без сознания в больничной палате, а его друзья тревожно смотрят на медицинский монитор у изголовья кровати. Как вы только что убедились, получить такой график не составляет большого труда.
Глава 6. Аналоговый оптический пульсометр 137 Обратите внимание на форму периодического сигнала. Высокий пик на графике — это систолическая волна. Эту волну мы ощущаем, прощупывая пульс на запястье или сонной артерии. За ней следует малая дикротическая волна, возникающая в момент захлопывания сердечного клапана. Осторожно пальпируя (прижимая пальцами) сонную артерию на левой или правой стороне шеи (рис. 6.9), вы можете ощутить как систолическую, так и дикротическую волну. Но это наблюдение тре- бует определенного навыка, а на графике электронного пульсометра характерные волны без труда увидит даже неопытный пользователь прибора. Рис. 6.9. Обнаружение волн пульса на сонной артерии В скетче примера есть параметр Threshold, по умолчанию равный 550. Это порого- вое значение сигнала на выходе сенсора, по достижении которого считается, что обнаружен толчок пульса. Но, как отмечают сами разработчики сенсора, это нена- дежный способ определять пульс. Абсолютная амплитуда сигнала существенно за- висит от силы прижатия сенсора, индивидуальных особенностей организма, темпе- ратуры тела и других параметров. При неправильно выбранном пороговом уровне возможны ложное срабатывание от дикротической волны или, наоборот, пропуски пульсаций. На практике в пульсометрах регистрируют не простое превышение статичного по- рога, а ищут устойчивый нарастающий фронт систолической волны — анакроти- ческое колено. Более сложные алгоритмы профессиональных приборов дополни- тельно определяют спадающий фронт — катакротическое колено, и по сочетанию всех факторов делают вывод, что зафиксирован толчок пульса. Библиотека PulseSensor Playground ищет анакротическое колено систолической волны по упрощенному алгоритму, а значение переменной Threshold использует как вспомогательный параметр. Применению более сложных алгоритмов цифровой обработки препятствует небольшой объем памяти и невысокое быстродействие большинства плат Arduino. Откройте следующий файл примера из библиотеки: Файл | Примеры | Примеры из пользовательских библиотек | PulseSensor Playground | Getting_BPM_to_
138 Часть II. Теория и практика Monitor и загрузите его в плату Arduino. Откройте окно встроенного монитора порта на скорости 9600 бод. Скетч этого примера выводит в монитор числовое значение частоты пульса. Если вы видите, что значение пульса аномально низкое, это означает, что скетч пропус- кает отдельные импульсы систолической волны. Попробуйте снизить значение Threshold до 500. Если частота пульса аномально высокая, следовательно, програм- ма фиксирует не только систолическую, но и дикротическую волну. Попробуйте увеличить значение Threshold ДО 600. Встроенный плоттер Arduino IDE наглядно отображает график пульсограммы, но наше устройство «привязано» к компьютеру. Чтобы сделать пульсометр автоном- ным и удобным в использовании, необходимо воспользоваться малогабаритным дисплеем. 6.4. Пульсометр с OLED-дисплеем В этом проекте мы задействуем малогабаритный экономичный OLED-дисплей с разрешением 128x64 пиксела. Его быстродействия и размера рабочего поля дос- таточно для отображения схематичной пульсограммы и цифрового значения часто- ты пульса. Электрическая схема соединения компонентов проекта представлена на рис. 6.10, его макет показан на рис. 6.11, а исходный код программы приведен в листинге 6.2. SCL Рис. 6.10. Схема подключения компонентов для пульсометра с OLED-дисплеем
Глава 6. Аналоговый оптический пульсометр 139 Рис. 6.11. Макет пульсометра с OLED-дисплеем Для индикации зафиксированных систолических импульсов применяется встроен- ный светодиод платы контроллера. При правильно размещенном на пальце и устойчиво работающем сенсоре светодиод на плате будет вспыхивать в такт толч- кам пульса. // Разрешаем прерывания низкого уровня // Это необходимо для более точного измерения частоты пульса #define USE_ARDUINO_INTERRUPTS true // Подключаем библиотеку пульсометра #include <PulseSensorPlayground.h> // Подключаем графические библиотеки дисплея #include <Adafruit_GFX.h> // Графическое ядро #include <Adafruit_SSD1306.h> // Библиотека OLED-дисплея #define SCREEN_WIDTH 128 // Ширина дисплея в пикселах #define SCREEN_HEIGHT 64 // Высота дисплея в пикселах #define OLED_RESET -1 //В нашем дисплее нет линии сброса // Создаем объект дисплея Adafruit SSD1306 oled(SCREEN WIDTH, SCREEN HEIGHT, &Wire, OLED RESET);
140 Часть II. Теория и практика #define PULSE_IND 13 // Вывод для подключения индикатора пульса, //а также встроенный светодиод платы Arduino Uno, Nano // Создаем объект сенсора PulseSensorPlayground pulseSensor; int sensor, drawSensor, drawSensorOld, drawThreshold; int Threshold =570; // Пороговое значение сигнала для библиотеки // пульсометра int xPos =0; // Текущая позиция по оси X на экране дисплея void setup() { oled.begin(SSD1306_SWITCHCAPVCC, ОхЗС); // Инициализируем дисплей oled.clearDisplay(); // Очищаем экран oled.display(); // Обновляем экран (обязательная процедура) oled.setTextSize(2); // Задаем размер текста oled.setTextColor(WHITE); // Задаем цвет текста pulseSensor.analoglnput(АО); // Назначаем вход для сигнала с сенсора pulseSensor.blinkOnPulse(PULSE_IND); // Встроенный светодиод платы // мигает в такт пульсу pulseSensor.setThreshold(Threshold); // Устанавливаем порог срабатывания pulseSensor.begin(); // Инициализируем сенсор void loop () { // Читаем показания сенсора int sensor = analogRead(AO); // Если обнаружен пульс, выводим числовое значение //в правый верхний угол экрана if (pulseSensor.sawStartOfBeat()) { int myBPM = pulseSensor.getBeatsPerMinute(); // Получаем частоту пульса oled.fillRect(90, 0, 128, 16, BLACK); // Очищаем область текста oled.setCursor(90, 0); // Задаем позицию курсора oled.print (myBPM); // Выводим частоту пульса // Масштабируем показания в размер дисплея по вертикали drawSensor = map(sensor, 0, 1023, 0, 47); // Если начало дисплея, рисуем начальную точку графика if (xPos ==0) { oled.drawPixel(xPos, 64 - drawSensor, WHITE); oled.display(); 'drawSensorOld = drawSensor;
Глава 6. Аналоговый оптический пульсометр 141 // Иначе рисуем линию от предыдущей точки к текущей else { oled.drawLine(xPos, 64 - drawSensor, xPos, 64 - drawSensorOld, WHITE); oled.display(); drawSensorOld = drawSensor; // Если достигнут конец экрана, очищаем экран и обнуляем счетчик отсчетов if (xPos >= 128) { xPos = 0; oled.clearDisplay(); oled.display(); } // Иначе просто инкрементируем счетчик позиции по оси X else { xPos++; Алгоритм программы в общем виде следующий: 1. Создаем объект дисплея. 2. Настраиваем и инициализируем дисплей. 3. Инициализируем пульсометр. 4. В главном цикле измеряем уровень сигнала на аналоговом входе АО. 5. Масштабируем измеренное значение при помощи встроенной функции тар о из диапазона выходных значений АЦП 0...1023 в диапазон размера свободного по- ля дисплея по вертикали. В нашем случае вертикальное разрешение дисплея 64 пиксела, из них верхние 16 заняты под строку цифр. Остается 48 пикселов (диапазон значений 0...47). 6. Если обнаружен пульс, отображаем его частоту, прорисовываем график по текущим координатам экрана, инкрементируем координаты по оси X. 7. Если достигнута правая граница экрана, обнуляем координату по оси X и очи- щаем экран для прорисовки следующего цикла. Комментарии к исходному коду детально описывают выполняемые действия. 6.5. Пульсометр с цветным TFT-дисплеем Электрическая схема соединения компонентов проекта представлена на рис. 6.12, его макет показан на рис. 6.13, а исходный код программы приведен в листинге 6.3. Для сборки этого макета вам потребуется аккуратность и начальные навыки чтения электрических схем. Резисторы на линиях CS, D/C, MOSI и CLK предназначены для согласования логи- ческих уровней между платой Arduino (логика TTL 5 вольт) и драйвером дисплея
142 Часть II. Теория и практика (логика 3 вольта). Если подключить дисплей напрямую к плате Arduino Uno, он не будет работать и может выйти из строя. Для подключения к платам на основе ESP8266 согласующие резисторы не нужны, т. к. логические уровни контроллера и дисплея совпадают. Рис. 6.12. Электрическая схема пульсометра с TFT-дисплеем Рис. 6.13. Макет пульсометра с цветным TFT-дисплеем
Глава 6. Аналоговый оптический пульсометр 143 Резистор, смонтированный последовательно со светодиодом, ограничивает идущий через него ток. В нашем случае мы не можем использовать встроенный светодиод платы Arduino Uno, потому что он подключен к выводу D13. В нашей схеме D13 работает как стан- дартная линия тактовых импульсов CLK для интерфейса SPI. Поэтому мы подклю- чили внешний светодиод к свободному выводу D8. // Разрешаем прерывания низкого уровня // Это необходимо для более точного измерения частоты пульса #define USE_ARDUINO_INTERRUPTS true // Подключаем библиотеку пульсометра #include <PulseSensorPlayground.h> // Подключаем графические библиотеки дисплея #include <Adafruit_GFX.h> // Графическое ядро #include <Adafruit_ST7735.h> // Библиотека TFT-дисплея на чипе ST7735 #include <SPI.h> #define TFT_CS 10 // Вывод CS дисплея #define TFT_DC 9 // Вывод D/C дисплея tdefine TFT_RST 0 // Сброс дисплея подключен к линии RES платы Arduino #define PULSE_IND 8 // Вывод для подключения индикатора пульса // Создаем объект дисплея Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); // Создаем объект сенсора PulseSensorPlayground pulseSensor; int sensor, drawSensor, drawSensorOld, drawThreshold; int Threshold =570; // Пороговое значение сигнала для библиотеки // пульсометра int xPos =0; // Текущая позиция по оси X на экране дисплея void setup() { // Устанавливаем максимальную скорость шины SPI, 1/2 тактовой частоты // для быстрой прорисовки дисплея SPI.setClockDivider(SPI_CLOCK_DIV2); tft.initR(INITR_BLACKTAB); // Инициализация чипа ST7735S tft.setRotation(3); // Горизонтальное положение дисплея
144 Часть II. Теория и практика tft.fillScreen(ST7735_BLACK); // Очистка экрана заливкой в черный цвет tft.setTextSize(2); // Размер текста tft.setTextColor(ST7735_GREEN); // Цвет текста pulseSensor.analoglnput(АО); // Назначаем вход для сигнала с сенсора pulseSensor.blinkOnPulse(PULSE_IND); // Встроенный светодиод платы мигает //в такт пульсу pulseSensor.setThreshold(Threshold); // Устанавливаем порог срабатывания pulseSensor.begin(); // Инициализируем сенсор void loop () { // Читаем показания сенсора int sensor = analogRead(AO); // Если обнаружен пульс, выводим числовое значение //в правый верхний угол экрана if (pulseSensor.sawStartOfBeat()) { int myBPM = pulseSensor.getBeatsPerMinute(); // Получаем частоту пульса tft.fillRect(122, 0, 160, 16, ST7735_BLACK); // Очищаем область текста tft.setCursor(122, 0); // Задаем позицию курсора tft.print(myBPM); // Выводим частоту пульса // Масштабируем показания в размер свободного поля дисплея по вертикали drawSensor = map(sensor, 0, 1023, 0, 112); // Если начало дисплея, рисуем начальную точку (линию единичной длины) if (xPos ==0) { tft.drawLine(xPos, tft.height() - drawSensor, xPos, tft.heightO - drawSensor - 1, ST7735_YELLOW); drawSensorOld = drawSensor; } // Иначе рисуем линию от предыдущей точки к текущей else { tft.drawLine (xPos, tft.heightO - drawSensor, xPos, tft.heightO - drawSensorOld, ST7735_YELLOW); drawSensorOld = drawSensor; // Если достигнут конец экрана, очищаем область графика //и обнуляем счетчик по оси X if (xPos >= 160) { xPos = 0; tft.fillRect(0, 17, 160, 128, ST7735_BLACK); // Очищаем область графика
Глава 6. Аналоговый оптический пульсометр 145 // Иначе просто инкрементируем счетчик отсчетов else { xPos++; // Небольшая задержка для оптимизации масштаба графика по горизонтали delay(16); } Алгоритм работы программы полностью аналогичен алгоритму программы для пульсометра с OLED-дисплеем (см. листинг 6.2). Различие заключается только в другой библиотеке дисплея и диапазоне масштабирования входного сигнала под экран с более высоким разрешением. TFT-экран работает быстрее, чем OLED, по- этому пришлось добавить небольшую задержку delay (16) в главном цикле. Варьи- руя значение этой задержки, вы можете менять масштаб графика по горизонтали. Чем меньше задержка, тем сильнее «растянут» график. 6.6. Задания для самостоятельной работы 1. Доработайте скетч, чтобы при частоте пульса менее 60 уд/мин числовое значе- ние на экране отображалось числом синего цвета (st7735_blue), а при частоте более 150 уд/мин — числом красного цвета (st7735_red). 2. Доработайте схему устройства и скетч, чтобы при отсутствии ударов пульса в течение одного цикла обновления дисплея раздавался звуковой сигнал тревоги. 6.7. Опыты с пульсометром Опыты, связанные с наблюдением за человеческим пульсом, требуют особого терпения и спокойствия. Если есть возможность, пригласите ассистента, который будет помогать вам в проведении опытов. 6.7.1. Опыт с наложением жгута Этот несложный и наглядный опыт поможет вам научиться правильно накладывать жгут при оказании первой помощи. Поместите сенсор на подушечку пальца. По- просите ассистента при помощи импровизированного жгута из куска резиновой трубки или широкой бельевой резинки пережать руку в районе предплечья. Обыч- но на это место надевают манжету для измерения давления крови. В зависимости от плотности наложения жгута, пульсация крови в периферийных сосудах и капил- лярах полностью или почти полностью прекратится, а сенсор перестанет реагиро- вать на пульсацию капилляров. Помните — даже при серьезных травмах кровообращение конечностей нельзя пол- ностью прерывать более чем на один час! Это грозит омертвением тканей конечно- сти и отравлением организма продуктами клеточного метаболизма после снятия жгута.
146 Часть //. Теория и практика 6.7.2. Опыт с реакцией капилляров на температуру Опустите пальцы руки в холодную воду (можно с кубиками льда) на несколько ми- нут. Выньте пальцы из воды, протрите насухо. Сразу после протирания поместите на безымянный палец сенсор. Зафиксируйте амплитуду систолической волны в на- чале опыта. Подождите 10-15 минут, пока пальцы согреются естественным теплом организма. Наблюдайте, как меняется амплитуда систолической волны на экране. Как вы объясните наблюдаемый эффект? Для ускорения согревания руки можно выпить около стакана горячего, но не крепкого чая. Кофеин, который содержится в крепком чае и кофе, сложным образом влияет на тонус периферийных сосудов и может исказить результаты измерений. 6.7.3. Опыт с частотой и глубиной дыхания (рефлекс Геринга) Поместите сенсор на палец. Успокойтесь, сидите неподвижно. Несколько раз вдох- ните медленно и глубоко. После каждого вдоха задерживайте дыхание на 10 секунд и медленно выдыхайте. Пульс должен замедлиться на 6—8 ударов в минуту. Теперь начните дышать неглубоко и быстро. Как изменились частота пульса и наполнение капилляров? 6.7.4. Рефлекс Ортнера Встаньте ровно, голову держите прямо. Подождите около минуты для стабилиза- ции пульса. Запрокиньте голову назад до предела. Частота пульса должна сокра- титься на 4-6 ударов в минуту. 6.7.5. Клиностатический рефлекс Даниелополу Испытуемый занимает вертикальное положение рядом с кроватью, успокаивается. Ассистент фиксирует частоту пульса. Затем испытуемый ложится на кровать. При переходе в горизонтальное положение частота пульса снижается на 10-12 ударов в минуту. 6.7.6. Ортостатический рефлекс Превеля Испытуемый спокойно лежит на кровати, ассистент фиксирует частоту пульса. За- тем испытуемый принимает вертикальное положение. Частота пульса увеличивает- ся на 10-12 ударов в минуту. В профессиональных медицинских исследованиях применяют специальную пово- ротную лежанку, которая позволяет менять положение тела испытуемого без уси- лий с его стороны.
Глава 6. Аналоговый оптический пульсометр 147_ 6.7.7. Опыт с физической нагрузкой Поместите сенсор на палец. Сидите спокойно не менее пяти минут, затем зафикси- руйте значение частоты пульса. Выполните 10-15 приседаний. Сравните частоту и наполнение пульса с аналогичными параметрами в состоянии покоя. Наблюдайте за постепенным восстановлением пульса. Сравните степень изменения параметров и скорость восстановления нормы пульса у подопытных с разным уровнем физиче- ской подготовки. 6.8. Информация для любознательных При ритмических сокращениях сердца возникают колебания стенок сосудов, кото- рые мы ощущаем, как пульс. График колебаний стенки сосудов называется сфигмо- граммой, а запись параметров пульса — сфигмографией. В научных и клинических исследованиях у человека записывают колебания стенки лучевой артерии, а у крупных животных — брюшной аорты. Сфигмограмма — это весьма полезный график, который несет в себе информацию не только о частоте сердечных сокращений. Наверняка вы не задумывались о том, что скорость распространения пульсовой волны значительно превышает скорость кровотока. Толчок пульса в запястье во- все не означает, что в этот момент туда поступила свежая кровь! Пульс — это вол- на избыточного давления, которая прокатилась по кровеносным сосудам в момент сокращения сердечной мышцы. Скорость движения крови в сосудах составляет всего 0,5 м/с, а скорость пульсовой волны в 14-20 раз быстрее и колеблется в диапазоне от 7 до 10 м/с. Скорость пуль- совой волны— это важный диагностический параметр! Мы рассмотрим проект устройства для измерения скорости пульсовой волны в главе 16.
ГЛАВА 7 Шагомер на акселерометре ADXL335 В главе 6 мы воспользовались встроенным плоттером среды разработки Arduino IDE для построения графика пульсаций крови в капиллярах. В этой главе мы по- этапно пройдем через процесс разработки проекта, начиная с анализа доступных данных и заканчивая работающим макетом устройства. На примере проекта про- стого шагомера вы научитесь использовать более мощные инструменты визуализа- ции и анализировать графики. Вы освоите на практике программы SFMonitor и FlexiPlot и оцените их достоинства и недостатки при использовании в любитель- ских проектах. Шагомер не измеряет напрямую биологические показатели человеческого организ- ма, но применяется для правильного дозирования физической нагрузки. Специаль- ные спортивные шагомеры предоставляют намного больше информации о процессе бега, чем бытовые гаджеты. Спортивные шагомеры измеряют скорость отрыва ног от земли, высоту подскока тела, ускорение шагового толчка, нагрузку на суставы при приземлении ступни и другие параметры. Все эти данные получаются путем измерения ускорений с помощью акселерометра и помогают спортсмену улучшить технику бега. В любительских условиях трудно повторить многофакторный спор- тивный шагомер, но нам вполне по силам разработать простое и полезное бытовое устройство. 7.1. Интегральный аналоговый акселерометр ADXL335 Акселерометр— это устройство, которое измеряет мгновенное ускорение по од- ному или нескольким направлениям (осям) и выдает результат измерения в анало- говой или цифровой форме. На все физические тела на поверхности Земли действу- ет ускорение свободного падения. Когда тело начинает перемещаться под действи- ем внешних сил, к ускорению свободного падения добавляется ускорение движения. Большинство акселерометров массового применения измеряют ускоре- ние по трем ортогональным осям: X, Y, Z — в корпусе микросхемы находятся три измерителя ускорений, которые изготовлены по интегральной технологии в виде единого микроскопически малого узла.
Глава 7. Шагомер на акселерометре ADXL335 Мы начнем работу над проектом со знакомства с простым интегральным акселеро- метром ADXL335 (рис. 7.1). На плате модуля условно показаны оси, по которым измеряются ускорения. Ось Z направлена перпендикулярно плоскости платы вверх. Рис. 7.1. Модуль аналогового акселерометра ADXL335 Микросхема питается напряжением +3,3 вольта, на плате имеется встроенный стабилизатор напряжения питания. На выходы X-out, Y-out и Z-out поступают аналоговые сигналы, уровень которых зависит от величины и направления дейст- вующего ускорения. Вывод ST (Self Test) предназначен для самотестирования мик- росхемы. Мы его использовать не будем. 7.2. Подключение ADXL335 к плате Arduino Uno Благодаря небольшому потребляемому току и удачному расположению выводов, модуль акселерометра можно подключить к плате Arduino Uno без соединительных проводов, — достаточно вставить штыревой разъем модуля в гнезда А0-А4 платы Arduino Uno (рис. 7.2). Рис. 7.2. Подключение модуля акселерометра ADXL335 к плате Arduino Uno
150 Часть II. Теория и практика Это необычный способ питания — от портов микроконтроллера. Мы воспользуем- ся тем, что при высоком логическом уровне на выводе порта напряжение близко к напряжению питания, а при низком логическом уровне — близко к нулю. Поэто- му модули с потребляемым током до 20 мА, которые оснащены встроенным стаби- лизатором 3,3 вольта, можно питать непосредственно от портов микроконтроллера. К другим платам Arduino модуль можно подключить соединительными проводами по следующей схеме: ADXL335 GND Z-out Y-out X-out VCC Arduino АО A1 A2 A3 A4 Для питания модуля можно использовать обычные выводы 5V и GND или другие порты. Не забудьте внести исправления в исходный код примеров программ, если измените схему подключения. В любом случае аналоговые выходы акселерометра должны быть подключены к аналоговым входам платы контроллера. Для проверки акселерометра и оценки формы выходных сигналов воспользуемся простым скетчем из листинга 7.1. #define GND АО // Общий провод (низкий уровень) tdefine VCC A4 // Питание (высокий уровень) int Xout, Yout, Zout; void setup() { // Включаем питание акселерометра pinMode(GND, OUTPUT); pinMode(VCC, OUTPUT); digitalWrite(GND, LOW); digitalWrite(VCC, HIGH); Serial.begin(115200) ; void loop() { Xout = analogRead(A3); Yout = analogRead(A2); Zout = analogRead(Al); Serial.print(Xout); Serial.print(",");
Глава 7. Шагомер на акселерометре ADXL335 151 Serial.print(Yout); Serial.print(V) ; Serial.println(Zout); delay(10); Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). Загрузите скетч и откройте окно монитора порта Arduino IDE. Вы увидите непре- рывный поток числовых данных, которые меняются сильнее, если двигать акселе- рометр. Но в таком виде эти данные для нас бесполезны. Откройте окно встроенного плоттера Arduino IDE и попробуйте резко двигать пла- ту акселерометра по очереди вдоль каждой координатной оси. Теперь другое дело! На графиках хорошо видно, как акселерометр реагирует на ускорения (рис. 7.3). Рис. 7.3. График отклика акселерометра в окне встроенного плоттера Arduino IDE
152 Часть II. Теория и практика Когда акселерометр неподвижен, на его выходах все равно присутствуют неболь- шие колебания сигнала. Это собственный шум акселерометра. Он мешает регист- рировать небольшие ускорения. У современных моделей цифровых акселерометров уровень собственного шума в несколько раз ниже. Мы разрабатываем шагомер, поэтому должны знать форму сигнала на выходах акселерометра при ходьбе и беге. Но сейчас наш макет привязан к компьютеру соединительным проводом. Для удобства проведения исследований организуем беспроводное подключение по Bluetooth. 7.3. Подключение шагомера к плоттеру FlexiPlot no Bluetooth Возьмите модуль Bluetooth, настроенный по инструкции разд. 3.6. Подключите его по следующей схеме: Arduino GND 5V D2 D3 Bluetooth GND VCC TXD RXD Загрузите в плату Arduino скетч из листинга 7.2. В этом скетче на выводах1 D2 (RX) и D3 (ТХ) задействована библиотека программного последовательного порта Sof twareseriai. Данные передаются в формате пакетов FlexiPlot. #include <SoftwareSerial.h> #define GND АО // GND для питания акселерометра #define VCC A4 // VCC для питания акселерометра int Xout, Yout, Zout; // Создаем виртуальный порт mySerial SoftwareSerial mySerial(2, 3); // RX, TX void setup() { // Включаем питание акселерометра pinMode(GND, OUTPUT); pinMode(VCC, OUTPUT); 1 Напоминаю, что для протокола UART линии ТХ и RX соединяются «перекрестно»: TX-+RX, RX—►ТХ.
Глава 7. Шагомер на акселерометре ADXL335 153^ digitalWrite(GND, LOW); digitalWrite(VCC, HIGH); // Инициализируем виртуальный порт mySerial.begin(115200); void loopO { Xout = analogRead(A3); Yout = analogRead(A2); Zout = analogRead(Al); // Пример формата блока данных FlexiPlot // {Р0|Roll|255,0,0|25|Pitch|0,255, 0|56} mySerial.print("{P0|Xout|255,0,0 Г); mySerial.print(Xout); mySerial.print("|Yout|0,255,0|"); mySerial.print(Yout); mySerial.print("|Zout|0,0,255|") ; mySerial.print(Zout); mySerial.println("}"); delay(20); Запустите программу FlexiPlot. Перейдите в меню Serial | Settings. Задайте номер виртуального порта Bluetooth (см. разд. 3.6) и скорость 115200 бод. Нажмите кнопку с изображением графика Add Line Chart. Выберите вкладку Settings в окне графика. Введите новый заголовок графика в поле Title. Снимите флажок с опции Auto Scaling Y. Когда вы наблюдали за показаниями акселерометра в окне плоттера Arduino IDE, то могли заметить, что значения уровня сигнала по всем трем осям не выходят за пределы диапазона 200...600. Воспользуемся этим наблюдением. Задайте новое значение Min Y = 200 и новое значение Max Y = 600. В поле Date Format оставьте только секунды — ss. Остальные настройки оставьте без изменений и вернитесь к вкладке Chart. Подключите макет шагомера к портативному источнику питания. Нажмите кнопку подключения к порту Connect to Device или комбинацию клавиш <Ctrl>+<F>. Про- грамма откроет последовательный порт Bluetooth, и данные начнут отображаться на графике. Если соединение не устанавливается, проверьте номер порта и привяз- ку модуля Bluetooth к ОС Windows. Возьмите макет в руку и начните ходить обычным шагом на расстоянии не более 10 метров от компьютера. Попросите помощника нажать кнопку останова в правом нижнем углу графика и внимательно изучите кривые уровней сигнала (рис. 7.4). На графике сигнала Xout наблюдаются отчетливые колебания в такт шагам.
154 Часть II. Теория и практика Рис. 7.4. Графики выходных сигналов ADXL335 в окне FlexiPlot В моем случае активной осью акселерометра является его ось X. При другом распо- ложении акселерометра на теле человека может стать активной другая ось. Поэтому для надежного подсчета шагов следует предусмотреть такое крепление шагомера к телу, которое подразумевает однозначное положение датчика (например, браслет), или отслеживать ускорения по всем трем осям. На основе графика, показанного на рис. 7.4, можно сделать вывод, что для надеж- ной фиксации импульса шага можно выбрать пороговое значение в диапазоне 400...450. Доработаем исходный скетч из листинга 7.2 и добавим в него программ- ное определение импульсов шага. Отладочную информацию будем выводить в плоттер FlexiPlot. Скетч после доработки представлен в листинге 7.3. Изменения и дополнения выделены в нем полужирным шрифтом. #include <SoftwareSerial.h> #define GND АО #define VCC A4 #define THLD 430 // Пороговое дна' |.чениа амплитуды импульса int Xout, Yout, Zout, count; boolean rise = 0, fall = 1;
Глава 7. Шагомер на акселерометре ADXL335 155 II Создаем виртуальный порт mySerial SoftwareSerial mySerial(2, 3); // RX, TX void setup() { // Включаем питание акселерометра pinMode(GND, OUTPUT); pinMode(VCC, OUTPUT); digitalWrite(GND, LOW); digitalWrite(VCC, HIGH); // Инициализируем виртуальный порт mySerial.begin(115200); void loop() { Xout = analogRead(A3); Yout = analogRead(A2); Zout = analogRead(Al); // Ждем передний (нарастающий) фронт импульса шага if (Xout > THLD && (rise = 0) && (fall = 1)) { rise = 1; // Зафиксирован передний фронт импульса шага fall = 0; // Сбрасываем флаг спада импульса count++; // Инкремент счетчика шагов // Ждем задний (спадающий) фронт импульса шага if (Xout < THLD && (rise = 1) && (fall = 0)) { fall = 1; // Зафиксирован задний фронт (спад) импульса шага rise = 0; // Сбрасываем флаг нарастания импульса // Пример формата блока данных FlexiPlot // {Р0|Roll|255,0,0125|Pitch| 0,255,0|56} // Выводим графики осевых ускорений в окно РО mySerial.print("{РО|Xout|255,0,0|"); mySerial.print(Xout); mySerial.print("|Yout|0,255,О Г); mySerial.print(Yout); mySerial.print("|Zout|0,0,255|") ; mySerial.print(Zout); mySerial.println("}"); // Выводим значение индикатора шага в окно Р1 mySerial.print("{Pl|Step|0,0,0|"); mySerial.print(rise); mySerial.println("}")/ delay(20);
156 Часть II. Теория и практика Нам необходимо сделать так, чтобы счетчик шагов инкрементировался только в момент достижения порогового уровня. Если просто сравнивать текущее и поро- говое значение, то счетчик шагов будет увеличиваться при каждом новом считыва- нии данных с порта, пока эти данные превышают порог. Заметив превышение по- рога, следует однократно увеличить счетчик шагов и дождаться следующего рабо- чего импульса. Для решения этой задачи мы будем фиксировать не только нарастание, но и спад импульса. Как только зафиксирован переход сигнала через порог «снизу вверх», мы инкрементируем счетчик шагов, поднимаем флаг rise (рост) и обнуляем флаг fail (спад). Теперь, пока флаг rise равен единице, мы больше не увеличиваем счетчик шагов. Как только зафиксирован переход сигнала через порог «сверху вниз», мы сбрасы- ваем флаг rise, поднимаем флаг fail и ждем следующий шаг. Для проверки правильности работы скетча мы выводим в новое окно Р1 плоттера FlexiPlot значение флага rise. В главном окне FlexiPlot нажмите на кнопку Add Line Chart. Выберите вкладку Settings в окне графика. Введите новый заголовок графика в поле Title. Снимите Рис. 7.5. Отладочные графики для скетча из листинга 7.3
Глава 7. Шагомер на акселерометре ADXL335 157 флажок с опции Auto Scaling Y. Задайте минимальное значение 0 и максимальное значение 1. В поле Date Format оставьте только секунды— ss. Остальные на- стройки оставьте без изменений и вернитесь к вкладке Chart. Расположите окно Р1 под окном РО. Загрузите скетч в плату Arduino, подключите плоттер FlexiPlot к порту Bluetooth и вновь проведите эксперимент с ходьбой и бегом в разных режимах. Если все рабо- тает правильно, вы должны получить графики, аналогичные изображенным на рис. 7.5. В некоторых случаях может потребоваться подбор нового порогового зна- чения thld под ваш экземпляр акселерометра. Теперь мы готовы собрать макет шагомера с OLED-дисплеем и написать для него скетч. 7.4. Простой шагомер с OLED-дисплеем Электрическая схема соединения компонентов проекта представлена на рис. 7.6, а его макет— на рис. 7.7. Подключите компоненты макета и загрузите в плату Arduino скетч из листинга 7.4. В этот скетч добавлены библиотека графического ядра и библиотека поддержки OLED-дисплея. На дисплее отображается количество шагов, приблизительная дистанция и количество затраченных калорий. Средняя длина шага и коэффициент расхода калорий вычисляется индивидуально для поль- зователя и записывается в код до компиляции. Рис. 7.6. Схема подключения компонентов в проекте шагомера с OLED-дисплеем
158 Часть II. Теория и практика Рис. 7.7. Макет шагомера на основе акселерометра ADXL335 с OLED-дисплеем Обратите внимание, что выводы А4 и А5 совпадают с выводами SDA и SCL, кото- рые нужны для подключения OLED-дисплея по шине 12С. Поэтому в схему под- ключения и скетч внесены соответствующие изменения. Теперь акселерометр питается от штатных выводов 5V и GND, а сигналы акселерометра считываются с выводов А0-А2. Возможно, придется заново подобрать значение порога thld. Интересный факт Расход энергии зависит только от пройденного расстояния и веса человека. Ходьба и бег дают одинаковый расход калорий на единицу длины пути. С точки зрения дие- ты бег эффективнее лишь потому, что калории сжигаются за меньшее время трени- ровки. 7.4.1. Определение средней длины шага Пройдите дистанцию определенной длины — например, 100 метров — и сосчитай- те шаги. Разделите дистанцию на количество шагов и получите длину шага в мет- рах. Можно приблизительно вычислить длину шага как 41% от роста. 7.4.2. Определение расхода калорий Расход калорий при ходьбе или беге вычисляют по формуле 0,5 х вес человека (кг) * расстояние (км) = энергия (Ккал)
Глава 7. Шагомер на акселерометре ADXL335 159 Учитывается полный вес человека — в одежде и со снаряжением. Например, если человек с полным весом 80 кг прошел дистанцию 3 км, то он затратил: 0,5 х 80 х 3 = 120 Ккал #include <Wire.h> #include <Adafruit_GFX.h> // графическое ядро #include <Adafruit_SSD1306.h> // библиотека OLED-дисплея #define X АО #define Y Al ttdefine Z A2 #define THLD 430 // Пороговое значение амплитуды импульса // Задайте здесь физиологические параметры пользователя #define WEIGHT_KG 80 // Вес пользователя, кг #define STEP_LENGTH 0.7 // Длина шага пользователя #define SCREEN_WIDTH 128 // Ширина дисплея в пикселах #define SCREEN_HEIGHT 64 // Высота дисплея в пикселах #define OLED_RESET -1 //В нашем дисплее нет линии сброса // Создаем объект дисплея Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET), int Xout, Yout, Zout, count, distance; boolean rise = 0, fall = 1; float energy; void setup() { // Активируем OLED-дисплей oled.begin(SSD1306_SWITCHCAPVCC, ОхЗС); oled.clearDisplay(); oled.display(); // Устанавливаем размер и цвет текста oled.setTextSize(2); oled.setTextColor(WHITE); delay(500); void loop() { Xout = analogRead(X); Yout = analogRead(Y); Zout = analogRead(Z); Serial.println(Xout);
Часть II. Теория и практика // Ждем передний (нарастающий) фронт импульса шага if (Xout > THLD && (rise == 0) && (fall ==1)) { rise =1; // Зафиксирован передний фронт импульса шага fall =0; // Сбрасываем флаг спада импульса count++; // Инкремент счетчика шагов distance = int (count * STEP_LENGTH); energy = 0.5 * WEIGHT_KG * distance / 1000; // Ждем задний (спадающий) фронт импульса шага. if (Xout < THLD && (rise == 1) && (fall ==0)) { fall = 1; // Зафиксирован задний фронт (спад) импульса шага rise = 0; // Сбрасываем флаг нарастания импульса showText(); delay(20); } // Функция вывода текста на дисплей void showText() { oled.clearDisplay(); // Выводим количество шагов oled.setCursor(0, 0) ; oled.print("Step:"); oled.setCursor(60, 0) ; oled.print(count); // Выводим расстояние oled.setCursor(0, 23) ; oled.print("Dist:"); oled.setCursor(60, 23); oled.print(distance); // Выводим энергию oled.setCursor(0, 46); oled.printC'kCal:") ; oled.setCursor(60, 46); if (energy < 1) { oled.print(energy, 2); } else { oled.print(energy); } // Обновляем экран дисплея oled.display() ;
Глава 7. Шагомер на акселерометре ADXL335 161_ 7.5. Задания для самостоятельной работы 1. Доработайте скетч шагомера так, чтобы счетчик шагов реагировал на превыше- ние порога ускорения по любой из трех осей: X, Y, Z. 2. Доработайте скетч так, чтобы недобросовестный пользователь не мог вручную искусственно «натрясти» показания шагомера. Подсказки: максимальная ско- рость бега человека— 44,7 км/ч. Это мировой рекорд. Средняя скорость бега мирового рекордсмена Усейна Болта— 37 км/ч. Скорость бега на коротких дис- танциях обычного тренированного спортсмена редко превышает 30 км/ч. Исходя из этих данных, рассчитайте минимальный допустимый интервал времени меж- ду импульсами шагов и воспользуйтесь встроенным счетчиком миллисекунд Arduino.
ГЛАВА 8 Бесконтактное измерение температуры тела Мы с детства привыкли измерять температуру при помощи контактного термомет- ра. Сначала это были опасные и неудобные ртутные градусники. Затем их сменили электронные термометры, которые работают намного быстрее и не содержат ртуть. Но измерение температуры контактным способом по-прежнему неудобно в некото- рых ситуациях: ♦ маленькие дети; ♦ спящие или беспокойные больные; ♦ животные; ♦ проверка самочувствия большой группы людей (класс, предприятие). Для быстрого и удобного измерения температуры тела применяют дистанционные термометры— пирометры. На рис. 8.1 изображен медицинский пирометр для из- мерения температуры тела в ушной раковине. Рис. 8.1. Бесконтактный медицинский термометр-пирометр
Глава 8. Бесконтактное измерение температуры тела 163 Мы изготовим самодельный пирометр, который можно применять не только для измерения температуры тела. С его помощью вы сможете измерить температуру компонентов электронной платы и любых других предметов. Основой проекта станет инфракрасный пиросенсор MLX90615 производства компании Melexis (рис. 8.2). Рис. 8.2. Инфракрасный пиросенсор MLX90615 Основные технические характеристики пиросенсора MLX90615 ♦ Диапазон температуры объекта измерений: -40...+115 °С ♦ Диапазон температуры окружающей среды: -40...+85 °С ♦ Точность измерения температуры объекта: ±0,5 °С ♦ Шаг дискретизации встроенного АЦП: ±0,02 °С (10 битов) ♦ Напряжение питания: 3,0...3,6 вольт ♦ Потребляемый ток: 25 мА ♦ Протокол обмена данными: SMBus (совместимый с 12С) ♦ Количество сенсоров на одной шине: до 127 8.1. Принцип действия и устройство инфракрасного пирометра Все физические тела, температура которых выше абсолютного ноля, испускают невидимое излучение в инфракрасном диапазоне. Интенсивность излучения зави- сит от температуры тела. Измеряя интенсивность инфракрасного излучения при помощи фотоприемника, мы можем вычислить температуру тела. Блок-схема пирометра MLX90615 изображена на рис. 8.3. Входное окно пирометра закрыто специальным полосовым светофильтром (я), который пропускает излуче- ние только в диапазоне 5,5... 14 мкм и отсекает излучение видимого спектра, ближ- него ИК-спектра и ультрафиолет. Пик излучения человеческого тела приходится на длину волны 10 мкм. Интенсивность инфракрасного излучения измеряется при помощи микроскопиче- ски малых интегральных термопар (б), которые соединены последовательно. Такие же термопары измеряют температуру корпуса датчика (в), чтобы компенсировать
164 Часть II. Теория и практика Digital Signal Processor Рис. 8.3. Блок-схема пирометра MLX90615 влияние температуры окружающей среды. Напряжение с термопар поступает на операционный усилитель (г). Усиленный аналоговый сигнал оцифровывается при помощи АЦП (д) и обрабатывается встроенным цифровым сигнальным процессо- ром (е). Этот миниатюрный процессор выполняет цифровую фильтрацию шума и низкочастотных помех, которые могут возникнуть, например, от ламп накаливания. Благодаря встроенной цифровой обработке, на выходе процессора мы получаем готовый результат измерений. 8.2. Подключение сенсора MLX90615 к плате Arduino При работе над книгой я использовал сенсор без монтажной платы, просто припаяв его выводы к гибким монтажным проводам (рис. 8.4). Если у вас нет опыта пайки, Рис. 8.4. Подключение разъема к датчику MLX90615
Глава 8. Бесконтактное измерение температуры тела 165_ просто вставьте выводы сенсора в гнездовую часть макетных проводов. Можно вставить выводы датчика прямо в макетную плату, но в этом случае будет труднее проводить опыты по измерению температуры тела и различных предметов. Схема подключения пиросенсора MLX90615 к плате Arduino Uno R3 показана на рис. 8.5. Сенсор, установленный на плате расширения, подключается аналогичным образом. КЛ! 1ЮЧ MLX90615 (вид снизу) Рис. 8.5. Схема подключения пиросенсора MLX90615 к плате Arduino Uno R3 Тщательно проверьте полярность питания! Пиросенсор не оснащен защитой от пере- полюсовки. 8.2.1. Проверка работоспособности сенсора Скачайте библиотеку Arduino MLX90615 по адресу https://github,com/skiselev/ MLX90615, распакуйте архив и сохраните каталог библиотеки в стандартный ката- лог библиотек Arduino. Откройте скетч демонстрационного примера Файл | При- меры | MLX90615 | mlx90615__test. Скомпилируйте и загрузите скетч в плату Arduino. Откройте монитор последовательного порта Arduino IDE. Если датчик подключен правильно и исправен, вы должны увидеть в окне монитора следующие строки: Melexis MLX90615 infra-red temperature sensor test Sensor ID number = 89B97B Ambient = 27.19 *C Object = 26.61 *C
166 Часть II. Теория и практика Разумеется, в вашем случае уникальный номер датчика и значения температуры будут другими. Аккуратно направьте окно пиросенсора в ушную раковину или на внутренний сгиб локтя и подождите около двух секунд, пока встроенный сигнальный процессор усреднит измерения. Вы увидите, что измеренное значение температуры вашего тела ниже, чем ожидаемое 36,6 °С, и составляет около 34...35 °С. В чем же причина такой большой погрешности? Вам следует знать о некоторых особенностях пиро- метрии. 8.3. Особенности бесконтактного измерения температуры Тот факт, что пиросенсор способен измерять температуру объекта с погрешностью ±0,5 °С, еще не означает, что температура будет на самом деле измерена с точ- ностью до половины градуса. А Результат измерения температуры объекта зависит от излучающего свойства по- верхности, расстояния до поверхности и размера объекта. Если пиросенсор MLX90615 не оснащен объективом, то для выбора дистанции из- мерения применяется простое правило: расстояние до объекта не должно превышать половину размера объекта в меньшем измерении. Например, если видимая поверхность объекта представляет собой прямоугольник 20x30 см, то дистанция между пиросенсором и объектом не должна превышать 10 см. Пиросенсор измеряет интенсивность инфракрасного излучения, которое испускает поверхность физического тела. Тела с разными свойствами поверхности по- разному излучают энергию в инфракрасном диапазоне. Способность поверхности излучать инфракрасные волны характеризуется коэффициентом излучения (КИ), который варьируется от 0 (абсолютное зеркало) до 1 (абсолютно черное тело). На практике КИ различных материалов лежит в диапазоне от 0,02 до 0,99. КИ чер- ной матовой поверхности наиболее близок к единице, а КИ белой или зеркальной поверхности существенно ниже. Проведите несложный физический опыт. Возьмите два одинаковых тонкостенных химических стакана. На один стакан снаружи наклейте матовую черную бумагу, а на второй — алюминиевую фольгу. Нагрейте воду до кипения и налейте в оба стакана. Измерьте температуру стаканов, направляя пирометр на их стенки с рас- стояния около 5 см. Результат измерения температуры первого стакана будет бли- зок к истинному— приблизительно 95...96°С. Для стакана, оклеенного фольгой, пирометр покажет температуру около 38...45 °С— в зависимости от степени зер- кальности фольги.
Глава 8. Бесконтактное измерение температуры тела 167_ Агрегатное состояние вещества (твердое тело, жидкость, пар) также влияет на результат измерения. Для внесения поправок применяются специальные таблицы коэффициентов излучения для различных поверхностей. А В приложении 3 приведена таблица коэффициентов излучения для наиболее типич- ных поверхностей. Это усредненные значения, которые служат лишь ориентиром при калибровке пирометра. Для более точных измерений потребуется настройка прибора с применением образцового лабораторного пирометра. КИ человеческой кожи лежит в диапазоне 0,84...0,97 и зависит от цвета и текстуры кожи. Также на результат измерения влияет близость капилляров и крупных сосу- дов к поверхности кожи и наполненность капилляров кровью. Поэтому температу- ру тела бесконтактным способом обычно измеряют в ушной раковине, на внутрен- ней поверхности ротовой полости, на коже лба или внутреннего сгиба локтя. Во встроенную память EEPROM сенсора MLX90615 можно записать поправочный коэффициент КИ. По умолчанию туда записано значение 1. Пользователь может записать в EEPROM собственный поправочный коэффициент, но мы не будем это делать. А В соседние ячейки памяти записаны фабричные калибровочные константы, уникаль- ные для каждого датчика. Если случайно стереть или заменить эти константы, то сенсор будет безнадежно испорчен! Для начинающего разработчика вероятность такой ошибки весьма высока. Проще и безопаснее добавить поправочный коэффициент в скетч. Возьмем за основу ранее загруженный демонстрационный скетч из библиотеки Arduino MLX90615 и добавим в него константу с плавающей запятой (листинг 8.1). Изменения выделены в скетче полужирным шрифтом. Так как пиросенсор занижа- ет показания температуры, мы делим измеренное значение на коэффициент, кото- рый меньше единицы. tinclude <Wire.h> #include <mlx90615.h> // Поправочный коэффициент излучения поверхности float coeff - 0.97; MLX90615 mix = MLX90615O; void setup() { Serial.begin(9600) ; Serial.println("Melexis MLX90615 infra-red temperature sensor test"); mix.begin(); Serial.print("Sensor ID number = "); Serial.println(mix.get_id(), HEX);
168 Часть II. Теория и практика void loop () { Serial.print("Ambient = "); Serial. print (mix. get_ambient_temp () /coeff); Serial.print(" *C\tObject = ") ; Serial. print (mix. get_ob j ect_temp () /coeff); Serial.println(" *C"); Serial.println(); delay(500); Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). Измерьте температуру своего тела при помощи обычного контактного медицинско- го термометра. Затем попробуйте измерять температуру различных частей тела с разными значениями коэффициента. В моем случае наиболее точное измерение температуры в ушной раковине получалось с КИ = 0,97, а на сгибе локтя и в облас- ти лба— при КИ = 0,9. Расстояние до поверхности кожи составляло 3...4 см. В профессиональных приборах для увеличения рабочей дистанции могут приме- няться специальные линзы, прозрачные для инфракрасного излучения. 8.4. Пирометр с OLED-дисплеем и настройкой КИ Прибор с постоянным значением КИ, отображающий результат измерения на мо- ниторе компьютера, плохо подходит для опытов с различными поверхностями или использования в быту. Мы соберем макет портативного пирометра с возможностью настройки КИ, оснащенный OLED-дисплеем. Поправочный коэффициент в диапа- зоне 0...1 будем вводить при помощи кнопок «больше» и «меньше». Электрическая схема соединения компонентов проекта представлена на рис. 8.6, а его макет — на рис. 8.7. Исходный код скетча приведен в листинге 8.2. #include <Wire.h> #include <Adafruit_GFX.h> // Графическое ядро #include <Adafruit_SSD1306.h> // Библиотека OLED-дисплея #include <mlx90615.h> // Библиотека пиросенсора #define BUT_L АО // Вход кнопки "меньше" (левая) #define BUT_R Al // Вход кнопки "больше" (правая)
Глава 8. Бесконтактное измерение температуры тела 169 MLX90615 (вид снизу) SCL / КЛЮЧ Рис. 8.6. Схема подключения компонентов в проекте пирометра с OLED-дисплеем Рис. 8.7. Макет инфракрасного пирометра с OLED-дисплеем
170 Часть II. Теория и практика #define SCREEN_WIDTH 128 // Ширина дисплея в пикселах #define SCREEN_HEIGHT 64 // Высота дисплея в пикселах #define OLED_RESET -I // В нашем дисплее нет линии сброса // Создаем объект дисплея Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLEDJRESET); MLX90615 mix = MLX90615O; // Создаем объект пиросенсора float coef = 0.90, obj; // Корректировочный коэффициент boolean butL, butR; // Переменные состояния кнопок void setup() { // Настраиваем входы кнопок, // включаем встроенные подтягивающие резисторы pinMode(BUT_L, INPUT_PULLUP); pinMode(BUT_R, INPUT_PULLUP); // Активируем OLED-дисплей oled.begin(SSD1306_SWITCHCAPVCC, ОхЗС); oled.clearDisplay(); oled.display(); // Устанавливаем размер и цвет текста oled.setTextSize(2); oled.setTextColor(WHITE); void loop() ' { // Читаем состояние кнопок (низкий уровень - нажата) butL = digitalRead(BUT_L); butR = digitalRead(BUT_R); if (IbutL) leftButton(); // Если нажата левая кнопка if (IbutR) rightButton(); // Если нажата правая кнопка delay(80); // Пауза для снижения частоты обновления // Получение и корректировка значения температуры obj = mix.get_object_temp() / coef; // Отображение температуры и КИ на дисплее showText(); // Функция обработки нажатия левой кнопки void leftButton() { delay(20); // Защита от дребезга контактов
Глава 8. Бесконтактное измерение температуры тела 171 if (IbutL) { if (coef > 0.02) coef = coef - 0.01; // Функция обработки нажатия правой кнопки void rightButton() { delay(20); // Защита от дребезга контактов if (IbutR) { if (coef < 0.99) coef = coef + 0.01; // Функция вывода текста на дисплей void showText() { oled.clearDisplay(); oled.setCursor(0, 15); oled.print("*C:"); oled.setCursor(45, 15) ; // Если температура объекта меньше 115С, // выводим значение температуры if.(obj < 115) { oled.print(obj); } // Иначе выводим индикацию ошибочного значения else { oled.print ("XXX.XX") ; } oled.setCursor(0, 40); oled.print("Em:"); oled.setCursor(45, 40); oled.print(coef) ; oled.display(); В приведенном скетче по умолчанию установлено значение КИ = 0,90. Это значе- ние приблизительно соответствует излучающим свойствам кожи человека. Значе- ние КИ можно менять при помощи кнопок «больше» и «меньше». Для устранения дребезга контактов используется задержка 20 мс. Кроме этого, в главный цикл до- бавлена задержка 80 мс, чтобы изменение значения КИ при нажатии кнопки не происходило слишком быстро. Для выводов, к которым подключены кнопки, в схеме использованы встроенные в микроконтроллер подтягивающие резисторы. Резисторы подключаются опцией input_pullup в строках: pinMode(BUT_L, INPUT_PULLUP); pinMode(BUT_R, INPUT_PULLUP);
172 Часть II. Теория и практика Пиросенсор технически не может измерять температуру выше 115 °С. Но если те- кущее значение КИ не соответствует свойствам поверхности, на которую направ- лен пиросенсор, то вычисленное значение температуры объекта может значительно превысить 115 °С. Очевидно, что это будет заведомо ошибочное значение. В таком случае вместо цифрового значения температуры будет выведена строка ХХХ.ХХ. 8.5. Задания для самостоятельной работы 1. Если в процессе работы пирометра вы изменили значение КИ, то новое значение будет утеряно при отключении питания. При каждом включении питания скетч начинает работу со значения по умолчанию. Доработайте скетч так, чтобы уста- новленное пользователем значение КИ сохранялось в энергонезависимой памяти EEPROM микроконтроллера на плате Arduino. В решении этой задачи вам помо- гут встроенная в Arduino IDE библиотека eeprom и демонстрационные примеры eeprom_read, eeprom_write И eeprom_update. 2. Доработайте скетч и макет так, чтобы при превышении определенной темпера- туры тела, например 37 °С, раздавался звуковой сигнал или включалась световая индикация.
ГЛАВА 9 Измеритель интенсивности ультрафиолетового излучения Ультрафиолетовое (УФ) излучение имеет большое значение для человеческого организма. Оно необходимо для усвоения витаминов и выработки «гормонов радо- сти» серотонина и дофамина, влияет на психологическое, эмоциональное и общее физическое состояние человека. При недостатке УФ-излучения человек испытыва- ет нехватку витамина D3, у него снижается иммунитет и работоспособность. Сово- купность этих расстройств называется «эффектом зимней депрессии», которому подвержено около 10-12% (по некоторым данным до 40%) населения в северном полушарии Земли. Но избыток УФ-излучения, особенно коротковолнового, весьма опасен и может привести к ожогам кожи и роговицы глаз, а также к меланоме и раку кожи. Поэто- му измерение интенсивности УФ-излучения входит в перечень обязательных исследований окружающей среды и гигиены рабочего места. Прежде чем приступить к работе над проектом измерителя УФ-излучения, давайте ближе познакомимся с объектом измерений. 9.1. Диапазоны и свойства ультрафиолетового излучения УФ-излучение с различной длиной волны по-разному влияет на организм человека. В медицине и биологии выделяют три основных биологически значимых диапа- зона: UVA, UVB и UVC, которые лежат за пределами видимой части спектра (рис. 9.1). Излучение, достигающее Земли из космоса, в разной степени поглощается в земной атмосфере (рис. 9.2). Наиболее жесткие и опасные компоненты внешнего излучения: космические лучи, гамма-излучение, рентгеновское излучение и ультрафиолет диапазона UVC — пол- ностью поглощаются в верхних слоях атмосферы и не причиняют нам вреда. Излучение диапазона UVB несет в себе высокую энергию и вредит здоровью чело- века. Излучение UVB отвечает за 65% опухолей кожи. К счастью, только 0,1% сол- нечной энергии, достигающей поверхности Земли, приходится на диапазон UVB.
174 Часть II. Теория и практика 100— Длина волны, нм - Рис. 9.1. Спектр светового излучения Видимый свет iiilii u Ш Ф || I! ш шщтттт о | ф II Швш '^^^^^^^ШШ^^0^Ш€Т^^^шШШ&Х^^^^Ш Рис. 9.2. Поглощение космического излучения в земной атмосфере
Глава 9. Измеритель интенсивности ультрафиолетового излучения 175_ Излучение диапазона UVA менее энергоемко и опасно. Оно вызывает такой желан- ный для нас загар кожи, участвует в усвоении витаминов и выработке гормонов. Но избыток излучения UVA ведет к преждевременному старению кожи и тоже прово- цирует различные формы рака кожи. В форме UVA земной поверхности достигает 4,9% солнечной энергии. Источником опасного УФ-излучения является не только Солнце. Жесткое излуче- ние UVB, которое возникает при дуговой электросварке и работе ртутных ламп, вызывает тяжелые ожоги кожи и роговицы глаз. В бытовой технике запрещено ис- пользовать открытые источники излучения UVB. Газоразрядные ртутные светиль- ники снабжают фильтрами, которые задерживают излучение диапазона UVB. Ультрафиолетовые лампы для соляриев, роста растений, проверки банкнот и дру- гих бытовых нужд работают в диапазоне UVA. Мы займемся исследованием спектра и безопасности различных источников света при помощи самодельного измерителя УФ-излучения в диапазонах UVA и UVB на основе современного фотосенсора VEML6075 производства компании Vishay. 9.2. Устройство и принцип работы сенсора VEML6075 Интегральный сенсор VEML6075 выпускается в миниатюрном корпусе 2х 1,25х х 1,5 мм (рис. 9.3) и может устанавливаться в смартфоны, смарт-часы, фитнес- браслеты, домашние метеостанции и прочие бытовые и промышленные приборы. Сенсор имеет режим пониженного энергопотребления для экономии заряда бата- реи. Под светофильтром из прозрачного пластика располагаются кремниевый фотодиод, АЦП и блок интерфейса 12С. Рис. 9.3. Сенсор УФ-излучения VEML6075 Основные технические характеристики сенсора УФ-излучения VEML6075 ♦ Напряжение питания: 1,7...3,6 В ♦ Потребляемый рабочий ток: 480 мкА
176 Часть II. Теория и практика ♦ Потребляемый ток в режиме сна: 800 нА ♦ Пик чувствительности UVA: 365 нм ♦ Пик чувствительности UVB: 330 нм ♦ Чувствительность к видимому и ИК-излучению: <1% ♦ Разрядность АЦП: 16 битов ♦ Частота шины I2C: 10...400 кГц ♦ Рабочая температура: -40...+85 °С Несмотря на то, что два пика чувствительности сенсора приходятся на УФ-диа- пазон, излучение видимого и инфракрасного диапазона вносит в результаты изме- рений некоторую помеху. Эту помеху необходимо компенсировать. Поэтому сен- сор VEML6075 имеет четыре регистра данных: ♦ UVA_DATA — интенсивность излучения в диапазоне UVA; ♦ UVB_DATA — интенсивность излучения в диапазоне UVB; ♦ UVCOMP1_DATA —компенсация излучения в видимом диапазоне; ♦ UVCOMP2_DATA — компенсация излучения в инфракрасном диапазоне. На рис. 9.4 показана спектральная диаграмма чувствительности сенсора VEML6075. 3S 100 в0 *° 50 40 зо ю 300 320 340 360 380 400 420 440 460 480 500 520 540 560 $80 600 Длина волны, нм Рис. 9.4. Спектральная диаграмма чувствительности сенсора VEML6075 I / \ иув / / VI / / 1 / 1 1 / / \ 1 / 1/ / If / /\ / S\ \ \ 1 \ 1 ^ \ \ \ А Наличие острых пиков чувствительности сенсора говорит о том, что надо вдумчиво и правильно интерпретировать результаты измерений. Если у источника света спектральный пик излучения не совпадает с пиком чувствительности сенсора, то показания измерительного прибора не будут соответствовать реальной мощности излучения источника. В таком случае следует по кривой спектральной диаграммы вычислить поправочный коэффициент и умножить на него измеренное значение. Коэффициент должен быть больше единицы.
Глава 9. Измеритель интенсивности ультрафиолетового излучения 177 9.3. Индекс УФ-излучения Интенсивность УФ-излучения измеряется в микроваттах на квадратный сантиметр поверхности (мкВт/см2) по отдельности для диапазонов UVA и UVB. В зависимо- сти от свойств источника, мощность УФ-излучения может варьироваться в широ- ком диапазоне — от ноля до десятков тысяч мкВт/см2. Но сделать какие-либо вы- воды на основании «сырых» данных может только подготовленный специалист. Тем более, что излучение обоих диапазонов влияет на организм человека в разной степени. Поэтому для удобства интерпретации результатов измерений используют индекс УФ-излучения (UVI, УФ-индекс). Среднее значение UVI вычисляется по формулам (1)...(5), в которые входят интенсивности излучений UVA и UVB, а также весовые коэффициенты а, 6, с, d и калибровочные константы а, Р, у, 8: = UVA — (a-a-UV ,) (6-a-UV 2) uvb , = uvb (C-P'uv^') (^-P-uv^) у 8 UVIA = UVA^ • J- • UVAr UVffi = UVBC()/cluVBi Средн. UVI = responsivity UVIA + UVIB 180 160 S -too 80 60 40 20 0 мамаш 1 А / / / / J / "\ Лето \ \ Осень /1/Ввсна' /Ж i \ \ \ К ч Зима *— N Ч ■маааааа -Mb. 4 6 8 10 12 14 16 18 20 Среднеевропейское время суток, ч 22 Рис. 9.5. Интенсивность УФ-излучения на территории Европы в зависимости от сезона и времени суток (1) (2) (3) (4) (5)
178 Часть II. Теория и практика Индекс УФ-излучения, вычисленный по формулам (1)...(5), лежит в диапазоне 0...10. Интенсивность естественного солнечного излучения зависит от географиче- ского расположения, времени года и состояния атмосферы (рис. 9.5). 9.4. Измеритель интенсивности УФ-излучения с OLED-дисплеем В проектах этой книги мы используем модуль расширения двухдиапазонного УФ-сенсора VEML6075 (рис. 9.6), который подключается к плате контроллера по шине 12С. Рис. 9.6. Модуль двухдиапазонного УФ-сенсора VEML6075 Для работы с этим сенсором в среде Arduino ГОЕ необходима его библиотека. Ска- чайте ее архив по адресу https://github.com/schizobovine/VEML6075, распакуйте его и установите библиотеку, как показано ъразд. 2.3.2. Подсоедините плату сенсора к Arduino Uno, как показано на рис. 9.7. Откройте файл примера Файл | Примеры | VEML6075 Library | test-veml6075 и загрузите SCL VEML6075 Рис. 9.7. Схема подключения модуля VEML6075 к плате Arduino Uno R3
Глава 9. Измеритель интенсивности ультрафиолетового излучения 179 скетч в плату Arduino. Откройте встроенный монитор порта на скорости 57 600 бод. Вы должны увидеть в окне монитора блрки данных, которые выводятся один раз в секунду. Блок данных содержит время в микросекундах с момента запуска скетча, значения интенсивности излучения в диапазонах UVA и UVB, вычисленный индекс UVI и идентификатор сенсора. Идентификатор всегда равен 26 и предназначен для проверки наличия и готовности сенсора на шине. В ответ на запрос идентификато- ра по адресу ОхЮ сенсор должен вернуть значение 26. Обратите внимание, что значение индекса излучения UVI нормируется и приводит- ся к диапазону 0...10, где максимум соответствует мощности наиболее интенсивно- го солнечного излучения на земной поверхности по результатам метеонаблюдений, а ноль— полному отсутствию УФ-излучения при рассеянном видимом свете. Такая условная шкала значений наиболее удобна и наглядна в быту. Если на сенсор попадает только свет видимого диапазона, то в окне монитора могут отображаться отрицательные значения UVA, UVB или индекса UVI. Это связано с тем, что каждый экземпляр сенсора подлежит индивидуальной калибровке после установки в прибор. Усредненные калибровочные константы библиотеки не обяза- тельно будут идеально подходить для компенсации засветки в видимом и инфра- красном диапазонах. Для калибровки требуется специальное лабораторное обору- дование и сложная ее процедура. Поэтому мы можем лишь смириться с небольшой погрешностью измерений, которая не имеет значения в бытовых условиях. Если сенсор работает правильно, подключите OLED-дисплей, как показано на рис. 9.8. Макет измерителя УФ-излучения в сборе изображен на рис. 9.9. \/EML6075 Рис. 9.8. Схема подключения компонентов в измерителе УФ-излучения
180 Часть II. Теория и практика Рис. 9.9. Макет измерителя УФ-излучения в сборе Загрузите в Arduino скетч из листинга 9.1. Исходный код собран из готовых биб- лиотек и не нуждается в подробных пояснениях. Мы используем методы getuvA (), getuvB () и getuvindex () для получения готовых значений интенсивности и индекса и выводим их в текстовом виде на дисплей один раз в секунду. Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). j #include <Wire.h> #include <Adafruit_GFX.h> // Графическое ядро #include <Adafruit_SSD1306.h> // Библиотека OLED-дисплея #include <VEML6075.h> #define SCREEN_WIDTH 128 // Ширина дисплея в пикселах #define SCREEN_HEIGHT 64 // Высота дисплея в пикселах #define OLED_RESET -1 //В нашем дисплее нет линии сброса // Создаем объект дисплея Adafruit SSD1306 oled(SCREEN WIDTH/ SCREEN HEIGHT, &Wire, OLED RESET),
Глава 9. Измеритель интенсивности ультрафиолетового излучения 181_ VEML6075 veml6075 = VEML6075O; // Создаем объект сенсора void setup() { // Активируем и очищаем OLED-дисплей oled.begin(SSD1306_SWITCHCAPVCC, ОхЗС); oled.clearDisplay(); oled.display(); // Устанавливаем размер и цвет текста oled.setTextSize(l); oled.setTextColor(WHITE); if (!veml6075.begin()) { oled.setCursor(10, 30) ; oled.print(F("VEML6075 not found!")); oled.display(); while (1); // Если сенсор не найден, остановить программу oled.setCursor(10, 5); oled.print("UVA: "); oled.setCursor(10, 30) ; oled.print("UVB: "); oled.setCursor(10, 55) ; oled.print("UVI: ••) ; oled.display(); void loop() { float value; veml6075.poll(); // Опрос сенсора (команда приготовить данные) oled.fillRect(35, 0, 127, 63, BLACK); value = veml6075.getUVA(); // Получаем значение UVA oled.setCursor(35, 5); oled.print(value, 2); value = veml6075.getUVB(); // Получаем значение UVB oled.setCursor(35, 30) ; oled.print(value, 2); value = veml6075.getUVIndex(); // Получаем значение индекса UVI oled.setCursor(35, 55); oled.print(value, 2); oled.display(); delay(1000); // Пауза между измерениями
182 Часть II. Теория и практика 9.4.1. Задания для самостоятельной работы 1. Модифицируйте скетч и макет таким образом, чтобы данные отображались на цветном TFT-дисплее разными цветами. 2. Доработайте скетч так, чтобы на дисплее отображался график солнечной актив- ности в течение светового дня. В данном случае можно обойтись без модуля ча- сов реального времени — достаточно включать измеритель в заданное время дня и выполнять измерения каждые 4 минуты при помощи функции minis (). В этом случае для дисплея размером 128 пикселов продолжительность сеанса наблюде- ний составит около 8 часов, а для дисплея размером 320 пикселов— около 20 часов (можно уменьшить длительность сеанса и оставить на экране место для дополнительной информации). 9.5. Онлайн-мониторинг солнечной активности У нас под рукой есть все необходимое для организации дистанционного монито- ринга солнечной активности — двухдиапазонный сенсор УФ-излучения, контрол- лер с подключением к сети Интернет и онлайновая приборная панель. Начнем с подготовки виртуальных приборов онлайновой панели Adafruit 10 (см. разд. 5.2.2). Создайте три потока данных с именами: UVA, UVB и UVI. В эти потоки мы будем передавать данные интенсивности излучения в двух диапазонах и значение индекса излучения. Создайте приборную панель с именем Ultraviolet. Перейдите в режим редактирова- ния приборной панели. Разместите на приборной панели блоки отображения ин- формации в соответствии со своими потребностями. Бесплатный сервис Adafruit 10 ограничивает только число потоков и панелей. Внутри панели вы можете размес- тить сколько угодно приборов. К одному потоку можно подключить несколько приборов. В качестве примера я создал приборную панель, которая состоит из трех круговых индикаторов, под которыми расположен график индекса УФ-излучения (рис. 9.10). На панель графика можно вывести до пяти потоков данных. Например, можно до- бавить кривые интенсивности излучения в диапазонах UVA и UVB и наблюдать, как они изменяются в зависимости от времени суток и состояния атмосферы (туман, дым, пыль). Для подключения к сети Интернет я использовал плату контроллера NodeMCU на основе ESP8266. С равным успехом можно взять любую плату Arduino и подклю- чить ее к сети Интернет, как рассказано в главе 4. Электрическая схема соединения компонентов проекта представлена на рис. 9.11, а его макет — на рис. 9.12. Откройте исходный код скетча из листинга 9.2. Подставьте в код имя и пароль до- машней сети Wi-Fi, а также имя пользователя и главный ключ сервиса Adafruit 10. Загрузите скетч в плату контроллера. Если все сделано правильно, в потоки данных
Глава 9. Измеритель интенсивности ультрафиолетового излучения 183 Рис. 9.10. Пример приборной панели для мониторинга УФ-излучения VEML6075 Рис. 9.11. Схема подключения сенсора VEML6075 к контроллеру NodeMCU
184 Часть II. Теория и практика Рис. 9.12. Макет схемы для онлайн-мониторинга УФ-излучения сервиса Adafruit 10 начнут поступать результаты измерений, которые отобразятся на приборах онлайновой панели. #include "AdafruitIO_WiFi.h" // Библиотека Adafruit 10 для Wi-Fi #include <Wire.h> #include <VEML6075.h> // Библиотека сенсора // Имя пользователя сервиса Adafruit 10 #define IOJJSERNAME и************ // Главный ключ сервиса Adafruit 10 #define IO_KEY **************************************** // Имя вашей сети WiFi #define WIFI_SSID „********„ // Пароль вашей сети WiFi #define WIFI_PASS ••********•• // Конструктор подключения к Adafruit 10 AdafruitIO_WiFi io(IOJJSERNAME, IO_KEY, WIFI_SSID, WIFI_PASS); VEML6075 veml6075 = VEML6075(); // Создаем объект сенсора // Объявляем объекты потоков с их ключами AdafruitIO_Feed *uva_feed = io.feed("UVA"); AdafruitIO_Feed *uvb_feed = io.feed("UVB"); AdafruitIO_Feed *uvi_feed = io.feed("UVI"); void setup() { Serial.begin(57600) ;
Глава 9. Измеритель интенсивности ультрафиолетового излучения 785 if (!veml6075.begin()) { Serial.print(F("VEML6075 not found!")); while (1); // Если сенсор не найден, остановить программу Serial.print("Connecting to Adafruit 10") // Подключаемся к io.adafruit,.com io.connect(); // Ожидаем подключение while (io.status() < AIO_CONNECTED) { Serial.print("."); delay(500); // Отладочное сообщение о подключении в монитор порта Serial.println(); Serial.println(io.statusText()); void loop() { float value; // Вызов метода io.run(); требуется в КАВДОМ скетче //и должен быть первой строкой цикла 1оор() // Вызов поддерживает соединение с io.adafruit.com //и обрабатывает входящие данные, io.run(); veml6075.poll (); // Опрос сенсора (команда приготовить данные) // Отправляем данные в потоки value = veml6075.getUVA(); // Получаем значение UVA if (value < 0) value = 0; uva_feed->save(value); value = veml6075.getUVB(); // Получаем значение UVB if (value < 0) value = 0; uvb_feed->save(value); value = veml6075.getUVIndex(); // Получаем значение индекса UVI if (value < 0) value = 0; uvi_feed->save(value); // Adafruit 10 ограничивает частоту поступления данных. // Поэтому делаем паузу 8 секунд между отправками данных, delay(8000);
186 Часть II. Теория и практика В листинге 9.3 приведен исходный код скетча для проводного подключения к Ин- тернету при помощи шилда Arduino Ethernet W5100 с использованием протокола MQTT. Особенности подключения к сервису Adafruit IO по протоколу MQTT рас- смотрены в комментариях к листингу 5.7 в разд. 5.2.5. #include <SPI.h> #include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" #include <Ethernet.h> #include <EthernetClient.h> #include <Dns.h> #include <Dhcp.h> #include <Wire.h> #include <VEML6075.h> // Библиотека сенсора // Задаем МАС-адрес сетевого шилда byte mac[] = {OxDE, OxAD, OxBE, OxEF, OxFE, OxED}; // Настройки доступа к Adafruit IO по протоколу MQTT #define AIO_SERVER "io.adafruit.com" #define AIO_SERVERPORT 1883 #define AIO_USERNAME и********». #define AIO KEY ,,**************************** VEML6075 veml6075 = VEML6075O; // Создаем объект сенсора // Создаем сетевого клиента EthernetClient client; // Создаем клиента MQTT-подключения Adafruit_MQTT_Client mqtt(&clientf AIO_SERVER, AIO_SERVERPORT, AIOJJSERNAME, AIO_KEY); // Необходимая строка, ничего не меняйте #define halt(s) { Serial.println(F( s )); while(1); } // Объявляем потоки в виде <username>/feeds/<feedname> Adafruit_MQTT_Publish uva_feed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/UVA"); Adafruit_MQTT_Publish uvb_feed = Adafruit_MQTT_Publish(&mqtt, AIOJJSERNAME "/feeds/UVB"); Adafruit_MQTT_Publish uvi_feed = Adafruit_MQTT_Publish(&mqtt, AIO USERNAME "/feeds/UVI");
Глава 9. Измеритель интенсивности ультрафиолетового излучения 187 I/ Объявляем хотя бы один поток входящих данных от сервера // Это обязательно НУЖНО сделать - особенность библиотеки Adafruit MQTT Adafruit_MQTT_Subscribe income = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/onoff"); void setup() { Serial.begin(115200); if (!veml6075.begin()) { Serial.print(F("VEML6075 not found!")); while (1); // Если сенсор не найден, остановить программу // Инициализируем клиента Ethernet Serial.print(F("\nlnit the Client...")); Ethernet.begin(mac); delay(1000); // Задержка для инициализации // Подписка на входящие данные MQTT // ОБЯЗАТЕЛЬНО для нормальной работы библиотеки mqtt.subscribe(&income); void loop() { // Устанавливаем подключение с сервером, // проверяем наличие подключения в каждом цикле 1оор(), // при необходимости восстанавливаем подключение MQTT_connect(); // Проверяем наличие входящих данных от сервера // ОБЯЗАТЕЛЬНО для нормальной работы библиотеки Adafruit_MQTT_Subscribe ^subscription; while ((subscription = mqtt.readSubscription(1000))) { if (subscription == &income) {• Serial.print (F(lfGot: ") ) ; Serial.println((char *)income.lastread); veml6075.poll(); // Опрос сенсора (команда приготовить данные) float value; // Отправляем данные в потоки value = veml6075.getUVA(); // Получаем значение UVA if (value < 0) value = 0; uva_feed.publish(value);
188 Часть II. Теория и практика value = veml6075.getUVB(); // Получаем значение UVB if (value < 0) value = 0; uvb_feed.publish(value); value = veml6075.getUVIndex(); // Получаем значение индекса UVI if (value < 0) value = 0; uvi_feed.publish(value); // Пингуем сервер для поддержания активного соединения // Если сервер не отвечает, объявляем соединение разорванным //и попытаемся восстановить его в следующем цикле 1оор() if (! mqtt.pingO) { mqtt.disconnect() ; } delay(5000); // Функция для соединения с сервером MQTT, проверки наличия соединения //и повторного соединения при необходимости void MQTT_connect() { int8_t ret; // Если уже подключено - ничего не делаем if (mqtt.connected()) { return; Serial.print("Connecting to MQTT... "); // При наличии соединения возвращается О while ((ret = mqtt.connect()) != 0) { // Если возвращен не 0, выводим текст ошибки //и повторяем попытку через 5 секунд Serial.println(mqtt.connectErrorString(ret)); Serial.println("Retrying MQTT connection in 5 seconds..."); mqtt.disconnect(); delay(5000); Serial.println("MQTT Connected! ") ; } 9.6. Опыты с измерителем УФ-излучения Для опытов нам потребуется источник УФ-излучения. Мы можем обойтись сол- нечным светом, но чем больше разных источников ультрафиолета удастся найти, тем разнообразнее получатся опыты.
Глава 9. Измеритель интенсивности ультрафиолетового излучения 189 У\ Меры безопасности при проведении опытов ( * \ Не смотрите на источники мощного УФ-излучения, которые не оборудованы защит- ным светофильтром! При проведении опытов не включайте источники жесткого или мощного УФ-излу- чения (электрическая дуга, бактерицидные лампы, солярий) без защитных очков или маски! Защищайте открытую поверхность кожи! Маломощные источники мягкого УФ-излучения: детекторы банкнот и невидимых меток, лампы для дискотек, лампы для фотофиксации лака на ногтях — безопасны в использовании без специальных средств защиты. Тем не менее, настоятельно не рекомендуем долго смотреть на подобные источники света или направлять излуче- ние УФ-светодиодов прямо в глаза. Это может вызвать утомление зрения и ухуд- шение цветовосприятия. Различные прозрачные материалы по-разному поглощают УФ-излучение. Так, некоторые виды прозрачного пластика и стекла почти полностью поглощают ультрафиолетовую часть спектра. И наоборот, некоторые стекла, которые выглядят глубоко фиолетовыми и даже черными, хорошо пропускают УФ-излучение. Поэто- му бытовые УФ-лампы часто изготавливают с колбами черного цвета. Они отфильтровывают вредную часть излучения. В качестве источника излучения для опытов лучше всего использовать солнечный свет, потому что в нем содержится излучение и UVA, и UVB. В зимнее время или в темное время суток можно использовать косметическую лампу для искусственно- го загара или так называемую «ногтевую лампу» для маникюра, которую применя- ют для отверждения фотолака или фотогеля (рис. 9.13). Лампу можно найти в зару- бежных интернет-магазинах ПО ключевым словам nail lamp ИЛИ nail dryer lamp или приобрести в магазине косметических аксессуаров. Можно также воспользо- ваться лампой для проверки банкнот. Рис. 9.13. Ультрафиолетовая лампа для маникюра 9.6.1. Опыт с измерением УФ-проницаемости оконных стекол В солнечный день поместите фотосенсор на подоконник, чтобы свет падал на него через оконное стекло. Замерьте интенсивность излучения. Теперь распахните окно,
190 Часть II. Теория и практика чтобы солнечный свет попадал напрямую на сенсор. Индекс УФ-излучения возрас- тет в несколько раз. Обычное оконное стекло поглощает около 50...70% ультрафио- лета. Вакуумные стеклопакеты, особенно со специальным покрытием, блокируют ультрафиолет еще сильнее. 9.6.2. Опыт с измерением УФ-проницаемости пластиков Возьмите прозрачный акриловый футляр от компакт-диска и поместите один слой пластика между сенсором и источником света. Насколько сильно изменилась ин- тенсивность УФ-излучения, достигающая сенсора? Проведите измерения с другими видами прозрачных пластиков. Если есть возможность, измерьте поглощение ульт- рафиолета стеклом от обычного сканера или копировального аппарата. Отложите образец, который меньше всего поглощает ультрафиолет. Он понадобится позже. 9.6.3. Опыт с отражением УФ-излучения от песка и воды Возьмите широкий плоский лоток и наполните его светлым песком, который обыч- но встречается на пляжах. Расположите лоток так, чтобы свет солнца или лампы отражался от песка на фотосенсор (угол падения равен углу отражения — школь- ный курс физики). Вы увидите, что песок отражает около 20...25% ультрафиолето- вого излучения. Это наблюдение объясняет, почему на пляже можно загореть, даже находясь под зонтиком или тентом. Частицы кварцевого песка хорошо отражают ультрафиолет в разных направлениях, и невидимое глазу излучение проникает в укрытие. Наполните лоток водой и вновь повторите опыт с отражением света. Вода отражает всего 5...7% излучения. Несмотря на то, что блики солнечного света на воде слепят глаза, а песок не дает бликов, основным источником побочного загара является именно кварцевый песок! 9.6.4. Опыт с проверкой качества солнцезащитных очков Возьмите различные солнцезащитные очки и проверьте степень поглощения ульт- рафиолета материалом их стекол. Дешевые акриловые очки даже с очень темными стеклами могут слабо поглощать ультрафиолет. Такие очки плохо защищают ваши глаза. При одинаковом исходном материале поглощение УФ-излучения также зави- сит от цвета стекол. Лучше всего поглощают ультрафиолет стекла желтого цвета. Очки с желтыми светофильтрами, которые хорошо защищают глаза, но почти не затеняют видимый свет, часто используют водители, пилоты-любители, спортсме- ны. Хуже всего защищают глаза от вредного ультрафиолета очки с синими или серо-синими стеклами.
Глава 9. Измеритель интенсивности ультрафиолетового излучения 1_91_ 9.6.5. Опыт с проверкой качества солнцезащитных кремов Вновь возьмите образец прозрачного материала, который хорошо пропускает ульт- рафиолетовое излучение. Как правило, хорошо подходят стекло от неисправного сканера или бесцветный листовой акриловый пластик (оргстекло). Иногда встреча- ется специальное защитное оргстекло с добавками, блокирующими ультрафиолет. Такое оргстекло не подойдет для опытов. Изготовьте из выбранного материала две пластины с размерами приблизительно 10x10 см. Замерьте степень поглощения обеих пластин в диапазонах UVA и UVB. Поместите небольшое количество солнцезащитного крема в центр одной из пла- стин и прижмите второй пластиной, чтобы между ними образовалась тонкая про- слойка крема. Измерьте степень поглощения ультрафиолета при наличии крема. Запишите ре- зультаты измерения. Тщательно промойте пластины мылом или другим моющим средством и повторите опыт для других кремов. Сравните их степени поглощения. Для достоверной оценки результата опытов важно, чтобы все измерения прово- дились в строго одинаковых условиях: мощность источника света, расстояние до источника, толщина слоя испытуемого вещества. Теперь, когда у вас есть собственный измеритель интенсивности УФ-излучения, вы можете проверить и сравнить качество своих солнцезащитных очков и кремов или выбрать защитное стекло для любимой картины из вашей коллекции, а также оце- нить безопасность длительного нахождения на солнце в определенной местности.
ГЛАВА 10 Измерение электрической активности кожи В этой главе мы обсудим измерение электрической активности кожи (ЭАК) в до- машней лаборатории. Вы узнаете, как самостоятельно изготовить контакты для из- мерений и какой измерительный модуль выбрать для подключения к Arduino. Затем мы изготовим макет измерителя ЭАК и проведем исследования того, как эмоцио- нальное и физическое состояние организма человека отражается на электрической активности кожи. 10.1. Что такое электрическая активность кожи? Электрическая активность кожи (ЭАК) раньше называлась иначе— кожно- гальваническая реакция (КГР, Galvanic Skin Response, GSR). Это важный показа- тель активности вегетативной нервной системы, отражающий уровень реакции человека на внешние раздражители. Термин ЭАК объединяет как параметры потенциала кожи, так и параметры сопро- тивления (проводимости) кожи. С точки зрения схемотехники, проще измерять со- противление кожи путем приложения внешнего напряжения к электродам (метод Фере), а затем преобразовывать сопротивление в проводимость. Из школьного кур- са физики мы знаем, что проводимость — величина, обратная сопротивлению. Почему в ответ на реакцию нервной системы меняется сопротивление кожи? Сама по себе кожа, особенно ее верхний ороговевший слой, весьма плохо проводит элек- трический ток. Но при активизации потовых желез проводимость кожи значитель- но увеличивается. Потовые железы работают как параллельно включенные рези- сторы. Чем больше желез активировано, тем лучше кожа проводит ток. Потовые железы, расположенные на коже ладоней и подошвах ног, реагируют на стресс и внешние раздражители в первую очередь, а остальные железы в основном предназначены для терморегуляции. Ученые полагают, что увлажнение ладоней и подошв при стрессе возникло в процессе эволюции, т. к. помогает увереннее схва- тить предметы и защищает кожу ступней и ладоней от порезов и трещин.
Глава 10. Измерение электрической активности кожи 193_ Активность потовых желез не поддается сознательному контролю и управляется глубинными процессами вегетативной нервной системы. Поэтому измерение ЭАК активно применяется в психологических исследованиях и медицине. Сенсор ЭАК является основным компонентом полиграфа (детектора лжи). Различают три основных составляющих реакции ЭАК: ♦ физическая — реакция на внешний физический раздражитель, занимающая не- сколько секунд. При повторении раздражителя уровень реакции снижается; ♦ тоническая — медленное угасание проводимости кожи, например, при утомле- нии; ♦ спонтанная — краткосрочная реакция без участия внешних физических раздра- жителей. Наблюдается, например, при медитации или просмотре волнующих фильмов. 10.2. Модули измерителя ЭАК В популярных зарубежных интернет-магазинах встречаются в основном два вари- анта модулей (рис. 10.1). Вариант рис. 10.1, а— это комплект из пары выносных контактов и платы измерителя проводимости кожи для измерительной системы Grove Systems. На мой взгляд, стоимость этого комплекта завышена, а его разъемы не подходят для монтажа на беспаечной макетной плате. Рекомендую выбрать ва- риант (б)— собственно плату измерителя проводимости и изготовить выносные контакты самостоятельно из подручных материалов— это не составит труда. В проектах и экспериментах для этой книги использован вариант (б). Рис. 10.1. Модули измерителя ЭАК (GSR-sensor): a — комплект из пары выносных контактов и платы измерителя проводимости кожи; 6 — отдельная плата модуля измерителя проводимости Интересной особенностью модуля (б) является наличие на плате не только анало- гового измерительного узла, но и аналого-цифрового преобразователя с интерфей- сом SPI. Причем на разъем выведен как цифровой, так и аналоговый сигналы. Это позволяет использовать модуль с платами контроллера, у которых отсутствуют или заняты аналоговые входы, но имеется интерфейс SPI.
194 Часть II. Теория и практика На плате модуля размещен стандартный трехконтактный звуковой разъем (джек) для подключения выносных контактов, а с обратной стороны платы имеются две контактные площадки, к которым можно припаять свой разъем. Это удобно — вы можете использовать для подключения выносных контактов провод от старых на- ушников или любые другие подходящие провода. Модуль питается от источника +5 вольт. На плате есть стабилизатор +3,3 вольт. При полностью разомкнутой цепи контактов, когда они не подключены к телу, на- пряжение на выходе OUT близко к нулю, а если контакты накоротко замкнуты — близко к напряжению питания +3,3 вольт. В Интернете можно найти множество вариантов простейшего измерителя кожной проводимости в виде двух контактов, один из которых подключен к линии питания +5 вольт, а второй напрямую к аналоговому входу платы Arduino. Работоспособность такого измерителя существенно зависит от индивидуальных особенностей кожи, а сигнал загрязнен наводками от сети 220 вольт, импульсными помехами от ламп дневного света и т. д. Полноценная схема измерителя содержит автоматическую регулировку усиления и фильтры сигнала, реализованные на операционных усили- телях. Если хотите уверенно и без проблем проводить эксперименты с измерением ЭАК, воспользуйтесь одним из готовых модулей (см. рис. 10.1) или изготовьте анало- гичный модуль самостоятельно. 10.3. Самодельные контакты сенсора ЭАК Конструкция контактов сенсора очень проста. Важно выполнить только одно усло- вие — контакты должны быть изготовлены из неполяризующих материалов (не об- разовывать гальваническую пару при контакте с кожей). Хорошо подойдут никели- рованные декоративные кнопки от одежды или канцелярские кнопки, к которым припаяны соединительные провода. Экранировать провода не обязательно. Для фиксации контактов на пальцах можно сшить кольца из широкой бельевой резинки или использовать текстильную застежку «липучку». Удобнее всего использовать двустороннюю «липучку», у которой нитевое и зацеп- ляющее покрытие расположены с двух сторон. Если такой застежки нет, приобре- тите в магазине швейных принадлежностей обычную текстильную «липучку» для одежды шириной 15...20 мм. Отрежьте два куска нитевой части длиной около 80 мм и два куска зацепляющей части длиной около 10...12 мм (рис. 10.2). Приклейте или пришейте короткие зацепляющие части с обратной стороны длин- ных частей (я использовал эластичный термоклей). В середине фиксаторов размес- тите контакты и подсоедините к ним мягкие проводники длиной 25-30 см в сили- коновой изоляции. Контакты изготовлены из металлических шайб и винтов с по- тайной головкой (рис. 10.3). К выводам контактов на обратной стороне платы модуля я припаял гнездовые час- ти разъема (рис. 10.4), а к проводам, идущим от контактов с текстильным фиксато- ром, — штыревые части, которые включаются в этот разъем. Полярность подклю- чения контактов не имеет значения.
Глава 10. Измерение электрической активности кожи 195 Рис. 10.2. Заготовки текстильной застежки для контактов Рис. 10.3. Пример конструкции контактов с текстильным фиксатором Рис. 10.4. Разъем для подключения контактов сенсора ЭАК
196 Часть II. Теория и практика 10.4. Подключение модуля измерителя ЭАК к плате Arduino Uno R3 Модуль измерителя ЭАК (см. рис. 10.1, б) можно подключить к аналоговому входу А0-А5 или к шине SPI платы Arduino. В первом случае аналоговый сигнал измери- теля с выхода операционного усилителя поступает напрямую на вход АЦП кон- троллера Arduino. Это самый простой способ подключений, которого достаточно для большинства простых проектов. Во втором случае для оцифровки измерений применяется собственная микросхема АЦП модуля, а готовые цифровые данные передаются по шине SPI. Такой способ подключения немного сложнее, зато больше разрядность (и точность) АЦП модуля и не нужен аналоговый порт. Это особенно важно для контроллеров на базе ESP8266, у которых всего один аналоговый вход. 10.4.1. Электрическая безопасность — это важно! В измерителе электрической активности кожи используется прямое подключение электродов к телу человека. Как пояснялось в разд. 1.2— если подключить изме- рительное устройство напрямую к компьютеру, на общем проводе устройства в случае ошибки коммутации электропроводки может присутствовать полное на- пряжение 220 вольт относительно заземленных предметов. Внимание! Категорически запрещается проводить опыты с подключением электродов к телу человека без качественной гальванической развязки между макетом устройства и компьютером, подключенным к электрической сети 220 вольт! В случае отсутствия специальной развязки используйте батарейное питание устрой- ства и передачу данных по беспроводному соединению Bluetooth или ноутбук с пи- танием от батареи (в приложении 2 рассказано про варианты батарейного питания макетов и устройств). Для беспроводной передачи данных в компьютер мы воспользуемся модулем Bluetooth (см. разд. 3.6) и библиотекой программного последовательного порта SoftwareSerial (CM. разд. 3.2.3). Если в качестве настольного компьютера вы используете ноутбук с питанием от батареи, то можно обойтись без модуля Bluetooth и программного порта SoftwareSerial и подключить контроллер Arduino к порту USB ноутбука обычным способом. Не забудьте только перед началом опытов отключить зарядное устройст- во ноутбука от сети! 10.4.2. Подключение к аналоговому порту Схема подключения модуля измерителя ЭАК к аналоговому порту платы Arduino Uno R3 изображена на рис. 10.5, а внешний вид собранного макета— на рис. 10.6. При подготовке проекта я подключал свой макет к ноутбуку с питанием от батареи и не использовал беспроводной канал Bluetooth для гальванической развязки.
Глава 10. Измерение электрической активности кожи 197 Рис. 10.5. Схема подключения измерителя ЭАК к Arduino Uno R3: аналоговый канал Рис. 10.6. Макет измерителя ЭАК с аналоговым подключением (модуль Bluetooth здесь не показан)
198 Часть II. Теория и практика В рассматриваемом же случае мы подключаем аналоговый выход OUT к входу АО встроенного АЦП микроконтроллера ATmega328, а для развязки измерителя ЭАК с компьютером задействован модуль Bluetooth и организовано питание от батарей- ного источника. Скетч для построения графика изменения проводимости кожи приведен в листин- ге 10.1. Как показал опыт измерений, напряжение на выходе OUT может меняться непредсказуемо и в широком диапазоне даже в течение одного сеанса измерений. Поэтому встроенный плоттер Arduino с неотключаемым автоматическим масшта- бированием очень неудобен — он периодически слишком сильно сжимает или рас- тягивает график по вертикали, что мешает наблюдать общую картину. Вдобавок график плоттера Arduino нельзя прокрутить назад, чтобы вернуться к просмотру предыдущих значений. В нашем случае наиболее удобен графопостроитель Serial Port Plotter (см. разд. 5.1.2). Он позволит нам в режиме реального времени включать и отключать масштабиро- вание и прокручивать график назад. #include <SoftwareSerial.h> // Подключение библиотеки SoftwareSerial mySerial(2, 3); // 2 - RX, 3 - ТХ void setup() { mySerial.begin(115200) ; void loopO { // Формат вывода - Serial Port Plotter mySerial.print("$") ; mySerial.print(analogRead(AO)); mySerial.printC1;") ; delay(100); Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). Загрузите скетч (листинг 10.1) в плату контроллера. Наденьте контакты на пальцы, как показано на рис. 10.7. Можно поместить контакты на подушечки пальцев. Плотность прилегания не имеет большого значения — достаточно обеспечить пол- ное прилегание контактов к коже с небольшим усилием. Запустите программу Serial Port Plotter. Выберите порт, к которому подключена плата Arduino, задайте скорость порта 115 200 бод. Запустите процесс отрисовки графика. Наблюдая за значениями в окне терминала под панелью графика, подбе-
Глава 10. Измерение электрической активности кожи рите оптимальные значения минимума и максимума по оси Y с некоторым запасом. Точный диапазон значений зависит от индивидуальных особенностей кожи испы- туемого. Рис. 10.7. Размещение выносных контактов измерителя ЭАК на пальцах руки Вращением колесика мыши или подбором значения в поле POINTS подберите оп- тимальный масштаб по оси X. Электрическая активность кожи— это медленно изменяющийся параметр. Даже самый быстрый отклик, наподобие реакции на испуг или боль, проявляется не сра- зу и длится не менее секунды. Сеанс измерений продолжается, как минимум, не- сколько минут, иногда десятки минут и даже несколько часов. Поэтому нет смысла выводить данные измерений в графопостроитель чаще, чем 5... 10 раз в секунду. Пример чтения графика ЭАК В качестве простейшего примера я снял график электрической активности своей кожи во время работы с макетом измерителя. Чтобы уместить график на страницах книги, я разбил его на две части: рис. 10.8 и 10.9. Ось Y пронумерована значениями выборок напряжения на аналоговом входе АО. Ось X пронумерована значениями счетчика выборок с шагом 100. Скетч отправляет выборки с интервалом 100 мс, поэтому 100 выборок соответст- вуют 100 х 100 = 10 000 мс = 10 секунд. Цена промежуточного деления графика — 20 выборок (2 секунды).
200 Часть II. Теория и практика Рис. 10.8. Первый блок измерений ЭАК: нарастание тонической формы, спонтанные и физические пики Рис. 10.9. Второй блок измерений ЭАК: спад тонической формы, спонтанные выбросы Полученный график легко читается, если знать, какие факторы воздействовали на эмоциональное и физическое состояние испытуемого. На интервале меток 2100...2300 (см. рис. 10.8) я испытал волнение по поводу того, какой успех у читателей будет иметь моя новая книга. Это спонтанная эмоцио- нальная составляющая. На интервале 2300...2400 волнение прошло, когда я вспом- нил, что и предыдущие книги были успешными. Но общая тоническая составляю- щая стала немного выше, чем в начале сеанса.
Глава 10. Измерение электрической активности кожи 201_ На метке 2420 я очень глубоко и резко вдохнул и задержал дыхание примерно на секунду. В результате на метке 2470 наблюдается пик физической реакции. Одно- временно с этим ощутимо пошла вверх общая тоническая составляющая, потому что я приступил к активным экспериментам, и начало нарастать общее возбужде- ние нервной системы. Самостоятельно найдите на графике отклики на два менее глубоких вдоха с за- держкой дыхания. Затем на интервале 2580...2700 (см. рис. 10.8 и 10.9) я снова сделал четыре макси- мально глубоких вдоха с задержкой дыхания. Обратите внимание, что общая реак- ция на эти вдохи заметно меньше, чем реакция на первый вдох. Так и должно быть — при повторении физического раздражителя в течение короткого интервала времени отклик нервной системы снижается. Начиная с выборки 2740 (см. рис. 10.9), я сидел спокойно и расслабленно. Общая тоническая составляющая пошла вниз. Видны слабые отклики на медленные рав- номерные вдохи. В районе выборки 2940 мой взгляд случайно упал на фотографию из путешествия, с которым связаны самые приятные воспоминания. Нервная сис- тема немедленно отреагировала двумя импульсами: на эмоции и более глубокий вдох. Найдите эти импульсы на графике. Как видите, глубинную реакцию нервной системы практически невозможно ута- ить— даже беглый взгляд на памятную фотографию приводит к заметному от- клику. Мы только что убедились, что для исследования ЭАК в домашних условиях доста- точно простого модуля, платы Arduino и пары самодельных контактов. Теперь зай- мемся усовершенствованием нашего устройства. 10.4.3. Подключение к шине SPI Если вы разрабатываете измерительный комплекс, в котором много датчиков, за- нимающих все аналоговые входы Arduino, или хотите подключить измеритель ЭАК к контроллеру, у которого вообще нет аналоговых входов, воспользуйтесь встроен- ным аналого-цифровым преобразователем МСР3201 на плате модуля. Микросхема МСР3201 представляет собой 12-разрядный АЦП с диапазоном пита- ния +2,7...+5,0 вольт и быстродействием до 100 тысяч выборок в секунду. Микро- схема взаимодействует с микроконтроллером по протоколу SPI. В алгоритме работы АЦП МСР3201 есть особенности, которые необходимо учиты- вать при разработке кода программы: 1. Микросхема МСР3201 работает в режиме spimodei. По умолчанию библиотека Arduino SPI работает в режиме modeo. Режим modei необходимо задать в явном виде. 2. Аналого-цифровое преобразование выполняется во время первого тактового им- пульса шины SPI. Поэтому самый младший разряд числа, переданного микро- схемой, — технический и всегда равен нулю. Для получения правильного значе- ния полученное двоичное число необходимо сдвинуть вправо на один разряд.
202 Часть II. Теория и практика 3. МСР3201 начинает передавать данные со старшего разряда (most-significant bit). Если после передачи всех 12 разрядов данных тактовые импульсы шины SPI продолжают поступать, то микросхема будет передавать те же самые данные, только в обратном порядке — начиная с младшего разряда. Обычно стандартные библиотеки считывают данные кратно целому байту. После считывания двух бай- тов подряд (8x2 = 16 разрядов) четыре старших разряда будут засорены дан- ными, которые микросхема МСР3201 передала в обратном порядке. Эти разряды следует очистить наложением битовой маски логической функцией ИЛИ. 4. Максимальная тактовая частота МСР3201 — 1,6 МГц. При работе с библиотекой Arduino SPI мы должны явно задать делитель частоты кварца на 16, чтобы полу- чить тактовую частоту шины SPI 16:16 = 1 МГц. Электрическая схема подключения модуля измерителя ЭАК представлена на рис. 10.10, его макет показан на рис. 10.11, а исходный код программы приведен в листинге 10.2. ужртют. Рис. 10.10. Схема подключения измерителя ЭАК по интерфейсу SPI SCK: pin 13 MISO: pin 12 CS: pin 10
Глава 10. Измерение электрической активности кожи 203 #include <SPI.h> // Подключаем библиотеку SPI ^include <SoftwareSerial.h> // Подключаем библиотеку SoftwareSerial SoftwareSerial mySerial(2, 3); /7 2- RX, 3 - ТХ word result =0; // Результат конвертации, два байта (слово) byte byteHigh =0; // Старший байт полученного результата конвертации byte byteLow =0; // Младший байт полученного результата конвертации const int slaveCS = 10; // Вывод линии CS SPI для МСР3201 // Создаем объект настроек с именем МСР3201 SPISettings MCP3201(SPI_CLOCK_DIV16, MSBFIRST, SPI_MODE1); void setup() { mySerial.begin(115200); // Активируем программный порт, 115200 бод pinMode(slaveCS, OUTPUT); // Настраиваем линию CS SPI как выход digitalWrite(slaveCS, HIGH); // Переводим CS в высокий уровень SPI.begin(); // Инициализируем SPI void loop() { SPI.beginTransaction(MCP3201); // Применяем настройки,занимаем шину SPI digitalWrite(slaveCS, LOW); // Переводим линию CS в низкий уровень byteHigh = SPI.transfer(0); // Получаем старший байт результата byteLow = SPI.transfer(0); // Получаем младший байт результата digitalWrite(slaveCS, HIGH); // Переводим линию CS в высокий уровень SPI.endTransactionO; // Освобождаем шину SPI result = word(byteHigh, byteLow); // Собираем результат из двух байтов result = result » 1; // Сдвигаем на один разряд вправо // Накладываем маску, чтобы оставить только младшие 12 разрядов result = result & ObOOOOllllllllllll; mySerial.println(result); // Выводим результат в порт delay(100); В соответствии с новыми правилами работы с библиотекой Arduino SPI, сначала создается объект настроек шины для ведомого устройства, затем эти настройки применяются перед началом каждой транзакции. В приведенном коде учтены особенности работы микросхемы МСР3201 по шине SPI. Мы устанавливаем частоту тактов SPI 1 МГц, режим model Полученное число сдвигаем на один разряд вправо, чтобы убрать нулевой технический бит, и наложе- нием маски обнуляем четыре старших разряда.
204 Часть II. Теория и практика Рис. 10.11. Макет измерителя ЭАК с подключением по SPI (модуль Bluetooth здесь не показан) Готовый результат транслируется в последовательный порт для визуализации на экране компьютера. При настройке программы визуализации имейте в виду, что разрядность АЦП модуля больше, чем у платы Arduino. При работе через аналого- вый порт АО платы Arduino результаты оцифровки лежат в диапазоне 0...1023 (см. листинг 10.1). Получаемые по шине SPI числовые значения находятся в диапазоне 0...4095. Нужен ли TFT-дисплей для измерителя ЭАК? Как мы уже говорили, электрическая активность кожи— это параметр, который изменяется очень медленно. Измерения занимают длительное время и, как правило, нуждаются в последующем изучении и расшифровке. Оператор измерительного прибора фиксирует метки времени для того или иного воздействия, а затем возвра- щается к сохраненным данным, меняет масштаб изображения и оценивает форму кривой отклика полностью и по частям. Малогабаритный дисплей, подключенный к плате Arduino, позволяет отобразить лишь малую часть полученных данных практически в режиме реального времени. Собственной памяти контроллера и его скромных вычислительных ресурсов недос- таточно для прокрутки графика на экране и масштабирования изображения. Разумеется, мы можем оснастить плату Arduino модулем быстродействующей памяти и органами управления для сохранения и просмотра данных. Но результат все равно получится заметно хуже, чем при построении графика на экране самого дешевого ноутбука. Любое конструктивное решение, даже если оно технически осуществимо, не должно противоречить здравому смыслу. Поэтому мы не будем подключать графический TFT-дисплей к измерителю ЭАК. Но если у читателя воз- никнет потребность в портативном устройстве, он может самостоятельно подклю- чить дисплей, взяв за основу проект из разд. 6.5.
Глава 10. Измерение электрической активности кожи 205 10.5. Опыты с измерителем ЭАК Опыты с измерением электрической активности кожи дают возможность предста- вить себя на месте настоящего ученого и получить опыт научных исследований. Кожно-гальваническая реакция зависит от индивидуальных особенностей испы- туемого, поэтому результаты многих опытов можно предсказать только в общих чертах. Перед вами раскрывается большой простор для исследований. Некоторые опыты можно провести на себе, но, в общем случае, результаты будут искажены. Например, вы не можете внезапно испугать себя. Поэтому для участия в ваших опытах лучше найти добровольцев. Желательно, чтобы испытуемый не знал заранее о подробностях методики иссле- дований и ожидаемых результатах. Разумеется, ваши методы воздействия на эмо- циональное состояние подопытного не должны нарушать общепринятые этические нормы или причинять вред. Участие в опытах само по себе возбуждает нервную систему. Прикрепив электроды к пальцам и настроив оборудование, попросите подопытного расслабиться и спо- койно думать о чем-то постороннем 5... 10 минут. Когда вы увидите, что проводи- мость кожи стабилизировалась и почти не меняется, можно приступать к опытам. 10.5.1. Опыт с глубоким дыханием Попросите испытуемого сделать максимально глубокий вдох. Вы увидите, что про- водимость кожи резко увеличилась— напряжение дыхательных мышц заставило симпатическую нервную систему послать импульсы на потовые железы. Эффект усиливается внезапным притоком дополнительного кислорода к мозгу. Но в целом дыхательный эффект сильно зависит от особенностей организма испытуемого. У одних людей колебания проводимости кожи заметны во время обычного разго- вора, а на других слабо влияет даже глубокий вдох. 10.5.2. Опыт с мускульным напряжением Попросите испытуемого сильно сжимать резиновый мячик свободной рукой или сжимать и расслаблять пальцы ног. Затем попросите напрячь мышцы брюшного пресса или крепко стиснуть зубы. Между опытами следует делать перерывы не ме- нее 15...20 секунд. Рука с электродами должна оставаться неподвижной. Какой вид физического напряжения дает максимальный отклик? По возможности проделайте опыты с несколькими участниками и сравните результаты. Зависит ли отклик от физической тренированности участника? 10.5.3. Опыт с воздействием температуры Проведите опыт 1 с глубоким дыханием. Затем, в зависимости от сезона года и климата, попросите испытуемого находиться несколько минут на холоде (напри- мер, выйти на холодный балкон) или в жарком месте. Повторите опыт 1. Измени-
206 Часть II. Теория и практика лась ли реакция на глубокий вдох? Затем проведите опыт с температурным контра- стом. Если испытуемый подвергался воздействию холода, дайте ему в свободную руку горячий предмет (например, кружку с чаем). Если испытуемый находился в жарком месте, положите ему в свободную ладонь кубики льда. Наблюдайте, как изменилась проводимость кожи. 10.5.4. Опыт с расположением электродов Вы уже знаете, что глубокий вдох дает выраженную реакцию проводимости кожи, и умеете различать эту реакцию на графике. Попробуйте менять расположение электродов на теле. Перенесите один электрод на палец другой руки. Попробуйте при помощи лейкопластыря или скотча крепить электроды на коже живота или спины. При каком расположении электродов наиболее заметно изменение прово- димости кожи? 10.5.5. Опыт с эффектом расслабления Попросите испытуемого максимально расслабиться, закрыть глаза, сидеть или ле- жать неподвижно и не думать ни о чем существенном. Наблюдайте, как постепенно меняется тоническая составляющая реакции. Если вам повезет и испытуемый уснет, то вы сможете наблюдать, как меняется проводимость кожи при внезапном пробуждении. 10.5.6. Опыт с воздействием боли Попросите испытуемого ущипнуть себя или уколоть иголкой. Несмотря на то, что испытуемый заранее был готов ощутить боль и сам является ее источником, орга- низм все равно отреагирует резким броском проводимости. В целом, нервная сис- тема одинаково резко реагирует как на дискомфорт, так и на удовольствие — но создать дискомфорт проще ;-). 10.5.7. Опыт с воздействием страха Попросите испытуемого расслабиться и сидеть спокойно с закрытыми глазами 30 секунд. Затем внезапно хлопните в ладоши перед его лицом или громко ударьте линейкой по столу. Проводимость кожи возрастет очень резко и сильно. Обратите внимание, что реакция потовых желез отстает от воздействия на 1...3 секунды. Такова особенность человеческого организма. В первую очередь срабатывают дви- гательные рефлексы, а также происходит выброс адреналина в кровь. Затем прояв- ляется вспомогательная реакция в виде увлажнения кожи. 10.5.8. Опыт с адаптацией и восстановлением Повторяйте один из способов воздействия (например, глубокий вдох) с интервалом менее 30 секунд. Вы увидите, что с каждым разом отклик уменьшается вплоть до полного исчезновения. Это явление называется адаптацией. Сделайте перерыв на
Глава 10. Измерение электрической активности кожи 207 несколько минут. Снимите электроды. Пусть восстановится периферийное крово- обращение, а кожа проветрится. Затем повторите опыт. Восстановилась ли реакция на раздражитель? Если да — до какого уровня? 10.5.9. Опыт со словами и ассоциациями В предыдущих опытах вы использовали физические раздражители, которые напря- мую воздействовали на нервную систему. Ментальные раздражители: музыка, сло- ва, рисунки — действуют косвенно, через сознание, но тоже вызывают изменение проводимости кожи. Приготовьте карточки, на которых крупно и разборчиво напи- саны короткие слова. Показывайте карточки испытуемому с интервалом не менее трех секунд, чтобы отклик проводимости кожи успел проявиться на графике. Пример набора слов приведен в табл. 10.1. Психологи установили, что существуют слова, на которые реагируют почти все подопытные. Эти слова выделены полу- жирным шрифтом. Зная детали биографии и быта испытуемого, вы можете подоб- рать другие слова, которые дадут наиболее выраженную реакцию. Даже специаль- но тренированному человеку очень сложно скрыть подсознательную реакцию на ключевые слова или изображения. Таблица 10.1. Пример набора слов для опытов с ЭАКнад испытуемым-мужчиной рыба женщина прогулка поцелуй карандаш лампа дело любовь тень белый чтение песок мяч боль свет трава цветок дорога {имя объекта} линия ненависть бумага берег ветер 10.5.10. Опыт с тревожным ожиданием Чтобы вызвать заметную реакцию проводимости кожи, не обязательно пугать испытуемого громким звуком или причинять ему физический дискомфорт. После того, как вы провели несколько предыдущих опытов, сделайте вид, что готовитесь к чему-то важному. Достаньте из ящика стола новые провода или электронную плату. Скажите испытуемому: «Сейчас может быть немного неприятно, но ты не бойся. Это не больно». Как правило, реакция нервной системы на тревожное ожи- дание оказывается сильнее, чем на укол иглой или удар. 10.5.11. Опыт с тревожной реакцией Как только испытуемый перешел в тревожное состояние после опыта 10, зайдите за его спину и внезапно проведите мягкой кисточкой или мизинцем по открытой коже шеи или руки. Вы сдержали обещание, что будет не больно, не так ли? Но от- клик кожной проводимости будет намного сильнее по сравнению с тем, если бы вы провели кисточкой по руке испытуемого в спокойной обстановке.
208 Часть II. Теория и практика 10.5.12. Опыт с мыслительным усилием Любая трудная мыслительная задача вызывает изменение проводимости кожи. Предложите испытуемому вычислить в уме значение математического выражения, найти опечатки в сложных словах, перевести с другого языка трудное предложение и т. д. 10.5.13. Опыт с загадыванием числа Попросите испытуемого написать число от 1 до 10 на листе бумаги. Поочередно называйте числа вслух и по графику ЭАК попытайтесь угадать, какое число загадал испытуемый. Это непростая задача, особенно если испытуемый попытается ввести вас в заблуждение: будет глубоко вдыхать, напрягать брюшной пресс или как-то иначе вызывать искусственную реакцию. 10.5.14. Опыт с обусловленным откликом Это самый сложный опыт из нашего цикла. Он не всегда получается даже у психо- логов с профессиональным оборудованием. Не расстраивайтесь, если у вас этот опыт не даст ожидаемого результата. Попробуйте провести опыт с разными людьми. Заранее приготовьте два стимулирующих воздействия (в психологии их называют стимулами). Первый стимул должен быть слабым — например тихий звонок, ней- тральное слово, слабый свет. Второй стимул должен быть достаточно сильным, чтобы вызвать заметную реакцию. Это может быть громкий удар, звук сирены, яркая вспышка и тому подобное. Сначала воздействуйте на испытуемого слабым стимулом и убедитесь, что реакция очень слабая или отсутствует. Затем примените сильный стимул и убедитесь в наличии заметного отклика. Важный момент — слабый и сильный стимул должны быть разного типа. Например, слово «дверь» в качестве слабого стимула и укол иглой в качестве сильного. Теперь одновременно примените оба стимула. Возможно, для этого потребуется помощник. Повторите сдвоенное воздействие три-пять раз с интервалом в 5... 10 се- кунд. Затем примените только слабый стимул. Наблюдаете ли вы такой же отклик, как при сильном стимуле? Если да — поздравляю, вы обнаружили обусловленный (связанный) отклик нервной системы. Вы применили только слабый стимул, на который нервная система раньше не отвечала, и получили ответ как на сильный стимул. Как вы думаете, почему в процессе эволюции у нервной системы человека образо- валась такая способность связывать стимулы?
ГЛАВА 11 Цифровой пульсоксиметр В главе 6 мы обсудили конструкцию простого аналогового пульсометра. В этой главе мы поговорим о более сложном устройстве, которое измеряет не только час- тоту пульса, но и степень насыщения крови кислородом — кислородную сатура- цию. Такое комбинированное устройство называется пулъсоксиметром. Приступая к работе над макетом пульсоксиметра, следует правильно выбрать сен- сор и модуль расширения. Мы возьмем для наших проектов популярный цифровой пульсоксиметр МАХ30102. Предыдущая версия этого устройства — МАХ30100 — также широко распространена среди разработчиков-любителей, но мы воспользу- емся его современной моделью с улучшенной функциональностью. Отдельное внимание следует уделить выбору правильного модуля расширения пульсоксиметра. Поскольку сенсоры МАХЗОЮО и МАХ30102 полностью совпада- ют по габаритам и расположению выводов, обе модели сенсора могут быть смон- тированы на одинаковых печатных платах. На рис. 11.1, а изображен очень попу- лярный, но устаревший модуль, который содержит ошибку в цепи питания сенсора, и очень часто контроллер Arduino «не видит» модуль на шине 12С. Детальное описание ошибки и способов ее устранения можно найти по адресу http:// reedpaper.com/archives/936. На рис. 11.1, б представлен более современный модуль расширения, который не содержит ошибки в разводке дорожек платы. Обычно на такую плату устанавлива- ют сенсор МАХ30102 в новом корпусе (хотя на плате может остаться надпись МАХ30100). Тем не менее на этой плате тоже иногда встречается неправильный стабилизатор питания. Проверить это очень легко. Найдите на обратной стороне платы компонент с тремя выводами (корпус SOT23) — это стабилизатор питания сенсора. На нем должны быть нанесены буквы 65К, что соответствует выходному напряжению 1,8 вольта. Это паспортное напряжение питания сенсора. К сожале- нию, на некоторых экземплярах платы модуля встречается стабилизатор с марки- ровкой 65Х и выходным напряжением 2,8 вольта. Нетрудно догадаться, что это на- пряжение значительно превышает паспортное. Сенсор не выходит из строя, но при таком завышенном напряжении питания нельзя гарантировать надежную работу микросхемы. Более подробно о диагностике ошибки и ее устранении можно прочи- тать по адресу http://reedpaper.com/archives/1197.
210 Часть II. Теория и практика Рис. 11.1. Два наиболее популярных варианта модуля расширения пульсоксиметра: а — на устаревшем сенсоре МАХ30100; б— на современном сенсоре МАХ30102 11.1. Принцип работы и устройство сенсора МАХ30102 В главе 6 мы уже говорили о том, как степень наполнения капилляров кровью влия- ет на интенсивность отраженного света. Для измерения уровня насыщения крови кислородом также используется измерение степени отражения/поглощения света, но механизм измерения немного сложнее. В профессиональной литературе принято говорить о поглощении света кровью и тканями организма. Действительно, многие профессиональные приборы с датчиком в виде клипсы (см. рис. 6.3) работают на просвет и измеряют уровень поглощения света. Но некоторые датчики— такие как МАХ30102— работают с отраженным светом. Для электронной схемы пульсоксиметра не имеет принципиального значения, интен- сивность какого света мы измеряем: отразившегося от сосудов или прошедшего сквозь сосуды. Просто нужно помнить, что степень поглощения и степень отраже- ния — это взаимно обратные величины. Чем сильнее кровь поглощает свет с опре- деленной длиной волны, тем хуже она отражает этот же свет. Далее мы будем говорить именно о степени поглощения света, потому что так при- нято в научной и технической литературе. Перенос кислорода от легких к тканям организма происходит при помощи гемо- глобина (НЬ). Это особый железосодержащий белок, способный захватывать и от- давать молекулы кислорода. Гемоглобин, присоединивший к себе кислород, назы- вается оксигемоглобином (ОхНЬ), а отдавший кислород— дезоксигемоглобином (ННЬ). Одна молекула гемоглобина способна присоединить до четырех молекул кислорода. В таком случае она считается насыщенной кислородом на 100%. Разу-
Глава 11. Цифровой пульсоксиметр 211 меется, разные молекулы гемоглобина в одно и то же время могут нести разное ко- личество молекул кислорода, а степень насыщения крови кислородом (кислородная сатурация) измеряется в среднем по общей массе молекул. Например, если 100 мо- лекул гемоглобина несут 400 молекул кислорода, то насыщение крови кислородом составляет 100%. Если же 100 молекул гемоглобина несут в общей сложности только 350 молекул кислорода, то сатурация составит: (350 : 400) х 100 = 87,5%. Здоровый человек с нормально функционирующими легкими на высоте уровня мо- ря имеет сатурацию артериальной крови в диапазоне 95... 100%. Венозная кровь, оттекающая от тканей (отдавшая кислород), имеет сатурацию около 75%. Высота над уровнем моря влияет на сатурацию. Высоко в горах воздух разрежен, и человек испытывает кислородное голодание. Почему важно измерять сатурацию крови? Кислород жизненно важен для организ- ма, особенно для головного мозга. Нехватка кислорода в крови (гипоксия) приво- дит к угнетению обменных процессов организма, слабости, вялости, головокруже- нию. Длительная острая гипоксия вызывает необратимые изменения клеток голов- ного мозга или их безвозвратную гибель. Стабильно пониженная сатурация крови может указывать на недостаточное содержание гемоглобина в крови или заболева- ние легких. Артериальная кровь, насыщенная кислородом, имеет ярко-красный цвет. Венозная кровь, отдавшая кислород, имеет темно-красный, иногда почти черный цвет. Ины- ми словами, чем больше кислорода содержится в крови, тем меньше она поглощает красный свет (но лучше отражает). Не трудно догадаться, что эту зависимость можно использовать для измерения концентрации кислорода в крови. Но не все так просто. Ведь кроме концентрации кислорода, на поглощение света в сосудах влияет еще и степень наполнения сосудов кровью. В главе 6 мы про- демонстрировали, как из переменного заполнения капилляров можно выделить импульсы сердцебиения. Но как из пульсирующего сигнала извлечь информацию о количестве кислорода в крови? Эта задача требует особого подхода! В пульсоксиметрах для выделения «кислородной» составляющей применяют два светодиода: красный с длиной волны 650 нм и инфракрасный с длиной волны 880 нм. Принцип измерения заключается в том, что в зависимости от насыщения крови ки- слородом меняется соотношение между поглощением красного и инфракрасного света. Таким образом, общее поглощение света меняется в такт сокращениям сердца, но соотношение между поглощением красного и инфракрасного света зави- сит только от уровня сатурации крови. Поэтому пульсоксиметр может одновремен- но измерять как частоту пульса, так и сатурацию крови. Посмотрите на рис. 11.2. На нем графически изображена зависимость поглощения красного и инфракрасного света в зависимости от длины волны излучения и концентрации кислорода в крови. Поглощение красного цвета сильно зависит от кислородной сатурации. Бедная ки- слородом кровь (ННЬ) интенсивно поглощает красный свет, а обогащенная кисло- родом кровь (ОхНЬ) красный свет не поглощает, а отражает (поэтому она ярко- красная). И наоборот, поглощение инфракрасного света возрастает с увеличением концентрации кислорода в крови. Иными словами, если кровь плохо поглощает
212 Часть II. Теория и практика красный свет, но хорошо поглощает инфракрасное излучение, то концентрация кислорода в крови велика, а точное значение сатурации вычисляется по соотноше- нию степени поглощения красного и инфракрасного света. 650 Длина волны, им 880 Рис. 11.2. График зависимости поглощения света кровью от концентрации кислорода и длины волны Как мы уже отмечали, содержание кислорода в артериальной крови намного выше, чем в венозной. Но какое содержание кислорода измеряет пульсоксиметр, если в тканях присутствуют и те, и другие кровеносные сосуды? Здесь применяется еще одна хитрость: пульсация кровотока наиболее выражена у сосудов, подающих све- жую кровь к тканям. У сосудов, отводящих использованную кровь от тканей, пуль- сация проходящего или отраженного света почти незаметна. Поэтому соотношение между поглощением красного и инфракрасного света обычно измеряют в момент достижения пика пульсовой кривой. Измеренное в этот момент соотношение соот- ветствует уровню насыщения кислородом артериальной крови. 11.1.1. Устройство микросхемы МАХ30102 Внутреннее устройство сенсора МАХ30102 изображено на рис. 11.3. Микросхема содержит два светодиода: красный и инфракрасный, а также драйвер светодиодов, при помощи которого можно регулировать ток, протекающий через светодиоды, и длительность импульсов вспышки светодиодов. Отраженный от тканей тела свет попадает на двухдиапазонный фотодиод, усилива- ется операционным усилителем и оцифровывается. Схема оснащена подавителем постоянной составляющей, возникающей от засветки фотодиода внешними источ- никами света. Оцифрованный сигнал поступает на цифровой фильтр и шумопода- витель. Результат измерения записывается в выходной регистр и считывается по шине 12С. Также в выходной регистр записывается результат измерения температу- ры при помощи встроенного термометра для компенсации зависимости показаний фотодиода от температуры корпуса.
Глава 11. Цифровой пульсоксиметр 213 RED 660 нм Фотодиод 880 нм Подавление внешнего света <АЦП Термометр АЦП Аналоговая часть Цифровой фильтр Регистр данных Цифровая часть Генератор ± Интерфейс I2C SCL 'sDA Драйвер LED МАХ30102 R_DRV IR_DRV GND PGND V Рис. 11.3. Внутреннее устройство микросхемы МАХ30102 На рис. 11.4 в общем виде изображена измерительная система на основе МАХ30102. Несмотря на то, что микросхема сенсора оснащена рстроенным АЦП и цифровым фильтром, основная обработка измерительных выборок выполняется программно в пользовательском устройстве. К счастью нам доступна достаточно мощная библиотека Arduino для МАХ30102. Скоро мы ей воспользуемся. Приложения Пользовательское устройство Драйверы Интерфейс 1С i 1Б vc myi и> hO МАХЗО1О2 Драйвер светодиодов Цифрово юподави J А гель 18- Электроника разрядный АЦП Подавитель засветки t1 Фото- диол Оптика 1—*► 1 Корпус Акриловое стекло «*- Человеческое тело Внешний . свет Рис. 11.4. Структурная схема пульсоксиметрической системы на основе МАХ30102 11.1.2. Основные технические характеристики пульсоксиметра МАХ30102 ♦ Габариты: 5,6x3,3x1,55 мм ♦ Рабочий диапазон температур: -40...+85 °С
214 Часть II. Теория и практика ♦ Напряжение питания: • микросхемы: 1,8 В • светодиодов: 3,3...5,2 В ♦ Потребляемый ток: • в режиме измерения: до 1200 мкА (в импульсе) • в режиме ожидания: 0,7... 10 мкА ♦ Разрядность АЦП: 18 битов ♦ Частота шины 12С: 400 кГц 11.2. Подключение МАХ30102 к плате Arduino Uno Подключение модуля МАХ30102 (см. рис. 11.1, б) к плате Arduino Uno не состав- ляет труда — достаточно подсоединить выводы питания и шины 12С, как показано на рис. 11.5. Внешний вид макета представлен на рис. 11.6. Рис. 11.5. Подключение модуля МАХ30102 к плате Arduino Uno R3 При проведении измерений крайне важно обеспечить постоянное усилие прижима оптической поверхности сенсора к коже. Сенсор должен прилегать плотно, но без чрезмерного усилия, чтобы не сдавливать капилляры кожи. Малейшие колебания усилия прижима сенсора приведут к большой погрешности или сбою измерений.
Глава 11. Цифровой пульсоксиметр 215 Нельзя зажимать плату сенсора между пальцами или прижимать палец к плате, лежащей на столе. Лучше закрепить ее на пальце при помощи эластичного резино- вого колечка или полоски лейкопластыря. Рис. 11.6. Внешний вид макета простого пульсоксиметра 11.2.1. Установка библиотеки пульсоксиметра Мы воспользуемся библиотекой sparkFun махзоюх для работы с сенсорами МАХ30102 и МАХ30105. Имейте в виду, что библиотеки для сенсора МАХ30100 не подойдут. Запустите среду разработки Arduino IDE и откройте менеджер библиотек. В строке поиска введите фрагмент махзо и выберите библиотеку SparkFun махзоюх Library. Если библиотека не найдена в репозитории (такое иногда случается), скачайте ар- хив библиотеки по адресу https://github.com/sparkfun/SparkFun_MAX3010x_ Sensor_Library. Уберите из названия скачанного архива фрагмент -master и добавь- те библиотеку из архива, как показано в разд. 2.3.2. . 11.2.2. Проверка и настройка пульсоксиметра Для проверки работоспособности пульсоксиметра и настройки оптимального по- ложения сенсора на пальце воспользуемся скетчем на основе фирменного примера компании SparkFun с открытым кодом (листинг 11.1). Скетч выводит в последова- тельный порт «сырые» данные с фотодиода. Эти данные наглядно иллюстрируют физику процессов, происходящих в кровеносной системе. Получаемый график мы будем наблюдать в окне плоттера Arduino IDE.
216 Часть II. Теория и практика #include <Wire.h> #include "MAX30105.h" MAX30105 pulseSensor; void setup() { Serial.begin(115200) ; Serial.println("Initializing..."); // Инициализируем сенсор if (!pulseSensor.begin(Wire, I2C_SPEED_FAST)) // Частота шины 400 кГц { // Если не удалось найти сенсор на шине по адресу 0x57 Serial.println("MAX30102 was not found. Please check wiring/power. "); while (1); // Настройки для оптимального отображения пиков на графике byte ledBrightness = OxlF; // Ток светодиодов: 0=Off до 255=50mA byte sampleAverage =8; // Число замеров для // усреднения: 1, 2, 4, 8, 16, 32 byte ledMode =2; // Режим: 1 = Только красный, 2 = Красный + ИК, // 3 = Красный + ИК + Зеленый // Режим 3 доступен для МАХ30105. Для сенсора МАХ30102 // используйте режим 2 int sampleRate = 100; // Частота выборок: 50, 100, 200, 400, 800, 1000, 1600, 3200 int pulseWidth = 411; // Длительность импульса: 69, 118, 215, 411 int adcRange = 4096; // Разрядность АЦП: 2048, 4096, 8192, 16384 // Конфигурируем сенсор с заданными настройками pulseSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); // Заранее принудительно настраиваем автомасштаб плоттера Arduino IDE // при помощи 500 усредненных значений, отправленных в порт // Измеряем значение в ИК-канале при включении const byte avgAmount = 64; long baseValue = 0; for (byte x = 0 ; x < avgAmount ; x++) { baseValue += pulseSensor.getIRO; // Читаем значение из регистра } baseValue /= avgAmount;
Глава 11. Цифровой пульсоксиметр 217 // Настраиваем масштаб плоттера, отправляя 500 значений в порт for (int x = 0 ; х < 500 ; х++) Serial.println(baseValue); void loop() { // Отправляем "сырые" данные в плоттер Serial.println(pulseSensor.getIR()); // Ниже фрагмент кода для отправки данных //в плоттер FlexyPlot (раскомментируйте при необходимости) /*Serial.print("{Р0I Heartbeat|255, 0, 0 I") ; Serial.print(pulseSensor.getIR()); Serial.println("}"); delay(5);*/ Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). В этом скетче мы проверяем наличие датчика на шине 12С и настраиваем режим работы светодиодов и АЦП для оптимального наблюдения за пульсацией кровото- ка. Затем 64 раза измеряем ток фотодиода по инфракрасному каналу и находим среднее арифметическое значение. Найденное значение отправляем 500 раз подряд в последовательный порт, чтобы сработала автоматическая настройка масштаба встроенного плоттера Arduino IDE. Далее программа переходит в главный цикл и непрерывно посылает в плоттер данные выборок. Загрузите в контроллер Arduino проверочный скетч, прикрепите модуль сенсора к подушечке среднего или безымянного пальца и откройте окно встроенного плот- тера на скорости 115 200 бод. Уже сейчас мы можем провести простейший опыт. Дождитесь, пока плоттер не начнет рисовать устойчивый график пульсаций крови (рис. 11.7). Задержите дыхание приблизительно на 30 секунд. Вы увидите, что амплитуда и форма импульсов почти не изменились, но постоянная составляющая начала уменьшаться (кривая графика слегка опустилась ниже). Этот эффект обу- словлен снижением количества кислорода в крови. Теперь начните глубоко и часто дышать. Кривая быстро пойдет вверх — концен- трация кислорода в крови резко возросла. При помощи графика трудно определить частоту пульса и невозможно определить численное значение кислородной сатура- ции, но мы можем наглядно убедиться в исправности сенсора и настроить опти- мальное крепление модуля на пальце.
218 Часть II. Теория и практика Рис. 11.7. Зависимость графика пульсаций кровотока от концентрации кислорода в крови 11.2.3. Встроенный датчик приближения Пульсоксиметр МАХ30102 может работать в режиме датчика приближения (proxi- mity sensor), который позволяет «разбудить» сенсор и сопряженное устройство только тогда, когда палец поднесен к оптической зоне датчика. В режиме ожидания инфракрасный светодиод излучает короткие вспышки, невидимые глазу, а пользо- вательская программа измеряет так называемый параметр «дельта» (delta) — раз- ницу между значениями тока через фотодиод в момент излучения инфракрасного импульса и в промежутке между импульсами. Если вблизи оптической зоны сенсо- ра нет отражающей поверхности, то изменение тока через фотодиод почти не на- блюдается, и величина тока определяется только постоянной внешней засветкой. Как только напротив рабочей поверхности сенсора появляется отражающий пред- мет, ток через фотодиод в момент импульса инфракрасной подсветки резко возрас- тает (то есть резко увеличивается дельта сигнала). Датчик приближения срабатыва- ет на расстоянии около 25...30 см. Скетч, демонстрирующий работу датчика приближения, приведен в листинге 16.2. В последовательный порт выводится текущее значение дельты и сообщение о при- ближении объекта к сенсору. #include <Wire.h> #include "MAX30105.h" MAX30105 pulseSensor; long unblockedValue; // Среднее значение в ПК-канале при включении
Глава 11. Цифровой пульсоксиметр 219 void setup() { Serial.begin(115200); Serial.println("MAX30102 Presence Sensing Example"); // Конфигурируем вывод встроенного светодиода piriMode(LED_BUILTIN, OUTPUT); // Гасим встроенный светодиод digitalWrite(LED_BUILTIN, LOW); // Инициализируем сенсор if (pulseSensor.begin(Wire, I2C_SPEED_FAST) == false) // Частота шины // 400 кГц { Serial.printIn("MAX30102 was not found. Please check wiring/power. ") ; while (1); // Настройка параметров светодиодов и АЦП // для максимальной дальности обнаружения byte ledBrightness = OxFF; // Ток через светодиод: O=0ff до 255=50тА byte sampleAverage =4; // Число замеров для усреднения: 1, 2, 4, 8, 16, 32 byte ledMode =2; // Режим: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green int sampleRate = 400; // Частота выборок: 50, 100, 200, // 400, 800, 1000, 1600, 3200 int pulseWidth = 411; // Длительность импульса: 69, 118, 215, 411 int adcRange = 2048; // Разрядность АЦП: 2048, 4096, 8192, 16384 // Конфигурируем сенсор с заданными настройками pulseSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); // Configure sensor with these settings pulseSensor.setPulseAmplitudeRed(O); // Гасим красный светодиод // Находим среднее значение ИК-канала при включении unblockedValue = 0; for (byte х = 0 ; х < 32 ; х++) { unblockedValue += pulseSensor.getIRO; // Читаем значение из регистра } unblockedValue /= 32; void loop () { long currentDelta = pulseSensor.getIRO - unblockedValue;
220 Часть II. Теория и практика Serial.print(" delta["); Serial.print(currentDelta); Serial.printC1]") ; if (currentDelta > (long)100)// Если что-то обнаружено { Serial.printC Something is there!"); // Включаем встроенный светодиод digitalWrite(LED_BUILTIN, HIGH); } else { // Иначе гасим встроенный светодиод digitalWrite(LED_BUILTIN, LOW); Serial.println(); } В этом скетче мы устанавливаем максимальный ток через светодиоды для увеличе- ния дальности обнаружения и отключаем красный светодиод сенсора, потому что он не нужен для датчика приближения. При срабатывании датчика приближения включается встроенный светодиод платы Arduino и выводится текстовое сообще- ние в порт. Светодиод платы Arduino гаснет при удалении объекта из оптической рабочей зоны датчика. При включении питания происходит настройка усредненного «нулевого» уровня сигнала фотодиода, относительно которого будет вычисляться дельта. Поэтому очень важно, чтобы при включении питания в оптической рабочей зоне сенсора не было предметов, иначе возникнет большая погрешность вычисления дельты. 11.3. Измеритель частоты пульса и сатурации крови К сожалению, измерение сатурации крови требует использования весьма сложных алгоритмов обработки сигнала. Ведь мы должны отфильтровать составляющую пульсации кровотока, а также нестабильную постоянную составляющую и собст- венные шумы сенсора, которые не до конца подавлены встроенным шумоподавите- лем. Поэтому мы не можем просто взять и прочитать из сенсора готовые значения частоты пульса и уровня сатурации. Необходимо накопить достаточное количество выборок и выполнить статистическую обработку при помощи процедур библиоте- ки SparkFun МАХЗОЮх. Объема оперативной памяти микроконтроллера ATmega328 едва хватает, чтобы накопить массив из 100 выборок и запустить самую простейшую программу для измерения частоты пульса и сатурации крови. Поэтому мы не можем использовать в нашем проекте даже скромный OLED-дисплей — придется выводить результаты
Глава 11. Цифровой пульсоксиметр 221_ измерений в последовательный порт. Рассматривайте скетч из листинга 16.3 в каче- стве основы для дальнейших разработок. Например, можно взять две платы Arduino Mini и соединить их через последовательный порт. Одна плата будет взаимодейст- вовать с сенсором и обрабатывать измерительные выборки, а вторая — отвечать за отображение данных на экране дисплея. #include <Wire.h> #include "MAX30105.h" #include lfspo2_algorithm.h" MAX30105 pulseSensor; #if defined (__AVR_ATmega328P ) | I defined (__AVR_ATmegal68 ) // Для плат на основе контроллеров ATmega320 и ATmegal68 //мы вынуждены отбросить 16 старших разрядов и оставить // только 16 младших разрядов по причине нехватки памяти uintl6_t irBuffer[100]; // Данные в канале ИК-света uintl6_t redBuffer[100]; // Данные в канале красного цвета #else // Для более мощных плат оставляем 32-разрядные даные uint32_t irBuffer[100]; // Данные в канале ИК-света uint32_t redBuffer[100]; // Данные в канале красного цвета #endif byte bufferLength; // Размер буфера данных int32_t spo2; // Значение SPO2 byte validSPO2; // Флаг корректности данных SPO2 int32_t heartRate; // Значение частоты пульса byte validHeartRate; // Флаг корректности частоты пульса void setup() { Serial.begin(115200) ; // Инициализируем сенсор if (IpulseSensor.begin(Wire, I2C_SPEED_FAST)) // Частота шины 400 кГц { Serial.println(F("MAX30102 was not found.")); while (1); // Прикрепите сенсор к пальцу и нажмите клавишу ввода Serial.println(F("Attach sensor to finger with rubber band. Press Enter to start conversion.")] while (Serial.available() == 0) ; // Ждем ввод любого символа Serial.read();
222 Часть II. Теория и практика // Настройка параметров светодиодов и АЦП byte ledBrightness = 60; // Ток через светодиод: 0=Off до 255=50тА byte sampleAverage = 4; // Число замеров для усреднения: 1, 2, 4, // 8, 16, 32 byte ledMode =2; // Режим: 1 = Red only, 2 = Red + ir, // 3 = Red + IR + Green byte sampleRate = 100; // Частота выборок: 50, 100, 200, 400, // 800, 1000, 1600, 3200 int pulseWidth = 411; // Длительность импульса: 69, 118, 215, 411 int adcRange = 4096; // Разрядность АЦП: 2048, 4096, 8192, 16384 // Конфигурируем сенсор с заданными настройками pulseSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); void loop () bufferLength = 100; // Собираем в буфер начальный пакет значений //в течение 4 секунд, 25 выборок в секунду for (byte i = 0; i < bufferLength; i++) // Ждем появление новых данных в выходных регистрах сенсора while (pulseSensor.available() == false) pulseSensor.check(); // Читаем данные в канале красного света redBuffer[i] = pulseSensor.getRedO; // Читаем данные в канале инфракрасного света irBufferfi] = pulseSensor.getIRO; //Мы получили текущую выборку // Разрешаем сенсору делать следующую выборку pulseSensor.nextSample(); Serial.print(F(".") ) ; ' } Serial.printIn(F("")); // Вычисляем частоту пульса и сатурацию на основе полученных выборок maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, SvalidHeartRate) , // Продолжаем собирать выборки в бесконечном цикле // Значения частоты пульса и сатурации обновляются один раз в секунду while (1) // Выбрасываем 25 старых выборок из буфера со сдвигом вверх for (byte i = 25; i < 100; i++)
Глава 11. Цифровой пульсоксиметр 223_ redBuffer[i - 25] = redBuffer[i]; irBuffer[i - 25] = irBufferfi]; // Собираем 25 новых выборок for (byte i = 75; i < 100; i++) { while (pulseSensor.available() == false) pulseSensor.check(); //Мы получили текущую выборку // Разрешаем сенсору делать следующую выборку redBuffer[i] = pulseSensor.getRed(); irBuffer[i] = pulseSensor.getIR(); pulseSensor.nextSampleO ; Serial.print(F("HR=")); Serial.print(heartRate, DEC); Serial.print(F(", SpO2=")); Serial.println(spo2, DEC); // После получения очередных 25 выборок заново вычисляем // частоту пульса и сатурацию maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, SheartRate, &validHeartRate) За основу этого скетча взят пример с открытым исходным кодом для библиотеки sparkFun махзоюх. Накопление нужного количества измерительных выборок зани- мает четыре секунды. Разумеется, с точки зрения пользователя неудобно, когда ин- формация о частоте пульса и сатурации обновляется один раз в четыре секунды. Поэтому полный буфер из 100 измерений формируется только в момент начала работы пульсоксиметра, а затем один раз в секунду содержимое буфера смещается на 25 позиций с вытеснением старых элементов. Затем в конец буфера дописыва- ются новые выборки и вычисляются новые результаты измерений. Таким образом, результаты измерений обновляются один раз в секунду. Частота измерений опреде- ляется настройками сенсора, а программа только ожидает готовности данных. Загрузите скетч в плату контроллера Arduino и откройте окно монитора последова- тельного порта на скорости 115 200 бод. Аккуратно прикрепите модуль сенсора к пальцу при помощи эластичной резинки или лейкопластыря. Программа ждет ввод любого символа через терминал порта. Можно просто нажать клавишу <Enter>. Программа начнет накапливать выборки и через 4 секунды появятся пер- вые результаты. Если вы наблюдаете в окне монитора много заведомо недостовер- ных значений, значит, необходимо откорректировать положение сенсора. Возмож- но, придется перенести сенсор на другой палец или изменить силу прижима к коже.
ГЛАВА 12 Датчик общего качества воздуха Чистота окружающего воздуха — это один из наиболее важных критериев безопас- ности окружающей среды. Ведь мы непрерывно вдыхаем воздух в любое время су- ток и в любом месте. Более того, во время занятий спортом объем воздуха, который прокачивают наши легкие, возрастает в несколько раз. Вдыхание во время трени- ровки загрязненного опасными примесями воздуха может перечеркнуть всю пользу от занятий спортом и даже причинить вред. Воздух, которым мы дышим, всегда содержит примеси: частицы пыли, органиче- ские и неорганические молекулы, посторонние газы. Эти примеси не обязательно имеют искусственное происхождение, но в любом случае влияют на качество воз- духа и безопасность окружающей среды. Для детального анализа состава воздуха применяется очень сложное лабораторное оборудование, которое с трудом умещается в автофургон. Такие мобильные лабо- ратории регулярно ездят по улицам городов и берут пробы воздуха. Кроме того, существуют стационарные посты контроля качества воздуха. Но в быту нас в первую очередь интересует мониторинг качества воздуха, которым мы дышим в закрытом помещении: дома, в офисе, в учебной аудитории, в спортза- ле. Нам вполне по силам решить эту задачу при помощи современных интеграль- ных сенсоров, которые появились в массовой продаже несколько лет назад. С сенсором, который измеряет количество частиц пыли, мы познакомимся в гла- ве 13, а сейчас пойдет речь о датчике качества воздуха CCS811. 12.1. Устройство и характеристики сенсора CCS811 В миниатюрном корпусе интегрального сенсора CCS&11 (рис. 12.1) находятся тон- копленочный чувствительный элемент с горячей подложкой, аналого-цифровой преобразователь и встроенный контроллер. Сенсор предназначен для использования в устройствах Интернета вещей, очисти- телях воздуха, кондиционерах, контроллерах «умного дома», различных «умных» гаджетах и смартфонах.
Глава 12. Датчик, общего качества воздуха 225 Рис. 12.1. Современный интегральный сенсор CCS811 Сенсор с горячей подложкой работает по широко известному принципу: на изоли- рующую подложку нанесены электроды и полупроводящий чувствительный слой (обычно окись олова или органическая пленка) со специфическими примесями. Подложку нагревают до рабочей температуры — постоянно или только на время проведения замера. Когда молекула определяемого вещества попадает на поверх- ность чувствительного слоя, вокруг нее тут же образуется временная зона повы- шенной проводимости, и сопротивление сенсора уменьшается. Чем больше моле- кул попало на поверхность, тем меньше сопротивление чувствительного слоя. Состав примесей чувствительного слоя определяет, на какие молекулы будет реагировать сенсор. Поскольку подложка нагрета, молекулы вскоре покидают чув- ствительный слой. Это позволяет сенсору быстро реагировать на изменение кон- центрации молекул вещества в воздухе. Сенсоры с горячей подложкой успешно определяют наличие и концентрацию молекул газов (метан, пропан и т. д.), спиртов, бензина и других летучих органиче- ских веществ. Радиолюбителям и энтузиастам платформы Arduino хорошо известны недорогие датчики серии MQ китайского производства (рис. 12.2), но это устаревшие модели с высоким потреблением электроэнергии для разогрева сенсора, низкой точностью и узким назначением. Разумеется, во многих случаях необходимо иметь сенсор, который реагирует только на молекулы определенного вещества— например, алкоголя или пропана. Но если нас интересует общее качество окружающего воз- духа, то нам нужен сенсор, который чутко реагирует на разнообразные примеси. Отличительными особенностями сенсора CCS811 являются малые габариты, низ- кое энергопотребление, встроенный АЦП, встроенный микроконтроллер с интер- фейсом 12С и широкий перечень определяемых органических примесей. Факти- чески, в приборах для мониторинга общего качества воздуха один миниатюрный сенсор CCS811 заменяет десяток устаревших датчиков серии MQ.
226 Часть II. Теория и практика Рис. 12.2. Популярные датчики газов серии MQ Следует помнить, что сенсор CCS811 не различает органические вещества, которые присутствуют в воздухе, а лишь определяет их наличие и общую концентрацию. По- этому его называют датчиком общего качества воздуха. Впрочем, в большинстве устройств мониторинга окружающей среды нужен именно такой универсальный дат- чик — мы ведь не можем знать заранее, особенно в условиях крупного города, какое вещество будет загрязнять воздух завтра. Нам важно обнаружить сам факт загряз- нения, а точный предметный анализ — задача для профессиональной лаборатории. 12.1.1. Основные технические характеристики датчика качества воздуха CCS811 ♦ Габариты: 2,7x4,00x1,1 мм ♦ Напряжение питания: 1,8...3,6 В ♦ Максимальный рабочий ток: 54 мА ♦ Потребляемый ток в режиме сна: 19 мкА ♦ Частота шины 12С: 100 / 400 кГц ♦ Рабочая температура: -40...+85 °С ♦ Диапазон значений eTVOC: 0...32768 мкг/м3 (ppb, частей на миллиард) ♦ Диапазон значений еСО2: 400...32768 мг/м3 (ррт, частей на миллион) Сенсор определяет общее содерэюание летучих органических соединений (TVOC, Total Volatile Organic Compounds) в виде молекул спиртов, альдегидов, кетонов, органических кислот, аминов, алифатических и ароматических углеводов, а также эквивалентное расчетное количество двуокиси углерода (еСО2, equivalent calculated СО2).
Глава 12. Датчик общего качества воздуха 227 Что такое эквивалент двуокиси углерода? Наверняка вы знаете про парниковый эффект — накопление тепла за счет того, что некоторые газы в атмосфере Земли экранируют тепловое излучение земной поверх- ности и не дают теплу рассеиваться в окружающем космическом пространстве. Этот эффект приводит к глобальному потеплению, резкой смене климата и таянию ледни- ков. Газы, которые вызывают парниковый эффект, называют парниковыми газами. В число таких газов входит и двуокись углерода — СОг (углекислый газ). Но разные газы дают различный парниковый эффект. Поэтому в качестве удобной универсаль- ной единицы измерения «парниковой опасности» используют эквивалентное количе- ство СО2, которое вызывает аналогичный по силе эффект. Например, парниковый эффект от выброса в атмосферу метана в 25 раз сильнее, чем от СОг. Поэтому 1 кг метана окажет на атмосферу Земли такое же вредное воз- действие, как 25 кг двуокиси углерода. Встроенный микроконтроллер сенсора CCS811 автоматически пересчитывает об- щую концентрацию органических молекул в воздухе в эквивалентную по степени парникового эффекта концентрацию двуокиси углерода. Следует понимать, что это не фактическое содержание углекислого газа в воздухе, а условная единица измерения. Сенсор CCS811 может работать в одном из пяти режимов: ♦ Mode 0 — режим сна (низкого потребления энергии); ♦ Mode 1 — постоянный подогрев, измерение каждую секунду; ♦ Mode 2 — импульсный подогрев, измерение каждые 10 секунд; ♦ Mode 3 — экономичный импульсный подогрев, измерение каждые 60 секунд; ♦ Mode 4 — постоянный подогрев, измерение каждые 250 мс. 12.1.2. Внимание: особенности эксплуатации сенсора Показания сенсора очень сильно зависят от чистоты чувствительной поверхности. Сенсору требуется время, чтобы за счет нагрева очистить рабочую поверхность от попавших на чувствительный слой органических молекул и войти в рабочий ре- жим. Во время начальной подготовки (отжиг поверхности) показаниям сенсора нельзя доверять. Отжиг поверхности происходит в течение первых 48 часов экс- плуатации. Поэтому производитель настоятельно рекомендует после покупки включить сенсор в режим постоянного подогрева на 48 часов и не использовать его в это время для измерений. После длительного перерыва в измерениях, включая режим сна, необходимо подо- ждать 20 минут в рабочем режиме, пока показания сенсора не стабилизируются. Когда сенсор переходит в режим с меньшей частотой измерений (например, из режима Mode 1 в режим Mode 3) необходимо выдержать промежуточную паузу не менее 10 минут в режиме Mode 0 (ожидание), прежде чем включить новый режим. При переходе в режим с большей частотой измерений промежуточная пауза не требуется.
228 Часть II. Теория и практика 12.2. Модуль расширения CCS811 Для макетирования проектов этой книги использован модуль расширения, изобра- женный на рис. 12.3, но вы можете взять любой другой вариант платы с сенсором CCS811. Следует лишь обратить внимание на необходимость согласования логиче- ских уровней и на напряжение питания. Наш модуль — самый простой и недоро- гой, он не содержит цепей согласования уровней и стабилизатора питания. Поэтому мы должны подключать его только к цепям питания +3,3 вольта, а также добавить согласующие резисторы или конвертер логических уровней при работе с пятиволь- товой логикой Arduino (см. разд. 3.1). Рис. 12.3. Модуль сенсора CCS811 для Arduino 12.2.1. Назначение выводов модуля ♦ VCC — питание +3,3 вольта; ♦ GND — общий провод; ♦ SCL — линия тактовых импульсов шины 12С; ♦ SDA — линия данных шины 12С; ♦ WAK — вход управления спящим режимом. При подаче высокого логического уровня сенсор переходит в режим ожидания с пониженным энергопотреблени- ем. В рабочем режиме на этом входе должен быть низкий логический уровень; ♦ INT — выход сигнала прерывания по событию окончания измерения; ♦ RST — вход сброса по низкому логическому уровню. В обычном режиме под- тянут резистором к шине питания; ♦ ADD — вход выбора адреса на шине 12С. В этом модуле при высоком логиче- ском уровне адрес сенсора 90 (0х5А), при низком логическом уровне 91 (0х5В). В других вариантах платы модуля этот вывод может отсутствовать, а адрес же- стко задан или выбирается перемычкой.
Глава 12. Датчик общего качества воздуха 229 12.2.2. Установка библиотеки Arduino Запустите среду разработки Arduino IDE, перейдите в меню Инструменты | Управлять библиотеками | Менеджер библиотек и в строке поиска введите: CCS8H. В результатах поиска найдите библиотеку Adafruit ccssn Library и на- жмите кнопку Установить. 12.3. Подключение и проверка модуля Схема подключения модуля CCS811 к плате Arduino Uno R3 показана на рис. 12.4. Библиотека Adafruit ccs8ii по умолчанию настроена для работы с фирменным мо- дулем, который доступен по фиксированному адресу 90 (0х5А), поэтому вывод мо- дуля ADD (см. рис. 12.3) можно никуда не подключать — он уже подтянут к шине питания через установленный на плате резистор. Если вы хотите, чтобы модуль был доступен по адресу 91 (0х5В), то соедините вывод ADD с общим проводом, а в скетче укажите адрес модуля в явном виде в качестве аргумента метода begin (), как показано в листинге 12.1. Обратите внимание, что в разрыв линий SCL и SDA включены резисторы с номи- налом 1 кОм для согласования логических уровней шины 12С между трехвольто- вым модулем сенсора и пятивольтовой платой контроллера. Без этих резисторов схема работать не будет. R1.R2 1 кОм CCS811 Рис. 12.4. Схема подключения модуля CCS811 к Arduino Uno R3
230 Часть II. Теория и практика #include "Adafruit_CCS811.h" // Создаем объект сенсора Adafruit_CCS811 ccs; void setup() { Serial.begin(9600); Serial.println("CCS811 test"); // Инициализация сенсора с адресом по умолчанию 90 (0х5А) // Для сенсора по адресу 91 (0х5В) укажите его адрес //в явном виде: ccs.begin(0x5B) if (Iccs.beginO) { // Если сенсор недоступен, сообщаем об ошибке //и останавливаем выполнение программы Serial.printIn("Failed to start sensor! Please check your wiring.") while(1); void loopO { if(ccs.available()){ if(!ccs.readData()){ Serial.print("eCO2: "); Serial.print(ccs.geteCO2()); Serial.print("ppm, TVOC: "); Serial.print (ccs.getTVOCO ) ; } else{ Serial.println("ERROR!"); while(1); delay(500); Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). За основу проверочного кода взят свободно распространяемый пример из библио- теки Adafruit CCS8H. Основное отличие от исходного варианта состоит в том, что на фирменной плате Adafruit CCS811 установлен еще и компенсирующий терморе- зистор. Он предназначен для точной компенсации влияния температуры окружаю- щей среды, а значение температуры можно прочитать программно. На плате, пока-
Глава 12. Датчик общего качества воздуха 231 занной на рис. 12.3, терморезистора нет, поэтому попытка прочитать температуру будет возвращать бессмысленное значение. Соберите схему, загрузите прошивку в контроллер и запустите встроенный мони- тор порта Arduino IDE. Если в окне монитора начнут отображаться значения еССЬ, TVOC и температуры, значит, схема собрана правильно, и сенсор исправен. Теперь дайте датчику время на достижение рабочего режима. В идеале, после первого включения следует оставить сенсор непрерывно работать 48 часов, и лишь затем можно приступать к практическим измерениям. Впрочем, вряд ли хоть один радио- любитель обладает настолько сильным терпением... 12.4. Монитор качества воздуха с OLED-дисплеем Чтобы наш монитор качества воздуха превратился в портативное устройство, доба- вим в конструкцию OLED-дисплей. Электрическая схема соединения компонентов проекта представлена на рис. 12.5, а его макет — на рис. 12.6. Обратите внимание, что на этой схеме дисплей подключен к шине 12С напрямую, а модуль сенсора — через согласующие резисторы с номиналом 1 кОм. R1.R2 1 кОм CCS811 Рис. 12.5. Схема монитора общего качества воздуха с OLED-дисплеем
232 Часть II. Теория и практика Рис. 12.6. Макет монитора общего качества воздуха с OLED-дисплеем Исходный код скетча представлен в листинге 12.2. Код основан на открытом исходном коде примера Adafruit CCS811, но доработан для совместимости с новой версией графической библиотеки OLED-дисплея. I ■■ ■ ■ ■ ....... : Листинг ИЛ, Скотч ыпнт1€ф:л общего качеств?, воздуха с OLEO-^WwfMieeM #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include "Adafruit_CCS811.h" #define SCREEN_WIDTH 128 // Ширина дисплея в пикселах #define SCREEN_HEIGHT 64 // Высота дисплея в пикселах #define OLED_RESET -1 //В нашем дисплее нет вывода RESET Adafruit_CCS811 ccs; // Объект сенсора Adafruit SSD1306 oled(SCREEN WIDTH, SCREEN HEIGHT, &Wire, OLED RESET);
Глава 12. Датчик общего качества воздуха 233 void setup() { Serial.begin(9600); if (!ccs.begin(0x5A)) { Serial.println("Failed to start sensor! Pleasecheck your wiring."); while (1); oled.begin(SSD1306_SWITCHCAPVCC, ОхЗС); // Адрес дисплея ОхЗС // Очистка буфера дисплея oled.clearDisplay(); oled.display(); // Размер текста oled.setTextSize(l); oled.setTextColor(WHITE); void loop() { oled.setCursor(0, 0) ; if (ccs.available()) { oled.clearDisplay() ;; if (!ccs.readData()) { oled.print("eC02: "); Serial.print("eCO2: "); float eCO2 = ccs.geteCO2(); oled.print(eCO2); Serial.print(eCO2); oled.print(" ppm\nTVOC: ") ; Serial.print(" ppm, TVOC: ") float TVOC = ccs.getTVOC(); oled.print(TVOC); Serial.print(TVOC); Serial.println(" ppb"); oled.print(" ppb"); oled.display(); } else { Serial.println("ERROR!"); while (1); delay(500);
234 Часть II. Теория и практика Исходный код этой несложной программы не нуждается в пояснениях. По сути, он составлен из двух уже известных вам фрагментов: листинга 12.1 (работа с сенсо- ром) и листинга 5.8 (работа с OLED-дисплеем). 12.4.1. Опыты с измерителем качества воздуха Теперь вы можете провести ряд опытов, чтобы определить, какие вещества наибо- лее сильно загрязняют атмосферу и создают парниковый эффект: ♦ смочите ватку спиртом, духами или органическим растворителем и помашите ваткой в воздухе недалеко от сенсора. Значения еСОг и TVOC резко возрастут, но если убрать источник органических молекул, показания сенсора вернутся к исходным значениям. Это означает, что летучие молекулы органического вещества покинули нагретый чувствительный слой. Повторите опыт с бензином и малярными растворителями. Проводите эти опыты в помещении с хорошей вентиляцией, чтобы пары растворителя не мешали проводить следующие опы- ты, а вы не вдыхали пары вредных веществ; ♦ подуйте с близкого расстояния на сенсор. Показания сенсора увеличатся. В вы- дыхаемом воздухе содержатся естественные примеси органических веществ, которые образуются в результате процессов метаболизма в человеческом орга- низме; ♦ распылите в помещении бытовой аэрозоль — например, лак для волос или ос- вежитель воздуха. Следите, чтобы частицы аэрозоля не попали внутрь сенсора! Через некоторое время сенсор отреагирует на молекулы ароматических веществ, а также на пропеллент — газ, который закачан в баллон для создания избыточ- ного давления и улучшения распыляемое™ аэрозоля. Традиционно в качестве пропеллента ранее применяли пропан или фреон, но эти газы наносят серьезный ущерб атмосфере и усиливают парниковый эффект. В современных аэрозолях стараются применять менее опасные пропелленты; ♦ поместите вблизи сенсора различные спелые фрукты и овощи (бананы, груши, помидоры). Какие плоды вызывают наиболее сильный отклик? ♦ по возможности проведите измерения в различных производственных поме- щениях: автомастерской, парикмахерской, рекламной мастерской, химической лаборатории, офисном помещении. 12.4.2. Задание для самостоятельной работы над проектом Доработайте электрическую схему и скетч таким образом, чтобы сенсор «просы- пался» один раз в минуту, выполнял несколько измерений подряд с усреднением результата и снова «засыпал».
Глава 12. Датчик общего качества воздуха 235 12.5. Онлайн-мониторинг качества воздуха Для дистанционного мониторинга качества воздуха мы вновь воспользуемся он- лайновой панелью Adafruit IO (см. разд. 5.2). Источником данных для панели в на- шем проекте послужит плата контроллера NodeMCU на базе ESP8266. С равным успехом можно использовать любые другие способы подключения Arduino к сети Интернет, рассмотренные в главе 4. Параллельно с передачей данных в сеть результаты измерений будут отображаться на OLED-дисплее. Войдите в учетную запись Adafruit IO и создайте два потока данных с именами: еС02 и tvoc. Затем создайте приборную панель с названием AirQuaiity. Напоминаю, что сервис Adafruit IO ограничивает число потоков и приборных панелей, но к од- ному потоку можно подключить неограниченное количество приборов внутри па- нели. Мы подключим к каждому потоку как круговой индикатор для отображения текущих значений, так и графопостроитель для наблюдения за долгосрочными ко- лебаниями уровня органических примесей в воздухе. При настройке индикаторов следует учитывать диапазоны возможных значений TVOC: от 0 до 32 768 и еСС^: от 400 до 32 768. Впрочем, для обычной городской квартиры можно ограничиться максимальным значением 10 000, иначе показания индикаторов на панели будут лишь незначительно отклоняться от начального уровня. Рис. 12.7. Пример приборной панели онлайн-монитора качества воздуха
236 Часть II. Теория и практика Рис. 12.8. Схема подключения сенсора CCS811 и OLED-дисплея к NodeMCU Рис. 12.9. Макет онлайн-монитора качества воздуха на основе NodeMCU
Глава 12. Датчик общего качества воздуха 237 На рис. 12.7 изображен пример расположения элементов приборной панели, кото- рую я создал в своей учетной записи. Подключите модуль сенсора и OLED-дисплей к плате NodeMCU или аналогичной плате контроллера на базе ESP8266, как показано на рис. 12.8. В данном случае со- гласующие резисторы 1 кОм на шине 12С не нужны, т. к. у ESP8266 трехвольтовые логические уровни. Пример макета онлайн-монитора качества воздуха показан на рис. 12.9. 12.5.1. Проблема совместимости ESP8266 и CCS811 При подключении сенсора CCS811 к плате ESP8266 возникает проблема совмести- мости с шиной 12С. Дело в том, что в ESP8266 реализована программная эмуляция шины 12С, которая, в отличие от аппаратной реализации Arduino, плохо поддержи- вает затягивание тактов. Что такое затягивание тактов на шине 12С? Ведущее устройство (контроллер) не обладает исключительным правом на управле- ние шиной. Если ведомое устройство не успевает обработать полученный бит или байт, оно может принудительно удерживать линию тактирования SCL в низком уровне. Например, иногда бывает так, что ведомое устройство может получать байты дан- ных или команд с большой скоростью, но ему требуется время, чтобы обработать полученный байт. В этом случае ведомое устройство «отпускает» линию SCL из низ- кого уровня только после завершения обработки — затягивает последний тактовый импульс байта на нужное время. Аппаратная реализация шины 12С поддерживает затягивание тактов естественным образом. Но при программной ее эмуляции постоянная проверка состояния линии SCL (даже когда это не требуется) существенно замедляет работу шины и устройст- ва в целом. Проблема совместимости выражается в том, что при подключении сенсора CCS811 к любому контроллеру на базе ESP8266 происходит зависание сенсора в произ- вольные моменты времени. После зависания требуется выполнить аппаратный сброс сенсора при помощи вывода RES или отключением питания. Причина зави- сания в том, что иногда встроенный микроконтроллер сенсора не успевает обрабо- тать полученную команду, пытается затянуть такт, но ESP8266 это «не понимает» и продолжает передачу. В итоге сенсор зависает, а скетч вместо результатов изме- рений выдает сообщение об ошибке. В принципе, в такой ситуации можно предусмотреть аппаратный сброс сенсора че- рез отдельный порт GPIO ESP8266, но полагаться только на сброс сенсора — это не самое лучшее решение. Ведь сенсор при зависании полностью блокирует работу шины 12С, и если к шине подключены другие устройства, они тоже будут недос- тупны, пока сенсор не пройдет цикл сброса и повторной инициализации. В библиотеке wire предусмотрен метод setciockstretchLimit (). Параметром этого метода является интервал в микросекундах, в течение которого контроллер согла- сен ждать, если ведомый затянет такт. Для сенсора CCS811 вполне достаточно ин- тервала 500 мкс. Разработчики компании Adafruit добавили в библиотеку сенсора
238 Часть И. Теория и практика CCS811 строку setciockstretchLimit (500), и на какое-то время это решило пробле- му. Но после очередного обновления библиотеки wire вызов этого метода перестал работать. Соответственно, все программы, скомпилированные с новой версией библиотеки wire, вновь стали приводить к зависанию сенсора. Мы применим более замысловатое, но более надежное решение, которое не зависит от обновления библиотеки wire — внесем небольшое изменение в один из файлов ядра описания платы ESP8266 для Arduino IDE. Внимательно выполните все пред- ложенные действия: 1. Откройте окно проводника Windows. В адресную строку введите следующий путь: C:\Users\/■userлaine7\AppData\Local\Arduinol5\packages\esp82бб\hardware\esp82бб 2. Подставьте в этот путь вместо [usemame] свое имя пользователя в системе Windows. Нажмите клавишу <Enter>. Вы должны попасть в каталог, в котором хранится единственный подкаталог с номером версии ядра ESP8266. На момент работы над книгой это была версия 2.4.2 (у вас может оказаться более новая вер- сия). Внутри этого каталога откройте каталог cores, далее каталог esp8266 и най- дите в нем файл core_esp8266_si2c.c. 3. Откройте этот файл при помощи неформатирующего редактора для программи- стов — например, Notepad++. 4. Найдите строку: twi_setClockStretchLimit(230) и исправьте в ней значение 230 на 50о. Сохраните файл. Теперь сенсору будет хватать времени на обработку команд контроллера. 5. Если вам не удается найти файл по указанному пути, просто введите имя файла core_esp8266_si2c.c в поле поиска проводника Windows. Если он найдет не- сколько файлов с таким именем в разных местах, отредактируйте их все. После следующего обновления версии ядра ESP8266 для Arduino IDE ваша правка может быть утрачена, и придется вновь найти и исправить файл. Если вдруг после обновления скетча сенсор начал зависать, проверьте значение лимита затягивания в файле core_esp8266_si2c.c. Теперь мы готовы скомпилировать скетч и загрузить прошивку в ESP8266. Исход- ный код скетча приведен в листинге 12.3. #include "AdafruitIO_WiFi.h" // Библиотека Adafruit 10 для Wi-Fi #include <Wire.h> // Библиотека поддержки I2C/TWI #include <Adafruit_GFX.h> // Графическое ядро #include <Adafruit_SSD1306.h> // Драйвер OLED #include "Adafruit_CCS811.h" // Библиотека сенсора
Глава 12. Датчик общего качества воздуха 239 II Имя пользователя сервиса Adafruit 10 #define IOJJSERNAME "reedpaper_com" // Главный ключ сервиса Adafruit 10 #define IO_KEY lfb3557fb49bd94192bd547bb2al6c615cfl // Имя вашей сети Wi-Fi #define WIFI_SSID "Rover" // Пароль вашей сети Wi-Fi #define WIFI_PASS flprst4xv8" // Конструктор подключения к Adafruit 10 AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS) ; #define SCREEN_WIDTH 128 // Ширина дисплея в пикселах #define SCREEN_HEIGHT 64 // Высота дисплея в пикселах #define OLED_RESET -1 //В нашем дисплее нет вывода RESET Adafruit_CCS811 ccs; // Объект сенсора // Объект дисплея Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREENJiEIGHT, &Wire, OLED_RESET); // Объявляем объекты потоков с их ключами AdafruitIO_Feed *eC02_feed = io.feed("eC02"); AdafruitIO_Feed *TVOC_feed = io.feed("TVOC"); void setup() { Serial.begin(9600); oled.begin(SSD1306_SWITCHCAPVCC, ОхЗС); // Адрес дисплея ОхЗС // Очистка буфера дисплея oled.clearDisplay(); oled.display(); oled.setTextSize(1); // Размер текста oled.setTextColor(WHITE); // Цвет текста if (!ccs.begin(0х5А)) { oled.setCursor(0, 0) ; oled.print("Sensor failed"); oled.display(); Serial.println("Failed to start sensor! Please check your wiring."); while (1); Serial.println("Connecting to Adafruit 10") oled.setCursor(0, 0);
240 Часть II. Теория и практика oled.println("Connecting to AIO"); oled.display(); // Подключаемся к io.adafruit.com io.connect(); // Ожидаем подключение while (io.status() < AIO_CONNECTED) { Serial.print("."); oled.print(".") ; oled.display() ; delay(500); // Отладочное сообщение о подключении в монитор порта Serial.println(io.statusText()) ; void loop() { // Вызов метода io.runO; требуется в КАВДОМ скетче //и должен быть первой строкой цикла 1оор() // Вызов поддерживает соединение с io.adafruit.com //и обрабатывает входящие данные. io.run(); oled.setCursor(0, 0); if (ccs.available()) { oled.clearDisplay(); if (!ccs.readData()) { oled.print("eC02: "); Serial.print("eC02: "); float eC02 = ccs.geteC02(); // Получаем значение еС02 eC02_feed->save(eC02); // Выводим еС02 в поток oled.print(eC02); Serial.print(eC02); oled.print(" ppm\nTVOC: ") ; Serial.print(" ppm, TVOC: "); float TVOC = ccs.getTVOC(); // Получаем значение TVOC TVOC_feed->save(TVOC); // Выводим TVOC в поток oled.print(TVOC); Serial.print(TVOC); Serial.println(" ppb"); oled.print(" ppb"); oled.display();
Глава 12. Датчик общего качества воздуха 241 else { Serial.println("ERROR!"); while (1); // Нельзя отправлять в потоки более 30 значений в минуту, // поэтому для двух потоков делаем паузу 4 секунды delay(4000); } Если инициализация сенсора по какой-то причине не удалась, на экран выводится сообщение Sensor failed, и программа зацикливается. При этом встроенный сторо- жевой таймер ESP8266 один раз в секунду перезагружает контроллер, и попытка активации сенсора повторяется. Если сенсор успешно инициализирован, происходит подключение к сервису АЮ. После подключения на дисплее начинают отображаться результаты измерений, параллельно данные поступают в потоки приборной панели АЮ. 12.5.2. Задание для самостоятельной работы В скетче из листинга 12.3 не предусмотрена обработка аварийных ситуаций: пре- рывания связи с сервисом АЮ и зависания сенсора. 1. Доработайте скетч так, чтобы он периодически проверял состояние соединения с АЮ и в случае внезапного разрыва связи выводил сообщение на экран и пы- тался восстановить связь. Для проверки статуса соединения используйте метод io.status о, который возвращает 1 при наличии соединения. 2. Доработайте схему подключения сенсора и скетч таким образом, чтобы при зависании сенсора через один из портов GPIO ESP8266 на вход сенсора RST по- ступал импульс сброса (низкий уровень), а затем происходила повторная ини- циализация сенсора. В исходном скетче присутствует проверка доступности сенсора при помощи метода ccs. available (), но в случае сбоя лишь выводится сообщение об ошибке в терминал. Как вы думаете, почему не всегда получится выводить сообщение о сбое сенсора на OLED-дисплей?
ГЛАВА 13 Измерение пыльности и дымности воздуха В производственных условиях часто осуществляется непрерывный мониторинг пыльности воздуха. Это необходимо делать в покрасочных и сушильных камерах, при производстве зеркал и интегральных микросхем — в любом производстве, где частицы пыли могут испортить готовую продукцию. На некоторых производствах: мельницы, столярные мастерские— смесь горючей пыли с воздухом может вы- звать взрыв и пожар. Кроме производственного процесса, мониторинг пыльности воздуха необходим для охраны здоровья персонала, постоянно работающего в помещениях, прилегающих к пыльному производству (например, на цементных заводах, деревообрабатываю- щих или асбесто-графитовых фабриках). Впрочем, мониторинг пыльности не будет лишним и для городской квартиры, особенно весной и летом, когда воздух напол- . нен уличной пылью и пыльцой растений — это сильные аллергены. Размер пыли характеризуется диаметром частиц в микронах (микрометрах, мкм). Частицы с размером менее 2,5 мкм (РМ2.5) называют взвешенными частицами, поскольку они медленно оседают под действием собственного веса и могут очень долго витать в воздухе. Также их называют тонкодисперсными частицами. Взве- шенные микрочастицы наиболее опасны для человеческого организма, потому что глубоко проникают в самые мелкие бронхи и остаются в легких, вызывая хрониче- ские заболевания. Частицы с диаметром менее 10 мкм (РМ10) чаще всего представляют собой пыльцу растений, частицы сажи и т. п. Такие частицы легко проникают в верхние дыха- тельные пути и тоже вызывают различные заболевания. Наименее опасна крупная домашняя пыль, которая видна невооруженным глазом и быстро оседает из воз- духа. Концентрация пыли обычно измеряется в мг/м3 или мкг/м3. При точных лабораторных исследованиях качества воздуха применяют специаль- ные фильтры и определяют размеры и количество частиц пыли, осевших на квад- ратный сантиметр поверхности фильтра, при помощи микроскопа. Но такой метод не подходит для постоянного мониторинга и быстрой оценки пыльности. Для изме-
Глава 13. Измерение пыльности и дым ноет и воздуха 243 рений на производстве и в быту нужен простой прибор, способный измерять коли- чество частиц пыли в воздухе быстро и с достаточной точностью. Принцип работы датчика пыли очень прост и схематически изображен на рис. 13.1. Светодиод и фотодиод направлены на рабочую зону под одинаковым углом. Час- тицы пыли или дыма, попавшие в луч света, отражают и рассеивают свет в сторону фотоприемника. На выходе фотоприемника возникает электрическое напряжение, которое линейно зависит от количества пылинок, попавших в луч света. Затем вы- ходной сигнал фотоприемника может быть усилен, отфильтрован от шумов и изме- рен встроенным или внешним контроллером. Источник света Фотоприемник Рабочая зона с частицами пыли Рис. 13.1. Принцип действия датчика пыли 13.1. Датчик пыли SHARP GP2Y1014AU0F Для проектов по измерению пыльности воздуха можно приобрести современный и недорогой датчик пыли SHARP GP2Y1014AU0F, который применяется в промыш- ленном и бытовом оборудовании (кондиционеры, вентиляторы, системы подачи воздуха). Рекомендую приобрести набор, состоящий из датчика, соединительных проводов, электролитического конденсатора и резистора (рис. 13.2). Резистор и конденсатор нужны для цепи питания источника света (светодиода). В кожухе датчика имеется большое круглое отверстие, через которое в его рабочую зону проникает окружающий воздух с частицами пыли. Под кожухом находится плата со схемой усиления и обработки сигнала, а также рабочая зона и оптическая система датчика (рис. 13.3). Обратите внимание на наклонные пластиковые перегородки возле рабочей зоны. Они образуют оптическую ловушку, чтобы свет, отразившийся от стенок сенсора, как можно меньше попадал в фотоприемник. Датчик измеряет только общую концентрацию пыли и не может различать состав пыли по размеру частиц. Тем не менее есть возможность отличать домашнюю пыль от дыма. Об этом мы поговорим позже.
244 Часть II. Теория и практика Рис. 13.2. Датчик пыли GP2Y1014AU0F и дополнительные компоненты Рис. 13.3. Оптическая система и рабочая зона датчика пыли 13.1.1. Основные технические характеристики датчика пыли GP2Y1014AU0F ♦ Минимальный размер частицы: 0,5 мкм ♦ Диапазон измерения: до 580 мг/м3 ♦ Время измерения: < 1 сек ♦ Тип выходного сигнала: аналоговый ♦ Выходное напряжение при отсутствии частиц: 0,1... 1,1 вольт ♦ Чувствительность: 0,5 вольта на каждые 100 мкг/м3 ♦ Точность: ±15% ♦ Напряжение питания: +5 вольт
Глава 13. Измерение пыльности и дымности воздуха 245 13.1.2. Воздушный поток через датчик Чтобы датчик оперативно реагировал на изменение концентрации пыли, желатель- но обеспечить постоянное движение воздушного потока через его рабочую зону. Если датчик встроен в бытовой прибор: кондиционер, вентилятор, нагреватель — то движение потока воздуха легко обеспечивается естественным образом. При автономном применении датчика поток воздуха несложно создать при помощи миниатюрного вентилятора (шумно, дорого) или при помощи небольшого нагрева- тельного элемента, расположенного под отверстием рабочей зоны. В качестве на- гревателя можно использовать миниатюрную лампу накаливания или керамиче- ский резистор. Недостаток такого метода — высокий потребляемый ток. Впрочем, допускается обойтись и без принудительного ускорения потока воздуха, но тогда датчик будет медленно реагировать на изменение пыльности. Производитель также рекомендует использовать защитный фильтр от крупных час- тиц пыли, которые могут оседать внутри датчика и повышать погрешность измере- ния. Не продувайте датчик от скопившейся пыли — вы можете засорить оптиче- скую систему! Для периодической очистки датчика лучше использовать пылесос с умеренным уровнем вакуума. 13.1.3. Управление подсветкой Для надежной регистрации частиц пыли светодиод должен излучать достаточно мощный поток света. Но светодиоды, работающие в режиме максимального излу- чения, быстро теряют излучающую способность. Поэтому в датчике пыли органи- зован импульсный режим подсветки с короткими импульсами. Такой режим значи- тельно продлевает срок службы светодиода и экономит электроэнергию. В схеме датчика имеется транзисторный ключ для управления светодиодом. Управляющие импульсы должны поступать с внешнего контроллера, который включает светоди- од, измеряет напряжение на выходе датчика и гасит светодиод. Через некоторое время рабочий цикл повторяется. В комплект датчика для Arduino входят: резистор с сопротивлением 150 Ом — для ограничения тока через светодиод, а также элек- тролитический конденсатор — для сглаживания пульсаций питающего напряжения в цепи питания светодиода. Резистор рассчитан на напряжение питания 5 вольт. Это важные компоненты, без них датчик не будет работать. Подключение светодиода к источнику питания 5 вольт без гасящего резистора при- ведет к поломке датчика! Требования к параметрам измерительного цикла указаны в техническом описании датчика и отображены на соответствующей диаграмме (рис. 13.4). Необходимо как можно точнее соблюдать эти требования, иначе датчик не будет работать пра- вильно. Длительность вспышки светодиода должна составлять 0,32±0,02 мс. Вспышки должны повторяться с периодом 10±1 мс. Внешний контроллер включает светоди- од подсветки, спустя 0,28 мс выполняет измерение напряжения на выходе датчика и гасит светодиод после окончания измерения. Спустя 10 мс контроллер повторяет цикл измерения.
246 Часть //. Теория и практика т = ю мс Pw = 0,32 мс Импульс света Светодиод Выходное напряжение Измерение Рис. 13.4. Диаграмма измерительного цикла датчика пыли 13.1.4. Назначение выводов датчика пыли Расположение выводов датчика показано на рис. 13.5. ♦ 1. V-LED — питание светодиода (+5 вольт — через резистор 150 Ом!); ♦ 2. LED-GND — «земля» светодиода; ♦ 3. LED — управление светодиодом (низкий уровень); ♦ 4. S-GND — «земля» датчика; ♦ 5. Vo — выход датчика; ♦ 6. Vcc — питание датчика (+5 вольт). Рис. 13.5. Расположение выводов датчика пыли GP2Y1014 Предупреждение! Не обращайте внимания на цвет проводов соединительного кабеля. Цвет проводов ничего не означает, и в разных экземплярах датчиков цвета проводников могут сле- довать в разном порядке. При монтаже учитывайте только номера контактов. 13.1.5. Монтаж датчика пыли Производитель рекомендует монтировать датчик на вертикальной поверхности та- ким образом, чтобы провода разъема были направлены вниз. В таком положении линзы оптической системы окажутся вверху, и на них не будет оседать пыль. Дат- чик можно приклеить к монтажной поверхности на двусторонний скотч.
Глава 13. Измерение пыльности и дымности воздуха 247 Не забудьте обеспечить свободную циркуляцию воздуха через отверстия датчика. Следует также избегать попадания внутрь датчика прямого света. 13.2. Подключение датчика пыли к плате Arduino Электрическая схема подключения датчика пыли к плате контроллера Arduino Uno представлена на рис. 13.6, а вариант внешнего вида макета— на рис. 13.7. Макет- 220 мкФ 10...25 В Рис. 13.6. Схема подключения датчика пыли к Arduino Uno Рис. 13.7. Внешний вид макета измерителя пыльности воздуха
248 Часть II. Теория и практика ная плата нужна лишь для того, чтобы подключить резистор и конденсатор в цепи питания светодиода. 13.3. Демонстрационный скетч и калибровка датчика Исходный код скетча, при помощи которого мы познакомимся на практике с рабо- той датчика пыли, приведен в листинге 13.1. За основу скетча взят фирменный открытый демокод, доступный по адресу https://github.com/sharpsensoruser/sharp-sensor-demos/blob/master/ Sharp_gp2y1014au0f_demo/sharp_gp2y1014au0f_demo.ino. Напомню также, что исходные коды программ (листинги), приведенные в книге, мож- но найти в сопровождающем ее электронном архиве (см. приложение 1). // Подключение датчика: GP2Y1014 V-LED LED-GND LED S-GND Vo Vcc Arduino Между Rl и Cl Cl и GND Вывод D7 GND A5 5V // Выводы Arduino const int sharpLEDPin =7; // Управление включением светодиода const int sharpVoPin = A5; // Аналоговый вход сигнала с датчика // Усреднение N измерений #define N 100 static unsigned long VoRawTotal = 0; static int VoRawCount = 0; // Начальное напряжение на выходе датчика // при отсутствии пыли, вольт static float Voc = 0.6; // Типовая чувствительноть, вольт на 100 мкг/м3. const float К = 0.5; void setup() { // Управляющий вывод настраиваем, как выход pinMode(sharpLEDPin, OUTPUT);
Глава 13. Измерение пыльности и дымности воздуха 249 Serial.begin(9600); Serial.printlnC") ; Serial.println("GP2Y1014AU0F Demo"); Serial.println("=================")• void loopO { // Включаем светодиод датчика (низким уровнем) digitalWrite(sharpLEDPin, LOW); // Ждем 0,28 мс после включения светодиода delayMicroseconds(280); // Считываем выходное напряжение датчика // Эта операция занимает около 100 микросекунд int VoRaw = analogRead(sharpVoPin); // Гасим светодиод датчика digitalWrite(sharpLEDPin, HIGH); // Выдерживаем паузу для завершения цикла 10 миллисекунд //с учетом ранее затраченного времени delayMicroseconds(9620); // 10000 - 280 - 100 мкс // Усредняем результаты N измерений float Vo = VoRaw; VoRawTotal += VoRaw; VoRawCount++; if ( VoRawCount >= N ) { // Если выполнено N' измерений Vo = 1.0 * VoRawTotal / N; VoRawCount = 0; VoRawTotal = 0; } else { return; // Вычисляем выходное напряжение в милливольтах //и выводим напряжение в монитор Vo = Vo / 1024.0 * 5.0; Serial.print("Vo=" + String (Vo *'1000) + " mV, "); // Отнимаем начальное напряжение от измеренного напряжения // Если получилась отрицательная величина, корректируем // значение начального напряжения float dV = Vo - Voc; if ( dV < 0 ) { dV = 0;
250 Часть II. Теория и практика Voc = Vo; // Вычисляем концентрацию пыли, мкг/м3 //и выводим концентрацию в монитор float dustDensity = dV / К * 100.0; Serial.println("DustDensity=" + String (dustDensity) + " ug/m3"); В программе мы включаем светодиод подсветки, ждем 0,28 мс (280 микросе- кунд)— в соответствии с диаграммой, показанной рис. 13.4, затем считываем на- пряжение на выходе датчика и гасим подсветку. Программа выполняет N измерений с интервалом 10 мс и вычисляет среднее ариф- метическое. По умолчанию N = 100. Затем усредненный результат измерений пере- считывается в напряжение и вычисляется концентрация пыли в воздухе. Загрузите скетч в контроллер Arduino. Если вы правильно подключили датчик, и он исправен, то в окне монитора появятся приблизительно такие результаты измере- ний, какие показаны на рис. 13.8. Если потрясти возле датчика листом газетной бумаги или потереть ладонь о ладонь, показания датчика заметно возрастут. Рис. 13.8. Результаты измерения концентрации пыли в воздухе жилой комнаты Процесс оцифровки напряжения на аналоговом входе у микроконтроллеров Atmel занимает около 100 мкс. Поэтому общая продолжительность свечения светодиода получается немного больше, чем сказано в руководстве: 0,38 мс вместо 0,32 мс. Но такое незначительное увеличение длительности импульса не вредит датчику и не влияет на точность измерений. А Начинающие разработчики часто забывают, что встроенный аналого-цифровой пре- '^ образователь плат Arduipo не срабатывает мгновенно, и пока не завершено выпол- нение команды anaiogRead, никакие другие команды контроллера не выполняются. Если вы хотите, чтобы преобразование происходило быстрее и не влияло на выпол- нение кода программы, используйте внешний быстродействующий АЦП с интерфей-
Глава 13. Измерение пыльности и дымности воздуха 251 сом I2C или SPI и выходом прерывания по готовности данных. В этом случае вы мо- жете дать команду внешнему модулю на оцифровку входной выборки, а результат прочитать позже. 13.3.1. Начальное напряжение и калибровка Даже при полном отсутствии пыли в воздухе на выходе датчика присутствует не- которое напряжение за счет попадания в фотоприемник отраженного света, а также из-за собственного шума фотоприемника. Согласно техническому описанию, на- чальное напряжение voc = 0,6 вольта. Чтобы получить правильный результат изме- рения, нужно из измеренного напряжения вычесть начальное напряжение: dV = Vo - Voc В процессе транспортировки и эксплуатации датчика может происходить дрейф начального напряжения в большую или меньшую сторону. Проще всего обнару- жить дрейф в меньшую сторону. Если результат dv получился отрицательным, зна- чит за новое значение voc мы принимаем измеренное значение vo. Таким образом поисходит автокалибровка в меньшую сторону. Это неидеальный метод, но он ра- ботает с приемлемой точностью. Если же датчик завышает начальное напряжение (например, при отсутствии пыли на самом деле выдает 0,7 вольта, а вы используете в расчетах voc = 0,6 вольта), этот факт трудно обнаружить автоматически и отли- чить от напряжения при наличии пыли. На плате датчика имеется потенциометр, который используется при заводской на- стройке собранного датчика. Тем не менее производитель не рекомендует само- стоятельно менять настройку датчика — лучше выполнять калибровку и подстрой- ку программно, при помощи подбора константы начального напряжения. Для калибровки датчика можно воспользоваться профессиональным оборудовани- ем для измерения пыльности воздуха или выполнить приблизительную калибровку самостоятельно. Для бытовых условий приблизительной калибровки будет доста- точно. Заклейте все отверстия датчика скотчем и подключите датчик к плате кон- троллера. Включите питание датчика и оставьте его лежать неподвижно минимум в течение суток. Затем, не двигая датчик, зафиксируйте показания. Даже при гер- метично закрытых отверстиях в рабочей зоне датчика может присутствовать неко- торое количество взвешенной пыли, поэтому нет смысла подбором константы voc добиваться стабильно нулевых показаний пыльности. Помните, что собственная погрешность датчика составляет 15%, а фотоприемник генерирует шум даже при отсутствии пыли. 13.4. Определение наличия дыма в воздухе Датчик GP2Y1014 реагирует на частицы пыли размером более 0,5 мкм, а размеры частиц дыма обычно не превышают 0,1 мкм. Тем не менее датчик реагирует на присутствие дыма в воздухе. Когда частиц дыма в рабочей зоне достаточно много, они тоже отражают свет в фотоприемник. Но характер отражения и, соответствен-
252 Часть II. Теория и практика но, характер выходного сигнала при наличии дыма существенно отличается от сиг- нала при наличии бытовой пыли1. Частицы пыли имеют разные размеры и хаотично перемещаются в рабочей зоне. Поэтому выборки напряжения на выходе датчика меняются столь же хаотично и в относительно большом интервале (по этой причине при измерении пыльности усредняют большое количество выборок). Частицы дыма более однородны и рав- номерно заполняют рабочую зону, поэтому на выходе мы получаем приблизитель- но одинаковые выборки. Но ведь наличие дыма не означает отсутствие пыли. В реальных условиях вместе с дымом в воздухе все равно будут присутствовать частицы пыли, поэтому на фоне относительно равномерных выборок, сформированных микрочастицами дыма, будут наблюдаться выбросы, вызванные частицами пыли, которые витают в возду- хе вместе с дымом. Более надежным индикатором наличия дыма является не отсутствие пиковых зна- чений, а отсутствие глубоких «провалов» между пиками. Хотя на выходе датчика присутствуют выборки с большими значениями, вызванные отражением света от частиц пыли, в целом при наличии дыма уровень напряжения на выходе датчика не опускается ниже некоторой «дымовой составляющей». Наш алгоритм обнаружения дыма будет следующим: 1. Выполняем серию из n измерений и сохраняем выборки в массив. 2. Сортируем значения массива по возрастанию. 3. Отбрасываем м первых наименьших и м последних наибольших значений выбо- рок, чтобы отсечь влияние случайных помех, из-за которых уровень выходного сигнала мог оказаться аномально низким или высоким. В этом алгоритме мы не используем максимальные значения для обнаружения дыма, но в целом отбрасывание крайних значений с обеих сторон диапазона яв- ляется одним из обязательных приемов статистической обработки результатов измерений. 4. Поскольку массив уже отсортирован по возрастанию, если первое из оставшихся значений массива превышает пороговое значение D, значит, и все остальные выборки тоже превышают уровень D, что говорит о наличии дыма. Если же, несмотря на отбрасывание м минимальных значений, оставшиеся выборки все равно опускаются ниже уровня D, значит, на выходе датчика присутствует толь- ко хаотичный «пылевой» сигнал с провалами между выборками. Алгоритм требует подбора значений n, м и d опытным путем на основании экспе- риментов при различных условиях пыльности и дымности воздуха. Для получения экспериментальных данных воспользуемся скетчем из листинга 13.2. Но перед тем 1 Здесь и далее мы говорим только про обычную бытовую пыль. Мелкодисперсную промышленную пыль очень трудно отличить от дыма без применения специальных датчиков с несколькими диапазо- нами длины волны подсветки или радиоизотопных датчиков.
Глава 13. Измерение пыльности и дым ноет и воздуха 253 как приступить к экспериментам, подготовим инструменты для визуализации и об- работки результатов измерений. Для построения столбчатой диаграммы результатов измерений мы применим гра- фопостроитель программы Microsoft Excel, который нагляден, удобен и обладает множеством настроек. Таблица будет автоматически заполняться данными при помощи плагина PLX-DAQ, о котором рассказано ъразд. 5.1.4. II Скетч предназначен для работы с плагином Excel PLX-DAQ // http://forum.arduino.cc/index.php?topic=437398.0 // Выводы Arduino const int sharpLEDPin =7; // Управление включением светодиода const int sharpVoPin = A5; // Аналоговый вход сигнала с датчика const int Voc = 400; // Начальное напряжение (мВ) при отсутствии пыли #define N 100 // Количество выборок void setup() { // Управляющий вывод настраиваем, как выход pinMode(sharpLEDPin, OUTPUT); Serial.begin(9600); Serial.println("CLEARSHEET"); // Очистка рабочего листа Excel // Первый "холостой" импульс светодиода подсветки digitalWrite(sharpLEDPin, LOW); delayMicroseconds(320); digitalWrite(sharpLEDPin, HIGH); delayMicroseconds(10000) ; for (int i = 0; i < 100; i++) { // Включаем светодиод датчика (низким уровнем) digitalWrite(sharpLEDPin, LOW); // Ждем 0,28 мс после включения светодиода delayMicroseconds(280); // Считываем выходное напряжение датчика // Эта операция занимает около 100 микросекунд int VoRaw = analogRead(sharpVoPin); // Гасим светодиод датчика digitalWrite(sharpLEDPin, HIGH);
254 Часть II. Теория и практика // Выдерживаем паузу для завершения цикла 10 миллисекунд //с учетом ранее затраченного времени delayMicroseconds(9620); // 10000 - 280 - 100 мкс // Вычисляем выходное напряжение в милливольтах //и выводим значение выборки в таблицу int Vo = (VoRaw / 1024.0 * 5.0) * 1000 - Voc; Serial.println((String) "DATA," + Vo) ; void loop() { В этом скетче начальное значение напряжения voc при отсутствии пыли принято по умолчанию на уровне 400 милливольт и соответствует экземпляру датчика, с кото- рым автор проводил эксперименты при работе над книгой. Вам необходимо опре- делить начальное напряжение своего датчика. Для этого сначала проведите калиб- ровку, как сказано в разд. 13.3.1, и определите величину начального напряжения при отсутствии пыли. Затем подставьте значение начального напряжения в код программы. При работе с датчиком обнаружено, что значение первой выборки в цикле измере- ний отличается очень большой погрешностью. Это связано с тем, что в датчик встроен фильтр низкой частоты, который входит в рабочий режим только при строго заданной периодичности импульсов подсветки. Поэтому результат первого измере- ния после долгого перерыва недостоверен. Это не имеет значения, если измерения ведутся непрерывно в течение длительного времени. Но если мы выполняем корот- кий цикл измерений с большим интервалом между циклами, то первую выборку цик- ла лучше отбросить. Поэтому в скетче предусмотрена «пустая» выборка (импульс подсветки) непосредственно перед началом рабочего цикла измерений. Программа выполняет цикл из n = юо измерений в строгом соответствии с техни- ческим руководством датчика и выводит результаты измерений в последователь- ный порт в формате плагина PLX-DAQ. 13.4.1. Построение диаграммы в таблице Excel Если вы еще не работали с плагином PLX-DAQ, перечитайте разд. 5.1.4 и скачайте свежий рабочий файл Excel со встроенным макросом. Откройте этот файл. Для удобства вы можете воспользоваться готовым файлом DustSensorTestxIsm из электронного архива, сопровождающего книгу (см. приложение 1). В этом файле уже настроено окно гистограммы для графического отображения значений выборок. В ответ на предупреждение системы безопасности, что запуск макросов отключен, нажмите кнопку Параметры и выберите опцию Включить это содержимое. В ра- бочем окне Excel появится окно плагина. Его можно передвинуть на удобное место до того, как запущен обмен данными.
Глава 13. Измерение пыльности и дымности воздуха 255 Укажите в окне плагина номер порта, к которому подключена плата Arduino, и на- жмите кнопку Connect (подключиться) в окне плагина. Контроллер Arduino авто- матически перезапустится. Скетч при запуске очистит рабочий лист Excel от ста- рых данных и заполнит первый столбец значениями выборок с выхода датчика. Если вы воспользовались готовым файлом, то Excel автоматически начнет отрисов- ку гистограммы (столбчатой диаграммы). Макрос плагина в сочетании с графопо- строителем Excel работает весьма медленно, поэтому отрисовка может занять око- ло 10 секунд после окончания передачи данных. Если быстродействия вашего ком- пьютера не хватает для динамической отрисовки гистограммы и происходят сбои макроса PLX-DAQ, то вам придется перед каждым обновлением данных удалять объект гистограммы, а затем создавать его заново. К счастью, это не трудно. Для создания объекта гистограммы выделите левой кнопкой мыши данные в столб- це таблицы, для которых будете строить гистограмму. Перейдите в меню Вставка | Гистограмма | Гистограмма с группировкой (рис. 13.9). Рис. 13.9. Создание объекта гистограммы Excel Для выделенных данных Excel автоматически построит гистограмму. Подберите удобные для вас размеры и положение графика на экране. На рис. 13.10 показана гистограмма результатов измерений пыльности воздуха в рабочем кабинете автора в середине дня. Источник дыма в помещении отсутству- ет. Напомню, что в этом разделе идет речь о последовательных выборках цикла без усреднения, в отличие от усредненных результатов, о которых говорилось в разд. 13.3 (см. рис. 13.8). Для обнаружения дыма нам нужны именно «сырые» данные без усреднения. В нашем случае отчетливо видны пики и провалы, вызван- ные хаотичным движением пылинок через рабочую зону датчика. На рис. 13.11 показана диаграмма значений выборок, когда датчик был расположен на расстоянии 20 см от места пайки и в рабочую зону попадал дым от канифоли. Эта диаграмма наглядно демонстрирует, насколько равномерно и интенсивно час-
256 Часть II. Теория и практика 250 -I - - 100 1л fs»omi.ocri<NmCQr-«^ffs.om^oo<t{Nin 00 ,н ■ РЯД1 !fi 88 ^ "* 00 00 ОТ ОТ Рис. 13.10. Результаты измерения пыльности при отсутствии дыма ; 3292 3291 3287 - 3286 *Ряд1 ф N N N N t^t^lfilAl/I^WUJNNNN Рис. 13.11. Результаты измерения пыльности при наличии дыма от канифоли
Глава 13. Измерение пыльности и дымности воздуха 257 тицы дыма отражают свет в рабочей зоне датчика. Редкие провалы могли возник- нуть из-за помех по цепи питания или завихрений воздуха вблизи рабочей зоны. На рис. 13.12 показана диаграмма значений выборок спустя 15 минут после окон- чания пайки, когда дым от флюса визуально уже не наблюдается. Тем не менее датчик обнаруживает наличие частиц дыма, и это хорошо заметно, если вниматель- но сравнить диаграммы на рис. 13.10 и 13.12. Если в последнем случае отбросить десять минимальных значений, то все остальные выборки не опускаются ниже уровня 100 милливольт, потому что мельчайшие частицы дыма формируют устой- чивое равномерное отражение. Рис. 13.12. Результаты измерений спустя 15 минут после окончания пайки Теперь мы готовы к настройке скетча, который будет обнаруживать дым в воздухе и отличать его от частиц бытовой пыли. Исходный код скетча приведен в листин- ге 13.3. #include <ArduinoSort.h> // Библиотека сортировки массивов #define N 100 // Количество выборок #define M 10 // Количество отбрасываемых крайних значений #define D 120 // Пороговое значение, признак дыма
258 • Часть II. Теория и практика / / Вью оды Arduino const int sharpLEDPin =7; // Управление включением подсветки const int alarmLEDPin =8; // Вывод индикатора тревоги const int sharpVoPin = A5; // Аналоговый вход сигнала с датчика const int Voc = 400; // Начальное напряжение (мВ) при отсутствии пыли int samples[N]; // Массив для хранения выборок void setup() { // Управляющий вывод настраиваем, как выход pinMode(sharpLEDPin, OUTPUT); Serial.begin(9600); void loop() { // Первый "холостой" импульс светодиода подсветки digitalWrite(sharpLEDPin, LOW); delayMicroseconds(320) ; digitalWrite(sharpLEDPin, HIGH); delayMicroseconds(10000) ; for (int i = 0; i < 100; i++) { // Включаем светодиод датчика (низким уровнем) digitalWrite(sharpLEDPin, LOW); // Ждем 0,28 мс после включения светодиода delayMicroseconds(280) ; // Считываем выходное напряжение датчика // Эта операция занимает около 100 микросекунд int VoRaw = analogRead(sharpVoPin); // Гасим светодиод датчика digitalWrite(sharpLEDPin, HIGH); // Выдерживаем паузу для завершения цикла 10 миллисекунд //с учетом ранее затраченного времени delayMicroseconds(9620); // 10000 - 280 - 100 мкс // Вычисляем выходное напряжение в милливольтах //и выводим значение выборки в таблицу int Vo = (VoRaw / 1024.0 * 5.0) * 1000 - Voc; samples[i] = Vo; sortArray(samples, N); // Сортировка массива по возрастанию Serial.print((String) "Min: " + samples[M] + " Max: " + samples[100 - M - 1])
Глава 13. Измерение пыльности и дымности воздуха 259 if (samples[M] > D) { // Если минимальное значение превышает // порог дымности Serial.println(" SMOKE ALARM!"); digitalWrite(alarmLEDPin, HIGH); // Включаем сигнал тревоги // или вентиляцию } else { Serial.println(); digitalWrite(alarmLEDPin, LOW); В этом скетче использована готовая библиотека сортировки массивов ArduinoSort. Скачайте ZIP-архив со свежей версией этой библиотеки по адресу https:// github.com/emilv/ArduinoSort. Установите библиотеку из архива, как сказано вподразд. «Автоматическая установка библиотеки» разд. 2.3.2. В скетче предусмотрено подключение индикатора тревоги при наличии дыма к вы- воду D8. При обнаружении дыма на этом выводе появляется высокий логический уровень, который можно использовать для управления внешним устройством — например, включать вентилятор вытяжной системы или звуковой сигнал тревоги. Программа получает с выхода датчика n = юо выборок выходного сигнала и со- храняет их в массиве. Далее массив сортируется по возрастанию. По умолчанию мы отбрасываем м = ю первых и последних значений отсортированного массива. Фактически все значения остаются в массиве, просто младшим элементом массива мы теперь считаем элемент с индексом [м] а старшим элементом — элемент с ин- дексом [N - м - 1 ]. Затем наименьшее и наибольшее значения усеченного массива выводятся на печать. Мы не используем наибольшее значение для обнаружения дыма, но наблюдать его полезно, чтобы понимать, как датчик реагирует на разные условия пыльности и дымности. Кроме того, наибольшее значение можно исполь- зовать для вычисления среднего арифметического значения загрязненности воздуха в цикле из n измерений. В коде программы по умолчанию заданы значения начального напряжения voc = 400 и пороговое значение d = 120, которые соответствуют параметрам датчи- ка автора книги. Читателю следует провести серию опытов при помощи скетча из листинга 13.2 и определить начальные параметры собственного датчика. Загрузите скетч в плату контроллера и откройте окно монитора порта. Расположите датчик таким образом, чтобы воздух свободно циркулировал через рабочую зону. Возьмите кусок ткани или газетной бумаги, несколько раз интенсивно сомните его, а затем расправьте и потрясите в воздухе вблизи датчика. Вы увидите, что значение максимальных выборок резко увеличится — вплоть до нескольких тысяч, в то вре- мя как значение минимальных выборок почти не возрастет (это зависит от тексту- ры конкретного источника пыли). Используйте источник дыма, например горячий паяльник или тлеющую бумагу, чтобы проверить реакцию датчика на дым. Вы сможете наблюдать, что при нал и-
260 Часть II. Теория и практика чии дыма резко возрастает не только максимальное, но и минимальное значение массива выборок, причем датчик реагирует даже на дым, который не заметен глазу. При необходимости подкорректируйте значение порога d, чтобы свести к миниму- му ложные срабатывания. 13.4.2. Задания для самостоятельной работы 1. Даже при самом аккуратном подборе пороговых значений программа изредка может давать ложное срабатывание на дым. Доработайте программу таким обра- зом, чтобы сигнал обнаружения дыма включался только в том случае, когда дым обнаружен не менее чем в пяти циклах измерений подряд. 2. Добавьте в программу вычисление среднего арифметического значения загряз- ненности воздуха в цикле измерений с использованием наибольшего и наи- меньшего значения массива после отбрасывания крайних Значений. 3. Организуйте вывод результатов измерений на дисплей, опираясь на навыки, по- лученные при работе над предыдущими проектами книги. 4. Организуйте вывод результатов измерений на онлайновую приборную панель Adafruit 10 по аналогии с примерами из предыдущих глав книги.
ГЛАВА 14 Шагомер на цифровом акселерометре LIS2DS12 В главе 7 мы рассмотрели проект шагомера на простом и популярном у радиолюби- телей, но уже устаревшем, аналоговом акселерометре ADXL335. В этой главе мы будем работать над проектом шагомера на современном цифровом акселерометре LIS2DS12. В целом, оба эти проекта иллюстрируют два концептуально разных подхода к про- ектированию электронного устройства. Проект аналогового шагомера основан на традиционном подходе. Мы берем про- стое периферийное устройство— аналоговый сенсор с минимальной функцио- нальностью— и выполняем всю последующую обработку данных при помощи собственной программы, записанной во внешний микроконтроллер. При таком подходе основная часть затрат на создание устройства относится именно к разра- ботке и отладке программного обеспечения. Разработчик должен обладать высокой квалификацией по части программирования и цифровой обработки сигналов. При- чем, если несколько разных предприятий независимо разрабатывают устройства на одинаковой элементной базе, то в каждом коллективе должны трудиться собствен- ные программисты с высокой квалификацией. Второй проект основан на современном интегральном сенсоре с заранее заложен- ными «умными» функциями. В чип сенсора встроен микроконтроллер, который выполняет различные виды обработки данных. Фирма-производитель уже разрабо- тала, отладила и записала в этот контроллер все необходимые программы. При- кладному разработчику остается лишь изучить техническое описание микросхемы, правильно настроить регистры конфигурации и получить готовые данные. Все ос- тальное за него уже сделано изготовителем чипа. Затраты времени и средств на создание нового устройства сокращаются в несколько раз. Можно спорить о том, хорошо это или плохо, но и потребность в специалистах высокой квалификации тоже сокращается в несколько раз, потому что разработка устройства становится все больше похожей на работу с детским конструктором. Так или иначе, но это реальное положение дел, а наша задача — изучить современ- ные компоненты и методы разработки, чтобы не отставать от жизни.
262 Часть II. Теория и практика 14.1. Назначение и функции акселерометра LIS2DS12 Малогабаритный трехосевой акселерометр LIS2DS12 производства компании STMicroelectronics предназначен для использования в различных гаджетах: смарт- фонах, фитнес-браслетах, умных часах, игровых контроллерах и т. п. Акселерометр упакован в миниатюрный пластиковый корпус LGA (рис. 14.1). Рис. 14.1. Интегральный акселерометр LIS2DS12 14.1.1. Основные технические характеристики акселерометра LIS2DS12 ♦ Напряжение питания: 1,62... 1,98 вольт ♦ Интерфейсы: I2C, SPI ♦ Диапазоны измерений: полная шкала ±2g/±4g/±8g/±16g ♦ Буфер данных: FIFO 256 значений ♦ Разрядность: 16 битов ♦ Габариты: 2x2x20,86 мм 14.1.2. Встроенные функции акселерометра LIS2DS12 Акселерометр LIS2DS12 оснащен встроенным микроконтроллером со следующими предустановленными функциями, которые основаны на измерении ускорений: ♦ шагомер — акселерометр автоматически распознает и считает шаги. Количест- во отмеченных шагов хранится в памяти микросхемы и может быть прочитано или обнулено внешним контроллером. Контроллер автоматически подстраивает порог срабатывания шагомера; ♦ датчик начала движения — чтобы шагомер не регистрировал случайные дви- жения, можно указать минимальное количество отмеченных шагов подряд, по- сле которых считается, что человек начал ходьбу и производится отсчет шагов; ♦ датчик свободного падения — генерирует прерывание, если гаджет, в который установлен акселерометр, начал свободно падать;
Глава 14. Шагомер на цифровом акселерометре US2DS12 263 ♦ определение ориентации — автоматически определяет положение в простран- стве и вырабатывает прерывание по событию смены ориентации; ♦ датчик одиночного и двойного касания — не все об этом знают, но в смарт- фонах одиночное и двойное касание экрана регистрируется не только сенсор- ным экраном, но и акселерометром. Акселерометры очень чувствительны к виб- рации и хорошо распознают импульсы от касаний экрана пальцем; ♦ пробуждение по началу движения — акселерометр может самостоятельно вы- ходить из спящего режима при начале движения; ♦ самокалибровка — встроенная схема вырабатывает эталонные импульсы уско- рений, которые воздействуют на чувствительный элемент, а встроенный микро- контроллер автоматически подбирает поправочные константы; ♦ хаб внешнего сенсора. Акселерометр может работать в режиме хаба — ведуще- го узла, получающего данные с других сенсоров, поддерживающих режим Sensor Hub. Хаб в состоянии получать до шести результатов измерений с одного внешнего сенсора и хранить их в буфере встроенного контроллера. Данные мо- гут быть прочитаны микроконтроллером гаджета в нужное время без обращения к внешнему сенсору. В проектах, предназначенных для мониторинга уровня физической нагрузки чело- века, пригодится встроенная функция шагомера. Фактически нам нужно лишь читать готовые показания счетчика шагов из памяти акселерометра, а всю черно- вую работу по распознаванию и подсчету шагов он сделает сам. 14.2. Модуль акселерометра LIS2DS12 В проекте цифрового шагомера мы задействуем миниатюрный модуль акселеро- метра, изображенный на рис. 14.2. Подписи к выводам нанесены с обратной сторо- ны платы, поэтому для удобства сборки макета рекомендую установить разъемы со стороны компонентов — как на рис. 14.2 и показано. Рис. 14.2. Модуль цифрового акселерометра LIS2DS12
264 Часть II. Теория и практика 14.2.1. Назначение выводов модуля ♦ SDO (SA0) — младший бит адреса в режиме 12С, выход MISO в режиме SPI; ♦ CS — выбор режима интерфейса. При CS = 1 работает шина 12С, шина SPI в ре- жиме ожидания. При CS = 0 шина 12С отключена, шина SPI активна. Вывод снабжен встроенным подтягивающим резистором и в режиме 12С может оста- ваться свободным; ♦ SCL — линия тактовых импульсов как для 12С, так и для SPI; ♦ SDA— двунаправленная линия данных 12С: вход MOSI в режиме SPI, выход SDO в режиме трехпроводного интерфейса (3-Wire); ♦ IT1 — выход сигнала прерывания 1; ♦ IT2 — выход сигнала прерывания 2; ♦ VCC — вход питания 3,3...5,0 вольт; ♦ GND — общий провод. Микросхема акселерометра допускает подтягивание выводов SCL и SDA к незави- симой шине питания, благодаря чему можно обойтись без согласования логических уровней с внешней трех- и пятивольтовой логикой. Но есть важный нюанс. На модуле, показанном на рис. 14.2, установлены подтягивающие резисторы 10 кОм, но они соединены с выходом стабилизатора питания 1,9 вольта, а не с вы- водом VCC. Это явная ошибка разработчиков модуля, потому что этого напряже- ния недостаточно для работы с пятивольтовой логикой, например, Arduino. Впро- чем, напряжение 1,9 вольта не соответствует также и логической единице трех- вольтовой логики (обычно это 2,0...2,4 вольта). Поэтому, например, контроллер ESP8266 будет ненадежно работать с таким модулем. Решение проблемы заключается в использовании внешних подтягивающих рези- сторов 2,2...3,6 кОм, включенных между выводом питания VCC и выводами SCL hSDA. Если у вас есть скальпель, паяльник для работы с миниатюрными SMD- компонентами, зоркий глаз и твердая рука, то вы можете сделать несложную дора- ботку платы модуля, о которой рассказано в статье по адресу www.reedpaper.com/ archives/1148. 14.3. Подключение и проверка модуля Подключите модуль LIS2DS12 к плате контроллера Arduino Uno R3, как показано на схеме, приведенной на рис. 14.3. Обратите внимание, что модуль питается на- пряжением 5 вольт, а линии SCL и SDA подтянуты к высокому уровню через рези- сторы с номиналом 2,2 кОм. Загрузите в контроллер Arduino прошивку из листинга 14.1 и откройте окно встро- енного монитора на скорости 9600 бод. Если модуль правильно подключен и ис- правен, то в окне монитора появится сообщение о том, что найден акселерометр, и далее будет отображаться количество подсчитанных шагов.
Глава 14. Шагомер на цифровом акселерометре LIS2DS12 265 Рис. 14.3. Схема подключения модуля акселерометра LIS2DS12 Возьмите макетную плату в руку и плавно покачивайте ее вверх-вниз, имитируя шаги. По умолчанию контроллер определяет, что началась ходьба, после первых шести зарегистрированных шагов подряд. До этого показания счетчика не меняют- ся, а затем сразу начинается отсчет сразу с седьмого шага. Таким образом, точная информация о пройденных шагах не будет утрачена, просто отображение данных начнется с седьмого шага. Но что, с точки зрения акселерометра, означает «шесть шагов подряд»? Это значит, что пауза между импульсами шагов не должна превы- шать две секунды, иначе встроенный контроллер будет считать, что это не начало ходьбы, а случайные движения. Если вы остановитесь, то шагомер зафиксирует остановку, а после возобновления ходьбы снова отсчитает шесть шагов подряд, прежде чем увеличивать показания счетчика. Но, разумеется, встроенный счетчик не обнуляется при остановке ходь- бы. Его можно обнулить командой сброса или отключением питания. Всего регист- ры 16-разрядного счетчика могут хранить до 65 535 шагов. #include <Wire.h> #define LIS2 ADDR OxlD // Или OxlE, если SDOO
266 Часть II. Теория и практика // Адреса регистров #define STEP_COUNTER_L ОхЗВ #define STEP_COUNTER_H ОхЗС #define FUNC_CTRL 0x3F #define CTRL1 0x20 void setup() { Serial.begin (9600); Wire.beginO ; // Проверяем наличие акселерометра Wire.beginTransmission(LIS2_ADDR); if (Wire.endTransmission () == 0) { Serial.println("LIS2DS found"); } else { Serial.printIn("LIS2DS not found!"); // Конфигурация: низкое потребление, выборки 50 Гц Wire.beginTransmission(LIS2_ADDR); Wire.write(CTRL1); Wire.write(B11110000) ; Wire.endTransmission(); // Включаем встроенную функцию шагомера Wire.beginTransmission(LIS2_ADDR); Wire.write(FUNC_CTRL); Wire.write(B00000011) ; Wire.endTransmission(); void loopO { // Посылаем в акселерометр адрес регистра Wire.beginTransmission(LIS2_ADDR); Wire.write(STEP_COUNTER_L); Wire.endTransmission(); // Читаем два байта из регистров счетчика шагов Wire.requestFrom(LIS2_ADDR, 2); byte stepL = Wire.readO; byte stepH = Wire.read{); // Преобразовываем два байта в слово word stepCount = word(stepH, stepL); // Выводим слово в монитор Serial.println(stepCount); delay(300);
Глава 14. Шагомер на цифровом акселерометре US2DS12 267_ Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). Для работы с LIS2DS12 и его встроенным шагомером нам не нужна библиотека Arduino (впрочем, на момент подготовки книги к печати такой библиотеки в пуб- личном доступе в Интернете и не существовало). Прежде всего, мы пытаемся обра- титься к акселерометру по адресу ОхЮ или OxiE— в зависимости от логического уровня на выводе SDO. В нашем случае вывод SDO никуда не подключен, и аксе- лерометр доступен по адресу ОхЮ. Для проверки доступности инициируем «пус- той» сеанс обмена ПО ШИНе 12С при ПОМОЩИ команд Wire.beginTransmission(LIS2_ADDR) и wire. endTransmission (). Вторая команда в случае успешного завершения сеанса возвращает ноль. Далее выполняем минимальную настройку акселерометра. В регистр конфигурации ctrli записываем двоичное число, которое соответствует режиму пониженного энергопотребления и частоте измерений 50 Гц. В данном случае мы выбираем ре- жим с низким энергопотреблением, при котором еще могут работать встроенные функции шагомера и детектора начала движения. Затем активируем встроенную функцию шагомера и детектора движения записью значения конфигурации в регистр funcctrl. На этом настройка завершена, и мож- но приступать к чтению данных из счетчика шагов. Счетчик шагов состоит из двух регистров: stepcounterl (младший байт) и stepcounterh (старший байт). Чтение двух байтов подряд по шине 12С происхо- дит следующим образом: 1. Посылаем в акселерометр адрес первого регистра: Wire.beginTransmission(LIS2_ADDR); Wire.write(STEP_COUNTER_L); Wire.endTransmission(); 2. Сообщаем, что будем читать два байта: Wire.requestFrom(LIS2_ADDR, 2) ; 3. Дважды выполняем чтение: byte stepL = Wire.read(); byte stepH = Wire.read(); Обратите внимание, что мы указали адрес только первого регистра (младшего бай- та счетчика). Встроенный контроллер акселерометра автоматически инкрементиру- ет адрес регистра и по второй команде чтения возвращает значение старшего байта счетчика шагов. Нам остается преобразовать два байта в 16-разрядное слово и вывести его в терми- нал: word stepCount = word(stepH, stepL); Serial.printIn(stepCount);
268 Часть II. Теория и практика Как вы могли убедиться, программа предельно проста, и основные затраты времени на разработку относятся к изучению технического описания микросхемы. 14.4. Шагомер с OLED-дисплеем Давайте соберем макет цифрового шагомера с OLED-дисплеем. На дисплей будет выводиться количество шагов и расстояние в метрах, вычисленное из длины одного шага, а также количество затраченной энергии в килокалориях. Счетчик шагов будет сбрасываться нажатием кнопки сброса. Электрическая схема соединения компонентов проекта представлена на рис. 14.4, а его макет — на рис. 14.5. Рис. 14.4. Схема цифрового шагомера с OLED-дисплеем Загрузите в плату контроллера скетч из листинга 14.2 #include <Wire.h> #include <Adafruit_GFX.h> // Графическое ядро #include <Adafruit_SSD1306.h> // Библиотека OLED-дисплея tdefine SCREEN_WIDTH 128 // Ширина дисплея в пикселах #define SCREEN_HEIGHT 64 // Высота дисплея в пикселах #define OLED_RESET -1 //В нашем дисплее нет линии сброса
Глава 14. Шагомер на цифровом акселерометре US2DS12 269 // Адрес шагомера на шине I2C #define LIS2_ADDR OxlD // Или OxlE // Вывод кнопки сброса #define CNT_RESET A3 // Адреса регистров #define STEP_COUNTER_MINTHS ОхЗА #define STEP_COUNTER_L ОхЗВ #define STEP_COUNTER_H ОхЗС tdefine FUNC_CTRL 0x3F #define CTRL1 0x20 // Задайте здесь физиологические параметры пользователя #define WEIGHT_KG 80 // Вес пользователя, кг #define STEP_LENGTH 0.7 // Длина шага пользователя float energy; word stepCount; int distance; // Создаем объект дисплея Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void setup() { Serial.begin (9600); Wire.beginO ; // Для кнопки сброса режим входа с подтягивающим резистором pinMode(CNT_RESET, INPUT_PULLUP); // Активируем OLED-дисплей oled.begin(SSD1306_SWITCHCAPVCC, ОхЗС); oled.clearDisplay(); // Очистка памяти дисплея oled.display(); // Вывод из памяти на экран // Устанавливаем размер и цвет текста oled.setTextSize(l); oled.setTextColor(WHITE); // Проверяем наличие акселерометра Wire.beginTransmission(LIS2_ADDR); if (Wire.endTransmission () ==0) { Serial.println("LIS2DS found");
270 Часть II. Теория и практика else { Serial.println("LIS2DS not found!"); // Конфигурация: низкое потребление, выборки 50 Гц Wire.beginTransmission(LIS2_ADDR); Wire.write(CTRL1); Wire.write(B11110000); Wire.endTransmission(); // Включаем встроенную функцию шагомера Wire.beginTransmission(LIS2_ADDR); Wire.write(FUNC_CTRL); Wire.write(B00000011) ; Wire.endTransmission(); void loop() { // Если нажата кнопка сброса счетчика шагов, //то устанавливаем в 1 бит сброса счетчика if (digitalRead(CNT_RESET)==O) { Wire.beginTransmission(LIS2_ADDR); Wire.write(STEP_COUNTER_MINTHS); Wire.write(B10010000); // Бит RST_nSTEP=l Wire.endTransmission() ; // Посылаем в акселерометр адрес регистра Wire.beginTransmission(LIS2_ADDR); Wire.write(STEP_COUNTER_L); Wire.endTransmission(); // Читаем два байта из регистров счетчика шагов Wire.requestFrom(LIS2_ADDR, 2); byte stepL = Wire.readO; byte stepH = Wire.readO; // Преобразовываем два байта в слово stepCount = word(stepH, stepL); // Вычисляем расстояние в метрах distance = int (stepCount * STEP_LENGTH); // Вычисляем затраченную энергию energy = 0.5 * WEIGHT_KG * distance / 1000; // Очищаем дисплей oled.clearDisplay(); // Выводим количество шагов oled.setCursor(0, 0); oled.print("Step:");
Глава 14. Шагомер на цифровом акселерометре LIS2DS12 271 oled.setCursor(60, 0) ; oled.print(stepCount); // Выводим расстояние oled.setCursor(0, 23) ; oled.printC'Dist:") ; oled.setCursor(60, 23) ; oled.print(distance); // Выводим энергию oled.setCursor(0, 46); oled.print("kCal:") ; oled.setCursor(60, 46); if (energy < 1) { oled.print(energy, 2) ; } else { oled.print(energy); } // Обновляем экран дисплея oled.display(); delay(300) ; Рис. 14.5. Макет цифрового шагомера с OLED-дисплеем
272 Часть II. Теория и практика Для этого скетча нам пригодились наши предыдущие наработки. Так, из листин- га 7.4 можно взять поддержку дисплея, а также часть кода, отвечающую за вычис- ление затраченной энергии и вывод данных на дисплей. Часть кода, отвечающего за настройку акселерометра и чтение счетчика шагов, совпадает с кодом листин- га 14.1. Кнопка сброса счетчика шагов подключена к выводу A3 контроллера Arduino. Что- бы уменьшить количество внешних элементов, для этого вывода включен встроен- ный подтягивающий резистор (режим inputpullup). В каждом проходе главного цикла программы проверяется нажатие кнопки сброса. Чтобы сбросить встроенный счетчик шагов, необходимо записать 1 в разряд RST_nSTEP регистра step_counter_minths (ОхЗА) микросхемы акселерометра. По- сле сброса счетчика шагов этот разряд автоматически обнуляется. Содержимое остальных разрядов этого регистра нас в данном случае не интересует, и мы остав- ляем для них значения по умолчанию. Таким образом, для сброса счетчика шагов необходимо записать в регистр stepcounterminths двоичное число юоюооо, где Старший разряд И еСТЬ RST_nSTEP. 14.5. Задания для самостоятельной работы 1. Изучите описание акселерометра и его регистров. Это техническое описание (datasheet) можно найти в файле LIS2DS12.pdf сопровождающего книгу электрон- ного архива (см. приложение /). 2. Постоянное свечение экрана вредит недорогим OLED-дисплеям и приводит к быстрому «выгоранию» пикселов. Доработайте программу таким образом, чтобы индикация на дисплее включалась только в том случае, если акселерометр находится в заданном положении (например, горизонтально) и неподвижен не менее 1 секунды. Индикация должна включаться на 3-5 секунд. 3. Акселерометр оснащен встроенным термометром. Добавьте в прошивку шаго- мера возможность чтения и отображения температуры.
ГЛАВА 15 Трехточечный электрокардиограф Электрокардиограмма (ЭКГ) — это графическое отображение величины электриче- ских потенциалов, возникающих во время сокращения и расслабления сердечной мышцы. Ранняя диагностика сердечных заболеваний важна для сохранения здоровья и жиз- ни пациента. По данным Всемирной организации здравоохранения (ВОЗ), смерт- ность от сердечно-сосудистых заболеваний превышает смертность от всех осталь- ных болезней, вместе взятых. К сожалению, Россия занимает по этому показателю одно из первых мест в мире. Во многом эта печальная картина является следствием легкомысленного отношения населения к собственному здоровью и пренебрежения регулярными обследованиями. Опытный врач-кардиолог может обнаружить на ЭКГ признаки заболеваний сердца еще до того, как их ощутит пациент. У диагностики по ЭКГ есть важные достоинства: ♦ неинвазивностъ — не требуется вводить зонды или электроды в тело пациента, причиняя травмы и дискомфорт; ♦ доступность— электрокардиографы широко распространены, портативны и относительно дешевы; ♦ скорость — врач может читать кардиограмму в режиме реального времени; ♦ универсальность — ЭКГ позволяет обнаружить большое количество сердечных заболеваний и скрытых аномалий: от сбоев сердечного ритма до нарушений ионно-калиевого обмена в организме. Сегодня многие знают, как выглядит график ЭКГ, но расшифровка кардиограммы для большинства из нас по-прежнему окутана ореолом тайны. Для полноценного чтения ЭКГ требуется серьезная профессиональная подготовка, но вы можете самостоятельно разобраться, из каких компонентов состоит ЭКГ и какие характер- ные признаки работы сердца они отражают. Приведенное в этой книге упрощенное описание электрокардиографии и измери- тельных устройств на базе Arduino предназначено только для общих образователь- ных целей и расширения кругозора читателей. Не используйте эти устройства для самостоятельной постановки диагноза. При подозрении на наличие сердечно- сосудистого заболевания незамедлительно обратитесь к врачу.
274 Часть II. Теория и практика 15.1. Фазы кардиограммы В процессе напряжения и расслабления мышцы человеческого тела генерируют колебания электрического потенциала, которые можно уловить при помощи элек- тродов и чувствительного усилителя. При сердцебиении— регулярном сокращении и расслаблении сердечной мыш- цы — в окружающих сердце тканях организма также возникают колебания элек- трического потенциала. График изменения этого потенциала зависит от многих факторов: степени напряжения и расслабления сердечной мышцы, усталости мыш- цы, концентрации питательных веществ, количества ионов калия и натрия в тканях и т. д. Кардиограмма в общем виде изображена на рис. 15.1. Она состоит из пяти главных зубцов: Р, Q, R, S, Т. Иногда удается наблюдать слабую волну U. Комплекс QRS Рис. 15.1. Общая структура периода кардиограммы Интервал PR соответствует электрическому импульсу, который начинает распро- страняться от правого предсердия в сторону левого предсердия. Правое предсер- дие — это первая полость сердца, на которую воздействует импульс. Он заставляет сердце сжаться и перегнать бедную кислородом кровь из верхней и нижней полых вен в правый желудочек. Следуя далее через верхнюю часть сердца, электрический импульс приводит в действие левое предсердие. Оно отвечает за прием насыщен- ной кислородом крови из легких и перекачку ее в левый желудочек. На интервале QT происходят сложные процессы. На протяжении комплекса QRS подключаются к работе оба желудочка. Правый желудочек начинает накачивать обедненную кровь в легкие через левую и правую легочные артерии. Левый желу-
Глава 15. Трехточечный электрокардиограф 275 дочек в то же время накачивает насыщенную кислородом кровь через аорту в ос- тальную кровеносную систему тела. Затем следует период относительного электрического спокойствия на протяжении сегмента ST. Наконец, зубец Г отражает фазу расслабления желудочков. Теперь, зная общую картину, можно более детально расшифровать зубцы кардио- граммы: ♦ Р — импульс сокращения систолы предсердий; ♦ Q— отклонение вниз, непосредственно предшествующее сокращению желу- дочка; ♦ R — пик сокращения желудочков; ♦ S — нисходящее отклонение сразу после сокращения желудочка; ♦ Т — восстановление желудочков; ♦ U — является преемником Т-волны, но не всегда наблюдается. Подготовленный специалист извлекает из формы зубцов и наличия искажений кар- диограммы большой объем информации о структуре сердца и работе его электро- проводной системы. 15.2. Назначение и расположение электродов Для измерения разности электрических потенциалов, возникающих при работе сер- дечной мышцы, нужны как минимум два электрода. В профессиональной клиниче- ской кардиографии для более точного и детального исследования всех нюансов ра- боты сердца используют 7-12 электродов, которые располагают на всех конечно- стях и поверхности груди пациента. Точки, с которых снимают значение потенциала, называют отведениями. Мы воспользуемся базовой трехэлектродной схемой, которая широко применяется в спортивных кардиомониторах и дистанционной электрокардиометрии. Два электрода, непосредственно снимающие разность потенциалов, располагаются справа и слева от сердца (рис. 15.2). Третий электрод называется опорным (рефе- ренсным) и не участвует непосредственно в измерении потенциалов. Он играет роль общего провода или «заземления» в измерительной схеме и предназначен для уравнивания потенциалов между телом пациента и общим проводом прибора. Та- ким способом устраняются наводки от сетей переменного тока 220 вольт и радио- приборов. Третий электрод располагается ближе к правой ноге, где находится точка нулевого потенциала относительно сердечной мышцы. Электроды регистрируют не только биотоки сердечной мышцы, но и биотоки остальных мышц тела, расположенных между электродами. Поэтому вариант рис. 15.2, б меньше подвержен помехам от биотоков мышц рук. Вариант располо- жения на рис. 15.2, а в основном применяется, когда трудно или невозможно раз- местить электроды на груди (бинты, хирургические швы, необходимость медицин- ских манипуляций).
276 Часть II. Теория и практика Общепринятое наименование электродов: ♦ RA (Right Arm) — правая рука; ♦ LA (Left Arm) — левая рука; ♦ RL (Right Leg) — правая нога. В процессе снятия кардиограммы необходимо лежать максимально неподвижно, с расслабленными мышцами тела. Рис. 15.2. Расположение электродов в трехэлектродной схеме ЭКГ: а — вариант, когда трудно или невозможно разместить электроды на груди; б — наиболее приемлемый вариант, который менее подвержен помехам от биотоков мышц рук 15.3. Модуль электрокардиографа AD8232 Получение качественной кардиограммы— сложная инженерная задача. Разность электрических потенциалов между электродами очень мала, а входные сигналы сильно зашумлены различными помехами. Поэтому для снятия кардиограммы не- достаточно простого усиления входного напряжения, поступающего с электро- дов, — необходимо провести фильтрацию сигналов как на входе, так и после уси- ления, удалить постоянный гальванический потенциал, который может возникнуть при контакте электродов с телом, автоматически настроить усиление.
Глава 15. Трехточечный электрокардиограф , 277 Компания Analog Devices разработала специальную микросхему для кардиометрии AD8232. Эта миниатюрная и экономичная микросхема может применяться как в профессиональном медицинском оборудовании, так и в бытовых приборах для спорта и фитнеса. Микросхема содержит все необходимые усилители и фильтры для построения схемы электрокардиографа с минимальным количеством внешних компонентов. Аналоговый выходной сигнал может быть оцифрован встроенным АЦП контроллера Arduino. В продаже широко представлены готовые модули ЭКГ на основе микросхемы AD8232. В основном это клоны модуля, разработанного фирмой SparkFun (рис. 15.3). В модуле предусмотрена функция контроля подключения электродов — при потере контакта электрода с телом или отключении проводов на выводах LO- и LO+ микросхемы появится высокий логический уровень. Микросхему AD8232 можно перевести в спящий режим подачей низкого уровня на вход SDN. Рис. 15.3. Типовой модуль ЭКГ на основе микросхемы AD8232 15.3.1. Назначение выводов модуля ЭКГ ♦ RA — Right Arm, правая рука; ♦ LA — Left Arm, левая рука; ♦ RL — Right Leg, правая нога; ♦ GND — общий провод; ♦ 3.3v — питание +3,3 вольта; ♦ OUTPUT — аналоговый выход; ♦ LO высокий уровень при обрыве в цепи электрода LA; ♦ LO+ — высокий уровень при обрыве в цепи электрода RA; ♦ SDN — при подаче низкого уровня микросхема переходит в спящий режим.
278 Часть II. Теория и практика Для опытов с ЭКГ можно приобрести готовый набор из модуля, соединительных проводов и клейких электродов с проводящим гелем (рис. 15.4) или изготовить электроды и провода самостоятельно. Рис. 15.4. Набор компонентов электрокардиографа Arduino Для изготовления самодельных электродов желательно использовать контакты из такого металла, который не окисляется и не образует гальваническую пару при контакте с кожей. Идеально подходят крупные застежки-кнопки для одежды, изго- товленные из нержавеющей стали (рис. 15.5). Такие кнопки можно купить в бли- жайшем магазине швейных принадлежностей. Рис. 15.5. Застежки-кнопки из нержавеющей стали — хорошая заготовка для изготовления электродов Вместо липкого диска можно использовать отрезок медицинского лейкопластыря с отверстием для провода посередине. Токопроводящий гель с успехом заменяется раствором поваренной соли (одна чайная ложка соли на стакан воды). Перед нало- жением самодельных электродов смочите поверхность электрода и кожу раствором соли.
Глава 15. Трехточечный электрокардиограф 279 Покупные клейкие электроды формально являются одноразовыми, но при аккурат- ном обращении их можно использовать достаточно долго. Впрочем, проводящий гель в центре диска быстро перестает прилипать к коже. Для восстановления свойств геля осторожно протрите его поверхность ваткой, смоченной в растворе поваренной соли. Сменные электроды можно найти в зарубежных интернет- магазинах ПО ключевым Словам Non-woven Fabric Electrode pads. 15.3.2. Электрическая безопасность — это важно! В электрокардиографе используется прямое подключение электродов к телу чело- века. Как пояснялось в разд. 1.2 — если подключить измерительное устройство на- прямую к компьютеру, на общем проводе устройства в случае ошибки коммутации электропроводки может присутствовать полное напряжение 220 вольт относитель- но заземленных предметов. Внимание! Категорически запрещается проводить опыты с подключением электродов к телу человека без качественной гальванической развязки между макетом устройства и компьютером, подключенным к электрической сети 220 вольт! В случае отсутствия специальной развязки используйте батарейное питание устрой- ства и передачу данных по беспроводному соединению Bluetooth или ноутбук с пи- танием от батареи (в приложении 2 рассказано про варианты батарейного питания макетов и устройств). Для беспроводной передачи данных в компьютер мы воспользуемся модулем Bluetooth (см. разд. 3.6) и библиотекой программного последовательного порта SoftwareSerial (CM. разд. 3.2.3). Если в качестве настольного компьютера вы используете ноутбук с питанием от батареи, то можно обойтись без модуля Bluetooth и программного порта SoftwareSerial и подключить контроллер Arduino к порту USB ноутбука обычным способом. Не забудьте только перед началом опытов отключить зарядное устройст- во ноутбука от сети! 15.3.3. Подключение кардиографа к Arduino Uno Схема подключения модуля кардиографа к контроллеру Arduino Uno R3 показана на рис. 15.6. Выход OUTPUT модуля подключен к аналоговому входу АО Arduino, а выходы индикатора обрыва электродов LO- и LO+ — к цифровым портам D5 и D4 соответственно. Для гальванической развязки кардиографа с компьютером применяется модуль Bluetooth и питание от батарейного источника. Как уже отме- чалось ранее, при использовании ноутбука с питанием от батареи можно обойтись без модуля Bluetooth. Перед сборкой макета убедитесь, что адаптер Bluetooth настроен на скорость обме- на 115 200 бод, которая указана в приводимом далее скетче. О настройке адаптеров Bluetooth рассказано в разд. 3.6.
280 Часть II. Теория и практика Рис. 15.6. Схема подключения модуля электрокардиографа AD8232 к Arduino Uno и адаптеру Bluetooth Исходный код программы для наблюдения ЭКГ приведен в листинге 15.1. Про- грамма считывает сигнал с аналогового входа АО и выводит числовые данные в по- следовательный порт. Кроме этого, программа проверяет логические уровни на линиях LO- и LO+. // Библиотека программного последовательного порта #include <SoftwareSerial.h> // Создаем программный последовательный порт SoftwareSerial mySerial(2, 3); // RX, TX void setup() { // Активируем программный последовательный порт mySerial.begin(115200); // Линии контроля за исправностью электродов pinMode(4, INPUT); // Вход линии LO+ pinMode(5, INPUT); // Вход линии LO-
Глава 15. Трехточечный электрокардиограф 281 // Встроенный светодиод платы Arduino pinMode(LED_BUILTIN, OUTPUT); void loopO { // Проверяем исправность электродов if ((digitalRead(4) ==1) || (digitalRead(5) ==1)) { // Выводим сообщение в порт mySerial.println("Check electrode!"); // Гасим встроенный светодиод digitalWrite(LED_BUILTIN, LOW); } // Если электроды исправны, выводим в порт данные для графика else { // Включаем встроенный светодиод digitalWrite(IEDJBUILTTN, HIGH); // Данные в формате FlexyPlot //mySerial.print("{РО|ECG|0,0,255|"); //mySerial.print(analogRead(АО) ); //mySerial.println("}"); // Данные в формате Serial Port Plotter mySerial.print("$"); mySerial.print(analogRead(AO)); mySerial.print(";"); // Данные в формате встроенного плоттера Arduino IDE //mySerial.println(analogRead(АО)); } // Небольшая пауза для выгрузки данных из порта delay(1); Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). В главном цикле скетча постоянно проверяется уровень сигнала на выводах LO+ и LO-. Если хотя бы на одном из этих выводов присутствует высокий логический уровень, то в порт выводится сообщение о неисправности электродов, и гаснет встроенный светодиод на плате контроллера. Если электроды подключены к моду- лю и имеют надежный контакт с кожей, то зажигается встроенный светодиод и ре- зультат оцифровки входного сигнала выводится в последовательный порт. Для отображения кардиограммы по умолчанию применяется графопостроитель Serial Port Plotter (см. разд. 5.7.2). В настройках раздела PLOT CONTROLS задайте следующие параметры:
282 Часть II. Теория и практика ♦ POINTS: 1500; ♦ YSTEP: 10; ♦ MIN:200; ♦ MAX: 500. Не забудьте выбрать номер порта, который соответствует соединению по Bluetooth на вашем компьютере, а также скорость соединения 115 200 бод. В скетче предусмотрены строки кода для вывода данных в формате FlexyPlot и встроенного плоттера Arduino IDE. При необходимости удалите комментарии из нужных для правильной работы строк. На рис. 15.7 изображен пример ЭКГ, снятой при расположении точек отвода (элек- тродов) по схеме, приведенной на рис. 15.2, а. По схеме, приведенной на рис. 15.2, б, мы получаем аналогичный график, но с большей амплитудой сигнала и несколько иным соотношением между высотами пиков ЭКГ. Рис. 15.7. Пример электрокардиограммы в окне графопостроителя Serial Port Plotter Проведите опыты с различным расположением электродов и выберите оптималь- ный вариант, при котором кардиограмма выглядит наиболее четко и детализо- ванно. Если график засорен шумами, или амплитуда сигнала постоянно меняется, необходимо обеспечить более надежный контакт электродов с кожей. Во время получения кардиограммы нельзя двигаться, разговаривать и напрягать мышцы тела. Желательно задержать дыхание или дышать неглубоко. Гелевый электролит даже у новых электродов при длительном хранении может вы- сохнуть и потерять липкость. Если электроды не обеспечивают надежный контакт с кожей, предварительно увлажните гелевую подушечку и кожу соленой водой.
Глава 15. Трехточечный электрокардиограф 283 15.4. Кардиомонитор с цветным TFT-дисплеем В главе 6 мы обсуждали проект пульсометра с цветным дисплеем. Теперь мы по- строим более сложное мобильное устройство— кардиомонитор, который будет показывать на дисплее кардиограмму, снятую с трех отведений, а также вычислять частоту пульса. Схема подключения компонентов проекта изображена на рис. 15.8. Внимательно изучите эту схему, прежде чем приступать к сборке макета. Схема подключения дисплея полностью идентична схеме, изображенной на рис. 5.25. Резисторы с со- противлением 1,0... 1,5 кОм нужны для согласования логических уровней на ши- не SPI. Рис. 15.8. Схема подключения компонентов кардиографа к TFT-дисплею Исходный код прошивки кардиомонитора приведен в листинге 15.2. Опытным пу- тем было установлено, что при нормальной работе значения оцифрованного сигна- ла не выходят за пределы числового диапазона 150...600, а импульсы сердечных сокращений (R-пики на рис. 15.1) можно фиксировать при пересечении числового порога 500. В вашем случае, особенно если вы используете самодельные электро- ды, числовые значения могут отличаться. В таком случае придется подобрать под- ходящие значения параметров: ecg_min, ecg_max и threshold. Частота пульса вычисляется по формуле:
284 Часть II. Теория и практика где Ri+\ и Rj — время в миллисекундах, соответствующее двум соседним R-пикам, Fp — частота сердечных сокращений в минуту, 60000 — количество миллисекунд в минуте. // Подключаем библиотеку пульсометра #include <PulseSensorPlayground.h> // Подключаем графические библиотеки дисплея #include <Adafruit_GFX.h> // Графическое ядро #include <Adafruit_ST7735.h> // Библиотека TFT-дисплея на чипе ST7735 #include <SPI.h> // Стандартное подключение выводов дисплея #define TFT_CS 10 // Вывод CS дисплея #define TFT_DC 9 // Вывод D/C дисплея #define TFT_RST 0 // Сброс дисплея подключен к RES платы Arduino // Подключение выводов для дисплейного шилда // http://www.http://reedpaper.com/archives/1035 //#define TFT_CS 9 // Вывод CS дисплея //#define TFT_DC 10 // Вывод D/C дисплея //#define TFT_RST 0 // Сброс дисплея подключен к RES платы Arduino #define ECG_MIN 150 // Минимальное корректное значение ЭКГ #define ECG_MAX 600 // Максимальное корректное значение ЭКГ #define THRESHOLD 500 // Порог срабатывания счетчика пульса // Создаем объект дисплея Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); uint32_t newMillis, oldMillis; uint8_t sensor, drawSensor, drawSensorOld; uint8_t xPos =0; // Текущая позиция по оси X на экране дисплея byte newBPM, oldBPM, badElectrode, pulse; void setup() { Serial.begin(9600); // Устанавливаем максимальную скорость шины SPI, 1/2 тактовой частоты // для быстрой прорисовки дисплея SPI.setClockDivider(SPI_CLOCK_DIV2); tft.initR(INITR_BLACKTAB); // Инициализация чипа ST7735S tft.setRotation(l); // Горизонтальное положение дисплея tft.fillScreen(ST7735_BLACK); // Очистка экрана заливкой в черный цвет tft.setTextSize(l); // Размер текста
Глава 15. Трехточечный электрокардиограф 285 tft.setTextColor(ST7735_GREEN); // Цвет текста tft.setCursor(50, 0); // Задаем позицию курсора tft.print("BPM: "); newMillis = millisO; oldMillis = millisO; void loop() { // Проверяем исправность электродов if (digitalRead(4) ==1) { // Выводим надпись красного цвета tft.setTextColor(ST7735_RED); tft.setCursor(0f 0) ; tft.print("LO+ "); badElectrode = 1; } else { // Выводим надпись зеленого цвета tft.setTextColor(ST7735_GREEN); tft.setCursor(0, 0); tft.print("LO+ ") ; badElectrode = 0; } if (digitalRead(5) ==1) { // Выводим надпись красного цвета tft.setTextColor(ST7735_RED); tft.setCursor(25, 0); tft.print("LO-"); badElectrode = 1; } else { // Выводим надпись зеленого цвета tft.setTextColor(ST7735_GREEN); tft.setCursor(25, 0) ; tft.print("LO-"); badElectrode = 0; // Если электроды исправны if (badElectrode == 0) { // Читаем показания сенсора int sensor = analogRead(AO); // Вычисление частоты пульса if ((pulse == 0) && (sensor > THRESHOLD))
286 Часть II. Теория и практика // Обнаружен нарастающий фронт R-пика oldMillis = newMillis; newMillis = millisO; pulse = 1; } if ((pulse == 1) && (sensor < THRESHOLD)) { // Обнаружен спадающий фронт R-пика pulse =0; newBPM = 60000 / (newMillis - oldMillis); if (newBPM != oldBPM) { tft.fillRect(75, 0, 100, 8, ST7735_BLACK); // Очищаем // область текста tft.setCursor(75, 0); // Задаем позицию курсора tft.print(newBPM); // Выводим частоту пульса oldBPM = newBPM; // Масштабируем показания в размер свободного поля дисплея по вертикали if (sensor > ECG_MAX) sensor = ECG_MAX; if (sensor < ECG_MIN) sensor = ECG_MIN; drawSensor = map(sensor, ECG_MIN, ECG_MAX, 0, 118); // Если начало дисплея, рисуем начальную точку (линию единичной длины) if (xPos ==0) { tft.drawLine(xPos, tft.height() - drawSensor, xPos, tft.height() - drawSensor - 1, ST7735_YELLOW); drawSensorOld = drawSensor; } // Иначе рисуем линию от предыдущей точки к текущей else { tft.drawLine(xPos, tft.height() - drawSensor, xPos, tft.height() - drawSensorOld, ST7735_YELLOW); drawSensorOld = drawSensor; // Если достигнут конец экрана, очищаем область графика //и обнуляем счетчик по оси X if (xPos >= 160) { xPos = 0; tft.fillRect(0, 8, 160, 128, ST7735_BLACK); // Очищаем // область графика } // Иначе просто инкрементируем счетчик отсчетов else { xPos++;
Глава 15. Трехточечный электрокардиограф 287 II Небольшая задержка для оптимизации масштаба графика по горизонтали delay(8); Работа программы начинается с инициализации дисплея. В главном цикле постоян- но проверяется состояние линий LO+ и LO-. Если хотя бы на одной линии появля- ется высокий уровень, то название этой линии выводится в верхней части дисплея красным цветом, а измерительный цикл не выполняется до тех пор, пока не будет восстановлено нормальное подключение электродов. В нормальном состоянии на- звания линий отображаются зеленым цветом. Также в верхней строке выводится частота пульса. В процессе считывания сигнала с выхода модуля ЭКГ программа ищет нарастаю- щий фронт R-пика. Признаком нарастающего фронта считается совпадение двух условий: уровень сигнала превышает пороговое значение и признак наличия им- пульса равен нулю. В момент обнаружения пика фиксируется новое значение счет- чика миллисекунд. Затем программа ожидает окончание R-пика и признак наличия импульса обнуляется. Далее вычисляется значение частоты пульса, и новое значение выводится на экран. Дисплей работает таким образом, что перед выводом нового текста нужно прину- дительно очистить область текста (залить цветом фона). Если выполнять очистку постоянно, то текст будет неприятно мерцать. Поэтому полученное значение часто- ты пульса выводится только в том случае, если оно не совпадает со старым значе- нием, которое уже есть на дисплее. Иногда, если напрягать мышцы тела во время работы кардиографа, измеренные значения могут выходить за пределы области отображения. Поэтому текущие зна- чения сначала ограничиваются по максимуму и минимуму, а затем масштабируют- ся по оси Y при помощи встроенной функции тар (). Подбирая задержку в последней строке, можно в небольших пределах менять мас- штаб графика по оси X. 15.5. Задания для самостоятельной работы 1. При плохом контакте электродов с кожей или при движении возникают пара- зитные пики кардиограммы, и значение частоты пульса может периодически ис- кажаться. Сделайте так, чтобы при резком изменении частоты пульса, когда но- вое значение отличается от предыдущего больше, чем на 15...20% в большую или меньшую сторону, новое значение считалось ошибочным и отбрасывалось. 2. Сделайте так, чтобы при отклонении частоты пульса от нормы кардиограмма отображалась красным цветом. 3. Добавьте в программу возможность подстройки порога срабатывания счетчика пульса. Сейчас значение threshold жестко записано в код. Реализуйте под- стройку порогового уровня при помощи двух кнопок. При наличии некоторого опыта программирования вы можете реализовать автоматическую подстройку порога. Программа должна постоянно следить за максимальной амплитудой R-пика и подстраивать порог счетчика на 10... 15% ниже амплитуды пика.
ГЛАВА 16 Измеритель скорости пульсовой волны В разд. 6.8 мы уже говорили, что скорость распространения пульсовой волны зна- чительно превышает скорость перемещения крови. Скорость движения частиц кро- ви в сосудах составляет всего 0,5 м/с, а скорость пульсовой волны в 14...20 раз больше и находится в диапазоне от 7 до 10 м/с. Измеряя скорость распространения пульсовой волны, врачи-диагносты получают важную информацию о состоянии сердечно-сосудистой системы пациента. Ско- рость распространения пульсовой волны прямо зависит от жесткости стенок сосу- дов. С возрастом сосуды теряют эластичность, и скорость волны возрастает. До 26 лет скорость волны у здорового человека составляет, в среднем, 7,5 м/с, а в 45 лет — 8 м/с. У гипертоников (людей, страдающих повышенным артериальным давлением) скорость пульсовой волны значительно увеличена. В стандартной методике скорость прохождения пульсовой волны традиционно из- меряется при помощи фото- или пьезодатчиков, установленных в области сонной и бедренной артерий. По разнице времени срабатывания датчиков определяется ско- рость прохождения волны. Но в последнее время, благодаря появлению недорогих и распространенных электрокардиографов и пульсометров, все чаще применяют комбинированный метод: определяют момент рабочего сокращения сердца по кар- диограмме, а приход пульсовой волны в конечную точку фиксируют при помощи плетизмографа (оптического пульсометра). Зная интервал времени между толчком сердца и появлением фронта волны в конечной точке, можно вычислить скорость волны. В условиях домашней или школьной лаборатории мы можем воспользоваться ком- бинацией двух уже знакомых нам приборов: пульсометра (см. главу 6) и электро- кардиографа (см. главу 75). Даже такое несложное оборудование позволяет изме- рить скорость пульсовой волны с приемлемой точностью. Приведенное в этой книге упрощенное описание электрокардиографии и измери- тельных устройств на базе Arduino предназначено только для общих образователь- ных целей и расширения кругозора читателей. Не используйте эти устройства для самостоятельной постановки диагноза. При подозрении на наличие сердечно- сосудистого заболевания незамедлительно обратитесь к врачу.
Глава 16. Измеритель скорости пульсовой волны 289 ЛТ 600 - 300 200 - 349800 349900 350000 350100 Рис. 16.1. Принцип измерения скорости пульсовой волны комбинированным методом Левый желудочек сердца Путь пульсовой волны Сенсор пульсометра Рис. 16.2. Измерение длины пути пульсовой волны
290 Часть II. Теория и практика Для вычисления скорости пульсовой волны мы будем измерять интервал времени АГ между R-пиком электрокардиограммы и пиком наполнения кровью сосудов пальца (рис. 16.1), а также измерим длину пути от сердца до места приложения сенсора пульсометра (рис. 16.2). Скорость пульсовой волны вычисляется по фор- муле: где Ур„— скорость пульсовой волны, м/с; АГ— интервал времени между фронта- ми ЭКГ и плетизмограммы, сек; L — длина пути волны в теле пациента в метрах. 16.1. Схема и макет измерительного устройства Схема электрических соединений этого проекта изображена на рис. 16.3. Еще раз напомню, что устройства, у которых электроды непосредственно контактируют с телом человека, должны быть гальванически развязаны с компьютером, чтобы устранить опасность поражения электрическим током. Поэтому мы воспользуемся модулем Bluetooth (для беспроводной связи с компьютером) и питанием от бата- Рис. 16.3. Схема электрических соединений измерителя скорости пульсовой волны
Глава 16. Измеритель скорости пульсовой волны 291 рейного источника (на схеме он не показан). Внешний вид макета измерительного устройства приведен на рис. 16.4. Исходный код прошивки измерителя представлен в листинге 16.1. Для отобра- жения графиков хорошо подходит графопостроитель Serial Port Plotter (см. разд. 5.1.2). Это приложение позволяет просматривать входные данные в спе- циальном окне терминала и гибко настраивать масштаб графиков по осям X и Y. Рис. 16.4. Внешний вид макета измерителя скорости пульсовой волны // Библиотека программного последовательного порта #include <SoftwareSerial.h> #define THRESHOLD_ECG 500 // Порог фиксации фронта импульса ЭКГ #define THRESHOLD_PULSE 500 // Порог фиксации фронта импульса кровотока // Создаем программный последовательный порт SoftwareSerial mySerial(2, 3); // RX, TX uint32_t sensorECG, sensorPulse, pulse; uint32_t millisECG, millisPulse, millisWave; byte flagECG, flagPulse;
292 Часть II. Теория и практика void setup() { // Активируем программный последовательный порт mySerial.begin(115200); // Линии контроля за исправностью электродов pinMode(4, INPUT); // Вход линии LO+ pinMode(5, INPUT); // Вход линии LO- // АО - вход сигнала ЭКГ // А1 - вход сигнала пульсометра // Встроенный светодиод платы Arduino pinMode(LED_BUILTIN, OUTPUT); void loop() { // Проверяем исправность электродов if ((digitalRead(4) ==1) || (digitalRead(5) ==1)) { // Гасим встроенный светодиод, пропускаем цикл digitalWrite(LEDJBUILTIN, LOW); } // Если электроды исправны, приступаем к обработке данных else { // Включаем встроенный светодиод digitalWrite(LED_BUILTINf HIGH); sensorECG = analogRead(AO); sensorPulse = analogRead(Al); pulse = map(sensorPulse, 200, 1023, 200, 600); // Фиксируем фронт R-пика ЭКГ if ((flagECG == 0) && (sensorECG > THRESHOLD_ECG)) { millisECG = millisO; flagECG = 1; // Фиксируем фронт импульса пульсометра в пальце if ((flagECG == 1) && (flagPulse = 0) && (pulse > THRESHOLD_PULSE)) { millisPulse = millisO; flagPulse = 1; // Если зафиксированы оба фронта, вычисляем интервал if ((flagECG == 1) && (flagPulse == 1)) { millisWave = millisPulse - millisECG; flagECG = 0; flagPulse = 0;
Глава 16. Измеритель скорости пульсовой волны 293 // Данные в формате Serial Port Plotter mySerial.print("$") ; mySerial.print(sensorECG); mySerial.print(" "); mySerial.print(pulse); mySerial.print(" "); mySerial.print(millisWave); mySerial.print(";"); // Данные в формате встроенного плоттера Arduino IDE //Serial.print(sensorECG); //Serial.print(" "); //Serial.print(pulse); //Serial.print(" "); //Serial.println(millisWave); // Небольшая пауза для выгрузки данных в порт delay(3); Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). В этом скетче для связи с внешним устройством используется виртуальный после- довательный порт, к которому подключен адаптер Bluetooth. В главном цикле постоянно проверяется исправность электродов электрокардио- графа. Если хотя бы на одном из выводов (lo+ или lo-) присутствует высокий логи- ческий уровень, то гаснет встроенный светодиод платы, и пропускается цикл изме- рения. Если электроды исправны, считываем текущие уровни аналоговых сигналов на входах до и А1. Здесь есть очень важный нюанс, о котором мы поговорим позже, когда будем вычислять скорость пульсовой волны. Наша главная техническая задача — найти восходящие фронты пиков сигнала на входах до и А1 и зафиксировать точное время обнаружения фронтов. Причем необ- ходимо правильно определить порядок фронтов: сначала зафиксировать время об- наружения пика ЭКГ, а затем время обнаружения пика пульсометра. Если мы пере- путаем фронты сигналов, то неправильно измерим задержку между ними. Чтобы исключить ошибку, воспользуемся двумя флагами событий: f lagECG и f lagPuise. В начальном состоянии оба флага равны нулю. В каждом цикле измерения прове- ряем, не превысил ли сигнал на выходе электрокардиографа пороговый уровень: if ((flagECG == 0) && (sensorECG > THRESHOLD_ECG)) { millisECG = millisO;
294 Часть II. Теория и практика flagECG = 1; } Если флаг события был равен нулю, и порог превышен, значит, обнаружен нарас- тающий фронт R-пика кардиограммы. Фиксируем текущее время в миллисекундах и поднимаем флаг события. Далее приступаем к проверке уровня сигнала на выходе пульсометра: if ((flagECG == 1) && (flagPulse = 0) && (pulse > THRESHOLD_PULSE)) { millisPulse = millisO; flagPulse = 1; } Если флаг события flagECG установлен в единицу, а флаг flagPulse еще равен нулю, значит, R-пик уже обнаружен, и можно искать пик сигнала пульсометра — проверять сигнал на превышение порога. Как только обнаружено превышение порога, фиксируем текущее время в миллисекундах и поднимаем второй флаг со- бытия. Теперь можно вычислить разницу между временем обнаружения R-пика кардио- граммы и временем обнаружения импульса кровотока в пальце: if ((flagECG == 1) && (flagPulse ==1)) { millisWave = millisPulse - millisECG; flagECG = 0; flagPulse = 0; } Значение millisWave соответствует времени распространения пульсовой волны от левого желудочка сердца до кончика пальца, на котором размещен датчик пульсо- метра. Здесь начинающие разработчики могут совершить распространенную ошибку. Дело в том, что аналого-цифровой преобразователь микроконтроллера не срабатывает мгновенно. Скорость работы встроенного АЦП зависит от настроек режима микро- контроллера. В режиме по умолчанию платы Arduino на основе микропроцессора ATmega328 выполняют оцифровку сигнала за 100 миллисекунд. Во время работы АЦП никакие другие команды программы не выполняются, но встроенный счетчик миллисекунд продолжает работать! Таким образом, каждое обращение к АЦП добавляет погрешность 100 миллисекунд к условному времени обнаружения события. Это не имеет значения, если мы, напри- мер, измеряем период следования импульсов на одном и том же входе. Ведь в таком случае шкала условного времени программы просто смещается относительно физи- ческой шкалы времени сигнала, но это не меняет интервал между импульсами одно- го и того же сигнала. Совсем другое дело, когда мы измеряем переменный интервал между импульсами двух разных сигналов. Посмотрите на эти строки кода в листинге программы: sensorECG = analogRead(AO); sensorPulse = analogRead(Al); Вторая строка начнет выполняться только спустя 100 миллисекунд после начала отработки первой строки! Поэтому выборки сю входа ai будут смещены относительно
Глава 16. Измеритель скорости пульсовой волны 295 выборок со входа до на 100 миллисекунд. Эту задержку необходимо вычесть из ре- зультата измерения. Кроме того, микроконтроллер расходует время на выполнение других команд про- граммы. Здесь ситуация еще сложнее, потому что скорость выполнения кода про- граммы зависит даже от версии компилятора языка высокого уровня, на котором написана программа. Вы можете подобрать точное калибровочное значение задерж- ки, но стоит обновить версию компилятора, и придется заново калибровать устрой- ство. Опытные разработчики в таких случаях используют вставки кода на языке ас- семблера (языке команд процессора) или применяют фиксированную версию компи- лятора. Строго говоря, на точность измерений влияет еще и крутизна фронтов импульсов, а также фазовые задержки в схемах электрокардиографа и пульсометра. Но влияние этих факторов, как и влияние версии компилятора на скорость выполнения кода, очень трудно предугадать. Поэтому дальнейшее увеличение точности измерений возможно только за счет сравнительной калибровки своего устройства при помощи профессионального медицинского оборудования. Описание методов точного определения тайминга — времени выполнения команд программы — выходит за рамки этой книги. Ограничимся лишь тем, что из изме- ренного значения интервала miiiiswave при окончательном расчете скорости пуль- Рис. 16.5. Графики сигналов измерителя скорости пульсовой волны в графопостроителе Serial Port Plotter
296 Часть II. Теория и практика совой волны будем вычитать 100 миллисекунд, затраченных на второе преобразо- вание, и еще 100 миллисекунд на остальные операции— итого 200 миллисекунд. Это поправочное значение было подобрано экспериментально при помощи качест- венного двухканального осциллографа, на входы которого подавали сигналы с кар- диографа и пульсометра. Измерительный цикл завершается выводом в последовательный порт текущих выборок сигналов и «сырого» значения интервала AT, По этим данным графопо- строитель Serial Port Plotter строит графики (рис. 16.5). Кривая (1)— это график электрокардиограммы, кривая (2) — график сигнала на выходе оптического пуль- сометра. Линия (3) показывает измеренное значение интервала А Т между фронтами сигналов (1) и (2). Графики предназначены для контроля над формой сигналов, по- ступающих с измерительных модулей. Точные цифровые значения отображаются в окне терминала под панелью графиков. 16.2. Измерение скорости пульсовой волны Запустите графопостроитель Serial Port Plotter и подключите его к виртуальному последовательному порту Bluetooth на скорости 115 200 бод. Установите настройки PLOT CONTROLS, как показано на рис. 16.5. Пока электроды электрокардиогра- фа не подключены к коже, данные не будут поступать в графопостроитель, а встро- енный светодиод на плате Arduino не будет гореть. Прикрепите электроды к телу, как показано на рис. 16.2. Закрепите сенсор пульсо- метра на подушечке среднего или безымянного пальца левой руки. Добейтесь того, чтобы на графопостроителе отображались чистые и качественные сигналы с нуж- ной амплитудой. Амплитуда выходного сигнала аналогового пульсометра очень сильно зависит от плотности прилегания сенсора, расположения сенсора и индиви- дуальных особенностей кожи и сосудов. Возможно, придется в коде программы настроить масштабирование сигнала пульсометра в строке: pulse = map(sensorPulse, 200, 1023, 200, 600); и подобрать порог обнаружения импульса: #define THRESHOLD_PULSE 500 Теперь можно приступать к сеансу измерения. Во время измерения нельзя двигать- ся. Рекомендуется на некоторое время задержать дыхание. Определите значение интервала между фронтами miiiiswave по линии Channel 2 на графике или по третьему столбцу чисел в окне терминала. Программа не фильтрует и не усредняет результаты измерений — добавление этих функций будет вам заданием для само- стоятельной работы. Запишите «сырые» результаты измерений. Вычтите из них поправочную константу 200. При помощи мягкого портновского метра или рулетки измерьте длину пути пульсовой волны Z, как показано пунктирной линией на рис. 16.2. Вычислите ско- рость пульсовой волны, не забывая перевести миллисекунды в секунды.
Глава 16. Измеритель скорости пульсовой волны 297 Во время работы над книгой я провел измерения на себе и получил такие резуль- таты: 1. Интервал между фронтами после вычитания поправки: 0,125...0,134 сек. 2. Длина пути пульсовой волны: 0,98 м. 3. Скорость пульсовой волны при крайних значениях измерительных выборок: • (1/0,125)х0,98 = 7,84 м/с • (1/0,134)х0,98 = 7,31м/с 4. Среднее арифметическое значение скорости (7,31 + 7,84) / 2 = 7,58 м/с. Полученное значение скорости пульсовой волны соответствует показателям здоро- вого человека среднего возраста. 16.3. Задания для самостоятельной работы 1. Доработайте программу, чтобы она могла работать с цифровым пульсоксимет- ром МАХ3102, о котором рассказано в главе 11. 2. Добавьте в программу усреднение результатов измерения интервала между фронтами. Например, пусть программа накапливает массив из 100 измерений, сортирует элементы массива по нарастанию, отбрасывает 10 первых и 10 по- следних элементов массива, а по оставшимся вычисляет среднее арифметиче- ское и выводит результат в терминал. Пример сортировки массива с отбрасыва- нием значений можно найти в главе 13. 3. Добавьте в схему кнопку, по нажатию которой будет начинаться сеанс измере- ния с накоплением/усреднением, а также звуковую индикацию начала и конца сеанса измерения. 4. Добавьте в программу автоматическое масштабирование сигнала оптического пульсометра при помощи программного подбора параметров функции тар (). 5. Проведите сеансы измерения у людей разного возраста. По возможности срав- ните скорость пульсовой волны у подростков и пожилых людей.
ГЛАВА 17 Измерение биопотенциала мышц Эта глава завершает книгу. Если вы внимательно изучили и самостоятельно вы- полнили проекты из предыдущих глав, то сейчас готовы к работе над проектом, который открывает большой простор для самостоятельного творчества. В главе 15 мы обсуждали измерение биопотенциала, возникающего при сокраще- нии сердечной мышцы. При сокращении любых других мышц также возникает разность электрических потенциалов, которую можно зарегистрировать при помо- щи чувствительной электронной схемы. График изменения биологического потен- циала мышцы называется миограммой, а процесс измерений — миографией. В отличие от кардиографии, где расположение электродов (точек отведения) жест- ко нормировано, в миографии применяют разные схемы размещения электродов — ведь в человеческом организме очень много мышц, работу которых нужно прове- рить. Некоторые из этих мышц очень маленькие. Но зачем врачи и ученые измеряют биопотенциал различных мышц? Анализируя миограмму, опытный врач может определить наличие различных заболеваний или уточнить имеющийся диагноз. По миограмме можно диагностировать не только заболевания самих мышц, но и скрытые заболевания периферийной нервной систе- мы, заболевания головного мозга и даже психические расстройства. Наиболее часто при диагностике снимают миограмму жевательных мышц, мимических мышц, силовых мышц рук и ног и даже мышц глазного века. Существуют различные способы миографии. Например, очень часто при миогра- фии слабым электрическим разрядом возбуждают нерв, идущий к мышце, а затем регистрируют изменение биопотенциала при ее сокращении. Для точного измере- ния слабых потенциалов, особенно в небольших мышцах, используют игольчатые электроды, которые вводят в мышцу или под кожу. Эти способы вызывают непри- ятные ощущения у пациента и требуют наличия медицинской квалификации иссле- дователя. Наиболее простой и абсолютно безболезненный способ регистрации биопотенциа- ла мышц заключается в прикладывании внешних электродов к коже и регистрации потенциалов, возникающих при естественном сокращении мышцы. Этим простым способом мы и воспользуемся. А для получения миограммы применим уже знако-
Глава 17. Измерение биопотенциала мышц 299 мый вам из главы 15 модуль трехточечного электрокардиографа на микросхеме AD8232. Однако у этого модуля есть некоторые ограничения по использованию в качестве регистратора биопотенциалов мышц. Электрические цепи фильтра низ- кой частоты и автоматической регулировки усиления модуля настроены на выделе- ние регулярных импульсов с частотой и амплитудой сердцебиения. Поэтому не все импульсы биотоков мышц одинаково хорошо поддаются наблюдению при помощи стандартного модуля электрокардиографа. Так что для большей наглядности мио- граммы вам придется опытным путем подобрать частоту и силу сокращения иссле- дуемой мышцы, а также места расположения электродов. 17.1. Изготовление и подключение электродов для миографии Для регистрации биопотенциала мышц можно воспользоваться готовыми электро- дами из набора электрокардиографа (см. рис. 15.4). Но, как уже отмечалось в гла- ве 75, такие электроды быстро теряют липкость и отклеиваются от кожи при со- кращении мышц. Поэтому я рекомендую усовершенствовать имеющиеся электро- ды или изготовить самодельные контактные пластины с креплениями. В этом вам предоставлена полная свобода творчества. Вы можете изготовить электроды на за- стежках-липучках, на резинках, на лейкопластыре или даже на присосках. Важно лишь, чтобы конструкция фиксатора обеспечивала надежный контакт с кожей и постоянное усилие прилегания. Если усилие прилегания не будет постоянным, миограмма окажется сильно искажена, а при сокращении и расслаблении мышцы чувствительный прибор станет регистрировать ложные импульсы. В качестве учебного примера измерим биопотенциал бицепса — мышцы, которая сгибает руку в локте. Расположение точек отведения показано на рис. 17.1. Рефе- ренсный электрод крепится чуть выше локтя с обратной стороны руки. В этой же точке следует крепить референсный электрод при измерении биопотенциалов мышц, сгибающих и разгибающих пальцы руки. Измерительные электроды Референсны электрод Рис. 17.1. Расположение электродов для регистрации биопотенциалов бицепса
300 Часть II. Теория и практика 17.2. Измерение биопотенциала бицепса Первым делом подготовим измерительное оборудование. Подключите к плате Arduino модуль электрокардиографа и модуль Bluetooth, как показано на рис. 15.6. Еще раз напоминаю, что при подключении электродов к телу человека необходимо обеспечить надежную гальваническую развязку между схемой устройства и ком- пьютером, который подключен к сети 220 вольт. В качестве гальванической развяз- ки мы используем беспроводное соединение по Bluetooth, а макет устройства пита- ем от батарейного источника питания (на рис. 15.6 он не показан). Загрузите в контроллер Arduino скетч из листинга 17.1. // Библиотека программного последовательного порта #include <SoftwareSerial.h> // Создаем программный последовательный порт SoftwareSerial mySerial(2, 3); // RX, TX void setup() { // Активируем программный последовательный порт mySerial.begin(115200); // Линии контроля за исправностью электродов pinMode(4, INPUT); // Вход линии LO+ pinMode(5, INPUT); // Вход линии LO- // Встроенный светодиод платы Arduino pinMode(LED_BUILTIN, OUTPUT); void loop () { // Проверяем исправность электродов if ((digitalRead(4) ==1) || (digitalRead(5) ==1)) { // Выводим сообщение в порт mySerial.println("Check electrode!"); // Гасим встроенный светодиод digitalWrite(LED_BUILTIN/ LOW); } // Если электроды исправны, выводим в порт данные для графика else { // Включаем встроенный светодиод digitalWrite(LED_BUILTIN, HIGH); // Данные в формате FlexyPlot //mySerial.print("{Р0IECG|0,0,255|");
Глава 17. Измерение биопотенциала мышц 301 //mySerial.print(analogRead(АО)); //mySerial.printlnC1}") ; // Данные в формате Serial Port Plotter mySerial.print("$"); mySerial.print(analogRead(AO)); mySerial.print(";"); // Данные в формате встроенного плоттера Arduino IDE //mySerial.printIn(analogRead(АО)); } // Небольшая пауза для выгрузки данных из порта • delay(1); Электронный архив Напомню, что исходные коды программ (листинги), приведенные в книге, можно най- ти в сопровождающем ее электронном архиве (см. приложение 1). Как и в предыдущих примерах использования модуля электрокардиографа, мы по- стоянно проверяем состояние выводов L- и L+. Если хотя бы на одном из выводов присутствует логический уровень, это означает обрыв в цепи электродов. В таком случае пропускаем измерение и гасим встроенный светодиод платы Arduino. Если с электродами все в порядке, то оцифровываем аналоговый сигнал на входе до и выводим числовое значение в последовательный порт. Запустите графопостроитель Serial Port Plotter и задайте следующие параметры графика: ♦ POINTS: 3000; ♦ YSTEP: 10; ♦ MIN:0; ♦ MAX: 1000. Не забудьте выбрать номер порта, который соответствует соединению по Bluetooth на вашем компьютере, а также скорость соединения 115 200 бод. Подключите электроды, как показано на рис. 17.1, и попробуйте наблюдать мио- грамму. В качестве нагрузки используйте тяжелую гантелю, гирю или упор для ру- ки. Статический упор хорош тем, что бицепс напрягается, но рука не сгибается в локте. В этом случае будут менее заметны помехи от движения руки. На рис. 17.2-17.5 показаны графики биопотенциала, снятые автором с бицепса ле- вой руки. Рисунок 17.2 демонстрирует характерный пример волнообразного импульса, воз- никающего при сокращении расслабленной и хорошо отдохнувшей мышцы. Сна- чала волокна мышцы вырабатывают положительный потенциал, но затем следует фаза реполяризации, которая относительно среднего уровня выглядит как отрица- тельная полуволна.
302 Часть II. Теория и практика Рис. 17.2. Типичная миограмма единичного сокращения бицепса На рис. 17.3 представлен график биопотенциала бицепса, слегка «засоренный» ра- ботой других мышц руки. 1000' 300 600 400 200 -; 9831.00 984000 V Л А ) 1 1 984500 \ 585000 Л К ) 1 t 985500 Channel 0 . , 1 » f , , *, 986000 Рис. 17.3. Миограмма бицепса с помехами от работы других мышц руки На рис. 17.4 показана миограмма утомленной мышцы, которая предварительно вы- полняла напряженную работу — многократное поднятие тяжелой гантели. Форма импульсов стала сильно отличаться от первоначальных плавных и округлых волн, а на спаде положительной полуволны наблюдается частая рябь. Это так называе- мый мелкий тремор (дрожание) мышцы. Наконец, на рис. 17.5 изображена миограмма мышцы, которая сильно и статично напряжена относительно долгое время. В данном случае мы наблюдаем только ин- тенсивный мышечный тремор, который на графике выглядит как шум.
Глава 17. Измерение биопотенциала мышц 303 Рис. 17.4. Миограмма утомленной мышцы с признаками тремора 10004- Channel 0 1,0375-Ю6 1,038 10е 1,0385'10* 1,039 10й 1,0395 105 Рис. 17.5. Тремор при статическом напряжении мышцы 17.3. Миография в прикладных проектах Начинающие разработчики-любители иногда пытаются использовать миографию в проектах по дистанционному управлению персонажами в компьютерных играх или роботизированной рукой-манипулятором. Такие проекты привлекательно выглядят в замыслах, но редко достигают успеха на практике. Давайте обсудим основные проблемы, с которыми сталкиваются разработчики. Тщательно обдумай- те эти проблемы, прежде чем приступать к разработке собственного проекта.
304 Часть II. Теория и практика 17.3.1. Переменный волнообразный сигнал С миографией было бы намного проще работать, если бы мышцы при напряжении вырабатывали постоянный потенциал, уровень которого был бы прямо пропорцио- нален силе напряжения мышцы. Увы, это не так. В момент сокращения мышца вырабатывает волнообразный сигнал (см. рис. 17.2), а при продолжительном ста- тическом напряжении начинает вырабатывать шумообразный сигнал тремора (см. рис. 17.5). Поэтому не удастся считывать текущий биопотенциал мышцы и пропорционально его уровню вырабатывать сигнал управления сервомашинкой или другим механизмом. Программа считывающего устройства должна не просто измерять биопотенциал, а выделять так называемые паттерны — фрагменты сиг- нала определенной формы, которые сигнализируют о работе мышцы. Для полно- ценного анализа работы конечности необходимо одновременно следить за паттер- нами биотоков как мышц-сгибателей, так и мышц-разгибателей. Например, для от- слеживания сгибания руки в локте необходимо измерять биопотенциал как бицепса, так и трицепса (см. рис. 17.1). Это значит, что требуется устройство, как минимум, с четырьмя электродами. При анализе более сложных движений количе- ство электродов (точек отведения) резко возрастает. 17.3.2. Нестабильный сигнал с помехами В отличие от кардиограммы, при снятии которой пациента можно попросить ле- жать неподвижно, миограмма мышц конечностей, совершающих движения, обычно искажена за счет переменного контакта электродов с кожей и влияния биопотен- циалов соседних мышц. Большое влияние на амплитуду и форму сигнала оказыва- ют анатомические особенности конкретного организма и даже физиологическое состояние организма в тот или иной момент (болезни, усталость). 17.3.3. Необходимость значительных аппаратных и вычислительных ресурсов Для надежного узнавания и выделения паттернов из искаженного и засоренного помехами сигнала требуется большой объем оперативной памяти и достаточно мощный процессор. Тем более, как мы уже говорили, для полноценного анализа движений конечности необходимо многоканальное оборудование. Поэтому требо- вания к вычислительной мощности устройства превосходят возможности плат Arduino на основе контроллеров Atmel. В данном случае нужны более мощные одноплатные компьютеры— например, Raspberry Pi или Omega21. В крайнем слу- чае можно использовать микроконтроллеры серии STM32. Описание одноплатных компьютеров и методов программирования для них выхо- дит за рамки этой книги. Но все же я хочу кратко упомянуть о интересном совре- 1 Про микрокомпьютер Omega2 подробно рассказано в книге «От Arduino до Omega. Платформы для мейкеров шаг за шагом», http://bhv.ru/books/book.php?id=198923.
Глава 17. Измерение биопотенциала мышц ЗОЦ менном методе решения задачи распознавания паттернов сигнала. Этот метод при- меним не только к миографии, но и во многих других областях. Благодаря быстродействующему беспроводному Интернету появилась возмож- ность «на лету» отправлять данные для обработки и распознавания в мощную са- мообучающуюся нейросеть. Манипулятор или протез, реагирующий на биотоки мышц, можно научить распознавать биотоки конкретного человека. На этапе обу- чения пациент выполняет стандартные движения, а измерительный модуль отправ- ляет в нейросеть данные в режиме реального времени. Нейросеть распознает и выделяет стандартные паттерны движений из индивидуального набора сигналов, а затем выгружает в память манипулятора набор наиболее характерных паттернов и соответствующие им команды движений. Далее манипулятор работает автономно, опираясь только на свой процессор. В такой системе наибольшую сложность представляет начальное обучение нейро- сети, потому что для обучения необходимо накопить большое количество образцов сигналов, которые соответствуют заведомо известным сочетаниям движений. Речь идет о миллионах обучающих образцов. Собрать такой объем достоверных дан- ных — очень сложная задача, но зато правильно обученные нейросети демонстри- руют высокое качество распознавания паттернов. Буквально несколько лет назад нейросети были экзотической новинкой и предме- том исследований серьезных научных коллективов. Но сегодня фреймворки (набо- ры программных решений) для работы с нейросетями доступны студентам, школь- никам и простым разработчикам-любителям. Дерзайте и придумывайте новые проекты, уважаемые читатели. У вас все полу- чится!
ПРИЛОЖЕНИЯ Приложение 1. Содержимое электронного архива Приложение 2. Источники питания для проектов Arduino Приложение 3. Коэффициенты излучения поверхности различных материалов
ПРИЛОЖЕНИЕ 1 Содержимое электронного архива Электронный архив, сопровождающий книгу, содержит все приведенные в ее лис- тингах исходные коды (табл. П1.1). Сам электронный архив к книге выложен на FTP-сервер издательства «БХВ-Пе- тербург» по адресу: ftp://ftp.bhv.ru/9785977540681.zip. Ссылка доступна и со стра- ницы книги на сайте www.bhv.ru. Таблица П1.1. Содержимое электронного архива Файл/каталог DustSensorTest.xIsm l2C_scanner listing-3.1 listing-3.2 listJng-3.3 listing-3.4 listing-3.5 listing-3.6 listing-4.1 listing-4.2 listing-4.3 listing-4.4 listing-5.1 listing-5.2 listing-5.3 listing-5.4 listing-5.5 Описание Готовый файл Excel со встроенным макросом PLX-DAQ Простая утилита Arduino для поиска устройств на шине I2C Пример использования встроенного класса Serial Пример использования библиотеки Wire для работы с шиной I2C Исходный код сканера шины I2C Пример чтения ID ключа iButton DS1990A по шине 1-Wire Пример использования библиотеки SPI Скетч для проверки передачи данных по Bluetooth Демонстрационный скетч для модуля ENC28J60 Проверочный пример для шилда Ethernet W5100 Демонстрационный скетч подключения ESP8266 Пример использования шилда Dragino Yun и консоли Linux Пример работы со встроенным плоттером Arduino IDE Пример работы с графопостроителем Serial Port Plotter Пример работы с графопостроителем FlexiPlot Пример отображения динамической диаграммы в FlexiPlot Пример работы с расширением PLX-DAQ
310 Приложение 1 Таблица П1.1 (продолжение) Файл/каталог listing-5.6 listing-5.7 listing-5.8 listing-5.9 listing-5.10 listing-6.1 listing-6.2 listing-6.3 listing-7.1 listing-7.2 listing-7.3 listing-7.4 listing-8.1 listing-8.2 listing-9.1 listing-9.2 listing-9.3 listing-10.1 listing-10.2 listing-11.1 listing-11.2 listing-11.3 listing-12.1 listing-12.2 listing-12.3 listing-13.1 listing-13.2 listing-13.3 listing-14.1 listing-14.2 listing-15.1 Описание Пример подключения к панели Adafruit IO по Wi-Fi Пример подключения к панели Adafruit IO no Ethernet Шаблон скетча для проектов с OLED-дисплеем Шаблон скетча для проектов с дисплеем TFT 128x160 Шаблон скетча для проектов с дисплеем TFT 240x320 Проверочный скетч для аналогового пульсометра Скетч пульсометра с OLED-дисплеем Скетч пульсометра с цветным TFT-дисплеем Скетч для проверки акселерометра ADXL335 Передача данных акселерометра через Bluetooth в FlexiPlot Пример выделения импульсов шага из сигнала акселерометра Скетч шагомера на акселерометре ADX335 с OLED-дисплеем Доработанный скетч для пирометра MLX90615 Скетч инфракрасного пирометра с OLED-дисплеем и настройкой КИ Скетч для измерителя УФ-излучения с OLED-дисплеем Онлайновый мониторинг интенсивности УФ-излучения с беспроводным подключением к сети Интернет Онлайновый мониторинг интенсивности УФ-излучения с проводным подключением платы Arduino к сети Интернет Скетч измерителя ЭАК с аналоговым каналом Скетч для чтения данных ЭАК по интерфейсу SPI Наблюдение пульсации кровотока при помощи сенсора МАХ30102 Пример использования датчика приближения МАХ30102 Измерение частоты пульса и кислородной сатурации крови Пробный скетч для проверки модуля CCS811 Скетч монитора общего качества воздуха с OLED-дисплеем Скетч онлайн-монитора общего качества воздуха на базе ESP8266 Демонстрационный скетч для проверки датчика пыли Скетч для получения экспериментальных данных в проекте датчика пыли Пример реализации алгоритма обнаружения дыма в воздухе Демонстрация работы встроенного шагомера LIS2DS12 Исходный код прошивки цифрового шагомера с OLED-дисплеем Простой скетч для регистрации электрокардиограммы
Содержимое электронного архива 311 Таблица П1.1 (окончание) Файл/каталог listing-15.2 listing-16.1 listing-17.1 LIS2DS12.pdf ColourPICs.pdf Описание Исходный код прошивки кардиомонитора с цветным TFT-дисплеем Исходный код прошивки измерителя скорости пульсовой волны Скетч для регистрации колебаний мышечного биопотенциала Техническое описание (datasheet) акселерометра LIS2DS12 Цветные рисунки из книги
ПРИЛОЖЕНИЕ 2 Источники питания для проектов Arduino В процессе программирования и отладки макеты Arduino можно питать непосред- ственно от порта USB, к которому подключена плата контроллера. Но предельный ток нагрузки у большинства портов USB не превышает 500 мА. Если этого тока недостаточно, можно воспользоваться сетевым источником питания с выходным напряжением 7... 12 вольт, который подключается к разъему платы Arduino Uno или к модулю стабилизатора (рис. П2.1). Рис. П2.1. Модуль стабилизатора питания с выходными напряжениями +3,3 и +5 вольт Микроконтроллеры большинства плат Arduino питаются напряжением +5 вольт, но для современных сенсоров и микросхем обычно требуется напряжение питания +3,3 вольта. Организовать трехвольтовое питание модулей расширения можно од- ним из следующих способов: ♦ использовать отдельный внешний источник питания. Это самый надежный спо- соб, но он усложняет проект;
Источники питания для проектов Arduino 313 ♦ использовать встроенный стабилизатор питания +3,3 вольта в конвертере USB- UART (см. разд. 3.2.1). Такой конвертер установлен на платы Arduino Uno и Nano или подключается отдельно. Недостаток способа— потребляемый от микросхемы конвертера ток не должен превышать 50 мА. Превышение допус- тимого тока может привести к прерыванию связи с компьютером через порт USB и выходу из строя микросхемы конвертера; ♦ на платах Arduino Uno R3 и ее аналогах китайского производства (DCCduino, RobotDYN и др.) установлена отдельная микросхема стабилизатора питания AMS1117-3.3 (рис. П2.2), которая формирует питающее напряжение +3,3 вольта с рабочим током до 1,0 ампера (в пике до 1,5 ампера). Этого достаточно для пи- тания большинства любительских проектов. Рис. П2.2. Встроенные стабилизаторы питания +3,3 и +5 вольт на плате Arduino Uno R3 Внимательно изучите платы и компоненты, которые будете использовать в проектах. Определите ограничения и требования к питанию макетов. Пренебрежение требова- ниями к питающему напряжению приводит к непредсказуемой работе устройства и выходу микросхем и сенсоров из строя. В проектах этой книги применяется плата Arduino Uno R3, которая обеспечивает качественное питание трехвольтовых модулей через вывод 3.3V. Если вы исполь- зуете другую плату контроллера Arduino, самостоятельно выберите схему питания, опираясь на материал этого приложения. П2.1. Автономное питание макетов и устройств Для полноценной работы с большинством проектов этой книги мы должны обеспе- чить автономное питание устройства или макета. Сложно проводить опыты с ша- гомером или измерителем солнечной активности, если они привязаны проводом к стационарному компьютеру или к сетевому блоку питания.
314 Приложение 2 Наиболее очевидный вариант автономного питания — так называемый резервный аккумулятор (Power Bank) для подзарядки мобильных гаджетов: телефонов, плее- ров, планшетов (рис. П2.3). В прочном корпусе пауэрбанка находятся литий- полимерные аккумуляторы и плата зарядного устройства. Достаточно подключить провод USB макета своего проекта вместо компьютера к разъему аккумулятора — его емкости хватит на несколько часов работы макета. Рис. П2.3. Резервный аккумулятор для мобильных гаджетов Но резервный аккумулятор не всегда есть в наличии, он дорого стоит и много весит. Кроме того, такой аккумулятор неудобно использовать для опытов с измере- нием параметров организма в движении. Вы можете самостоятельно изготовить простые, легкие и недорогие источники питания для своих автономных устройств. П2.1.1. Источник питания на одной батарее ААА Специально для питания мобильных устройств от обычных «пальчиковых» батарей разработана серия микросхем NCP1402xx. Это повышающий преобразователь напряжения. К входу преобразователя подключается одна химическая батарея со стандартным рабочим напряжением 1,5 вольта. На выходе преобразователя, в зави- симости от номинала микросхемы, получается постоянное напряжение с одним из фиксированных значений: 1,9; 2,7; 3,0; 3,3; 4,0; 5,0 вольт. Номинал микросхемы обозначается комбинацией букв на корпусе. Например, микросхема NCP1402SN50T генерирует напряжение +5,0 вольт и обозначается буквами DAH на корпусе. Для работы преобразователя требуется минимальное количество внешних компонентов. Преобразователь NCP1402 обладает замечательной способностью стартовать при входном напряжении всего 0,8 вольта и продолжать работать при снижении вход- ного напряжения до 0,3 вольта. Иными словами, преобразователь практически пол- ностью «вытягивает» из обычной батарейки накопленную в ней электрическую энергию. По этой причине вместо обычных химических батарей нельзя использовать переза- ряжаемые аккумуляторы — они необратимо выйдут из строя при глубоком разряде до 0,3 вольта.
Источники питания для проектов Arduino 315 Для питания переносных устройств можно воспользоваться готовым недорогим пятивольтовым модулем на основе микросхемы NCP1402SN50T (рис. П2.4), кото- рый оснащен креплением пальчиковой батареи типоразмера ААА. На модуле есть выключатель питания, контрольный светодиод и самовосстанавливающийся предо- хранитель, который защищает преобразователь от короткого замыкания в нагрузке. Модуль можно найти в интернет-магазинах по ключевым словам LilyPad power supply. Рис. П2.4. Преобразователь питающего напряжения 1,5-5,0 вольт Для подключения преобразователя к плате Arduino припаяйте к выходным клем- мам преобразователя отрезок провода с штекером USB, который соответствует ти- пу гнезда USB на плате Arduino. Если под рукой нет подходящего провода USB, можно при помощи обычных проводов соединить клемму преобразователя со зна- ком «минус» — с выводом GND, а клемму со знаком «плюс» — с выводом VIN платы Arduino. Тщательно проверьте полярность подключения перед первой пода- чей питания на плату! П2.1.2. Заряжаемый источник питания на литий-полимерной батарее Автономный источник питания на пальчиковой батарейке очень прост и удобен в эксплуатации. Но использованные батарейки приходится выбрасывать. Это за- тратно и засоряет окружающую среду. Кроме того, удельная емкость солевых бата- реек в 6...8 раз меньше, чем у литий-полимерных аккумуляторов. Удельная емкость щелочных батареек (110-160 Втч/кг) сопоставима с удельной емкостью стандарт- ных литиевых аккумуляторов (110-240 Втч/кг). Но щелочные батарейки все равно приходится выбрасывать. Вы можете самостоятельно изготовить простой заряжаемый источник питания из двух недорогих модулей и литий-полимерного аккумулятора. Аккумулятор будет заряжаться от порта USB или обычного зарядного устройства для мобильных теле- фонов.
316 Приложение 2 Модули, из которых предлагается собрать заряжаемый источник питания, выбраны не случайно. Они идеально совместимы между собой по габаритам и расположе- нию выводов, недорого стоят и продаются в различных интернет-магазинах. Модуль повышающего преобразователя Модуль повышающего преобразователя можно найти в Интернете по ключевым словам МТ3608 boost converter. Два наиболее популярных и недорогих варианта платы изображены на рис. П2.5. Для полной конструктивной совместимости с за- рядным устройством я рекомендую приобрести вариант, показанный на рис. П2.5, а, но в остальном вариант, показанный на рис. П2.5, б, полностью идентичен по ха- рактеристикам. Вариант модуля, показанный на рис. П2.5, я, оснащен гнездом miniUSB, но в на- шем случае это гнездо не пригодится. а б Рис. П2.5. Варианты конструкции модулей повышающего преобразователя МТ3608 Основные технические характеристики модуля повышающего преобразователя ♦ Диапазон входных напряжений: 2...24 вольта ♦ Максимальное выходное напряжение: 28 вольт, плавная регулировка ♦ Максимальный ток нагрузки: 2 ампера ♦ Длительный ток нагрузки: I ампер Характеристики преобразователя позволяют подключить к нему один пальчиковый литий-полимерный аккумулятор или ячейку с напряжением 3,7 вольта и получить на выходе питающее напряжение 5 вольт. Модуль зарядного устройства Li-Po Модуль зарядного устройства для литий-полимерных аккумуляторов можно найти в интернет-магазинах по ключевым словам ТР4056 lithium charger. Вариант конст- рукции, который нам нужен, изображен на рис. П2.6.
Источники питания для проектов Arduino 317 Рис. П2.6. Зарядное устройство для литий-полимерного аккумулятора К разъему USB или расположенным по бокам клеммам «+» и «-» подключается источник зарядного тока. Это может быть порт USB компьютера или стандартный сетевой адаптер с выходным напряжением 5 вольт. Ячейка батареи или пальчико- вый литий-полимерный аккумулятор подключается к клеммам В+ и В-. Нагрузка подключается к клеммам OUT+ и OUT-. Потребитель может получать питание от внешнего источника одновременно с про- цессом заряда аккумулятора. Если во время работы внезапно отключить внешнее питание, зарядное устройство безразрывно переключает потребителя на питание от аккумулятора. Потребитель даже не заметит отключения внешнего источника и продолжит работать без перезагрузки. Зарядное устройство защищает аккумулятор от глубокого разряда и автоматически отключает нагрузку при разряде аккумулятора до напряжения около 2,4 вольта. Также на плате, показанной на рис. П2.6, имеется защита от кратковременной пе- реполюсовки батареи. Это актуально для пальчиковых аккумуляторов 18650, кото- рые можно неправильно установить в держатель. Будьте очень внимательны при подключении аккумулятора! Защита от переполюсовки работает несколько секунд, затем микросхема ТР4056 перегревается и выходит из строя. Другие варианты модулей на основе ТР4056 во- обще не имеют защиты от переполюсовки — микросхема мгновенно сгорает, и акку- мулятор в обратной полярности напрямую соединяется с внешним источником пита- ния и нагрузкой! Модуль оснащен двумя светодиодами: красный светодиод сигнализирует о процес- се заряда аккумулятора, синий — обозначает окончание заряда. Если аккумулятор не подключен, синий светодиод постоянно горит, а красный быстро вспыхивает. При длительной работе от внешнего источника питания синий светодиод иногда будет гаснуть, а красный— включаться, указывая на периодическую подзарядку батареи. Это нормальный процесс. Литий-полимерный аккумулятор К зарядному устройству подключается одиночный литий-полимерный аккумулятор с номинальным напряжением 3,7 вольта. Можно использовать цилиндрический аккумулятор 18650 с держателем (рис. П2.7, а) или литий-полимерную ячейку в пластиковой упаковке (рис. П2.7, б).
318 Приложение 2 Рис. П2.7. Литий-полимерный аккумулятор с держателем (а) и ячейка (б) для автономного источника питания Схема подключения и монтаж Схема соединения компонентов изображена на рис. П2.8. Для наглядности показа- но подключение аккумуляторной ячейки. Держатель для аккумулятора 18650 под- ключается аналогичным образом. вход зарядного устройства Зарядное устройство Повышающий преобразователь выход 5 вольт Li-Po-аккумулятор (ячейка) 3,7 вольта Рис. П2.8. Схема соединения компонентов заряжаемого автономного источника питания Чтобы готовый источник питания получился более компактным, платы зарядного устройства и преобразователя склейте между собой двусторонним вспененным скотчем, а выводы от OUT+ к VIN+ и от OUT- к VIN- соедините пропущенными насквозь через отверстия перемычками из луженого провода, как показано на рис. П2.9. Получившийся «сэндвич» затяните в широкую термоусадочную трубку или поместите в пластиковый корпус. Не будет лишним сделать в корпусе несколь-
Источники питания для проектов Arduino 379 ко вентиляционных отверстий. В этот же корпус можно \\o\\i\ > р •: и м-к-икч in i мм- полимерного аккумулятора, отделив ее от выступающих > юк .:. i \i мы к«|рюм- ной прокладкой. Рис. П2.9. Способ компактного монтажа модулей источник
ПРИЛОЖЕНИЕ 3 Коэффициенты излучения поверхности различных материалов Материал Алюминиевая фольга Алюминиевый лист Алюминий грубой обработки Алюминий полированный Алюминий сильно окисленный Асфальт Базальт Бериллий Бетон Бетонные плитки Бумага офисная Висмут Вода Вольфрам полированный Вольфрамовая нить Гипс серый Гипс белый Глинозем, обработка пламенем Гранит Дуб Железо полированное Железо (грубый слиток) Коэффициент излучения 0,04 0,09 0,07 0,039-0,057 0,2-0,31 0,93 0,72 0,18 0,85 0,63 0,55 0,34 0,95-0,963 0,04 0,032-0,35 0,85 0,98 0,8 0,45 0,91 0,14-0,38 0,87-0,95
Коэффициенты излучения поверхности различных материалов 321 (продолжение) Материал Железо (пластина, покрытая красной ржавчиной) Железо (темно-серая поверхность) Золото чистое, высокой полировки Инконель окисленный Кадмий Карбид кремния Каучук (мягкий) Каучук (твердая глянцевая пластина) Кирпич, огнеупорная глина Красный кирпич Ламповая сажа Латунь, окисленная при 600 °С Латунь полированная Лед Магний полированный Медная необработанная пластина Медно-никелевый сплав полированный Медь, нагретая и покрытая толстым окисным слоем Медь полированная Молибден полированный Мрамор белый Никель окисленный Никель полированный Окись магния Олово неокисленное Опилки Песок Пластмассы Платина (полированная пластина) Поверхность, обработанная прессованием углеродом Полость черного тела Провод нихромовый Коэффициент излучения 0,61 0,31 0,018-0,035 0,71 0,02 0,83-0,96 0,86 0,94 0,75 0,9 0,96 0,6 0,03 0,97 0,07-0,13 0,22 0,059 0,78 0,023-0,052 0,05-0,18 0,95 0,59-0,86 0,072 0,20-0,55 0,04 0,75 0,76 0,91 0,054-0,104 0,98 1 0,65-0,79
322 Приложение 3 (окончание) Материал Ртуть жидкая Свинец окисленный Свинец чистый неокисленный Серебро полированное Слой металла, нанесенный на медь гальваническим способом Сталь мягкая Сталь нержавеющая Сталь нержавеющая полированная Сталь нержавеющая 301 Стекло Стекло, пирекс Сурьма полированная Титан полированный Углерод не окисленный Углеродистая нить Фарфор глазурованный Хлопковая ткань Хром полированный Черная краска силиконовая Черная краска эмаль Черная краска эпоксидная Черная оптическая диафрагма Чугун после плавки Чугун после плавки и тепловой обработки Коэффициент излучения 0,1 0,43 0,057-0,075 0,02-0,03 0,03 0,20-0,32 0,85 0,075 0,54-0,63 0,92 0,85-0,95 0,28-0.31 0,19 0,81 0,77 0,92 0,77 0,08-0,36 0,93 0.8 0,89 0,95 0,44 0,60-0,70
Предметный указатель 1 1-Wire 21 А AD8232 277 Adafruit GFX, графическое ядро 109 Adafruit 10, АЮ 91 Arduino IDE 16 Arduino Mega 2560 R3 11 Arduino Mini 9 Arduino Nano 8 Arduino Uno R3 10 Arduino Yun61 ATmega2560 11 ATmega328 7 В Bluetooth 39 0 Low Energy 41 0 адаптер USB 44 0 модули НС-06 и НС-05 40 С СОМ-порт 23 Connected device См. Подключенное устройство D DHTll 101 Dragino Yun61 E ENC28J60 51 ESP8266 12 0 модули ESP-xx 15 F ■ FlexiPlot75, 152 G Galvanic Skin Response, GSR См. ЭАК 1 1 I2C21 0 ведомое устройство 29 0 ведущее устройство 29 iButton 33 Internet of Things, IoT См. Интернет вещей IrDA 23 м МАС-адрес 54 MATLAB 70 МАХ30100 209,210 МАХ30102 209 Microsoft Excel 70 N NaN, Not a Number 104 NodeMCU 14
324 Предметный указатель One Wire, библиотека 34 Online dashboard См. Онлайновая приборная панель Serial, встроенный класс 26 SoftwareSerial, встроенная библиотека 27 SP121 SPI, библиотека 37 PLX-DAQ81 Power over Ethernet, PoE 51 Proximity sensor См. Датчик приближения PuTTY, терминал 67 Raw data 91 RS-232 23 SD Card Formatter, утилита 56 Serial plotter 71 Serial Port Plotter 73, 198 Termite, терминал порта 28 TFT, технология 119 TVOC, Total Volatile Organic Compounds 226 и UART21,23 UVI См. Индекс УФ-излучения w W5100 55 WeMosDl 14 Wire, встроенная библиотека 30 Абсолютно черное тело 166 Абсолютное зеркало 166 Акселерометр 148 0 активная ось 154 0 собственный шум 152 Библиотека Arduino 18 Биопотенциал 298 Бицепс 299 Бутлоадер (загрузчик) 65 Буферы порта 27 Гамма-излучение 173 Гемоглобин 130,210 Гипоксия 211 Графические примитивы 111 Графопостроитель 70 Группа потоков данных 93 Датчик 0 касания 263 0 качества воздуха 224, 226 0 начала движения 262 0 приближения 218 0 свободного падения 262 Двунаправленная шина данных 22 Дезоксигемоглобин 210 Дельта сигнала 218 Дисплей 0 OLED 107, 108 0 монохромный строковый 107, 108 0 плотность изображения 110 0 система координат ПО 0 универсальный дисплейный шилд 125 0 цвет пиксела 110 0 цветной TFT 107, 108 Дистанционный термометр См. Пирометр Затягивание тактов шины I С 237
Предметный указатель 325 И Инверсный цвет 130 Индекс УФ-излучения 177 Интернет вещей 50 Интерфейс обмена даными 21 к КГР, кожно-гальваническая реакция См. ЭАК Конвертер USB-UART 24 О виртуальный порт 24 Контактный термометр 162 Контроллер 7 Космические лучи 173 Коэффициент излучения 166 л Логические уровни 22 О преобразователь уровней 22 О согласование уровней 22 м Миограмма 298 Миография 298 Модуль расширения 7 н Нейросеть 305 Обратный цвет См. Инверсный цвет Оксигемоглобин 210 Онлайновая приборная панель 91 Определение ориентации 263 Оптические датчики ЧСС 132 п Паразитное питание 33 Парниковые газы 227 Парниковый эффект 227 Паттерны 304 Пирометр 162 Пиросенсор 163 0 дистанция измерения 166 Платформа разработки См. Техническая платформа Плетизмография оптическая 129 Плоттер Arduino 71 Подключенное устройство 50 Порт COM, RS-232 22 0 бит четности 24 0 битрейт 24 0 бод (бит в секунду) 24 0 стартовый бит 24 0 стоповый бит 24 Поток данных 93 Протокол обмена данными 21 Пульсограмма 0 анакротическое колено 137 0 дикротическая волна 137 0 катакротическое колено 137 0 систолическая волна 137 Пульсоксиметр 209 Пульсометр 129 Расход калорий 158 Рентгеновское излучение 173 Референсный электрод 299 Рефлекс 0 Геринга 146 0 Даниелополу, клиностатический 146 0 Ортнера 146 0 Превеля, ортостатический 146 Самокалибровка акселерометра 263 Сатурация 211 Сенсор с горячей подложкой См. Элемент с горячей подложкой Скорость 0 движения частиц крови 288 0 пульсовой волны 147, 288 Солнечная активность 182 Средняя длина шага 158 Столбчатые диаграммы 78 Сфигмограмма 147 Сфигмография 147 Техническая платформа 7 Тремор мышцы 302
326 Предметный указатель Ультрафиолетовое излучение 173 О меры безопасности 188 О мягкое излучение, источники 189 ш Шагомер 148,262 ШилдЮ Формат данных 21 Фотосенсор 175 Хаб внешнего сенсора 263 Цифровой акселерометр 261 Частота сердечных сокращений 129 ЭАК 192 О измеритель проводимости кожи 193 О контакты сенсора 194 О обусловленный отклик 208 0 реакция спонтанная 193 0 реакция тоническая 193 0 реакция физическая 193 0 чтение графика 199 Эквивалентное количество двуокиси углерода 226 ЭКГ См. Электрокардиограмма Электрическая активность кожи См. ЭАК Электрокардиограмма 273 0 отведения 275 0 референсный электрод 275 0 Фазы 274 Элемент с горячей подложкой 224