BMP280 气压计驱动

 

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

注意事项

  1. I2C 地址选择:BMP280 的 I2C 地址由 SDO 引脚决定。SDO 接地时地址为 0x76,接 VCC 时为 0x77。务必正确配置,否则无法通信。
  2. 校准参数:补偿计算需要依赖从传感器读取的校准参数。这些参数存储在传感器的特定寄存器中,需在初始化时读取并保存。
  3. 计算复杂度:温度和气压的补偿计算相对复杂,涉及多个中间变量和校准参数。务必仔细检查计算过程,确保与数据手册中的公式一致。
  4. 时序要求:在写入配置寄存器后或请求数据后,需要给予传感器足够的转换时间(可根据配置的过采样率和工作模式查阅数据手册确定具体时间)。
  5. 电源去耦:为减少电源噪声对测量精度的影响,建议在 BMP280 的 VCC 和 GND 引脚之间靠近传感器的位置放置一个 0.1μF 的陶瓷电容。

调试建议

其他平台资源

 

专注于matlab/simulink,电子电路,编程