传感器介绍
BMP390数字压力传感器BMP390是一种基于成熟的传感原理的数字压力和温度测量传感器。
传感器模块安装在一个非常紧凑的10针金属盖lgpackage中,占地面积仅为2.0 2.0 mm2,封装高度最大为0.8 mm。
它的小尺寸和3.2 uA @1Hz的低功耗允许在电池驱动的设备中实现,如手机,GPS模块或手表。
典型应用垂直速度指示(例如上升/下沉速度)物联网增强GPS导航(例如。
室内导航和定位(地板检测,电梯检测)户外导航,休闲和运动应用天气预报医疗保健应用(如肺量测定)健身应用如增强卡路里检测ar和VR应用环境感知目标设备飞行玩具无人机手机如手机,平板电脑。
寄存器介绍
如图所示,在手册的4.3章节就有寄存器配置。各个详细的参数点击进去即可。值得注意的是某些寄存器的值和SD0的接线有关,SD0接VCC和GND时候,寄存器的设置值是要变化的。感兴趣的可以对照手册阅读,很容易就会知道原因。本次的SD0是接VCC来操作的。
#define BMP390_Write 0xEE
#define BMP390_Read 0xEF
#define CMD_Addr 0x7E //重置
#define CHIP_ID_Addr 0x00 //0x60//0x50
#define PWR_CTRL_Addr 0x1B //工作模式
#define IF_CONF_Addr 0x1A //串口设置
#define INT_CTRL_Addr 0x19 //中断设置
#define OSR_Addr 0x1C //采样设置
#define ODR_Addr 0x1D //输出速率
#define CONFIG_Addr 0x1F //IIR过滤器设置
#define ERR_REG_Addr 0x02
#define STATUS_Addr 0x03
这就是配置的INIT中用到的寄存器地址(在SD0接VCC的情况下)
IIC的读写流程
写入通过以写模式(RW- ‘O‘)发送从地址来完成,从而得到从地址111011xo (’X’由SDO引脚的状态决定),这也就是说的SD0的接线影响到的一些配置。然后主机发送寄存器地址对和寄存器数据。事务以停止条件结束。
为了能够读取寄存器,首先必须以写模式发送寄存器地址(从地址111011Xo)。
然后必须生成一个停止或重复启动条件。
在此之后,从机以读取模式(RW-'1)在地址111011X1上寻址,之后从机从自动递增的寄存器地址发送数据,直到出现NOACKM和停止条件。
图16描述了这一点,其中从寄存器OxF6和OxF7中读取两个字节。
.h文件
#define BMP390_Write 0xEE
#define BMP390_Read 0xEF
#define CMD_Addr 0x7E //重置
#define CHIP_ID_Addr 0x00 //0x60//0x50
#define PWR_CTRL_Addr 0x1B //工作模式
#define IF_CONF_Addr 0x1A //串口设置
#define INT_CTRL_Addr 0x19 //中断设置
#define OSR_Addr 0x1C //采样设置
#define ODR_Addr 0x1D //输出速率
#define CONFIG_Addr 0x1F //IIR过滤器设置
#define ERR_REG_Addr 0x02
#define STATUS_Addr 0x03
#define PSR_B2_Addr 0x06
#define PSR_B1_Addr 0x05
#define PSR_B0_Addr 0x04
#define TMP_B2_Addr 0x09
#define TMP_B1_Addr 0x08
#define TMP_B0_Addr 0x07
//校准地址
#define NVM_PAR_P11_Addr 0x45
#define NVM_PAR_P10_Addr 0x44
#define NVM_PAR_P9_H_Addr 0x43
#define NVM_PAR_P9_L_Addr 0x42
#define NVM_PAR_P8_Addr 0x41
#define NVM_PAR_P7_Addr 0x40
#define NVM_PAR_P6_H_Addr 0x3F
#define NVM_PAR_P6_L_Addr 0x3E
#define NVM_PAR_P5_H_Addr 0x3D
#define NVM_PAR_P5_L_Addr 0x3C
#define NVM_PAR_P4_Addr 0x3B
#define NVM_PAR_P3_Addr 0x3A
#define NVM_PAR_P2_H_Addr 0x39
#define NVM_PAR_P2_L_Addr 0x38
#define NVM_PAR_P1_H_Addr 0x37
#define NVM_PAR_P1_L_Addr 0x36
#define NVM_PAR_T3_Addr 0x35
#define NVM_PAR_T2_H_Addr 0x34
#define NVM_PAR_T2_L_Addr 0x33
#define NVM_PAR_T1_H_Addr 0x32
#define NVM_PAR_T1_L_Addr 0x31
struct bmp3_calib_data{
uint16_t par_t1;
uint16_t par_t2;
int8_t par_t3;
int16_t par_p1;
int16_t par_p2;
int8_t par_p3;
int8_t par_p4;
uint16_t par_p5;
uint16_t par_p6;
int8_t par_p7;
int8_t par_p8;
int16_t par_p9;
int8_t par_p10;
int8_t par_p11;
int64_t t_lin;
};
struct bmp3_uncomp_data {
uint32_t pressure;
uint32_t temperature;
};
struct bmp3_data {
int64_t temperature;
uint64_t pressure;
};
u8 BMP390_Init(void);
u32 Temperature_Read(void);
u32 Pressure_Read(void);
void Parameter_Reading(int *Pressure_Para,int *Temperature_Para);
double Correcting_Pressure(u32 Pressure,int *Pressure_Para,double Corr_Temperature);
double Correcting_Temperature(u32 Temperature,int *Temperature_Para);
float Pressure_Value(void);
.C代码
基本的一些IIC的代码在这里不过多展示。提前修改IIC的代码,准备为某个地址写入某个值的代码。以及一个读取某个寄存器地址的值的代码。
void BMP390_Write_Byte(u8 addr,u8 data)
{
bmp390lStart();
if(bmp390lSendByte(BMP390_Write))
{
bmp390lStop();
}
if(bmp390lSendByte(addr))
{
bmp390lStop();
}
if(bmp390lSendByte(data))
{
bmp390lStop();
}
bmp390lStop();
}
u8 BMP390_Read_Byte(u8 addr)
{
u8 BMP390_Data;
bmp390lStart();
if(bmp390lSendByte(BMP390_Write))
{
bmp390lStop();
}
if(bmp390lSendByte(addr))
{
bmp390lStop();
}
bmp390lStart();
if(bmp390lSendByte(BMP390_Read))
{
bmp390lStop();
}
BMP390_Data = CHT8310RecByte();
bmp390lStop();
return BMP390_Data;
}
接下来是关于bmp的初始化函数:
u8 BMP390_Init(void)
{
u8 BMP390_ID;
BMP390_Write_Byte(CMD_Addr,0xB6);//RESET
delay_ms(100);
BMP390_ID = BMP390_Read_Byte(CHIP_ID_Addr);//0x60
BMP390_Write_Byte(PWR_CTRL_Addr,0x33);//Set Working mode and state of sensor
BMP390_Write_Byte(IF_CONF_Addr,0x00);//Serial interface settings
BMP390_Write_Byte(INT_CTRL_Addr,0x02);//Set interrupt config
BMP390_Write_Byte(OSR_Addr,0x15);//Set the PM-RATE and PM-PRC,Set the TMPI-RATE and TMP-PRC
BMP390_Write_Byte(ODR_Addr,0x04);//Set the configuration of the output data rates by means of setting the subdivision/subsampling.
BMP390_Write_Byte(CONFIG_Addr,0x00);//IIR
return BMP390_ID;
}
这里运行之后应该会得到CHIP_ID_ADDR的值,得到0x50或者0x60都是可以的。
之后就是得到储存大气压和温度的寄存器位置的值:
u32 Temperature,Pressure;
u32 Temperature_Read(void)
{
u8 Temp_MSB,Temp_CSB,Temp_LSB;
//u32 Temperature;
Temp_MSB = BMP390_Read_Byte(TMP_B2_Addr);
Temp_CSB = BMP390_Read_Byte(TMP_B1_Addr);
Temp_LSB = BMP390_Read_Byte(TMP_B0_Addr);
Temperature = (Temp_MSB<<16)+(Temp_CSB<<8)+Temp_LSB;
uncomp_data.temperature = Temperature;
return Temperature;
}
u32 Pressure_Read(void)
{
u8 Pressure_MSB,Pressure_CSB,Pressure_LSB;
//u32 Pressure;
Pressure_MSB = BMP390_Read_Byte(PSR_B2_Addr);
Pressure_CSB = BMP390_Read_Byte(PSR_B1_Addr);
Pressure_LSB = BMP390_Read_Byte(PSR_B0_Addr);
Pressure = (Pressure_MSB<<16)+(Pressure_CSB<<8)+Pressure_LSB;
uncomp_data.pressure = Pressure;
return Pressure;
}
运行这两段函数就会得到大气压和温度的16进制显示。
接下来就是得到内存映射修剪系数,具体作用下文会讲,也就是上图地址的值。
void Parameter_Reading(int *Pressure_Para,int *Temperature_Para)
{
u8 Temp_Config0,Temp_Config1,Temp_Config2,Temp_Config3,Temp_Config4;
u8 Press_Config0,Press_Config1,Press_Config2,Press_Config3,Press_Config4;
u8 Press_Config5,Press_Config6,Press_Config7,Press_Config8,Press_Config9;
u8 Press_Config10,Press_Config11,Press_Config12,Press_Config13,Press_Config14;
u8 Press_Config15;
//Temperature coefficients
Temp_Config0 = BMP390_Read_Byte(NVM_PAR_T1_L_Addr);
Temp_Config1 = BMP390_Read_Byte(NVM_PAR_T1_H_Addr);
Temp_Config2 = BMP390_Read_Byte(NVM_PAR_T2_L_Addr);
Temp_Config3 = BMP390_Read_Byte(NVM_PAR_T2_H_Addr);
Temp_Config4 = BMP390_Read_Byte(NVM_PAR_T3_Addr);
calib_data.par_t1 = Concat_Bytes(Temp_Config1, Temp_Config0);
calib_data.par_t2 = Concat_Bytes(Temp_Config3, Temp_Config2);
calib_data.par_t3 = (int8_t)Temp_Config4;
//Pressure coefficients
Press_Config0 = BMP390_Read_Byte(NVM_PAR_P1_L_Addr);
Press_Config1 = BMP390_Read_Byte(NVM_PAR_P1_H_Addr);
Press_Config2 = BMP390_Read_Byte(NVM_PAR_P2_L_Addr);
Press_Config3 = BMP390_Read_Byte(NVM_PAR_P2_H_Addr);
Press_Config4 = BMP390_Read_Byte(NVM_PAR_P3_Addr);
Press_Config5 = BMP390_Read_Byte(NVM_PAR_P4_Addr);
Press_Config6 = BMP390_Read_Byte(NVM_PAR_P5_L_Addr);
Press_Config7 = BMP390_Read_Byte(NVM_PAR_P5_H_Addr);
Press_Config8 = BMP390_Read_Byte(NVM_PAR_P6_L_Addr);
Press_Config9 = BMP390_Read_Byte(NVM_PAR_P6_H_Addr);
Press_Config10 = BMP390_Read_Byte(NVM_PAR_P7_Addr);
Press_Config11 = BMP390_Read_Byte(NVM_PAR_P8_Addr);
Press_Config12 = BMP390_Read_Byte(NVM_PAR_P9_L_Addr);
Press_Config13 = BMP390_Read_Byte(NVM_PAR_P9_H_Addr);
Press_Config14 = BMP390_Read_Byte(NVM_PAR_P10_Addr);
Press_Config15 = BMP390_Read_Byte(NVM_PAR_P11_Addr);
calib_data.par_p1 = (int16_t)Concat_Bytes(Press_Config1, Press_Config0);
calib_data.par_p2 = (int16_t)Concat_Bytes(Press_Config3, Press_Config2);
calib_data.par_p3 = (int8_t)Press_Config4;
calib_data.par_p4 = (int8_t)Press_Config5;
calib_data.par_p5 = Concat_Bytes(Press_Config7, Press_Config6);
calib_data.par_p6 = Concat_Bytes(Press_Config9, Press_Config8);
calib_data.par_p7 = (int8_t)Press_Config10;
calib_data.par_p8 = (int8_t)Press_Config11;
calib_data.par_p9 = (int16_t)Concat_Bytes(Press_Config13, Press_Config12);
calib_data.par_p10 = (int8_t)Press_Config14;
calib_data.par_p11 = (int8_t)Press_Config15;
}
使用这段代码得到并保存上述地址的值。
为什么要得到之前这么多寄存器的值呢?因为要用这些值进行修正,具体咋弄的,我也不知道。。。就是看到手册是这样说的,这样计算的。
具体的计算方式可以看手册的54和55页。我自己按照手册中的算法是没有成功的。计算出来的温度是-107度,大气压是109235pa,和实际相差太多了。
最后也是没找到原因。于是在网上参考了别人大佬的算法最后得到解决,链接我会放在后面。以下是大佬的计算方式:
double Corr_Temperature,Corr_Pressure,t_lin;
double Correcting_Temperature(u32 Temperature,int *Temperature_Para)
{
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; /* 存储这个data6为t_lin因为计算气压要用到 */
comp_temp = (int64_t)((partial_data6 * 25) / 16384);
comp_data.temperature = comp_temp;
Corr_Temperature = comp_temp/100.0;
return Corr_Temperature;
}
double Correcting_Pressure(u32 Pressure,int *Pressure_Para,double Corr_Temperature)
{
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;
Corr_Pressure = comp_press/100.0;
return Corr_Pressure;
}
最后在用一个函数调用他们即可
u32 Temp_temp,Alti_temp,Pres_temp,Pressure,Temperature;
float Pressure_Value(void)
{
int Pressure_Para[11],Temperature_Para[3];
u8 Config,i,t=0;
u32 Temperature_Temp;
u32 Pressure_Temp,Altitude_Temp;
double Correcting_Temp,Correcting_Press;
float Altitude;
BMP390_Init();
delay_ms(10);
Parameter_Reading(Pressure_Para,Temperature_Para);
//Config = BMP390_Read_Byte(ERR_REG_Addr);
Pressure = 0;
Temperature = 0;
for (i=0;i<Average_Times;i++)
{
Config = BMP390_Read_Byte(STATUS_Addr);
//while(1)
// {
if(((Config>>5)&0x01) && ((Config>>6)&0x01) && i == 0)
{
Pressure = Pressure_Read();
Temperature = Temperature_Read();
break;
}
else if(((Config>>5)&0x01) && ((Config>>6)&0x01) && i > 0)
{
Pressure = Pressure + Pressure_Read();
Temperature = Temperature + Temperature_Read();
break;
}
else
{
break;
}
//}
}
Pressure = Pressure/Average_Times;
Temperature = Temperature/Average_Times;
Correcting_Temp = Correcting_Temperature(Temperature,Temperature_Para);
Correcting_Press = Correcting_Pressure(Pressure,Pressure_Para,Correcting_Temp)+Offest_Pressure;
Altitude = 44330*(1-pow(Correcting_Press/Standard_atmospheric_pressure,1.0/5.255));
Pressure_Temp = Correcting_Press*10;
Pres_temp = Pressure_Temp/10;
Pres_temp = Pressure_Temp%10;
Temperature_Temp = Correcting_Temp*10;
Temp_temp = Temperature_Temp/10;
Temp_temp = Temperature_Temp%10;
Altitude_Temp = Altitude*10;
Alti_temp = Altitude_Temp/10;
Alti_temp = Altitude_Temp%10;
return Altitude_Temp;
}
这就是最后得到的值,符合实际。
这是参考的两位大佬的链接,大伙可以去看看。我也是按照他们的流程所写的。