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应为0x58return 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();// 初始化BMP280if (!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 驱动。