BME280 with STM32

Few month ago I covered a tutorial on BME180 sensor, and a lot of you guys requested me to do the same for BME280. So today this tutorial covers the BME280 sensor with STM32. We will cover the temperature, pressure and humidity using the ST’s HAL library.

Description

BME280 can operate in 3 different modes

  • Sleep Mode
  • Forced Mode
  • Normal Mode

In Sleep mode, no measurements are performed and the power consumption is minimum. All the Registers are accessible, and we can read or modify them.

In forced mode, the sensor performs a single measurement and goes back to sleep. the measurement results can be obtained from the data registers.
For the next measurement, the Forced mode needs to be selected again.

In Normal mode, the BME280 does not go to the sleep. It perpetuates between the measurement and the standby. This mode is often used when the data is continuously required, for eg in case of gaming, or monitoring the room.


Measurement

Humidity Measurement can be enabled or skipped. When enabled, several oversampling options exist.

The humidity measurement is controlled by the osrs_h[2:0] (ctrl_hum Register) setting, which is shown below. For the humidity measurement, oversampling is possible to reduce the noise. The resolution of the humidity measurement is fixed at 16 bit ADC output.

Pressure measurement can be enabled or skipped. When enabled, several oversampling options exist.

The pressure measurement is controlled by the osrs_p[2:0] (ctrl_meas Register) setting which is shown below. For the pressure measurement, oversampling is possible to reduce the noise. The resolution of the pressure data depends on the IIR filter and the oversampling setting:
• When the IIR filter is enabled, the pressure resolution is 20 bit.
• When the IIR filter is disabled, the pressure resolution is 16 + (osrs_p – 1) bit, e.g. 18 bit when osrs_p is set to ‘3’.

Similarly, the Temperature measurement Register is shown below. The resolution of the Temperature is similar to that of the Pressure measurement.


Configuration

The “config” register sets the rate, filter and interface options of the device. Writes to the “config” register in normal mode may be ignored but In sleep mode writes are not ignored.

Here we set the standby time for the normal mode (Bits 7,6,5) and the IIR Filter Coefficients (Bits 4,3,2). This will be shown in the next section, where I will show the code.

Standby time combines with the Measurement time and together they are responsible for the cycle time (output data rate).


Connection

The connection is pretty simple. Connect the SCK to PB6 (SCL) and SDI to PB7 (SDA). The board is powered by 3.3V.

Note here that the SDO is connected to the ground. This is a important parameter while using the I2C for communication.

As mentioned in the datasheet, the address of the BME280 is 111011X0 and here X is determined by the SDO pin. Since I have connected it to the ground, the address in my case would be 11101100 that is 0xEC.



Some Insight into the code

int BME280_Config (uint8_t osrs_t, uint8_t osrs_p, uint8_t osrs_h, uint8_t mode, uint8_t t_sb, uint8_t filter)
{
	// Read the Trimming parameters
	TrimRead();


	uint8_t datatowrite = 0;
	uint8_t datacheck = 0;

	// Reset the device
	datatowrite = 0xB6;  // reset sequence
	if (HAL_I2C_Mem_Write(BME280_I2C, BME280_ADDRESS, RESET_REG, 1, &datatowrite, 1, 1000) != HAL_OK)
	{
		return -1;
	}

	HAL_Delay (100);


	// write the humidity oversampling to 0xF2
	datatowrite = osrs_h;
	if (HAL_I2C_Mem_Write(BME280_I2C, BME280_ADDRESS, CTRL_HUM_REG, 1, &datatowrite, 1, 1000) != HAL_OK)
	{
		return -1;
	}
	HAL_Delay (100);
	HAL_I2C_Mem_Read(BME280_I2C, BME280_ADDRESS, CTRL_HUM_REG, 1, &datacheck, 1, 1000);
	if (datacheck != datatowrite)
	{
		return -1;
	}


	// write the standby time and IIR filter coeff to 0xF5
	datatowrite = (t_sb <<5) |(filter << 2);
	if (HAL_I2C_Mem_Write(BME280_I2C, BME280_ADDRESS, CONFIG_REG, 1, &datatowrite, 1, 1000) != HAL_OK)
	{
		return -1;
	}
	HAL_Delay (100);
	HAL_I2C_Mem_Read(BME280_I2C, BME280_ADDRESS, CONFIG_REG, 1, &datacheck, 1, 1000);
	if (datacheck != datatowrite)
	{
		return -1;
	}


	// write the pressure and temp oversampling along with mode to 0xF4
	datatowrite = (osrs_t <<5) |(osrs_p << 2) | mode;
	if (HAL_I2C_Mem_Write(BME280_I2C, BME280_ADDRESS, CTRL_MEAS_REG, 1, &datatowrite, 1, 1000) != HAL_OK)
	{
		return -1;
	}
	HAL_Delay (100);
	HAL_I2C_Mem_Read(BME280_I2C, BME280_ADDRESS, CTRL_MEAS_REG, 1, &datacheck, 1, 1000);
	if (datacheck != datatowrite)
	{
		return -1;
	}

	return 0;
}

BME280 Config configures the oversampling, mode, standby time and filter configuration.

  • First of all it will read the Trimming parameters. These values are stored in the Non Volatile Memory of the device, and they remain unchanged.
    We use these values along with the RAW data to get the accurate results.
  • After reading the Trimming values, it resets the device once. To do so, we write 0xB6 to the Reset Register (0xE0)
  • After resetting, we write the oversampling data for the Humidity. This is done in the ctrl_hum Register (0xF2)
  • Next we set the IIR Filter Coefficient and Standby Time in the config Register (0xF5). The standby time starts at the 5th bit of the config register and this is why I have shifted the data by 5. Similarly the filter coefficient is shifted by 2.
  • At last we will modify the ctrl_meas Register (0xF4). Here we will set the oversampling data for the pressure and temperature along with the working mode for the device.
    The pressure oversampling data has been shifted by 2 as the it starts at the 2nd bit. Similarly the temperature data is shifted by 5. The first 2 bits (1:0) of the ctrl_meas Register controls the mode.

int BMEReadRaw(void)
{
	uint8_t RawData[8];

	// Check the chip ID before reading
	HAL_I2C_Mem_Read(&hi2c1, BME280_ADDRESS, ID_REG, 1, &chipID, 1, 1000);

	if (chipID == 0x60)
	{
		// Read the Registers 0xF7 to 0xFE
		HAL_I2C_Mem_Read(BME280_I2C, BME280_ADDRESS, PRESS_MSB_REG, 1, RawData, 8, HAL_MAX_DELAY);

		/* Calculate the Raw data for the parameters
		 * Here the Pressure and Temperature are in 20 bit format and humidity in 16 bit format
		 */
		pRaw = (RawData[0]<<12)|(RawData[1]<<4)|(RawData[2]>>4);
		tRaw = (RawData[3]<<12)|(RawData[4]<<4)|(RawData[5]>>4);
		hRaw = (RawData[6]<<8)|(RawData[7]);

		return 0;
	}

	else return -1;
}

BMEReadRaw Reads the Raw Temperature, Humidity and Pressure data from the Sensor.

  • It first checks the ID of the device by reading the ID Register (0xD0).
  • If the ID is 0x60, it continues reading the RAW data by reading the 8 bytes starting from PRESS_MSB_REG (0xF2)
  • Out of these 8 bytes, 3 Bytes are used by Pressure (20 Bits in total), 3 Bytes by Temperature, and the last 2 bytes by Humidity.
  • Here we combine these data and store them in 32 bit signed integers, pRaw, tRaw and hRaw.

In order to calculate the actual Temperature, Pressure and Humidity, we use the Compensation formulas. These formulas are defined on page number 25 of the datasheet.

The pRaw, tRaw and hRaw we calculated above is fed to these formulas, and the respective Pressure, Temperature and Humidity values are obtained.


void BME280_Measure (void)
{
	if (BMEReadRaw() == 0)
	{
		  if (tRaw == 0x800000) Temperature = 0; // value in case temp measurement was disabled
		  else
		  {
			  Temperature = (BME280_compensate_T_int32 (tRaw))/100.0;  // as per datasheet, the temp is x100
		  }

		  if (pRaw == 0x800000) Pressure = 0; // value in case temp measurement was disabled
		  else
		  {
#if SUPPORT_64BIT
			  Pressure = (BME280_compensate_P_int64 (pRaw))/256.0;  // as per datasheet, the pressure is x256

#elif SUPPORT_32BIT
			  Pressure = (BME280_compensate_P_int32 (pRaw));  // as per datasheet, the pressure is Pa

#endif
		  }

		  if (hRaw == 0x8000) Humidity = 0; // value in case temp measurement was disabled
		  else
		  {
			  Humidity = (bme280_compensate_H_int32 (hRaw))/1024.0;  // as per datasheet, the temp is x1024
		  }
	}


	// if the device is detached
	else
	{
		Temperature = Pressure = Humidity = 0;
	}
}

BME280_Measure measures the three parameters.

  • It first read the RAW values using the BMEReadRaw function
  • If either of the parameters are skipped (oversampling is set to 0), the value returned will be 0x800000 (or 0x8000 in case of humidity)
    In that case, the value will be set to 0 for the respective parameter.
  • Otherwise the compensation formulas are used to calculate the accurate values of the parameters.

The main function

float Temperature, Pressure, Humidity;

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_I2C1_Init();

  BME280_Config(OSRS_2, OSRS_16, OSRS_1, MODE_NORMAL, T_SB_0p5, IIR_16);

  while (1)
  {
	  BME280_Measure();
	  HAL_Delay (500);
  }
}
  • Here first of all we have to define the variables as the float.
  • Inside the main function call the MBE280_Config function.
  • Here I am setting the oversampling for temperature to 2, pressure to 16 and humidity to 1. Also the mode is normal mode, the standby time is 0.5ms and the IIR filter coefficient is 16.
  • The values I have used are from the example in the datasheet. You can see the image below
  • Inside the while loop, we call the BME280_Measure function and it does the rest of the measurement and store the values in the variables that we defined earlier.


Result

Below is the image showing the values of all three parameters.

Check out the VIDEO Below



DOWNLOAD

You can buy me a coffee Sensor by clicking DONATE OR Just click DOWNLOAD to download the code

controllerstech

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
Menu