• 欢迎访问少将全栈,学会感恩,乐于付出,珍惜缘份,成就彼此、推荐使用最新版火狐浏览器和Chrome浏览器访问本网站。
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏少将全栈吧
  • 欢迎加博主微信:jiang_shaobo

Crazepony使用气压计(或者叫高度计)MS5611

点滴 admin 5年前 (2015-06-27) 916次浏览 已收录 1个评论 扫描二维码

MS5611气压传感器是由MEAS(瑞士)推出的SPI和I?C总线接口的新一代高分辨率气压传感器,分辨率可达到10cm。我们使用的I2C接口,挂在MPU5060的从I2C接口上。MS5611有2种型号的封装MS5611-01BA03(金属封装) 和MS5611-01BA01(塑壳封装),我们使用的金属封装。

Crazepony使用气压计(或者叫高度计)MS5611

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

Crazepony使用气压计(或者叫高度计)MS5611

Crazepony使用气压计(或者叫高度计)MS5611

MS5611的I2C操作命令

下面以I2C连接模式讲解,符合Crazepony硬件上的连接。对MS5611芯片操作,只有5个命令。

  • 复位芯片

复位MS5611芯片,写入一个字节0x1E即可。

IICwriteOneByte( ms5611Address, 0x1E);      // Reset Device 
  • 读取PROM中的值

MS5611气压传感器在出厂的时候,将该片IC对应的6个系数写在了内部寄存器(PROM)中,读取该系数,用于后面对实际温度和实际气压的计算。

内部寄存器的位置分别为0xA2/0xA4/0xA6/0xA8/0xAA/0xAC/0xAE,只需要对该位置读取2个字节则可。

IICreadBytes( ms5611Address, 0xA2, 2, data);    // Read Calibration Data C1
c1.bytes[1] = data[0];
c1.bytes[0] = data[1];

IICreadBytes( ms5611Address, 0xA4, 2, data);    // Read Calibration Data C2
c2.bytes[1] = data[0];
c2.bytes[0] = data[1];

IICreadBytes( ms5611Address, 0xA6, 2, data);    // Read Calibration Data C3
c3.bytes[1] = data[0];
c3.bytes[0] = data[1];

IICreadBytes( ms5611Address, 0xA8, 2, data);    // Read Calibration Data C4
c4.bytes[1] = data[0];
c4.bytes[0] = data[1];

IICreadBytes( ms5611Address, 0xAA, 2, data);    // Read Calibration Data C5
c5.bytes[1] = data[0];
c5.bytes[0] = data[1];

IICreadBytes( ms5611Address, 0xAC, 2, data);    // Read Calibration Data C6
c6.bytes[1] = data[0];
c6.bytes[0] = data[1]; 
  • 配置进行D1转化

D1转化即气压转化,告知IC进行气压转化,下一步就可以读取气压值(24位)。如果OSR为4096,则写入0x48即可。

IICwriteOneByte( ms5611Address, 0x48); 
  • 配置进行D2转化

D2转化即温度转化,告知IC进行温度转化,下一步就可以读取温度值(24位)。如果OSR为4096,则写入0x58即可。

IICwriteOneByte( ms5611Address, 0x58); 
  • 读取ADC的值

ADC值即上面进行的D1转化或者D2转化,为24位数值。对0x00读取3个字节即可。

IICreadBytes( ms5611Address, 0x00, 3, data);    // Request temperature read 

上面这5个命令,是对ms5611操作的所有命令了。我们可以获得6个系数(只需要在初始化时读取一遍即可),然后就是传感器测量到的温度数值和气压数值。下面就是要对读到的气压值和温度值进行计算,获得真实的气压(帕斯卡)和温度(摄氏度)。

实际温度和气压的计算

首先看ms5611出厂时已经确定的6个系数:

  • c1,气压敏感度,SENS
  • c2,气压偏差值,OFF
  • c3,气压敏感度的温度系数,简写为TCS
  • c4,气压偏差值的温度系数,简写为TCO
  • c5,参考温度,Tref
  • c6,温度系数,TEMPSENS

上面6个系数为出厂时已经确定,为16位数值。不同的MS5611芯片会不相同,但是同一片芯片是固定的,只需要在初始化时读取一遍,用于后面的计算。

进行D1和D2转化,获得气压数值d1和温度数值d2,为24位数值。

得到了上面8个值之后,就可以计算当前的实际温度和实际气压了。计算过程如下。

Crazepony使用气压计(或者叫高度计)MS5611

二阶温度补偿

不同温度对大气压强测量有着很大影响,MS5611手册提供有二阶温度补偿的方法。如果温度低于20摄氏度,则进行二阶温度补偿。

Crazepony使用气压计(或者叫高度计)MS5611

扩展-气压计的应用

智能手机

气压传感器首次在智能手机上使用是在Galaxy Nexus上,而之后推出的一些Android旗舰手机里也包含了这一传感器,像GalaxySIII、GalaxyNote2和小米2手机上也都有。

登山测高

对于喜欢登山的人来说,都会非常关心自己所处的高度。海拔高度的测量方法,一般常用的有2种方式,一是通过GPS全球定位系统,二是通过测出大气压,然后根据气压值计算出海拔高度。

导航辅助

现在不少开车人士会用手机来进行导航,不过常常会有人抱怨在高架桥里导航常常会出错 。比如在高架桥上时,GPS说右转,而实际上右边根本没有右转
出口,这主要是GPS无法判断你是桥上还是桥下而造成的错误导航。一般高架桥上下两层的高度都会有几米到十几米的距离了,而GPS的误差可能会有几十米,
所以发生上面的事情也就可以理解了。

而如果手机里增加一个气压传感器就不一样了,他的精度可以做到1米的误差,这样就可以很好的辅助GPS来测量出所处的高度,错误导航的问题也就容易解决了。

室内定位

由于在室内无法很好的接收GPS信号,所以当使用者进入一幢很厚的楼宇时,内置感应器可能会失去卫星的信号,所以无法识别用户的地理位置,并且无法
感知垂直高度。而如果手机加上气压传感器再配合加速计、陀螺仪等技术就可以做到精准的室内定位。这样以后你在商场购物时,就可以通过手机定位来告诉你你想
购买的产品在商场的那个位置,哪一层楼。

渔具

另外气压传感器还可以为钓鱼爱好者提供相关信息(鱼在水中分层及活跃性与大气压相关)或天气预报等功能。

不过目前气压传感器还处于一个被忽略的状态,气压传感器要想被更多人了解和使用还需要一些相关技术的成熟和普及,以及更多的开发者针对这一传感器推出更多的应用和相关功能。

转载自:http://www.crazepony.com/book/

喜欢 (0)
[🍬谢谢你请我吃糖果🍬🍬~]
分享 (0)
关于作者:
少将,关注Web全栈开发、项目管理,持续不断的学习、努力成为一个更棒的开发,做最好的自己,让世界因你不同。
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(1)个小伙伴在吐槽
  1. 你好crazepony的代码是开源的、请参考。
    故事、自己写2016-02-26 22:25 回复 未知操作系统 | 未知浏览器
  2. MS5611.h参考如下:#ifndef __MS5611_H#define __MS5611_H#include "IIC.h"#include "delay.h"// addresses of the device CSB =0 #ifdef DEBUG_HW_I2C#define MS5611_ADDR 0x77// 0xEE // default I2C address#else#define MS5611_ADDR 0xEE // default I2C address#endif// registers of the device#define MS561101BA_D1 0x40#define MS561101BA_D2 0x50#define MS561101BA_RESET 0x1E// D1 and D2 result size (bytes)#define MS561101BA_D1D2_SIZE 3// OSR (Over Sampling Ratio) constants#define MS561101BA_OSR_256 0x00 //Conversion time 0.6ms Resolution 0.065mbar#define MS561101BA_OSR_512 0x02 //Conversion time 1.2ms Resolution 0.042mbar#define MS561101BA_OSR_1024 0x04 //Conversion time 2.3ms Resolution 0.027mbar#define MS561101BA_OSR_2048 0x06 //Conversion time 4.6ms Resolution 0.018mbar#define MS561101BA_OSR_4096 0x08 //Conversion time 9.1ms Resolution 0.012mbar#define MS561101BA_PROM_BASE_ADDR 0xA2 // by adding ints from 0 to 6 we can read all the prom configuration values. // C1 will be at 0xA2 and all the subsequent are multiples of 2#define MS561101BA_PROM_REG_COUNT 6 // number of registers in the PROM#define MS561101BA_PROM_REG_SIZE 2 // size in bytes of a prom registry.//Other#define MSLP 101325 // Mean Sea Level Pressure = 1013.25 hPA (1hPa = 100Pa = 1mbar)// Temperature in 1C// Pressure in 0.01mbar = Pa// Altitude in meter// VerticalSpeed in m/sextern volatile float MS5611_Temperature,MS5611_Pressure,MS5611_Altitude,MS5611_VerticalSpeed;extern uint8_t Baro_ALT_Updated ; //气压计高度更新完成标志。extern uint8_t paOffsetInited;void MS5611_Init(void);void MS5611_Thread(void);void MS5611_ThreadNew(void) ;uint8_t WaitBaroInitOffset(void);#endif//------------------End of File----------------------------MS5611.c参考如下:#include "config.h"#include "MS5611.h"#include <math.h>#include "stm32f10x_it.h"#undef ALTI_SPEED#define MS5611Press_OSR MS561101BA_OSR_4096 //气压采样精度#define MS5611Temp_OSR MS561101BA_OSR_4096 //温度采样精度// 气压计状态机#define SCTemperature 0x01 //开始 温度转换#define CTemperatureing 0x02 //正在转换温度#define SCPressure 0x03 //开始转换 气压#define SCPressureing 0x04 //正在转换气压值#define MOVAVG_SIZE 10 //保存最近10组数据 5static uint8_t Now_doing = SCTemperature; //当前转换状态static uint16_t PROM_C[MS561101BA_PROM_REG_COUNT]; //标定值存放static uint32_t Current_delay=0; //转换延时时间 us static uint32_t Start_Convert_Time; //启动转换时的 时间 us static int32_t tempCache;static float Alt_Offset_m = 0;//#define PA_OFFSET_INIT_NUM 50 static float Alt_offset_Pa=0; //存放着0米(离起飞所在平面)时 对应的气压值 这个值存放上电时的气压值 double paOffsetNum = 0; uint16_t paInitCnt=0;uint8_t paOffsetInited=0;//interface for outside uint8_t Baro_ALT_Updated = 0; //气压计高度更新完成标志。//units (Celsius degrees*100, mbar*100 ).//单位 [温度 度] [气压 帕] [高度 米] volatile float MS5611_Temperature,MS5611_Pressure,MS5611_Altitude,MS5611_VerticalSpeed;// 延时表单位 us 不同的采样精度对应不同的延时值uint32_t MS5611_Delay_us[9] = { 1500,//MS561101BA_OSR_256 0.9ms 0x00 1500,//MS561101BA_OSR_256 0.9ms 2000,//MS561101BA_OSR_512 1.2ms 0x02 2000,//MS561101BA_OSR_512 1.2ms 3000,//MS561101BA_OSR_1024 2.3ms 0x04 3000,//MS561101BA_OSR_1024 2.3ms 5000,//MS561101BA_OSR_2048 4.6ms 0x06 5000,//MS561101BA_OSR_2048 4.6ms 11000,//MS561101BA_OSR_4096 9.1ms 0x08};// FIFO 队列 static float Temp_buffer[MOVAVG_SIZE],Press_buffer[MOVAVG_SIZE],Alt_buffer[MOVAVG_SIZE];static uint8_t temp_index=0,press_index=0; //队列指针//添加一个新的值到 温度队列 进行滤波void MS561101BA_NewTemp(float val) { Temp_buffer[temp_index] = val; temp_index = (temp_index + 1) % MOVAVG_SIZE;}//添加一个新的值到 气压队列 进行滤波void MS561101BA_NewPress(float val){ Press_buffer[press_index] = val; press_index = (press_index + 1) % MOVAVG_SIZE;}//添加一个新的值到 高度队列 进行滤波void MS561101BA_NewAlt(float val) { int16_t i; for(i=1;i<MOVAVG_SIZE;i++) Alt_buffer[i-1] = Alt_buffer[i]; Alt_buffer[MOVAVG_SIZE-1] = val;}//读取队列的平均值float MS561101BA_getAvg(float * buff, int size) { float sum = 0.0; int i; for(i=0; i<size; i++) { sum += buff[i]; } return sum / size;}/**************************实现函数*********************************************函数原型: void MS561101BA_readPROM(void)*功  能: 读取 MS561101B 的工厂标定值读取 气压计的标定值 用于修正温度和气压的读数*******************************************************************************/void MS561101BA_readPROM(void) { u8 inth,intl; uint8_t i2cret[2]; int i; for (i=0;i<MS561101BA_PROM_REG_COUNT;i++) { #ifdef DEBUG_HW_I2C i2cRead(MS5611_ADDR, MS561101BA_PROM_BASE_ADDR + (i * MS561101BA_PROM_REG_SIZE),2, i2cret); PROM_C[i]=i2cret[0]<<8 | i2cret[1]; #else IIC_Start(); IIC_Send_Byte(MS5611_ADDR); IIC_Wait_Ack(); IIC_Send_Byte(MS561101BA_PROM_BASE_ADDR + (i * MS561101BA_PROM_REG_SIZE)); IIC_Wait_Ack(); IIC_Stop(); delay_us(5); IIC_Start(); IIC_Send_Byte(MS5611_ADDR+1); //进入接收模式 delay_us(1); IIC_Wait_Ack(); inth = IIC_Read_Byte(1); //带ACK的读数据 delay_us(1); intl = IIC_Read_Byte(0); //最后一个字节NACK IIC_Stop(); PROM_C[i] = (((uint16_t)inth << 8) | intl); #endif }}/**************************实现函数*********************************************函数原型: void MS561101BA_reset(void)*功  能: 发送复位命令到 MS561101B *******************************************************************************/void MS561101BA_reset(void) { #ifdef DEBUG_HW_I2C i2cWrite(MS5611_ADDR, MS561101BA_RESET, 1); #else IIC_Start(); IIC_Send_Byte(MS5611_ADDR); //写地址 IIC_Wait_Ack(); IIC_Send_Byte(MS561101BA_RESET);//发送复位命令 IIC_Wait_Ack(); IIC_Stop(); #endif}/**************************实现函数*********************************************函数原型: void MS561101BA_startConversion(uint8_t command)*功  能: 发送启动转换命令到 MS561101B可选的 转换命令为 MS561101BA_D1 转换气压 MS561101BA_D2 转换温度 *******************************************************************************/void MS561101BA_startConversion(uint8_t command) {#ifdef DEBUG_HW_I2C i2cWrite(MS5611_ADDR, command, 1); #else // initialize pressure conversion IIC_Start(); IIC_Send_Byte(MS5611_ADDR); //写地址 IIC_Wait_Ack(); IIC_Send_Byte(command); //写转换命令 IIC_Wait_Ack(); IIC_Stop();#endif}#define CMD_ADC_READ 0x00 // ADC read command/**************************实现函数*********************************************函数原型: unsigned long MS561101BA_getConversion(void)*功  能: 读取 MS561101B 的转换结果 *******************************************************************************/uint32_t MS561101BA_getConversion(void) { uint32_t conversion = 0; u8 temp[3]; #ifdef DEBUG_HW_I2C i2cRead(MS5611_ADDR,CMD_ADC_READ ,3, temp); conversion=temp[0] << 16 | temp[0] <<8 | temp[2]; #else IIC_Start(); IIC_Send_Byte(MS5611_ADDR); //写地址 IIC_Wait_Ack(); IIC_Send_Byte(0);// start read sequence IIC_Wait_Ack(); IIC_Stop(); IIC_Start(); IIC_Send_Byte(MS5611_ADDR+1); //进入接收模式 IIC_Wait_Ack(); temp[0] = IIC_Read_Byte(1); //带ACK的读数据 bit 23-16 temp[1] = IIC_Read_Byte(1); //带ACK的读数据 bit 8-15 temp[2] = IIC_Read_Byte(0); //带NACK的读数据 bit 0-7 IIC_Stop(); conversion = (unsigned long)temp[0] * 65536 + (unsigned long)temp[1] * 256 + (unsigned long)temp[2]; #endif return conversion;}/**************************实现函数*********************************************函数原型: void MS561101BA_init(void)*功  能: 初始化 MS561101B *******************************************************************************/void MS5611_Init(void) { MS561101BA_reset(); // 复位 MS561101B delay_ms(100); // 延时 MS561101BA_readPROM(); // 读取EEPROM 中的标定值 待用 }/**************************实现函数*********************************************函数原型: void MS561101BA_GetTemperature(void)*功  能: 读取 温度转换结果 *******************************************************************************/void MS561101BA_GetTemperature(void){ tempCache = MS561101BA_getConversion(); }/**************************实现函数*********************************************函数原型: float MS561101BA_get_altitude(void)*功  能: 将当前的气压值转成 高度。 *******************************************************************************/float MS561101BA_get_altitude(void){ static float Altitude,AltPre; float dz,dt; uint32_t current=0; static uint32_t tp=0; // 是否初始化过0米气压值? if(Alt_offset_Pa == 0) { if(paInitCnt > PA_OFFSET_INIT_NUM) { Alt_offset_Pa = paOffsetNum / paInitCnt; paOffsetInited=1; } else paOffsetNum += MS5611_Pressure; paInitCnt++; Altitude = 0; //高度 为 0 return Altitude; } //计算相对于上电时的位置的高度值 。单位为m Altitude = 4433000.0 * (1 - pow((MS5611_Pressure / Alt_offset_Pa), 0.1903))*0.01f; Altitude = Altitude + Alt_Offset_m ; //加偏置 #ifdef ALTI_SPEED current=micros(); dt=(tp>0)?((current - tp)/1000000.0f):0; tp=current; dz=(Altitude-AltPre); AltPre=Altitude; //m if(dt>0) MS5611_VerticalSpeed = dz / dt;#endif return Altitude; }/**************************实现函数*********************************************函数原型: void MS561101BA_getPressure(void)*功  能: 读取 气压转换结果 并做补偿修正 *******************************************************************************///static float lastPress=0,newPress=0;//static float press_limit_coe = 1;void MS561101BA_getPressure(void) { int64_t off,sens; int64_t TEMP,T2,Aux_64,OFF2,SENS2; // 64 bits int32_t rawPress = MS561101BA_getConversion(); int64_t dT = tempCache - (((int32_t)PROM_C[4]) << 8); TEMP = 2000 + (dT * (int64_t)PROM_C[5])/8388608; off = (((int64_t)PROM_C[1]) << 16) + ((((int64_t)PROM_C[3]) * dT) >> 7); sens = (((int64_t)PROM_C[0]) << 15) + (((int64_t)(PROM_C[2]) * dT) >> 8); if (TEMP < 2000) { // second order temperature compensation T2 = (((int64_t)dT)*dT) >> 31; Aux_64 = (TEMP-2000)*(TEMP-2000); OFF2 = (5*Aux_64)>>1; SENS2 = (5*Aux_64)>>2; TEMP = TEMP - T2; off = off - OFF2; sens = sens - SENS2; } //------------- 气压修正 ----------------// newPress=(((((int64_t)rawPress) * sens) >> 21) - off) / 32768;// // press_limit_coe = 1.0f; // // //机动时限制气压值降低(气压高度增高)// if(ALT_LOCK_FLAG == 0xff && (Math_abs(IMU_Pitch)>15 || Math_abs(IMU_Roll)>15))// { // press_limit_coe = 0.01f; //0.005// if(newPress<lastPress)// newPress = (1 - press_limit_coe) * lastPress + press_limit_coe * newPress; // }// lastPress = newPress;// // MS5611_Pressure = newPress; //原始的方法 MS5611_Pressure = (((((int64_t)rawPress) * sens) >> 21) - off) / 32768; //温度队列处理 MS561101BA_NewTemp(TEMP*0.01f); MS5611_Temperature = MS561101BA_getAvg(Temp_buffer,MOVAVG_SIZE); //0.01c MS5611_Altitude = MS561101BA_get_altitude(); // 单位:m }/**************************实现函数*********************************************函数原型: void MS5611BA_Routing(void)*功  能: MS5611BA 的运行程序 ,需要定期调用 以更新气压值和温度值。 *******************************************************************************/void MS5611_Thread(void) { switch(Now_doing) { //查询状态 看看我们现在 该做些什么? case SCTemperature: //启动温度转换 MS561101BA_startConversion(MS561101BA_D2 + MS5611Temp_OSR); Current_delay = MS5611_Delay_us[MS5611Temp_OSR] ;//转换时间 Start_Convert_Time = micros(); //计时开始 Now_doing = CTemperatureing;//下一个状态 break; case CTemperatureing: //正在转换中 if((micros()-Start_Convert_Time) > Current_delay) { //延时时间到了吗? MS561101BA_GetTemperature(); //取温度 Now_doing = SCPressure; } break; case SCPressure: //启动气压转换 MS561101BA_startConversion(MS561101BA_D1 + MS5611Press_OSR); Current_delay = MS5611_Delay_us[MS5611Press_OSR];//转换时间 Start_Convert_Time = micros();//计时开始 Now_doing = SCPressureing;//下一个状态 break; case SCPressureing: //正在转换气压值 if((micros()-Start_Convert_Time) > Current_delay) { //延时时间到了吗? MS561101BA_getPressure(); //更新 计算 Baro_ALT_Updated = 0xff; //高度更新 完成。 Now_doing = SCTemperature; //从头再来 } break; default: Now_doing = SCTemperature; break; }}void MS5611_ThreadNew(void) { switch(Now_doing) { //查询状态 看看我们现在 该做些什么? case SCTemperature: //启动温度转换 //开启温度转换 MS561101BA_startConversion(MS561101BA_D2 + MS5611Temp_OSR); Current_delay = MS5611_Delay_us[MS5611Temp_OSR] ;//转换时间 Start_Convert_Time = micros(); //计时开始 Now_doing = CTemperatureing;//下一个状态 break; case CTemperatureing: //正在转换中 if((micros()-Start_Convert_Time) > Current_delay) { //延时时间到了吗? MS561101BA_GetTemperature(); //取温度 //启动气压转换 MS561101BA_startConversion(MS561101BA_D1 + MS5611Press_OSR); Current_delay = MS5611_Delay_us[MS5611Press_OSR];//转换时间 Start_Convert_Time = micros();//计时开始 Now_doing = SCPressureing;//下一个状态 } break; case SCPressureing: //正在转换气压值 if((micros()-Start_Convert_Time) > Current_delay) { //延时时间到了吗? MS561101BA_getPressure(); //更新 计算 Baro_ALT_Updated = 0xff; //高度更新 完成。 // Now_doing = SCTemperature; //从头再来 //开启温度转换 MS561101BA_startConversion(MS561101BA_D2 + MS5611Temp_OSR); Current_delay = MS5611_Delay_us[MS5611Temp_OSR] ;//转换时间 Start_Convert_Time = micros(); //计时开始 Now_doing = CTemperatureing;//下一个状态 } break; default: Now_doing = CTemperatureing; break; }}//注意,使用前确保uint8_t WaitBaroInitOffset(void){ uint32_t startTime=0; uint32_t now=0; startTime=micros(); //us while(!paOffsetInited) { MS5611_ThreadNew(); now=micros(); if((now-startTime)/1000 >= PA_OFFSET_INIT_NUM * 50) //超时 { return 0; } } return 1;}//------------------End of File----------------------------
    故事、自己写2016-02-26 22:31 回复 未知操作系统 | 未知浏览器
  3. 你好crazepony的代码是开源的、请参考 https://github.com/Crazepony/crazepony-firmware-none/releases
    故事、自己写2016-02-26 22:32 回复 未知操作系统 | 未知浏览器