Arduino Projects

Interface BME680 Environmental Sensor with Arduino

Introduction

In this tutorial, we will learn to Interface BME680 Environmental Sensor with Arduino microcontroller. The BME680 is an Integrated Environmental Gas sensor that measures ambient temperature, relative humidity, barometric pressure, gas (VOC) & IAQ. We know pressure varies with altitude, BME680 can measure the approximate altitude values. Besides these, using some mathematical equation relating to temperature and humidity, we can also derive the Dew Point. Simply, we can get all these parameters from Arduino Adafruit BME680 Library & Code.

The BME680 is a highly upgraded version of the BMP180 and BME280 with additional features. Before this, we created some weather station projects using the BME280 based on the ESP32 as well as ESP8266. We also built a wireless weather station using BME280 and Lora. Here we will implement the same weather station with BME680 and Arduino. Besides the weather station, we will also measure IAQ or Air Quality Index, or Gas VOC.

Components Required

The purchase link of the BME680 sensor and Arduino board is given below, along with some additional essential components.

S.NComponents NameDescriptionQuantityGet Products from Amazon
1Arduino NanoArduino Nano board1https://amzn.to/3swvBuO
2BME680Environmental Sensor1https://amzn.to/2R7LhXZ
3Jumper WiresMale to Male Jumper Wires4https://amzn.to/2JWSR44
4USB 2.0 cableUSB 2.0 cable type A/B1https://amzn.to/3688OwF

BME680 Integrated Environmental Sensor

The BME680 is a digital 4-in-1 sensor measuring gas, humidity, pressure, and temperature based on proven sensing principles. The gas sensor on the BME680 can detect a variety of volatile organic compounds to monitor indoor air quality. The sensor has high linearity and high accuracy.

BME680 Environmental Sensor

They have developed the BME680 specifically for mobile applications and wearables, where size and low power consumption are important requirements. The BME680 has features like distinctive operating mode, optimized power consumption, long-term stability, and high EMC strength. To measure air quality, the gas sensor inside the BME680 can detect a wide range of gases such as volatile organic compounds (VOCs). To learn more about the BME680 sensor, you can check out the BME680 Datasheet.


BME680 Specifications & Features

  • Working voltage: 1.7V to 3.6V
  • Temperature range: -40~+85℃
  • Humidity range: 0-100% r.H.
  • Pressure range: 300-1100hPa
  • IAQ Range: 0-500 PPM
  • Interface Type: I2C (up to 3.4MHZ)/ SPI (3 and 4 wire, up to 10MHz)
  • I2C address: 0x76 (default)/ 0x77 (optional)
  • Standby Current: 0.29 to 0.8 uA
  • Sleep Current: 0.15 to 1 uA
  • VOC Detection & Measurement (Ethane, Isoprene, Ethanol, Acetone, Carbon Monoxide)

BME680 Pinouts

Most of the BME680 Breakout board has 6 pins which some boards like Grove BME680 Board, BlueDot BME680 Board, or Pimoroni BME680 have more or fewer pins. But overall functionality of the pins remains the same.

BME680 Breakout Board

Most BME680 breakout boards have 6 pins that some boards like Grove BME680 board, BlueDot BME680 board, or Pimoroni BME680 have more or fewer pins. But the overall functionality of the pin is the same.

  • VCC: Power supply pin requires 1.7V to 3.6V for operation
  • GND: GND Pin
  • SCL: Serial Clock Pin for I2C Interface/ SCK Pin for SPI Communication
  • SDA: Serial Data Pin for I2C Interface/ MOSI Pin for SPI Communication
  • SDO: MISO Pin for SPI Communication
  • CS: Chip Select Pin for SPI Interface

BME680 Typical Applications & Target Devices

  • Indoor air quality
  • Home automation and control
  • Internet of things
  • Weather forecast
  • Used in handheld devices like mobile phones, tablet PCs, GPS devices, Wearables, Watches
  • GPS enhancement (e.g. time-to-first-fix improvement, dead reckoning, slope detection)
  • Indoor navigation (change of floor detection, elevator detection)
  • Outdoor navigation, leisure, and sports applications
  • Vertical velocity sign (rise/sink speed)

BME680 as IAQ (Indoor Air Quality) Sensor

The BME680 is a metal oxide-based sensor that detects VOS by absorbing its sensitive layer. BME680 reacts with most volatile compounds to pollute indoor air (except CO2). The VOC in the air around the BME680 can measure the sum of contaminants, such as and high VOC levels because of gassing out of paint, furniture, or garbage, cooking, food consumption, and sweating out of breath.

As a raw signal, BME680 outputs resistance values ​​and VOC concentration changes because of variation. The higher the concentration of reducing VOCs, the lower the resistance and vice versa. Parameters other than VOC concentration (example: humidity level affects this raw signal), smart algorithms converted the raw value in indoor air quality to an indoor air quality (IAQ) index within BSEC.

Air Quality Index

The IAQ scale ranges from 0 (clean air) to 50,000 (highly polluted air). The algorithms automatically calibrate and adapt themselves to the adaptive environment where the sensor operates during operation. The calibration process considers the recent measurement history showing that the IAQ of “22” shows “typically good” air and the IAQ of “250” shows “specific polluted” air.


Changing the BME680 default I2C address

The BME680 breakout has a default I2C address of 0x76. But you can change the I2C address so you can use two breakouts on the same raspberry pi or Arduino. Connect SDO to GND to change the I2C address to 0x77.


Circuit Diagram & Assembly

About the sponsor: This article is sponsored by PCBway Company, one of the most experienced PCB and PCB assembly manufacturers. They produce high-quality PCBs at a reasonable price, only $5 for 10 PCBs and a total of $30 for 20 PCB assembly. In addition, new members also receive a $5 bonus.

Interface BME680 with Arduino using I2C Interface

The BME680 integrated environmental sensor has both I2C and SPI interfaces. First, we will learn how to use the BME680 I2C pins, to interface it with the Arduino board. We provide the connection diagram below.

I2C Interface for BME680 and Arduino

The connection between the BME680 and the Arduino is quite simple. Connect the VCC pin of the BME680 to the Arduino 3.3V pin and the GND to the GND. Also, connect the I2C pin of the BME680, i.e. the SDA and SCL pins to the Arduino A4 and A5 pins, respectively. You can use the jumper wires and assemble the circuit on the breadboard which is shown below.

Circuit Diagram to Interface BME680 Environmental Sensor with Arduino

Interface BME680 with Arduino using SPI Interface

After BME680 and Arduino I2C interfacing. Let’s Interface BME680 Environmental Sensor with Arduino in SPI mode. I provided a connection diagram for the BME680 SPI interface with Arduino below.

SPI Interface for BME680 with Arduino

The SPI connection between the BME680 and the Arduino is quite simple. Connect the VCC pin of the BME680 to the Arduino 3.3V pin and the GND to the GND. Similarly, connect Arduino digital 13, 11, and 12, and 10 to SCL, SDA, SDO, CS pin of BME680. You can use the jumper wires and assemble the circuit on the breadboard which is shown below.

Circuit Diagram to Interface BME680 Environmental Sensor with Arduino

Adafruit BME680 Library for Arduino

The BME680 library developed by Adafruit can measure temperature, humidity, pressure, altitude, dew point, and gas. The library is simple and using a few lines of code, you can interface BME680 with the Arduino.

The library needs another library for a compilation called Adafruit Unified Sensor. You can download the library from the following link.

Download: Adafruit Unified Sensor

After adding the above library to the Arduino IDE, you can add the BME680 Arduino library to the Arduino IDE. I attached the download link to the library below.

Download: Adafruit BME680 Library


Source Code/program

Program Code: BME680 Arduino I2C Interface

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
 
#define SEALEVELPRESSURE_HPA (1013.25)
 
Adafruit_BME680 bme; // I2C
 
void setup() 
{
  Serial.begin(9600);
  while (!Serial);
  Serial.println(F("BME680 test"));
 
  if (!bme.begin()) 
  {
    Serial.println("Could not find a valid BME680 sensor, check wiring!");
    while (1);
  }
 
  // Set up oversampling and filter initialization
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C for 150 ms
}
 
void loop() 
{
  if (! bme.performReading()) 
  {
    Serial.println("Failed to perform reading :(");
    return;
  }
  
  float temperature = bme.temperature;
  float pressure = bme.pressure / 100.0;
  float altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
  float humidity = bme.humidity;
  float gas = bme.gas_resistance / 1000.0;
  double dewPoint = dewPointFast(temperature, humidity);
  
  Serial.print("Temperature = ");
  Serial.print(temperature);
  Serial.println(" *C");
 
  Serial.print("Pressure = ");
  Serial.print(pressure);
  Serial.println(" hPa");
 
  Serial.print("Humidity = ");
  Serial.print(humidity);
  Serial.println(" %");
 
  Serial.print("Dew Point = ");
  Serial.print(dewPoint);
  Serial.println(" *C");
 
  Serial.print("Approx. Altitude = ");
  Serial.print(altitude);
  Serial.println(" m");
 
  Serial.print("Gas = ");
  Serial.print(gas);
  Serial.println(" KOhms");
 
  
 
  Serial.println();
  delay(2000);
}
 
double dewPointFast(double celsius, double humidity)
{
  double a = 17.271;
  double b = 237.7;
  double temp = (a * celsius) / (b + celsius) + log(humidity * 0.01);
  double Td = (b * temp) / (a - temp);
  return Td;
}

Program Code: BME680 Arduino SPI Interface

#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
 
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
 
#define SEALEVELPRESSURE_HPA (1013.25)
 
Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);
 
void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println(F("BME680 async test"));
 
  if (!bme.begin()) {
    Serial.println(F("Could not find a valid BME680 sensor, check wiring!"));
    while (1);
  }
 
  // Set up oversampling and filter initialization
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C for 150 ms
}
 
void loop() {
  // Tell BME680 to begin measurement.
  unsigned long endTime = bme.beginReading();
  if (endTime == 0) {
    Serial.println(F("Failed to begin reading :("));
    return;
  }
  
  Serial.print(F("Reading started at "));
  Serial.print(millis());
  Serial.print(F(" and will finish at "));
  Serial.println(endTime);
 
  Serial.println(F("You can do other work during BME680 measurement."));
  delay(50); // This represents parallel work.
  // There's no need to delay() until millis() >= endTime: bme.endReading()
  // takes care of that. It's okay for parallel work to take longer than
  // BME680's measurement time.
 
  // Obtain measurement results from BME680. Note that this operation isn't
  // instantaneous even if milli() >= endTime due to I2C/SPI latency.
  if (!bme.endReading()) {
    Serial.println(F("Failed to complete reading :("));
    return;
  }
  Serial.print(F("Reading completed at "));
  Serial.println(millis());
 
  float temperature = bme.temperature;
  float pressure = bme.pressure / 100.0;
  float altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
  float humidity = bme.humidity;
  float gas = bme.gas_resistance / 1000.0;
  double dewPoint = dewPointFast(temperature, humidity);
  
  Serial.print("Temperature = ");
  Serial.print(temperature);
  Serial.println(" *C");
 
  Serial.print("Pressure = ");
  Serial.print(pressure);
  Serial.println(" hPa");
 
  Serial.print("Humidity = ");
  Serial.print(humidity);
  Serial.println(" %");
 
  Serial.print("Dew Point = ");
  Serial.print(dewPoint);
  Serial.println(" *C");
 
  Serial.print("Approx. Altitude = ");
  Serial.print(altitude);
  Serial.println(" m");
 
  Serial.print("Gas = ");
  Serial.print(gas);
  Serial.println(" KOhms");
 
  Serial.println();
  delay(2000);
}
 
double dewPointFast(double celsius, double humidity)
{
  double a = 17.271;
  double b = 237.7;
  double temp = (a * celsius) / (b + celsius) + log(humidity * 0.01);
  double Td = (b * temp) / (a - temp);
  return Td;
}

Demonstration & Results

Here is the testing and demonstration of how we Interface BME680 Environmental Sensor with Arduino. You can use any of the above circuits, either the I2C circuit or the SPI circuit. Upload the code as per a circuit diagram. After uploading the code to the Arduino board, open the serial monitor. You will see the following results.

Serial Monitor to Monitor BME680 Sensor Parameters

Gradual monitoring shows temperature in degrees Celsius, humidity in percent, atmospheric pressure in HPA, altitude in meters, dew point in degrees Celsius, and gas resistance values. The sensor is used to get the so-called gas resistance and then calculate an index of air quality (IAQ) from a combination of humidity and air gas content readings.

Adafruit BME680 Arduino code cannot calculate IAQ. So you need to use some other library to calculate the Air Quality Index (IAQ), which is described below.

Calculating BME680 IAQ using BSEC Arduino Library

We have conceptualized the BSEC Fusion Library to provide high-level signal processing and fusion for the BME680. The library receives compensated sensor values from the sensor API. Processes BME680 signals to provide the requested sensor outputs.

The IAQ index is a function of humidity that contributes up to 25% and gas concentration contributes up to 75%. In this current version we have used only humidity and gas permeability for the index, but adding temperature will be straightforward because for humans the temperature is more or less the overall air quality indicator, and the humidity and gas permeability increases.

It supported the BSEC library on 32, 16, and 8 bit MCU platforms. And unfortunately, the library is not supported by Arduino UNO, Nano, Pro Mini, etc. Some Arduino Boards only supported the library like Arduino MEGA 2560, Arduino Zero & Arduino Due. Download the library from the link below and use it with the supported Arduino Board.

Download: BME680 BSEC Library

Add the BSEC library to the Arduino IDE and follow some instructions from this link to change the library.

Source Code/Program

Copy the following code and upload it to the supported Arduino Board.

#include "bsec.h"
 
// Helper functions declarations
void checkIaqSensorStatus(void);
void errLeds(void);
 
// Create an object of the class Bsec
Bsec iaqSensor;
 
String output;
 
// Entry point for the example
void setup(void)
{
  Serial.begin(115200);
  Wire.begin();
 
  iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire);
  output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix);
  Serial.println(output);
  checkIaqSensorStatus();
 
  bsec_virtual_sensor_t sensorList[10] = {
    BSEC_OUTPUT_RAW_TEMPERATURE,
    BSEC_OUTPUT_RAW_PRESSURE,
    BSEC_OUTPUT_RAW_HUMIDITY,
    BSEC_OUTPUT_RAW_GAS,
    BSEC_OUTPUT_IAQ,
    BSEC_OUTPUT_STATIC_IAQ,
    BSEC_OUTPUT_CO2_EQUIVALENT,
    BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
  };
 
  iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
  checkIaqSensorStatus();
 
  // Print the header
  output = "Timestamp [ms], raw temperature [°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, temperature [°C], relative humidity [%], Static IAQ, CO2 equivalent, breath VOC equivalent";
  Serial.println(output);
}
 
// Function that is looped forever
void loop(void)
{
  unsigned long time_trigger = millis();
  if (iaqSensor.run()) { // If new data is available
    output = String(time_trigger);
    output += ", " + String(iaqSensor.rawTemperature);
    output += ", " + String(iaqSensor.pressure);
    output += ", " + String(iaqSensor.rawHumidity);
    output += ", " + String(iaqSensor.gasResistance);
    output += ", " + String(iaqSensor.iaq);
    output += ", " + String(iaqSensor.iaqAccuracy);
    output += ", " + String(iaqSensor.temperature);
    output += ", " + String(iaqSensor.humidity);
    output += ", " + String(iaqSensor.staticIaq);
    output += ", " + String(iaqSensor.co2Equivalent);
    output += ", " + String(iaqSensor.breathVocEquivalent);
    Serial.println(output);
  } else {
    checkIaqSensorStatus();
  }
}
 
// Helper function definitions
void checkIaqSensorStatus(void)
{
  if (iaqSensor.status != BSEC_OK) {
    if (iaqSensor.status < BSEC_OK) {
      output = "BSEC error code : " + String(iaqSensor.status);
      Serial.println(output);
      for (;;)
        errLeds(); /* Halt in case of failure */
    } else {
      output = "BSEC warning code : " + String(iaqSensor.status);
      Serial.println(output);
    }
  }
 
  if (iaqSensor.bme680Status != BME680_OK) {
    if (iaqSensor.bme680Status < BME680_OK) {
      output = "BME680 error code : " + String(iaqSensor.bme680Status);
      Serial.println(output);
      for (;;)
        errLeds(); /* Halt in case of failure */
    } else {
      output = "BME680 warning code : " + String(iaqSensor.bme680Status);
      Serial.println(output);
    }
  }
}
 
void errLeds(void)
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  digitalWrite(LED_BUILTIN, LOW);
  delay(100);
}

The following parameters will be displayed every 3 seconds:

  • Timestamp in milliseconds
  • Raw Temperature in °C
  • Pressure in hPa
  • Raw Relative Humidity in %
  • Raw data from the gas sensor as a resistance value in Ohm
  • IAQ index
  • IAQ Accuracy
  • Temperature in °C
  • Relative Humidity in %
  • Static IAQ
  • CO2 equivalent
  • Breath VOC equivalent output
BME680 Arduino BSEC

The initial value of the BME680 IAQ index is 25.00. and it stays that way for a good while. Only after several minutes does the IAQ value drift.

Wrapping Up

Finally, I hope you have learned to Interface BME680 Environmental Sensor with Arduino. If you need any kind of help regarding this project please do let me know in the comment section below.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button