/* BNO055_BMP280_t3 Basic Example Code
by: Kris Winer
date: April 25, 2015
license: Beerware - Use this code however you'd like. If you
find it useful you can buy me a beer some time.
adapted for minimalist testing BMP280 purposes
It uses SDA/SCL on pins 17/16, respectively, and it uses the Teensy 3.1-specific Wire library i2c_t3.h.
The Add-on shield can also be used as a stand-alone breakout board for any Arduino, Teensy, or
other microcontroller by closing the solder jumpers on the back of the board.
The BMP280 is a simple but high resolution (20-bit) pressure sensor, which can be used in its high resolution
mode but with power consumption of 20 microAmp, or in a lower resolution mode with power consumption of
only 1 microAmp. The choice will depend on the application.
All sensors communicate via I2C at 400 Hz or higher.
SDA and SCL should have external pull-up resistors (to 3.3V).
4K7 resistors are on the BNO055_BMP280 breakout board.
Hardware setup:
Breakout Board --------- Arduino/Teensy
3V3 ---------------------- 3.3V
SDA -----------------------A4/17
SCL -----------------------A5/16
GND ---------------------- GND
Note: The BNO055_BMP280 breakout board is an I2C sensor and uses the Arduino Wire or Teensy i2c_t3.h library.
Because the sensor is not 5V tolerant, we are using a 3.3 V 8 MHz Pro Mini or a 3.3 V Teensy 3.1.
We have disabled the internal pull-ups used by the Wire library in the Wire.h/twi.c utility file.
We are also using the 400 kHz fast I2C mode by setting the TWI_FREQ to 400000L /twi.h utility file.
The Teensy has no internal pullups and we are using the Wire.begin function of the i2c_t3.h library
to select 400 Hz i2c speed.
*/
//#include <Wire.h>
#include <i2c_t3.h>
//#include <kinetis.h>
// BMP280 registers
#define BMP280_TEMP_XLSB 0xFC
#define BMP280_TEMP_LSB 0xFB
#define BMP280_TEMP_MSB 0xFA
#define BMP280_PRESS_XLSB 0xF9
#define BMP280_PRESS_LSB 0xF8
#define BMP280_PRESS_MSB 0xF7
#define BMP280_CONFIG 0xF5
#define BMP280_CTRL_MEAS 0xF4
#define BMP280_STATUS 0xF3
#define BMP280_RESET 0xE0
#define BMP280_ID 0xD0 // should be 0x58
#define BMP280_CALIB00 0x88
#define BMP280_ADDRESS 0x76 // Address of BMP280
//#define BMP280_ADDRESS 0x77 // Address of BMP280 adafruit
#define SerialDebug true // set to true to get Serial output for debugging
enum Posr {
P_OSR_00 = 0, // no op
P_OSR_01,
P_OSR_02,
P_OSR_04,
P_OSR_08,
P_OSR_16
};
enum Tosr {
T_OSR_00 = 0, // no op
T_OSR_01,
T_OSR_02,
T_OSR_04,
T_OSR_08,
T_OSR_16
};
enum IIRFilter {
full = 0, // bandwidth at full sample rate
BW0_223ODR,
BW0_092ODR,
BW0_042ODR,
BW0_021ODR // bandwidth at 0.021 x sample rate
};
enum Mode {
BMP280Sleep = 0,
forced,
forced2,
normal
};
enum SBy {
t_00_5ms = 0,
t_62_5ms,
t_125ms,
t_250ms,
t_500ms,
t_1000ms,
t_2000ms,
t_4000ms,
};
// Specify BMP280 configuration
//uint8_t Posr = P_OSR_16, Tosr = T_OSR_02, Mode = normal, IIRFilter = BW0_042ODR, SBy = t_62_5ms; // set pressure amd temperature output data rate
uint8_t Posr = P_OSR_16, Tosr = T_OSR_02, Mode = normal, IIRFilter = full, SBy = t_00_5ms;
// t_fine carries fine temperature as global value for BMP280
int32_t t_fine;
// Pin definitions
//int intPin = 8; // These can be changed, 2 and 3 are the Arduinos ext int pins
//int myLed = 13;
uint16_t Pcal[8]; // calibration constants from BMP280 PROM registers
uint32_t D1 = 0, D2 = 0; // raw BMP280 pressure and temperature data
double Temperature, Pressure; // stores BMP280 pressures sensor pressure and temperature
int32_t rawPress, rawTemp; // pressure and temperature raw count output for BMP280
// BMP280 compensation parameters
uint16_t dig_T1, dig_P1;
int16_t dig_T2, dig_T3, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9;
int msec = 50, delt_t=0, count=0;
float sec = 0.0;
void setup()
{
// Setup for Master mode, pins 16/17, external pullups, 400kHz for Teensy 3.1
Wire.begin(I2C_MASTER, 0x00, I2C_PINS_16_17, I2C_PULLUP_EXT, I2C_RATE_100);
//Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_100);
delay(1000);
Serial.begin(38400);
while (!Serial) delay(1000);
// pinMode(myLed, OUTPUT);
// digitalWrite(myLed, HIGH);
I2Cscan(); // check for I2C devices on the bus8
delay(1000);
// Read the WHO_AM_I register of the BMP280 this is a good test of communication
byte f = readByte(BMP280_ADDRESS, BMP280_ID); // Read WHO_AM_I register for BMP280
Serial.print("BMP280 ");
Serial.print("I AM ");
Serial.print(f, HEX);
Serial.print(" I should be ");
Serial.println(0x58, HEX);
Serial.println(" ");
delay(1000);
writeByte(BMP280_ADDRESS, BMP280_RESET, 0xB6); // reset BMP280 before initilization
delay(1000);
BMP280Init(); // Initialize BMP280 altimeter
Serial.println("Calibration coeficients:");
Serial.print("dig_T1 =");
Serial.println(dig_T1);
Serial.print("dig_T2 =");
Serial.println(dig_T2);
Serial.print("dig_T3 =");
Serial.println(dig_T3);
Serial.print("dig_P1 =");
Serial.println(dig_P1);
Serial.print("dig_P2 =");
Serial.println(dig_P2);
Serial.print("dig_P3 =");
Serial.println(dig_P3);
Serial.print("dig_P4 =");
Serial.println(dig_P4);
Serial.print("dig_P5 =");
Serial.println(dig_P5);
Serial.print("dig_P6 =");
Serial.println(dig_P6);
Serial.print("dig_P7 =");
Serial.println(dig_P7);
Serial.print("dig_P8 =");
Serial.println(dig_P8);
Serial.print("dig_P9 =");
Serial.println(dig_P9);
Serial.flush();
delay(2000);
}
void loop()
{
delt_t = millis() - count;
if (delt_t > msec) { // update based on delt_t
rawPress = readBMP280Pressure();
Pressure = (float) bmp280_compensate_P(rawPress)/25600.; // Pressure in mbar
rawTemp = readBMP280Temperature();
Temperature = (float) bmp280_compensate_T(rawTemp)/100.;
float altitude = 145366.45f*(1.0f - pow((Pressure/1013.25f), 0.190284f));
if(SerialDebug) {
Serial.println("BMP280:");
Serial.print("Altimeter temperature = ");
Serial.print( Temperature, 2);
Serial.println(" C"); // temperature in degrees Celsius
Serial.print("Altimeter temperature = ");
Serial.print(9.*Temperature/5. + 32., 2);
Serial.println(" F"); // temperature in degrees Fahrenheit
Serial.print("Altimeter pressure = ");
Serial.println(Pressure, 6);
/*
Serial.println(" mbar");// pressure in millibar
Serial.print("Altitude = ");
Serial.print(altitude, 2);
Serial.println(" feet");
Serial.println(" ");
*/
}
// digitalWrite(myLed, !digitalRead(myLed));
count = millis();
sec += (msec/1000.0);
Serial.print("sec: ");
Serial.println(sec);
}
}
int32_t readBMP280Temperature() {
uint8_t rawData[3]; // 20-bit pressure register data stored here
readBytes(BMP280_ADDRESS, BMP280_TEMP_MSB, 3, &rawData[0]);
return (int32_t) (((int32_t) rawData[0] << 16 | (int32_t) rawData[1] << 8 | rawData[2]) >> 4);
}
int32_t readBMP280Pressure() {
uint8_t rawData[3]; // 20-bit pressure register data stored here
readBytes(BMP280_ADDRESS, BMP280_PRESS_MSB, 3, &rawData[0]);
return (int32_t) (((int32_t) rawData[0] << 16 | (int32_t) rawData[1] << 8 | rawData[2]) >> 4);
}
void BMP280Init()
{
// Configure the BMP280
// Set T and P oversampling rates and sensor mode
writeByte(BMP280_ADDRESS, BMP280_CTRL_MEAS, Tosr << 5 | Posr << 2 | Mode);
// Set standby time interval in normal mode and bandwidth
writeByte(BMP280_ADDRESS, BMP280_CONFIG, SBy << 5 | IIRFilter << 2);
// Read and store calibration data
uint8_t calib[24];
readBytes(BMP280_ADDRESS, BMP280_CALIB00, 24, &calib[0]);
dig_T1 = (uint16_t)(((uint16_t) calib[1] << 8) | calib[0]);
dig_T2 = ( int16_t)((( int16_t) calib[3] << 8) | calib[2]);
dig_T3 = ( int16_t)((( int16_t) calib[5] << 8) | calib[4]);
dig_P1 = (uint16_t)(((uint16_t) calib[7] << 8) | calib[6]);
dig_P2 = ( int16_t)((( int16_t) calib[9] << 8) | calib[8]);
dig_P3 = ( int16_t)((( int16_t) calib[11] << 8) | calib[10]);
dig_P4 = ( int16_t)((( int16_t) calib[13] << 8) | calib[12]);
dig_P5 = ( int16_t)((( int16_t) calib[15] << 8) | calib[14]);
dig_P6 = ( int16_t)((( int16_t) calib[17] << 8) | calib[16]);
dig_P7 = ( int16_t)((( int16_t) calib[19] << 8) | calib[18]);
dig_P8 = ( int16_t)((( int16_t) calib[21] << 8) | calib[20]);
dig_P9 = ( int16_t)((( int16_t) calib[23] << 8) | calib[22]);
}
// Returns temperature in DegC, resolution is 0.01 DegC. Output value of
// “5123” equals 51.23 DegC.
int32_t bmp280_compensate_T(int32_t adc_T)
{
int32_t var1, var2, T;
var1 = ((((adc_T >> 3) - ((int32_t)dig_T1 << 1))) * ((int32_t)dig_T2)) >> 11;
var2 = (((((adc_T >> 4) - ((int32_t)dig_T1)) * ((adc_T >> 4) - ((int32_t)dig_T1))) >> 12) * ((int32_t)dig_T3)) >> 14;
t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
return T;
}
// Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8
//fractional bits).
//Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
uint32_t bmp280_compensate_P(int32_t adc_P)
{
long long var1, var2, p;
var1 = ((long long)t_fine) - 128000;
var2 = var1 * var1 * (long long)dig_P6;
var2 = var2 + ((var1*(long long)dig_P5)<<17);
var2 = var2 + (((long long)dig_P4)<<35);
var1 = ((var1 * var1 * (long long)dig_P3)>>8) + ((var1 * (long long)dig_P2)<<12);
var1 = (((((long long)1)<<47)+var1))*((long long)dig_P1)>>33;
if(var1 == 0)
{
return 0;
// avoid exception caused by division by zero
}
p = 1048576 - adc_P;
p = (((p<<31) - var2)*3125)/var1;
var1 = (((long long)dig_P9) * (p>>13) * (p>>13)) >> 25;
var2 = (((long long)dig_P8) * p)>> 19;
p = ((p + var1 + var2) >> 8) + (((long long)dig_P7)<<4);
return (uint32_t)p;
}
// I2C scan function
void I2Cscan() {
// scan for i2c devices
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
Serial.print("I2C address: ");
Serial.println(address);
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknow error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
}
// I2C read/write functions
void writeByte(uint8_t address, uint8_t subAddress, uint8_t data) {
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.write(data); // Put data in Tx buffer
Wire.endTransmission(); // Send the Tx buffer
}
uint8_t readByte(uint8_t address, uint8_t subAddress) {
uint8_t data; // `data` will store the register data
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive
// Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
// Wire.requestFrom(address, 1); // Read one byte from slave register address
Wire.requestFrom(address, (size_t) 1); // Read one byte from slave register address
data = Wire.read(); // Fill Rx buffer with result
return data; // Return data read from slave register
}
void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest) {
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive
// Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
uint8_t i = 0;
// Wire.requestFrom(address, count); // Read bytes from slave register address
Wire.requestFrom(address, (size_t) count); // Read bytes from slave register address
while (Wire.available()) { // Put read results in the Rx buffer
dest[i++] = Wire.read();
}
}