Моя метеостанция на DHT22 честно отчитывалась температурой и влажностью, но перед ливнем молчала: влажность уже зашкаливала, а предчувствия дождя в доме всё не было. Погоду предчувствует давление — оно падает за несколько часов до фронта, и это измеримо: перепад в 10 гПа за полдня почти всегда приносит осадки. DHT давление не видит в принципе — у него другой физики нет, температуру и влажность он тянет из одной точки, и оба показания от этого честнее не становятся.
Вторая причина поставить барометр — высота. BMP280 замечает смену этажа: три метра это около 0,4 гПа, а собственный шум датчика в высоком разрешении — порядка 0,16 Па, сантиметры воздуха. Лифт на девятый этаж — 27 метров перепада, и датчик покажет их без всякого GPS. В этом уроке подключим модуль по I2C, разберёмся с адресами, посчитаем высоту честной формулой — сначала библиотекой Adafruit_BMP280, потом на голом Wire в симуляторе.
Пара слов про единицы, чтобы сводка погоды и датчик говорили на одном языке. Датчик отдаёт паскали, библиотеки удобнее в гектопаскалях, а метеосводка у нас — в миллиметрах ртутного столба: 1013,25 гПа — это те самые 760 мм, а миллиметр переводится в гектопаскали умножением на 1,333. Я держу в скетче гектопаскали: и для формулы высоты удобнее, и с прогнозом погоды сравнивать можно на глаз, без калькулятора.
Четыре провода и адрес, который любит путаться
Схема классическая для шины: VCC к 5 В на модулях со стабилизатором (голый чип хочет 1,71–3,6 В — не испытывайте его на прочность), GND, SDA на A4, SCL на A5. Перед подачей питания я пробегаю глазами распиновку модуля: у разных продавцов подписи выводов пляшут, и SCL на краю платы встречается чаще, чем хочется. Адрес — тот, что мы ловили сканером: 0x76 или 0x77, выбирает его вывод SDO. На большинстве дешёвых модулей SDO притянут к земле — датчик живёт на 0x76; у плат Adafruit обычно 0x77. Если модуль молчит, сканер I2C-адресов покажет, на какой двери он стучит на самом деле.
Ток у датчика смешной: единицы микроампер при измерении раз в секунду — Bosch заявляет около 2,7 мкА в типовом режиме. Метеостанция на батарейках тратит больше на дисплей и радиоканал, чем на сам датчик. И удобство для макетки: BMP280 встанет на ту же шину, что и экран из первого урока раздела, — пины A4 и A5 по-прежнему одни на всех.
Про подтяжки и провода — по краткой памяти первого урока: на модуле уже стоят резисторы 4,7 кОм, добавлять сверху не надо, а провода до полуметра при 100 кГц работают без вопросов. Мои dupont-проводки на длине больше метра уже подваливали — датчик то отвечал, то нет; переставил его на соседний ряд макетки поближе к мастеру — и всё встало на место. Правило простое: чем капризнее модуль, тем ближе к Uno.
| Вызов | Что возвращает | На что смотреть |
|---|---|---|
| bmp.begin(0x76) | true, если датчик ответил | адрес обязан совпасть с реальным; вернул false — запускайте сканер |
| bmp.readTemperature() | температуру в °C | пригодна и для контроля корпуса — перегрев тащит давление за собой |
| bmp.readPressure() | давление в паскалях | 101325 Па = 1013,25 гПа; делите на 100 для гектопаскалей |
| bmp.readAltitude(1013.25) | высоту в метрах | точность упирается в p0: погодный ход давления даёт до ±240 метров |
Библиотека ставится через менеджер: Скетч → Подключить библиотеку → Управлять библиотеками, поиск «Adafruit BMP280» — менеджер сам подтянет Adafruit Unified Sensor и BusIO. Под капотом там всё, что мы уже умеем руками: запись конфигурации в 0xF4 с битовыми полями из урока про datasheet, чтение шести байтов с 0xF7 и сборка 20-бит значений, как в уроке про битовые операции. После ручной работы по предыдущим двум урокам библиотека читается как вежливый перевод: всё то же самое, только человеческим языком.
Единственное, что за вечер руками не собрать честно, — пересчёт сырых значений в паскали. BMP280 требует формул компенсации с калибровочными коэффициентами из регистров 0x88–0xA1, и коэффициенты у каждого экземпляра свои, заводские. Библиотека читает их при begin() и прячет под readPressure() — за это я и терплю три зависимости от Adafruit.
У чипа есть и второй интерфейс — SPI на четыре провода, и выбирается он тем же выводом, что и адрес: CSB, притянутый к питанию, включает I2C-режим, а по отдельному выводу — SPI. На макетке я всегда выбираю I2C: два пина вместо четырёх, и остаются свободными цифровые линии. SPI оправдан, когда датчик опрашивают сотни раз в секунду — например, в дроны, где высоту надо знать каждый кадр. Для метеостанции и лифта сотни килогерц шины хватает с огромным запасом.
#include <Wire.h>#include <Adafruit_BMP280.h> Adafruit_BMP280 bmp; // шина I2C, адрес задаём в begin() #define SEALEVELPRESSURE_HPA 1013.25 // стандартная атмосфера для высоты void setup() { Serial.begin(9600); Serial.println("BMP280: метеостанция"); if (!bmp.begin(0x76)) { // у Adafruit-плат обычно 0x77 Serial.println("Датчик молчит: проверьте адрес и провода"); while (true) delay(10); }} void loop() { double t = bmp.readTemperature(); // градусы Цельсия double p = bmp.readPressure() / 100.0; // Па -> гПа double h = bmp.readAltitude(SEALEVELPRESSURE_HPA); // метры Serial.print("t="); Serial.println(t, 1); Serial.print("p="); Serial.println(p, 1); Serial.print("h="); Serial.println(h, 1); delay(1000);}Что видно в симуляторе: сначала уходит байт конфигурации 0b00100111 — температура ×1, давление ×1, режим normal, всё по битовой карте из datasheet. Потом мастер пишет адрес 0xF7 и просит шесть байтов: давление идёт первым, температура следом. Заглушка отдаёт по 42 на каждый байт, и сборка честно даёт rawP = 42 на 4096 плюс 42 на 16 плюс 2 — это 172706. На живом датчике то же число живое: дышит от погоды, подпрыгивает в лифте, проседает на этаж выше.
Формула высоты в симе настоящая: h = 44330 × (1 − (p/p0) в степени 0,1903). Подставьте 1005 гПа при p0 = 1013,25 — получите около 69 метров; 1020 гПа дадут минус 56, а 1000 гПа — примерно 111. Быстрая проверка в уме: у земли гектопаскаль стоит около 8 метров, и формула с этим сходится. Именно эту математику прячет readAltitude() — только на живой плате давление сначала проходит компенсацию заводской калибровкой.
Почему в симе нет печати давления в паскалях: без заводских коэффициентов сырой отсчёт в паскали не пересчитать честно — любое число было бы выдумкой, и я не хочу учить вас выдумывать. Поэтому сим показывает сырое 20-бит значение и честную формулу высоты от подставленного давления, а живой датчик в библиотеке переведёт сырое в паскали сам. Это разделение — сырые байты у нас, физика у калибровки — честная модель того, что происходит на настоящей плате.
Высота, которая плывёт
readAltitude(1013.25) — это высота над условной стандартной атмосферой, а не над вашим двором. Погодный ход давления за неделю — 20–30 гПа, и формула переведёт их в 160–240 метров кажущегося подъёма без единого шага пешком. Лечу я это в два шага. Первый: p0 калибрую по известной точке — дошёл до моря, обнулил показание, записал актуальное давление и подставляю его вместо 1013,25. Второй: усредняю — скользящее окно на 8–16 отсчётов глушит дрожь последней цифры, а опрос раз в секунду для метеостанции и так избыточен.
Вторая причина прыжков — не погодная: датчик греется. Модуль, прижатый к стабилизатору или спрятанный в наглухой корпус, живёт в собственной микропогоде, и давление плывёт вместе с ней. Сажайте датчик на край макетки, подальше от горячих деталей — график в Serial Plotter покажет дрейф нагляднее любых рассуждений. А когда захочется к давлению добавить влажность — это уже BME280: сравнение родственных датчиков я делал в разделе про DHT.
Мой любимый тест — лифт. Я посадил BMP280 на Nano с повербанком, обнулил высоту на первом этаже и поехал на девятый: показания уползли на 24–27 метров — восемь пролётов по три метра. Зато на одной высоте, но при смене погоды, те же показания за неделю уехали на десятки метров — и это лучший способ прочувствовать разницу между высотой и давлением: датчик честно меряет второе, а первое мы получаем только вместе с откалиброванным p0.
- 1. Сколько сигнальных проводов нужно BMP280 в режиме I2C?
- 2. На большинстве дешёвых модулей BMP280 адрес…
- 3. Что возвращает readPressure()?
- 4. Давление упало на 10 гПа, вы никуда не ехали. readAltitude покажет…
- 5. Почему rawP в симуляторе не меняется?
- Схема: VCC, GND, SDA → A4, SCL → A5; адрес 0x76 или 0x77 выбирает вывод SDO
- Adafruit_BMP280: begin(0x76), readTemperature() в °C, readPressure() в паскалях, readAltitude(p0) в метрах
- Под капотом — голый Wire: конфиг в 0xF4, шесть байтов с 0xF7, пересчёт через заводскую калибровку 0x88–0xA1
- Высота: h = 44330 × (1 − (p/p0)^0,1903); у земли 1 гПа стоит около 8 метров
- Погода двигает давление на 20–30 гПа = до 240 метров кажущихся: калибруйте p0 и усредняйте отсчёты
Частые вопросы по теме урока
- Сколько сигнальных проводов нужно BMP280 в режиме I2C?
- Питание и земля не считаются: SDA на A4, SCL на A5. Четыре сигнальных — это SPI, второй режим того же чипа. Два: SDA и SCL
- На большинстве дешёвых модулей BMP280 адрес…
- SDO притянут к земле — 0x76. У Adafruit обычно 0x77, а 0x68 занята часами DS3231. 0x76
- Что возвращает readPressure()?
- Паскали: 101325 Па = 1013,25 гПа. Делите на 100 — получаете гектопаскали для формулы высоты, и сводка погоды становится сравнимой с датчиком на глаз. Паскали
- Давление упало на 10 гПа, вы никуда не ехали. readAltitude покажет…
- У земли гектопаскаль стоит около 8 метров: падение давления формула честно переведёт в кажущийся подъём. Лечится калибровкой p0 по известной точке — выходил к морю и обнулял показание. Плюс 80 метров
- Почему rawP в симуляторе не меняется?
- В симуляторе датчик-заглушка: на каждый запрошенный байт она отвечает 42, а движок честно собирает из них 172706. На живом BMP280 те же регистры отдают живые измерения. Заглушка отдаёт фиксированные байты по 42