mmuyu 发表于 2023-10-10 23:37:02

BMP280 气压补偿及数据转换

    通常bmp280采样得到的数据是未经转换的,例如30万hpa的气压数值肯定是不正常的,那么我们就得进行转换和对气压进行补偿。

首先,我们看一下官方给出的气压转换的算法需要哪些寄存器数据进行补偿转换:



可以看见,里面的dig_P2就是寄存器数据,除了要求使用P1到P9的数据进行转换,还需要使用到温度进行气压补偿,因此我们除了读取气压,气压相关的寄存器之外,我们还需要读取温度和温度相关的寄存器进行计算得到精确的数值。

对应寄存器的地址是:



每个寄存器由两个直接组成,因此我们对每个寄存器的数值要取出后再重新组合

接下来,我们编写代码取出数值放到全局变量,变量类型根据手册给出的即可。

全局变量:



封装一下寄存器的读取函数,把两个字节组成short:

short bmp280_reg_read(char addr){
    short temp=0;
    I2C_GenerateSTART(I2C1, ENABLE);//启动iic
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );//等待切换到主线模式
    I2C_Send7bitAddress(I2C1, 0xee, I2C_Direction_Transmitter);//发送从机地址 写模式
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//等待切换到发送模式
    I2C_SendData(I2C1, addr);//发送读id地址

    I2C_GenerateSTART(I2C1, ENABLE);
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress(I2C1, 0xef, I2C_Direction_Receiver);//发送从机地址 读模式
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//等待切换到接收模式 同时充当ack确认
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));//等待接收数据
    uint8_t l_temp=I2C_ReceiveData(I2C1);
    I2C_AcknowledgeConfig(I2C1, DISABLE);//主机发送ack
    I2C_GenerateSTOP(I2C1, ENABLE);

    I2C_GenerateSTART(I2C1, ENABLE);
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress(I2C1, 0xee, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    I2C_SendData(I2C1, addr+1);

    I2C_GenerateSTART(I2C1, ENABLE);
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress(I2C1, 0xef, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
    uint8_t m_temp=I2C_ReceiveData(I2C1);
    I2C_AcknowledgeConfig(I2C1, DISABLE);
    I2C_GenerateSTOP(I2C1, ENABLE);

    temp=((short)m_temp<<8);
    temp|=(short)l_temp;
    printf("reg_data:%d\n",temp);
    return temp;

}

同时也把上次的气压温度封装成一个函数:

uint32_t bmp280_get_val(char addr){
    uint8_t temp_data[] = { 0x00, 0x00, 0x00 };
    I2C_GenerateSTART(I2C1, ENABLE);
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress(I2C1, 0xee, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    I2C_SendData(I2C1, addr);

    I2C_GenerateSTART(I2C1, ENABLE);
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress(I2C1, 0xef, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
    temp_data = I2C_ReceiveData(I2C1);
    I2C_AcknowledgeConfig(I2C1, DISABLE);
    I2C_GenerateSTOP(I2C1, ENABLE);

    I2C_GenerateSTART(I2C1, ENABLE);
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress(I2C1, 0xee, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    I2C_SendData(I2C1, addr+1);

    I2C_GenerateSTART(I2C1, ENABLE);
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress(I2C1, 0xef, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
    temp_data = I2C_ReceiveData(I2C1);
    I2C_AcknowledgeConfig(I2C1, DISABLE);
    I2C_GenerateSTOP(I2C1, ENABLE);

    I2C_GenerateSTART(I2C1, ENABLE);
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress(I2C1, 0xee, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    I2C_SendData(I2C1, addr+2);

    I2C_GenerateSTART(I2C1, ENABLE);
    while( !I2C_CheckEvent( I2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress(I2C1, 0xef, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
    temp_data = I2C_ReceiveData(I2C1);
    I2C_AcknowledgeConfig(I2C1, DISABLE);
    I2C_GenerateSTOP(I2C1, ENABLE);

    uint32_t temp_val= (uint32_t)((uint32_t)temp_data << 12) | (uint32_t)(temp_data << 4) | (uint32_t)(temp_data >> 4);
    return temp_val;

}

接下来,是两个温度和气压补偿的算法,我们可以看pdf提供的代码:



因为文档的问题,里面的字符编码不同,直接复制粘贴会出错并且由于变量类型不同,我们需要做一点小修改,以适配stm32或者riscv32:

double bmp280_compensate_T_double(int32_t adc_T)
{
    double var1, var2, T;
    var1=((((double)adc_T)/16384.0)-(((double)dig_T1)/1024.0)) *((double)dig_T2);
    var2=((((double)adc_T)/131072.0-((double)dig_T1)/8192.0) * (((double)adc_T)/131072.0-((double)dig_T1)/8192.0)) *((double)dig_T3);
    t_fine = (int32_t) (var1 + var2);
    T = (var1 + var2) / 5120.0;
    return T;
}

double bmp280_compensate_P_double(int32_t adc_P) {
    double var1, var2, p;
    var1 = ((double) t_fine / 2.0) - 64000.0;
    var2 = var1 * var1 * ((double) dig_P6) / 32768.0;
    var2 = var2 + var1 * ((double) dig_P5) * 2.0;
    var2 = (var2 / 4.0) + (((double) dig_P4) * 65536.0);
    var1 = (((double) dig_P3) * var1 * var1 / 524288.0+ ((double) dig_P2) * var1) / 524288.0;
    var1 = (1.0 + var1 / 32768.0) * ((double) dig_P1);
    if (var1 == 0.0) {
      return 0; // avoid exception caused by division by zero
    }
    p = 1048576.0 - (double)adc_P;
    p = (p - (var2 / 4096.0)) * 6250.0 / var1;
    var1 = ((double) dig_P9) * p * p / 2147483648.0;
    var2 = p * ((double) dig_P8) / 32768.0;
    p = p + (var1 + var2 + ((double) dig_P7)) / 16.0;
    return p;
}

最后,我们只需要读取寄存器的补偿值,通过文档提供的算法对气压和文温度进行转换即可:



通过串口查看数据:



可以看到,转换得到32摄氏度和103609pa的气压,对应1036千帕,我们找一部手机可以支持气压检测的查看目前气压:



可以看到,有点误差,但是还算接近。



不知道不敢问 发表于 2023-10-15 17:49:57

针不戳,加油!:)
页: [1]
查看完整版本: BMP280 气压补偿及数据转换