本文由RT-Thread论坛用户@纯白酱原创公布:https://club.rt-thread.org/as...

我的项目形容

应用新唐公司的NUC980,开发一款室内环境监测平台。采集端通常位于家庭中的室内,采集传感器数据,如温湿度数据,光照数据,空气质量数据等,读取实现后,打包成json格局的数据,通过以太网,应用http post形式传输传感器数据。

设施清单

主控板:NUC980-IOT
传感器扩大板:板载多种传感器,基于立创EDA制作,已开源,开源地址为:立创EDA-传感器扩大板
服务器:基于腾讯云搭建的一款云服务器,运行的是Windows server 2019,已装置thingsboard开源物联网云平台。

传感器扩大板简介

定位模块:基于华大北斗的TAU1202,默认波特率为115200,双频定位,亚米级定位,定位成果优异。

光照度:基于vishy的vcnl4040

温湿度:基于盛思锐的SHT30

二氧化碳浓度/空气质量指数(TVOC):基于盛思锐的SGP30

PM2.5:基于攀藤科技的PMS7003

甲醛:基于达特的WS-K-S甲醛传感器模组

大气压强:基于歌尔电子的SPL06-007(能够等效代替SPL06-001)

姿势:基于invensense的mpu-6050

重要提醒

1、服务器局部,运行的thingsboard社区版,能够自用/商用,本次是运行在腾讯云的服务器上的,也能够运行在树莓派等嵌入式linux平台上,不便用户治理传感器数据,确保传感器数据不流通至外网。
2、传感器扩大板反对多种传感器,通信接口为I2C和串口。本次只用到I2C接口,且I2C接口的姿势传感器并未应用(因为感觉室内不须要监测本身的姿势数据)。串口接口的传感器并未应用。

测试截图


开发流程

采集端开发流程

一、RT-Thread Studio下载并装置

在https://www.rt-thread.org/page/studio.html中,下载并装置RT-Thread Studio,并提前注册好RT-Thread账号,并在装置好后登录RT-Thread Studio

二、装置开发板资源包

1、关上RT-Thread Studio

2、进入主页面后,点击SDK Manager,能够装置本次流动的开发板NUC980-IOT的反对包

3、拖动右侧的滑块到上面,抉择NK-980IOT,装置BSP资源包

4、应用两根microusb数据线,别离连贯两根USB接口(在左上方),将拨码开关均调节至off模式,即boot from usb模式,此模式能够下载程序用,例如下载到DDR中间接运行程序,不便程序调试阶段,不间断更新程序。或者下载到板载SPI NAND中,并通过调节拨码开关均至ON,按图中最左侧RESET按键后,即可从SPI NAND中运行程序,即失常收回给客户时,运行程序的模式。

两个USB接口别离为虚构串口和调试下载的性能,同时连贯,不便观测调试数据和下载程序。

三、创立工程

抉择文件-新建-RT-THhread我的项目,创立基于开发板资源包的工程

点击基于开发板,并抉择开发板为NK-980IOT,自定义取名工程名称,留神不要与现有的工程名称反复,填写结束后,点击实现,并期待IDE创立工程,约半分钟到两分钟左右,具体工夫由开发者的电脑性能决定。

四、编译程序

创立好工程后,双击project name/application/main.c,能够看到main.c中有一个点灯例程。

图中定义了板载的三个LED对应的引脚,其中,PG15引脚对应板载的绿色LED灯,然而PG15引脚上电默认为JTAG性能,并非一般GPIO,须要在project name/board/nu_pin_init.c文件中,初始化该引脚,零碎会主动调用该函数

初始化后,板载的三个LED灯则均能失常闪动

点击左上角的编译按钮,即可编译好程序,并在project name/Debug目录下生成rtthread.bin文件,初始demo工程,通常编译用时在一分钟左右,工夫由电脑CPU性能决定。

五、下载程序

下载NU_Wrtier软件,链接:https://gitee.com/OpenNuvoton/NUC980_NuCWriter.git,能够git clone该仓库,并在NUC980_NuCWriter/ Release / Win64中运行。

下载好后,运行软件,并参考https://github.com/RT-Thread/rt-thread/tree/master/bsp/nuvoton/nk-rtu980,readme.md中,下载程序到DDR的内容。

应用 NuWriter 将 rtthread.bin 下载到 SDRAM 中,而后运行它。

抉择类型:DDR/SRAM << Press Re-Connect >> 抉择文件:指定您的 rtthread.bin 文件(在project name/Debug目录下)。 执行地址:0x0 选项:下载并运行 << Press Download >> Enjoy!!!

六、正式开发程序

依据本次我的项目需要,确定须要应用的传感器驱动程序和设施驱动程序和数据处理驱动程序,目录如下:

序号名称性能是否已适配软件包?
1温湿度传感器通过I2C,读取温湿度传感器数据
2光照度传感器通过I2C,读取光照度传感器数据否,须要自行依据编写驱动程序
3空气质量传感器通过I2C,读取空气质量传感器数据
4CJSON将读取出的各项传感器数据处理为JSON格局
5以太网驱动通过以太网,传输数据到指定地址
6HTTP POST基于TCP通信,通过HTTP协定,POST办法,向指定地址发送解决好的传感器数据(JSON格局)

根据上述剖析,别离增加各项软件包:

双击RT-Thread Setting

增加如图的软件包

在硬件栏中使能传感器通信接口I2C2

使能结束后,在main.c中增加初始化sgp30的相干函数

#define SGP30_I2C_BUS_NAME       "i2c2"#define SGP30_I2C_ADDRESS        0x58static int rt_hw_sgp30_port(void){    struct rt_sensor_config cfg;    cfg.intf.type = RT_SENSOR_INTF_I2C;    cfg.intf.dev_name = SGP30_I2C_BUS_NAME;    cfg.intf.user_data = (void *) SGP30_I2C_ADDRESS;    rt_hw_sgp30_init("sg3", &cfg);    return RT_EOK;}INIT_COMPONENT_EXPORT(rt_hw_sgp30_port);

依据论坛,及官网文档,别离调用软件包,并读取传感器数据。因为vcnl4040光照度传感器,并未有软件包适配,咱们依据RT-Thread对立的I2C通信驱动,编写读取程序:

/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2021-07-09     coolwhite       the first version */#include <rtthread.h>#define DBG_ENABLE#define DBG_LEVEL DBG_LOG#define DBG_SECTION_NAME  "VCNL4040"#define DBG_COLOR#include <rtdevice.h>#include <stdio.h>#include <ulog.h>#include <rtdbg.h>#define HW_ADR 0x60rt_uint32_t test;rt_uint32_t Illuminance_als;static struct rt_i2c_bus_device *i2c_bus = RT_NULL; /* I2C总线设施句柄 */rt_uint8_t l;rt_uint8_t h;static rt_err_t vcnl4040_write(struct rt_i2c_bus_device *bus, uint8_t hwadr, uint8_t reg, rt_uint8_t *data){    rt_uint8_t buf[3];    struct rt_i2c_msg msgs;    rt_uint32_t buf_size = 1;    buf[0] = reg; //cmd    if (data != RT_NULL)    {        buf[1] = data[0];        buf[2] = data[1];        buf_size = 3;    }    msgs.addr = hwadr;    msgs.flags = RT_I2C_WR;    msgs.buf = buf;    msgs.len = buf_size;    /* 调用I2C设施接口传输数据 */    if (rt_i2c_transfer(bus, &msgs, 1) == 1)    {        return RT_EOK;    }    else    {        return -RT_ERROR;    }}rt_err_t read_regs(struct rt_i2c_bus_device *bus, uint8_t reg, rt_uint8_t *data){    struct rt_i2c_msg msgs[2];    rt_int8_t res = 0;    msgs[0].addr = HW_ADR; /* Slave address */    msgs[0].flags = RT_I2C_WR; /* Write flag */    msgs[0].buf = &reg; /* Slave register address */    msgs[0].len = 1; /* Number of bytes sent */    msgs[1].addr = HW_ADR; /* Slave address */    msgs[1].flags = RT_I2C_RD; /* Read flag */    msgs[1].buf = data; /* Read data pointer */    msgs[1].len = 2; /* Number of bytes read */    if (rt_i2c_transfer((struct rt_i2c_bus_device *) bus, msgs, 2) == 2)    {        res = RT_EOK;    }    else    {        res = -RT_ERROR;    }}void vcnl4040_init(const char *name){    /* 查找I2C总线设施,获取I2C总线设施句柄 */    i2c_bus = (struct rt_i2c_bus_device *) rt_device_find(name);    if (i2c_bus == RT_NULL)    {        rt_kprintf("can't find %s device!\n", name);    }    else    {        rt_uint8_t cmd[2];        cmd[0] = 0x00;        cmd[1] = 0x00;        vcnl4040_write(i2c_bus, HW_ADR, 0x00, cmd);        rt_kprintf("vncl4040 init sussess at %s", name);        rt_thread_mdelay(500);    }}void test_vcnl4040(){    rt_uint8_t data[2];    data[0] = 0x00;    data[1] = 0x00;    rt_uint8_t data1[2];    data1[0] = 0x00;    data1[1] = 0x00;    rt_uint8_t als_l;    rt_uint8_t als_h;    read_regs(i2c_bus, 0x09, data1);    l = data[0];    h = data[1];    als_l = data1[0];    als_h = data1[1];    rt_uint16_t als_data;    als_data = als_h;    als_data <<= 8;    als_data += als_l;    Illuminance_als = als_data / 10;    LOG_I("Illuminance_als=%d\n",Illuminance_als);}

在application文件夹中,创立一个cloud_send.c文件,在其中,调用cjson软件包,并解决传感器数据为JSON格局:

    char *thingsboard_sensor_send;    cJSON *csensor = cJSON_CreateObject();    cJSON *cbaro = cJSON_CreateNumber(baro);    cJSON *cco2concentration = cJSON_CreateNumber(co2concentration);    cJSON *ctvocconcentration = cJSON_CreateNumber(tvocconcentration);    cJSON *chumidity = cJSON_CreateNumber(humi1);    cJSON *ctemperature = cJSON_CreateNumber(temp1);    cJSON *cIlluminance_als = cJSON_CreateNumber(Illuminance_als);    cJSON_AddItemToObject(csensor, "Illuminance_als", cIlluminance_als);    cJSON_AddItemToObject(csensor, "baro", cbaro);    cJSON_AddItemToObject(csensor, "co2concentration", cco2concentration);    cJSON_AddItemToObject(csensor, "tvocconcentration", ctvocconcentration);    cJSON_AddItemToObject(csensor, "humidity", chumidity);    cJSON_AddItemToObject(csensor, "temperature", ctemperature);    thingsboard_sensor_send = cJSON_Print(csensor);

解决好传感器数据后,调用webclient软件包,发送传感器数据到指定地址:

/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2022-05-05     11618       the first version *//* * Copyright (c) 2006-2022, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2018-08-03    chenyong      the first version */#include <string.h>#include <rtthread.h>#include <webclient.h>#include <cJson.h>#define POST_RESP_BUFSZ                10240#define POST_HEADER_BUFSZ              10240#define POST_LOCAL_URI                 "http://124.220.198.111:8080/api/v1/QLYe1sufLVvb2e2K3lFb/telemetry"extern double temp1;extern double humi1;extern double baro;extern int32_t co2concentration;extern int32_t tvocconcentration;extern rt_uint32_t Illuminance_als;/* send HTTP POST request by common request interface, it used to receive longer data */static int webclient_post_comm(const char *uri, const void *post_data, size_t data_len){    struct webclient_session* session = RT_NULL;    unsigned char *buffer = RT_NULL;    int index, ret = 0;    int bytes_read, resp_status;    buffer = (unsigned char *) web_malloc(POST_RESP_BUFSZ);    if (buffer == RT_NULL)    {        rt_kprintf("no memory for receive response buffer.\n");        ret = -RT_ENOMEM;        goto __exit;    }    /* create webclient session and set header response size */    session = webclient_session_create(POST_HEADER_BUFSZ);    if (session == RT_NULL)    {        ret = -RT_ENOMEM;        goto __exit;    }    /* build header for upload */    webclient_header_fields_add(session, "Content-Length: %d\r\n", strlen(post_data));    webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n");    /* send POST request by default header */    if ((resp_status = webclient_post(session, uri, post_data, data_len)) != 200)    {        rt_kprintf("webclient POST request failed, response(%d) error.\n", resp_status);        ret = -RT_ERROR;        session == RT_NULL;        goto __exit;    }    __exit: if (session)    {        webclient_close(session);        session == RT_NULL;    }    if (buffer)    {        web_free(buffer);    }    session == RT_NULL;    return ret;}/* send HTTP POST request by simplify request interface, it used to received shorter data */static int webclient_post_smpl(const char *uri, const char *post_data, size_t data_len){    char *response = RT_NULL;    char *header = RT_NULL;    size_t resp_len = 0;    int index = 0;    webclient_request_header_add(&header, "Content-Length: %d\r\n", strlen(post_data));    webclient_request_header_add(&header, "Content-Type: application/octet-stream\r\n");    if (webclient_request(uri, header, post_data, data_len, (void **) &response, &resp_len) < 0)    {        rt_kprintf("webclient send post request failed.");        web_free(header);        return -RT_ERROR;    }    rt_kprintf("webclient send post request by simplify request interface.\n");    if (header)    {        web_free(header);    }    if (response)    {        web_free(response);    }    return 0;}void thingsboard_post_test(){    char *uri = RT_NULL;    char *thingsboard_sensor_send;    cJSON *csensor = cJSON_CreateObject();    cJSON *cbaro = cJSON_CreateNumber(baro);    cJSON *cco2concentration = cJSON_CreateNumber(co2concentration);    cJSON *ctvocconcentration = cJSON_CreateNumber(tvocconcentration);    cJSON *chumidity = cJSON_CreateNumber(humi1);    cJSON *ctemperature = cJSON_CreateNumber(temp1);    cJSON *cIlluminance_als = cJSON_CreateNumber(Illuminance_als);    cJSON_AddItemToObject(csensor, "Illuminance_als", cIlluminance_als);    cJSON_AddItemToObject(csensor, "baro", cbaro);    cJSON_AddItemToObject(csensor, "co2concentration", cco2concentration);    cJSON_AddItemToObject(csensor, "tvocconcentration", ctvocconcentration);    cJSON_AddItemToObject(csensor, "humidity", chumidity);    cJSON_AddItemToObject(csensor, "temperature", ctemperature);    thingsboard_sensor_send = cJSON_Print(csensor);        uri = web_strdup(POST_LOCAL_URI);        if (uri == RT_NULL)        {            rt_kprintf("no memory for create post request uri buffer.\n");        }        webclient_post_comm(uri, (void *) thingsboard_sensor_send, rt_strlen(thingsboard_sensor_send));    if (uri)    {        web_free(uri);    }    cJSON_Delete(csensor);    thingsboard_sensor_send=RT_NULL;    rt_free(thingsboard_sensor_send);    rt_thread_mdelay(1000);}#ifdef FINSH_USING_MSH#include <finsh.h>//MSH_CMD_EXPORT_ALIAS(thingsboard_post_test, thingsboard_post_test, webclient post request test.);#endif /* FINSH_USING_MSH */

七、连贯硬件并再次下载程序

将传感器扩大板与NK-980IOT开发板,应用杜邦线连贯,并插上网线,应用USB数据线,连贯电脑并下载程序,下载程序步骤能够参考上文,不再赘述。
下载实现后,采集端开发告一段落。

云平台开发流程

Thingsboard一款开源的云平台,官网地址为:https://thingsboard.io,用户可在官网,学习到thingsboard的下载(社区版),装置,与应用。

一、登录物联网云平台

登录thingsboard云平台(链接:http://124.220.198.111:8080)链接依据本人服务器部署状况,会有所不同。初学者倡议部署在树莓派上,硬件老本较低,传感器数据不易流出外网。

在登录页面,输出用户名和明码(须要以总管理员的身份创立)

二、创立设施

输出正确的用户名和明码后,登录,即可看到云平台的整体配置界面:

咱们为了让采集端接入云平台通信,须要先创立设施,点击设备选项:

点击右上角的创立设施:

自定义名称,并间接点击增加

三、查看设施凭证

单击test_nuc980,抉择复制设施拜访令牌

也能够点击治理凭据,手动复制拜访令牌

四、在采集端中填写拜访令牌

thingsboard反对多种通信协议,在社区版中,通常应用的是HTTP协定、MQTT协定、COAP协定,本次我的项目次要应用HTTP协定,其余协定请依据官网文档,自行学习。

通过HTTP协定上传传感器数据的通常API接口为:

http(s)://host:port/api/v1/$ACCESS_TOKEN/telemetry

其中,http(s)://host:port替换为通常你部署的服务器地址,能够是公网地址,也能够是内网地址。
$ACCESS_TOKEN即拜访令牌,比方test_nuc980设施,对应的拜访令牌为:yUtSRivycEvXiamNMC2F

确定好传输地址后,在采集端工程:project name/application/cloud_send.c中,替换默认地址:

五、设施遥测数据查看

烧录好采集端工程,并实现硬件接线后,即可在云平台查看传输的传感器数据
单击设施名称:

点击最新遥测数据:

能够看到采集端数据曾经发送到云平台,依据最近更新工夫,能够观测数据传输是否出现异常。

六、设施数据仪表盘配置

在最新遥测数据中查看,并不能直观的展现出设施数据的长时间状况下的变化趋势等,所以咱们须要配置一个仪表盘,以便查看数据。
在主菜单中,单击仪表盘:

点击右上角的“+”,新建一个仪表盘:

输出题目,即可增加仪表盘

增加实现后,点击关上仪表板:

点击右下角的功能键,并抉择创立一个新的部件:

为了更好的展现温湿度、光照度等数据的长时间变化趋势度,抉择chart部件:

抉择工夫序列图部件:

单击增加数据源:

配置实体别名,即绑定设施:

配置结束后,在键名处即可找到对应的传感器数据名称,键名次要由采集端定义,如需批改,请在采集端批改键名与对应的传感器数据:

本次抉择显示温度数据,即键名为temperature的数据,单击蓝色圆圈,可定制折线图的折线色彩:


配置好喜爱的色彩后,点击设置,设置该折线图的名称,在此,咱们将其命名为温度:

点击增加即可,并随后点击右下角的确认更改:

即可看到温度的数据变动曲线:

其余传感器数据的配置形式能够参照上文,以此类推。

七、查看更长时间的传感器数据变动曲线

单击右上角的工夫按钮:

能够查看更多工夫维度的传感器数据变动折线图(默认为1分钟):

配置好后,折线图即产生变动:

流程演示

采集端流程:

云平台端流程:

视频演示

正在编辑,稍后上传

开源链接

链接: https://pan.baidu.com/s/1J_Lh... 提取码: 6sey 复制这段内容后关上百度网盘手机App,操作更不便哦
--来自百度网盘超级会员v5的分享

心得体会

NUC980芯片,之前并未关注过,通过本次流动,让我理解到RT-Thread在NUC980上的运行及其劣势所在:开发便当,资源十分丰盛(多路串口,多路USB等等),在疫情三年,芯片市场动荡的状况下,NUC980无望局部取代价格极度暴涨的STM32,在工业管制,数据采集等畛域取得更大的市场。

备注

thingsboard是一款开源的物联网平台,本次流动所展现的云平台数据,在以下链接中能够看到:NUC980室内环境监测仪表盘,如果有大家有须要测试或者理解这款云平台,能够在文章评论区留言,我能够凋谢肯定数量的测试账号,不便大家体验。