Estación meteorológica compacta: Arduino Nano y ESP8266 con sensor BMP280 y pantalla OLED/Nokia LCD
Componentes y suministros
| Arduino Nano R3 | 1 |
| Sensor presión barométrica BMP280 I2C (MyOctopus) | 1 |
| Pantalla LCD Nokia 5110 | 1 |
| NodeMCU 1.0 (ESP12E) | 1 |
| Pantalla OLED gráfica 128x64 | 1 |
Herramientas necesarias
- Soldador (genérico)
Sobre el proyecto
Este dispositivo consta de dos ensamblajes independientes en una misma caja.
Uno es el barómetro Arduino con sensor BMP180 (en el código se usa BMP180, aunque el componente listado es BMP280), que muestra la presión atmosférica en tiempo real y las diferencias a -1h y -3h. Estos informes son particularmente útiles para pronósticos meteorológicos locales a corto plazo. El código proviene del sitio web "shelvin.de", donde se introduce la diferencia entre la presión absoluta y la relativa para la altitud dada en la línea "druck_offset=" del código. Los resultados se muestran en la pantalla LCD N5110, que también muestra la temperatura interna.

El siguiente dispositivo funciona con una placa ESP8266 que conecta una pantalla OLED de 0.96 pulgadas. El ESP8266 se conecta vía Wi-Fi a la página "openweathermap", de donde obtiene un pronóstico de tres días y lo presenta en la pantalla OLED. Para ello, necesitas introducir una API key en el código, que se obtiene en la página de OpenWeatherMap. Instrucciones detalladas para instalar librerías y código en el ESP8266 están en: Guía de inicio ESP8266 Weather Station. En este caso uso la placa NodeMCU 1.0 (módulo ESP12E).
La imagen siguiente muestra el esquema del dispositivo completo.
Código
Código barómetro Arduino Arduino
// Luftdruck Ausgabe aktuell // Luftdruckdifferenz wird mit 1 und 3 Stunden vorher (im EEPROM) verglichen und ausgegeben // Temperatur Ausgabe aktuell // // Bauteile: // LCD Display vom Nokia 5110 // BMP180 Luftdrucksensor // Arduino Uno // // Matthias Busse Version 1.0 vom 21.9.2014
#include <Wire.h>
#include <avr/sleep.h>
#include <EEPROM.h>
int eepromAdresse=0, eepromMax=1023; int eepromOldAdr, eepromDif1=60, eepromDif3=180;
#define I2C_ADDRESS 0x77
const unsigned char oversampling_setting = 3;
const unsigned char pressure_waittime[4] = { 5, 8, 14, 26 };
int ac1, ac2, ac3, b1, b2, mb, mc, md; unsigned int ac4, ac5, ac6;
int temp = 20, temp_mittel=200, test=0; long druck = 1013, druck_mittel=101300;
float t, temp_offset=0.0, d, dAlt, dDiff, druck_offset=2.0;
int zeitabgl=0, mitteln=5; char tstring[5], dstring[7];
volatile int sleepcounter = 0;
static const byte ASCII[][5] = {
{0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x5f, 0x00, 0x00}, {0x00, 0x07, 0x00, 0x07, 0x00},
{0x14, 0x7f, 0x14, 0x7f, 0x14}, {0x24, 0x2a, 0x7f, 0x2a, 0x12}, {0x23, 0x13, 0x08, 0x64, 0x62},
{0x36, 0x49, 0x55, 0x22, 0x50}, {0x00, 0x05, 0x03, 0x00, 0x00}, {0x00, 0x1c, 0x22, 0x41, 0x00},
{0x00, 0x41, 0x22, 0x1c, 0x00}, {0x14, 0x08, 0x3e, 0x08, 0x14}, {0x08, 0x08, 0x3e, 0x08, 0x08},
{0x00, 0x50, 0x30, 0x00, 0x00}, {0x08, 0x08, 0x08, 0x08, 0x08}, {0x00, 0x60, 0x60, 0x00, 0x00},
{0x20, 0x10, 0x08, 0x04, 0x02}, {0x3e, 0x51, 0x49, 0x45, 0x3e}, {0x00, 0x42, 0x7f, 0x40, 0x00},
{0x42, 0x61, 0x51, 0x49, 0x46}, {0x21, 0x41, 0x45, 0x4b, 0x31}, {0x18, 0x14, 0x12, 0x7f, 0x10},
{0x27, 0x45, 0x45, 0x45, 0x39}, {0x3c, 0x4a, 0x49, 0x49, 0x30}, {0x01, 0x71, 0x09, 0x05, 0x03},
{0x36, 0x49, 0x49, 0x49, 0x36}, {0x06, 0x49, 0x49, 0x29, 0x1e}, {0x00, 0x36, 0x36, 0x00, 0x00},
{0x00, 0x56, 0x36, 0x00, 0x00}, {0x08, 0x14, 0x22, 0x41, 0x00}, {0x14, 0x14, 0x14, 0x14, 0x14},
{0x02, 0x01, 0x51, 0x09, 0x06}, {0x32, 0x49, 0x79, 0x41, 0x3e}, {0x7e, 0x11, 0x11, 0x11, 0x7e},
{0x7f, 0x49, 0x49, 0x49, 0x36}, {0x3e, 0x41, 0x41, 0x41, 0x22}, {0x7f, 0x41, 0x41, 0x22, 0x1c},
{0x7f, 0x09, 0x09, 0x09, 0x01}, {0x3e, 0x41, 0x49, 0x49, 0x7a}, {0x7f, 0x08, 0x08, 0x08, 0x7f},
{0x00, 0x41, 0x7f, 0x41, 0x00}, {0x20, 0x40, 0x41, 0x3f, 0x01}, {0x7f, 0x08, 0x14, 0x22, 0x41},
{0x7f, 0x40, 0x40, 0x40, 0x40}, {0x7f, 0x02, 0x0c, 0x02, 0x7f}, {0x7f, 0x04, 0x08, 0x10, 0x7f},
{0x3e, 0x41, 0x41, 0x41, 0x3e}, {0x7f, 0x09, 0x09, 0x09, 0x06}, {0x3e, 0x41, 0x51, 0x21, 0x5e},
{0x7f, 0x09, 0x19, 0x29, 0x46}, {0x46, 0x49, 0x49, 0x49, 0x31}, {0x01, 0x01, 0x7f, 0x01, 0x01},
{0x3f, 0x40, 0x40, 0x40, 0x3f}, {0x1f, 0x20, 0x40, 0x20, 0x1f}, {0x3f, 0x40, 0x38, 0x40, 0x3f},
{0x63, 0x14, 0x08, 0x14, 0x63}, {0x07, 0x08, 0x70, 0x08, 0x07}, {0x61, 0x51, 0x49, 0x45, 0x43},
{0x00, 0x7f, 0x41, 0x41, 0x00}, {0x02, 0x04, 0x08, 0x10, 0x20}, {0x00, 0x41, 0x41, 0x7f, 0x00},
{0x04, 0x02, 0x01, 0x02, 0x04}, {0x40, 0x40, 0x40, 0x40, 0x40}, {0x00, 0x01, 0x02, 0x04, 0x00},
{0x20, 0x54, 0x54, 0x54, 0x78}, {0x7f, 0x48, 0x44, 0x44, 0x38}, {0x38, 0x44, 0x44, 0x44, 0x20},
{0x38, 0x44, 0x44, 0x48, 0x7f}, {0x38, 0x54, 0x54, 0x54, 0x18}, {0x08, 0x7e, 0x09, 0x01, 0x02},
{0x0c, 0x52, 0x52, 0x52, 0x3e}, {0x7f, 0x08, 0x04, 0x04, 0x78}, {0x00, 0x44, 0x7d, 0x40, 0x00},
{0x20, 0x40, 0x44, 0x3d, 0x00}, {0x7f, 0x10, 0x28, 0x44, 0x00}, {0x00, 0x41, 0x7f, 0x40, 0x00},
{0x7c, 0x04, 0x18, 0x04, 0x78}, {0x7c, 0x08, 0x04, 0x04, 0x78}, {0x38, 0x44, 0x44, 0x44, 0x38},
{0x7c, 0x14, 0x14, 0x14, 0x08}, {0x08, 0x14, 0x14, 0x18, 0x7c}, {0x7c, 0x08, 0x04, 0x04, 0x08},
{0x48, 0x54, 0x54, 0x54, 0x20}, {0x04, 0x3f, 0x44, 0x40, 0x20}, {0x3c, 0x40, 0x40, 0x20, 0x7c},
{0x1c, 0x20, 0x40, 0x20, 0x1c}, {0x3c, 0x40, 0x30, 0x40, 0x3c}, {0x44, 0x28, 0x10, 0x28, 0x44},
{0x0c, 0x50, 0x50, 0x50, 0x3c}, {0x44, 0x64, 0x54, 0x4c, 0x44}, {0x00, 0x08, 0x36, 0x41, 0x00},
{0x00, 0x00, 0x7f, 0x00, 0x00}, {0x00, 0x41, 0x36, 0x08, 0x00}, {0x10, 0x08, 0x08, 0x10, 0x08},
{0x78, 0x46, 0x41, 0x46, 0x78}
};
#define RST 12 #define CE 11 #define DC 10 #define DIN 9 #define CLK 8
void setup(){
for(int i=0; i < eepromMax; i+=4) eepromWriteLong(0,i);
watchdogOn();
ADCSRA = ADCSRA & B01111111; ACSR = B10000000; DIDR0 = DIDR0 | B00111111;
Wire.begin();
bmp180_get_cal_data();
bmp180_read_temperature_and_pressure(&temp_mittel,&druck_mittel);
pinMode(RST, OUTPUT); pinMode(CE, OUTPUT); pinMode(DC, OUTPUT); pinMode(DIN, OUTPUT); pinMode(CLK, OUTPUT);
digitalWrite(RST, LOW); digitalWrite(RST, HIGH);
LcdWriteCmd(0x21); LcdWriteCmd(0xB8); LcdWriteCmd(0x04); LcdWriteCmd(0x14);
LcdWriteCmd(0x20); LcdWriteCmd(0x0C); LcdClearScreen();
}
void loop() {
bmp180_read_temperature_and_pressure(&temp, &druck);
temp_mittel = ((temp_mittel * (mitteln-1)) + temp) / mitteln;
druck_mittel = ((druck_mittel * (mitteln-1)) + druck) / mitteln;
t=((float)temp_mittel/10.0)+temp_offset;
d=((float)druck_mittel/100.0)+druck_offset;
LcdClearLine(0); LcdXY(12,0); LcdWriteString(dtostrf(d,7,2,dstring)); LcdXY(60,0); LcdWriteString("hPa");
eepromWriteLong(d*100, eepromAdresse);
eepromOldAdr=eepromAdresse -(eepromDif1*4);
if(eepromOldAdr < 0) eepromOldAdr = eepromMax + 1 + eepromOldAdr;
dAlt=(float)eepromReadLong(eepromOldAdr)/100.0; dDiff=d-dAlt;
LcdClearLine(2); LcdXY(8,2); LcdWriteString("1h:");
if(dAlt > 800) { LcdXY(27,2); if(dDiff < 0.0) LcdWriteString("-"); else LcdWriteString("+"); if(dDiff < 0.0) dDiff=dDiff*-1.0; LcdXY(34,2); LcdWriteString(dtostrf(dDiff,4,2,dstring)); }
LcdXY(60,2); LcdWriteString("hPa");
eepromOldAdr=eepromAdresse -(eepromDif3*4);
if(eepromOldAdr < 0) eepromOldAdr = eepromMax + 1 + eepromOldAdr;
dAlt=(float)eepromReadLong(eepromOldAdr)/100.0; dDiff=d-dAlt;
LcdClearLine(3); LcdXY(8,3); LcdWriteString("3h:");
if(dAlt > 800) { LcdXY(27,3); if(dDiff < 0.0) LcdWriteString("-"); else LcdWriteString("+"); if(dDiff < 0.0) dDiff=dDiff*-1.0; LcdXY(34,3); LcdWriteString(dtostrf(dDiff,4,2,dstring)); }
LcdXY(60,3); LcdWriteString("hPa");
LcdClearLine(5); LcdXY(8,5); LcdWriteString("Temp. "); LcdXY(43,5); LcdWriteString(dtostrf(t,4,1,tstring)); LcdXY(73,5); LcdWriteString("C");
eepromAdresse += 4; if(eepromAdresse > eepromMax) eepromAdresse=0;
pwrDown(54);
}
void eepromWriteLong(long lo, int adr) {
byte by; for(int i=0;i < 4;i++) { by = (lo >> ((3-i)*8)) & 0x000000ff; EEPROM.write(adr+i, by); }
}
long eepromReadLong(int adr) {
long lo=0; for(int i=0;i < 3;i++){ lo += EEPROM.read(adr+i); lo = lo << 8; } lo += EEPROM.read(adr+3); return lo;
}
void LcdWriteString(char *characters) { while(*characters) LcdWriteCharacter(*characters++); }
void LcdWriteCharacter(char character) { for(int i=0; i < 5; i++) LcdWriteData(ASCII[character - 0x20][i]); LcdWriteData(0x00); }
void LcdWriteCmd(byte cmd){ digitalWrite(DC, LOW); digitalWrite(CE, LOW); shiftOut(DIN, CLK, MSBFIRST, cmd); digitalWrite(CE, HIGH); }
void LcdWriteData(byte cmd){ digitalWrite(DC, HIGH); digitalWrite(CE, LOW); shiftOut(DIN, CLK, MSBFIRST, cmd); digitalWrite(CE, HIGH); }
void LcdClearScreen() { for(int i=0; i < 504; i++) LcdWriteData(0x00); }
void LcdClearLine(int line) { LcdXY(0, line); for(int i=0; i < 84; i++) LcdWriteData(0x00); }
void LcdXY(int x, int y) { LcdWriteCmd(0x80|x); LcdWriteCmd(0x40|y); }
void bmp180_read_temperature_and_pressure(int* temp, long* druck) {
int ut= bmp180_read_ut(); long up = bmp180_read_up();
long x1, x2, x3, b3, b5, b6, p; unsigned long b4, b7;
x1 = ((long)ut - ac6) * ac5 >> 15;
x2 = ((long) mc << 11) / (x1 + md);
b5 = x1 + x2; *temp = (b5 + 8) >> 4;
b6 = b5 - 4000;
x1 = (b2 * (b6 * b6 >> 12)) >> 11;
x2 = ac2 * b6 >> 11;
x3 = x1 + x2;
if (oversampling_setting == 3) b3 = ((int32_t) ac1 * 4 + x3 + 2) << 1;
if (oversampling_setting == 2) b3 = ((int32_t) ac1 * 4 + x3 + 2);
if (oversampling_setting == 1) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 1;
if (oversampling_setting == 0) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 2;
x1 = ac3 * b6 >> 13;
x2 = (b1 * (b6 * b6 >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (ac4 * (uint32_t) (x3 + 32768)) >> 15;
b7 = ((uint32_t) up - b3) * (50000 >> oversampling_setting);
p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
x1 = (p >> 8) * (p >> 8); x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
*druck = p + ((x1 + x2 + 3791) >> 4);
}
unsigned int bmp180_read_ut() { write_register(0xf4,0x2e); delay(5); return read_int_register(0xf6); }
void bmp180_get_cal_data() {
ac1 = read_int_register(0xAA); ac2 = read_int_register(0xAC); ac3 = read_int_register(0xAE);
ac4 = read_int_register(0xB0); ac5 = read_int_register(0xB2); ac6 = read_int_register(0xB4);
b1 = read_int_register(0xB6); b2 = read_int_register(0xB8); mb = read_int_register(0xBA);
mc = read_int_register(0xBC); md = read_int_register(0xBE);
}
long bmp180_read_up() {
write_register(0xf4,0x34+(oversampling_setting<<6));
delay(pressure_waittime[oversampling_setting]);
unsigned char msb, lsb, xlsb;
Wire.beginTransmission(I2C_ADDRESS); Wire.write(0xf6); Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, 3);
while(!Wire.available()) {} msb = Wire.read();
while(!Wire.available()) {} lsb |= Wire.read();
while(!Wire.available()) {} xlsb |= Wire.read();
return (((long)msb<<16) | ((long)lsb<<8) | ((long)xlsb)) >>(8-oversampling_setting);
}
void write_register(unsigned char r, unsigned char v) { Wire.beginTransmission(I2C_ADDRESS); Wire.write(r); Wire.write(v); Wire.endTransmission(); }
char read_register(unsigned char r) { unsigned char v; Wire.beginTransmission(I2C_ADDRESS); Wire.write(r); Wire.endTransmission(); Wire.requestFrom(I2C_ADDRESS, 1); while(!Wire.available()) {} v = Wire.read(); return v; }
int read_int_register(unsigned char r) { unsigned char msb, lsb; Wire.beginTransmission(I2C_ADDRESS); Wire.write(r); Wire.endTransmission(); Wire.requestFrom(I2C_ADDRESS, 2); while(!Wire.available()) {} msb = Wire.read(); while(!Wire.available()) {} lsb = Wire.read(); return (((int)msb<<8) | ((int)lsb)); }
void pwrDown(int sekunden) {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
for(int i=0; i < sekunden; i++) { sleep_enable(); sleep_mode(); sleep_disable(); }
}
void watchdogOn() {
MCUSR = MCUSR & B11110111;
WDTCSR = WDTCSR | B00011000;
WDTCSR = B00000110;
WDTCSR = WDTCSR | B01000000;
MCUSR = MCUSR & B11110111;
}
ISR(WDT_vect) { sleepcounter++; }
Esquemáticos
Proceso de manufactura
- La Kazoo: De Mirlitón Antiguo a Juguete Plástico Moderno – Historia, Fabricación y Futuro
- Giftduino: El Set de Regalo Arduino Definitivo para Aficionados y Educadores
- Visualiza Temperatura, Humedad y Presión BME280 en Pantalla Táctil Nextion
- Registrador de Datos de Alto Rendimiento para Globo Meteorológico con Arduino
- Estación Meteorológica Portátil Arduino por $10 – Nano, DHT22, BMP180 y LCD
- eDOT: Reloj Preciso y Estación Meteorológica Arduino con Control IR Integrado
- Monitorización Meteorológica en Tiempo Real con Arduino y ThingSpeak IoT
- Monitorización IoT de Presión en Tiempo Real con MKR GSM, Arduino Cloud y Google Sheets
- Construye una Estación Meteorológica Arduino Fiable con Sensores DHT
- Caja de Juegos Arcade LEGO con Arduino Nano – Kit DIY con Batería, LCD y 5 Juegos
- Elimine cables puente: Cómo BreadShield conecta Arduino directamente a protoboards