手搓一个分布式大气监测系统(四)基于TencentOS Tiny RISC-V开发板打造PM2.5监测终端

2020-05-13 12:03:03 浏览数 (1)

背景

鹅民大气监测项目是一个以腾讯云物联网开发平台为基础起点,并叠加多款云产品后,实现的一个验证型项目。

我们的目标是基于腾讯完善的产品与技术能力,与志愿者们共同建设一套用于监测生活环境大气的系统,监测终端就分布在志愿者的身边,所以这个系统的数据,更贴近每个人的生活空间,以及提供更细粒度的数据监测能力。

鹅民大气监测项目前期已搭建了25个种子监测点,接下去将吸引更多的志愿者来搭建终端,接入系统,一起搭建监测网络。从二期开始,大气监测项目组优选了几款开发套件完成了验证测试,志愿者可根据挑选的开发套件来完成相应的监测终端。

pm25-01.pngpm25-01.png
pm25-02.pngpm25-02.png

这篇文章分享下如何使用 TencentOS Tiny RISC-V定制开发套件打造 PM2.5 监测终端。

总体方案

整个系统计划由如下几个模块组成:

数据采集模块:在终端侧采集传感器的监测数据。(大气监测终端)

无线接入模块:提供多种无线协议,支持终端接入网络。(LoRaWAN网关)

设备接入模块:在云平台侧处理各种无线接入协议及设备数据规整。(IoT Explorer平台)

业务处理模块:管理终端设备,分析传感器数据及可视化。(Web界面或者APP应用)

arch.pngarch.png

1 硬件准备

成品实物

hardware01.jpghardware01.jpg

1.1 开发板简介

EVB_LX 是腾讯物联网操作系统TencentOS tiny 团队联合兆易创新(GD32)、南京厚德物联网有限公司三方合作设计的一款物联网评估板,用于TencentOS tiny 基础内核、RISC-V新IP核架构和IoT组件功能体验和评估。

开发板功能图如下所示:

EVB_LX.pngEVB_LX.png

1.2 开发板特性

CPU :GD32VF103RBT6, 108MHz,128K Flash,32KB SRAM

显示屏 :OLED,64*32分辨率

电源特性 :Micro USB接口,5V供电,内部有5V转3.3V的DCDC,MCU供电电压为3.3V,系统IO电压也为3.3V

按键 :一个复位按键,一个功能按键

外部扩展存储 :SPI FLASH

LED指示灯 :上电指示 LED,红色;一个用户定义LED,蓝色

调试接口 :板载GD-Link下载调试器,UART2串口连接PC

XTAL :8MHz,32.768KHz

传感器扩展接口E53 Interface :支持E53传感器案例扩展板(支持UART、SPI、IIC、GPIO、ADC、DAC等)

网络模块扩展接口WAN Interface :支持多种无线通信模组扩展(UART&SPI&GPIO)

操作系统支持 :TencentOS tiny

1.3 开发板硬件详解

1.3.1 电源电路
  • 电源稳压电路 外部USB输入电压一般为5V,但这并不能直接作为电源给EVB_LX供电,EVB_LX上的元器件供电电压范围普遍在1.8V-3.6V,推荐电压均为3.3V,(BC35供电范围是:3.1V-4.2V,推荐电压3.8V,使用3.3V也可以正常工作),因此需要将5V的电平转换成3.3V供给EVB_LX开发板使用,这里使用RT8059作为3.3V稳压器芯片。 RT8059是一款高效率脉冲宽度降压型DC/DC转换器。输入电压2.8V-5.5V,输出电压可调范围为:0.6V-Vin,输出电流可以达到1A。在我们提供的电路中将输出调节至3.3V,让开发板正常工作。
sch_power.pngsch_power.png
1.3.2 GD32V最小系统电路

单片机最小系统或者叫最小硬件单元电路,指用最少元器件组成的单片机可以正常工作的系统。最小系统基本由电源、单片机、晶振、复位电路、程序烧录接口组成,电源使用3.3V直接供电,其他部分原理图如下:

sch_mcu.pngsch_mcu.png
1.3.3 USB电平转换电路

USB电平转换电路是用于MCU和PC通信的场景中。PC机上的通信接口使用USB接口,相应的电平逻辑需要遵照USB电平规则,而MCU的串行通信接口是串口,相应电平需要遵循TTL原则。为了使两者可以互相通信,就需要一个电平转换器,EVB_LX上使用了CH340芯片作为转换器,CH340外围只需要接很少的元器件即可以实现USB总线转接,使用非常方便也广泛运用在USB转TTL工具上,电路如下:

sch_ch340.pngsch_ch340.png
1.3.4 OLED显示电路

OLED液晶显示模块用来向用户显示系统状态、参数或者要输入系统的功能。为了展示良好的视觉效果,模块使用SSD1306驱动的OLED显示屏,分辨率为64*32。SSD1306芯片专为共阴极OLED面板设计,嵌入了对比控制器、显示RAM和晶振,并减少了外部器件和功耗,有256级亮度控制。

该款OLED使用IIC接口,由于IIC接口空闲时引脚要上拉,因此下面的原理图中接了10k电阻上拉,然后才接入MCU引脚。

sch_oled.pngsch_oled.png
1.3.5 用户按键

开发板带有一个系统Reset按键,和一个功能按键。复位按键是直接接入GD32V MCU的硬件复位Pin,按下复位按键,系统自动重启复位。功能按键可以提供给开发者做功能定义开发,都是使用GPIO口,方向为输入,低电平有效。其原理图如下图所示。

sch_key.pngsch_key.png
1.3.6 LED程序指示灯

为了方便项目开发调试,EVB_LX开发板接出来一个LED灯,供用户自己设置状态使用,该LED灯接MCU的PB2引脚,当PB2引脚输出高电平时,会点亮LED灯。

sch_led.pngsch_led.png
1.3.7 Flash存储电路扩展

开发板带有一个SPI Nor Flash芯片扩展,用户存储一部分用户数据和存储空间扩展,电路图如下:

sch_spi_flash.pngsch_spi_flash.png
1.3.8 多串口切换电路

开发板带有多串口切换功能,通过拨S2 开关可以切换串口映射关系,开关切换到PC AT,可以使用PC机上的串口助手发送AT命令来调试WAN口的通信模组;当开关切换到MCU AT,是通过GD32V MCU的串口直接来发送AT指令控制通信模组,同时CH340串口连接PC可以做日志输出。串口切换电路图如下:

sch_uart_switch.pngsch_uart_switch.png
1.3.9 E53 传感器扩展接口

开发板设计有E53接口的传感器扩展板接口,该接口可兼容所有E53接口的传感器扩展板,实现不同物联网案例场景的快速搭建。该接口可接入UART、SPI、I2C、ADC等通信协议的传感器,其原理图如下图所示。

sch_e53_interface.pngsch_e53_interface.png
1.3.10 WAN通信模块扩展接口

开发板设计有通信扩展板的扩展接口,该接口可接入WIFI、NB-IoT、2G、腾讯定制IoT模组、LoRaWAN等不同通信方式的通信扩展板,以满足不同场景上云的需求,其原理图如下图所示。

sch_wan_interface.pngsch_wan_interface.png
1.3.11开发板部分引脚和模块映射关系
sch_pinmap.pngsch_pinmap.png

1.4 开发板套件安装指南

1.4.1 检查配套设备
  • 开发板底板
hardware02.jpghardware02.jpg
  • LoRaWAN模组

瑞兴恒方研发的LoRaWAN通信模组,使用串口AT进行交互,简单方便

hardware03.jpghardware03.jpg
  • PM2.5空气传感器扩展板

主要用于转接PM2.5 传感器到开发板的E53接口上

hardware04.jpghardware04.jpg
  • PM2.5空气传感器PMSA003

我们选用的是攀藤粉尘传感器PMSA003,检测精度高,可测试PM2.5等多种空气质量参数。

hardware05.jpghardware05.jpg
1.4.2 安装WAN口LoRa模块
lora_install.jpglora_install.jpg
1.4.3 安装传感器扩展板
sensor_install.jpgsensor_install.jpg

根据您开发套件配套的传感扩展板安装其中一个即可。

1.4.4 连接Micor USB线

Micro USB线的功能是供电及调试,将线一头与开发板的Micro接口(GD-Link)连接,另一头接到电脑的USB口上。(程序下载完了,也可以把usb线接到pc uart的端口,用于打印日志)

usb_install.pngusb_install.png

2. 定制开发板EVB_LX软件开发环境准备

2.1 Nuclei Studio IDE下载

目前GD32V成熟的集成开发环境是由芯来科技提供的Nuclei Studio IDE,TencentOS tiny中的RISC-V项目也是基于Nuclei Studio IDE。首先我们下载Nuclei Studio IDE软件开发包,下载链接为https://www.nucleisys.com/download.php 如下图所示。

nuclei_studio_ide.pngnuclei_studio_ide.png

单击“Nuclei Studio:芯来集成开发环境(Nuclei Studio IDE)”即可进入下载页面。

2.2 Nuclei Studio IDE安装

下载下来的芯来集成开发环境(IDE)Nuclei Studio压缩包解压后包含若干个文件。

Nuclei Studio软件包:该软件包中包含了Nuclei Studio IDE的软件。注意:具体版本以及文件名可能会不断更新;

HBird_Driver.exe:此文件为芯来蜂鸟调试器的USB驱动安装文件,调试时需要安装此驱动使得其USB能够被识别;

JDK安装文件:jdk-8u512-windows-x64.exe;

  • 1.Nuclei Studio IDE是基于eclipse的,eclipse需要jdk环境支持,你的电脑如果没有安装jdk环境需要先安装jdk-8u512-windows-x64.exe,直接双击安装即可,如果已经安装可以跳过;
  • 2.安装HBird_Driver.exe
  • 3.Nuclei Studio软件本身为绿色软件无需安装,安装好JDK运行环境后,直接单击Nuclei Studio文件夹中eclipsec.exe即可启动Nuclei Studio。
nuclei_studio_file.pngnuclei_studio_file.png

直接单击NucleiStudio_IDE文件包中NucleiStudio文件夹下面的eclipse.exe可执行文件,即可启动Nuclei Studio;

第一次启动Nuclei Studio后,将会弹出对话框要求设置Workspace目录,该目录将用于放置后续创建项目的文件夹,如图所示;

nuclei_studio_workspace.pngnuclei_studio_workspace.png

设置好Workspace目录之后,确保Workspace的路径中没有中文,单击“Launch”按钮,将会启动Nuclei Studio。第一次启动后的Nuclei Studio界面如图所示。

nuclei_studio_welcome.pngnuclei_studio_welcome.png

2.3 导入基于TencentOS tiny的RISC-V工程

先下载TencentOS tiny项目,下载地址为:

https://github.com/Tencent/TencentOS-tiny

官方地址直接下载zip包或者直接使用下面的命令clone下来:

git clone https://github.com/Tencent/TencentOS-tiny.git

在菜单栏选择”File->Import“,出现如图对话框,选择”General“菜单下”Exit Project into Workspace“,设置导入方式,然后点击按钮”Next“。

project_import.pngproject_import.png

选择导入的方式后,点击” Browse“按钮选择TencentOS tiny项目中GD32V工程路径。注意:进入到” TencentOS-tinyboardTencentOS_tiny_EVB_LXeclipselorawan"这一级目录即可,如图所示。

project_import01.pngproject_import01.png

2.4 编译下载调试基于TencentOS tiny的RISC-V工程

导入之后,就可看到TencentOS tiny的hello_world工程了,如图所示:

project_lorawan.pngproject_lorawan.png

lorawan工程文件夹上右键 Debug As,选择Debug Configuration,配置调试参数,如下图所示:

project_debug_set.pngproject_debug_set.png
project_debug_set01.pngproject_debug_set01.png
project_debug_set02.pngproject_debug_set02.png

在Debugger选项中修改调试参数:

-f "${workspace_loc:/${ProjName}/openocd_gdlink.cfg}"

set mem inaccessible-by-default off

set arch riscv:rv32

set remotetimeout 250

然后点击Debug即可进入调试窗口,如下图所示,可以进行单步、跳步执行,设置断点等

project_run.pngproject_run.png

3. 终端LoRaWAN程序开发简介

程序基于TencentOS Tiny 操作系统完成,主要处理pm2.5传感器数据接收,lorawan模组驱动,串口收发等,主要功能就是通过RISC-V芯片的串口3采集PMSA003传感器数据,然后解析出来,再通过串口驱动和TencentOS Tiny的AT框架驱动LoRaWAN模组将结构化的空气质量数据发送到LoRa服务器,进而转发到腾讯云和应用端。

pmsa003传感器的串口协议如下:

pms003.pngpms003.png

协议数据示例:

`

17:10:48.321收←◆42 4D 00 1C 00 3F 00 42 00 58 00 32 00 32 00 32 05 8C 00 E0 00 18 00 14 00 10 00 0E 00 00 03 D5 `

`

17:10:49.324收←◆42 4D 00 1C 00 3E 00 42 00 58 00 31 00 32 00 32 05 64 00 E0 00 18 00 14 00 10 00 0E 00 00 03 AB `

`

17:10:50.328收←◆42 4D 00 1C 00 3A 00 42 00 58 00 30 00 32 00 32 05 14 00 E0 00 1C 00 14 00 10 00 0E 00 00 03 5A `

`

17:10:51.329收←◆42 4D 00 1C 00 39 00 42 00 56 00 30 00 32 00 32 05 14 00 D0 00 18 00 10 00 0B 00 0A 00 00 03 36

`

具体处理逻辑是这样:

串口接收 --> 数据缓存解析校验 --> 取出其中26字节载荷发到邮箱 --> 邮箱接收并通过LoRa模组发送

硬件这边尽量对传感器数据简化处理,云平台有设备解析引擎,只需将传感器的原始数据取出上报,云端再将其转成JSON。

主要代码介绍如下图:

code.pngcode.png

代码流程如下:

workflow.pngworkflow.png

如果上面的源码分析没完全搞懂也没关系,这不影响我们的接入操作。只需要记得处理一行设备参数相关的代码即可。

1.进入<TencentOS-tinyboardTencentOS_tiny_EVB_LXeclipselorawan>目录,导入lorawan工程。

2.修改ApplicationLoRaWANlora_demo.c.。

tos_lora_module_join_otaa("your devui", "your appkey");

填入节点相应的 DevEUI 和 AppKEY。鹅民大气监测项目目前将会为参与活动的同事分配专用的密钥 DevEUI 和 AppKey。

3.修改完毕后,重新编译并下载程序。复位我们做好的 PM2.5 监测终端,确保有470M 的LoRa网关信号覆盖,即可在云端看到监测终端的上报。

4. 腾讯物联网平台创建大气监测设备

创建项目和产品
  1. 登录 物联网开发平台控制台,选择【新建项目】。
  2. 在新建项目页面,填写项目基本信息后,单击【保存】
    • 项目名称:输入“LoRa 大气监测演示”或其他名称。
    • 项目描述:按照实际需求填写项目描述。
  3. 项目新建成功后,即可新建产品。
新建产品
  1. 进入该项目的产品列表页面,单击【新建产品】。
  2. 在新建产品页面,填写产品基本信息。
    • 产品名称:输入“LoRa大气监测”或其他产品名称。
    • 产品类型:选择“用户自定义”。
    • 认证方式:选择“密钥认证”。
    • 通信方式:选择“LoRaWAN”。
product_create.pngproduct_create.png
  1. 产品新建成功后,您可在产品列表页查看“LoRa大气监测”。
创建数据模板

单击产品名称,进入产品配置页,在【自定义功能】配置项下,单击【新建功能】,自定义产品功能。

这里我们就不一一定义数据模板了,直接导入下面的json代码:

代码语言:txt复制
{
  "version": "1.0",
  "profile": {
    "ProductId": "4KQMKIIH5U",
    "CategoryId": "22"
  },
  "properties": [
    {
      "id": "PM1_CF1",
      "name": "PM1浓度_CF1",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "μ g/m3"
      },
      "required": false
    },
    {
      "id": "PM2d5_CF1",
      "name": "PM2d5浓度_CF1",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "μ g/m3"
      },
      "required": false
    },
    {
      "id": "PM10_CF1",
      "name": "PM10浓度_CF1",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "μ g/m3"
      },
      "required": false
    },
    {
      "id": "PM1",
      "name": "PM1浓度",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "μ g/m3"
      },
      "required": false
    },
    {
      "id": "PM2d5",
      "name": "PM2d5浓度",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "μ g/m3"
      },
      "required": false
    },
    {
      "id": "PM10",
      "name": "PM10浓度",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "μ g/m3"
      },
      "required": false
    },
    {
      "id": "particles_0d3",
      "name": "颗粒物个数_0d3",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "个"
      },
      "required": false
    },
    {
      "id": "particles_0d5",
      "name": "颗粒物个数_0d5",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "个"
      },
      "required": false
    },
    {
      "id": "particles_1",
      "name": "颗粒物个数_1",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "个"
      },
      "required": false
    },
    {
      "id": "particles_2d5",
      "name": "颗粒物个数_2d5",
      "desc": "",
      "mode": "rw",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "个"
      },
      "required": false
    },
    {
      "id": "particles_5",
      "name": "颗粒物个数_5",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "个"
      },
      "required": false
    },
    {
      "id": "particles_10",
      "name": "颗粒物个数_10",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "65535",
        "start": "0",
        "step": "1",
        "unit": "个"
      },
      "required": false
    },
    {
      "id": "version",
      "name": "版本号",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "255",
        "start": "0",
        "step": "1",
        "unit": ""
      },
      "required": false
    },
    {
      "id": "Error",
      "name": "错误代码",
      "desc": "",
      "mode": "r",
      "define": {
        "type": "int",
        "min": "0",
        "max": "255",
        "start": "0",
        "step": "1",
        "unit": ""
      },
      "required": false
    }
  ],
  "events": [],
  "actions": []
}
product_create_data.pngproduct_create_data.png
配置 LoRaWAN 参数

在设备开发页面中,按需调整 LoRaWAN 参数配置。本示例中使用默认的 OTAA 配置。

explorer_guide_1_3_lorawan_profile.pngexplorer_guide_1_3_lorawan_profile.png
设备数据解析

在设备开发页面中,按需调整设备数据解析。由于 LoRa 类资源有限设备不适合直接传输 JSON 格式数据,使用“设备数据解析”可以将设备原始数据转化为产品 JSON 数据。

设备数据协议

在本示例中,设备上行数据共有14个,包括PM2.5 PM10等数据

数据解析脚本

上行数据解析的脚本主函数为 RawToProtocol,其带有 fPort、bytes 两个入参:

  • fPort:设备上报的 LoRaWAN 协议数据的 FPort 字段。
  • bytes:设备上报的 LoRaWAN 协议数据的 FRMPayload 字段。

脚本主函数的出参为产品数据模版协议格式的对象。

在上行数据解析部分,javascript 示例代码如下:

代码语言:txt复制
function RawToProtocol(fPort, bytes) {
    var data = {
        "method": "report",
        "clientToken" : new Date(),
        "params" : {}
    };
    var i = 0;
    
    data.params.PM1_CF1 = (bytes[i  ] << 8) | bytes[i  ];
    data.params.PM2d5_CF1 = (bytes[i  ] << 8) | bytes[i  ];
    data.params.PM10_CF1 = (bytes[i  ] << 8) | bytes[i  ];
    
    data.params.PM1 = (bytes[i  ] << 8) | bytes[i  ];
    data.params.PM2d5 = (bytes[i  ] << 8) | bytes[i  ];
    data.params.PM10 = (bytes[i  ] << 8) | bytes[i  ];
    
    data.params.particles_0d3 = (bytes[i  ] << 8) | bytes[i  ];
    data.params.particles_0d5 = (bytes[i  ] << 8) | bytes[i  ];
    data.params.particles_1 = (bytes[i  ] << 8) | bytes[i  ];
    data.params.particles_2d5 = (bytes[i  ] << 8) | bytes[i  ];
    data.params.particles_5 = (bytes[i  ] << 8) | bytes[i  ];
    data.params.particles_10 = (bytes[i  ] << 8) | bytes[i  ];
    
    data.params.version = bytes[i  ];
    data.params.Error = bytes[i  ]
    
    return data;
}

下行数据解析的脚本主函数为 ProtocolToRaw,其入参为产品数据模版协议格式的对象,案例不涉及下行控制,可以不处理。

在下行数据解析部分,javascript 示例代码如下:

代码语言:txt复制
function ProtocolToRaw(obj) {
	return [];
}
product_script.pngproduct_script.png
创建测试设备

在设备调试页面中,单击【新建设备】,设备名为 PM25_001。

DevEUI 等信息可从 LoRa 节点开发板硬件获得,需要与前文的代码保持一致。

tos_lora_module_join_otaa("your devui", "your appkey");

dev_new.pngdev_new.png
查看设备状态
  1. 保持 LoRa 节点和 LoRa 网关 为运行状态。
  2. 进入【控制台】>【产品开发】>【设备调试】,可查看到设备 "PM25_001" 。
  3. 单击【调试】,可进入设备详情页。
dev_status.pngdev_status.png
  1. 单击【设备属性】,可查询设备上报到开发平台的最新数据及历史数据。
  2. 设备属性的最新值:会显示设备上报的最新数据。
  3. 设备属性的更新时间:显示数据的更新时间。
pm25_data.pngpm25_data.png
  1. 单击【查看】,可查看某个属性的历史上报数据。
查看设备通信日志

单击【设备日志】,可查询该设备某段时间范围的所有上下行数据。

  • 上行:上行指设备端上报到开发平台的数据。
  • 下行:下行指从开发平台下发到设备的数据。
pm25_log.pngpm25_log.png

0 人点赞