首页 > 其他分享 >外设驱动库开发笔记52:PM3003S激光粉尘仪驱动

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

时间:2023-03-20 21:33:08浏览次数:48  
标签:粉尘 模块 PM3003S 激光 52 传感器 驱动 pm

  空气质量是现代日常生活中人们所关注的事情,也是生存环境好坏的一种体现。其中粉尘数量监测更是空气质量检测中最常见的对象,在我们的检测设备中也经常会有这种需求。检测手段也是多种多样,这一篇中,我们就来讨论使用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激光粉尘传感器模块的驱动程序,同样史记与对象的方式实现的。同时我们设计了一个测试用例,对驱动程序进行了测试,结果如预期。事实上,我们这个测试用例是从我们的一个实际项目中接选出来的,而在这个实际的产品项目中我们也是的这套驱动程序。

欢迎关注:

标签:粉尘,模块,PM3003S,激光,52,传感器,驱动,pm
From: https://www.cnblogs.com/foxclever/p/17237892.html

相关文章

  • Linux 网络设备驱动整理
      注意:拥有硬件探测机制的总线,例如USB,PCI总线上的设备不需要dts描述;没有探测机制的总线,如I2C设备应该用dts描述。PCIE网卡因为属于pci设备,不需要dts描述;但是PCIE控......
  • 04期:领域驱动设计与微服务
    这里记录的是学习分享内容,文章维护在Github:studeyang/leanrning-share。如何理解领域驱动设计?随着微服务的兴起,你一定听说过领域驱动设计DDD(domain-drivendesign),但是如......
  • Go语言:利用 TDD 测试驱动开发帮助理解数组与动态数组(切片)的区别
    ArrayVSSlice数组允许你以特定的顺序在变量中存储相同类型的多个元素。对于数组来说,最常见的就是迭代数组中的元素。我们创建一个Sum函数,它使......
  • macOS 13.3 Beta 4 (22E5246b)With OpenCore 0.9.1开发版 and winPE双引导分区原版镜像
    镜像特点完全由黑果魏叔官方制作,针对各种机型进行默认配置,让黑苹果安装不再困难。系统镜像设置为双引导分区,全面去除clover引导分区(如有需要,可以自行直接替换opencore分区文......
  • 四轮驱动,助力元服务澎湃动力
    黎明前的暗夜下,巍巍昆仑侧广袤草原上,一道激光无声闪过,一辆黑马披星戴月疾驰向北。天边泛起朦朦金光,远处黑马的合金轮毂激射出金色炫光。鸿蒙元服务(简称元服务)是华为提供的......
  • mysql-connector-python驱动和django-mysql-pool连接池
    ##################### 为了设计一个公用的、安全的连接池接口,可以考虑以下几个方面:封装连接池初始化和获取连接的逻辑,使得调用者不需要了解连接池的具体实现细节,只需要调......
  • 使用EB配置Icu驱动
    概述ICU 全称输入捕获单元,其驱动程序负责提供AUTOSAR指定的标准信号测量服务。ICU通道的底层捕获引擎可以是GTM单元的TIM通道、CC6比较器CCU6模块,或GPT12定时器的ERU......
  • LED车灯 手电筒外置MOS降压恒流驱动IC 12-36V 9V 1A驱动方案
    本品特点:宽输入电压范围:9V~100V ◆固定工作频率:140KHZ◆可设定电流范围:10mA~6000mA◆内置抖频电路,降低对其他设备的EMI干扰◆平均电流模式采样,恒流精度更高◆CS电......
  • 64位系统 asp 连接 access 没有找到驱动的解决方案
    之前asp连接acess一直没有问题: https://www.cnblogs.com/personnel/p/4583031.html今天,在一台64位的windows10上连接时,提示出错。查了一下,说是因为系统没有安装......
  • 6352.美丽子集的数目-337
    美丽子集的数目给你一个由正整数组成的数组nums和一个正整数k。如果nums的子集中,任意两个整数的绝对差均不等于k,则认为该子数组是一个美丽子集。返回数组n......