STM32MP157实现串口接收数据上云-云数据库存储多设备数据&界面显示实现


前言

本篇分享:

前几篇博客分享了STM32MP157实现串口接收数据上云,实现了STM32MP157的串口在接收到数据时能上传至服务器,让用户可以随时随地查看一个设备的实时信息。

本篇要分享的是如何在之前的基础上更进一步,实现云数据库存储多设备数据以及界面显示


准备工作:

一.软件安装

整个过程的实现大体思路是:
数据–>STM32MP157–>云平台–>NODE-RED–>MYSQL

为了实现多设备数据存储云数据库并实现界面显示,这里需要在服务器安装两个必要的软件:MYSQL、NODE-RED用于实现数据存储和界面显示,并且推荐安装宝塔Linux面板和phpMyAdmin数据库可视化操作软件,这里四个软件都用到了,所以推荐都安装,网上有很多安装教程,这里就不赘述了。

  • 必要安装:MYSQL(存储数据)、NODE-RED(连接阿里云和数据库&界面显示)
  • 推荐安装:宝塔Linux面板(安装软件方便,可一键安装MYSQL和phpMyAdmin)、phpMyAdmin(云端数据库可视化操作)

安装完软件后记得在服务器的 安全组规则中添加需要使用的端口号

  • 路径:控制台-云服务器ECS-蓝色示例名称-配置安全组规则-配置规则-添加安全组规则
  • 操作:如宝塔面板的端口范围输入9696/9696、授权对象输入0.0.0.0/0即可;NODE-RED的端口号为1880
  • 另外,在宝塔面板的安全里面同样也要放行端口(两边都要)
  • 安装软件后输入ip+端口发现页面无法打开就检查下安全组规则有没有配置

改进工作:

二.代码改进

现在将串口接收的数据也规定为JSON格式(如:{“id”:“1”,“2_CurrentVoltage”:“90”}),并解析该数据,得到所需数据进行上传。

1.串口接收

​串口则要实现一次性接收PC端串口调试助手发送的全部数据,再去进行解析
​这时,原来写的串口接收代码就无法满足要求了,接收数据时会出现如下问题:

在这里插入图片描述
可以看到,每当串口接收到8位数据时FD_ISSET函数就能检测到设备为可读状态,而id和电压数据可能为一位数也可能为两位数,则不可能使用接收字符个数去判断,用接收次数判断的话后续添加数据时还需要计算发送的字符个数再对次数进行更改,以上两种方法均不太可取。

​这里使用的方法则是再增加一个串口接收线程保存接收的数据并且增加两个变量rece_byte_new和rece_byte_old,当接收到数据时rece_byte_new++。在主循环中则判断rece_byte_new>0时进入一个循环,等待数据接收完,在循环体内将rece_byte_new赋值给rece_byte_old,循环延时的时间设置为比串口接收8位数据稍大的时间(这个时间很重要,不能太大也不能太小,太小接收不完8位数据就去判断old和new是否相等会导致提前退出循环,太大会降低接收效率消耗不必要的时间,根据波特率115200计算,串口接收8位数据约为520us,这里设置为650us),这样无论数据多长这里都不需要进行更改,直到rece_byte_new和rece_byte_old相等时退出循环,继续执行后续的数据解析。代码如下:

/*相关头文件*/
#include <string.h>
#include <pthread.h>

/*全局变量*/
char rece_data[256];

/*创建进程*/
pthread_t id2;
pthread_create(&id2,NULL,serial_lsd2,&serportfd_PC);//创建线程

/*串口接收外部数据线程*/
void *serial_lsd2(void *d)//串口接收外部数据线程
{
    
    
    int tfd=*(int *)d;
    char rec_data[64];
    fd_set rd;
    
    while (1)
    {
    
    
        /*检查设备(文件描述符tfd)是否可读*/
        FD_ZERO(&rd);//清空rd
        FD_SET(tfd,&rd);//将tfd添加进rd中
        if(select(tfd+1,&rd,NULL,NULL,NULL)<0)//检查设备是否可读
            perror("select");

        /*如果tfd可读 执行select后rd中tfd仍为1 FD_ISSET(tfd,&rd)成立 则读取并打印数据*/
        if(FD_ISSET(tfd,&rd))//如果可读则读取并打印数据
        {
    
    
            rece_byte_new++;//持续时间为数据读取和保存的时间
            while(read(tfd,rec_data,1)>0)
            {
    
    
                strcat(rece_data,rec_data); 
            }  
        }
    }
}

/*主循环相应代码*/
/*检测到外部设备正在传输数据*/
if(rece_byte_new > 0)
{
    
    
    /*循环等待数据传输完毕*/
    while(rece_byte_new != rece_byte_old)
    {
    
    
        rece_byte_old = rece_byte_new;
        /*波特率115200下1字节传输时间约为520us 此处设置延时应比理论时间稍长*/
        usleep(650);
    }

    /*退出循环表示数据接收完毕 标志位清零等待下一次接收*/
    rece_byte_new = 0;
    rece_byte_old = 0;

    printf("Successfully received data!\n");//成功接收数据提示
    //后续代码-数据解析
}

2.JSON数据解析

​当接收到JSON格式的数据后该如何对数据进行解析,提取出AT指令(发送消息到云平台)所需的数据呢?

​这里我先是使用了cJSON第三方库进行解决,解决步骤就是将接收到的字符串转化成JSON对象,再调用cJSON_GetObjectItem对相应字段后的数据进行提取,提取后再用cJSON_Print函数将其转为字符串。但由于提取出的字符串自带引号,串口又不能直接发送引号,这里又需要用到sscanf函数对字符串进行提取,稍微有点麻烦……

​所以,我直接使用了sscanf函数对数据进行提取……

while(1)
{
    
    
    //代码-等待数据接收完成
    /*数据提取 约定数据传输的格式为JSON格式*/
    sscanf(rece_data,"{\"id\":\"%d\",\"%d_CurrentVoltage\":\"%d\"}",&int_id,&int_identifier,&int_CurrentVoltage);

    /*判断数据是否有误 再决定是否上传至云端*/
    send=1;
    if(int_id <= 0 || int_CurrentVoltage <= 0 || (int_id != int_identifier))//此处约定 int_id == int_identifier
    {
    
       
        printf("data error\n");
        send=0;
    } 

    /*数据无误*/
    if(send==1)
    {
    
    
        /*生成AT指令*/
        sprintf(send_data,"AT+MPUB=\"/sys/a1cdS8zCRA0/863488054279453/thing/event/property/post\",1,0,\"{\\22id\\22:%d,\\22params\\22:{\\22%d_CurrentVoltage\\22:%d},\\22version\\22:\\221.0\\22,\\22method\\22:\\22thing.event.property.post\\22}\"\r",int_id,int_identifier,int_CurrentVoltage);
        /*向4G模块发送AT指令*/
        write(serportfd_4G,send_data,strlen(send_data));
    }
    memset(rece_data,0,sizeof(rece_data));//清空rece_data
}

转发工作:

三.云产品流转

1.作用

在设备接收到数据后,将该数据转发至NODE-RED

2.自定义产品功能&添加设备

​在上面代码中出现了%d_CurrentVoltage是因为我在阿里云对产品新增了两个功能,用于显示两台设备的数据,标识符分别为1_CurrentVoltage2_CurrentVoltage。另外,为了后续连接云数据库还需要增加一个NODE-RED设备用于MQTT通讯。

​添加产品功能和设备的方法之前讲过了,这里就简述下:

  • 添加自定义功能:产品-Air724(产品名)-功能定义-编辑草稿-添加自定义功能-发布上线。
  • 添加设备:设备-添加设备,产品选同类型即可,DeviceName 我这里设置为NODE-RED
    在这里插入图片描述

3.创建数据传输规则

​接着,需要进行数据传输规则的创建,在规则引型中找到云产品流转。

在这里插入图片描述
点击回到旧版,旧版使用较方便(新版还没用过:_)

在这里插入图片描述
点击创建规则数据格式选JSON,其他可以自己定义。

在这里插入图片描述
在这里插入图片描述
点击编写SQL,字段输入*(即转发接收到的所有数据),Topic选择物模型数据上报,设备选择接收板子上传数据的那个设备,再选择我们AT指令中发送的Topic:thing/event/propert/post,点击确认。

在这里插入图片描述
再点击添加操作。

在这里插入图片描述
操作选择发布到另一个Topic,Topic选择NODE-RED的user/get,点击确认。

在这里插入图片描述
返回到云产品流转界面,点击启动即可。

在这里插入图片描述
存储工作:

四.MYSQL操作

这里讲一下MYSQL可视化的操作(终端操作直接调到下方根据表结构建表即可),安装完宝塔面板后,在软件商店中安装MYSQLphpMyAdmin
在这里插入图片描述
安装完后,在数据库中找到phpMyAdmin,点击通过面板访问。

在这里插入图片描述
登录需要输入MYSQL的用户名和密码,安装完的MYSQL有默认用户名和密码,网上有查询教程。之前安装过的,就输入数据库登录的用户名和密码即可。

​点击新建一个数据库。

在这里插入图片描述
新建两个数据表存储不同设备数据(一张表存储一个设备数据,多个设备就建多张表)。

在这里插入图片描述
输入字段名,可以添加一个id的字段让其自增作为主键,这样后续就可以对数据表进行删除和编辑等操作。

在这里插入图片描述创建完成后继续在左边选择新建数据表,再新建一个表device_2,结构和上表相同即可。

在这里插入图片描述
连接&显示工作:

五.NODE-RED操作

1.总体思路

NODE-RED这边的总体思路就是接收云平台发送的数据,将数据发送至函数处理,在函数节点将数据进行提取处理成SQL语句后发送至MQSQL节点实现数据的存储;另外用switch节点(功能类似c语言中的switch),根据id去决定更新界面中的设备1电压表还是设备2电压表数据。

2.安装节点

​安装好NODE-RED后输入服务器ip:1880打开NODE-RED,可以看到左边为NODE-RED节点栏,这里可以找到需要的节点并直接拖出到中间即可配置使用(中文设置在右上角三条横杠的设置中)。

​这里需要用到的MYSQL节点dashboard节点原本都没有,需要自行下载。点击右上角三条横杆-节点管理-安装,搜索node-red-dashboardnode-red-node-mysql安装即可,想用table的节点的话需要另外安装node-red-node-ui-table(之前一直奇怪为什么我的dashboard没有table这个节点)

在这里插入图片描述

3.节点配置

  • mqtt in节点

    mqtt in节点的作用是实现NRED-RED与云平台的MQTT通讯。在节点栏里找到网络下面的mqtt in节点并拖出,双击节点,点击服务端后面的编辑图标。

    在这里插入图片描述
    点开后,需要配置的有连接中的服务端和客户端ID安全中的用户名和密码,如何获取这些参数可以看下之前4G设备向云发送数据中的2.连接阿里云操作,名称自定义即可,设置好后返回上图这个界面再将主题补充完整(填云产品流转的转发数据中设置的那个Topic)。配置完后点击完成,再点击NODE-RED右上角的部署,部署完后看到mqtt in节点下方出现已连接即为成功

  • mysql节点

    mysql节点的作用是,实现NODE-RED与MYSQL的连接。安装完MYSQL节点后,在左侧节点栏存储中找到mysql节点并拖出,双击mysql节点,点击编辑,配置MYSQL的Host(MYSQL和NODE-RED安装在同一服务器下输入服务器ip或127.0.0.1均可)、端口号(MYSQL默认端口号)、登录用户名密码以及要连接的数据库名称配置好后点击部署,部署完后mysql节点下方出现connected即为成功

    在这里插入图片描述

  • function节点

    function节点的作用主要是对数据的处理。在左侧节点栏功能中找到function节点并拖出,双击function节点,可以在函数的文本编辑框中用JS语言编写代码,这部分代码主要要实现的功能是对从阿里云发送的数据进行提取,再组合成一条SQL语句,再发送至MYSQL数据库进行执行,从而达到数据存储的目的。

    在这里插入图片描述

具体代码如下所示:

/*定义插入数据SQL语句*/
var find = "INSERT INTO `db_devices2`.`device_%s` (`CurrentVoltage`) VALUES ('%s')"

/*根据设备补充SQL语句*/
if (msg.payload.requestId == 1)//如果设备id为1
{
    
    
    var newMsg = {
    
    
        // @ts-ignore
        "topic": util.format(find, msg.payload.requestId, msg.payload.items["1_CurrentVoltage"].value )//用format函数将接收到的数据对SQL语句进行补充(如果对JSON不熟悉,可以用debug得到数据所在路径,下面在debug节点中介绍)
    }
}
else if (msg.payload.requestId == 2)//如果设备id为2
{
    
    
    var newMsg = {
    
    
        // @ts-ignore
        "topic": util.format(find, msg.payload.requestId, msg.payload.items["2_CurrentVoltage"].value )
    }
}

/*赋值并返回*/
msg.topic = newMsg.topic
return msg;

代码解析:

这段代码是在 Node-RED 环境中,使用 JavaScript 编写的代码。它用于构造消息对象,并通过修改消息对象的 topic 属性来更新消息。

这段代码中的 "msg" 是消息对象,是一种在节点间传递信息的方式。在这段代码中,消息对象携带了 payload 属性,该属性是一个包含请求 ID 和其他数据项的对象。代码通过判断请求 ID 的值是 1 还是 2,来选择需要获取的数据项。然后它创建一个新的消息对象 "newMsg",并在该对象中指定了该消息的主题。最后,原始消息对象的主题属性被重新设置为 "newMsg" 的主题,并返回该消息对象。

这段代码中的 util.format 方法是 Node.js 中的格式化工具,用于构造新的消息主题。该方法的第一个参数是一个字符串,它包含了两个占位符,用于表示请求 ID 和数据项的值。第二个参数是请求 ID 的值,第三个参数是数据项的值。最终,消息的主题将是一个插入语句,用于将数据项的值插入到数据库中。

具体来说:
定义了一个字符串变量 find,表示要执行的 SQL 语句;该SQL语句将通过 "msg" 消息对象在节点间传递(传递给数据库节点时,就能根据消息对象携带的SQL语句执行相应的操作)。
判断 msg.payload.requestId 的值,如果为 1,则创建一个名为 newMsg 的对象,并赋予其 topic 属性;
同理,如果 msg.payload.requestId 的值为 2,则创建一个名为 newMsg 的对象,并赋予其 topic 属性;
最后,将 msg 的 topic 属性更新为 newMsg 的 topic 属性,并返回 msg 对象,传递给下一节点。
util.format() 函数功能类似 sprintf 函数

// @ts-ignore 是 TypeScript 的注释,表示忽略类型检查。
  • debug节点

    debug节点在左侧节点栏的共通中,其作用是接收前面节点输出的数据并在调试窗口进行显示

    在完成mqtt in、function、mysql三个节点的配置后,可以在mqtt in以及function节点后连接一个debug节点,方便用户查看接收的数据是否准确。

    这里连接好点击部署,并运行开发板程序向云平台发送数据,测试数据是否可以正常插入数据库。

    在这里插入图片描述
    可以看到在数据发送成功后,NODE-RED右侧的调试窗口打印出了相关信息,这些就是NODE-RED接收到云平台转发的数据。

    在这里插入图片描述
    这时候,可以看到debug3正确打印了SQL语句,查看MYSQL数据库,发现数据已成功存储。

    在这里插入图片描述
    在function函数内不知该如何写数据路径时,可以使用debug得到,比如需要value的路径,方式如下图所示。

    复制得到的结果为payload.items[“1_CurrentVoltage”].value,然后在payload前加上msg.即可。gauge节点中还有相关图片描述!

    在这里插入图片描述
    在这里插入图片描述

  • switch节点

    switch节点在左侧节点栏的功能中,作用类似于c语言当中的switch-case,配置方法就是在属性处输入想要判断的变量,在下方输入具体的值即可。

      ![在这里插入图片描述](https://img-blog.csdnimg.cn/bcf2a6f2416a41b3b379fdeac429313b.png#pic_center)
    

    每增加一个项switch节点后都会多出一个数据输出口,将光标放在上面可以看到该输出口具体信息。

    在这里插入图片描述

  • gauge节点

    gauge节点在左侧节点栏的dashboard中,部署后可以在ui界面显示一个表盘,将想要展示的数据以表盘形式展示
    同样的,路径在右侧复制后前面加上msg.,粘贴至Value format处并在两端加上两个大括号(如下图)。
    Units处输入想要的单位即可。
    Label即为该表盘的名称。
    Group点击旁边的编辑按钮,NameTab自定义即可。

    在这里插入图片描述
    配置完成后点击部署,在浏览器中新建一个标签页,在网址栏中输入ip:1880/ui即可访问NODE-RED的ui界面,设备1的数据为刚刚上传的电压数据。

    在这里插入图片描述

4.页面布局

​页面的自动布局默认为“Z”字型布局,当横着放不下两个表的时候,会自动移动至下行的行首。
如果不想让其自动布局,可以点击这个layout进行布局

在这里插入图片描述
Width处可以更改页面宽度,将gauge上锁后表盘的位置可以自行拖动调节,布局成自己想要的效果。

在这里插入图片描述
Theme中也可以对页面风格进行调节,将页面调成自己想要的风格。

在这里插入图片描述


六.源码(转载请注明出处)

在这里插入图片描述


结语

经测试,MP157串口在接收到正确数据后,将数据上传实现云存储,并且用户可以在界面查看多个设备的实时数据;串口接收到错误数据时也会给予相应提示并且本次数据将不会上传。

至此,云数据库存储多设备数据&界面显示已成功实现。

以上就是全部内容,如有错误请批评指正。

猜你喜欢

转载自blog.csdn.net/Octopus1633/article/details/126670608
今日推荐