Componentes · 15 min de leitura

BME280 com Arduino: temperatura, umidade, pressão e altitude

Ligue um BME280 ou BMP280 ao Arduino: endereço I2C 0x76/0x77, biblioteca da Adafruit, altitude pela pressão ao nível do mar, aviso de 3,3 V, estação meteorológica com ESP32 e Pico.

O BME280 é um sensor ambiental digital fabricado pela Bosch que mede temperatura, umidade relativa e pressão do ar em um único chip minúsculo. Para usá-lo com um Arduino, você só precisa de quatro fios (VCC, GND, SDA, SCL) e da biblioteca Adafruit BME280; poucas linhas de código mostram leituras em °C, % e hPa no Monitor Serial. Como mede pressão, ele também consegue calcular a sua altura acima do nível do mar, ou seja, a altitude. O irmão dele, o BMP280, parece quase idêntico, mas não mede umidade; ele só dá temperatura e pressão.

Neste guia você vai aprender a diferença entre os dois sensores, por que o endereço I2C às vezes é 0x76 e às vezes 0x77, como ligá-los a um Arduino Uno, a um ESP32 e a um Raspberry Pi Pico, como funciona a fórmula da altitude e como escolher a pressão ao nível do mar certa. Depois você vai montar uma miniestação meteorológica com ESP32 que abre no celular, rodar no Pico um driver MicroPython sem biblioteca e ver como um único sketch revela o problema muito comum do “BMP280 vendido como BME280”.

Módulo sensor de temperatura, umidade e pressão BME280
Módulo BME280: o chip minúsculo com tampa metálica mede temperatura, umidade e pressão e se conecta por I2C ou SPI.

O que é o BME280 e como ele funciona?

O BME280 tem três elementos sensores. O sensor de pressão mede o quanto uma fina membrana de silício se flexiona sob o ar que a pressiona, usando o efeito piezorresistivo. O sensor de umidade é uma camada de polímero cuja capacitância muda conforme ela absorve a umidade do ar. O sensor de temperatura informa a temperatura ambiente e também é usado para corrigir as outras duas medições. Cada chip é calibrado individualmente na fábrica e os coeficientes ficam guardados na memória interna dele; a biblioteca os lê na inicialização e converte os números brutos em unidades reais com as fórmulas do datasheet. O pequeno furo na tampa metálica deixa o ar chegar ao sensor, então nunca o cubra com fita ou cola.

CaracterísticaBME280BMP280
MedeTemperatura, umidade, pressãoTemperatura, pressão
Temperatura-40…+85 °C, ±1 °C (±0,5 °C a 25 °C)-40…+85 °C, ±1 °C (±0,5 °C a 25 °C)
Umidade relativa0–100%, ±3%Nenhuma
Faixa de pressão300–1100 hPa300–1100 hPa
Precisão da pressãoAbsoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m)Absoluta ±1 hPa, relativa ±0,12 hPa (≈ ±1 m)
Tensão de alimentação do chip1,71–3,6 V1,71–3,6 V
Corrente (1 leitura por segundo)3,6 µA (as três medições)2,7 µA
Corrente em sleep0,1 µA0,1 µA
InterfaceI2C (até 3,4 MHz) e SPI (até 10 MHz)I2C e SPI
ID do chip (registrador 0xD0)0x600x58
Tamanho do chip2,5 × 2,5 mm (quadrado)2,0 × 2,5 mm (retangular)

Resumindo, o BMP280 é um BME280 um pouco mais barato, sem o sensor de umidade; as leituras de pressão e temperatura dele são igualmente boas. Se você só precisa de altitude ou de pressão do ar, um BMP280 basta. Para projetos em que a umidade importa, como uma estação meteorológica, uma estufa ou o monitoramento do clima de um cômodo, escolha o BME280. Um degrau acima na família, o BME680/BME688 acrescenta um sensor de gás que detecta compostos orgânicos voláteis (COVs) no ar, mas custa várias vezes mais.

BME280 ou DHT11/DHT22?

CaracterísticaDHT11DHT22BME280
Faixa e precisão de temperatura0–50 °C, ±2 °C-40…+80 °C, ±0,5 °C-40…+85 °C, ±1 °C
Precisão de umidade±5%±2–5%±3%
Pressão e altitudeNãoNãoSim
Leitura mais rápidaUma vez por segundoUma vez a cada 2 segundosDezenas por segundo
LigaçãoUm único fio de dadosUm único fio de dadosI2C ou SPI
Corrente (medindo)≈ 1 mA≈ 1,5 mAAbaixo de 1 mA

Os sensores DHT são baratos e simples, mas são lentos, de vez em quando dão erros de leitura e não medem pressão. O BME280 divide o mesmo barramento I2C com outros dispositivos, como um display, quase não consome corrente em sleep e é ideal para projetos que funcionam com bateria por meses. Para os detalhes do DHT11, veja sensor de temperatura e umidade DHT11 e, para ver todas as opções lado a lado, leia a comparação de sensores de temperatura.

Tipos de módulo e o aviso de 3,3 V

O chip sozinho é tão pequeno que sempre é usado em uma placa breakout, e dois tipos são comuns. Os módulos de 6 pinos (normalmente roxos e vendidos como GY-BME280-3.3 ou GY-BMP280-3.3) têm os pinos VCC, GND, SCL, SDA, CSB e SDO; a maioria não tem regulador, e o 3.3 do nome diz justamente isso: alimente-os só com 3,3 V. Os módulos de 4 pinos (VIN, GND, SCL, SDA) normalmente têm um pequeno regulador de 3,3 V e, muitas vezes, transistores de conversão de nível para as linhas I2C, então podem ir no pino 5V do Arduino Uno. Se não tiver certeza de qual tipo você tem, procure na placa um minúsculo chip regulador de três pernas; se não houver, use 3,3 V.

Ligar um módulo de 3,3 V sem regulador no pino 5V pode danificar o sensor; o máximo absoluto do chip é de 4,25 V. Um sensor danificado nem sempre morre de vez; às vezes ele dá temperaturas alguns graus fora ou valores de pressão erráticos, o que deixa o defeito mais difícil de perceber.

Ligação do BME280: Arduino Uno, ESP32 e Pico

Pino do BME280Arduino UnoESP32Raspberry Pi Pico
VCC / VIN3.3V (6 pinos) ou 5V (4 pinos, com regulador)3V33V3(OUT), pino 36
GNDGNDGNDGND, pino 38
SCLA5GPIO 22GP5, pino 7
SDAA4GPIO 21GP4, pino 6
CSB (6 pinos)3.3V (seleciona I2C)3V33V3
SDO (6 pinos)Aberto ou GND: 0x76, 3.3V: 0x77Aberto ou GND: 0x76, 3V3: 0x77Aberto ou GND: 0x76, 3V3: 0x77

O endereço é onde a maioria das pessoas empaca. Se o pino SDO do chip estiver no GND, o endereço é 0x76; se estiver em 3,3 V, é 0x77. A maioria dos módulos baratos puxa o SDO para o GND com um resistor, então o endereço deles é 0x76, enquanto as placas da própria Adafruit usam 0x77, e a biblioteca tenta 0x77 por padrão. Por isso você deve escrever o endereço explicitamente no código. Se o pino CSB estiver no GND na inicialização, o chip passa para o modo SPI e não responde no I2C; se você usa I2C, ligue o CSB em 3,3 V ou confira se o módulo já o puxa para cima. Você encontra os pinos I2C da sua placa na ferramenta Pinagem e a lógica do barramento I2C em O que é I2C?.

Se você quer dois sensores no mesmo barramento, ligue o pino SDO de um deles em 3,3 V para mudar o endereço para 0x77; nos módulos de 4 pinos, isso normalmente se faz com um jumper de solda no verso. Para mais de dois sensores, o SPI é mais adequado: o SCL vai no SCK (13 no Uno), o SDA no MOSI (11), o SDO no MISO (12), e o pino CSB de cada sensor vai em um pino digital próprio; no código, basta declarar o objeto como Adafruit_BME280 bme(10);. Como o Uno de 5 V aciona as linhas SPI diretamente, você precisa colocar um conversor de nível entre ele e um módulo de 3,3 V.

O Arduino Uno trabalha em 5 V, e a biblioteca Wire liga os resistores de pull-up internos de A4 e A5 para 5 V. Um módulo de 3,3 V de 6 pinos normalmente funciona mesmo assim, porque os resistores de pull-up do módulo mantêm o barramento em torno de 3,3 V, mas, para um projeto permanente, a escolha mais segura é um módulo de 4 pinos com regulador ou um conversor de nível lógico. O ESP32 e o Pico já trabalham em 3,3 V, então não têm esse problema.

Instalando a biblioteca Adafruit BME280

  1. No Arduino IDE, abra Ferramentas > Gerenciar Bibliotecas e busque Adafruit BME280.
  2. Ao clicar em Instalar, escolha Instalar tudo na janela que pergunta sobre as dependências, para que a Adafruit Unified Sensor e a Adafruit BusIO também sejam instaladas.
  3. Se o seu sensor for um BMP280, instale do mesmo jeito a biblioteca Adafruit BMP280; a biblioteca do BME280 não reconhece o BMP280.
  4. Se quiser, abra Arquivo > Exemplos > Adafruit BME280 Library > bme280test, mas não se esqueça de colocar o endereço (0x76) na linha begin().

Primeiro sketch: lendo temperatura, umidade e pressão com o BME280

C++ (Arduino IDE)
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}
FunçãoO que faz
bme.begin(0x76)Inicia o sensor; retorna true se um dispositivo responder no endereço e o ID do chip for 0x60
readTemperature()Temperatura, °C
readHumidity()Umidade relativa, %
readPressure()Pressão, Pa (divida por 100 para hPa)
readAltitude(P0)Altura em relação à pressão ao nível do mar P0 (hPa), em metros
seaLevelForAltitude(altitude, P)Pressão ao nível do mar a partir de uma altitude conhecida, hPa
sensorID()O ID do chip lido: 0x60 BME280, 0x58 BMP280
setTemperatureCompensation(x)Soma x °C a cada leitura de temperatura; umidade e pressão são corrigidas de acordo

Quando você carrega o sketch e abre o Monitor Serial em 9600 baud, vê valores de mais ou menos 23,4 °C, 45% de umidade e 1009,8 hPa nas condições de um cômodo. A pressão muda devagar, ao longo de horas; sopre no sensor e você verá a umidade subir em segundos, toque nele com um dedo e a temperatura sobe. Por padrão, a biblioteca mede continuamente no modo normal com a maior sobreamostragem (x16); isso é ideal para um primeiro teste, mas, como você vai ver abaixo, outra configuração dá resultados mais precisos para medições meteorológicas de longo prazo.

Modos de medição: forced, normal e as configurações certas

O BME280 tem três modos. No modo sleep, ele não mede e consome 0,1 µA. No modo forced, ele faz uma única medição e volta a dormir; para cada valor novo, você chama takeForcedMeasurement(). No modo normal, ele continua medindo sozinho com o tempo de espera que você definir. A sobreamostragem (oversampling) mede o mesmo valor várias vezes e tira a média para reduzir o ruído, e o filtro IIR suaviza picos súbitos de pressão (uma porta batendo, uma rajada de vento). No datasheet, a Bosch recomenda estas configurações conforme o uso:

UsoModoSobreamostragem (pressão / temperatura / umidade)Filtro IIRCorrente média
Monitoramento do tempoForced, 1 leitura por minutox1 / x1 / x1Desligado≈ 0,16 µA
Medição de umidadeForced, 1 leitura por segundoPulada / x1 / x1Desligado≈ 2,9 µA
Navegação em ambientes internos (andares, elevadores)Normal, espera de 0,5 msx16 / x2 / x116≈ 633 µA
Quando o sensor mede continuamente, o chip e a placa esquentam muito pouco; isso se chama autoaquecimento. Se você está medindo a temperatura do cômodo ou de fora, use o modo forced e se contente com algumas leituras por minuto. Se a leitura ainda ficar acima de um termômetro confiável por um valor constante, você pode acrescentar uma correção como bme.setTemperatureCompensation(-1.0);.

Pressão ao nível do mar e cálculo da altitude

A pressão do ar cai conforme você sobe, então a altitude pode ser calculada a partir da pressão medida. A biblioteca usa esta fórmula barométrica: h = 44330 × (1 − (P / P0)^0,1903). Aqui, P é a pressão que você mede e P0 é a pressão atual ao nível do mar (as duas em hPa). A atmosfera padrão considera P0 = 1013,25 hPa, e perto do nível do mar uma diferença de 1 hPa corresponde a cerca de 8,3 metros.

O problema é que o P0 não é fixo; ele varia mais ou menos entre 990 e 1035 hPa conforme o tempo. Se o valor real hoje for 1023 hPa e você deixar 1013,25 no código, o sensor vai mostrar uma altitude cerca de 80 metros baixa demais. Para ter resultados precisos, você precisa manter o P0 atualizado: use o valor de “pressão ao nível do mar” informado pelos serviços de meteorologia ou o valor Q do boletim METAR do aeroporto mais próximo (por exemplo, Q1018, que significa 1018 hPa). Também dá para fazer o caminho inverso: se você sabe a altitude do seu local, calcule o P0 com seaLevelForAltitude(altitude, pressure). Por exemplo, se o sensor ler 905 hPa em Ancara (cerca de 938 m), a pressão reduzida ao nível do mar fica em cerca de 1012,6 hPa, que é o número que você vê nos apps de previsão do tempo.

Para a altitude absoluta, a precisão absoluta de ±1 hPa significa uma incerteza de cerca de ±8 metros. Nas medições relativas, porém, o sensor é muito melhor: ±0,12 hPa ≈ ±1 m. Um andar de prédio tem cerca de 3 metros, ou 0,36 hPa, então o BME280 consegue dizer com facilidade em que andar você está ou detectar um elevador em movimento. O sketch abaixo tira a média de 20 leituras na inicialização como referência e depois mostra a altura em relação a esse ponto e a pressão ao nível do mar calculada a partir de uma altitude conhecida:

C++ (Arduino IDE)
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 você pegar a placa do chão e levantá-la acima da cabeça, verá o valor “Baslangica gore” (em relação ao início) subir cerca de 2 metros. Como a pressão do ar muda alguns hPa ao longo do dia, essa leitura relativa deriva depois de algumas horas, então, no uso de longo prazo, você precisa atualizar a referência de vez em quando. Para acalmar ainda mais as leituras, você pode acrescentar a média móvel de filtragem de dados de sensores.

Miniestação meteorológica com ESP32: uma página web que você abre no celular

Graças ao Wi-Fi do ESP32, você pode ver as leituras do BME280 em uma página web de qualquer celular ou computador na mesma rede. O sketch abaixo usa a biblioteca WebServer que vem com o core do ESP32, então não precisa de biblioteca extra. A página principal carrega uma vez e, depois, um pequeno trecho de JavaScript dentro dela busca um JSON em /veri a cada 5 segundos e atualiza os valores sem recarregar a página. O sensor funciona no modo forced, então só faz uma medição quando alguém está olhando a página, e a pressão é mostrada reduzida ao nível do mar para você comparar com a previsão do tempo. Se é a sua primeira vez com o ESP32, comece por O que é o ESP32?.

  1. Ligue o BME280 como na tabela: VCC no 3V3, SDA no GPIO 21, SCL no GPIO 22.
  2. Coloque os dados da sua rede nos campos WIFI_ADI (nome da rede) e WIFI_SIFRE (senha) do código, e a altitude do seu local em RAKIM_M.
  3. Selecione ESP32 Dev Module como placa e carregue o sketch.
  4. Abra o Monitor Serial a 115200 baud; depois de conectado, ele mostra o endereço IP.
  5. Digite esse endereço (por exemplo, 192.168.1.42) no navegador de um celular na mesma rede Wi-Fi; aparecem cartões com temperatura, umidade e pressão.
C++ (Arduino IDE)
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}
O ESP32 esquenta alguns graus enquanto funciona e, se você colocar o sensor bem ao lado da placa, esse calor estraga a leitura. Afaste o BME280 da placa com um cabo de 10–15 cm, coloque-o perto dos furos de ventilação da caixa e mantenha-o longe do sol. Para um painel mais avançado, com gráficos e controle por botões, passe para servidor web e WebSocket no ESP32.

BME280 com o Raspberry Pi Pico (MicroPython)

O MicroPython não tem módulo embutido para o BME280. Em vez de baixar um arquivo de driver, o código abaixo traz um pequeno driver dentro dele: lê os coeficientes de calibração, faz o sensor tirar uma única medição no modo forced e calcula o resultado com as fórmulas do datasheet. Como ele verifica o ID do chip, também funciona com o BMP280 e pula sozinho a linha de umidade. Ligue o sensor no GP4 (SDA), no GP5 (SCL) e no 3V3(OUT) e salve o código no Pico pelo Thonny como main.py. Se o Pico é novidade para você, O que é o Raspberry Pi Pico? e fundamentos do MicroPython vão facilitar as coisas.

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)

Vale notar alguns detalhes do código. A configuração de umidade (registrador 0xF2) só passa a valer depois de uma escrita no 0xF4, então a configuração de umidade é enviada primeiro e o comando de medição depois. O valor 0x25 escrito no 0xF4 significa “temperatura x1, pressão x1, modo forced”; com essas configurações, uma medição leva no máximo cerca de 10 ms, então esperar 15 ms basta. Testado com os valores de calibração de exemplo do datasheet do BMP280 da Bosch, o código retorna 25,08 °C e 1006,5 hPa, ou seja, os cálculos dele batem exatamente com as fórmulas da Bosch.

O BMP280 vendido como BME280: qual sensor você tem de verdade?

Como os dois chips cabem no mesmo desenho de placa, alguns vendedores vendem módulos BMP280 como BME280; às vezes a placa só diz “BME/BMP280”. O sintoma é sempre o mesmo: a biblioteca Adafruit BME280 mostra “Could not find a valid BME280 sensor, check wiring, address, sensor ID!” e, logo abaixo, SensorID was: 0x58. Outras bibliotecas não mostram erro, mas sempre informam a umidade como 0 ou nan. Não há nada de errado com a sua ligação; o chip que você tem é um BMP280, que não mede umidade.

Sensor BME280
Sensor BME280
Sensor BMP280
Sensor BMP280
  • Olhe o formato do chip: se a tampa metálica for quadrada (2,5 × 2,5 mm), é um BME280; se for claramente retangular (2,0 × 2,5 mm), é um BMP280. Dê zoom com a câmera do celular e a diferença fica fácil de ver.
  • Leia o ID do chip: o método mais confiável é o sketch abaixo; ele lê o ID no registrador 0xD0 do chip e diz qual sensor é.
  • Fique de olho no preço: um BME280 genuíno custa bem mais que um BMP280, então desconfie de módulos “BME280” vendidos muito abaixo do preço de mercado.
C++ (Arduino IDE)
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 o resultado for 0x58, não se preocupe: as leituras de temperatura e pressão do BMP280 são tão boas quanto as do BME280. Instale a biblioteca Adafruit BMP280 e use o sketch abaixo; se precisar de umidade, acrescente um DHT22 separado ao projeto ou devolva o produto. De vez em quando você também encontra amostras de BMP280 com ID 0x56 ou 0x57; para elas, escreva a linha begin como bmp.begin(0x76, 0x56).

C++ (Arduino IDE)
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}

Ideias de projetos com BME280

  • Estação meteorológica de mesa: mostre temperatura, umidade e pressão em um display OLED de 0,96 polegada ou em um LCD I2C que divida o mesmo barramento I2C.
  • Previsão do tempo barométrica: registre a pressão a cada hora; uma queda de mais de 2 hPa em 3 horas costuma indicar piora do tempo, enquanto uma subida constante aponta para céu limpo.
  • Ponto de orvalho e aviso de mofo: calcule o ponto de orvalho com a fórmula de Magnus (a = 17,62, b = 243,12 °C) e dispare um alerta quando a temperatura da parede chegar perto dele.
  • Estufa inteligente: acione uma ventoinha ou uma bomba de nebulização conforme a umidade e a temperatura; detalhes no projeto de estufa inteligente com Arduino.
  • Registrador de dados: grave as leituras em um módulo de cartão SD ou, com um ESP32, no Google Sheets e trace um gráfico semanal.
  • Sensor para casa inteligente: envie os valores de um ESP32 para o Home Assistant via MQTT.
  • Estação externa a bateria: acorde o ESP32 do deep sleep a cada 10 minutos; o BME280 consome só 0,1 µA dormindo.
  • Contador de andares: use o sketch de altitude relativa para mostrar em que andar você chegou no elevador ou pela escada.

Erros comuns e como resolvê-los

SintomaCausa provávelSolução
“Could not find a valid BME280 sensor”, SensorID 0x0 ou 0xFFEndereço errado ou defeito na ligaçãoUse begin(0x76), confira se SDA e SCL não estão trocados e se o GND está ligado, rode um scanner I2C
Mesmo erro, SensorID 0x58O chip na verdade é um BMP280Use a biblioteca Adafruit BMP280 e acrescente um sensor separado para a umidade
fatal error: Adafruit_Sensor.h: No such file or directory (arquivo não encontrado)Uma biblioteca de dependência não está instaladaInstale a biblioteca Adafruit Unified Sensor
As leituras são nanNenhuma medição nova pedida no modo forced, ou o begin() falhouChame takeForcedMeasurement() antes de cada leitura e confira o resultado do begin()
Temperatura 1–3 °C alta demaisAutoaquecimento pela medição contínua, calor de um ESP32 ou de um regulador próximoPasse para o modo forced, afaste o sensor da placa, use setTemperatureCompensation() se precisar
Pressão baixa, de até 900 hPaÉ a pressão da estação; ela cai conforme a altitude sobeReduza-a ao nível do mar com seaLevelForAltitude() para comparar com as previsões
Altitude errada em dezenas de metrosA pressão ao nível do mar ficou em 1013,25Coloque o P0 atual (QNH) ou calibre com uma altitude conhecida
Travamentos aleatórios com fios longosO barramento I2C está longo e com ruídoMantenha o cabo abaixo de 50 cm, reduza a velocidade do I2C ou use SPI
Não coloque o sensor em uma caixa fechada e hermética; o ar precisa chegar ao chip para as medições de umidade e pressão. Ao ar livre, um abrigo com venezianas, aberto embaixo e protegido da chuva e do sol direto (como os abrigos das estações meteorológicas), dá os resultados mais precisos. Se o sensor se molhar com condensação, pode mostrar 100% de umidade por um tempo; ele volta ao normal quando seca.

O BME280 cuida de todas as medições básicas de uma estação meteorológica em uma pequena placa: primeiro confirme o endereço e o ID do chip, depois escolha o modo de medição conforme o seu objetivo e mantenha a pressão ao nível do mar atualizada para a altitude. No app BlueGrays você encontra projetos que dá para combinar com este guia, como medição de temperatura e umidade com DHT11 e DHT22, displays meteorológicos com ESP32, um registrador de temperatura e um servidor web no ESP32, cada um com esquemas do circuito e código passo a passo.

Perguntas frequentes

Qual é a diferença entre o BME280 e o BMP280?

O BME280 mede temperatura, umidade relativa e pressão; o BMP280 só mede temperatura e pressão e não tem sensor de umidade. A precisão de pressão e de temperatura dos dois é a mesma. Os chips também são diferentes: o BME280 é quadrado (2,5 × 2,5 mm), o BMP280 retangular (2,0 × 2,5 mm), e os IDs de chip são 0x60 e 0x58.

O endereço I2C do BME280 é 0x76 ou 0x77?

É 0x76 quando o pino SDO está ligado ao GND e 0x77 quando está ligado a 3,3 V. A maioria dos módulos baratos usa 0x76, enquanto as placas da Adafruit usam 0x77. A biblioteca da Adafruit tenta 0x77 por padrão, então talvez você precise escrever bme.begin(0x76) no código; se estiver em dúvida, rode um sketch scanner I2C.

O BME280 funciona com 5V?

O chip em si funciona com no máximo 3,6 V. A maioria dos módulos de 4 pinos marcados VIN tem regulador, então pode ser ligada no 5V. Alimente os módulos de 6 pinos de 3,3 V sem regulador só com 3,3 V; 5 V pode danificar o sensor.

Como resolvo “Could not find a valid BME280 sensor”?

Primeiro confira o valor de SensorID mostrado abaixo do erro. Se for 0x58, o seu sensor é um BMP280 e você deve usar a biblioteca Adafruit BMP280. Se for 0x0 ou 0xFF, é um problema de endereço ou de ligação: tente begin(0x76), garanta que SDA e SCL não estão trocados e que o pino CSB está em 3,3 V.

Qual é a precisão da medição de altitude do BME280?

Ele mede variações de altura relativa com cerca de ±1 m, o que basta para detectar uma mudança de andar. A altitude absoluta depende da pressão ao nível do mar que você informar; um erro de 1 hPa desloca o resultado em cerca de 8 m. Se você colocar o valor atual de QNH ou calibrar com uma altitude conhecida, consegue chegar a poucos metros.

Por que meu BME280 lê a temperatura alta demais?

As causas mais comuns são o autoaquecimento pela medição contínua e o calor de peças próximas, como o ESP32 ou um regulador. Passe para o modo forced, faça algumas leituras por minuto e afaste o sensor da placa com um cabo. Se sobrar uma diferença constante, compare com um termômetro confiável e corrija com setTemperatureCompensation().

Ver todos os projetos
Temperatura e umidade com DHT11
#55Intermediário

Temperatura e umidade com DHT11

Qual é a temperatura do seu quarto? O ar está úmido ou seco? O sensor DHT11 mede a temperatura e a umidade, e o Arduino mostra os valores em um display LCD de duas linhas, atualizando a cada poucos se

4.7(47)
73
Temperatura e umidade com ESP32 e DHT22 (com display LCD)
#117Intermediário

Temperatura e umidade com ESP32 e DHT22 (com display LCD)

Este projeto mede a temperatura e a umidade do ambiente com um sensor DHT22 e exibe os dados em tempo real em um LCD I2C 16x2. Os dados são lidos do sensor pelo protocolo de um fio (one-wire) com a biblioteca Adafruit DHT. Este projeto serve de base para estações meteorológicas IoT, automação residencial ou sistemas de monitoramento ambiental em estufas. A comunicação com o DHT22 é feita pelo pino GPIO 4 do ESP32.

4.8(38)
56
Relógio, calendário e estação meteorológica de matriz de pontos (MAX7219, DS1307)
#85Intermediário
Premium

Relógio, calendário e estação meteorológica de matriz de pontos (MAX7219, DS1307)

Um painel com texto em rolagem para sua mesa ou parede que mostra, em sequência, a hora, a data e as condições do ambiente. No display LED 8x32, você vê primeiro a temperatura em Celsius e Fahrenheit,

5.0(50)
66
Registrador de temperatura com ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
#144Avançado
Premium

Registrador de temperatura com ESP32 (DHT22 + DS1307 RTC + microSD + OLED)

Monte um registrador de temperatura com data e hora usando ESP32! Leia a temperatura e a umidade do DHT22 a cada minuto, obtenha a hora real do DS1307 RTC e grave os dados em CSV no cartão microSD. O OLED exibe a temperatura atual em letras grandes, a porcentagem de umidade, a data e a hora e o contador de registros. O arquivo /temp_log.csv no cartão SD pode ser aberto no Excel, Google Sheets ou pandas do Python para análise — ideal para monitorar estufas, acompanhar a temperatura de casa ou…

4.7(7)
12
ESP32 HTTPClient + API de clima (com display OLED SSD1306)
#134Avançado
Premium

ESP32 HTTPClient + API de clima (com display OLED SSD1306)

Neste projeto, usamos o ESP32 para fazer uma chamada REST à API de clima wttr.in pela internet com HTTPClient.h. Diferentemente da versão anterior com LCD I2C, aqui usamos um display OLED SSD1306 (128×64), que permite usar fontes grandes, ícones vetoriais e uma apresentação visual rica em uma única tela. Sete ícones vetoriais de condições do tempo (ensolarado, parcialmente nublado, nublado, chuvoso, com neve, com tempestade e com neblina) são desenhados durante a execução, sem arquivos bitmap.

4.3(10)
19
Servidor web assíncrono com ESP32 (IP no LCD)
#129Avançado

Servidor web assíncrono com ESP32 (IP no LCD)

Neste projeto, transformamos o ESP32 em um servidor web assíncrono que você pode controlar pelo celular ou computador na mesma rede Wi-Fi. Com a biblioteca ESPAsyncWebServer, o servidor processa várias requisições ao mesmo tempo (ao contrário do WebServer.h tradicional, que bloqueia a execução ao processar uma requisição). Você poderá abrir o endereço IP do ESP32 no navegador e clicar nos botões ON/OFF (as rotas /on e /off) para ligar e desligar o LED conectado ao GPIO 5.

4.8(16)
26
ESP32 HTTPClient + API de clima (com display LCD)
#133Avançado
Premium

ESP32 HTTPClient + API de clima (com display LCD)

Neste projeto, usamos o ESP32 para fazer uma chamada REST à API de clima wttr.in pela internet com HTTPClient.h. Interpretamos a resposta JSON com ArduinoJson v7 e mostramos cidade, temperatura, umidade, condições do tempo e vento em um display LCD I2C, em turco e inglês. O wttr.in é grátis e não exige chave de API — basta informar o nome de uma cidade para consultar o clima atual. Os dados se atualizam sozinhos a cada 30 minutos, e o LED dá um retorno visual diferente para cada tela.

4.7(13)
20
Display LCD I2C com ESP32 (16x2)
#119Intermediário
Premium

Display LCD I2C com ESP32 (16x2)

Neste projeto, exibimos texto conectando um display LCD de 16x2 caracteres ao ESP32 pelo protocolo I2C. Com o I2C, controlamos o display usando apenas dois pinos de dados (SDA e SCL), dispensando o uso de seis ou mais pinos da conexão paralela tradicional. O código mostra uma mensagem fixa na primeira linha e um contador que aumenta a cada segundo na segunda linha. Na inicialização, também executamos um scanner I2C para mostrar o endereço do display no Monitor Serial (geralmente 0x27 ou 0x3F).

4.9(23)
40