外设驱动库开发笔记52:PM3003S激光粉尘仪驱动

news/2025/1/17 21:30:59/

  空气质量是现代日常生活中人们所关注的事情,也是生存环境好坏的一种体现。其中粉尘数量监测更是空气质量检测中最常见的对象,在我们的检测设备中也经常会有这种需求。检测手段也是多种多样,这一篇中,我们就来讨论使用PM3003S 激光粉尘传感器实现粉尘测量。

1、功能概述

  PM3003S 激光粉尘传感器模块采用光学散射原理,可精确检测并计算单位体积内空气中不同粒径的悬浮颗粒物的个数,内置四方独有的尘源智能识别,配以流量稳定的气泵,可实现颗粒物PM1.0、PM2.5、PM10、TSP质量浓度的实时输出。
  PM3003S 激光粉尘传感器模块接口采用TTL电平。通讯报文包括起始符、长度、命令符、数据以及校验和。具体的数据格式如下。

  PM3003S 激光粉尘传感器模块有4中命令:读取粉尘仪测量结果,功能码0x0B;开启或关闭粉尘仪测量,功能码0x0C;读取或读取粉尘仪校准系数,功能码0x07;读取粉尘仪编码,功能码0x1F。具体如下表;

  PM3003S 激光粉尘传感器模块具有6个通道,可以输出PM10,PM2.5,PM1.0以及TSP等。

2、驱动设计与实现

  PM3003S 激光粉尘传感器模块驱动的设计我们依然采用基于对象的方式来实现。在实现之前,我们需要考虑一下PM3003S 激光粉尘传感器模块对象的具体内容。

2.1、对象定义

  首先我们需要考虑对象类型的定义。关于PM3003S 激光粉尘传感器模块对象我们从对象的属性及方法两个方面来考虑。
  对于PM3003S 激光粉尘传感器模块的属性,其6个通道的粉尘测量值,状态值、报警值、PM1.0、PM2.5、PM10以及TSP等表示了PM3003S 激光粉尘传感器模块的工作状态,多以我们将其设定为属性。同样的矫正系数表示PM3003S 激光粉尘传感器模块的配置状态、传感器编码标识了PM3003S 激光粉尘传感器模块的唯一性,我们也将其设计为属性。
  再来看PM3003S 激光粉尘传感器模块的方法。在这里我们并不实现PM3003S 激光粉尘传感器模块对象的全部方法,我们只考虑哪些对具体平台依赖性较大的方法。对于PM3003S 激光粉尘传感器模块只有读写操作是与平台相关的,所以我们将其作为对象的方法。于是我们可以设计PM3003S 激光粉尘传感器模块对象类型如下:

/*定义PM3003S对象类型*/
typedef struct PM3003S {uint8_t status;uint8_t alarm;uint16_t sensorCode[5];uint32_t pm1d0;uint32_t pm2d5;uint32_t pm10;uint32_t tsp;uint32_t up0d3um;uint32_t up0d5um;uint32_t up1d0um;uint32_t up2d5um;uint32_t up5d0um;uint32_t up10um;float dustFactor;void (*SendCommand)(uint8_t *cmd,uint16_t rSize);
}PM3003ObjectType;

  对于一个对象来说我们不能直接使用其对对象变量,二是需要先对其进行初始化配置才可以使用。所以我们还需要实现PM3003S 激光粉尘传感器模块对象的初始化函数。

/*对象初始化配置*/
PM3003SErrorType Pm3003sInitialization(PM3003ObjectType *pm,Pm3003sSendCommandType send)
{if((pm==NULL)||(send==NULL)){return PM3003S_PARAMETER_ERROR;}pm->SendCommand=send;pm->status=0;pm->alarm=0;for(int i=0;i<5;i++){pm->sensorCode[i]=0;}pm->pm1d0=0;pm->pm2d5=0;pm->pm10=0;pm->tsp=0;pm->up0d3um=0;pm->up0d5um=0;pm->up1d0um=0;pm->up2d5um=0;pm->up5d0um=0;pm->up10um=0;pm->dustFactor=0.0;return PM3003S_NO_ERROR;
}

2.2、对象操作

  我们已经设计了PM3003S激光粉尘传感器模块对象的类型,并且实现了对象变量的初始化函数。接下来我们将实现PM3003S激光粉尘传感器模块的各种操作。

2.2.1、获取测量结果

  我们使用PM3003S激光粉尘传感器模块的根本目的就是获取测量数据。根据前面的描述,获取测量数据的功能码为0x0B,所以根据协议格式可实现如下:

/*读取测量结果*/
void Pm3003sReadMeasureResult(PM3003ObjectType *pm)
{uint8_t cmd[]={0x11,0x02,0x0B,0x07,0xDB};pm->SendCommand(cmd,5);
}

2.2.2、启停粉尘仪

  我们也可以使用命令启动或停止PM3003S激光粉尘传感器模块,所需功能码为0x0C,根据命令格式我们可以实现停止或启动PM3003S 激光粉尘传感器模块的函数如下:

/*停止粉尘测量*/
void Pm3003sTurnoffDustMeasurement(PM3003ObjectType *pm)
{uint8_t cmd[]={0x11,0x03,0x0C,0x01,0x1E,0xC1};pm->SendCommand(cmd,6);
}/*开启粉尘测量*/
void Pm3003sTurnonDustMeasurement(PM3003ObjectType *pm)
{uint8_t cmd[]={0x11,0x03,0x0C,0x02,0x1E,0xC0};pm->SendCommand(cmd,6);
}

2.2.3、操作粉尘系数

  我们也可以使用命令读取或者设置PM3003S激光粉尘传感器模块的粉尘校准系数,所需功能码为0x0C,根据命令格式我们可以实现读取或者设置PM3003S 激光粉尘传感器模块粉尘校准系数的函数如下:

/*读取粉尘校准系数*/
void Pm3003sGetDustCalibrationFactor(PM3003ObjectType *pm)
{uint8_t cmd[]={0x11,0x01,0x07,0xE7};pm->SendCommand(cmd,4);
}/*设置粉尘校准系数*/
void Pm3003sSetDustCalibrationFactor(PM3003ObjectType *pm,uint8_t data)
{uint8_t cmd[]={0x11,0x02,0x07,0x00,0x00};cmd[3]=data;cmd[4]=CalculateChecksum(cmd,4);pm->SendCommand(cmd,5);
}

2.2.4、读取编码

  每一台PM3003S激光粉尘传感器模块都有一个唯一的编码,我们可以使用相应的功能吗读取。根据协议格式,我们可以编写相应的读取PM3003S激光粉尘传感器模块唯一编码的函数如下:

/*查询传感器编码*/
void Pm3003sQueryingSensorCode(PM3003ObjectType *pm)
{uint8_t cmd[]={0x11,0x01,0x1F,0xCF};pm->SendCommand(cmd,4);
}

3、驱动的使用

  我们基于对象设计了PM3003S激光粉尘传感器模块的驱动,接下来我们考虑如何使用这一驱动。

3.1、声明并初始化对象

  与以往一样,首先使用前门定义的PM3003S激光粉尘传感器模块对象类型生命一个对象变量,具体如下:

PM3003ObjectType pm3003s;

  对于声明的对象变量我们需要使用初始化函数先对其进行初始化才可使用。初始化函数有2个变量,第一个变量是我们需要初始化的对象变量,第二个变量则是发送函数的指针,其函数原型定义如下:

/*定义发送函数指针类型*/
typedef void (*Pm3003sSendCommandType)(uint8_t *cmd,uint16_t rSize);

  我们这个示例实在STM32平台实现的,使用的是STM32的HAL库,所以我们的实现如下:

/*发送数据*/
static void SendBytes(uint8_t *instruction,uint16_t length)
{/*关闭中断*/__HAL_UART_DISABLE_IT(&huart2,UART_IT_RXNE);pmiRxLength=0;HAL_UART_Transmit(&huart2,instruction,length,100);/*启用串口接收中端*/__HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE);
}

  有了上述准备我们就可以对对象变量进行初始化了。使用初始化函数,将对应的参数传给初始化函数即可,具体实现如下:

if(Pm3003sInitialization(&pm3003s,SendBytes)!=PM3003S_NO_ERROR){Error_Handler();}

3.2、基于对象进行操作

  对象初始化完成后,我们就可以基于对象对PM3003S激光粉尘传感器模块进行相应的操作了。在我们这个实例中,我们设计了一个60秒的周期获取测量数据的操作。每一个周期的前10秒以干净空气对通道进行清洁,接下来的50秒钟,我们每秒钟获取一侧数据。具体实现如下:

if(pmiRxLength>=5){if(Pm3003sParsingMessage(&pm3003s,pmiRxBuffer,pmiRxLength)!=PM3003S_INCOMPLETE_ERROR){pmiRxLength=0;}else{errorCount++;if(errorCount>150){pmiRxLength=0;errorCount=0;}}}if(pmiRxLength==0){/*操作过程判断*/Pm3003sOperation();}/*操作过程判断*/
static void Pm3003sOperation(void)
{if(aPara.phyPara.sSecond<10)          //清洗{if(pm3003s.status != 0x01)  //停止粉尘测量{Pm3003sTurnoffDustMeasurement(&pm3003s);}else if(((uint8_t)aPara.phyPara.dustFactor)!=pm3003s.dustFactor)//设置粉尘系数{Pm3003sSetDustCalibrationFactor(&pm3003s,(uint8_t)aPara.phyPara.dustFactor);readRequst=1;}else if(readRequst==1)//读取粉尘系数{Pm3003sGetDustCalibrationFactor(&pm3003s);readRequst=0;}else if(Pm3003sSelfCheck()){Pm3003sQueryingSensorCode(&pm3003s);}}else if(aPara.phyPara.sSecond>=10)    //调整{if(pm3003s.status != 0x02)     //启动粉尘测量{Pm3003sTurnonDustMeasurement(&pm3003s);}else{Pm3003sReadMeasureResult(&pm3003s);}}
}

4、应用总结

  在本篇中,我们设计并实现了PM3003S激光粉尘传感器模块的驱动程序,同样史记与对象的方式实现的。同时我们设计了一个测试用例,对驱动程序进行了测试,结果如预期。事实上,我们这个测试用例是从我们的一个实际项目中接选出来的,而在这个实际的产品项目中我们也是的这套驱动程序。

欢迎关注:


http://www.ppmy.cn/news/337538.html

相关文章

【嵌入式环境下linux内核及驱动学习笔记-(16)linux总线、设备、驱动模型之input框架】

目录 1、Linux内核输入子系统概念导入1.1 输入设备工作机制1.2 运行框架1.3 分层思想 2、驱动开发步骤2.1 在init()或probe()函数中2.2 在exit&#xff08;&#xff09;或remove&#xff08;&#xff09;函数中&#xff1a;2.3 上报事件2.4 input驱动要素导图2.5 input驱动的总…

基于GeoTools的GeoJson导入到PostGis实战

GeoJson是一种对各种地理数据结构进行编码的格式&#xff0c;基于json的地理空间信息数据交换格式。GeoJson对象可以用来表示几何&#xff0c;特征或者特征集合。支持地理点、线、面、多点、多线、多面及几何集合。GeoJson不是本文的重点&#xff0c;因此不再赘述。 PostGIS是在…

大疆 RoboMaster 3508/2006/GM6020 电机使用教程

19年开始使用大疆的电机&#xff0c;刚开始接触有很多东西不懂&#xff0c;网上除了RM官网提供的一些资料外没有很多其他的资料&#xff0c;现在使用大疆电机近一年了&#xff0c;想分享一下自己的经验。 1.硬件部分 1.C610电调只能连接M2006电机&#xff0c;C620电调连接M35…

【3d地图】vue中使用echarts geo3D

文章目录 前言一、echarts是什么&#xff1f;二、使用步骤1.引入echarts库&#xff0c;3d地图必须安装echarts-gl依赖2.制作地图JSON文件2.1 制作自己的json 3.引入到vue组件中4.创建一个有固定宽高大小的div元素5.配置echarts参数6.挂载到mounted钩子&#xff0c;并且组件销毁…

【超详细】基于大疆RoboMaster开发板C型的BMI088数据读取

【超详细】基于大疆RoboMaster开发板C型的BMI088数据读取 这里以博世传感器公司产出的BMI088型号的IMU为例&#xff0c;其里面有3轴高精度加速度计和3轴高精度陀螺仪&#xff0c;其他的特性不再介绍 同时这里的IMU是安装在大疆公司出产的RoboMaster开发板C型&#xff0c;单片机…

RK3588平台开发系列讲解(USB篇)USB Device端口组合配置过程

文章目录 一、configfs二、configfs 配置过程2.1、使能相关的宏2.2、挂载configfs2.3、创建名为g1的usb复合设备2.4、配置PID和VID2.5、创建并配置strings子目录2.6、创建configuration和字符串2.7、创建functions2.8、将functions和configuration关联起来2.9、绑定到UDC,使能…

Redis 缓存淘汰机制

Redis是一款高效的K-V数据库&#xff0c;本文主要是对redis中淘汰数据的机制进行一个简单的介绍。在redis中淘汰数据有俩种&#xff0c;一种是过期淘汰&#xff0c;另外一种是基于LRU淘汰算法的数据淘汰。 因为最近项目需要&#xff0c;打算实现一个简单的LRU算法缓存&#xf…

硬盘服务器哪个好用吗,服务器用固态硬盘好还是机械硬盘好

随着市面上的硬盘不断升级换代&#xff0c;高性价比的固态硬盘越来越受欢迎&#xff0c;原因是固态硬盘相比传统机械硬盘来说各方面性能更好。服务器固态硬盘跟机械硬盘的区别如下&#xff1a; 首先硬盘的基本参数包括容量&#xff0c;转速&#xff0c;平均访问时间&#xff0c…