The Introduction and Usage of BMP280


Right off the assembly line
The BMP280 is an insanely small SMD device (2.0mm x 2.5mm) so you'll need to get hold of a breakout board to use it on the bench. It is small, since its intended application is for deployment within a mobile phone. That may seem a bit unusual as you would probably think of this device used only in a weather station environment until you realise that pressure can be used to measure altitude.

In fact the applications that are suggested by Bosch Sensortech (manufactures the BMP280) are:

  • Enhancement of GPS navigation (e.g. time-to-first-fix improvement, dead-reckoning, slope detection)
  • Indoor navigation (floor detection, elevator detection)
  • Outdoor navigation, leisure and sports applications
  • Weather forecast
  • Health care applications (e.g. spirometry)
  • Vertical velocity indication (e.g. rise/sink speed)
  • [ More details about BMP280: ]


Source: datasheet Figure 1

Initially it would seem that measuring height using a BMP280 chip is a little redundant since a GPS system is far more accurate and also gives you height information as well. Now, I did a little research on Google and that last statement may not be so accurate!

We all tend to assume that any system we have is absolutely accurate and I thought GPS was in that category (based on the fact that my satnav shows me exactly where I am - but how accurate is that?). It turns out to be about ±10m!

Despite the fact that GPS satellites have atomic clocks on board and even after adjustment for relativistic changes due to speed of travel and distance above the earth - there are other factors that influence GPS accuracy including the atmosphere, satellite position inaccuracy and more see below..

Did you know that military did not believe that Einstein's theory of relativity would apply and built in a software switch to inside the satellite code to stop adjustment for that science (they had to turn it on when they found Enistein's relativity theorem did apply even to their satellites!).
Why a GPS height Measurement is not that accurate
Garmin GPS receivers are typically accurate to 10m [horizontal measurement] [Source:].

GPS versus barometric altitude: the definitive answer

In the link above there is a discussion of GPS vs Barometric Pressure measurement. In that article it discusses how hang gliders and paragliders must fly within a specific defined volumetric space so that they are not eliminated from the competition. To do that it is important that they can measure height accurately using their own instruments and you would have thought that the GPS system is ideal for that. Maybe not!

The thing about GPS is that the GPS receiver knows where the satellites are so it knows its position relative to 4 or more satellites with extreme accuracy (more satellites give increasing positional accuracy). The problem is that the orbit of the satellites does not mean that the satellite or GPS receiver knows where the ground is located!

""Your GPS unit has multiple models (datums) of the Earth in its memory."

In fact each GPS unit has multiple models of the earth's surface e.g. WGS 84 (World Geodetic System - created in 1984). Other datums can be more accurate for specific countries e.g. in the UK OSGB36 (ordinance survey data). There are quite a few other datum sets but WGS 84 is commonly used for GPS systems.

The WGS 84 system defines an oblate spheroid that approximates the shape of the Earth and this is where errors can occur depending on where you are located. In the UK you would be 70m above the true height, and in India 100m below! (See the link above for a heatmap of height variation around the globe). Depending on your GPS the error may be calculated and compensated out (geoid correction).

Additionally there are other horizontal error sources due to:

  • Ionospheric effect (±5m)
  • Satellite position error (±2.5)
  • Satellite clock error (±2m)
  • Multipath interference (±1m)
  • Tropospheric effect (±0.5m)
  • Maths and rounding errors (±1m)
Total horizontal error: ±15m. It is estimated that the vertical error is 3 times this: ±45m.

Another error source is from averaging the information over time e.g. over a few seconds so there will be a delay in output reading while climbing or falling.

Using Barometric Pressure for Height Measurement
In fact all aviation uses a Barometric pressure measurement converted to show a height measurement, since pressure decreases with height. Factors that affect the reading are temperature and so altimeters are temperature compensated. Another factor is the ground level pressure measurement (defines zero height) which varies with the weather so altimeters allow setting of the ground level pressure reading (obtained from weather services for aviation) to eliminate local pressure changes. lookup QNH and QNE

With the BMP280 the pressure range is from 300 to 1100 hPa which means height can be measured from +9000m to -500m. It also has an relative accuracy of ±0.12 hPa. This equates to a relative accuracy of ±1m.

Note: This is probably the maximum inaccuracy - see later for actual measurements that show the sensor (the specific one I am using) is far more sensitive to relative height change.
Even if this inaccuracy is correct across the range of batches of all BMP280's then it still represents a hugely more accurate reading than usign a GPS for height measurement.

The absolute accuracy is ±1hPa equivalent to 11.9m [ 9500.0/(1100-300) ] - this is still quite a bit better than GPS vertical readings. To get a more accurate height reading the unit would have to be calibrated i.e. set the output reading to zero on the ground (or get the current ground level pressure reading for the area from an aviation service and input it to the microcontroller).

The BMP280 (all electronic barometers probably) can react very fast to pressure changes - there is no waiting around - The datasheet indicates that you can read the device 157 times a second (for the BMP180 it is 120Hz). This means variations in height can be rapidly detected. This is a bit too fast for height measurements - you won't need that many data points - although they can be used when employing the IIR filter (BMP280 only) i.e. oversampling and then filtering to get a stable output. The rapid measurement rate would be more appropriate for spirometry (measurement of breathing).

Measuring Altitude
To measure altitude you have to know the pressure reading at sea level. The commonly used value is 101325 Pa or 1013.25mb - this was intended to represent the mean atmospheric pressure at sea level. Unfortunately the value is not representative of the pressure at sea level in many different countries.

Really, the only way is to obtain the pressure value for sea level on the day from a reliable forecast.

Note that the value will change through out the day anyway. so you really need a radio link transmitting the current pressure on the ground to your measuring device. This would make the altitude measurement as accurate as possible even when local pressure values change.

Schematic diagram
Note you don't need the level translator parts if your breakout board has them onboard. If it does have them then connect from the uno to the breakout board directly. Alternatively use a 3V3 arduino for direct connection.


Note: The I2C connections are the two top left ones on an Arduino Uno if the usb connector is at the left of the board. They are not marked. The left one is SCL and the right one is SDA. They are the two shielded pins opposite the 6 pin connector.
Typical pressure Results through the day
These reading are taken from the serial monitor output from the Arduino serial port for both Adafruti BMP280 library and I2C library (I2C library 1st). Height is not calibrated = wrong (except where noted).

10.15 3/8/17 avg 3-4th aug 1007mbar sea level pressure forecast
Probe BMP280: Sensor found
HeightPT1: 7.41 m; Height: 81.49 Pressure: 100350.00 Pa; T: 22.97 C
HeightPT1: 14.10 m; Height: 80.99 Pressure: 100356.00 Pa; T: 23.03 C
HeightPT1: 80.79 m; Height: 80.74 Pressure: 100359.00 Pa; T: 23.14 C

16:37 3/8/17
Probe BMP280: Sensor found
HeightPT1: 6.81 m; Height: 74.95 Pressure: 100428.00 Pa; T: 23.43 C
HeightPT1: 13.01 m; Height: 74.95 Pressure: 100428.00 Pa; T: 23.50 C
HeightPT1: 18.62 m; Height: 74.78 Pressure: 100430.00 Pa; T: 23.55 C

17.06 3/8/17
HeightPT1: 73.82 m; Height: 73.61 Pressure: 100444.00 Pa; T: 24.29 C
HeightPT1: 73.82 m; Height: 73.86 Pressure: 100441.00 Pa; T: 24.29 C
HeightPT1: 73.80 m; Height: 73.61 Pressure: 100444.00 Pa; T: 24.29 C

17:13 3/8/17
HeightPT1: 72.57 m; Height: 72.77 Pressure: 100454.00 Pa; T: 24.50 C
HeightPT1: 72.60 m; Height: 72.94 Pressure: 100452.00 Pa; T: 24.50 C
HeightPT1: 72.63 m; Height: 72.85 Pressure: 100453.00 Pa; T: 24.50 C
HeightPT1: 72.65 m; Height: 72.85 Pressure: 100453.00 Pa; T: 24.51 C

22:18 3/8/17
Probe BMP280: Sensor found
HeightPT1: 5.31 m; Height: 58.44 Pressure: 100625.00 Pa; T: 27.80 C
HeightPT1: 10.11 m; Height: 58.11 Pressure: 100629.00 Pa; T: 27.85 C
HeightPT1: 14.51 m; Height: 58.53 Pressure: 100624.00 Pa; T: 27.89 C

MP280 test 17.06 3/8/17 Adafruit library output (when SDO pulled to 3V3)
Temperature = 24.61 *C
Pressure = 100444.17 Pa
Approx altitude = 73.60 m

3/8/17 Adafruit library output (when SDO pulled to 3V3)
Temperature = 24.99 *C
Pressure = 100462.96 Pa
Approx altitude = 72.02 m

3/8/17 Adafruit library output (when SDO pulled to 3V3)
Temperature = 25.03 *C
Pressure = 100458.71 Pa
Approx altitude = 72.38 m

07:09 4/8/17 forecast pressure 1009mbar avg sea level pressure
Probe BMP280: Sensor found
HeightPT1: 5.08 m; Height: 55.85 Pressure: 100656.00 Pa; T: 21.30 C
HeightPT1: 9.68 m; Height: 55.68 Pressure: 100658.00 Pa; T: 21.36 C
HeightPT1: 13.87 m; Height: 55.85 Pressure: 100656.00 Pa; T: 21.42 C

09:04 4/8/17
HeightPT1: 49.79 m; Height: 49.57 Pressure: 100731.00 Pa; T: 22.46 C
HeightPT1: 49.79 m; Height: 49.74 Pressure: 100729.00 Pa; T: 22.46 C
HeightPT1: 49.80 m; Height: 49.91 Pressure: 100727.00 Pa; T: 22.45 C
HeightPT1: 49.80 m; Height: 49.82 Pressure: 100728.00 Pa; T: 22.44 C

Different libraries give the same result
Here the adafruit library was given the actual forecast sea level pressure to get an altitude. I don't think it is too accurate because you have to have the actual ground level pressure value at your location. where I am is about 23m above sea level not 2m as shown below!

The I2C Sensor library does not let you change the default value of 1013.25mb so you would need to go and write some code to allow accurate height measurement adjustment.

Different libraries Adafruit and I2C library (same result)

07:41 13/8/17 forecast pressure 1020mbar avg sea level pressure
I2C Sensor LIB: Probe BMP280: Sensor found
HeightPT1: 1.82 m; Height: 20.03 Pressure: 101758.00 Pa; T: 23.27 C
HeightPT1: 3.50 m; Height: 20.28 Pressure: 101755.00 Pa; T: 23.34 C
HeightPT1: 5.01 m; Height: 20.12 Pressure: 101757.00 Pa; T: 23.33 C

07:42 13/8/17 Adafruit library forecast pressure 1020mbar
Temperature = 23.70 *C
Pressure = 101755.11 Pa
Approx altitude = 20.27 m
Note: The I2C sensor lib code averages the 1st 10 readings (see example 2 below) so the left hand values are not stable (until 10 values are gathered) the next measurement is the unaveraged height reading (20.03).

Interestingly there is a difference in temperature readings; Maybe one of the library code implementations is not right.

Warning: Getting a calibrated height using a predicted forecast pressure reading is not accurate as it will be slightly different at your location, so it is best to design code to store the value (when you are at ground level - by pressing a dedicated button, or gather the data on pwoer up). Then use this value as the calibration value for measuring relative height from ground level.
Why your BMP280 won't start
If you're like me and you have a breakout board without level shifters and you create some level shifters using a few components, to get I2C mode going, and then get the example code into the Arduino uno r3. Then you wonder why it's doing absolutely nothing.

As a typical engineer you give it a go and then - it's time to read the manual! - this is always a last resort unless there is a danger of blowing up a $800 component! In which case read the manual first.

It turns out that the communication mode of the BMP280 is set on power up by the state of various control inputs.

One "gotha" is that an OUTPUT in SPI mode turns into an INPUT in I2C mode!
SPI mode uses more pins to define its interface and one of these unused the outputs (in SPI mode) is used as an input in I2C mode!. If you have a breakout board then these control inputs are left floating, meaning its just not going to work unless you set them before power up.

Warning: Holding any interface pin high while VDDIO is switched off will damage the chip due to current flow through protection diode. This could happen if you are designing a complex power management system where control pins are connected to the processor and power to the chip is controlled separately.
Conversely, if VDD is off and VDDIO is supplied, control pins at the chip are held at high-z (inactive).

IC2 Mode Selection
To get I2C mode going the Chip Select pin (CS) must be held at the VDDIO level as the BMP280 powers up.

If CS is held low during power up SPI mode is active.

I2C Address Selection
In addition to that the SDO pin (used as an output in SPI mode) is used as an input that selects one of two I2C addresses. This pin must be held low to get the lower address.

If you don't want to continuously change from high to low on SDO when changing which library you use just go into the Adafruit library (or I2C Sensor library) and change the BMP280_address from 0x77 to 0x76 (Adafruit library). The file is at:

C:\Users\<user name>\Documents\Arduino\libraries\Adafruit_BMP280_Library\Adafruit_BMP280.h

I2C pullups
SDI is a bi directional open drain and must have a pullup attached.

There is no need for a pullup on SCK as it is input; In I2C mode the device is only ever a slave and does not do clock stretching. I tested this using a resistor drop down (5V to 3V) using 1k connected to a 1k5 then to ground. With the SCK input connected to the top of the 1k5 - it works fine.

Note You can only do this if you use the BMP280 on its own since I2C requires pullups so that the bus can be released for other devices.

Note: The SDI and SCK pins are not true open drain pins and only SDI and SDO are implemented as bi-directional.

Table 29 in the datasheet (Pin description) shows what is going on:


Adafruit Library just won't go
I found that the ADAFruit BMP280 Library would just not work - the reason was that the SDO (used as an input in I2c mode) has been defaulted to 0x77 in software - that means the SDO pin needs to be pulled high (3V3 high) to work with this library (or change the default address in the library to 0x76).

I2C Address for the BMP280
The device can be set to one of two I2C addresses, so you can have two separate pressure sensors on one I2C bus. The selection is made using the SDO pin as an input, and when low selects address 0x76, and when high selects address 0x77.

BMP280 Datasheet

Software Library and versions
Arduino IDE Version
Version : 1.6.4

Adafruit BMP280 Library
The libraries used here is are

  • Adafruit BMP280 Library 1.0.2
  • I2C-Sensor-Lib Ver 0.8.2
...both can easily installed from the Arduino IDE.

If you do not see the library as an entry when you click the menus:

Sketch-->Include Library

Then select manage libraries :

Sketch-->Include Library -->Manage Libraries...

Search for and install <lib name> using the "Filter Your Search" form.

Code size results from libraries used:
For the simple example code used there is a large difference in code use as shown below.

The Adafruit BMP280 uses 1334 bytes more than I2C Sensor Lib - this is something to note if you are running out of code space.

Code use I2C-Sensor-Lib Lbrary:
Sketch uses 8,830 bytes (27%) of program storage space. Maximum is 32,256 bytes.
Global variables use 563 bytes (27%) of dynamic memory, leaving 1,485 bytes for local variables.

Code use Adafruit BMP280 Lbrary:
Sketch uses 10,164 bytes (31%) of program storage space. Maximum is 32,256 bytes.
Global variables use 563 bytes (27%) of dynamic memory, leaving 1,485 bytes for local variable
Differences between the libraries
The adafruit BMP280 library comes with a member function (or method) that allows entry of the sea level altitude and returns the altitude based on this value and your current barometric reading (See example 1 below). This is a sparse library and does not give any other methods to control the register settings within the device.

On the other hand I2C Sensor lib does have methods to set the internal parameters of the device but does not have a sea level altitude correction function. You really need a corrector adjustment to get more accurate altitudes (see below).

Adding a method to the I2C Sensor lib
This requires a simple addition to the library file:

  • C:\Users\<username>\Documents\Arduino\libraries\I2C-Sensor-Lib_iLib\src\i2c_BMP280.h
Find the top method


...and add in the one shown below:


/**< gives the number of meters above sea level */
void getAltitude(float& meter)
uint32_t iPascal;

meter = 44330.0*(1-pow(float(iPascal)/101325.0,1.0/5.255));


/**< gives the number of meters above sea level. JFM parameterised sea level*/
void getAltitude(float& meter,float seaLevelmbar)
uint32_t iPascal;

meter = 44330.0*(1-pow(float(iPascal)/(seaLevelmbar*100),1.0/5.255));

This just adds a public method that allows the sea level pressure (forecast) to be entered instead of the default 1013.25mbar value which gives a more accurate height reading.
Top Bottom