BME280 и Arduino: температура, влажность, давление и высота (отличия от BMP280)
Как подключить BME280 или BMP280 к Arduino: I2C-адрес 0x76/0x77, библиотека Adafruit, высота по давлению на уровне моря, предупреждение о 3,3 V, метеостанция на ESP32 и код для Pico.
BME280 — цифровой датчик окружающей среды от Bosch, который измеряет температуру, относительную влажность и атмосферное давление одним крошечным чипом. Для работы с Arduino нужны всего четыре провода (VCC, GND, SDA, SCL) и библиотека Adafruit BME280; несколько строк кода выводят в монитор порта показания в °C, % и гПа (hPa). Поскольку датчик измеряет давление, он может вычислить и высоту твоего места над уровнем моря. Его «брат» BMP280 выглядит почти так же, но не измеряет влажность: он даёт только температуру и давление.
В этом руководстве ты узнаешь, чем отличаются два датчика, почему I2C-адрес бывает то 0x76, то 0x77, как подключить их к Arduino Uno, ESP32 и Raspberry Pi Pico, как работает формула высоты и как выбрать правильное давление на уровне моря. Затем ты соберёшь мини-метеостанцию на ESP32, которая открывается с телефона, запустишь на Pico драйвер на MicroPython без библиотек и увидишь, как один скетч выявляет очень распространённую проблему «BMP280, проданный как BME280».

Что такое BME280 и как он работает?
Внутри BME280 три чувствительных элемента. Датчик давления на основе пьезорезистивного эффекта измеряет, насколько прогибается тонкая кремниевая мембрана под давлением воздуха. Датчик влажности — это полимерный слой, ёмкость которого меняется по мере того, как он впитывает влагу из воздуха. Датчик температуры сообщает температуру окружающей среды и также используется для коррекции двух других измерений. Каждый чип индивидуально калибруется на заводе, а коэффициенты записываются в его внутреннюю память; при запуске библиотека считывает их и переводит сырые числа в реальные единицы по формулам из даташита. Маленькое отверстие в металлической крышке пропускает воздух к датчику, поэтому никогда не закрывай его скотчем или клеем.
| Характеристика | BME280 | BMP280 |
|---|---|---|
| Что измеряет | Температура, влажность, давление | Температура, давление |
| Температура | -40…+85 °C, ±1 °C (±0,5 °C при 25 °C) | -40…+85 °C, ±1 °C (±0,5 °C при 25 °C) |
| Относительная влажность | 0–100%, ±3% | Нет |
| Диапазон давления | 300–1100 гПа | 300–1100 гПа |
| Точность давления | Абсолютная ±1 гПа, относительная ±0,12 гПа (≈ ±1 м) | Абсолютная ±1 гПа, относительная ±0,12 гПа (≈ ±1 м) |
| Напряжение питания чипа | 1,71–3,6 V | 1,71–3,6 V |
| Ток (1 измерение в секунду) | 3,6 µA (все три измерения) | 2,7 µA |
| Ток в режиме сна | 0,1 µA | 0,1 µA |
| Интерфейс | I2C (до 3,4 MHz) и SPI (до 10 MHz) | I2C и SPI |
| Chip ID (регистр 0xD0) | 0x60 | 0x58 |
| Размер чипа | 2,5 × 2,5 мм (квадратный) | 2,0 × 2,5 мм (прямоугольный) |
Проще говоря, BMP280 — это чуть более дешёвый BME280 без датчика влажности; давление и температуру он измеряет так же хорошо. Если нужны только высота или атмосферное давление, BMP280 хватит. Для проектов, где важна влажность, например метеостанции, теплицы или контроля микроклимата в комнате, выбирай BME280. На ступень выше в семействе стоит BME680/BME688: он добавляет газовый датчик, который обнаруживает в воздухе летучие органические соединения (VOC), но стоит в несколько раз дороже.
BME280 или DHT11/DHT22?
| Характеристика | DHT11 | DHT22 | BME280 |
|---|---|---|---|
| Диапазон и точность по температуре | 0–50 °C, ±2 °C | -40…+80 °C, ±0,5 °C | -40…+85 °C, ±1 °C |
| Точность по влажности | ±5% | ±2–5% | ±3% |
| Давление и высота | Нет | Нет | Да |
| Самое быстрое чтение | 1 раз в секунду | 1 раз в 2 секунды | Десятки раз в секунду |
| Подключение | Один провод данных | Один провод данных | I2C или SPI |
| Ток (во время измерения) | ≈ 1 mA | ≈ 1,5 mA | Менее 1 mA |
Датчики DHT дешёвые и простые, но медленные, иногда выдают ошибки чтения и не измеряют давление. BME280 же делит одну шину I2C с другими устройствами, например с дисплеем, во сне почти не потребляет ток и идеально подходит для проектов, которые месяцами работают от батарей. Подробности о DHT11 смотри в статье Датчик температуры и влажности DHT11, а чтобы увидеть все варианты рядом, прочитай сравнение датчиков температуры.
Виды модулей и предупреждение о 3,3 V
Отдельный чип настолько мал, что его всегда используют на плате-модуле, и распространены два вида таких модулей. 6-пиновые модули (обычно фиолетовые, продаются как GY-BME280-3.3 или GY-BMP280-3.3) имеют пины VCC, GND, SCL, SDA, CSB и SDO; у большинства из них нет стабилизатора, и цифра 3.3 в названии говорит именно об этом: питать их можно только от 3,3 V. 4-пиновые модули (VIN, GND, SCL, SDA) обычно несут маленький стабилизатор на 3,3 V, а часто и транзисторы для согласования уровней на линиях I2C, поэтому их можно подключать к пину 5V Arduino Uno. Если не знаешь точно, какой вид у тебя, поищи на плате крошечную трёхногую микросхему стабилизатора; если её нет, используй 3,3 V.
Подключение BME280: Arduino Uno, ESP32 и Pico
| Пин BME280 | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC / VIN | 3.3V (6 пинов) или 5V (4 пина, со стабилизатором) | 3V3 | 3V3(OUT), пин 36 |
| GND | GND | GND | GND, пин 38 |
| SCL | A5 | GPIO 22 | GP5, пин 7 |
| SDA | A4 | GPIO 21 | GP4, пин 6 |
| CSB (6 пинов) | 3.3V (выбор I2C) | 3V3 | 3V3 |
| SDO (6 пинов) | Свободен или GND: 0x76, 3.3V: 0x77 | Свободен или GND: 0x76, 3V3: 0x77 | Свободен или GND: 0x76, 3V3: 0x77 |
На адресе спотыкается больше всего людей. Если пин SDO чипа на GND, адрес 0x76; если на 3,3 V — 0x77. В большинстве дешёвых модулей SDO подтянут к GND резистором, поэтому их адрес 0x76, а на фирменных платах Adafruit — 0x77, и библиотека по умолчанию пробует 0x77. Поэтому адрес стоит явно указать в коде. Если при включении пин CSB на GND, чип переходит в режим SPI и не отвечает по I2C; если используешь I2C, подключи CSB к 3,3 V или убедись, что модуль уже подтягивает его вверх. I2C-пины своей платы найдёшь в утилите распиновки, а логику шины I2C — в статье Что такое I2C?.
Если на одной шине нужны два датчика, подключи пин SDO одного из них к 3,3 V, чтобы сменить его адрес на 0x77; на 4-пиновых модулях это обычно делается паяной перемычкой на обратной стороне платы. Для более чем двух датчиков лучше подходит SPI: SCL идёт на SCK (13 на Uno), SDA на MOSI (11), SDO на MISO (12), а пин CSB каждого датчика — на свой цифровой пин; в коде достаточно объявить объект как Adafruit_BME280 bme(10);. Поскольку 5-вольтовая Uno управляет линиями SPI напрямую, между ней и 3,3-вольтовым модулем обязательно нужен преобразователь уровней.
Установка библиотеки Adafruit BME280
- В Arduino IDE открой Инструменты › Управлять библиотеками (Tools › Manage Libraries) и найди Adafruit BME280.
- После нажатия «Установить» (Install) в окне с вопросом о зависимостях выбери Установить все (Install all), чтобы заодно установились Adafruit Unified Sensor и Adafruit BusIO.
- Если у тебя датчик BMP280, точно так же установи библиотеку Adafruit BMP280: библиотека BME280 не распознаёт BMP280.
- При желании открой пример «Файл › Примеры › Adafruit BME280 Library › bme280test» (File › Examples), но не забудь указать адрес (0x76) в строке begin().
Первый скетч: чтение температуры, влажности и давления с BME280
1#include <Wire.h>
2#include <Adafruit_Sensor.h>
3#include <Adafruit_BME280.h>
4
5#define DENIZ_SEVIYESI_HPA 1013.25 // bugünkü deniz seviyesi basıncı / today's sea-level pressure
6
7Adafruit_BME280 bme;
8
9void setup() {
10 Serial.begin(9600);
11 // Önce 0x76, olmazsa 0x77 dene / try 0x76 first, then 0x77
12 if (!bme.begin(0x76) && !bme.begin(0x77)) {
13 Serial.println(F("BME280 bulunamadi! Kablolari ve adresi kontrol et."));
14 Serial.print(F("Chip ID: 0x"));
15 Serial.println(bme.sensorID(), HEX); // 0x58 ise bu bir BMP280 / 0x58 means BMP280
16 while (true) delay(10);
17 }
18 Serial.println(F("BME280 hazir"));
19}
20
21void loop() {
22 float sicaklik = bme.readTemperature(); // °C
23 float nem = bme.readHumidity(); // % bağıl nem / % relative humidity
24 float basinc = bme.readPressure() / 100.0F; // Pa -> hPa
25 float irtifa = bme.readAltitude(DENIZ_SEVIYESI_HPA); // metre / meters
26
27 Serial.print(F("Sicaklik: ")); Serial.print(sicaklik, 1); Serial.println(F(" C"));
28 Serial.print(F("Nem: ")); Serial.print(nem, 1); Serial.println(F(" %"));
29 Serial.print(F("Basinc: ")); Serial.print(basinc, 1); Serial.println(F(" hPa"));
30 Serial.print(F("Irtifa: ")); Serial.print(irtifa, 0); Serial.println(F(" m"));
31 Serial.println();
32 delay(2000);
33}| Функция | Что делает |
|---|---|
| bme.begin(0x76) | Запускает датчик; возвращает true, если по адресу отвечает устройство с chip ID 0x60 |
| readTemperature() | Температура, °C |
| readHumidity() | Относительная влажность, % |
| readPressure() | Давление, Па (раздели на 100, чтобы получить гПа) |
| readAltitude(P0) | Высота относительно давления на уровне моря P0 (гПа), в метрах |
| seaLevelForAltitude(высота, P) | Давление на уровне моря по известной высоте, гПа |
| sensorID() | Считанный chip ID: 0x60 — BME280, 0x58 — BMP280 |
| setTemperatureCompensation(x) | Прибавляет x °C к каждому показанию температуры; влажность и давление корректируются соответственно |
Загрузи скетч и открой монитор порта на скорости 9600 бод: в комнатных условиях ты увидишь примерно 23,4 °C, влажность 45% и 1009,8 гПа. Давление меняется медленно, на протяжении часов; подыши на датчик — и влажность поднимется за считаные секунды, коснись его пальцем — и температура пойдёт вверх. По умолчанию библиотека измеряет непрерывно в нормальном режиме (normal) с максимальной передискретизацией (x16); для первого теста это идеально, но, как ты увидишь ниже, для долгих метеоизмерений другая настройка даёт более точные результаты.
Режимы измерения: forced, normal и правильные настройки
У BME280 три режима. В режиме sleep (сон) он не измеряет и потребляет 0,1 µA. В режиме forced (принудительный) он делает одно измерение и снова засыпает; для каждого нового значения ты вызываешь takeForcedMeasurement(). В режиме normal (нормальный) он непрерывно измеряет без команд, с заданным временем ожидания между измерениями. Передискретизация (oversampling) измеряет одно и то же значение несколько раз и усредняет его, чтобы уменьшить шум, а IIR-фильтр сглаживает резкие скачки давления (хлопнувшая дверь, порыв ветра). В даташите Bosch рекомендует такие настройки в зависимости от задачи:
| Задача | Режим | Передискретизация (давление / температура / влажность) | IIR-фильтр | Средний ток |
|---|---|---|---|---|
| Мониторинг погоды | Forced, 1 измерение в минуту | x1 / x1 / x1 | Выкл. | ≈ 0,16 µA |
| Измерение влажности | Forced, 1 измерение в секунду | Пропуск / x1 / x1 | Выкл. | ≈ 2,9 µA |
| Навигация в помещении (этажи, лифты) | Normal, ожидание 0,5 мс | x16 / x2 / x1 | 16 | ≈ 633 µA |
Давление на уровне моря и расчёт высоты
С высотой атмосферное давление падает, поэтому по измеренному давлению можно рассчитать высоту. Библиотека использует такую барометрическую формулу: h = 44330 × (1 − (P / P0)^0,1903). Здесь P — измеренное давление, а P0 — текущее давление на уровне моря (оба в гПа). В стандартной атмосфере принимается P0 = 1013,25 гПа, а у уровня моря разница в 1 гПа соответствует примерно 8,3 метра.
Подвох в том, что P0 — величина непостоянная: в зависимости от погоды она гуляет примерно от 990 до 1035 гПа. Если сегодня реальное значение 1023 гПа, а в коде осталось 1013.25, датчик покажет высоту примерно на 80 метров ниже настоящей. Для точных результатов P0 нужно держать актуальным: бери значение «давление, приведённое к уровню моря» из метеосервисов или значение Q из сводки METAR ближайшего аэропорта (например, Q1018 означает 1018 гПа). Можно пойти и обратным путём: если высота твоего места известна, рассчитай P0 с помощью seaLevelForAltitude(высота, давление). Например, если в Анкаре (около 938 м) датчик показывает 905 гПа, давление, приведённое к уровню моря, составит около 1012,6 гПа — это и есть число, которое ты видишь в приложениях погоды.
Для абсолютной высоты абсолютная точность ±1 гПа означает погрешность около ±8 метров. Зато в относительных измерениях датчик гораздо лучше: ±0,12 гПа ≈ ±1 м. Этаж в доме — это около 3 метров, или 0,36 гПа, поэтому BME280 легко определит, на каком ты этаже, или заметит движение лифта. Скетч ниже при запуске берёт за опорное значение среднее из 20 измерений, а затем выводит высоту относительно этой точки и давление на уровне моря, рассчитанное по известной высоте:
1#include <Wire.h>
2#include <Adafruit_Sensor.h>
3#include <Adafruit_BME280.h>
4
5#define BILINEN_IRTIFA 938.0 // bulunduğun yerin rakımı (m), örnek Ankara / your altitude (m), e.g. Ankara
6
7Adafruit_BME280 bme;
8float referansHpa; // açılıştaki basınç / pressure at start-up
9
10void setup() {
11 Serial.begin(9600);
12 if (!bme.begin(0x76)) {
13 Serial.println(F("BME280 bulunamadi!"));
14 while (true) delay(10);
15 }
16 // İç mekan navigasyonu ayarı: düşük gürültü / indoor navigation preset: low noise
17 bme.setSampling(Adafruit_BME280::MODE_NORMAL,
18 Adafruit_BME280::SAMPLING_X2, // sıcaklık / temperature
19 Adafruit_BME280::SAMPLING_X16, // basınç / pressure
20 Adafruit_BME280::SAMPLING_X1, // nem / humidity
21 Adafruit_BME280::FILTER_X16, // IIR filtre / IIR filter
22 Adafruit_BME280::STANDBY_MS_0_5);
23 delay(1000); // filtre otursun / let the filter settle
24
25 float toplam = 0;
26 for (int i = 0; i < 20; i++) { // 20 ölçümün ortalaması / average of 20 readings
27 toplam += bme.readPressure() / 100.0F;
28 delay(50);
29 }
30 referansHpa = toplam / 20;
31}
32
33void loop() {
34 float basinc = bme.readPressure() / 100.0F; // istasyon basıncı / station pressure
35 float denizSeviyesi = bme.seaLevelForAltitude(BILINEN_IRTIFA, basinc); // hPa
36 float bagilYukseklik = bme.readAltitude(referansHpa); // başlangıca göre / relative to start
37
38 Serial.print(F("Istasyon basinci: ")); Serial.print(basinc, 2); Serial.println(F(" hPa"));
39 Serial.print(F("Deniz seviyesi (QNH): ")); Serial.print(denizSeviyesi, 1); Serial.println(F(" hPa"));
40 Serial.print(F("Baslangica gore: ")); Serial.print(bagilYukseklik, 2); Serial.println(F(" m"));
41 Serial.println();
42 delay(1000);
43}Если взять плату с пола и поднять над головой, значение «Baslangica gore» (относительно старта) вырастет примерно на 2 метра. Поскольку атмосферное давление за день меняется на несколько гПа, через несколько часов это относительное показание уплывает, поэтому при долгой работе опорную точку нужно время от времени обновлять. Чтобы ещё больше успокоить показания, можно добавить скользящее среднее из статьи Фильтрация данных датчиков.
Мини-метеостанция на ESP32: веб-страница, которая открывается с телефона
Благодаря Wi-Fi у ESP32 показания BME280 можно смотреть на веб-странице с любого телефона или компьютера в той же сети. Скетч ниже использует библиотеку WebServer, которая входит в ядро ESP32, поэтому дополнительные библиотеки не нужны. Главная страница загружается один раз, а затем небольшой фрагмент JavaScript в ней каждые 5 секунд запрашивает JSON с адреса /veri и обновляет значения без перезагрузки страницы. Датчик работает в режиме forced, то есть измеряет только тогда, когда кто-то смотрит на страницу, а давление показывается приведённым к уровню моря, чтобы его можно было сравнить с прогнозом погоды. Если ESP32 для тебя в новинку, начни со статьи Что такое ESP32?.
- Подключи BME280, как в таблице: VCC к 3V3, SDA к GPIO 21, SCL к GPIO 22.
- Впиши данные своей сети в поля WIFI_ADI (имя сети) и WIFI_SIFRE (пароль) в коде, а высоту своего места — в RAKIM_M.
- Выбери плату ESP32 Dev Module и загрузи скетч.
- Открой монитор порта на скорости 115200 бод; после подключения к сети там появится IP-адрес.
- Введи этот адрес (например, 192.168.1.42) в браузере телефона, подключённого к той же сети Wi-Fi; появятся карточки температуры, влажности и давления.
1#include <WiFi.h>
2#include <WebServer.h>
3#include <Wire.h>
4#include <Adafruit_Sensor.h>
5#include <Adafruit_BME280.h>
6
7const char* WIFI_ADI = "WiFiAdin"; // kendi ağ adın / your network name
8const char* WIFI_SIFRE = "WiFiSifren"; // kendi şifren / your password
9const float RAKIM_M = 938.0; // bulunduğun yerin rakımı / your local altitude
10
11Adafruit_BME280 bme;
12WebServer server(80);
13
14// Telefonda açılan sayfa, 5 sn'de bir /veri'yi okur / phone page, reads /veri every 5 s
15const char SAYFA[] PROGMEM = R"rawliteral(
16<!DOCTYPE html><html><head><meta charset="utf-8">
17<meta name="viewport" content="width=device-width,initial-scale=1">
18<title>Mini Hava İstasyonu</title>
19<style>
20body{font-family:sans-serif;text-align:center;background:#0f172a;color:#e2e8f0;margin:0;padding:16px}
21.k{display:inline-block;min-width:140px;margin:8px;padding:16px;border-radius:14px;background:#1e293b}
22.d{font-size:2.2em;font-weight:bold;margin:6px 0}
23</style></head><body>
24<h2>Mini Hava İstasyonu</h2>
25<div class="k">Sıcaklık<div class="d" id="t">--</div>°C</div>
26<div class="k">Nem<div class="d" id="h">--</div>%</div>
27<div class="k">Basınç<div class="d" id="p">--</div>hPa</div>
28<script>
29async function guncelle() {
30 const v = await (await fetch('/veri')).json();
31 document.getElementById('t').textContent = v.t.toFixed(1);
32 document.getElementById('h').textContent = v.h.toFixed(0);
33 document.getElementById('p').textContent = v.p.toFixed(1);
34}
35guncelle();
36setInterval(guncelle, 5000);
37</script>
38</body></html>
39)rawliteral";
40
41void anaSayfa() {
42 server.send(200, "text/html", SAYFA);
43}
44
45void veriGonder() {
46 bme.takeForcedMeasurement(); // tek ölçüm al, sonra uyu / one measurement, then sleep
47 float p = bme.readPressure() / 100.0F;
48 String json = "{\"t\":" + String(bme.readTemperature(), 2) +
49 ",\"h\":" + String(bme.readHumidity(), 1) +
50 ",\"p\":" + String(bme.seaLevelForAltitude(RAKIM_M, p), 1) + "}";
51 server.send(200, "application/json", json);
52}
53
54void setup() {
55 Serial.begin(115200);
56 Wire.begin(21, 22); // SDA, SCL
57 if (!bme.begin(0x76)) {
58 Serial.println("BME280 bulunamadi!");
59 while (true) delay(10);
60 }
61 // Hava durumu izleme ayarı: kendi kendini ısıtmayı azaltır / weather monitoring preset: less self-heating
62 bme.setSampling(Adafruit_BME280::MODE_FORCED,
63 Adafruit_BME280::SAMPLING_X1, // sıcaklık / temperature
64 Adafruit_BME280::SAMPLING_X1, // basınç / pressure
65 Adafruit_BME280::SAMPLING_X1, // nem / humidity
66 Adafruit_BME280::FILTER_OFF);
67
68 WiFi.mode(WIFI_STA);
69 WiFi.begin(WIFI_ADI, WIFI_SIFRE);
70 while (WiFi.status() != WL_CONNECTED) {
71 delay(500);
72 Serial.print(".");
73 }
74 Serial.print("\nTarayicida ac / open in browser: http://");
75 Serial.println(WiFi.localIP());
76
77 server.on("/", anaSayfa);
78 server.on("/veri", veriGonder);
79 server.begin();
80}
81
82void loop() {
83 server.handleClient();
84}BME280 с Raspberry Pi Pico (MicroPython)
В MicroPython нет встроенного модуля для BME280. Вместо того чтобы скачивать файл драйвера, код ниже несёт небольшой драйвер внутри себя: он считывает калибровочные коэффициенты, заставляет датчик сделать одно измерение в режиме forced и рассчитывает результат по формулам из даташита. Поскольку код проверяет chip ID, он работает и с BMP280 и автоматически пропускает строку влажности. Подключи датчик к GP4 (SDA), GP5 (SCL) и 3V3(OUT), а в Thonny сохрани код на Pico под именем main.py. Если Pico для тебя в новинку, статьи Что такое Raspberry Pi Pico? и Основы MicroPython облегчат дело.
1from machine import Pin, I2C
2import struct, time
3
4i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000)
5ADR = 0x76 # olmazsa 0x77 dene / try 0x77 if it fails
6P0 = 1013.25 # deniz seviyesi basıncı (hPa) / sea-level pressure (hPa)
7
8def s8(x): # işaretli 8 bit / signed 8-bit
9 return x - 256 if x > 127 else x
10
11chip = i2c.readfrom_mem(ADR, 0xD0, 1)[0]
12BME = chip == 0x60 # 0x60 BME280, 0x58 BMP280
13print("Chip ID:", hex(chip), "BME280" if BME else "BMP280 (nem yok / no humidity)")
14
15# Fabrika kalibrasyon katsayıları / factory calibration coefficients
16T1, T2, T3, P1, P2, P3, P4, P5, P6, P7, P8, P9 = struct.unpack("<HhhHhhhhhhhh", i2c.readfrom_mem(ADR, 0x88, 24))
17if BME:
18 H1 = i2c.readfrom_mem(ADR, 0xA1, 1)[0]
19 e = i2c.readfrom_mem(ADR, 0xE1, 7)
20 H2 = struct.unpack("<h", e[0:2])[0]
21 H3 = e[2]
22 H4 = (s8(e[3]) << 4) | (e[4] & 0x0F)
23 H5 = (s8(e[5]) << 4) | (e[4] >> 4)
24 H6 = s8(e[6])
25 i2c.writeto_mem(ADR, 0xF2, b"\x01") # nem x1 (ctrl_meas'tan önce) / humidity x1 (before ctrl_meas)
26
27def oku():
28 i2c.writeto_mem(ADR, 0xF4, b"\x25") # sıcaklık x1, basınç x1, forced mod / temp x1, press x1, forced mode
29 time.sleep_ms(15) # ölçümün bitmesini bekle / wait for the measurement
30 d = i2c.readfrom_mem(ADR, 0xF7, 8 if BME else 6)
31 adc_p = (d[0] << 12) | (d[1] << 4) | (d[2] >> 4)
32 adc_t = (d[3] << 12) | (d[4] << 4) | (d[5] >> 4)
33
34 # Sıcaklık (datasheet formülü) / temperature (datasheet formula)
35 v1 = (adc_t / 16384 - T1 / 1024) * T2
36 v2 = (adc_t / 131072 - T1 / 8192) ** 2 * T3
37 t_fine = v1 + v2
38 t = t_fine / 5120
39
40 # Basınç, Pa / pressure, Pa
41 v1 = t_fine / 2 - 64000
42 v2 = v1 * v1 * P6 / 32768 + v1 * P5 * 2
43 v2 = v2 / 4 + P4 * 65536
44 v1 = (P3 * v1 * v1 / 524288 + P2 * v1) / 524288
45 v1 = (1 + v1 / 32768) * P1
46 p = 1048576 - adc_p
47 p = (p - v2 / 4096) * 6250 / v1
48 p = p + (P9 * p * p / 2147483648 + p * P8 / 32768 + P7) / 16
49
50 h = None
51 if BME: # nem, % / humidity, %
52 adc_h = (d[6] << 8) | d[7]
53 x = t_fine - 76800
54 x = (adc_h - (H4 * 64 + H5 / 16384 * x)) * (H2 / 65536 * (1 + H6 / 67108864 * x * (1 + H3 / 67108864 * x)))
55 x = x * (1 - H1 * x / 524288)
56 h = min(max(x, 0), 100)
57 return t, p / 100, h # °C, hPa, %
58
59while True:
60 t, p, h = oku()
61 irtifa = 44330 * (1 - (p / P0) ** 0.1903) # metre / meters
62 print("Sicaklik: %.1f C Basinc: %.1f hPa Irtifa: %.0f m" % (t, p, irtifa))
63 if h is not None:
64 print("Nem: %.1f %%" % h)
65 time.sleep(2)В коде стоит обратить внимание на несколько деталей. Настройка влажности (регистр 0xF2) вступает в силу только после записи в 0xF4, поэтому сначала отправляется настройка влажности, а потом команда измерения. Значение 0x25, записанное в 0xF4, означает «температура x1, давление x1, режим forced»; с такими настройками измерение длится максимум около 10 мс, так что ожидания в 15 мс достаточно. При проверке на примерных калибровочных значениях из даташита Bosch на BMP280 код выдаёт 25,08 °C и 1006,5 гПа, то есть его расчёты в точности совпадают с формулами Bosch.
BMP280 под видом BME280: какой датчик у тебя на самом деле?
Поскольку оба чипа подходят к одной и той же разводке платы, некоторые продавцы выдают модули с BMP280 за BME280; иногда на плате написано просто «BME/BMP280». Симптом всегда один: библиотека Adafruit BME280 выводит «Could not find a valid BME280 sensor, check wiring, address, sensor ID!» (не найден подходящий датчик BME280), а сразу под этим SensorID was: 0x58. Другие библиотеки ошибки не показывают, но всегда сообщают влажность 0 или nan. С проводами всё в порядке: у тебя просто чип BMP280, который не измеряет влажность.


- Посмотри на форму чипа: если металлическая крышка квадратная (2,5 × 2,5 мм), это BME280; если явно прямоугольная (2,0 × 2,5 мм) — BMP280. Приблизь чип камерой телефона, и разница будет хорошо видна.
- Считай chip ID: самый надёжный способ — скетч ниже; он читает идентификатор в регистре 0xD0 чипа и сообщает, какой это датчик.
- Обрати внимание на цену: настоящий BME280 заметно дороже BMP280, так что к модулям «BME280», которые продаются намного ниже рыночной цены, стоит относиться с подозрением.
1#include <Wire.h>
2
3void setup() {
4 Serial.begin(9600);
5 Wire.begin();
6 bool bulundu = false;
7
8 for (uint8_t adres = 0x76; adres <= 0x77; adres++) {
9 Wire.beginTransmission(adres);
10 if (Wire.endTransmission() != 0) continue; // bu adreste cihaz yok / no device at this address
11
12 Wire.beginTransmission(adres);
13 Wire.write(0xD0); // chip ID register'ı / chip ID register
14 Wire.endTransmission();
15 Wire.requestFrom(adres, (uint8_t)1);
16 uint8_t id = Wire.read();
17 bulundu = true;
18
19 Serial.print(F("Adres 0x"));
20 Serial.print(adres, HEX);
21 Serial.print(F(" Chip ID 0x"));
22 Serial.print(id, HEX);
23 if (id == 0x60) Serial.println(F(" -> BME280 (sicaklik + nem + basinc)"));
24 else if (id >= 0x56 && id <= 0x58) Serial.println(F(" -> BMP280 (nem olcmez)"));
25 else if (id == 0x61) Serial.println(F(" -> BME680 / BME688"));
26 else if (id == 0x55) Serial.println(F(" -> BMP180"));
27 else Serial.println(F(" -> bilinmeyen yonga / unknown chip"));
28 }
29
30 if (!bulundu) Serial.println(F("0x76 ve 0x77'de sensor yok: kablolari kontrol et"));
31}
32
33void loop() {
34}Если результат 0x58, не расстраивайся: температуру и давление BMP280 измеряет так же хорошо, как BME280. Установи библиотеку Adafruit BMP280 и используй скетч ниже; если нужна влажность, добавь в проект отдельный DHT22 или верни товар. Изредка попадаются и экземпляры BMP280 с ID 0x56 или 0x57; для них строку begin нужно записать как bmp.begin(0x76, 0x56).
1#include <Wire.h>
2#include <Adafruit_BMP280.h>
3
4Adafruit_BMP280 bmp;
5
6void setup() {
7 Serial.begin(9600);
8 if (!bmp.begin(0x76) && !bmp.begin(0x77)) {
9 Serial.println(F("BMP280 bulunamadi! Kablolari ve adresi kontrol et."));
10 while (true) delay(10);
11 }
12 // Datasheet'in önerdiği varsayılan ayarlar / default settings from the datasheet
13 bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,
14 Adafruit_BMP280::SAMPLING_X2, // sıcaklık / temperature
15 Adafruit_BMP280::SAMPLING_X16, // basınç / pressure
16 Adafruit_BMP280::FILTER_X16, // IIR filtre / IIR filter
17 Adafruit_BMP280::STANDBY_MS_500); // bekleme süresi / standby time
18}
19
20void loop() {
21 Serial.print(F("Sicaklik: ")); Serial.print(bmp.readTemperature(), 1); Serial.println(F(" C"));
22 Serial.print(F("Basinc: ")); Serial.print(bmp.readPressure() / 100.0F, 1); Serial.println(F(" hPa"));
23 Serial.print(F("Irtifa: ")); Serial.print(bmp.readAltitude(1013.25), 0); Serial.println(F(" m"));
24 Serial.println();
25 delay(2000);
26}Идеи проектов с BME280
- Настольная метеостанция: выводи температуру, влажность и давление на OLED-дисплей или I2C LCD, подключённый к той же шине I2C.
- Прогноз погоды по барометру: записывай давление каждый час; падение более чем на 2 гПа за 3 часа обычно предвещает ухудшение погоды, а устойчивый рост — ясное небо.
- Точка росы и предупреждение о плесени: рассчитай точку росы по формуле Магнуса (a = 17,62, b = 243,12 °C) и подавай сигнал, когда температура стены приближается к ней.
- Умная теплица: включай вентилятор или насос туманообразования в зависимости от влажности и температуры; подробности в статье Проект умной теплицы на Arduino.
- Регистратор данных: записывай показания на модуль SD-карты или, с ESP32, в Google Таблицы и строй недельный график.
- Датчик для умного дома: отправляй значения с ESP32 в Home Assistant по MQTT.
- Уличная станция на батареях: буди ESP32 из глубокого сна каждые 10 минут; во сне BME280 потребляет всего 0,1 µA.
- Счётчик этажей: с помощью скетча относительной высоты показывай, на каком этаже ты оказываешься в лифте или на лестнице.
Частые ошибки и как их исправить
| Симптом | Вероятная причина | Решение |
|---|---|---|
| «Could not find a valid BME280 sensor», SensorID 0x0 или 0xFF | Неверный адрес или ошибка в подключении | Укажи begin(0x76), проверь, не перепутаны ли SDA и SCL и подключён ли GND, запусти I2C-сканер |
| Та же ошибка, SensorID 0x58 | На самом деле это чип BMP280 | Используй библиотеку Adafruit BMP280, а для влажности добавь отдельный датчик |
| fatal error: Adafruit_Sensor.h: No such file or directory (файл не найден) | Не установлена зависимая библиотека | Установи библиотеку Adafruit Unified Sensor |
| Значения nan | В режиме forced не запрошено новое измерение, или вызов begin() завершился ошибкой | Вызывай takeForcedMeasurement() перед каждым чтением и проверяй результат begin() |
| Температура завышена на 1–3 °C | Самонагрев из-за непрерывных измерений, тепло от ESP32 или стабилизатора рядом | Перейди в режим forced, отодвинь датчик от платы, при необходимости используй setTemperatureCompensation() |
| Давление около 900 гПа | Это давление на уровне станции; оно падает с ростом высоты | Чтобы сравнивать с прогнозами, приведи его к уровню моря с помощью seaLevelForAltitude() |
| Высота ошибается на десятки метров | Давление на уровне моря оставлено равным 1013.25 | Введи текущее P0 (QNH) или откалибруй по известной высоте |
| Случайные зависания на длинных проводах | Шина I2C длинная и шумная | Держи кабель короче 50 см, снизь скорость I2C или перейди на SPI |
BME280 выполняет на одной маленькой плате все основные измерения метеостанции: сначала проверь адрес и chip ID, затем выбери режим измерения под свою задачу, а для расчёта высоты держи давление на уровне моря актуальным. В приложении BlueGrays есть проекты, которые можно объединить с этим руководством: измерение температуры и влажности на DHT11 и DHT22, погодные дисплеи на ESP32, регистратор температуры и веб-сервер на ESP32 — каждый с пошаговыми схемами подключения и кодом.
Частые вопросы
Чем BME280 отличается от BMP280?
BME280 измеряет температуру, относительную влажность и давление; BMP280 измеряет только температуру и давление, датчика влажности у него нет. Точность давления и температуры у них одинаковая. Различаются и чипы: BME280 квадратный (2,5 × 2,5 мм), BMP280 прямоугольный (2,0 × 2,5 мм), а их chip ID — 0x60 и 0x58.
I2C-адрес BME280 — 0x76 или 0x77?
0x76, когда пин SDO подключён к GND, и 0x77, когда он подключён к 3,3 V. Большинство дешёвых модулей используют 0x76, а платы Adafruit — 0x77. Библиотека Adafruit по умолчанию пробует 0x77, поэтому в коде может понадобиться написать bme.begin(0x76); если сомневаешься, запусти скетч I2C-сканера.
Работает ли BME280 от 5 V?
Чип как таковой рассчитан максимум на 3,6 V. У большинства 4-пиновых модулей с пометкой VIN есть стабилизатор, поэтому их можно подключать к 5V. 6-пиновые 3,3-вольтовые модули без стабилизатора питай только от 3,3 V: 5 V может повредить датчик.
Как исправить ошибку «Could not find a valid BME280 sensor»?
Сначала посмотри на значение SensorID, которое выводится под ошибкой. Если это 0x58, датчик у тебя BMP280, и нужна библиотека Adafruit BMP280. Если 0x0 или 0xFF, проблема в адресе или подключении: попробуй begin(0x76), убедись, что SDA и SCL не перепутаны и что пин CSB на 3,3 V.
Насколько точно BME280 измеряет высоту?
Изменения относительной высоты он измеряет с точностью около ±1 м, и этого хватает, чтобы заметить переход на другой этаж. Абсолютная высота зависит от введённого давления на уровне моря: ошибка в 1 гПа сдвигает результат примерно на 8 м. Если ввести текущее значение QNH или откалибровать по известной высоте, можно добиться точности в несколько метров.
Почему BME280 завышает температуру?
Самые частые причины — самонагрев из-за непрерывных измерений и тепло от соседних деталей, например ESP32 или стабилизатора. Перейди в режим forced, делай несколько измерений в минуту и вынеси датчик от платы на кабеле. Если остаётся постоянное смещение, сравни показания с надёжным термометром и исправь его через setTemperatureCompensation().
Что собрать после прочтения
Все проекты
Температура и влажность с DHT11
Насколько тепло в твоей комнате и влажный ли воздух или сухой? Датчик DHT11 измеряет температуру и влажность, а Arduino выводит значения на двухстрочный LCD-экран и обновляет их каждые пару секунд. Ес

Температура и влажность с DHT22 на ESP32 (с LCD-дисплеем)
Этот проект измеряет температуру и влажность воздуха датчиком DHT22 и в реальном времени показывает данные на I2C LCD 16x2. Данные читаются с датчика по однопроводному протоколу через библиотеку Adafruit DHT. Проект служит основой для IoT-метеостанций, умного дома или систем мониторинга среды в теплицах. Связь с DHT22 идёт через пин GPIO 4 у ESP32.

Часы, календарь и метеостанция на матрице (MAX7219, DS1307)
Табло с бегущей строкой для стола или стены, которое по очереди показывает время, дату и погоду в комнате. На светодиодном дисплее 8x32 сначала видна температура в градусах Цельсия и Фаренгейта, затем

Регистратор температуры на ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
Собери на ESP32 регистратор температуры с отметками времени! Каждую минуту читай температуру и влажность с DHT22, бери реальное время из DS1307 RTC и записывай всё на карту microSD в формате CSV. OLED показывает текущую температуру (крупным шрифтом), влажность в процентах, время и счётчик записей. Файл /temp_log.csv на SD-карте открывается в Excel, Google Sheets или Python pandas — идеально для теплиц, комнат, лабораторий и хранения продуктов.

ESP32 HTTPClient + API погоды (с OLED-дисплеем SSD1306)
В этом проекте ESP32 через HTTPClient.h делает вызов REST API к сервису погоды (wttr.in). В отличие от прошлой версии с I2C LCD, здесь используется OLED SSD1306 (128×64), который позволяет крупные шрифты, векторные значки и богатую картинку на одном экране. Семь векторных значков погоды (солнечно, переменная облачность, облачно, дождь, снег, гроза, туман) рисуются во время работы (растровые файлы не нужны). Температура выводится крупными цифрами.

Асинхронный веб-сервер на ESP32 (с выводом IP на LCD)
В этом проекте ESP32 превращается в асинхронный веб-сервер, которым можно управлять с телефона или компьютера в той же сети Wi-Fi. Благодаря библиотеке ESPAsyncWebServer сервер может обрабатывать несколько запросов одновременно (в отличие от классического WebServer.h, который блокируется на одном запросе). Открыв IP-адрес ESP32 в браузере, ты нажимаешь кнопки ON/OFF (маршруты /on и /off) и включаешь и выключаешь светодиод на GPIO 5.

ESP32 HTTPClient + API погоды (с экраном LCD)
В этом проекте ESP32 через HTTPClient.h делает вызов REST API к сервису погоды (wttr.in) через интернет. Полученный ответ в JSON разбирается с помощью ArduinoJson v7, а город, температура, влажность, погода и ветер выводятся на I2C LCD на турецком и английском. wttr.in бесплатен и не требует ключа API — достаточно указать любое название города, чтобы получить текущую погоду. Данные автоматически обновляются каждые 30 минут.

I2C LCD-дисплей (16x2) на ESP32
В этом проекте символьный LCD-экран 16x2 подключается к ESP32 по протоколу I2C и выводит текст. Благодаря I2C экраном можно управлять всего двумя пинами данных (SDA и SCL), не тратя 6+ пинов, как при классическом параллельном подключении. Код печатает постоянное сообщение в первой строке и счётчик, растущий каждую секунду, во второй. Кроме того, при запуске работает сканер I2C, который выводит адрес дисплея в монитор порта.
Другие статьи
Приложение BlueGrays
Собери эту схему шаг за шагом в телефоне
Схема подключения, код и список деталей на одном экране. 200+ проектов на Arduino, ESP32 и Pico готовы к сборке.
Наведи камеру телефона
Наведи камеру на код — откроется магазин приложений на телефоне.
или открыть магазин

