Метеостанция из ардуино

Домашняя метеостанция на базе Arduino -2

  • 07.01.16 12:20
  • VaDiKGts
  • #268860
  • Гиктаймс
  • Из песочницы
  • 7
  • 3700

Arduino

Вместо введения

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

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

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

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

  1. Датчик измерения давления и температуры BMP180:
    ПодробнееДатчик BMP180 стал дальнейшим развитием датчика BMP085. BMP180 стал меньше по размерам, потребляет меньше электроэнергии, также датчик стал точнее и отличается более высокой стабильностью.
    Изображение BMP180
    Диапазон измерения давления 300-1100 ГПа
    Погрешность измерения давления 0,06 ГПа (режим энергосбережения), 0,02 ГПа (режим повышенной точности)
    Погрешность измерения высоты над уровнем моря 0,5 метра (режим энергосбережения), 0,17 метров (режим повышенной точности)
    Абсолютная точность измерения (p = 300..1100 ГПа, t = 0..65 С0, питание 3,3 В) Давление: — 4,0… + 2,0 ГПа Температура: ± 1 С0
    Среднее потребление тока (при частоте обновления данных 1 Гц) 3 мкА – режим энергосбережения, 32 мкА – расширенный режим
    Максимальный ток 650 мкА
    Время измерения давления 5 мс (обычный режим)
    Частота передачи данных максимум 3,4 МГц

  2. Датчик измерения температуры и влажности DHT22
    ПодробнееДатчик температуры и влажности DHT-22 (AM2302), отличается от датчика DHT-11 большими точностью и диапазоном измерения влажности и температуры. Содержит в себе АЦП (аналогово-цифровой преобразователь) для преобразования аналоговых значений влажности и температуры. При подключении датчика к микроконтроллеру, рекомендуется между выводами VCC и SDA разместить подтягивающий pull-up резистор номиналом 10 кОм, а также конденсатор ёмкостью 100 нФ между питанием и «землёй». Но мне ничего паять не пришлось, так нашёл датчик, распаенный на плате с конденсатором и резистором.
    Изображение DHT22
    Напряжение питания 3,3 – 5 В
    Диапазон измерения влажности 0 – 100% с точностью 2 – 5%
    Диапазон измерения температуры — 40 – + 125 С0 с точностью ± 0,5 С0
    Частота опроса датчика не более раза в 2 секунды

  3. Датчик освещенности BH1750 (рассматривать его здесь не буду, так как во время припайки к нему ножек, спалил одну из дорожек).
    Изображение BH1750

С датчиками определился. Но что делать с данными, поступающими от датчиков. Решил выводить на дисплей. Картинку хотелось цветную, поэтому монохромные решения отбросил сразу. После нескольких минут поиска был выбран TFT дисплей ST7735 размером 1,8 дюймов.
ПодробнееПоскольку дисплей использует 4-проводной SPI протокод для связи и имеет свой собственный пикселе-адресуемый буфер кадра, он может использоваться с любыми видами микроконтроллеров. 1.8-дюймовый дисплей имеет 128×160 цветных пикселя. Также имеется слот для карты памяти microSD, следовательно, можно легко загружать полноцветные растровые изображения из FAT16 / FAT32 файловой системы microSD карты.
Характеристики:

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

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

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

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

Скетч #include <Wire.h> // library for communication with I2C devices #include <Adafruit_Sensor.h> // Core library for all sensors #include <Adafruit_BMP085_U.h> // library for BMP180 #include <Adafruit_GFX.h> // Core graphics library #include <Adafruit_ST7735.h> // Hardware-specific library #include <SPI.h> // 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 порту.

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

Теги:

Arduino, БГУИР, ВМСиС, кафедра ЭВМ 

Домашняя метеостанция на базе Ардуино

Давненько хотелось сделать мини метеостанцию-надоело выглядывать в окно чтобы посмотреть на градусник за стеклом. Этот приборчик заменит гигрометр, барометр и термометр а также покажет текущее время. В данном посту я расскажу как быстро и просто собрать небольшую метеостанцию на базе Ардуино. Основой будет плата Arduino Nano можно применить другие платы- Arduino Uno, Arduino Pro mini). Данные атмосферного давления и температуры в помещении будем получать с датчика BMP180, а влажность и температуру на улице с датчика DHT11. Часы реального времени DS1302 будут указывать текущее время. Всю информацию выводим на двухстрочный дисплей LCD1602.
Датчик DHT11 передает информацию по одному проводу на ардуино. Питается напряжением 5 В. Он измеряет влажность в пределах от 20 до 80%. Температура измеряет в диапазоне от 0 до 50оС.
Датчик BMP180 измеряет атмосферное давление диапазоне 300-1100 hPa, температуру в диапазоне -40 +85оС. Напряжение питания составляет 3.3 В. Подключается по протоколу связи I2C.
Часы реального времени DS1302 питаются напряжением 5 В и подключается по протоколу связи I2C. При установке в соответствующее гнездо батарейки CR2032 поддерживают ход часов при отключении основного питания.
Дисплей LCD1602 питается напряжением 5 Вольт и также подключается по протоколу связи I2C.
Эта самоделка сделана на базе готовых плат и датчиков, поэтому ее можно повторить любому начинающему любителю поработать с паяльником. Заодно можно получить азы программирования Ардуино. Я программировал эту метеостанцию в программе визуального программирования FLPROG за 15 минут. Не нужно вручную часами писать скетчи, данная программа помогает начинающим (и не только) быстро освоить азы программирования устройств на основании платформы Ардуино.
Кому лень повозиться с программой — скетч ( только выставлять текущее время часов надо будет):
#include <wire.h> #include «DHT_NEW.h» #include <iarduino_RTC.h> #include <liquidcrystal_I2C.h> #include <bmp085.h> BMP085 _bmp085 = BMP085(); long _bmp085P = 0; long _bmp085T = 0; long _bmp085A = 0; LiquidCrystal_I2C _lcd1(0x3f, 16, 2); int _dispTempLength1=0; boolean _isNeedClearDisp1; DHT _dht1; iarduino_RTC _RTC1(RTC_DS1302, 7, 5, 6); unsigned long _dht1LRT = 0UL; unsigned long _dht1Tti = 0UL; int _disp1oldLength = 0; unsigned long _bmp0852Tti = 0UL; String _RTC1_GetTime2_StrOut; int _disp2oldLength = 0; void setup() { Wire.begin(); delay(10); _bmp085.init(MODE_ULTRA_HIGHRES,116, true); _RTC1.begin(); _RTC1.period(1); _lcd1.init(); _lcd1.backlight(); _dht1.setup(4); _dht1LRT = millis(); _dht1Tti = millis(); } void loop() {if (_isNeedClearDisp1) {_lcd1.clear(); _isNeedClearDisp1= 0;} if(_isTimer(_bmp0852Tti, 1000)) { _bmp0852Tti = millis(); _bmp085.getAltitude(&_bmp085A); _bmp085.getPressure(&_bmp085P); _bmp085.getTemperature(&_bmp085T); } //Плата:1 if (1) { _dispTempLength1 = ((((((String(«T:»)) + (( _floatToStringWitRaz((_bmp085T)/(10.00),1))) + (String(«*»)))) + (((String(«P:»)) + (( _floatToStringWitRaz((_bmp085P)/(133.3),0))) + (String(«*»)))) + (((String(«»)) + (( _floatToStringWitRaz(_dht1.humidity,0))) + (String(«%»))))).length(); if (_disp1oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;} _disp1oldLength = _dispTempLength1; _lcd1.setCursor(int((16 — _dispTempLength1)/2), 0); _lcd1.print((((((String(«T:»)) + (( _floatToStringWitRaz((_bmp085T)/(10.00),1))) + (String(«*»)))) + (((String(«P:»)) + (( _floatToStringWitRaz((_bmp085P)/(133.3),0))) + (String(«*»)))) + (((String(«»)) + (( _floatToStringWitRaz(_dht1.humidity,0))) + (String(«%»))))); } else { if (_disp1oldLength > 0) {_isNeedClearDisp1 = 1; _disp1oldLength = 0;} } if(_isTimer(_dht1Tti, 2000)) { if(_isTimer(_dht1LRT, ( _dht1.getMinimumSamplingPeriod()))) { _dht1.readSensor(); _dht1LRT = millis(); _dht1Tti = millis(); } } if (1) { _dispTempLength1 = ((((((String(«t:»)) + (( _floatToStringWitRaz(_dht1.temperature,0))) + (String(«*»)))) + (_RTC1_GetTime2_StrOut)))).length(); if (_disp2oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;} _disp2oldLength = _dispTempLength1; _lcd1.setCursor(int((16 — _dispTempLength1)/2), 1); _lcd1.print((((((String(«t:»)) + (( _floatToStringWitRaz(_dht1.temperature,0))) + (String(«*»)))) + (_RTC1_GetTime2_StrOut)))); } else { if (_disp2oldLength > 0) {_isNeedClearDisp1 = 1; _disp2oldLength = 0;} } _RTC1_GetTime2_StrOut = _RTC1.gettime(«H:i:sD»); } String _floatToStringWitRaz(float value, int raz) { return String(value, raz); } bool _isTimer(unsigned long startTime, unsigned long period ) { unsigned long currentTime; currentTime = millis(); if (currentTime>= startTime) {return (currentTime>=(startTime + period));} else {return (currentTime >=(4294967295-startTime+period));} }
Применять такой прибор можно где угодно или дома, на природе или поместить в автомобиль. Есть возможность запитать схему от аккумуляторов, применив плату заряда, в итоге будет переносная модель метеостанции.
Всю информацию можно получить посмотрев в видео:

Перечень материалов и инструментов
-плата Arduino Nano
-двухстрочный дисплей LCD1602;
-часы реального времени DS1302;
-датчик атмосферное давления и температуры BMP180;
-датчик температуры и влажности DHT11;
-блок зарядки от телефона;
-любой подходящий корпус
-пинцет;
ножницы;
-паяльник;
-кембрик;
-тестер;
-соединительные провода;
-провод четырехжильный для выносного датчика.
Шаг первый. Делаем корпус для метеостанции
Подобрал пластмассовую коробочку из магазина Fix Price (всего то 17р). Предварительно вырезал в крышке окно для дисплея. Затем вырезал частично перегородки в коробке, сделал отверстия для USB разъема платы Arduino проем для датчика BMP180 Датчика BMP180 будет находится на наружной стороне корпуса, чтобы исключить лишний нагрев от электронной начинки находящейся внутри. После я покрасил корпус самоделки изнутри потому что пластик прозрачный. Коробка закрывается на защелку и в ней все элементы неплохо поместились.
Шаг второй. Сборка схемы прибора.
Фото схемы
Далее надо скоммутировать по схеме все платы и датчики метеостанции. Делаем это с помощью монтажных проводов с соответствующими разъемами. Я не делал соединения на пайке ,так в перспективе при выходе какого то модуля из строя (или по другим причинам) можно легко его заменить. На винтовом разъеме подключается кабель датчика DHT11 идущий на улицу. Питание можно осуществить с разъема USB платы Ардуино на компьютер, или подав напряжение 7-12В на контакт VIN и GND.
Сначала я собрал схему вне корпуса и запрограммировал и отладил ее в программе FLPROG.
Фото блок схемы в программе FLPROG.
Когда первый раз запрограммировал и включил схема метеостанции заработала. Сейчас стало возможным иметь данные о погоде за бортом и в комнате. В общем получилась интересная домашняя метеостанция с множеством различных функций.
Фото в сборе
Неплохая получилась самодельная конструкция собранная в выходные. Было увлекательно самому сделать интересный и полезный приборчик. Сделать самостоятельно такой девайс, я думаю по плечу даже начинающему.Это не требует больших затрат времени и денег. Применить можно его где хочешь в доме на загородной даче. На всю работу пошло два выходных вечера всю электронику брал на Алиэкспресс. Остальные материалы нашлись у меня по сусекам. На базе платформы Ардуино можно собирать множество разнообразных полезных устройств.
Всем спасибо за внимание, вам успехов и удачи и в вашей жизни и в творчестве!Доставка новых самоделок на почту

Получайте на почту подборку новых самоделок. Никакого спама, только полезные идеи!

*Заполняя форму вы соглашаетесь на обработку персональных данных

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

Нам понадобятся:

  • Arduino UNO или иная совместимая плата;
  • датчик температуры и влажности DHT11 или другой;
  • датчик давления BMP085 или более современный BMP180, или иной;
  • датчик углекислого газа MQ135 (опционально);
  • LCD дисплей 1602 или другой;
  • потенциометр 10 кОм;
  • корпус для погодной станции;
  • кусок фольгированного стеклотекстолита;
  • винты для крепления компонентов;
  • персональный компьютер со средой разработки Arduino IDE.
  • соединительные провода;
  • разъём для подачи питания;
  • паяльник.

Инструкция по созданию домашней метеостанции на Arduino

1Подбор корпусадля будущей метеостанции

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

Прикиньте, как все компоненты будут размещаться внутри. Прорежьте окно для закрепления LCD дисплея, если его нет. Если будете размещать внутри датчик углекислого газа, который достаточно сильно греется, то разместите его в противоположной от других датчиков стороне или сделайте его выносным. Предусмотрите отверстие для разъёма питания.

Корпус для самодельной домашней метеостанции

2Используемые компоненты

  • LCD-дисплей 1602 использует 6 пинов Arduino + 4 на питание (подсветка и знакосинтезатор).
  • Датчик температуры и влажности DHT11 подключается к любому цифровому пину. Для чтения значений будем использовать библиотеку DHT11.
  • Датчик давления BMP085 подключается по интерфейсу I2C к двум пинам Arduino: SDA – к аналоговому пину A4 и SCL – к аналоговому пину A5. Обратим внимание, что для питания на датчик подаётся напряжение +3,3 В.
  • Датчик углекислого газа MQ135 подключается к одному из аналоговых пинов.

Компоненты домашней метеостанции

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

Используя же все 3 датчика, у нас будут задействованы 7 цифровых и 3 аналоговых пина Ардуино, не считая питания, естественно.

3Схема соединениякомпонентов метеостанции

Схема метеостанции показана на рисунке. Тут всё ясно.

Схема домашней метеостанции

4Скетч метеостанции

Напишем скетч для Ардуино. Код по возможности снабжён подробными комментариями.

Скетч для метеостанции на Arduino (разворачивается) /* СОЕДИНЕНИЯ Подключение датчика температуры-влажности DHT11 — — OUT > цифровой пин 9 — «+» > +3V (+5V) — «-» > GND Подключение датчика давления-температуры BMP085 — — VCC > 3.3V; (поддерживается 1.8 — 3.6 В) — GND > GND — SDA > аналоговый пин A4 — SCL > аналоговый пин A5 Детектор газа ————————————— — A0 — VCC — GND ЖКИ ———————————————— — LCD RS > к цифровым выводам 12 — 8 — LCD Enable > к выводам 11 — 9 — LCD D4 > к выводам 5 — 4 — LCD D5 > к выводам 4 — 5 — LCD D6 > к выводам 3 — 6 — LCD D7 > к выводам 2 — 7 — LCD R/W > GND — 10K резистор между +5V и землёй — сброс > к LCD VO (пин 3) */ // Подключение библиотек: #include <dht11.h> // датчика температуры-влажности #include <LiquidCrystal.h> // LCD #include <Wire.h> // датчика BMP085 #include <MQ135.h> // газовый детектор MQ135 LiquidCrystal lcd(12, 11, 5, 4, 3, 2); /* соединение LCD-шилда \x## — для вывода кириллических символов, где ## — номера символов в таблице */ dht11 sensorTempHumid; // датчик температуры и влажности MQ135 gasSensor = MQ135(A0); // датчик газа #define RZERO 76.63 float rzero; // показания с датчика газа float ppm; int del = 5000; // задержка, мс /* Oversampling Setting (OSS) — настройки разрешения для датчика давления BMP085, см. https://www.sparkfun.com/tutorials/253 OSS может быть 0, 1, 2 или 3: 0 — ультранизкое потребление, низкое разрешение; 1 — стандартное потребление; 2 — высокое разрешение; 3 — ультравысокое разрешение и максимальное потребление. */ const unsigned char OSS = 0; // Калибровочные переменные для BMP085: int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; long b5; float temperature; // температура long pressure; // давление // Для прогноза: const float p0 = 101325; // давление на уровне моря, Па. const float currentAltitude = 179.5; // высота погодной станции над уровнем моря, м; const float ePressure = p0 * pow((1 — currentAltitude/44330), 5.255); // нормальное давление на данной высоте, Па. float weatherDiff; #define DHT11PIN 9 // пин 9 датчика DHT11. #define BMP085_ADDRESS 0x77 /* I2C адрес датчика BMP085; см. https://www.sparkfun.com/tutorials/253 */ void setup() { lcd.begin(16, 2); // инициализация ЖК Wire.begin(); // инициализация I2C bmp085Calibration(); // калибровка датчика BMP085 } void loop() { // Проверка датчика давления-влажности: int chk = sensorTempHumid.read(DHT11PIN); switch (chk) { case DHTLIB_OK: lcd.clear(); break; case DHTLIB_ERROR_CHECKSUM: lcd.clear(); lcd.print(«Checksum error»); delay(del); return; case DHTLIB_ERROR_TIMEOUT: lcd.clear(); lcd.print(«Time out error»); delay(del); return; default: lcd.clear(); lcd.print(«Unknown error»); delay(del); return; } // Считываем с датчика BMP085: temperature = bmp085GetTemperature(bmp085ReadUT()); temperature *= 0.1; pressure = bmp085GetPressure(bmp085ReadUP()); pressure *= 0.01; // Разница давлений для вычисления простого прогноза weatherDiff = pressure — ePressure; rzero = gasSensor.getRZero(); ppm = gasSensor.getPPM(); // ЖК: lcd.setCursor(0, 0); // курсор на строку 1, поз. 1; //lcd.print(«p = «); lcd.print(pressure*3/4); // Па -> мм рт.ст. lcd.print(«mmHg «); // мм рт.ст. // «Прогноз»: if(weatherDiff > 250) lcd.print(«Sun»); else if ((weatherDiff <= 250) || (weatherDiff >= -250)) lcd.print(«Cloudy»); else if (weatherDiff > -250) lcd.print(«Rain»); lcd.setCursor(0, 1); // переход на строку 2 //lcd.print(«t=»); lcd.print(temperature, 1); lcd.print(«C «); //lcd.print(«f=»); lcd.print(sensorTempHumid.humidity); lcd.print(«% «); lcd.print(ppm); //lcd.print(«t=»); //lcd.print(sensorTempHumid.temperature); //lcd.print(«C «); delay(del); lcd.clear(); } // ВЫЧИСЛЕНИЕ ДАВЛЕНИЯ // Функция получает калибровочные значения для BMP085 // и должна быть запущена в начале. void bmp085Calibration() { ac1 = bmp085ReadInt(0xAA); ac2 = bmp085ReadInt(0xAC); ac3 = bmp085ReadInt(0xAE); ac4 = bmp085ReadInt(0xB0); ac5 = bmp085ReadInt(0xB2); ac6 = bmp085ReadInt(0xB4); b1 = bmp085ReadInt(0xB6); b2 = bmp085ReadInt(0xB8); mb = bmp085ReadInt(0xBA); mc = bmp085ReadInt(0xBC); md = bmp085ReadInt(0xBE); } // Вычисление нескомпенсированной температуры. // Возврашает значение в десятых долях градуса Цельсия. short bmp085GetTemperature(unsigned int ut) { long x1, x2; x1 = (((long)ut — (long)ac6)*(long)ac5) >> 15; x2 = ((long)mc << 11)/(x1 + md); b5 = x1 + x2; return ((b5 + 8)>>4); } /* Вычисление нескомпенсированного давления. Калибровочные значения должны быть уже известны. b5 также необходимо, поэтому сначала нужно вызвать bmp085GetTemperature(). Возвращает значение в Паскалях. */ long bmp085GetPressure(unsigned long up) { long x1, x2, x3, b3, b6, p; unsigned long b4, b7; b6 = b5 — 4000; // вычисление b3: x1 = (b2 * (b6 * b6)>>12)>>11; x2 = (ac2 * b6)>>11; x3 = x1 + x2; b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2; // вычисление b4: x1 = (ac3 * b6)>>13; x2 = (b1 * ((b6 * b6)>>12))>>16; x3 = ((x1 + x2) + 2)>>2; b4 = (ac4 * (unsigned long)(x3 + 32768))>>15; b7 = ((unsigned long)(up — b3) * (50000>>OSS)); if (b7 < 0x80000000) p = (b7<<1)/b4; else p = (b7/b4)<<1; x1 = (p>>8) * (p>>8); x1 = (x1 * 3038)>>16; x2 = (-7357 * p)>>16; p += (x1 + x2 + 3791)>>4; return p; } // Чтение нескомпенсированного значения температуры. unsigned int bmp085ReadUT() { unsigned int ut; // Записывает 0x2E в регистр 0xF4 // для запроса показаний температуры: Wire.beginTransmission(BMP085_ADDRESS); Wire.write(0xF4); Wire.write(0x2E); Wire.endTransmission(); delay(5); // Читает 2 байта из регистров 0xF6 и 0xF7 ut = bmp085ReadInt(0xF6); return ut; } // Чтение давления (нескомпенсированного). unsigned long bmp085ReadUP() { unsigned char msb, lsb, xlsb; unsigned long up = 0; // Записывает 0x34+(OSS<<6) в регистр 0xF4 // для запроса показаний давления: Wire.beginTransmission(BMP085_ADDRESS); Wire.write(0xF4); Wire.write(0x34 + (OSS<<6)); Wire.endTransmission(); // Ожидание преобразования, задержка зависит от OSS: delay(2 + (3<<OSS)); // Чтение регистров 0xF6 (MSB), 0xF7 (LSB), 0xF8 (XLSB): Wire.beginTransmission(BMP085_ADDRESS); Wire.write(0xF6); Wire.endTransmission(); Wire.requestFrom(BMP085_ADDRESS, 3); // Ожидание данных: while(Wire.available() < 3); msb = Wire.read(); lsb = Wire.read(); xlsb = Wire.read(); up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS); return up; } // Читает 1 байт из BMP085 по адресу ‘address’. char bmp085Read(unsigned char address) { unsigned char data; Wire.beginTransmission(BMP085_ADDRESS); Wire.write(address); Wire.endTransmission(); Wire.requestFrom(BMP085_ADDRESS, 1); while(!Wire.available()); return Wire.read(); } // Читает 2 байта из BMP085, начиная с адреса ‘address’. int bmp085ReadInt(unsigned char address) { unsigned char msb, lsb; Wire.beginTransmission(BMP085_ADDRESS); Wire.write(address); Wire.endTransmission(); Wire.requestFrom(BMP085_ADDRESS, 2); while(Wire.available()<2); msb = Wire.read(); lsb = Wire.read(); return (int) (msb<<8 | lsb); }

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

5Сборка метеостанции

Сделаем печатную плату для размещения компонентов внутри корпуса – это самое удобное решение для компоновки и подключения сенсоров. Для изготовления печатной платы в домашних условиях я использую «лазерно-утюжную» технологию (мы её подробно описывали в прошлых статьях) и травление с помощью лимонной кислоты. Предусмотрим на плате места для перемычек («джамперов»), чтобы иметь возможность отключать датчики. Это будет полезно, если будет нужно перепрограммировать микроконтроллер, когда возникнет желание модифицировать программу.

Печатная плата для домашней метеостанции

С помощью пайки установим датчики давления и газов.

Для установки платы Arduino Nano удобно использовать специальные адаптеры или гнёзда с шагом 2,54. Но за неимением этих деталей и из-за экономии пространства внутри корпуса, я установлю Ардуино также пайкой.

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

Предусмотрим места для подводки внешнего питания к нашей самодельной плате. Я буду использовать обычное зарядное устройство на 5 В от старого сломанного роутера. Плюс 5 вольт от зарядного устройства будут подаваться на пин Vin платы Arduino.

Сборка метеостанции на Ардуино

ЖК-экран будет крепиться винтами прямо к корпусу, к передней части. Подключаться будет проводами с разъёмами быстрого подключения типа «Dupont».

Установим печатную плату внутри корпуса и закрепим винтами. Подключим LCD-экран к ножкам Arduino согласно схеме.

Аккуратно закрываем корпус метеостанции.

6Включение метеостанции

Ещё раз перепроверив, что всё подключили правильно, подаём питание на нашу метеостанцию. ЖК-экран должен загореться, и через несколько секунд на нём появятся данные о давлении, небольшой прогноз, основанный на показаниях давления, а также данные о температуре, влажности и концентрации углекислого газа.

Домашняя метеостанция в работе

Выводы

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

Предисловие

Что, ещё одна погодная станция на Arduino?! Да, ещё одна и, что-то мне подсказывает, не последняя в интернете вещей.

Точно также, как каждый программист обязан написать программу «Hello World!», так и каждый ардуинщик обязан иметь за плечами опыт построения простой или не очень метеостанции.
Уже созданных проектов метеостанций в интернете описано немалое количество, читатель может выбрать любой из них для реализации. Не скрою, я внимательно изучил около десятка подобных проектов и ещё кучу смежных. Поэтому нельзя сказать, что я создал всё с нуля, конечно же я «стоял на плечах гигантов».

Сразу скажу, что в мои планы не входило использование сторонних сервисов для хранения и отображения данных. Хотелось лично пощупать и понять как всё это работает изнутри от начала до конца, от А до Я.

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

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

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

Прототипирование

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

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

Каждый, кто клепает по вечерам свои поделки pet-project для «internet of things», должен отдавать себе отчёт в том, что он создаёт именно прототип, полуфабрикат. До уровня нормального промышленного изделия ему очень далеко. Поэтому не следует поручать нашим любительским поделкам какие-либо ответственные участки жизнеобеспечения и надеяться, что они нас не подведут.

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

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

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

Требования

Обычно этот этап пропускают. Решая сделать что-нибудь эдакое прямо сейчас, а потом выясняются мелкие детали, которые ставят весь проект в тупик или вовсе делают его неподъемным. Все наши хотелки необходимо записывать, я использую для этого гугл диск, он доступен с ПК и с мобильного устройства.

Итак, наша метеостанция должна:

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

Датчики используются самые простые и дешевые. Например, забегая наперед скажу, что температуру DHT22 измеряет достаточно точно, а вот с влажностью немного неточен. Но, опять таки повторюсь, это не имеет значения, поскольку перед нами — прототип, и разброс в 5% влажности ни на что важное в нашей жизни не повлияет.

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

Железо. Выбор компонентов

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

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

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

Выход есть. Можно просто взять и повторить чей-то проект. Я же изучил уже существующие проекты метеостанций и надеюсь сделал шаг вперед.

Итак. Архитектура погодной станции базируется на Arduino. Потому что Arduino имеет небольшой порог вхождения и я уже имел с этим дело. Дальше выбирать уже проще.

Сразу стало ясно, что в составе метеостанции будет удаленый, заоконный датчик и центральный модуль.

Центральный, основной блок будет расположен внутри помещения. Это важно определить на начальном этапе, от этого «пляшут» такие важные характеристики как температурный режим работы и питание.

Удаленный датчик (или датчики) будет без «мозгов», его задача — периодически проводить измерения и передавать данные на центральный домашний блок. Центральный блок принимает данные от всех датчиков, показывает их на экране и отправляет их же в интернет в базу данных. Ну, а там уже много проще, как только данные оказываются в базе с ними можно делать всё что захочешь, даже графики рисовать.

Для сношений с внешним миром интернет был однозначно выбран WiFi модуль ESP8266 практически без альтернативы (прим. возможно сейчас такие альтернативы появились). К Arduino выпускаются Ethernet платы расширения, но совсем не хотелось привязываться к кабелю.

Интересный вопрос состоял в том, чем обеспечивать связь между заоконным датчиком (или датчиками, про требование расширяемости системы помним?) и центром. Радиомаячки на 433 Мгц однозначно не подходят (они не подходят ни для чего вообще).

Воспользоваться опять ESP8266 ?

Минусы такого решения:

  • необходим устойчивый WiFi за пределами дома

  • дальность связи не будет большой

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

  • большее энергопотребление.

  • Энергопотребление ESP8266 :

  • при передаче 120—170 mA

  • при приеме 50—56 mA

  • в режиме Deep Sleep 10 µA (мкА)

  • в выключенном состоянии 5 µA (мкА).

В конце концов для связи удаленных датчиков с основным домашним блоком был выбран чип nRF24L01+ с 2,4 Ггц передатчиком и приемником в одном флаконе, с дополнительной внешней антенной, чтоб уж наверняка «пробить» стены.

Энергопотребление nRF24L01+ 2,4 GHz :

  • при приеме 11 mA
  • при передаче на скорости 2Mbps — 13 mA
  • в режиме standby-I — 26 μA (мкА)
  • в выключенном состоянии 900 nA (нА).

Что у ESP8266, что у nRF24L01+ диапазон рабочих температур подходящий: от -40℃ до +80℃.

Купить nRF24L01+ можно примерно за $1, или сразу с внешней антенной за $3. Купить ESP8266-01 можно примерно за $4. Читайте внимательно описание товара! Иначе купите одну антенну.

Ядро системы вырисовалось. Переходим к самим датчикам.

На улице, как известно, температура может достигать отрицательных значений, поэтому датчик DHT11 не подходит, а вот DHT22 в самый раз.

Характеристики DHT22 / AM2302 :

  • питание от 3,3 В до 5 В, рекомендуется 5 В
  • потребление 2.5mA максимум, в момент измерения и передачи данных
  • диапазон измерения влажности 0-100% с погрешностью 2-5%
  • диапазон измерения температуры от -40 до +125°C с погрешностью ±0.5°C
  • запрос на измерение не чаще 0,5 Гц — одного раза в 2 секунды.

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

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

  • питание от 3,3 В до 5 В
  • потребление 2,5 mA максимум, в момент измерения и передачи данных
  • диапазон измерения влажности 20-80% с погрешностью 5%
  • диапазон измерения температуры от 0 до +50°C с погрешностью ±2°C
  • запрос на измерение не чаще 1 Гц — одного раза в секунду.

Купить DHT22 можно примерно за $3. DHT11 стоит дешевле — $1, но он и менее точен.

Теперь возвращаемся опять к Arduino. Какую плату выбрать?

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

BMP085 Barometric Pressure Sensor Module for arduino (или как сделать метеостанцию своими руками)

Метеостанция своими руками.
Дело было вечером, делать было нечего после нового года. Как обычно, во время зимних новогодних каникул хочется занять голову да и руки тоже чем-нибудь полезным, творческим. В эти новогодние каникулы решил сделать метеостанцию своими руками. Готовиться начал заранее, все компоненты закупал и собирал перед новым годом, а основное программирование делал на каникулах.
(под катом много фотографий!)
Сначала пробегусь по компонентам, ссылки давать не буду, так как на eBay (в личном кабинете) товары ушли в архив. Многие компоненты покупал неспеша на аукционе eBay. Впервые опробовал аукцион, раньше всегда покупал «buy it now». Что могу сказать, если не спешить с покупками, то некоторые компоненты можно купить дешевле (разница иногда бывает в два раза).
Датчик давления ВМР085
Это основной датчик. Когда я увидел его на eBay, то понял, что хочу собрать именно домашнюю метеостанцию.
Прилетел датчик в обычном конверте, внутри обклеенном пупыркой.

Внутри конверта была визитка продавца и датчик, запакованный в антистатический пакет и завёрнутый в ещё один слой пупырки

Антистатический пакет был запаян, дабы влага во время перелёта не грозила датчику

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


Все бы хорошо, но маркировка контактов нанесена в зеркальном виде.
Подключается датчик по шине I2C и питается от 3,3 В. То есть для нормального функционирования нужно 4 провода (+, -, SDA, SCL)
Опрашивать датчик можно 2 способами: или через библиотеку, или используя функции прямо скетче.
Пример программы:
ВМР085 #include <Wire.h>
#define BMP085_ADDRESS 0x77 // I2C address of BMP085
const unsigned char OSS = 0; // Oversampling Setting
// Calibration values
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;
long b5;
short temperature;
long pressure;
void setup()
{
Serial.begin(9600);
Wire.begin();
bmp085Calibration();
}
void loop()
{
temperature = bmp085GetTemperature(bmp085ReadUT());
pressure = bmp085GetPressure(bmp085ReadUP());
Serial.print(«Temperature: „);
Serial.print(temperature/10.0, DEC);
Serial.println(“ C»);
Serial.print(«Pressure: „);
Serial.print(pressure/133.322, DEC);
Serial.println(“ mm Hg»);
Serial.println();
delay(1000);
}
void bmp085Calibration()
{
ac1 = bmp085ReadInt(0xAA);
ac2 = bmp085ReadInt(0xAC);
ac3 = bmp085ReadInt(0xAE);
ac4 = bmp085ReadInt(0xB0);
ac5 = bmp085ReadInt(0xB2);
ac6 = bmp085ReadInt(0xB4);
b1 = bmp085ReadInt(0xB6);
b2 = bmp085ReadInt(0xB8);
mb = bmp085ReadInt(0xBA);
mc = bmp085ReadInt(0xBC);
md = bmp085ReadInt(0xBE);
}
short bmp085GetTemperature(unsigned int ut)
{
long x1, x2;
x1 = (((long)ut — (long)ac6)*(long)ac5) >> 15;
x2 = ((long)mc << 11)/(x1 + md);
b5 = x1 + x2;
return ((b5 + 8)>>4);
}
long bmp085GetPressure(unsigned long up)
{
long x1, x2, x3, b3, b6, p;
unsigned long b4, b7;
b6 = b5 — 4000;
// Calculate B3
x1 = (b2 * (b6 * b6)>>12)>>11;
x2 = (ac2 * b6)>>11;
x3 = x1 + x2;
b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;
// Calculate B4
x1 = (ac3 * b6)>>13;
x2 = (b1 * ((b6 * b6)>>12))>>16;
x3 = ((x1 + x2) + 2)>>2;
b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
b7 = ((unsigned long)(up — b3) * (50000>>OSS));
if (b7 < 0x80000000)
p = (b7<<1)/b4;
else
p = (b7/b4)<<1;
x1 = (p>>8) * (p>>8);
x1 = (x1 * 3038)>>16;
x2 = (-7357 * p)>>16;
p += (x1 + x2 + 3791)>>4;
return p;
}
// Read 1 byte from the BMP085 at ‘address’
char bmp085Read(unsigned char address)
{
unsigned char data;
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(address);
Wire.endTransmission();
Wire.requestFrom(BMP085_ADDRESS, 1);
while(!Wire.available())
;
return Wire.read();
}
int bmp085ReadInt(unsigned char address)
{
unsigned char msb, lsb;
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(address);
Wire.endTransmission();
Wire.requestFrom(BMP085_ADDRESS, 2);
while(Wire.available()<2)
;
msb = Wire.read();
lsb = Wire.read();
return (int) msb<<8 | lsb;
}
// Read the uncompensated temperature value
unsigned int bmp085ReadUT()
{
unsigned int ut;
// Write 0x2E into Register 0xF4
// This requests a temperature reading
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(0xF4);
Wire.write(0x2E);
Wire.endTransmission();
// Wait at least 4.5ms
delay(5);
// Read two bytes from registers 0xF6 and 0xF7
ut = bmp085ReadInt(0xF6);
return ut;
}
// Read the uncompensated pressure value
unsigned long bmp085ReadUP()
{
unsigned char msb, lsb, xlsb;
unsigned long up = 0;
// Write 0x34+(OSS<<6) into register 0xF4
// Request a pressure reading w/ oversampling setting
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(0xF4);
Wire.write(0x34 + (OSS<<6));
Wire.endTransmission();
// Wait for conversion, delay time dependent on OSS
delay(2 + (3<<OSS));
// Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(0xF6);
Wire.endTransmission();
Wire.requestFrom(BMP085_ADDRESS, 3);
// Wait for data to become available
while(Wire.available() < 3)
;
msb = Wire.read();
lsb = Wire.read();
xlsb = Wire.read();
up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);
return up;
}
Помимо этого в датчике есть собственный термо-сенсор для компенсации давления и альтиметр
Arduino Nano v3.0
Это сердце всей метеостанции. По простому говоря, контроллер в миниатюрном размере.
Покупал
Рассказывать подробно про контроллер не буду, так как до меня уже это сделали:
Обзор 1
Обзор 2
Посылка с lightake была сборная, контроллер пришел в пакете, где был USB-кабель и Arduino в запаянном антистатическом пакете.

Чтобы оценить размеры, рядом с Arduino положил монетку номиналом 1 руб.

Плата контроллера вблизи


USB-кабель хороший, с ферритовым кольцом. Питается Arduino по USB кабелю. Среду разработки можно скачать отсюда (страница для скачивания ). Язык «С»-подобный, с освоением проблем не было, так как на нем очень много программирую на работе.
LCD экран
На работе в закромах нашёл совместимый LCD 1602 экран. С подключением пришлось повозиться, так как даташита на него не нашёл. В результате LCD заработал.

Но после недолгой эксплуатации заметил, что мне этого экрана мало и вывести больше данных не получится, так как он имеет всего 2 строки по 16 символов в каждой. Поначалу кажется, что этих параметров хватит, но когда начинаешь программировать, то понимаешь, что максимум можно впихнуть 3-4 параметра. А если делать меню (я ведь подумывал сделать меню на этом экране), то свободного места остаётся на 1-2 параметра.
В итоге начал подыскивать себе другой экран. Сначала присматривался к графическому экрану от Nokia 3310 и даже в аукционе eBay участвовал, чтобы его купить, но не сложилось (чему я очень рад), поэтому мне пришлось отказаться от этого экрана. Сейчас я понимаю, что он был бы слишком мал для моих целей, так как есть с чем сравнивать.
Случайно просматривая шилды на Arduino, я наткнулся на графический экран 12864 на контроллере ST7920. У этого экрана и размер подходящий, и хорошее разрешение для моих нужд (128х64). То есть можно спокойно разместить 6-7 строк по 20 символов нормально читающегося шрифта. Так как экран графический, то помимо текста разными шрифтами можно разместить и графику. Короче, это именно то, что мне нужно было, все присутствовало в этом экране, поэтому я не выдержал и заказал.
Посылка пришла быстро и была упаковано стандартно: конверт-пупырка, внутри ещё слой пупырки и экран в антистатическом пакете:



Чтобы оценить размеры, рядом с LCD положил монетку номиналом 1 руб.


Чтобы быстро подключить экран к Arduino, к контактам LCD припаял линейку контактов. Подключать LCD можно по последовательной шине и по параллельной. Я выбрал первый вариант, так как свободных контактов Arduino и так мало.
Подключение (взято из сети):
— Контакт 1 (GND) подключается к общей шине
— Контакт 2 (VCC) подключается к шине питания +5V, причём потребляемый ток сравнительно небольшой и дисплей можно питать от встроенного стабилизатора Arduino.
— Контакты 4, 5 и 6 подключаются к цифровым выходам Arduino, образуя последовательный интерфейс SPI:
контакт 4 – (RS) – соответствует линии CS (например 7)
контакт 5 – (RW) – соответствует линии MOSI (например 8)
контакт 6 – (E) – соответствует линии SCK (например 3)
номера контактов Arduino могут быть любыми, главное не забыть потом правильно указать их в тексте программы при инициализации дисплея.
— Контакт 15 (PSB) соединяется с общей шиной.
— Контакты 19 (A) и 20 (K) – это питание подсветки (+5V и GND соответственно). Для регулировки яркости подсветки можно использовать переменный резистор 10кОм, включённый между шинами питания и GND. Напряжение с его движка подаётся на контакт 19 дисплея.
По этой инструкции я подключил все, кроме подсветки. В качестве питания подсветки я использовал ШИМ Arduino.
Для того, чтобы программно подключить LCD к Arduino, используется библиотека u8glib. Скачать можно . Если есть проблемы скачивания, то могу библиотеку залить на narod.ru.
Сама библиотека не сложная и позволяет выводить текст разным шрифтом, рисовать линию, рисовать простейшие геометрические фигуры (прямоугольник, круг), выводить на экран свои изображения, подготовленные специальным образом. В принципе, этого инструмента достаточно для большинства задач.
Вот результат простенькой программы:

Сама программа:
LCD7920 #include «U8glib.h»
U8GLIB_ST7920_128X64 u8g(3, 9, 8, U8G_PIN_NONE); // SPI E = 3, RW = 9, RS = 8
// Подпрограмма определения свободной памяти
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v — (__brkval == 0? (int) &__heap_start: (int) __brkval);
}
void setup(void) {
u8g.setFont(u8g_font_6x10); // шрифт
u8g.setRot180(); //Перевернул экран
analogWrite(6, 115); // Устанавливаем яркость экрана (анод подсветки на 6 pin)
}
void loop(void) {
u8g.firstPage();
do {
u8g.setColorIndex(1); // белые чернила, черный фон
u8g.setPrintPos(1, 12); // позиция
u8g.print(«Hello!!!»); // вывод текста
u8g.drawBox(0,22,128,9); // Закрашиваем прямоугольник белым
u8g.setColorIndex(0); // белые чернила, черный фон
u8g.setPrintPos(1, 30); // позиция
u8g.print(«Word…»); // вывод текста
u8g.setColorIndex(1); // белые чернила, черный фон
u8g.setPrintPos(1, 50); // позиция
u8g.print(«After start =»); // вывод текста
u8g.setPrintPos(85, 50); // позиция
u8g.print(millis() / 1000); // вывод число секунд после старта
u8g.setPrintPos(1, 64); // позиция
u8g.print(freeRam ()); // вывод сколько памяти занято
} while( u8g.nextPage() );
delay(200);
}
Часы реального времени DS1307
Ещё один компонент для моей метеостанции. На данном шилде реализованы часы реального времени. Заказывал их на аукционе eBay. Продавец прислал платку часов в нереально большой коробке

Внутри коробки было два листка А4 с рекламой и платка часов, обмотанная целлофаном

Хочу заметить, что плата не превышает размером 2 руб. монету, а коробка была размером 13х15х5 см.
Плата была упакована в антистатический пакет

Платка вблизи


С данным модулем мне пришлось повозиться. Во-первых, были трудности подключения. А во-вторых, кварц на данной плате никакой. Если бы знал, что на модуль потрачу столько времени, то, скорее всего, собрал бы его сам, благо в сети полно схем. Самая простейшая схема содержит 4-5 компонентов.
По поводу подключения. Я нашёл библиотеку, в которой было сказано, что интерфейс I2C можно подключать не на привычные аналоговые входы Arduino (А4 и А5), а на любые дискретные. Как написано, так и сделал. Сначала ничего не работало, после долгого танца с бубном часы завелись. Ну, подумал, всё, проблемы закончились, но после того, как я попытался этот же модуль подключить к другой Arduino, пляски с бубном продолжились. Много времени потратил на поиски решения данной проблемы и практически везде указывалось либо на неправильное подключение, либо на отсутствие подтягивающих резисторов на контактах SCL и SDA. Я уже хотел с паяльником в плату лезть, но на одном форуме случайно наткнулся на код, где было сказано, чтобы SCL и SDA подключать к стандартным портам I2C на Arduino. После стандартного подключения, все сразу заработало.
Теперь по поводу кварца. Не знаю, что там за кварц ставят китайцы, но часы с таким кварцем убегали в сутки на 10-11 сек. В месяц данная погрешность составляет 5 минут, а в год 1 час. Нафиг такие часы не нужны. Пришлось снова лезть в сеть и искать, как исправить данный баг. Первое попавшее решение говорит о том, что нужно заземлить кварц. Сделал — результат нулевой. Ещё где-то нашёл, что нужно найти старую материнку и выпаять оттуда часовой кварц. Сделал — результат есть. Теперь часы убегают не на 10-11 секунд, а на 1,5 секунды в сутки. Скажем так, стало лучше, но до идеала далеко. Так как больше с паяльником возится неохота, то было решено подводить часы программно, то есть раз в сутки подводить часы на нужную величину. После 10 суток, часы ушли не более, чем на секунду. Метод хорош, но только тогда, когда устройство синхронизации Arduino подключено к питанию, иначе часы работают от батарейки и все равно убегают.
Небольшая тестовая программа:
RTC DC1307 #include «Wire.h»
#define DS1307_I2C_ADDRESS 0x68 // SDA A4, SCL A5
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}
byte bcdToDec(byte val)
{
return ( (val/16*10) + (val%16) );
}
void setDateDs1307(byte second, // 0-59
byte minute, // 0-59
byte hour) // 0-99
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0);
Wire.write(decToBcd(second));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.endTransmission();
}
void getDateDs1307(byte *second,
byte *minute,
byte *hour)
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 3);
*second = bcdToDec(Wire.read());
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read());
}
void setup()
{
byte second, minute, hour;
Wire.begin();
Serial.begin(9600);
second = 45;
minute = 5;
hour = 16;
setDateDs1307(second, minute, hour);
}
void loop()
{
byte second, minute, hour;
getDateDs1307(&second, &minute, &hour);
Serial.print(hour, DEC);
Serial.print(«:»);
Serial.print(minute, DEC);
Serial.print(«:»);
Serial.println(second, DEC);
delay(1000);
}
Здесь не использована библиотека, да и функции усечены, для чтения и записи времени.
Датчик температуры и влажности DHT11
Про данный датчик рассказывать нечего. Я бы его даже не стал использовать, если бы не нужна была влажность. К сожалению, я его не сфотографировал, когда получил, поэтому фотографий не будет. Фотографии датчика можно будет посмотреть ниже, где я его подключил к Arduino. Подключение датчика простое (+, цифровой выход, -). Обычно датчики делают четырёх контактные. При таком форм-факторе третий контакт ни к чему не подключают.
Для подключения к Arduino можно использовать библиотеку. Скачать можно .
Небольшая тестовая программа c выводом информации на LCD дисплей 1602:
DHT11 // include the library code:
#include <dht11.h>
#include <LiquidCrystal.h>
// Declare objects
dht11 DHT11;
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);
#define DHT11PIN 7
int i;
void setup()
{
lcd.begin(16, 2);
lcd.print(«Status: „);
i=0;
}
void loop()
{
int chk = DHT11.read(DHT11PIN);
lcd.setCursor(8, 0);
switch (chk)
{
case 0: lcd.print(“OK „); break;// lcd.setCursor(11, 0); lcd.print(millis()/2000); break;
case -1: lcd.print(“Checksum error»); mErr(); break;
case -2: lcd.print(«Time out error»); mErr(); break;
default: lcd.print(«Unknown error»); mErr(); break;
}
delay(500);
lcd.setCursor(15, 0);
switch (i)
{
case 0: lcd.print(«^»); lcd.setCursor(15, 1); lcd.print(» «);break;
case 1: lcd.print(«v»); lcd.setCursor(15, 1); lcd.print(» «);break;
default: lcd.setCursor(15, 1); lcd.print(«E»); break;
}
i=i+1;
if (i>1) i=0;
lcd.setCursor(0, 1);
lcd.print(«H=»);
lcd.setCursor(2, 1);
lcd.print((float)DHT11.humidity, 0);
lcd.setCursor(4, 1);
lcd.print(«%»);
lcd.setCursor(8, 1);
lcd.print(«T=»);
lcd.setCursor(10, 1);
lcd.print((float)DHT11.temperature, 0);
lcd.setCursor(12, 1);
lcd.print(«C»);
}
void mErr()
{
lcd.setCursor(2, 1);
lcd.print(«**»);
lcd.setCursor(10, 1);
lcd.print(«**»);
i=5;
}
Минусы у датчика есть – данные с датчика идут только в целых числах, да и диапазон слабенький.
Вроде, про все компоненты написал. Осталось собрать все в единое целое.
Упс, чуть не забыл! Для того, чтобы все собрать устройство, нужен корпус. Корпус тоже заказывал на Ebay. Продавец оказался из Англии. Посылка дошла быстро, но фотографировать её не стал. Все фотографии корпуса ниже.
Сначала собрал все на столе с помощью специальных проводков. Написал тестовую программу и залил её в контроллер.


На самом деле синий цвет подсветки гораздо ярче. Даже при минимальной яркости (Bright=5) происходит засветка кадра.
Чтобы все собрать без проводов, было решено сделать мини материнскую плату, а платка Arduino и шилды надевались на разъёмы. В случае чего, их с лёгкостью можно быстро извлечь. LCD экран и кнопки для управления я решил также цеплять на разъёмах, только датчик температуры впаять на проводах.
Вот такая вышла платка


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

Материнская плата с установленными шилдами и платой Arduino.

Вот так выглядит полное подключение к материнской плате

Вместо кнопок использовал самодельный шилд, спаянный на макетной плате. В качестве кнопок использовал кнопки из старых мышек.
Как видно, количество проводов убавилось.
Основная проблема размещения в корпус — это ровно выпилить паз под LCD экран. Как я ни старался, все равно идеально не получилось. Щели в некоторых местах были чуть больше 1 мм. Чтобы все смотрелось аккуратно, я взял чёрный герметик для аквариума и залил все щели, заодно экран крепил именно на этот герметик. После высыхания герметика снаружи обрезал излишки. При ярком освещении герметик видно, а при обычном — все сливается с корпусом.
Вот так выглядит корпус изнутри с установленным LCD экраном и материнской платой.

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

Долго думал, как приладить кнопки в корпус и, самое главное, какие использовать кнопки…
В радиоэлектронных магазинах приглянулись кнопка с длинным шпиньком и наконечники, которые надеваются на этот шпинёк. Эти кнопки используются для пайки на плату. Все бы хорошо, но у них есть минус – ход нажатия очень маленький и громкий.
Размещать кнопки пришлось в два этапа: первый — разместить кнопки на плате, второй — эту плату крепить ещё на одной плате. И все это потом засовывать в корпус на направляющие.
Вот так выглядит платка с кнопками:


Вот так выглядит плата-держатель:

Здесь видны направляющие, в которые вставляется плата с кнопками. Некоторые элементы паял для того, чтобы придать жёсткость плате.
Теперь все засовываем в корпус
Без подключения кнопок:

С подключением кнопок:

Закрываем корпус и включаем. Все прекрасно работает, кнопки отрабатывают, как нужно.

Фотографии разных экранов


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






В конце размещаю небольшое видео работы устройства в разных режимах:
http://www.youtube.com/watch?v=KsiVaUWkXNA&feature=youtu.be
У кого видео здесь не отображается, вот ссылка на Youtube
Пора заканчивать обзор.
Немного напишу о программе, а потом краткие выводы. Когда писал программу, не думал, что очень быстро упрусь в ограничение в 30720 байт.

Пришлось оптимизировать код. Многие куски кода выносил в подпрограммы. Никогда бы не подумал, что оператор switch… case в компилированном виде занимает больше места, чем несколько if… else. Ещё экономит место правильное объявление переменных. Если объявлять массив long, хотя вполне можно обойтись byte, то перерасход памяти достигает 500 байт в зависимости от размерности массива. Когда пишешь программу, то об этом не думаешь, а уже потом, когда анализируешь программу, то понимаешь, что некоторые вещи сделал неправильно, и начинаешь оптимизировать код. После того, как проблемы с размером программы были решены, я упёрся в ограничение оперативной памяти. Выражалось это в том, что программа начинала виснуть после загрузки. Пришлось вводить подпрограмму подсчёта свободной оперативной памяти. В результате, был вынужден отказаться от одного алгоритма предсказывания погоды, так как он должен выводить пиктограммы на экран. Сам алгоритм работает, а вот вывод пиктограмм пришлось заремировать. У меня есть ещё задумки, как оптимизировать код, но в ближайшем будущем оставляю работать устройство, как есть, чтобы оценить работоспособность и выявить все баги.
Теперь небольшие выводы
Минусы
1) Цена. Оправдание этому минусу – хобби никогда не бывает дешёвым.
Плюсы
1) Большой функционал устройства
2) Наращивание функций ограничивается только используемым контроллером и собственным желанием
3) Эстетическое удовольствие от созерцания и моральное удовльствие от того, что я все-таки собрал и доделал это устройство

Погодная станция на Arduino своими руками

Приветствую, Самоделкины!
Сегодня мы будем делать многофункциональную погодную станцию для наблюдения за микроклиматом в помещении.
Автор YouTube канала «AlexGyver» давно хотел сделать нечто подобное, чтобы она (станция) измеряла различные параметры микроклимата в комнате, в частности концентрацию углекислого газа. Так же наша станция должна показывать другие параметры микроклимата, например, температуру, влажность, давление, показывать время и дату, сигнализировать, например, об уровне углекислого газа, ну и до кучи строить графики в разных временных интервалах, это будет полезно, как ради интереса, так и пригодится любителям что-то выращивать или содержать специфичных животных.
В основе системы лежит платформа arduino nano, которая будет считывать показания датчиков и выводить их на дисплей. Дисплей возьмем самый дешевый из больших, символьный 2004 с переходником на шину I2C. Места на дисплее много, так что организуем часы. Для этого понадобится модуль реального времени, который будет считать секунды, причем даже после отключения питания.
Основной датчик нашей метеостанции BME280, появился у китайцев относительно недавно.
Этот датчик крут тем, что стоит чуть дороже палки шаурмы, но умеет с высокой точностью измерять температуру, влажность и атмосферное давление. И все это вот в этой маленькой коробочке с дырочкой.
Следующий датчик — это MH-Z19, собственно датчик углекислого газа, он в этой схеме самый дорогой, стоит 1000 с хвостиком рублей. Для переключения режимов будем использовать сенсорную кнопку, которая будет находиться внутри корпуса и реагировать на палец через его стенку. Также для индикации углекислого газа понадобится 3-ех цветный светодиод.
Все компоненты куплены на aliexpress, ссылки найдете на странице проекта.
Сейчас нам нужно спаять все по схеме. На странице проекта представлены 2 варианта схемы, но они полностью идентичны, просто автор их по-разному оформил.
Ну и собственно вот, все спаяли.
Как на схеме, общие провода скручиваем в пучок и паяем на ардуино. К проводам питания автор подпаялся отдельно и на конце использовал micro USB модуль, для более удобного использования.
И вот еще светодиод с резистором на общей ноге.
Сейчас подключаем arduino к компьютеру для загрузки прошивки. Архив с прошивкой качаем опять же со страницы проекта. Там нет ничего сложного, все делается в несколько кликов мышкой.
В самой прошивке есть несколько настроек.
Значит, что у нас тут есть. Большие часы:
Время и дата, кстати, устанавливаются автоматически во время загрузки прошивки. Устанавливаются они такие же, как на компьютере, с которого загружается прошивка. Справа от часов дата. Ниже у нас строчка по выбору (сейчас стоит день недели транслитом «Vosk» — воскресенье). В прошивке можно поставить год или секунды в реальном времени.
Далее у нас температура, влажность и углекислый газ.
По углекислому газу вот табличка:
Атмосферное давление (в мм рт. ст.) и предсказания погоды на основе изменений этого самого давления за последний час.
В общем, если цифра доходит до сотки, то с очень большой вероятностью будет жуткий шквальный ливень с грозой летом или густой снегопад с метелью зимой.
Если же значение отрицательное, то следует ждать улучшение плохой погоды. Вот такая забавная штука.
Далее графики. Кликом по кнопке листаем график температуры за последний час. Тут 15 столбиков. График сдвигается каждые 4 минуты. Сверху максимальное значение из показанного на графике, снизу минимальное из показанного и чуть выше текущая.
Тут тоже самое, но за сутки.
Углекислый газ.
Кстати, из любого графика можно выйти на главный экран, задержав палец на сенсоре около одной секунды.
Цвета светодиода. Зеленый — малая концентрация углекислого газа, синий – повышенная, и мигающий красный — очень высокое, значит нужно срочно проветривать.
При большом содержании углекислого газа понижается работоспособность, повышается сонливость и прочее, прочее.
Собственно, вот и все, что можно сказать о прошивке. Осталось собрать эти электронные потроха в корпус и поставить на стол. Будем использовать вот такой корпус, который идеально подходит под этот проект и вообще под дисплеи 2004, единственное, придется отрезать лишний батарейный отсек.
Размечаем лицевую часть под окошко дисплея и выпиливаем это окошко.
В итоге получаем почти идеальное окошко, которое нужно в буквальном смысле доработать напильником.
Прежде чем клеить модули друг на друга, нужно определить какие из них греются, чтобы в дальнейшем не размещать датчик температуры рядом с теплыми компонентами. В этом нам поможет тепловизор для смартфона.
Сразу видим, как нагревается токоограничивающий резистор подсветки дисплея, тут размещать датчик точно нельзя. Из всех остальных модулей нагревается только датчик углекислого газа (на 2 градуса выше температуры окружающего воздуха). Также до 30 градусов греется микроконтроллер на плате и совсем чуть-чуть греется светодиод.
Окей, продолжаем кромсать корпус и сделаем узкое окошко под светодиодный индикатор, которое зальем горячим клеем.
Начинаем крепить модули на плату дисплея, используя двусторонний скотч и горячий клей.
Сенсорную кнопку крепим на заднюю часть корпуса на 2 узеньких кусочка скотча, потому что прижимать сенсор к пластику нельзя. Пользоваться этим весьма удобно.
Выпиливаем еще пару окошек под порты питания и прошивки. Теперь нам надо все это собрать. Капаем 4 капли суперклея по углам корпуса, этого будет достаточно.
А вот с модулем реального времени у нас проблема, он не вмещается под крышкой.
Можно оставить и так, но это будет грустно, поэтому автор решил поставить микроверсию этого модуля с резервным питанием от ионистора.
Схема подключения для него вот такая:
Теперь все идеально. Также необходимо насверлить отверстий для обоих чувствительных мест датчика углекислого газа. Для греющихся резисторов и для датчика температуры также сверлим отверстия.
Подключаем.
Оставим станцию на столе и через пару часов посмотрим на графики.
На графике за час видим, как понижалась температура воздуха и как выветривался углекислый газ. Очень наглядно видим эффективность проветривания.
Вот такой у нас сегодня получился полезный девайс, который поможет наблюдать за климатом в помещении даже глянув на измерения один раз за сутки, потому что график позволяет буквально заглянуть в прошлое, что очень удобно и интересно.
Благодарю за внимание. До новых встреч!
Видео:

Доставка новых самоделок на почту

Получайте на почту подборку новых самоделок. Никакого спама, только полезные идеи!

*Заполняя форму вы соглашаетесь на обработку персональных данных

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

Ардуино. Метеостанция на LCD 1602 и DHT11

После сборки схемы, загрузите в микроконтроллер следующий скетч ( ссылка на скачивание архива со скетчем для метеостанции и необходимыми библиотеками). Информация с датчика DHT22 выводиться будет на монитор порта Arduino IDE и на жидкокристаллический дисплей 1602a, для отображения информации использован русский шрифт для LCD и символы (в скетче есть подробные комментарии).

#include <Wire.h> // библиотека для протокола IIC #include <LiquidCrystal_I2C.h> // подключаем библиотеку LCD IIC LiquidCrystal_I2C lcd(0x27,20,2); // присваиваем имя lcd для дисплея #include «DHT.h» // подключаем библиотеку для DHT11 DHT dht(2, DHT11); // к какому порту подключаем датчик // создаем символ градуса и присваиваем имя «gradus» byte gradus = { 0b01100,0b10010,0b10010,0b01100,0b00000,0b00000,0b00000,0b00000 }; // создаем русскую букву «П» byte P = { 0b11111,0b10001,0b10001,0b10001,0b10001,0b10001,0b10001,0b00000 }; // создаем русскую букву «У» byte Y = { 0b10001,0b10001,0b10001,0b01111,0b00001,0b00001,0b01110,0b00000 }; // создаем русскую букву «Л» byte L = { 0b00111,0b01001,0b10001,0b10001,0b10001,0b10001,0b10001,0b00000 }; // создаем русскую букву «Ж» byte ZH = { 0b10101,0b10101,0b10101,0b01110,0b10101,0b10101,0b10101,0b00000 }; // создаем русскую букву «Ь» byte znak = { 0b10000,0b10000,0b10000,0b11110,0b10001,0b10001,0b11110,0b00000 }; void setup() { Serial.begin(9600); // запуск последовательного порта lcd.init(); // инициализация LCD дисплея lcd.backlight(); // включение подсветки дисплея lcd.createChar(1, gradus); lcd.createChar(2, P); lcd.createChar(3, Y); lcd.createChar(4, L); lcd.createChar(5, ZH); lcd.createChar(6, znak); } void loop() { // если нужны точные значение, то используйте float, вместо byte byte h = dht.readHumidity(); // считываем значение температуры byte t = dht.readTemperature(); // считываем значение влажности Serial.print(«Temperature: «); Serial.println(t); // отправляем значение температуры на монитор Serial.print(«Humidity: «); Serial.println(h); // отправляем значение температуры на монитор Serial.println(» «); // пустая строка lcd.setCursor(0,0); // ставим курсор на 1 символ первой строки lcd.print(«TEM»); // используем латинские буквы lcd.print(char(2)); // выводим русскую букву «П» lcd.print(«EPAT»); // используем латинские буквы lcd.print(char(3)); // выводим русскую букву «У» lcd.print(«PA: «); // используем латинские буквы lcd.print(t); // выводим значение температуры на LCD lcd.print(char(1)); // выводим знак градуса lcd.setCursor(2,1); // ставим курсор на 3 символ второй строки lcd.print(«B»); // используем латинские буквы lcd.print(char(4)); // выводим русскую букву «Л» lcd.print(«A»); // используем латинские буквы lcd.print(char(5)); // выводим русскую букву «Ж» lcd.print(«HOCT»); // используем латинские буквы lcd.print(char(6)); // выводим русскую букву «Ь» lcd.print(«: «); // используем латинские буквы lcd.print(h); // выводим значение влажности на LCD lcd.print(«%»); // выводим знак процент delay(1000); }

Пояснения к коду:

  1. В скетче можно использовать до 8 русских букв и символов;
  2. На дисплее 1602а заменяйте буквы из кириллицы — латиницей;
  3. Скорость обновления данных замените на необходимое значение.

Если у вас есть в наличии Bluetooth модуль HC-06, то вы можете сделать его прошивку и получать данные со своей метеостанции уже на своем смартфоне. Данный модуль может обеспечивать передачу сигнала до 30 метров, что вполне достаточно для небольших квартир и частных домов. Пример такой метеостанции с датчиком DHT11 подробно рассмотрен в еще одном проекте Метеостанция на Ардуино и Андроид.