IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> NUC980开发板DIY项目大挑战:室内环境采集监测系统 -> 正文阅读

[嵌入式]NUC980开发板DIY项目大挑战:室内环境采集监测系统

本文由RT-Thread论坛用户@纯白酱原创发布:https://club.rt-thread.org/ask/article/75b0b1edc9ec7289.html

#项目描述
使用新唐公司的NUC980,开发一款室内环境监测平台。采集端通常位于家庭中的室内,采集传感器数据,如温湿度数据,光照数据,空气质量数据等,读取完成后,打包成json格式的数据,通过以太网,使用http post方式传输传感器数据。
#设备清单
主控板:NUC980-IOT
传感器扩展板:板载多种传感器
服务器:基于腾讯云搭建的一款云服务器,运行的是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接口的姿态传感器并未使用(因为感觉室内不需要监测自身的姿态数据)。串口接口的传感器并未使用。
#测试截图
QQ图片20220515164301.png
QQ图片20220515165127.png
#开发流程
##采集端开发流程
###一、RT-Thread Studio下载并安装
https://www.rt-thread.org/page/studio.html中,下载并安装RT-Thread Studio,并提前注册好RT-Thread账号,并在安装好后登录RT-Thread Studio
###二、安装开发板资源包
1、打开RT-Thread Studioccb65c3e1812a315b5b758b98cb415ca.png

2、进入主页面后,点击SDK Manager,可以安装本次活动的开发板NUC980-IOT的支持包
b32599090bbc15745d25f30b0cbb7e92.png

3、拖动右侧的滑块到下面,选择NK-980IOT,安装BSP资源包
e403b5cedb9886d4eabbe28bbb45d23b.png.webp

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

两个USB接口分别为虚拟串口和调试下载的功能,同时连接,方便观测调试数据和下载程序。
###三、创建工程
选择文件-新建-RT-THhread项目,创建基于开发板资源包的工程
2e85b76b95d566af314439efb0dc7db8.png.webp

点击基于开发板,并选择开发板为NK-980IOT,自定义取名工程名称,注意不要与现有的工程名称重复,填写完毕后,点击完成,并等待IDE创建工程,约半分钟到两分钟左右,具体时间由开发者的电脑性能决定。
337f404df2a38bb9eff6ca68e656e4f6.png.webp

###四、编译程序
创建好工程后,双击project name/application/main.c,可以看到main.c中有一个点灯例程。
c55f39c01884295cc05facf5e4fb94d5.png.webp

图中定义了板载的三个LED对应的引脚,其中,PG15引脚对应板载的绿色LED灯,但是PG15引脚上电默认为JTAG功能,并非普通GPIO,需要在project name/board/nu_pin_init.c文件中,初始化该引脚,系统会自动调用该函数
1c1ee4aafa4f5618af33392b5c741af2.png.webp

初始化后,板载的三个LED灯则均能正常闪烁
ec1ee4499537746975d07aa2cf8f97bb.png.webp

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

###五、下载程序
下载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!!!
2770f284faf0d4e873f89965d02feb59.png.webp
###六、正式开发程序
根据本次项目需求,确定需要使用的传感器驱动程序和设备驱动程序和数据处理驱动程序,目录如下:

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

根据上述分析,分别添加各项软件包:

双击RT-Thread Setting
74b24ad981258b291280334b70535803.png
添加如图的软件包
e220f0b2ccb53bc8d79507e98674cbd8.png
在硬件栏中使能传感器通信接口I2C2
d3739bda2bce5afd6d8498d9aae47d6a.png.webp
使能完毕后,在main.c中添加初始化sgp30的相关函数

#define SGP30_I2C_BUS_NAME       "i2c2"
#define SGP30_I2C_ADDRESS        0x58

static 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 0x60
rt_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数据线,连接电脑并下载程序,下载程序步骤可以参考上文,不再赘述。
下载完成后,采集端开发告一段落。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-21 19:08:40  更:2022-05-21 19:10:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:34:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码