Метеостанция на ардуино какой длины провод. Домашняя метеостанция на Arduino и отправка данных на "Народный мониторинг"

В этой статье мы расскажем о том, как собрать полноценную метеостанцию, передающую данные о погоде на широко известный сервис «народный мониторинг ».

Наша метеостанция будет состоять из двух устройств: компактного автономного устройства, измеряющего погодные показатели, и устройства-ретранслятора, получающего эти показатели и отправляющего их на «народный мониторинг». Устройства будут связываться по беспроводному каналу связи на частоте 433 МГц. Автономная часть будет питаться от трёх пальчиковых батареек и сможет просуществовать на одном комплекте батарей до года при периоде опроса датчиков в 20 мин.

Такая конструкция позволяет не сверлить стены для прокладки проводов с улицы, где необходимо производить измерения, в помещение, где результатами этих измерений надо пользоваться.

Что для этого необходимо?

Для изготовления автономного передатчика нам понадобятся:

    Держатель пальчиковых батареек на x3 AA

Для изготовления ретранслятора нам понадобятся:

Так же удобно установить два светодиода для индикации процессов:

Для звуковой индикации разряда батареи автономной части удобно использовать пьезо-пищалку:

Как это собрать?

Сборка автономной части

Сборка ретранслятора

На этом сборка минимально функционального ретранслятора закончена. Если вы хотите установить светодиодную индикацию и звуковую сигнализацию, то выполните пункты ниже.


Исходный код

Код автономной части

meteo_sensor.ino #include #include #include #include // Таймаут между посылками (не более 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 #include #include #include 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 () ; } }

Регистрация метеостанции в «Народном мониторинге»

Чтобы данные, передаваемые нашим устройством, корректно отображались на народном мониторинге, необходимо выполнить следующее:


Демонстрация работы устройства

Что ещё можно сделать?

    Teensy прямо на борту имеет часы реального времени (RTC). Для их работоспособности не хватает только кварца. Можно купить кварц на 32,768 КГц в любом магазине радиоэлементов и припаять его. Тогда можно пробуждать Teensy по будильнику RTC. Достоинство в том, что можно будить устройство чаще в те часы, когда нужны более точные показания. Например, в рабочее время будить устройство каждые 5 минут, а в остальное - каждые полчаса.

Как большинство работающих людей, занятие собственными проектами отнимает единственно оставшееся свободное время. Поэтому уже давно не творил и «чесались руки» что-либо сделать. Данная возможность появилась как ни странно в университете. За окном сентябрь, 4 курс и надвигающийся курсовой по схемотехнике. Нам сказали, что курсовые можно будет делать в двух вариациях: бумажном и «железе».

На протяжении 5 лет бумажный курсовой в нашем университете делался по принципу «возьми старые и собери их воедино». Такой подход меня не устраивал своей рутинностью, поэтому я сразу же выбрал курсовой в «железе». В качестве сердца курсовых был предложен микроконтроллер Arduino ввиду своей легкообучаемости. После определения с типом курсового оставался ещё один вопрос: а что именно бы сделать. Так как опыта в программировании микроконтроллеров не было, то сразу же открыл гугл и начал изучать существующие проекты. Проектов много, некоторые из них довольно простые, некоторые гениальны (3D сканер, например), но подавляющее большинство не имело практического применения. А мне хотелось именно того, что не валялось бы потом на полке и не собирало там пыль. После получасового экскурса в мир Arduino, меня заинтересовало тема домашних метеостанций, да и проекты показались не очень сложными в реализации (что в основном и подкупило новичка).

Вот так была выбрана тема для курсового и со временем проблем вроде как не намечалось.

Выбор компонентов

Просматривая разные проекты я понимал, что мне вполне достаточно будет Nano или даже Pro Mini, но всё-таки выбрал Arduino Uno в надежде, что программирование для Arduino мне понравится и в дальнейшем реализую ещё какие-нибудь проекты. Паяльник до этого в руках ни разу не держал, поэтому для более легкой разработки решил также приобрести Sensor Shield v4.

Подробнее

Плата способствует быстрому подключению датчиков, модулей, серво моторов, интерфейсов Serial и I2C, а также выводит все порты контроллера формфактора Duemilanova/Uno(также может быть подключена и в серию мега, но с ограничениями и вытекающими последствиями). Поддерживает другие шилды поверх себя.


В качестве источников для метеорологических данных выбрал следующие датчики:


С датчиками определился. Но что делать с данными, поступающими от датчиков. Решил выводить на дисплей. Картинку хотелось цветную, поэтому монохромные решения отбросил сразу. После нескольких минут поиска был выбран TFT дисплей ST7735 размером 1,8 дюймов.

Подробнее

Поскольку дисплей использует 4-проводной SPI протокод для связи и имеет свой собственный пикселе-адресуемый буфер кадра, он может использоваться с любыми видами микроконтроллеров. 1.8-дюймовый дисплей имеет 128x160 цветных пикселя. Также имеется слот для карты памяти microSD, следовательно, можно легко загружать полноцветные растровые изображения из FAT16 / FAT32 файловой системы microSD карты.

Характеристики:

  • Диагональ дисплея - 1.8 дюймов, разрешение 128x160 пикселей, 18-битный цвет (262 144 цвета)
  • Контроллер со встроенной пиксельной адресацией буфера видеопамяти
  • Встроенный слот для microSD - использует более 2 цифровых линий
  • Совместим с 3.3 и 5V
  • Габариты: 34 мм х 56 мм х 6,5 м


Программирование контроллера Arduino

После того, как определились с компонентами для метеостанции, начнём программирование контроллера. Для прошивки Arduino использовалась среда разработки Arduino IDE. Также использовал библиотеки от Adafruit.

Перед тем, как перейти к скетчу, рассмотрим функционал:

  • Показания снимаются с датчиков каждые 10 секунд и обновляются на экране только те показатели, которые были изменены по сравнению с прошлым измерением
  • Реализована передача данных по COM порту

Скетч

#include // library for communication with I2C devices #include // Core library for all sensors #include // library for BMP180 #include // Core graphics library #include // Hardware-specific library #include // library for communication with SPI devices #include "dht.h" // library for DHT #define DHT22_PIN 2 // connect data pin of DHT22 to 2 digital pin #define TFT_CS 10 // connect CS pin of TFT to 10 digital pin #define TFT_RST 9 // connect RST pin of TFT to 9 digital pin // you can also connect this to the Arduino reset // in which case, set this #define pin to 0! #define TFT_DC 8 // connect DC pin of TFT to 8 digital pin Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); //initialize TFT #define TFT_SCLK 13 // connect SCLK pin of TFT to 13 digital pin #define TFT_MOSI 11 // connect MOSI pin of TFT to 11 digital pin dht DHT; Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085); //initialize BMP180 int bmpFlag = 0; struct { uint32_t total; uint32_t ok; uint32_t crc_error; uint32_t time_out; uint32_t connect; uint32_t ack_l; uint32_t ack_h; uint32_t unknown; } stat = { 0,0,0,0,0,0,0,0}; // struct for dht status void setup(void) { Serial.begin(9600); Serial.println("Meteo Test"); Serial.println(""); if(!bmp.begin()) // check connection for BMP180 { Serial.print("Ooops, no BMP180 detected ... Check your wiring or I2C ADDR!"); bmpFlag = 1; } tft.initR(INITR_BLACKTAB); // Initialize TFT and fill with black color tft.fillScreen(ST7735_BLACK); tft.setRotation(tft.getRotation() + 1); tft.setTextSize(1.5); delay(500); // delay in order to ensure that TFT was initialized } // last measured data float oldTemperature = 0, oldAltitude = 0, oldPressure = 0, oldDHTHumidity = 0, oldDHTTemperature; bool wasUpdate = false; void loop(void) { if(Serial.available() > 0) // we have data is Serial port { Serial.read(); // read byte from serial port and send last measured data printValue("Pressure", oldPressure, " hPa", false); printValue("Temperature", oldTemperature, " C", false); printValue("Altitude", oldAltitude, " m", false); printValue("Humidity", oldDHTHumidity, "%", false); printValue("DHT_temperature", oldDHTTemperature, " C", false); Serial.println("END_TRANSMISSION"); } sensors_event_t event; float temperature, altitude; if(bmpFlag == 0){ bmp.getEvent(&event); // get data from BMP180 if (event.pressure) { bmp.getTemperature(&temperature); float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA; altitude = bmp.pressureToAltitude(seaLevelPressure, event.pressure, temperature); } else { Serial.println("Sensor error"); } } uint32_t start = micros(); int chk = DHT.read22(DHT22_PIN);// get data from DHT22 uint32_t stop = micros(); stat.total++; switch (chk) // check status of DHT22 { case DHTLIB_OK: stat.ok++; break; case DHTLIB_ERROR_CHECKSUM: stat.crc_error++; Serial.print("Checksum error,\t"); break; case DHTLIB_ERROR_TIMEOUT: stat.time_out++; Serial.print("Time out error,\t"); break; case DHTLIB_ERROR_CONNECT: stat.connect++; Serial.print("Connect error,\t"); break; case DHTLIB_ERROR_ACK_L: stat.ack_l++; Serial.print("Ack Low error,\t"); break; case DHTLIB_ERROR_ACK_H: stat.ack_h++; Serial.print("Ack High error,\t"); break; default: stat.unknown++; Serial.print("Unknown error,\t"); break; } if(bmpFlag != 0 || !event.pressure) // update data { tft.fillRect(0, 30, 160, 6, ST7735_BLACK); tft.setCursor(0, 30); tft.setTextColor(ST7735_RED); printValue("ERROR BMP INITIALIZATION", 0, "", true); } else { if(event.pressure != oldPressure) { tft.fillRect(0, 30, 160, 7, ST7735_BLACK); tft.setCursor(0, 30); tft.setTextColor(ST7735_RED); printValue("Pressure", event.pressure, " hPa", true); oldPressure = event.pressure; wasUpdate = true; } if(temperature != oldTemperature) { tft.fillRect(0, 38, 160, 7, ST7735_BLACK); tft.setCursor(0, 38); tft.setTextColor(ST7735_WHITE); printValue("Temperature", temperature, " C", true); oldTemperature = temperature; wasUpdate = true; } if(altitude != oldAltitude) { tft.fillRect(0, 46, 160, 7, ST7735_BLACK); tft.setCursor(0, 46); tft.setTextColor(ST7735_BLUE); printValue("Altitude", altitude, " m", true); oldAltitude = altitude; wasUpdate = true; } } if(DHT.humidity != oldDHTHumidity) { tft.fillRect(0, 54, 160, 7, ST7735_BLACK); tft.setCursor(0, 54); tft.setTextColor(ST7735_GREEN); printValue("Humidity", DHT.humidity, "%", true); oldDHTHumidity = DHT.humidity; wasUpdate = true; } if(DHT.temperature != oldDHTTemperature) { tft.fillRect(0, 80, 160, 7, ST7735_BLACK); tft.setCursor(0, 80); tft.setTextColor(ST7735_YELLOW); printValue("DHT_temperature", DHT.temperature, " C", true); oldDHTTemperature = DHT.temperature; wasUpdate = true; } if(wasUpdate) { Serial.println("END_TRANSMISSION"); } wasUpdate = false; delay(10000); } void printValue(char* title, double value, char* measure, bool tftPrint) { if(tftPrint) // print data to TFT { tft.print(title); tft.print(": "); tft.print(value); tft.println(measure); } Serial.print(title); // send data to Serial port Serial.print(": "); Serial.print(value); Serial.println(measure); }

Самое время собрать корпус

Главным условием курсового было рабочий прототип в презентабельном виде. Поэтому пришлось купить корпус и, вооружившись напильником, любым способом засунуть метеостанцию в корпус.

В местном магазине радиоэлектроники был приобретён корпус.

Корпус

(На фото корпус немного не такой. У меня крышка прозрачная)



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

Корпус с отверстиями для датчиков и питания



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

Система перед "запихиванием" в корпус



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

Чудо-юда рыба-кит



Прикручиваем крышку, подключаем питание и ждём.

Законченная метеостанция в корпусе



После вывода результатов на экран, выявляем неприятную ошибку измерения влажности: DHT22 усердно выдаёт цифру 99,90% (крайне редко бывает 1,00%). Начинаем разбираться в чём проблема. Первое, что делаем - смотрим вывод значений в COM порт. Вроде всё нормально. После нексольких перезаливок, разборок и сборок корпуса в голову приходит мысль поискать ответ в гугле. Как и ожидалось русский гугл ничего дельного не сказал. Окей. Начинаем искать на английском и на одном из форумов натыкаемся на ребят с похожей проблемой. Первые четыре страницы обсуждения ничего дельного не дают, а на пятой странице находим ответ на наш вопрос:
Humidity sensors can easily be affected by the wrong gasses or very long exposure to high humidity IIRC. In the datasheet there is a procedure how to «reset» the sensor, you could give it a try.

Оставался вопрос только в том, когда и как я успел навредить DHT22. Но подходило время сдавать курсовой и поэтому я оставил решение этой проблемы на потом.

Послесловие

Курсовой был сдан. Метеостанция отложена на неопределенное время до закрытия всех хвостов в университете. Однако, к метеостанции пришлось вернутся раньше, чем я думал. Так сложилось, что в середине ноября я поменял рабочее место и в новой команде я познакомился с людьми, которые интересуются платформой Arduino и им подобными. Поэтому мой интерес к данной платформе не успев остыть, разгорелся снова. Я достал свою метеостанцию, подключил к компьютеру и вспомнил, что я реализовывал передачу данных с Arduino по COM порту. И тут мне пришла в голову идея, написать программу, принимающую данные через COM порт от Arduino и передавать эти данные на народный мониторинг , но это уже совсем другая история.

Также хотелось бы иметь беспроводные датчики и всё-таки реализовать метеостанцию на Arduino Pro Mini. Поэтому мною были заказаны 4 Arduino Pro Mini с питанием 3,3В, 4 радиомодуля nRF24L01+ и ещё кое-какие дополнительные датчики, о чём я также постараюсь рассказать в следующий раз. А пока я жду посылки, в планах реализовать подключение часов реального времени для возможности сохранения времени обновления данных и самих данных на microSD карту при условии отсутствия соединения с клиентом по COM порту.

Вы можете помочь и перевести немного средств на развитие сайта



Недавно мой коллега устраивал небольшую научную выставку.
Мой учитель попросил меня представить какой-нибудь проект по электронике студентам в колледже. У меня было два дня, чтобы придумать что-то интересное и достаточно простое.



Так как погодные условия здесь достаточно переменчивы, а температура колеблется в диапазоне 30-40°С, я решил сделать домашнюю метеостанцию.

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

Обычно это следующие датчики:

  • ветра
  • влажности
  • дождя
  • температуры
  • давления
  • высоты

Моя цель – сделать портативную настольную метеостанцию своими руками.

Она должна уметь определять следующие параметры:

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

Шаг 1: Покупаем нужные компоненты







  • DHT22 , датчик температуры и влажности.
  • BMP180 , датчик давления.
  • Припой
  • Однорядный разъем на 40 выходов

Из оборудования вам понадобятся:

  • Паяльник
  • Плоскогубцы для носоупоров
  • Провода

Шаг 2: Датчик температуры и влажности DHT22







Для измерения температуры используются разные датчики. Популярностью пользуются DHT22, DHT11, SHT1x

Я объясню, чем они отличаются друг от друга, и почему я использовал именно DHT22.

Датчик AM2302 использует цифровой сигнал. Этот датчик работает на уникальной системе кодировки и сенсорной технологии, поэтому его данные надежны. Его сенсорный элемент соединен с 8-битным однокристальным компьютером.

Каждый сенсор этой модели термокомпенсированный и точно откалиброванный, коэффициент калибровки находится в однократно программируемой памяти (ОТР-память). При чтении показаний сенсор будет вызывать коэффициент из памяти.

Маленький размер, низкое потребление энергии, большое расстояние передачи (100 м) позволяют AM2302 подходить почти ко всем приложениям, а 4 выхода в один ряд делают монтаж очень простым.

Давайте рассмотрим плюсы и минусы трех моделей датчиков.

DHT11

Плюсы: не требует пайки, самый дешевый из трех моделей, быстрый стабильный сигнал, дальность свыше 20 м, сильная интерференция.
Минусы: Библиотека! Нет вариантов разрешения, погрешность измерений температуры +/- 2°С, погрешность измерений уровня относительной влажности +/- 5%, неадекватный диапазон измеряемых температур (0-50°С).
Области применения: садоводство, сельское хозяйство.

DHT22

Плюсы: не требует пайки, невысокая стоимость, сглаженные кривые, малые погрешности измерений, большой диапазон измерений, дальность больше 20 м, сильная интерференция.
Минусы: чувствительность могла быть выше, медленное отслеживание температурных изменений, нужна библиотека.
Области применения: изучение окружающей среды.

SHT1x

Плюсы: не требует пайки, сглаженные кривые, малые погрешности измерений, быстрое срабатывание, низкое потребление энергии, автоматический режим сна, высокая стабильность и согласованность данных.
Минусы: два цифровых интерфейса, погрешность в измерении уровня влажности, диапазон измеряемых температур 0-50°С, нужна библиотека.
Области применения: эксплуатация в суровых условиях и в долгосрочных установках. Все три датчика относительно недорогие.

Соединение

  • Vcc – 5В или 3,3В
  • Gnd – с Gnd
  • Data – на второй вывод Arduino

Шаг 3: Датчик давления BMP180



BMP180 – барометрический датчик атмосферного давления с I2C-интерфейсом.
Барометрические датчики атмосферного давления измеряют абсолютное значение окружающего воздуха. Этот показатель зависит от конкретных погодных условий и от высоты над уровнем моря.

У модуля BMP180 имелся 3,3В стабилизатор на 662кОм, который я, по собственной глупости, случайно взорвал. Пришлось делать обводку питания напрямую к чипу.

Из-за отсутствия стабилизатора, я ограничен в выборе источника питания – напряжение выше 3,3В разрушит датчик.
У других моделей может не быть стабилизатора, обязательно проверяйте его наличие.

Схема соединения датчика и шины I2C с Arduino (nano или uno)

  • SDA — A4
  • SCL — A5
  • VCC — 3.3V
  • GND – GND

Давайте немного поговорим о давлении, и его связи с температурой и высотой.

Атмосферное давление в любой точке непостоянно. Сложное взаимодействие между вращением Земли, наклоном Земной оси, приводит к появлению множества областей высокого и низкого давления, что, в свою очередь, приводит к ежедневной смене погодных условий. Наблюдая за изменением давления, вы можете сделать краткосрочный прогноз погоды.

Например, падение давления обычно означает дождливую погоду или приближение грозы (приближение области низкого давления, циклона). Поднимающееся давление обычно означает сухую ясную погоду (над вами проходит область высокого давления, антициклон).

Атмосферное давление также изменяется с высотой. Абсолютное давление в базовом лагере на Эвересте (5400 м над уровнем моря) ниже, чем абсолютное давление в Дели (216 м над уровнем моря).

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

Измерение высоты

Среднее давление на уровне моря 1013,25 ГПа (или миллибар). Если подняться над атмосферой, это значение упадет до нуля. Кривая этого падения вполне понятна, поэтому вы можете сами вычислить высоту над уровнем моря, используя следующее уравнение: alti=44330*

Если вы примите давление на уровне моря 1013,25 Гпа как р0, решением уравнения будет ваша текущая высота над уровнем моря.

Меры предосторожности

Не забывайте, что датчику BMP180 нужен доступ к окружающей атмосфере, чтобы иметь возможность считывать давление воздуха, не помещайте датчик в закрытый корпус. Небольшого вентиляционного отверстия будет вполне достаточно. Но и слишком открытым его не оставляйте – ветер будет сбивать показания давления и высоты. Продумайте защиту от ветра.

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

Защитите от влаги. Датчик BMP180 чувствителен к уровню влажности, постарайтесь предотвратить возможное попадание воды на датчик.

Не ослепите датчик. Неожиданностью стала чувствительность силикона в датчике к свету, который может попасть на него через отверстие в крышке чипа. Для максимально точных измерений постарайтесь защитить датчик от окружающего света.

Шаг 4: Собираем прибор







Устанавливаем однорядные разъемы для Arduino Nano. Вообще, мы обрезали их до нужного размера и немного зашкурили, так что они смотрятся, словно такими и были. Потом припаиваем их. После, устанавливаем однорядные разъемы для датчика DHT22.

Устанавливаем 10кОМ резистор от вывода данных к земле (Gnd). Все паяем.
Потом точно также устанавливаем однорядный разъем для датчика BMP180, питание делаем 3,3В. Соединяем все с шиной I2C.

В последнюю очередь подключаем LCD-дисплей, на ту же I2C шину, что и датчик BMP180.
(в четвертый разъем я планирую позже подключить RTC-модуль (часы реального времени), чтобы прибор еще и время показывал).

Шаг 5: Кодирование




Загрузите библиотеки

Чтобы установить библиотеки на Arduino, перейдите по ссылке

#include
#include #include #include "DHT.h" #include

SFE_BMP180 pressure;

#define ALTITUDE 20.56 #define I2C_ADDR 0x27 // <<- Add your address here. #define Rs_pin 0 #define Rw_pin 1 #define En_pin 2 #define BACKLIGHT_PIN 3 #define D4_pin 4 #define D5_pin 5 #define D6_pin 6 #define D7_pin 7

#define DHTPIN 2 // what digital pin we"re connected to

// Uncomment whatever type you"re using! //#define DHTTYPE DHT11 // DHT 11 #define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 DHT dht(DHTPIN, DHTTYPE); LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin); float t1,t2;

void setup() { Serial.begin(9600); lcd.begin (16,2); // <<-- our LCD is a 20x4, change for your LCD if needed // LCD Backlight ON lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); lcd.setBacklight(HIGH); lcd.home (); // go home on LCD lcd.print("Weather Station"); delay(5000); dht.begin(); pressure.begin(); } void loop() { char status; double T,P,p0,a; status = pressure.startTemperature(); if (status != 0) { delay(status);

status = pressure.getTemperature(T); if (status != 0) { Serial.print("1"); lcd.clear(); lcd.setCursor(0,0); lcd.print("Baro Temperature: "); lcd.setCursor(0,1); lcd.print(T,2); lcd.print(" deg C "); t1=T; delay(3000);

status = pressure.startPressure(3); if (status != 0) { // Wait for the measurement to complete: delay(status);

status = pressure.getPressure(P,T); if (status != 0) {lcd.clear(); lcd.setCursor(0,0); lcd.print("abslt pressure: "); lcd.setCursor(0,1); lcd.print(P,2); lcd.print(" mb "); delay(3000);

p0 = pressure.sealevel(P,ALTITUDE); // we"re at 1655 meters (Boulder, CO)

a = pressure.altitude(P,p0); lcd.clear(); lcd.setCursor(0,0); lcd.print("Altitude: "); lcd.setCursor(0,1); lcd.print(a,0); lcd.print(" meters"); delay(3000); } } } } float h = dht.readHumidity(); // Read temperature as Celsius (the default) float t = dht.readTemperature(); t2=t; lcd.clear(); lcd.setCursor (0,0); // go to start of 2nd line lcd.print("Humidity: "); lcd.setCursor(0,1);lcd.print(h); lcd.print(" %"); delay(3000); lcd.clear(); lcd.setCursor (0,0); // go to start of 2nd line lcd.print("DHT Tempurature: "); lcd.setCursor(0,1); lcd.print(t); lcd.print(" deg C "); delay(3000); lcd.clear(); lcd.setCursor (0,0); // go to start of 2nd line lcd.print("Mean Tempurature: "); lcd.setCursor(0,1); lcd.print((t1+t2)/2); lcd.print(" deg C "); delay(3000); }

Я использовал версию Arduino 1.6.5, код точно к ней подходит, к более поздним так же может подойти. Если код по каким-либо причинам не подходит, используйте версию 1.6.5 как базовую.

Я тестировал отдельные части системы на Arduino UNO. Т.е. подключал к уно ESP модуль и изучал его, отключал, затем подключал nRF24 и т.д. Для финальной реализации заоконного датчика выбрал Arduino Pro Mini как наиболее близкую к Uno из миниатюрных.



По энергопотреблению Arduino Pro Mini также выглядит неплохо:

  • нет преобразователя USB-TTL, который сам по себе «кушает» много,
  • светодиод подключен через 10к резистор.

Для продвинутого сбережения энергии планировалось:

  • удалить светодиод - индикатор питания на Arduino Pro Mini (я пожалел, не стал портить плату)
  • либо использовать «голую» сборку на микропроцессоре Atmel ATmega328 (не использовал)
  • использовать библиотеку Low Power Library или JeeLib .

Из библиотек выбрал Low Power Library , она проста и содержит только то, что нужно.


Для центрального блока, поскольку к нему планировалось подключить многочисленную периферию, была выбрана плата Arduino Mega. К тому же она полностью совместима с UNO и имеет больше памяти. Забегая наперед скажу, что этот выбор полностью оправдался.


Купить Arduino Mega можно примерно за $8.

Питание и энергопотребление

Теперь про питание и энергопотребление.


Arduino Pro Mini бывают двух видов:

  • на напряжение питания 5В и частоту 16МГц
  • на напряжение питания 3,3В и частоту 8МГц.

Поскольку радио-модуль nRF24L01+ требует для питания 3,3 В, а быстродействие здесь не важно, то покупайте Arduino Pro Mini на 8MHz и 3,3В.


При этом диапазон питающего напряжения Arduino Pro Mini составляет:

  • 3,35-12 В для модели 3,3 В
  • 5-12 В для модели 5 В.

У меня уже была Arduino Pro Mini на 5В, только поэтому я её и использовал. Купить Arduino Pro Mini можно примерно за $4.


Питание центрального блока будет от сети 220 В через небольшой блок питания, дающий на выходе 12В, 450mA, 5W. Типа такого за $5. Там еще есть отдельный вывод на 5В.



А ежели этого не хватит, то можно и помощнее поставить. Другими словами экономить электропитание для центрального блока нет особого смысла. А вот для удаленного беспроводного датчика энергосбережение является важнейшей частью. Но и функциональность не хотелось бы терять.


Поэтому Arduino Pro Mini и радиомодуль nRF24 будут запитываться от связки 4-х Ni-Mh аккумуляторов.


И помните, максимальная емкость современного аккумулятора примерно 2500-2700mAh, всё что больше это либо маркетинговые уловки (Ansmann 2850) либо обман (UltraFire 3500).


Li-Ion аккумуляторы я не использую по нескольким причинам:

  • очень дорогие
  • при снижении температуры окружающего воздуха ниже 0°C происходит снижение мощности литий-ионного аккумулятора до 40-50%
  • те которые дешёвые производятся без защиты и небезопасны (при КЗ или разряде могут взрываться и гореть, см. кучу роликов на ютюбе)
  • стареют, даже если не используются (впрочем это можно сказать обо всех химических элементах), через 2 года Li-Ion батарея теряет около 20% ёмкости.

Для прототипа вполне можно обойтись качественными Ni-MH AA или AAA аккумуляторами. Тем более, что нам не нужны большие токи. Единственный минус Ni-MH аккумуляторов - это их долгая зарядка.

Общая схема метеостанции

Подведем итоги. Вот общая схема как всё работает.



Продолжение следует.

Теги: Добавить метки

Продолжаем развивать нашу метеостанцию.

Перед тем, как перейти к обновлению, хочу внести немного ясности.

Мне написал один из наших коллег с вопросом, по какой причине введен сторожевой таймер?

Сторожевой таймер стоит на случай ч.п. Как показывает практика, ENC28J60 не тянет более (если не подводит память) 4 одновременных соединений. Учитывая сколько служебных соединений, постоянно происходит для поддержания работы самой сети, и просто левый трафик, создаваемый всяческими домашними игрушками (например, современные телевизоры, сканируют доступные хосты в сети и открытые у них порты) конструкция попросту уходит в ступор. ENC28J60 не умеет самостоятельно работать с сетевыми протоколами и все реализовано в библиотеках. Возможно дело именно в них.
Проверял все доступные библиотеки и разные модули (вдруг брак), но добиться стабильной работы в течении длительного времени у меня не получилось. Максимальный срок был порядка 3-4 недель.
Именно для этого там крутится "пес" и в случае чего дергает контроллер. После этого проблема ушла.
Также не отрицаю, что возможно в моей домашней сети есть определенные нюансы или проблемы. Но раз проблема была у меня, она может выплыть и у другого человека. Я пока нашел только такое решение.
Насколько мне известно, на чипах от Wiznet (W5100 и выше) этого нет, ну или просто плохо искали.

Переходим к обновлению

Самое главное, мы уходим от чипа ENC28J60 и переходим на W5100 . Я пытался реализовать все на старом чипе, но не хватает памяти микроконтроллера из-за очень больших библиотек для ENC28J60 . При использовании нового чипа, стандартной библиотеки от разработчика и всех внесенных изменений, остается еще более 20% свободной памяти микроконтроллера ATMega328 . А это, новые плюшки!

В этой версии (назовем её второй) добавлена возможность передачи показаний с датчиков по беспроводной связи используя частоту 433 мГц . Сами модули я брал у Китайцев, маркировка XY-MK-5V . Хочу отметить, что качество передачи далеко от совершенства. Возможны потери сигнала, шумы, не возможность одновременной передачи и т.д и т.п. Но их цена (менее $1 за комплект) компенсируют эти недостатки. Скажу Вам по секрету, что именно эти (самые дешевые) модули стоят во многих фирменных метеостанциях для домашнего использования. Ого, неожиданно?

Начнем с базовой станции

Мы переходим на Arduino UNO и Ethernet Shield (первой версии) на базе чипа W5100 . Это бутерброд и описывать его нету смысла. Я опишу только дополнительно задействованные контакты для модулей XY-MK-5V .

Модуль передатчика использует питание 5V , GND (куда без матушки то) и D2 пин на контроллере. Изменить контакт D2 (DATA) можно, используя функцию vw_set_tx_pin из библиотеки vw.

В отличии от предыдущего скетча, в этом задействованы две дополнительные библиотеки:

#include #include

Сам скетч

Скрытый текст

#include #include #include #include #include #include #include #include #define DHTTYPE DHT22 #define DHTPIN 5 DHT dht(DHTPIN, DHTTYPE); byte mac = {0x54, 0x34, 0x31, 0x31, 0x31, 0x31}; char server = "narodmon.ru"; int port = 8283; IPAddress ip(192,168,0,201); EthernetClient client; BMP085 dps = BMP085(); long Temperature = 0, Pressure = 0; float H, dP, dPt; bool interval = true; EasyTransferVirtualWire ET; struct SEND_DATA_STRUCTURE{ byte ID; // Идентификатор устройства int Temperature; // Температура float Pressure; // Давление float Humidity; // Влажность float dewPoint; // Точка росы/инея }; SEND_DATA_STRUCTURE broadcast; void setup() { // Инициализация сторожевого таймера (Watchdog timer) wdt_disable(); delay(8000); wdt_enable(WDTO_8S); // Инициализация консоли Serial.begin(9600); // Инициализация датчика DHT dht.begin(); // Инициализация модуля 433 мГц ET.begin(details(broadcast)); vw_set_ptt_inverted(true); vw_set_tx_pin(2); vw_setup(2000); // Стартуем сеть, если не дождались данных с DHCP сервера то // присваеваем себе адрес самостоятельно if (Ethernet.begin(mac) == 0) Ethernet.begin(mac, ip); // Инициализация 1-Wire Wire.begin(); delay(200); // Инициализация BMP180 с корректировкой высоты // dps.init(MODE_STANDARD, 3200, true); // Инициализация BMP180 dps.init(); Serial.println(Ethernet.localIP()); // Отправляем первые данные сразу после включения устройства send_info(true); } // dewPoint function NOAA // reference (1) : http://wahiduddin.net/calc/density_algorithms.htm // reference (2) : http://www.colorado.edu/geography/weather_station/Geog_site/about.htm double dewPoint(double celsius, double humidity) { // (1) Saturation Vapor Pressure = ESGG(T) double RATIO = 373.15 / (273.15 + celsius); double RHS = -7.90298 * (RATIO - 1); RHS += 5.02808 * log10(RATIO); RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO))) - 1) ; RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ; RHS += log10(1013.246); // factor -3 is to adjust units - Vapor Pressure SVP * humidity double VP = pow(10, RHS - 3) * humidity; // (2) DEWPOINT = F(Vapor Pressure) double T = log(VP/0.61078); // temp var return (241.88 * T) / (17.558 - T); } void send_info(bool eth) { bool fail = true; while(fail) { // Пытаемся считать данные с датчика влажности DHT до тех пор, пока не получим // результат. В 90% случаев все работает нормально, но нам нужны 100% if((H = dht.readHumidity()) >= 0) { // Получение влажности и температуры с датчика BMP180 dps.getPressure(&Pressure); dps.getTemperature(&Temperature); // Подсчитываем точку росы, если температура на улице выше 0 градусов Цельсия // и ожидаем результат выше 0, в противном случае выводим 0. Это необходимо // чтобы не вводить в заблуждения в зимее время года. // dP = Temperature>0?((dPt=dewPoint(Temperature*0.1, H))<0?0:dPt):0; dP = dewPoint(Temperature*0.1, H); // Отправляем данные в эфир 433 мГц broadcast.ID = 1; broadcast.Temperature = floor(Temperature*0.1); broadcast.Pressure = floor(Pressure/133.3*10)/10; broadcast.Humidity = floor(H*10)/10; broadcast.dewPoint = floor(dP*10)/10; ET.sendData(); delay(250); if(eth) { // Подключаемся к серверу "Народный мониторинг" if(client.connect(server, port)) { // Начинаем передачу данных // адрес_устройства_в_проекте, имя_устройства, GPS широта, GPS долгота client.print(F("#fe-31-31-0e-5a-3b#Arduino Uno#71.344699#27.200014\n")); // Температура client.print(F("#T0#")); client.print(Temperature*0.1); client.print(F("#Температура\n")); // Давление client.print("#P1#"); client.print(Pressure/133.3); client.print(F("#Давление\n")); // Влажность client.print("#H1#"); client.print(H); client.print(F("#Влажность\n")); // Точка росы\инея client.print("#T1#"); client.print(dP); client.print((dP <= 0)? F("#Точка инея\n"):F("#Точка росы\n")); //client.print(F("#Точка росы\n")); // Отправляем конец телеграммы client.print("##"); // Даем время отработать Ethernet модулю и разрываем соединение delay(250); client.stop(); } } // Останавливаем цикл, если передача завершена fail = !fail; break; } delay(250); } } void loop() { // Каждые 4 секунды сбрасываем сторожевой таймер микроконтроллера // Каждые 6 минут отправляем данные на "Народный мониторинг" // Каждые 30 секунд отсылаем данные в эфир 433 if(!(millis()%1000)) wdt_reset(); if(!(millis()%360000)) send_info(true); if(!(millis()%30000)) send_info(false); }

К самим модулям необходимо добавить антенну. Для 433 мГц достаточно обычного медного провода длинной 17 см . Без антенны можете забыть о нормальной работе.

Переходим к самой важной части этого обновления - локальная беспроводная станция

Для её реализации (на коленке) я использовал аналог Arduino NANO (на базе ATMega328 ) и TFT дисплей на чипе ST7735S с разрешением 128 x 160

Скрытый текст



Распиновка дисплей -> контроллер

============================= LED | 3.3V SCK | SCK (13) SDA | MOSI (11) A0 | DC (9) RESET | RST (8) CS | CS (10) GND | GND VCC | 5V ============================

Модуль приемник подключается также как передатчик, только DATA к пину D7 .

Пару снимков, как это выглядит:

Скрытый текст

Скетч приемника

Скрытый текст

#include #include #include #include int x, y; int w = 128, h = 160; int size; // 433 EasyTransferVirtualWire ET; struct SEND_DATA_STRUCTURE{ byte ID; // Идентификатор устройства int Temperature; // Температура float Pressure; // Давление float Humidity; // Влажность float dewPoint; // Точка росы/инея }; SEND_DATA_STRUCTURE broadcast; int Log_Temperature = -1; float Log_Pressure = -1; float Log_Humidity = -1; float Log_dewPoint = -1; // TFT #define cs 10 #define dc 9 #define rst 8 char Temperature, Pressure, Humidity, dewPoint; String info; TFT TFTscreen = TFT(cs, dc, rst); void setup(){ Serial.begin(9600); // Инициализация модуля 433 мГц ET.begin(details(broadcast)); vw_set_ptt_inverted(true); vw_set_rx_pin(7); vw_setup(2000); vw_rx_start(); // Инициализация и начальная настройка дисплея TFTscreen.begin(); TFTscreen.setRotation(2); TFTscreen.background(0, 0, 0); // Рисуем статические элементы // 1. Заходите к нам в гости TFTscreen.stroke(255, 255, 255); TFTscreen.setTextSize(1); TFTscreen.text(" ", 10, 10); // 2. Описание показаний с датчиков TFTscreen.text("mmHg", w/2+5, 80); TFTscreen.text("%", w/2+5, 100); TFTscreen.text("C", w/2+5, 120); broadcast.Temperature = 0; broadcast.Pressure = 0; broadcast.Humidity = 0; broadcast.dewPoint = 0; TFTPrint(); } void loop(){ if(ET.receiveData()){ if(broadcast.ID == 1) TFTPrint(); /* Serial.println(broadcast.Temperature); Serial.println(broadcast.Pressure); Serial.println(broadcast.Humidity); Serial.println(broadcast.dewPoint); Serial.println(); */ } } void changes(int size, int x, int y, bool up, bool clear = false) { if(clear) TFTscreen.stroke(0, 0, 0); else { changes(size, x, y, !up, true); TFTscreen.stroke((up)?0:255, 0, (up)?255:0); } if((size%2) == 0) size++; while(size > 0) { TFTscreen.line(x, y, x+(size--), y); ++x, (up)?--y:++y, --size; } /* while(size > 0) { TFTscreen.line(x, y, (up)?x+size-1:x, (up)?y:y+size-1); ++x, ++y, --size; } */ } int x_center(int w, int length, int size) { return floor((w-length*(size*5)+size*2)/2); } int x_alignment_right(int w, int length, int size) { return ceil(w-length*(size*5)+size*2); } void TFTPrint() { size = 3; // ================================================================================== // Вывод показаний температуры // ================================================================================== if(broadcast.Temperature != Log_Temperature) { TFTscreen.setTextSize(size); // Затираем устаревшие данные String info = String(Log_Temperature); info.concat(" C"); if(Log_Temperature > 0) info = "+"+info; info.toCharArray(Temperature, info.length()+1); TFTscreen.stroke(0, 0, 0); TFTscreen.text(Temperature, x_center(w, info.length()+1, size), 35); // Выводим новые показания info = String(broadcast.Temperature); info.concat(" C"); if(broadcast.Temperature > 0) info = "+"+info; info.toCharArray(Temperature, info.length()+1); // Меняем цвет значения температуры в зависимости от самой температуры int r, g = 0, b; if(broadcast.Temperature > 0) { r = map(broadcast.Temperature, 0, 40, 255, 150); // Красный b = map(broadcast.Temperature, 0, 40, 30, 0); // Изменяем оттенок для более наглядного перехода через ноль } else { r = map(broadcast.Temperature, -40, 0, 0, 30); // Изменяем оттенок для более наглядного перехода через ноль b = map(broadcast.Temperature, -40, 0, 150, 255); // Синий } TFTscreen.stroke(b, g, r); // ВНИМАНИЕ: в библиотеке перепутаны позиции цветов, место RGB используется BGR! TFTscreen.text(Temperature, x_center(w, info.length()+1, size), 35); } size = 1; // ================================================================================== // Вывод показаний давления // ================================================================================== if(broadcast.Pressure != Log_Pressure) { TFTscreen.setTextSize(size); // Затираем устаревшие данные info = String(Log_Pressure); info.toCharArray(Pressure, info.length()); TFTscreen.stroke(0, 0, 0); TFTscreen.text(Pressure, x_alignment_right(w/2-5, info.length(), size), 80); // Выводим новые показания info = String(broadcast.Pressure); info.toCharArray(Pressure, info.length()); TFTscreen.stroke(255, 255, 255); TFTscreen.text(Pressure, x_alignment_right(w/2-5, info.length(), size), 80); changes(10, 106, 85, (broadcast.Pressure > Log_Pressure)?true:false); } else { changes(10, 106, 85, true, true); changes(10, 106, 85, false, true); } // ================================================================================== // Вывод показаний влажности // ================================================================================== if(broadcast.Humidity != Log_Humidity) { TFTscreen.setTextSize(size); // Затираем устаревшие данные info = String(Log_Humidity); info.toCharArray(Humidity, info.length()); TFTscreen.stroke(0, 0, 0); TFTscreen.text(Humidity, x_alignment_right(w/2-5, info.length(), size), 100); // Выводим новые показания info = String(broadcast.Humidity); info.toCharArray(Humidity, info.length()); TFTscreen.stroke(255, 255, 255); TFTscreen.text(Humidity, x_alignment_right(w/2-5, info.length(), size), 100); changes(10, 106, 105, (broadcast.Humidity > Log_Humidity)?true:false); } else { changes(10, 106, 105, true, true); changes(10, 106, 105, false, true); } // ================================================================================== // Вывод показаний точки росы\инея // ================================================================================== if(broadcast.dewPoint != Log_dewPoint) { TFTscreen.setTextSize(size); // Затираем устаревшие данные info = String(Log_dewPoint); info.toCharArray(dewPoint, info.length()); TFTscreen.stroke(0, 0, 0); TFTscreen.text(dewPoint, x_alignment_right(w/2-5, info.length(), size), 120); // Выводим новые показания info = String(broadcast.dewPoint); info.toCharArray(dewPoint, info.length()); TFTscreen.stroke(255, 255, 255); TFTscreen.text(dewPoint, x_alignment_right(w/2-5, info.length(), size), 120); changes(10, 106, 125, (broadcast.dewPoint > Log_dewPoint)?true:false); } else { changes(10, 106, 125, true, true); changes(10, 106, 125, false, true); } // Обновляем значения в логах для последующего сравнения показаний Log_Temperature = broadcast.Temperature; Log_Pressure = broadcast.Pressure; Log_Humidity = broadcast.Humidity; Log_dewPoint = broadcast.dewPoint; }

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

Как мне показалось, дизайн это та часть проекта, которая отнимает большую часть времени!

Скрытый текст

Часть данных сфабрикованы для отображения некоторых элементов дизайна.

Артефакты на дисплее, это пыль и прочая грязь скопившаяся за долго время нахождения дисплея в... где то там, ... ну там, не помню откуда его достал! Отстаньте!

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

  1. x_center
  2. x_alignment_right

Первая производит центровку текста, а вторая выравнивание по правой части указанной зоны. Все вычисления производятся относительно размеров заданного текста, исходя из выражения 1 size = 1PX х 1PX сегмента шрифта.

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

Кстати, цвет и оттенок основной температуры изменяется в зависимости от самой температуры. Довольно спорное решение, но на мой взгляд, визуально комфортное. Я некоторое время бился над ней, и понял, что значения в функции stroke , объекта TFT дисплея, указаны в неверном порядке. BGR место RGB . Это ошибка разработчика, ну или я что-то не понимаю.

PS : Все довольно интересно, но на мой взгляд заслуживает дальнейшего развития. Чем и займемся через какое то время.

 

Возможно, будет полезно почитать: