其他分享
首页 > 其他分享> > stm32驱动BMP388温度气压传感器

stm32驱动BMP388温度气压传感器

作者:互联网

        最近在搞一个小东西用到了气压传感器,最终选择了BMP388。搜索发现网上关于388的资料少之又少,官方给出的Arduino代码几千行全是英文注释。。。所以去翻看了一下数据手册做了些笔记,分享出来希望帮助有需要的同学。第一次发文章如有错误还请海涵。下面先贴上成功的图片:

                                     

BMP388的一些特性介绍:

  1. 它有FIFO存储器,可以不断采集数据存入其中然后一次读出,不使用。
  2. 有中断引脚,可产生FIFO溢出中断或者数据准备完毕中断等,不使用。
  3. 有SPI模式和IIC模式,我用的是IIC模式,此时CS引脚要接高。SDO用于决定IIC地址,SDO接地为0x76,SDO为0x77,这里我们的SDO接地。
  4. 有三种模式,Sleep是睡眠模式,Force是一次采样进入Sleep,Normal是按照一定的采样间隔连续多次采样,这里采用Normal。

相关寄存器的介绍:

                            

上面是一些场景的推荐设置,从上到下分别是低功耗手持设备,动态手持设备,天气预测,掉落检测,室内导航,无人机。osrs_p是气压过采样等级,osrs_t是温度过采样等级,IIR那个是滤波等级。)

                                                     

0x1D寄存器的一些补充介绍

以下内容都是我猜测的哈,不知道正不正确。

             

如图,在Normal模式下,每一个采样间隔Ts由采样时间和空闲时间组成,这个Ts通过设置0x1D寄存器(odr_sel)来设置。寄存器为0x00的时候是1分频,Ts=5ms即200Hz,当寄存器为0x01的时候是2分频,寄存器为0x03的时候是4分频这个样子,最大为0x11。但是我们要预防一种情况,就是采样是需要时间的,如果这个时间比Ts还大,那么还没采样结束就又开始了一次采样,可能就出问题了,所以我们要预防这种情况,因此需要计算采样时间Tconv,计算公式如下:    

                           

举个例子,在我们代码中设置osr_t和osr_p都是000,也就是设置的过采样系数都是1,当然这么设置精度相对会低一些。

按照公式,这时候Tconv = 4939us ,这时候算出来的odr_sel是0x00(对应分频系数1),因此最大输出速率可以设置为200Hz,0x1D那个寄存器写0x00就行了。不过因为转换时间Tconv跟Ts=5ms太接近了,为了避免意外,我们最后在0x0D寄存器写0x01对应输出2分频,这样两次采样间隔就是10ms,由4.949ms的Tconv和(10-4.949)ms的空闲时间组成。

读写寄存器

这里我们用的是IIC协议,大致说一下读写过程。(建议IIC协议stm32的输出引脚配置为开漏吧,虽然我也不知道为啥。)

IIC写:

  1. 首先发送开始信号,然后发送从机地址左移一位加上读写控制位构成的8位数据,其中读写控制位为0是写,是1则为读(看图),然后等待从机应答。
  2. 发送寄存器地址、等待从机应答、发送要写的数据、等待从机应答
  3. 重复2直到要配置的寄存器配置完(如果只写一个寄存器可以跳过这步)。
  4. 发送结束信号。

  IIC读:

  1. 发送开始信号,然后先设置为写模式,等待应答,然后发送要读取的寄存器地址,等待应答,可以选择发送一个结束信号也可以不发送。
  2. 再发送开始信号,设置为读模式,等待从机应答,然后就会接收到要读的内容,数据高位在前,读完8位后,如果此时主机发送应答信号给从机,那么从机将自动将下一个寄存器的数据发送过来,直到主机发送不应答信号,主机再发送一个结束信号通讯结束。
  3. 一般来说,我们需要读的是气压和温度数据,而这48位数据是再连续的地址中,因此可以设置要读的寄存器为0x04,然后就可以连续读取6次数据,每读完8位发送一个应答信号,这样就可以一次性读完48位数据,连续读是官方推荐的方式,官方不推荐每次只读一个寄存器的数据,因为会容易造成数据混乱。同理,我们也可以一次读完那21个修正系数相关的寄存器。

总的流程

1.尝试读取0x00寄存器,看读到的是否为0x50,如果是则通信成功。

2.读取21个修正寄存器的值保存下来后面会用到。

3.往0x7E寄存器写0xB6重置全部寄存器(这一步应该是可以跳过的)。

4.配置过采样系数,配置滤波系数,使能气压采样或者温度采样或者都使能,配置分频寄存器的值,选择Normal模式即可开始采样。

5.查询0x03寄存器相关位是否1,若为1则代表采样结束了,可以读数了。

6.按照修正算法修正读到的值。

相关算法代码如下:

修正系数产生:

   //这里是把读到的21个寄存器值合成相关的修正系数,存在结构体内
    calib_data.par_t1  = Concat_Bytes(reg_data[1], reg_data[0]);
    calib_data.par_t2  = Concat_Bytes(reg_data[3], reg_data[2]);
    calib_data.par_t3  = (int8_t)reg_data[4];
    calib_data.par_p1  = (int16_t)Concat_Bytes(reg_data[6], reg_data[5]);
    calib_data.par_p2  = (int16_t)Concat_Bytes(reg_data[8], reg_data[7]);
    calib_data.par_p3  = (int8_t)reg_data[9];
    calib_data.par_p4  = (int8_t)reg_data[10];
    calib_data.par_p5  = Concat_Bytes(reg_data[12], reg_data[11]);
    calib_data.par_p6  = Concat_Bytes(reg_data[14],  reg_data[13]);
    calib_data.par_p7  = (int8_t)reg_data[15];
    calib_data.par_p8  = (int8_t)reg_data[16];
    calib_data.par_p9  = (int16_t)Concat_Bytes(reg_data[18], reg_data[17]);
    calib_data.par_p10 = (int8_t)reg_data[19];
    calib_data.par_p11 = (int8_t)reg_data[20];

 先修正温度

//先修正温度,里面有个t_lin在修正气压的时候用到,因为气压跟温度有某种关系嘛
//uncomp是一个结构体保存了未修正的温度和气压
void compensate_temperature()
{
    uint64_t partial_data1;
    uint64_t partial_data2;
    uint64_t partial_data3;
    int64_t  partial_data4;
    int64_t  partial_data5;
    int64_t  partial_data6;
    int64_t  comp_temp;

    partial_data1 = uncomp_data.temperature - (256 * calib_data.par_t1);
    partial_data2 = calib_data.par_t2 * partial_data1;
    partial_data3 = partial_data1 * partial_data1;
    partial_data4 = (int64_t)partial_data3 * calib_data.par_t3;
    partial_data5 = ((int64_t)(partial_data2 * 262144) + partial_data4);
    partial_data6 = partial_data5 / 4294967296;
    calib_data.t_lin = partial_data6;              
    comp_temp = (int64_t)((partial_data6 * 25)  / 16384);
    comp_data.temperature = comp_temp;   //修正结果保存在comp结构体内
}

再修正气压 

//修正气压
void compensate_pressure()
{
    int64_t partial_data1;
    int64_t partial_data2;
    int64_t partial_data3;
    int64_t partial_data4;
    int64_t partial_data5;
    int64_t partial_data6;
    int64_t offset;
    int64_t sensitivity;
    uint64_t comp_press;

    partial_data1 = calib_data.t_lin * calib_data.t_lin;
    partial_data2 = partial_data1 / 64;
    partial_data3 = (partial_data2 * calib_data.t_lin) / 256;
    partial_data4 = (calib_data.par_p8 * partial_data3) / 32;
    partial_data5 = (calib_data.par_p7 * partial_data1) * 16;
    partial_data6 = (calib_data.par_p6 * calib_data.t_lin) * 4194304;
    offset = (calib_data.par_p5 * 140737488355328) + partial_data4 + partial_data5 + partial_data6;

    partial_data2 = (calib_data.par_p4 * partial_data3) / 32;
    partial_data4 = (calib_data.par_p3 * partial_data1) * 4;
    partial_data5 = (calib_data.par_p2 - 16384) * calib_data.t_lin * 2097152;
    sensitivity = ((calib_data.par_p1 - 16384) * 70368744177664) + partial_data2 + partial_data4 + partial_data5;

    partial_data1 = (sensitivity / 16777216) * uncomp_data.pressure;
    partial_data2 = calib_data.par_p10 * calib_data.t_lin;
    partial_data3 = partial_data2 + (65536 * calib_data.par_p9);
    partial_data4 = (partial_data3 * uncomp_data.pressure) / 8192;
    partial_data5 = (partial_data4 * uncomp_data.pressure) / 512;
    partial_data6 = (int64_t)((uint64_t)uncomp_data.pressure * (uint64_t)uncomp_data.pressure);
    partial_data2 = (calib_data.par_p11 * partial_data6) / 65536;
    partial_data3 = (partial_data2 * uncomp_data.pressure) / 128;
    partial_data4 = (offset / 4) + partial_data1 + partial_data5 + partial_data3;
    comp_press = (((uint64_t)partial_data4 * 25) / (uint64_t)1099511627776);
    comp_data.pressure = comp_press;
}

上面就是主要的开发流程和修正算法啦,如果有什么不的可以看看数据手册哦,如果想要完整的程序(带有详细注释哦),请到我的主页找找下载链接,也算是对本人的支持啦!转载请注明出处,谢谢!

标签:采样,par,partial,stm32,气压,BMP388,寄存器,calib,data
来源: https://blog.csdn.net/qq_43862401/article/details/106502397