- // Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
- // t_fine carries fine temperature as global value
- BMP280_S32_t t_fine;
- BMP280_S32_t bmp280_compensate_T_int32(BMP280_S32_t adc_T)
- {
- BMP280_S32_t var1, var2, T;
- var1 = ((((adc_T>>3) – ((BMP280_S32_t)dig_T1<<1))) * ((BMP280_S32_t)dig_T2)) >> 11;
- var2 = (((((adc_T>>4) – ((BMP280_S32_t)dig_T1)) * ((adc_T>>4) – ((BMP280_S32_t)dig_T1))) >> 12) *
- ((BMP280_S32_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. Output value of “96386” equals 96386 Pa = 963.86 hPa
- BMP280_U32_t bmp280_compensate_P_int32(BMP280_S32_t adc_P)
- {
- BMP280_S32_t var1, var2;
- BMP280_U32_t p;
- var1 = (((BMP280_S32_t)t_fine)>>1) – (BMP280_S32_t)64000;
- var2 = (((var1>>2) * (var1>>2)) >> 11 ) * ((BMP280_S32_t)dig_P6);
- var2 = var2 + ((var1*((BMP280_S32_t)dig_P5))<<1);
- var2 = (var2>>2)+(((BMP280_S32_t)dig_P4)<<16);
- var1 = (((dig_P3 * (((var1>>2) * (var1>>2)) >> 13 )) >> 3) + ((((BMP280_S32_t)dig_P2) * var1)>>1))>>18;
- var1 =((((32768+var1))*((BMP280_S32_t)dig_P1))>>15);
- if (var1 == 0)
- {
- return 0; // avoid exception caused by division by zero
- }
- p = (((BMP280_U32_t)(((BMP280_S32_t)1048576)-adc_P)-(var2>>12)))*3125;
- if (p < 0x80000000)
- {
- p = (p << 1) / ((BMP280_U32_t)var1);
- }
- else
- {
- p = (p / (BMP280_U32_t)var1) * 2;
- }
- var1 = (((BMP280_S32_t)dig_P9) * ((BMP280_S32_t)(((p>>3) * (p>>3))>>13)))>>12;
- var2 = (((BMP280_S32_t)(p>>2)) * ((BMP280_S32_t)dig_P8))>>13;
- p = (BMP280_U32_t)((BMP280_S32_t)p + ((var1 + var2 + dig_P7) >> 4));
- return p;
- }
5.代码编写
5.1创建定时器及读取线程
在FreeRTOS例程中增加软件定时器和读取线程,实现如下:
- envirThreadID = osThreadNew(Environ_Thread, NULL, &envirThreadattr);
- if (envirThreadID == NULL)
- {
- printf("Create environment thread failed!\r\n");
- }
- timerid_2 = osTimerNew(Timer2_CallBack, osTimerPeriodic, NULL, NULL);
- if(NULL != timerid_2) {
- ret = osTimerStart(timerid_2, 2000);
- if(osOK != ret) {
- printf("Create timer2 failed!\r\n");
- }
- }
- void Timer2_CallBack(void *arg)
- {
- UNUSED(arg);
- static uint8_t toggle = 0;
- toggle = !toggle;
- osThreadFlagsSet(envirThreadID, 0x00000001);
- }
- void Environ_Thread(void *argument)
- {
- UNUSED(argument);
- volatile uint32_t env_flags = 0;
- volatile uint32_t env_times = 0;
- int32_t adc_temp, adc_pres, temp, temp_fine;
- uint32_t barometer;
- BMP280_trimming_param bmp280_trim = {0};
- bmp280_reset(BMP280_I2C_ADDR);
- osDelay(5);
- bmp280_init(BMP280_I2C_ADDR, &bmp280_trim);
- while (1)
- {
- env_times++;
- env_flags = osThreadFlagsWait(0x00000001, osFlagsWaitAny, osWaitForever);
- osThreadFlagsClear(env_flags);
- bmp280_force_convert(BMP280_I2C_ADDR, BMP280_OSRS_X2, BMP280_OSRS_X16);
- osDelay(50);
- bmp280_read_adc(BMP280_I2C_ADDR, &adc_pres, &adc_temp);
- temp = bmp280_calc_temperature(&temp_fine, adc_temp, &bmp280_trim);
- barometer = bmp280_calc_barometer(&temp_fine, adc_pres, &bmp280_trim);
- printf("Envir->baro(hPa)temp(C):%.2f,%.1f\n", (double)barometer / 100.0, (double)temp / 100.0);
- }
- }
5.2复位初始化
对BMP280的复位操作只需要在线程开始入口处执行一次,实现如下:
- int8_t bmp280_reset(uint8_t addr)
- {
- uint8_t rx_data;
- I2C_DMA_Write_Byte_Data(addr, BMP280_REG_RESET, 0xB6);
- osDelay(10);
- I2C_DMA_Read_Byte(addr, BMP280_REG_ID, &rx_data);
- printf("BMP280 ID:0x%02X\r\n", rx_data);
- return 0;
- }
5.3开启测量转换
在线程循环中周期触发转换,实现如下:
- int8_t bmp280_force_convert(uint8_t addr, uint8_t osrs_t, uint8_t osrs_p)
- {
- uint8_t ctrl_meas = ((osrs_t & 0x07) << 5) | ((osrs_p & 0x07) << 2) | BMP280_MODE_FORCE;
- uint8_t rx_data = 0;
- I2C_DMA_Write_Byte_Data(addr, BMP280_REG_CTRL_MEAS, ctrl_meas);
- I2C_DMA_Read_Byte(addr, BMP280_REG_ID, &rx_data);
- if((rx_data & 0xFC) == (ctrl_meas & 0xFC)) {
- return 0;
- }
- else {
- return -1;
- }
- }
5.4读取转换值并计算
在触发转换后等待转换完成,然后读取转换结果并计算温度和气压,具体实现如下:
- int8_t bmp280_read_adc(uint8_t addr, int32_t* adc_pres, int32_t* adc_temp)
- {
- uint8_t rx_data[6] = {0};
- I2C_DMA_Read_Bytes(addr, BMP280_REG_PRESS_VAL, rx_data, 6);
- *adc_pres = (int32_t)(rx_data[0] << 12) | (rx_data[1] << 4) | (rx_data[2] >> 4);
- *adc_temp = (int32_t)(rx_data[3] << 12) | (rx_data[4] << 4) | (rx_data[5] >> 4);
- if((0x80000 == *adc_pres) || (0x80000 == *adc_temp)) {
- printf("bmp280 read invalid value\r\n");
- return -1;
- }
- else {
- return 0;
- }
- }
- int32_t bmp280_calc_temperature(int32_t *temp_fine, int32_t adc_temp, BMP280_trimming_param *ptr_trim)
- {
- int32_t var1, var2, temperature;
- var1 = ((((adc_temp >> 3) - ((int32_t)ptr_trim->dig_t1 << 1))) * ((int32_t)ptr_trim->dig_t2)) >> 11;
- var2 = (((((adc_temp >> 4) - ((int32_t)ptr_trim->dig_t1)) * ((adc_temp >> 4) - ((int32_t)ptr_trim->dig_t1))) >> 12) * ((int32_t)ptr_trim->dig_t3)) >> 14;
- *temp_fine = var1 + var2;
- temperature = (*temp_fine * 5 + 128) >> 8;
- return temperature;
- }
- uint32_t bmp280_calc_barometer(const int32_t *temp_fine, int32_t adc_pres, BMP280_trimming_param *ptr_trim)
- {
- int32_t pvar1, pvar2;
- uint32_t baro;
- pvar1 = (*temp_fine >> 1) - (int32_t)64000;
- pvar2 = (((pvar1 >> 2) * (pvar1 >> 2)) >> 11) * ((int32_t)ptr_trim->dig_p6);
- pvar2 = pvar2 + ((pvar1 * ((int32_t)ptr_trim->dig_p5)) << 1);
- pvar2 = (pvar2 >> 2) + (((int32_t)ptr_trim->dig_p4) << 16);
- pvar1 = (((ptr_trim->dig_p3 * (((pvar1 >> 2) * (pvar1 >> 2)) >> 13)) >> 3) + ((((int32_t)ptr_trim->dig_p2) * pvar1) >> 1)) >> 18;
- pvar1 = (((32768 + pvar1) * (int32_t)ptr_trim->dig_p1) >> 15);
- if(0 != pvar1) {
- baro = ((int32_t)(((int32_t)1048576) - adc_pres) - (pvar2 >> 12)) * 3125;
- if(baro <= 0x80000000) {
- baro = (baro << 1) / (uint32_t)pvar1;
- }
- else {
- baro = (baro / (uint32_t)pvar1) * 2;
- }
- pvar1 = (((int32_t)ptr_trim->dig_p9) * ((int32_t)(((baro >> 3) * (baro >>3)) >> 13))) >> 12;
- pvar2 = (((int32_t)(baro >> 2)) * (int32_t)ptr_trim->dig_p8) >> 13;
- baro = (uint32_t)((int32_t)baro + ((pvar1 + pvar2 + ptr_trim->dig_p7) >> 4));
- }
- else{
- baro = 0;
- }
- return baro;
- }
6.结果展示
在串口日志中可以看到在周期性的打印温度和气压值。
bmp08