STM32 I2C Library for BMP280 Temperature and Pressure Sensor
Please read Liability Disclaimer and License Agreement CAREFULLY
Before going further please read BMP280 datasheet
BMP280.h
#ifndef __BMP280_H__
#define __BMP280_H__
#include "stm32f1xx_hal.h"
#include "i2c.h"
#include <stdint.h>
#include <stdbool.h>
/**
* Mode of BMP280 module operation.
* Forced - Measurement is initiated by user.
* Normal - Continues measurement.
*/
typedef enum {
BMP280_MODE_SLEEP = 0,
BMP280_MODE_FORCED = 1,
BMP280_MODE_NORMAL = 3
} BMP280_Mode;
typedef enum {
BMP280_FILTER_OFF = 0,
BMP280_FILTER_2 = 1,
BMP280_FILTER_4 = 2,
BMP280_FILTER_8 = 3,
BMP280_FILTER_16 = 4
} BMP280_Filter;
/**
* Pressure oversampling settings
*/
typedef enum {
BMP280_SKIPPED = 0, /* no measurement */
BMP280_ULTRA_LOW_POWER = 1, /* oversampling x1 */
BMP280_LOW_POWER = 2, /* oversampling x2 */
BMP280_STANDARD = 3, /* oversampling x4 */
BMP280_HIGH_RES = 4, /* oversampling x8 */
BMP280_ULTRA_HIGH_RES = 5 /* oversampling x16 */
} BMP280_Oversampling;
/**
* Stand by time between measurements in normal mode
*/
typedef enum {
BMP280_STANDBY_05 = 0, /* stand by time 0.5ms */
BMP280_STANDBY_62 = 1, /* stand by time 62.5ms */
BMP280_STANDBY_125 = 2, /* stand by time 125ms */
BMP280_STANDBY_250 = 3, /* stand by time 250ms */
BMP280_STANDBY_500 = 4, /* stand by time 500ms */
BMP280_STANDBY_1000 = 5, /* stand by time 1s */
BMP280_STANDBY_2000 = 6, /* stand by time 2s BMP280, 10ms BME280 */
BMP280_STANDBY_4000 = 7, /* stand by time 4s BMP280, 20ms BME280 */
} BMP280_StandbyTime;
/**
* Configuration parameters for BMP280 module.
*/
typedef struct {
BMP280_Mode mode;
BMP280_Filter filter;
BMP280_Oversampling oversampling_pressure;
BMP280_Oversampling oversampling_temperature;
BMP280_StandbyTime standby;
} bmp280_params_t;
/**
* Initialize BMP280 module, probes for the device, soft resets the device,
* reads the calibration constants, and configures the device using the supplied
* parameters. Returns true on success otherwise false.
*
* The I2C address is assumed to have been initialized in the dev, and
* may be either BMP280_I2C_ADDRESS_0 or BMP280_I2C_ADDRESS_1. If the I2C
* address is unknown then try initializing each in turn.
*
* This may be called again to soft reset the device and initialize it again.
*/
bool bmp280_init(void);
/**
* Start measurement in forced mode.
* The module remains in forced mode after this call.
* Do not call this method in normal mode.
*/
bool bmp280_force_measurement(void);
/**
* Check if BMP280 is busy with measuring temperature/pressure.
* Return true if BMP280 is busy.
*/
bool bmp280_is_measuring(void);
/**
* Read compensated temperature and pressure data:
*
* Temperature in degrees Celsius times 100.
*
* Pressure in Pascals in fixed point 24 bit integer 8 bit fraction format.
*/
bool bmp280_read_fixed(int32_t *temperature, uint32_t *pressure);
/**
* Read compensated temperature and pressure data:
* Temperature in degrees Celsius.
* Pressure in Pascals.
*/
bool bmp280_read_float(float *temperature, float *pressure);
#endif // __BMP280_H__
BMP280.c
#include "BMP280.h"
#define BMP280_I2C_ADDRESS 0x76 //or 0x77
#define BMP280_ADDRESS (BMP280_I2C_ADDRESS << 1) //or 0x77
#define BMP280_CHIP_ID 0x58 /* BMP280 has chip-id 0x58 */
/**
* BMP280 registers
*/
#define BMP280_REG_TEMP_XLSB 0xFC /* bits: 7-4 */
#define BMP280_REG_TEMP_LSB 0xFB
#define BMP280_REG_TEMP_MSB 0xFA
#define BMP280_REG_TEMP (BMP280_REG_TEMP_MSB)
#define BMP280_REG_PRESS_XLSB 0xF9 /* bits: 7-4 */
#define BMP280_REG_PRESS_LSB 0xF8
#define BMP280_REG_PRESS_MSB 0xF7
#define BMP280_REG_PRESSURE (BMP280_REG_PRESS_MSB)
#define BMP280_REG_CONFIG 0xF5 /* bits: 7-5 t_sb; 4-2 filter; 0 spi3w_en */
#define BMP280_REG_CTRL 0xF4 /* bits: 7-5 osrs_t; 4-2 osrs_p; 1-0 mode */
#define BMP280_REG_STATUS 0xF3 /* bits: 3 measuring; 0 im_update */
#define BMP280_REG_CTRL_HUM 0xF2 /* bits: 2-0 osrs_h; */
#define BMP280_REG_RESET 0xE0
#define BMP280_REG_ID 0xD0
#define BMP280_REG_CALIB 0x88
#define BMP280_REG_HUM_CALIB 0x88
#define BMP280_RESET_VALUE 0xB6
#define BMP280_RESPONCE_TIME 500
uint16_t dig_T1;
int16_t dig_T2;
int16_t dig_T3;
uint16_t dig_P1;
int16_t dig_P2;
int16_t dig_P3;
int16_t dig_P4;
int16_t dig_P5;
int16_t dig_P6;
int16_t dig_P7;
int16_t dig_P8;
int16_t dig_P9;
uint8_t id; /* Chip ID */
bmp280_params_t myParams;
static bool read_register16(uint8_t addr, uint16_t *value) {
uint8_t rx_buff[2];
if (HAL_I2C_Mem_Read(&hi2c1, BMP280_ADDRESS, addr, 1, rx_buff, 2, BMP280_RESPONCE_TIME) == HAL_OK) {
*value = (uint16_t) ((rx_buff[1] << 8) | rx_buff[0]);
return true;
} else
return false;
}
static inline int read_data(uint8_t addr, uint8_t *value, uint8_t len) {
if (HAL_I2C_Mem_Read(&hi2c1, BMP280_ADDRESS, addr, 1, value, len, BMP280_RESPONCE_TIME) == HAL_OK)
return 0;
else
return 1;
}
static bool read_calibration_data(void) {
if (read_register16(0x88, &dig_T1) && read_register16(0x8a, (uint16_t *) &dig_T2)
&& read_register16(0x8c, (uint16_t *) &dig_T3) && read_register16(0x8e, &dig_P1)
&& read_register16(0x90, (uint16_t *) &dig_P2) && read_register16(0x92, (uint16_t *) &dig_P3)
&& read_register16(0x94, (uint16_t *) &dig_P4) && read_register16(0x96, (uint16_t *) &dig_P5)
&& read_register16(0x98, (uint16_t *) &dig_P6) && read_register16(0x9a, (uint16_t *) &dig_P7)
&& read_register16(0x9c, (uint16_t *) &dig_P8) && read_register16(0x9e, (uint16_t *) &dig_P9))
{
return true;
}
return false;
}
static int write_register8(uint8_t addr, uint8_t value) {
if (HAL_I2C_Mem_Write(&hi2c1, BMP280_ADDRESS, addr, 1, &value, 1, BMP280_RESPONCE_TIME) == HAL_OK)
return false;
else
return true;
}
bool bmp280_init(void) {
/**
* Initialize default parameters.
* Default configuration:
* mode: NORAML
* filter: OFF
* oversampling: x4
* standby time: 250ms
*/
myParams.mode = BMP280_MODE_NORMAL;
myParams.filter = BMP280_FILTER_16;
myParams.oversampling_pressure = BMP280_ULTRA_HIGH_RES;
myParams.oversampling_temperature = BMP280_ULTRA_HIGH_RES;
myParams.standby = BMP280_STANDBY_250;
if (read_data(BMP280_REG_ID, &id, 1)) {
return false;
}
// Soft reset.
if (write_register8(BMP280_REG_RESET, BMP280_RESET_VALUE)) {
return false;
}
// Wait until finished copying over the NVP data.
while (1) {
uint8_t status;
if (!read_data(BMP280_REG_STATUS, &status, 1) && (status & 1) == 0)
break;
}
if (!read_calibration_data()) {
return false;
}
uint8_t config = (myParams.standby << 5) | (myParams.filter << 2);
if (write_register8(BMP280_REG_CONFIG, config)) {
return false;
}
if (myParams.mode == BMP280_MODE_FORCED) {
myParams.mode = BMP280_MODE_SLEEP; // initial mode for forced is sleep
}
uint8_t ctrl = (myParams.oversampling_temperature << 5) | (myParams.oversampling_pressure << 2) | (myParams.mode);
if (write_register8(BMP280_REG_CTRL, ctrl)) {
return false;
}
return true;
}
bool bmp280_force_measurement(void) {
uint8_t ctrl;
if (read_data(BMP280_REG_CTRL, &ctrl, 1))
return false;
ctrl &= ~0b11; // clear two lower bits
ctrl |= BMP280_MODE_FORCED;
if (write_register8(BMP280_REG_CTRL, ctrl))
return false;
return true;
}
bool bmp280_is_measuring(void) {
uint8_t status;
if (read_data(BMP280_REG_STATUS, &status, 1))
return false;
if (status & (1 << 3)) {
return true;
}
return false;
}
/**
* Compensation algorithm is taken from BMP280 datasheet.
*
* Return value is in degrees Celsius.
*/
static inline int32_t compensate_temperature(int32_t adc_temp, int32_t *fine_temp) {
int32_t var1, var2;
var1 = ((((adc_temp >> 3) - ((int32_t) dig_T1 << 1))) * (int32_t) dig_T2) >> 11;
var2 = (((((adc_temp >> 4) - (int32_t) dig_T1) * ((adc_temp >> 4) - (int32_t) dig_T1)) >> 12) * (int32_t) dig_T3) >> 14;
*fine_temp = var1 + var2;
return (*fine_temp * 5 + 128) >> 8;
}
/**
* Compensation algorithm is taken from BMP280 datasheet.
*
* Return value is in Pa, 24 integer bits and 8 fractional bits.
*/
static inline uint32_t compensate_pressure(int32_t adc_press, int32_t fine_temp) {
int64_t var1, var2, p;
var1 = (int64_t) fine_temp - 128000;
var2 = var1 * var1 * (int64_t) dig_P6;
var2 = var2 + ((var1 * (int64_t) dig_P5) << 17);
var2 = var2 + (((int64_t) dig_P4) << 35);
var1 = ((var1 * var1 * (int64_t) dig_P3) >> 8) + ((var1 * (int64_t) dig_P2) << 12);
var1 = (((int64_t) 1 << 47) + var1) * ((int64_t) dig_P1) >> 33;
if (var1 == 0) {
return 0; // avoid exception caused by division by zero
}
p = 1048576 - adc_press;
p = (((p << 31) - var2) * 3125) / var1;
var1 = ((int64_t) dig_P9 * (p >> 13) * (p >> 13)) >> 25;
var2 = ((int64_t) dig_P8 * p) >> 19;
p = ((p + var1 + var2) >> 8) + ((int64_t) dig_P7 << 4);
return p;
}
bool bmp280_read_fixed(int32_t *temperature, uint32_t *pressure) {
int32_t adc_pressure;
int32_t adc_temp;
uint8_t data[6];
if (read_data(BMP280_REG_PRESS_MSB, data, 6)) {
return false;
}
adc_pressure = data[0] << 12 | data[1] << 4 | data[2] >> 4;
adc_temp = data[3] << 12 | data[4] << 4 | data[5] >> 4;
int32_t fine_temp;
*temperature = compensate_temperature(adc_temp, &fine_temp);
*pressure = compensate_pressure(adc_pressure, fine_temp);
return true;
}
bool bmp280_read_float(float *temperature, float *pressure) {
int32_t fixed_temperature;
uint32_t fixed_pressure;
uint32_t fixed_humidity;
if (bmp280_read_fixed(&fixed_temperature, &fixed_pressure)) {
*temperature = (float) fixed_temperature / 100.0;
*pressure = (float) fixed_pressure / 25600.0;
return true;
}
return false;
}
Comments powered by CComment