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










Info

You can help with the development by DONATING
To download the code, click DOWNLOAD button and view the Ad. The project will download after the Ad is finished.

12 Comments. Leave new

  • Talha bin Irfan
    March 2, 2024 10:07 PM

    Hello Sir can you address me how do i integrate turbidity and ph sensor with stm32Wl55j1 microcontroller.They both give analogue output,i tried them by accessing adc pin of stm32 but not getting answer.Kindly guide me regarding this.

    Reply
  • Hello I am using the STM32L476RG with a BME280 but all values are zero, do you know how to fix it? In the debugger there are no warnings/errors. I am sure all the connections are right and I am using 4.7k resistor.

    Reply
  • Hello would you be able to do this tutorial for a STM32 Nucleo L476RG with the BME280? I am having issues with it not working and I simply can not figure it out

    Reply
    • Read the ID first to check if the connection is OK. If it doesn’t respond, try using 4.7K pull up resistors to the SCL and SDA Lines.

      Reply
  • do you know why it doesn’t work on STM32L476?

    Reply
  • thanks for all that
    actually i’ll be happier if you connect BME688 sensor to an stm32 board.

    Reply
  • Thamanoon Kedwiriyakarn
    April 24, 2023 9:29 AM

    Hellow, thak you very much for your tutorials.

    Reply
  • Harshesh Shah
    April 22, 2023 7:38 PM

    can anybody help me to perform SPI protocol.

    Reply
  • Has anyone been successful with the 32-bit code? My pressure measurements are about 20% too low (displaying around 827 hPa when its actually around 1013hPs0. I get the same results with the code from the Bosch Github site. Used two different sensors, same results. Clues welcome.

    Reply
    • Im having the same problem. I tested the Adafruit lib and there is everything ok. Theres something wrong with the SPI interface.

      Reply
  • works 🙂 thank you!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

keyboard_arrow_up

Adblocker detected! Please consider reading this notice.

We've detected that you are using AdBlock Plus or some other adblocking software which is preventing the page from fully loading.

We don't have any banner, Flash, animation, obnoxious sound, or popup ad. We do not implement these annoying types of ads!

We need money to operate the site, and almost all of it comes from our online advertising.

Please add controllerstech.com to your ad blocking whitelist or disable your adblocking software.

×