MS5611气压传感器的使用
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
MS5611气压传感器的使用
——中北大学:马政贵
图1 MS5611的电路图
MS5611气压传感器支持SPI和IIC总线接口,为降低通讯时间,选择使用SPI通讯,设计的电路图如图1所示。
根据电路原理图,程序使用SPI总线接口的模式0方式(时钟空闲时为低,数据捕获于第1个时钟沿)。
MS5611内含低功耗的24位ADC,高度分辨率可达10cm。
4.1 MS5611的初始化:
根据数据手册,MS5611在上电之后应发送一次复位指令,用来将出厂校准数据载入相应的寄存器中。
复位完成后,再读取这些出厂校准数据,后续用于气压和温度的计算。
/*******************************************************************************
功能:对MS5611进行初始化
参数:无
返回值:无
*******************************************************************************/
void MS5611_Init(void)
{
static unsigned char temp_rest;
SPI_MS5611_CS_L;
delay_us(10);
SPI2_ReadWriteByte(CMD_MS5611_RESET); //发送复位指令
delay_ms(20); //复位需要2.8ms,这里取长一点时间,确保复位
SPI_MS5611_CS_H;
delay_us(10);
/*--------------复位后读取PROM内容------------------*/
C1 = SPI_MS5611_Read(CMD_MS5611_PROM_C1);
C2 = SPI_MS5611_Read(CMD_MS5611_PROM_C2);
C3 = SPI_MS5611_Read(CMD_MS5611_PROM_C3);
C4 = SPI_MS5611_Read(CMD_MS5611_PROM_C4);
C5 = SPI_MS5611_Read(CMD_MS5611_PROM_C5);
C6 = SPI_MS5611_Read(CMD_MS5611_PROM_C6);
}
备注:u16 SPI_MS5611_Read(u8 ReadAddr)为寄存器读取函数,参数ReadAddr为要读取的寄存器地址,函数返回相应寄存器的值。
在MS5611.h头文件中根据芯片手册对相应寄存器地址进行了宏定义:
/*MS5611模块传感器地址定义*/
#define MS5611_ADC 0x00
#define CMD_MS5611_RESET 0x1E
#define CMD_MS5611_PROM_Setup 0xA0
#define CMD_MS5611_PROM_C1 0xA2
#define CMD_MS5611_PROM_C20xA4
#define CMD_MS5611_PROM_C3 0xA6
#define CMD_MS5611_PROM_C4 0xA8
#define CMD_MS5611_PROM_C5 0xAA
#define CMD_MS5611_PROM_C6 0xAC
#define CMD_MS5611_PROM_CRC0xAE
#define CMD_CONVERT_D1_OSR4096 0x48
#define CMD_CONVERT_D2_OSR4096 0x58
4.2 MS5611数据读取及转换:
对MS5611进行数据读取时,要先发送相应的转换指令。
MS5611可以进行气压和温度的测量,因此,有两条相应的转换指令,根据精度的不同,每条转换指令又分为5条具体指令。
程序中,我们均按最高精度来进行转换,转换时间约9ms。
由于我们的任务调度基于时间片调度模式,为避免造成程序堵塞,数据读取采用switch语句,从而避免在数据转换时的等待,可以去运行其他任务。
气压和温度的计算过程根据芯片手册进行,具体如下:
图2 气压和温度的计算末尾还进行了相应的二阶温度补偿,具体过程为:
图3 二阶温度补偿
由当前气压和温度值,可计算得到当前高度,公式为:
其中,为海平面气压值;P 为当前大气压值;T 为当前温度值,单位℃。
/*******************************************************************************
功能:读取MS5611数据,并求取温度、高度值
参数:无
返回值:无
说明:得到的温度为温度值*100(即实际温度放大100倍)
*******************************************************************************/
void MS5611_get_Data(void)
{
static unsigned char data[3];
static unsigned char temp;
static unsigned char MS5611_Count=0,MS5611_Num=0;
static unsigned int D1,D2; //D1为气压,D2为温度
static long long dT,T2,Temperature,Pressure;
0065.0)
15.273(*)1)((257.510+-=T P
P h 0P
static double OFF,OFF2,SENS,SENS2;
static double tmp_float,Altitude[3];
MS5611_Count++;
MS5611_Num++;
switch(MS5611_Count)
{
case 1:
SPI_MS5611_CS_L;
delay_us(10);
SPI2_ReadWriteByte(CMD_CONVERT_D2_OSR4096); //温度转换指令
break;
case 2: //读取温度值SPI_MS5611_CS_H;
delay_us(10);
SPI_MS5611_CS_L;
delay_us(10);
if(0xfe == SPI2_ReadWriteByte(0x00)) //判断读取是否正确
{
data[2] = SPI2_ReadWriteByte(0x00);
data[1] = SPI2_ReadWriteByte(0x00);
data[0] = SPI2_ReadWriteByte(0x00);
}
delay_us(10);
SPI_MS5611_CS_H;
D2 = ((unsigned int)data[2]<<16) | ((unsigned int)data[1]<<8) | data[0];
dT = D2 - (unsigned int)C5*256;
Temperature = 2000 + dT*C6/8388608;
break;
case 3:
SPI_MS5611_CS_L;
delay_us(10);
SPI2_ReadWriteByte(CMD_CONVERT_D1_OSR4096); //气压转换指令
break;
case 4: //读取气压值SPI_MS5611_CS_H;
delay_us(10);
SPI_MS5611_CS_L;
delay_us(10);
if(0xfe == SPI2_ReadWriteByte(0x00)) //判断读取是否正确
{
data[2] = SPI2_ReadWriteByte(0x00);
data[1] = SPI2_ReadWriteByte(0x00);
data[0] = SPI2_ReadWriteByte(0x00);
}
delay_us(10);
SPI_MS5611_CS_H;
D1 = ((unsigned int)data[2]<<16) | ((unsigned int)data[1]<<8) | data[0];
OFF = (unsigned int)C2*65536 + (unsigned int)C4*dT/128;
SENS = (unsigned int)C1*32768 + (unsigned int)C3*dT/256;
Pressure = (D1*SENS/2097152-OFF)/32768;
break;
default: //二阶温度补偿及高度计算if(Temperature<2000)
{
T2 = (signed int)((double)dT*(double)dT/2147483648);
OFF2 = 5 * (Temperature-2000) * (Temperature-2000) / 2;
SENS2 = 5 * (Temperature-2000) * (Temperature-2000) / 4;
if(Temperature<-1500)
{
OFF2 = OFF2+7*(Temperature+1500)*(Temperature+1500);
SENS2 = SENS2+11*(Temperature+1500)*(Temperature+1500)/2;
}
}
else
{
T2 = 0;
OFF2 = 0;
SENS2 = 0;
}
Temperature = Temperature - T2;
OFF = OFF - OFF2;
SENS = SENS - SENS2;
Pressure = (D1*SENS/2097152-OFF)/32768;
Altitude[0] = 44330 * (1.0 - pow(Pressure / 101325.0, 0.190295));
Altitude[1] = (pow(101325.0/Pressure, 1/5.257)-1.0) * ((float)Temperature/100.0+273.5) / 0.0065;
if(100 == MS5611_Num)
{
MS5611_Num = 0;
printf("D1=%d,D2=%d,T=%d P=%d H1=%f H2=%f\n",D1,D2,(signed int)Temperature,(signed int)Pressure,Altitude[0],Altitude[1]);
}
MS5611_Count=0;
break;
}
}
在程序更正之前,测试过程中,会偶尔出现数据突变的情况,下图为通过串口打印出来的数据:
其中第一列D1为数字气压值,,第二列D2位数字温度值,第三列T为温度值(单位℃,放大100倍显示),第四列H1为绝对气压高度值,第五列H2为相对气压高度值。
从上两图中可以看出,高度值会时不时的出现一百多米的高度跳变,而原始数据D1、D2并没有出现太大变化,因此可以推断为求解过程中出现问题。
通多对数据的逆运算,发现计算过程中,中间结果超过类型范围从而造成溢出的问题。
例如:
Temperature = 2000 + dT*C6/8388608;
根据上图中的粉红色数据对温度值进行解算,应该算出的结果为T=2481,但是实际程序中的结果为T =1961。
由于之前的dT定义为signed int(4 bytes)类型,范围为-2147483648 ~
+2147483647,dT*C6的乘积为4039640374,从而造成溢出,运算得到的值变为-255326922,而得到错误的结果。
将类型定义为long long(8 bytes)之后,问题得到解决。
说明:
1、气压和温度的计算过程中,要注意中间变量的数据类型定义要符合相应范围;
2、MS5611在刚刚通电数10s内读到的数值不稳定,需要一段时间的预读取使其稳定下来,预读取次数可设定为200;或者通过与GPS进行对比,当两者之间的差值在一定范围内时,才将这时气压得到的高度值作为基准值;
3、应用层进行数据取用时,应进行数字低通滤波,上一次值的权重因子可取0.8,当前值的权重因子则为0.2。
参看:
1、Measurement Specialties, Inc.-《MS5611-01BA03 Barometric Pressure Sensor, with stainless steel cap》
2、潘银松,刘天刚,马泽忠,刘智华-《基于MS5611的小型无人机高度检测系统设计》。