Search Code

Lesson 96-3: Barometric Pressure, Temperature, and Approximate Altitude Sensor BMP390 with Arduino on LCD2004

Lesson 96-3: Barometric Pressure, Temperature, and Approximate Altitude Sensor BMP390 with Arduino on LCD2004

The BMP390 is a highly precise barometric pressure, temperature, and approximate altitude sensor from Bosch. This tutorial, part of the Arduino Step-by-Step course by Robojax, focuses on how to read data from this sensor and display it on a large 20x4 (LCD2004) character display. This setup is ideal for projects where you need to see all sensor readings simultaneously on a single screen, making it perfect for environmental monitoring stations, weather stations, or as a precise altimeter for model rockets or drones.

BMP380_pink-module-1

Here are some practical project ideas you can build with this setup:

  • Building a home weather station that displays temperature, pressure, and altitude.
  • Creating a high-precision altimeter for a model rocket or high-altitude balloon to track its ascent and descent.
  • Developing a data logger for a greenhouse or server room where you can monitor atmospheric conditions in real-time.
  • Constructing a device to measure the difference in altitude between floors in a building, as demonstrated in the video.
BMP380_pink-module-4

Hardware Required

  • Arduino Uno (or any compatible board)
  • BMP390 Barometric Pressure Sensor Module
  • LCD2004 (20x4) I2C LCD Display
  • Jumper Wires

Wiring Guide

BMP390_arduino_wiring_2-gravity-module
BMP390_arduino_wiring_pink-1-from-sda-scl-pins
BMP390_arduino_wiring_pink-2
BMP390_LCD2004_wiring_pink

The wiring for this project is straightforward, as both the BMP390 sensor and the LCD2004 use the I2C communication protocol. This allows you to connect both devices using only two data lines (SDA and SCL) plus power and ground.

In the video, the sensor's VIN pin is connected to a digital pin (pin 12) on the Arduino. This is a clever trick used in the code to control power to the sensor, allowing the Arduino to turn it on or off programmatically. The sensor's SDA and SCL lines are connected to the Arduino's A4 and A5 pins, respectively.

For the LCD2004, the VCC and GND pins are connected to the Arduino's 5V and GND pins. Its SDA and SCL pins are also connected to A4 and A5, sharing the same I2C bus as the sensor.

Note on I2C Addresses: Each I2C device has a unique address. The LCD2004 often uses address 0x27 or 0x3F. You must run an I2C scanner sketch to find the correct address for your specific LCD, as shown in the video. The BMP390 sensor also needs to be detected on the bus.

 

BMP380_pink-module-2
BMP288-1

Code Explanation

This section explains the user-configurable parts of the code. The full program is available below the article. The code is designed to be modular, with a custom function to retrieve data and another to display it on the LCD.

1. Library and Pin Configuration

The code begins by including the necessary libraries for the BMP390 sensor and the I2C LCD. You will need to install the Adafruit BMP3XX library and the LiquidCrystal_I2C library using the Arduino Library Manager.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BMP3XX.h"
#include <LiquidCrystal_I2C.h>

// Set the LCD address to 0x27 or 0x3F for a 20 chars and 4 line display
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Pin for the BMP390 VIN
int bmpVCCPin = 12;
  • LiquidCrystal_I2C lcd(0x27, 20, 4);: This line initializes the LCD. The first parameter is the I2C address, which you must change to match your LCD (e.g., 0x3F). The second and third parameters are the number of columns (20) and rows (4) for your LCD2004.
  • int bmpVCCPin = 12;: This defines the Arduino pin that will provide power to the BMP390 sensor. You can change this to any other digital pin. The code sets this pin as an output and sets it HIGH in the setup() function to supply 5V to the sensor.

2. Configuring Display Units

boolean fahrenheit = true;//for Celsius set it to "false"
  • boolean fahrenheit = true;: This variable controls the temperature unit printed on the serial monitor. Setting it to true displays Fahrenheit, while setting it to false displays Celsius. The LCD display code always shows both units.

3. The getBMP() Function

This is a powerful custom function that retrieves a specific reading from the sensor. It takes a single character argument to specify which value you want.

float getBMP(char type)
{
   float value;
   float temp = bmp.temperature;
   if(type =='F') {
       value = temp *9/5 + 32;//convert to Fahrenheit
   } else if(type =='K') {
       value = temp + 273.15;//convert to Kelvin
   } else if(type =='P') {
       value = bmp.pressure / 100.0F; // read pressure in hPa
   } else if(type =='A') {
       value = bmp.readAltitude(SEALEVELPRESSURE_HPA);// read altitude
   } else {
       value = bmp.temperature;// read temperature in Celsius
   }
   return value;
}

How to use: To get a specific value, call the function with the corresponding character. For example, getBMP('F') returns the temperature in Fahrenheit, getBMP('P') returns the pressure in hectopascals (hPa), and getBMP('A') returns the approximate altitude in meters.

4. The lcdDisplay() Function

This function is a helper that simplifies printing a title and a value on the LCD at a specific position. It handles the cursor positioning and unit symbols (like °C, °F, hPa, m) automatically.

void lcdDisplay(int tc, int tr, String title, int vc, int vr, float value, char symbol)
{
   lcd.setCursor (tc,tr);
   lcd.print(title);
   if(vc !=99) {
       lcd.setCursor (vc,vr);
   }
   lcd.print(value);
   // ... code to print the correct unit symbol based on 'symbol' ...
}

How to use: You must provide the starting character (column) and line (row) for the title, the title text itself, the character and line position for the value, the numerical value, and a symbol character (e.g., 'C', 'F', 'p', 'm') to print the correct unit. A value of 99 for the value's character position tells the function to print the value immediately after the title.

Live Project Demonstration

In the video (at 28:05), Robojax demonstrates the project in action. The LCD2004 screen clearly shows all four key readings at once: Temperature in Celsius, Temperature in Fahrenheit, Pressure in hPa, and the Approximate Altitude in meters. This is a significant advantage over a smaller LCD1602, which can only show two of these values at a time.

He also performs a heat test using a heat gun (in video at 30:30), showing how the displayed temperature and altitude values respond instantly to changes in the sensor's environment, confirming the sensor's high precision and fast sampling rate.

To demonstrate the altitude feature, Robojax takes the project to a 25th floor of a building (in video at 35:43). The sensor reads an approximate altitude of 57.2 meters at the top, compared to a negative reading at the ground floor, showing a clear difference corresponding to the building's height.

The project for using the BMP390 as a thermostat to control a relay is covered in Lesson 96-4: Barometric Pressure, Temperature, and Approximate Altitude Sensor BMP390 with Arduino as a Thermostat.

Driving the sensor with basic code on the serial monitor is covered in Lesson 96-1: Barometric Pressure, Temperature, and Approximate Altitude Sensor BMP390 with Arduino Basic Code.

Displaying the sensor data on a smaller two-line screen is covered in Lesson 96-2: Barometric Pressure, Temperature, and Approximate Altitude Sensor BMP390 with Arduino on LCD1602.

Related projects from this video

Chapters

  • [00:00] Introduction to the BMP390 project
  • [01:19] Understanding the BMP390 sensor and its features
  • [05:45] Wiring diagram for BMP390 with Arduino Uno
  • [10:29] Installing the necessary Arduino libraries
  • [11:38] Explanation of the basic BMP390 code
  • [16:54] Setting up the LCD2004 and I2C address scanner
  • [20:09] Detailed code explanation for LCD2004 display
  • [26:22] Live demonstration with serial monitor and heat test
  • [28:05] Demonstration of the project on LCD2004
  • [32:12] Real-world altitude test on the 25th floor

Images

LCD2004_display-2
LCD2004_display-2
BMP288-1
BMP288-1
BMP380_pink-module-4
BMP380_pink-module-4
BMP380_pink-module-3-size
BMP380_pink-module-3-size
BMP380_pink-module-2
BMP380_pink-module-2
BMP380_pink-module-1
BMP380_pink-module-1
BMP380_pink-module-gravitiy-1
BMP380_pink-module-gravitiy-1
BMP390_arduino_wiring_2-gravity-module-sda-scl-pins
BMP390_arduino_wiring_2-gravity-module-sda-scl-pins
BMP390_arduino_wiring_2-gravity-module
BMP390_arduino_wiring_2-gravity-module
BMP390_arduino_wiring_pink-1-from-sda-scl-pins
BMP390_arduino_wiring_pink-1-from-sda-scl-pins
BMP390_arduino_wiring_pink-2
BMP390_arduino_wiring_pink-2
BMP390_LCD2004_wiring_pink
BMP390_LCD2004_wiring_pink
436-Lesson 96-3: BMP390 with LCD2004
Language: C++
/*
 * Lesson 96: BMP390 with LCD2004
 * with Arduino with LCD2004
Download and resource page https://robojax.com/RJT456

 * Watch video instruction on YouTube:  https://youtu.be/XevQYG_A5xA
 * 
 * Code updated by Ahmad Shamshiri for Robojax.com
 * on Jan 13, 2022 at 17:10 in Ajax, Ontario, Canada
  
  This video is part of Arduino Step by Step Course which starts here: https://youtu.be/-6qSrDUA5a8
 

If you found this tutorial helpful, please support me so I can continue creating content like this
and make a donation using PayPal http://robojax.com/L/?id=64


  This is a library for the BMP390 temperature & pressure sensor

  Designed specifically to work with the Adafruit BMP388 Breakout
  ----> http://www.adafruit.com/products/3966

  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface.

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing products
  from Adafruit!

  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 **************************************************************************
 */
#include <Wire.h>

#include <Adafruit_Sensor.h>
#include "Adafruit_BMP3XX.h"


#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BMP3XX bmp;
int bmpVCCPin = 12;
boolean fahrenheit = true;//for Celsius set it to "false"

#include <LiquidCrystal_I2C.h>
// Set the LCD address to 0x27 or 0x3F for a 20 chars and 4  line display
LiquidCrystal_I2C lcd(0x27, 20, 4);


void setup() {
    pinMode(bmpVCCPin, OUTPUT);// set pin as output
    digitalWrite(bmpVCCPin,HIGH);// always keep it high (5V) for BMB390 module
     
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Adafruit BMP388 / BMP390 test");

  if (!bmp.begin_I2C()) {   // hardware I2C mode, can pass in address & alt Wire
    Serial.println("Could not find a valid BMP3 sensor, check wiring!");
    while (1);
  }

  // Set up oversampling and filter initialization
  bmp.setTemperatureOversampling(BMP3_OVERSAMPLING_8X);
  bmp.setPressureOversampling(BMP3_OVERSAMPLING_4X);
  bmp.setIIRFilterCoeff(BMP3_IIR_FILTER_COEFF_3);
  bmp.setOutputDataRate(BMP3_ODR_50_HZ);
  // initialize the LCD, 
  lcd.begin();
  // Turn on the blacklight and print a message.
  lcd.backlight();     
  lcd.print("Robojax Video");
  lcd.setCursor (0,1); // go to start of 2nd line
  lcd.print("BMP390 Test LCD2004");
  lcd.setCursor (0,2); // go to start of 3nd line
  lcd.print("www.Robojax.com");  
  delay(4000);  
}

void loop() {
  if (! bmp.performReading()) {
    Serial.println("Failed to perform reading :(");
    return;
  }

    // Robojax.com BME390 Code
   lcd.clear();// clear previous values from screen  

lcdDisplay(
             // to print Celsius:
             0, // character 0 
             0, // line 0
             "Celsius: ", 

             // to print Celsius value
             12, // character undefined
             0, // line 0
             getBMP('C'),
             'C'
             );  

 lcdDisplay(
             // to print fahrenheit:
             0, // character 0 
             1, // line 2
             "Fahrenheit: ", 

             // to print Fahrenheit value
             12, // character 9
             1, // line 2
             getBMP('F'),
             'F'
             );  
 

lcdDisplay(
             // to print pressure text
             0, // character 0 
             2, // line 3
             "Pressure:", 

             // to print pressure value
             99, // character undefined
             2, // line 3
             getBMP('P'),
             'p' 
             );  
  lcdDisplay(
             // to print altitude text
             0, // character 0 
             3, // line 4
             "Aprx. Alt.:", 

             // to print Altitude value
             12, // character undefined
             3, // line 4
             getBMP('A'),
             'm' 
             );                   
        delay(4000);

     // Robojax.com BMP390 Code                                

  //take action, do something when temperature is greater than 38.0 C
  if(bmp.temperature >38.0)
  {
   digitalWrite(10, HIGH); 

   
  }else{
    digitalWrite(10, LOW);
  }
  delay(2000);
  printRobojax(false);//set to true, or false
  
}//loop ends here

/*
 * @brief returns temperature or relative humidity
 * @param "type" is character
 *     C = Celsius
 *     K = Kelvin
 *     F = Fahrenheit
 *     H = Humidity
 *     P = Pressure
 *     A = Altitude
 * @return returns one of the values above
 * Usage: to get Fahrenheit type: getBMP('F')
 * to print it on serial monitor Serial.println(getBMP('F'));
 * Written by Ahmad Shamshiri on July 13, 2019. Update 13 Jan 2022
 * at 20:56 
 * in Ajax, Ontario, Canada
 * www.Robojax.com 
 */
float getBMP(char type)
{
   // Robojax.com BMP390 Code
  float value;
    float temp = bmp.temperature;
  if(type =='F')
   {
    value = temp *9/5 + 32;//convert to Fahrenheit 
   }else if(type =='K')
   {
    value = temp + 273.15;//convert to Kelvin
   }else if(type =='P')
   {
    value = bmp.pressure / 100.0F; // read pressure
   }else if(type =='A')
   {
    value = bmp.readAltitude(SEALEVELPRESSURE_HPA);// read altitude
   }else{
    value = bmp.temperature;// read temperature
   }
   return value;
    // Robojax.com BME390 Code
}//getBME



/*
 * lcdDisplay(int tc, int tr, String title, int vc, int vr, float value)
 * displays value and title on LCD1602
 * How to use:
 * If you want to display: "Temp.: 340.45K" starting from first character
 * on second row.
 * use:
 * lcdDisplay(0, 1, "Temp.: ", 340.45,'K')
 *   
 *   'C' is degree symbol for C and F
 * tc  is character number  (0)
 * tr is row in the lcd (1)
 * title is the text (Voltage:)
 * vc value for character 
 * vr value for  row or line
 * value is the value (13.56)
 */
void lcdDisplay(int tc, int tr, String title, int vc, int vr, float value,char symbol)
{
   // Robojax.com LCD1602 for BMP390 Demo

   lcd.setCursor (tc,tr); //
   lcd.print(title);
   if(vc !=99)
   {
   lcd.setCursor (vc,vr); //
   }   
   lcd.print(value);
   if(symbol == 'C')
   {
    lcd.print((char)223);
    lcd.print('C');
   }else if(symbol == 'F')
   {
    lcd.print((char)223);
    lcd.print('F');
   }else if(symbol =='k')
   {
    lcd.print("K");
   }else if(symbol =='p')
   {
    lcd.print("hPa");
   }else if(symbol =='m')
   {
    lcd.print("m");
   }
}
 // Robojax.com LCD1602 for BMP390 Demo

/*
 * 
 * this function, if called, will print Robojax stuff
 * */
 void printRobojax( boolean doPrint)
 {
  if (doPrint){
   lcd.clear();// clear previous values from screen  
   lcd.setCursor (0,0); //set to line char 1, line 1
   lcd.print("Robojax  Tutorial"); 

   lcd.setCursor (0,1); //set to line char 1, line 2
   lcd.print("BME390 Demonstration");    

   lcd.setCursor (0,0); //set to line char 1, line 1
   lcd.print("Robojax  Tutorial"); 

   lcd.setCursor (0,2); //set to line char 1, line 3
   lcd.print("Dispaly on LCD2004");  

   lcd.setCursor (0,3); //set to line char 1, line 4
   lcd.print("www.ROBOJAX.com");
   delay(4000);     
  }     
 }

Resources & references

Files📁

Datasheet (pdf)