Search

BMP388 Barometric Sensor Setup for ESP8266 NodeMCU (Arduino IDE)

The BMP388, a small yet highly accurate absolute barometric pressure sensor, is commonly employed for altitude estimation in drone technology. It finds applications in indoor/outdoor navigation, GPS systems, and more. This tutorial elucidates the utilization of the BMP388 pressure sensor with Arduino boards, encompassing a wiring diagram and sample code demonstration.

Introducing the BMP388 Barometric Sensor

The BMP388 stands as a precise, low-power, and low-noise absolute barometric pressure sensor, capable of measuring both absolute pressure and temperature. Given the correlation between pressure and altitude, accurate altitude estimation becomes feasible. Hence, this sensor proves invaluable for drone and navigation tasks. Additionally, its utility extends to various other applications including:

  • Vertical velocity calculation
  • Internet of Things
  • Weather forecasting and weather stations
  • Healthcare applications
  • Fitness applications
  • And more…

We utilize the BMP388 sensor as a module, as depicted in the accompanying figure. It’s also available in various alternative formats.

The image below displays the reverse side of the sensor.

BMP388 Technical Specifications

Below is a table detailing the key features of the BMP388 sensor. For additional information, please refer to the datasheet.

Operation range300 to 1250 hPa (pressure)
-40 to +85ºC (temperature)
InterfaceI2C and SPI
Average typical current consumption3.4 µA @ 1Hz
Absolute accuracy pressure (typ.)
P=900 …1100 hPa (T=25 … 40°C)
±0.5 hPa
Relative accuracy pressure (typ.)
P=900…1100 hPa (T=25 … 40°C)
±0.08 hPa
Noise in pressure (lowest bandwidth, highest resolution)0.03 Pa
Maximum sampling rate200 Hz

BMP388 Pinout

Presented below is the pin configuration of the BMP388 module we are utilizing—variations may exist for other modules.

VINPowers the sensor (5V)
3V3Powers the sensor (3V3)
GNDCommon GND
SCKSCL pin for I2C communication
SCK pin for SPI communication
SDOSDO (MISO) pin for SPI communication
SDISDI (MOSI) pin for SPI communication
SDA pin for I2C communication
CSChip select pin for SPI communication
INTInterrupt pin

BMP388 Interface

As previously noted, the BMP388 sensor accommodates both I2C and SPI interfaces.

BMP388 I2C

For I2C communication protocol, utilize the following pins:

BMP388ESP8266
SDI (SDA)GPIO 4 (D2)
SCK (SCL)GPIO 5 (D1)

BMP388 SPI

For SPI communication protocol, utilize the following pins:

BMP388ESP8266
SCKGPIO 14 (D5)
SDI (MOSI)GPIO 13 (D7)
SDO (MISO)GPIO 12 (D6)
CS (Chip Select)GPIO 15 (D8)

Schematic – ESP8266 NodeMCU with BMP388

The BMP388 supports communication via both I2C and SPI protocols.

ESP8266 with BMP388 via I2C

Refer to the following schematic diagram for wiring the BMP388 to the ESP8266 using the default I2C pins.

ESP8266 with BMP388 via SPI

Alternatively, if you prefer SPI communication, refer to the schematic diagram below for wiring the BMP388 to the ESP8266 using the default SPI pins.

Installing the Adafruit BMP3XX Library

Various libraries are compatible with the BMP388 sensor and ESP8266. For this tutorial, we’ll utilize the Adafruit BMP3XX library.

Follow these steps to install the library in your Arduino IDE:

Open your Arduino IDE and navigate to Sketch > Include Library > Manage Libraries. The Library Manager will appear.

In the search box, type “adafruit bmp3xx” and install the library when it appears.

Installing the Adafruit_Sensor Library

To utilize the BMP3XX library, you also need to install the Adafruit_Sensor library. Follow these steps to install it in your Arduino IDE:

Go to Sketch > Include Library > Manage Libraries and type “Adafruit Unified Sensor” in the search box.

Scroll down to find the library and install it.

Code – BMP388 Pressure, Altitude, and Temperature Readings

A great way to acquaint yourself with a new sensor is by starting with a basic example provided by the library.

Once you’ve installed the BMP3XX library, follow these steps:

  • Open the Arduino IDE and navigate to File > Examples > Adafruit BMP3XX Library > bmp3XX_simpletest. We’ve made a few modifications to ensure full compatibility with the ESP8266.
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BMP3XX.h"

#define BMP_SCK 14
#define BMP_MISO 12
#define BMP_MOSI 13
#define BMP_CS 15

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BMP3XX bmp;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Adafruit BMP388 / BMP390 test");

  if (!bmp.begin_I2C()) {   // hardware I2C mode, can pass in address & alt Wire
  //if (! bmp.begin_SPI(BMP_CS)) {  // hardware SPI mode  
  //if (! bmp.begin_SPI(BMP_CS, BMP_SCK, BMP_MISO, BMP_MOSI)) {  // software SPI mode
    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);
}

void loop() {
  if (! bmp.performReading()) {
    Serial.println("Failed to perform reading :(");
    return;
  }
  Serial.print("Temperature = ");
  Serial.print(bmp.temperature);
  Serial.println(" *C");

  Serial.print("Pressure = ");
  Serial.print(bmp.pressure / 100.0);
  Serial.println(" hPa");

  Serial.print("Approx. Altitude = ");
  Serial.print(bmp.readAltitude(SEALEVELPRESSURE_HPA));
  Serial.println(" m");

  Serial.println();
  delay(2000);
}

Sea Level Pressure

To attain more precise pressure and altitude readings, adjust the sea level pressure according to your location in the SEALEVELPRESSURE_HPA variable:

#define SEALEVELPRESSURE_HPA (1013.25)

How the Code Works

Understanding the functionality of the code aids in comprehending its operation.

Libraries

The code starts by importing necessary libraries: Wire for I2C, SPI (if opting for SPI), Adafruit_Sensor, and Adafruit_BMP3XX to interface with BMP388 sensor.

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

SPI communication

While I2C is preferred, the code accommodates SPI usage. SPI pin definitions are outlined.

#define BMP_SCK 14
#define BMP_MISO 12
#define BMP_MOSI 13
#define BMP_CS 15

Sea level pressure

A variable SEALEVELPRESSURE_HPA is set to default sea level pressure in hectopascals, vital for altitude estimation based on pressure variance. For precise results, adjust the value to reflect the current sea level pressure.

#define SEALEVELPRESSURE_HPA (1013.25)

setup()

Serial communication is initialized, followed by BMP388 sensor setup using I2C mode by default. SPI setup options are also provided, though I2C is recommended. Sensor parameters like oversampling, filter, and output data rate are configured.

Serial.begin(115200);

Init BMP388 Sensor I2C

This example uses I2C communication protocol by default. The following line starts an Adafruit_BMP3XX object called bmp on the default ESP8266 I2C pins: GPIO 5 (SCL), GPIO 4 (SDA).

if (!bmp.begin_I2C()) {   // hardware I2C mode, can pass in address & alt Wire

To use SPI, you need to comment this previous line and uncomment one of the following lines for hardware SPI (use the default SPI pins and choose the CS pin) or software SPI (use any pins).

//if (! bmp.begin_SPI(BMP_CS)) {  // hardware SPI mode  
//if (! bmp.begin_SPI(BMP_CS, BMP_SCK, BMP_MISO, BMP_MOSI)) {  // software SPI mode

Set up the following parameters (oversampling and filter) for the sensor.

// 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);

To increase the resolution of the raw sensor data, it supports oversampling. We’ll use the default oversampling parameters, but you can change them.

  • setTemperatureOversampling(): set temperature oversampling.
  • setPressureOversampling(): set pressure oversampling.

These methods can accepts one of the following parameters:

  • BMP3_NO_OVERSAMPLING
  • BMP3_OVERSAMPLING_2X
  • BMP3_OVERSAMPLING_4X
  • BMP3_OVERSAMPLING_8X
  • BMP3_OVERSAMPLING_16X
  • BMP3_OVERSAMPLING_32X

The setIIRFilterCoeff() function sets the coefficient of the filter (in samples). It can be:

  • BMP3_IIR_FILTER_DISABLE (no filtering)
  • BMP3_IIR_FILTER_COEFF_1
  • BMP3_IIR_FILTER_COEFF_3
  • BMP3_IIR_FILTER_COEFF_7
  • BMP3_IIR_FILTER_COEFF_15
  • BMP3_IIR_FILTER_COEFF_31
  • BMP3_IIR_FILTER_COEFF_63
  • BMP3_IIR_FILTER_COEFF_127

Set the output data rate with the setOutputDataRate() function. It can accept one of the following options:

BMP3_ODR_200_HZBMP3_ODR_100_HZBMP3_ODR_50_HZBMP3_ODR_25_HZ,BMP3_ODR_12_5_HZBMP3_ODR_6_25_HZBMP3_ODR_3_1_HZBMP3_ODR_1_5_HZBMP3_ODR_0_78_HZBMP3_ODR_0_39_HZ,BMP3_ODR_0_2_HZBMP3_ODR_0_1_HZBMP3_ODR_0_05_HZBMP3_ODR_0_02_HZBMP3_ODR_0_01_HZBMP3_ODR_0_006_HZBMP3_ODR_0_003_HZ, or BMP3_ODR_0_001_HZ

loop()

In the loop(), we’ll get measurements from the BMP388 sensor.

First, tell the sensor to get new readings with bmp.performReading().

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

Then, get and print the temperature, pressure and altitude readings as follows:

Serial.print("Temperature = ");
Serial.print(bmp.temperature);
Serial.println(" *C");

Serial.print("Pressure = ");
Serial.print(bmp.pressure / 100.0);
Serial.println(" hPa");

Serial.print("Approx. Altitude = ");
Serial.print(bmp.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");

You get each specific reading as follows:

  • bmp.temperature: returns temperature reading
  • bmp.pressure: returns pressure reading
  • bmp.readAltitude (SEALEVELPRESSURE_HPA): returns altitude estimation

Demonstration

Once you’ve configured the sea level pressure for your location, upload the code to your board. In Arduino IDE, navigate to Tools > Boards and select your board. Then, in Tools > Port, choose the COM port.

Once uploaded, open the Serial Monitor at a baud rate of 115200. The readings will display in the Serial Monitor.

Note that altering the sensor’s altitude will reflect in the altitude reading. The altitude estimation is highly accurate, detecting even small changes in centimeters or inches. You can verify it by comparing with your location’s altitude, obtainable from this website.

ESP8266 NodeMCU Web Server with BMP388

Here, we present an example of a web server that you can create with the ESP8266 to showcase BMP388 readings on a web page.

Installing Libraries – Async Web Server

To construct the web server, you’ll require the following libraries. Click on the links below to download them.

As these libraries aren’t accessible through the Arduino Library Manager, you must manually copy the library files to the Arduino Installation Libraries folder. Alternatively, you can utilize the Arduino Library Manager to install them.

Code

Then, upload the following code to your board (type your SSID and password).

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP3XX.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

//Uncomment if using SPI
/*#define BMP_SCK 14
#define BMP_MISO 12
#define BMP_MOSI 13
#define BMP_CS 15*/

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BMP3XX bmp;

float temp;
float pres;
float alt;

AsyncWebServer server(80);
AsyncEventSource events("/events");

unsigned long lastTime = 0;  
unsigned long timerDelay = 30000;  // send readings timer

void getBMPReadings(){
  if (! bmp.performReading()) {
    Serial.println("Failed to perform reading :(");
    return;
  }
  temp = bmp.temperature;
  pres = bmp.pressure / 100.0;
  alt = bmp.readAltitude(SEALEVELPRESSURE_HPA);
}

String processor(const String& var){
  getBMPReadings();
  //Serial.println(var);
  if(var == "TEMPERATURE"){
    return String(temp);
  }
  else if(var == "PRESSURE"){
    return String(pres);
  }
 else if(var == "ALTITUDE"){
    return String(alt);
  }
}

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>BMP388 Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  <link rel="icon" href="data:,">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    p {  font-size: 1.2rem;}
    body {  margin: 0;}
    .topnav { overflow: hidden; background-color: #0F7173; color: white; font-size: 1.4rem; }
    .content { padding: 20px; }
    .card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }
    .cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
    .reading { font-size: 2rem; }
    .card.temperature { color: #272932; }
    .card.altitude { color: #D8A47F; }
    .card.pressure { color: #F05D5E; }
  </style>
</head>
<body>
  <div class="topnav">
    <h3>BMP388 WEB SERVER</h3>
  </div>
  <div class="content">
    <div class="cards">
      <div class="card pressure">
        <h4><i class="fas fa-angle-double-down"></i> PRESSURE</h4><p><span class="reading"><span id="pres">%PRESSURE%</span> hPa</span></p>
      </div>
      <div class="card altitude">
        <h4><i class="fas fa-long-arrow-alt-up"></i> ALTITUDE</h4><p><span class="reading"><span id="alt">%ALTITUDE%</span> m</span></p>
      </div>
      <div class="card temperature">
        <h4><i class="fas fa-thermometer-half"></i> TEMPERATURE</h4><p><span class="reading"><span id="temp">%TEMPERATURE%</span> &deg;C</span></p>
      </div>
    </div>
  </div>
<script>
if (!!window.EventSource) {
 var source = new EventSource('/events');
 
 source.addEventListener('open', function(e) {
  console.log("Events Connected");
 }, false);
 source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
 }, false);
 
 source.addEventListener('message', function(e) {
  console.log("message", e.data);
 }, false);
 
 source.addEventListener('temperature', function(e) {
  console.log("temperature", e.data);
  document.getElementById("temp").innerHTML = e.data;
 }, false);
 
 source.addEventListener('pressure', function(e) {
  console.log("pressure", e.data);
  document.getElementById("pres").innerHTML = e.data;
 }, false);
 
 source.addEventListener('altitude', function(e) {
  console.log("altitude", e.data);
  document.getElementById("alt").innerHTML = e.data;
 }, false);
}
</script>
</body>
</html>)rawliteral";

void setup() {
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  
  // Set device as a Wi-Fi Station
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Setting as a Wi-Fi Station..");
  }
  Serial.print("Station IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  // Init BMEP388 sensor
  if (!bmp.begin_I2C()) {   // hardware I2C mode, can pass in address & alt Wire
  //if (! bmp.begin_SPI(BMP_CS)) {  // hardware SPI mode  
  //if (! bmp.begin_SPI(BMP_CS, BMP_SCK, BMP_MISO, BMP_MOSI)) {  // software SPI mode
    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);

  //Get readings when initializing
  getBMPReadings();

  // Handle Web Server
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Handle Web Server Events
  events.onConnect([](AsyncEventSourceClient *client){
    if(client->lastId()){
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);
  server.begin();
}

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    getBMPReadings();
    Serial.printf("Pressure = %.2f hPa \n", pres);
    Serial.printf("Altitude = %.2f m \n", alt);
    Serial.printf("Temperature = %.2f ºC \n", temp);
    Serial.println();

    // Send Events to the Web Server with the Sensor Readings
    events.send("ping",NULL,millis());
    events.send(String(pres).c_str(),"pressure",millis());
    events.send(String(alt).c_str(),"altitude",millis());
    events.send(String(temp).c_str(),"temperature",millis());
    
    lastTime = millis();
  }
}

Demonstration

Once the upload is complete, launch the Serial Monitor with a baud rate of 115200 to obtain the ESP8266’s IP address.

Next, open a web browser and enter the IP address. This will grant you access to the web server, displaying the most recent sensor readings. Access to the web server is available on your computer, tablet, or smartphone within your local network.

The sensor readings are continuously updated on the web server through Server-Sent Events. For further insight into its functionality, you may refer to the Server-Sent Events tutorial.

Wrapping Up

In conclusion, the BMP388 emerges as a compact and highly accurate pressure sensor, offering precise altitude estimation alongside temperature measurement capabilities. Its versatility extends to various applications such as outdoor/indoor navigation, drone technology, weather monitoring, and more.

This tutorial has equipped you with the knowledge to integrate the BMP388 sensor seamlessly with the ESP8266 development board using the Arduino IDE. We trust that you’ve found this introductory guide beneficial. Furthermore, we offer comprehensive guides for numerous other sought-after sensors.

Leave a Comment