BMP280 气压计驱动
代码示例与解析
基于 STM32 HAL 库的 BMP280 驱动代码,包含初始化和数据读取函数。
BMP280 驱动头文件 (bmp280.h)
#ifndef BMP280_H
#define BMP280_H
#include "stm32f1xx_hal.h" // 根据你的STM32系列调整
#include <stdint.h>
// BMP280 I2C 地址(根据SDO引脚连接决定)
#define BMP280_I2C_ADDR (0x76 << 1) // SDO接地
// #define BMP280_I2C_ADDR (0x77 << 1) // SDO接VCC
// BMP280 寄存器地址
#define BMP280_CHIP_ID_REG 0xD0
#define BMP280_RESET_REG 0xE0
#define BMP280_STATUS_REG 0xF3
#define BMP280_CTRL_MEAS_REG 0xF4
#define BMP280_CONFIG_REG 0xF5
#define BMP280_PRESS_MSB_REG 0xF7
#define BMP280_TEMP_MSB_REG 0xFA
#define BMP280_CALIB_DATA_START_REG 0x88
// 校准参数结构体
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;
} BMP280_CalibData;
// 传感器实例结构体
typedef struct {
I2C_HandleTypeDef *i2c_handle;
uint8_t i2c_addr;
BMP280_CalibData calib_data;
} BMP280_HandleTypeDef;
// 函数声明
uint8_t BMP280_Init(BMP280_HandleTypeDef *bmp, I2C_HandleTypeDef *hi2c, uint8_t addr);
uint8_t BMP280_ReadTemperatureAndPressure(BMP280_HandleTypeDef *bmp, float *temperature, float *pressure);
uint8_t BMP280_ReadRawData(BMP280_HandleTypeDef *bmp, int32_t *raw_temp, int32_t *raw_press);
void BMP280_CompensateTemperature(BMP280_HandleTypeDef *bmp, int32_t raw_temp, float *temperature);
void BMP280_CompensatePressure(BMP280_HandleTypeDef *bmp, int32_t raw_press, int32_t raw_temp, float *pressure);
#endif
BMP280 驱动源文件 (bmp280.c)
#include "bmp280.h"
#include <math.h>
// 私有函数声明
static uint8_t BMP280_ReadRegister(BMP280_HandleTypeDef *bmp, uint8_t reg_addr, uint8_t *data, uint16_t len);
static uint8_t BMP280_WriteRegister(BMP280_HandleTypeDef *bmp, uint8_t reg_addr, uint8_t data);
static void BMP280_ReadCalibrationData(BMP280_HandleTypeDef *bmp);
// 初始化BMP280
uint8_t BMP280_Init(BMP280_HandleTypeDef *bmp, I2C_HandleTypeDef *hi2c, uint8_t addr) {
uint8_t chip_id;
bmp->i2c_handle = hi2c;
bmp->i2c_addr = addr;
// 读取芯片ID进行验证
if (BMP280_ReadRegister(bmp, BMP280_CHIP_ID_REG, &chip_id, 1) != HAL_OK) {
return 0;
}
if (chip_id != 0x58) { // BMP280的芯片ID应为0x58
return 0;
}
// 读取校准数据
BMP280_ReadCalibrationData(bmp);
// 软复位
BMP280_WriteRegister(bmp, BMP280_RESET_REG, 0xB6);
HAL_Delay(10);
// 配置传感器工作模式
// 设置温度和气压过采样为x1,正常模式
BMP280_WriteRegister(bmp, BMP280_CTRL_MEAS_REG, 0x27);
// 配置滤波器系数和 standby 时间
BMP280_WriteRegister(bmp, BMP280_CONFIG_REG, 0x00);
return 1;
}
// 读取校准数据
static void BMP280_ReadCalibrationData(BMP280_HandleTypeDef *bmp) {
uint8_t calib_data[24];
// 读取0x88-0x9F的校准数据
BMP280_ReadRegister(bmp, BMP280_CALIB_DATA_START_REG, calib_data, 24);
// 解析温度校准参数(注意字节顺序)
bmp->calib_data.dig_T1 = (uint16_t)((uint16_t)calib_data[1] << 8) | calib_data[0];
bmp->calib_data.dig_T2 = (int16_t)((uint16_t)calib_data[3] << 8) | calib_data[2];
bmp->calib_data.dig_T3 = (int16_t)((uint16_t)calib_data[5] << 8) | calib_data[4];
// 解析气压校准参数
bmp->calib_data.dig_P1 = (uint16_t)((uint16_t)calib_data[7] << 8) | calib_data[6];
bmp->calib_data.dig_P2 = (int16_t)((uint16_t)calib_data[9] << 8) | calib_data[8];
bmp->calib_data.dig_P3 = (int16_t)((uint16_t)calib_data[11] << 8) | calib_data[10];
bmp->calib_data.dig_P4 = (int16_t)((uint16_t)calib_data[13] << 8) | calib_data[12];
bmp->calib_data.dig_P5 = (int16_t)((uint16_t)calib_data[15] << 8) | calib_data[14];
bmp->calib_data.dig_P6 = (int16_t)((uint16_t)calib_data[17] << 8) | calib_data[16];
bmp->calib_data.dig_P7 = (int16_t)((uint16_t)calib_data[19] << 8) | calib_data[18];
bmp->calib_data.dig_P8 = (int16_t)((uint16_t)calib_data[21] << 8) | calib_data[20];
bmp->calib_data.dig_P9 = (int16_t)((uint16_t)calib_data[23] << 8) | calib_data[22];
}
// 读取温度和气压数据
uint8_t BMP280_ReadTemperatureAndPressure(BMP280_HandleTypeDef *bmp, float *temperature, float *pressure) {
int32_t raw_temp, raw_press;
if (BMP280_ReadRawData(bmp, &raw_temp, &raw_press) != HAL_OK) {
return 0;
}
BMP280_CompensateTemperature(bmp, raw_temp, temperature);
BMP280_CompensatePressure(bmp, raw_press, raw_temp, pressure);
return 1;
}
// 读取原始数据
uint8_t BMP280_ReadRawData(BMP280_HandleTypeDef *bmp, int32_t *raw_temp, int32_t *raw_press) {
uint8_t data[6];
// 读取压力和温度数据寄存器(0xF7-0xFC)
if (BMP280_ReadRegister(bmp, BMP280_PRESS_MSB_REG, data, 6) != HAL_OK) {
return 0;
}
// 组合压力数据(20位)
*raw_press = (int32_t)(((uint32_t)data[0] << 12) | ((uint32_t)data[1] << 4) | ((uint32_t)data[2] >> 4));
// 组合温度数据(20位)
*raw_temp = (int32_t)(((uint32_t)data[3] << 12) | ((uint32_t)data[4] << 4) | ((uint32_t)data[5] >> 4));
return 1;
}
// 温度补偿计算
void BMP280_CompensateTemperature(BMP280_HandleTypeDef *bmp, int32_t raw_temp, float *temperature) {
int32_t var1, var2, T;
var1 = ((((raw_temp >> 3) - ((int32_t)bmp->calib_data.dig_T1 << 1))) *
((int32_t)bmp->calib_data.dig_T2)) >> 11;
var2 = (((((raw_temp >> 4) - ((int32_t)bmp->calib_data.dig_T1)) *
((raw_temp >> 4) - ((int32_t)bmp->calib_data.dig_T1))) >> 12) *
((int32_t)bmp->calib_data.dig_T3)) >> 14;
T = var1 + var2;
*temperature = ((T * 5 + 128) >> 8) / 100.0f;
}
// 压力补偿计算
void BMP280_CompensatePressure(BMP280_HandleTypeDef *bmp, int32_t raw_press, int32_t raw_temp, float *pressure) {
int64_t var1, var2, p;
int32_t var1_t, var2_t, T;
// 先计算温度补偿的部分中间变量(重用温度计算中的部分)
var1_t = ((((raw_temp >> 3) - ((int32_t)bmp->calib_data.dig_T1 << 1))) *
((int32_t)bmp->calib_data.dig_T2)) >> 11;
var2_t = (((((raw_temp >> 4) - ((int32_t)bmp->calib_data.dig_T1)) *
((raw_temp >> 4) - ((int32_t)bmp->calib_data.dig_T1))) >> 12) *
((int32_t)bmp->calib_data.dig_T3)) >> 14;
T = var1_t + var2_t;
// 计算压力补偿
var1 = ((int64_t)T) - 128000;
var2 = var1 * var1 * (int64_t)bmp->calib_data.dig_P6;
var2 = var2 + ((var1 * (int64_t)bmp->calib_data.dig_P5) << 17);
var2 = var2 + (((int64_t)bmp->calib_data.dig_P4) << 35);
var1 = ((var1 * var1 * (int64_t)bmp->calib_data.dig_P3) >> 8) +
((var1 * (int64_t)bmp->calib_data.dig_P2) << 12);
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)bmp->calib_data.dig_P1) >> 33;
if (var1 == 0) {
*pressure = 0;
return;
}
p = 1048576 - raw_press;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((int64_t)bmp->calib_data.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((int64_t)bmp->calib_data.dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)bmp->calib_data.dig_P7) << 4);
*pressure = (float)p / 256.0f;
}
// 读取寄存器
static uint8_t BMP280_ReadRegister(BMP280_HandleTypeDef *bmp, uint8_t reg_addr, uint8_t *data, uint16_t len) {
return HAL_I2C_Mem_Read(bmp->i2c_handle, bmp->i2c_addr, reg_addr, 1, data, len, 100);
}
// 写入寄存器
static uint8_t BMP280_WriteRegister(BMP280_HandleTypeDef *bmp, uint8_t reg_addr, uint8_t data) {
return HAL_I2C_Mem_Write(bmp->i2c_handle, bmp->i2c_addr, reg_addr, 1, &data, 1, 100);
}
主程序示例 (main.c)
#include "main.h"
#include "stm32f1xx_hal.h"
#include "bmp280.h"
#include <stdio.h>
// 全局变量
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart2;
BMP280_HandleTypeDef bmp280;
// 函数声明
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART2_UART_Init(void);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART2_UART_Init();
// 初始化BMP280
if (!BMP280_Init(&bmp280, &hi2c1, BMP280_I2C_ADDR)) {
printf("BMP280初始化失败!\r\n");
while (1);
}
printf("BMP280初始化成功!\r\n");
while (1) {
float temperature, pressure;
// 读取温度和气压
if (BMP280_ReadTemperatureAndPressure(&bmp280, &temperature, &pressure)) {
printf("温度: %.2f °C, 气压: %.2f Pa\r\n", temperature, pressure);
// 计算海拔高度(简化计算,需要海平面基准气压)
float altitude = 44330.0 * (1.0 - pow(pressure / 101325.0, 1.0/5.255));
printf("海拔: %.2f 米\r\n", altitude);
} else {
printf("读取BMP280数据失败!\r\n");
}
HAL_Delay(2000); // 每2秒读取一次
}
}
// 其他必要的初始化函数(SystemClock_Config, MX_I2C1_Init等)需要根据你的具体硬件实现
BMP280 使用要点
为了帮助你更好地理解和使用 BMP280,下面是一些关键信息:
| 项目 | 详细说明/参数 |
|---|---|
| 通信接口 | I²C 或 SPI |
| I²C 地址 | 0x76 (SDO 接地) 或 0x77 (SDO 接 VCC) |
| 电源电压 | 3.3V ⚠️切勿接入5V,以免烧毁传感器 |
| 测量范围 | 温度: -40°C ~ +85°C, 气压: 300~1100 hPa |
| 核心功能 | 测量大气压强和温度,可通过气压值换算海拔高度(需海平面基准气压参考) |
| 关键步骤 | 1. 读取芯片ID(0x58)验证 2. 读取校准参数 3. 配置工作模式 4. 读取数据并进行补偿计算 |
| 工作模式 | 睡眠模式(Sleep Mode)、正常模式(Normal Mode)、强制模式(Forced Mode) |
参考代码 bmp280气压计源码 www.youwenfan.com/contentcsh/56690.html
注意事项
- I2C 地址选择:BMP280 的 I2C 地址由 SDO 引脚决定。SDO 接地时地址为 0x76,接 VCC 时为 0x77。务必正确配置,否则无法通信。
- 校准参数:补偿计算需要依赖从传感器读取的校准参数。这些参数存储在传感器的特定寄存器中,需在初始化时读取并保存。
- 计算复杂度:温度和气压的补偿计算相对复杂,涉及多个中间变量和校准参数。务必仔细检查计算过程,确保与数据手册中的公式一致。
- 时序要求:在写入配置寄存器后或请求数据后,需要给予传感器足够的转换时间(可根据配置的过采样率和工作模式查阅数据手册确定具体时间)。
- 电源去耦:为减少电源噪声对测量精度的影响,建议在 BMP280 的 VCC 和 GND 引脚之间靠近传感器的位置放置一个 0.1μF 的陶瓷电容。
调试建议
- 如果读取数据失败,首先检查 I2C 通信是否正常。可以尝试读取芯片 ID 寄存器 (0xD0),确认是否正确返回 0x58。
- 利用逻辑分析仪或示波器观察 I2C 总线上的 SCL 和 SDA 信号,有助于排查通信问题。
- 确保 HAL 库中的 I2C 初始化配置(时钟速度等)与 BMP280 兼容(通常支持标准模式 100kHz 和快速模式 400kHz)。
其他平台资源
- Arduino:可使用 Adafruit_BMP280 库。
- MicroPython:有开源的
bmp280.py驱动库。 - ESP8266/ESP32:通常也可使用 Arduino 的库或 MicroPython 驱动。