Interface BME680 Environmental Sensor with Arduino

Want to build a personal air quality tracker that tells if your bedroom, your workshop, or workplace has adequate ventilation? Install the BME680 environmental sensor module on an Arduino and monitor every aspect of your indoor environment.

The state-of-the-art BME680 breakout lets you measure temperature, pressure, humidity, and indoor air quality, and the best part is that it’s Arduino-compatible!

The BME680 Environmental Sensor

At the heart of the module is the next-generation environmental sensor manufactured by Bosch – BME680.

bme680 module hardware overview chip

This small sensor has temperature, humidity, barometric pressure, and VOC gas (volatile organic compounds) sensing capabilities. It contains a small MOx (metal-oxide) sensor. The heated metal oxide changes resistance based on VOCs in the air, so it can be used to detect gases & alcohols such as Ethanol, Alcohol and Carbon Monoxide and perform air quality measurements. Therefore the BME680 can work as a fully standalone environmental sensor.

Like most gas sensors, this sensor is sensitive to multiple gases and alcohols, but cannot tell which is which. It will give you one resistance value, with overall VOC content. So, it is best for measuring changes in a known gas density, not detecting which is changing.

Like the BME280, this precision sensor can measure humidity with ±3% accuracy, barometric pressure with ±1 hPa absolute accuracy, and temperature with ±1.0°C accuracy. The pressure measurements are so precise; you can even use it as an altimeter with ±1 meter accuracy.

Here are the complete specifications:

Temp-40°C to 85°C
Humidity0 to 100% RH with ±3% accuracy
Pressure300Pa to 1100 hPa with ±1 hPa absolute accuraccy
Altitude0 to 30,000 ft (9.2 km) with ±1 meter accuracy

For more details, please refer below datasheet.

What are volatile organic compounds (VOCs)?

Volatile organic compounds (VOCs) are emitted as gases from certain products we use to build and maintain our homes (such as Air fresheners, cleaning products, Cosmetics, Fuel oil, gasoline, Paint, varnishes, Carpet, and vinyl flooring etc.). VOCs include a variety of chemicals, some of which may have short- and long-term adverse health effects.

Common examples of VOCs that may be present in our daily lives are: benzene, ethylene glycol, formaldehyde, methylene chloride, tetrachloroethylene, toluene, xylene, and 1,3-butadiene.

Power Requirement

The module comes with a XC6206 3.3V precise voltage regulator and voltage level translator, so you can use it with your favorite 3.3V or 5V microcontroller without worry.

bme680 module voltage regulator translator

The BME680 consumes less than 1mA during measurements and only 0.15µA during sleep mode. This low power consumption allows the implementation in battery driven devices such as handsets, wearables or smart watches.

Digital interfaces

The sensor communicates via either I2C or SPI.

I2C Interface

The sensor uses the I2C interface for communication with the Arduino. It supports two separate I2C addresses: 0x77Hex and 0x76Hex. This allows two BME680s to be used on the same bus or to avoid address conflicts with another device on the bus.

bme680 module i2c address selection pin

The SDO pin determines the I2C address of the module. This pin has a built-in pull-up resistor. Therefore, when you leave the SDO pin unconnected, the default I2C address is 0x77Hex and when you connect it to GND, the line is pulled LOW and the I2C address becomes 0x76Hex.

SPI Interface

The sensor can also communicate via the SPI interface.

FYI:

If you have to choose between the two, SPI is generally the better tool, if you need faster transfer speeds (up to 10 MHz). I2C, on the other hand, is best if you have limited pins available on your microcontroller.

How BME680 MEMS Gas sensor works?

Unlike MQ2 or MQ3, BME680 gas sensor is fabricated with micro-electro-mechanical system (MEMS) technology. MEMS based gas detection provides dramatic size reduction, a reduction in power consumption, and the ability to increase functionality and selectivity.

A typical MEMS gas sensor consists of a metal oxide semiconductor layer (sensing material) that reacts with the target gas, at least two electrodes to monitor the electrical resistance/current variations, and a micro-hotplate to increase the operating temperature.

metal oxide gas sensor construction

When metal oxide semiconductor layer is heated at high temperature, oxygen is adsorbed on the surface. In clean air, electrons from the conduction band in metal-oxide are attracted to oxygen molecules. This form an electron depletion layer just below the surface of metal-oxide particles and forms a potential barrier. As a result, the metal-oxide layer becomes highly resistive and prevents electric current flow.

In the presence of gases, however, the surface density of adsorbed oxygen decreases as it reacts with the gases; which lowers the potential barrier. Electrons are then released into the metal-oxide layer, allowing current to flow freely through the sensor.

metal oxide gas sensor working animation

BME680 Module Pinout

Now let’s have a look at the pinout.

bme680 environmental sensor pinout

Power Pins:

VCC is the power pin. You can connect it to 5V output from your Arduino.

GND is the common ground for power and logic.

SPI Logic pins:

SCL is the SPI Clock pin, its an input to the chip

SDA is the Serial Data In (SDI/MOSI)pin, for data sent from your microcontroller to the BME680.

SDO is the Serial Data Out (SDO/MISO) pin, for data sent from the BME680 to your microcontroller.

CS is the Chip Select pin, pull it LOW to enable an SPI communication. If you want to connect multiple BME680’s to one microcontroller, have them share the SDI, SDO and SCK pins and assign each one a unique CS pin.

I2C Logic pins:

SCL is also the I2C clock pin, connect to your microcontrollers I2C clock line.

SDA is also the I2C data pin, connect to your microcontrollers I2C data line.

Preparing BME680 Module for Use

Prior to the first use of the sensor, it is recommended that you run it for 48 hours to burn-in, and then 30 minutes in the desired mode every time the sensor is in use. The reason for this is that the sensitivity level of the sensor changes during initial use and the resistance gradually increases as the MOx heats up to its baseline reading over time.

Wiring BME680 Module with Arduino

Now that we know everything about the module, we can begin hooking it up to our Arduino!

I2C Wiring

Use this wiring if you want to connect via I2C interface.

Start by connecting the VCC pin to the power supply, 3V-5V is fine. Use the same voltage that your microcontroller logic is based off of. For most Arduinos, that is 5V. For 3.3V logic devices, use 3.3V. Now connect GND to common ground.

Connect the SCL pin to the I2C clock pin and the SDI pin to the I2C data pin on your Arduino. Note that each Arduino Board has different I2C pins which should be connected accordingly. On the Arduino boards with the R3 layout, the SDA (data line) and SCL (clock line) are on the pin headers close to the AREF pin. They are also known as A5 (SCL) and A4 (SDA).

The following illustration shows the wiring.

wiring connecting bme680 sensor module with arduino through i2c interface

SPI Wiring

Since it’s an SPI-capable sensor, you can use hardware or software SPI. However, it is recommended that you use hardware SPI pins as they are much faster than ‘bit-banging’ the interface code using another set of pins.

Again, each Arduino Board has different SPI pins which should be connected accordingly. For Arduino boards such as the UNO/Nano V3.0 those pins are digital 13 (SCK), 12 (MISO), 11 (MOSI) and 10 (SS).

If you are using a different Arduino board, it is advisable to check the official documentation about SPI pin locations before proceeding.

The following illustration shows the wiring.

wiring connecting bme680 sensor module with arduino through spi interface

Once your module is connected to the Arduino it’s time to write some code!

Library Installation

To begin reading sensor data, you will need to install the Adafruit_BME680 library. It is available from the Arduino library manager.

To install the library navigate to the Sketch > Include Library > Manage Libraries… Wait for Library Manager to download libraries index and update list of installed libraries.

manage libraries

Filter your search by typing ‘adafruit bme680‘. Click on that entry, and then select Install.

installing bme680 library in arduino ide

The BME280 sensor library uses the Adafruit Sensor support backend. So, search the library manager for Adafruit Unified Sensor and install that too (you may have to scroll a bit)

adafruit unified sensor library installation

BME680 Example Sketches

The Adafruit_BME680 library has a number of example sketches. You can use these example sketches as a basis for developing your own code.

To access the example sketches, navigate to the File > Examples > Adafruit BME680 Library You will see a selection of example sketches.

adafruit bme680 library example sketches

Arduino Code – Reading gas, pressure, humidity, temperature, and altitude

Load the bme680test sketch from the example sketches into your Arduino IDE. This is a basic Arduino sketch. Go ahead and upload it to your Arduino. You should see temperature, pressure, humidity, gas, and approx. altitude on the serial monitor.

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

// Uncomment if you want to use SPI
//#define BME_SCK 13
//#define BME_MISO 12
//#define BME_MOSI 11
//#define BME_CS 10

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME680 bme;
//Adafruit_BME680 bme(BME_CS); // Uncomment if you want to use SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO,  BME_SCK);

void setup() {
  Serial.begin(9600);
  while (!Serial);

  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;
  }
  Serial.print("Temperature = ");
  Serial.print(bme.temperature);
  Serial.println(" *C");

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

  Serial.print("Humidity = ");
  Serial.print(bme.humidity);
  Serial.println(" %");

  Serial.print("Gas = ");
  Serial.print(bme.gas_resistance / 1000.0);
  Serial.println(" KOhms");

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

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

Note that you must set your serial monitor to a speed of 115200 baud to try out the sketch.

You will see myriad of data displaying temperature, pressure, humidity, gas, and approx. altitude values. Try moving your sensor around and notice how the data changes.

bme680 sensor arduino code output

Code Explanation:

The sketch starts with including four necessary libraries viz. Wire.h (for I2C), SPI.h (for SPI), Adafruit_Sensor.h and Adafruit_BME680.h.

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

This example uses I2C communication protocol to communicate with the sensor. However, the code is prepared if you want to use SPI. You just need to uncomment the following lines of code that define the SPI pins.

//#define BME_SCK 13
//#define BME_MISO 12
//#define BME_MOSI 11
//#define BME_CS 10

Next, a variable called SEALEVELPRESSURE_HPA is defined. This variable saves the sea level pressure in millibar and is used to estimate the altitude for a given pressure by comparing it with the sea level pressure. This sketch uses the default value, but for accurate results, replace the value with the current sea level pressure at your location.

#define SEALEVELPRESSURE_HPA (1013.25)

This sketch uses I2C communication protocol by default. The following line creates an Adafruit_BME680 object called bme on the Arduino I2C pins.

Adafruit_BME680 bme;

If you want to use SPI, you need to comment previous line and uncomment the following lines.

//Adafruit_BME680 bme(BME_CS);
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO,  BME_SCK);

In the setup, we initialize the serial communication with PC and call the begin() function. The begin() function initializes I2C interface and checks if the chip ID is correct. It then resets the chip using soft-reset & waits for the sensor for calibration after wake-up.

Serial.begin(9600);
while (!Serial);

if (!bme.begin()) {
	Serial.println("Could not find a valid BME680 sensor, check wiring!");
	while (1);
}

Next, we set up some parameters for the sensor.

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

Let’s look at each function one by one.

setTemperatureOversampling(uint8_t os)

setPressureOversampling(uint8_t os)

setHumidityOversampling(uint8_t os)

To increase the effective resolution of measurements and reduce noise, the BME680 supports oversampling (taking multiple samples and averaging them together). There are three functions called setTemperatureOversampling(), setHumidityOversampling() and setPressureOversampling() to set oversampling for temperature, humidity, and pressure measurements, respectively. These functions accept one of the following parameters:

  • BME680_OS_NONE (turns off reading)
  • BME680_OS_1X
  • BME680_OS_2X
  • BME680_OS_4X
  • BME680_OS_8X
  • BME680_OS_16X

setIIRFilterSize(fs)

The BME680 also features an internal IIR filter to reduce short-term changes in sensor output values caused by external disturbances (such as slamming a door or blowing air into the sensor). The setIIRFilterSize() function sets the IIR filter. The IIR filter can be configured to different filter coefficients by choosing one of the following parameters:

  • BME680_FILTER_SIZE_0 (no filtering)
  • BME680_FILTER_SIZE_1
  • BME680_FILTER_SIZE_3
  • BME680_FILTER_SIZE_7
  • BME680_FILTER_SIZE_15
  • BME680_FILTER_SIZE_31
  • BME680_FILTER_SIZE_63
  • BME680_FILTER_SIZE_127

setGasHeater(heaterTemp, heaterTime)

In addition, the gas sensor hot plate can be configured to be heated before the gas measurement is performed. The setGasHeater() function sets the heater profile and accepts two arguments

  • heaterTemp – The heater temperature (in °C)
  • heaterTime – The time the heater should be on (in milliseconds)

For example, bme.setGasHeater(320, 150) will heat the gas sensor hot plate at 320°C for 150 milliseconds.

In the loop, we call the bme.performReading() function to perform a reading in blocking mode. Once this is done we can access bme’s instance variables using the dot (.) operator.

bme.temperature returns temperature reading.

bme.pressure returns barometric pressure reading.

bme.humidity returns relative humidity reading.

bme.gas_resistance returns gas resistance.

bme.readAltitude(SEALEVELPRESSURE_HPA) function calculates the altitude (in meters) from the specified atmospheric pressure (in hPa), and sea-level pressure (in hPa).

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

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

Serial.print("Humidity = ");
Serial.print(bme.humidity);
Serial.println(" %");

Serial.print("Gas = ");
Serial.print(bme.gas_resistance / 1000.0);
Serial.println(" KOhms");

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