单片机类库封装

轻语言单片机的类库与 Arduino Library 结构基本一致,封装前需要您掌握基础的 C/C++ 编程知识。

内置类库参考

安装包里面已经内置了常用传感器的扩展库,路径位于:

VcnStudio安装目录/sdk/mcu/components/esp32

上方路径指向的文件夹中,每个子文件夹表示一个独立类库。

每个类库的文件夹结构都是相同的,具体含义请参考下方结构说明。

类库结构

轻语言单片机类库采用 文件夹/文件 结构,非独立类库文件,因为方便修改类库源代码、测试,轻语言类库文件结构为:

类库名称文件夹/
├── static/
│   ├── libs/
│   └── └── C|C++|Arduino类库
└── libtree.xml
  • static

    • 静态资源文件夹、在该文件夹中含有一个 libs 文件夹, libs 文件夹中存放封装好的 C 或 Arduino 标准库。

    • 该文件夹中目前不能储存其它数据,只能在libs中存放原始C/C++库。

  • libtree.xml

    • 类库配置文件,该文件用于配置类库的名称、描述、以及类库组件的函数。

配置文件 libtree.xml 详解

轻语言单片机类库封装的本质是将原生 Arduino 库或 C++ 写的库翻译成中文。

因此如果您已经有了一个 Arduino 的库,那么只需要在配置文件中添加其中文函数即可,如果没有 Arduino 库需要先将需要的功能或者传感器代码封装成 Arduino 库。

以安装包内置的 DHT22 温湿度传感器库为例,该库中的配置文档内容为:

<?xml version="1.0" encoding="utf-8"?>
<package>
  <library 
    name="DHT22" 
    author="官方" 
    package="" 
    description="‌DHT22温度传感器是一种结合了温度和湿度测量功能的数字传感器,广泛用于各种环境监测和控制系统中。‌ 它通过数字信号输出测量结果,具有高精度、快速响应和稳定性,适用于物联网应用‌。" 
    type="component">
    <component 
        name="DHT22" 
        en="DHT22"
        include="DHT22.h" 
        comment="本库封装自开源库 https://github.com/dvarrel/DHT22 可用于在单片机中读取基于DHT22系列的温湿度传感器相关数据。">
            <construct name="DHT22" args="(数据引脚 为 整数型)" comment="使用指定的接收数据的引脚构造一个DHT22对象。" />
            <method name="取原始数据值" en="getRawData" args="()" return="整数型" comment="获取传感器原始数据(40位)。返回类型:uint64_t 类型的变量,包含40位的原始数据。" />
            <method name="取原始文本数据值" en="getRawStrData" args="()" return="文本型" comment="获取传感器原始数据(40位)并转换为字符串;包含40位的原始数据,并在左侧补零。" />
            <method name="取湿度百分比" en="getHumidity" args="()" return="单精度小数" comment="获取湿度百分比(%rH)、单位为百分比(%rH)。" />
            <method name="取温度" en="getTemperature" args="()" return="单精度小数" comment="获取温度值、单位为摄氏度(°C)。" />
            <method name="取错误代码" en="getLastError" args="()" return="整数型" comment="获取上次读取传感器时的错误代码。" />
            <method name="取调试信息" en="debug" args="()" return="文本型" comment="获取调试信息,包括定时信息、40位数据和计算值。" />
    </component>
  </library>
</package>

上方文档中,library 节点中的属性含义分别为:

  • name 表示类库名称

  • author 表示类库作者

  • package 单片机暂时不需要设置包名,但需要保留设置为空

  • description 描述类库的功能

  • type 类库类型,默认为:component 不可视组件、后期可能会支持可视组件。

library 节点中存放当前类库中的组件,可以含有多个组件:

组件节点(不可视)必须使用 component 标签名,component 节点中的属性含义为:

  • name 组件名称

  • en 组件对应的原生英文名称

  • include 使用这个组件时需要导入的头文件

  • comment 组件注释、描述

component 节点即表示一个组件,其子节点表示组件的方法和构造函数,componen 节点中支持的标签有:

  • construct 表示构造函数

    • name 构造函数名称,必须为原生类构造函数

    • args 表示构造函数参数

    • comment 构造函数注释

  • method 表示函数方法

    • name 函数名称

    • en 函数对应英文名称

    • args 函数参数

    • return 函数返回值

    • comment 函数注释说明

核心封装逻辑

将英文版本的库翻译成中文,核心逻辑是通过在配置文件中配置 component、 method 等节点实现将原库中使用 public 修饰的英文函数翻译成中文。

#ifndef _DHT22_H
#define _DHT22_H
#include "Arduino.h"

class DHT22{
  public:
    enum error{
            OK,
            ERR_TIMING_80,
            ERR_TIMING_50,
            ERR_TIMING_BITS,
            ERR_CRC
          };
  private:
    uint8_t _pinData;
    uint32_t _timer;
    uint64_t _rawData;
    uint16_t _h16bits;
    uint16_t _t16bits;
    uint8_t _crc8bits;
    uint8_t _timing80L = 80;
    uint8_t _timing80H = 80;
    uint8_t _timing50 = 50;
    uint8_t _timingBit0 = 27; //specs for AM2303
    uint8_t _timingBit1 = 70; //specs for AM2303
    bool _firstStart=true;
    error _lastError;

    const uint8_t T = 30;
    const uint16_t cSamplingTime = 2100; // ms : dht22 sampling rate ~0.5Hz

  public:
    DHT22(uint8_t pinData){
      _pinData = pinData;
    };

    /** @return 40bits of data sensor : h16 + t16 + crc8**/
    uint64_t getRawData();

    /** @return 40bits in a String ("0" left include)**/
    String getRawStrData();

    /** @return humidity %rH **/
    float getHumidity();

    /** @return temperature in °C **/
    float getTemperature();

    /** @return code from last readSensor() request **/
      uint8_t getLastError();

    /** @return String with timings, 40bits, and calculate values**/
    String debug();

  private:
    /** @brief measure timings of sensor*/
    void measureTimings();

    /**
    *@brief read the 40bits sensor data
    *@return 0 if no error, num of error instead
    */
    uint8_t readSensor();

    /** @brief compute checksum of h & t data
     * @return true if checksum==crc**/
    bool computeCRC();
};
#endif

上方代码中 public 修饰的函数即为我们要封装翻译成中文的函数。

例如构造函数:

DHT22(uint8_t pinData){
  _pinData = pinData;
};

对应的配置节点为:

<construct name="DHT22" args="(数据引脚 为 整数型)" comment="使用指定的接收数据的引脚构造一个DHT22对象。" />

其它函数:

 /** @return 40bits of data sensor : h16 + t16 + crc8**/
 uint64_t getRawData();

对应配置节点为:

<method name="取原始数据值" en="getRawData" args="()" return="整数型" comment="获取传感器原始数据(40位)。返回类型:uint64_t 类型的变量,包含40位的原始数据。" />

构造函数节点中,name 属性值为 英文类名。

函数节点中,name 属性值为中文函数名,en 为对应的英文函数名称。

注意事项

大多数情况下,文件名与库中的类名应该是一致的。

如果类名与文件名称不一致,那么 component 节点中的 en 属性的值应该设置为类名。

同时 component 中的 construct 节点的构造函数 name 属性也必须设置为类名。