STM32 之BMP280的应用--基于RTOS的环境
文章目录
- 1 项目应用
- 1.1 介绍一下bmp280
- 1.2 性能尺寸
- 1.2 工作原理
- 1.3 典型应用
- 1.4 与 BMP388 的对比
- 1.4 总结
- 2 电路介绍
- 2.1 设计原理图
- 2.2 接线说明
- 3 应用开发
- 3.1 软I2C 配置
- 3.2 BMP280 初始化
- 3.3 温度和压强读取, 数据校准
1 项目应用
项目中需要采集大气压力,通过采集大气压力,初步估算现在的高度。
1.1 介绍一下bmp280
BMP280 是 Bosch Sensortec 推出的一款高精度、低功耗的数字式气压传感器。它是前代产品 BMP180 的升级版,在尺寸、精度和噪音性能上都有显著改进。它通过测量大气压来间接计算海拔高度,同时也能提供温度读数。由于其优异的性能和低廉的价格,BMP280 在创客项目、消费电子和工业应用中变得极其流行。
1.2 性能尺寸
主要特点和优势
高精度:
气压精度: 典型值为 ±1 hPa(相当于海平面高度变化约 ±8.5米)。
相对精度: 更佳,非常适合测量相对高度变化。
温度精度: 典型值为 ±1.0°C。
低功耗:
在标准模式下的功耗仅为 2.7 μA,这使得它非常适合电池供电的便携设备,如智能手机、GPS追踪器或户外传感器。
高分辨率与低噪音:
气压和温度读数具有很高的分辨率,可以通过配置滤波器来优化性能,适应不同的应用场景(如天气监测或无人机飞行)。
小尺寸:
采用极其紧凑的 LGA 封装,尺寸仅为 2.0 × 2.5 × 0.95 mm³。这使其可以轻松集成到空间受限的移动设备中。
强大的接口支持:
支持标准的 I²C 和 SPI 通信协议,可以灵活地与各种微控制器(如 Arduino, ESP32, Raspberry Pi Pico)连接。
高响应速率:
相比于 BMP180,BMP280 的数据输出速率更快,更适合需要快速响应的应用。
1.2 工作原理
BMP280 的核心是一个微机电系统(MEMS) 压阻式压力传感器和一个温度传感器。
传感器内部的硅膜会随着外界气压的变化而产生微小的形变。
这种形变会导致嵌入在硅膜上的压敏电阻的电阻值发生变化。
内置的 ASIC(专用集成电路)将这些模拟信号转换为高分辨率的数字信号,并通过 I²C 或 SPI 接口输出。
温度传感器用于对气压测量进行温度补偿,以确保读数在不同温度环境下的准确性。
1.3 典型应用
凭借其测量气压和温度的能力,BMP280 被广泛应用于:
海拔高度测量:通过气压值换算得到高度(注意:高度精度受天气变化影响)。
天气预报:监测气压变化趋势,可以用于预测短期的天气变化(例如,气压持续下降通常预示着坏天气的到来)。
室内室外导航:作为 GPS 的补充,在GPS信号弱时(如隧道、城市峡谷)或无法提供高度信息时提供辅助导航。
健康与运动监测:用于可穿戴设备,记录爬楼梯、登山等活动的海拔增益。
无人机和飞行控制器:提供关键的高度保持(定高)数据。
物联网(IoT)节点:作为环境数据记录仪,收集气压和温度信息。
1.4 与 BMP388 的对比
简单总结:BMP388 是 BMP280 的高性能升级版,主要在精度、稳定性和功耗上进行了优化。对于大多数业余项目和一般性应用,BMP280 已经完全足够且性价比极高。而对于有严格性能要求的专业应用,则应选择 BMP388。
1.4 总结
BMP280 是一款功能强大、经济实惠且易于使用的环境传感器,是嵌入式项目和物联网应用的瑞士军刀。它在精度、功耗和成本之间取得了完美的平衡,这也是其经久不衰的原因。如果您正在寻找一款入门级的气压/高度计,BMP280 是一个非常可靠的选择。
2 电路介绍
2.1 设计原理图
2.2 接线说明
这里通讯采用I2C的通讯
VCC 接 3.3V
GND 接 GND
SCL 接 PB8
SDA 接 PB9
3 应用开发
3.1 软I2C 配置
这里采用软I2C,主要的原因:在测试过程总。软的I2C会相对比较稳定。
// 向指定设备写入数据
uint8_t Soft_I2C_Write(uint8_t devAddr, uint8_t regAddr, uint8_t *pData, uint16_t len)
{uint16_t i;Soft_I2C_Start(); // 起始信号Soft_I2C_Send_Byte(devAddr & 0xFE); // 发送设备地址+写模式if(Soft_I2C_Wait_Ack()) // 等待应答{Soft_I2C_Stop();return 1;}Soft_I2C_Send_Byte(regAddr); // 发送寄存器地址if(Soft_I2C_Wait_Ack()){Soft_I2C_Stop();return 1;}for(i = 0; i < len; i++){Soft_I2C_Send_Byte(pData[i]); // 发送数据if(Soft_I2C_Wait_Ack()){Soft_I2C_Stop();return 1;}}Soft_I2C_Stop(); // 停止信号return 0;
}// 从指定设备读取数据
uint8_t Soft_I2C_Read(uint8_t devAddr, uint8_t regAddr, uint8_t *pData, uint16_t len)
{Soft_I2C_Start(); // 起始信号Soft_I2C_Send_Byte(devAddr & 0xFE); // 发送设备地址+写模式if(Soft_I2C_Wait_Ack()){Soft_I2C_Stop();return 1;}Soft_I2C_Send_Byte(regAddr); // 发送寄存器地址if(Soft_I2C_Wait_Ack()){Soft_I2C_Stop();return 1;}Soft_I2C_Start(); // 重复起始信号Soft_I2C_Send_Byte(devAddr | 0x01); // 发送设备地址+读模式if(Soft_I2C_Wait_Ack()){Soft_I2C_Stop();return 1;}// 读取数据for(uint16_t i = 0; i < len; i++){if(i == len - 1)pData[i] = Soft_I2C_Read_Byte(1); // 最后一个字节发送NACKelsepData[i] = Soft_I2C_Read_Byte(0); // 发送ACK继续读取}Soft_I2C_Stop(); // 停止信号return 0;
}I2C_Status I2C1_ReadByte(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data)
{u8 res;dev_addr<<=1;res=Soft_I2C_Read(dev_addr,reg_addr,data,1);if(res==0)return I2C_OK;elsereturn I2C_TIMEOUT;}
I2C_Status I2C1_ReadBytes(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len)
{u8 res;dev_addr<<=1;res=Soft_I2C_Read(dev_addr,reg_addr,data,len);if(res==0)return I2C_OK;elsereturn I2C_TIMEOUT;}I2C_Status I2C1_WriteByte(uint8_t dev_addr, uint8_t reg_addr, uint8_t data)
{u8 res;dev_addr<<=1;res=Soft_I2C_Write(dev_addr,reg_addr,&data,1);if(res==0)return I2C_OK;elsereturn I2C_TIMEOUT;
}
3.2 BMP280 初始化
配置 BMP280 的核心在于理解和操作其内部的控制寄存器。整个过程可以分为以下几个步骤:初始化 -> 配置工作模式 -> 配置滤波与输出数据速率 -> 读取数据。
步骤一:初始化和通信检查
初始化 I²C/SPI 通信。
读取 WHO_AM_I 寄存器(地址 0xD0)。BMP280 固定返回 0x58。这是一个确认传感器连接正确的良好方式。
步骤二:配置测量模式 (CTRL_MEAS)
这是最核心的配置,决定了传感器如何工作。
选择过采样率 (osrs_t 和 osrs_p):
更高的过采样率意味着传感器会采集更多样本进行平均,从而提高精度,但也会增加功耗和测量时间。
设置为 0 (跳过) 可以节省功耗,如果你不需要该数据。
常用设置:对于高度测量,通常压力采样率设置得比温度更高,例如 osrs_p = 0x05 (x16), osrs_t = 0x02 (x2)。
选择工作模式 (mode):
休眠模式 (Sleep): 00 - 低功耗模式,不进行任何测量。
强制模式 (Forced): 01 或 10 - 执行一次测量,将结果存入数据寄存器,然后自动返回休眠模式。适用于低功耗应用的按需测量。
正常模式 (Normal): 11 - 持续循环测量。测量间隔 = 测量时间 + standby time (t_sb)。
步骤三:配置滤波和待机时间 (CONFIG)
这个寄存器主要优化在 Normal mode 下的数据输出。
IIR 滤波器 (filter):
用于平滑输出数据,抑制高频噪音(例如无人机旋翼引起的快速气压变化)。
滤波器系数越高,输出越平滑,但对气压变化的响应也会变慢。
对于气象监测,推荐使用较高的滤波(如 4 或 8)。对于高度快速变化的无人机,推荐使用较低的滤波(如 2 或关闭)。
待机时间 (t_sb):
仅在 Normal mode 下有效。
它定义了两次测量之间的间隔时间。与 osrs_p 和 osrs_t 共同决定输出数据速率 (ODR)。
ODR = 1 / (测量时间 + standby_time)
// 初始化BMP280
uint8_t BMP280_Init(BMP280_Device *dev, uint8_t i2c_addr)
{dev->addr = i2c_addr; u8 sta;// 检查设备IDif ((sta=BMP280_ReadID(dev) )!= 0x58) {rt_kprintf("BMP280 not found!\n");rt_kprintf("is id %d\r\n",sta);return 0;}// 复位设备if (BMP280_Reset(dev) != I2C_OK) {rt_kprintf("BMP280 reset failed!\n");return 0;}rt_thread_mdelay(10);// 读取校准数据if (BMP280_ReadCalibrationData(dev) != I2C_OK) {rt_kprintf("Read calibration data failed!\n");return 0;}// 配置传感器if (BMP280_Config(dev, BMP280_MODE_NORMAL, BMP280_OSRS_2X, BMP280_OSRS_16X,BMP280_FILTER_16, BMP280_STANDBY_250) != I2C_OK) {rt_kprintf("BMP280 config failed!\n");return 0;}return 1;
}
3.3 温度和压强读取, 数据校准
在 Forced mode 下,写入模式后需要等待测量完成。可以通过读取 STATUS 寄存器(地址 0xF3)的 measuring bit (bit3) 来判断,为 1 表示正在转换,为 0 表示完成。更简单的方法是延时等待(数据手册提供了最大转换时间表,例如 16x 压力采样 + 2x 温度采样约需 7.6ms)。
读取数据:
一次性读取从 PRESS_MSB (0xF7) 到 TEMP_LSB (0xFA) 的共 6 个字节的数据寄存器。
补偿计算:
原始的压力和温度数据(通常是 20-bit)需要根据芯片内部存储的校准参数(共 24 个,从地址 0x88 到 0xA1)进行复杂的补偿计算,才能得到精确的值。这个过程通常由一个专门的函数(如 bmp280_compensate_T_int32(), bmp280_compensate_P_int64())来完成。强烈建议使用官方或 Adafruit 的驱动库,它们已经实现了这些复杂的计算。
// 读取传感器数据
uint8_t BMP280_ReadData(BMP280_Device *dev)
{uint8_t data[6];int32_t adc_p, adc_t;// 读取原始数据if (I2C1_ReadBytes(dev->addr, BMP280_REG_PRESS_MSB, data, 6) != I2C_OK) {return I2C_ERROR;}// 组合压力数据adc_p = (int32_t)(((uint32_t)data[0] << 12) | ((uint32_t)data[1] << 4) | ((uint32_t)data[2] >> 4));// 组合温度数据adc_t = (int32_t)(((uint32_t)data[3] << 12) | ((uint32_t)data[4] << 4) | ((uint32_t)data[5] >> 4));// 计算实际值BMP280_CalculateData(dev, adc_t, adc_p);return I2C_OK;
}// 计算实际温度气压值
void BMP280_CalculateData(BMP280_Device *dev, int32_t adc_t, int32_t adc_p)
{int32_t var1, var2, t_fine;int64_t var1_p, var2_p, p;BMP280_CalibData *calib = &dev->calib;// 计算温度(官方算法)var1 = ((((adc_t >> 3) - ((int32_t)calib->dig_T1 << 1))) * ((int32_t)calib->dig_T2)) >> 11;var2 = (((((adc_t >> 4) - ((int32_t)calib->dig_T1)) * ((adc_t >> 4) - ((int32_t)calib->dig_T1))) >> 12) * ((int32_t)calib->dig_T3)) >> 14;t_fine = var1 + var2;// 温度转换为摄氏度dev->data.temperature = (t_fine * 5 + 128) >> 8;dev->data.temperature /= 100.0f;// 计算压力(官方算法)var1_p = ((int64_t)t_fine) - 128000;var2_p = var1_p * var1_p * (int64_t)calib->dig_P6;var2_p = var2_p + ((var1_p * (int64_t)calib->dig_P5) << 17);var2_p = var2_p + (((int64_t)calib->dig_P4) << 35);var1_p = ((var1_p * var1_p * (int64_t)calib->dig_P3) >> 8) + ((var1_p * (int64_t)calib->dig_P2) << 12);var1_p = (((((int64_t)1) << 47) + var1_p)) * ((int64_t)calib->dig_P1) >> 33;if (var1_p == 0) {dev->data.pressure = 0;return;}p = 1048576 - adc_p;p = (((p << 31) - var2_p) * 3125) / var1_p;var1_p = (((int64_t)calib->dig_P9) * (p >> 13) * (p >> 13)) >> 25;var2_p = (((int64_t)calib->dig_P8) * p) >> 19;p = ((p + var1_p + var2_p) >> 8) + (((int64_t)calib->dig_P7) << 4);dev->data.pressure = (float)p / 256.0f;// 计算海拔(简化公式,海平面气压为101325Pa)dev->data.altitude = 44330.0f * (1.0f - powf(dev->data.pressure / 101325.0f, 0.1903f));
}