当前位置:   article > 正文

MS5611气压计数据采集(模拟IIC)/温度采集/相对高度求解

ms5611

原文链接:https://blog.csdn.net/qq_43445076/article/details/110439895

MS5611气压计数据采集(模拟IIC)/温度采集/相对高度求

知识补充-OSR
在一些数字信号处理领域的算法或标准中,"Convert D1 (OSR=256)"是一种特定的转换过程。这里的"D1"表示输入信号的数据,"OSR"表示过采样比率(Oversampling Ratio),256表示具体的过采样倍数。
通常情况下,过采样是指在信号采样过程中使用比实际需要更高的采样率。在这种情况下,过采样倍数表示在采样过程中每个原始输入样本被重复采样的次数。
"Convert D1 (OSR=256)"的含义是,对输入信号D1应用一个过采样倍数为256的转换。具体的转换过程可能涉及将输入信号进行重复采样、滤波、放大或其他数字信号处理操作,以实现特定的目标,如降噪、提高分辨率或改善信号质量。
在这里插入图片描述
原文链接:https://blog.csdn.net/qq_43509788/article/details/109142401
在这里插入图片描述
2.过采样

​ 先概括下过采样的原理,ADC的量化噪声功率一定,和采样速率,采样点数无关,在这个前提下提高采样速率,那么从频域看量化噪声的功率密度减小(横坐标拉长,功率面积一定时,纵坐标幅值变小),而信号功率不变,频域中量化噪声和信号重叠部分减小,相当于将很大一部分量化噪声和信号进行了分离,在通过低通滤波器,保留信号部分去除噪声部分,得以有效提高信噪比SNR,进而提高有效位数,提高分辨率。下面通过两张对比图进行介绍。仔细分析图1的(a)和(b),图1是示意图,图1中三角部分信号功率谱密度不变,(b)中的采样率提高后信号功率密度依然不变,噪声的功率不变(灰色矩形面积不变),但是采样率提高后长度变长,因而高度变矮,因此和信号重叠部分减小,在通过理想低通滤波器后,去除大部分噪声,保留信号成分,就能有效提高信噪比,进而提高分辨率。
在这里插入图片描述在这里插入图片描述

1、 MS5611气压计属性

1.1 基础属性

MS5611使用24位ADC,可以采集温度和气压,并且温度可以用来补偿气压,MS5611在出厂时进行了校准,校准的6个系数存储在PROM寄存器中, PROM寄存器起始地址0XA0, 从0xA0到0XAE, 一共16字节, 一共16*8 = 128位,其中每两个字节为一个系数:
第一个系数: 制造商定的,我们不用在意
第二到第七个系数:我们需要读取,后面用于气压计算
第八个系数:CRC
看下面这个图
在这里插入图片描述

在这里插入图片描述

0xEE //MS5611的地址,也是写的地址 0xEF //MS5611读的地址,读1,写0 IIC从设备地址为111 01110,

MS5611的I2C地址为0b111011Cx,其中C比特位由CSB引脚决定,为CSB引脚的补码值==(取反)==。GY-86上
MS5611的CSB引脚接地,所以CSB引脚值为0,8位I2C地址为0b1110111x(0xEE),7位I2C地址为
0b1110111(0x77)。

在这里插入图片描述

1.2

5个命令(COMMANDS)

分别是:
1、复位
2、读取PROM
3、D1转换, 其实就是设置读取气压的一些参数,然后MS5611会返回24字节(下文会说明)
4、D2转换,其实就是设置读取温度的一些参数
5、读取ADC中的数据

PROM读序列,对应手册去看
我们一开始需要确定传感器PROM中的系数值,由于这个值是固定的,只要测出来了就不用再测第二次:
在这里插入图片描述
转换序列下面描述了进行一次气压数值转换的过程。
在这里插入图片描述

1.3 SPI和IIC接口

IIC模式:PS拉高
SPI模式:PS拉低
本实验用的是模拟IIC读取数据
IIC模式中CSB拉低时, IIC从设备地址为0111 0111, CSB拉高时,IIC设备地址为0111 0110
在这里插入图片描述

2、 温度气压读取

IIC开始、结束、等待ack、读取发送函数等(参考匿名)

#define MS5611_ADDR             0x77   //0xee //
#define CMD_RESET               0x1E // ADC reset command
#define CMD_ADC_READ            0x00 // ADC read command
#define CMD_ADC_CONV            0x40 // ADC conversion command
#define CMD_ADC_D1              0x00 // ADC D1 conversion
#define CMD_ADC_D2              0x10 // ADC D2 conversion
#define CMD_ADC_256             0x00 // ADC OSR=256
#define CMD_ADC_512             0x02 // ADC OSR=512
#define CMD_ADC_1024            0x04 // ADC OSR=1024
#define CMD_ADC_2048            0x06 // ADC OSR=2048
#define CMD_ADC_4096            0x08 // ADC OSR=4096
#define CMD_PROM_RD             0xA0 // Prom read command
#define PROM_NB                 8
#define MS5611_OSR				0x08	//CMD_ADC_4096

//开始信号
int I2c_Soft_Start()
{
	MS5611_IIC_SDA = 1;
	MS5611_IIC_SCL = 1;
	delay_us(4);
	if(!MS5611_READ_SDA)return 0;	//SDA线为低电平则总线忙,退出
	MS5611_IIC_SDA = 0;
	delay_us(4);
	if(MS5611_READ_SDA) return 0;	//SDA线为高电平则总线出错,退出
	MS5611_IIC_SDA = 0;
	delay_us(4);
	return 1;	

}
//结束信号
void I2c_Soft_Stop()
{
	MS5611_IIC_SCL = 0;
	delay_us(4);
	MS5611_IIC_SDA = 0;
	delay_us(4);
	MS5611_IIC_SCL = 1;
	delay_us(4);
	MS5611_IIC_SDA = 1;
	delay_us(4);
}
//应答
void I2c_Soft_Ask()
{
	MS5611_IIC_SCL = 0;
	delay_us(4);
	MS5611_IIC_SDA = 0;
	delay_us(4);
	MS5611_IIC_SCL = 1;
	delay_us(4);
	MS5611_IIC_SCL = 0;
	delay_us(4);
}
//非应答
void I2c_Soft_NoAsk()
{
	MS5611_IIC_SCL = 0;
	delay_us(4);
	MS5611_IIC_SDA = 1;
	delay_us(4);
	MS5611_IIC_SCL = 1;
	delay_us(4);
	MS5611_IIC_SCL = 0;
	delay_us(4);
}
// 等待回复
int I2c_Soft_WaitAsk(void) 	 //返回为:=1无ASK,=0有ASK
{
    u8 ErrTime = 0;
	MS5611_IIC_SCL = 0;
	delay_us(4);
	MS5611_IIC_SDA = 1;			
	delay_us(4);
	MS5611_IIC_SCL = 1;
	delay_us(4);
	while(MS5611_READ_SDA)
	{
		ErrTime++;
		if(ErrTime>50)
		{
			I2c_Soft_Stop();
			return 1;
		}
	}
	MS5611_IIC_SCL = 0;
	delay_us(4);
	return 0;
}

// IIC发送一个字节
void I2c_Soft_SendByte(u8 SendByte) //数据从高位到低位//
{
    u8 i=8;
    while(i--)
    {
        MS5611_IIC_SCL = 0;
        delay_us(4);
		if(SendByte&0x80)
			MS5611_IIC_SDA = 1;  
		else 
			MS5611_IIC_SDA = 0;   
        SendByte<<=1;
        delay_us(4);
		MS5611_IIC_SCL = 1;
		delay_us(4);
    }
    MS5611_IIC_SCL = 0;
}  

//读1个字节,ack=1时,发送ACK,ack=0,发送NACK
u8 I2c_Soft_ReadByte(u8 ask)  //数据从高位到低位//
{ 
    u8 i=8;
    u8 ReceiveByte=0;

    MS5611_IIC_SDA = 1;				
    while(i--)
    {
		ReceiveByte<<=1;      
		MS5611_IIC_SCL = 0;
		delay_us(4);
		MS5611_IIC_SCL = 1;
		delay_us(4);	
		if(MS5611_READ_SDA)
		{
			ReceiveByte|=0x01;
		}
    }
    MS5611_IIC_SCL = 0;

	if (ask)
		I2c_Soft_Ask();
	else
		I2c_Soft_NoAsk();  
    return ReceiveByte;
} 


// IIC写一个字节数据
u8 IIC_Write_1Byte(u8 SlaveAddress,u8 REG_Address,u8 REG_data)
{
	I2c_Soft_Start();
	I2c_Soft_SendByte(SlaveAddress<<1);   
	if(I2c_Soft_WaitAsk())
	{
		I2c_Soft_Stop();
		return 1;
	}
	I2c_Soft_SendByte(REG_Address);       
	I2c_Soft_WaitAsk();	
	I2c_Soft_SendByte(REG_data);
	I2c_Soft_WaitAsk();   
	I2c_Soft_Stop(); 
	return 0;
}

// IIC读1字节数据
u8 IIC_Read_1Byte(u8 SlaveAddress,u8 REG_Address,u8 *REG_data)
{      		
	I2c_Soft_Start();
	I2c_Soft_SendByte(SlaveAddress<<1); 
	if(I2c_Soft_WaitAsk())
	{
		I2c_Soft_Stop();
		return 1;
	}
	I2c_Soft_SendByte(REG_Address);     
	I2c_Soft_WaitAsk();
	I2c_Soft_Start();
	I2c_Soft_SendByte(SlaveAddress<<1 | 0x01);
	I2c_Soft_WaitAsk();
	*REG_data= I2c_Soft_ReadByte(0);
	I2c_Soft_Stop();
	return 0;
}	



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
2.1 第一步:初始化MS5611

初始化包括:
1、复位
2、读取PROM中的6个关键系数

// 复位
void MS5611_Reset(void)
{
	// MS5611_ADDR:0x77    CMD_RESET:0x1E
    IIC_Write_1Byte(MS5611_ADDR, CMD_RESET, 1);
}
u8 MS5611_Read_Prom(void)
{
	uint8_t rxbuf[2] = { 0, 0 };
	u8 check = 0;
	u8 i;

	for (i = 0; i < PROM_NB; i++)
	{
		check += IIC_Read_nByte(MS5611_ADDR, CMD_PROM_RD + i * 2, 2, rxbuf); // send PROM READ command
		ms5611_prom[i] = rxbuf[0] << 8 | rxbuf[1];
	}
	if(check == PROM_NB)
		return 1;
	else
		return 0;
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

2.2 第二步:获取温度数据

在这里插入图片描述
首先发送Convert D2命令,进行相应的配置,再发送ADC Read命令,然后MS5611会返回24位的温度数据, 这时候再去读取这些温度数据。

// 写入数据
void MS5611_Start_T(void)
{
	//CMD_ADC_CONV + CMD_ADC_D2 + MS5611_OSR = 0x48
	IIC_Write_1Byte(MS5611_ADDR, CMD_ADC_CONV + CMD_ADC_D2 + MS5611_OSR, 1); // D2 (temperature) conversion start!
}
// 读取24位温度数据
void MS5611_Read_Adc_T(void)
{
	IIC_Read_nByte( MS5611_ADDR, CMD_ADC_READ, 3, t_rxbuf ); // read ADC
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
2.3 第三步:获取气压数据

在这里插入图片描述
首先发送Convert D1命令,进行相应的配置,然后再发送ADC Read命令, 然后MS5611会返回24位的气压数据, 这时候再去读取这些气压数据。

// 写入数据
void MS5611_Start_P(void)
{
	CMD_ADC_CONV + CMD_ADC_D1 + MS5611_OSR = 0x58
  IIC_Write_1Byte(MS5611_ADDR, CMD_ADC_CONV + CMD_ADC_D1 + MS5611_OSR, 1); // D1 (pressure) conversion start!
}
// 读取24位气压数据
void MS5611_Read_Adc_P(void)
{
	IIC_Read_nByte(MS5611_ADDR, CMD_ADC_READ, 3, p_rxbuf); // read ADC
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3、温度补偿气压

在这里插入图片描述
在这里插入图片描述
绝对高度(海拔)的求解公式:
H= 44300*(1- (P/P0)^(1/5.256) )
H为高度
P0为标准大气压(≈101Kpa)
P为读取的气压 (注意单位得和P0相同)

相对高度(例如飞机起飞前和飞行中的高度差)的求解
这里提供一个思路:
MS5611开机上电一段时间后,读取静止100组数据并转换成海拔,取个平均,这个海拔高度就相当于基准海拔,如果你把MS5611拿高或者拿低, 此时的海拔与基准海拔相见就是相对高度。
ps:求相对高度的时候,可以对此时的海拔高度数据进行一个滑动窗滤波,这样求出的相对高度比较平滑。

void MS5611_BaroAltCalculate(void)
{
	float height = 0;
	int64_t off2 = 0, sens2 = 0, delt = 0, f = 0, f2 = 0;
	int32_t temperature = 0, pressure = 0, T2 = 0;
	int32_t dT = 0;
	int64_t off =0, sens =0;
	static int num = 0;
	static int cnt = 0;
	double ms5611SumDat = 0.0;
	
	ms5611_ut = (t_rxbuf[0] << 16) | (t_rxbuf[1] << 8) | t_rxbuf[2]; // 读取的原始温度值
	ms5611_up = (p_rxbuf[0] << 16) | (p_rxbuf[1] << 8) | p_rxbuf[2]; // 读取的原始气压值
		
    dT = ms5611_ut - ((uint32_t)ms5611_prom[5] << 8);
    off = ((uint64_t)ms5611_prom[2] << 16) + (((int64_t)dT * ms5611_prom[4]) >> 7);
    sens = ((uint64_t)ms5611_prom[1] << 15) + (((int64_t)dT * ms5611_prom[3]) >> 8);
	// 实际温度: 2007:20.07 ℃
    temperature = 2000 + (((int64_t)dT * ms5611_prom[6]) >> 23); 
	
    if (temperature < 2000) 
	{ 
		T2 = (dT*dT)>>31;
		delt = temperature - 2000;
		delt = delt * delt;
		off2 = (5 * delt) >> 1;
		sens2 = (5 * delt) >> 2;
        if (temperature < -1500) 
		{ 
            delt = temperature + 1500;
            delt = delt * delt;
            off2  += 7 * delt;
            sens2 += (11 * delt) >> 1;
        }
    }
	temperature -= T2;
    off  -= off2; 
    sens -= sens2;
	
	ms5611Data.temperature = (double)temperature / 100.0;  // ℃
	// 温度补偿后的气压  100009 = 1000.09 mbar = 100009 Pa
    pressure = (((ms5611_up * sens ) >> 21) - off) >> 15; // mbar
	ms5611Data.pressure = (double)pressure / 100.0;
	
	height = (double)((1.0f - pow((double)pressure / 101325.0f, 0.190295f)) * 44330.0f); // meter
	ms5611Data.height = height;
		
	// 求相对高度
	// 上电100个数据后
	if(num > 100) 
	{
		if(cnt < MS5611_WIN_FILTER)
		{
			alt[cnt] = ms5611Data.height;
			cnt++;
		}
		else
		{
			ms5611SumDat = 0.0;
			for(int i=0; i<MS5611_WIN_FILTER-1; i++)
			{
				alt[i] = alt[i+1];
				ms5611SumDat += alt[i];
			}
			alt[cnt-1] = ms5611Data.height;
			ms5611SumDat += alt[cnt-1];
			ms5611CurAlt = ms5611SumDat/MS5611_WIN_FILTER; // 当前100组数据的高度平均
			if(baroCalOk == true)
			{
				ms5611CurAlt -= ms5611StartAlt; // 当前相对高度
			}
		}
		num = 100;
	}
	num++;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/782994
推荐阅读
相关标签
  

闽ICP备14008679号