Беспроводная метеостанция [Амперка / Вики]
Что это такое?
В этой статье мы расскажем о том, как собрать полноценную метеостанцию, передающую данные о погоде на широко известный сервис «народный мониторинг».
Наша метеостанция будет состоять из двух устройств: компактного автономного устройства, измеряющего погодные показатели, и устройства-ретранслятора, получающего эти показатели и отправляющего их на «народный мониторинг». Устройства будут связываться по беспроводному каналу связи на частоте 433 МГц. Автономная часть будет питаться от трёх пальчиковых батареек и сможет просуществовать на одном комплекте батарей до года при периоде опроса датчиков в 20 мин.
Такая конструкция позволяет не сверлить стены для прокладки проводов с улицы, где необходимо производить измерения, в помещение, где результатами этих измерений надо пользоваться.
Что для этого необходимо?
Для изготовления автономного передатчика нам понадобятся:
Держатель пальчиковых батареек на x3 AA
Для изготовления ретранслятора нам понадобятся:
Так же удобно установить два светодиода для индикации процессов:
Для звуковой индикации разряда батареи автономной части удобно использовать пьезо-пищалку:
Как это собрать?
Сборка автономной части
Сборка ретранслятора
- Вставьте Ethernet шилд в Arduino Uno, установите сверху макетку и вставьте в неё беспроводной приёмник. Подключите вывод
7
Arduino к выводу2
приёмника. - Подключите питание и землю приёмника к выводам
и GND5V
Arduino.
На этом сборка минимально функционального ретранслятора закончена. Если вы хотите установить светодиодную индикацию и звуковую сигнализацию, то выполните пункты ниже.
- Установите светодиоды и резисторы, подключите красный светодиод к контакту
6
, зелёный — к контакту5
. - Установите пьезопищалку, подключите её к контакту
4
.
Исходный код
Код автономной части
- meteo_sensor.ino
#include <Arduino.h> #include <SHT1x.h> #include <LowPower_Teensy3.h> #include <ampline.h> // Таймаут между посылками (не более 65535) #define TIMEOUT 60000 // Количество попыток отправки посылки #define ATTEMPTS 3 // Информационный пин передатчика #define RF_PIN 5 // Пины датчика температуры и влажности #define GND1_PIN 10 #define VCC1_PIN 11 #define GND2_PIN 7 #define VCC2_PIN 8 #define DATA_PIN 12 #define CLK_PIN 9 AmperkaLine rf(RF_PIN); SHT1x sht1x(CLK_PIN, DATA_PIN); void loop(void); // Функция усыпления платы. Каждые TIMEOUT секунд // будет вызываться функция loop_func. TEENSY3_LP LP = TEENSY3_LP(); sleep_block_t* LP_config; void sleep_mode(void) { LP_config = (sleep_block_t*)calloc(1,sizeof(sleep_block_t)); // Просыпаться будем по таймеру LP_config->modules = (LPTMR_WAKE); // Задаём таймаут для таймера LP_config->lptmr_timeout = TIMEOUT; // По истечении таймаута будет вызываться функция loop LP_config->callback = loop; LP.Hibernate(LP_config); } // Функция включения периферии void periferial_start(void) { // Включаем линию передачи данных pinMode(RF_PIN, OUTPUT); // Включаем питания и земли датчиков температуры и влажности pinMode(GND1_PIN, OUTPUT); pinMode(GND2_PIN, OUTPUT); pinMode(VCC1_PIN, OUTPUT); pinMode(VCC2_PIN, OUTPUT); digitalWrite(GND1_PIN, LOW); digitalWrite(GND2_PIN, LOW); digitalWrite(VCC1_PIN, HIGH); digitalWrite(VCC2_PIN, HIGH); // Включаем светодиод для индикации передачи pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); // Выбираем в качестве опорного напряжения внутренний // источник (=1.2 В) analogReference(INTERNAL); } // Функция выключения периферии void periferial_stop(void) { // Выключаем линию передачи данных pinMode(RF_PIN, INPUT); // Выключаем датчик температуры и влажности pinMode(GND1_PIN, INPUT); pinMode(GND2_PIN, INPUT); pinMode(VCC1_PIN, INPUT); pinMode(VCC2_PIN, INPUT); pinMode(18, INPUT_PULLUP); pinMode(19, INPUT_PULLUP); // Выключаем светодиод digitalWrite(LED_BUILTIN, LOW); } void setup(void) { // Ничего не инициализируем, сразу засыпаем sleep_mode(); } // Эта функция выполняется раз в TIMEOUT секунд void loop(void) { unsigned long msg; byte temp, humidity, voltage; // Включаем периферию periferial_start(); // Подождём, пока включится датчик температуры и влажности delay(30); // Получаем входные данные с сенсоров temp = (byte)(sht1x.readTemperatureC() + 40.)*2; humidity = (byte)sht1x.readHumidity(); voltage = analogRead(A0)/4; // Составляем из данных посылку msg = 0; msg |= voltage; msg <<= 8; msg |= humidity; msg <<= 8; msg |= temp; // Отправляем несколько раз посылку for(int i = 0; i < ATTEMPTS; i++) rf.send(msg); // Выключаем периферию periferial_stop(); // После выхода из функции плата снова уснёт }
Код платы, работающей в помещении
- receiver.ino
#include <Arduino.h> #include <SPI.h> #include <Ethernet.h> #include <ampline.h> byte mac[] = { 0x90, 0xA7, 0xDA, 0x0F, 0xBC, 0x75 }; char server[] = "narodmon.ru"; EthernetClient client; const int rfpin = 7; AmperkaLine rf(rfpin); void setup(void) { pinMode(rfpin, INPUT); pinMode(6, OUTPUT); Serial.begin(9600); Serial.println("Started."); } void loop(void) { static unsigned long pushtimeout = 0; static float temp, humidity, voltage; unsigned long msg; int res; if((res = rf.receive(&msg)) == 0) { temp = ((float)(msg&0xFF))/2. - 40.; msg >>= 8; humidity = (float)(msg&0xFF); msg >>= 8; voltage = (float)(msg&0xFF) / 256. * 1.2 * 10 * 1.1; digitalWrite(6, HIGH); Serial.print("Temp: "); Serial.print(temp); Serial.print(", humidity: "); Serial.print(humidity); Serial.print(", voltage: "); Serial.println(voltage); digitalWrite(6, LOW); } else Serial.println('E'); if(millis() - pushtimeout > 60000*5) { pushtimeout = millis(); Serial.println("Starting Ethernet..."); if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); while(1) { } } delay(1000); Serial.println("connecting..."); if (client.connect(server, 8283)) { Serial.println("connected"); client.println("#90-A7-DA-0F-BC-75#Sensor#55.751775#37.616856#0.0"); client.print("#90A7DA0FBC7501#"); client.print(temp, DEC); client.println("#In"); client.print("#90A7DA0FBC7502#"); client.print(humidity, DEC); client.println("#Humidity"); client.print("#90A7DA0FBC7503#"); client.print(voltage, DEC); client.println("#Voltage"); client.println("##"); } else Serial.println("connection failed"); { unsigned long tm = millis(); while(millis() - tm < 5000) { if (client.available()) { char c = client.read(); Serial.print(c); } } } client.stop(); } }
Регистрация метеостанции в «Народном мониторинге»
Чтобы данные, передаваемые нашим устройством, корректно отображались на народном мониторинге, необходимо выполнить следующее:
Установить уникальный MAC-адрес устройства.
- Зарегистрироваться на сайте «Народного мониторинга».
Авторизоваться.
- Открыть список датчиков и установить номиналы передаваемых данных.
Демонстрация работы устройства
Что ещё можно сделать?
Teensy прямо на борту имеет часы реального времени (RTC). Для их работоспособности не хватает только кварца. Можно купить кварц на 32,768 КГц в любом магазине радиоэлементов и припаять его. Тогда можно пробуждать Teensy по будильнику RTC. Достоинство в том, что можно будить устройство чаще в те часы, когда нужны более точные показания. Например, в рабочее время будить устройство каждые 5 минут, а в остальное — каждые полчаса.
Метеостанция на Arduino от А до Я. Часть 3 / Habr
Продолжение. Предыдущая часть.
Оглавление:
Наконец мы подошли к самой трудной части для любого программиста — описать по-человечески что он там наваял.
Исходный код для сервера составляет около 1300 строк, включая отступы, но это не должно вас пугать. Исходный текст снабжен подробными комментариями, в этом плане я не ошибусь, если скажу, что мои исходники описаны лучше чем любые другие которые вы только сможете найти. В комментариях прямо в исходном тексте вы найдете всю распиновку для подключения модулей и все необходимые ссылки на внешнюю документацию. Секрет прост — я писал комментарии для себя постоянно, «по ходу пьесы», поэтому никаких трудностей с документированием не испытал.
Как я уже писал вы можете начать и не имея всех модулей под рукой. Например, можно начать не имея радиомодуля или ESP8266. Датчик барометрического давления BMP180 также может отсутствовать. Добавите потом. Правда в этом случае вам (возможно) придется самостоятельно закомментировать в скетче те участки кода, которые отвечают за взаимодействие с отсутствующими блоками, но скорее всего этого не потребуется. Главное, чтобы хоть что-то собралось и заработало, тогда веселее продолжать.
Конкретно сейчас, в данном месте повествования, у нас пока ещё не собран заоконный (внешний) модуль и нет своего веб-сервера с базой данных, то нам пока не нужны (но если есть — подключите сразу, чтобы потом не копаться):
- радиомодуль nRF24L01+
- WiFi модуль ESP8266.
И всё таки я начну, пожалуй, с ESP8266, как самого проблемного в программировании и эксплуатации модуля. Причина кроется в разнообразии исполнения самих модулей и их прошивок.
Как я уже писал стандартные AT-прошивки для него имеют ряд недостатков:
- они всё ещё сыроваты (по состоянию на 2016)
- мне не удалось найти нормальную библиотеку для Arduino для управления модулем ESP8266 с помощью AT команд, пришлось «колхозить» самому.
Код для ESP8266 я не оформлял в отдельную библиотеку, а просто написал необходимые функции, поэтому скетч вышел таким длинным. Причём я реализовал только нужный мне функционал. Всё программирование для ESP с помощью AT команд сводится в итоге к парсингу строк и настройке задержек между командами.
Исходный код для сервера (центрального модуля) server.ino вы можете найти и скачать здесь.
Рядом я положил прошивку для ESP8266 в файле firmware/AT23-SDK101-nocloud.bin
и в том же каталоге находится документация для любознательных. Прошив указанную прошивку вы можете быть уверены, что мой скетч у вас заработает с WiFi так как было задумано. С другими AT прошивками я не экспериментировал. Дело в том, что мне удалось таки отыскать «продвинутую» не AT прошивку, и даже немного поучаствовать в её создании, которая как нельзя лучше подходит для наших целей (вот она esp-link). Однако, как это часто случается, всё произошло уже после завершения работы над текущей версии метеостанции, поэтому решено было оставить всё так как есть.
Итак, в самом начале вам придётся прошить указанную AT прошивку. Сложного тут ничего нет, но и простого тоже. Как это сделать описано много где в сети — ESP8266 — подключение и обновление прошивки.
Поскольку у моего USB-TTL конвертора не хватило мощности по току и USB порт постоянно отваливался (вот это поворот!), то электрически я подключил модуль для его прошивки способом «Arduino в качестве простого USB-to-Serial TTL конвертора».
Так как я работаю в Linux, то и прошивал с помощью esptool.py
. Для удобства прошивки я «наколхозил» небольшую вспомогательную плату с переключателями (здесь не описана).
После прошивки нужно установить скорость порта 57600 (так как для SoftSerial скорость порта в 115200 является большой и не гарантирует стабильную работу) командой
AT+UART_DEF=57600,8,1,0,0
Далее нужно слегка изменить стандартные библиотеки Arduino IDE, а именно в файле arduino/hardware/arduino/avr/libraries/SoftwareSerial/SoftwareSerial.h
изменить соответствующую строку на
#define _SS_MAX_RX_BUFF 128 // RX buffer size
в файле arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h
изменить соответствующие строки на
#define SERIAL_TX_BUFFER_SIZE 128
#define SERIAL_RX_BUFFER_SIZE 128
и в файле arduino/hardware/arduino/avr/cores/arduino/USBAPI.h
изменить соответствующую строку на
#define SERIAL_BUFFER_SIZE 128
Строго говоря это неправильно, т.к. при обновлении Arduino SDK эти файлы скорее всего будут перезаписаны и придется повторить все исправления заново. По науке мы должны изобрести свою библиотеку, которая манипулирует указанными значениями (если получится), но это на любителя.
Так или иначе предварительные манипуляции закончены.
Теперь переходим непосредственно к коду центрального блока (серверу) server.ino
В первых же строках вы должны изменить настройки доступа к вашей точке WiFi
const String SSID = "...";
const String PASSWORD = "...";
работу с веб сервером подробно рассмотрим позже.
Далее идут (закомментированные) отладочные определения:
//#define DEBUG
//#define DEBUG_RF
//#define DEBUG_ESP
//#define DEBUG_LOG_SD
Если что-то пойдёт не так вы всегда можете их раскомментировать, перекомпилировать и перезалить скетч и получить больше отладочной информации в консоли или записать её в файл на SD карту. Причем вы можете раскомментировать только то, что вам нужно. Например, барахлит модуль nRF24L01+? Тогда раскоментируем только DEBUG_RF, и т.д.
Далее идут обширные комментарии с распиновкой, инициализацией и подробным описанием всей периферии.
Здесь вы можете изменить номер радиоканала для nRF24L01+
#define RF_CHANNEL 73
Далее идёт void setup()
, что там делается понятно из подробных комментариев. Ну и затем void loop()
, код работы с веб-сервером пока не рассматриваем.
После заливки скетча, ваш центральный блок оживёт и что-то вам покажет, но не сразу, а спустя 10 минут — значение DELAY_LOCAL_SENSOR
. Можете его изменить конечно же.
На дисплее должны отобразиться: комнатная температура и влажность (данные поступят от датчика DHT11) и барометрическое давление (от BMP180).
За отображение на дисплее LCD 16×4 отвечают функции:
void lcdClearRow(int row)
// Печатает на экране показания удалённых, уличных датчиков
void lcdPrintOutdoor(int temperature, int humidity, float voltage)
// Печатает на экране показания внутренних, домашних датчиков
void lcdPrintHome(int temperature, int humidity, int pressure)
void lcdPrintInfo(char info[LCD_MAX_COLS])
void lcdPrintStatus()
void lcdPrintLastSensorTime()
Дизайн дисплея LCD1604 следующий.
В первой (верхней) строке печатается стилизованная иконка (идущий человечек) призванная обозначить погоду на улице (вышел на улицу, идёт по улице). Иконку придумывал сам, поэтому, если у вас есть лучшая идея (умещающаяся в 5х8 пикселов), можете указать в комментариях (в виде byte-массива). Поупражняться в пиксель-арте можно здесь Custom Character Generator for HD44780 LCD Modules. В этой же строке печатается напряжение питания заоконного модуля.
Во второй строке печатается «погода в доме» и атмосферное давление. Иконка дома стандартная, всем понятная.
В третьей строке lcdPrintLastSensorTime()
печатает сколько прошло времени (в сек) со момента снятия последних показаний датчиков, соответственно уличного и, через запятую, домашнего. Пригодится чтобы точно знать, что метеостанция не показывает погоду за вчера. По сути это отладочная информация и её можно убрать в финальной версии.
И в последней четвёртой строке экрана с помощью функции lcdPrintStatus()
печатается статусная информация, где
- s — это локальный датчик давления
- e — это модуль ESP8266
- i — это подключение к WiFi
- w — это доступность web сервера
- l — лог-файл на SD карте
После каждого из этих условных буквенных обозначений будет стоять знак «плюс» или «минус», что означает нет или есть ошибки, проблемы в работе соответствующих модулей.
Возвращаясь к вопросу выбора железа, поясню про преимущества выбора текстового LCD1604 дисплея перед графическим. Дело в том, что модули LCD1604 купленные у различных продавцов в большинстве случаев будут одинаковыми и предсказуемыми в подключении и просты в программировании. Чего нельзя сказать о графических дисплеях, хотя нарисовать и показать на них можно гораздо больше. Разборчивость изображения с расстояния в несколько метров опять же лучше у текстового дисплея, таки да, на графическом дисплее можно сделать шрифт побольше, но тогда много ли можно на нём уместить?
Далее. Как только вы зальете скетч и убедитесь, что все работает как надо, то можете переподключить «материнскую» плату Arduino Mega к внешнему источнику питания. Или оставить как есть, подключённым к USB компьютера, чтобы посматривать на всю эту красоту в отладочной консоли.
Если у вас не все блоки в сборе, то вы можете закомментировать ненужный код. Хотя, повторюсь, должно работать и так, просто будете получать сообщения об ошибках в консоли. Как это обойти?
Например, вы ещё не приобрели датчик атмосферного давления BMP180. В скетче server.ino ищем строки, отвечающие за подключение соответствующих библиотек, в нашем случае это
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
Комментируем этот блок.
Далее в Arduino IDE запускаем компиляцию кода (не прошивку) и смотрим на какие строки ругается компилятор. Комментируем эти строки. Операцию повторяем до тех пор, пока код не будет собираться нормально, без ошибок. Хорошей практикой будет перед редактированием создать копию скетча, чтобы, когда из солнечного Китая приедет нужный датчик, не повторять все операции обратно.
Ссылки на используемые библиотеки даны в исходном коде. Если такой ссылки нет, то использовалась стандартная библиотека Arduino IDE.
На всякий случай все библиотеки (кроме стандартных), которыя я использовал сохранены в каталоге libraries. Строго говоря, это неправильно. Вы должны скачать свежие версии библиотек из их официальных репозиториев (с исправленными ошибками, новыми возможностями), но на тот случай если их затруднительно найти, либо они уже удалены, либо старые версии не поддерживаются, только для этого случая я сохранил все используемые библиотеки.
Далее следует сборка заоконного датчика, поэтому эта часть вышла короткой, чтобы не смешивать.
Метеостанция на ардуино своими руками
Благодаря современным устройствам для измерения погодных условий вы можете всегда оставаться в курсе прогнозов на интересующую дату или время. Но в некоторых ситуациях вам необходимо измерять параметры окружающей среды здесь и сейчас.
Если десять – двадцать лет назад такую функцию выполняли громоздкие термометры и анемометры, сегодня замер температуры и влажности может производиться с помощью электронного устройства. Которое запросто поместиться в кармане или в дорожной сумке, благодаря чему вы сможете взять его с собой куда угодно или разместить в подвале, теплице, собственной мастерской, сушилке и других помещениях, где важно контролировать уровень температуры и влажности.
Что потребуется для изготовления портативной метеостанции?
Датчики температуры и влажности окружающей среды достаточно часто применяются человеком в повседневной жизни. Вы могли и раньше встречать их в конструкции автомобилей, самолетов, в некоторых мобильных телефонах и т.д. Их даже можно приобрести как отдельный прибор в интернет-магазине, но куда интересней изготовить такую домашнюю метеостанцию самостоятельно.
Для этого вам понадобиться такой набор элементов:
- Датчик температуры и влажности DHT11 – используется как основное приспособление для регистрации параметров окружающей среды;
- Плата Arduino UNO – необходима для обработки получаемых с датчика данных и вывода их на цифровой дисплей;
- Электронный дисплей – устройство для отображения измеряемых данных и перевода их в понятную для обывателей форму;
- Макетная плата – предназначена для фиксации всех элементов и размещения на жестком основании, упрощает электрическое соединение всех деталей;
- Соединительные провода со штекером или под пайку.
В данной ситуации выбран датчик DHT11, как одно из наиболее популярных средств фиксации температуры и влажности, помимо этого он хорошо подходит для всевозможных домашних проектов. В его состав входит резистивный элемент, определяющий влажность и термистор, определяющий температуру. Для передачи и преобразования сигнала используется микроконтроллер, в этом примере мы установим Arduino, хотя вы можете использовать и другой.
Характеристики датчика DHT11

Следует отметить, что данный датчик выбран как наиболее доступный и удобный в применении. Помимо этого он характеризуется следующими рабочими параметрами:
- Напряжение питания от 3 до 5 В;
- Потребляет от источника питания ток в 2,5 мА;
- Способен измерять влажность окружающего пространства в пределах от 20 до 80%;
- Температурные колебания измеряет в пределах от 0 до 50°С;
- Погрешность при измерении влажности составляет 5%, а при измерении температуры в пределах 2%;
- Частота измерений составляет одно измерение в секунду;
- Габариты датчика составляют 12×15,5*5,5 мм.
Датчик DHT11 имеет пластиковый корпус и оснащается четырьмя контактами, такое количество выводов обеспечивает удобство подсоединения к устройствам обработки данных. В работе самодельной метеостанции все четыре вывода не используются, из них вам понадобится только три VCC, GND, DATA. Запитать датчик вы можете от любого источника с уровнем напряжения на выходе от 3 до 5 В.
В некоторых схемах можно встретить подключение резистора на 5 – 10 кОм к выводу передачи данных от датчика к микроконтроллеру. Следует отметить, что в данной ситуации этого делать не нужно, так как резистор уже входит в состав платы.

В интернете вы найдете как отдельные датчики, так и уже собранные в готовый модуль. Последние гораздо удобнее, поэтому предпочтительнее использовать их. Несмотря на то, что внешний вид модулей отличается, их принцип подключения идентичен, вам необходимо лишь обратить внимание на расположение выходов с датчика.
Подключение датчика к микроконтроллеру Arduino
От измерительного устройства к Arduino поступает цифровой сигнал, передающий сразу обе величины (температуру и влажность).
Передача данных от датчика к микроконтроллеру имеет такую последовательность:
- От микроконтроллера Arduino к датчику поступает запрос путем смены сигнала с 0 на 1;
- Получив запрос, DHT11 выдает Arduino информацию посредством изменения битовой кодировки;
- При согласовании запроса и ответа от DHT11 на Arduino поступает отчет в размере 5 байт о состоянии температуры и влажности.
В передаваемом отчете из 5 байт первые два содержат информацию об уровне температуры, вторые два о влажности, а пятый представляет собой контрольную сумму уровня температуры и влажности во избежание ошибки измерений. Так как передача данных от DHT11 имеет свои особенности, для корректировки его взаимодействия с микроконтроллером были внесены изменения в программу. Для этого через компьютер или ноутбук необходимо записать на Arduino следующую программу:
Метеостанция на Arduino
Ниже представлена принципиальная схема самодельной метеостанции на основе датчика DHT11 и микроконтроллера Arduino.

Вышеприведенная схема метеостанции, которую вы можете собрать своими руками, будет отображать на мониторе информацию о температуре и влажности. Но с датчиком DHT11 на мониторе будет отображаться только целое число, а дробное значение обнуляется. В принципе, десятичные данные температуры и влажности для него совершенно неактуальны из-за низкой точности измерений. Но, если в вашей ситуации важно знать точную величину с определенным количеством знаков после запятой, датчик DHT11 придется заменить на более совершенный DHT22.
Следует отметить, что предложенная выше программа уже включает в себя возможность получения значения с дробной частью. Поэтому если возможности вашего монитора ограничены или вы не хотите загромождать его лишними нулями после запятой при использовании датчика DHT11, вам придется немного изменить предложенную программу, дополнив ее функцией плавающей точки – dtostrf.
Почему важно знать индекс тепла?
Как вы могли заметить, погода на улице в разные дни ощущается совершенно по-разному. Несмотря на то, что термометр показывает одну и ту же отметку, ощущаться одна и та же температура будет иначе. Это обусловлено значительным влиянием влажности на ваш организм.
Так, при повышении температуры воздуха в летний период организму требуется выделить куда больше влаги для компенсации перегрева от окружающей среды. При выделении влаги из организма (потообразовании) тело человека отдает тепловую энергию молекулам жидкости, которые испаряются, значительно облегчая процесс охлаждения. Но, при наличии в окружающей среде большого процентного содержания влаги, выделение молекул пота будет затруднено, из-за чего организм не сможет так просто охладиться.
Поэтому так важно контролировать соотношение температуры и влажности окружающей среды для маленьких детей и людей преклонного возраста. Их соотношение, в предложенном варианте домашней метеостанции, отображается тепловым индексом, который рассчитывается на основании величины температуры и влажности. Угроза получения теплового удара или перегрева особенно остро возникает при достижении отметки теплового индекса в 91 °F (32 °C) и выше. Благодаря предложенному варианту домашней метеостанции вы можете измерять и тепловой индекс, что поможет вам обезопасить себя и близких от случайного перегрева.
В приведенной схеме домашней метеостанции на мониторе данные распределяются следующим образом:
- HiX (heat index) – тепловой индекс;
- T – величина температуры окружающей среды;
- H – процент влажности.
Рисунок 4: пример отображения данных на мониторе
Метеостанция для записи температуры, атмосферного давления и влажности [Амперка / Вики]
// библиотека для работы I²C #include <Wire.h> // библиотека для работы с метеосенсором #include <TroykaMeteoSensor.h> // Подключаем библиотеку для работы с дисплеем #include <QuadDisplay2.h> // библиотека для работы с модулями IMU #include <TroykaIMU.h> // библиотека для работы с протоколом 1-Wire #include <OneWire.h> // библиотека для работы с датчиком DS18B20 #include <DallasTemperature.h> // библиотека для работы с SPI #include <SPI.h> // библиотека для работы с SD-картами #include <SD.h> // сигнальный пин датчика DS18B20 #define ONE_WIRE_BUS 5 // даём разумное имя для CS пина microSD-карты #define SD_CS_PIN 8 // создаём объект для работы с метеосенсором TroykaMeteoSensor meteoSensor; // создаём объект класса QuadDisplay, передаём номер пина CS, включаем режим работы с SPI QuadDisplay qd(10, true); // создаём объект для работы с барометром Barometer barometer; // создаём объект для работы с библиотекой OneWire OneWire oneWire(ONE_WIRE_BUS); // создадим объект для работы с библиотекой DallasTemperature DallasTemperature sensor(&oneWire); // перечисляем имена операций, которые мы будем выводить на дисплей enum { SAVE_SD, // имя для операции, которая записывает на SD данные IN, // имя для операции, которая выводит на дисплей надпись "In" TEMP_IN, // имя для операции, которая выводит на дисплей температуру с метеосенсора CEL, // имя для операции, которая выводит на дисплей символ °C HUM_IN, // имя для операции, которая выводит на дисплей влажность с метеосенсора PPM, // имя для операции, которая выводит на дисплей символ % BAR_IN, // имя для операции, которая выводит на дисплей давление с барометра в миллиметрах ртутного столба MER, // имя для операции, которая выводит на дисплей надпись "Hg" EMPTY, // имя для операции, которая очищает дисплей OUT, // имя для операции, которая выводит на дисплей надпись "Out" TEMP_OUT // имя для операции, которая выводит на дисплей температуру с датчика DS18B20 }; // создаем массив, в котором будем хранить последовательность операций int chain[] = { IN, TEMP_IN, CEL, HUM_IN, PPM, BAR_IN, MER, EMPTY, OUT, TEMP_OUT, CEL, EMPTY, SAVE_SD }; // создаем объект класса long для хранения счетчика unsigned long respite_Time = 0; // создаем объект для регулировки времени показа значений на экране int slowdown_qd = 1000; // создаем объект для хранения номера выполняемой операции int number_qd = 0; // создаем объект для записи данных на SD строкой String dataString = ""; void setup() { // инициализация дисплея qd.begin(); // инициализируем метеосенсора meteoSensor.begin(); // инициализация барометра barometer.begin(); // инициализируем работу с датчиком DS18B20 sensor.begin(); // устанавливаем разрешение датчика от 9 до 12 бит sensor.setResolution(12); // инициализируем карту памяти SD.begin(SD_CS_PIN); // собираем верхнюю строчку с наименованием данных dataString = "TEMP_IN (ºC)\tHUM_IN (%)\tBAR_IN (mmHg)\tTEMP_OUT (ºC)"; // вызываем функцию сохранения данных на SD saveSD(dataString); } void loop() { // запускаем бесконечный счетчик. Его содержимое будет обрабатываться с периодом равным slowdown_qd if (millis() - respite_Time > slowdown_qd) { // запускаем процесс, который будет выполнять операции согласно последовательности в chain switch (chain[number_qd]) { case IN: qd.displayDigits(QD_I, QD_n, QD_NONE, QD_NONE); break; case TEMP_IN: showData(meteoSensor.getTemperatureC()); break; case CEL: qd.displayDigits(QD_NONE, QD_NONE, QD_DEGREE, QD_C); break; case HUM_IN: showData(meteoSensor.getHumidity()); break; case PPM: qd.displayDigits(QD_NONE, QD_NONE, QD_DEGREE, QD_UNDER_DEGREE); break; case BAR_IN: qd.displayInt(barometer.readPressureMillimetersHg()); break; case MER: qd.displayDigits(QD_NONE, QD_NONE, QD_H, QD_9); break; case EMPTY: qd.displayClear(); break; case OUT: qd.displayDigits(QD_O, QD_u, QD_t, QD_NONE); break; case TEMP_OUT: // переменная для хранения температуры float temperature; // отправляем запрос на измерение температуры sensor.requestTemperatures(); // выводим значение с датчика DS18B20 на экран qd.displayFloat(sensor.getTempCByIndex(0), 1); break; case SAVE_SD: // собираем в строку сначала температура с метеосенсора dataString = String(meteoSensor.getTemperatureC()) + "\t"; // потом влажность dataString += String(meteoSensor.getHumidity()) + "\t"; // давление dataString += String(barometer.readPressureMillimetersHg()) + "\t"; // и температура с датчика DS18B20 dataString += String(sensor.getTempCByIndex(0)) + "\t"; // вызываем функцию сохранения данных на SD saveSD(dataString); break; } number_qd++; // проверяем не превысил ли номер операции количество операций if (number_qd > sizeof(chain) / sizeof(int) - 1) number_qd = 0; respite_Time = millis(); } } // функция работы датчика температуры и влажности void showData(float data) { // считываем данные с датчика int stateSensor = meteoSensor.read(); switch (stateSensor) { // выводим показания на дисплей case SHT_OK: qd.displayFloat(data, 1); break; // выводим сообщение "Errd", если ошибка данных или сенсор не подключён case SHT_ERROR_DATA: qd.displayDigits(QD_E, QD_r, QD_r, QD_d); // выводим сообщение "ErrC", если ошибка контрольной суммы case SHT_ERROR_CHECKSUM: qd.displayDigits(QD_E, QD_r, QD_r, QD_C); break; } } // функция сохранения данных на карту памяти void saveSD(String data) { // создаем файл для записи данных File dataFile = SD.open("datalog.txt", FILE_WRITE); // если файл существует и открылся if (dataFile) { // сохраняем данные dataFile.println(data); // закрываем файл dataFile.close(); } else { // если файл не доступен выводим ошибку на дисплей qd.displayDigits(QD_E, QD_r, QD_r, QD_S); } }
Arduino&Oregon или погодная станция своими руками / Habr
Не так давно ко мне в руки попалБлагодаря удачному стечению обстоятельств случилось так, что в одном месте оказались:
- Arduino — 1 шт.
- Датчик для измерения температуры и влажности Oregon THGN132N — 2 шт.
- RF-kit (приемник и передатчик) на 433МГц — 1 шт.
Дополнительно к вышеперечисленному (исключительно для быстрого прототипирования) использовался Starter Kit от Seeed Studio (из него понадобился base shield, дисплей 16х2 с последовательным интерфейсом, модуль светодиода и соединительные кабели).
Фото для самых нетерпеливых:
Диапазон 433МГц широко используется в различных бытовых приборах — на этой частоте «общаются» автосигнализации, системы управления светом, погодные станции и т.п. Приемники и передатчики для этого дипазона широко доступны и стоят совсем недорого.
Датчиками THGN132N оснащаются многие погодные станции Oregon и их так же можно приобрести отдельно. Они позволяют измерять температуру и относительную влажность, работают в широком температурном диапазоне (-40.0°C до +70.0°C), при этом точность измерения температуры — 0.1°C. Стоимость невысока и определяется в большей степени жадностью продавцов.
Под крышкой батарейного отсека находится переключатель «каналов» — доступны 3 варианта.
Датчик один раз примерно в 40 секунд передает данные о своем состоянии.
Передача осуществляется с помощью «on-off-keying» (OOK) и Манчестерского кодирования на несущей частоте 433.92МГц.
Протокол для датчиков Oregon (и некоторых других) энтузиасты в большей степени разобрали, что позволило осуществить текущий проект.
Хватит теории, переходим к практике. Собираем тестовый стенд:
- К ардуино подключаем base shield,
- RF-приемник подключаем к D2 (будем использовать прерывания),
- Дисплейный модуль — к D11 и D12 (TX и RX соответственно),
- Модуль светодиода — к D13.
Я использовал комплектующие серии Grove — они все оснащены идентичными разъемами и предельно просто подключаются к соответствующим разъемам шилда.
Адаптированный скетч со страницы из предыдущей ссылки (там автор использовал «мегу», пришлось немного подправить код под свое железо) для моих датчиков показывал следующие данные:OSV2 1A 2D 10 E3 20 07 88 04 3F 94
OSV2 1A 2D 20 08 8C 27 10 83 43 B6
Выяснилось, что (последовательно):
1A 2D — тип датчика (кстати, тут сразу вылезло некоторое несоответствие описания протокола и датчиков — этому коду соответствует другой набор датчиков, но это не помешало дальнейшей работе),
10 (20 для другого датчика) — номер канала передается в старших 4 битах (зависит от положения переключателя на датчике, принимает значения 1, 2, 4, при этом 4 соответствует 3 выбранному каналу),
E3 (08) — идентификатор конкретного датчика (?), но это значение может меняться после замены батарейки в датчике и нажатия кнопки Reset (расположена рядом с переключателем каналов и рекомендована к обязательному нажатию после замены батарейки).
Дальше содержится информация о состоянии батарейки (флаг того, что ее пора сменить) и данные, характерные для датчика: информация о текущей температуре и относительной влажности воздуха.
Из этого «разбора» для себя я выявил следующее: для метеостанции на ардуино можно задействовать существенно больше датчиков, нежели к заводской (например, для идентификации использовать комбинацию «тип датчика — канал», а не просто «канал» и т.п.), можно использовать не только те датчики, что вы приобрели самостоятельно, но и «соседские» (к сожалению, в моем радиоэфире были данные только от моих датчиков — у соседей или нет таких, или просто «не добивают»).
Теперь последние приготовления: для первого датчика выбираем 1 канал и отправляем его за окно на мороз, второму датчику назначаем 2 канал и оставляем пока жить при комнатной температуре. Датчики будем идентифицировать именно по каналу — для текущего случая этого более чем достаточно.
Немного программирования и готово:
На первой строке дисплея отображается текущая температура, относительная влажность и состояние батареи датчика за окном, на второй — то же самое, но для комнатного датчика. Светодиод, подключенный к ардуино моргает, когда приняты данные от какого-либо датчика (just for fun).
Дисплей из «стартового набора» одновременно обрадовал и разочаровал.
В «плюсах» — задействовано минимум цифровых выводов, в «минусах» — отсутствие поддержки кириллицы и в текущей версии библиотеки отсутствует возможность генерации своих символов (хотел нарисовать символы для «полной» и «пустой» батарейки).
Из-за последнего ограничения просмотрел доступные символы и подобрал два, подходящих для данного случая.
Результат виден на фото (у первого датчика установлена свежая батарейка, а во второй специально для теста был установлен почти разряженный элемент питания).
Небольшое замечание по дальности: в спецификации на орегоновские датчики заявлено, что они работают на расстоянии до 30 метров от базового блока.
В моем же случае (видимо из-за того, что качество RF-приемника или «загрязненность» эфира высока) система устойчиво работает при условии, что датчик находится на расстоянии до 5-7 метров (преграды в виде 1-2 стен тоже присутствуют). Надо будет при возможности приобрести приемник другого производителя и протестировать с ним.
Таким образом в «сухом остатке»:
- если у вас есть метеостанция (или датчики Oregon) их можно достаточно просто включить в систему домашней автоматизации без нарушения их штатной работы в составе заводской метеостанции,
- можно использовать не только свои, но и «соседские» датчики,
- несколько часов проведено с пользой и достигнут желаемый результат.
To-do:
- Добавить больше датчиков (уже готовы к подключению модули на DHT11, DHT22 (температура и влажность), BMP085 (температура и атмосферное давление).
- Подключить Ethernet-шилд с SD-картой и, использовав Google Chart Tools, сделать страничку с текущими значениями параметров и красивыми графиками (возможно, что веб-сервер придется городить где-нибудь на NAS, а ардуина будет только измерять и передавать серверу значения, но это уже совсем другая история).
- Задействовать RF-передатчик для управления люстрой (сейчас пока к ее оригинальному пульту другая ардуина подключена с помощью оптопар и «нажимает» кнопки на нем, но это тоже тема не для этого топика).
Ссылки по теме:
Эксперимент 16. Метеостанция [Амперка / Вики]
Список деталей для эксперимента
Принципиальная схема
Схема на макетке
Скетч
- p160_meteostation.ino
#include <math.h> int minute = 1; // Параметр конкретного типа термистора (из datasheet): #define TERMIST_B 4300 #define VIN 5.0 void setup() { // мы хотим передавать информацию на компьютер через USB, а // точнее через последовательный (англ. serial) порт. // Для этого необходимо начать (англ. begin) передачу, указав // скорость. 9600 бит в секунду — традиционная скорость. // Функция «begin» не является глобальной, она принадлежит // объекту с именем «Serial». Объекты — это «продвинутые» // переменные, которые обладают собственными функциями, // к которым обращаются через символ точки. Serial.begin(9600); // передаём заголовок нашей таблицы в текстовом виде, иначе // говоря печатаем строку (англ. print line). Символы «\t» — // это специальная последовательность, которая заменяется на // знак табуляции (англ. tab): 8-кратный выровненный пробел Serial.println("Minute\tTemperature"); } void loop() { // вычисляем температуру в °С с помощью магической формулы. // Используем при этом не целые числа, а вещественные. Их ещё // называют числами с плавающей (англ. float) точкой. В // выражениях с вещественными числами обязательно нужно явно // указывать дробную часть у всех констант. Иначе дробная // часть результата будет отброшена float voltage = analogRead(A0) * VIN / 1024.0; float r1 = voltage / (VIN - voltage); float temperature = 1./( 1./(TERMIST_B)*log(r1)+1./(25. + 273.) ) - 273; // печатаем текущую минуту и температуру, разделяя их табом. // println переводит курсор на новую строку, а print — нет Serial.print(minute); Serial.print("\t"); Serial.println(temperature); delay(60000); // засыпаем на минуту ++minute; // увеличиваем значение минуты на 1 // откройте окно Serial Monitor в среде Arduino, оставьте на // сутки, скопируйте данные в Excel, чтобы построить графики }
Пояснения к коду
Очень часто бывает полезно обмениваться данными, например, с компьютером. В частности, для отладки работы устройства: можно, например, смотреть, какие значения принимают переменные.
В данном эксперименте мы знакомимся со стандартным объектом
Serial
, который предназначен для работы с последовательным портом (UART) Arduino, и его методами (функциями, созданными для работы с данным объектом)begin()
,print()
иprintln()
, которые вызываются после точки, идущей за именем объекта:чтобы обмениваться данными, нужно начать соединение, поэтому
Serial.begin(baudrate)
вызывается вsetup()
Serial.print(data)
отправляет содержимоеdata
. Если мы хотим отправить текст, можно просто заключить его в пару двойных кавычек:""
. Кириллица, скорее всего, будет отображаться некорректно.Serial.println(data)
делает то же самое, только добавляет в конце невидимый символ новой строки.
В
print()
иprintln()
можно использовать второй необязательный параметр: выбор системы счисления, в которой выводить число (это может бытьDEC
,BIN
,HEX
,OCT
для десятичной, двоичной, шестнадцатеричной и восьмеричной систем счисления соответственно) или количество знаков после запятой для дробных чисел.
Например,
Serial.println(18,BIN); Serial.print(3.14159,3);
в мониторе порта даст результат
10010 3.142
Монитор порта, входящий в Arduino IDE, открывается через меню Сервис или сочетанием клавиш Ctrl+Shift+M. Следите за тем, чтобы в мониторе и в скетче была указана одинаковая скорость обмена данными,
baudrate
. Скорости 9600 бит в секунду обычно достаточно. Другие стандартные значения можете посмотреть в выпадающем меню справа внизу окна монитора порта.Вам не удастся использовать цифровые порты 0 и 1 одновременно с передачей данных по последовательному порту, потому что по ним также идет передача данных, как и через USB-порт платы.
При запуске монитора порта скетч в микроконтроллере перезагружается и начинает работать с начала. Это удобно, если вам нельзя упустить какие-то данные, которые начинаю передаваться сразу же. Но в других ситуациях это может мешать, помните об этом нюансе!
Если вы хотите читать какие-то данные в реальном времени, не забывайте делать
delay()
хотя бы на 100 миллисекунд, иначе бегущие числа в мониторе будет невозможно разобрать. Вы можете отправлять данные и без задержки, а затем, к примеру, скопировать их для обработки в стороннем приложении.Последовательность
\t
выводится как символ табуляции (8 пробелов с выравниванием). Также вы можете использовать, например, последовательность\n
для перевода строки. Если вы хотите использовать обратный слеш, его нужно экранировать вторым таким же:\\
.
Вопросы для проверки себя
Какие действия нужно предпринять, чтобы читать на компьютере данные с Arduino?
О каких ограничениях не следует забывать при работе с последовательным портом?
Как избежать ошибки в передаче данных, содержащих обратный слэш (
\
)?
Задания для самостоятельного решения
Перед таблицей данных о температуре добавьте заголовок (например, «Meteostation»).
Добавьте столбец, содержащий количество секунд, прошедших с момента запуска микроконтроллера. Можно уменьшить интервал передачи данных.
← Комнатный термометр | Оглавление | Пантограф →