Componenti · 14 min di lettura

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".

Modulo sensore BME280 di temperatura, umidità e pressione
Modulo BME280: il minuscolo chip con coperchio metallico misura temperatura, umidità e pressione e si collega via I2C o SPI.

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.

CaratteristicaBME280BMP280
MisuraTemperatura, umidità, pressioneTemperatura, 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à relativa0–100 %, ±3 %No
Campo di pressione300–1100 hPa300–1100 hPa
Precisione di pressioneAssoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m)Assoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m)
Tensione di alimentazione del chip1,71–3,6 V1,71–3,6 V
Corrente (1 lettura al secondo)3,6 µA (tutte e tre le misure)2,7 µA
Corrente in sleep0,1 µA0,1 µA
InterfacciaI2C (fino a 3,4 MHz) e SPI (fino a 10 MHz)I2C e SPI
Chip ID (registro 0xD0)0x600x58
Dimensioni del chip2,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?

CaratteristicaDHT11DHT22BME280
Campo e precisione di temperatura0–50 °C, ±2 °C-40…+80 °C, ±0,5 °C-40…+85 °C, ±1 °C
Precisione di umidità±5 %±2–5 %±3 %
Pressione e altitudineNoNoSì
Lettura più rapida1 al secondo1 ogni 2 secondiDecine al secondo
CollegamentoUn solo filo datiUn solo filo datiI2C o SPI
Corrente (durante la misura)≈ 1 mA≈ 1,5 mAMeno 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.

Collegare un modulo da 3,3 V senza regolatore al pin 5V può danneggiare il sensore; il limite assoluto del chip è 4,25 V. Un sensore danneggiato non sempre muore del tutto: a volte dà temperature spostate di qualche grado o pressioni incoerenti, e questo rende il guasto più difficile da individuare.

Collegamento del BME280: Arduino Uno, ESP32 e Pico

Pin del BME280Arduino UnoESP32Raspberry Pi Pico
VCC / VIN3.3V (6 pin) o 5V (4 pin, con regolatore)3V33V3(OUT), pin 36
GNDGNDGNDGND, pin 38
SCLA5GPIO 22GP5, pin 7
SDAA4GPIO 21GP4, pin 6
CSB (6 pin)3.3V (seleziona l'I2C)3V33V3
SDO (6 pin)Libero o GND: 0x76, 3.3V: 0x77Libero o GND: 0x76, 3V3: 0x77Libero 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.

L'Arduino Uno lavora a 5 V e la libreria Wire attiva le resistenze di pull-up interne di A4 e A5 verso i 5 V. Un modulo a 6 pin da 3,3 V di solito funziona lo stesso, perché le pull-up del modulo tengono il bus intorno ai 3,3 V, ma per un progetto definitivo la scelta più sicura è un modulo a 4 pin con regolatore o un convertitore di livello logico. ESP32 e Pico funzionano già a 3,3 V, quindi non hanno questo problema.

Installare la libreria Adafruit BME280

  1. Nell'Arduino IDE apri Strumenti > Gestisci librerie e cerca Adafruit BME280.
  2. Quando premi Installa, scegli Install all nella finestra che chiede delle dipendenze, così vengono installate anche Adafruit Unified Sensor e Adafruit BusIO.
  3. Se il tuo sensore è un BMP280, installa allo stesso modo la libreria Adafruit BMP280; la libreria del BME280 non riconosce il BMP280.
  4. 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

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}
FunzioneChe 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:

UsoModalitàSovracampionamento (pressione / temperatura / umidità)Filtro IIRCorrente media
Monitoraggio meteoForced, 1 misura al minutox1 / x1 / x1Disattivato≈ 0,16 µA
Misura dell'umiditàForced, 1 misura al secondoSaltata / x1 / x1Disattivato≈ 2,9 µA
Navigazione indoor (piani, ascensore)Normal, attesa di 0,5 msx16 / x2 / x116≈ 633 µA
Quando il sensore misura senza sosta, il chip e la scheda si scaldano leggermente; è il cosiddetto autoriscaldamento. Se misuri la temperatura di una stanza o dell'esterno, usa la modalità forced e accontentati di qualche misura al minuto. Se la lettura resta comunque più alta di una quantità costante rispetto a un termometro affidabile, puoi aggiungere una correzione come bme.setTemperatureCompensation(-1.0);.

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:

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}

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?.

  1. Collega il BME280 come nella tabella: VCC a 3V3, SDA a GPIO 21, SCL a GPIO 22.
  2. 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.
  3. Seleziona ESP32 Dev Module come scheda e carica lo sketch.
  4. Apri il Monitor seriale a 115200 baud; appena connesso, mostra l'indirizzo IP.
  5. 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.
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}
L'ESP32 si scalda di qualche grado mentre funziona e, se metti il sensore subito accanto alla scheda, quel calore falsa la misura. Allontana il BME280 dalla scheda con un cavo di 10–15 cm, mettilo vicino alle feritoie di ventilazione del contenitore e tienilo al riparo dal sole. Per un pannello più evoluto con grafici e pulsanti passa a Web server ESP32 e WebSocket.

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.

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)

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à.

BME280
BME280
BMP280
BMP280
  • 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.
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}

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).

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}

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

SintomoCausa probabileSoluzione
"Could not find a valid BME280 sensor", SensorID 0x0 o 0xFFIndirizzo sbagliato o errore di collegamentoUsa begin(0x76), verifica che SDA e SCL non siano invertiti e che GND sia collegato, esegui uno scanner I2C
Stesso errore, SensorID 0x58Il chip in realtà è un BMP280Usa la libreria Adafruit BMP280 e aggiungi un altro sensore per l'umidità
fatal error: Adafruit_Sensor.h: No such file or directoryManca una libreria dipendenteInstalla la libreria Adafruit Unified Sensor
I valori sono nanNessuna nuova misura richiesta in modalità forced oppure begin() fallitoChiama takeForcedMeasurement() prima di ogni lettura e controlla il risultato di begin()
Temperatura più alta di 1–3 °CAutoriscaldamento per misura continua, calore di un ESP32 o di un regolatore vicinoPassa 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 aumentaRiducila al livello del mare con seaLevelForAltitude() per confrontarla con le previsioni
Altitudine sbagliata di decine di metriPressione al livello del mare lasciata a 1013,25Inserisci la P0 attuale (QNH) o calibra con un'altitudine nota
Blocchi casuali con cavi lunghiIl bus I2C è lungo e disturbatoTieni il cavo sotto i 50 cm, abbassa la velocità I2C o usa l'SPI
Non chiudere il sensore in una scatola sigillata senza aria; per misurare umidità e pressione l'aria deve raggiungere il chip. All'esterno, un contenitore a lamelle aperto in basso, che ripari da pioggia e sole diretto (come le capannine delle stazioni meteo), dà i risultati più precisi. Se il sensore si bagna per la condensa, può indicare il 100 % di umidità per un po'; una volta asciutto torna normale.

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().

Vedi tutti i progetti
Temperatura e umidità con DHT11
#55Intermedio

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

4.7(47)
64
ESP32 DHT22 Temperatura e umidità (con display LCD)
#117Intermedio

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.

4.8(38)
54
Orologio a matrice di punti, calendario e stazione meteo (MAX7219, DS1307)
#85Intermedio
Premium

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

5.0(50)
66
Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
#144Avanzato
Premium

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

4.7(7)
12
ESP32 HTTPClient + API meteo (con display OLED SSD1306)
#134Avanzato
Premium

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

4.3(10)
18
Server web asincrono ESP32 (con indicazione dell'IP sul display LCD)
#129Avanzato
Premium

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).

4.8(16)
26
ESP32 HTTPClient + API meteo (con schermo LCD)
#133Avanzato
Premium

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

4.7(13)
20
Schermo LCD I2C per ESP32 (16x2)
#119Intermedio
Premium

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

4.9(23)
40