• 外设驱动库开发笔记18:MS5837压力变送器驱动


      绝对压力的检测是常见的需求。在我们的系统中也常常会遇到。而MS5837压力传感器也是我们进场会采用的方案。在这篇里我们将讨论并实现MS5837压力传感器的驱动。

    1、功能概述

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

     

      MS5837压力传感器采用I2C总线通讯,与MCU可以实现I2C通讯。硬件连接方式如下:

     

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

     

      因为MS5837的地址是固定的,所以一个I2C总线只能挂1个MS5837模块。其设备地址固定为:0xEC。

    2、驱动设计与实现

      我们已经了解了MS5837的基本功能和操作方式。接下来我们就根据前面的分析实现MS5837的驱动。

    2.1、对象定义

      在使用该对象之前,我们需要定义对象,我们根据MS5837的属性和操作来定义对象。

    2.1.1、对象类型抽象

      为了方便操作与复用,我们使用基于对象的操作。这里我们先来抽象MS5837压力传感器对象的类型,该类型包含了MS5837的必要属性和对MS5837基本操作。

      我们先来分析MS5837压力传感器对象的属性。MS5837压力传感器使用的是I2C通讯接口,需要一个地址分辨总线上的不同设备,所以我们将I2C设备地址作为MS5837压力传感器对象的一个属性。此外,在计算MS5837压力传感器测量的压力、温度值时需要使用6个校准参数,而且这些参数每台设备都是不一样的,所以我们将这些参数作为属性来保存其值。

      接下来我们再来分析MS5837压力传感器对象的操作。我们使用MS5837压力传感器时,需要向其写命令和从其读数据,而读写操作都依赖于具体的硬件平台,所以我们将写数据和读数据作为对象的操作。此外,为控制时序,我们需要延时操作,而延时行为的实现亦依赖于具体的软硬件平台,所以我们将延时也作为对象的操作。

      根据上述我们对MS5837压力传感器对象的分析,我们可以抽象MS5837压力传感器的对象类型为:

     1 /* 定义MS5837对象类型 */
     2 typedef struct MS5837Object {
     3       uint8_t devAddress;                 //设备地址
     4       uint16_t caliData[6];        //校准数据
     5       float temperature;
     6       float pressure;
     7       void (*Write)(struct MS5837Object *ms,uint8_t command);/*向MS5837下发指令,指令格式均为1个字节*/
     8       void (*Read)(struct MS5837Object *ms,uint8_t *rData,uint16_t rSize);/*从MS5837读取多个字节数据的值*/
     9       void (*Delayms)(volatile uint32_t nTime);     //毫秒秒延时函数
    10 }MS5837ObjectType;

    2.1.2、对象初始化

      在使用之前,我们先要使用对象类型声明对象,但声明的对象只是一个变量,该对象变量在使用前必须初始化,所以我们定义了对象初始化函数。

     1 /* 初始化MS5837对象 */
     2 void MS5837Initialization(MS5837ObjectType *ms,MS5837Write write,MS5837Read read,MS5837Delayms delay)
     3 {
     4     if((ms==NULL)||(write==NULL)||(read==NULL)||(delay==NULL))
     5        {
     6               return;  
     7        }
     8       
     9        ms->Write=write;
    10        ms->Read=read;
    11        ms->Delayms=delay;
    12       
    13        ms->devAddress=0b11101100;
    14        ms->pressure=0.0;
    15        ms->temperature=0.0;
    16       
    17        ResetForMs5837(ms);
    18       
    19        GetCalibrationData(ms);
    20 }

    2.2、对象操作

      完成了对象的声明与初始化之后,我们就可以使用对象变量来操作对象了。关于MS5837的操作主要有:设备复位、校准值获取、转换值的读取。下面将一一实现。

    2.2.1、复位操作

      复位操作在MS5837压力传感器有电时就可执行,但一般会在上电之后需要复位一下,以保持内存中的校准参数值是正确的。此外,当I2C的SDA引脚因未知原因出现阻塞时,复位能消除这种不确定性。复位操作只需要发送一条命令,其时序图如下:

     

    1 /*复位MS5837操作*/
    2 void ResetForMs5837(MS5837ObjectType *ms)
    3 {
    4   uint8_t command=COMMAND_RESET;
    5 
    6   /*下发复位命令*/
    7   ms->SendCommand(ms,command);
    8 }

    2.2.2、读取校准值

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

     

     1 /*读取MS5837内存寄存器的数据*/
     2 static uint16_t ReadPromFromMs5837(MS5837ObjectType *ms,uint8_t command)
     3 {
     4   /*下发读取指定内存单元的命令*/
     5   ms->Write(ms,command);
     6  
     7   /*接收读取的指定内存单元的值*/
     8   uint8_t promValue[2];
     9   ms->Read(ms,promValue,2);
    10  
    11   uint16_t result=(uint16_t)promValue[0];
    12   result=(result<<8)+(uint16_t)promValue[1];
    13  
    14   return result;
    15 }

    2.2.3、读取转换值

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

     

     1 /*读取MS5837ADC的转换值*/
     2 static uint32_t ReadConversionFromMs5837(MS5837ObjectType *ms,uint8_t command)
     3 {
     4   /*下发转化对象及精度配置命令*/
     5      
     6   ms->Write(ms,command);
     7  
     8   ms->Delayms(10);
     9  
    10   /*下发读取ADC的命令*/
    11   ms->Write(ms,COMMAND_ADC_READ);
    12  
    13   ms->Delayms(10);
    14  
    15   /*接收读取的ADC转换结果*/
    16   uint8_t adcValue[3];
    17   ms->Read(ms,adcValue,3);
    18  
    19   uint32_t result=(uint32_t)adcValue[0];
    20   result=(result<<8)+(uint32_t)adcValue[1];
    21   result=(result<<8)+(uint32_t)adcValue[2];
    22  
    23   return result;
    24 }

      这里获取的只是ADC的数字码值。我们想要得到温度和压力的物理量值还需要使用校准值,通过厂家提供的公式计算得到。

    3、驱动的使用

      在前面我们描述了MS5837压力传感器的基本情况,在此基础上设计并实现了MS5837压力传感器对象的驱动程序。这一节我们将设计一个简单的应用来验证驱动设计是否符合要求。

    3.1、声明并初始化对象

      使用基于对象的操作我们需要先得到这个对象,所以我们先要使用前面定义的MS5837压力传感器对象类型声明一个MS5837压力传感器对象变量,具体操作格式如下:

      MS5837ObjectType ms5837;

      声明了这个对象变量并不能立即使用,我们还需要使用驱动中定义的初始化函数对这个变量进行初始化。这个初始化函数所需要的输入参数如下:

      MS5837ObjectType *ms,MS5837对象

      MS5837Write write,向MS5837写数据函数指针

      MS5837Read read,从MS5837读数据函数指针

      MS5837Delayms delayms,毫秒延时函数指针

      对于这些参数,对象变量我们已经定义了。我们需要重点关注几个函数指针,首先要定义这几个函数,并将函数指针作为参数。这几个函数的类型如下:

    1 /*向MS5837下发指令,指令格式均为1个字节*/
    2 typedef void (*MS5837Write)(struct MS5837Object *ms,uint8_t command);
    3 
    4 /*从MS5837读取多个字节数据的值*/
    5 typedef void (*MS5837Read)(struct MS5837Object *ms,uint8_t *rData,uint16_t rSize);
    6 
    7 /*毫秒秒延时函数*/
    8 typedef void (*MS5837Delayms)(volatile uint32_t nTime);

      对于这几个函数我们根据样式定义就可以了,具体的操作可能与使用的硬件平台有关系。片选操作函数用于多设备需要软件操作时,如采用硬件片选可以传入NULL即可。具体函数定义如下:

     1 /*通过I2C1接口下发命令*/
     2 static void SendCommandToMS5837(MS5837ObjectType *ms,uint8_t command)
     3 {
     4   HAL_I2C_Master_Transmit(&ms5837hi2c,ms->devAddress,&command,1,1000);
     5 }
     6  
     7 /*通过I2C1接口读取数据*/
     8 static void GetDatasFromMS5837(MS5837ObjectType *ms,uint8_t *rData,uint16_t rSize)
     9 {
    10   HAL_I2C_Master_Receive(&ms5837hi2c,ms->devAddress,rData,rSize,1000);
    11 }

      对于延时函数我们可以采用各种方法实现。我们采用的STM32平台和HAL库则可以直接使用HAL_Delay()函数。于是我们可以调用初始化函数如下:

      MS5837Initialization(&ms5837,SendCommandToMS5837,GetDatasFromMS5837,HAL_Delay);

    3.2、基于对象进行操作

      我们定义了对象变量并使用初始化函数给其作了初始化。接着我们就来考虑操作这一对象获取我们想要的数据。我们在驱动中已经将获取数据并转换为转换值的比例值,接下来我们使用这一驱动开发我们的应用实例。

     1 /*获取压力变送器数据*/
     2 void MS5837GetMeasureData(void)
     3 {
     4        float pressure=0.0;
     5        float temperature=0.0;
     6       
     7        GetMS5837ConversionValue(&ms5837,MS5837_OSR8192,MS5837_OSR8192);
     8       
     9        pressure=ms5837.pressure;
    10        temperature=ms5837.temperature;
    11 }

    4、应用总结

      我们已经实现了MS5837压力传感器的驱动程序,也设计了一个简单的应用来验证这一驱动程序。验证的结果与我们预期一样,得到了我们需要的数据。我们也曾将这一驱动应用于实际项目,效果也是令人满意的。

      使用驱动是需要注意,MS5837压力传感器虽然采用了I2C接口,但它的地址是固定的,所以一条总线上只能有一台MS5837压力传感器。所以在驱动中地址是固化在驱动程序中不可修改的。

      源码下载:https://github.com/foxclever/ExPeriphDriver

    欢迎关注:

  • 相关阅读:
    vi 命令 使用方法
    再论C++之垃圾回收(GC)
    Iterative (non-recursive) Quick Sort
    DirectSound的应用
    JavaScript也能求爱哦
    lol匹配算法
    一年成为Emacs高手(像神一样使用编辑器)
    SSH深度历险(四) Maven初步学�
    char* 和char[]的差别
    数据仓库与数据挖掘的一些基本概念
  • 原文地址:https://www.cnblogs.com/foxclever/p/13976662.html
Copyright © 2020-2023  润新知