Моя первая комнатная метеостанция полгода прожила на стене и ни разу не ответила на главный вопрос осени: брать ли зонт. Температуру она показывала, влажность показывала, а про давление говорить было нечем — DHT22 его физически не чувствует. В ноябре я угадывал дождь по колену, глядя в темнеющее окно, при том что в ящике лежал модуль BMP280 за двести рублей, умеющий ровно то, чего станции не хватало.
За один вечер BMP280 лёг на ту же макетку, станция выросла из термогигрометра в барометр, бонусом появился второй термометр — который тут же поспорил с первым на целый градус, об этом споре ниже. В уроке разберём, как разделить труд между двумя сенсорами, посадить их на одну шину I2C и собрать единый кадр данных, из которого потом вырастут и лог, и прогноз по тренду давления.
Разделение труда: что меряет каждый
DHT22 закрывает влажность: у BMP280 влажностного сенсора нет вообще, и никакие формулы его не заменят. Взамен BMP280 приносит атмосферное давление — от 300 до 1100 гектопаскалей с абсолютной точностью около ±1 гПа и разрешением до 0,16 Па — и собственный термометр. Для быта полезно помнить пересчёт: 1 гПа = 0,75 мм рт. ст., так что привычные 747 миллиметров — это 996 гПа; гектопаскаль и миллибар — одно и то же, поэтому старые справочники не врут. Норма для средней полосы — 730–780 мм; всё, что проседает ниже 735, на моей даче означает смену погоды в ближайшие сутки.
Кто из двух термометров главный — вопрос не точности, а места измерения. BMP280 меряет температуру собственного кристалла: чип подогревает себя рабочим током, и показание уползает на 1–2 градуса выше воздуха; чем больше рядом с платой греющихся соседей, тем сильнее. DHT22 видит воздух у решётки корпуса, но раз в две секунды и со своей погрешностью. Моё правило: воздух — ряд от DHT22, давление — ряд от BMP280, а второй термометр держим как контрольный: если ряды внезапно разошлись сильнее обычного — это не метеорология, это диагностика.
| Параметр | DHT22 | BMP280 |
|---|---|---|
| Что меряет | температуру и влажность | давление и температуру кристалла |
| Диапазон | −40…+80 °C, 0–100 % | 300–1100 гПа, −40…+85 °C |
| Точность | ±0,5 °C, ±2 % по влажности | ±1 гПа, температура гуляет от самонагрева |
| Интерфейс | однопроводной протокол DHT | I2C, адрес 0x76 или 0x77 |
| Опрос | раз в 2 секунды | хоть 10 раз в секунду |
| Цена модуля | ≈350 ₽ | ≈200 ₽ |
Два устройства на двух проводах
BMP280 садится на шину I2C: SDA на A4, SCL на A5 — как устроена шина и зачем общая земля, мы проходили в уроке про два провода I2C. Единственная развилка — адрес: при SDO, притянутом к земле, модуль отвечает на 0x76, при подтяжке к питанию — на 0x77. Большинство китайских модулей из коробки сидят на 0x76; если не отвечает ни один вариант — сканер шины I2C покажет фактический адрес за минуту.
С питанием аккуратнее, чем с DHT: чип рассчитан на 3,3 В, и голый сенсор без обвязки на пятивольтовой шине выгорает. Модули со стабилизатором на плате честно принимают 5 В — их видно по крупной микросхеме-стабилизатору рядом с разъёмом. LCD-дисплей из наших уроков живёт на той же шине без конфликтов: у каждого устройства свой адрес, шина не путается, лишь бы все три устройства сидели на одной паре SDA и SCL и на одной земле.
#include "DHT.h"#include "Adafruit_BMP280.h" DHT dht(2, DHT22);Adafruit_BMP280 bmp; unsigned long lastPoll = 0;unsigned long trendMs = 0; // метка прошлого замера для трендаfloat pTrend = 0; // давление на той метке void setup() { Serial.begin(9600); dht.begin(); trendMs = millis(); if (!bmp.begin(0x76)) { // часть модулей отвечает на 0x77 Serial.println("BMP280: не найден, прогоните сканер I2C"); } pTrend = bmp.readPressure() / 100.0;} void loop() { if (millis() - lastPoll >= 2000) { lastPoll = millis(); float t = dht.readTemperature(); float h = dht.readHumidity(); float p = bmp.readPressure() / 100.0; // Па -> гПа float pmm = p * 0.750062; // гПа -> мм рт. ст. if (millis() - trendMs >= 10800000UL) { // тренд раз в три часа trendMs = millis(); pTrend = p; } Serial.print("t="); Serial.print(t, 1); Serial.print(" h="); Serial.print(h, 0); Serial.print(" p="); Serial.print(p, 1); Serial.print(" pmm="); Serial.print(pmm, 1); Serial.print(" dp="); Serial.println(p - pTrend, 2); }}Здесь три строки, на которых всё держится. bmp.begin(0x76) инициализирует сенсор по адресу; вернулся false — значит, адрес другой, питание просело или SDA и SCL перепутаны местами. readPressure() возвращает паскали: примерно сто тысяч в нормальный день, поэтому делим на сто и получаем гектопаскали, а множитель 0,750062 переводит их в миллиметры ртутного столба для людей. Пары имя=значение в одной строке — старая договорённость раздела: такой кадр без переделок читает Serial Plotter.
Колонка dp= — тренд, разница с показанием трёхчасовой давности. В учебном скетче она честная, но скудная: одна метка на 10800000 миллисекунд, и первые три часа после включения тренд считается от старта. Для настоящего прогноза нужен суточный ряд — его пишут на SD-карту, а к кадру добавляют время из RTC. Мой порог для средней полосы: минус три гПа за три часа — с вероятностью сильно выше половины к вечеру зарядит.
Проверить барометр — дело одного вечера, и я советую сделать это до того, как станция переедет на стену. Откройте сайт ближайшей метеостанции и сравните давление: ваше показание будет отличаться на две-пять гектопаскалей, и это не поломка, а разница высот между вашим этажом и их метеобоксом. Запишите смещение один раз — дальше оно будет вашим вечным паспортом сборки, и упавшее на десятку давление вы заметите глазами, без таблиц. Если смещение плывёт день ото дня — ищите просадку питания или греющийся рядом с платой блок, а не виноватого в датчике.
И последнее про место установки: барометр любит тишину и покой. Сквозняк от форточки, близость радиатора и прямое солнце на корпус дают те самые два-три гектопаскаля плавающего смещения, которые потом разбивают прогноз. Я прибиваю станцию к внутренней стене коридора, в метре от окон и батареи — показания оттуда совпадают с районной метеостанцией лучше, чем с соседским барометром за окном.
Прогноз по тренду: чего стоит колонка dp
Барометр прогнозирует не погоду, а её смену — и это ровно то, чего термогигрометру не хватало. Мой рабочий алгоритм прост: колонка dp= уезжает в лог за неделю, взгляд на кривую — и собственные пороги. Падение на три гПа за три часа в моей широте почти всегда приносит дождь в течение ночи, рост на два — сушит после. За два года наблюдений я ни разу не пожалел о потраченном на этот журнал вечере: когда синоптики обещают ливень, а колонка dp= стоит в нуле, я спокойно выхожу без зонта — и почти всегда не промокаю. Точные числа у каждого свои: от высоты местности, этажа и того, как часто открывается окно рядом с датчиком.
Высота — главный источник систематической лжи: на подъём давление падает примерно на 1,2 гПа каждые 10 метров, поэтому девятый этаж постоянно живёт на 3–4 гПа ниже первого. Библиотека умеет вычислять высоту через readAltitude по давлению на уровне моря — для комнаты это баловство, для дрона рабочий инструмент. Куда вывести кадр дальше — подскажут уроки про метеостанцию с меню на LCD и про точку росы: колонки dp и ah встанут в существующий формат без переделки.
- 1. Что меряет BMP280, чего нет у DHT22?
- 2. Какой адрес у BMP280, если вывод SDO притянут к земле?
- 3. Что возвращает метод readPressure() библиотеки Adafruit?
- 4. Почему термометр BMP280 показывает выше температуры воздуха?
- 5. Давление упало на 3 гПа за три часа. О чём это говорит?
- DHT22 закрывает влажность, BMP280 — давление и запасной термометр: по одиночке метеостанция неполная.
- SDO на земле — адрес 0x76, на питании — 0x77; сомневаетесь — сканер шины I2C отвечает за минуту.
- readPressure() отдаёт паскали: делите на 100 ради гПа, умножайте на 0,750062 ради миллиметров для людей.
- Термометры спорят на градус — норма: BMP280 греет сам себя, поэтому воздух читает DHT22, давление — BMP280.
- Тренд dp= важнее абсолютного давления: минус три гПа за три часа обещает погодную смену громче любых формул.
Частые вопросы по теме урока
- Что меряет BMP280, чего нет у DHT22?
- Давление — главный козырь BMP300/BMP280: от 300 до 1100 гПа с точностью около ±1 гПа. Влажности у BMP280 нет вовсе — за ней к DHT22. Атмосферное давление
- Какой адрес у BMP280, если вывод SDO притянут к земле?
- SDO на земле — 0x76, SDO на питании — 0x77. Большинство китайских модулей из коробки отвечают на 0x76; сомнения лечит сканер шины I2C. 0x76
- Что возвращает метод readPressure() библиотеки Adafruit?
- readPressure() отдаёт паскали (около 101325). Для гПа делите на 100, для мм рт. ст. умножаете гПа на 0,750062. Паскали
- Почему термометр BMP280 показывает выше температуры воздуха?
- BMP280 меряет температуру своего кристалла, а не воздуха: самонагрев +1–2 °C — норма. Поэтому воздух доверяют DHT22, а BMP280 — давление. Кристалл подогревает себя рабочим током на 1–2 градуса
- Давление упало на 3 гПа за три часа. О чём это говорит?
- Резкое падение давления — классический предвестник дождя, рост — к прояснению. Медленный дрейф в десятые гПа действительно шум, три гПа за три часа — сигнал. К смене погоды, скорее к дождю