zoukankan      html  css  js  c++  java
  • STM32应用实例六:与MS5837压力传感器的I2C通讯

    MS5837压力传感器是一种可用于电路板上,适用于检测10-1200mbar压力范围的传感器,灵敏度非常高,理论上能够检测到0.01mbar的压力变化,实际使用过程中测试并无明显的变化。

    MS5837采用I2C总线通讯,与STM32的MCU可以实现I2C通讯。硬件连接方式如下:

    MS5837只有5个基本命令:复位、读取出厂校准值、数据1转换(压力值数据)、数据2转换(温度值数据)和读取ADC的转换结果。具体分配如下:

     

    因为MS5837的地址是固定的,所以一个I2C总线只能挂1个MS5837模块。为了让程序具有较好的可移植性,我们在便写程序时不使用对硬件的直接操作,而采用函数指针来操作,所以我们定义了:

    /*向MS5837下发指令,指令格式均为1个字节*/

    typedef void (*WriteCommandToMs5837Type)(uint8_t deviceAddress,uint8_t command);

    /*从MS5837读取多个字节数据的值*/

    typedef void (*ReadBytesFromMs5837Type)(uint8_t deviceAddress,uint8_t *pData,uint16_t bytesNum);

    以上两个函数指针来实现针对硬件的读写操作。接下来我们开始编写代码。

    1)复位操作

    复位操作的数据流如下图所示,只需要发送一条命令就可完成:

     

    /*复位MS5837操作*/
    
    void ResetForMs5837(uint8_t deviceAddress,WriteCommandToMs5837Type WriteCommandToMs5837)
    
    {
    
      uint8_t command=COMMAND_RESET;
    
      /*下发复位命令*/
    
      WriteCommandToMs5837(deviceAddress,command);
    
    }

    2)读取校准值

    校准值是出厂时厂家校准的各种系数,每台设备都有差异,是固定不变的,只需要一次读取就可以了,共有6个系数,均为16为整数。首先发送读系数的命令,然后读取就可以了,每次读取1个,分6次读取。过程数据流如下图所示:

     

    /*从MS5837的PROM中读取校准数据*/
    
    void GetCalibrationData(uint8_t deviceAddress,uint16_t *caliPara,WriteCommandToMs5837Type WriteCommandToMs5837,ReadBytesFromMs5837Type ReadBytesFromMs5837)
    
    {
    
      /*C1压力灵敏度*/
    
      caliPara[0]=ReadPromFromMs5837(deviceAddress,COMMAND_PROM_READ_C1,WriteCommandToMs5837,ReadBytesFromMs5837);
    
      /*C2压力补偿值*/
    
      caliPara[1]=ReadPromFromMs5837(deviceAddress,COMMAND_PROM_READ_C2,WriteCommandToMs5837,ReadBytesFromMs5837);
    
      /*C3压力灵敏度温度系数*/
    
      caliPara[2]=ReadPromFromMs5837(deviceAddress,COMMAND_PROM_READ_C3,WriteCommandToMs5837,ReadBytesFromMs5837);
    
      /*C4压力补偿温度系数*/
    
      caliPara[3]=ReadPromFromMs5837(deviceAddress,COMMAND_PROM_READ_C4,WriteCommandToMs5837,ReadBytesFromMs5837);
    
      /*C5参考温度*/
    
      caliPara[4]=ReadPromFromMs5837(deviceAddress,COMMAND_PROM_READ_C5,WriteCommandToMs5837,ReadBytesFromMs5837);
    
      /*C6温度传感器温度系数*/
    
      caliPara[5]=ReadPromFromMs5837(deviceAddress,COMMAND_PROM_READ_C6,WriteCommandToMs5837,ReadBytesFromMs5837);
    
    }

    3)读取转换值

    读取转换结果值是我们的目的,可以读取温度和压力两个量,不过一次只能读一个。首先发送命令设定采集压力还是温度,并设定精度。然后发送读取的命令,最后读取对应的值。再使用校准系数计算出最终的物理值。

     

    /*获取转换值,包括温度和压力*/
    
    void GetConversionValue(uint8_t deviceAddress,float *pPres,float *pTemp,uint16_t *caliPara,uint16_t *semaphore,WriteCommandToMs5837Type WriteCommandToMs5837,ReadBytesFromMs5837Type ReadBytesFromMs5837)
    
    {
    
      uint16_t senst1;        //C1压力灵敏度
    
      uint16_t offt1;         //C2压力补偿值
    
      uint16_t tcs;           //C3压力灵敏度温度系数
    
      uint16_t tco;           //C4压力补偿温度系数
    
      uint16_t tref;          //C5参考温度
    
      uint16_t tempsens;      //C6温度传感器温度系数
    
     
    
      /*从MS5837的PROM中读取校准数据*/
    
      if(*semaphore>0)
    
      {
    
        GetCalibrationData(deviceAddress,caliPara,WriteCommandToMs5837,ReadBytesFromMs5837);
    
        *semaphore=*semaphore-1;
    
      }
    
      senst1=caliPara[0];
    
      offt1=caliPara[1];
    
      tcs=caliPara[2];
    
      tco=caliPara[3];
    
      tref=caliPara[4];
    
      tempsens=caliPara[5];
    
     
    
      uint32_t digitalPressureValue;
    
      uint32_t digitalTemperatureValue;
    
     
    
      /*读取压力数据*/
    
      digitalPressureValue=ReadConversionFromMs5837(deviceAddress,COMMAND_CONVERTD1OSR4096,WriteCommandToMs5837,ReadBytesFromMs5837);
    
     
    
      Delayms(20);
    
     
    
      /*读取温度数据*/
    
      digitalTemperatureValue=ReadConversionFromMs5837(deviceAddress,COMMAND_CONVERTD2OSR4096,WriteCommandToMs5837,ReadBytesFromMs5837);
    
     
    
      /*对温度进行一阶修正*/
    
      int32_t dT;
    
      int32_t temp;
    
      dT=digitalTemperatureValue-tref*256;
    
      temp=(int32_t)(2000+dT*tempsens/pow(2,23));
    
     
    
      /*对压力进行一阶修正*/
    
      int64_t off;
    
      int64_t sens;
    
      int32_t pres;
    
      off=(int64_t)(offt1*pow(2,17)+(tco*dT)/pow(2,6));
    
      sens=(int64_t)(senst1*pow(2,16)+(tcs*dT)/pow(2,7));
    
      pres=(int32_t)((digitalPressureValue*sens/pow(2,21)-off)/pow(2,15));
    
     
    
      /*对温度和压力进行二阶修正*/
    
      int64_t ti=0;
    
      int64_t offi=0;
    
      int64_t sensi=0;
    
      int64_t off2=0;
    
      int64_t sens2=0; 
    
     
    
      if(temp<2000)
    
      {
    
        ti=(int64_t)(11*dT*dT/pow(2,35));
    
        offi=(int64_t)(31*(temp-2000)*(temp-2000)/pow(2,3));
    
        sensi=(int64_t)(63*(temp-2000)*(temp-2000)/pow(2,5));
    
       
    
        off2=off-offi;
    
        sens2=sens-sensi;
    
       
    
        temp=temp-(int32_t)ti;
    
        pres=(int32_t)((digitalPressureValue*sens2/pow(2,21)-off2)/pow(2,15));
    
      }
    
     
    
      if((-4000<=temp)&&(temp<=8500))
    
      {
    
        *pTemp=(float)temp/100.0;
    
      }
    
      if((1000<=pres)&&(pres<=120000))
    
      {
    
        *pPres=(float)pres/100.0;
    
      }
    
    }

    最终在STM32的I2C接口实现通讯时,实现2个WriteCommandToMs5837Type(uint8_t deviceAddress,uint8_t command);和ReadBytesFromMs5837Type(uint8_t deviceAddress,uint8_t *pData,uint16_t bytesNum);函数并调用就可以了,换做其他的平台也只需要重写这两个函数就能实现通讯了。

  • 相关阅读:
    linux sysfs (2)
    微软——助您启动云的力量网络虚拟盛会
    Windows Azure入门教学系列 全面更新啦!
    与Advanced Telemetry创始人兼 CTO, Tom Naylor的访谈
    Windows Azure AppFabric概述
    Windows Azure Extra Small Instances Public Beta版本发布
    DataMarket 一月内容更新
    和Steve, Wade 一起学习如何使用Windows Azure Startup Tasks
    现实世界的Windows Azure:与eCraft的 Nicklas Andersson(CTO),Peter Löfgren(项目经理)以及Jörgen Westerling(CCO)的访谈
    正确使用Windows Azure 中的VM Role
  • 原文地址:https://www.cnblogs.com/foxclever/p/6533907.html
Copyright © 2011-2022 走看看