飞控开发--气压计MS5611

2023-05-16

ms5611简介:

官方给出的最大分辨率:10cm

工作电压: 1.8v ~ 3.6v

气压 AD 精度:24位

工作环境:-40 ~ +85°C,10 ~ 1200mbar(毫巴 = 百帕)

通讯接口: I2C/SPI (PS:1 - I2C ; PS:0 - SPI)

焊接条件: <250°C < 40秒

开发环境:

开发板: stm32F4discovery

气压计模块:GY-63(ms5611)

开发工具:window7 + MDK(Keil5.1)

程序依赖模块: I2C/SPI 驱动 (此处使用的i2c通讯接口)

MS5611接口及相应寄存器定义-drv_ms5611.h

 

#include "stdbool.h"
#include <math.h>

// MS5611, Standard address 0x77
#define MS5611_ADDR             0x77

#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_4096_CONV_DELAY       8220   // 8.22ms
#define MS5611_OSR_2018_CONV_DELAY       4130   // 4.13ms
#define MS5611_OSR_1024_CONV_DELAY       2080   
#define MS5611_OSR_512_CONV_DELAY        1060   
#define MS5611_OSR_256_CONV_DELAY        540    

bool ms5611Init(void);  

void ms5611_start_ut(void);
void ms5611_get_ut(void);
void ms5611_start_up(void);
void ms5611_get_up(void);
void ms5611_calculate(int32_t *pressure, int32_t *temperature);

float getEstimatedAltitude(int32_t baroPressure);
  • ms5611 i2c 地址定义,由芯片管脚 CSB 决定.111011Cx,其中C为CSB引脚的补码值(取反).

    ms5611_addr

TIP: 本案例中i2c地址 0x77 并没有把i2c 的读写标志位包括,所以在I2C 读写代码实现时务必手动左移。

  • ms5611 官方手册 寄存器地址 说明:

     

    ms5611reg

ms5611 代码实现 - drv_ms5611.c

 

#include "drv_system.h"
#include "drv_i2c.h"
#include "drv_ms5611.h"
static uint32_t ms5611_ut;  // static result of temperature measurement


static uint32_t ms5611_up;  // static result of pressure measurement
static uint16_t ms5611_c[PROM_NB];  // on-chip ROM
//static uint8_t ms5611_osr = CMD_ADC_4096;

#define PA_OFFSET_INIT_NUM 50   

static float Alt_offset_Pa=0; 
double paOffsetNum = 0; 
uint16_t  paInitCnt=0;
uint8_t paOffsetInited=0;

static uint16_t ms5611_prom(int8_t coef_num);  
static void ms5611_reset(void);
static uint32_t ms5611_read_adc(void);
static int8_t ms5611_crc(uint16_t *prom);

bool ms5611Init(void)

{

    bool ack = false;
    uint8_t sig;
    int i;

    delayMs(10); // No idea how long the chip takes to power-up, but let's make it 10ms
    ack = i2cRead(MS5611_ADDR, CMD_PROM_RD, 1, &sig);
    if (!ack)
        return false;

    ms5611_reset();
    // read all coefficients
    for (i = 0; i < PROM_NB; i++)
        ms5611_c[i] = ms5611_prom(i);

    if(ms5611_crc(ms5611_prom) != 0)
        return false;

return true;
}



static void ms5611_reset(void)
{
    i2cWrite(MS5611_ADDR, CMD_RESET, 1);
    delayMs(10);
}


/*
* 读取 ms5611 出厂校准数据
*/
static uint16_t ms5611_prom(int8_t coef_num)
{
    uint8_t rxbuf[2] = { 0, 0 };

    i2cRead(MS5611_ADDR, CMD_PROM_RD + coef_num * 2, 2, rxbuf); // send PROM READ command

return rxbuf[0] << 8 | rxbuf[1];

}


/*
* 读取 ms5611 采集的 温度/气压(24bit)
*/

static uint32_t ms5611_read_adc(void)
{
    uint8_t rxbuf[3];

    i2cRead(MS5611_ADDR, CMD_ADC_READ, 3, rxbuf); // read ADC

return (rxbuf[0] << 16) | (rxbuf[1] << 8) | rxbuf[2];

}

 /*
 * 开始采集温度.
 */
 void ms5611_start_ut(void)
{
    i2cWrite(MS5611_ADDR, CMD_ADC_CONV + CMD_ADC_D2 + CMD_ADC_4096, 1); // D2 (temperature) conversion start!
}

 

 /*
  * 读取出 MS5611 采集的温度AD值
  */
 void ms5611_get_ut(void)
{
    ms5611_ut = ms5611_read_adc();
}

 /*
  * 开始采集气压.
  */
 void ms5611_start_up(void)
{
    i2cWrite(MS5611_ADDR, CMD_ADC_CONV + CMD_ADC_D1 + CMD_ADC_4096, 1); // D1 (pressure) conversion start!
}

 /*
  * 读取出 MS5611 采集的气压AD值
  */
void ms5611_get_up(void)
{
    ms5611_up = ms5611_read_adc();
}

/*
 * 读取的气压&温度AD值转换为实际值并作温度补偿(温度精度:0.01℃,气压精度:0.01mbar)
 */
void ms5611_calculate(int32_t *pressure, int32_t *temperature)
{
    uint32_t press;
    int64_t temp;
    int64_t delt;

    int32_t dT = (int64_t)ms5611_ut - ((uint64_t)ms5611_c[5] * 256);
    int64_t off = ((int64_t)ms5611_c[2] << 16) + (((int64_t)ms5611_c[4] * dT) >> 7);
    int64_t sens = ((int64_t)ms5611_c[1] << 15) + (((int64_t)ms5611_c[3] * dT) >> 8);
    temp = 2000 + ((dT * (int64_t)ms5611_c[6]) >> 23);

    if (temp < 2000) { // temperature lower than 20degC
        delt = temp - 2000;
        delt = 5 * delt * delt;
        off -= delt >> 1;
        sens -= delt >> 2;

        if (temp < -1500) { // temperature lower than -15degC
            delt = temp + 1500;
            delt = delt * delt;
            off -= 7 * delt;
            sens -= (11 * delt) >> 1;
        }
    }

    press = ((((int64_t)ms5611_up * sens) >> 21) - off) >> 15;

    if (pressure)
        *pressure = press;
    if (temperature)
        *temperature = temp;
}



/*
 * ms5611 prom 数据 校验
 */
static int8_t ms5611_crc(uint16_t *prom)
{
    int32_t i, j;
    uint32_t res = 0;
    uint8_t zero = 1;
    uint8_t crc = prom[7] & 0xF;
    prom[7] &= 0xFF00;

    // if eeprom is all zeros, we're probably fucked - BUT this will return valid CRC lol
    for (i = 0; i < 8; i++) {
        if (prom[i] != 0)
            zero = 0;
    }

    if (zero)
        return -1;

    for (i = 0; i < 16; i++) {
        if (i & 1)
            res ^= ((prom[i >> 1]) & 0x00FF);
        else
            res ^= (prom[i >> 1] >> 8);
        for (j = 8; j > 0; j--) {
            if (res & 0x8000)
                res ^= 0x1800;
            res <<= 1;
        }
    }

    prom[7] |= crc;

    if (crc == ((res >> 12) & 0xF))
        return 0;

return -1;
}

/*
 * 气压解算为高度值(cm)
 */
float getEstimatedAltitude(int32_t baroPressure)
{
    static float Altitude;

    if(Alt_offset_Pa == 0){ 
        if(paInitCnt > PA_OFFSET_INIT_NUM){
            Alt_offset_Pa = paOffsetNum / paInitCnt;
            paOffsetInited=1;
        }else
        paOffsetNum += baroPressure;  
        paInitCnt++; 
        Altitude = 0; 
return Altitude;

    }

    Altitude = 4433000.0f * (1 - powf((((float) baroPressure) / Alt_offset_Pa), 0.190295f));

return Altitude; 
}

  • 由于气压受温度影响,所以需要进行温度补偿。void ms5611_calculate(int32_t *pressure, int32_t *temperature)

温度计算公式:

实际和参考温度之间的差异:
<div style = "text-align:center;">
{% katex [displayMode] %}
dT = D2 - T_{REF} = D2 - C5*2^{8}
{% endkatex %}
</div>

实际温度(-40...85°C / 0.01°C的分辨率):
<div style = "text-align:center;">
{% katex [displayMode] %}
TEMP = 20 + dTTEMPSENS = 2000 + dTC6/2^{23}
{% endkatex %}
</div>

温度补偿下气压计算公式:

实际温度抵消 :
<div style = "text-align:center;">
{% katex [displayMode] %}
OFF = OFF_{T1} + TCOdT = C22^{16} + (C4*dT) / 2^{7}
{% endkatex %}
</div>

实际温度灵敏度 :
<div style = "text-align:center;">
{% katex [displayMode] %}
SENS = SENS_{T1} + TCSdT = C12^{15} + (C3*dT) / 2^{8}
{% endkatex %}
</div>

温度补偿后得到的气压值:(10 ~ 1200mbar/ 0.001mbar分辨率)
<div style = "text-align:center;">
{% katex [displayMode] %}
P = D1SENS - OFF = (D1SENS / 2^{21}) / 2^{15}
{% endkatex %}
</div>

Tip: C1 C2 .. 等值都来自芯片内置的 PROM 数据,在初始化代码时读取

 

ms5611_prom

 

**Tip: 并且由于此芯片在 大于20°C下比较准,低于20°C气压误差骤增,所以还必须做二阶温度补偿 **

 

ms5611_second_order

 

  • 气压值到高度的解算 float getEstimatedAltitude(int32_t baroPressure)
    气压转换高度公式为:
    <div style = "text-align:center;">

$$Altitude = 4 433 000 * [1 - (\frac{p}{p_{0}})^{\frac{1}{5.255}}]$$

</div>

tip: Altitude 为高度(cm); P 为温度补偿后的气压值; {% katex [displayMode] %}P_{0} {% endkatex %}标准大气压(101 325 Pa)或者基准气压。



作者:叶子的背叛
链接:https://www.jianshu.com/p/9e99f814ac68
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

飞控开发--气压计MS5611 - 简书 (jianshu.com)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

飞控开发--气压计MS5611 的相关文章

随机推荐

  • 西门子S7-1200系列PLC定时器指令

    定时器指令是在PLC程序设计中非常常见的一种指令 xff0c S7 1200系列PLC的定时器的指令格式及使用方式都不同于S7 200系列PLC S7 1200系列PLC的采用的是IEC标准的定时器指令 xff0c 用户程序中可以使用的定时
  • 0基础学springboot之对数据库的增删改查

    1 xff1a 使用的是mysql数据库 xff0c 数据库中的表为student 2 xff1a 创建springboot项目 xff0c 在pom文件里加载mysql依赖 lt dependency gt lt groupId gt m
  • 平衡车Car_Balance(一)——电机

    目录 一 电机简要概述 二 常见电机种类 1 直流有刷电机 xff08 BDC xff0c 最最最常见的电机 xff09 2 直流无刷电机 xff08 BLDC xff09 3 舵机 4 步进电机 三 平衡小车选用电机及需要关注的参数 1
  • 用matlab进行xlsx表格的提取和操作

    用matlab进行xlsx表格的提取和操作 一 数据的提取二 垃圾数据的清除三 数据的分类四 图像的绘制 在学习数学建模时 xff0c 我们会碰到大数据的问题 xff0c 这类问题通常要进行数据预处理 xff0c 这是我用matlab进行预
  • Android 开发艺术探索笔记(5,我的头条面试经历分享

    public Messenger Handler target mTarget 61 target getIMessenger public Messenger IBinder target mTarget 61 IMessenger St
  • 穿越机F4飞控F405代码pcb文件,原理图

    穿越机F4飞控F405代码pcb文件 原理图 xff0c 源代码 xff0c 穿越机无人机 xff0c F4V3飞控PCB资料 xff0c AD格式原理图 PCB图 Bo可直接打板id 61 659104114509 amp
  • 【AD20学习笔记】网表导入及模块化布局设计(1)

    7 20 今天写完 本章快捷键总结 xff08 绿色是自己设的 xff09 Q可以切换单位 xff08 但是要右击按着欸 xff0c 有一定失败概率 xff09 JC可以查元件位号 F6可以进行矩形的元件摆放 按shift 是可以多选 TM
  • 【五一创作】微服务学习笔记

    微服务学习 写一个服务的步骤一般可以有 1 xff0c 在pom xml文件中导入相关的依赖 2 xff0c 编写相关的配置类 xff08 application yml xff09 配置类编写的三步 1 服务的端口 2 服务的名字 3 服
  • Win10启动或关闭windows功能,一直显示“请稍后”该怎么办?(win10请稍后)

    解决方法一 xff1a 1 按下 Win 43 R 组合键呼出运行 xff0c 输入 xff1a services msc 点击确定打开服务 xff1b 2 在服务界面中双击打开 Windows Modules Installer xff0
  • ROS2 CmakeList如何正确引入第三方.so文件

    在使用ros2开发的时候难免会需要引入第三方的厂家提供的 so文件库 注意这里说的并不是自己写的cpp文件转成 so然后再自己的工程项目中使用 例如经常使用的ICANCmd h头文件和libCanCmd so库还有onnx推理的时候onnx
  • 实战篇 | 基于freeRTOS的多任务事件传输

    之前分享了很多关于freeRTOS的知识 xff0c 那么我们怎么在实战中去写代码呢 xff1f 本篇文章重在对基于freeRTOS的架构代码的解析 整个功能如下图 xff1a 为什么要用freeRTOS 在实际项目中 xff0c 如果程序
  • 浅谈安卓UI设计,android串口工具apk

    lt xml version 61 34 1 0 34 encoding 61 34 utf 8 34 gt lt android support constraint ConstraintLayout xmlns android 61 h
  • 四轴飞行器-基于STM32微控制器(电子入门必看)

    nbsp nbsp nbsp nbsp nbsp nbsp 从开始做微型多旋翼飞行器以来 我经常和一大批有着同样爱好的朋友们互相交流 他们走着我曾经走过的路 也经历着我所经历过的坎坷 无论我在何坛何群 总有朋友追问着很多重复的问题 未能全部
  • 基于stm32cubeMX的平衡小车HAL库+蓝牙遥控+直立环+速度环+转向环 STM32F103C8T6

    基于stm32cubeMX的平衡小车HAL库 蓝牙遥控 直立环 速度环 转向环 一 代码工程链接 我的平衡车代码 HAL库 cubeMX配置 主控stm32f103 程序代码容易移植 建议先看完正文 工程 平衡车工程 PCB 代码程序 蓝牙
  • Java日常学习:运用链栈实现进制转换

    一 简单介绍 今天我就给大家带来java中的链栈实现进制转换的方法 xff0c 该方法也是在学习栈的时候发现的 xff0c 我们都知道在进制转换的时候有很多种方法 xff0c 其中最常用也最容易理解的就是除基倒取余法 xff0c 那么我们先
  • CLion解决中文输出乱码(2022年最新教程)

    CLion是个很好用的IDE xff0c 但是在用CLion写C C 43 43 代码时 xff0c 中文输出会是乱码 xff0c 此前博主也找了很多资料 xff0c 但是网上的教程大多都是脱裤子放屁 xff0c 治标不治本 xff0c 在
  • 【Linux网络编程】TCP并发服务器的实现(IO多路复用select)

    文章目录 一 服务器模型1 1 服务器概念1 2 TCP并发服务器的意义1 3 实现TCP并发服务器的方式 二 使用IO多路复用实现TCP并发服务器优势三 select函数四 TCP并发服务器的构建4 1 创建套接字4 2 填写服务器网络信
  • 树莓派解决cannot currently show the desktop最优法

    最近在搞树莓派前面的步骤都轻轻松松的解决了这个问题卡了我很久 这个是解决之后的效果 xff0c 我使用改分辨率用了很多办法这个办法解决的效率最快 直接在下载好文件的解决 1 将有sd卡的读卡器插入 2 在config txt文件中加入四句话
  • 十、C++中的类 class与struct的区别

    面向对象程序设计 xff0c 需要诸如类和对象这样的概念 C 43 43 支持面向过程 基于对象 面向对象 泛型编程四种 C语言不支持面向对象编程 类是一种将数据和函数组织在一起的方式 一个函数参数过多 xff0c 代码不好维护 xff0c
  • 飞控开发--气压计MS5611

    ms5611简介 xff1a 官方给出的最大分辨率 xff1a 10cm 工作电压 xff1a 1 8v 3 6v 气压 AD 精度 xff1a 24位 工作环境 xff1a xff0d 40 43 85 C xff0c 10 1200mb