29 октября 2014 в 18:50

Ещё одна метеостанция, пошаговая видеоинструкция tutorial

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

Станция собиралась по этой схеме.


Ну а вот и сам урок


Проект созданный в процессе урока

Созданный скетч
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "DHT.h"
#include <OneWire.h>
#include "RTClib.h"
#include <BMP085.h>
BMP085  _bmp085 = BMP085();
long _bmp085P = 0;
long _bmp085T = 0;
long _bmp085A = 0;
byte _d18x2x1Addr[8] = {0x28, 0xFF, 0x11, 0x94, 0x3C, 0x4, 0x0, 0x48};
RTC_DS1307  _RTC1;
DateTime  _tRTC1;
LiquidCrystal_I2C _lcd1(0x3F, 20, 4);
int _dispTempLength1 = 0;
boolean _isNeedClearDisp1;
DHT _dht1(2, DHT22);
OneWire  _ow3(3);
String _gtv1;
String _gtv2;
String _gtv3;
String _gtv4;
String _gtv5;
String _gtv6;
bool _gtv7 = 0;
int _gtv8 = 0;
bool _gtv9 = 0;
unsigned long _d18x2x1Tti = 0UL;
float _d18x2x1O = 0.00;
unsigned long _bmp0851Tti = 0UL;
unsigned long _dht1Tti = 0UL;
float _dht1t = 0.00;
float _dht1h = 0.00;
bool _count1I = 0;
int _count1P = 0;
bool _trgs1 = 0;
bool _D1B1 = 0;
bool _tim1I = 0;
bool _tim1O = 0;
unsigned long _tim1P = 0UL;
int _disp1oldLength = 0;
int _disp2oldLength = 0;
String _mux1;
int _disp3oldLength = 0;
String _mux2;
int _disp4oldLength = 0;
String _mux3;
int _disp5oldLength = 0;
bool _bounseInput5S = 0;
bool _bounseInput5O = 0;
unsigned long _bounseInput5P = 0UL;
bool _bounseInput4S = 0;
bool _bounseInput4O = 0;
unsigned long _bounseInput4P = 0UL;
void setup()
{
  Wire.begin();
  _bmp085.init(MODE_ULTRA_HIGHRES, 300, true);
  _RTC1.begin();
  pinMode(5, INPUT);
  digitalWrite(5, HIGH);
  pinMode(4, INPUT);
  digitalWrite(4, HIGH);

  _lcd1.init();
  _lcd1.noBacklight();
  _bounseInput5O =  digitalRead(5);
  _bounseInput4O =  digitalRead(4);
  _dht1.begin();
}
void loop()
{ _tRTC1 = _RTC1.now();
  if (_isTimer(_dht1Tti, 8000)) {
    _dht1Tti = millis();
    float tempDht2;
    tempDht2 = _dht1.readTemperature();
    if (!(isnan(tempDht2))) {
      _dht1t = tempDht2;
    }
    tempDht2 = _dht1.readHumidity();
    if (!(isnan(tempDht2))) {
      _dht1h = tempDht2;
    }
  } if (_isNeedClearDisp1) {
    _lcd1.clear();
    _isNeedClearDisp1 = 0;
  }
  if (_isTimer(_bmp0851Tti, 6000)) {
    _bmp0851Tti = millis();
    _bmp085.getAltitude(&_bmp085A);
    _bmp085.getPressure(&_bmp085P);
    _bmp085.getTemperature(&_bmp085T);
  }
  bool  _bounceTmp5 =  (digitalRead (5));

  if (_bounseInput5S)
  {
    if (millis() >= (_bounseInput5P + 40))
    {
      _bounseInput5O = _bounceTmp5;
      _bounseInput5S = 0;
    }
  }
  else
  {
    if (_bounceTmp5 != _bounseInput5O )
    {
      _bounseInput5S = 1;
      _bounseInput5P = millis();
    }
  }
  bool  _bounceTmp4 =  (digitalRead (4));

  if (_bounseInput4S)
  {
    if (millis() >= (_bounseInput4P + 40))
    {
      _bounseInput4O = _bounceTmp4;
      _bounseInput4S = 0;
    }
  }
  else
  {
    if (_bounceTmp4 != _bounseInput4O )
    {
      _bounseInput4S = 1;
      _bounseInput4P = millis();
    }
  }



  if (_isTimer(_d18x2x1Tti, 5000)) {
    _d18x2x1Tti = millis();
    _d18x2x1O =  _readDS18_ow3(_d18x2x1Addr, 0);
  }
  _gtv1 = ((String("T-")) + (( _floatToStringWitRaz((_d18x2x1O), 2))) + (String("C")));
  _gtv2 = ((String("T-")) + (( _floatToStringWitRaz((_bmp085T) / (10.00), 1))) + (String("C")));
  _gtv3 = ((String("P-")) + ((String((_bmp085P) / (1000)))) + (String("kPa")));
  _gtv4 = ((String("A")) + ((String(_bmp085A))) + (String("cm")));
  _gtv5 = ((String("T-")) + (( _floatToStringWitRaz(_dht1t, 2))) + (String("C")));
  _gtv6 = ((String("H-")) + (( _floatToStringWitRaz(_dht1h, 2))) + (String("%")));

  if (!(_bounseInput5O))
  {
    if (! _count1I)
    {
      _count1P = _count1P + 1;
      _count1I = 1;
    }
  }
  else
  {
    _count1I = 0;
  }
  if (_count1P < 0 ) _count1P = 0;
  if (_gtv7) _count1P = 0;
  _gtv7 =  _count1P  >=  3;
  _gtv8 = _count1P;
  if ( (!(_bounseInput4O)) || (!(_bounseInput5O)) ) _trgs1 = 1;
  if (_gtv9) _trgs1 = 0;
  if ( (_trgs1) && (_bounseInput5O) )
  {
    if (_tim1I)
    {
      if ( _isTimer(_tim1P, 20000)) _tim1O = 1;
    }
    else
    {
      _tim1I = 1;
      _tim1P = millis();
    }
  }
  else
  {
    _tim1O = 0;
    _tim1I = 0;
  }
  if (_trgs1) {
    if (! _D1B1) {
      _lcd1.backlight();
      _D1B1 = 1;
    }
  } else {
    if (_D1B1) {
      _lcd1.noBacklight();
      _D1B1 = 0;
    }
  }
  _gtv9 = _tim1O;
  if (1) {
    _dispTempLength1 = (((((String((_tRTC1.hour())))) + (String(":")) + ((String((_tRTC1.minute())))) + (String(":")) + ((String((_tRTC1.second()))))))).length();
    if (_disp1oldLength > _dispTempLength1) {
      _isNeedClearDisp1 = 1;
    }
    _disp1oldLength = _dispTempLength1;
    _lcd1.setCursor(0, 0);
    _lcd1.print(((((String((_tRTC1.hour())))) + (String(":")) + ((String((_tRTC1.minute())))) + (String(":")) + ((String((_tRTC1.second())))))));
  } else {
    if (_disp1oldLength > 0) {
      _isNeedClearDisp1 = 1;
      _disp1oldLength = 0;
    }
  }
  if (1) {
    _dispTempLength1 = (((((String((_tRTC1.day())))) + (String("-")) + ((String((_tRTC1.month())))) + (String("-")) + ((String((_tRTC1.year()))))))).length();
    if (_disp2oldLength > _dispTempLength1) {
      _isNeedClearDisp1 = 1;
    }
    _disp2oldLength = _dispTempLength1;
    _lcd1.setCursor(9, 0);
    _lcd1.print(((((String((_tRTC1.day())))) + (String("-")) + ((String((_tRTC1.month())))) + (String("-")) + ((String((_tRTC1.year())))))));
  } else {
    if (_disp2oldLength > 0) {
      _isNeedClearDisp1 = 1;
      _disp2oldLength = 0;
    }
  }
  if ((_gtv8) == 0) {
    _mux1 = String("DS18B2");
  }
  if ((_gtv8) == 1) {
    _mux1 = String("Bmp-085");
  }
  if ((_gtv8) == 2) {
    _mux1 = String("DHT-22");
  }
  if (1) {
    _dispTempLength1 = ((_mux1)).length();
    if (_disp3oldLength > _dispTempLength1) {
      _isNeedClearDisp1 = 1;
    }
    _disp3oldLength = _dispTempLength1;
    _lcd1.setCursor(int((20 - _dispTempLength1) / 2), 1);
    _lcd1.print((_mux1));
  } else {
    if (_disp3oldLength > 0) {
      _isNeedClearDisp1 = 1;
      _disp3oldLength = 0;
    }
  }
  if ((_gtv8) == 0) {
    _mux2 = _gtv1;
  }
  if ((_gtv8) == 1) {
    _mux2 = _gtv2;
  }
  if ((_gtv8) == 2) {
    _mux2 = _gtv5;
  }
  if (1) {
    _dispTempLength1 = ((_mux2)).length();
    if (_disp4oldLength > _dispTempLength1) {
      _isNeedClearDisp1 = 1;
    }
    _disp4oldLength = _dispTempLength1;
    _lcd1.setCursor(0, 2);
    _lcd1.print((_mux2));
  } else {
    if (_disp4oldLength > 0) {
      _isNeedClearDisp1 = 1;
      _disp4oldLength = 0;
    }
  }
  if ((_gtv8) == 0) {
    _mux3 = String("-----");
  }
  if ((_gtv8) == 1) {
    _mux3 = ((_gtv3) + (String("/")) + (_gtv4));
  }
  if ((_gtv8) == 2) {
    _mux3 = _gtv6;
  }
  if (1) {
    _dispTempLength1 = ((_mux3)).length();
    if (_disp5oldLength > _dispTempLength1) {
      _isNeedClearDisp1 = 1;
    }
    _disp5oldLength = _dispTempLength1;
    _lcd1.setCursor(0, 3);
    _lcd1.print((_mux3));
  } else {
    if (_disp5oldLength > 0) {
      _isNeedClearDisp1 = 1;
      _disp5oldLength = 0;
    }
  }



}
bool _isTimer(unsigned long startTime, unsigned long period )
{
  unsigned long endTime;
  endTime = startTime + period;
  return (millis() >= endTime);
}
String  _floatToStringWitRaz(float value, int raz)
{
  float tv;
  int ti = int(value);
  String ts = String(ti);
  if (raz == 0) {
    return ts;
  }
  ts += ".";
  float tf = abs(value - ti);
  for (int i = 1; i <= raz; i++ )
  {
    tv = tf * 10;
    ti = int(tv);
    ts += String(ti);
    tf = (tv - ti);
  }
  return ts;
}
float _convertDS18x2xData(byte type_s, byte data[12])
{
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s)
  {
    raw = raw << 3;
    if (data[7] == 0x10) {
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  }
  else
  {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;   else if (cfg == 0x20) raw = raw & ~3;  else if (cfg == 0x40) raw = raw & ~1;
  }
  return  (float)raw / 16.0;
}
float _readDS18_ow3(byte addr[8], byte type_s)
{ byte data[12];
  byte i;
  _ow3.reset();
  _ow3.select(addr);
  _ow3.write(0xBE);
  for ( i = 0; i < 9; i++) {
    data[i] = _ow3.read();
  }
  _ow3.reset();
  _ow3.select(addr);
  _ow3.write(0x44, 1);
  return _convertDS18x2xData(type_s, data);
}



PS. В следующем видео уроке планируется подключение SD картридера для логгирования показаний датчиков.
Автор: @totuin
FLProg
рейтинг 27,13
Графическая среда программирования Arduino

Комментарии (20)

  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      У меня экранное меню. При нажатии на кнопку переключаются показания. В каждом меню показания всех параметров с одного из датчиков. Так что можно просмотреть температуры на всех датчиках. В конце урока я все показываю.
  • 0
    «Открываем нашу программу...» — а можно поподробнее?
    lad — это LD?
    • 0
      Всеми горячо любимое НЛО очень трепетно относится к публикации ссылок, и я один раз уже на этом обжёгся. Программа называется FLProg. Яндекс о ней знает. И да LAD — это язык LD. Но чаще его все таки называют LAD.
  • 0
    Какая максимальная длина проводов до датчиков? Сами датчики можно использовать «outdoor»? Как снимать показания удаленно, например по сети?
    • 0
      Извините что долго не отвечал, у меня ночные смены, только пришёл на работу.
      Насчет датчиков:
      DS18B20 у меня влагозащищенного исполнения, так что использовать его на улице без проблем. DHT-22 я пробовал на три дня оставить за окном. Развернул спиной наверх, что бы щели снегом не заносило. Пока полет нормальный. На улице снег и -13. Не знаю что будет дальше, все зависит от аккуратности китайцев у которых я его купил. BMP-85 на улицу не выкидывал. Подключал простым сетевым кабелем. Где то на просторах интернета вычитал схему. В каждой паре проводов цветная жила — сигнальная, белая — GND. Длинна получилась около семи метров. Все работает нормально. Ну в принципе там скорость обмена небольшая, да и токи копеечные. Так что я думаю что можно и значительно длиннее использовать. Если честно мне не нравится точность этих датчиков. Разница между показаниями DS18B20 и DHT-22 ровно 1 градус. Мне здесь не чем их откалибровать, поэтому я просто от одного отнял полградуса к другому прибавил. В принципе если есть возможность проверить датчик в паре с калиброванным, то можно потом математикой привести показания в норму. BMP-085 почему то реально греется, особенно при попытке подключить его на 5V. Соответственно температуру показывает не окружающего воздуха а самого себя.Хотя возможно мне просто датчик такой попался. Ebay это такая лотерея.
      По поводу сети, пока реализации в проекте нет, но в ближайшие месяцы появится. Сейчас это основная задача. Ehternet и WIFI шилды уже пришли, давно уже лежат RF платки, постараюсь реализовать все виды коммуникаций.
      • 0
        Мне здесь не чем их откалибровать,

        Вода, в которой тает лед, имеет температуру 0 градусов Цельсия. Кипящая вода имеет температуру примерно 100 градусов Цельсия, (зависит от давления). Дерзайте!
        • 0
          Ну ладно с DS18B20 ещё можно так поизголятся. А как Вы представляете засовывание DHT-22 в кипящий чайник ). Да и нет такой задачи. Моя основная задача была дать пользователям программы представление о принципах работы с сенсорами. Ну а как они будут их реализовывать — это уже ограниченно только их фантазией.
          • 0
            /me задумался, выдерживает ли латекс 100 градусов цельсия… =)

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

            Может это и не принципиально, но перфекционист во мне негодует.
            • 0
              Конечно можно, я просто пошутил
      • +3
        У меня на текущий момент уже как больше года DHT-22 живет на улице.
        Ранее жил в монтажной коробке обычной с вент. отверстиями.
        Однако, недавно решил все сделать по нормальному.
        Результат ниже.
        • +1
          Кстати очень интересное и оригинальное применение тарелочкам. Я даже не сразу вспомнил что это такое. В детстве нам в столовой на таких желе давали. Извините — нахлынуло
      • 0
        А можно попросить вас добавить в ближайшее время в проект вывод показаний датчиков на порт I/O?
        Что-бы можно было подключить как к любому роутеру по консольному порту, так и передать по радио в прозрачном режиме.
        Спасибо!
        • 0
          Вот сейчас занимаюсь подключением по I2C недорогого датчика INA219, который меряет ток заряда/разряда батареи, подключенной к солнечной панели. Было-бы очень классно его так-же добавить в проект. Готов оказать посильную финансовую помощь, выслать датчики и т.д.
          • 0
            Без проблем. Я стараюсь добавить в проект все железо которое мне присылают. Если конечно это в принципе возможно. Судя по описанию с Вашим датчиком проблем не будет. Пока что я не смог подключить только присланную мне VGA камеру, хотя она и заявлена как поддерживаемая Arduino.
            По поводу вывода на I/O. На сайте в разделе документация в видеоуроках есть урок «Передача данных через Comm порт». Посмотрите его, там все понятно. Ссылку давать не буду — НЛО не дремлет.
            • +2
              Хмм, я как-бы полный ноль в Ардуинах, все больше на роутерах делать приходилось, буду благодарен (думаю, не только я) за добавление в реальные примеры. Хотелось-бы не городить зоопарк, а все датчики в моем случае поставить на I2C шину.

              Собирал свой джентльменский набор, относительно бюджетно, все на I2C, может кому-то пригодится:
              AM2321 — датчик влажности и температуры
              BH1750 — датчик освещенности (китайский модуль GY-302)
              BMP085 — датчик давления и температуры (китайский модуль GY-65), он у вас уже есть
              INA219 — датчик тока и напряжения
              LM75 — простой датчик температуры
              DS1621 — еще один простой датчик температуры.
              PCF8591 — простейший АЦП/ЦАП для каких-то аналоговых датчиков (китайский модуль YL-40)
              PCF8574 — I/O для управления реле, датчиков «сухой контакт» и т.д.

              Хочу потом еще настроить данные отправлять, как с роутера, но уже с Ардуины и рисовать красивые графики, как тут OnLine мониторинг параметров автономной энергосистемы по радиоканалу

              P.S. Программу видел, скачал, разбираюсь. Большое спасибо!
              • 0
                Конечно повесить все на одну шину I2C, это все очень красиво, но есть некоторые моменты. Как вы понимаете опрос датчиков с последовательным интерфейсом, это не мгновенно. На это требуется время. Например опрос DHT-22 занимает почти секунду, опрос DS18B20 — полсекунды где то. Ардуинка не многозадачная, соответственно на это время останавливается выполнение остальной программы. Часто это критично. Например я с этим столкнулся при организации динамического отображения на семи сегментных индикаторах. На время опроса датчика индикация соответственно пропадает. Получается не очень приятное моргание.В таких случаях наверное поможет разнесенная система. Какая ни будь дешевенькая микра читает датчики, медленно и верно и отправляет данные по ком — порту другой. Ну а та уже занимается вопросами отображения, управления и т. д. При текущй цене на ардуинку можно сделать вообще идеальный вариант. Когда для каждой задачи (отображение, ввод данных пользователя, чтение датчиков, управление внешними устройствами) будет отвечать свой контроллер. Ну и в качестве центрального мозга выступает либо ПК либо Мега
                • 0
                  Спасибо за ответ. Да, я все это понимаю и меня именно интересует Ардуина как устройство съема данных, их накопления на время съема и выброс полученных параметров на I/O. А дисплей и сервис это можно второй чип подключить.
                  В любом случае спасибо. Буду следить за вашими дальнейшими разработками и публикациями.
                  Напишите пожалуйста мне в личку для дальнейших дискуссий, мне к сожалению, карма не позволяет.
                  • 0
                    Сегодня если получится, я напишу пост с еще одним видео уроком, описывающим прокачку метеостанции возможностью логгирования данных на SD карту, и сброса файла на компорт
  • 0
    del. Ошибся веткой.

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

Самое читаемое Разное