zoukankan      html  css  js  c++  java
  • 外设驱动库开发笔记31:S-Modlue远红外气体传感器驱动

      在气体分析类产品中,我们经常会用到远红外气体传感器。我们就在碳氢类气体成分分析中使用了S-Modlue远红外气体传感器。接下来,我们将讨论S-Modlue远红外气体传感器驱动的设计与实现。

    1、功能概述

      S-MODULE EVO 使用非分散红外检测技术NDIR,集成稳定红外光源,配置可靠性能的光电探测器,确保了传感器检测的稳定性能。

      S-MODULE采用的是RS232串行通讯接口,但其通讯接口对外只有一个通讯引脚,所以实现的是半双工模式。串口参数为:2400波特率,7位数据位,1位停止位,偶校验。

      在应用层采用的则是Modbus ASCII协议。S-MODULE非分光红外气体模块支持03和06功能码。S-MODULE非分光红外气体模块支持的Modbus参数如下:

    2、驱动设计与实现

      我们知道S-Module远红外气体传感器采用基于半双工RS232接口的Modbus ASCII通讯协议。接下来我们将基于它的协议规则设计并实现驱动程序。

    2.1、对象定义

      在使用一个对象之前我们需要获得一个对象。同样的我们想要S-Modlue远红外气体传感器就需要先定义S-Modlue远红外气体传感器的对象。

    2.1.1、对象的抽象

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

      先来考虑属性,作为属性肯定是用于标识或记录对象特征的东西。我们来考虑S-Modlue远红外气体传感器对象的属性。首先Modbus协议对象都有站地址用以标识不同的设备,所以我们将设备地址作为对象的一个属性。此外,状态信息、温度、浓度等实时信息表示了对象当前的工作状态,所以我们将这些参数也作为对象的属性。

      接着我们还需要考虑S-Modlue远红外气体传感器对象的操作问题。我们需要从S-Modlue远红外气体传感器获取数据和下发命令,就需要通过串口发送消息,但串口的处理与具体的平台相关,所以我们将其作为对象的操作。此外,在操作对象的过程中需要控制时序,所以延时操作函数必不可少,而延时操作函数往往依赖于具体的软硬件平台,所以将延时函数作为对象的操作。

      根据上述我们对S-Modlue远红外气体传感器的分析,我们可以定义S-Modlue远红外气体传感器的对象类型如下:

    /*定义NDIR对象类型*/
    typedef struct NdirObject {
     uint8_t moduleAddress;
     uint16_t status;
     uint32_t softVersion;
     float concentration;
     float temperature;
     void (*SendByte)(uint8_t data);
     void (*Delayms)(volatile uint32_t nTime);
    }NdirObjectType;
    

    2.1.2、对象初始化

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

    /*NDIR初始化配置函数*/
    void NdirInitialization(NdirObjectType *ndir,  //NDIR对象
                            uint8_t moduleAddress, //模块地址
                            NdirSendByteType send, //发送数据操作函数
                            NdirDelaymsType delayms //毫秒延时操作函数
                           )
    {
     if((ndir==NULL)||(send==NULL)||(delayms==NULL))
     {
      return;
     }
     ndir->SendByte=send;
     ndir->Delayms=delayms;
     
     ndir->moduleAddress=moduleAddress;
     
     ndir->concentration=0.0;
     ndir->temperature=0.0;
     
     ndir->status=0;
     ndir->softVersion=0;
    }
    

    2.2、对象操作

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

      对于S-Modlue远红外气体传感器对象来说,最基本的操作就是向其发送操作命令或数据消息。这是基于串口的Modbus ASCII协议的数据通讯,基于此我们可编写响应的数据发送操作函数如下:

    /*发送数据给舒茨非分光红外气体检测模块(读写数据)*/
    static void NDIRSendData(NdirObjectType *ndir,uint8_t *txData,uint16_t length)
    {
     uint16_t sendDataAmount=0;
     uint8_t sendDataArray[17]; //不小于(length+1)*2+3
     uint8_t rawData[7];//含校验码
     for(int i=0;i<length;i++)
     {
      rawData[i]=txData[i];
     }
     rawData[6]=CheckSumCalc(txData,length);
     uint8_t objData[14];
     uint16_t cLength=ConvertHexArrayToASCIICharArray(rawData,length+1,objData);
     
     sendDataArray[sendDataAmount++]=':';
     for(int i=0;i<cLength;i++)
     {
      sendDataArray[sendDataAmount++]=objData[i];
     }
     sendDataArray[sendDataAmount++]=0x0D;
     sendDataArray[sendDataAmount++]=0x0A;
     
     for(uint16_t sendDataIndex=0;sendDataIndex<sendDataAmount;sendDataIndex++)
     {
      /*发送一个字节*/
      ndir->SendByte(sendDataArray[sendDataIndex]);
     }
    }
    

    3、驱动的使用

      我们已经实现了S-Module远红外气体传感器的驱动程序,但我们还需要验证一下它的正确性,所以在本节中我们就来设计一个简单的验证应用。

    3.1、声明并初始化对象

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

      NdirObjectType ndir;

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

    NdirObjectType *ndir,  //NDIR对象
    uint8_t moduleAddress, //模块地址
    NdirSendByteType send, //发送数据操作函数
    NdirDelaymsType delayms //毫秒延时操作函数
    

      对于这些参数,对象变量我们已经定义了。模块地址根据我们实际的使用情况输入就好了。主要的是我们需要定义几个函数,并将函数指针作为参数。这几个函数的类型如下:

    /*发送一个字节操作函数指针类型*/
    typedef void (*NdirSendByteType)(uint8_t data);
    /*毫秒延时函数指针类型*/
    typedef void (*NdirDelaymsType)(volatile uint32_t nTime);
    

      对于这几个函数我们根据样式定义就可以了,具体的操作可能与使用的硬件平台有关系。具体函数定义如下:

    static void SendByteForNdir(uint8_t data)
    {
     HAL_UART_Transmit(&ndirhuart,&data,1,1000);
    }
    

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

    /*上位通讯设备端口初始化配置*/
    void Ndir_Init_Configuration(void)
    {
     NDIR_USART_Init_Configuration();  //配置串口中断
     
     /*NDIR初始化配置函数*/
     NdirInitialization(&ndir,  //NDIR对象
                        0x02, //模块地址
                        SendByteForNdir, //发送数据操作函数
                        HAL_Delay //毫秒延时操作函数
                        );
     
     /*读软件版本*/
     ReadNDIRSoftVersion(&ndir,rxBuffer);
    }
    

    3.2、基于对象进行操作

      我们定义了对象变量并使用初始化函数给其作了初始化。接着我们就来考虑操作这一对象获取我们想要的数据。我们在驱动中已经封装了温度、浓度以及状态信息的操作函数,接下来我们使用这一驱动开发我们的应用实例。

    /*NDIR数据操作*/
    void Ndir_Comm_Process(void)
    {
     /*从舒茨非分光红外气体检测模块读取浓度值*/
     ReadConcentrationData(&ndir,rxBuffer);
     
     /*从舒茨非分光红外气体检测模块读取内部温度值*/
     ReadTemperatureData(&ndir,rxBuffer);
     
     /*从舒茨非分光红外气体检测模块读取状态标志*/
     ReadNDIRStatusflags(&ndir,rxBuffer);
    }
    

    4、应用总结

      在我们的气体分析仪产品上,我们就是用来S-Module远红外气体传感器,也是基于我们的这一驱动实现的,通讯稳定,效果良好。

      在使用驱动程序时需要注意,驱动程序将解析程序封装到了数据发送函数中,可以直接调用数据读取函数就可以了,也可以单独调用解析函数来实现,具体工作方式可应需求实现。

    欢迎关注:

    如果阅读这篇文章让您略有所得,还请点击下方的【好文要顶】按钮。

    当然,如果您想及时了解我的博客更新,不妨点击下方的【关注我】按钮。

    如果您希望更方便且及时的阅读相关文章,也可以扫描上方二维码关注我的微信公众号【木南创智

  • 相关阅读:
    【YBTOJ】守卫挑战
    【YBTOJ】【Luogu P6089】[JSOI2015]非诚勿扰
    【Luogu P4092】[HEOI2016/TJOI2016]树
    【YBTOJ】【Luogu P3232】[HNOI2013]游走
    【CodeForces 396B】On Sum of Fractions
    【P2579】【ZJTSC05】沼泽鳄鱼
    【YBTOJ】【USACO03MAR】最大均值
    【YBTOJ】防具布置
    VC 静态库与动态库(二)静态库创建与使用
    VC 静态库与动态库(一)介绍
  • 原文地址:https://www.cnblogs.com/foxclever/p/15256907.html
Copyright © 2011-2022 走看看