ГЛАВА 22 Метеостанция на Arduino

Как на Arduino делать устройства лучше фирменных

Вдруг из темноты выступила какая-то фигура, очертания которой показались д'Артаньяну знакомыми, и привычный его слуху голос сказал.

— Я принес ваш плащ, сударь, сегодня прохладный вечер.

А. Дюма. Три мушкетера

Домашняя метеостанция — один из самых необходимых и оправданных радиолюбительских проектов. Как мы уже говорили, бытовые метеостанции, имеющиеся в продаже, не выдерживают никакой критики — ни с точки зрения удобства пользования и дизайна, ни с точки зрения метрологических качеств. Через руки автора этих строк прошло не менее десятка моделей бытовых метеостанций, и ни у одной из них работу нельзя было признать удовлетворительной. Дисплеи перенасыщены лишней информацией, значения температуры «разъезжаются», показатели влажности не совпадают на десятки процентов, в довершение всего станция все время теряет внешний радиодатчик и поймать его можно, только полностью отключив питание и тем самым потеряв настройки дисплея и часов…

Все эти проблемы не имеют никаких объективных предпосылок и явно возникают исключительно из-за халатности разработчиков и производителей. С помощью современной элементной базы они легко решаются на среднем любительском уровне при наличии минимального терпения и аккуратности. Единственное, возможно, узкое место, которое трудно преодолеть при самодеятельном конструировании, представляет собой дисплей — после ознакомления с ассортиментом того же «Чипа-Дипа» становится понятно, почему для почти каждого бытового прибора придумывают экран своей оригинальной конструкции. Но тут уж ничего не поделаешь, придется выбирать, что дают. В остальном Arduino позволяет подойти к конструированию метеостанции «по-взрослому» — не делая скидок на любительское происхождение при выборе функциональности. Поскольку мы станем ориентироваться на ассортимент готовых модулей, то результат окажется, как минимум, не дороже тех убогих произведений, которыми переполнены интернет-магазины домашней техники. При этом мы легко сможем реализовать дополнительные функции, которые либо присущи очень дорогим моделям, либо отсутствуют в промышленных образцах вовсе. Самое трудное, как всегда в таких случаях, — оформление конечного результата так, чтобы его было не стыдно повесить на стенку, но тут все в ваших руках.

Должен сказать, что в процессе отладки конструкции, описанной далее, производители комплектующих для Arduino не переставали меня удивлять. Я был готов к тому, что показания приобретенных датчиков придется корректировать программным путем, — совершенно невероятно, чтобы они на производстве подвергались уточняющей калибровке. Однако, датчики и без коррекции удовлетворяли требованиям!

А 2-милливаттный Xbee-радиодатчик спокойно работал через три межкомнатных перегородки — лучше фирменного роутера Wi-Fi в тех же условиях.

Техническое задание

Перед тем как приступать к проектированию, надо точно определить, к чему мы стремимся. Давайте сформулируем, что должна «уметь» и из каких основных узлов состоять домашняя метеостанция.

Главный модуль — измерение внутренней температуры (в месте установки), влажности и атмосферного давления. Питание от сети.

□ Выносной датчик внешней (уличной) температуры и влажности — связь с главным модулем по радиоканалу, питание от батарейки (а значит, функции энергосбережения). Связь должна надежно работать как минимум через оконный стеклопакет, а лучше — через бревенчатую (в идеале — кирпичную или бетонную) стенку, на расстоянии не менее 5–7 метров.

Часы реального времени с календарем — должны иметь автономное питание и возможность автоматической/полуавтоматической коррекции хода.

Дисплей главного модуля — внешняя температура/влажность, внутренняя температура/влажность, атмосферное давление, время, дата, день недели. Проработаем два варианта: с ЖК-модулем (тем, который описан в предыдущей главе) и с более эстетично выглядящим, но и существенно более дорогим светящимся экраном на основе OLED.

Запись показаний на SD-карту — этот пункт появился сам собой в процессе подбора комплектующих. Оказалось, что добавление этой функции в буквальном смысле ничего не стоит (в «Амперке» разница в цене между платами Wireless Shield просто и Wireless Shield SD с гнездом для карты MicroSD составляет 200 рублей). Такая возможность может оказаться полезной, например, школьнику, которого обязывают вести погодный дневник.

Метрологические требования — при установке выносного датчика рядом с главным модулем расхождение показаний по температуре желательно не более 0,5 °C, по влажности — не более 2 %. Абсолютное значение ошибки измерения температуры вблизи нуля градусов — не более 0,5 °C. Отметим, что погрешность барометра можно не нормировать — его показания в любом случае придется подгонять «по месту» по причинам, о которых далее.

Выбор компонентов и схема станции

Изучив каталог «Амперки» и сравнив на всякий случай с тем, что предлагают другие торговые организации, выберем следующие компоненты:

□ плату Arduino Uno (для главного модуля);

□ плату Arduino Mini (для выносного датчика);

□ сетевой блок питания 5 В, 1000 мА;

□ датчик температуры и влажности SHT1x (2 штуки: для главного модуля и выносного датчика);

□ барометр SEN05291P;

□ часы RTC на основе DS-1307;

□ ХЬее-радиомодуль (2 штуки: для главного модуля и выносного датчика);

□ плату расширения Wireless Shield SD;

□ ЖК-дисплей МТ-12864J или два OLED-индикатора WEH001602В.

Строчный матричный OLED-индикатор WEH001602В фирмы Winstar представляет собой дисплей с крупными (почти 10 мм) и яркими матричными символами, размещенными по 16 символов в 2 строки на каждом. К сожалению, более, чем двухстрочных дисплеев с символами достаточно большого размера не существует, поэтому придется идти на усложнение конструкции и ставить две штуки (зато можно подобрать их с разными цветами, чтобы разделить данные и время/дату). Два таких индикатора обойдутся в сумму почти, как три ЖК-дисплея MT-12864J, но зато они намного лучше выглядят и имеют меньше внешних соединений, что позволит освободить контакты платы Arduino Uno, задействованные во взаимодействии с SD-картой (в варианте с MT-12864J SD-карту использовать не получится). Индикаторы выпускаются в разных цветах, я выбрал желтый для метеоданных и зеленый для времени. Приобрести эти индикаторы может быть непросто — их не оказалось не только в «Амперке», но и в розничной продаже вообще, пришлось заказывать и ждать доставки.

Полная схема подключения всех компонентов для главного модуля станции в варианте с двумя такими OLED-индикаторами представлена на рис. 22.1. На схеме не показаны соединения с SD-картой (контакты D4 и D11-D13), а также подключение Xbee-модуля (питание 3,3 В и контакты последовательного порта D1 и D2) — все это осуществляется автоматически при установке платы Wireless Shield SD на плату Arduino. Естественно, также не показан сам последовательный порт, размещенный на плате Arduino. Версию с ЖК-дисплеем мы опишем позже, а сейчас рассмотрим последовательно особенности подключения и программирования каждого из компонентов.

Подключение строчных OLED-дисплеев

Как мы уже говорили, для строчных матричных экранов стандартный контроллер носит название HD44780. Для работы с ним имеется стандартная библиотека LiquidCrystal, входящая в состав Arduino IDE. С командами HD44780 совместим интерфейс любых подобных конструкций, причем и ЖК- и OLED-разновидностей, однострочных или многострочных. Потому необязательно применять именно WEH001602В (буква В в конце наименования в данном случае указывает на высоту строки, 1602 означает, что это 16 символов на 2 строки). Почти без изменения программы можно ставить в схему любой подобный индикатор, в том числе и других производителей. Однако фирма Winstar захотела несколько улучшить стандарт, и потому ее произведения все-таки имеют свои особенности, о которых мы поговорим далее.

В OLED-версии дисплеев отсутствует вывод управления контрастом Vo (вывод 3 индикатора не подключается), и также ни к чему не подсоединяются выводы 15 и 16, в ЖК-версии управляющие подсветкой. Правда, некоторые сетевые источники утверждают, что функциональность этих выводов можно восстановить путем перестановки некоторых перемычек на плате, и таким образом управлять яркостью свечения точек, но не очень понятно, зачем. Индикаторы WEH001602В могут работать как от питания 5 В, так и от питания 3,3 В, и именно от напряжения питания зависит яркость. Опыт показал, что нормальной яркости свечения дисплей достигает уже при 3,3 В. На схеме рис. 22.1 он подключен к питанию 5 В, при котором яркость в нормальных условиях явно избыточна. Однако я предполагаю, что передняя панель будет выполняться из прозрачного дымчатого пластика, затемняющего «потроха» прибора, так что в готовом изделии яркость окажется в самый раз.

Рис. 22.1. Схема главного модуля метеостанции с OLED-индикаторами

* * *

Подробности

Работа индикатора и контроллера от одного напряжения питания заодно позволит избавиться от необходимости соединять выходы Arduino со входами дисплея через резистивные делители согласования 5-вольтовых и 3-вольтовых уровней (так, как это будет делаться при подключении Xbee-модуля в выносном датчике, см. далее). А обязательно ли их устанавливать вообще? Зная, как устроены КМОП-входы микросхем (см. главу 15), мы можем ответить на этот вопрос совершенно точно. Что будет происходить, если выход с уровнем 5 В подключить ко входу микросхемы, питающейся от напряжения 3,3 В? Как только напряжение на входе превысит напряжение питания более, чем на 0,6 В, через защитный диод на входе потечет ток. Его величина зависит от разных факторов (от величины превышения напряжения, от мощности выходного транзистора, от сопротивления защитного диода в прямом направлении), и эксперимент показывает, что в данном случае ток составит порядка 2 мА на каждом выводе. То есть на семь подключенных в данном случае выводов величина дополнительного тока составит около 15 мА, что примерно удвоит потребление всей схемы Arduino Uno. Это не опасно для микросхем и не критично при питании прибора от сети, но может послужить источником неприятностей при батарейном питании и, тем более, при вводе схемы в режим энергосбережения. Именно по этой причине мы в дальнейшем в выносном датчике и озаботимся установкой делителей (в главном модуле благодаря плате Wireless Shield такой делитель на всякий случай уже установлен и без нашего вмешательства).

* * *

Потребление индикатора WEH001602В при питании 5 В, согласно фирменной документации, составит 43 мА. Обратите внимание, что это почти в полтора раза меньше, чем потребление ЖК-панели MT-12864J с включенной подсветкой. На самом деле потребление будет еще ниже — цифра в документации указывает на случай, когда засвечены все точки матрицы, в реальной жизни такого, конечно, не случается.

Контроллер WS0010

Модернизированный вариант стандартного контроллера HD44780 от Winstar носит незамысловатое наименование WS0010. Главное отличие его от стандартного заключается в наличии нескольких встроенных таблиц шрифтов, из-за чего управление этим дисплеем усложняется, и нам придется немного модернизировать стандартную библиотеку LiquidCrystal. Но проблема заключается не в одних только шрифтах — как водится, что-то улучшив, разработчики что-то и ухудшили.

Для начала следует увеличить задержку после включения питания перед инициализацией. В оригинале, согласно спецификации на традиционный контроллер HD44780, она составляет 50 мс, но для версии WS0010 этого недостаточно — документация требует минимум 500 мс. Если это исправление не внести, то и без того плохо отработанный контроллер будет «глючить» вплоть до полной неработоспособности: после включения вместо символов появятся произвольные картинки, они могут бегать по экрану и мерцать. Капризность дисплеев фирмы Winstar отмечали многие, но, к сожалению, доступную замену сыскать очень сложно.

Для увеличения задержки разыщите в папке libraries/LiquidCrystal файл LiquidCrystal.cpp. Первым делом сделайте его копию, сохранив ее, например, как LiquidCrystal.cpp.bak. Затем откройте его через Блокнот, и в тексте функции

void LiquidCrystal::begin найдите строку

delayMicroseconds(50000);

В оригинальном файле эта строка имеет номер 100. Измените число 50000 (50 мс) на 800000 (0,8 секунды) и сохраните файл. После этого нужно заново откомпилировать программы Arduino, применяющие эту библиотеку. В том числе можно это сделать и для старого типа контроллеров, если у вас такие программы имеются, — увеличение задержки при включении ничему не помешает.

Крупный недостаток этих дисплеев — ни в традиционном HD44780, ни в новом WS0010 не предусмотрено наличие аппаратного Reset. Потому при первом запуске после перепрограммирования вы, скорее всего, получите на дисплеях сплошной мусор. Кнопку Reset контроллера для перезапуска применять бессмысленно — дисплей-то при этом не перезапускается, а устанавливается в непредсказуемое состояние. Обычно помогает перезапуск отключением питания — выдергивание USB-кабеля с последующей вставкой сетевого адаптера вместо него.

Если полностью избавиться от мусора при включении станции все-таки не удается (это, кроме всего прочего, зависит и от конкретного экземпляра индикатора), то поставьте на задней панели станции кнопку с двумя парами перекидных контактов, одной парой размыкающую линию питания индикатора при нажатии, а второй в это же время замыкающей на землю вывод Reset контроллера. При отладке все время дергать USB-кабель неудобно, но в этом случае можно просто выдергивать проводок питания индикатора с последующим перезапуском контроллера кнопкой Reset на плате. Описанный в главе 21 графический дисплей MT-12864J, у которого есть нормальный аппаратный перезапуск, таких сложностей не требует, — его вывод Reset просто соединяется с выводом Reset платы Arduino (как и показано на рис. 21.4).

* * *

Заметки на полях

Отмечу; что от одного «глюка» индикаторов WEH001602B мне так и не удалось избавиться: какую из двух строк в операторе setCursor считать строкой 0, а какую строкой 1 — почему-то это зависит от характера питания. При питании всей схемы от USB нулевой строкой преимущественно оказывается нижняя, а при питании от адаптера 7,5 В — всегда верхняя, что надо учитывать при программировании.

Пишем по-русски

Далее нужно разобраться с русским языком — модели дисплеев с новым контроллером WS0010 русифицируются переключением кодовой таблицы, что в стандартной библиотеке LiquidCrystal не предусмотрено. Введением таких таблиц в фирме Winstar кардинально решили проблему национальных прошивок: 255 символов на все языки не хватает, а применение Unicode в восьмиразрядном контроллере весьма затруднено. Ранее в каждый регион приходилось поставлять дисплеи со своим языком, что вызывало понятные трудности у потребителя.

С контроллером WS0010 этого не требуется, в нем уже записаны четыре таблицы: ENGLISH_JAPANESE, две таблицы WESTERN EUROPEAN и ENGLISH_RUSSIAN. Выбор осуществляется переключением двух специальных битов FT (font table), которые в старом варианте просто не задействованы и не должны ничему мешать, — в силу чего отредактированная библиотека должна быть полностью совместима со старыми типами дисплеев. Если они все-таки мешать будут (автор, естественно, никакой гарантии дать не может), то придется использовать два варианта библиотеки или усложнять ее введением специальной функции установки font_table. Здесь же мы просто добавим одну лишнюю строку в тот же файл LiquidCrystal.срр.

Для объявления кириллической таблицы шрифтов найдите в файле начало функции void LiquidCrystal::begin. Там, внутри оператора if (lines > 1), имеется строка номер 87: _displayfunction |= LCD_2Line;. Сразу после нее (перед замыкающей операторной скобкой «}») вставьте еще одну строку:

_displayfunction |= 0x02; //russian codetable

Она устанавливает биты FT в состояние 1:0, соответствующее таблице ENGLISH_RUSSIAN. Сами коды кириллических символов одинаковы и для старого варианта HD44780 с «прошитой» русской таблицей, и для нового WS0010 (табл. 22.1). Подогнать под кодировку UTF-8 здесь их не удастся (и исправить перечеркнутый ноль тоже). В отличие от таблицы ASCII, в этих таблицах указаны только кириллические символы, отличающиеся от английских, потому в функции print () совпадающие буквы в обоих языках можно указывать напрямую, как обычно, а кириллические придется вставлять указанием их числового кода.

В табл. 22.1 приведены шестнадцатеричные коды символов (в строке записываются с предваряющим х), а также восьмеричные. В тексте программ на основе и без того совершенно нечитаемого языка С, на мой взгляд, восьмеричные выглядят компактнее, потому что требуют одного лишь предваряющего обратного слэша.

Обычные символы и коды можно писать вперемешку. Например, процедура замены английских названий дней недели на русские при выводе показаний часов DS1307 (см. далее) будет выглядеть, как показано в листинге далее. Сами часы выдают дни недели в цифровом виде, а соответствующие им англоязычные константы MON, TUE и т. п. уже определены в файле ds1307.h.

Подключение библиотеки LiquidCrystal

После подключения библиотеки LiquidCrystal к программе ее необходимо инициализировать, причем с указанием реальных контактов, к которым присоединяются выводы выбора индикатора RS, разрешения Е и линии данных. Индикаторы на базе HD44780 могут подключаться как по восьмипроводной, так и по четырехпроводной линии данных. Все реальные библиотеки в целях экономии числа соединений, естественно, выбирают второй способ. В нашем случае таких индикаторов два: четыре линии данных у них будут общие, а линии RS и Е различаются — ими мы будем обеспечивать выбор текущего дисплея.

Таким образом, тестовая программа для двух дисплеев WEH001602В, подключенных согласно схеме на рис. 22.1, будет выглядеть следующим образом:

Часы реального времени DS-1307

Модуль часов реального времени RTC на основе микросхемы DS-1307, предлагаемый в «Амперке», имеет один недостаток — к нему требуется батарейка редко встречающегося в продаже типоразмера CR1225, которую придется приобретать отдельно. Проблемой в дальнейшем это, однако, не станет: согласно спецификации, DS-1307 потребляют ток 0,5 мкА, так что в теории этой батарейки при ее емкости 48 мА-ч должно хватать примерно лет на десять — больше, чем ее гарантийный срок хранения. Надо учесть, что без установленной батарейки часы неработоспособны, и их не удастся даже запрограммировать.

Сам модуль представляет собой практически «голую» микросхему DS-1307 с установленными резисторами «подтяжки» для интерфейса 12С. К Arduino модуль подключается через штатные выводы аппаратного I2C (TWI) MK AVR, т. е. через контакты платы Arduino А4 (SDA) и А5 (SCL). Доступ к этому интерфейсу реализован в стандартной библиотеке Wire.h, поставляемой вместе со средой Arduino IDE. Подробно об интерфейсе I2С (другое название интерфейса: TWI, Two Wire Interface) можно прочесть в моей книге [21], здесь мы только укажем, что к нему одновременно могут подключаться до 128 устройств (различаются они программно по индивидуальному адресу). Поэтому на схеме к тем же выводам подключен еще и барометр, который мы рассмотрим позднее.

* * *

Заметки на полях

Следует отметить, что существует очень много библиотек Arduino для работы с часами DS-1307, и большинство из них не используют аппаратный порт I2C, предполагая подключение к другим цифровым выводам. Как рассказывается в моей книге [21], аппаратная реализация I2C (TWI) в AVR действительно оставляет желать лучшего. Но в данном случае мы пойдем именно этим путем — наш барометр тоже применяет тот же способ, а, значит, мы можем сэкономить на выводах, подключив эти устройства к одному и тому же интерфейсу. Что же касается неудобств реализации интерфейса, то все трудности здесь скрыты от нас создателями библиотеки.

* * *

Библиотеку RTC можно скачать с официального сайта Seeed[44]. Все взаимодействие программы с часами заключается в подключении библиотек ds1307.h и Wire.h, вызове функции инициализации clock.begin() и считывании показаний с помощью единственной функции clock.getTime(), которая обеспечивает обновление целого выводка скрытых переменных, таких как clock.hour, clock.minute и т. п. Потому основная проблема в программировании взаимодействия с часами не в том, чтобы периодически читать показания и выводить их на дисплей, а в том, как удобно и корректно организовать их начальную установку и периодическую коррекцию.

Установка часов

Привычную установку часов с помощью одной-двух кнопочек в современных условиях я считаю приемлемым методом только в случае самых простых радиолюбительских конструкций — подобных той, что рассматривалась в главе 20. Так как там мы еще не изучали последовательный порт и другие коммуникационные возможности контроллеров, то и не умели организовать установку часов иным способом. В устройствах, ориентированных на практическое применение, заставлять пользователя жать на кнопочки после каждого сбоя в питании — признак либо лени, либо крайней безграмотности разработчика.

Самым, вероятно, прогрессивным способом установки и коррекции встроенных часов будет полная автоматизация этого процесса — подобно тому, как это делает Windows, периодически обновляя внутренние часы через Интернет незаметно для пользователя. В случае готового доступа в Интернет это просто, а вот для автономного прибора потребуются соответствующие беспроводные функции. Их можно организовать двояким способом: либо через службы точного времени (так устроены некоторые серийные метеостанции), либо через подключение GPS-модуля, имеющего доступ к сигналам точного времени по определению.

Существует модуль Arduino DCF77 radio clock receiver, ориентированный на прием радиосигналов служб точного времени (известных, как DCF77)[45]. Способ имеет тот недостаток, что работает не везде, — так, модули, ориентированные на немецкий передатчик во Франкфурте-на-Майне, глохнут уже километрах в ста к востоку от Москвы. Как ни странно, но никаких серийно выпускаемых модулей (необязательно именно ориентированных на Arduino), предназначенных для приема сигналов российских служб точного времени, я так и не нашел — возможно, они просто неактуальны в связи с распространением спутниковых систем навигации.

Применение для этой цели приемников GPS (или GPS/Глонасс), конечно, более универсальный и повсеместно доступный способ. Но в нашем случае я счел это нецелесообразным — GPS-приемник удорожит нашу станцию примерно вдвое, а использоваться будет лишь изредка. Потому здесь мы пожертвуем полной автоматизацией, и сделаем процесс полуавтоматическим, через подключение к компьютеру.

Обновить время, раз в полгода подключив станцию к любому компьютеру, совсем несложно, тем более что никаких дополнительных аппаратных средств для этого не понадобится. В версии станции с SD-карточкой мы еще и будем хранить на ней софт, упрощающий этот процесс.

Скетч под названием Clock_set.ino для проверки функционирования и установки часов реального времени, подключенных по схеме рис. 22.1, можно скачать с сайта автора по ссылке http://revich.lib.ru/AVR/Meteoset.zip. Он принимает команды от компьютера и, в соответствии с принятым символом, выполняет ту или иную операцию. По приему символа «D» (десятичный код 68) контроллер переходит в режим установки часов из компьютера и ждет, что ему придут еще последовательно семь байтов в десятичной форме: год (младшие две цифры), месяц, дата, часы, минуты, секунды и день недели (понедельник — первый). В общем-то, последняя цифра не нужна, т. к. день недели полностью определяется остальными данными, но в часах его установка почему-то предусмотрена отдельно, и в библиотеке DS1307.h имеется соответствующая функция.

Со значением года создатели библиотеки придумали пользователю дополнительные заморочки. В сами часы загружается лишь один байт, соответствующий двум последним цифрам года, но почему-то при обращении к функциям установки из библиотеки DS1307.h нужно загружать двухбайтовое число, представляющее год полностью. Функции Windows, которые применяются в нашей Delphi-программе (см. далее), тоже выдают год целиком. Но чтобы не возиться с передачей двухбайтового числа через порт, мы в компьютерной программе вычитаем из значения года число 2000, затем в программе Clock_set.ino снова его прибавляем, а в библиотечных функциях (см. в конце файла DS1307.cpp из библиотеки RTC) оно опять вычитается, как и требуют часы. Глупость, конечно, но править библиотеку по столь незначительному поводу мы не станем. По окончанию установки часов контроллер выдает в «верхнюю» программу строку «Ok».

По приходу команды «R» (десятичный код 82) контроллер считывает часы и выдает их «наружу», причем день недели выдается английским сокращением, как в примере из библиотеки. Впоследствии мы воспользуемся этим разделением по командам для приема данных через последовательный порт из другого источника.

В качестве составной части скетч Clock_set.ino вошел в полную программу метеостанции, но может использоваться и как отдельная тестовая программа.

Для облегчения задачи установки часов я написал утилиту на Delphi, которая взаимодействует с программой Clock_set.ino с помощью всего двух кнопок (точно так же он работает и с полной программой метеостанции). Эту утилиту под названием MeteoSet можно найти в том же архиве, что и скетч Clock_set.ino. В архиве, кроме собственно программы (файл setmeteo.exe), находится папка с Delphi-проектом, который читатель волен использовать по собственному усмотрению. Проект создан в версии Delphi 7, но после преобразования будет компилироваться и в любой более поздней версии, изменения вносить не потребуется.

Предварительно соедините компьютер со станцией USB-кабелем, загрузите в прибор скетч Clock_set.ino и установите в запущенной на компьютере программе setmeteo.exe соответствующий порт (предусмотрены номера от СОМ1 до СОМ8). После этого можно прочесть показания часов из станции (кнопка Read Time from Station), сравнить их с текущим временем (показывается внизу окна программы) и обновить через нажатие кнопки Set current Time. Перед проведением этой операции целесообразно принудительно обновить время в самом компьютере через пункт Настройка даты и времени контекстного меню области уведомлений (хотя Windows делает это автоматически по расписанию, но не каждый день, и часы могут «уйти»).

Температура, влажность и давление

Выбранные нами Arduino-модули для измерения температуры, влажности и атмосферного давления также применяют связь по двухпроводному интерфейсу I2С. При этом библиотека для Barometer Sensor на основе чипа ВМР085[46] ориентирована на тот же самый аппаратный интерфейс I2С, реализованный через стандартную библиотеку Wire.h, что и часы DS-13G7. Потому на схеме рис. 22.1 Barometer Sensor и подключен к тем же самым выводам А4 и А5. Микросхема ВМР085 производства Bosh устроена так, что перед чтением показаний давления следует обязательно прочесть температуру (см. пример по ссылке в сноске 3). Именно эту температуру мы в дальнейшем будем демонстрировать в качестве «внутренней» на дисплее главного модуля нашей станции — хотя нет никаких проблем в том, чтобы выводить и значение, получаемое из модуля SHT1.

Что же касается атмосферного давления, то модуль ВМР085 выдает его, как водится, в паскалях в виде действительного числа (т. е. типа float). В программе придется ввести коэффициент пересчета для его представления в привычных миллиметрах ртутного столба, притом в виде целого числа (указывать десятичные доли атмосферного давления не имеет смысла). Вот тут и скажутся все преимущества высокоуровневого языка Arduino — этот коэффициент имеет величину 0,0075 (750 мм рт. ст. — это 1000 гПа с высокой точностью). Для умножения на такую величину в ассемблерной программе придется сначала преобразовывать ее в целое число, применять довольно громоздкие процедуры перемножения многобайтовых чисел, потом приводить результат к нужному виду (см. главу 20), а у нас это сведется к одной строке в программе:

mmHg = int(pressure*0.0075)+5;

Здесь мы применяем явное преобразование типов — результат умножения переменной pressure типа float на дробный коэффициент мы сразу приводим к целому виду типа int. За такую роскошь мы, конечно, расплачиваемся дополнительными килобайтами кода, но в данном случае оно того стоит.

* * *

Подробности

А зачем здесь к полученному значению добавляется еще и число 5? Это поправочный коэффициент, который вводится индивидуально из следующих соображений. В главе 20 мы упоминали, что для небольших высот над уровнем моря при изменении высоты на каждые 10–12 м давление меняется примерно на 1 мм рт. ст. В пределах такого города, как Москва, показания могут меняться в зависимости от местоположения примерно на 10 миллиметров. Мы же хотим, чтобы станция показывала величины, близкие к тем, что передаются Гидрометцентром, — иначе, проглядев прогноз погоды, ее показания придется все время пересчитывать в уме. Так что коэффициент 5 — это экспериментально вычисленная поправка в моем случае. Будьте готовы, что вам ее придется пересчитать, сравнивая показания с теми, что публикуются для вашего населенного пункта каждые три часа в интернет-службах погоды. Если же вы хотите, чтобы станция показывала реальное давление без всяких поправок, то просто вычеркнуть этот коэффициент из программы будет недостаточно — придется датчик дополнительно калибровать. А это дело непростое — не каждый физический институт имеет средства для поверки датчиков атмосферного давления, потому и проще подогнать его показания под Гидрометцентр.

* * *

В библиотеке для барометра — файле Barometer.cpp (папка Barometer_sensor) — необходимо закомментировать забытые разработчиками тестовые строки 28 и 40: Serial.print ("Teinperaturet: ") и Serial.print ("Temperaturet2: "). В противном случае у вас собьется прием данных от Xbee-модуля и все время на индикаторных панелях будет возникать лишний мусор.

В отличие от барометрического, библиотека для модуля измерения температуры и влажности SHT1x[47] применяет не аппаратный интерфейс 12С, а его программную реализацию (подробнее о том, как это делается, рассказано в моей книге [21]). Модуль подключается к любым цифровым выводам — на схеме рис. 22.1 в этом качестве выступают выводы А2 и A3 (что соответствует цифровым выводам 16 и 17). В программе в секции определений их надо указать:

#include <SHT1x.h>

#define dataPin 16

#define clockPin 17

SHT1x sht1x(dataPin, clockPin);

Особенность подключения SHT1x, как мы видим на схеме, — наличие двух разъемов, где выводы питания дублируются (рассмотрев плату, я не обнаружил между ними разницы), а сигнальные линии Data и SCK пространственно разделены. Это не доставляет никаких проблем при создании конструкции (все равно задействовано лишь два вывода Arduino), но если вы хотите уменьшить число проводов, то в «Амперке», кроме SHT1x, предлагается и другой подобный датчик — DHT11 (имеющий, впрочем, как утверждается, меньшую точность).

Тестовые программы для обоих модулей прилагаются к соответствующим библиотекам. В скетче для SHT1x следует только не забыть заменить номера выводов на указанные на схеме рис. 22.1.

Подключение радиомодулей ХЬее

Подключение Xbee-модулей, возможно, самая сложная часть проекта. Трудность тут заключается в том, что для коммуникации с контроллером они используют тот же последовательный порт, что и USB-соединение с компьютером (собственно, Xbee-модуль представляет собой как бы продолжение UART в замену проводному кабелю). Поэтому Xbee-модуль будет мешать не только коммуникации с компьютером, но и процессу программирования платы, отчего перед каждой модификацией программы его придется извлекать из схемы и вставлять заново. Опыт показал, что это делать необязательно, если ХЬее-модуль не участвует в коммуникации (т. е. не осуществляет приема или передачи), но в общем случае на это полагаться не стоит — проще отключить его и подключить заново.

Xbee-модули не требуют для своей работы каких-либо библиотек — serial-коммуникация через них осуществляется совершенно прозрачно для программиста, с применением стандартных функций последовательного порта. Это, как мы говорили, позволит нам через один и тот же порт осуществлять и прием данных от внешнего датчика, и установку часов из компьютера. Правда, тогда при подключении к компьютеру ХЬее-модуль придется извлекать из устройства точно так же, как это делается при программировании контроллера. Но делать это придется очень редко — только для подстройки времени, если часы DS-1307 сильно убегут, т. е. не чаще, чем где-то раз в полгода), ну и, разумеется, при смене батарейки, которой, как обещают производители, должно хватить на несколько лет.

* * *

Подробности

Если мы не хотим озадачивать пользователя извлечением Xbee-модуля, то пришлось бы использовать как минимум Arduino Mega, где UART-портов несколько. На мой взгляд, как и в случае применения GPS-модуля для полностью автоматической установки часов, это слишком большая цена за функцию, которая будет применяться лишь изредка.

Кстати, подкину еще одну идею: если приобрести третий ХЬее-модуль, настроить его на совместную работу с остальными и подключать его к компьютеру через специальный Xbee-адаптер, то через него можно не только устанавливать часы, как через обычный UART, но даже и программировать контроллер. Программу станции при этом можно использовать ту же, что приведена далее, только тогда перед обращением к часам извлекать ХЬее-модуль не придется. Предлагаю вам заняться на досуге такой доработкой — базовый материал для нее есть в статье о настройке ХЬее на сайте «Амперки», которая упомянута в разд. «Подключение и настройка ХЬее-модулей» этой главы.

Из этой ситуации можно вывернуться и еще одним способом — попросту организовать программный UART на свободных выводах Arduino Uno (правда, в случае ЖК-дисплея для этого может не хватить контактов платы). О том, как это делается, см. http://arduino.ua/ru/prog/SoftwareSerial. Вариант этого способа — применить для общения датчика со станцией не ХЬее, а, например, беспроводной модуль на основе nRF24L01+[48]. Он предназначен в принципе для тех же целей, но управляется не через UART, а через SPI, и его можно использовать параллельно с записью на SD-карточку. Как видите, платформа Arduino дает большое разнообразие способов решения для любых пришедших в голову идей.

Подключение и настройка ХЬее-модулей

Здесь придется повозиться: настройка пары ХЬее-модулей для совместной работы — не самое простое занятие. Мы применим для их прошивки не отдельную плату XBee-USB адаптера (который один раз используется, а затем оказывается ненужным), а универсальную Wireless Shield, которую потом приспособим и в схеме станции, причем в варианте с разъемом для SD-карты (Wireless Shield SD[49]). Ее подробное описание можно найти на украинском сайте Arduino[50]. Там же имеются рекомендации по подключению Xbee-модулей фирмы Digi. Обычно контроллер из платы Arduino перед прошивкой Xbee-модулей через Wireless Shield рекомендуют извлекать, но мы поступим иначе — в упомянутом разделе украинского сайта приведена программа-заглушка, которую перед настройкой следует закачать в Arduino, чтобы контроллер не мешал прошивке модулей. Программа очень проста и состоит из двух строк:

void setup() { }

void loop () { }

Отметим, что в обратной ситуации (т. е. при прошивке Arduino в присутствии ХЬее-модуля) столь простого решения не существует — при необходимости изменить программу Xbee-модуль придется извлекать каждый раз.

Скомпилируйте эту программу в новом файле и загрузите в Arduino. Затем подсоедините Wireless Shield к плате Arduino Uno, установите в него Xbee-модуль (не забудьте про соответствие номеров контактов на модуле и «шилде»!) и переключите на плате Wireless Shield микропереключатель в положение «USB». Не забывайте, что для нормальной работы Xbee-модуля с контроллером переключатель надо возвращать в положение «Micro».

При подключении USB-кабеля к Arduino Uno теперь должен загореться красный светодиод PWR в углу платы Wireless Shield. При работе с модулем следует обращать внимание на этот светодиод — его ровное и яркое свечение сигнализирует о том, что модуль вставлен правильно. В этом неудобство применения таких модулей — они-то прошиваются один раз, а рабочую программу приходится долго отлаживать. Потому стоит постараться отладить все возможное до установки ХЬее-модуля, и напоследок оставить только беспроводные функции.

Теперь отвлечемся от украинского сайта — на нем рекомендуют настраивать мо- дуль руками с помощью посылки команд. Мы пойдем более простым путем и обратимся к статье на сайте Amperka.ru «Настройка пары модулей ХВее Series 2 для коммуникации друг с другом»[51]. Учтите, что все сказанное далее относится к модулям Series 2 (на плате помечены буковками S2), а встречающиеся в некоторых магазинах более дешевые модули Series 1 (они не помечены никак) настраиваются несколько иначе и несовместимы с Series 2.

Пропускаем там все, касающееся подключения модуля к XBee-USB адаптеру, и далее узнаем, что надо скачать специальную программу X–CTU с сайта производителя. Отправившись по ссылке, даже подготовленный человек растеряется, — только для Windows там представлены три варианта указанной программы. Скачиваем наугад самую верхнюю (на момент написания этих строк это XCTU ver. 5.2.8.6) и устанавливаем. Ура! Мы попали как раз на то, что надо.

Запускаем X–CTU, первым делом выбираем СОМ-порт, соответствующий Arduino, и для проверки жмем кнопку Test/Query (напоминаю, что в Arduino перед этим уже должна быть загружена программа-заглушка или контроллер извлечен из платы). Далее переходим на вкладку Modem Configuration и скачиваем свежие версии прошивок через кнопку Download new versions (что будет выполняться довольно долго — программа скачивает обновления для всех устройств, которые в ней предусмотрены).

И, наконец, выполняем собственно прошивку, как описывается в статье, для двух Xbee-модулей: одного в режиме «координатора», другого — «роутера». Сначала выбираем тип модема, определенный программой через Test/Query (в нашем случае ХВ24-В), затем в поле Function Set находим пункт ZNET 2.5 COORDINATOR AT (не ошибитесь! Там много пунктов с похожими названиями). Кроме этого, устанавливаем идентификатор сети в графе PAN ID (рис. 22.2).

Рис. 22.2. Установка параметров Xbee-модуля в программе X–CTU

Он должен быть одинаковый для обоих модулей, пусть у нас он будет равен 0FFF. Можно установить скорость обмена в пункте Serial interfacing/BD-BaudRate, однако по умолчанию там и без того установлено значение 3 (9600). Потом на всякий случай поставьте отметку в пункте Always update firmware (при повторной прошивке этого можно не делать) и, наконец, нажмите кнопку Write.

Для второго модуля в поле Function Set находим ZNET 2.5 ROUTER/END DEVICE AT и делаем все то же самое, только еще в пункте Sleep Modes/SM-Sleep Mode выбираем значение 1 — PIN HIBERNATE (это нам понадобится для установки режима энергосбережения в выносном датчике). Кроме этого, советуют в пункте Serial Interfacing/D7-DIO7 Configuration установить значение 0 (CTS flow control disabled). После этого устройство конфигурируется именно как END DEVICE, и нам станет доступен Sleep-режим, который активируется установкой логической 1 на выводе 9 модуля.

Обязательно сохраните обе конфигурации (Profile | Save). При повторном подключении модулей можно прочесть зашитую в них конфигурацию, нажав кнопку Read, и в случае необходимости что-то подправить.

* * *

Подробности

Xbee-модули фирмы Digi имеют весьма капризный характер. Если у вас в процессе настройки модуль перестал откликаться на запросы программы X–CTU, то не кидайтесь сразу выбрасывать довольно дорогой девайс, полагая его испорченным. Помогает следующая последовательность действий, проверенная мной на практике:

1. Извлеките из платы Wireless Shield (или из XBee-USB адаптера, если вы используете его) «неисправный» Xbee-модуль и подключите ее к компьютеру.

2. Запустите X–CTU, сразу перейдите на вкладку Modem Configuration, загрузите любую из сохраненных конфигураций (Profile | Load) и попробуйте загрузить ее в устройство через кнопку Write. Естественно, вы получите сообщение о том, что никакого модема не обнаружено.

3. Закройте это окошко и вставьте Xbee-модуль в плату. Затем снова нажмите кнопку Write. Скорее всего, модем «пропишется» как надо. После этого его можно будет прочесть кнопкой Read, как обычно, и внести необходимые исправления. Если с первого раза не получится, повторите эти операции.

* * *

После прошивки пометим модули на всякий случай, наклеив на них «лейблы» с буквами С (для «координатора») и R (для «роутера») и значением ID — вдруг мы захотим подключить еще один модуль? «Координатор» мы присоединим к основному модулю станции, а «роутер» — к выносному датчику (только END DEVICE можно вводить в режим энергосбережения).

Теперь мы отложим настроенные Xbee-модули и займемся настройкой Arduino Mini, который у нас ляжет в основу выносного датчика станции.

Выносной датчик на основе Arduino Mini

Кстати, у Arduino Mini, несмотря на его миниатюрные размеры, портов даже больше, чем у Arduino Uno, — обратите на его схеме внимание на выводы AD6 и AD7 (см. http://arduino.ru/Hardware/ArduinoBoardMini). Правда, они могут использоваться только по прямому назначению — как аналоговые входы. По аналогии с выводами AD0-AD5 (цифровые порты 14–19) может показаться, что им должны соответствовать цифровые порты с номерами 20 и 21, но это не так: AD6 и AD7 представляют собой отдельные входы АЦП контроллера ATmega328 (ADC6 и ADC7), которые, в отличие от остальных, никак не связаны с цифровыми выводами портов.

Отсутствие входов AD6 и AD7 в большинстве остальных модификаций Arduino объясняется просто: выводы ADC6 и ADC7 имеются лишь у ATmega328 в плоских корпусах TQFP и MLF, где число выводов увеличено до 32, а в PDIP-корпусе с 28 выводами, на которых построено большинство обычных модификаций Arduino, они отсутствуют.

Для программирования Arduino Mini нам придется создать отдельную конструкцию, включающую внешний USB-Serial адаптер, который придется приобрести отдельно. В датчике такой адаптер нам не нужен, и он все равно будет конфликтовать с Xbee-модулем. Потому мы создадим отдельную схему для программирования платы, а отладку функций энергосбережения, чтения показаний датчика SHT1x и работы с Xbee-модулем вынесем на отдельный макет.

Схема для программирования Arduino Mini показана на рис. 22.3.

Рис. 22.3. Схема для программирования Arduino Mini

Обратите внимание, что линии RxD и TxD платы и адаптера соединены перекрестно. Конденсатор между выводами Reset адаптера и платы выбирается в пределах 0,1–0,5 мкФ — он служит для сброса контроллера перед программированием. Его можно не подключать, но тогда перед программированием на всякий случай нужно сбрасывать контроллер вручную, кнопкой на плате (нажимать не сразу, а когда появляется надпись Uploading, или, в русском варианте Загружаем).

При подключении этой схемы через кабель mini-USB к компьютеру, USB-Serial адаптер должен самостоятельно прописаться в системе — в разделе Порты (СОМ и LPT) Диспетчера задач возникнет еще одно устройство под названием Arduino USB Serial Light Adapter (СОМxx). Запустите Arduino IDE, укажите ей через меню Сервис | Плата тип платы Arduino Mini w/ATmega328), а затем через меню Сервис | Порт — номер порта, который показывает Диспетчер задач для USB-Serial адаптера. При подключении должны гореть два светодиода: на адаптере и на плате контроллера.

Убедимся, что все работает, загрузив в контроллер какую-нибудь простенькую программку, вроде стандартного мигания светодиода на выводе 13. В Arduino Mini такого светодиода нет, но на этом выводе имеется балластный резистор 1 кОм, потому светодиод к нему можно подключать непосредственно (отрицательным выводом к «земле»). Текст всемирно известной тестовой программы на всякий случай привожу:

void setup()

{

pinMode(13, OUTPUT); // настраиваем 13 вывод на выход

}

void loop()

{

digitalWrite(13, HIGH); // включаем светодиод

delay(1000); // ждем 1000 миллисекунд

digitalWrite(13, LOW); // выключаем светодиод

delay(1000); // ждем 1000 миллисекунд

}

Если с первого раза получаете «отлуп» (в виде того самого красного сообщения avrdude: stk500_getsync(): not in sync: resp =0x1c), то проделайте следующее: запустите Диспетчер задач и найдите там устройство Arduino USB Serial Light Adapter. Затем выдерните USB-кабель из адаптера и сразу включите вновь (в Диспетчере задач устройство исчезнет и опять появится). Теперь ему следует сделать дополнительный программный сброс — в контекстном меню Arduino USB Serial Light Adapter разыщите пункт Отключить. Отключите устройство и сразу же включите опять (напомню, что в Windows 7 и 8 пункт меню будет называться Задействовать). Если после этих манипуляций связь с платой все равно не заработает, как надо, то перезагрузите компьютер — должно помочь.

Схема выносного датчика

Схема выносного датчика показана на рис. 22.4. Его мы будем вводить в режим энергосбережения, потому придется принять ряд схемотехнических мер.

Рис. 22.4. Схема выносного датчика метеостанции

Подключение Xbee-модуля к Arduino Mini отличается от стандартного наличием линии Sleep (контакт 9 платы Xbee-модуля). По этой линии мы будем загонять модуль в режим низкого потребления в паузах между измерениями. Обратите внимание, что выходы Arduino подключены к модулю через согласующие делители R1/R2 и R3/R4 с довольно большим сопротивлением, — без согласования, как мы говорили, ток через эти выводы резко возрастет. В этих же целях придется выпаять из платы Arduino Mini желтый неуправляемый светодиод, который сигнализирует о подаче питания (его не было в ранних релизах Arduino Mini). Этот светодиод мы заменим на красный, подключенный к стандартному 13-му выводу платы и заставим его кратковременно включаться в момент считывания показаний и передачи их в станцию (напомним, что к 13-му выводу на плате уже подключен балластный резистор 1 кОм).

Хитрое включение батарейного питания ориентировано на достижение энергосбережения в максимальной степени. От трех элементов АА (реальное напряжение около 4,5–4,8 В) питается плата Arduino, а от отвода между вторым и третьим — модуль ХЬее (напряжение 3,0–3,2 В). Диод D1 типа КД922 (с переходом Шоттки, т. е. с малым падением напряжения) развязывает источники питания 5 и 3,3 В, чтобы они по каким-то причинам не начали работать друг на друга. Если бы мы подключили обычное питание 7–9 В к стабилизатору платы, а модуль ХЬее через какой-нибудь из стандартных «шилдов» со встроенным стабилизатором 3,3 В, то теряли бы питание не только на самих стабилизаторах, но и за счет их собственного потребления.

* * *

Подробности

Правда, в Arduino Mini установлен малопотребляющий стабилизатор LP2985AIM5-5.0 (в этом отличие Mini от Uno, где стоит стабилизатор NCP1117ST50T3G — более мощный, но совсем не экономичный). Однако его, во-первых, может не хватить для питания Xbee-модуля в случае, если мы выберем Pro-версию (согласно документации фирмы Digi, модуль ХЬее Pro может потреблять в момент передачи почти 300 мА, а LP2985 допускает только 150). Во-вторых, для получения 3,3 В все равно нужен дополнительный стабилизатор, а в нашем Wireless Shield установлен СХ1117-3.3 — тоже не самый экономичный.

* * *

В результате при батарейном питании проще вообще обойтись без нагромождения стабилизаторов — до напряжения 1,1 В на каждый элемент схема должна работать надежно, а это практически 80 % емкости щелочных батарей (см. рис. 9.2). И раз уж мы применяем Arduino, который позволяет многое без особого напряжения сил, то для удобства станем измерять напряжение батареи датчика, передавать его в главный модуль вместе с данными и заставлять станцию сигнализировать, если элементы питания на исходе. В главном модуле для индикации того, что батарейки садятся, заставим строку с внешними данными мигать, если напряжение ниже установленного порога (пусть это будет 3,3 В — по 1,1 В на каждый элемент, возможно, по результатам эксплуатации эту величину придется подкорректировать). Мне неизвестны какие-либо бытовые приборы, имеющие подобную функцию контроля за напряжением источников питания (кроме, разумеется, мобильников или фотокамер), — пусть это будет наше ноу-хау.

Программу для выносного датчика можно скачать с сайта автора по ссылке http://revich.lib.ru/AVR/Extsens.zip. В программе используются встроенные возможности Arduino IDE для ввода контроллера в режим энергосбережения и пробуждения по встроенному таймеру WDT. О применении этих режимов можно прочесть на официальном сайте Arduino по ссылке http://playground.arduino.cc/Learning/ArduinoSleepCode (к сожалению, на английском языке). Поиском в Сети можно найти и русскоязычные примеры их использования.

* * *

Подробности

Заметим, что в этой конструкции применяется довольно несовершенный метод измерения аналоговой величины напряжения батарейки, когда в качестве опорного напряжения АЦП использован внутренний источник (см. строку analogReference (INTERNAL), подробности о работе АЦП в МК AVR см. главу 20 и книгу [21]). Потому коэффициент пересчета не вычисляется теоретически, а должен устанавливаться именно путем калибровки, причем с реальным источником питания (набором батареек), а не при подключении к USB или внешнему адаптеру.

Делитель напряжения R5/R6 (он добавляет к общему потреблению менее микроампера) нужен для «подгонки» измеряемого значения под опорное. Не стоит бояться, что входное сопротивление АЦП внесет погрешность при установке столь высокоомного делителя — в МК AVR оно измеряется десятками гигаом. В данном случае выходной код АЦП определяется формулой ADC = 1024Vin/Vref (подробности см. в главах 17 и 20). При превышении входным напряжением опорного этот код «застынет» на максимальном значении 1023, так что нам необходимо иметь на входе АЦП напряжение, заведомо меньшее опорного. А опорное напряжение определяется в нашем случае внутренним источником и имеет величину примерно 1,2 В с довольно большим разбросом. Отсюда соотношение сопротивлений резисторов этого делителя должно быть около 5, а точное значение величины коэффициента в программе, с помощью которого вычисляется реальная величина напряжения (переменная voltage, см. строку 105 исходного текста скетча) и должно быть определено с помощью калибровки. Коэффициент будет равен частному от деления реального напряжения батареи в вольтах на величину кода АЦП (переменная val) — у меня он получился равным 0,0059. Если задаться величиной опорного напряжения, равной 1,1 В, то теоретический расчет даст близкое значение.

Чтобы проверить и при надобности уточнить значение коэффициента, измерьте напряжение батарейки мультиметром во время работы датчика, затем сравните с тем, что запишется в файл на карте (см. далее). Поделив записанное значение на измеренное, вы получите поправку, на которую необходимо умножить значение коэффициента из программы. В случае ЖК-индикатора без записи на карту, операция калибровки будет сложнее — вам придется временно подправить программу так, чтобы вывести на дисплей значение напряжения, получаемое с датчика.

* * *

Во время работы в соответствии с программой датчик основное время потребляет примерно 500 мкА, и каждые 8 секунд по WD-таймеру включается примерно на 0,8 с — снимает показания с SHT-модуля, измеряет напряжение батарейки и передает данные через Xbee-модуль. Напряжение батарейки во избежание случайных выбросов усредняется за каждые 16 показаний. Измерения показали, что во включенном состоянии потребление всего выносного датчика в среднем составляет около 15 мА. Пиковое потребление обычного Xbee-модуля в момент передачи может превышать 40 мА, но это происходит лишь в течение нескольких миллисекунд, и мы этими выбросами можем пренебречь в своих расчетах. Итого среднее потребление датчика составит приблизительно 2 мА — в соответствии с данными приложения 2 АА-батареек должно хватить примерно на два месяца непрерывной работы.

Заметим, что если бы мы писали программу на ассемблере, то могли бы уменьшить время активного состояния в несколько десятков раз, и батарейки работали бы гораздо дольше.

Ресурс батареек можно увеличить, если задать снятие показаний и их передачу не каждое пробуждение по WD-таймеру, а, например, каждое седьмое (т. е. примерно раз в минуту), но отладка такой медленной программы резко усложнится.

Версия станции с ЖК-дисплеем

У нас уже все готово для того, чтобы представить версию метеостанции без записи на SD-карту. Реализацию этой версии мы оформим в виде варианта с ЖК-дисплеем MT-12864J, рассмотренным в главе 21. Для подключения SPI-интерфейса карты вместе с дисплеем у нас все равно не хватит выводов, так что запись на карту мы реализуем отдельно.

Схема метеостанции в таком варианте представлена на рис. 22.5.

Рис. 22.5. Схема метеостанции с ЖК-дисплеем MT-12864J

Подключение датчиков и часов ничем не отличается от рассмотренного ранее, а подключение ЖК-дисплея и обращение с ним описано в главе 21. Полную программу для этого случая можно скачать с сайта автора по ссылке http://revich.lib.ru/AVR/Meteo_LCD.zip. Внешний вид дисплея при работе этой программы показан на рис. 22.6.

Рис. 22.6. Отображение результатов работы метеостанции на ЖК-дисплее

Если внешний датчик будет недоступен (отключен, пропадет связь, закончатся батарейки), то в верхней строке после слов «На улице» будут отображаться прочерки. Если передаваемая устройством величина напряжения батарейки станет меньше порога (установленного нами в 3,3 В), то строка с данными начнет мигать. После включения питания внешнего датчика в течение первых 16 переданных показаний вместо значения напряжения батарейки станут передаваться одни нули, соответственно, дисплей главного модуля также будет миганием напоминать, что батареи в датчике якобы разряжены. Однако примерно через 2 минуты начнет передаваться измеренное среднее значение, и все должно встать на свои места.

* * *

Подробности

Величину порога, возможно, придется подкорректировать по результатам испытаний. Arduino Mini фактически ничего, кроме контроллера, не содержит, и она должна вообще «тянуть» вплоть до полного истощения батареек (согласно документации, у ATmega328 нижний предел питания 1,8 В[52]). У сенсора SHT1x нижний порог повыше (2,4 В), но это тоже далеко за пределами того, что дадут три даже истощенных элемента. То есть, нас будет лимитировать Xbee-модуль, который, согласно документации фирмы Digi, функционирует до 2,1 В. Из этих соображений и выбран порог в 1,1 В на элемент: 2,2 В на модуль или 3,3 В на все питание. В реальности это требует тщательной проверки, причем с реальными батарейками, а не в искусственно созданных условиях. Что же касается дальности работы выносного датчика, то Xbee-модули проявили себя наилучшим образом — в процессе испытаний данные уверенно принимались через три гипсолитовых межкомнатных перегородки толщиной 20 см каждая (уровень сигнала Wi-Fi в тех же условиях падает примерно на 70–80 дБ, что снижает скорость передачи до почти полной неработоспособности канала). Впрочем, если вас дальность работы не удовлетворит, то та же фирма Digi выпускает намного более мощный Xbee Pro.

Запись на SD-карту и программа станции с OLED-дисплеем

Наличие библиотеки для работы с SD-картой— один из самых ярких примеров преимуществ Arduino. Можно только представить себе, сколько трудов стоило бы написание на ассемблере кода доступа к флэш-карте, отформатированной в системе FAT32. Не невозможная задача, конечно, но весьма трудновыполнимая, особенно для любителя, да и вряд ли кто-нибудь когда-нибудь пытался выполнить ее на ассемблере. В моей книжке [21] есть пример кода записи/чтения применительно к картам типа ММС — «младшему брату» карт Secure Digital. Ни о каких именах файлов, разумеется, там и речи не идет — данные пишутся просто в ячейки памяти карты, и считаны могут быть только таким же способом, через контроллер. А здесь такие операции, как создание, удаление файла или проверка его существования, стандартные для «больших» компьютеров, выполняются не сложнее, чем в Windows. С единственным ограничением — собственно форматирование карты должно быть выполнено заранее.

Обычно карты продаются уже отформатированными в нужной нам системе FAT 16 или FAT32. Однако оно может «слететь» в процессе эксплуатации или наших с вами издевательств над картой, кроме того, изредка встречаются карты, отформатированные в системе, отличной от FAT. Для того, чтобы проверить систему и при необходимости заново отформатировать карту, ее надо вставить в кардридер компьютера, подождать, пока она появится в Проводнике и через контекстное меню выбрать пункт Свойства. Там на самой первой вкладке Общие будет показана Система, в которой отформатирована эта карта. Если она отличается от FAT 16 (просто FAT) или FAT32, то закройте окно свойств, заново вызовите контекстное меню и выберите пункт Форматировать.

Мы воспользуемся уже упоминавшимся модулем Wireless Shield SD, кроме разъема для Xbee-модуля, имеющим также слот для миниатюрной карты MicroSD. Более универсальным будет отдельный SD Card shield V4.0,4 куда можно вставлять SD-карты обычного типоразмера (карты MicroSD вставляются в него через адаптер). Обращение с этими модулями совершенно одинаково, и заняты у них одни и те же контакты, ориентированные на применение библиотеки SD, входящей в комплект Arduino IDE.

Недостаток большинства подобных стандартных Arduino-модулей с разъемом для SD-карты состоит в том, что они в качестве вывода «выбор кристалла» задействуют вывод номер 4. Это сделано по понятным причинам — чтобы освободить стандартный вывод SS порта SPI (вывод 10) для использования этого интерфейса в каких-то иных целях. Однако такой прием приводит к ограничениям на применение вывода 10 — он должен быть установлен только «на выход», иначе стандартные функции SPI контроллера работать не будут. Потому вместо одного дополнительного вывода карта фактически занимает два. К счастью, в качестве выходного мы можем применять порт 10 по своему усмотрению — в нашей схеме он служит одной из линий данных.

Работа метеостанции с функциями записи на SD-карту

Полную программу метеостанции с OLED-индикаторами, построенной согласно схеме на рис. 22.1 с добавленными функциями записи на SD-карту, можно скачать с сайта автора по ссылке http://revichJib.ru/AVR/Meteo_OLED.zip. Внешний вид индикационной панели с отображением данных показан на рис. 22.7 далее, в разд. «Конструкция». Согласно этой программе, при каждом включении питания в файл data.txt будет записываться строка Arduino meteostation data. А в установленные моменты времени в него записываются данные в виде строки:

06:00 06.04.14 +21.2 26 750 +20.7 27 4.4

Здесь после значения времени идут сведения о внутренней температуре и влажности, затем давление, потом температура и влажность с выносного датчика. В конце выводится информация о напряжении батареи датчика, которая позволит осуществлять контроль за работой узла определения разрядки батареи (в случае необходимости подкорректировать порог надо знать, при каком напряжении датчик прекратил работу). Строка содержит 40 символов, так что об исчерпании пространства на карте можно не беспокоиться — самой маленькой карты объемом в гигабайт хватит примерно на 8 тысяч лет непрерывной записи. Учитывая такой объем свободного пространства, на карте удобно заодно хранить все сопутствующие программы: Arduino IDE вместе с прошивкой станции и утилиту для установки часов. В соответствии с программой, запись данных на карту будет происходить в часы, кратные трем: в 0, 3, 6, 9, 12, 15, 18 и 21 час. Согласно международным правилам, три часа составляют так называемый синоптический интервал, а моменты записи должны отсчитываться по всемирному времени UTC. В настоящее время московский регион отличается от UTC на четыре часа (т. е. всемирному времени 00:00 соответствует московское 04:00), потому для укладки в стандартный ряд синоптических наблюдений необходимо учитывать эту поправку[53]. Закомментированная строка в начале процедуры записи на карту if (clock.second = 0) служит для отладки программы — если ее восстановить (а вышележащую, наоборот, спрятать за комментарием), то запись на карту будет происходить каждую минуту.

После вставки карты следует обязательно перезагрузить станцию и проследить, чтобы после загрузки в первую очередь появилась надпись SD card Ok. Если вместо этого появляется сообщение об ошибке инициализации SD card failed, то выключить и включить питание станции необходимо еще раз. Если карта инициализировалась верно, то в файл data.txt на ней запишется строка Arduino meteostation data. Если этот файл на карте не существовал, то он будет создан заново, иначе указанная строка просто запишется в него еще раз, сигнализируя о том, что станция включалась.

Подтверждение тому, что запись действительно идет успешно, можно получить, если проследить за поведением станции в момент, соответствующий очередному сеансу записи, — не должно появиться сообщение File open failed!, которое возникает, если карта просто отсутствует в слоте. Если же карта вставлена, но инициализация прошла неудачно, то в момент записи станция «повиснет» примерно на 12 секунд — таковы особенности работы библиотеки SD.

Повторю — для успешной записи на карту карта должна быть вставлена в слот до включения питания станции. Следует взять за правило перезапускать станцию после каждого извлечения/вставки карты. Предоставляю читателю самому поэкспериментировать с модификацией программы, которая позволила бы избежать таких ограничений. Вероятно, для этого придется привлечь какую-нибудь другую библиотеку по работе с SD-картами в Arduino — особенность прилагаемой библиотеки SD в том, что если карта однажды была инициализирована, то после извлечения и последующей ее вставки при работающем контроллере от программы невозможно добиться не только сообщений об ошибках, но не получается даже принудительно инициализировать карту заново.

Конструкция

Все элементы разработанных нами схем по рис. 22.1 и 22.5 продаются в комплекте с соединительными кабелями, исключение составляют только дисплеи. В «Амперке» имеется в продаже специальная расширительная плата Troyka Shield, позволяющая подключать подобную периферию. Таким образом, самый простой вариант создания законченной конструкции главного модуля станции заключается в приобретении этой платы и установке друг на друга последовательно трех плат (Arduino Uno, Troyka Shield и Wireless Shield). Ha Wireless Shield, которая должна быть сверху этого «бутерброда» (для лучшей работы модуля ХЬее), имеется поле пустых контактов достаточного размера, чтобы на нем можно было установить контактную колодку для подключения ЖК-дисплея.

Все это монтируется в пластиковый (обязательно!) корпус, передняя стенка которого вырезана под дисплей. Работе ХЬее пластиковый корпус не помешает, а вот датчики лучше вынести наружу — даже то небольшое количество тепла, которое выделяют компоненты схемы при работе, исказит значения температуры, а влажность в герметичном корпусе может отличаться от реальной на десятки процентов (не в этом ли причина столь плохой работы серийных изделий?).

Сложнее окажется конструкция варианта с двумя OLED-дисплеями — на стандартных Arduino-платах для них просто не хватит места. Возможный вариант — изготовление кросс-платы, на которую устанавливаются все модули, соединенные дорожками с контактами платы Arduino. Отверстия на кросс-плате делаются так, чтобы штыри Wireless Shield можно было протащить насквозь, пропаять, а затем надеть на них плату Arduino Uno с другой стороны. На рис. 22.7 показано, как выглядит вариант конструктивного исполнения станции с отображением информации на дисплеях.

Рис. 22.7. Готовая метеостанция на стене загородного дома

В выносном датчике устанавливать какие-либо платы расширения не имеет особого смысла. Все компоненты схемы по рис. 22.4 можно установить на печатной макетной плате (подобной показанной на рис. 3.2 слева), и соединить их монтажными проводами. Конечно, не стоит паять непосредственно выводы платы Arduino Mini — придется приобрести переходные колодки типа PBS.

Трудность состоит в том, что шаг выводов Xbee-модуля — 2 мм, и под него довольно сложно найти готовую плату. Так что придется либо раскладывать и изготавливать ее самостоятельно, либо пожертвовать экземпляром Wireless Shield, вырезав из нее кусок с колодками для подключения Xbee-модуля. На этой плате рядом с колодками имеются соединенные с ними контактные площадки, расположенные с обычным шагом 2,5 мм, куда можно поместить вилку штыревого PLS-разъема, получив таким образом переходную панельку для установки в обычную плату. Все это монтируется в корпус вместе с батарейным отсеком на три элемента типоразмера АА или С. Как и в случае главного модуля станции, плату SHT1x с датчиками лучше вынести за пределы корпуса, защитив ее от внешних воздействий ограждением или кожухом из пластиковой сетки.

О недостатках Arduino

Как мы видим, проектировать и изготавливать конструкции с помощью Arduino гораздо проще, чем обычным дедовским способом, из отдельных компонентов. Но за эту простоту приходится платить. В некотором смысле ситуация с Arduino напоминает историю персональных компьютеров — как известно, самым первым продуктом компании Microsoft, созданной в 1976 году, была реализация языка Бейсик под компьютер Altair, для которой требовалось аж целых 4 килобайта памяти. Андрее Хейлсберг тоже создавал свою первую версию Pascal на чистом ассемблере, получив файл объемом 31 Кбайт. Современные среды программирования (в том числе и для тех же самых языков) занимают гигабайты, но при этом работают на гигагерцовых компьютерах медленнее, чем первые продукты Гейтса и Хейлсберга на машинах того времени с тактовой частотой и объемом памяти в тысячи раз меньшими. Подобно им и AVR-контроллеры, запрограммированные в среде Arduino, оказываются далеки от своих потенциальных возможностей.

Я не ставлю перед собой задачу как-то принизить значение Arduino и отговорить читателей от работы с этой платформой. Наоборот, я всячески приветствую ее энтузиастов и распространителей. Хочется только, чтобы натолкнувшись в Сети на ее критику, неискушенный читатель не впадал в уныние, а хорошо представлял себе, как говорится, «на каком свете он находится».

Простота Arduino во многом обусловлена тем, что практически все действия в программе осуществляются в ее главном цикле. Но такая простота оборачивается недостаточной надежностью работы — «правильно» запрограммированный контроллер работает почти исключительно через прерывания. Например, неверно заставлять программу отслеживать нажатие кнопки в главном цикле и убирать дребезг путем простых временных задержек, как это делается в распространенном примере для начинающих[54]. Когда контроллер основное время занят последовательным отслеживанием происходящих событий, он запросто может потерять какое-то из них. Так поступали в семидесятые годы, когда контроллеры были намного примитивнее сегодняшних. В «правильной» программе состояние кнопки отслеживается по внешнему прерыванию, а дребезг убирается его запретом и последующим разрешением по прерыванию таймера. Только так эти действия не могут помешать никаким другим процедурам в программе.

В Arduino просто эксплуатируется факт, что современные микроконтроллеры работают очень быстро, но, по мере усложнения программы, вы довольно скоро упретесь в порог этого быстродействия и не будете понимать, как из этой ситуации вывернуться. На Habrahabr.ru один критик платформы писал, что «вы можете всю жизнь формировать задержки с помощью delay-функций и не иметь простейшего представления, как работает таймер на микроконтроллере».

Впечатляют и размеры программ, получающихся после компилирования скетчей в среде Arduino IDE. Программа метеостанции с ЖК-дисплеем займет почти 20 килобайт — около 10 тыс. AVR-команд. Это непредставимо большая величина для таких устройств, и неудивительно, что при выполнении времязависимых операций они будут тормозить, — именно по этой причине при сборе данных, поступающих из последовательного порта, нам приходится с помощью задержек ожидать, пока они не соберутся в буфере. А если нам понадобится принять или передать пару десятков килобайт или мегабайт данных, что много больше объема буфера? Как угадать задержки так, чтобы гарантированно ничего не потерять?

Программа, состоящая из всего двух функций: digitalWrite (HIGH) и digitalWrite (LOW), переменно переключающих внешний вывод без искусственных задержек, при проверке на осциллографе покажет меандр с частотой 50Гц — это в контроллере, работающем на частоте 16 МГц! Простая замена этих функций на непосредственное управление портом, даже без выхода за пределы среды Arduino, ускоряет выполнение операций переключения порта примерно в 10 тыс. раз — с почти 2 миллисекунд до долей микросекунды.

Хорошей иллюстрацией к расточительности языка служит также пример пустой программы из двух строк, которую мы употребляли в качестве заглушки при программировании Xbee-модуля. Ее размер после компиляции составит целых 466 байтов — с помощью ассемблера в такой объем можно запросто втиснуть небольшую программку ориентирования по звездам для орбитального аппарата (реальный случай с одним программистом 60-х годов прошлого века из НАСА, который упаковал такую программу в остававшиеся свободными 256 байт памяти бортовой ЭВМ спутника).

Нет особых проблем применять к разработке программ для Arduino все возможности МК AVR, включая и прерывания, но при этом среда Arduino потеряет свою простоту и идеальную приспособленность к нуждам любителей. Придется ковыряться в англоязычных «даташитах», изучать регистры, прерывания и таймеры, вникать в тонкости программирования той или иной процедуры, и тогда вы быстро придете к выводу, что Arduino IDE вместе с языком Proccesing только мешают — придется переходить на обычный С или на ассемблер. К этому выводу в конце концов приходят все, кто старается двигаться дальше. Но не унывайте: Arduino дает отличный старт!

Более 800 000 книг и аудиокниг! 📚

Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением

ПОЛУЧИТЬ ПОДАРОК