STM32F1与STM32CubeIDE编程实例-BMP280气压温度传感器驱动

BMP280气压温度传感器驱动

1、BMP280介绍

BMP280 是一款专为移动应用设计的绝对气压传感器。 传感器模块采用极其紧凑的封装。 它的小尺寸和低功耗允许在手机、GPS 模块或手表等电池供电的设备中实施。

作为其前身 BMP180,BMP280 基于博世久经考验的压阻式压力传感器技术,具有高精度和线性度以及长期稳定性和高 EMC 鲁棒性。 众多设备操作选项提供了最高的灵活性,可针对功耗、分辨率和滤波器性能优化设备。 为开发人员提供了一组经过测试的默认设置(例如用例),以使设计尽可能简单。

在这里插入图片描述

BMP有如下特性:

  • 操作范围(全精度):
    • 压力:300…1100 hPa
    • 温度:-40…85°C
  • 绝对精度(Temp. @0…65°C):~ ±1 hPa
  • 相对精度(p = 700…900hPa,Temp. @ +25…+40°C):± 0.12 hPa (典型),相当于±1 m
  • 平均电流消耗(1 Hz 数据刷新率):2.74 μA,典型值(超低功耗模式)
  • 睡眠模式下的平均电流消耗:0.1 μA
  • 平均测量时间:5.5 msec,(超低功耗预设)
  • 电源电压 VDDIO:1.2 … 3.6 V
  • 电源电压 VDD:1.71 … 3.6 V
  • 数据分辨率:
    • 压力:0.01 hPa (< 10 cm)
    • 温度:0.01°C
  • 温度系数偏移(+25°…+40°C @900hPa):± 0.12 hPa(典型)相当于 ±1 m
  • 接口:I2C或SPI

2、BMP280配置

关于STM32CubeIDE工程创建、配置请参考前面文章:

本次BMP280的配置如下:

在这里插入图片描述

3、BMP280驱动实现

1)BMP280驱动基本定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#ifndef \_\_BMP280\_H\_\_
#define \_\_BMP280\_H\_\_

#include "stm32f1xx\_hal.h"
#include <stdint.h>
#include <stdbool.h>

/\*\*
\* BMP280 寄存器
\*/
#define BMP280\_REG\_TEMP\_XLSB 0xFC /\* bits: 7-4 \*/
#define BMP280\_REG\_TEMP\_LSB 0xFB
#define BMP280\_REG\_TEMP\_MSB 0xFA
#define BMP280\_REG\_TEMP (BMP280\_REG\_TEMP\_MSB)
#define BMP280\_REG\_PRESS\_XLSB 0xF9 /\* bits: 7-4 \*/
#define BMP280\_REG\_PRESS\_LSB 0xF8
#define BMP280\_REG\_PRESS\_MSB 0xF7
#define BMP280\_REG\_PRESSURE (BMP280\_REG\_PRESS\_MSB)
#define BMP280\_REG\_CONFIG 0xF5 /\* bits: 7-5 t\_sb; 4-2 filter; 0 spi3w\_en \*/
#define BMP280\_REG\_CTRL 0xF4 /\* bits: 7-5 osrs\_t; 4-2 osrs\_p; 1-0 mode \*/
#define BMP280\_REG\_STATUS 0xF3 /\* bits: 3 measuring; 0 im\_update \*/
#define BMP280\_REG\_CTRL\_HUM 0xF2 /\* bits: 2-0 osrs\_h; \*/
#define BMP280\_REG\_RESET 0xE0
#define BMP280\_REG\_ID 0xD0
#define BMP280\_REG\_CALIB 0x88
#define BMP280\_REG\_HUM\_CALIB 0x88

#define BMP280\_RESET\_VALUE 0xB6



#define BMP280\_I2C\_ADDRESS\_0 (0x76) // SD0为低电平时地址
#define BMP280\_I2C\_ADDRESS\_1 (0x77) // SD0为高电平时地址

#define BMP280\_CHIP\_ID 0x58 /\* BMP280 芯片ID 0x58 \*/
#define BME280\_CHIP\_ID 0x60 /\* BME280 芯片ID 0x60 \*/

/\*\*
\* BMP280操作模式.
\* Forced - 测量由用户发起
\* Normal - 连续测量
\*/
typedef enum {
BMP280_MODE_SLEEP = 0,
BMP280_MODE_FORCED = 1,
BMP280_MODE_NORMAL = 3
} BMP280_Mode;

typedef enum {
BMP280_FILTER_OFF = 0,
BMP280_FILTER_2 = 1,
BMP280_FILTER_4 = 2,
BMP280_FILTER_8 = 3,
BMP280_FILTER_16 = 4
} BMP280_Filter;

/\*\*
\* 气压过采样类型
\*/
typedef enum {
BMP280_SKIPPED = 0, /\* 无测量 \*/
BMP280_ULTRA_LOW_POWER = 1, /\* 采样 x1 \*/
BMP280_LOW_POWER = 2, /\* 采样 x2 \*/
BMP280_STANDARD = 3, /\* 采样 x4 \*/
BMP280_HIGH_RES = 4, /\* 采样 x8 \*/
BMP280_ULTRA_HIGH_RES = 5 /\* 采样 x16 \*/
} BMP280_Oversampling;

/\*\*
\*正常模式下测量之间的待机时间
\*/
typedef enum {
BMP280_STANDBY_05 = 0, /\* 待机时间 0.5ms \*/
BMP280_STANDBY_62 = 1, /\* 待机时间 62.5ms \*/
BMP280_STANDBY_125 = 2, /\* 待机时间 125ms \*/
BMP280_STANDBY_250 = 3, /\* 待机时间 250ms \*/
BMP280_STANDBY_500 = 4, /\* 待机时间 500ms \*/
BMP280_STANDBY_1000 = 5, /\*待机时间 1s \*/
BMP280_STANDBY_2000 = 6, /\* 待机时间 2s BMP280, 10ms BME280 \*/
BMP280_STANDBY_4000 = 7, /\*待机时间 4s BMP280, 20ms BME280 \*/
} BMP280_StandbyTime;

/\*\*
\* BMP280配置参数
\*/
typedef struct {
BMP280_Mode mode;
BMP280_Filter filter;
BMP280_Oversampling oversampling_pressure;
BMP280_Oversampling oversampling_temperature;
BMP280_Oversampling oversampling_humidity;
BMP280_StandbyTime standby;
} bmp280\_params\_t;


typedef struct {
uint16\_t dig_T1;
int16\_t dig_T2;
int16\_t dig_T3;
uint16\_t dig_P1;
int16\_t dig_P2;
int16\_t dig_P3;
int16\_t dig_P4;
int16\_t dig_P5;
int16\_t dig_P6;
int16\_t dig_P7;
int16\_t dig_P8;
int16\_t dig_P9;

/\* BME280 的湿度补偿 \*/
uint8\_t dig_H1;
int16\_t dig_H2;
uint8\_t dig_H3;
int16\_t dig_H4;
int16\_t dig_H5;
int8\_t dig_H6;

uint16\_t addr;

I2C_HandleTypeDef\* i2c;

bmp280\_params\_t params;

uint8\_t id; /\* Chip ID \*/

} bmp280\_t;

2)BMP280驱动接口基本定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/\*\*
\*初始化默认参数.
\* 默认参数:
\* 模式: NORAML
\* 滤波器: OFF
\* 过采样: x4
\* 等待机时间: 250ms
\*/
void bmp280\_init\_default\_params(bmp280\_params\_t \*params);

/\*\*
\* BMP280初始化
\*/
bool bmp280\_init(bmp280\_t \*dev, bmp280\_params\_t \*params);

bool bmp280\_force\_measurement(bmp280\_t \*dev);
bool bmp280\_is\_measuring(bmp280\_t \*dev);
bool bmp280\_read\_fixed(bmp280\_t \*dev, int32\_t \*temperature,uint32\_t \*pressure, uint32\_t \*humidity);
bool bmp280\_read\_float(bmp280\_t \*dev, float \*temperature,float \*pressure, float \*humidity);
bool bmp280\_is\_ready(bmp280\_t \*dev);

3)BMP280驱动定辅助函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// 读取16位寄存值
static bool read\_register16(bmp280\_t \*dev, uint8\_t addr, uint16\_t \*value) {
uint16\_t tx_buff;
uint8\_t rx_buff[2];
tx_buff = (dev->addr << 1);

if (HAL\_I2C\_Mem\_Read(dev->i2c, tx_buff, addr, 1, rx_buff, 2, 5000)
== HAL_OK) {
\*value = (uint16\_t) ((rx_buff[1] << 8) | rx_buff[0]);
return true;
} else
return false;

}

// 判断BMP180设备是否就绪
bool bmp280\_is\_ready(bmp280\_t \*dev){
return HAL\_I2C\_IsDeviceReady(dev->i2c, dev->addr, 1, 1000);
}

// 读取数据
static inline int read\_data(bmp280\_t \*dev, uint8\_t addr, uint8\_t \*value,
uint8\_t len) {
uint16\_t tx_buff;
tx_buff = (dev->addr << 1);
if (HAL\_I2C\_Mem\_Read(dev->i2c, tx_buff, addr, 1, value, len, 5000) == HAL_OK)
return 0;
else
return 1;
}

// 读取校准数据
static bool read\_calibration\_data(bmp280\_t \*dev) {

if (read\_register16(dev, 0x88, &dev->dig_T1)
&& read\_register16(dev, 0x8a, (uint16\_t \*) &dev->dig_T2)
&& read\_register16(dev, 0x8c, (uint16\_t \*) &dev->dig_T3)
&& read\_register16(dev, 0x8e, &dev->dig_P1)
&& read\_register16(dev, 0x90, (uint16\_t \*) &dev->dig_P2)
&& read\_register16(dev, 0x92, (uint16\_t \*) &dev->dig_P3)
&& read\_register16(dev, 0x94, (uint16\_t \*) &dev->dig_P4)
&& read\_register16(dev, 0x96, (uint16\_t \*) &dev->dig_P5)
&& read\_register16(dev, 0x98, (uint16\_t \*) &dev->dig_P6)
&& read\_register16(dev, 0x9a, (uint16\_t \*) &dev->dig_P7)
&& read\_register16(dev, 0x9c, (uint16\_t \*) &dev->dig_P8)
&& read\_register16(dev, 0x9e,
(uint16\_t \*) &dev->dig_P9)) {

return true;
}

return false;
}

// 读取湿度校准数据
static bool read\_hum\_calibration\_data(bmp280\_t \*dev) {
uint16\_t h4, h5;

if (!read\_data(dev, 0xa1, &dev->dig_H1, 1)
&& read\_register16(dev, 0xe1, (uint16\_t \*) &dev->dig_H2)
&& !read\_data(dev, 0xe3, &dev->dig_H3, 1)
&& read\_register16(dev, 0xe4, &h4)
&& read\_register16(dev, 0xe5, &h5)
&& !read\_data(dev, 0xe7, (uint8\_t \*) &dev->dig_H6, 1)) {
dev->dig_H4 = (h4 & 0x00ff) << 4 | (h4 & 0x0f00) >> 8;
dev->dig_H5 = h5 >> 4;

return true;
}

return false;
}

// 写8位寄存器
static int write\_register8(bmp280\_t \*dev, uint8\_t addr, uint8\_t value) {
uint16\_t tx_buff;

tx_buff = (dev->addr << 1);

if (HAL\_I2C\_Mem\_Write(dev->i2c, tx_buff, addr, 1, &value, 1, 10000) == HAL_OK)
return false;
else
return true;
}



// 温度补偿
static inline int32\_t compensate\_temperature(bmp280\_t \*dev, int32\_t adc_temp,
int32\_t \*fine_temp) {
int32\_t var1, var2;

var1 = ((((adc_temp >> 3) - ((int32\_t) dev->dig_T1 << 1)))
\* (int32\_t) dev->dig_T2) >> 11;
var2 = (((((adc_temp >> 4) - (int32\_t) dev->dig_T1)
\* ((adc_temp >> 4) - (int32\_t) dev->dig_T1)) >> 12)
\* (int32\_t) dev->dig_T3) >> 14;

\*fine_temp = var1 + var2;
return (\*fine_temp \* 5 + 128) >> 8;
}

// 气压补偿
static inline uint32\_t compensate\_pressure(bmp280\_t \*dev, int32\_t adc_press,
int32\_t fine_temp) {
int64\_t var1, var2, p;

var1 = (int64\_t) fine_temp - 128000;
var2 = var1 \* var1 \* (int64\_t) dev->dig_P6;
var2 = var2 + ((var1 \* (int64\_t) dev->dig_P5) << 17);
var2 = var2 + (((int64\_t) dev->dig_P4) << 35);
var1 = ((var1 \* var1 \* (int64\_t) dev->dig_P3) >> 8)
+ ((var1 \* (int64\_t) dev->dig_P2) << 12);
var1 = (((int64\_t) 1 << 47) + var1) \* ((int64\_t) dev->dig_P1) >> 33;

if (var1 == 0) {
return 0; // avoid exception caused by division by zero
}

p = 1048576 - adc_press;
p = (((p << 31) - var2) \* 3125) / var1;
var1 = ((int64\_t) dev->dig_P9 \* (p >> 13) \* (p >> 13)) >> 25;
var2 = ((int64\_t) dev->dig_P8 \* p) >> 19;

p = ((p + var1 + var2) >> 8) + ((int64\_t) dev->dig_P7 << 4);
return p;
}

// BME280温度补偿
static inline uint32\_t compensate\_humidity(bmp280\_t \*dev, int32\_t adc_hum,
int32\_t fine_temp) {
int32\_t v_x1_u32r;

v_x1_u32r = fine_temp - (int32\_t) 76800;
v_x1_u32r = ((((adc_hum << 14) - ((int32\_t) dev->dig_H4 << 20)
- ((int32\_t) dev->dig_H5 \* v_x1_u32r)) + (int32\_t) 16384) >> 15)
\* (((((((v_x1_u32r \* (int32\_t) dev->dig_H6) >> 10)
\* (((v_x1_u32r \* (int32\_t) dev->dig_H3) >> 11)
+ (int32\_t) 32768)) >> 10) + (int32\_t) 2097152)
\* (int32\_t) dev->dig_H2 + 8192) >> 14);
v_x1_u32r = v_x1_u32r
- (((((v_x1_u32r >> 15) \* (v_x1_u32r >> 15)) >> 7)
\* (int32\_t) dev->dig_H1) >> 4);
v_x1_u32r = v_x1_u32r < 0 ? 0 : v_x1_u32r;
v_x1_u32r = v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r;
return v_x1_u32r >> 12;
}



4)BMP280驱动定义实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
void bmp280\_init\_default\_params(bmp280\_params\_t \*params) {
params->mode = BMP280_MODE_NORMAL;
params->filter = BMP280_FILTER_OFF;
params->oversampling_pressure = BMP280_STANDARD;
params->oversampling_temperature = BMP280_STANDARD;
params->oversampling_humidity = BMP280_STANDARD;
params->standby = BMP280_STANDBY_250;
}

bool bmp280\_init(bmp280\_t \*dev, bmp280\_params\_t \*params) {

if (dev->addr != BMP280_I2C_ADDRESS_0
&& dev->addr != BMP280_I2C_ADDRESS_1) {
printf("invalid address\r\n");
return false;
}

if (read\_data(dev, BMP280_REG_ID, &dev->id, 1)) {
printf("read reg id failed\r\n");
return false;
}

printf("chip id = 0x%x\r\n",dev->id);
if (dev->id != BMP280_CHIP_ID && dev->id != BME280_CHIP_ID) {
printf("read chip id failed\r\n");
return false;
}
printf("chip id = 0x%x\r\n",dev->id);
// Soft reset.
if (write\_register8(dev, BMP280_REG_RESET, BMP280_RESET_VALUE)) {
printf("reset failed\r\n");
return false;
}

// Wait until finished copying over the NVP data.
while (1) {
uint8\_t status;
if (!read\_data(dev, BMP280_REG_STATUS, &status, 1)
&& (status & 1) == 0)
break;
}

if (!read\_calibration\_data(dev)) {
printf("read calibration data failed\r\n");
return false;
}

if (dev->id == BME280_CHIP_ID && !read\_hum\_calibration\_data(dev)) {
printf("bme280 read\_hum\_calibration\_data failed \r\n");
return false;
}

uint8\_t config = (params->standby << 5) | (params->filter << 2);
if (write\_register8(dev, BMP280_REG_CONFIG, config)) {
printf("set config failed\r\n");
return false;
}

if (params->mode == BMP280_MODE_FORCED) {
params->mode = BMP280_MODE_SLEEP; // initial mode for forced is sleep
}

uint8\_t ctrl = (params->oversampling_temperature << 5)
| (params->oversampling_pressure << 2) | (params->mode);

if (dev->id == BME280_CHIP_ID) {
// Write crtl hum reg first, only active after write to BMP280\_REG\_CTRL.
uint8\_t ctrl_hum = params->oversampling_humidity;
if (write\_register8(dev, BMP280_REG_CTRL_HUM, ctrl_hum)) {
printf("write bme280 reg ffailed\r\n");
return false;
}
}

if (write\_register8(dev, BMP280_REG_CTRL, ctrl)) {
printf("write reg ctrl failed \r\n");
return false;
}

return true;
}

bool bmp280\_force\_measurement(bmp280\_t \*dev) {
uint8\_t ctrl;
if (read\_data(dev, BMP280_REG_CTRL, &ctrl, 1))
return false;
ctrl &= ~0b11; // clear two lower bits
ctrl |= BMP280_MODE_FORCED;
if (write\_register8(dev, BMP280_REG_CTRL, ctrl)) {
return false;
}
return true;
}

bool bmp280\_is\_measuring(bmp280\_t \*dev) {
uint8\_t status;
if (read\_data(dev, BMP280_REG_STATUS, &status, 1))
return false;
if (status & (1 << 3)) {
return true;
}
return false;
}

bool bmp280\_read\_fixed(bmp280\_t \*dev, int32\_t \*temperature, uint32\_t \*pressure,
uint32\_t \*humidity) {
int32\_t adc_pressure;
int32\_t adc_temp;
uint8\_t data[8];

// Only the BME280 supports reading the humidity.
if (dev->id != BME280_CHIP_ID) {
if (humidity)
\*humidity = 0;
humidity = NULL;
}

// Need to read in one sequence to ensure they match.
size\_t size = humidity ? 8 : 6;
if (read\_data(dev, 0xf7, data, size)) {
return false;
}

adc_pressure = data[0] << 12 | data[1] << 4 | data[2] >> 4;
adc_temp = data[3] << 12 | data[4] << 4 | data[5] >> 4;

int32\_t fine_temp;
\*temperature = compensate\_temperature(dev, adc_temp, &fine_temp);
\*pressure = compensate\_pressure(dev, adc_pressure, fine_temp);

if (humidity) {
int32\_t adc_humidity = data[6] << 8 | data[7];
\*humidity = compensate\_humidity(dev, adc_humidity, fine_temp);
}

return true;
}

bool bmp280\_read\_float(bmp280\_t \*dev, float \*temperature, float \*pressure,
float \*humidity) {
int32\_t fixed_temperature;
uint32\_t fixed_pressure;
uint32\_t fixed_humidity;
if (bmp280\_read\_fixed(dev, &fixed_temperature, &fixed_pressure,
humidity ? &fixed_humidity : NULL)) {
\*temperature = (float) fixed_temperature / 100;
\*pressure = (float) fixed_pressure / 256;
if (humidity)
\*humidity = (float) fixed_humidity / 1024;
return true;
}

return false;
}

4、驱动测试实现

main.c文件中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include "bmp280/bmp280.h"
#include <stdio.h>
/\* USER CODE END Includes \*/

/\* Private variables ---------------------------------------------------------\*/

/\* USER CODE BEGIN PV \*/
bmp280\_t bmp280;

float pressure, temperature, humidity;

uint16\_t size;
uint8\_t Data[256];
/\* USER CODE END PV \*/

int main(void) {
/\* USER CODE BEGIN 1 \*/

/\* USER CODE END 1 \*/

/\* MCU Configuration--------------------------------------------------------\*/

/\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/
HAL\_Init();

/\* USER CODE BEGIN Init \*/

/\* USER CODE END Init \*/

/\* Configure the system clock \*/
SystemClock\_Config();

/\* USER CODE BEGIN SysInit \*/

/\* USER CODE END SysInit \*/

/\* Initialize all configured peripherals \*/
MX\_GPIO\_Init();
MX\_USART1\_UART\_Init();
MX\_I2C1\_Init();
/\* USER CODE BEGIN 2 \*/
bmp280\_init\_default\_params(&bmp280.params);
bmp280.addr = BMP280_I2C_ADDRESS_0;
bmp280.i2c = &hi2c1;
printf("bmp280 demo\r\n");
if (!bmp280\_is\_ready(&bmp280)) {
printf("not found bmp280\r\n");
while (1)
;
}

if (!bmp280\_init(&bmp280, &bmp280.params)) {
printf("BMP280 initialization failed\n");
while (1)
;
}
bool bme280p = bmp280.id == BME280_CHIP_ID;
if (bme280p) {
printf("found bmp280\r\n");
} else {
printf("found bme280\r\n");
}
/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
while (1) {
/\* USER CODE END WHILE \*/

/\* USER CODE BEGIN 3 \*/
HAL\_Delay(100);
while (!bmp280\_read\_float(&bmp280, &temperature, &pressure, &humidity)) {
printf("Temperature/pressure reading failed\n");
HAL\_Delay(2000);
}

printf("Pressure: %.2f Pa, Temperature: %.2f C", pressure, temperature);

if (bme280p) {
printf(", Humidity: %.2f\n", humidity);

}

else {
printf("\n");
}
HAL\_Delay(2000);
}
/\* USER CODE END 3 \*/
}

文章来源: https://iotsmart.blog.csdn.net/article/details/125868103