美文网首页
飞控开发--气压计MS5611

飞控开发--气压计MS5611

作者: 叶子的背叛 | 来源:发表于2016-03-21 00:33 被阅读0次

    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_addrms5611_addr

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

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


      ms5611regms5611reg

    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_promms5611_prom

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

    ms5611_second_orderms5611_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)或者基准气压。


    完整源码,包含 测试 和 所需的I2C驱动.click here

    相关文章

      网友评论

          本文标题:飞控开发--气压计MS5611

          本文链接:https://www.haomeiwen.com/subject/rpdklttx.html