Parçalar · 11 dk okuma

BME280 Arduino: Sıcaklık, Nem, Basınç ve İrtifa (BMP280 Farkı)

BME280 ve BMP280 Arduino'ya nasıl bağlanır? 0x76/0x77 I2C adresi, Adafruit kütüphanesi, irtifa hesabı, 3,3 V uyarısı, ESP32 hava istasyonu ve Pico kodu.

BME280, Bosch'un ürettiği ve sıcaklık, bağıl nem ve hava basıncını tek bir minik yongada ölçen dijital bir çevre sensörüdür. Arduino ile kullanmak için dört kablo (VCC, GND, SDA, SCL) ve Adafruit BME280 kütüphanesi yeterlidir; birkaç satır kodla Seri Monitör'de °C, % ve hPa değerlerini görürsün. Basıncı ölçtüğü için bulunduğun yerin deniz seviyesinden yüksekliğini, yani irtifayı da hesaplayabilir. Kardeşi BMP280 neredeyse aynı görünür ama nem ölçmez; yalnızca sıcaklık ve basınç verir.

Bu yazıda iki sensörün farkını, I2C adresinin neden bazen 0x76 bazen 0x77 olduğunu, Arduino Uno, ESP32 ve Raspberry Pi Pico bağlantısını, irtifa formülünü ve doğru deniz seviyesi basıncını seçmeyi öğreneceksin. Ardından telefondan açılan bir ESP32 mini hava istasyonu kuracak, Pico'da kütüphanesiz bir MicroPython sürücüsü çalıştıracak ve piyasada çok yaygın olan "BME280 diye satılan BMP280" sorununu tek bir kodla nasıl yakalayacağını göreceksin.

BME280 sıcaklık, nem ve basınç sensörü modülü
BME280 modülü: metal kapaklı minik yonga sıcaklık, nem ve basıncı ölçer; I2C ya da SPI ile bağlanır.

BME280 nedir, nasıl çalışır?

BME280'in içinde üç ölçüm elemanı vardır. Basınç sensörü, havanın bastırdığı ince bir silikon zarın esnemesini piezorezistif yöntemle ölçer. Nem sensörü, havadaki nemi emdikçe kapasitesi değişen bir polimer katmandır. Sıcaklık sensörü hem ortam sıcaklığını verir hem de diğer iki ölçümün düzeltilmesinde kullanılır. Her yonga fabrikada tek tek kalibre edilir ve katsayılar yonganın içindeki belleğe yazılır; kütüphane açılışta bu katsayıları okur ve ham sayıları datasheet'teki formüllerle gerçek birimlere çevirir. Metal kapaktaki küçük delik havanın sensöre ulaşmasını sağlar, bu yüzden deliği bantla ya da yapıştırıcıyla kapatmamalısın.

ÖzellikBME280BMP280
ÖlçtükleriSıcaklık, nem, basınçSıcaklık, basınç
Sıcaklık-40…+85 °C, ±1 °C (25 °C'de ±0,5 °C)-40…+85 °C, ±1 °C (25 °C'de ±0,5 °C)
Bağıl nem%0–100, ±%3Yok
Basınç aralığı300–1100 hPa300–1100 hPa
Basınç doğruluğuMutlak ±1 hPa, bağıl ±0,12 hPa (≈ ±1 m)Mutlak ±1 hPa, bağıl ±0,12 hPa (≈ ±1 m)
Yonga besleme gerilimi1,71–3,6 V1,71–3,6 V
Akım (saniyede 1 ölçüm)3,6 µA (üç ölçüm birlikte)2,7 µA
Uyku akımı0,1 µA0,1 µA
ArayüzI2C (3,4 MHz'e kadar) ve SPI (10 MHz'e kadar)I2C ve SPI
Chip ID (0xD0 register'ı)0x600x58
Yonga boyutu2,5 × 2,5 mm (kare)2,0 × 2,5 mm (dikdörtgen)

Kısacası BMP280, nem ölçümü çıkarılmış ve biraz daha ucuz bir BME280'dir; basınç ve sıcaklık ölçümleri aynı kalitededir. Yalnızca irtifa ya da hava basıncı lazımsa BMP280 yeter. Hava istasyonu, sera ya da oda iklimi gibi nemin önemli olduğu projelerde BME280 seçmelisin. Ailenin bir üst üyesi BME680/BME688 ise bunlara havadaki uçucu organik bileşikleri (VOC) algılayan bir gaz sensörü de ekler, ama fiyatı birkaç kat yüksektir.

BME280 mi, DHT11/DHT22 mi?

ÖzellikDHT11DHT22BME280
Sıcaklık aralığı ve doğruluğu0–50 °C, ±2 °C-40…+80 °C, ±0,5 °C-40…+85 °C, ±1 °C
Nem doğruluğu±%5±%2–5±%3
Basınç ve irtifaYokYokVar
En hızlı okumaSaniyede 12 saniyede 1Saniyede onlarca
BağlantıTek veri hattıTek veri hattıI2C ya da SPI
Akım (ölçüm yaparken)≈ 1 mA≈ 1,5 mA1 mA altı

DHT sensörleri ucuz ve basittir ama yavaştır, zaman zaman okuma hatası verir ve basınç ölçmez. BME280 ise aynı I2C hattını ekran gibi başka cihazlarla paylaşır, uyurken neredeyse hiç akım çekmez ve pille aylarca çalışan projeler için idealdir. DHT11'in ayrıntıları için DHT11 Sıcaklık ve Nem Sensörü yazısına, bütün seçenekleri yan yana görmek için sıcaklık sensörleri karşılaştırması yazısına bakabilirsin.

Modül çeşitleri ve 3,3 V uyarısı

Çıplak yonga çok küçük olduğu için hep bir modül kartıyla kullanılır ve piyasada iki yaygın tür vardır. 6 pinli modüllerde (genellikle mor renkli, GY-BME280-3.3 ya da GY-BMP280-3.3 adıyla) VCC, GND, SCL, SDA, CSB ve SDO pinleri bulunur; çoğunun üzerinde regülatör yoktur ve adlarındaki 3.3 de bunu anlatır: yalnızca 3,3 V ile beslenmelidir. 4 pinli modüllerde (VIN, GND, SCL, SDA) ise genellikle küçük bir 3,3 V regülatör ve çoğu zaman I2C hatları için seviye dönüştürücü transistörler bulunur; bunlar Arduino Uno'nun 5V pinine bağlanabilir. Modülünün hangi tür olduğundan emin değilsen kartın üzerinde üç bacaklı küçük bir regülatör yongası ara; bulamazsan 3,3 V kullan.

Regülatörsüz bir 3,3 V modülü 5V pinine bağlamak sensörü bozabilir; yonganın mutlak sınırı 4,25 V'tur. Zarar gören bir sensör her zaman tamamen ölmez, bazen birkaç derece kaymış sıcaklık ya da tutarsız basınç değerleri verir; bu da hatayı fark etmeyi zorlaştırır.

BME280 bağlantısı: Arduino Uno, ESP32 ve Pico

BME280 piniArduino UnoESP32Raspberry Pi Pico
VCC / VIN3.3V (6 pinli) ya da 5V (4 pinli, regülatörlü)3V33V3(OUT), pin 36
GNDGNDGNDGND, pin 38
SCLA5GPIO 22GP5, pin 7
SDAA4GPIO 21GP4, pin 6
CSB (6 pinli)3.3V (I2C seçilir)3V33V3
SDO (6 pinli)Boş ya da GND: 0x76, 3.3V: 0x77Boş ya da GND: 0x76, 3V3: 0x77Boş ya da GND: 0x76, 3V3: 0x77

Adres konusu en sık takılınan noktadır. Yonganın SDO pini GND'deyse adres 0x76, 3,3 V'taysa 0x77 olur. Ucuz modüllerin çoğunda SDO bir dirençle GND'ye çekildiği için adres 0x76'dır; Adafruit'in kendi kartlarında ise 0x77'dir ve kütüphane de varsayılan olarak 0x77'yi dener. Bu yüzden kodda adresi açıkça yazmak gerekir. CSB pini açılışta GND'de olursa yonga SPI moduna geçer ve I2C'ye yanıt vermez; I2C kullanacaksan CSB'yi 3,3 V'a bağla ya da modülde zaten yukarı çekildiğinden emin ol. Kartının I2C pinlerini Pinout aracında, I2C hattının mantığını da I2C nedir yazısında bulabilirsin.

Aynı hatta iki sensör kullanmak istersen birinin SDO pinini 3,3 V'a bağlayıp adresini 0x77 yap; 4 pinli modüllerde bu genellikle kartın arkasındaki bir lehim köprüsüyle yapılır. İkiden fazla sensör için SPI daha uygundur: SCL pini SCK'ye (Uno'da 13), SDA pini MOSI'ye (11), SDO pini MISO'ya (12) bağlanır ve her sensörün CSB pini ayrı bir dijital pine gider; kodda nesneyi Adafruit_BME280 bme(10); diye tanımlaman yeterlidir. 5 V'luk Uno'da SPI hatları doğrudan sürüldüğü için 3,3 V'luk modülle arasına mutlaka seviye dönüştürücü koymalısın.

Arduino Uno 5 V ile çalışır ve Wire kütüphanesi A4 ile A5'teki dahili pull-up dirençlerini 5 V'a açar. 3,3 V'luk 6 pinli modül çoğu zaman yine de çalışır, çünkü modüldeki pull-up dirençleri hattı 3,3 V civarında tutar; ama kalıcı bir projede regülatörlü 4 pinli modül ya da bir lojik seviye dönüştürücü kullanmak en güvenlisidir. ESP32 ve Pico zaten 3,3 V ile çalıştığı için bu sorun onlarda yoktur.

Adafruit BME280 kütüphanesini kurmak

  1. Arduino IDE'de Araçlar > Kütüphaneleri Yönet menüsünü aç ve Adafruit BME280 ara.
  2. Kur düğmesine bastığında bağımlılıkları soran pencerede Install all seç; böylece Adafruit Unified Sensor ve Adafruit BusIO da kurulur.
  3. Sensörün BMP280 ise aynı şekilde Adafruit BMP280 kütüphanesini kur; BME280 kütüphanesi BMP280'i tanımaz.
  4. İstersen Dosya > Örnekler > Adafruit BME280 Library > bme280test örneğini aç, ama begin() satırına adresi (0x76) yazmayı unutma.

İlk kod: BME280 ile sıcaklık, nem ve basınç okuma

Arduino (C++)
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}
FonksiyonNe yapar?
bme.begin(0x76)Sensörü başlatır; adreste yanıt ve chip ID 0x60 ise true döner
readTemperature()Sıcaklık, °C
readHumidity()Bağıl nem, %
readPressure()Basınç, Pa (100'e bölünce hPa)
readAltitude(P0)P0 (hPa) deniz seviyesi basıncına göre yükseklik, metre
seaLevelForAltitude(rakım, P)Bilinen rakımdan deniz seviyesi basıncı, hPa
sensorID()Okunan chip ID: 0x60 BME280, 0x58 BMP280
setTemperatureCompensation(x)Her sıcaklık okumasına x °C ekler; nem ve basınç da buna göre düzeltilir

Kodu yükleyip Seri Monitör'ü 9600 baud'da açtığında oda koşullarında aşağı yukarı 23,4 °C sıcaklık, %45 nem ve 1009,8 hPa basınç gibi değerler görürsün. Basınç birkaç saat içinde yavaşça değişir; nefesini sensöre üflersen nemin saniyeler içinde yükseldiğini, parmağınla dokunursan sıcaklığın arttığını izleyebilirsin. Kütüphane varsayılan olarak normal modda ve en yüksek örneklemeyle (x16) sürekli ölçüm yapar; bu ilk deneme için idealdir, ama aşağıda göreceğin gibi uzun süreli hava ölçümünde başka bir ayar daha doğru sonuç verir.

Ölçüm modları: forced, normal ve doğru ayar

BME280'in üç modu vardır. Uyku (sleep) modunda ölçüm yapmaz ve 0,1 µA çeker. Forced modda tek bir ölçüm yapıp yeniden uykuya döner; yeni değer için her seferinde takeForcedMeasurement() çağırırsın. Normal modda ise ayarladığın bekleme süresiyle kendi kendine sürekli ölçer. Oversampling (aşırı örnekleme) aynı değeri birkaç kez ölçüp ortalayarak gürültüyü azaltır, IIR filtre ise ani basınç sıçramalarını (kapı çarpması, rüzgâr) yumuşatır. Bosch datasheet'te kullanım amacına göre şu ayarları önerir:

KullanımModOversampling (basınç / sıcaklık / nem)IIR filtreOrtalama akım
Hava durumu izlemeForced, dakikada 1 ölçümx1 / x1 / x1Kapalı≈ 0,16 µA
Nem ölçümüForced, saniyede 1 ölçümYok / x1 / x1Kapalı≈ 2,9 µA
İç mekân navigasyonu (kat, asansör)Normal, 0,5 ms beklemex16 / x2 / x116≈ 633 µA
Sensör sürekli ölçüm yaptığında yonga ve kart çok az da olsa ısınır; buna kendi kendini ısıtma denir. Oda ya da dış hava sıcaklığı ölçüyorsan forced modu kullan ve dakikada birkaç ölçüm yeterli olsun. Ölçüm hâlâ güvendiğin bir termometreden sabit bir farkla yüksekse bme.setTemperatureCompensation(-1.0); gibi bir düzeltme ekleyebilirsin.

Deniz seviyesi basıncı ve irtifa hesabı

Hava basıncı yükseldikçe azalır, bu yüzden ölçülen basınçtan yükseklik hesaplanabilir. Kütüphanenin kullandığı barometrik formül şudur: h = 44330 × (1 − (P / P0)^0,1903). Burada P ölçtüğün basınç, P0 ise o anki deniz seviyesi basıncıdır (ikisi de hPa). Standart atmosferde P0 = 1013,25 hPa kabul edilir ve deniz seviyesine yakın yerlerde 1 hPa'lık fark yaklaşık 8,3 metreye karşılık gelir.

Sorun şu ki P0 sabit değildir; hava durumuna göre kabaca 990 ile 1035 hPa arasında oynar. Bugün gerçek değer 1023 hPa iken kodda 1013,25 bırakırsan sensör yüksekliği yaklaşık 80 metre eksik gösterir. Doğru sonuç için P0'ı güncel tutmalısın: meteoroloji sitelerinde "deniz seviyesine indirgenmiş basınç" olarak verilen değeri ya da en yakın havalimanının METAR raporundaki Q değerini (örneğin Q1018, yani 1018 hPa) kullanabilirsin. Tersini de yapabilirsin: bulunduğun yerin rakımını biliyorsan seaLevelForAltitude(rakım, basınç) ile P0'ı hesaplarsın. Örneğin Ankara'da (yaklaşık 938 m) sensör 905 hPa ölçüyorsa deniz seviyesine indirgenmiş basınç yaklaşık 1012,6 hPa'dır; hava durumu uygulamalarında gördüğün sayı da budur.

Mutlak yükseklik için ±1 hPa'lık mutlak doğruluk ±8 metre civarında belirsizlik demektir. Ama bağıl ölçümde sensör çok daha iyidir: ±0,12 hPa ≈ ±1 m. Bir apartman katı yaklaşık 3 metre, yani 0,36 hPa olduğu için BME280 hangi katta olduğunu ya da asansörün hareketini rahatça algılar. Aşağıdaki kod açılışta 20 ölçümün ortalamasını referans alır, sonra bu noktaya göre yüksekliği ve bilinen rakımdan deniz seviyesi basıncını yazar:

Arduino (C++)
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}

Kartı yerden alıp başının üzerine kaldırdığında "Başlangıca göre" değerinin yaklaşık 2 metre arttığını görürsün. Hava basıncı gün içinde birkaç hPa değiştiği için bu bağıl ölçüm saatler sonra kayar; uzun süreli kullanımda referansı ara sıra yenilemen gerekir. Ölçümleri daha da sakinleştirmek için sensör verisi filtreleme yazısındaki hareketli ortalamayı ekleyebilirsin.

ESP32 ile mini hava istasyonu: telefondan açılan web sayfası

ESP32'nin Wi-Fi'si sayesinde BME280 ölçümlerini aynı ağdaki telefon ya da bilgisayardan bir web sayfasında görebilirsin. Aşağıdaki kod ESP32 çekirdeğiyle birlikte gelen WebServer kütüphanesini kullandığı için ek bir kütüphane gerektirmez. Ana sayfa bir kez yüklenir, ardından içindeki küçük JavaScript her 5 saniyede bir /veri adresinden JSON çeker ve sayfa yenilenmeden değerleri günceller. Sensör forced modda çalışır, yani yalnızca biri sayfaya baktığında ölçüm yapar; basınç da hava durumu tahminleriyle karşılaştırılabilsin diye deniz seviyesine indirgenmiş olarak gösterilir. ESP32'yi ilk kez kullanıyorsan önce ESP32 nedir yazısına göz at.

  1. BME280'i tablodaki gibi bağla: VCC 3V3'e, SDA GPIO 21'e, SCL GPIO 22'ye.
  2. Koddaki WIFI_ADI ve WIFI_SIFRE alanlarına kendi ağının bilgilerini, RAKIM_M alanına bulunduğun yerin rakımını yaz.
  3. Kartı ESP32 Dev Module olarak seç ve kodu yükle.
  4. Seri Monitör'ü 115200 baud'da aç; bağlantı kurulunca ekranda IP adresi yazar.
  5. Aynı Wi-Fi ağındaki telefonunun tarayıcısına bu adresi (örneğin 192.168.1.42) yaz; sıcaklık, nem ve basınç kartları açılır.
Arduino (C++)
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}
ESP32 çalışırken birkaç derece ısınır ve sensörü kartın hemen yanına koyarsan bu ısı ölçümü bozar. BME280'i 10–15 cm'lik bir kabloyla karttan uzaklaştır, kutunun havalandırma deliklerinin yanına yerleştir ve güneş almayan bir yere koy. Grafikler ve buton kontrolü olan daha gelişmiş bir panel için ESP32 web sunucu ve WebSocket yazısına geçebilirsin.

Raspberry Pi Pico ile BME280 (MicroPython)

MicroPython'un içinde BME280 için hazır bir modül gelmez. Bir sürücü dosyası indirmek yerine aşağıdaki kod küçük bir sürücüyü kendi içinde taşır: kalibrasyon katsayılarını okur, sensöre forced modda tek ölçüm yaptırır ve datasheet'teki formüllerle sonucu hesaplar. Chip ID'ye baktığı için BMP280 ile de çalışır ve nem satırını kendiliğinden atlar. Sensörü GP4 (SDA), GP5 (SCL) ve 3V3(OUT) pinlerine bağla, kodu Thonny'de main.py adıyla Pico'ya kaydet. Pico'yu yeni tanıyorsan Raspberry Pi Pico nedir ve MicroPython temelleri yazıları işini kolaylaştırır.

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)

Kodda dikkat edilecek birkaç ayrıntı var. Nem ayarı (0xF2 register'ı) ancak ardından 0xF4'e yazıldığında geçerli olur, bu yüzden önce nem, sonra ölçüm komutu gönderilir. 0xF4'e yazılan 0x25 değeri "sıcaklık x1, basınç x1, forced mod" anlamına gelir; bu ayarla bir ölçüm en fazla 10 ms kadar sürdüğü için 15 ms beklemek yeterlidir. Kod, Bosch'un BMP280 datasheet'indeki örnek kalibrasyon değerleriyle denendiğinde 25,08 °C ve 1006,5 hPa sonucunu verir, yani hesaplar Bosch'un formülleriyle birebir aynıdır.

BME280 diye satılan BMP280 sorunu: sensörün hangisi?

İki yonga aynı kart tasarımına oturduğu için bazı satıcılar BMP280'li modülleri BME280 diye satar; kartın üzerinde bazen yalnızca "BME/BMP280" yazar. Belirtisi hep aynıdır: Adafruit BME280 kütüphanesi "Could not find a valid BME280 sensor, check wiring, address, sensor ID!" hatası verir ve hemen altında SensorID was: 0x58 yazar. Başka kütüphaneler ise hata vermeden nemi hep 0 ya da nan gösterir. Kablolarda bir sorun yoktur; elindeki yonga nem ölçmeyen bir BMP280'dir.

BME280
BME280
BMP280
BMP280
  • Yonganın şekline bak: Metal kapak kareyse (2,5 × 2,5 mm) BME280, belirgin şekilde dikdörtgense (2,0 × 2,5 mm) BMP280'dir. Telefonun kamerasıyla yakınlaştırınca fark kolayca görülür.
  • Chip ID'yi oku: En kesin yöntem aşağıdaki koddur; yonganın 0xD0 register'ındaki kimlik numarasını okur ve hangi sensör olduğunu yazar.
  • Fiyata dikkat et: Gerçek BME280, BMP280'den belirgin şekilde pahalıdır; piyasanın çok altında satılan "BME280" modüllerinden şüphelen.
Arduino (C++)
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}

Sonuç 0x58 çıkarsa üzülme: BMP280'in sıcaklık ve basınç ölçümleri BME280 ile aynı kalitededir. Adafruit BMP280 kütüphanesini kurup aşağıdaki kodu kullan; nem gerekiyorsa projeye ayrı bir DHT22 ekleyebilir ya da ürünü iade edebilirsin. Nadiren 0x56 ya da 0x57 kimlikli BMP280 örnekleri de çıkar; bunlar için begin satırını bmp.begin(0x76, 0x56) şeklinde yazman gerekir.

Arduino (C++)
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 ile proje fikirleri

  • Masaüstü hava istasyonu: Sıcaklık, nem ve basıncı aynı I2C hattına bağlanan bir OLED ekranda ya da I2C LCD'de göster.
  • Barometre ile hava tahmini: Basıncı saatte bir kaydet; 3 saatte 2 hPa'dan fazla düşüş genellikle havanın bozacağını, istikrarlı yükseliş ise açık havayı haber verir.
  • Çiy noktası ve küf uyarısı: Magnus formülüyle (a = 17,62, b = 243,12 °C) çiy noktasını hesapla; duvar sıcaklığı bu değere yaklaşınca uyarı ver.
  • Akıllı sera: Nem ve sıcaklığa göre fanı ya da sisleme pompasını çalıştır; ayrıntılar Arduino akıllı sera projesi yazısında.
  • Veri kaydedici: Ölçümleri SD kart modülüne ya da ESP32 ile Google E-Tablolar'a yazıp haftalık grafik çıkar.
  • Akıllı ev sensörü: ESP32 ile değerleri MQTT üzerinden Home Assistant'a gönder.
  • Pille çalışan dış mekân istasyonu: ESP32'yi deep sleep ile 10 dakikada bir uyandır; BME280 uykuda yalnızca 0,1 µA çeker.
  • Kat ölçer: Bağıl irtifa koduyla asansörde ya da merdivende kaçıncı kata çıktığını göster.

Sık yapılan hatalar ve çözümleri

BelirtiOlası sebepÇözüm
"Could not find a valid BME280 sensor", SensorID 0x0 ya da 0xFFYanlış adres ya da kablo hatasıbegin(0x76) yaz, SDA ile SCL'nin yerini ve GND'yi kontrol et, I2C tarayıcıyı çalıştır
Aynı hata, SensorID 0x58Yonga aslında BMP280Adafruit BMP280 kütüphanesini kullan, nem için ayrı sensör ekle
fatal error: Adafruit_Sensor.h: No such file or directoryBağımlı kütüphane kurulmamışAdafruit Unified Sensor kütüphanesini kur
Değerler nanForced modda yeni ölçüm istenmemiş ya da begin() başarısızHer okumadan önce takeForcedMeasurement() çağır, begin() sonucunu kontrol et
Sıcaklık 1–3 °C yüksekSürekli ölçümle kendi kendini ısıtma, yakındaki ESP32 ya da regülatörün ısısıForced moda geç, sensörü karttan uzaklaştır, gerekirse setTemperatureCompensation() kullan
Basınç 900 hPa gibi düşükBu istasyon basıncıdır; rakım yükseldikçe düşerHava tahminiyle karşılaştırmak için seaLevelForAltitude() ile deniz seviyesine indirge
İrtifa onlarca metre yanlışDeniz seviyesi basıncı 1013,25 olarak bırakılmışGüncel P0 değerini (QNH) gir ya da bilinen rakımla kalibre et
Uzun kabloda rastgele donmalarI2C hattı uzun ve gürültülüKabloyu 50 cm'nin altında tut, I2C hızını düşür ya da SPI kullan
Sensörü kapalı ve havasız bir kutuya koyma; nem ve basınç ölçümü için havanın yongaya ulaşması gerekir. Dış mekânda yağmurdan ve doğrudan güneşten koruyan, altı açık, panjurlu bir kutu (meteoroloji istasyonlarındaki gibi) en doğru sonucu verir. Sensör yoğuşma nedeniyle ıslanırsa bir süre nemi %100 gösterebilir; kuruyunca normale döner.

BME280, tek bir küçük kartla bir hava istasyonunun bütün temel ölçümlerini yapar: önce adresi ve chip ID'yi doğrula, ardından ölçüm modunu amacına göre seç, irtifa için deniz seviyesi basıncını güncel tut. BlueGrays uygulamasında DHT11 ve DHT22 ile sıcaklık-nem ölçümü, ESP32 hava durumu ekranları, sıcaklık kaydedici ve ESP32 web sunucusu gibi bu yazıyla birleştirebileceğin projeleri adım adım devre şemaları ve kodlarıyla bulabilirsin.

Sıkça sorulan sorular

BME280 ile BMP280 arasındaki fark nedir?

BME280 sıcaklık, bağıl nem ve basıncı ölçer; BMP280 ise yalnızca sıcaklık ve basıncı ölçer, nem sensörü yoktur. Basınç ve sıcaklık doğrulukları aynıdır. Yongaları da farklıdır: BME280 kare (2,5 × 2,5 mm), BMP280 dikdörtgendir (2,0 × 2,5 mm) ve chip ID'leri 0x60 ile 0x58'dir.

BME280'in I2C adresi 0x76 mı 0x77 mi?

SDO pini GND'ye bağlıysa 0x76, 3,3 V'a bağlıysa 0x77'dir. Ucuz modüllerin çoğu 0x76, Adafruit kartları 0x77 kullanır. Adafruit kütüphanesi varsayılan olarak 0x77'yi denediği için kodda bme.begin(0x76) yazman gerekebilir; emin değilsen I2C tarayıcı kodunu çalıştır.

BME280 5V ile çalışır mı?

Yonganın kendisi en fazla 3,6 V ile çalışır. 4 pinli ve VIN yazan modüllerin çoğunda regülatör bulunduğu için bunlar 5V'a bağlanabilir. 6 pinli, regülatörsüz 3,3 V modülleri ise yalnızca 3,3 V ile beslemelisin; 5 V sensörü bozabilir.

"Could not find a valid BME280 sensor" hatası nasıl çözülür?

Önce hatanın altındaki SensorID değerine bak. 0x58 ise sensörün BMP280'dir ve Adafruit BMP280 kütüphanesini kullanmalısın. 0x0 ya da 0xFF ise adres ya da kablo sorunudur: begin(0x76) dene, SDA-SCL'nin yer değiştirmediğinden ve CSB pininin 3,3 V'ta olduğundan emin ol.

BME280 ile irtifa ne kadar doğru ölçülür?

Bağıl yükseklik değişimini yaklaşık ±1 m doğrulukla ölçer, bu da kat farkını algılamaya yeter. Mutlak irtifa ise girdiğin deniz seviyesi basıncına bağlıdır; 1 hPa'lık hata yaklaşık 8 m sapma yaratır. Güncel QNH değerini girer ya da bilinen bir rakımla kalibre edersen birkaç metrelik doğruluğa yaklaşırsın.

BME280 sıcaklığı neden yüksek gösteriyor?

En sık sebepler sensörün sürekli ölçümden kendi kendini ısıtması ve yakındaki ESP32, regülatör gibi parçaların ısısıdır. Forced moda geçip dakikada birkaç ölçüm al ve sensörü kablo ile karttan uzaklaştır. Sabit bir fark kalırsa güvenilir bir termometreyle karşılaştırıp setTemperatureCompensation() ile düzelt.

Tüm projeleri gör
DHT11 İle Sıcaklık Ve Nem
#55Orta

DHT11 İle Sıcaklık Ve Nem

Odan kaç derece, hava nemli mi, kuru mu? DHT11 sensörü sıcaklığı ve nemi ölçer, Arduino da bu değerleri iki satırlık LCD ekrana yazar ve birkaç saniyede bir yeniler. Sensöre bir şey olursa ekranda hat

4.7(47)
64
ESP32 DHT22 Sıcaklık ve Nem (LCD Ekranlı)
#117Orta

ESP32 DHT22 Sıcaklık ve Nem (LCD Ekranlı)

DHT22 sensörü ile ortam sıcaklığını ve nem oranını ölçüp 16x2 I2C LCD ekranda gerçek zamanlı olarak gösteren bir projedir. Adafruit DHT kütüphanesi kullanılarak tek kablo (one-wire) protokolü ile sensörden veri okunur. Bu proje, IoT hava istasyonu, akıllı ev otomasyonu veya seralarda ortam takip sistemlerinin temelini oluşturur. ESP32'nin GPIO 4 pini üzerinden DHT22 ile haberleşme sağlanır.

4.8(38)
54
Dot Matrix Saat, Takvim ve Hava İstasyonu (MAX7219, DS1307)
#85Orta
Premium

Dot Matrix Saat, Takvim ve Hava İstasyonu (MAX7219, DS1307)

Masada ya da duvarda durup saati, tarihi ve odanın havasını sırayla gösteren kayan yazılı bir pano. 8x32 LED ekranda önce sıcaklık hem Celsius hem Fahrenheit olarak, sonra nem, ardından iki noktası he

5.0(50)
66
ESP32 Sıcaklık Loglayıcı (DHT22 + DS1307 RTC + microSD + OLED)
#144İleri
Premium

ESP32 Sıcaklık Loglayıcı (DHT22 + DS1307 RTC + microSD + OLED)

ESP32 ile zamanlı sıcaklık ve nem kayıt sistemi kur! Bu projede DHT22 sensörü ile dakikada bir sıcaklık/nem okuyup DS1307 RTC modülünden aldığın gerçek zaman etiketiyle microSD karta CSV formatında kaydediyoruz. OLED ekranda büyük font ile son sıcaklık değeri, nem yüzdesi, timestamp ve toplam kayıt sayısı canlı gösterilir. SD kart üzerindeki `/temp_log.csv` dosyası Excel/Google Sheets/Python pandas ile açılıp analiz edilebilir — sera monitörü, ev/oda sıcaklık takibi, laboratuvar veri toplama,

4.7(7)
12
ESP32 HTTPClient + Hava Durumu API (SSD1306 OLED Ekranlı)
#134İleri
Premium

ESP32 HTTPClient + Hava Durumu API (SSD1306 OLED Ekranlı)

Bu projede ESP32 ile internet üzerinden hava durumu API'sine (wttr.in) `HTTPClient.h` kullanarak REST API çağrısı yapıyoruz. Bir önceki I2C LCD versiyonundan farklı olarak burada SSD1306 OLED (128×64) ekran kullanıyoruz — büyük font, vector ikonlar ve tek ekranda zengin görsel sunum mümkün oluyor. Hava durumu için 7 farklı vector ikon (güneşli, parçalı bulutlu, bulutlu, yağmurlu, karlı, fırtınalı, sisli) runtime'da çiziliyor (bitmap dosyası gerektirmez). Sıcaklık 3x büyük fontla ortada, hava dur

4.3(10)
18
ESP32 Async Web Server (LCD'de IP Göstergeli)
#129İleri
Premium

ESP32 Async Web Server (LCD'de IP Göstergeli)

Bu projede ESP32'yi aynı Wi-Fi ağındaki telefonunuzdan veya bilgisayarınızdan kontrol edebileceğiniz **asenkron bir web sunucusuna** dönüştürüyoruz. ESPAsyncWebServer kütüphanesi sayesinde sunucu birden fazla isteği aynı anda işleyebiliyor (klasik `WebServer.h` gibi tek istekte bloklamıyor). Tarayıcıdan ESP32'nin IP adresine bağlanıp ON/OFF butonlarına basarak (`/on` ve `/off` adresleri) GPIO 5'e bağlı LED'i açıp kapatabileceksiniz.

4.8(16)
26
ESP32 HTTPClient + Hava Durumu API (LCD Ekranlı)
#133İleri
Premium

ESP32 HTTPClient + Hava Durumu API (LCD Ekranlı)

Bu projede ESP32 ile internet üzerinden hava durumu API'sine (wttr.in) `HTTPClient.h` kullanarak REST API çağrısı yapıyoruz. ArduinoJson v7 ile dönen JSON cevabını parse edip şehir, sıcaklık, nem, hava durumu ve rüzgar bilgilerini I2C LCD ekranda hem Türkçe hem İngilizce gösteriyoruz. wttr.in ücretsizdir, API key gerektirmez — herhangi bir şehir ismini yazarak o şehrin anlık hava durumunu çekebilirsiniz. 30 dakikada bir otomatik güncelleme, LED ile her ekran için farklı görsel feedback ve eksiks

4.7(13)
20
ESP32 I2C LCD Ekran (16x2)
#119Orta
Premium

ESP32 I2C LCD Ekran (16x2)

Bu projede 16x2 karakter LCD ekranı I2C protokolü üzerinden ESP32'ye bağlayarak metin görüntülüyoruz. I2C sayesinde sadece 2 data pini (SDA ve SCL) ile ekranı kontrol edebiliyoruz; klasik paralel bağlantıdaki 6+ pin israfı ortadan kalkıyor. Kod ilk satıra sabit bir mesaj, ikinci satıra ise her saniye artan bir sayaç yazdırıyor. Ayrıca başlangıçta I2C tarayıcı çalıştırarak ekranın adresini Serial Monitor'a yazdırıyoruz (genelde 0x27 veya 0x3F).

4.9(23)
40