MS5607 气压计调试记录

采用 SPI通讯方式驱动MS5607,主控用的是STM32F777
程序是利用STM32CUBEMX生成的 驱动 根据芯片手册和一些参考资料自己写的,数据暂时看是没问题的。
没有测试环境 没有系统测试过。

1,上电初始化MS5607:主要是复位芯片 然后读出prom校准数据(C1-C6)

向spi总线发送0x1e,复位芯片

void MX56XX_Ba_Reset(void)
{
    uint8_t _cmd=0x1e;
    
    MS5607_SPI_CS(0);
    MS56XX_ReadWriteByte(_cmd);    
    MS5607_SPI_CS(1);
    delay_xms(3);

}

然后读取prom校准数据,这个数据是厂商写好的 ,只需要开机上电读取一次就行。
prom read地址从0xA0到0xAE 。

image.png

void MX56XX_Read_Prom_Data(void)
{
    uint8_t _cmd;
    uint8_t _ctr;
    uint8_t  _buff[2];  

    _cmd = 0xa0;   //prom首地址

    for(_ctr = 0;_ctr<8;_ctr++)  
    {
        MS5607_SPI_CS(0);   
        MS56XX_ReadWriteByte(_cmd); 
        _buff[0] = MS56XX_ReadWriteByte(0XFF); 
        _buff[1] = MS56XX_ReadWriteByte(0XFF);
        Cal_C[_ctr]=(_buff[0]<<8)+_buff[1];     
        _cmd += 0x02;         
        MS5607_SPI_CS(1);
    }
}

这里有个地方需要注意 ,下图是prom的内存映射。


image.png

之前读取的数据一直不对,以为数据C1的地址是0xa0,后来看了手册后才知道还有制造商的信息。
从prom的内存映射可以看出,prom的首地址 存放的是制造商的数据和设备信息 ,地址 1-6是校准数据c1-c6,地址7是4bit的crc校验信息。
所以 这就是循环读取8次的原因,然后Cal_C[1]~Cal_C[6] 就对应了的C1~C6的校准数据。Cal_C[7]是CRC校验数据,可以进行验证通信使用。

image.png

还有就是C1~C6的数据是16位的 ,我用的SPI读取是读一个字节,所以 连续读取两次在组成16位的数据在用就可以了。

2 以上初始化完成以后,接下来就是循环读取D1,D2的值 然后用公式计算 数字温度和压强。

读地址是ADC Rread 0x00。
D1 的分辨率 OSR=4096 地址 0x48
D2的分辨率 OSR=4096 地址 0x58

image.png

计算公式和变量信息。


image.png

读D1

uint8_t  _presbuf[3];
uint32_t MS56XX_Do_Conversion_Pres(void)  //数据读取
{
    uint8_t  _cmd=0X48;
    uint32_t _D1;
//  uint8_t  _buf[4];
    MS5607_SPI_CS(0);
    MS56XX_ReadWriteByte(_cmd);    //0x48 -->D1  OSR=4096
    MS5607_SPI_CS(1);
        
    MS56XX_Read_Buf(0x00,_presbuf,3);
    _D1=(_presbuf[0]<<16)+ (_presbuf[1]<<8) +(_presbuf[2]);//读取adc值
//_D1=_buf[0]<<24 | buf[1]<<16 |buf[2]<<8 | buf[3];//读取adc值

    return _D1;
}

读D2


uint8_t  _tempbuf[3];
uint32_t MS56XX_Do_Conversion_Temp(void)  //数据读取
{
    uint8_t  _cmd=0X58;

    uint32_t _D2;
    MS5607_SPI_CS(0);
    MS56XX_ReadWriteByte(_cmd);  //0x58 -->D2  OSR=4096
    MS5607_SPI_CS(1);   
    MS56XX_Read_Buf(0x00,_tempbuf,3);
    _D2=(_tempbuf[0]<<16)+ (_tempbuf[1]<<8) +(_tempbuf[2]);//读取adc值 
    return _D2;
}

//读取并计算数字温度


char MS56XX_GetTemperature (void)     //计算温度
{
    D2_Temp = MS56XX_Do_Conversion_Temp ( );      //循环读取 D1 D2

    if(D2_Temp == 0)
        return 0;
    
        delay_ms ( 10 );

    if(D2_Temp > (  ( uint32_t ) Cal_C[5] * (0x00000001 << 8) ))
        dT  = D2_Temp - (  ( uint32_t ) Cal_C[5] * (0x00000001 << 8) );  //公式 dT = D2 - TREF = D2 - C5 * 2^8
    else
    {
        dT  = (  ( uint32_t ) Cal_C[5] * (0x00000001 << 8) ) - D2_Temp;     
        dT *= -1;
    }
    Temperature = 2000 + ( dT * Cal_C[6] ) / (0x00000001 << 23); //算出温度值的100倍,2001表示20.01°  公式TEMP =20°C + dT * TEMPSENS =2000 + dT * C6 / 2^23

    if(Temperature<-4000) Temperature=-4000;
    if(Temperature>8500) Temperature=8500;
    return 1;
}

读取并计算数字气压

char MS56XX_GetPressure (void)  //计算温度补偿压力
{
    D1_Pres = MS56XX_Do_Conversion_Pres ( );   //循环读取 D1 D2

    if(D1_Pres == 0)
        return 0;
    
        delay_xms ( 10 );
    
    OFF =  ( ( int64_t )Cal_C[2] * (0x00000001 << 17) ) + ( ( int64_t ) Cal_C[4] * dT ) / 64.0;    //公式 OFF = OFFT1 + TCO *dT = C2 *2^17 +(C4 *dT )/ 2^6
    SENS        = ( ( int64_t ) Cal_C[1] * (0x00000001 << 16) ) + ( ( int64_t ) Cal_C[3] * dT ) / 128.0; //公式SENS = SENST1 + TCS* dT= C1 * 2^16 + (C3 * dT )/ 2^7

    //温度补偿部分    逻辑看芯片手册   
    
    if ( Temperature < 2000 ) // second order temperature compensation when under 20 degrees C
    {
        T2 = ( dT * dT ) / (( uint64_t )0x0000000001 << 31);
        OFF2        = 61 *  (( Temperature - 2000 ) * ( Temperature - 2000 )) / 16;
        SENS2       = 2 * (( Temperature - 2000 ) * ( Temperature - 2000 )) ;
        if ( Temperature < -1500 )
        {
            OFF2        = OFF2 + 15 * (( Temperature + 1500 ) * ( Temperature + 1500 )) ;
            SENS2       = SENS2 + 8 * (( Temperature + 1500 ) * ( Temperature + 1500 )) ;
        }
    }
    else        //(Temperature > 2000)
    {
        T2 = 0;
        OFF2        = 0;
        SENS2       = 0;
    }

    Temperature = Temperature - T2;
    OFF         = OFF - OFF2;
    SENS        = SENS - SENS2;
    
    
    Pressure = ( D1_Pres * SENS / (0x00000001 << 21) - OFF ) / (0x00000001 << 15); //公式 P = D1 * SENS - OFF = (D1 * SENS / 2^21 - OFF) / 2^15

    Ms5607.Temperature=(float)Temperature/100;          //单位  ℃     
    Ms5607.Pressure=(float)Pressure/100;           //单位  mbar 

    if(Ms5607.Temperature<-40) Ms5607.Temperature=-40;
    if(Ms5607.Temperature>85)  Ms5607.Temperature=85;
    if(Ms5607.Pressure<10)       Ms5607.Pressure=10;
    if(Ms5607.Pressure>1200)     Ms5607.Pressure=1200;

    printf("Pressure=%4f mbar\r\n",Ms5607.Pressure);
        
    return 1;
}

温度补偿部分的逻辑


image.png

补充1

/********************************************************************************

** 1MPa=1000,000Pa=10bar=10000mbar hPa(百帕)=mbar(毫巴)。

** 每提高12m,大气压下降1mmHg(1毫升水银柱)或者每上升9m,大气压降低100Pa。
** 例如已知气压970hpa,如何求出海拔是多少? 标准大气压为1013.25百帕(hpa)
** 所以,海拔高度为h=(1013.25-970)*9=389.25(米)。

********************************************************************************/
补充2

image.png

SPI时序:在分辨率=4096的是时候 adc的转换时间是8.22ms 所以要留够延时时序。
D1和D2虽然变量定义是32的 但是实际读取字节的时候是读取24bit的数据,也就是3个字节的数据。

//SPI 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint8_t MS56XX_ReadWriteByte(uint8_t TxData)
{
  uint8_t Rxdata;
  HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, 1000);   
    
  return Rxdata;                              //返回收到的数据               
}


uint8_t MS56XX_Read_Buf(uint8_t reg ,uint8_t *pbuf,uint8_t len)//参数说明  发送寄存器位置   读取指定长度的数据 放在pbuf里
{
  u8 status,_ctr;
        
    MS5607_SPI_CS(0);
    delay_xms(9);//预留给ad转换时间,因为osr=4096分辨率   时序上转换时间约为8.2ms
  status=MS56XX_ReadWriteByte(reg);  //发送寄存器位置  
    
    for(_ctr=0;_ctr

结果


image.png

笔者在调试时,参考了以下博文,向这些博主及作者表示感谢!

MS56XX:

https://blog.csdn.net/zhxlx/article/details/93984496

https://bbs.21ic.com/icview-1722818-1-3.html

https://blog.csdn.net/xian_z/article/details/76461696

SPI:
https://www.jianshu.com/p/5de187bf5b75

你可能感兴趣的:(MS5607 气压计调试记录)