Проект метеостанции на ардуино с wifi. Метеостанция на Arduino с беспроводным датчиком температуры. Общая схема метеостанции

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



Так как погодные условия здесь достаточно переменчивы, а температура колеблется в диапазоне 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 аккумуляторов - это их долгая зарядка.

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

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



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

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

Как большинство работающих людей, занятие собственными проектами отнимает единственно оставшееся свободное время. Поэтому уже давно не творил и «чесались руки» что-либо сделать. Данная возможность появилась как ни странно в университете. За окном сентябрь, 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 UNO, но подойдет и другая плата с Atmega328p на борту. Для отображения используем графический экран WG12864B. Также подключим два датчика температуры ds18b20. Один внутри помещения, второй вынесем наружу. Начнем.

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

    Arduino UNO (Или любая другая Arduino совместимая плата)
    - WG12864B графический экран
    - ds18b20 датчик температуры, 2шт
    - Блок питания 6 – 12 В
    - Резисторы 4.7 Ком 0.25 Вт, 2 шт.
    - Резисторы 100 ом 0.25 Вт
    - Батарейный отсек для 4 батареек типа ААА «мизинчиковых»
    - Коробка от картриджа приставки SEGA
    - Изолента
    - Соединительные провода
    - Монтажная плата
    - Кнопки
    - Канцелярский нож
    - Паяльник
    - Припой, канифоль
    - Двусторонний скотч

    Шаг 1 Подготовка WG12864B3.
    Тех, кто не работал до этого с экранами, может напугать большое количество модификаций, с виду одинаковых, экранов. Немного поясню. Большинство экранов такого типа работают на микросхемах ks0107/ks0108. Все экраны можно раздлить на 4 типа:

    Вариант A: HDM64GS12L-4, Crystalfontz CFAG12864B, Sparkfun LCD-00710CM, NKC Electronics LCD-0022, WinStar WG12864B-TML-T

    Вариант B: HDM64GS12L-5, Lumex LCM-S12864GSF, Futurlec BLUE128X64LCD, AZ Displays AGM1264F, Displaytech 64128A BC, Adafruit GLCD, DataVision DG12864-88, Topway LM12864LDW, Digitron SG12864J4, QY-12864F, TM12864L-2, 12864J-1

    Вариант C: Shenzhen Jinghua Displays Co Ltd. JM12864

    Вариант D: Wintek- Cascades WD-G1906G, Wintek - GEN/WD-G1906G/KS0108B, Wintek/WD-G1906G/S6B0108A, TECDIS/Y19061/HD61202, Varitronix/MGLS19264/HD61202

    Выглядят они почти одинаково. Но пины подключение у них разные. Я выбрал, и вам рекомендую, WG12864B3 V2.0, но если экран пришел другой, или просто под руками такого нет, вы легко разберётесь с помощью таблицы:

    Вкратце характеристики:

    В интернете много разных схем подключения, и все вроде как рабочие. Все дело в том, что существуют не только разные экраны, но и два способа их подключения: последовательный и параллельный. При использовании подключения по последовательному порту – нам понадобится всего 3 выхода микроконтроллера. При параллельном минимум 13. Выбор в данном случаем очевиден, у Arduino и так не много выводов. Для параллельного соединения схема подключения следующая:

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

    WG12864B – Arduino UNO 1 (GND) - GND 2 (VCC) - +5V 4 (RS) – 10 5 (R/W) – 11 6 (E) – 13 15 (PSB) – GND 19 (BLA) – через резистор 100 Ом - +5V 20 (BLK) – GND

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

    Резистор в 100 Ом нужен, чтобы напряжением в 5 вольт, случайно не сжечь диоды подсветки.

    Шаг 2 Изготовление корпуса.
    Для корпуса возьмем коробку от картриджа приставки Sega. Если не найдете под руками эту коробку, можно использовать и другой корпус. Главное, чтобы в него поместился экран и Arduino.

    Срезаем прозрачную пленку, сверху коробки, так чтобы не оставалось кусков:

    Затем, используя канцелярский нож, вырезаем окошко размером 37х69, для экрана.

    С обратной стороны по краю выреза клеим двусторонний скотч, желательно черного цвета:

    Снимаем защитную бумажку со скотча, и приклеиваем на него наш экран:

    С внешней стороны должно выглядеть так:

    Ниже экран, также на двусторонний скотч, крепим Arduino, сделав предварительно вырезы под USB- порт и гнездо питания:

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

    Шаг 3 Датчики температуры.
    Мы будем использовать цифровые датчики температуры DS18B20. Используя их мы получаем большую точность измерения, погрешность не более 0,5 °C, в большом диапазоне температур -55 … + 125 °C. Кроме этого, датчик цифровой и все вычисления выполняет сам, а Arduino просто получает готовые показания. При подключении этого датчика не забывайте о подтягивающем резисторе, номиналом 4.7 КОм, между контактами DQ и VDD. Также возможно несколько вариантов подключения. С внешним питание, на мой взгляд лучший вариант, его и будем использовать:

    При любом варианте питания, датчики подключаются параллельно:

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

    Общий провод от обоих кнопок подключаем к GND, провод от первой кнопки подключаем к A0, от второй к A1.
    Крепим на двусторонний скотч рядом с Arduino:

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

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

    Провод от шины данных DQ обоих датчиков подключаем к pin 5 Arduino.
    Vdd - +5 Arduino.
    GND – GND Arduino.

    Шаг 4 Питание.
    Для питания можно использовать блок питания напряжением от 6 до 12 вольт. На конце провода блика питания следует напаять штекер, подходящий к гнезду питания Arduino:

    Или можете поместить в корпус батарейный отсек для четырех батареек типа «ААА», «мизинчиковые». И подключить плюсовой провод от отсека к Vin Arduino, а минус к GND.

    Шаг 5 Подготовка среды программировании.
    Для начала необходимо скачать и установить Arduino IDE с официального сайта

    А также добавить в две библиотеки, необходимые для скетча. OneWire – необходима для связи с датчиками ds18b20:

    U8glib – используется для вывода информации на экран:

    Скачиваем библиотеки. Затем распаковываем архивы, и перемещаем содержимое архивов в папку «libraries», находящуюся в папке с установленной Arduino IDE. Также можно добавить библиотеки через Arduino IDE. Для этого, не распаковывая архивы, запускаем Arduino IDE, выбираем в меню Скетч – Подключить библиотеку. В самом верху выпадающего списка выбираем пункт «Добавить.Zip библиотеку». Указываем место нахождения скачанных архивов. После всех действий, необходимо перезагрузить Arduino IDE.

    Шаг 6 Редактирование скетча.
    Датчики температуры работают по протоколу One Wire и имеют уникальный адрес для каждого устройства - 64-разрядный код. Добавлять команды поиска датчиков в скетч не целесообразно. Незачем нагружать Arduino каждый раз икать датчики. Поэтому вначале, собрав все вместе, заливаем в Arduino скетч, находящийся в меню Файл – Примеры – Dallas Temperature – OneWireSearch. Затем запускаем Инструменты - Монитор порта. Arduino должна найти наши датчики, написать адреса и показания температуры. Эти адреса необходимо записать или просто скопировать куда-нибудь. Теперь открываем скетч Ard_Tic_Tak_WG12864B_2_x_Term_Serial, и ищем строки:

    Byte addr1={0x28, 0xFF, 0x75, 0x4E, 0x87, 0x16, 0x5, 0x63};//адрес внутреннего byte addr2={0x28, 0xFF, 0xDD, 0x14, 0xB4, 0x16, 0x5, 0x97};//адрес внешнего датчика

    Заменяем адреса соответствующих местонахождению датчиков, на свои адреса.
    У нас часы не используют модуль RTC (часы реального времени), поэтому необходимо откорректировать ход часов. Для удобства раскомментируйте строку (на экране появятся секунды):

    //u8g.setPrintPos(44, 50); u8g.print(sek); // Выводим секунды для контроля правильности хода

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

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

    If (micros() - prevmicros >494000) { // поменять на другое для корректировки было 500000

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

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

    Наша метеостанция будет состоять из двух устройств: компактного автономного устройства, измеряющего погодные показатели, и устройства-ретранслятора, получающего эти показатели и отправляющего их на «народный мониторинг». Устройства будут связываться по беспроводному каналу связи на частоте 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 минут, а в остальное - каждые полчаса.