Skip to content

Commit b2443e6

Browse files
committed
Large overhaul. Add get/set for mode. Add set for oversample. Add ref pressure. Add generic i2c port.
setMode() can now be used to enter one of three modes (sleep, normal, force). Current mode can be read with getMode(). setPressureOversample(), etc used to set oversample rate for pressure, humidity, temp. User can now pass in wire port (eg Wire1, softWire, etc) to beginI2C(). Reference pressure can now be setReferencePressure() for more accurate local altitude.
1 parent 2a4b227 commit b2443e6

File tree

3 files changed

+265
-49
lines changed

3 files changed

+265
-49
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
Get basic environmental readings from the BME280
3+
By: Nathan Seidle
4+
SparkFun Electronics
5+
Date: March 9th, 2018
6+
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
7+
8+
https://github.com/sparkfun/SparkFun_BME280_Arduino_Library
9+
10+
This example shows how to obtain humidity, pressure, and current temperature from the BME280. It
11+
assumes an I2C connection.
12+
13+
Resources:
14+
Uses Wire.h for I2C operation
15+
Uses SPI.h for SPI operation
16+
17+
Development environment specifics:
18+
Arduino IDE 1.8.5
19+
20+
*/
21+
22+
#include "Wire.h"
23+
24+
#include "SparkFunBME280.h"
25+
BME280 mySensor; //Global sensor object
26+
27+
void setup()
28+
{
29+
Serial.begin(9600);
30+
while(!Serial); //Wait for terminal to open
31+
Serial.println("Reading basic values from BME280");
32+
33+
if (mySensor.beginI2C() == false) //Begin communication over I2C
34+
{
35+
Serial.println("The chip did not respond. Please check wiring.");
36+
while(1); //Freeze
37+
}
38+
}
39+
40+
void loop()
41+
{
42+
Serial.print("Humidity: ");
43+
Serial.print(mySensor.readFloatHumidity(), 0);
44+
45+
Serial.print(" Pressure: ");
46+
Serial.print(mySensor.readFloatPressure(), 0);
47+
48+
Serial.print(" Alt: ");
49+
//Serial.print(mySensor.readFloatAltitudeMeters(), 1);
50+
Serial.print(mySensor.readFloatAltitudeFeet(), 1);
51+
52+
Serial.print(" Temp: ");
53+
//Serial.print(mySensor.readTempC(), 2);
54+
Serial.print(mySensor.readTempF(), 2);
55+
56+
Serial.println();
57+
58+
delay(50);
59+
}

src/SparkFunBME280.cpp

Lines changed: 168 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,14 @@ BME280::BME280( void )
4040

4141
//Select interface mode
4242
settings.commInterface = I2C_MODE; //Can be I2C_MODE, SPI_MODE
43+
4344
//Select address for I2C. Does nothing for SPI
4445
settings.I2CAddress = 0x77; //Ignored for SPI_MODE
46+
4547
//Select CS pin for SPI. Does nothing for I2C
4648
settings.chipSelectPin = 10;
47-
settings.runMode = 0;
48-
settings.tempOverSample = 0;
49-
settings.pressOverSample = 0;
50-
settings.humidOverSample = 0;
5149

50+
settings.runMode = 0;
5251
}
5352

5453

@@ -63,13 +62,14 @@ BME280::BME280( void )
6362
//****************************************************************************//
6463
uint8_t BME280::begin()
6564
{
65+
delay(2); //Make sure sensor had enough time to turn on. BME280 requires 2ms to start up.
66+
6667
//Check the settings structure values to determine how to setup the device
67-
uint8_t dataToWrite = 0; //Temporary variable
6868
switch (settings.commInterface)
6969
{
7070

7171
case I2C_MODE:
72-
Wire.begin();
72+
if(_i2cPort != 0) _i2cPort->begin();
7373
break;
7474

7575
case SPI_MODE:
@@ -125,30 +125,141 @@ uint8_t BME280::begin()
125125
calibration.dig_H5 = ((int16_t)((readRegister(BME280_DIG_H5_MSB_REG) << 4) + ((readRegister(BME280_DIG_H4_LSB_REG) >> 4) & 0x0F)));
126126
calibration.dig_H6 = ((int8_t)readRegister(BME280_DIG_H6_REG));
127127

128-
//Set the oversampling control words.
129-
//config will only be writeable in sleep mode, so first insure that.
130-
writeRegister(BME280_CTRL_MEAS_REG, 0x00);
128+
settings.runMode = 3; // 3, Normal mode
129+
settings.tStandby = 0; // 0, 0.5ms
130+
settings.filter = 0; // 0, filter off
131+
132+
setPressureOverSample(1); //Default
133+
setHumidityOverSample(1); //Default
134+
setTempOverSample(1); //Default
135+
136+
setMode(MODE_NORMAL); //Go!
131137

132-
//Set the config word
133-
dataToWrite = (settings.tStandby << 0x5) & 0xE0;
134-
dataToWrite |= (settings.filter << 0x02) & 0x1C;
135-
writeRegister(BME280_CONFIG_REG, dataToWrite);
138+
return(readRegister(BME280_CHIP_ID_REG)); //Should return 0x60
139+
}
140+
141+
//Begin comm with BME280 over I2C
142+
bool BME280::beginI2C(TwoWire &wirePort)
143+
{
144+
_i2cPort = &wirePort;
145+
_i2cPort->begin(); //The caller can begin their port and set the speed. We just confirm it here otherwise it can be hard to debug.
136146

137-
//Set ctrl_hum first, then ctrl_meas to activate ctrl_hum
138-
dataToWrite = settings.humidOverSample & 0x07; //all other bits can be ignored
139-
writeRegister(BME280_CTRL_HUMIDITY_REG, dataToWrite);
147+
settings.commInterface = I2C_MODE;
148+
//settings.I2CAddress = 0x77; //We assume user has set the I2C address using setI2CAddress()
140149

141-
//set ctrl_meas
142-
//First, set temp oversampling
143-
dataToWrite = (settings.tempOverSample << 0x5) & 0xE0;
144-
//Next, pressure oversampling
145-
dataToWrite |= (settings.pressOverSample << 0x02) & 0x1C;
146-
//Last, set mode
147-
dataToWrite |= (settings.runMode) & 0x03;
148-
//Load the byte
149-
writeRegister(BME280_CTRL_MEAS_REG, dataToWrite);
150+
if(begin() == 0x60) return(true); //Begin normal init with these settings. Should return chip ID of 0x60
151+
return(false);
152+
}
153+
154+
//Set the mode bits in the ctrl_meas register
155+
//Mode 00 = Sleep
156+
// 01 and 10 = Forced
157+
// 11 = Normal mode
158+
void BME280::setMode(uint8_t mode)
159+
{
160+
if(mode > 0b11) mode = 0; //Error check. Default to sleep mode
150161

151-
return readRegister(0xD0);
162+
uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG);
163+
controlData &= ~( (1<<1) | (1<<0) ); //Clear the mode[1:0] bits
164+
controlData |= mode; //Set
165+
writeRegister(BME280_CTRL_MEAS_REG, controlData);
166+
}
167+
168+
//Gets the current mode bits in the ctrl_meas register
169+
//Mode 00 = Sleep
170+
// 01 and 10 = Forced
171+
// 11 = Normal mode
172+
uint8_t BME280::getMode()
173+
{
174+
uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG);
175+
return(controlData & 0b11111100); //Mask out all but bits 1 and 0
176+
}
177+
178+
//Set the temperature oversample value
179+
//0 turns off temp sensing
180+
//1 to 16 are valid over sampling values
181+
void BME280::setTempOverSample(uint8_t overSampleAmount)
182+
{
183+
overSampleAmount = checkSampleValue(overSampleAmount); //Error check
184+
185+
uint8_t originalMode = getMode(); //Get the current mode so we can go back to it at the end
186+
187+
setMode(MODE_SLEEP); //Config will only be writeable in sleep mode, so first go to sleep mode
188+
189+
//Set the osrs_t bits (7, 6, 5) to overSampleAmount
190+
uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG);
191+
controlData &= ~( (1<<7) | (1<<6) | (1<<5) ); //Clear bits 765
192+
controlData |= overSampleAmount << 5; //Align overSampleAmount to bits 7/6/5
193+
writeRegister(BME280_CTRL_MEAS_REG, controlData);
194+
195+
setMode(originalMode); //Return to the original user's choice
196+
}
197+
198+
//Set the pressure oversample value
199+
//0 turns off pressure sensing
200+
//1 to 16 are valid over sampling values
201+
void BME280::setPressureOverSample(uint8_t overSampleAmount)
202+
{
203+
overSampleAmount = checkSampleValue(overSampleAmount); //Error check
204+
205+
uint8_t originalMode = getMode(); //Get the current mode so we can go back to it at the end
206+
207+
setMode(MODE_SLEEP); //Config will only be writeable in sleep mode, so first go to sleep mode
208+
209+
//Set the osrs_p bits (4, 3, 2) to overSampleAmount
210+
uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG);
211+
controlData &= ~( (1<<4) | (1<<3) | (1<<2) ); //Clear bits 432
212+
controlData |= overSampleAmount << 2; //Align overSampleAmount to bits 4/3/2
213+
writeRegister(BME280_CTRL_MEAS_REG, controlData);
214+
215+
setMode(originalMode); //Return to the original user's choice
216+
}
217+
218+
//Set the humidity oversample value
219+
//0 turns off humidity sensing
220+
//1 to 16 are valid over sampling values
221+
void BME280::setHumidityOverSample(uint8_t overSampleAmount)
222+
{
223+
overSampleAmount = checkSampleValue(overSampleAmount); //Error check
224+
225+
uint8_t originalMode = getMode(); //Get the current mode so we can go back to it at the end
226+
227+
setMode(MODE_SLEEP); //Config will only be writeable in sleep mode, so first go to sleep mode
228+
229+
//Set the osrs_h bits (2, 1, 0) to overSampleAmount
230+
uint8_t controlData = readRegister(BME280_CTRL_HUMIDITY_REG);
231+
controlData &= ~( (1<<2) | (1<<1) | (1<<0) ); //Clear bits 2/1/0
232+
controlData |= overSampleAmount << 0; //Align overSampleAmount to bits 2/1/0
233+
writeRegister(BME280_CTRL_HUMIDITY_REG, controlData);
234+
235+
setMode(originalMode); //Return to the original user's choice
236+
}
237+
238+
//Validates an over sample value
239+
//Allowed values are 0 to 16
240+
//These are used in the humidty, pressure, and temp oversample functions
241+
uint8_t BME280::checkSampleValue(uint8_t userValue)
242+
{
243+
switch(userValue)
244+
{
245+
case(0): break; //Valid
246+
case(1): break; //Valid
247+
case(2): break; //Valid
248+
case(4): break; //Valid
249+
case(8): break; //Valid
250+
case(16): break; //Valid
251+
default:
252+
userValue = 1; //Default to 1x
253+
break; //Good
254+
}
255+
return(userValue);
256+
}
257+
258+
//Set the global setting for the I2C address we want to communicate with
259+
//Default is 0x77
260+
void BME280::setI2CAddress(uint8_t address)
261+
{
262+
settings.I2CAddress = address; //Set the I2C address for this device
152263
}
153264

154265
//Strictly resets. Run .begin() afterwards
@@ -191,11 +302,25 @@ float BME280::readFloatPressure( void )
191302

192303
}
193304

305+
//Sets the internal variable _referencePressure so the
306+
void BME280::setReferencePressure(float refPressure)
307+
{
308+
_referencePressure = rePressure;
309+
}
310+
311+
//Return the local reference pressure
312+
float BME280::getReferencePressure()
313+
{
314+
return(_referencePressure);
315+
}
316+
317+
318+
194319
float BME280::readFloatAltitudeMeters( void )
195320
{
196321
float heightOutput = 0;
197322

198-
heightOutput = ((float)-45846.2)*(pow(((float)readFloatPressure()/(float)101325), 0.190263) - (float)1);
323+
heightOutput = ((float)-45846.2)*(pow(((float)readFloatPressure()/(float)_referencePressure), 0.190263) - (float)1);
199324
return heightOutput;
200325

201326
}
@@ -287,15 +412,15 @@ void BME280::readRegisterRegion(uint8_t *outputPointer , uint8_t offset, uint8_t
287412
{
288413

289414
case I2C_MODE:
290-
Wire.beginTransmission(settings.I2CAddress);
291-
Wire.write(offset);
292-
Wire.endTransmission();
415+
_i2cPort->beginTransmission(settings.I2CAddress);
416+
_i2cPort->write(offset);
417+
_i2cPort->endTransmission();
293418

294419
// request bytes from slave device
295-
Wire.requestFrom(settings.I2CAddress, length);
296-
while ( (Wire.available()) && (i < length)) // slave may send less than requested
420+
_i2cPort->requestFrom(settings.I2CAddress, length);
421+
while ( (_i2cPort->available()) && (i < length)) // slave may send less than requested
297422
{
298-
c = Wire.read(); // receive a byte as character
423+
c = _i2cPort->read(); // receive a byte as character
299424
*outputPointer = c;
300425
outputPointer++;
301426
i++;
@@ -332,14 +457,14 @@ uint8_t BME280::readRegister(uint8_t offset)
332457
switch (settings.commInterface) {
333458

334459
case I2C_MODE:
335-
Wire.beginTransmission(settings.I2CAddress);
336-
Wire.write(offset);
337-
Wire.endTransmission();
460+
_i2cPort->beginTransmission(settings.I2CAddress);
461+
_i2cPort->write(offset);
462+
_i2cPort->endTransmission();
338463

339-
Wire.requestFrom(settings.I2CAddress, numBytes);
340-
while ( Wire.available() ) // slave may send less than requested
464+
_i2cPort->requestFrom(settings.I2CAddress, numBytes);
465+
while ( _i2cPort->available() ) // slave may send less than requested
341466
{
342-
result = Wire.read(); // receive a byte as a proper uint8_t
467+
result = _i2cPort->read(); // receive a byte as a proper uint8_t
343468
}
344469
break;
345470

@@ -375,10 +500,10 @@ void BME280::writeRegister(uint8_t offset, uint8_t dataToWrite)
375500
{
376501
case I2C_MODE:
377502
//Write the byte
378-
Wire.beginTransmission(settings.I2CAddress);
379-
Wire.write(offset);
380-
Wire.write(dataToWrite);
381-
Wire.endTransmission();
503+
_i2cPort->beginTransmission(settings.I2CAddress);
504+
_i2cPort->write(offset);
505+
_i2cPort->write(dataToWrite);
506+
_i2cPort->endTransmission();
382507
break;
383508

384509
case SPI_MODE:

0 commit comments

Comments
 (0)