BMP280气压温度传感器的I2C通信驱动程序,包含高精度测量、温度补偿、数据滤波、多种工作模式等功能。
一、硬件连接与配置
1.1 BMP280引脚定义
BMP280 (LGA-8封装)
├── VCC → 3.3V
├── GND → GND
├── SCL → I2C时钟线
├── SDA → I2C数据线
└── CSB → 接VCC (I2C模式)
SDO → 接地(地址0x76) 或 接VCC(地址0x77)
1.2 STM32连接
STM32F103C8T6
├── I2C1
│ ├── SCL → PB6
│ └── SDA → PB7
├── 或 I2C2
│ ├── SCL → PB10
│ └── SDA → PB11
└── 电源
├── 3.3V → BMP280 VCC
└── GND → BMP280 GND
二、核心驱动代码
2.1 BMP280驱动头文件
c
/**
* @file bmp280.h
* @brief BMP280气压温度传感器驱动
*/
#ifndef __BMP280_H
#define __BMP280_H
#include "stm32f1xx_hal.h"
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
/* BMP280 I2C地址 */
#define BMP280_I2C_ADDR_WRITE 0xEC // 写地址 (0x76 << 1)
#define BMP280_I2C_ADDR_READ 0xED // 读地址 (0x76 << 1 | 1)
#define BMP280_I2C_ADDR_WRITE_2 0xEE // 备用写地址 (0x77 << 1)
#define BMP280_I2C_ADDR_READ_2 0xEF // 备用读地址 (0x77 << 1 | 1)
/* BMP280寄存器定义 */
#define BMP280_REG_ID 0xD0
#define BMP280_REG_RESET 0xE0
#define BMP280_REG_STATUS 0xF3
#define BMP280_REG_CTRL_MEAS 0xF4
#define BMP280_REG_CONFIG 0xF5
#define BMP280_REG_PRESS_MSB 0xF7
#define BMP280_REG_PRESS_LSB 0xF8
#define BMP280_REG_PRESS_XLSB 0xF9
#define BMP280_REG_TEMP_MSB 0xFA
#define BMP280_REG_TEMP_LSB 0xFB
#define BMP280_REG_TEMP_XLSB 0xFC
#define BMP280_REG_CALIB_START 0x88
#define BMP280_REG_CALIB_END 0xA1
/* BMP280复位值 */
#define BMP280_RESET_VALUE 0xB6
/* BMP280芯片ID */
#define BMP280_CHIP_ID 0x58
/* 工作模式 */
typedef enum {
BMP280_MODE_SLEEP = 0, // 睡眠模式
BMP280_MODE_FORCED = 1, // 强制模式
BMP280_MODE_FORCED_2 = 2, // 强制模式2
BMP280_MODE_NORMAL = 3 // 正常模式
} BMP280_Mode;
/* 过采样率 */
typedef enum {
BMP280_OSR_SKIP = 0, // 跳过
BMP280_OSR_X1 = 1, // 1倍
BMP280_OSR_X2 = 2, // 2倍
BMP280_OSR_X4 = 3, // 4倍
BMP280_OSR_X8 = 4, // 8倍
BMP280_OSR_X16 = 5 // 16倍
} BMP280_Oversampling;
/* 滤波器系数 */
typedef enum {
BMP280_FILTER_OFF = 0, // 关闭滤波器
BMP280_FILTER_2 = 1, // 系数2
BMP280_FILTER_4 = 2, // 系数4
BMP280_FILTER_8 = 3, // 系数8
BMP280_FILTER_16 = 4 // 系数16
} BMP280_Filter;
/* 待机时间 (ms) */
typedef enum {
BMP280_STANDBY_0_5 = 0, // 0.5ms
BMP280_STANDBY_62_5 = 1, // 62.5ms
BMP280_STANDBY_125 = 2, // 125ms
BMP280_STANDBY_250 = 3, // 250ms
BMP280_STANDBY_500 = 4, // 500ms
BMP280_STANDBY_1000 = 5, // 1000ms
BMP280_STANDBY_2000 = 6, // 2000ms
BMP280_STANDBY_4000 = 7 // 4000ms
} BMP280_StandbyTime;
/* 校准参数结构体 */
typedef struct {
uint16_t dig_T1; // 温度校准参数1
int16_t dig_T2; // 温度校准参数2
int16_t dig_T3; // 温度校准参数3
uint16_t dig_P1; // 气压校准参数1
int16_t dig_P2; // 气压校准参数2
int16_t dig_P3; // 气压校准参数3
int16_t dig_P4; // 气压校准参数4
int16_t dig_P5; // 气压校准参数5
int16_t dig_P6; // 气压校准参数6
int16_t dig_P7; // 气压校准参数7
int16_t dig_P8; // 气压校准参数8
int16_t dig_P9; // 气压校准参数9
int32_t t_fine; // 精细温度值
} BMP280_CalibData;
/* BMP280设备结构体 */
typedef struct {
I2C_HandleTypeDef *hi2c; // I2C句柄
uint8_t i2c_addr; // I2C地址
BMP280_CalibData calib_data; // 校准数据
BMP280_Mode mode; // 工作模式
BMP280_Oversampling osr_temp; // 温度过采样
BMP280_Oversampling osr_press; // 气压过采样
BMP280_Filter filter; // 滤波器系数
BMP280_StandbyTime standby; // 待机时间
uint8_t chip_id; // 芯片ID
uint8_t initialized; // 初始化标志
} BMP280_Handle;
/* 测量结果结构体 */
typedef struct {
float temperature; // 温度 (°C)
float pressure; // 气压 (hPa)
float altitude; // 海拔高度 (m)
uint32_t timestamp; // 时间戳
} BMP280_Data;
/* 函数声明 */
uint8_t BMP280_Init(BMP280_Handle *bmp, I2C_HandleTypeDef *hi2c, uint8_t addr);
uint8_t BMP280_ReadID(BMP280_Handle *bmp);
uint8_t BMP280_Reset(BMP280_Handle *bmp);
uint8_t BMP280_ReadCalibration(BMP280_Handle *bmp);
uint8_t BMP280_SetConfig(BMP280_Handle *bmp);
uint8_t BMP280_StartMeasurement(BMP280_Handle *bmp);
uint8_t BMP280_IsMeasurementReady(BMP280_Handle *bmp);
uint8_t BMP280_ReadData(BMP280_Handle *bmp, BMP280_Data *data);
float BMP280_CalculateAltitude(float pressure, float sea_level_hpa);
float BMP280_CalculateSeaLevelPressure(float pressure, float altitude);
void BMP280_SetMode(BMP280_Handle *bmp, BMP280_Mode mode);
void BMP280_SetOversampling(BMP280_Handle *bmp, BMP280_Oversampling osr_temp,
BMP280_Oversampling osr_press);
void BMP280_SetFilter(BMP280_Handle *bmp, BMP280_Filter filter);
void BMP280_SetStandby(BMP280_Handle *bmp, BMP280_StandbyTime standby);
void BMP280_PrintCalibration(BMP280_CalibData *calib);
void BMP280_PrintConfig(BMP280_Handle *bmp);
/* 海平面标准气压 */
#define SEA_LEVEL_PRESSURE_HPA 1013.25f
#endif /* __BMP280_H */
2.2 BMP280驱动实现
c
/**
* @file bmp280.c
* @brief BMP280驱动实现
*/
#include "bmp280.h"
/* 全局变量 */
static uint8_t bmp280_buffer[24];
static BMP280_Data bmp280_data;
/**
* @brief I2C写入一个字节
*/
static uint8_t BMP280_WriteByte(BMP280_Handle *bmp, uint8_t reg, uint8_t data)
{
uint8_t tx_data[2] = {reg, data};
if(HAL_I2C_Master_Transmit(bmp->hi2c, bmp->i2c_addr, tx_data, 2, 100) != HAL_OK)
{
return 1; // 传输失败
}
return 0; // 成功
}
/**
* @brief I2C读取多个字节
*/
static uint8_t BMP280_ReadBytes(BMP280_Handle *bmp, uint8_t reg, uint8_t *data, uint8_t len)
{
/* 先发送寄存器地址 */
if(HAL_I2C_Master_Transmit(bmp->hi2c, bmp->i2c_addr, ®, 1, 100) != HAL_OK)
{
return 1;
}
/* 然后读取数据 */
if(HAL_I2C_Master_Receive(bmp->hi2c, bmp->i2c_addr, data, len, 100) != HAL_OK)
{
return 1;
}
return 0;
}
/**
* @brief 初始化BMP280
*/
uint8_t BMP280_Init(BMP280_Handle *bmp, I2C_HandleTypeDef *hi2c, uint8_t addr)
{
if(bmp == NULL || hi2c == NULL)
return 1;
/* 初始化结构体 */
bmp->hi2c = hi2c;
bmp->i2c_addr = addr;
bmp->mode = BMP280_MODE_SLEEP;
bmp->osr_temp = BMP280_OSR_X2;
bmp->osr_press = BMP280_OSR_X16;
bmp->filter = BMP280_FILTER_4;
bmp->standby = BMP280_STANDBY_1000;
bmp->initialized = 0;
/* 1. 读取芯片ID */
if(BMP280_ReadID(bmp) != 0)
{
printf("BMP280: Failed to read chip ID\n");
return 2;
}
if(bmp->chip_id != BMP280_CHIP_ID)
{
printf("BMP280: Invalid chip ID: 0x%02X\n", bmp->chip_id);
return 3;
}
printf("BMP280: Chip ID: 0x%02X\n", bmp->chip_id);
/* 2. 复位芯片 */
if(BMP280_Reset(bmp) != 0)
{
printf("BMP280: Reset failed\n");
return 4;
}
HAL_Delay(10); // 等待复位完成
/* 3. 读取校准参数 */
if(BMP280_ReadCalibration(bmp) != 0)
{
printf("BMP280: Failed to read calibration data\n");
return 5;
}
/* 4. 配置传感器 */
if(BMP280_SetConfig(bmp) != 0)
{
printf("BMP280: Failed to set configuration\n");
return 6;
}
bmp->initialized = 1;
printf("BMP280: Initialized successfully\n");
return 0;
}
/**
* @brief 读取芯片ID
*/
uint8_t BMP280_ReadID(BMP280_Handle *bmp)
{
if(BMP280_ReadBytes(bmp, BMP280_REG_ID, &bmp->chip_id, 1) != 0)
{
return 1;
}
return 0;
}
/**
* @brief 复位芯片
*/
uint8_t BMP280_Reset(BMP280_Handle *bmp)
{
return BMP280_WriteByte(bmp, BMP280_REG_RESET, BMP280_RESET_VALUE);
}
/**
* @brief 读取校准参数
*/
uint8_t BMP280_ReadCalibration(BMP280_Handle *bmp)
{
uint8_t calib_data[24];
/* 读取24字节的校准数据 */
if(BMP280_ReadBytes(bmp, BMP280_REG_CALIB_START, calib_data, 24) != 0)
{
return 1;
}
/* 解析温度校准参数 */
bmp->calib_data.dig_T1 = (calib_data[1] << 8) | calib_data[0];
bmp->calib_data.dig_T2 = (calib_data[3] << 8) | calib_data[2];
bmp->calib_data.dig_T3 = (calib_data[5] << 8) | calib_data[4];
/* 解析气压校准参数 */
bmp->calib_data.dig_P1 = (calib_data[7] << 8) | calib_data[6];
bmp->calib_data.dig_P2 = (calib_data[9] << 8) | calib_data[8];
bmp->calib_data.dig_P3 = (calib_data[11] << 8) | calib_data[10];
bmp->calib_data.dig_P4 = (calib_data[13] << 8) | calib_data[12];
bmp->calib_data.dig_P5 = (calib_data[15] << 8) | calib_data[14];
bmp->calib_data.dig_P6 = (calib_data[17] << 8) | calib_data[16];
bmp->calib_data.dig_P7 = (calib_data[19] << 8) | calib_data[18];
bmp->calib_data.dig_P8 = (calib_data[21] << 8) | calib_data[20];
bmp->calib_data.dig_P9 = (calib_data[23] << 8) | calib_data[22];
/* 调试输出 */
printf("BMP280: Calibration data loaded\n");
printf(" T1=%u, T2=%d, T3=%d\n",
bmp->calib_data.dig_T1, bmp->calib_data.dig_T2, bmp->calib_data.dig_T3);
printf(" P1=%u, P2=%d, P3=%d\n",
bmp->calib_data.dig_P1, bmp->calib_data.dig_P2, bmp->calib_data.dig_P3);
return 0;
}
/**
* @brief 配置传感器
*/
uint8_t BMP280_SetConfig(BMP280_Handle *bmp)
{
uint8_t ctrl_meas = 0;
uint8_t config = 0;
/* 配置控制测量寄存器 */
ctrl_meas = (bmp->osr_temp << 5) | (bmp->osr_press << 2) | bmp->mode;
/* 配置寄存器 */
config = (bmp->standby << 5) | (bmp->filter << 2);
/* 写入配置 */
if(BMP280_WriteByte(bmp, BMP280_REG_CTRL_MEAS, ctrl_meas) != 0)
{
return 1;
}
if(BMP280_WriteByte(bmp, BMP280_REG_CONFIG, config) != 0)
{
return 2;
}
return 0;
}
/**
* @brief 启动测量
*/
uint8_t BMP280_StartMeasurement(BMP280_Handle *bmp)
{
uint8_t ctrl_meas = 0;
/* 读取当前配置 */
if(BMP280_ReadBytes(bmp, BMP280_REG_CTRL_MEAS, &ctrl_meas, 1) != 0)
{
return 1;
}
/* 设置为强制模式或正常模式 */
ctrl_meas &= ~0x03; // 清除模式位
ctrl_meas |= bmp->mode;
/* 写回寄存器 */
if(BMP280_WriteByte(bmp, BMP280_REG_CTRL_MEAS, ctrl_meas) != 0)
{
return 2;
}
return 0;
}
/**
* @brief 检查测量是否完成
*/
uint8_t BMP280_IsMeasurementReady(BMP280_Handle *bmp)
{
uint8_t status = 0;
/* 读取状态寄存器 */
if(BMP280_ReadBytes(bmp, BMP280_REG_STATUS, &status, 1) != 0)
{
return 0; // 读取失败,认为未完成
}
/* 检查bit3 (measuring) 是否为0 */
if((status & 0x08) == 0)
{
return 1; // 测量完成
}
return 0; // 测量中
}
/**
* @brief 读取原始数据
*/
static uint8_t BMP280_ReadRawData(BMP280_Handle *bmp, int32_t *raw_temp, int32_t *raw_press)
{
uint8_t data[6];
/* 读取6字节数据 (3字节气压 + 3字节温度) */
if(BMP280_ReadBytes(bmp, BMP280_REG_PRESS_MSB, data, 6) != 0)
{
return 1;
}
/* 解析原始气压数据 */
*raw_press = (int32_t)(((uint32_t)data[0] << 12) | ((uint32_t)data[1] << 4) | ((uint32_t)data[2] >> 4));
/* 解析原始温度数据 */
*raw_temp = (int32_t)(((uint32_t)data[3] << 12) | ((uint32_t)data[4] << 4) | ((uint32_t)data[5] >> 4));
return 0;
}
/**
* @brief 补偿温度计算
* @param raw_temp 原始温度值
* @param calib 校准数据指针
* @return 补偿后的温度 (°C)
*/
static float BMP280_CompensateTemperature(int32_t raw_temp, BMP280_CalibData *calib)
{
int32_t var1, var2, T;
float temp = 0.0f;
var1 = ((((raw_temp >> 3) - ((int32_t)calib->dig_T1 << 1))) * ((int32_t)calib->dig_T2)) >> 11;
var2 = (((((raw_temp >> 4) - ((int32_t)calib->dig_T1)) *
((raw_temp >> 4) - ((int32_t)calib->dig_T1))) >> 12) *
((int32_t)calib->dig_T3)) >> 14;
calib->t_fine = var1 + var2;
T = (calib->t_fine * 5 + 128) >> 8;
temp = (float)T / 100.0f;
return temp;
}
/**
* @brief 补偿气压计算
* @param raw_press 原始气压值
* @param calib 校准数据指针
* @return 补偿后的气压 (Pa)
*/
static float BMP280_CompensatePressure(int32_t raw_press, BMP280_CalibData *calib)
{
int64_t var1, var2, p;
float pressure = 0.0f;
var1 = ((int64_t)calib->t_fine) - 128000;
var2 = var1 * var1 * (int64_t)calib->dig_P6;
var2 = var2 + ((var1 * (int64_t)calib->dig_P5) << 17);
var2 = var2 + (((int64_t)calib->dig_P4) << 35);
var1 = ((var1 * var1 * (int64_t)calib->dig_P3) >> 8) + ((var1 * (int64_t)calib->dig_P2) << 12);
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)calib->dig_P1) >> 33;
if(var1 == 0)
{
return 0; // 避免除零错误
}
p = 1048576 - raw_press;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((int64_t)calib->dig_P9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((int64_t)calib->dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)calib->dig_P7) << 4);
pressure = (float)p / 256.0f;
return pressure;
}
/**
* @brief 读取补偿后的数据
*/
uint8_t BMP280_ReadData(BMP280_Handle *bmp, BMP280_Data *data)
{
int32_t raw_temp, raw_press;
float temperature, pressure;
/* 检查是否初始化 */
if(!bmp->initialized)
{
return 1;
}
/* 检查测量是否完成 */
if(!BMP280_IsMeasurementReady(bmp))
{
return 2; // 测量未完成
}
/* 读取原始数据 */
if(BMP280_ReadRawData(bmp, &raw_temp, &raw_press) != 0)
{
return 3;
}
/* 补偿温度计算 */
temperature = BMP280_CompensateTemperature(raw_temp, &bmp->calib_data);
/* 补偿气压计算 */
pressure = BMP280_CompensatePressure(raw_press, &bmp->calib_data);
/* 转换为hPa */
pressure = pressure / 100.0f;
/* 计算海拔高度 (标准海平面压力1013.25hPa) */
float altitude = BMP280_CalculateAltitude(pressure, SEA_LEVEL_PRESSURE_HPA);
/* 保存数据 */
data->temperature = temperature;
data->pressure = pressure;
data->altitude = altitude;
data->timestamp = HAL_GetTick();
/* 如果是在强制模式,切换回睡眠模式 */
if(bmp->mode == BMP280_MODE_FORCED || bmp->mode == BMP280_MODE_FORCED_2)
{
BMP280_SetMode(bmp, BMP280_MODE_SLEEP);
}
return 0;
}
/**
* @brief 计算海拔高度
* @param pressure 当前气压 (hPa)
* @param sea_level_hpa 海平面气压 (hPa)
* @return 海拔高度 (m)
*/
float BMP280_CalculateAltitude(float pressure, float sea_level_hpa)
{
if(pressure <= 0 || sea_level_hpa <= 0)
return 0.0f;
return 44330.0f * (1.0f - powf(pressure / sea_level_hpa, 0.190295f));
}
/**
* @brief 计算海平面气压
* @param pressure 当前气压 (hPa)
* @param altitude 当前海拔 (m)
* @return 海平面气压 (hPa)
*/
float BMP280_CalculateSeaLevelPressure(float pressure, float altitude)
{
if(pressure <= 0)
return 0.0f;
return pressure / powf(1.0f - (altitude / 44330.0f), 5.255f);
}
/**
* @brief 设置工作模式
*/
void BMP280_SetMode(BMP280_Handle *bmp, BMP280_Mode mode)
{
bmp->mode = mode;
BMP280_SetConfig(bmp);
}
/**
* @brief 设置过采样率
*/
void BMP280_SetOversampling(BMP280_Handle *bmp, BMP280_Oversampling osr_temp,
BMP280_Oversampling osr_press)
{
bmp->osr_temp = osr_temp;
bmp->osr_press = osr_press;
BMP280_SetConfig(bmp);
}
/**
* @brief 设置滤波器
*/
void BMP280_SetFilter(BMP280_Handle *bmp, BMP280_Filter filter)
{
bmp->filter = filter;
BMP280_SetConfig(bmp);
}
/**
* @brief 设置待机时间
*/
void BMP280_SetStandby(BMP280_Handle *bmp, BMP280_StandbyTime standby)
{
bmp->standby = standby;
BMP280_SetConfig(bmp);
}
/**
* @brief 打印校准参数
*/
void BMP280_PrintCalibration(BMP280_CalibData *calib)
{
printf("=== BMP280 Calibration Data ===\n");
printf("Temperature:\n");
printf(" T1: %u\n", calib->dig_T1);
printf(" T2: %d\n", calib->dig_T2);
printf(" T3: %d\n", calib->dig_T3);
printf("Pressure:\n");
printf(" P1: %u\n", calib->dig_P1);
printf(" P2: %d\n", calib->dig_P2);
printf(" P3: %d\n", calib->dig_P3);
printf(" P4: %d\n", calib->dig_P4);
printf(" P5: %d\n", calib->dig_P5);
printf(" P6: %d\n", calib->dig_P6);
printf(" P7: %d\n", calib->dig_P7);
printf(" P8: %d\n", calib->dig_P8);
printf(" P9: %d\n", calib->dig_P9);
printf("t_fine: %ld\n", calib->t_fine);
printf("===============================\n");
}
/**
* @brief 打印配置
*/
void BMP280_PrintConfig(BMP280_Handle *bmp)
{
printf("=== BMP280 Configuration ===\n");
printf("I2C Address: 0x%02X\n", bmp->i2c_addr);
printf("Chip ID: 0x%02X\n", bmp->chip_id);
printf("Mode: %d\n", bmp->mode);
printf("Temperature OSR: %d\n", bmp->osr_temp);
printf("Pressure OSR: %d\n", bmp->osr_press);
printf("Filter: %d\n", bmp->filter);
printf("Standby Time: %d\n", bmp->standby);
printf("Initialized: %s\n", bmp->initialized ? "Yes" : "No");
printf("============================\n");
}
三、I2C配置与主程序
3.1 I2C配置
c
/**
* @file i2c_config.c
* @brief I2C配置
*/
#include "main.h"
I2C_HandleTypeDef hi2c1;
/**
* @brief I2C1初始化
*/
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; // 100kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c1);
}
/**
* @brief I2C GPIO初始化
*/
void MX_I2C1_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO时钟使能 */
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
/* PB6 - I2C1_SCL */
/* PB7 - I2C1_SDA */
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // 开漏输出
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* 引脚重映射 (如果需要) */
// __HAL_AFIO_REMAP_I2C1_ENABLE();
}
/**
* @brief I2C错误处理回调
*/
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
printf("I2C Error: 0x%08lX\n", hi2c->ErrorCode);
/* 重新初始化I2C */
HAL_I2C_DeInit(hi2c);
MX_I2C1_Init();
}
3.2 主程序示例
c
/**
* @file main.c
* @brief BMP280主程序
*/
#include "main.h"
#include "bmp280.h"
#include <stdio.h>
#include <string.h>
/* 全局变量 */
BMP280_Handle bmp280;
BMP280_Data bmp_data;
UART_HandleTypeDef huart1;
/* 函数声明 */
void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_USART1_UART_Init(void);
void Error_Handler(void);
void BMP280_Test(void);
void BMP280_ContinousRead(void);
void BMP280_HighPrecisionTest(void);
/* 重定向printf到串口 */
int _write(int file, char *ptr, int len)
{
HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, 1000);
return len;
}
/**
* @brief 主函数
*/
int main(void)
{
/* HAL库初始化 */
HAL_Init();
/* 系统时钟配置 */
SystemClock_Config();
/* 外设初始化 */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_I2C1_GPIO_Init();
MX_I2C1_Init();
printf("\nSTM32 BMP280 I2C Driver\n");
printf("=======================\n");
/* 初始化BMP280 */
printf("Initializing BMP280...\n");
if(BMP280_Init(&bmp280, &hi2c1, BMP280_I2C_ADDR_WRITE) != 0)
{
printf("BMP280 initialization failed!\n");
/* 尝试备用地址 */
printf("Trying alternative address...\n");
if(BMP280_Init(&bmp280, &hi2c1, BMP280_I2C_ADDR_WRITE_2) != 0)
{
printf("BMP280 not found at any address!\n");
Error_Handler();
}
}
/* 打印配置信息 */
BMP280_PrintConfig(&bmp280);
BMP280_PrintCalibration(&bmp280.calib_data);
/* 设置高精度模式 */
BMP280_SetOversampling(&bmp280, BMP280_OSR_X2, BMP280_OSR_X16);
BMP280_SetFilter(&bmp280, BMP280_FILTER_16);
BMP280_SetStandby(&bmp280, BMP280_STANDBY_1000);
BMP280_SetMode(&bmp280, BMP280_MODE_NORMAL);
printf("\nConfiguration updated for high precision mode\n");
/* 主循环 */
while(1)
{
static uint32_t last_read = 0;
uint32_t current_time = HAL_GetTick();
/* 每1秒读取一次 */
if(current_time - last_read >= 1000)
{
last_read = current_time;
/* 读取数据 */
if(BMP280_ReadData(&bmp280, &bmp_data) == 0)
{
printf("Temperature: %.2f C, Pressure: %.2f hPa, Altitude: %.2f m\n",
bmp_data.temperature, bmp_data.pressure, bmp_data.altitude);
/* 控制LED (温度指示) */
if(bmp_data.temperature > 30.0f)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // LED亮
}
else
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // LED灭
}
}
else
{
printf("Failed to read BMP280 data\n");
}
}
HAL_Delay(10);
}
}
/**
* @brief 系统时钟配置
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* 配置HSE 8MHz */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RMP_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; // 8MHz * 9 = 72MHz
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* 配置系统时钟 */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // HCLK = 72MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // PCLK1 = 36MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // PCLK2 = 72MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}
/**
* @brief GPIO初始化
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO时钟使能 */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/* LED引脚配置 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // 默认关闭
}
/**
* @brief 错误处理
*/
void Error_Handler(void)
{
__disable_irq();
while(1)
{
/* LED快速闪烁表示错误 */
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(100);
}
}
四、高级功能扩展
4.1 数据滤波与平均
c
/**
* @file bmp280_filter.c
* @brief BMP280数据滤波
*/
#include "bmp280.h"
#define FILTER_WINDOW_SIZE 10
/* 滑动窗口滤波器 */
typedef struct {
float buffer[FILTER_WINDOW_SIZE];
uint8_t index;
uint8_t count;
float sum;
} MovingAverageFilter;
static MovingAverageFilter temp_filter = {0};
static MovingAverageFilter press_filter = {0};
static MovingAverageFilter alt_filter = {0};
/**
* @brief 初始化滤波器
*/
void BMP280_Filter_Init(void)
{
memset(&temp_filter, 0, sizeof(temp_filter));
memset(&press_filter, 0, sizeof(press_filter));
memset(&alt_filter, 0, sizeof(alt_filter));
}
/**
* @brief 滑动平均滤波
*/
float BMP280_MovingAverage(MovingAverageFilter *filter, float new_value)
{
/* 减去最旧的值 */
if(filter->count >= FILTER_WINDOW_SIZE)
{
filter->sum -= filter->buffer[filter->index];
}
/* 添加新值 */
filter->buffer[filter->index] = new_value;
filter->sum += new_value;
filter->index = (filter->index + 1) % FILTER_WINDOW_SIZE;
/* 更新计数 */
if(filter->count < FILTER_WINDOW_SIZE)
{
filter->count++;
}
/* 计算平均值 */
return filter->sum / filter->count;
}
/**
* @brief 卡尔曼滤波
*/
typedef struct {
float q; // 过程噪声协方差
float r; // 测量噪声协方差
float x; // 估计值
float p; // 估计误差协方差
float k; // 卡尔曼增益
} KalmanFilter;
static KalmanFilter temp_kalman = {0.001, 0.1, 25.0, 1.0, 0.0};
static KalmanFilter press_kalman = {0.001, 0.1, 1013.25, 1.0, 0.0};
float BMP280_KalmanFilter(KalmanFilter *kf, float measurement)
{
/* 预测 */
kf->p = kf->p + kf->q;
/* 更新 */
kf->k = kf->p / (kf->p + kf->r);
kf->x = kf->x + kf->k * (measurement - kf->x);
kf->p = (1 - kf->k) * kf->p;
return kf->x;
}
/**
* @brief 读取滤波后的数据
*/
uint8_t BMP280_ReadFilteredData(BMP280_Handle *bmp, BMP280_Data *data, uint8_t filter_type)
{
BMP280_Data raw_data;
/* 读取原始数据 */
if(BMP280_ReadData(bmp, &raw_data) != 0)
{
return 1;
}
/* 应用滤波 */
switch(filter_type)
{
case 0: // 无滤波
*data = raw_data;
break;
case 1: // 滑动平均
data->temperature = BMP280_MovingAverage(&temp_filter, raw_data.temperature);
data->pressure = BMP280_MovingAverage(&press_filter, raw_data.pressure);
data->altitude = BMP280_MovingAverage(&alt_filter, raw_data.altitude);
data->timestamp = raw_data.timestamp;
break;
case 2: // 卡尔曼滤波
data->temperature = BMP280_KalmanFilter(&temp_kalman, raw_data.temperature);
data->pressure = BMP280_KalmanFilter(&press_kalman, raw_data.pressure);
data->altitude = raw_data.altitude; // 海拔使用原始值
data->timestamp = raw_data.timestamp;
break;
}
return 0;
}
4.2 气象站功能
c
/**
* @file weather_station.c
* @brief 简单气象站功能
*/
#include "bmp280.h"
/* 气象数据记录 */
typedef struct {
float min_temp;
float max_temp;
float avg_temp;
float min_press;
float max_press;
float avg_press;
uint32_t sample_count;
uint32_t start_time;
} WeatherStats;
static WeatherStats weather_stats = {0};
static BMP280_Data history[24 * 60]; // 24小时历史数据,每分钟一个点
static uint8_t history_index = 0;
/**
* @brief 初始化气象统计
*/
void Weather_InitStats(void)
{
memset(&weather_stats, 0, sizeof(weather_stats));
weather_stats.min_temp = 100.0f;
weather_stats.max_temp = -100.0f;
weather_stats.min_press = 2000.0f;
weather_stats.max_press = 0.0f;
weather_stats.start_time = HAL_GetTick();
}
/**
* @brief 更新气象统计
*/
void Weather_UpdateStats(float temperature, float pressure)
{
weather_stats.sample_count++;
/* 温度统计 */
if(temperature < weather_stats.min_temp)
weather_stats.min_temp = temperature;
if(temperature > weather_stats.max_temp)
weather_stats.max_temp = temperature;
weather_stats.avg_temp += (temperature - weather_stats.avg_temp) / weather_stats.sample_count;
/* 气压统计 */
if(pressure < weather_stats.min_press)
weather_stats.min_press = pressure;
if(pressure > weather_stats.max_press)
weather_stats.max_press = pressure;
weather_stats.avg_press += (pressure - weather_stats.avg_press) / weather_stats.sample_count;
/* 保存历史数据 (每分钟) */
static uint32_t last_minute = 0;
uint32_t current_minute = HAL_GetTick() / 60000; // 转换为分钟
if(current_minute != last_minute)
{
last_minute = current_minute;
history[history_index].temperature = temperature;
history[history_index].pressure = pressure;
history[history_index].timestamp = HAL_GetTick();
history_index = (history_index + 1) % (24 * 60);
}
}
/**
* @brief 打印气象报告
*/
void Weather_PrintReport(void)
{
uint32_t uptime = (HAL_GetTick() - weather_stats.start_time) / 1000; // 秒
printf("\n=== Weather Station Report ===\n");
printf("Uptime: %lu seconds\n", uptime);
printf("Samples: %lu\n", weather_stats.sample_count);
printf("\nTemperature Statistics:\n");
printf(" Current: %.2f C\n", bmp_data.temperature);
printf(" Minimum: %.2f C\n", weather_stats.min_temp);
printf(" Maximum: %.2f C\n", weather_stats.max_temp);
printf(" Average: %.2f C\n", weather_stats.avg_temp);
printf("\nPressure Statistics:\n");
printf(" Current: %.2f hPa\n", bmp_data.pressure);
printf(" Minimum: %.2f hPa\n", weather_stats.min_press);
printf(" Maximum: %.2f hPa\n", weather_stats.max_press);
printf(" Average: %.2f hPa\n", weather_stats.avg_press);
printf("\nAltitude: %.2f m\n", bmp_data.altitude);
printf("==============================\n");
}
/**
* @brief 气压趋势分析
* @return 0:稳定, 1:上升, 2:下降, 3:快速变化
*/
uint8_t Weather_AnalyzePressureTrend(void)
{
static float last_pressure[3] = {0};
static uint8_t index = 0;
uint8_t trend = 0;
/* 保存最近3个压力值 */
last_pressure[index] = bmp_data.pressure;
index = (index + 1) % 3;
/* 计算变化率 */
if(last_pressure[0] != 0 && last_pressure[1] != 0 && last_pressure[2] != 0)
{
float change_1h = (last_pressure[2] - last_pressure[0]) / 2.0f;
if(change_1h > 0.5f)
{
trend = 1; // 上升
}
else if(change_1h < -0.5f)
{
trend = 2; // 下降
}
if(fabs(change_1h) > 2.0f)
{
trend = 3; // 快速变化
}
}
return trend;
}
/**
* @brief 天气预报
*/
const char* Weather_Forecast(void)
{
float pressure = bmp_data.pressure;
uint8_t trend = Weather_AnalyzePressureTrend();
if(pressure > 1022.0f && trend == 0) // 高压稳定
{
return "Clear/Sunny";
}
else if(pressure > 1013.0f && trend == 2) // 高压下降
{
return "Cloudy/Rain possible";
}
else if(pressure < 1000.0f && trend == 2) // 低压下降
{
return "Rain/Stormy";
}
else if(pressure < 1013.0f && trend == 1) // 低压上升
{
return "Clearing/Improving";
}
else
{
return "Fair/Partly cloudy";
}
}
参考代码 BMP280的i2c通信程序 www.youwenfan.com/contentcsv/70777.html
五、测试程序
5.1 完整测试程序
c
/**
* @file bmp280_test.c
* @brief BMP280测试程序
*/
#include "bmp280.h"
/**
* @brief 测试I2C扫描
*/
void Test_I2C_Scan(void)
{
printf("Scanning I2C bus...\n");
for(uint8_t addr = 0x08; addr < 0x78; addr++)
{
uint8_t result = HAL_I2C_IsDeviceReady(&hi2c1, addr << 1, 3, 10);
if(result == HAL_OK)
{
printf("Device found at address: 0x%02X\n", addr);
}
}
printf("Scan complete.\n");
}
/**
* @brief 测试BMP280基本功能
*/
void Test_BMP280_Basic(void)
{
printf("\n=== BMP280 Basic Test ===\n");
BMP280_Handle bmp;
BMP280_Data data;
/* 初始化 */
if(BMP280_Init(&bmp, &hi2c1, BMP280_I2C_ADDR_WRITE) != 0)
{
printf("Initialization failed!\n");
return;
}
/* 设置正常模式 */
BMP280_SetMode(&bmp, BMP280_MODE_NORMAL);
/* 连续读取10次 */
for(int i = 0; i < 10; i++)
{
if(BMP280_ReadData(&bmp, &data) == 0)
{
printf("Read %d: %.2f C, %.2f hPa, %.2f m\n",
i+1, data.temperature, data.pressure, data.altitude);
}
else
{
printf("Read %d: Failed\n", i+1);
}
HAL_Delay(1000);
}
printf("Test complete.\n");
}
/**
* @brief 测试不同过采样率
*/
void Test_Oversampling_Rates(void)
{
printf("\n=== Testing Oversampling Rates ===\n");
BMP280_Handle bmp;
BMP280_Data data;
/* 初始化 */
BMP280_Init(&bmp, &hi2c1, BMP280_I2C_ADDR_WRITE);
/* 测试温度过采样率 */
BMP280_Oversampling temp_osr[] = {
BMP280_OSR_SKIP, BMP280_OSR_X1, BMP280_OSR_X2,
BMP280_OSR_X4, BMP280_OSR_X8, BMP280_OSR_X16
};
const char* temp_osr_names[] = {
"SKIP", "X1", "X2", "X4", "X8", "X16"
};
for(int i = 0; i < 6; i++)
{
printf("\nTemperature OSR: %s\n", temp_osr_names[i]);
BMP280_SetOversampling(&bmp, temp_osr[i], BMP280_OSR_X16);
BMP280_SetMode(&bmp, BMP280_MODE_FORCED);
HAL_Delay(50); // 等待测量
if(BMP280_ReadData(&bmp, &data) == 0)
{
printf(" Temperature: %.2f C\n", data.temperature);
}
}
/* 测试气压过采样率 */
BMP280_Oversampling press_osr[] = {
BMP280_OSR_SKIP, BMP280_OSR_X1, BMP280_OSR_X2,
BMP280_OSR_X4, BMP280_OSR_X8, BMP280_OSR_X16
};
const char* press_osr_names[] = {
"SKIP", "X1", "X2", "X4", "X8", "X16"
};
for(int i = 0; i < 6; i++)
{
printf("\nPressure OSR: %s\n", press_osr_names[i]);
BMP280_SetOversampling(&bmp, BMP280_OSR_X2, press_osr[i]);
BMP280_SetMode(&bmp, BMP280_MODE_FORCED);
HAL_Delay(50); // 等待测量
if(BMP280_ReadData(&bmp, &data) == 0)
{
printf(" Pressure: %.2f hPa\n", data.pressure);
}
}
printf("\nOversampling test complete.\n");
}
/**
* @brief 测试滤波器
*/
void Test_Filter(void)
{
printf("\n=== Testing Filter Settings ===\n");
BMP280_Handle bmp;
BMP280_Data data;
/* 初始化 */
BMP280_Init(&bmp, &hi2c1, BMP280_I2C_ADDR_WRITE);
BMP280_SetOversampling(&bmp, BMP280_OSR_X2, BMP280_OSR_X16);
BMP280_SetMode(&bmp, BMP280_MODE_NORMAL);
/* 测试不同滤波器设置 */
BMP280_Filter filters[] = {
BMP280_FILTER_OFF, BMP280_FILTER_2,
BMP280_FILTER_4, BMP280_FILTER_8, BMP280_FILTER_16
};
const char* filter_names[] = {
"OFF", "2", "4", "8", "16"
};
for(int i = 0; i < 5; i++)
{
printf("\nFilter: %s\n", filter_names[i]);
BMP280_SetFilter(&bmp, filters[i]);
/* 等待滤波器稳定 */
HAL_Delay(1000);
/* 读取10个样本 */
float pressures[10];
for(int j = 0; j < 10; j++)
{
if(BMP280_ReadData(&bmp, &data) == 0)
{
pressures[j] = data.pressure;
printf(" Sample %d: %.2f hPa\n", j+1, pressures[j]);
}
HAL_Delay(100);
}
/* 计算标准差 */
float sum = 0, mean = 0, stddev = 0;
for(int j = 0; j < 10; j++) sum += pressures[j];
mean = sum / 10;
for(int j = 0; j < 10; j++)
{
stddev += (pressures[j] - mean) * (pressures[j] - mean);
}
stddev = sqrtf(stddev / 10);
printf(" Mean: %.2f hPa, StdDev: %.4f hPa\n", mean, stddev);
}
printf("\nFilter test complete.\n");
}
/**
* @brief 测试精度和稳定性
*/
void Test_Precision_Stability(void)
{
printf("\n=== Testing Precision and Stability ===\n");
BMP280_Handle bmp;
BMP280_Data data;
/* 初始化 */
BMP280_Init(&bmp, &hi2c1, BMP280_I2C_ADDR_WRITE);
/* 设置最高精度 */
BMP280_SetOversampling(&bmp, BMP280_OSR_X16, BMP280_OSR_X16);
BMP280_SetFilter(&bmp, BMP280_FILTER_16);
BMP280_SetMode(&bmp, BMP280_MODE_NORMAL);
printf("Collecting 100 samples (1 sample/second)...\n");
float temperatures[100];
float pressures[100];
for(int i = 0; i < 100; i++)
{
if(BMP280_ReadData(&bmp, &data) == 0)
{
temperatures[i] = data.temperature;
pressures[i] = data.pressure;
if(i % 10 == 0)
{
printf(" Sample %d: %.2f C, %.2f hPa\n",
i+1, data.temperature, data.pressure);
}
}
HAL_Delay(1000);
}
/* 计算统计数据 */
float temp_sum = 0, press_sum = 0;
float temp_min = 100, temp_max = -100;
float press_min = 2000, press_max = 0;
for(int i = 0; i < 100; i++)
{
temp_sum += temperatures[i];
press_sum += pressures[i];
if(temperatures[i] < temp_min) temp_min = temperatures[i];
if(temperatures[i] > temp_max) temp_max = temperatures[i];
if(pressures[i] < press_min) press_min = pressures[i];
if(pressures[i] > press_max) press_max = pressures[i];
}
float temp_mean = temp_sum / 100;
float press_mean = press_sum / 100;
float temp_stddev = 0, press_stddev = 0;
for(int i = 0; i < 100; i++)
{
temp_stddev += (temperatures[i] - temp_mean) * (temperatures[i] - temp_mean);
press_stddev += (pressures[i] - press_mean) * (pressures[i] - press_mean);
}
temp_stddev = sqrtf(temp_stddev / 100);
press_stddev = sqrtf(press_stddev / 100);
printf("\n=== Results ===\n");
printf("Temperature:\n");
printf(" Min: %.2f C, Max: %.2f C, Range: %.2f C\n",
temp_min, temp_max, temp_max - temp_min);
printf(" Mean: %.3f C, StdDev: %.3f C\n", temp_mean, temp_stddev);
printf(" Resolution: ~%.3f C\n", temp_stddev);
printf("\nPressure:\n");
printf(" Min: %.2f hPa, Max: %.2f hPa, Range: %.2f hPa\n",
press_min, press_max, press_max - press_min);
printf(" Mean: %.3f hPa, StdDev: %.3f hPa\n", press_mean, press_stddev);
printf(" Resolution: ~%.3f hPa\n", press_stddev);
printf(" Altitude resolution: ~%.2f m\n",
44330.0f * (1.0f - powf((press_mean - press_stddev) / press_mean, 0.190295f)));
printf("\nPrecision test complete.\n");
}
六、故障排除
6.1 常见问题解决
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| I2C通信失败 | 1. 地址错误 2. 上拉电阻未接 3. 总线冲突 | 1. 扫描I2C地址 2. 添加4.7k上拉电阻 3. 检查设备连接 |
| 数据不正确 | 1. 校准参数未读取 2. 补偿算法错误 3. 电源噪声 | 1. 检查校准读取 2. 验证补偿计算 3. 添加去耦电容 |
| 测量漂移 | 1. 自热效应 2. 环境变化 3. 传感器老化 | 1. 降低测量频率 2. 添加温度补偿 3. 重新校准 |
| 响应慢 | 1. 过采样率过高 2. 滤波器过强 3. 待机时间过长 | 1. 降低过采样率 2. 调整滤波器 3. 减少待机时间 |
6.2 调试函数
c
/**
* @brief BMP280调试函数
*/
void BMP280_Debug_Print(BMP280_Handle *bmp)
{
uint8_t reg_val;
printf("\n=== BMP280 Debug Info ===\n");
/* 读取所有主要寄存器 */
BMP280_ReadBytes(bmp, BMP280_REG_ID, ®_val, 1);
printf("ID Register: 0x%02X\n", reg_val);
BMP280_ReadBytes(bmp, BMP280_REG_RESET, ®_val, 1);
printf("Reset Register: 0x%02X\n", reg_val);
BMP280_ReadBytes(bmp, BMP280_REG_STATUS, ®_val, 1);
printf("Status Register: 0x%02X\n", reg_val);
printf(" Measuring: %s\n", (reg_val & 0x08) ? "Yes" : "No");
printf(" im_update: %s\n", (reg_val & 0x01) ? "Yes" : "No");
BMP280_ReadBytes(bmp, BMP280_REG_CTRL_MEAS, ®_val, 1);
printf("Ctrl_meas Register: 0x%02X\n", reg_val);
printf(" osrs_t: %d\n", (reg_val >> 5) & 0x07);
printf(" osrs_p: %d\n", (reg_val >> 2) & 0x07);
printf(" mode: %d\n", reg_val & 0x03);
BMP280_ReadBytes(bmp, BMP280_REG_CONFIG, ®_val, 1);
printf("Config Register: 0x%02X\n", reg_val);
printf(" t_sb: %d\n", (reg_val >> 5) & 0x07);
printf(" filter: %d\n", (reg_val >> 2) & 0x07);
printf("=========================\n");
}