BME280 Arduino: temperatura, humedad, presión y altitud (BMP280)
Cómo conectar el BME280 y el BMP280 a Arduino: dirección I2C 0x76/0x77, librería Adafruit, cálculo de altitud, aviso de 3,3 V, estación ESP32 y código Pico.
El BME280 es un sensor ambiental digital fabricado por Bosch que mide temperatura, humedad relativa y presión atmosférica en un solo chip diminuto. Para usarlo con Arduino solo necesitas cuatro cables (VCC, GND, SDA, SCL) y la librería Adafruit BME280; con unas pocas líneas de código verás valores en °C, % y hPa en el Monitor Serie. Como mide la presión, también puede calcular tu altura sobre el nivel del mar, es decir, la altitud. Su hermano, el BMP280, es casi idéntico a la vista pero no mide la humedad; solo da temperatura y presión.
En esta guía aprenderás la diferencia entre los dos sensores, por qué la dirección I2C a veces es 0x76 y a veces 0x77, cómo conectarlos a Arduino Uno, ESP32 y Raspberry Pi Pico, cómo funciona la fórmula de altitud y cómo elegir la presión a nivel del mar correcta. Después montarás una miniestación meteorológica con ESP32 que se abre en tu móvil, ejecutarás en la Pico un driver de MicroPython sin librerías y verás cómo un solo sketch destapa el problema tan frecuente del "BMP280 vendido como BME280".

¿Qué es el BME280 y cómo funciona?
Dentro del BME280 hay tres elementos de medida. El sensor de presión mide, por efecto piezorresistivo, cuánto se flexiona una fina membrana de silicio bajo el empuje del aire. El sensor de humedad es una capa de polímero cuya capacidad cambia a medida que absorbe la humedad del aire. El sensor de temperatura da la temperatura ambiente y además se usa para corregir las otras dos medidas. Cada chip se calibra uno por uno en fábrica y los coeficientes se guardan en su memoria interna; la librería los lee al arrancar y convierte los valores en bruto en unidades reales con las fórmulas de la hoja de datos. El pequeño orificio de la tapa metálica deja que el aire llegue al sensor, así que nunca lo tapes con cinta ni pegamento.
| Característica | BME280 | BMP280 |
|---|---|---|
| Mide | Temperatura, humedad, presión | Temperatura, presión |
| Temperatura | -40…+85 °C, ±1 °C (±0,5 °C a 25 °C) | -40…+85 °C, ±1 °C (±0,5 °C a 25 °C) |
| Humedad relativa | 0–100 %, ±3 % | No |
| Rango de presión | 300–1100 hPa | 300–1100 hPa |
| Precisión de presión | Absoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m) | Absoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m) |
| Tensión de alimentación del chip | 1,71–3,6 V | 1,71–3,6 V |
| Consumo (1 lectura por segundo) | 3,6 µA (las tres medidas) | 2,7 µA |
| Consumo en reposo | 0,1 µA | 0,1 µA |
| Interfaz | I2C (hasta 3,4 MHz) y SPI (hasta 10 MHz) | I2C y SPI |
| Chip ID (registro 0xD0) | 0x60 | 0x58 |
| Tamaño del chip | 2,5 × 2,5 mm (cuadrado) | 2,0 × 2,5 mm (rectangular) |
En resumen, el BMP280 es un BME280 algo más barato sin sensor de humedad; sus medidas de presión y temperatura son igual de buenas. Si solo necesitas altitud o presión atmosférica, te basta un BMP280. Para proyectos en los que la humedad importa, como una estación meteorológica, un invernadero o el control del clima de una habitación, elige el BME280. Un escalón por encima, el BME680/BME688 añade un sensor de gas que detecta compuestos orgánicos volátiles (COV) en el aire, pero cuesta varias veces más.
¿BME280 o DHT11/DHT22?
| Característica | DHT11 | DHT22 | BME280 |
|---|---|---|---|
| Rango y precisión de temperatura | 0–50 °C, ±2 °C | -40…+80 °C, ±0,5 °C | -40…+85 °C, ±1 °C |
| Precisión de humedad | ±5 % | ±2–5 % | ±3 % |
| Presión y altitud | No | No | Sí |
| Lectura más rápida | 1 por segundo | 1 cada 2 segundos | Decenas por segundo |
| Conexión | Un solo cable de datos | Un solo cable de datos | I2C o SPI |
| Consumo (midiendo) | ≈ 1 mA | ≈ 1,5 mA | Menos de 1 mA |
Los sensores DHT son baratos y sencillos, pero lentos, dan errores de lectura de vez en cuando y no miden la presión. El BME280 comparte el mismo bus I2C con otros dispositivos, como una pantalla, casi no consume nada en reposo y es ideal para proyectos que funcionan meses con pilas. Para los detalles del DHT11, consulta Sensor de temperatura y humedad DHT11, y para ver todas las opciones juntas, la comparativa de sensores de temperatura.
Tipos de módulo y el aviso de 3,3 V
El chip desnudo es tan pequeño que siempre se usa montado en un módulo, y hay dos tipos habituales. Los módulos de 6 pines (normalmente morados y vendidos como GY-BME280-3.3 o GY-BMP280-3.3) tienen los pines VCC, GND, SCL, SDA, CSB y SDO; la mayoría no lleva regulador, y eso es justo lo que indica el 3.3 del nombre: aliméntalos solo con 3,3 V. Los módulos de 4 pines (VIN, GND, SCL, SDA) suelen llevar un pequeño regulador de 3,3 V y a menudo transistores adaptadores de nivel para las líneas I2C, así que pueden ir al pin 5V del Arduino Uno. Si no sabes qué tipo tienes, busca en la placa un pequeño chip regulador de tres patas; si no lo hay, usa 3,3 V.
Conexión del BME280: Arduino Uno, ESP32 y Pico
| Pin del BME280 | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC / VIN | 3.3V (6 pines) o 5V (4 pines, con regulador) | 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 pines) | 3.3V (selecciona I2C) | 3V3 | 3V3 |
| SDO (6 pines) | Libre o GND: 0x76, 3.3V: 0x77 | Libre o GND: 0x76, 3V3: 0x77 | Libre o GND: 0x76, 3V3: 0x77 |
La dirección es donde más gente se atasca. Si el pin SDO del chip está a GND, la dirección es 0x76; si está a 3,3 V, es 0x77. La mayoría de los módulos baratos llevan SDO a GND mediante una resistencia, así que usan 0x76, mientras que las placas de Adafruit usan 0x77, y la librería prueba 0x77 por defecto. Por eso conviene escribir la dirección de forma explícita en el código. Si el pin CSB está a GND al encender, el chip pasa a modo SPI y deja de responder por I2C; si usas I2C, conecta CSB a 3,3 V o asegúrate de que el módulo ya lo lleva a nivel alto. Encontrarás los pines I2C de tu placa en la herramienta Pinout y el funcionamiento del bus en ¿Qué es I2C?.
Si quieres dos sensores en el mismo bus, conecta el pin SDO de uno de ellos a 3,3 V para cambiar su dirección a 0x77; en los módulos de 4 pines esto suele hacerse con un puente de soldadura en la parte trasera. Para más de dos sensores es mejor SPI: SCL va a SCK (13 en el Uno), SDA a MOSI (11), SDO a MISO (12) y el pin CSB de cada sensor a un pin digital propio; en el código basta con declarar el objeto como Adafruit_BME280 bme(10);. Como el Uno de 5 V excita directamente las líneas SPI, entre él y un módulo de 3,3 V es imprescindible un adaptador de nivel.
Instalar la librería Adafruit BME280
- En el Arduino IDE, abre Herramientas > Administrar bibliotecas y busca Adafruit BME280.
- Al pulsar Instalar, elige Install all en la ventana que pregunta por las dependencias, para que también se instalen Adafruit Unified Sensor y Adafruit BusIO.
- Si tu sensor es un BMP280, instala de la misma forma la librería Adafruit BMP280; la librería del BME280 no reconoce el BMP280.
- Si quieres, abre Archivo > Ejemplos > Adafruit BME280 Library > bme280test, pero no olvides poner la dirección (0x76) en la línea de begin().
Primer sketch: leer temperatura, humedad y presión con el 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}| Función | Qué hace |
|---|---|
| bme.begin(0x76) | Inicia el sensor; devuelve true si un dispositivo responde en la dirección y su chip ID es 0x60 |
| readTemperature() | Temperatura, °C |
| readHumidity() | Humedad relativa, % |
| readPressure() | Presión, Pa (entre 100 da hPa) |
| readAltitude(P0) | Altura respecto a la presión a nivel del mar P0 (hPa), en metros |
| seaLevelForAltitude(altitud, P) | Presión a nivel del mar a partir de una altitud conocida, hPa |
| sensorID() | El chip ID leído: 0x60 BME280, 0x58 BMP280 |
| setTemperatureCompensation(x) | Suma x °C a cada lectura de temperatura; la humedad y la presión se corrigen en consecuencia |
Al cargar el sketch y abrir el Monitor Serie a 9600 baudios, verás en condiciones de interior valores de unos 23,4 °C, 45 % de humedad y 1009,8 hPa. La presión cambia despacio a lo largo de las horas; si echas el aliento sobre el sensor verás subir la humedad en segundos, y si lo tocas con el dedo, la temperatura aumenta. Por defecto la librería mide de forma continua en modo normal con el sobremuestreo más alto (x16); es ideal para una primera prueba, pero como verás abajo, otro ajuste da resultados más precisos en mediciones meteorológicas de larga duración.
Modos de medida: forced, normal y el ajuste correcto
El BME280 tiene tres modos. En modo sleep no mide y consume 0,1 µA. En modo forced hace una sola medida y vuelve a dormir; para cada valor nuevo llamas a takeForcedMeasurement(). En modo normal mide continuamente por sí solo con el tiempo de espera que configures. El sobremuestreo (oversampling) mide el mismo valor varias veces y lo promedia para reducir el ruido, y el filtro IIR suaviza los saltos bruscos de presión (un portazo, una ráfaga de viento). En su hoja de datos, Bosch recomienda estos ajustes según el uso:
| Uso | Modo | Sobremuestreo (presión / temperatura / humedad) | Filtro IIR | Consumo medio |
|---|---|---|---|---|
| Monitorización meteorológica | Forced, 1 medida por minuto | x1 / x1 / x1 | Desactivado | ≈ 0,16 µA |
| Medida de humedad | Forced, 1 medida por segundo | Omitida / x1 / x1 | Desactivado | ≈ 2,9 µA |
| Navegación en interiores (pisos, ascensor) | Normal, espera de 0,5 ms | x16 / x2 / x1 | 16 | ≈ 633 µA |
Presión a nivel del mar y cálculo de la altitud
La presión del aire disminuye con la altura, así que la altitud se puede calcular a partir de la presión medida. La librería usa esta fórmula barométrica: h = 44330 × (1 − (P / P0)^0,1903). Aquí P es la presión que mides y P0 la presión a nivel del mar en ese momento (ambas en hPa). La atmósfera estándar toma P0 = 1013,25 hPa y, cerca del nivel del mar, una diferencia de 1 hPa equivale a unos 8,3 metros.
El problema es que P0 no es fija: varía más o menos entre 990 y 1035 hPa según el tiempo. Si hoy el valor real es 1023 hPa y dejas 1013,25 en el código, el sensor marcará una altitud unos 80 metros más baja. Para obtener resultados precisos tienes que mantener P0 actualizada: usa la "presión reducida al nivel del mar" que publican los servicios meteorológicos o el valor Q del METAR del aeropuerto más cercano (por ejemplo Q1018, es decir, 1018 hPa). También puedes hacerlo al revés: si conoces la altitud de tu ubicación, calcula P0 con seaLevelForAltitude(altitud, presión). Por ejemplo, si el sensor marca 905 hPa en Ankara (unos 938 m), la presión reducida al nivel del mar es de unos 1012,6 hPa, justo la cifra que ves en las apps del tiempo.
Para la altitud absoluta, la precisión absoluta de ±1 hPa supone una incertidumbre de unos ±8 metros. En las medidas relativas, en cambio, el sensor es mucho mejor: ±0,12 hPa ≈ ±1 m. Un piso de un edificio mide unos 3 metros, es decir, 0,36 hPa, así que el BME280 detecta sin problemas en qué planta estás o si un ascensor se mueve. El siguiente sketch toma como referencia la media de 20 medidas al arrancar y luego muestra la altura respecto a ese punto y la presión a nivel del mar calculada con una altitud conocida:
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}Si levantas la placa del suelo hasta por encima de tu cabeza, verás que el valor "Baslangica gore" (respecto al inicio) sube unos 2 metros. Como la presión atmosférica cambia unos cuantos hPa a lo largo del día, esta medida relativa deriva al cabo de unas horas, así que en un uso prolongado tendrás que renovar la referencia de vez en cuando. Para estabilizar aún más las lecturas puedes añadir la media móvil del artículo Filtrar datos de sensores.
Miniestación meteorológica con ESP32: una página web que abres en el móvil
Gracias al Wi-Fi del ESP32 puedes ver las lecturas del BME280 en una página web desde cualquier móvil u ordenador de la misma red. El sketch de abajo usa la librería WebServer que viene con el core del ESP32, así que no necesita librerías extra. La página principal se carga una vez y luego un pequeño JavaScript pide JSON a /veri cada 5 segundos y actualiza los valores sin recargar la página. El sensor funciona en modo forced, de modo que solo mide cuando alguien mira la página, y la presión se muestra reducida al nivel del mar para que puedas compararla con las previsiones del tiempo. Si es tu primera vez con el ESP32, empieza por ¿Qué es el ESP32?.
- Conecta el BME280 como en la tabla: VCC a 3V3, SDA a GPIO 21, SCL a GPIO 22.
- Escribe los datos de tu red en los campos WIFI_ADI (nombre de la red) y WIFI_SIFRE (contraseña) del código, y la altitud de tu ubicación en RAKIM_M.
- Elige ESP32 Dev Module como placa y carga el sketch.
- Abre el Monitor Serie a 115200 baudios; al conectarse, muestra la dirección IP.
- Escribe esa dirección (por ejemplo 192.168.1.42) en el navegador de un móvil conectado a la misma red Wi-Fi; aparecerán las tarjetas de temperatura, humedad y presión.
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 la Raspberry Pi Pico (MicroPython)
MicroPython no trae un módulo listo para el BME280. En lugar de descargar un archivo de driver, el código de abajo lleva dentro un pequeño driver: lee los coeficientes de calibración, hace que el sensor tome una sola medida en modo forced y calcula el resultado con las fórmulas de la hoja de datos. Como comprueba el chip ID, también funciona con el BMP280 y se salta por sí solo la línea de humedad. Conecta el sensor a GP4 (SDA), GP5 (SCL) y 3V3(OUT) y guarda el código en la Pico desde Thonny con el nombre main.py. Si la Pico es nueva para ti, ¿Qué es la Raspberry Pi Pico? y Fundamentos de MicroPython te lo pondrán más fácil.
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)Hay algunos detalles del código que conviene conocer. El ajuste de humedad (registro 0xF2) solo surte efecto después de escribir en 0xF4, por eso primero se envía el ajuste de humedad y después la orden de medida. El valor 0x25 escrito en 0xF4 significa "temperatura x1, presión x1, modo forced"; con estos ajustes una medida dura como mucho unos 10 ms, así que basta con esperar 15 ms. Probado con los valores de calibración de ejemplo de la hoja de datos del BMP280 de Bosch, el código devuelve 25,08 °C y 1006,5 hPa, es decir, sus cálculos coinciden exactamente con las fórmulas de Bosch.
El BMP280 vendido como BME280: ¿qué sensor tienes realmente?
Como los dos chips encajan en el mismo diseño de placa, algunos vendedores venden módulos BMP280 como BME280; a veces la placa solo dice "BME/BMP280". El síntoma es siempre el mismo: la librería Adafruit BME280 muestra "Could not find a valid BME280 sensor, check wiring, address, sensor ID!" y justo debajo SensorID was: 0x58. Otras librerías no dan error, pero siempre indican una humedad de 0 o nan. Tu cableado está bien; el chip que tienes es un BMP280, que no mide la humedad.


- Fíjate en la forma del chip: si la tapa metálica es cuadrada (2,5 × 2,5 mm), es un BME280; si es claramente rectangular (2,0 × 2,5 mm), es un BMP280. Con el zoom de la cámara del móvil la diferencia se ve fácilmente.
- Lee el chip ID: el método más fiable es el sketch de abajo; lee el identificador del registro 0xD0 del chip y te dice qué sensor es.
- Atento al precio: un BME280 auténtico cuesta bastante más que un BMP280; desconfía de los módulos "BME280" que se venden muy por debajo del precio de mercado.
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}Si el resultado es 0x58, no te preocupes: las medidas de temperatura y presión del BMP280 son igual de buenas que las del BME280. Instala la librería Adafruit BMP280 y usa el sketch de abajo; si necesitas la humedad, añade un DHT22 aparte al proyecto o devuelve el producto. De vez en cuando también aparecen muestras de BMP280 con ID 0x56 o 0x57; para ellas, escribe la línea de begin como 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}Ideas de proyectos con el BME280
- Estación meteorológica de escritorio: muestra temperatura, humedad y presión en una pantalla OLED o en un LCD I2C conectados al mismo bus I2C.
- Previsión del tiempo con barómetro: registra la presión cada hora; una bajada de más de 2 hPa en 3 horas suele anunciar empeoramiento del tiempo, mientras que una subida constante indica cielos despejados.
- Punto de rocío y aviso de moho: calcula el punto de rocío con la fórmula de Magnus (a = 17,62, b = 243,12 °C) y lanza un aviso cuando la temperatura de la pared se acerque a él.
- Invernadero inteligente: activa un ventilador o una bomba de nebulización según la humedad y la temperatura; los detalles, en el proyecto de invernadero inteligente con Arduino.
- Registrador de datos: guarda las lecturas en un módulo de tarjeta SD o, con un ESP32, en Google Sheets y saca una gráfica semanal.
- Sensor para casa inteligente: envía los valores desde un ESP32 a Home Assistant por MQTT.
- Estación exterior a pilas: despierta el ESP32 del deep sleep cada 10 minutos; el BME280 solo consume 0,1 µA en reposo.
- Contador de pisos: usa el sketch de altitud relativa para mostrar a qué planta has llegado en el ascensor o por la escalera.
Errores frecuentes y cómo solucionarlos
| Síntoma | Causa probable | Solución |
|---|---|---|
| "Could not find a valid BME280 sensor", SensorID 0x0 o 0xFF | Dirección incorrecta o fallo de cableado | Usa begin(0x76), comprueba que SDA y SCL no estén intercambiados y que GND esté conectado, ejecuta un escáner I2C |
| Mismo error, SensorID 0x58 | El chip es en realidad un BMP280 | Usa la librería Adafruit BMP280 y añade otro sensor para la humedad |
| fatal error: Adafruit_Sensor.h: No such file or directory | Falta una librería dependiente | Instala la librería Adafruit Unified Sensor |
| Los valores salen nan | No se pidió una medida nueva en modo forced o begin() falló | Llama a takeForcedMeasurement() antes de cada lectura y comprueba el resultado de begin() |
| Temperatura 1–3 °C demasiado alta | Autocalentamiento por medida continua, calor de un ESP32 o regulador cercano | Pasa a modo forced, aleja el sensor de la placa y, si hace falta, usa setTemperatureCompensation() |
| Presión tan baja como 900 hPa | Es la presión de la estación; baja al aumentar la altitud | Redúcela al nivel del mar con seaLevelForAltitude() para compararla con las previsiones |
| Altitud errónea en decenas de metros | Presión a nivel del mar dejada en 1013,25 | Introduce la P0 actual (QNH) o calibra con una altitud conocida |
| Bloqueos aleatorios con cables largos | El bus I2C es largo y ruidoso | Mantén el cable por debajo de 50 cm, baja la velocidad I2C o usa SPI |
El BME280 hace en una sola placa pequeña todas las medidas básicas de una estación meteorológica: primero confirma la dirección y el chip ID, después elige el modo de medida según tu objetivo y, para la altitud, mantén actualizada la presión a nivel del mar. En la app BlueGrays encontrarás proyectos que puedes combinar con esta guía, como la medida de temperatura y humedad con DHT11 y DHT22, pantallas meteorológicas con ESP32, un registrador de temperatura y un servidor web con ESP32, todos con esquemas de circuito y código paso a paso.
Preguntas frecuentes
¿Cuál es la diferencia entre el BME280 y el BMP280?
El BME280 mide temperatura, humedad relativa y presión; el BMP280 solo mide temperatura y presión y no tiene sensor de humedad. La precisión de presión y temperatura es la misma. Los chips también son distintos: el BME280 es cuadrado (2,5 × 2,5 mm), el BMP280 rectangular (2,0 × 2,5 mm), y sus chip ID son 0x60 y 0x58.
¿La dirección I2C del BME280 es 0x76 o 0x77?
Es 0x76 cuando el pin SDO está conectado a GND y 0x77 cuando está a 3,3 V. La mayoría de los módulos baratos usan 0x76 y las placas de Adafruit 0x77. La librería de Adafruit prueba 0x77 por defecto, así que quizá tengas que escribir bme.begin(0x76) en el código; si dudas, ejecuta un escáner I2C.
¿El BME280 funciona con 5 V?
El chip en sí admite como máximo 3,6 V. La mayoría de los módulos de 4 pines con pin VIN llevan regulador, así que pueden conectarse a 5V. Los módulos de 6 pines de 3,3 V sin regulador deben alimentarse solo con 3,3 V; 5 V pueden dañar el sensor.
¿Cómo soluciono el error "Could not find a valid BME280 sensor"?
Mira primero el valor SensorID que aparece debajo del error. Si es 0x58, tu sensor es un BMP280 y debes usar la librería Adafruit BMP280. Si es 0x0 o 0xFF, es un problema de dirección o de cableado: prueba begin(0x76) y asegúrate de que SDA y SCL no estén intercambiados y de que el pin CSB esté a 3,3 V.
¿Qué precisión tiene el BME280 midiendo altitud?
Mide los cambios de altura relativa con una precisión de unos ±1 m, suficiente para detectar un cambio de piso. La altitud absoluta depende de la presión a nivel del mar que introduzcas; un error de 1 hPa desplaza el resultado unos 8 m. Si introduces el QNH actual o calibras con una altitud conocida, te acercarás a unos pocos metros.
¿Por qué mi BME280 marca una temperatura demasiado alta?
Las causas más habituales son el autocalentamiento por medir sin parar y el calor de piezas cercanas como el ESP32 o un regulador. Pasa a modo forced, toma unas pocas medidas por minuto y aleja el sensor de la placa con un cable. Si queda una diferencia constante, compárala con un termómetro fiable y corrígela con setTemperatureCompensation().
Proyectos para hacer después de leer esto
Ver todos los proyectos
Temperatura y humedad con DHT11
¿Qué temperatura hace en tu habitación, y el aire está húmedo o seco? El sensor DHT11 mide la temperatura y la humedad, y el Arduino escribe los valores en una pantalla LCD de dos líneas, actualizándo

ESP32 DHT22 Temperatura y humedad (con pantalla LCD)
Se trata de un proyecto que mide la temperatura y la humedad ambientales mediante el sensor DHT22 y las muestra en tiempo real en una pantalla LCD I2C 16x2. Los datos del sensor se leen mediante el protocolo de un solo cable (one-wire) utilizando la biblioteca DHT de Adafruit. Este proyecto constituye la base para estaciones meteorológicas IoT, sistemas de automatización doméstica inteligente o sistemas de monitorización ambiental en invernaderos.

Reloj matricial, calendario y estación meteorológica (MAX7219, DS1307)
Un panel de texto en movimiento para tu mesa o tu pared que muestra por turnos la hora, la fecha y el clima de la habitación. En la pantalla LED de 8x32 aparece primero la temperatura en grados Celsiu

Registrador de Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
¡Construye un registrador de temperatura con marca de tiempo con ESP32! Lee temperatura/humedad del DHT22 cada minuto, obtén la hora real del DS1307 RTC y registra en tarjeta microSD como CSV. El OLED muestra en vivo la temperatura (fuente grande), porcentaje de humedad, marca de tiempo y contador de registros. El archivo `/temp_log.csv` en la tarjeta SD se abre en Excel, Google Sheets o Python pandas para análisis — perfecto para monitoreo de invernadero, seguimiento de temperatura del hog

ESP32 HTTPClient + API del tiempo (con pantalla OLED SSD1306)
En este proyecto, utilizamos el ESP32 para realizar una llamada a la API REST de la información meteorológica (wttr.in) a través de Internet, utilizando `HTTPClient.h`. A diferencia de la versión anterior con pantalla LCD I2C, aquí utilizamos una pantalla OLED SSD1306 (128×64), lo que permite utilizar fuentes grandes, iconos vectoriales y una presentación visual muy rica en una sola pantalla. Para indicar el tiempo, se dibujan en tiempo de ejecución 7 iconos vectoriales diferentes (soleado, parc

Servidor web asíncrono ESP32 (con indicación de IP en la pantalla LCD)
En este proyecto, convertimos el ESP32 en un **servidor web asíncrono** que puedes controlar desde tu teléfono o tu ordenador, siempre que estén conectados a la misma red Wi-Fi. Gracias a la biblioteca ESPAsyncWebServer, el servidor puede procesar varias solicitudes al mismo tiempo (a diferencia del clásico `WebServer.h`, que se bloquea con una sola solicitud).

ESP32 HTTPClient + API del tiempo (con pantalla LCD)
En este proyecto, utilizamos el ESP32 para realizar una llamada a la API REST de la página web de información meteorológica (wttr.in) a través de Internet, utilizando `HTTPClient.h`. Analizamos la respuesta JSON devuelta con ArduinoJson v7 y mostramos la información sobre la ciudad, la temperatura, la humedad, el tiempo y el viento en una pantalla LCD I2C, tanto en turco como en inglés. wttr.in es gratuito y no requiere clave API: basta con escribir el nombre de cualquier ciudad para obtener su

Pantalla LCD I2C para ESP32 (16x2)
En este proyecto, mostramos texto conectando una pantalla LCD de 16x2 caracteres al ESP32 a través del protocolo I2C. Gracias al I2C, podemos controlar la pantalla con solo 2 pines de datos (SDA y SCL); así se elimina el desperdicio de pines que supone la conexión paralela clásica, que requiere más de 6 pines. El código imprime un mensaje fijo en la primera línea y un contador que aumenta cada segundo en la segunda línea. Además, al inicio ejecutamos el escáner I2C para mostrar la dirección de l
Más artículos
App BlueGrays
Monta este circuito paso a paso en tu teléfono
Esquema, código y lista de piezas en una sola pantalla. Más de 160 proyectos de Arduino, ESP32 y Pico listos para montar.
Escanea con tu teléfono
Apunta la cámara al código y se abrirá la tienda de apps de tu teléfono.
o ábrela en la tienda

