端点物联开发教程之(二)开发演示

2024-06-13 15:52

本文主要是介绍端点物联开发教程之(二)开发演示,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、产品定义

二、基础资源下载

三、嵌入式端开发

3.1 工程搭建

3.2 模型文件修改

3.3 头文件定义

3.4 模型功能开发

3.5 mqtt应用层配置

3.6启动任务

四、用户后端开发

4.1 功能分析

4.2 创建模型文件

4.3 添加基础功能

4.4 数据更新

4.5 阈值设置

4.6 模型添加

五、用户前端开发

5.1 界面分析

5.2 简易模型

5.3 完整模型

六、模型联调


本项目的交流QQ群:701889554

物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html

物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html

物联网实战--平台篇https://blog.csdn.net/ypp240124016/category_12653350.html

资源文件下载https://download.csdn.net/download/ypp240124016/89425313

一、产品定义

        这是开发的第一步,首先要明确开发内容和目标。作为演示项目,我们定义为一个温湿度计,它的功能较为简单,就是定时上报温湿度数据,同时用户可以设置高温和高湿报警阈值,当温度或湿度超过阈值时候用户端界面会变成红色。

        那么,有上述定义可知,主要变量就是温度、湿度和两个各自的阈值,还有各自的报警状态,以下是字段定义表格:

        表格最后一列中的N是转正基数,避免在传输时出现负数;M是精度值,如果精度是小数点后一位那么M就等于10,后两位M就等于100,以此类推。这样做的好处在之前的净化器文章中有说过了,核心目的是为了保证传输的数据类型都是正整数,便于字节流传输时分解与整合,因为长度大于1字节的数据在网络传输中会出现网络序大小端的问题,不同的CPU架构大小端是不一样的,具体可以看下这篇文章。所以我们在设计传输协议的时候要规避这个问题,把所有的数值都转成正整数,然后统一高位先传输的原则转成字节流,这样就不存在大小端的问题了。

        有了具体字段之后就可以定义命令类型了,具体看下面表格:

        有了以上这些定义,我们就可以进行设备端的开发了。

二、基础资源下载

资源文件下载https://download.csdn.net/download/ypp240124016/89425313

        上图是资源结构图,我们现在要使用的是嵌入式端源码这个压缩包,把它解压出来就可以进行下一步的开发了。

三、嵌入式端开发
3.1 工程搭建

解压后目录如下:

点开Project文件夹,内容如下图所示,我们复制 Project-净化器(M2M) 整个文件夹在同目录下粘贴。

然后将副本改名为 演示温湿度计。

接着把下图这几个名字都改下就可以打开工作空间了,

最后打开目录里的工作空间,此时还没有温湿度计的项目,需要添加进来,顺序如下所示。同时把项目名称也改下,这样就完成了新项目的基础搭建了。

3.2 模型文件修改

        接下里就可以进入正式的开发了,首先删除app_ap01.c文件,这是原来净化器项目的文件,我们这里需要根据型号重新定义一个文件,型号就定义为TH01,所以新文件就是app_th01.c了,修改后的文件结构如下图所示,Keil的文件编辑格式最好改成UTF-8的,便于汉字注释。

        下图的两个头文件名称也改下,这样就可以编译了,编译后原来工程的相关内容会报错,删除或者注释掉就行,再编译一次,应该就能编译通过了,一个具体的工程模板就完成了,剩下的是具体产品内容定义了。

        

3.3 头文件定义

        模型文件从app_th01.h开始,根据第一节的产品定义,头文件定义如下:

        其中的温湿度报警阈值需要掉电保存,所以定义了一个存储结构体,为了确保数据的准确性,读取时候采用CRC校验,如果校验出错就使用默认的阈值。

3.4 模型功能开发

        首先进行配置参数读取,这里就是温湿度的报警阈值了。如果是第一次读取或者存储出错,那么就是用默认阈值,默认报警温度是50℃,默认报警湿度是95%。

        传感器部分只有温湿度了,这里沿用净化器项目的配置,接线是SDA--PB8,SCL--PB9。

        剩下的就是数据传输的内容了,根据定义,数据上行有状态数据和阈值数据,具体代码如下,其中状态数据发送前对报警状态做了判别,数据流根据定义里的N M值做了转换,发送时命令值也是根据头文件的定义传入。

        下行数据有三种类型,其中阈值数据并不需要实时发送,只有当用户端需要查看时再立刻发送即可,所以在用户端的物模型前端里设置请求指令进行请求一次即可,这样可以减少无效数据传输。这种需求在传统的物联网开发中比较难以实现,倒不是技术上有什么难度,而是沟通成本太高,正常嵌入式开发人员很难直接跟前端人员进行需求沟通的;那么,对于我们端到端的开发模式,这个需求可以内部自行消化。

        阈值设置就是赋值+保存了,没什么特别的;最后再即时返回当前阈值即可。

        最后就是将整个任务运行起来就行了。

        模型app_th01.c的所有C代码如下:


#include "app_th01.h" 
#include "app_mqtt.h" Th01SaveStruct g_sTh01Save={0};
Th01WorkStruct g_sTh01Work={0};/*		
================================================================================
描述 : 配置参数读取
输入 : 
输出 : 
================================================================================
*/
void app_th01_read(void) 
{EEPROM_Read(TH01_EEPROM_ADDR, (u8 *)&g_sTh01Save, sizeof(g_sTh01Save));if(g_sTh01Save.crcValue!=drv_crc16((u8*)&g_sTh01Save, sizeof(g_sTh01Save)-2)){g_sTh01Save.temp_thresh=1500;//高于50℃报警g_sTh01Save.humi_thresh=950;//高于95%报警app_th01_write();printf("app th01 read new!\n");}  printf("alarm temp=%.1fC, humi=%.1f%%\n", (g_sTh01Save.temp_thresh-1000)/10.f, g_sTh01Save.humi_thresh/10.f);
}/*		
================================================================================
描述 : 配置参数保存
输入 : 
输出 : 
================================================================================
*/
void app_th01_write(void)
{g_sTh01Save.crcValue=drv_crc16((u8*)&g_sTh01Save, sizeof(g_sTh01Save)-2);EEPROM_Write(TH01_EEPROM_ADDR, (u8 *)&g_sTh01Save, sizeof(g_sTh01Save));  
}/*		
================================================================================
描述 : SHT30温湿度初始化
输入 : 
输出 : 
================================================================================
*/
void app_sht30_init(void)
{//SDA--PB8   SCL--PB9RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//开启引脚时钟I2cDriverStruct *pIIC=&g_sTh01Work.tag_sht30.tag_iic;//引脚赋值pIIC->pin_sda=GPIO_Pin_8;pIIC->port_sda=GPIOB;pIIC->pin_scl=GPIO_Pin_9;pIIC->port_scl=GPIOB;  drv_sht30_init(&g_sTh01Work.tag_sht30);//初始化
}/*		
================================================================================
描述 : 整体初始化
输入 : 
输出 : 
================================================================================
*/
void app_th01_init(void)
{app_th01_read();//参数读取app_mqtt_init();  //mqtt应用层配置初始化app_sht30_init(); //温湿度传感器初始化
} /*		
================================================================================
描述 : 发送设备的状态数据
输入 : 
输出 : 
================================================================================
*/
void app_th01_send_status(void)
{u8 cmd_buff[20]={0};u16 cmd_len=0;u16 tmp_u16=0;tmp_u16=g_sTh01Work.tag_sht30.temp_value*10+1000;u8 temp_alarm=tmp_u16>=g_sTh01Save.temp_thresh;//报警检测cmd_buff[cmd_len++]=tmp_u16>>8;cmd_buff[cmd_len++]=tmp_u16;  //温度tmp_u16=g_sTh01Work.tag_sht30.humi_value*10;u8 humi_alarm=tmp_u16>=g_sTh01Save.humi_thresh;//报警检测cmd_buff[cmd_len++]=tmp_u16>>8;cmd_buff[cmd_len++]=tmp_u16;  //湿度g_sTh01Work.alarm_type=temp_alarm<<4 | humi_alarm;cmd_buff[cmd_len++]=g_sTh01Work.alarm_type;//报警类型  drv_server_send_msg(TH01_CMD_DATA, cmd_buff, cmd_len);//底层发送  
}/*		
================================================================================
描述 : 发送阈值数据
输入 : 
输出 : 
================================================================================
*/
void app_th01_send_thresh(void)
{u8 cmd_buff[20]={0};u16 cmd_len=0;u16 tmp_u16=0;tmp_u16=g_sTh01Save.temp_thresh;cmd_buff[cmd_len++]=tmp_u16>>8;cmd_buff[cmd_len++]=tmp_u16;  //温度阈值tmp_u16=g_sTh01Save.humi_thresh;cmd_buff[cmd_len++]=tmp_u16>>8;cmd_buff[cmd_len++]=tmp_u16;  //湿度阈值drv_server_send_msg(TH01_CMD_THRESH, cmd_buff, cmd_len); //底层发送    
}/*		
================================================================================
描述 : 设备解析服务器下发的数据
输入 : 
输出 : 
================================================================================
*/
u16 app_th01_recv_parse(u8 cmd_type, u8 *buff, u16 len)
{u8 *pData=buff;switch(cmd_type){case TH01_CMD_THRESH://请求阈值数据{app_th01_send_thresh();//返回阈值数值break;}case TH01_CMD_SET_TEMP://设置温度阈值{u16 temp_thresh=pData[0]<<8|pData[1];pData+=2;g_sTh01Save.temp_thresh=temp_thresh;app_th01_write();//保存app_th01_send_thresh();//返回阈值数值break;}        case TH01_CMD_SET_HUMI://设置湿度阈值{u16 humi_thresh=pData[0]<<8|pData[1];pData+=2;g_sTh01Save.humi_thresh=humi_thresh;app_th01_write();//保存app_th01_send_thresh();//返回阈值数值break;}   }return 0;
}/*		
================================================================================
描述 : 温湿度计总任务线程
输入 : 
输出 : 
================================================================================
*/
void app_th01_thread_entry(void *parameter) 
{u16 run_cnts=0;printf("app_th01_thread_entry start ****\n");delay_os(1000);app_th01_init();//初始化while(1){app_mqtt_main(); //MQTT主程序delay_os(20);//延时,每个任务线程都要添加,才不会阻塞,最小延时5ms, 即delay_os(5);if(run_cnts%200==0)//20*200=4000ms 执行一次{drv_sht30_read_th(&g_sTh01Work.tag_sht30);//读取温湿度值app_th01_send_status();//上报状态数据}run_cnts++;}}
3.5 mqtt应用层配置

        根据自己的应用需求,需要对app_mqtt.c的内容做配置修改,首先是测试的SN码要根据定义的设备型号进行设置,我们这里定义的型号值是A108,测试的SN是A1080123。

        其它要修改的就是模型的命令解析函数,通过函数接口注册即可。至于通讯密码,暂时跟之前的一样就行了,自己也可以随机生成,只要到时候跟QT的C++后端有对应就行了。

3.6启动任务

        最后,就是在user_app.c中启动任务就行了,至此,嵌入式端的开发就基本完成,剩下的就是等用户端的物模型完成后进行联调即可。

四、用户后端开发
4.1 功能分析

        下图是参考界面,我们只要在这个界面的基础上再加一个阈值设置即可。所以主要功能就是解析温湿度数据并发送到前端显示,同时根据报警类型设置提示文字和改变颜色;最后就是温湿度的阈值设置功能。

4.2 创建模型文件

        首先创建C++模型文件ModelTh01,该类继承于BaseModel类,

        

4.3 添加基础功能

        首先定义跟嵌入式端一样的命令类型,这个务必保持一致,命令值有修改需要两端同时修改;然后是基本的模型显示、隐藏函数和数据接口函数,这些接口都是通用的,不过不同的物模型需要自定义,具体如下图所示,都有注释。

        这些函数的具体代码如下,有些还不完善:

#include "ModelTh01.h"ModelTh01::ModelTh01(QObject *parent) : BaseModel(parent)
{m_secTickets=0;checkTimer = new QTimer(this);checkTimer->setInterval(1*1000);//心跳检测checkTimer->start(); connect(checkTimer, SIGNAL(timeout()),this,SLOT(slotCheckTimeout()));
}void ModelTh01::slotCheckTimeout(void)
{m_secTickets++;if(m_onlineState>0)//离线检测{if(m_secTickets - m_onlineTime>40){m_onlineState=DEV_STATE_OFF_LINE;       }else{m_onlineState=DEV_STATE_ON_LINE;}
//            emit siqUpdateOnlineState(m_onlineState);   }}QByteArray ModelTh01::takeModelPassword(u8 index)
{static u8 passwd_table[5][16]={0x9D, 0x53, 0x09, 0xBF, 0x75, 0x28, 0xDE, 0x94, 0x4A, 0xFD, 0xB3, 0x69, 0x1F, 0xD2, 0x88, 0x3E, 0xF4, 0xAA, 0x5D, 0x13, 0xC9, 0x7F, 0x31, 0xE7, 0x9D, 0x53, 0x06, 0xBC, 0x72, 0x28, 0xDB, 0x91,0x47, 0xFD, 0xB3, 0x66, 0x1C, 0xD2, 0x88, 0x3B, 0xF1, 0xB5, 0x75, 0x39, 0xFA, 0xBE, 0x7E, 0x42,0x03, 0xC7, 0x88, 0x4B, 0x0C, 0xD0, 0x91, 0x54, 0x15, 0xD9, 0x9A, 0x5E, 0x21, 0xE2, 0xA6, 0x67, 0x2A, 0xEB, 0xAF, 0x70, 0x34, 0xF4, 0xB8, 0x79, 0x3D, 0xFD, 0xC1, 0x82, 0x46, 0x06, 0xCA, 0x8B, };if(index>=5)index=0;QByteArray ba;ba.setRawData((char*)&passwd_table[index][0], 16);return ba;}void ModelTh01::showModel(QObject *parent)
{hideModel();m_modelParent=parent; if(m_modelEngine==nullptr){m_modelEngine=new QQmlApplicationEngine(this);m_modelEngine->rootContext()->setContextProperty("theModelTh01", this);m_modelEngine->rootContext()->setContextProperty("theCenterMan", this->parent());}m_modelEngine->load("qrc:/qmlRC/modelQml/TH01/ModelTh01.qml");
}void ModelTh01::hideModel(void)
{if(m_modelEngine)delete m_modelEngine;m_modelEngine=nullptr;m_modelParent=nullptr;
}void ModelTh01::showSimple(QObject *parent)
{m_simpleParent=parent; if(m_simpleEngine==nullptr){m_simpleEngine=new QQmlApplicationEngine(this);m_simpleEngine->rootContext()->setContextProperty("theModelTh01", this);m_simpleEngine->rootContext()->setContextProperty("theCenterMan", this->parent());}m_simpleEngine->load("qrc:/qmlRC/modelQml/TH01/SimpleTh01.qml");
}void ModelTh01::hideSimple(void)
{if(m_simpleEngine)delete m_simpleEngine;m_simpleEngine=nullptr;m_simpleParent=nullptr;
}int ModelTh01::setRawData(u32 app_id, u32 dev_sn, u8 pack_num, u8 msg_type, u8 *msg_buff, u16 msg_len)
{if(dev_sn!=m_devSn)return 0;u8 *pData=msg_buff;msg_len=msg_len;if(m_upPackNum==pack_num)return 0;m_upPackNum=pack_num;m_appID=app_id;
//    qDebug()<<"msg_type="<<msg_type;switch(msg_type){case TH01_CMD_DATA://状态数据{break;}case TH01_CMD_THRESH://阈值数据{break;}}QDateTime current_date_time = QDateTime::currentDateTime();m_updateTime=current_date_time.toString("hh:mm:ss");m_onlineTime=m_secTickets;m_onlineState=DEV_STATE_ON_LINE;return 0;
}
4.4 数据更新

        现在,我们需要对温湿度本身的功能进行完善,首先是定义信号函数,把状态数据发送到前端显示,内容有温度值、温度报警状态,湿度值、湿度报警状态;另一方面,还有温度阈值和湿度阈值,所以在此定义了两个信号函数:

        这两个函数是在数据解析函数里调用的,数据解析跟嵌入式端的数据组合正好是相反的过程,具体看下面的代码;同时,我们对设备的在线状态进行了更新。


int ModelTh01::setRawData(u32 app_id, u32 dev_sn, u8 pack_num, u8 msg_type, u8 *msg_buff, u16 msg_len)
{if(dev_sn!=m_devSn)return 0;u8 *pData=msg_buff;msg_len=msg_len;if(m_upPackNum==pack_num)return 0;m_upPackNum=pack_num;m_appID=app_id;
//    qDebug()<<"msg_type="<<msg_type;switch(msg_type){case TH01_CMD_DATA://状态数据{int temp=pData[0]<<8|pData[1];//温度 原始数据float temp_f=(temp-1000)/10.f;//温度浮点数据pData+=2;int humi=pData[0]<<8|pData[1];float humi_f=humi/10.f;pData+=2;u8 alarm_type=pData[0];pData+=1;QString temp_str=QString::asprintf("%.1f", temp_f);QString humi_str=QString::asprintf("%.1f", humi_f);emit siqUpdateSensorValues(temp_str, humi_str, alarm_type>>4, alarm_type&0x0F);break;}case TH01_CMD_THRESH://阈值数据{int temp=pData[0]<<8|pData[1];//温度 原始数据float temp_f=(temp-1000)/10.f;//温度浮点数据pData+=2;int humi=pData[0]<<8|pData[1];float humi_f=humi/10.f;pData+=2;QString temp_str=QString::asprintf("%.1f", temp_f);QString humi_str=QString::asprintf("%.1f", humi_f);emit siqUpdateThresh(temp_str, humi_str);break;}}QDateTime current_date_time = QDateTime::currentDateTime();m_updateTime=current_date_time.toString("hh:mm:ss");m_onlineTime=m_secTickets;m_onlineState=DEV_STATE_ON_LINE;return 0;
}
4.5 阈值设置

        阈值设置需要提供函数接口给前端调用,根据QML的特性,C++端的函数加上Q_INVOKABLE关键字后就可以暴露给前端QML了,传入参数一般是字符串,具体内容让C++方面来判断比较方便,最后把结果返回显示就行。对于阈值设置,根据文档定义组合数据,具体的以下两个函数就解决了。


QString ModelTh01::setTempThresh(QString temp_str)
{float temp_f=temp_str.toFloat();if(temp_f<0.f || temp_f>120.f){return QString("输入范围有误!");}u16 temp_u16=temp_f*10+1000;u8 make_buff[100]={0};u16 make_len=0;make_buff[make_len++]=temp_u16>>8;make_buff[make_len++]=temp_u16;emit sigSendDownMsg(m_appID, m_devSn, m_downPackNum++, TH01_CMD_SET_TEMP, make_buff, make_len);return "";
}QString ModelTh01::setHumiThresh(QString humi_str)
{float humi_f=humi_str.toFloat();if(humi_f<20.f || humi_f>100.f){return QString("输入范围有误!");}u16 humi_u16=humi_f*10;u8 make_buff[100]={0};u16 make_len=0;make_buff[make_len++]=humi_u16>>8;make_buff[make_len++]=humi_u16;emit sigSendDownMsg(m_appID, m_devSn, m_downPackNum++, TH01_CMD_SET_HUMI, make_buff, make_len);return "";
}

        这样,物模型的C++后端就完成了,整体看来,跟C++也没多大关系,所以只要有点C语言的基础,开发物模型很容易就上手了。

4.6 模型添加

        基本模型开发完成后可以添加到主程序内,这样便于后续前端的调试开发,根据下面图片步骤在CenterMan类中操作即可。


      密码添加

五、用户前端开发
5.1 界面分析

        再次看下这个界面,主要就是一个渐变色背景+数值显示,温湿度有各自的状态提示;最后就是在合适的位置加入阈值设置的功能。

5.2 简易模型

        先搞定网格内的简易模型,对于温湿度计较为简单,就是图片替换,底部温湿度值显示即可。那么,我们要先准备好图片和创建简易模型文件,简易模型继承于BaseSimpleView,这个文件已经有了基本布局,只要修改内容即可。添加或者删除QML文件后需要鼠标右键项目工程,点击  执行qmake 才能正确编译。

        然后再加入一些模型自身的内容,即温湿度显示,主要就是接收来自后端的更新数据了,在温湿度显示那里,我们对报警状态用红色字体显示。

有了这个基本模型,就可以添加看看效果了。在主页的右上角 手动添加即可,SN要输入正确,具体效果如下,照片可以选择自己喜欢的。

        

5.3 完整模型

        完整模型也需要再建立文件,该文件继承于BaseModelView,文件主要是对颜色进行了配置,整体效果如下。

        然后就是数据显示模块了,由于温湿度显示结构基本一致,主要是内容差异,所以显示单元可以做成一个组件模块,然后在主页面里配置即可。该模块的效果和代码如下:

import QtQuick 2.7
import "../base"//数据显示单元
Item {signal siqThreshClicked()property var headText: "温度 | 正常"property var valueText: "26.3"property var valueColor: "white"property var unionText: "℃"property var threshText: "50.0"implicitWidth: 300implicitHeight: 200Text{id:id_headText //头部标题height: 40width: 160anchors{horizontalCenter:parent.horizontalCentertop:parent.top}text: headTextfont.pointSize: 18font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"color: "white"verticalAlignment: Text.AlignVCenterhorizontalAlignment: Text.AlignHCenter}Text{id:id_valueText //数值height: 100width: 150anchors{horizontalCenter:parent.horizontalCentertop:id_headText.bottomtopMargin:10}text: valueTextfont.pointSize: 50font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"color: valueColorverticalAlignment: Text.AlignVCenterhorizontalAlignment: Text.AlignHCenter}Text{id:id_unionText //单位height: 40width: 60anchors{right:id_headText.righttop:id_valueText.top}text: unionTextfont.pointSize: 15font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"color: "white"verticalAlignment: Text.AlignVCenterhorizontalAlignment: Text.AlignRight}Text{id:id_threshText //阈值height: 40width: 40anchors{horizontalCenter:id_valueText.horizontalCentertop:id_valueText.bottom}text: threshTextfont.pointSize: 15font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"font.bold: id_mouseArea.pressedcolor: "white"verticalAlignment: Text.AlignVCenterhorizontalAlignment: Text.AlignRightMouseArea{id:id_mouseAreaanchors.fill: parentonClicked: {siqThreshClicked()}}}Text{id:id_union2Text //单位height: 40width: 60anchors{left:id_threshText.rightverticalCenter:id_threshText.verticalCenter}text: unionTextfont.pointSize: 15font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"color: "white"verticalAlignment: Text.AlignVCenterhorizontalAlignment: Text.AlignLeft}}

        底部比较小的数值即阈值,点击文本就会弹出设置对话框。这里的对话框与主程序的对话框类似,因为物模型的qml和主程序的qml是隔离的,所以主程序的基础文件可以根据需要迁移到物模型这边过来。

        那么,对于阈值对话框就可以从BaseEditDialog这边继承过来了。

        在完整模型文件内,对模块参数进行配置,定义了温度模块和湿度模块,设置对话框根据打开类型进行温湿度设置的区分,具体如下:

        完整模型内,数据更新是通过后端发送过来的数据进行判断显示,具体如下:

        最后,在打开完整模型后,前端应该主动请求一下阈值数据,

        这样,整个物模型的开发基本完成了。

六、模型联调

        接下来就是整个物模型的联调了,首先设备端直接用代码配置一下app_id和dev_sn,然后注释再重新编译烧录,这样设备就变成有设备号的初始状态了。

        QT端重新执行qmake,然后编译运行,等设备差不多联网成功后,手动添加设备,SN为A1080123,添加成功后简易模型和完整模型的界面如下所示:

                     

        下面是演示视频:

温湿度计

        如果设置和颜色变化没问题,那这个模型基本上也就成了。

        总体来讲,整个物模型的开发和上线还是挺简单的,相比于用json描述物模型,直接代码操作灵活性会更好;在编写物模型的过程中,虽然用到了C语言和QT的C++、QML,但是后端内容跟C++关系并不大,照着其它已有模型做更改就行了,只要遵循一些C++的代码格式即可;而QML类似于js语言,js语言与C语言本质上属于同一语系,语法上很相似,只要多做几个界面,QML很容易就上手了。

        所以,端点物联的开发套件很适合嵌入式端的开发人员做一些自己的创意产品,有C语言基础之后,对照着其它模型、按自己的想法更改,就能快速开发、上线一款自己的物联网产品。相比于米家、涂鸦、阿里云这些大平台,流程和难度降低了很多,很适合个人开发者。

本节的嵌入式工程:https://download.csdn.net/download/ypp240124016/89428338

本节的QT工程:https://download.csdn.net/download/ypp240124016/89428344

这篇关于端点物联开发教程之(二)开发演示的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1057745

相关文章

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

Python应用开发——30天学习Streamlit Python包进行APP的构建(9)

st.area_chart 显示区域图。 这是围绕 st.altair_chart 的语法糖。主要区别在于该命令使用数据自身的列和指数来计算图表的 Altair 规格。因此,在许多 "只需绘制此图 "的情况下,该命令更易于使用,但可定制性较差。 如果 st.area_chart 无法正确猜测数据规格,请尝试使用 st.altair_chart 指定所需的图表。 Function signa

Steam邮件推送内容有哪些?配置教程详解!

Steam邮件推送功能是否安全?如何个性化邮件推送内容? Steam作为全球最大的数字游戏分发平台之一,不仅提供了海量的游戏资源,还通过邮件推送为用户提供最新的游戏信息、促销活动和个性化推荐。AokSend将详细介绍Steam邮件推送的主要内容。 Steam邮件推送:促销优惠 每当平台举办大型促销活动,如夏季促销、冬季促销、黑色星期五等,用户都会收到邮件通知。这些邮件详细列出了打折游戏、

X-AnyLabeling使用教程

1.AI 模型自动分割标注使用教程 2.AI 模型自动目标检测标注使用教程

WDF驱动开发-WDF总线枚举(一)

支持在总线驱动程序中进行 PnP 和电源管理 某些设备永久插入系统,而其他设备可以在系统运行时插入和拔出电源。 总线驱动 必须识别并报告连接到其总线的设备,并且他们必须发现并报告系统中设备的到达和离开情况。 总线驱动程序标识和报告的设备称为总线的 子设备。 标识和报告子设备的过程称为 总线枚举。 在总线枚举期间,总线驱动程序会为其子 设备创建设备对象 。  总线驱动程序本质上是同时处理总线枚

青龙面板2.9之Cdle傻妞机器人编译教程

看到有的朋友对傻妞机器人感兴趣,这里写一下傻妞机器人的编译教程。 第一步,这里以linux amd64为例,去官网下载安装go语言安装包: 第二步,输入下方指令 cd /usr/local && wget https://golang.google.cn/dl/go1.16.7.linux-amd64.tar.gz -O go1.16.7.linux-amd64.tar.gz

青龙面板部署通用教程,含服务器、路由器、X86等部署方法

1. 拉取镜像/更新镜像 docker pull whyour/qinglong:latest 2. 删除镜像 docker rmi whyour/qinglong:latest 3. 启动容器 普通服务器 docker run -dit \-v $PWD/ql/config:/ql/config \-v $PWD/ql/log:/ql/log \-v $PWD/ql/db:

宝塔面板部署青龙面板教程【简单易上手】

首先,你得有一台部署了宝塔面板的服务器(自己用本地电脑也可以)。 宝塔面板部署自行百度一下,很简单,这里就不走流程了,官网版本就可以,无需开心版。 首先,打开宝塔面板的软件商店,找到下图这个软件(Docker管理器)安装,青龙面板还是安装在docker里,这里依赖宝塔面板安装和管理docker。 安装完成后,进入SSH终端管理,输入代码安装青龙面板。ssh可以直接宝塔里操作,也可以安装ssh连接

PS系统教程25

介绍软件 BR(bridge) PS 配套软件,方便素材整理、管理素材 作用:起到桥梁作用 注意:PS和BR尽量保持版本一致 下载和安装可通过CSDN社区搜索,有免费安装指导。 安装之后,我们打开照片只需双击照片,就自动在Ps软件中打开。 前提:电脑上有PS软件 三种预览格式 全屏预览 评星级 直接按数字键就可以 方向键可以更换图片 esc退出 幻灯片放

JavaWeb系列六: 动态WEB开发核心(Servlet) 上

韩老师学生 官网文档为什么会出现Servlet什么是ServletServlet在JavaWeb项目位置Servlet基本使用Servlet开发方式说明快速入门- 手动开发 servlet浏览器请求Servlet UML分析Servlet生命周期GET和POST请求分发处理通过继承HttpServlet开发ServletIDEA配置ServletServlet注意事项和细节 Servlet注