最近在搞一个小东西用到了气压传感器,最终选择了BMP388。搜索发现网上关于388的资料少之又少,官方给出的Arduino代码几千行全是英文注释。。。所以去翻看了一下数据手册做了些笔记,分享出来希望帮助有需要的同学。第一次发文章如有错误还请海涵。下面先贴上成功的图片:
(上面是一些场景的推荐设置,从上到下分别是低功耗手持设备,动态手持设备,天气预测,掉落检测,室内导航,无人机。osrs_p是气压过采样等级,osrs_t是温度过采样等级,IIR那个是滤波等级。)
以下内容都是我猜测的哈,不知道正不正确。
如图,在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的输出引脚配置为开漏吧,虽然我也不知道为啥。)
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;
}
上面就是主要的开发流程和修正算法啦,如果有什么不懂的可以看看数据手册哦,如果想要完整的程序(带有详细注释哦),请到我的主页找找下载链接,也算是对本人的支持啦!转载请注明出处,谢谢!