基于LORA的一主多从监测系统_BMP280气压传感器

关联:LORA 、HAL、气压传感器

这个传感器也是比较常见的,但灵敏度什么的都没啥问题,不过气压传感器不是很好去观察这个变化,毕竟一个地方的大气压基本不会有太大波动,我们可以在百度搜索所在地的平均大气压,与我们测量得到的大气压进行对比,如果差的不是很多则认为没啥问题。

比如我测得大气压为101.4kpa,百度搜索南京平均大气压,差不多也在101.1左右,所以我们的测量是没问题的,说完这个如何判断我们的测量值是否正确,下面我们来说一下如何通过代码获取到这个气压值

这里我们使用硬件I2C来与气压传感器通信,首先我们需要定义如下寄存器地址

#define BMP280_REG_TEMP_XLSB   0xFC /* bits: 7-4 */
#define BMP280_REG_TEMP_LSB    0xFB
#define BMP280_REG_TEMP_MSB    0xFA
#define BMP280_REG_TEMP        (BMP280_REG_TEMP_MSB)
#define BMP280_REG_PRESS_XLSB  0xF9 /* bits: 7-4 */
#define BMP280_REG_PRESS_LSB   0xF8
#define BMP280_REG_PRESS_MSB   0xF7
#define BMP280_REG_PRESSURE    (BMP280_REG_PRESS_MSB)
#define BMP280_REG_CONFIG      0xF5 /* bits: 7-5 t_sb; 4-2 filter; 0 spi3w_en */
#define BMP280_REG_CTRL        0xF4 /* bits: 7-5 osrs_t; 4-2 osrs_p; 1-0 mode */
#define BMP280_REG_STATUS      0xF3 /* bits: 3 measuring; 0 im_update */
#define BMP280_REG_CTRL_HUM    0xF2 /* bits: 2-0 osrs_h; */
#define BMP280_REG_RESET       0xE0
#define BMP280_REG_ID          0xD0
#define BMP280_REG_CALIB       0x88
#define BMP280_REG_HUM_CALIB   0x88

#define BMP280_RESET_VALUE     0xB6

这些地址我们无需关心,如果只是使用这个传感器获取测量值我们无需关心太多底层的东西,我们只需要把精力放在代码逻辑以及实现上,我们可以粗略的理解为这些寄存器有一部分是控制功能,以及配置,有一部分是存放数据的,需要我么去读这个寄存器。

网上目前能找到的寄存器手册是博士的,手册是全英文的,但我们只需要关系重点信息,比如这个ID,这个ID就是我们去读器件指定的一个地址,可以读到一个值,这个值就是这个器件的ID,这个寄存器是可读寄存器,一般这个ID是出厂就固定的,不可修改。

我们读这个ID的作用是什么呢?

1、通过读这个ID我们可以判断设备的大概工作状态,以及与设备通信的链路是否正常,手册可以看到设备的ID为0x58,并且要读到这个ID,我们必须在传感器完成上电和重启之后

2、这个ID我们可以写到器件初始化里面,通过初始化时读取这个器件ID实现判断器件是否正常工作和准备就绪

这个寄存器是设备状态寄存器,一共有两个bit构成,手册了分别有对这两个bit的具体含义说明,这个我们一般也不用太过关心

这个是我们需要好好去研究的寄存器,我们所需要的压力数据就是从这个寄存器获得,分别有三个寄存器,这三个寄存器分别保存压力数据的高位、低位、小数位,注意0xF9里面只有bit7-bit4是我们的需要的,其余四个bit我们不用关心。

知道从哪个寄存器读取数据,我们也要关心一下读到的数据是不是直接可用,还是需要进行转换,通过手册我们可以看到读到的单位为Pa,我们日常使用的是KPa,我们将得到的值缩小一千倍就可以。

下面是部分核心代码

/**
 * @brief 读取 BMP280 或 BME280 传感器的温度、压力和湿度数据。
 * 
 * @param dev 指向 BMP280 设备的句柄,包含设备的配置信息和标识符。
 * @param temperature 指向整型变量的指针,用于存储读取到的温度值(单位:摄氏度)。
 * @param pressure 指向无符号整型变量的指针,用于存储读取到的压力值(单位:Pa)。
 * @param humidity 指向无符号整型变量的指针,用于存储读取到的湿度值(单位:%RH)。
 * 
 * @return 
 *   - true: 数据读取成功。
 *   - false: 数据读取失败,可能由于设备通信错误或读取数据不正确。
 * 
 * @note 
 *   - 该函数根据传感器的 ID 检查是否支持湿度读取。如果设备不是 BME280,则湿度值将被置为 0,且湿度指针将被设置为 NULL。
 *   - 温度、压力和湿度的读取操作在一个序列中完成,以确保数据的一致性。
 *   - 读取的数据格式为 6 或 8 字节,具体取决于湿度是否被请求。对应的读取地址为 0xf7。
 *   - 原始压力和温度数据由传感器返回,并通过相应的补偿函数进行转换,得出实际的物理值。
 *   - 如果请求湿度数据,则还将读取 2 字节的湿度值,并使用补偿函数进行处理。
 */
bool bmp280_read_fixed(BMP280_HandleTypedef *dev, int32_t *temperature, uint32_t *pressure,
		uint32_t *humidity) {
	int32_t adc_pressure;          // 原始压力数据
	int32_t adc_temp;             // 原始温度数据
	uint8_t data[8];              // 存储读取的原始数据

	// 只有 BME280 支持读取湿度。
	if (dev->id != BME280_CHIP_ID) {
		if (humidity)
			*humidity = 0;        // 如果不支持湿度,设置湿度为 0
		humidity = NULL;         // 将湿度指针设置为 NULL
	}

	// 需要一次性读取,以确保数据一致性。
	size_t size = humidity ? 8 : 6;  // 根据是否读取湿度确定读取字节数
	if (read_data(dev, 0xf7, data, size)) {
		return false;             // 读取数据失败
	}

	// 解析原始压力和温度数据
	adc_pressure = data[0] << 12 | data[1] << 4 | data[2] >> 4;
	adc_temp = data[3] << 12 | data[4] << 4 | data[5] >> 4;

	int32_t fine_temp;              // 用于补偿温度计算的临时变量
	*temperature = compensate_temperature(dev, adc_temp, &fine_temp); // 补偿温度
	*pressure = compensate_pressure(dev, adc_pressure, fine_temp);     // 补偿压力

	if (humidity) {
		// 读取并补偿湿度数据
		int32_t adc_humidity = data[6] << 8 | data[7];
		*humidity = compensate_humidity(dev, adc_humidity, fine_temp); // 补偿湿度
	}

	return true;                   // 成功读取所有数据
}

忘记说了,BMP280传感器也能测温度,但是我们有AHT20所以就不需要他的温度值,从上面的代码来看,比较关键的函数有两个,这两个函数分别处理温度和气压,这里我们只关心气压compensate_pressure,具体实现如下:

/**
 * @brief 补偿 BMP280 传感器的原始压力数据,计算实际压力值。
 * 
 * @param dev 指向 BMP280 设备的句柄,包含设备的校准系数。
 * @param adc_press 原始压力数据,从传感器读取的 ADC 值。
 * @param fine_temp 经过补偿的温度值,用于压力计算的精确度提高。
 * 
 * @return 计算得到的实际压力值(单位:Pa)。
 *         如果计算过程中出现除零错误,则返回 0。
 * 
 * @note 
 *   - 该函数根据传感器的校准系数(如 dig_P1, dig_P2 等)进行复杂的补偿计算。
 *   - 计算过程中使用了多个中间变量(var1 和 var2)来帮助获得最终的压力值。
 *   - 为了避免除零错误,函数首先检查 var1 是否为 0。如果是,则返回 0。
 *   - 返回的压力值是以 Pa 为单位的实际压力值,可用于进一步的数据处理和分析。
 */
static inline uint32_t compensate_pressure(BMP280_HandleTypedef *dev, int32_t adc_press,
        int32_t fine_temp) {
    int64_t var1, var2, p;

    var1 = (int64_t) fine_temp - 128000;  // 将温度值转换为 var1
    var2 = var1 * var1 * (int64_t) dev->dig_P6; // 根据校准系数计算 var2
    var2 = var2 + ((var1 * (int64_t) dev->dig_P5) << 17); // 累加压力校准系数
    var2 = var2 + (((int64_t) dev->dig_P4) << 35); // 累加压力校准系数
    var1 = ((var1 * var1 * (int64_t) dev->dig_P3) >> 8)
            + ((var1 * (int64_t) dev->dig_P2) << 12); // 完成 var1 的计算
    var1 = (((int64_t) 1 << 47) + var1) * ((int64_t) dev->dig_P1) >> 33; // 计算最终的 var1

    if (var1 == 0) {
        return 0;  // 避免因除零而引发的异常
    }

    p = 1048576 - adc_press;  // 计算压力的初步值
    p = (((p << 31) - var2) * 3125) / var1; // 应用补偿公式

    // 根据校准系数计算最终压力值的修正
    var1 = ((int64_t) dev->dig_P9 * (p >> 13) * (p >> 13)) >> 25;
    var2 = ((int64_t) dev->dig_P8 * p) >> 19;

    p = ((p + var1 + var2) >> 8) + ((int64_t) dev->dig_P7 << 4); // 计算最终压力值
    return p; // 返回实际压力值
}

这个玩意具体实现不需要理解,我们只用知道返回的为实际压力值即可,找个变量接着返回值就OK啦,

手册上也提供了一些计算代码,感兴趣可以去研究一下,我们这里调用这个函数的时候传入指向无符号整型变量的指针,用来保存数据。

我们在实际展示的时候缩小1000倍就可以,至此气压传感器的驱动实现完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值