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 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.
| Özellik | BME280 | BMP280 |
|---|---|---|
| Ölçtükleri | Sı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, ±%3 | Yok |
| Basınç aralığı | 300–1100 hPa | 300–1100 hPa |
| Basınç doğruluğu | Mutlak ±1 hPa, bağıl ±0,12 hPa (≈ ±1 m) | Mutlak ±1 hPa, bağıl ±0,12 hPa (≈ ±1 m) |
| Yonga besleme gerilimi | 1,71–3,6 V | 1,71–3,6 V |
| Akım (saniyede 1 ölçüm) | 3,6 µA (üç ölçüm birlikte) | 2,7 µA |
| Uyku akımı | 0,1 µA | 0,1 µA |
| Arayüz | I2C (3,4 MHz'e kadar) ve SPI (10 MHz'e kadar) | I2C ve SPI |
| Chip ID (0xD0 register'ı) | 0x60 | 0x58 |
| Yonga boyutu | 2,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?
| Özellik | DHT11 | DHT22 | BME280 |
|---|---|---|---|
| Sıcaklık aralığı ve doğruluğu | 0–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 irtifa | Yok | Yok | Var |
| En hızlı okuma | Saniyede 1 | 2 saniyede 1 | Saniyede onlarca |
| Bağlantı | Tek veri hattı | Tek veri hattı | I2C ya da SPI |
| Akım (ölçüm yaparken) | ≈ 1 mA | ≈ 1,5 mA | 1 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.
BME280 bağlantısı: Arduino Uno, ESP32 ve Pico
| BME280 pini | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC / VIN | 3.3V (6 pinli) ya da 5V (4 pinli, regülatörlü) | 3V3 | 3V3(OUT), pin 36 |
| GND | GND | GND | GND, pin 38 |
| SCL | A5 | GPIO 22 | GP5, pin 7 |
| SDA | A4 | GPIO 21 | GP4, pin 6 |
| CSB (6 pinli) | 3.3V (I2C seçilir) | 3V3 | 3V3 |
| SDO (6 pinli) | Boş ya da GND: 0x76, 3.3V: 0x77 | Boş ya da GND: 0x76, 3V3: 0x77 | Boş 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.
Adafruit BME280 kütüphanesini kurmak
- Arduino IDE'de Araçlar > Kütüphaneleri Yönet menüsünü aç ve Adafruit BME280 ara.
- Kur düğmesine bastığında bağımlılıkları soran pencerede Install all seç; böylece Adafruit Unified Sensor ve Adafruit BusIO da kurulur.
- Sensörün BMP280 ise aynı şekilde Adafruit BMP280 kütüphanesini kur; BME280 kütüphanesi BMP280'i tanımaz.
- İ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
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}| Fonksiyon | Ne 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ım | Mod | Oversampling (basınç / sıcaklık / nem) | IIR filtre | Ortalama akım |
|---|---|---|---|---|
| Hava durumu izleme | Forced, dakikada 1 ölçüm | x1 / x1 / x1 | Kapalı | ≈ 0,16 µA |
| Nem ölçümü | Forced, saniyede 1 ölçüm | Yok / x1 / x1 | Kapalı | ≈ 2,9 µA |
| İç mekân navigasyonu (kat, asansör) | Normal, 0,5 ms bekleme | x16 / x2 / x1 | 16 | ≈ 633 µA |
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:
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.
- BME280'i tablodaki gibi bağla: VCC 3V3'e, SDA GPIO 21'e, SCL GPIO 22'ye.
- Koddaki WIFI_ADI ve WIFI_SIFRE alanlarına kendi ağının bilgilerini, RAKIM_M alanına bulunduğun yerin rakımını yaz.
- Kartı ESP32 Dev Module olarak seç ve kodu yükle.
- Seri Monitör'ü 115200 baud'da aç; bağlantı kurulunca ekranda IP adresi yazar.
- 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.
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}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.
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.


- 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.
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.
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
| Belirti | Olası sebep | Çözüm |
|---|---|---|
| "Could not find a valid BME280 sensor", SensorID 0x0 ya da 0xFF | Yanlış 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 0x58 | Yonga aslında BMP280 | Adafruit BMP280 kütüphanesini kullan, nem için ayrı sensör ekle |
| fatal error: Adafruit_Sensor.h: No such file or directory | Bağımlı kütüphane kurulmamış | Adafruit Unified Sensor kütüphanesini kur |
| Değerler nan | Forced modda yeni ölçüm istenmemiş ya da begin() başarısız | Her okumadan önce takeForcedMeasurement() çağır, begin() sonucunu kontrol et |
| Sıcaklık 1–3 °C yüksek | Sü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üşük | Bu istasyon basıncıdır; rakım yükseldikçe düşer | Hava 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 donmalar | I2C hattı uzun ve gürültülü | Kabloyu 50 cm'nin altında tut, I2C hızını düşür ya da SPI kullan |
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.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
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

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.

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

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,

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

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.

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

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).
Diğer yazılar
BlueGrays uygulaması
Bu devreyi telefonunda adım adım kur
Devre şeması, kod ve parça listesi tek ekranda. 160'tan fazla Arduino, ESP32 ve Pico projesi seni bekliyor.
Telefonunla tara
Kamerayı koda tut; telefonunun uygulama mağazası açılır.
ya da mağazada aç

