外设驱动库开发笔记17:MS5803压力变送器驱动

很多时候我们需要检测被控对象的绝对压力,而且在我们的多款产品中也有这样的需求。当然检测绝对压力的传感器有很多,我们经常使用MS5803来实现压力检测。本篇中我们将设计并实现MS5803系列压力传感器的驱动。

1、功能概述

MS5803系列产品包含压阻传感器和传感器接口ICMS5803系列压力传感器的主要功能是将未补偿的压阻压力传感器的模拟输出电压24位数字值,以及提供一个24位数字值的温度传感器。

1.1、硬件描述

MS5803系列压力传感器是新一代高分辨率高度计传感器,它是为高度计和高度分辨率为20厘米的变压计优化。能够同时获得压力值和温度值,其中压力测量范围为10-1100mbar,温度的测量范围是-40-85摄氏度。MS5803系列压力传感器各引脚功能如下:

MS5803系列压力传感器具有SPII2C总线接口。MS5803系列压力传感器模块包括一个高线性压力传感器和一个超低功率24ΔΣADC与内部工厂校准系数。它提供一个精确的数字24位压力和温度值和不同的操作模式。传感器内部结构图如下:

我们使用MS5803系列压力传感器时,需要做的就是选择不同的通讯接口与其实现数字通讯的过程。

1.2、通讯接口

MS5803系列压力传感器支持SPII2C总线通讯,通过协议选择引脚PS来决定采用什么接口。将协议选择引脚PS拉低,选择SPI协议,将PS拉高,激活I2C总线协议。在不同协议下相关引脚的定义如下:

在不同协议下各引脚所支持的参数是有些许差异的。在SPI接口模式下时钟引脚最大可达20MHz;在I2C接口模式下时钟引脚最大可达200kHz。具体的参数如下图:

SPI模式下,SCLK作为外部输入时钟,SDI作为串行数据输入,支持Mode0Mode3的时钟极性和相位。传感器的响应数据输出为SDO引脚,片选信号为CSB引脚。SPI模式下接线示意图如下:

I2C模式下,SCLK为外部串行时钟输入,SDA为串行数据通讯。CSB引脚作为地址选择,可以链接到VDD或者GND,这也意味着MS5803可以在一条I2C总线接两个设备。在CSP接高电平时,地址为0x76(1110110 b),而CSB接低电平时,地址为0x77 (1110111 b)这个地址是高七位,最后以为有读写命令来决定。实现写命令时,最后一位为0,实现读命令时,最后一位为1I2C模式下接线图如下:

1.3、数据访问

无论是在SPI模式还是在I2C模式,MS5803系列压力传感器都是通过5类命令实现的。这些命令包括:复位、读取出厂校准值、数据1转换(压力值数据)、数据2转换(温度值数据)和读取ADC的转换结果。具体命令定义如下:

从上图,我们知道每个命令的大小为1字节(8)。需要说明的是,ADC读取指令后,设备将返回24位结果,PROM读取则是16位结果。PROM的地址使用Ad2Ad1Ad0位嵌入到PROM读命令中。关于这128bit PROM的地址分配如下图所示:

MS5803系列压力传感器每个模块都是在两个温度和两个压力下单独校准的。这6个必要的系数来补偿工艺变化和温度变化,就存储在每个模块的128bit PROM中。这些6个系数必须由软件读取,并在程序中使用,将D1D2转换成补偿的压力和温度值。

2、驱动设计与实现

我们已经了解了MS5803压力传感器基本操作。在此基础上,我们将设计并实现MS5803压力传感器的驱动程序。

2.1、对象定义

在使用一个对象之前我们需要获得一个对象。同样的我们想要MS5803压力传感器就需要先定义MS5803压力传感器的对象。

2.1.1、对象的抽象

我们要得到MS5803压力传感器对象,需要先分析其基本特性。一般来说,一个对象至少包含两方面的特性:属性与操作。接下来我们就来从这两个方面思考一下MS5803压力传感器的对象。

先来考虑属性,作为属性肯定是用于标识或记录对象特征的东西。我们来考虑MS5803压力传感器对象属性。首先MS5803有一系列的产品,不同产品线的补偿计算方式有很大差异,所以我们将产品类型作为属性以区别不同的产品。MS5803拥有SPII2C两种通讯方式可供选择,为了确定具体设备所采用的接口,我们将其作为对象的属性以记录其使用的接口方式。在采用I2C接口模式时,每台设备都有一个设备地址,这个地址用于区分同一总线上不同的设备,所以我们将地址作为对象的属性。而对于MS5803每台都有6个校准参数,这些参数在测量是需要用到,所以我们需要保存这些参数,所以我们将其作为属性。

接着我们还需要考虑MS5803压力传感器对象的操作问题。无论是使用SPI接口还是使用I2C接口我们都需要向MS5803写命令和从MS5803读数据,而读写行为都与所处的硬件平台相关,所以我们将读和写数据作为对象的操作。为控制时序,我们需要延时操作,但延时操作也与具体的软硬件平台相关,所以我们将其作为对象的操作。在使用SPI接口方式时,若使用软件控制片选信号,则会依赖于硬件,我们将针对片选信号的操作作为对象的操作。

根据上述我们对MS5803压力传感器的分析,我们可以定义MS5803压力传感器的对象类型如下:

typedef struct MS5803Object {uint8_t devAddress;                 //设备地址MS5803PortType port;            //通讯端口协议MS5803ModelType model;    //设备的类型uint16_t caliData[6];        //校准数据float temperature;float pressure;void (*Write)(struct MS5803Object *ms,uint8_t command);//向MS5803写信息void (*Read)(struct MS5803Object *ms,uint8_t *rData,uint16_t rSize);//从MS5803读数据void (*ChipSelcet)(MS5803CSType en);     //片选信号,用于SPI接口void (*Delayms)(volatile uint32_t nTime);     //毫秒秒延时函数
}MS5803ObjectType;

2.1.2、对象初始化

我们知道,一个对象仅作声明是不能使用的,我们需要先对其进行初始化,所以这里我们来考虑MS5803压力传感器对象的初始化函数。一般来说,初始化函数需要处理几个方面的问题。一是检查输入参数是否合理;二是为对象的属性赋初值;三是对对象作必要的初始化配置。据此我们设计MS5803压力传感器对象的初始化函数如下:

/* MS5803对象初始化 */
void MS5803Initialization(MS5803ObjectType *ms,             //MS5803对象MS5803ModelType model,    //类型MS5803PortType port,            //通讯端口uint8_t address,                        //I2C设备地址MS5803Write write,                //写数据函数MS5803Read read,                         //读数据函数MS5803ChipSelcet cs,            //SPI片选信号MS5803Delayms delayms              //毫秒延时)
{if((ms==NULL)||(write==NULL)||(read==NULL)||(delayms==NULL)){return;}ms->Write=write;ms->Read=read;ms->Delayms=delayms;ms->model=model;ms->port=port;if(port==I2C){if((address==0x76)||(address==0x77)){ms->devAddress=(address<<1);}else if((address==0xEC)||(address==0xEE)){ms->devAddress=address;}else{ms->devAddress=0x00;}ms->ChipSelcet=cs;}else{ms->devAddress=0xFF;if(cs==NULL){ms->ChipSelcet=MS5803ChipSelect;}else{ms->ChipSelcet=cs;}}ms->pressure=0.0;ms->temperature=0.0;ResetForMS5803(ms);GetMS5803CalibrationData(ms);
}

2.2、对象操作

我们已经完成了MS5803压力传感器对象类型的定义和对象初始化函数的设计。但我们的主要目标是获取对象的信息,接下来我们还要实现面向MS5803压力传感器的各类操作。

MS5803压力传感器的其实就是基于前面我们所说的命令来实现的。根据这些命令的作用,我们可以大致分为三个方面:设备复位、ADC转换配置及数据获取、校准系数的获取。下面我么五年就从这三个方面来看一看MS5803压力传感器的操作。

2.2.1、复位操作

复位操作可以在电源供电后的任意时刻发送,但一般要求在开机后首先发送复位程序。这样可以确保校准PROM加载到内部寄存器。当然复位操作也可以用来重置设备ROM以便从我们未知的情况中恢复。

在使用SPI通讯接口时,无论是模式0还是模式3其操作是一样的,SPI方式下的时序图如下:

I2C通讯接口时,有时候通讯可能会出现SDA被未定义的状态阻塞的时候,可以通过复位操作来恢复通讯。I2C方式下的时序图如下:

/*复位MS5803操作*/
void ResetForMS5803(MS5803ObjectType *ms)
{uint8_t command=COMMAND_RESET;/*下发复位命令*/ms->Write(ms,command);ms->Delayms(3);
}

2.2.2、读取校准值

校准值是出厂时厂家校准的各种系数,每台设备都有差异,但每台设备是固定不变的,只需要一次读取就可以了,共有6个系数,均为16为整数。

用户复位后,执行一次PROMread命令,读取校准PROM的内容,计算校准系数。关于PROM我们前面已经描述过了,总共有8个地址,地址0包含工厂数据和设置,地址1-6校准系数,地址7包含串行代码和CRC

SPI接口通讯模式下,我们发送都对应地址的命令,等待接收数据即可。命令为8位,返回数据为16位,时序图如下:

I2C接口通讯模式下,PROM读命令由两部分组成。第一个命令将系统设置为PROM读模式。第二部分从系统中获取数据。首先发送读系数的命令,然后读取就可以了,每次读取1个,分6次读取。I2C模式下的时序图如下所示:

/*读取MS5803内存寄存器的数据*/
static uint16_t ReadPromFromMS5803(MS5803ObjectType *ms,uint8_t command)
{/*下发读取指定内存单元的命令*/ms->Write(ms,command);/*接收读取的指定内存单元的值*/uint8_t promValue[2];ms->Read(ms,promValue,2);uint16_t result=(uint16_t)promValue[0];result=(result<<8)+(uint16_t)promValue[1];return result;
}

2.2.3、读取转换值

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

对于配置转换及读取转换的结果,在SPI接口模式下,按两步实现:先设置转换精度,等待转换结束再读取数据。具体的时序图如下:

对于配置转换及读取转换的结果,在I2C接口模式下,按三步实现:先设置转换精度,等待转换结束发送读ADC命令,最后读取数据。具体的时序图如下:

/*读取MS5803ADC的转换值*/
static uint32_t ReadConversionFromMS5803(MS5803ObjectType *ms,uint8_t command)
{/*下发转化对象及精度配置命令*/ms->Write(ms,command);ms->Delayms(10);/*下发读取ADC的命令*/ms->Write(ms,COMMAND_ADC_READ);if(ms->port==I2C){ ms->Delayms(10);}/*接收读取的ADC转换结果*/uint8_t adcValue[3];ms->Read(ms,adcValue,3);uint32_t result=(uint32_t)adcValue[0];result=(result<<8)+(uint32_t)adcValue[1];result=(result<<8)+(uint32_t)adcValue[2];return result;
}

3、驱动的使用

我们已经设计并实现了MS5803压力传感器的驱动程序,这个驱动程序是否符合要求还需要验证。这一节我们就来设计一个简单的应用验证这一驱动程序。

3.1、声明并初始化对象

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

MS5803ObjectType ms5803;

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

MS5803ObjectType *msMS5803对象

MS5803ModelType model,类型

MS5803PortType port,通讯端口

uint8_t addressI2C设备地址

MS5803Write write,写数据函数

MS5803Read read,读数据函数

MS5803ChipSelcet csSPI片选信号

MS5803Delayms delayms,毫秒延时

对于这些参数,对象变量我们已经定义了。设备类型和通讯端口都是枚举,我们只需要根据实际的配置情况选择就可以了。设备地址则在采用I2C通讯时,根据实际输入。我们主要需要关注的是定义几个函数,并将函数指针作为参数。这几个函数的类型如下:

/*向MS5803下发指令,指令格式均为1个字节*/
typedef void (*MS5803Write)(MS5803ObjectType *ms,uint8_t command);/*从MS5803读取多个字节数据的值*/
typedef void (*MS5803Read)(MS5803ObjectType *ms,uint8_t *rData,uint16_t rSize);/*片选信号,用于SPI接口*/
typedef void (*MS5803ChipSelcet)(MS5803CSType en);    /*毫秒秒延时函数*/
typedef void (*MS5803Delayms)(volatile uint32_t nTime);  

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

/*通过I2C1接口下发命令*/
static void SendCommandToMS5803(MS5803ObjectType *ms,uint8_t command)
{HAL_I2C_Master_Transmit(&ms5803hi2c,ms->devAddress,&command,1,1000);
}/*通过I2C1接口读取数据*/
static void GetDatasFromMS5803(MS5803ObjectType *ms,uint8_t *rData,uint16_t rSize)
{HAL_I2C_Master_Receive(&ms5803hi2c,ms->devAddress,rData,rSize,1000);
}

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

MS5803Initialization(&ms5803,MS580302BA,I2C,0xEC,SendCommandToMS5803,GetDatasFromMS5803,NULL,HAL_Delay);

这里我们使用的型号是MS580302BA,采用I2C接口,地址为0xEC。因为使用的是I2C接口所以片选输入NULL

3.2、基于对象进行操作

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

/*获取压力变送器数据*/
void GetPressureSenserData(void)
{float pressure=0.0;float temperature=0.0;GetMS5803ConversionValue(&ms5803,MS5803_OSR4096,MS5803_OSR4096);pressure=ms5803.pressure;temperature=ms5803.temperature;
}

4、应用总结

在本篇中,我们实现了MS5803压力传感器的驱动程序,并基于驱动程序开发了简单的验证应用。我们也多次在项目中使用MS5803压力传感器,使用的就是这一套驱动程序,应用的效果非常不错。

在使用I2C接口时,引脚CSB应连接到VDDGND。因为MS5803的地址位仅有1位是可以通过CSB设定的,所以一条I2C总线最多只能挂2MS5803模块。当CSBVDD时地址最低位为1;当CSBGND时地址最低位为0

在使用驱动时需注意,采用SPI接口的器件需要考虑片选操作的问题。如果片选信号是通过硬件电路来实现的,我们在初始化时给其传递NULL值。如果是软件操作片选则传递我们编写的片选操作函数。

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

欢迎关注:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499345.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通讯接口应用笔记1:RS485通讯上下拉电阻的选择

RS485是一种常见的通讯接口方式&#xff0c;在我们的实际产品中也是多次使用。但我们平常并不会去过多考虑某一实现的细节问题&#xff0c;不过最近我们遇到了一个因如上下拉电阻的选择问题而造成的通讯故障&#xff0c;所以在这一片中我们来讨论一下RS485总线上下拉电阻的选择…

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

绝对压力的检测是常见的需求。在我们的系统中也常常会遇到。而MS5837压力传感器也是我们进场会采用的方案。在这篇里我们将讨论并实现MS5837压力传感器的驱动。 1、功能概述 MS5837压力传感器是一种可用于电路板上&#xff0c;适用于检测10-1200mbar压力范围的传感器&#xf…

外设驱动库开发笔记19:BMP280压力温度传感器驱动

压力和温度监测在嵌入式系统开发中是非常常见的需求&#xff0c;特别是对环境大气压力和温度的检测需求就更常见了。我们一般都会选择一些封装较小操作比较方便的压力传感器。BMP280就是满足这一要求的器件。在这一篇中我们将设计并实现BMP280的驱动。 1、功能概述 BMP280是一…

一个简单的空气质量数据监测站项目

大气质量数据监测站用于测试空气质量监测及数据采集&#xff0c;实现野外或者室内空气质量的检测。并通过网络将数据上传到OneNet​显示。​ 1、项目概述 本项目是一个定制项目&#xff0c;要求采集大气的压力、温度、湿度、PM25、位置等数据并上传到指定的后台服务器。但有时…

一个基于STM32实现的多组分气体分析仪项目

本篇将简要的总结一下一个基于STM32F412ZG实现的多组分气体分析仪的项目。简要描述该项目的软硬件设计及其验证。 一、项目概述 多组分气体分析仪是我公司近期研发的三个主要产品之一。采用模块化设计&#xff0c;可增减配置&#xff0c;可分析混合气体中的氧气、氢气、甲烷、…

外设驱动库开发笔记20:BME280压力湿度温度传感器驱动

嵌入式产品开发中&#xff0c;我们常常会有检测环境温度、压力、湿度的需求。如果有一个集成有这3个传感器的元件&#xff0c;无疑将是很方便的。博世的BME280就能实现这一要求。在这一篇中我们将讨论BME280的驱动设计与实现。 1、功能概述 BME280是一款专为移动应用而开发的…

外设驱动库开发笔记21:BME680环境传感器驱动

环境传感器是一类我们很常用的传感器。它可以方便我们获取压力、温度、湿度以及空气质量等数据。在这一篇中&#xff0c;我们将分析BME680环境传感器的功能&#xff0c;并设计和实现BME680环境传感器的驱动。 1、功能概述 BME680是一款专为移动应用和可穿戴设备开发的集成环境…

外设驱动库开发笔记22:ADXL345三轴数字加速度计驱动

移动设备的广泛应用增加对移动过程中各种参数的检测需求。ADXL345三轴数字加速度计可以用来检测加速度、进而测量倾斜角度等。在这一篇中&#xff0c;我们将讨论ADXL345三轴数字加速度计驱动程序的设计与实现。 1、功能概述 ADXL345是一款小而薄的超低功耗3轴加速度计&#x…

外设驱动库开发笔记23:AT24Cxx外部存储器驱动

在我们的应用开发过程中&#xff0c;经常会使用到外部的EEPROM外部存储器来保存一些参数和配置数据等。而比较常用的就是AT24Cxx系列产品&#xff0c;这一节我们来开发用于操作AT24Cxx系列产品的驱动。 1、功能概述 AT24Cxx系列EEPROM包括从1Kbit到2Mbit的各种容量。AT24Cxx系…

外设驱动库开发笔记24:FM24xxx系列FRAM存储器驱动

虽然说使用EEPROM保存参数很有效&#xff0c;但操作及使用次数均有一下限制。当我们的一些参数需要不定时修改或存储时&#xff0c;使用FRAM就更为方便一点。这一节我们就来设计并实现FM24xxx系列FRAM的驱动。 1、功能概述 我们首先说一下铁电随机存取存储器&#xff0c;F-RA…

外设驱动库开发笔记25:FM25xxx FRAM存储器驱动

在我们的项目中&#xff0c;时常会有参数或数据需要保存。铁电存储器的优良性能和操作方便常常被我们选用。FM25xxx FRAM存储器就是我们经常使用到的一系列铁电存储器&#xff0c;这一篇我们将讨论FM25xxx FRAM存储器的驱动设计、实现及使用。 1、功能概述 FM25xxx FRAM存储器…

步进电机驱动技术1:基于TMC2660的步进电机驱动

步进电机的应用非常广泛&#xff0c;在各种设备中经常会遇到&#xff0c;而步进电机的驱动则是使用步进电机必不可少的部分&#xff0c;可以有多种方式来实现步进电机的驱动&#xff0c;在这里我们来考虑一下基于TMC2660驱动芯片的步进电机驱动。 1、功能概述 TMC2660是德国T…

外设驱动库开发笔记26:nRF24L01无线通讯驱动

现在无线在我们的生活中无处不在。而我们开发的物联网产品也大量使用无线通讯。在这一篇文章中&#xff0c;我们将讨论nRF24L01无线通讯模块驱动程序的开发与实现。 1、功能概述 nRF24L01是一款工作在2.4~2.5GHz世界通用ISM 频段的单片无线收发器芯片无线收发器包括&#xff…

外设驱动库开发笔记27:ESP8266无线通讯驱动

我们的物联网产品所使用的平台都支持无线通讯&#xff0c;而且无线通讯本身更的成本较低&#xff0c;受到大家的欢迎。在本篇文章中&#xff0c;我们将详细讨论并实现ESP8266无线通讯模块的驱动。 1、功能概述 ESP8266是由乐鑫公司出品的一款物联网芯片&#xff0c;因为价格较…

外设驱动库开发笔记28:W5500以太网控制器

以太网通讯是一种被广泛使用的数据通讯方式。在嵌入式应用中也经常使用&#xff0c;但协议栈的实现并不是一件容易的事。不过有些以太网控制器就带有协议栈&#xff0c;如W5500。在本篇中我们将讨论如何设计并实现W5500以太网控制器的驱动。 1、功能概述 W5500是WIZnet开发的…

外设驱动库开发笔记29:DS17887实时时钟驱动

一些时候&#xff0c;在我们的嵌入式产品中需要记录时间&#xff0c;所以我们就需要获取时钟&#xff0c;当然实现的方式多种多样&#xff0c;有的MCU本身就有这一功能&#xff0c;不过精度较低。当我们的应用要求较高时就需要使用专门的实时时钟芯片&#xff0c;如DS17887。在…

外设驱动库开发笔记30:宇电AI-BUS通讯驱动

嵌入式系统通常都会与外部设备进行通讯&#xff0c;这就涉及到通讯协议的问题。这些通讯协议有的是标准协议有的厂家自定义的协议&#xff0c;如宇电的AI-BUS。在本篇中&#xff0c;我们将讨论AI-BUS的驱动&#xff0c;以便于与宇电设备的通讯。 1、功能概述 宇电的设备使用基…

步进电机驱动技术3:基于ULN2003的步进电机驱动

在我们的项目中&#xff0c;经常使用到低电压小功率的步进电机&#xff0c;此类步进电机若采用驱动器控制不断成本高也过于复杂&#xff0c;我们可以直接使用场效应管或者达林顿管来实现对其的驱动。在本篇中&#xff0c;我们就来讨论一下基于ULN2003A达林顿管实现对步进电机的…

通讯接口应用笔记2:MAX3160实现多协议通讯

在一些应用需求中&#xff0c;我们需要对外部提供串行通讯端口&#xff0c;但这些端口所通讯的目标设备各有不同&#xff0c;接口协议也有RS232以及RS485和RS422多种。面对这种情况&#xff0c;我们当然可以同时设计多个串口以适应不同需要&#xff0c;但无疑对硬件资源是一种浪…

电机速度曲线规划1:梯形速度曲线设计与实现

电机驱动是很常见的应用&#xff0c;在很多系统中我们都会碰到需要改变电机的速度以实现相应的控制功能&#xff0c;这就涉及到电机速度曲线规划的问题。在这篇中我们就来简单讨论一下电机的梯形曲线规划的问题。 1、基本原理 梯形速度曲线控制算法是工业控制领域应用最为广泛…