logo elektroda
logo elektroda
X
logo elektroda

DIY barograph/barometer with BME280 and Arduino Nano - how to build cheaply and get up and running w

JanuszArtur  10 3675 Cool? (+21)
📢 Listen (AI):

TL;DR

  • Zbudowano tani barograf/barometr na Arduino Nano, czujniku BME280 i wyświetlaczu LCD 20x4 z zapisem historii ciśnienia.
  • Układ rysuje wykres z 128 próbek w EEPROM, odświeża pomiar okresowo i pozwala zmieniać interwał przyciskiem.
  • W projekcie wykorzystano Nano za około 12 zł, wyświetlacz za około 50 zł i czujnik za 4 zł; zamiast AdaFruit BME280 wybrano tańszy moduł.
  • Działa poprawnie i wygląda dobrze, a jasność LCD regulowanym potencjometrem 5 kΩ można dostroić przez jumper I2C; autor chciałby jeszcze automatycznego skalowania osi Y.
Generated by the language model.
I bought a barometer. The seller said there was a mistake, not 50pln but 500pln it was supposed to be. He refunded the money.

I bought another one - broken, it's sitting under the kitchen table waiting for a return label.

I bought a third one - a new USSR, but it didn't survive transport....
So much for the basic question "why do this, isn't it easier to buy on the alegro?", or: "they are available online - why waste time?".

I found the projects SECRET and closed on the electrode, so had to look elsewhere. It was supposed to be simple, easy, clear, not very expensive.

I rummaged through my resources. I had a display (about 50pln), a Nano (about 12pln), and for 4pln I bought an I2C SPI BMP280 3.3V pressure transmitter.
I used this development: Link but it proved problematic to use the AdaFruit BME280 product because of the price (over 70pln cheapest I could find).

I have converted the code to the following, as the regular BME280 does not support all the commands as the AdaFruit does:

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include "GyverButton.h"
#include <BME280I2C.h>                      
#define BTN_PIN 3                            
#define BASE_PERIOD 675000                   
#define MIN_VAL 990                          
#define MAX_VAL 1035                         
LiquidCrystal_I2C lcd(0x27, 20, 4);          
GButton butt1(BTN_PIN);
BME280I2C bme;                               
uint32_t tmr1, tmr2;                         
uint32_t set_period = BASE_PERIOD;           
int16_t plot_array[20];                      
uint16_t base_array[128];                    
int16_t value, delta;                        
byte interval = 1 ;                          
void setup() {
  read_all();
  attachInterrupt(1, isr, CHANGE);
  butt1.setDebounce(80);                     
  butt1.setTimeout(300);                     
  lcd.init();
  lcd.backlight();
  lcd.clear();
  Wire.begin();
  if (!bme.begin()) { // Initialization of the BME280 sensor
    lcd.setCursor(3, 1);
    lcd.print(F("NIE WIDZE CZUJKI"));
    lcd.setCursor(7, 2);
    lcd.print(F("BME280"));
    while (1);
  }
  if (!digitalRead(BTN_PIN)) {                         
    for (byte i = 0; i < 128; i++) base_array[i] = 0;  
    update_all();                                      
    lcd.setCursor(4, 1);                               
    lcd.print(F("KASUJ HISTORIE"));
    lcd.setCursor(8, 2);
    lcd.print(F("<OK>"));
  }
  while (!digitalRead(BTN_PIN));
  lcd.clear();
  initPlot();                                
  float pres, temp, hum;
  bme.read(pres, temp, hum);
  value = round(pres);                        
  base_array[0] = value;
  get_data();
}
void isr() {                                  
  butt1.tick();
}
void loop() {
  butt1.tick();                               
  if (butt1.isClick()) {                      
    interval *= 2;                            
    if (interval > 8) interval = 1;
    set_period = BASE_PERIOD * interval;      
    get_data();                               
  }
  if (millis() - tmr1 >= BASE_PERIOD) {       
    tmr1 = millis();                          
    for (int i = 126; i >= 0; i--) {          
      base_array[i + 1] = base_array[i];
    }
    float pres, temp, hum;
    bme.read(pres, temp, hum);
    value=round(pres);                                     
    base_array[0] = value;                                 
    update_all();                                          
  }
  if (millis() - tmr2 >= set_period) {                     
    tmr2 = millis();                                       
    get_data();
  }
}
void get_data() {                                           
  for (int i = 15; i >= 0; i--) {
    drawPlot(0, 3, 16, 4, MIN_VAL, MAX_VAL, (base_array[i * interval]));
  }
  delta = ((base_array[0]) - (base_array[15 * interval]));  
  screen_data(value, delta, (interval * 3));                
}
void screen_data(int value, int delta, byte interval) {    
  lcd.setCursor(16, 0);
  lcd.print(int(value));
  lcd.setCursor(17, 2);
  if (delta == value) delta = 0;
  if (delta > 0) {
    lcd.print("+");
  } else if (delta < 0) {
    lcd.print("-");
  } else if (delta == 0) {
    lcd.print(" ");
  }
  lcd.setCursor(18, 2);
  lcd.print(abs(delta));
  if (abs(delta) < 10) {
    lcd.setCursor(19, 2);
    lcd.print(" ");
  }
  lcd.setCursor(17, 1);
  lcd.print("hPa");
  lcd.setCursor(17, 3);
  lcd.print(interval);
  (interval < 10) ? lcd.print("h ") : lcd.print("h");
}
void initPlot() {
  byte row8[8] = {0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row7[8] = {0b00000,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row6[8] = {0b00000,  0b00000,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row5[8] = {0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row4[8] = {0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row3[8] = {0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111};
  byte row2[8] = {0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111};
  byte row1[8] = {0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111};
  lcd.createChar(0, row8);
  lcd.createChar(1, row1);
  lcd.createChar(2, row2);
  lcd.createChar(3, row3);
  lcd.createChar(4, row4);
  lcd.createChar(5, row5);
  lcd.createChar(6, row6);
  lcd.createChar(7, row7);
}
void drawPlot(byte pos, byte row, byte width, byte height, int min_val, int max_val, int fill_val) {
  for (byte i = 0; i < width; i++) {
    plot_array[i] = plot_array[i + 1];
  }
  fill_val = constrain(fill_val, min_val, max_val);
  plot_array[width - 1] = fill_val;
  for (byte i = 0; i < width; i++) {
    int infill, fract;
    infill = floor((float)(plot_array[i] - min_val) / (max_val - min_val) * height * 10);
    fract = (infill % 10) * 8 / 10;
    infill = infill / 10;
    for (byte n = 0; n < height; n++) {
      if (n < infill && infill > 0) {
        lcd.setCursor(i, (row - n));
        lcd.write(0);
      }
      if (n >= infill) {
        lcd.setCursor(i, (row - n));
        if (fract > 0) lcd.write(fract);
        else lcd.write(16);
        for (byte k = n + 1; k < height; k++) {
          lcd.setCursor(i, (row - k));
          lcd.write(16);
        }
        break;
      }
    }
  }
}
void update_all() {
  eeprom_update_block((void*)&base_array, 0, sizeof(base_array));
}
void read_all() {
  eeprom_read_block((void*)&base_array, 0, sizeof(base_array));
}
.

I connected a 5kOhm potentiometer to the I2C converter jumper so that I could 'adjust the brightness' of the display.
Power supply with samsung cable - I cut off the broken USB-C end.
A bend from a broken power supply.
3D printing I made ABS. SolidWorks, STEP, STL files - attached.
Works cool. Recommended.
It looks like this:

Black barometer in a rectangular casing with an LCD display, set on a red background. .

Black electronic DIY project with a cable on a red background. .

DIY digital barometer with LCD display in a black casing. .

LCD screen showing pressure readings and bar graph .

LCD display showing barometer data. .

LCD display with pressure graph and data .

3D render of a housing with three separate components, part of an electronic project. .

3D case design for a barometer created in CAD software. .

LCD display layout with dimension details. .

IF YOU WOULD LIKE, please suggest changing the code as described below.

TO:
- The dream would be that the graph would be scaled for each interval (3, 6, 12, 24h) and start with the minimum measured pressure value as the minimum of the Y axis and end with the maximum measured pressure value and this would be the MAX of the Y axis.

Of course, this is a redesign. Not my design. The author is Mirko Pavleski. I only adapted to the poor-elements.
Attachments:
  • 3D-szkice.rar (744.41 KB) You must be logged in to download this attachment.

About Author
JanuszArtur
JanuszArtur wrote 301 posts with rating 94 . Live in city Warszawa. Been with us since 2007 year.

Comments

Jawi_P 02 Feb 2025 21:45

. I don't think I understand you quite well, but for a foreigner you handle Polish quite well. A little more and you'll be ok. As for "hardware" - you could also think about some ESP32, already with... [Read more]

efi222 03 Feb 2025 01:07

For such small changes in the graph, you could try displaying it on an automatic scale. This looks more dynamic (pictorial). [Read more]

JanuszArtur 03 Feb 2025 09:34

. Super. Please quote me an ESP32 with already built-in display of the same - or larger size, at a similar price. I would be happy to buy a 4x20 OLED for 50pln in the BIG version. Will you provide a link... [Read more]

efi222 03 Feb 2025 10:52

. You've written that you've rewritten a ready-made one, so keep trying to make modifications yourself. . You can dream on, or take matters into your own hands :) . I am an amateur with no connection... [Read more]

Anonymous 04 Feb 2025 21:28

ESP with OLed from 35pln, depending on the size, even 2" TFT, add a BME280 connection, somehow it is possible, software is a piece of cake, ESPEasy is even possible to throw the readings on the server... [Read more]

vodiczka 16 Feb 2025 09:49

. That what? [Read more]

efi222 16 Feb 2025 12:30

My understanding is this: The author of the topic found the barometer in an online shop for 50pln and ordered it. The seller realised that the price displayed was wrong and that the barometer actually... [Read more]

vodiczka 16 Feb 2025 12:46

This may have been the case, but juxtaposed with the next two cases, it looks like an invention of the author rather than actual problems related to the purchase of three barometers consecutively. In addition,... [Read more]

JanuszArtur 17 Feb 2025 11:47

. I stated at the beginning the reason why I got pissed....m and instead of buying more junk, I looked and did. One of the barometers purchased is lying under the table still waiting for a return label.... [Read more]

efi222 17 Feb 2025 13:30

. Maybe not the first, but it's a fact. Consumer visits to this section are not that uncommon at all. I understand the comparison of the presented design with factory equipment. I just don't know what... [Read more]

FAQ

TL;DR: A working 20 × 4 LCD barograph costs ≈ 66 PLN—56 % below the 150 PLN goal—and is “simple = uncomplicated” [Elektroda, JanuszArtur, post #21421897] Why it matters: You can visualise 24 h of pressure data for the price of one takeaway pizza.

Quick Facts

• Core parts: Arduino Nano (≈ 12 PLN), 20 × 4 I²C LCD (≈ 50 PLN), BME280 sensor (≈ 4 PLN) [Elektroda, 21421897] • Base logging period: 675 000 ms (11 min 15 s) — 128 records ≈ 24 h history • View windows: 3 h, 6 h, 12 h, 24 h selectable with one button • Typical sea-level pressure: 980 – 1050 hPa [WMO, 2023] • Target budget declared by author: ≤ 150 PLN [Elektroda, 21422553]

What hardware do I need to build the barograph?

You need an Arduino Nano, a 20 × 4 HD44780 LCD with I²C backpack, a BME280 pressure sensor module, a 5 kΩ potentiometer for backlight, a Micro-USB power lead, and printed ABS housing [Elektroda, JanuszArtur, post #21421897]

How much will the project cost?

Parts in the author’s build total ≈ 66 PLN: LCD 50 PLN, Nano 12 PLN, BME280 4 PLN. This is 56 % under the stated 150 PLN ceiling [Elektroda, #21421897; #21422553].

How often does the sketch sample pressure and what intervals can I display?

The code logs a reading every 675 000 ms (11 min 15 s). The button cycles intervals of 1, 2, 4, 8 records, shown as 3 h, 6 h, 12 h and 24 h windows on the LCD [Elektroda, 21421897]

How can I add automatic Y-axis scaling?

  1. In get_data(), compute min/max from base_array for the selected interval.
  2. Pass those values to drawPlot() instead of fixed MIN_VAL/MAX_VAL.
  3. Refresh the plot after each new sample. Result: the graph stretches to full height for every time window.

Can I swap the Nano for an ESP32 with built-in display?

Yes. ESP32 boards with 0.96-inch OLED start around 35 PLN and can drive BME280 over I²C. You must port the sketch to use U8g2 or TFT_eSPI for graphics [Elektroda, Anonymous, post #21425096]

How accurate is the BME280 sensor?

Bosch specifies ±1 hPa absolute accuracy and ±0.12 hPa relative accuracy between 700–1100 hPa [Bosch, 2022]. That rivals entry-level aneroid barometers (±3 hPa typical).

What happens if the sensor is missing or wired wrongly?

During setup, bme.begin() returns false, the LCD shows “NIE WIDZE CZUJKI BME280”, and the code enters an infinite loop—no readings are taken [Elektroda, 21421897]

How do I dim the LCD backlight?

The author inserted a 5 kΩ potentiometer between the I²C backpack’s LED pin and ground. Adjusting resistance changes current and brightness [Elektroda, 21421897]

How much history is stored in EEPROM?

base_array holds 128 signed 16-bit values. At 11.25-minute spacing, that equals exactly 24 hours of data. update_all() writes the full array to EEPROM, preserving history after power loss [Elektroda, 21421897]

How do I change the displayed pressure range?

Edit MIN_VAL and MAX_VAL constants (990/1035 by default) and recompile. If you later implement auto-scaling these constants become dynamic so manual adjustment is unnecessary.

Which Arduino libraries are required?

Include LiquidCrystal_I2C, Wire, GyverButton, and BME280I2C. All are available through the Arduino Library Manager [Elektroda, 21421897]

What pressure extremes should I expect in Central Europe?

Records show 962 hPa (deep low) to 1054 hPa (strong high) since 1960, a 92 hPa span [DWD, 2021]. Design your auto-scale logic to handle this range.
Generated by the language model.
%}