BME280 Arduino: temperatura, umidità, pressione e altitudine
Collegare BME280 e BMP280 ad Arduino: indirizzo I2C 0x76/0x77, libreria Adafruit, calcolo dell'altitudine, avviso 3,3 V, stazione meteo ESP32 e codice Pico.
Il BME280 è un sensore ambientale digitale prodotto da Bosch che misura temperatura, umidità relativa e pressione atmosferica in un unico chip minuscolo. Per usarlo con Arduino ti bastano quattro fili (VCC, GND, SDA, SCL) e la libreria Adafruit BME280; con poche righe di codice vedi i valori in °C, % e hPa nel Monitor seriale. Dato che misura la pressione, può anche calcolare la tua altezza sul livello del mare, cioè l'altitudine. Il suo fratello, il BMP280, è quasi identico a vederlo ma non misura l'umidità: fornisce solo temperatura e pressione.
In questa guida scoprirai la differenza tra i due sensori, perché l'indirizzo I2C a volte è 0x76 e a volte 0x77, come collegarli ad Arduino Uno, ESP32 e Raspberry Pi Pico, come funziona la formula dell'altitudine e come scegliere la giusta pressione al livello del mare. Poi costruirai una mini stazione meteo con ESP32 che si apre sul telefono, farai girare sul Pico un driver MicroPython senza librerie e vedrai come un solo sketch smaschera il diffusissimo problema del "BMP280 venduto come BME280".

Che cos'è il BME280 e come funziona?
Nel BME280 ci sono tre elementi di misura. Il sensore di pressione misura, con effetto piezoresistivo, quanto si flette una sottile membrana di silicio sotto la spinta dell'aria. Il sensore di umidità è uno strato di polimero la cui capacità cambia man mano che assorbe l'umidità dell'aria. Il sensore di temperatura fornisce la temperatura ambiente e serve anche a correggere le altre due misure. Ogni chip viene calibrato singolarmente in fabbrica e i coefficienti vengono salvati nella sua memoria interna; la libreria li legge all'avvio e converte i valori grezzi in unità reali con le formule del datasheet. Il forellino nel coperchio metallico lascia arrivare l'aria al sensore, quindi non coprirlo mai con nastro adesivo o colla.
| Caratteristica | BME280 | BMP280 |
|---|---|---|
| Misura | Temperatura, umidità, pressione | Temperatura, pressione |
| Temperatura | -40…+85 °C, ±1 °C (±0,5 °C a 25 °C) | -40…+85 °C, ±1 °C (±0,5 °C a 25 °C) |
| Umidità relativa | 0–100 %, ±3 % | No |
| Campo di pressione | 300–1100 hPa | 300–1100 hPa |
| Precisione di pressione | Assoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m) | Assoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m) |
| Tensione di alimentazione del chip | 1,71–3,6 V | 1,71–3,6 V |
| Corrente (1 lettura al secondo) | 3,6 µA (tutte e tre le misure) | 2,7 µA |
| Corrente in sleep | 0,1 µA | 0,1 µA |
| Interfaccia | I2C (fino a 3,4 MHz) e SPI (fino a 10 MHz) | I2C e SPI |
| Chip ID (registro 0xD0) | 0x60 | 0x58 |
| Dimensioni del chip | 2,5 × 2,5 mm (quadrato) | 2,0 × 2,5 mm (rettangolare) |
In breve, il BMP280 è un BME280 un po' più economico senza sensore di umidità; le sue misure di pressione e temperatura sono altrettanto buone. Se ti servono solo l'altitudine o la pressione atmosferica, basta un BMP280. Per i progetti in cui l'umidità conta, come una stazione meteo, una serra o il monitoraggio del clima di una stanza, scegli il BME280. Un gradino più su, il BME680/BME688 aggiunge un sensore di gas che rileva i composti organici volatili (COV) nell'aria, ma costa diverse volte di più.
BME280 o DHT11/DHT22?
| Caratteristica | DHT11 | DHT22 | BME280 |
|---|---|---|---|
| Campo e precisione di temperatura | 0–50 °C, ±2 °C | -40…+80 °C, ±0,5 °C | -40…+85 °C, ±1 °C |
| Precisione di umidità | ±5 % | ±2–5 % | ±3 % |
| Pressione e altitudine | No | No | Sì |
| Lettura più rapida | 1 al secondo | 1 ogni 2 secondi | Decine al secondo |
| Collegamento | Un solo filo dati | Un solo filo dati | I2C o SPI |
| Corrente (durante la misura) | ≈ 1 mA | ≈ 1,5 mA | Meno di 1 mA |
I sensori DHT sono economici e semplici, ma lenti, ogni tanto restituiscono errori di lettura e non misurano la pressione. Il BME280 condivide lo stesso bus I2C con altri dispositivi come un display, in sleep non consuma quasi nulla ed è ideale per i progetti che funzionano mesi a batteria. Per i dettagli sul DHT11 leggi Sensore di temperatura e umidità DHT11, e per vedere tutte le opzioni a confronto il confronto dei sensori di temperatura.
Tipi di modulo e l'avviso sui 3,3 V
Il chip nudo è così piccolo che si usa sempre montato su un modulo, e i tipi più diffusi sono due. I moduli a 6 pin (di solito viola, venduti come GY-BME280-3.3 o GY-BMP280-3.3) hanno i pin VCC, GND, SCL, SDA, CSB e SDO; la maggior parte non ha regolatore, ed è proprio quello che indica il 3.3 nel nome: alimentali solo a 3,3 V. I moduli a 4 pin (VIN, GND, SCL, SDA) di solito montano un piccolo regolatore da 3,3 V e spesso transistor traslatori di livello per le linee I2C, quindi possono andare sul pin 5V dell'Arduino Uno. Se non sei sicuro di quale tipo hai, cerca sulla scheda un piccolo chip regolatore a tre piedini; se non c'è, usa i 3,3 V.
Collegamento del BME280: Arduino Uno, ESP32 e Pico
| Pin del BME280 | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC / VIN | 3.3V (6 pin) o 5V (4 pin, con regolatore) | 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 pin) | 3.3V (seleziona l'I2C) | 3V3 | 3V3 |
| SDO (6 pin) | Libero o GND: 0x76, 3.3V: 0x77 | Libero o GND: 0x76, 3V3: 0x77 | Libero o GND: 0x76, 3V3: 0x77 |
L'indirizzo è il punto in cui si blocca la maggior parte delle persone. Se il pin SDO del chip è a GND l'indirizzo è 0x76; se è a 3,3 V è 0x77. La maggior parte dei moduli economici porta SDO a GND tramite una resistenza e quindi usa 0x76, mentre le schede di Adafruit usano 0x77, e la libreria prova 0x77 come impostazione predefinita. Per questo conviene scrivere l'indirizzo in modo esplicito nel codice. Se all'accensione il pin CSB è a GND, il chip passa in modalità SPI e non risponde più in I2C; se usi l'I2C, collega CSB a 3,3 V o assicurati che il modulo lo porti già alto. Trovi i pin I2C della tua scheda nello strumento Pinout e il funzionamento del bus in Che cos'è l'I2C?.
Se vuoi due sensori sullo stesso bus, collega il pin SDO di uno dei due a 3,3 V per portare il suo indirizzo a 0x77; sui moduli a 4 pin di solito si fa con un ponticello di stagno sul retro. Per più di due sensori è meglio l'SPI: SCL va a SCK (13 sull'Uno), SDA a MOSI (11), SDO a MISO (12) e il pin CSB di ogni sensore a un proprio pin digitale; nel codice basta dichiarare l'oggetto come Adafruit_BME280 bme(10);. Dato che l'Uno a 5 V pilota direttamente le linee SPI, tra lui e un modulo da 3,3 V serve assolutamente un traslatore di livello.
Installare la libreria Adafruit BME280
- Nell'Arduino IDE apri Strumenti > Gestisci librerie e cerca Adafruit BME280.
- Quando premi Installa, scegli Install all nella finestra che chiede delle dipendenze, così vengono installate anche Adafruit Unified Sensor e Adafruit BusIO.
- Se il tuo sensore è un BMP280, installa allo stesso modo la libreria Adafruit BMP280; la libreria del BME280 non riconosce il BMP280.
- Se vuoi, apri File > Esempi > Adafruit BME280 Library > bme280test, ma non dimenticare di scrivere l'indirizzo (0x76) nella riga begin().
Primo sketch: leggere temperatura, umidità e pressione con il 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}| Funzione | Che cosa fa |
|---|---|
| bme.begin(0x76) | Avvia il sensore; restituisce true se un dispositivo risponde all'indirizzo e il suo chip ID è 0x60 |
| readTemperature() | Temperatura, °C |
| readHumidity() | Umidità relativa, % |
| readPressure() | Pressione, Pa (divisa per 100 dà hPa) |
| readAltitude(P0) | Altezza rispetto alla pressione al livello del mare P0 (hPa), in metri |
| seaLevelForAltitude(altitudine, P) | Pressione al livello del mare a partire da un'altitudine nota, hPa |
| sensorID() | Il chip ID letto: 0x60 BME280, 0x58 BMP280 |
| setTemperatureCompensation(x) | Aggiunge x °C a ogni lettura di temperatura; umidità e pressione vengono corrette di conseguenza |
Dopo aver caricato lo sketch e aperto il Monitor seriale a 9600 baud, in una stanza vedrai valori di circa 23,4 °C, 45 % di umidità e 1009,8 hPa. La pressione cambia lentamente nel corso delle ore; se aliti sul sensore vedrai l'umidità salire in pochi secondi, se lo tocchi con un dito la temperatura aumenta. Per impostazione predefinita la libreria misura in continuo in modalità normale con il sovracampionamento più alto (x16); è l'ideale per una prima prova, ma come vedrai sotto, un'altra impostazione dà risultati più precisi nelle misure meteo di lungo periodo.
Modalità di misura: forced, normal e l'impostazione giusta
Il BME280 ha tre modalità. In modalità sleep non misura e assorbe 0,1 µA. In modalità forced esegue una sola misura e torna a dormire; per ogni nuovo valore chiami takeForcedMeasurement(). In modalità normal misura in continuo da solo con il tempo di attesa che imposti. Il sovracampionamento (oversampling) misura più volte lo stesso valore e ne fa la media per ridurre il rumore, mentre il filtro IIR smussa i salti improvvisi di pressione (una porta sbattuta, una raffica di vento). Nel datasheet Bosch consiglia queste impostazioni a seconda dell'uso:
| Uso | Modalità | Sovracampionamento (pressione / temperatura / umidità) | Filtro IIR | Corrente media |
|---|---|---|---|---|
| Monitoraggio meteo | Forced, 1 misura al minuto | x1 / x1 / x1 | Disattivato | ≈ 0,16 µA |
| Misura dell'umidità | Forced, 1 misura al secondo | Saltata / x1 / x1 | Disattivato | ≈ 2,9 µA |
| Navigazione indoor (piani, ascensore) | Normal, attesa di 0,5 ms | x16 / x2 / x1 | 16 | ≈ 633 µA |
Pressione al livello del mare e calcolo dell'altitudine
La pressione dell'aria diminuisce salendo di quota, quindi l'altitudine si può calcolare dalla pressione misurata. La libreria usa questa formula barometrica: h = 44330 × (1 − (P / P0)^0,1903). Qui P è la pressione che misuri e P0 la pressione attuale al livello del mare (entrambe in hPa). L'atmosfera standard assume P0 = 1013,25 hPa e, vicino al livello del mare, una differenza di 1 hPa corrisponde a circa 8,3 metri.
Il problema è che P0 non è fissa: varia grosso modo tra 990 e 1035 hPa a seconda del tempo. Se oggi il valore reale è 1023 hPa e lasci 1013,25 nel codice, il sensore indicherà un'altitudine più bassa di circa 80 metri. Per risultati precisi devi tenere P0 aggiornata: usa la "pressione ridotta al livello del mare" pubblicata dai servizi meteo oppure il valore Q del METAR dell'aeroporto più vicino (per esempio Q1018, cioè 1018 hPa). Puoi anche fare il contrario: se conosci l'altitudine del luogo in cui ti trovi, calcoli P0 con seaLevelForAltitude(altitudine, pressione). Per esempio, se ad Ankara (circa 938 m) il sensore misura 905 hPa, la pressione ridotta al livello del mare è di circa 1012,6 hPa, proprio il numero che vedi nelle app meteo.
Per l'altitudine assoluta, la precisione assoluta di ±1 hPa significa un'incertezza di circa ±8 metri. Nelle misure relative, invece, il sensore è molto migliore: ±0,12 hPa ≈ ±1 m. Un piano di un palazzo è alto circa 3 metri, cioè 0,36 hPa, quindi il BME280 capisce senza problemi a che piano sei o se un ascensore si muove. Lo sketch qui sotto prende come riferimento la media di 20 misure all'avvio, poi stampa l'altezza rispetto a quel punto e la pressione al livello del mare calcolata da un'altitudine nota:
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}Se sollevi la scheda da terra fin sopra la testa, vedrai il valore "Baslangica gore" (rispetto alla partenza) salire di circa 2 metri. Dato che la pressione atmosferica cambia di qualche hPa durante la giornata, questa misura relativa deriva dopo alcune ore, quindi in un uso prolungato devi rinnovare il riferimento di tanto in tanto. Per rendere le letture ancora più stabili puoi aggiungere la media mobile dell'articolo Filtrare i dati dei sensori.
Mini stazione meteo con ESP32: una pagina web da aprire sul telefono
Grazie al Wi-Fi dell'ESP32 puoi vedere le letture del BME280 su una pagina web da qualsiasi telefono o computer della stessa rete. Lo sketch qui sotto usa la libreria WebServer inclusa nel core ESP32, quindi non servono librerie aggiuntive. La pagina principale si carica una volta, poi un piccolo JavaScript al suo interno chiede il JSON a /veri ogni 5 secondi e aggiorna i valori senza ricaricare la pagina. Il sensore lavora in modalità forced, quindi misura solo quando qualcuno guarda la pagina, e la pressione viene mostrata ridotta al livello del mare così puoi confrontarla con le previsioni del tempo. Se è la prima volta che usi l'ESP32, parti da Che cos'è l'ESP32?.
- Collega il BME280 come nella tabella: VCC a 3V3, SDA a GPIO 21, SCL a GPIO 22.
- Scrivi i dati della tua rete nei campi WIFI_ADI (nome della rete) e WIFI_SIFRE (password) del codice e l'altitudine del tuo luogo in RAKIM_M.
- Seleziona ESP32 Dev Module come scheda e carica lo sketch.
- Apri il Monitor seriale a 115200 baud; appena connesso, mostra l'indirizzo IP.
- Digita quell'indirizzo (per esempio 192.168.1.42) nel browser di un telefono collegato alla stessa rete Wi-Fi; compaiono le schede di temperatura, umidità e pressione.
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 con il Raspberry Pi Pico (MicroPython)
MicroPython non include un modulo per il BME280. Invece di scaricare un file driver, il codice qui sotto si porta dietro un piccolo driver: legge i coefficienti di calibrazione, fa eseguire al sensore una singola misura in modalità forced e calcola il risultato con le formule del datasheet. Dato che controlla il chip ID, funziona anche con il BMP280 e salta da solo la riga dell'umidità. Collega il sensore a GP4 (SDA), GP5 (SCL) e 3V3(OUT) e salva il codice sul Pico da Thonny con il nome main.py. Se il Pico è una novità per te, Che cos'è il Raspberry Pi Pico? e Le basi di MicroPython ti semplificheranno la vita.
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)Alcuni dettagli del codice meritano attenzione. L'impostazione dell'umidità (registro 0xF2) diventa effettiva solo dopo una scrittura in 0xF4, perciò si invia prima l'impostazione dell'umidità e poi il comando di misura. Il valore 0x25 scritto in 0xF4 significa "temperatura x1, pressione x1, modalità forced"; con queste impostazioni una misura dura al massimo circa 10 ms, quindi attendere 15 ms basta. Provato con i valori di calibrazione di esempio del datasheet del BMP280 di Bosch, il codice restituisce 25,08 °C e 1006,5 hPa: i suoi calcoli coincidono esattamente con le formule di Bosch.
Il BMP280 venduto come BME280: quale sensore hai davvero?
Poiché i due chip si montano sullo stesso circuito stampato, alcuni venditori vendono moduli BMP280 come BME280; a volte sulla scheda c'è scritto solo "BME/BMP280". Il sintomo è sempre lo stesso: la libreria Adafruit BME280 stampa "Could not find a valid BME280 sensor, check wiring, address, sensor ID!" e subito sotto SensorID was: 0x58. Altre librerie non danno errori, ma indicano sempre un'umidità di 0 o nan. I collegamenti non c'entrano: il tuo chip è un BMP280, che non misura l'umidità.


- Guarda la forma del chip: se il coperchio metallico è quadrato (2,5 × 2,5 mm) è un BME280; se è chiaramente rettangolare (2,0 × 2,5 mm) è un BMP280. Con lo zoom della fotocamera del telefono la differenza si vede facilmente.
- Leggi il chip ID: il metodo più affidabile è lo sketch qui sotto; legge l'identificativo nel registro 0xD0 del chip e ti dice di quale sensore si tratta.
- Occhio al prezzo: un vero BME280 costa sensibilmente più di un BMP280; diffida dei moduli "BME280" venduti molto al di sotto del prezzo di mercato.
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}Se il risultato è 0x58, niente paura: le misure di temperatura e pressione del BMP280 sono buone quanto quelle del BME280. Installa la libreria Adafruit BMP280 e usa lo sketch qui sotto; se ti serve l'umidità, aggiungi al progetto un DHT22 separato o restituisci il prodotto. Ogni tanto capitano anche esemplari di BMP280 con ID 0x56 o 0x57; per questi scrivi la riga begin come 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}Idee di progetto con il BME280
- Stazione meteo da scrivania: mostra temperatura, umidità e pressione su un display OLED o su un LCD I2C collegati allo stesso bus I2C.
- Previsioni con il barometro: registra la pressione ogni ora; un calo di oltre 2 hPa in 3 ore di solito annuncia un peggioramento del tempo, mentre una salita costante indica cielo sereno.
- Punto di rugiada e allarme muffa: calcola il punto di rugiada con la formula di Magnus (a = 17,62, b = 243,12 °C) e lancia un avviso quando la temperatura della parete gli si avvicina.
- Serra intelligente: aziona una ventola o una pompa di nebulizzazione in base a umidità e temperatura; i dettagli nel progetto di serra intelligente con Arduino.
- Data logger: salva le letture su un modulo scheda SD o, con un ESP32, su Google Fogli e ricava un grafico settimanale.
- Sensore per la casa smart: invia i valori da un ESP32 a Home Assistant tramite MQTT.
- Stazione esterna a batteria: risveglia l'ESP32 dal deep sleep ogni 10 minuti; in sleep il BME280 assorbe solo 0,1 µA.
- Contapiani: usa lo sketch dell'altitudine relativa per mostrare a che piano sei arrivato in ascensore o sulle scale.
Errori comuni e soluzioni
| Sintomo | Causa probabile | Soluzione |
|---|---|---|
| "Could not find a valid BME280 sensor", SensorID 0x0 o 0xFF | Indirizzo sbagliato o errore di collegamento | Usa begin(0x76), verifica che SDA e SCL non siano invertiti e che GND sia collegato, esegui uno scanner I2C |
| Stesso errore, SensorID 0x58 | Il chip in realtà è un BMP280 | Usa la libreria Adafruit BMP280 e aggiungi un altro sensore per l'umidità |
| fatal error: Adafruit_Sensor.h: No such file or directory | Manca una libreria dipendente | Installa la libreria Adafruit Unified Sensor |
| I valori sono nan | Nessuna nuova misura richiesta in modalità forced oppure begin() fallito | Chiama takeForcedMeasurement() prima di ogni lettura e controlla il risultato di begin() |
| Temperatura più alta di 1–3 °C | Autoriscaldamento per misura continua, calore di un ESP32 o di un regolatore vicino | Passa alla modalità forced, allontana il sensore dalla scheda, se serve usa setTemperatureCompensation() |
| Pressione bassa, intorno a 900 hPa | È la pressione della stazione; scende quando l'altitudine aumenta | Riducila al livello del mare con seaLevelForAltitude() per confrontarla con le previsioni |
| Altitudine sbagliata di decine di metri | Pressione al livello del mare lasciata a 1013,25 | Inserisci la P0 attuale (QNH) o calibra con un'altitudine nota |
| Blocchi casuali con cavi lunghi | Il bus I2C è lungo e disturbato | Tieni il cavo sotto i 50 cm, abbassa la velocità I2C o usa l'SPI |
Il BME280 svolge su una sola piccola scheda tutte le misure di base di una stazione meteo: prima verifica indirizzo e chip ID, poi scegli la modalità di misura in base al tuo obiettivo e, per l'altitudine, tieni aggiornata la pressione al livello del mare. Nell'app BlueGrays trovi progetti da abbinare a questa guida, come la misura di temperatura e umidità con DHT11 e DHT22, display meteo con ESP32, un registratore di temperatura e un web server ESP32, ognuno con schemi elettrici e codice passo passo.
Domande frequenti
Qual è la differenza tra BME280 e BMP280?
Il BME280 misura temperatura, umidità relativa e pressione; il BMP280 misura solo temperatura e pressione e non ha il sensore di umidità. La precisione di pressione e temperatura è la stessa. Anche i chip sono diversi: il BME280 è quadrato (2,5 × 2,5 mm), il BMP280 rettangolare (2,0 × 2,5 mm), e i loro chip ID sono 0x60 e 0x58.
L'indirizzo I2C del BME280 è 0x76 o 0x77?
È 0x76 quando il pin SDO è collegato a GND e 0x77 quando è collegato a 3,3 V. La maggior parte dei moduli economici usa 0x76, le schede Adafruit 0x77. La libreria Adafruit prova 0x77 come impostazione predefinita, quindi potresti dover scrivere bme.begin(0x76) nel codice; nel dubbio, esegui uno scanner I2C.
Il BME280 funziona a 5 V?
Il chip in sé regge al massimo 3,6 V. La maggior parte dei moduli a 4 pin con il pin VIN ha un regolatore e quindi si può collegare al 5V. I moduli a 6 pin da 3,3 V senza regolatore vanno alimentati solo a 3,3 V; i 5 V possono danneggiare il sensore.
Come si risolve l'errore "Could not find a valid BME280 sensor"?
Guarda prima il valore SensorID stampato sotto l'errore. Se è 0x58 il tuo sensore è un BMP280 e devi usare la libreria Adafruit BMP280. Se è 0x0 o 0xFF si tratta di un problema di indirizzo o di collegamento: prova begin(0x76) e assicurati che SDA e SCL non siano invertiti e che il pin CSB sia a 3,3 V.
Quanto è preciso il BME280 nel misurare l'altitudine?
Misura le variazioni di altezza relativa con una precisione di circa ±1 m, sufficiente a rilevare un cambio di piano. L'altitudine assoluta dipende dalla pressione al livello del mare che inserisci; un errore di 1 hPa sposta il risultato di circa 8 m. Inserendo il QNH attuale o calibrando su un'altitudine nota puoi arrivare a pochi metri.
Perché il mio BME280 segna una temperatura troppo alta?
Le cause più comuni sono l'autoriscaldamento dovuto alla misura continua e il calore di componenti vicini come l'ESP32 o un regolatore. Passa alla modalità forced, fai qualche misura al minuto e allontana il sensore dalla scheda con un cavo. Se resta uno scarto costante, confrontalo con un termometro affidabile e correggilo con setTemperatureCompensation().
Progetti da realizzare dopo questo articolo
Vedi tutti i progetti
Temperatura e umidità con DHT11
Quanti gradi ci sono nella tua stanza, e l'aria è umida o secca? Il sensore DHT11 misura temperatura e umidità, e l'Arduino scrive i valori su uno schermo LCD a due righe, aggiornandoli ogni paio di s

ESP32 DHT22 Temperatura e umidità (con display LCD)
Si tratta di un progetto che misura la temperatura e l'umidità dell'ambiente tramite il sensore DHT22 e le visualizza in tempo reale su un display LCD I2C 16x2. I dati vengono letti dal sensore utilizzando il protocollo one-wire tramite la libreria Adafruit DHT. Questo progetto costituisce la base per stazioni meteorologiche IoT, sistemi di automazione domestica intelligente o sistemi di monitoraggio ambientale nelle serre. La comunicazione con il DHT22 avviene tramite il pin GPIO 4 dell'ESP32.

Orologio a matrice di punti, calendario e stazione meteo (MAX7219, DS1307)
Un pannello a scritte scorrevoli per la scrivania o la parete che mostra a turno l'ora, la data e il clima della stanza. Sul display LED 8x32 compaiono prima la temperatura in Celsius e Fahrenheit, po

Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
Costruisci un data logger di temperatura con timestamp usando ESP32! Leggi temperatura/umidità dal DHT22 ogni minuto, ottieni l'ora reale dal DS1307 RTC e registra su scheda microSD in formato CSV. L'OLED mostra dal vivo temperatura (font grande), percentuale di umidità, timestamp e contatore di log. Il file `/temp_log.csv` sulla scheda SD si apre in Excel, Google Sheets o Python pandas per l'analisi — perfetto per il monitoraggio di serre, tracciamento della temperatura domestica, raccolta

ESP32 HTTPClient + API meteo (con display OLED SSD1306)
In questo progetto, utilizzando l'ESP32, effettuiamo una chiamata REST all'API meteo (wttr.in) tramite Internet utilizzando `HTTPClient.h`. A differenza della precedente versione con LCD I2C, qui utilizziamo un display OLED SSD1306 (128×64), che consente di utilizzare caratteri di grandi dimensioni, icone vettoriali e una ricca presentazione visiva su un unico schermo. Per le condizioni meteorologiche, 7 diverse icone vettoriali (soleggiato, parzialmente nuvoloso, nuvoloso, piovoso, nevoso, temp

Server web asincrono ESP32 (con indicazione dell'IP sul display LCD)
In questo progetto trasformiamo l'ESP32 in un **server web asincrono** che potrete controllare dal vostro telefono o computer collegato alla stessa rete Wi-Fi. Grazie alla libreria ESPAsyncWebServer, il server è in grado di elaborare più richieste contemporaneamente (a differenza del classico `WebServer.h`, che si blocca su una singola richiesta).

ESP32 HTTPClient + API meteo (con schermo LCD)
In questo progetto, utilizzando l'ESP32, effettuiamo una chiamata REST all'API meteo (wttr.in) tramite Internet utilizzando `HTTPClient.h`. Analizziamo la risposta JSON restituita tramite ArduinoJson v7 e visualizziamo le informazioni relative a città, temperatura, umidità, condizioni meteorologiche e vento sul display LCD I2C sia in turco che in inglese. wttr.in è gratuito e non richiede una chiave API: basta digitare il nome di una città qualsiasi per ottenere le condizioni meteorologiche in t

Schermo LCD I2C per ESP32 (16x2)
In questo progetto visualizziamo del testo collegando un display LCD a 16x2 caratteri all'ESP32 tramite il protocollo I2C. Grazie all'I2C possiamo controllare il display utilizzando solo 2 pin di dati (SDA e SCL); si elimina così lo spreco dei 6+ pin tipici del collegamento parallelo classico. Il codice stampa un messaggio fisso sulla prima riga e un contatore che aumenta ogni secondo sulla seconda riga. Inoltre, all'inizio, eseguendo lo scanner I2C, stampiamo l'indirizzo del display sul Serial
Altri articoli
App BlueGrays
Costruisci questo circuito passo passo sul telefono
Schema, codice ed elenco componenti in un’unica schermata. Oltre 160 progetti Arduino, ESP32 e Pico da realizzare.
Inquadra con il telefono
Punta la fotocamera sul codice: si apre lo store del tuo telefono.
oppure apri lo store

