Componentes · 15 min de lectura

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

Módulo sensor BME280 de temperatura, humedad y presión
Módulo BME280: el diminuto chip con tapa metálica mide temperatura, humedad y presión y se conecta por I2C o SPI.

¿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ísticaBME280BMP280
MideTemperatura, humedad, presiónTemperatura, 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 relativa0–100 %, ±3 %No
Rango de presión300–1100 hPa300–1100 hPa
Precisión de presiónAbsoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m)Absoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m)
Tensión de alimentación del chip1,71–3,6 V1,71–3,6 V
Consumo (1 lectura por segundo)3,6 µA (las tres medidas)2,7 µA
Consumo en reposo0,1 µA0,1 µA
InterfazI2C (hasta 3,4 MHz) y SPI (hasta 10 MHz)I2C y SPI
Chip ID (registro 0xD0)0x600x58
Tamaño del chip2,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ísticaDHT11DHT22BME280
Rango y precisión de temperatura0–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 altitudNoNoSí
Lectura más rápida1 por segundo1 cada 2 segundosDecenas por segundo
ConexiónUn solo cable de datosUn solo cable de datosI2C o SPI
Consumo (midiendo)≈ 1 mA≈ 1,5 mAMenos 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.

Conectar un módulo de 3,3 V sin regulador al pin 5V puede dañar el sensor; el máximo absoluto del chip es 4,25 V. Un sensor dañado no siempre muere del todo; a veces da temperaturas desviadas unos grados o presiones erráticas, y eso hace que el fallo sea más difícil de detectar.

Conexión del BME280: Arduino Uno, ESP32 y Pico

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

El Arduino Uno trabaja a 5 V y la librería Wire activa las resistencias pull-up internas de A4 y A5 a 5 V. Un módulo de 6 pines de 3,3 V suele funcionar igualmente, porque las pull-up del módulo mantienen el bus en torno a 3,3 V, pero para un proyecto permanente lo más seguro es un módulo de 4 pines con regulador o un conversor de nivel lógico. El ESP32 y la Pico ya funcionan a 3,3 V, así que no tienen este problema.

Instalar la librería Adafruit BME280

  1. En el Arduino IDE, abre Herramientas > Administrar bibliotecas y busca Adafruit BME280.
  2. 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.
  3. 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.
  4. 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

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}
FunciónQué 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:

UsoModoSobremuestreo (presión / temperatura / humedad)Filtro IIRConsumo medio
Monitorización meteorológicaForced, 1 medida por minutox1 / x1 / x1Desactivado≈ 0,16 µA
Medida de humedadForced, 1 medida por segundoOmitida / x1 / x1Desactivado≈ 2,9 µA
Navegación en interiores (pisos, ascensor)Normal, espera de 0,5 msx16 / x2 / x116≈ 633 µA
Cuando el sensor mide sin parar, el chip y la placa se calientan muy ligeramente; es lo que se llama autocalentamiento. Si mides la temperatura de una habitación o del exterior, usa el modo forced y confórmate con unas pocas medidas por minuto. Si aun así la lectura queda siempre por encima de un termómetro fiable en la misma cantidad, puedes añadir una corrección como bme.setTemperatureCompensation(-1.0);.

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:

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}

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

  1. Conecta el BME280 como en la tabla: VCC a 3V3, SDA a GPIO 21, SCL a GPIO 22.
  2. 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.
  3. Elige ESP32 Dev Module como placa y carga el sketch.
  4. Abre el Monitor Serie a 115200 baudios; al conectarse, muestra la dirección IP.
  5. 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.
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}
El ESP32 se calienta unos grados mientras funciona, y si pones el sensor justo al lado de la placa, ese calor estropea la medida. Separa el BME280 de la placa con un cable de 10–15 cm, colócalo junto a las rejillas de ventilación de la caja y mantenlo a la sombra. Para un panel más completo con gráficas y botones, sigue con Servidor web ESP32 y WebSocket.

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.

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)

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.

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

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

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}

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íntomaCausa probableSolución
"Could not find a valid BME280 sensor", SensorID 0x0 o 0xFFDirección incorrecta o fallo de cableadoUsa begin(0x76), comprueba que SDA y SCL no estén intercambiados y que GND esté conectado, ejecuta un escáner I2C
Mismo error, SensorID 0x58El chip es en realidad un BMP280Usa la librería Adafruit BMP280 y añade otro sensor para la humedad
fatal error: Adafruit_Sensor.h: No such file or directoryFalta una librería dependienteInstala la librería Adafruit Unified Sensor
Los valores salen nanNo 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 altaAutocalentamiento por medida continua, calor de un ESP32 o regulador cercanoPasa a modo forced, aleja el sensor de la placa y, si hace falta, usa setTemperatureCompensation()
Presión tan baja como 900 hPaEs la presión de la estación; baja al aumentar la altitudRedúcela al nivel del mar con seaLevelForAltitude() para compararla con las previsiones
Altitud errónea en decenas de metrosPresión a nivel del mar dejada en 1013,25Introduce la P0 actual (QNH) o calibra con una altitud conocida
Bloqueos aleatorios con cables largosEl bus I2C es largo y ruidosoMantén el cable por debajo de 50 cm, baja la velocidad I2C o usa SPI
No metas el sensor en una caja cerrada y hermética; para medir humedad y presión el aire tiene que llegar al chip. En exteriores, una caja con lamas, abierta por abajo y que proteja de la lluvia y del sol directo (como las garitas de las estaciones meteorológicas), da los resultados más precisos. Si el sensor se moja por condensación, puede marcar 100 % de humedad durante un rato; vuelve a la normalidad cuando se seca.

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

Ver todos los proyectos
Temperatura y humedad con DHT11
#55Intermedio

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

4.7(47)
64
ESP32 DHT22 Temperatura y humedad (con pantalla LCD)
#117Intermedio

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.

4.8(38)
54
Reloj matricial, calendario y estación meteorológica (MAX7219, DS1307)
#85Intermedio
Premium

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

5.0(50)
66
Registrador de Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
#144Avanzado
Premium

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

4.7(7)
12
ESP32 HTTPClient + API del tiempo (con pantalla OLED SSD1306)
#134Avanzado
Premium

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

4.3(10)
18
Servidor web asíncrono ESP32 (con indicación de IP en la pantalla LCD)
#129Avanzado
Premium

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

4.8(16)
26
ESP32 HTTPClient + API del tiempo (con pantalla LCD)
#133Avanzado
Premium

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

4.7(13)
20
Pantalla LCD I2C para ESP32 (16x2)
#119Intermedio
Premium

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

4.9(23)
40