373_BMP180 PRESSURE SENSOR
Quote from Defran on October 27, 2026, 10:57 am
The BMP180 is a digital atmospheric pressure and temperature sensor. It communicates via the I2C bus and allows you to measure pressure, temperature, and calculate an approximate altitude.
Main features:
Type: Digital barometric sensor
Pressure: 300–1100 hPa
Temperature: −40 to +85 °C
Pressure resolution: Up to 0.01 hPa
Absolute accuracy: ±1 hPa typical
I2C address: 0x77 (fixed)
Chip supply voltage: 1.8–3.6 V
Outputs: Digital pressure and temperatureIn our simulated component BMP180_PRESSURE, Arduino requests measurements via the I2C bus, using address 0x77. The data is displayed on an SSD1306 OLED screen, showing atmospheric pressure in hPa, temperature in °C, and estimated altitude in meters. Applications: weather stations, barometers, altimeters, and environmental monitoring systems. It is designed for the latest versions of Simulide 1 and 2.
SUBCIRCUIT SCRIPT AND INO PROGRAM:
Both are shown separately below.
// BMP180s SCRIPT. DEFRAN26A // Direccion I2C fija: 0x77 (escritura 0xEE, lectura 0xEF) // VP: 0..5 V = 300..1100 hPa; VT: 0..5 V = -20..60 C // SDA open-drain; ACK sobre el noveno pulso SCL. IoPin@ SDA = component.getPin("SDA"); IoPin@ SCL = component.getPin("SCL"); IoPin@ VP = component.getPin("VP"); IoPin@ VT = component.getPin("VT"); const int ESPERA = 0; const int RECIBIR = 1; const int ACK_ESCLAVO = 2; const int TRANSMITIR = 3; const int ACK_MASTER = 4; const int FIN = 5; array<uint> reg(256, 0); int fase = ESPERA; int bits = 0; uint recibido = 0; uint pointer = 0; uint txDato = 0; int txBit = 7; bool primerDato = true; bool direccionCorrecta = false; bool direccionLectura = false; bool novenoAlto = false; bool oldSCL = true; bool oldSDA = true; bool procesando = false; bool sdaForzada = false; bool iniciarTxTrasAck = false; bool siguienteEsValor = false; bool masterConfirmo = false; void releaseSDA() { sdaForzada = false; SDA.setStateZ(true); } void pullSDA() { sdaForzada = true; SDA.setOutState(false); SDA.setStateZ(false); } void set16(uint a, int v) { uint w = uint(v) & 0xFFFF; reg[a] = (w >> 8) & 255; reg[a+1] = w & 255; } void loadCalibration() { set16(0xAA, 408); // AC1 set16(0xAC, -72); // AC2 set16(0xAE, -14383);// AC3 set16(0xB0, 32741); // AC4 set16(0xB2, 32757); // AC5 set16(0xB4, 23153); // AC6 set16(0xB6, 6190); // B1 set16(0xB8, 4); // B2 set16(0xBA, -32768);// MB set16(0xBC, -8711); // MC set16(0xBE, 2868); // MD } void updateMeasurement(uint cmd) { double vP = VP.getVoltage(); double vT = VT.getVoltage(); if (vP < 0) vP = 0; if (vP > 5) vP = 5; if (vT < 0) vT = 0; if (vT > 5) vT = 5; double pressurePa = 30000.0 + vP*16000.0; double tempC = -20.0 + vT*16.0; if (cmd == 0x2E) { // UT aproximado: 28525 corresponde a unos 20 C con esta calibracion int ut = int(28525.0 + (tempC-20.0)*125.0); if (ut < 0) ut = 0; if (ut > 65535) ut = 65535; reg[0xF6] = (uint(ut) >> 8) & 255; reg[0xF7] = uint(ut) & 255; reg[0xF8] = 0; } else if ((cmd & 0x3F) == 0x34) { uint oss = (cmd >> 6) & 3; // Inversion lineal aproximada de la compensacion a 20 C. int baseUP = int(34000.0 + (pressurePa-101465.0)/3.028); if (baseUP < 0) baseUP = 0; uint up = uint(baseUP) << oss; uint adc = up << (8-oss); reg[0xF6] = (adc >> 16) & 255; reg[0xF7] = (adc >> 8) & 255; reg[0xF8] = adc & 255; } reg[0xF4] = cmd & 0xDF; // SCO=0: conversion inmediata } void resetRegisters() { for (uint i=0; i<256; i++) reg[i] = 0; loadCalibration(); reg[0xD0] = 0x55; reg[0xD1] = 0x01; reg[0xF6] = 0x80; pointer = 0; } void escribirRegistro(uint direccion, uint valor) { direccion &= 0xFF; if (direccion == 0xE0 && valor == 0xB6) { resetRegisters(); return; } if (direccion == 0xF4) { updateMeasurement(valor); return; } if (direccion == 0xD0 || direccion == 0xD1) return; if (direccion >= 0xAA && direccion <= 0xBF) return; reg[direccion] = valor & 0xFF; } void ponerBitTx() { if (((txDato >> txBit) & 1) != 0) releaseSDA(); else pullSDA(); } void comenzarTx() { txDato = reg[pointer & 0xFF]; txBit = 7; bits = 0; fase = TRANSMITIR; ponerBitTx(); } void reposo() { fase = ESPERA; bits = 0; recibido = 0; novenoAlto = false; releaseSDA(); } void comenzar() { // El puntero se conserva ante un START repetido. fase = RECIBIR; bits = 0; recibido = 0; direccionCorrecta = false; direccionLectura = false; primerDato = true; siguienteEsValor = false; iniciarTxTrasAck = false; novenoAlto = false; releaseSDA(); } void procesarByte(uint valor) { if (primerDato) { direccionCorrecta = ((valor >> 1) == 0x77); direccionLectura = (valor & 1) != 0; iniciarTxTrasAck = direccionCorrecta && direccionLectura; primerDato = false; siguienteEsValor = false; } else if (direccionCorrecta && !direccionLectura) { if (!siguienteEsValor) { pointer = valor & 0xFF; siguienteEsValor = true; } else { escribirRegistro(pointer, valor); pointer = (pointer + 1) & 0xFF; } iniciarTxTrasAck = false; } else direccionCorrecta = false; } void setup() { // inicializacion en reset(). } void reset() { SCL.setPinMode(1); VP.setPinMode(1); VT.setPinMode(1); SDA.setPinMode(3); SDA.setOutHighV(5.0); SDA.setOutState(false); SDA.setStateZ(true); procesando = false; sdaForzada = false; resetRegisters(); fase = ESPERA; bits = 0; recibido = 0; primerDato = true; siguienteEsValor = false; iniciarTxTrasAck = false; masterConfirmo = false; direccionCorrecta = false; direccionLectura = false; novenoAlto = false; oldSCL = SCL.getInpState(); oldSDA = SDA.getInpState(); SCL.changeCallBack(element, true); SDA.changeCallBack(element, true); } void voltChanged() { if (procesando) return; procesando = true; bool scl = SCL.getInpState(); bool sda = SDA.getInpState(); bool subidaSCL = !oldSCL && scl; bool bajadaSCL = oldSCL && !scl; bool bajadaSDA = oldSDA && !sda; bool subidaSDA = !oldSDA && sda; oldSCL = scl; // actualizar ANTES de cambiar SDA. oldSDA = sda; if (!subidaSCL && !bajadaSCL && scl && !sdaForzada) { if (bajadaSDA) comenzar(); else if (subidaSDA) reposo(); } if (fase == RECIBIR) { if (subidaSCL) { recibido = ((recibido << 1) | (sda ? 1 : 0)) & 0xFF; bits++; if (bits == 8) procesarByte(recibido); } else if (bajadaSCL && bits == 8) { if (direccionCorrecta) { fase = ACK_ESCLAVO; novenoAlto = false; pullSDA(); } else fase = FIN; } } else if (fase == ACK_ESCLAVO) { if (subidaSCL) novenoAlto = true; else if (bajadaSCL && novenoAlto) { novenoAlto = false; fase = FIN; releaseSDA(); if (iniciarTxTrasAck) comenzarTx(); else { fase = RECIBIR; bits = 0; recibido = 0; } } } else if (fase == TRANSMITIR) { if (subidaSCL) bits++; else if (bajadaSCL) { if (bits == 8) { releaseSDA(); fase = ACK_MASTER; novenoAlto = false; } else if (bits > 0 && bits < 8) { txBit = 7 - bits; ponerBitTx(); } } } else if (fase == ACK_MASTER) { if (subidaSCL) { novenoAlto = true; masterConfirmo = !sda; } else if (bajadaSCL && novenoAlto) { fase = FIN; if (masterConfirmo) { pointer = (pointer + 1) & 0xFF; comenzarTx(); } else releaseSDA(); } } procesando = false; }// BMP180 PRESSURE SENSOR. DEFRAN26A // BMP180: 0x77 OLED: 0x3C // Librerias: Adafruit BMP085 Library, Adafruit GFX, Adafruit SSD1306 #include <Wire.h> #include <Adafruit_BMP085.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define OLED_ANCHO 128 #define OLED_ALTO 64 #define OLED_RESET -1 #define OLED_ADDR 0x3C Adafruit_SSD1306 oled(OLED_ANCHO, OLED_ALTO, &Wire, OLED_RESET); Adafruit_BMP085 bmp; const unsigned long PERIODO_MS = 700; const float PRESION_MAR_HPA = 1013.25; const byte GRAF_PUNTOS = 29; float historial[GRAF_PUNTOS]; byte muestras = 0; byte siguiente = 0; unsigned long anterior = 0; bool sensorOK = false; void setup() { Wire.begin(); Wire.setClock(100000); // 100 kHz. if (!oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {} oled.clearDisplay(); oled.setTextColor(SSD1306_WHITE); oled.setTextSize(1); oled.setCursor(10, 24); oled.print(F("STARTING BMP180...")); oled.display(); sensorOK = bmp.begin(BMP085_ULTRALOWPOWER); if (!sensorOK) {mostrarError(F("BMP180 NOT PRESENT")); return;} anterior = millis() - PERIODO_MS; } void loop() { if (!sensorOK) return; unsigned long ahora = millis(); if (ahora - anterior < PERIODO_MS) return; anterior = ahora; float presion = bmp.readPressure() / 100.0; // Pa -> hPa float temperatura = bmp.readTemperature(); // grados Celsius float altitud = bmp.readAltitude(PRESION_MAR_HPA * 100.0); // metros if (presion < 100 || presion > 1300 || isnan(presion) || isnan(temperatura)) { mostrarError(F("READING ERROR")); return; } guardarPresion(presion); mostrarDatos(presion, temperatura, altitud); } void mostrarError(const __FlashStringHelper *mensaje) { oled.clearDisplay(); oled.setTextColor(SSD1306_WHITE); oled.setTextSize(1); oled.drawRoundRect(0, 0, 128, 64, 5, SSD1306_WHITE); oled.setCursor(4, 13); oled.print(F("METEO STATION")); oled.drawFastHLine(12, 27, 104, SSD1306_WHITE); oled.setCursor(13, 37); oled.print(mensaje); oled.display(); } void guardarPresion(float hpa) { historial[siguiente] = hpa; siguiente = (siguiente + 1) % GRAF_PUNTOS; if (muestras < GRAF_PUNTOS) muestras++; } void dibujarGrafica() { const int x = 96, y = 46, w = 29, h = 16; oled.drawRect(x - 2, y - 2, w + 4, h + 4, SSD1306_WHITE); if (muestras < 2) return; float minimo = historial[0]; float maximo = historial[0]; for (byte i = 1; i < muestras; i++) { if (historial[i] < minimo) minimo = historial[i]; if (historial[i] > maximo) maximo = historial[i]; } if (maximo - minimo < 0.6) { float medio = (maximo + minimo) * 0.5; minimo = medio - 0.3; maximo = medio + 0.3; } byte inicio = (muestras == GRAF_PUNTOS) ? siguiente : 0; for (byte i = 1; i < muestras; i++) { byte ia = (inicio + i - 1) % GRAF_PUNTOS; byte ib = (inicio + i) % GRAF_PUNTOS; int xa = x + (long)(i - 1) * (w - 1) / (muestras - 1); int xb = x + (long)i * (w - 1) / (muestras - 1); int ya = y + h - 1 - (int)((historial[ia] - minimo) * (h - 1) / (maximo - minimo)); int yb = y + h - 1 - (int)((historial[ib] - minimo) * (h - 1) / (maximo - minimo)); oled.drawLine(xa, ya, xb, yb, SSD1306_WHITE); } } void mostrarDatos(float presion, float temperatura, float altitud) { oled.clearDisplay(); oled.setTextColor(SSD1306_WHITE); oled.fillRoundRect(0, 0, 128, 13, 3, SSD1306_WHITE); // Banda superior invertida oled.setTextColor(SSD1306_BLACK); oled.setTextSize(1); oled.setCursor(6, 3); oled.print(F("BMP180 | BAROMETER")); oled.setTextColor(SSD1306_WHITE); oled.setCursor(4, 18); // Presion grande, sin parpadeos: solo se actualiza cada 700 ms oled.setTextSize(3); if (presion >= 1000.0) {oled.print((int)(presion + 0.5));} else {oled.print(presion, 0);} oled.setTextSize(1); oled.setCursor(89, 30); oled.print(F("hPa")); oled.drawFastHLine(4, 42, 120, SSD1306_WHITE); oled.setTextSize(1); oled.setCursor(4, 47); oled.print(F("TEMP")); oled.setCursor(4, 56); oled.print(temperatura, 1); oled.write((uint8_t)247); // Simbolo de grado de la fuente integrada oled.print(F("C")); oled.setCursor(53, 47); oled.print(F("ALT")); oled.setCursor(53, 56); oled.print((int)(altitud + (altitud >= 0 ? 0.5 : -0.5))); oled.print(F("m")); dibujarGrafica(); oled.display(); }PROVIDED FILES:
The ZIP file contains all parts of the example, hardware and software. The subcircuit is included as a inner extraZIP for the user's discretionary use.
P. de Francisco

The BMP180 is a digital atmospheric pressure and temperature sensor. It communicates via the I2C bus and allows you to measure pressure, temperature, and calculate an approximate altitude.
Main features:
Type: Digital barometric sensor
Pressure: 300–1100 hPa
Temperature: −40 to +85 °C
Pressure resolution: Up to 0.01 hPa
Absolute accuracy: ±1 hPa typical
I2C address: 0x77 (fixed)
Chip supply voltage: 1.8–3.6 V
Outputs: Digital pressure and temperature
In our simulated component BMP180_PRESSURE, Arduino requests measurements via the I2C bus, using address 0x77. The data is displayed on an SSD1306 OLED screen, showing atmospheric pressure in hPa, temperature in °C, and estimated altitude in meters. Applications: weather stations, barometers, altimeters, and environmental monitoring systems. It is designed for the latest versions of Simulide 1 and 2.
SUBCIRCUIT SCRIPT AND INO PROGRAM:
Both are shown separately below.
// BMP180s SCRIPT. DEFRAN26A
// Direccion I2C fija: 0x77 (escritura 0xEE, lectura 0xEF)
// VP: 0..5 V = 300..1100 hPa; VT: 0..5 V = -20..60 C
// SDA open-drain; ACK sobre el noveno pulso SCL.
IoPin@ SDA = component.getPin("SDA");
IoPin@ SCL = component.getPin("SCL");
IoPin@ VP = component.getPin("VP");
IoPin@ VT = component.getPin("VT");
const int ESPERA = 0;
const int RECIBIR = 1;
const int ACK_ESCLAVO = 2;
const int TRANSMITIR = 3;
const int ACK_MASTER = 4;
const int FIN = 5;
array<uint> reg(256, 0);
int fase = ESPERA;
int bits = 0;
uint recibido = 0;
uint pointer = 0;
uint txDato = 0;
int txBit = 7;
bool primerDato = true;
bool direccionCorrecta = false;
bool direccionLectura = false;
bool novenoAlto = false;
bool oldSCL = true;
bool oldSDA = true;
bool procesando = false;
bool sdaForzada = false;
bool iniciarTxTrasAck = false;
bool siguienteEsValor = false;
bool masterConfirmo = false;
void releaseSDA()
{
sdaForzada = false;
SDA.setStateZ(true);
}
void pullSDA()
{
sdaForzada = true;
SDA.setOutState(false);
SDA.setStateZ(false);
}
void set16(uint a, int v)
{
uint w = uint(v) & 0xFFFF;
reg[a] = (w >> 8) & 255;
reg[a+1] = w & 255;
}
void loadCalibration()
{
set16(0xAA, 408); // AC1
set16(0xAC, -72); // AC2
set16(0xAE, -14383);// AC3
set16(0xB0, 32741); // AC4
set16(0xB2, 32757); // AC5
set16(0xB4, 23153); // AC6
set16(0xB6, 6190); // B1
set16(0xB8, 4); // B2
set16(0xBA, -32768);// MB
set16(0xBC, -8711); // MC
set16(0xBE, 2868); // MD
}
void updateMeasurement(uint cmd)
{
double vP = VP.getVoltage();
double vT = VT.getVoltage();
if (vP < 0) vP = 0;
if (vP > 5) vP = 5;
if (vT < 0) vT = 0;
if (vT > 5) vT = 5;
double pressurePa = 30000.0 + vP*16000.0;
double tempC = -20.0 + vT*16.0;
if (cmd == 0x2E)
{
// UT aproximado: 28525 corresponde a unos 20 C con esta calibracion
int ut = int(28525.0 + (tempC-20.0)*125.0);
if (ut < 0) ut = 0;
if (ut > 65535) ut = 65535;
reg[0xF6] = (uint(ut) >> 8) & 255;
reg[0xF7] = uint(ut) & 255;
reg[0xF8] = 0;
}
else if ((cmd & 0x3F) == 0x34)
{
uint oss = (cmd >> 6) & 3;
// Inversion lineal aproximada de la compensacion a 20 C.
int baseUP = int(34000.0 + (pressurePa-101465.0)/3.028);
if (baseUP < 0) baseUP = 0;
uint up = uint(baseUP) << oss;
uint adc = up << (8-oss);
reg[0xF6] = (adc >> 16) & 255;
reg[0xF7] = (adc >> 8) & 255;
reg[0xF8] = adc & 255;
}
reg[0xF4] = cmd & 0xDF; // SCO=0: conversion inmediata
}
void resetRegisters()
{
for (uint i=0; i<256; i++) reg[i] = 0;
loadCalibration();
reg[0xD0] = 0x55;
reg[0xD1] = 0x01;
reg[0xF6] = 0x80;
pointer = 0;
}
void escribirRegistro(uint direccion, uint valor)
{
direccion &= 0xFF;
if (direccion == 0xE0 && valor == 0xB6)
{
resetRegisters();
return;
}
if (direccion == 0xF4)
{
updateMeasurement(valor);
return;
}
if (direccion == 0xD0 || direccion == 0xD1) return;
if (direccion >= 0xAA && direccion <= 0xBF) return;
reg[direccion] = valor & 0xFF;
}
void ponerBitTx()
{
if (((txDato >> txBit) & 1) != 0) releaseSDA();
else pullSDA();
}
void comenzarTx()
{
txDato = reg[pointer & 0xFF];
txBit = 7;
bits = 0;
fase = TRANSMITIR;
ponerBitTx();
}
void reposo()
{
fase = ESPERA;
bits = 0;
recibido = 0;
novenoAlto = false;
releaseSDA();
}
void comenzar()
{
// El puntero se conserva ante un START repetido.
fase = RECIBIR;
bits = 0;
recibido = 0;
direccionCorrecta = false;
direccionLectura = false;
primerDato = true;
siguienteEsValor = false;
iniciarTxTrasAck = false;
novenoAlto = false;
releaseSDA();
}
void procesarByte(uint valor)
{
if (primerDato)
{
direccionCorrecta = ((valor >> 1) == 0x77);
direccionLectura = (valor & 1) != 0;
iniciarTxTrasAck = direccionCorrecta && direccionLectura;
primerDato = false;
siguienteEsValor = false;
}
else if (direccionCorrecta && !direccionLectura)
{
if (!siguienteEsValor)
{
pointer = valor & 0xFF;
siguienteEsValor = true;
}
else
{
escribirRegistro(pointer, valor);
pointer = (pointer + 1) & 0xFF;
}
iniciarTxTrasAck = false;
}
else direccionCorrecta = false;
}
void setup()
{
// inicializacion en reset().
}
void reset()
{
SCL.setPinMode(1);
VP.setPinMode(1);
VT.setPinMode(1);
SDA.setPinMode(3);
SDA.setOutHighV(5.0);
SDA.setOutState(false);
SDA.setStateZ(true);
procesando = false;
sdaForzada = false;
resetRegisters();
fase = ESPERA;
bits = 0;
recibido = 0;
primerDato = true;
siguienteEsValor = false;
iniciarTxTrasAck = false;
masterConfirmo = false;
direccionCorrecta = false;
direccionLectura = false;
novenoAlto = false;
oldSCL = SCL.getInpState();
oldSDA = SDA.getInpState();
SCL.changeCallBack(element, true);
SDA.changeCallBack(element, true);
}
void voltChanged()
{
if (procesando) return;
procesando = true;
bool scl = SCL.getInpState();
bool sda = SDA.getInpState();
bool subidaSCL = !oldSCL && scl;
bool bajadaSCL = oldSCL && !scl;
bool bajadaSDA = oldSDA && !sda;
bool subidaSDA = !oldSDA && sda;
oldSCL = scl; // actualizar ANTES de cambiar SDA.
oldSDA = sda;
if (!subidaSCL && !bajadaSCL && scl && !sdaForzada)
{
if (bajadaSDA) comenzar();
else if (subidaSDA) reposo();
}
if (fase == RECIBIR)
{
if (subidaSCL)
{
recibido = ((recibido << 1) | (sda ? 1 : 0)) & 0xFF;
bits++;
if (bits == 8) procesarByte(recibido);
}
else if (bajadaSCL && bits == 8)
{
if (direccionCorrecta)
{
fase = ACK_ESCLAVO;
novenoAlto = false;
pullSDA();
}
else fase = FIN;
}
}
else if (fase == ACK_ESCLAVO)
{
if (subidaSCL) novenoAlto = true;
else if (bajadaSCL && novenoAlto)
{
novenoAlto = false;
fase = FIN;
releaseSDA();
if (iniciarTxTrasAck) comenzarTx();
else
{
fase = RECIBIR;
bits = 0;
recibido = 0;
}
}
}
else if (fase == TRANSMITIR)
{
if (subidaSCL) bits++;
else if (bajadaSCL)
{
if (bits == 8)
{
releaseSDA();
fase = ACK_MASTER;
novenoAlto = false;
}
else if (bits > 0 && bits < 8)
{
txBit = 7 - bits;
ponerBitTx();
}
}
}
else if (fase == ACK_MASTER)
{
if (subidaSCL)
{
novenoAlto = true;
masterConfirmo = !sda;
}
else if (bajadaSCL && novenoAlto)
{
fase = FIN;
if (masterConfirmo)
{
pointer = (pointer + 1) & 0xFF;
comenzarTx();
}
else releaseSDA();
}
}
procesando = false;
}
// BMP180 PRESSURE SENSOR. DEFRAN26A
// BMP180: 0x77 OLED: 0x3C
// Librerias: Adafruit BMP085 Library, Adafruit GFX, Adafruit SSD1306
#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_ANCHO 128
#define OLED_ALTO 64
#define OLED_RESET -1
#define OLED_ADDR 0x3C
Adafruit_SSD1306 oled(OLED_ANCHO, OLED_ALTO, &Wire, OLED_RESET);
Adafruit_BMP085 bmp;
const unsigned long PERIODO_MS = 700;
const float PRESION_MAR_HPA = 1013.25;
const byte GRAF_PUNTOS = 29;
float historial[GRAF_PUNTOS];
byte muestras = 0;
byte siguiente = 0;
unsigned long anterior = 0;
bool sensorOK = false;
void setup()
{
Wire.begin();
Wire.setClock(100000); // 100 kHz.
if (!oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {}
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
oled.setTextSize(1);
oled.setCursor(10, 24); oled.print(F("STARTING BMP180..."));
oled.display();
sensorOK = bmp.begin(BMP085_ULTRALOWPOWER);
if (!sensorOK) {mostrarError(F("BMP180 NOT PRESENT")); return;}
anterior = millis() - PERIODO_MS;
}
void loop()
{
if (!sensorOK) return;
unsigned long ahora = millis();
if (ahora - anterior < PERIODO_MS) return;
anterior = ahora;
float presion = bmp.readPressure() / 100.0; // Pa -> hPa
float temperatura = bmp.readTemperature(); // grados Celsius
float altitud = bmp.readAltitude(PRESION_MAR_HPA * 100.0); // metros
if (presion < 100 || presion > 1300 || isnan(presion) || isnan(temperatura))
{
mostrarError(F("READING ERROR"));
return;
}
guardarPresion(presion);
mostrarDatos(presion, temperatura, altitud);
}
void mostrarError(const __FlashStringHelper *mensaje)
{
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
oled.setTextSize(1);
oled.drawRoundRect(0, 0, 128, 64, 5, SSD1306_WHITE);
oled.setCursor(4, 13); oled.print(F("METEO STATION"));
oled.drawFastHLine(12, 27, 104, SSD1306_WHITE);
oled.setCursor(13, 37);
oled.print(mensaje);
oled.display();
}
void guardarPresion(float hpa)
{
historial[siguiente] = hpa;
siguiente = (siguiente + 1) % GRAF_PUNTOS;
if (muestras < GRAF_PUNTOS) muestras++;
}
void dibujarGrafica()
{
const int x = 96, y = 46, w = 29, h = 16;
oled.drawRect(x - 2, y - 2, w + 4, h + 4, SSD1306_WHITE);
if (muestras < 2) return;
float minimo = historial[0];
float maximo = historial[0];
for (byte i = 1; i < muestras; i++)
{
if (historial[i] < minimo) minimo = historial[i];
if (historial[i] > maximo) maximo = historial[i];
}
if (maximo - minimo < 0.6)
{
float medio = (maximo + minimo) * 0.5;
minimo = medio - 0.3;
maximo = medio + 0.3;
}
byte inicio = (muestras == GRAF_PUNTOS) ? siguiente : 0;
for (byte i = 1; i < muestras; i++)
{
byte ia = (inicio + i - 1) % GRAF_PUNTOS;
byte ib = (inicio + i) % GRAF_PUNTOS;
int xa = x + (long)(i - 1) * (w - 1) / (muestras - 1);
int xb = x + (long)i * (w - 1) / (muestras - 1);
int ya = y + h - 1 - (int)((historial[ia] - minimo) * (h - 1) / (maximo - minimo));
int yb = y + h - 1 - (int)((historial[ib] - minimo) * (h - 1) / (maximo - minimo));
oled.drawLine(xa, ya, xb, yb, SSD1306_WHITE);
}
}
void mostrarDatos(float presion, float temperatura, float altitud)
{
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
oled.fillRoundRect(0, 0, 128, 13, 3, SSD1306_WHITE); // Banda superior invertida
oled.setTextColor(SSD1306_BLACK);
oled.setTextSize(1);
oled.setCursor(6, 3); oled.print(F("BMP180 | BAROMETER"));
oled.setTextColor(SSD1306_WHITE);
oled.setCursor(4, 18); // Presion grande, sin parpadeos: solo se actualiza cada 700 ms
oled.setTextSize(3);
if (presion >= 1000.0) {oled.print((int)(presion + 0.5));}
else {oled.print(presion, 0);}
oled.setTextSize(1);
oled.setCursor(89, 30); oled.print(F("hPa"));
oled.drawFastHLine(4, 42, 120, SSD1306_WHITE);
oled.setTextSize(1);
oled.setCursor(4, 47); oled.print(F("TEMP"));
oled.setCursor(4, 56); oled.print(temperatura, 1);
oled.write((uint8_t)247); // Simbolo de grado de la fuente integrada
oled.print(F("C"));
oled.setCursor(53, 47); oled.print(F("ALT"));
oled.setCursor(53, 56);
oled.print((int)(altitud + (altitud >= 0 ? 0.5 : -0.5)));
oled.print(F("m"));
dibujarGrafica();
oled.display();
}
PROVIDED FILES:
The ZIP file contains all parts of the example, hardware and software. The subcircuit is included as a inner extraZIP for the user's discretionary use.
P. de Francisco
Uploaded files: