外设驱动库开发笔记45:MS4515DO压力传感器驱动

  很多时候我们需要检测流量和压力这些参数,比如我们要检测大气压,或者通过测量差压来获得输送流体的流量等,都需要用到压力传感器。这一篇我们就来讨论MS4515DO压力传感器的数据获取。

1、功能概述

  MS4515DO是TE公司推出的一款基于PCB安装的小型陶瓷基压力传感器。该传感器采用最新的CMOS传感器调节电路,制造出一种低成本、高性能的数字输出压力(14bit)和温度(11bit)传感器,以满足OEM客户最严格的要求。
  MS4515DO完全校准和温度补偿,总误差带在补偿范围内小于1.0%。该传感器采用直流3.3V或5.0V单电源供电模式,对外接口采用I2C总线或三线SPI的模式。其结构图如下:

  MS4515DO和MS4525DO拥有相同的功能和模式,区别只在于输出的物理量单位不同而已。它们都拥有可以检测差压和绝压的型号,但操作是完全一样的,所以本篇的讨论事实上适用于相关系列的全部型号的应用。

1.1、MS4515DO的I2C地址

  作为I2C接口的设备都会有一个设备地址,MS4515DO压力传感器也不例外。而MS4515DO和MS4525DO系列传感器的I2C地址在出厂时已特定写入,并根据型号中的字母来指示其地址设定。具体如下:

  预设的设备地址是7位的,不包含读写位的指示。我们使用时需要将其左移一位并根据读写操作来定义读写位,0为写,1为读。

1.2、数据输出格式

  在I2C通讯模式下,MS4515DO和MS4525DO传感器有四个I2C读取命令,分别为:Read_MR、Read_DF2、Read_DF3和Read_DF4。这四个命令可以获取不同的数据,这些命令的具体报文格式定义如下图:

  所以我们想要获取MS4515DO和MS4525DO传感器的数据就需要通过上述命令来实现。从上述的命令报文格式可以看出,这些命令在本质上是没有差别的,都多少数据完全由主机来控制,也就是我们开发的驱动程序来控制。事实上,我们只需要考虑Read_DF4这个命令就可以涵盖所有想要的数据。
  我们需要注意的是,上述的报文中有两位存储的是状态信息,该状态信息表示获取的数据是最新的数据还是旧数据或者错误报警。通过判断这个数据可以决定我们在数据解析时如何处理相应的报文。

2、驱动设计与实现

  我们已经了解了MS4515DO和MS4525DO传感器的结构、接口方式、设备地址以及数据输出格式。接下来我们就可以考虑如何实现MS4515DO和MS4525DO传感器的驱动程序了。

2.1、对象定义

  我们依然还是先来考虑MS4515DO和MS4525DO传感器的对象定义。我们定义一个对象无非考虑属性和操作两个部分。
  首先我们来考虑MS4515DO和MS4525DO传感器对象的属性。首先MS4515DO和MS4525DO传感器采用I2C接口通讯,所以每台都有一个设备地址。这个地址标识了I2C总线上该设备的唯一性,所以我们将设备地址作为MS4515DO和MS4525DO传感器对象的一个属性。对于MS4515DO和MS4525DO传感器来说存在多种类型,而不同的类型对应不同的数据计算方式,所以针对某一具体实例,我们需要记录它的类型,所以我们为其定义一个类型属性。我们在计算压力值时,不同的量程最后得到的压力值与测量量程有关,所以我们还需要记录实例的量程上下限,所以将这两个数据也定义为对象的属性。为了操作方便我们将最终得到的温度和压力数据也都作为对象的属性。
  从前面的描述中,我们知道MS4515DO和MS4525DO传感器的数据输出格式是固定的,这为我们解析这一数据提供了思路。我们将读出的4个字节与我们想要得到的数据组成联合体,利用结构体和联合体在内存中的关系可以方便的解析数据对象,如下图所示:

  这些个数据即是我们想要的先要得到的,同时他们也记录了MS4515DO和MS4525DO传感器对象当前的状态,所以我们将其也作为对象的属性。
  其次我们来考虑MS4515DO和MS4525DO传感器对象的操作。我们需要将对象的哪些行为定义为操作呢?一般的我们考虑那些不能直接实现,而是要依赖特定的软硬件平台才能实现的对象行为。我们需要向MS4515DO和MS4525DO传感器发送命令,也需要从传感器获取对象,而无论读还是写都是依赖于具体的软硬件平台才能去定的,所以我们将向传感器写信息和从传感器读信息作为对象的2个操作。为了控制时序,我们一般需要演示处理函数,而演示处理函数的实现也是依赖于具体的软硬件平台的,所以我们将延时函数定义为对象的一个操作。
  我们分析了MS4515DO和MS4525DO传感器对象可能的属性和操作。根据前述的分析,我们可以定义MS4515DO和MS4525DO传感器对象的类型如下:

/* 定义MS45x5DO对象类型 */
typedef struct MS45x5DOObject {uint8_t devAddress;   //设备地址union {struct {uint16_t pressure:14;uint16_t status:2;uint16_t insignificance:5;uint16_t temperature:11;            }pData;uint8_t rData[4];}msData;            //读出的数值MS45x5DOType type;  //MS4515DO的类型float pUpperRange;  //压力量程上限float pLowerRange;  //压力量程下限float fTemperature; //计算的温度值float fPressure;    //计算的压力值void (*Write)(struct MS45x5DOObject *ms,uint8_t *wData,uint16_t wSize); //向MS45x5DO写数据void (*Read)(struct MS45x5DOObject *ms,uint8_t *rData,uint16_t rSize);  //从MS45x5DO读数据void (*Delayms)(volatile uint32_t nTime);     //毫秒秒延时函数
}MS45x5DOObjectType;

  我们定义了MS4515DO和MS4525DO传感器对象的类型,使用该类型我们可以定义我们想要的对象变量,但对象变量需要进行必要的配置才能真正的实例化,这个过程我们将其称之为对象的初始化。

/* 初始化MS45x5DO对象 */
void MS45x5DOInitialization(MS45x5DOObjectType *ms, //MS5837对象uint8_t devAddress,     //设备地址MS45x5DOType type,      //MS4515DO的类型float pMax,             //压力量程上限float pMin,             //压力量程下限MS45x5DOWrite write,    //向MS45x5DO写数据函数指针MS45x5DORead read,      //从MS45x5DO读数据函数指针MS45x5DODelayms delayms //毫秒延时函数指针)
{if((ms==NULL)||(write==NULL)||(read==NULL)||(delayms==NULL)){return;	}ms->Write=write;ms->Read=read;ms->Delayms=delayms;if((devAddress==0x28)||(devAddress==0x36)||(devAddress==0x46)||((0x48<=devAddress)&&(devAddress<=0x51))){ms->devAddress=(devAddress<<1);}else if((devAddress==0x50)||(devAddress==0x6C)||(devAddress==0x8C)||((0x48<=(devAddress/2))&&((devAddress/2)<=0x51))){ms->devAddress=devAddress;}else{ms->devAddress=0x00;}ms->type=type;ms->fPressure=0.0;ms->fTemperature=0.0;ms->msData.rData[0]=0;ms->msData.rData[1]=0;ms->msData.rData[2]=0;ms->msData.rData[3]=0;if((fabs(pMax)<=0.0000001)&&(fabs(pMin)<=0.0000001)){ms->pUpperRange=100.0;ms->pLowerRange=0.0;}else{ms->pUpperRange=pMax;ms->pLowerRange=pMin;}
}

2.2、对象操作

  我们已经可以得到一个对象变量并将它实例化,我们还需要考虑它的操作问题。对于MS4515DO和MS4525DO传感器来说其操作比较简单,最主要的操作包括数据获取和地址设定。

2.2.1、获取数据

  对于我们来说获取MS4515DO和MS4525DO传感器的测量数据是我们的主要目的。我们可以从MS4515DO和MS4525DO传感器获取压力和温度数据,其测量范围与输出数据的对应关系如下图所示:

  根据上表中的数据对应关系,我们可以编写获取MS4515DO和MS4525DO传感器的数据并解析的函数。

/*获取转换值,包括温度和压力*/
void GetMS45x5DOConversionValue(MS45x5DOObjectType *ms)
{uint8_t rData[4]={0,0,0,0};float maxCount=16383;float minCount=0;if(ms->type==MS45x5DO_TypeA){maxCount=13106;minCount=1638;}else{maxCount=14746;minCount=819;}ms->Read(ms,rData,4);ms->msData.rData[0]=rData[1];ms->msData.rData[1]=rData[0];ms->msData.rData[2]=rData[3];ms->msData.rData[3]=rData[2];if(ms->msData.pData.status!=MS45x5DO_Fault){ms->fPressure=(((float)ms->msData.pData.pressure-minCount)/maxCount)*(ms->pUpperRange-ms->pLowerRange)+ms->pLowerRange;ms->fTemperature=((float)ms->msData.pData.temperature/2047.0)*200.0-50.0;}
}

2.2.2、地址设置

  关于MS4515DO和MS4525DO传感器,在出厂时已经设定了设备地址并在型号编码中给予指示。但在一些特殊情形下我们可能需要修改它的设备地址,这就需要用到MS4515DO和MS4525DO传感器的地址修改操作。

/*修改MS45x5DO的设备地址*/
void ModifyMS45x5DODecAddress(MS45x5DOObjectType *ms,uint8_t newAddress)
{uint8_t eepromByte[3];uint16_t eepromTemp=0x00;//第1步、进入命令模式eepromByte[0]=0xA0;eepromByte[1]=0x00;eepromByte[2]=0x00;ms->Write(ms,eepromByte,3);//第2步、发送读EEPROM命令eepromByte[0]=0x02;eepromByte[1]=0x00;eepromByte[2]=0x00;ms->Write(ms,eepromByte,3);//第3步、获取EEPROM的值ms->Read(ms,eepromByte,3);//第4步、修改为新地址if(eepromByte[0]==0x5A){eepromTemp=(eepromByte[1]<<8)+eepromByte[2];eepromTemp=(eepromTemp&0xE007)+0xC00+(newAddress<<3);eepromByte[1]=(uint8_t)((eepromTemp&0xFF00)>>8);eepromByte[1]=(uint8_t)(eepromTemp&0x00FF);}else{return;}//第5步、将新地址写入EEPROMeepromByte[0]=0x02;ms->Write(ms,eepromByte,3);//第6步、退出命令模式eepromByte[0]=0x80;eepromByte[1]=0x00;eepromByte[2]=0x00;ms->Write(ms,eepromByte,3);
}

3、驱动的使用

  我们已经设计并实现了MS4515DO和MS4525DO压力传感器的驱动程序。接下来我们将简单的说明如何使用这一驱动,并设计一个简单的示例验证这一驱动程序的正确性。

3.1、声明并初始化对象

  我们是基于对象设计的MS4515DO和MS4525DO压力传感器的驱动程序,所以在使用驱动时,我们需要先声明一个对象变量,然后基于该对象变量来实现具体的对象操作。我们先声明对象如下:

MS45x5DOObjectType msDP;

  声明了这个对象变量之后,我们还需要使用初始化函数对其进行初始化方可使用。这一初始化函数拥有8个参数:

MS45x5DOObjectType *ms, //MS5837对象
uint8_t devAddress,     //设备地址
MS45x5DOType type,      //MS4515DO的类型
float pMax,             //压力量程上限
float pMin,             //压力量程下限
MS45x5DOWrite write,    //向MS45x5DO写数据函数指针
MS45x5DORead read,      //从MS45x5DO读数据函数指针
MS45x5DODelayms delayms //毫秒延时函数指针

  第一个参数正是我们要初始化的对象变量。第二个参数为我们所要操作的MS4515DO对象的设备地址。第三个参数是MS4515DO对象的具体类型,根据实际设备选择枚举即可。第四和第五个参数是该对象的物理量量程,根据具体对象而定。后面三个参数是实现对象操作的函数指针。这三个函数指针需要我们根据具体的软硬件平台来实现。它们的原型如下:

/*向MS45x5DO下发指令,指令格式均为1个字节*/
typedef void (*MS45x5DOWrite)(struct MS45x5DOObject *ms,uint8_t *wData,uint16_t wSize);
/*从MS45x5DO读取多个字节数据的值*/
typedef void (*MS45x5DORead)(struct MS45x5DOObject *ms,uint8_t *rData,uint16_t rSize);
/*毫秒秒延时函数*/
typedef void (*MS45x5DODelayms)(volatile uint32_t nTime);

  我们根据函数原型定义,在具体的实现平台上实现它们,如我们在STM32平台上可以实现如下:

/*向MS45x5DO下发指令,指令格式均为1个字节*/
static void WriteToDP(MS45x5DOObjectType *ms,uint8_t *wData,uint16_t wSize)
{HAL_I2C_Master_Transmit(&hi2c2,ms->devAddress,wData,wSize,1000);
}
/*从MS45x5DO读取多个字节数据的值*/
static void ReadFromDP(MS45x5DOObjectType *ms,uint8_t *rData,uint16_t rSize)
{HAL_I2C_Master_Receive(&hi2c2,ms->devAddress,rData, rSize, 1000);
}

  延时函数我们可以直接使用HAL库中的HAL_Delay也可以自己编写,在HAL库中HAL_Delay是一个弱化定义的函数,我们可以重写这一函数来实现不同的应用需求。到这里我们就可以使用对象初始化函数来初始化前面声明的对象变量了。具体如下:

MS45x5DOInitialization(&msDP, //MS5837对象0x28,     //设备地址MS45x5DO_TypeA,      //MS4515DO的类型DPUpperRange,          //压力量程上限DPLowerRange,          //压力量程下限WriteToDP,    //向MS45x5DO写数据函数指针ReadFromDP,   //从MS45x5DO读数据函数指针HAL_Delay //毫秒延时函数指针);

3.2、基于对象进行操作

  完成了对象的初始化后,我们就可以基于对象来实现相应的操作了。如我们使用驱动获取msDP对象的差压数据如下:

/*差压数据获取*/
void GetFlowDPDatas(void)
{GetMS45x5DOConversionValue(&msDP);aPara.phyPara.dPressure =msDP.fPressure;aPara.phyPara.dTemperature=msDP.fTemperature;
}

4、应用总结

  我们设计并实现了MS4515DO和MS4525DO压力传感器对象的驱动程序,并基于驱动程序实现了一个简单的测试实例,获得的结果如下:

  从上述两图中我们可以知道我们的驱动程序是正确的。事实上这一驱动已应用于我们的流量测量设备中,实现的效果良好。

欢迎关注:

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

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

相关文章

外设驱动库开发笔记48:MCP4725单通道DAC驱动

在产品设计过程中&#xff0c;我们经常会遇到数模转换的应用需求。在本篇种我们就来讨论一下MCP4725单通道数模转换器的驱动设计与实现。 1、功能概述 MCP4725是一个低功耗&#xff0c;高精度&#xff0c;单通道&#xff0c;12位缓冲电压输出数字到模拟转换器(DAC)与非易失性存…

如何确保不使用动态内存

在许多嵌入式应用程序中&#xff0c;内存分配必须是静态的&#xff0c;而不是动态的。意味着在应用程序中不应使用对malloc()或free()等内容的调用&#xff0c;因为它们可能会在运行时失败&#xff08;内存不足、堆碎片&#xff09;。 但是&#xff0c;当与第三方库甚至 C/C 标…

go 单元测试 testing 打印输出_2020,你需掌握go 单元测试进阶篇

本文说明go语言自带的测试框架未提供或者未方便地提供的测试方案&#xff0c;主要是用于解决写单元测试中比较头痛的依赖问题。也就是伪造模式&#xff0c;经典的伪造模式有桩对象(stub),模拟对象(mock)和伪对象(fake)。比较幸运的是&#xff0c;社区有丰富的第三方测试框架支持…

一文读懂Git工作流

Git是目前最流行的代码管理工具&#xff0c;相信大家也都是在用Git来管理自己团队的源代码。 团队一般为了规范开发&#xff0c;保持良好的代码提交记录以及维护 Git 分支结构清晰&#xff0c;方便后续维护等&#xff0c;都会迫切需要一个比较规范的 Git 工作流。 本文就是在…

xbox360fsd更新游戏封面_游戏类短视频创作指南

一&#xff0e;起步阶段1.内容发布垂直&#xff0c;整体风格一致&#xff0c;选定一个品类的游戏内容风格持续更新注意&#xff1a;冷启动时期不要频繁更换游戏类型2.账号IP化 根据自身风格特色打造独特的风格账号。有利延长账号生命周期&#xff0c;提升粉丝转化率。搞笑、中二…

开发者们都在关注的网站

开发者们都在关注的网站 &#x1f609; 综合类&#xff08;5个&#xff09; 1、GitHub 全球最大的编程开源社区&#xff0c;很多优秀的开源项目都在上边&#xff0c;不知道这个都不要说自己是程序员&#x1f602; 访问地址&#xff1a;https://github.com 2、CSDN 全球最大中…

ios framework 调用第三方 framework_Python基础:标准库和常用的第三方库

Python的标准库有&#xff1a;名称作用datetime为日期和时间处理同时提供了简单和复杂的方法。zlib直接支持通用的数据打包和压缩格式&#xff1a;zlib&#xff0c;gzip&#xff0c;bz2&#xff0c;zipfile&#xff0c;以及 tarfile。random提供了生成随机数的工具。math为浮点…

作图神器ProcessOn - 免费好用

因工作需要&#xff0c;我经常需要花一些流程图&#xff0c;时序图&#xff0c;架构图什么的&#xff0c;之前使用的Windows系统&#xff0c;大部分情况下就用的Visio来画图。后来为了工作方便&#xff0c;换成了Mac电脑&#xff0c;结果发现Mac上没有Visio&#xff0c;然后就在…

三电平igbt死区时间计算_基于大功率三电平IGBT模块并联的参考设计

当前的可再生能源行业中&#xff0c;光伏和风力发电均面临着补贴逐步退坡&#xff0c;平价上网时代即将到来的挑战。为应对这一挑战&#xff0c;光伏逆变器和风力变流器厂家研发的新品单机功率越来越高&#xff0c;以取得更低的单位功率成本。市场上1.5MW的集中式光伏逆变器和3…

手把手教你搭建开发环境之Java开发

大家好呀&#xff0c;从今天开始&#xff0c;我们的手把手系列教程就正式开始啦。 如果你觉得本文对你有一些帮助&#xff0c;欢迎大家关注、点赞、分享给需要的小伙伴们&#xff0c;谢谢大家啦。 前言 Java虽然是一个比较老的语言&#xff0c;但到现在依然充满了活力&#x…

opc服务器组态文件已写保护_远程组态软件不仅方便了PLC无线远程监控,也大大降低了工程成本...

远程组态软件不仅方便了PLC无线远程监控&#xff0c;也大大降低了工程成本组态软件远程监控1.本地上位SCADA系统采集分布各地现场PLC等设备运行的数据&#xff0c;并可以下发控制指令&#xff1b;2.提供稳定的OPC接口服务&#xff0c;常年稳定运行&#xff0c;规模可达10万数据…

奇妙的安全旅行之加密算法概述

前言 hi&#xff0c;大家好呀&#xff0c;信息安全作为当前社会中比较重要的一个课题&#xff0c;已经覆盖了人们生活的方方面面&#xff0c;虽然有时候我们可能并没有意识到&#xff0c;其实信息安全防护已经在背后默默的保护我们的信息安全了。例如&#xff0c;当你在互联网…

怎么调节电机启动值_开关式智能充电机-全自动充电机-铅酸电池充电机品牌-济南能华...

开关式智能充电机-全自动充电机-铅酸电池充电机品牌-济南能华NHCD系列 全自动智能充电机&#xff0c;可调智能充电机&#xff0c;可调直流充电机&#xff0c;可调全自动充电机 &#xff0c;可调蓄电池充电机 便携式可调智能充电机 便携式全自动充电机 大功率可调充电机 大功率智…

奇妙的安全旅行之MD算法

hi&#xff0c;大家好&#xff0c;今天我们开始介绍消息摘要算法中的MD&#xff08;Message Digest&#xff09;算法&#xff0c;MD算法家族包括&#xff1a;MD2&#xff0c;MD4&#xff0c;MD5&#xff0c;MD算法生成的消息摘长度要都是128位的。 其中MD5算法是消息摘要算法的…

的图层类型有哪些_东莞都市领航平面设计培训班都学习哪些内容?

平面设计的工作稳定性是很高的&#xff0c;经济繁荣时期毫无疑问&#xff0c;即使经济下滑&#xff0c;仍不会有很大影响&#xff0c;以前两年为例&#xff0c;北美的大规模裁员浪潮&#xff0c;给高科技行业带来巨大冲击&#xff0c;放慢了高科技产品的开发速度&#xff0c;当…

dockerfile拉取私库镜像_还在用Alpine作为你Docker的Python开发基础镜像?其实Ubuntu更好一点...

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_173一般情况下&#xff0c;当你想为你的Python开发环境选择一个基础镜像时&#xff0c;大多数人都会选择Alpine&#xff0c;为什么&#xff1f;因为它太小了&#xff0c;仅仅只有 5 MB 左右&#xff08;对比 Ubuntu 系列镜像接…

2020,再见;2021,我来了!

现在是2021年1月16日下午16点33分&#xff0c;星期六。此时北京正在通报昨日新冠肺炎新增病例情况&#xff0c;这种每天戴口罩的鬼日子还不知道什么时候能结束。最近由于天气变冷&#xff0c;病毒更容易存活和传播&#xff0c;最近一个月就突然又变的非常紧张起来了&#xff0c…

cuda tensorflow版本对应_Windows10下安装tensorflow-gpu(2.2.0)安装教程(避坑+保姆式教学)...

本文实现了Windows10下GPU版本的tensorflow2.2.0的安装&#xff0c;用到的软件主要包括&#xff1a;CUDA 10.2 cuDNN Anaconda tensorflow-gpu 2.2.0。&#xff08;注&#xff1a;此教程在Win7环境下也同样适用&#xff01;另附报错缺少cudart64_101.dll的解决办法&#xff…

奇妙的安全旅行之DES算法(二)

hi&#xff0c;大家好&#xff0c;上一节我们详细介绍了对称加密算法DES的基本内容&#xff0c;由于明文的长度不固定&#xff0c;而加密算法只能处理特定长度的一块数据&#xff0c;所以就需要对比较长的明文进行分组后再加密&#xff0c;但是分组后&#xff0c;最后一组的长度…

c++创建虚拟串口_linux虚拟串口控制器驱动实现——适用于无开发板学习串口驱动...

在上一章我们已经说明了uart驱动的开发流程&#xff0c;本章我们就不再介绍uart相关的接口实现&#xff0c;仅通过实现一个虚拟的串口控制器程序&#xff0c;用以说明虚拟串口的开发流程。本次开发的虚拟串口提供的功能如下&#xff1a;提供两个串口实例串口名称的前缀为vttyU为…