• [常见问题汇总帖] 无法生成vmlinux.h
    租了一个HECS(云耀云服务器)。版本下图所示。CONFIG_DEBUG_INFO_BTF状态开启。这是bpftool的版本也存在vmlinux文件这是我内核源码文件的截图。但是生成vmlinux.h时总会报错。
  • [问题求助] 基于openHarmony的智能可穿戴户外定位系统
    开发基于openHarmony的智能可穿戴户外定位系统,应该去哪里查看要购买的相应设备
  • [技术干货] 基于STM32+华为云IOT设计的智能垃圾桶
    一、项目介绍在商业街、小吃街和景区等人流密集的场所,垃圾桶的及时清理对于提供良好的游客体验至关重要。然而,传统的垃圾桶清理方式通常是定时或定期进行,无法根据实际情况进行及时响应,导致垃圾桶溢满,影响环境卫生,给游客带来不便和不满。为了解决这一问题,本项目基于STM32F103ZET6主控芯片和华为云物联网平台,设计了一套智能垃圾桶管理系统。该系统通过NBIOT-BC26模块连接到华为云物联网平台,实现了垃圾桶数据的实时采集和上传。在本地,垃圾桶通过多种传感器进行数据采集。使用DHT11模块实时监测环境温度和湿度,以了解垃圾桶所处环境的状态。采用中科微电子出品的GPS模块,通过串口输出GPS数据,实现垃圾桶的定位功能。垃圾桶口还配备了红外传感器,用于检测垃圾桶是否已满。通过NBIOT-BC26模块,采集到的数据被实时上传到华为云物联网平台。在保洁人员管理中心,开发了一个数据大屏,采用Qt开发,运行在Windows系统下。数据大屏展示了该区域内垃圾桶的详细情况,包括环境温度、湿度、GPS定位和垃圾桶的满溢状态。当垃圾桶满了时,上位机会实时发送短信通知保洁人员进行清理,并提供垃圾桶的位置信息,以便保洁人员快速响应并进行清理操作。通过这套智能垃圾桶管理系统,垃圾桶的清理可以根据实际情况进行及时调度,提高了垃圾桶的使用效率,改善了环境卫生状况,提升了游客的体验感。同时,保洁人员能够更加高效地管理垃圾桶,提升工作效率,减少资源浪费。整个系统的设计旨在提供一个智能、高效的垃圾桶管理解决方案,为公共场所的环境卫生管理带来便利和改进。二、设计思路总结2.1 硬件选型【1】主控芯片:STM32F103ZET6STM32F103系列是意法半导体(STMicroelectronics)推出的低功耗、高性能的32位ARM Cortex-M3微控制器系列。选择STM32F103ZET6作为主控芯片,是因为它具有较高的计算能力和丰富的外设接口,能够满足项目的需求。【2】通信模块:NBIOT-BC26NBIOT-BC26是一种窄带物联网(NB-IoT)通信模块,支持低功耗、广覆盖、远距离的物联网通信。它能够将垃圾桶采集到的数据通过NB-IoT网络上传到云平台,实现实时监测和远程管理。【3】传感器模块:DHT11模块:用于采集环境温度和湿度数据。DHT11是一种低成本、数字式温湿度传感器,具有简单的接口和良好的性能,适用于本项目的温湿度监测需求。GPS模块:用于实现垃圾桶的定位功能。选择中科微电子出品的GPS模块,通过串口输出GPS数据,能够准确获取垃圾桶的位置信息。红外传感器:用于检测垃圾桶是否已满。红外传感器能够通过红外线的反射来判断垃圾桶内是否有垃圾,从而判断垃圾桶的满溢状态。【5】数据大屏:采用Qt开发,运行在Windows系统下。数据大屏通过图形界面展示垃圾桶的详细情况,包括环境温度、湿度、GPS定位和垃圾桶的满溢状态。项目的硬件选型包括主控芯片、通信模块、传感器模块、红外传感器和数据大屏。这些硬件组件相互配合,实现了智能垃圾桶管理系统的功能,包括数据采集、通信传输、定位功能和信息展示。2.2 硬件设计【1】主控芯片选择: 作为整个系统的核心,选择了STM32F103ZET6作为主控芯片。该芯片具有较高的计算能力和丰富的外设接口,能够满足项目的需求。主控芯片负责与各个硬件模块进行通信和数据处理,同时控制通信模块的数据传输。【2】通信模块选择: 为了实现垃圾桶数据的实时采集和上传,选择了NBIOT-BC26通信模块。NBIOT-BC26支持窄带物联网通信,具有低功耗、广覆盖和远距离传输的特点,能够将采集到的数据通过NB-IoT网络上传到华为云物联网平台。【3】传感器模块选择:DHT11模块用于采集环境温度和湿度数据。DHT11是一种低成本、数字式温湿度传感器,通过数字信号输出温湿度数值,具有简单的接口和良好的性能,适用于本项目的温湿度监测需求。GPS模块用于实现垃圾桶的定位功能。选择中科微电子出品的GPS模块,通过串口输出GPS数据,能够准确获取垃圾桶的位置信息。红外传感器设计: 为了检测垃圾桶是否已满,采用红外传感器。红外传感器能够通过红外线的反射来判断垃圾桶内是否有垃圾,从而判断垃圾桶的满溢状态。红外传感器与主控芯片相连,通过数字输入口接收传感器的信号,并进行处理判断。【4】数据大屏设计: 数据大屏采用Qt开发,运行在Windows系统下。通过图形界面展示垃圾桶的详细情况,包括环境温度、湿度、GPS定位和垃圾桶的满溢状态。主控芯片通过与数据大屏的通信接口实时传输数据,数据大屏根据接收到的数据进行展示。整个硬件设计思路是将各个硬件模块与主控芯片相连接,通过主控芯片的控制和数据处理,实现数据的采集、通信传输、定位功能和信息展示。通过合理选择硬件组件,并进行适当的连接和接口设计,实现了智能垃圾桶管理系统的功能。2.3 软件设计【1】系统架构设计: 软件设计的第一步是确定系统的整体架构。根据项目需求,可以采用分层架构设计,将系统划分为应用层、业务逻辑层和驱动层。应用层负责与用户交互,业务逻辑层处理具体的业务逻辑,驱动层与硬件模块进行通信和控制。【2】硬件驱动设计: 针对每个硬件模块,需要编写相应的驱动程序。主控芯片与通信模块、传感器模块和红外传感器进行通信,通过串口、I2C、SPI等接口与它们进行数据交互。每个硬件模块的驱动程序应包括初始化、数据采集和控制等功能。【3】数据处理与逻辑控制: 主控芯片负责接收来自各个硬件模块的数据,并进行处理和逻辑控制。例如,从DHT11传感器读取温湿度数据后,可以进行数据的校验和转换,然后根据设定的阈值判断是否需要进行烘干操作。同时,主控芯片还负责控制红外传感器进行垃圾桶满溢状态的检测。【4】通信与数据上传: 通过NBIOT-BC26通信模块,将采集到的数据通过NB-IoT网络上传到华为云物联网平台。主控芯片与通信模块进行通信,将需要上传的数据打包成相应的格式,并通过串口等接口发送给通信模块,实现数据的上传。【5】用户界面设计: 软件还需要设计用户界面,以便用户可以直观地查看垃圾桶的状态和数据信息。可以使用Qt等工具进行界面设计,展示环境温度、湿度、GPS定位和垃圾桶的满溢状态等信息。用户界面与主控芯片进行通信,接收数据并进行展示。整个软件设计思路是基于系统架构设计,通过硬件驱动、数据处理与逻辑控制、通信与数据上传以及用户界面设计等模块的开发,实现智能垃圾桶管理系统的功能。软件设计需要与硬件设计相结合,保证数据的采集、处理、传输和展示的协调运作。2.4 系统交互流程【1】用户打开智能垃圾桶管理系统的应用程序。【2】系统初始化:系统进行硬件初始化,包括主控芯片、通信模块、传感器模块和红外传感器的初始化。确保通信模块连接到NB-IoT网络,并与华为云物联网平台建立通信连接。【3】环境监测:系统开始监测环境温度和湿度,并获取垃圾桶的定位信息。主控芯片通过DHT11传感器获取温湿度数据,通过GPS模块获取垃圾桶的位置信息。【4】数据处理与逻辑控制:主控芯片对采集到的数据进行处理和逻辑控制。可以根据温度和湿度数据判断垃圾桶是否需要进行清理,并通过红外传感器检测垃圾桶的满溢状态。【5】数据上传:主控芯片将处理后的数据通过通信模块上传到华为云物联网平台。数据可以包括环境温度、湿度、GPS定位和垃圾桶的满溢状态等信息。上传的数据可以以JSON等格式进行打包,通过NB-IoT网络传输到华为云物联网平台。【6】数据展示:用户界面接收从主控芯片传输过来的数据,并进行展示。用户可以在界面上查看环境温度、湿度、GPS定位和垃圾桶的满溢状态等信息。数据展示可以通过图表、文字、图像等形式进行呈现,以便用户直观地了解系统的状态和数据信息。整个系统的交互流程涉及到硬件模块的数据采集、主控芯片的数据处理与逻辑控制、通信模块的数据上传以及用户界面的数据展示和用户交互。通过这些步骤,用户可以方便地监测和管理智能垃圾桶的状态和数据信息。三、部署华为云物联网平台华为云官网: cid:link_12打开官网,搜索物联网,就能快速找到 设备接入IoTDA。3.1 物联网平台介绍华为云物联网平台(IoT 设备接入云服务)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助我们快速构筑物联网解决方案。使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi等多种网络接入物联网平台,并使用LWM2M/CoAP、MQTT、HTTPS协议将业务数据上报到平台,平台也可以将控制命令下发给设备。业务应用通过调用物联网平台提供的API,实现设备数据采集、命令下发、设备管理等业务场景。3.2 开通物联网服务地址: cid:link_10进来默认会提示开通标准版,在2023的1月1号年之后没有基础版了。开通之后,点击总览,查看接入信息。 我们当前设备准备采用MQTT协议接入华为云平台,这里可以看到MQTT协议的地址和端口号等信息。总结:端口号: MQTT (1883)| MQTTS (8883) 接入地址: 7445c6bcd3.st1.iotda-app.cn-north-4.myhuaweicloud.com根据域名地址得到IP地址信息:Microsoft Windows [版本 10.0.19044.2728](c) Microsoft Corporation。保留所有权利。​C:\Users\11266>ping 7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com​正在 Ping 7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com [117.78.5.125] 具有 32 字节的数据:来自 117.78.5.125 的回复: 字节=32 时间=42ms TTL=30来自 117.78.5.125 的回复: 字节=32 时间=35ms TTL=30来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=30来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=30​117.78.5.125 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),往返行程的估计时间(以毫秒为单位): 最短 = 35ms,最长 = 42ms,平均 = 37ms​C:\Users\11266>MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口比较合适。 接下来的ESP8266就采用1883端口连接华为云物联网平台。3.3 创建产品(1)创建产品点击产品页,再点击左上角创建产品。(2)填写产品信息根据自己产品名字填写。(3)产品创建成功(4)添加自定义模型产品创建完成之后,点击进入产品详情页面,翻到最下面可以看到模型定义。先点击自定义模型。再创建一个服务ID。接着点击新增属性。3.4 添加设备产品是属于上层的抽象模型,接下来在产品模型下添加实际的设备。添加的设备最终需要与真实的设备关联在一起,完成数据交互。(1)注册设备(2)根据自己的设备填写(3)保存设备信息创建完毕之后,点击保存并关闭,得到创建的设备密匙信息。该信息在后续生成MQTT三元组的时候需要使用。(4) 设备创建完成3.5 MQTT协议主题订阅与发布(1)MQTT协议介绍当前的设备是采用MQTT协议与华为云平台进行通信。MQTT是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。MQTT是专门针对物联网开发的轻量级传输协议。MQTT协议针对低带宽网络,低计算能力的设备,做了特殊的优化,使得其能适应各种物联网应用场景。目前MQTT拥有各种平台和设备上的客户端,已经形成了初步的生态系统。MQTT是一种消息队列协议,使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合,相对于其他协议,开发更简单;MQTT协议是工作在TCP/IP协议上;由TCP/IP协议提供稳定的网络连接;所以,只要具备TCP协议栈的网络设备都可以使用MQTT协议。 本次设备采用的ESP8266就具备TCP协议栈,能够建立TCP连接,所以,配合STM32代码里封装的MQTT协议,就可以与华为云平台完成通信。华为云的MQTT协议接入帮助文档在这里: cid:link_8业务流程:(2)华为云平台MQTT协议使用限制描述限制支持的MQTT协议版本3.1.1与标准MQTT协议的区别支持Qos 0和Qos 1支持Topic自定义不支持QoS2不支持will、retain msgMQTTS支持的安全等级采用TCP通道基础 + TLS协议(最高TLSv1.3版本)单帐号每秒最大MQTT连接请求数无限制单个设备每分钟支持的最大MQTT连接数1单个MQTT连接每秒的吞吐量,即带宽,包含直连设备和网关3KB/sMQTT单个发布消息最大长度,超过此大小的发布请求将被直接拒绝1MBMQTT连接心跳时间建议值心跳时间限定为30至1200秒,推荐设置为120秒产品是否支持自定义Topic支持消息发布与订阅设备只能对自己的Topic进行消息发布与订阅每个订阅请求的最大订阅数无限制(3)主题订阅格式帮助文档地址:cid:link_8对于设备而言,一般会订阅平台下发消息给设备 这个主题。设备想接收平台下发的消息,就需要订阅平台下发消息给设备 的主题,订阅后,平台下发消息给设备,设备就会收到消息。如果设备想要知道平台下发的消息,需要订阅上面图片里标注的主题。以当前设备为例,最终订阅主题的格式如下:$oc/devices/{device_id}/sys/messages/down​最终的格式:$oc/devices/6419627e40773741f9fbdac7_dev1/sys/messages/down(4)主题发布格式对于设备来说,主题发布表示向云平台上传数据,将最新的传感器数据,设备状态上传到云平台。这个操作称为:属性上报。帮助文档地址:cid:link_3根据帮助文档的介绍, 当前设备发布主题,上报属性的格式总结如下:发布的主题格式:$oc/devices/{device_id}/sys/properties/report 最终的格式:$oc/devices/6419627e40773741f9fbdac7_dev1/sys/properties/report发布主题时,需要上传数据,这个数据格式是JSON格式。​上传的JSON数据格式如下:​{ "services": [ { "service_id": <填服务ID>, "properties": { "<填属性名称1>": <填属性值>, "<填属性名称2>": <填属性值>, .......... } } ]}根据JSON格式,一次可以上传多个属性字段。 这个JSON格式里的,服务ID,属性字段名称,属性值类型,在前面创建产品的时候就已经介绍了,不记得可以翻到前面去查看。​根据这个格式,组合一次上传的属性数据:{"services": [{"service_id": "stm32","properties":{"DS18B20":18,"motor_water":1,"motor_oxygen":1,"temp_max":10,"water_hp":130,"motor_food":0,"time_food":0,"oxygen_food":3}}]}3.6 MQTT三元组MQTT协议登录需要填用户ID,设备ID,设备密码等信息,就像我们平时登录QQ,微信一样要输入账号密码才能登录。MQTT协议登录的这3个参数,一般称为MQTT三元组。接下来介绍,华为云平台的MQTT三元组参数如何得到。(1)MQTT服务器地址要登录MQTT服务器,首先记得先知道服务器的地址是多少,端口是多少。帮助文档地址:cid:link_2MQTT协议的端口支持1883和8883,它们的区别是:8883 是加密端口更加安全。但是单片机上使用比较困难,所以当前的设备是采用1883端口进连接的。根据上面的域名和端口号,得到下面的IP地址和端口号信息: 如果设备支持填写域名可以直接填域名,不支持就直接填写IP地址。 (IP地址就是域名解析得到的)华为云的MQTT服务器地址:114.116.232.138域名:7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com华为云的MQTT端口号:1883(2)生成MQTT三元组华为云提供了一个在线工具,用来生成MQTT鉴权三元组: cid:link_9打开这个工具,填入设备的信息(也就是刚才创建完设备之后保存的信息),点击生成,就可以得到MQTT的登录信息了。下面是打开的页面:填入设备的信息: (上面两行就是设备创建完成之后保存得到的)直接得到三元组信息。得到三元组之后,设备端通过MQTT协议登录鉴权的时候,填入参数即可。ClientId 6419627e40773741f9fbdac7_dev1_0_0_2023032108Username 6419627e40773741f9fbdac7_dev1Password 861ac9e6a579d36888b2aaf97714be7af6c77017b017162884592bd68b086a6e3.7 模拟设备登录测试经过上面的步骤介绍,已经创建了产品,设备,数据模型,得到MQTT登录信息。 接下来就用MQTT客户端软件模拟真实的设备来登录平台。测试与服务器通信是否正常。(1)填入登录信息打开MQTT客户端软件,对号填入相关信息(就是上面的文本介绍)。然后,点击登录,订阅主题,发布主题。(2)打开网页查看完成上面的操作之后,打开华为云网页后台,可以看到设备已经在线了。点击详情页面,可以看到上传的数据。到此,云平台的部署已经完成,设备已经可以正常上传数据了。四、上位机开发为了方便查看设备上传的数据,对设备进行远程控制,接下来利用Qt开发一款Android和windows系统的上位机。使用华为云平台提供的API接口获取设备上传的数据,也可以给设备下发指令,控制设备。为了方便查看设备上传的数据,对设备进行远程控制,接下来利用Qt开发一款Android和windows系统的上位机。使用华为云平台提供的API接口获取设备上传的数据,也可以给设备下发指令,控制设备。4.1 Qt开发环境安装Qt的中文官网: cid:link_13QT5.12.6的下载地址:cid:link_11打开下载链接后选择下面的版本进行下载:qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details软件安装时断网安装,否则会提示输入账户。安装的时候,第一个复选框里勾选一个mingw 32编译器即可,其他的不管默认就行,直接点击下一步继续安装。说明: 我这里只是介绍PC端的环境搭建(这个比较简单)。 Android的开发环境比较麻烦,可以去我的博客里看详细文章。选择MinGW 32-bit 编译器:4.2 创建IAM账户创建一个IAM账户,因为接下来开发上位机,需要使用云平台的API接口,这些接口都需要token进行鉴权。简单来说,就是身份的认证。 调用接口获取Token时,就需要填写IAM账号信息。所以,接下来演示一下过程。地址: cid:link_4获取Token时,除了AIM账号外,还需要项目凭证:faa0973835ab409ab48182e2590f4ad3鼠标点击自己昵称,点击统一身份认证。点击左上角创建用户。创建成功:4.3 获取影子数据帮助文档:cid:link_5设备影子介绍:设备影子是一个用于存储和检索设备当前状态信息的JSON文档。每个设备有且只有一个设备影子,由设备ID唯一标识设备影子仅保存最近一次设备的上报数据和预期数据无论该设备是否在线,都可以通过该影子获取和设置设备的属性简单来说:设备影子就是保存,设备最新上传的一次数据。我们设计的软件里,如果想要获取设备的最新状态信息,就采用设备影子接口。如果对接口不熟悉,可以先进行在线调试:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=ShowDeviceShadow在线调试接口,可以请求影子接口,了解请求,与返回的数据格式。设备影子接口返回的数据如下:{ "device_id": "6419627e40773741f9fbdac7_dev1", "shadow": [ { "service_id": "stm32", "desired": { "properties": null, "event_time": null }, "reported": { "properties": { "DS18B20": 18, "motor_water": 1, "motor_oxygen": 1, "temp_max": 10, "water_hp": 130, "motor_food": 0, "time_food": 0, "oxygen_food": 3 }, "event_time": "20230321T081126Z" }, "version": 0 } ]}4.4 修改设备属性地址: cid:link_6接口说明设备的产品模型中定义了物联网平台可向设备下发的属性,应用服务器可调用此接口向指定设备下发属性。平台负责将属性以同步方式发送给设备,并将设备执行属性结果同步返回。修改设备属性的接口,可以让服务器给设备下发指令,如果需要控制设备。在线调试地址:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=UpdateProperties修改设备属性是属于同步命令,需要设备在线才可以进行调试,先使用MQTT客户端登录服务器,模拟设备上线。然后进行调试,测试数据远程下发给设备。【1】利用MQTT客户端先登录设备 (这是同步命令,必须在线才能调试)【2】点击调试{"services":{"temp_max":100}}【4】可以看到,MQTT客户端软件上已经收到了服务器下发的消息由于是同步命令,服务器必须要收到设备的响应才能顺利完成一个流程,设备响应了服务器才能确定数据下发成功。MQTT设备端如何响应呢?设备响应格式说明:cid:link_7下面进行实操:当服务器通过在线调试,发送指令下来之后,客户端将请求ID复制下来,添加到发布主题的格式里,再回复回去,服务器收到了响应,一次属性修改就完美完成了。就是成功的状态:下面是请求的总结: (响应服务器的修改设备属性请求)上报主题的格式:$oc/devices/{device_id}/sys/properties/set/response/request_id=$oc/devices/6419627e40773741f9fbdac7_dev1/sys/properties/set/response/request_id=响应的数据:{"result_code": 0,"result_desc": "success"}4.5 设计上位机前面2讲解了需要用的API接口,接下来就使用Qt设计上位机,设计界面,完成整体上位机的逻辑设计。【1】新建Qt工程选择工程路径,放在英文路径下。创建完毕。新建Android的模板:【2】界面设计【4】代码设计:配置参数读取与保存/*功能: 保存数据到文件*/void Widget::SaveDataToFile(QString text){ /*保存数据到文件,方便下次加载*/ QString file; file=QCoreApplication::applicationDirPath()+"/"+ConfigFile; QFile filesrc(file); filesrc.open(QIODevice::WriteOnly); QDataStream out(&filesrc); out << text; //序列化写字符串 filesrc.flush(); filesrc.close();}/*功能: 从文件读取数据*/QString Widget::ReadDataFile(void){ //读取配置文件 QString text,data; text=QCoreApplication::applicationDirPath()+"/"+ConfigFile; //判断文件是否存在 if(QFile::exists(text)) { QFile filenew(text); filenew.open(QIODevice::ReadOnly); QDataStream in(&filenew); // 从文件读取序列化数据 in >> data; //提取写入的数据 filenew.close(); } return data; //返回值读取的值}【3】代码设计:云端数据解析//解析反馈结果void Widget::replyFinished(QNetworkReply *reply){ QString displayInfo; int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); //读取所有数据 QByteArray replyData = reply->readAll(); qDebug()<<"状态码:"<<statusCode; qDebug()<<"反馈的数据:"<<QString(replyData); //更新token if(function_select==3) { displayInfo="token 更新失败."; //读取HTTP响应头的数据 QList<QNetworkReply::RawHeaderPair> RawHeader=reply->rawHeaderPairs(); qDebug()<<"HTTP响应头数量:"<<RawHeader.size(); for(int i=0;i<RawHeader.size();i++) { QString first=RawHeader.at(i).first; QString second=RawHeader.at(i).second; if(first=="X-Subject-Token") { Token=second.toUtf8(); displayInfo="token 更新成功."; //保存到文件 SaveDataToFile(Token); break; } } QMessageBox::information(this,"提示",displayInfo,QMessageBox::Ok,QMessageBox::Ok); return; } //判断状态码 if(200 != statusCode) { //解析数据 QJsonParseError json_error; QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error); if(json_error.error == QJsonParseError::NoError) { //判断是否是对象,然后开始解析数据 if(document.isObject()) { QString error_str=""; QJsonObject obj = document.object(); QString error_code; //解析错误代码 if(obj.contains("error_code")) { error_code=obj.take("error_code").toString(); error_str+="错误代码:"; error_str+=error_code; error_str+="\n"; } if(obj.contains("error_msg")) { error_str+="错误消息:"; error_str+=obj.take("error_msg").toString(); error_str+="\n"; } //显示错误代码 QMessageBox::information(this,"提示",error_str,QMessageBox::Ok,QMessageBox::Ok); } } return; } //设置属性 if(function_select==12 || function_select==13) { //解析数据 QJsonParseError json_error; QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error); if(json_error.error == QJsonParseError::NoError) { //判断是否是对象,然后开始解析数据 if(document.isObject()) { QJsonObject obj = document.object(); if(obj.contains("response")) { QJsonObject obj1=obj.take("response").toObject(); int val=0; QString success; if(obj1.contains("result_code")) { val=obj1.take("result_code").toInt(); } if(obj1.contains("result_desc")) { success=obj1.take("result_desc").toString(); } if(val==0 && success =="success") { //显示状态 QMessageBox::information(this,"提示","远程命令操作完成.",QMessageBox::Ok,QMessageBox::Ok); return; } else { //显示状态 QMessageBox::information(this,"提示","设备未正确回应.请检查设备网络.",QMessageBox::Ok,QMessageBox::Ok); return; } } } } } //查询设备属性 if(function_select==0) { //解析数据 QJsonParseError json_error; QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error); if(json_error.error == QJsonParseError::NoError) { //判断是否是对象,然后开始解析数据 if(document.isObject()) { QJsonObject obj = document.object(); if(obj.contains("shadow")) { QJsonArray array=obj.take("shadow").toArray(); for(int i=0;i<array.size();i++) { QJsonObject obj2=array.at(i).toObject(); if(obj2.contains("reported")) { QJsonObject obj3=obj2.take("reported").toObject(); if(obj3.contains("properties")) { QJsonObject properties=obj3.take("properties").toObject(); qDebug()<<"开始解析数据...."; } } } } } } return; }}五、代码实现5.1 BC26连接云平台实现代码下面是使用STM32F103ZET6和BC26连接华为云物联网平台实现MQTT设备登录、主题订阅和主题发布的实现代码:#include "stdio.h"#include "string.h"#include "stdlib.h"// 定义华为云物联网平台的服务器地址、端口号、设备ID和设备密码#define MQTT_SERVER "mqtt://xxxxxx.iotplatform.com" // 请替换为实际的服务器地址#define MQTT_PORT 1883 // 请根据实际情况修改端口号#define DEVICE_ID "your_device_id" // 请替换为实际的设备ID#define DEVICE_PASSWORD "your_device_password" // 请替换为实际的设备密码// 定义MQTT相关的参数#define MQTT_CLIENT_ID "your_client_id" // 请替换为实际的客户端ID#define MQTT_TOPIC "your_topic" // 请替换为实际的主题// 定义MQTT消息接收回调函数void mqtt_message_received(char *topic, char *payload) { printf("Received message on topic: %s\n", topic); printf("Payload: %s\n", payload);}// 建立MQTT连接void mqtt_connect() { // 连接到华为云物联网平台的MQTT服务器 // 这里使用的是MQTT的QoS 1级别 // 请根据实际情况修改QoS级别和其他参数 char command[256]; sprintf(command, "AT+QMTCFG="aliauth",0,%d,"%s","%s"", MQTT_PORT, DEVICE_ID, DEVICE_PASSWORD); printf("Sending command: %s\n", command); // 发送AT指令连接到MQTT服务器 // ... // 订阅主题 sprintf(command, "AT+QMTSUB=0,1,"%s",1", MQTT_TOPIC); printf("Sending command: %s\n", command); // 发送AT指令订阅主题 // ...}// 发布MQTT消息void mqtt_publish(char *payload) { // 发布消息到指定的主题 char command[256]; sprintf(command, "AT+QMTPUB=0,0,0,0,"%s"", MQTT_TOPIC); printf("Sending command: %s\n", command); // 发送AT指令设置发布的主题 // ... sprintf(command, "AT+QMTPUB=0,1,0,0,%d", strlen(payload)); printf("Sending command: %s\n", command); // 发送AT指令设置消息的长度 // ... printf("Sending payload: %s\n", payload); // 发送消息的内容 // ... // 等待MQTT服务器返回发布结果 // ...}int main() { // 初始化串口和其他硬件模块 // ... // 连接到华为云物联网平台的MQTT服务器 mqtt_connect(); // 进入主循环 while (1) { // 处理其他任务 // ... // 检查是否有需要发布的消息 // 如果有,调用mqtt_publish函数发布消息 // ... // 检查是否有接收到的MQTT消息 // 如果有,调用mqtt_message_received函数处理消息 // ... } return 0;}5.2 BC26模块的MQTT协议指令BC26模块是一款支持NB-IoT通信技术的物联网模块,可以通过AT指令与外部设备进行通信和控制。下面是BC26模块与MQTT协议相关的一些常用AT指令及其功能:【1】AT+QMTOPEN:打开MQTT客户端连接。功能:通过该指令连接到MQTT服务器。参数:服务器地址、端口号、用户名和密码等。示例:AT+QMTOPEN=0,"mqtt://xxxxxx.iotplatform.com",1883【2】AT+QMTCLOSE:关闭MQTT客户端连接。功能:通过该指令关闭与MQTT服务器的连接。参数:无。示例:AT+QMTCLOSE=0【3】AT+QMTCONN:建立MQTT连接。功能:通过该指令建立与MQTT服务器的连接。参数:客户端ID、用户名、密码等。示例:AT+QMTCONN=0,"your_client_id","your_username","your_password"【4】AT+QMTDISC:断开MQTT连接。功能:通过该指令断开与MQTT服务器的连接。参数:无。示例:AT+QMTDISC=0【5】AT+QMTSUB:订阅MQTT主题。功能:通过该指令订阅指定的MQTT主题。参数:主题、QoS级别等。示例:AT+QMTSUB=0,1,"your_topic",1【6】AT+QMTUNS:取消订阅MQTT主题。功能:通过该指令取消订阅指定的MQTT主题。参数:主题。示例:AT+QMTUNS=0,1,"your_topic"【7】AT+QMTPUB:发布MQTT消息。功能:通过该指令发布消息到指定的MQTT主题。参数:主题、消息内容、QoS级别等。示例:AT+QMTPUB=0,0,0,0,"your_topic"【8】AT+QMTRECV:接收MQTT消息。功能:通过该指令接收从MQTT服务器接收到的消息。参数:无。示例:AT+QMTRECV=0这些是BC26模块中与MQTT协议相关的一些常用AT指令。5.3 读取DHT11传感器的温湿度数据以下是使用STM32F103ZET6读取DHT11传感器的温湿度数据的实现代码:#include "stm32f10x.h"#include "dht11.h"int main(void){ // 初始化DHT11传感器 DHT11_Init(); while (1) { // 读取DHT11传感器的温湿度数据 DHT11_Result result = DHT11_Read(); if (result.status == DHT11_OK) { // 温度数据 uint8_t temperature = result.temperature; // 湿度数据 uint8_t humidity = result.humidity; // 在这里进行温湿度数据的处理和使用 // ... // 延时一段时间后再次读取 DelayMs(2000); } else { // 读取失败,可以进行相应的错误处理 // ... } }}在主函数中,通过循环不断读取DHT11传感器的温湿度数据。如果读取成功,可以从result结构体中获取温度和湿度数据,并进行相应的处理。如果读取失败,可以根据需要进行错误处理。5.4 DHT11.c和DHT11.h代码dht11.h:#ifndef DHT11_H#define DHT11_H#include "stm32f10x.h"typedef struct{ uint8_t status; // 读取状态,0表示成功,其他表示失败 uint8_t humidity; // 湿度值 uint8_t temperature; // 温度值} DHT11_Result;void DHT11_Init(void);DHT11_Result DHT11_Read(void);#endifdht11.c:#include "dht11.h"#define DHT11_PORT GPIOA#define DHT11_PIN GPIO_Pin_0static void DHT11_Delay(uint32_t us){ uint32_t count = us * 8; while (count--) { __NOP(); }}static void DHT11_SetOutput(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_PORT, &GPIO_InitStructure);}static void DHT11_SetInput(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(DHT11_PORT, &GPIO_InitStructure);}static uint8_t DHT11_ReadByte(void){ uint8_t byte = 0; for (uint8_t i = 0; i < 8; i++) { while (!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 等待低电平结束 } DHT11_Delay(30); if (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { byte |= (1 << (7 - i)); } while (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 等待高电平结束 } } return byte;}void DHT11_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_PORT, &GPIO_InitStructure); GPIO_SetBits(DHT11_PORT, DHT11_PIN);}DHT11_Result DHT11_Read(void){ DHT11_Result result; result.status = 1; DHT11_SetOutput(); GPIO_ResetBits(DHT11_PORT, DHT11_PIN); DHT11_Delay(18000); GPIO_SetBits(DHT11_PORT, DHT11_PIN); DHT11_Delay(20); DHT11_SetInput(); if (!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { while (!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 等待低电平结束 } while (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 等待高电平结束 } uint8_t data[5]; for (uint8_t i = 0; i < 5; i++) { data[i] = DHT11_ReadByte(); } uint8_t sum = data[0] + data[1] + data[2] + data[3]; if (sum == data[4]) { result.status = 0; result.humidity = data[0]; result.temperature = data[2]; } } return result;}dht11.h文件定义了DHT11传感器的初始化函数DHT11_Init()和读取函数DHT11_Read(),以及DHT11_Result结构体用于存储读取结果。dht11.c文件实现了DHT11传感器的初始化和读取函数。在初始化函数中,配置了DHT11引脚的GPIO模式和速度。在读取函数中,通过发送开始信号和接收数据的方式读取DHT11传感器的温湿度数据,并进行校验。5.5 GPS数据解析在STM32F103ZET6上通过串口2读取GPS模块返回的定位数据并解析经纬度和定位状态。#include "stm32f10x.h"#include <stdio.h>#include <string.h>// 定义串口2接收缓冲区大小#define RX_BUFFER_SIZE 256// 定义GPS数据解析状态typedef enum { GPS_STATE_IDLE, // 空闲状态 GPS_STATE_RECEIVING, // 接收中状态 GPS_STATE_COMPLETE // 接收完成状态} GPS_State;// 定义接收缓冲区和接收状态变量char rxBuffer[RX_BUFFER_SIZE];volatile uint16_t rxIndex = 0;volatile GPS_State gpsState = GPS_STATE_IDLE;// 处理接收到的GPS数据void processGPSData() { // 在这里进行GPS数据解析和处理 // 解析经纬度和定位状态等信息 // 根据需要进行相应的操作或显示 // 例如,打印经纬度和定位状态 printf("Latitude: %s\n", latitude); printf("Longitude: %s\n", longitude); printf("Position Fix Status: %s\n", positionStatus);}// 串口2接收中断处理函数void USART2_IRQHandler(void) { if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) { char data = USART_ReceiveData(USART2); // 接收到回车换行符表示一条完整的GPS数据 if (data == '\n') { rxBuffer[rxIndex] = '\0'; rxIndex = 0; gpsState = GPS_STATE_COMPLETE; } else { // 将接收到的数据存储到缓冲区中 rxBuffer[rxIndex] = data; rxIndex++; // 接收缓冲区溢出时进行处理 if (rxIndex >= RX_BUFFER_SIZE) { rxIndex = 0; gpsState = GPS_STATE_IDLE; } } }}int main(void) { // 初始化串口2和GPIO引脚 // 设置串口2的波特率、数据位、停止位等参数 // 使能串口2接收中断 USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); NVIC_EnableIRQ(USART2_IRQn); while (1) { // 如果接收到完整的GPS数据 if (gpsState == GPS_STATE_COMPLETE) { // 处理接收到的GPS数据 processGPSData(); // 处理完成后,重置接收状态为IDLE gpsState = GPS_STATE_IDLE; } }}代码中的串口初始化和中断处理部分是基于标准库的使用方式。
  • [技术干货] 基于STM32+华为云IOT设计的智能衣柜
    一、项目介绍随着智能家居的发展,人们对于家居设备的智能化和远程控制需求越来越高。智能衣柜作为智能家居的一部分,可以提供衣物存储和保护的功能,并通过传感器和互联网技术实现对衣柜内部环境的监测和控制,为用户提供更好的使用体验。本项目基于STM32F103ZET6主控芯片设计了一个智能衣柜系统,主要功能包括温度和湿度的监测以及烘干控制。为了实现温湿度的监测,采用了DHT11传感器,可以准确地测量环境的温度和湿度。通过将传感器连接到STM32F103ZET6,可以实时获取衣柜内部的温湿度数据。为了实现烘干功能,系统使用加热丝和小风扇来制造热气并循环衣柜内部的空气,以去除湿气并防止衣物发霉。加热丝的控制采用继电器来控制加热丝的通断,从而控制烘干的开关。通过与STM32F103ZET6的连接,可以实现对加热丝和小风扇的控制。为了实现远程监控和控制,系统采用了ESP8266-WIFI模块将采集到的温湿度数据上传到华为云物联网平台。用户可以通过在Android手机上开发的Qt应用程序远程查看衣柜的实时温度和湿度,并设置湿度阀值。如果湿度超出阀值,系统会通过本地蜂鸣器报警和手机APP提示用户,以防止衣物发霉。此外,用户还可以通过手机APP远程控制衣柜的烘干系统,去除湿气,防止衣物发霉或出现霉味。整个系统通过将传感器、主控芯片、继电器、ESP8266-WIFI模块和手机APP进行集成,实现了智能衣柜的温湿度监测和远程控制功能,为用户提供了便捷、智能的衣物存储和保护解决方案。二、设计思路总结2.1 硬件选型在该项目中,以下是一些可能的硬件选型:【1】主控芯片:STM32F103ZET6,它是一款性能强大的32位ARM Cortex-M3微控制器,具有丰富的外设和存储器,适合用作智能衣柜系统的主控芯片。【2】温湿度传感器:DHT11,能够准确地测量环境的温度和湿度。【3】网络通信模块:ESP8266-WIFI模块,可以实现与互联网的连接,用于将采集到的温湿度数据上传到华为云物联网平台。【4】继电器:用于控制加热丝的通断,从而控制烘干的开关。选择合适的继电器型号和规格,以适应加热丝的电流和电压要求。【5】蜂鸣器:用于本地报警,当湿度超出阀值时发出报警声音。【5】Android手机:作为用户界面,通过Qt开发的Android手机APP实现远程查看和控制衣柜的温湿度以及烘干系统的开关控制。2.2 硬件设计使用STM32F103ZET6作为主控芯片,连接温湿度传感器DHT11,继电器,蜂鸣器和ESP8266-WIFI模块。将DHT11传感器连接到主控芯片的GPIO口,以实时获取衣柜内部的温湿度数据。通过继电器控制加热丝的通断,以控制烘干系统的开关。连接蜂鸣器到主控芯片的GPIO口,当湿度超出阀值时发出报警声音。将ESP8266-WIFI模块连接到主控芯片的串口,以实现与华为云物联网平台的通信。2.3 软件设计使用STM32的开发环境进行固件开发,编写相应的代码来实现温湿度传感器的读取、继电器的控制和蜂鸣器的报警功能。编写与ESP8266-WIFI模块通信的代码,实现将采集到的温湿度数据上传到华为云物联网平台。在华为云物联网平台上创建相应的设备和数据通道,以接收和存储来自智能衣柜的温湿度数据。开发基于Qt的Android手机APP,通过与华为云物联网平台的接口,实现远程查看衣柜的实时温湿度和控制烘干系统的开关。在手机APP上设置湿度阀值,当湿度超出阀值时,触发本地蜂鸣器报警和手机APP的提示功能。2.4 系统交互流程STM32主控芯片读取DHT11传感器的温湿度数据。根据采集到的数据,控制继电器开关加热丝和小风扇,实现烘干功能。将温湿度数据通过ESP8266-WIFI模块上传到华为云物联网平台。用户通过Qt开发的Android手机APP远程访问华为云物联网平台,获取衣柜的实时温湿度数据。如果湿度超出设定的阀值,系统发出本地蜂鸣器报警和手机APP的提示,提醒用户。用户可以通过手机APP远程控制烘干系统的开关,去除湿气,防止衣物发霉或出现霉味。通过上述系统设计思路,实现了智能衣柜的温湿度监测和远程控制功能,提供了更智能、便捷的衣物存储和保护解决方案。三、部署华为云物联网平台华为云官网: cid:link_11打开官网,搜索物联网,就能快速找到 设备接入IoTDA。3.1 物联网平台介绍华为云物联网平台(IoT 设备接入云服务)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助我们快速构筑物联网解决方案。使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi等多种网络接入物联网平台,并使用LWM2M/CoAP、MQTT、HTTPS协议将业务数据上报到平台,平台也可以将控制命令下发给设备。业务应用通过调用物联网平台提供的API,实现设备数据采集、命令下发、设备管理等业务场景。3.2 开通物联网服务地址: cid:link_10进来默认会提示开通标准版,在2023的1月1号年之后没有基础版了。开通之后,点击总览,查看接入信息。 我们当前设备准备采用MQTT协议接入华为云平台,这里可以看到MQTT协议的地址和端口号等信息。总结:端口号: MQTT (1883)| MQTTS (8883) 接入地址: 7445c6bcd3.st1.iotda-app.cn-north-4.myhuaweicloud.com根据域名地址得到IP地址信息:Microsoft Windows [版本 10.0.19044.2728](c) Microsoft Corporation。保留所有权利。​C:\Users\11266>ping 7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com​正在 Ping 7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com [117.78.5.125] 具有 32 字节的数据:来自 117.78.5.125 的回复: 字节=32 时间=42ms TTL=30来自 117.78.5.125 的回复: 字节=32 时间=35ms TTL=30来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=30来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=30​117.78.5.125 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),往返行程的估计时间(以毫秒为单位): 最短 = 35ms,最长 = 42ms,平均 = 37ms​C:\Users\11266>MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口比较合适。 接下来的ESP8266就采用1883端口连接华为云物联网平台。3.3 创建产品(1)创建产品点击产品页,再点击左上角创建产品。(2)填写产品信息根据自己产品名字填写。(3)产品创建成功(4)添加自定义模型产品创建完成之后,点击进入产品详情页面,翻到最下面可以看到模型定义。先点击自定义模型。再创建一个服务ID。接着点击新增属性。3.4 添加设备产品是属于上层的抽象模型,接下来在产品模型下添加实际的设备。添加的设备最终需要与真实的设备关联在一起,完成数据交互。(1)注册设备(2)根据自己的设备填写(3)保存设备信息创建完毕之后,点击保存并关闭,得到创建的设备密匙信息。该信息在后续生成MQTT三元组的时候需要使用。(4) 设备创建完成3.5 MQTT协议主题订阅与发布(1)MQTT协议介绍当前的设备是采用MQTT协议与华为云平台进行通信。MQTT是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。MQTT是专门针对物联网开发的轻量级传输协议。MQTT协议针对低带宽网络,低计算能力的设备,做了特殊的优化,使得其能适应各种物联网应用场景。目前MQTT拥有各种平台和设备上的客户端,已经形成了初步的生态系统。MQTT是一种消息队列协议,使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合,相对于其他协议,开发更简单;MQTT协议是工作在TCP/IP协议上;由TCP/IP协议提供稳定的网络连接;所以,只要具备TCP协议栈的网络设备都可以使用MQTT协议。 本次设备采用的ESP8266就具备TCP协议栈,能够建立TCP连接,所以,配合STM32代码里封装的MQTT协议,就可以与华为云平台完成通信。华为云的MQTT协议接入帮助文档在这里: cid:link_8业务流程:(2)华为云平台MQTT协议使用限制描述限制支持的MQTT协议版本3.1.1与标准MQTT协议的区别支持Qos 0和Qos 1支持Topic自定义不支持QoS2不支持will、retain msgMQTTS支持的安全等级采用TCP通道基础 + TLS协议(最高TLSv1.3版本)单帐号每秒最大MQTT连接请求数无限制单个设备每分钟支持的最大MQTT连接数1单个MQTT连接每秒的吞吐量,即带宽,包含直连设备和网关3KB/sMQTT单个发布消息最大长度,超过此大小的发布请求将被直接拒绝1MBMQTT连接心跳时间建议值心跳时间限定为30至1200秒,推荐设置为120秒产品是否支持自定义Topic支持消息发布与订阅设备只能对自己的Topic进行消息发布与订阅每个订阅请求的最大订阅数无限制(3)主题订阅格式帮助文档地址:cid:link_8对于设备而言,一般会订阅平台下发消息给设备 这个主题。设备想接收平台下发的消息,就需要订阅平台下发消息给设备 的主题,订阅后,平台下发消息给设备,设备就会收到消息。如果设备想要知道平台下发的消息,需要订阅上面图片里标注的主题。以当前设备为例,最终订阅主题的格式如下:$oc/devices/{device_id}/sys/messages/down​最终的格式:$oc/devices/6419627e40773741f9fbdac7_dev1/sys/messages/down(4)主题发布格式对于设备来说,主题发布表示向云平台上传数据,将最新的传感器数据,设备状态上传到云平台。这个操作称为:属性上报。帮助文档地址:cid:link_3根据帮助文档的介绍, 当前设备发布主题,上报属性的格式总结如下:发布的主题格式:$oc/devices/{device_id}/sys/properties/report 最终的格式:$oc/devices/6419627e40773741f9fbdac7_dev1/sys/properties/report发布主题时,需要上传数据,这个数据格式是JSON格式。​上传的JSON数据格式如下:​{ "services": [ { "service_id": <填服务ID>, "properties": { "<填属性名称1>": <填属性值>, "<填属性名称2>": <填属性值>, .......... } } ]}根据JSON格式,一次可以上传多个属性字段。 这个JSON格式里的,服务ID,属性字段名称,属性值类型,在前面创建产品的时候就已经介绍了,不记得可以翻到前面去查看。​根据这个格式,组合一次上传的属性数据:{"services": [{"service_id": "stm32","properties":{"DS18B20":18,"motor_water":1,"motor_oxygen":1,"temp_max":10,"water_hp":130,"motor_food":0,"time_food":0,"oxygen_food":3}}]}3.6 MQTT三元组MQTT协议登录需要填用户ID,设备ID,设备密码等信息,就像我们平时登录QQ,微信一样要输入账号密码才能登录。MQTT协议登录的这3个参数,一般称为MQTT三元组。接下来介绍,华为云平台的MQTT三元组参数如何得到。(1)MQTT服务器地址要登录MQTT服务器,首先记得先知道服务器的地址是多少,端口是多少。帮助文档地址:cid:link_2MQTT协议的端口支持1883和8883,它们的区别是:8883 是加密端口更加安全。但是单片机上使用比较困难,所以当前的设备是采用1883端口进连接的。根据上面的域名和端口号,得到下面的IP地址和端口号信息: 如果设备支持填写域名可以直接填域名,不支持就直接填写IP地址。 (IP地址就是域名解析得到的)华为云的MQTT服务器地址:114.116.232.138域名:7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com华为云的MQTT端口号:1883(2)生成MQTT三元组华为云提供了一个在线工具,用来生成MQTT鉴权三元组: cid:link_9打开这个工具,填入设备的信息(也就是刚才创建完设备之后保存的信息),点击生成,就可以得到MQTT的登录信息了。下面是打开的页面:填入设备的信息: (上面两行就是设备创建完成之后保存得到的)直接得到三元组信息。得到三元组之后,设备端通过MQTT协议登录鉴权的时候,填入参数即可。ClientId 6419627e40773741f9fbdac7_dev1_0_0_2023032108Username 6419627e40773741f9fbdac7_dev1Password 861ac9e6a579d36888b2aaf97714be7af6c77017b017162884592bd68b086a6e3.7 模拟设备登录测试经过上面的步骤介绍,已经创建了产品,设备,数据模型,得到MQTT登录信息。 接下来就用MQTT客户端软件模拟真实的设备来登录平台。测试与服务器通信是否正常。(1)填入登录信息打开MQTT客户端软件,对号填入相关信息(就是上面的文本介绍)。然后,点击登录,订阅主题,发布主题。(2)打开网页查看完成上面的操作之后,打开华为云网页后台,可以看到设备已经在线了。点击详情页面,可以看到上传的数据。到此,云平台的部署已经完成,设备已经可以正常上传数据了。四、上位机开发为了方便查看设备上传的数据,对设备进行远程控制,接下来利用Qt开发一款Android和windows系统的上位机。使用华为云平台提供的API接口获取设备上传的数据,也可以给设备下发指令,控制设备。为了方便查看设备上传的数据,对设备进行远程控制,接下来利用Qt开发一款Android和windows系统的上位机。使用华为云平台提供的API接口获取设备上传的数据,也可以给设备下发指令,控制设备。4.1 Qt开发环境安装Qt的中文官网: https://www.qt.io/zh-cn/QT5.12.6的下载地址:https://download.qt.io/archive/qt/5.12/5.12.6打开下载链接后选择下面的版本进行下载:qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details软件安装时断网安装,否则会提示输入账户。安装的时候,第一个复选框里勾选一个mingw 32编译器即可,其他的不管默认就行,直接点击下一步继续安装。说明: 我这里只是介绍PC端的环境搭建(这个比较简单)。 Android的开发环境比较麻烦,可以去我的博客里看详细文章。选择MinGW 32-bit 编译器:4.2 创建IAM账户创建一个IAM账户,因为接下来开发上位机,需要使用云平台的API接口,这些接口都需要token进行鉴权。简单来说,就是身份的认证。 调用接口获取Token时,就需要填写IAM账号信息。所以,接下来演示一下过程。地址: cid:link_4获取Token时,除了AIM账号外,还需要项目凭证:faa0973835ab409ab48182e2590f4ad3鼠标点击自己昵称,点击统一身份认证。点击左上角创建用户。创建成功:4.3 获取影子数据帮助文档:cid:link_5设备影子介绍:设备影子是一个用于存储和检索设备当前状态信息的JSON文档。每个设备有且只有一个设备影子,由设备ID唯一标识设备影子仅保存最近一次设备的上报数据和预期数据无论该设备是否在线,都可以通过该影子获取和设置设备的属性简单来说:设备影子就是保存,设备最新上传的一次数据。我们设计的软件里,如果想要获取设备的最新状态信息,就采用设备影子接口。如果对接口不熟悉,可以先进行在线调试:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=ShowDeviceShadow在线调试接口,可以请求影子接口,了解请求,与返回的数据格式。设备影子接口返回的数据如下:{ "device_id": "6419627e40773741f9fbdac7_dev1", "shadow": [ { "service_id": "stm32", "desired": { "properties": null, "event_time": null }, "reported": { "properties": { "DS18B20": 18, "motor_water": 1, "motor_oxygen": 1, "temp_max": 10, "water_hp": 130, "motor_food": 0, "time_food": 0, "oxygen_food": 3 }, "event_time": "20230321T081126Z" }, "version": 0 } ]}4.4 修改设备属性地址: cid:link_6接口说明设备的产品模型中定义了物联网平台可向设备下发的属性,应用服务器可调用此接口向指定设备下发属性。平台负责将属性以同步方式发送给设备,并将设备执行属性结果同步返回。修改设备属性的接口,可以让服务器给设备下发指令,如果需要控制设备。在线调试地址:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=UpdateProperties修改设备属性是属于同步命令,需要设备在线才可以进行调试,先使用MQTT客户端登录服务器,模拟设备上线。然后进行调试,测试数据远程下发给设备。【1】利用MQTT客户端先登录设备 (这是同步命令,必须在线才能调试)【2】点击调试{"services":{"temp_max":100}}【4】可以看到,MQTT客户端软件上已经收到了服务器下发的消息由于是同步命令,服务器必须要收到设备的响应才能顺利完成一个流程,设备响应了服务器才能确定数据下发成功。MQTT设备端如何响应呢?设备响应格式说明:cid:link_7下面进行实操:当服务器通过在线调试,发送指令下来之后,客户端将请求ID复制下来,添加到发布主题的格式里,再回复回去,服务器收到了响应,一次属性修改就完美完成了。就是成功的状态:下面是请求的总结: (响应服务器的修改设备属性请求)上报主题的格式:$oc/devices/{device_id}/sys/properties/set/response/request_id=$oc/devices/6419627e40773741f9fbdac7_dev1/sys/properties/set/response/request_id=响应的数据:{"result_code": 0,"result_desc": "success"}4.5 设计上位机前面2讲解了需要用的API接口,接下来就使用Qt设计上位机,设计界面,完成整体上位机的逻辑设计。【1】新建Qt工程选择工程路径,放在英文路径下。创建完毕。新建Android的模板:【2】界面设计【4】代码设计:配置参数读取与保存/*功能: 保存数据到文件*/void Widget::SaveDataToFile(QString text){ /*保存数据到文件,方便下次加载*/ QString file; file=QCoreApplication::applicationDirPath()+"/"+ConfigFile; QFile filesrc(file); filesrc.open(QIODevice::WriteOnly); QDataStream out(&filesrc); out << text; //序列化写字符串 filesrc.flush(); filesrc.close();}/*功能: 从文件读取数据*/QString Widget::ReadDataFile(void){ //读取配置文件 QString text,data; text=QCoreApplication::applicationDirPath()+"/"+ConfigFile; //判断文件是否存在 if(QFile::exists(text)) { QFile filenew(text); filenew.open(QIODevice::ReadOnly); QDataStream in(&filenew); // 从文件读取序列化数据 in >> data; //提取写入的数据 filenew.close(); } return data; //返回值读取的值}【3】代码设计:云端数据解析//解析反馈结果void Widget::replyFinished(QNetworkReply *reply){ QString displayInfo; int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); //读取所有数据 QByteArray replyData = reply->readAll(); qDebug()<<"状态码:"<<statusCode; qDebug()<<"反馈的数据:"<<QString(replyData); //更新token if(function_select==3) { displayInfo="token 更新失败."; //读取HTTP响应头的数据 QList<QNetworkReply::RawHeaderPair> RawHeader=reply->rawHeaderPairs(); qDebug()<<"HTTP响应头数量:"<<RawHeader.size(); for(int i=0;i<RawHeader.size();i++) { QString first=RawHeader.at(i).first; QString second=RawHeader.at(i).second; if(first=="X-Subject-Token") { Token=second.toUtf8(); displayInfo="token 更新成功."; //保存到文件 SaveDataToFile(Token); break; } } QMessageBox::information(this,"提示",displayInfo,QMessageBox::Ok,QMessageBox::Ok); return; } //判断状态码 if(200 != statusCode) { //解析数据 QJsonParseError json_error; QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error); if(json_error.error == QJsonParseError::NoError) { //判断是否是对象,然后开始解析数据 if(document.isObject()) { QString error_str=""; QJsonObject obj = document.object(); QString error_code; //解析错误代码 if(obj.contains("error_code")) { error_code=obj.take("error_code").toString(); error_str+="错误代码:"; error_str+=error_code; error_str+="\n"; } if(obj.contains("error_msg")) { error_str+="错误消息:"; error_str+=obj.take("error_msg").toString(); error_str+="\n"; } //显示错误代码 QMessageBox::information(this,"提示",error_str,QMessageBox::Ok,QMessageBox::Ok); } } return; } //设置属性 if(function_select==12 || function_select==13) { //解析数据 QJsonParseError json_error; QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error); if(json_error.error == QJsonParseError::NoError) { //判断是否是对象,然后开始解析数据 if(document.isObject()) { QJsonObject obj = document.object(); if(obj.contains("response")) { QJsonObject obj1=obj.take("response").toObject(); int val=0; QString success; if(obj1.contains("result_code")) { val=obj1.take("result_code").toInt(); } if(obj1.contains("result_desc")) { success=obj1.take("result_desc").toString(); } if(val==0 && success =="success") { //显示状态 QMessageBox::information(this,"提示","远程命令操作完成.",QMessageBox::Ok,QMessageBox::Ok); return; } else { //显示状态 QMessageBox::information(this,"提示","设备未正确回应.请检查设备网络.",QMessageBox::Ok,QMessageBox::Ok); return; } } } } } //查询设备属性 if(function_select==0) { //解析数据 QJsonParseError json_error; QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error); if(json_error.error == QJsonParseError::NoError) { //判断是否是对象,然后开始解析数据 if(document.isObject()) { QJsonObject obj = document.object(); if(obj.contains("shadow")) { QJsonArray array=obj.take("shadow").toArray(); for(int i=0;i<array.size();i++) { QJsonObject obj2=array.at(i).toObject(); if(obj2.contains("reported")) { QJsonObject obj3=obj2.take("reported").toObject(); if(obj3.contains("properties")) { QJsonObject properties=obj3.take("properties").toObject(); qDebug()<<"开始解析数据...."; } } } } } } return; }}五、代码实现5.1 ESP8266连接云平台实现代码以下是使用STM32F103ZET6和ESP8266连接华为云物联网平台,通过MQTT协议实现设备登录、主题订阅和主题发布的实现代码:#include "stm32f10x.h"#include "stdio.h"#include "string.h"// 定义ESP8266的串口USART_TypeDef* ESP_USARTx = USART1;// 定义MQTT服务器的地址和端口const char* MQTT_SERVER = "mqtt.eclipse.org";const int MQTT_PORT = 1883;// 定义设备ID和设备密码const char* DEVICE_ID = "your_device_id";const char* DEVICE_PASSWORD = "your_device_password";// 定义订阅的主题const char* SUBSCRIBE_TOPIC = "your_subscribe_topic";// 定义发布的主题const char* PUBLISH_TOPIC = "your_publish_topic";// 定义接收缓冲区和发送缓冲区的大小#define RX_BUFFER_SIZE 1024#define TX_BUFFER_SIZE 1024// 定义接收缓冲区和发送缓冲区char rxBuffer[RX_BUFFER_SIZE];char txBuffer[TX_BUFFER_SIZE];// 定义接收缓冲区的索引和标志位volatile uint16_t rxIndex = 0;volatile uint8_t rxComplete = 0;// 发送数据到ESP8266void ESP8266_SendData(const char* data) { sprintf(txBuffer, "%s\r\n", data); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n');}// 从ESP8266接收数据void ESP8266_ReceiveData(uint16_t size) { while (size--) { rxBuffer[rxIndex++] = USART_ReceiveData(ESP_USARTx); } if (rxIndex >= RX_BUFFER_SIZE) { rxComplete = 1; rxIndex = 0; }}// 处理接收到的数据void ProcessReceivedData() { // TODO: 根据接收到的数据进行处理}// ESP8266串口中断处理函数void USART1_IRQHandler(void) { if (USART_GetITStatus(ESP_USARTx, USART_IT_RXNE) != RESET) { ESP8266_ReceiveData(1); }}// 连接到MQTT服务器void MQTT_Connect() { // 发送连接请求 sprintf(txBuffer, "AT+CIPSTART="TCP","%s",%d\r\n", MQTT_SERVER, MQTT_PORT); ESP8266_SendData(txBuffer); // 等待连接成功 while (!strstr(rxBuffer, "CONNECTED")) { if (rxComplete) { ProcessReceivedData(); rxComplete = 0; } } // 发送MQTT连接请求 sprintf(txBuffer, "AT+MQTTCONNECT="%s","%s"\r\n", DEVICE_ID, DEVICE_PASSWORD); ESP8266_SendData(txBuffer); // 等待连接成功 while (!strstr(rxBuffer, "CONNECTED")) { if (rxComplete) { ProcessReceivedData(); rxComplete = 0; } }}// 订阅主题void MQTT_Subscribe() { sprintf(txBuffer, "AT+MQTTSUBSCRIBE="%s"\r\n", SUBSCRIBE_TOPIC); ESP8266_SendData(txBuffer);}// 发布消息void MQTT_Publish(const char* message) { sprintf(txBuffer, "AT+MQTTPUBLISH="%s","%s"\r\n", PUBLISH_TOPIC, message); ESP8266_SendData(txBuffer);}int main(void) { // 初始化ESP8266的串口 USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(ESP_USARTx, &USART_InitStructure); USART_Cmd(ESP_USARTx, ENABLE); USART_ITConfig(ESP_USARTx, USART_IT_RXNE, ENABLE); NVIC_EnableIRQ(USART1_IRQn); // 连接到MQTT服务器 MQTT_Connect(); // 订阅主题 MQTT_Subscribe(); while (1) { if (rxComplete) { ProcessReceivedData(); rxComplete = 0; } // TODO: 处理其他业务逻辑 // 发布消息 MQTT_Publish("Hello, MQTT!"); // 延时一段时间 delay_ms(1000); }}以上代码用于演示使用STM32F103ZET6和ESP8266连接华为云物联网平台,通过MQTT协议实现设备登录、主题订阅和主题发布的基本功能。5.2 ESP8266的MQTT协议指令ESP8266通过MQTT协议连接到服务器的相关AT指令主要有以下几个:【1】AT+CIPSTART:建立TCP连接功能:使用TCP协议连接到远程服务器用法:AT+CIPSTART="TCP","<服务器地址>",<服务器端口>示例:AT+CIPSTART="TCP","mqtt.eclipse.org",1883【2】AT+MQTTCONNECT:连接到MQTT服务器功能:使用MQTT协议连接到MQTT服务器用法:AT+MQTTCONNECT="<设备ID>","<设备密码>"示例:AT+MQTTCONNECT="your_device_id","your_device_password"【3】AT+MQTTPUBLISH:发布消息功能:向指定主题发布消息用法:AT+MQTTPUBLISH="<主题>","<消息内容>"示例:AT+MQTTPUBLISH="your_publish_topic","Hello, MQTT!"【4】AT+MQTTSUBSCRIBE:订阅主题功能:订阅指定的主题用法:AT+MQTTSUBSCRIBE="<主题>"示例:AT+MQTTSUBSCRIBE="your_subscribe_topic"【5】AT+CIPCLOSE:关闭TCP连接功能:关闭当前的TCP连接用法:AT+CIPCLOSE这些AT指令可以通过串口与ESP8266进行通信,实现与MQTT服务器的连接、消息发布和订阅等功能。通过这些指令,可以在嵌入式设备上实现与云端的通信和数据交换,从而实现物联网应用。5.3 读取DHT11传感器的温湿度数据以下是使用STM32F103ZET6读取DHT11传感器的温湿度数据的实现代码:#include "stm32f10x.h"#include "dht11.h"int main(void){ // 初始化DHT11传感器 DHT11_Init(); while (1) { // 读取DHT11传感器的温湿度数据 DHT11_Result result = DHT11_Read(); if (result.status == DHT11_OK) { // 温度数据 uint8_t temperature = result.temperature; // 湿度数据 uint8_t humidity = result.humidity; // 在这里进行温湿度数据的处理和使用 // ... // 延时一段时间后再次读取 DelayMs(2000); } else { // 读取失败,可以进行相应的错误处理 // ... } }}在主函数中,通过循环不断读取DHT11传感器的温湿度数据。如果读取成功,可以从result结构体中获取温度和湿度数据,并进行相应的处理。如果读取失败,可以根据需要进行错误处理。5.4 DHT11.c和DHT11.h代码dht11.h:#ifndef DHT11_H#define DHT11_H#include "stm32f10x.h"typedef struct{ uint8_t status; // 读取状态,0表示成功,其他表示失败 uint8_t humidity; // 湿度值 uint8_t temperature; // 温度值} DHT11_Result;void DHT11_Init(void);DHT11_Result DHT11_Read(void);#endifdht11.c:#include "dht11.h"#define DHT11_PORT GPIOA#define DHT11_PIN GPIO_Pin_0static void DHT11_Delay(uint32_t us){ uint32_t count = us * 8; while (count--) { __NOP(); }}static void DHT11_SetOutput(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_PORT, &GPIO_InitStructure);}static void DHT11_SetInput(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(DHT11_PORT, &GPIO_InitStructure);}static uint8_t DHT11_ReadByte(void){ uint8_t byte = 0; for (uint8_t i = 0; i < 8; i++) { while (!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 等待低电平结束 } DHT11_Delay(30); if (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { byte |= (1 << (7 - i)); } while (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 等待高电平结束 } } return byte;}void DHT11_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = DHT11_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_PORT, &GPIO_InitStructure); GPIO_SetBits(DHT11_PORT, DHT11_PIN);}DHT11_Result DHT11_Read(void){ DHT11_Result result; result.status = 1; DHT11_SetOutput(); GPIO_ResetBits(DHT11_PORT, DHT11_PIN); DHT11_Delay(18000); GPIO_SetBits(DHT11_PORT, DHT11_PIN); DHT11_Delay(20); DHT11_SetInput(); if (!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { while (!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 等待低电平结束 } while (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { // 等待高电平结束 } uint8_t data[5]; for (uint8_t i = 0; i < 5; i++) { data[i] = DHT11_ReadByte(); } uint8_t sum = data[0] + data[1] + data[2] + data[3]; if (sum == data[4]) { result.status = 0; result.humidity = data[0]; result.temperature = data[2]; } } return result;}dht11.h文件定义了DHT11传感器的初始化函数DHT11_Init()和读取函数DHT11_Read(),以及DHT11_Result结构体用于存储读取结果。dht11.c文件实现了DHT11传感器的初始化和读取函数。在初始化函数中,配置了DHT11引脚的GPIO模式和速度。在读取函数中,通过发送开始信号和接收数据的方式读取DHT11传感器的温湿度数据,并进行校验。
  • [赛事资讯] CodeCraft云上先锋黑客松-软件精英实战营赛题发布
    赛题简介本次大赛的赛题需要选手通过代码操控4个机器人完成物资递送任务,以实现收益最大化。赛题模拟了真实机器人的操作接口并通过物理引擎来模拟真实世界的物理法则,如惯性、摩擦、碰撞等。         比赛所使用的判题器和数据集完全开放给大家下载,并且我们给判题器做了图形化界面设计+键盘操作机器人的能力,让大家可以低门槛的上手本次赛题。         为了照顾到使用不同平台的选手,本次大赛特地对判题器做了跨平台设计,可以支持Windows、Linux、MacOS三个平台,选手可以根据自身习惯选择其中一款判题器下载。         每次运行判题器,都会产生一个回放文件置于replay目录中,可以用判题器自带的播放器进行播放,以分析过往比赛的表现。附件下载1. 赛题文档.zip:===页面下方===包含:复赛任务书、判题器使用说明、编译运行环境说明2. WindowsRelease.zip :===下载链接===包含:Windows版本的判题器、播放器、数据集、SDK3. LinuxRelease.zip :===下载链接===包含:Linux版本的判题器、播放器、数据集、SDK4. MacOSRelease.zip :===下载链接===包含:MacOS版本的判题器、播放器、数据集、SDK,该版本可同时支持x86和M1芯片。5.SDK :===页面下方===包含:python、java、C++、C4种语言
  • [技术干货] 基于STM32设计的智能门锁2(采用华为云IOT平台)
    1. 前言随着智能家居的快速发展,智能门锁作为家庭安全的重要组成部分,受到了越来越多用户的关注和需求。为了满足用户对安全和便捷的需求,决定设计一款基于STM32的智能门锁,并将其与华为云IOT平台相结合。传统的门锁存在一些弊端,比如使用钥匙容易丢失、开锁过程繁琐等。而智能门锁的出现,有效地解决了这些问题。我选择使用STM32作为智能门锁的核心控制器,因为STM32系列具有低功耗、高性能和丰富的外设接口等优点,非常适合嵌入式应用。华为云IOT平台作为一个强大的云服务平台,提供了丰富的物联网解决方案和强大的数据处理能力。将智能门锁与华为云IOT平台相结合,可以实现远程控制、数据监测和智能化的功能,为用户带来更加便捷和安全的居家体验。智能门锁设计具有以下主要特点和功能:安全可靠:采用先进的加密算法和身份验证机制,确保门锁的安全性。用户可以通过手机APP、指纹识别或密码等方式进行开锁,有效防止非法入侵。远程控制:通过与华为云IOT平台的连接,用户可以通过手机APP在任何地方实现对门锁的远程控制。比如,可以远程开关门锁、查看开锁记录等。多种开锁方式:除了传统的钥匙开锁方式外,我们的智能门锁还支持多种开锁方式,如指纹识别、密码输入、手机APP控制等。用户可以根据自己的需求选择最方便的开锁方式。实时监测:智能门锁可以实时监测门锁状态、开锁记录等信息,并将这些数据上传到华为云IOT平台进行存储和分析。用户可以通过手机APP查看相关数据,了解家庭安全状况。智能化功能:基于华为云IOT平台的数据处理能力,我们的智能门锁还可以实现一些智能化的功能。比如,可以设置自动开锁时间、远程授权开锁等。2. 设备硬件与功能介绍这篇文章就介绍如何使用华为物联网云平台实现智能锁的应用场景构建,硬件采用STM32F103ZET6 + ESP8266+步进电机实现。在华为云IOT物联网平台构建智能锁项目,配置好云端,设备端通过ESP8266连接华为物联网平台,实现数据上报,交互,实现远程开锁、关锁、获取锁的状态等功能,不用担心忘记出门关锁,也不用担心忘记带钥匙无法开门的情况。ESP8266是物联网解决方案里比较热门的WIFI设备,支持串口+AT指令控制,任意支持串口的单片机都可以使用ESP8266快速实现联网。步进电机采用常规28BYJ-48来模拟当做门锁的电机,驱动板采用ULN2003。3. 创建云端设备登录官网: cid:link_3直接搜索物联网,打开页面。选择设备接入:选择免费试用:在产品页面,点击右上角创建产品:填上产品信息:得到产品ID,保存好ID,点击查看详情:产品ID为:61b9ba3a2b2aa20288c1e7f1.点击设备页面,注册设备:填充信息进行注册:保存设备密匙和设备ID,点击保存关闭会自动下载文件保存,后面生成密码和登录账号需要使用关闭后就看到创建好的设备了:点击产品页面,选择刚才创建的产品:选择自定义模型---创建数据模型服务:选择新增属性,创建设备的属性4. 创建MQTT登录账号和密匙设备创建完成接来下生成MQTT登录账号、密匙,方便设备登录云端平台。官网工具地址: cid:link_1打开刚才创建设备时,下载的密匙文件,把内容复制出来对应的填进去,生成即可。5. 拼接主题订阅与发布的格式官方文档介绍: cid:link_0在产品页面可以,看到主题的全部格式:总结的格式如下: 格式: $oc/devices/{device_id}/sys/messages/down //订阅主题: 平台下发消息给设备 $oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/messages/down ​ ​ 格式: $oc/devices/{device_id}/sys/properties/report //设备上报数据 $oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/properties/report ​ 上属性的数据格式: //上报的属性消息 (一次可以上报多个属性,在json里增加就行了) {"services": [{"service_id": "lock","properties":{"门锁":1}}]}上面属性里的服务ID和属性里的名称,在设备页面,影子设备页面查看。6. MQTT客户端模拟设备登录云端下面使用MQTT客户端模拟设备登录服务器测试,看设备创建的是否OK。服务器的IP地址是: 121.36.42.100端口号是: 1883打开MQTT客户端软件,按照提示,输入相关参数后,点击连接,然后再点击订阅主题,发布主题即可:查看云端服务器的情况: 可以看到设备已经在线了,并且收到上传的数据。修改一下锁的状态,上报属性再查看:发现云端的状态也已经改变,现在设备上报已经OK。接下来测试命令下发,实现远程开锁关锁的功能:打开产品页面,新增加命令:命令添加成功:在设备页面,选择同步命令下发:点击确定后,查看MQTT客户端,发现已经收到数据了:$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497/sys/commands/request_id=88e2626f-290d-405e-962d-51554445a8fd{"paras":{"lock":1},"service_id":"lock","command_name":"lock"}设备端解析收到的数据,就可以完成多步进电机的控制,完成开锁关锁。7. STM32+ESP8266连接云端工程是keil5工程项目源码与视频演示:cid:link_2main函数代码如下: #include "stm32f10x.h" #include "led.h" #include "delay.h" #include "key.h" #include "usart.h" #include < string.h > #include "timer.h" #include "bluetooth.h" #include "esp8266.h" #include "mqtt.h" ​ //华为物联网服务器的设备信息 #define MQTT_ClientID "61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510" #define MQTT_UserName "61b9ba3a2b2aa20288c1e7f1_QQ1126626497" #define MQTT_PassWord "385ce91dfe7da5b7431868d5d87e7998163c493344040935d5a00024d6324242" ​ //订阅与发布的主题 #define SET_TOPIC "$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/messages/down" //订阅 #define POST_TOPIC "$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/properties/report" //发布 ​ char mqtt_message[200];//上报数据缓存区 ​ int main() { u32 time_cnt=0; u32 i; u8 key; LED_Init(); BEEP_Init(); KEY_Init(); USART1_Init(115200); TIMER1_Init(72,20000); //超时时间20ms USART2_Init(9600);//串口-蓝牙 TIMER2_Init(72,20000); //超时时间20ms USART3_Init(115200);//串口-WIFI TIMER3_Init(72,20000); //超时时间20ms USART1_Printf("正在初始化WIFI请稍等.\\n"); if(ESP8266_Init()) { USART1_Printf("ESP8266硬件检测错误.\\n"); } else { //非加密端口 USART1_Printf("WIFI:%d\\n",ESP8266_STA_TCP_Client_Mode("CMCC-Cqvn","99pu58cb","121.36.42.100",1883,1)); } //2. MQTT协议初始化 MQTT_Init(); //3. 连接华为服务器 while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord)) { USART1_Printf("服务器连接失败,正在重试...\\n"); delay_ms(500); } USART1_Printf("服务器连接成功.\\n"); //3. 订阅主题 if(MQTT_SubscribeTopic(SET_TOPIC,0,1)) { USART1_Printf("主题订阅失败.\\n"); } else { USART1_Printf("主题订阅成功.\\n"); } while(1) { key=KEY_Scan(0); if(key==2) { time_cnt=0; sprintf(mqtt_message,"{"services": [{"service_id": "lock","properties":{"门锁":1}}]}"); MQTT_PublishData(POST_TOPIC,mqtt_message,0); USART1_Printf("发送状态1\\r\\n"); } else if(key==3) { time_cnt=0; sprintf(mqtt_message,"{"services": [{"service_id": "lock","properties":{"门锁":0}}]}"); MQTT_PublishData(POST_TOPIC,mqtt_message,0); USART1_Printf("发送状态0\\r\\n"); } ​ if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\\0'; for(i=0;i< USART3_RX_CNT;i++) { USART1_Printf("%c",USART3_RX_BUFFER[i]); } USART3_RX_CNT=0; USART3_RX_FLAG=0; } ​ //定时发送心跳包,保持连接 delay_ms(10); time_cnt++; if(time_cnt==500) { MQTT_SentHeart();//发送心跳包 time_cnt=0; } } }
  • [技术干货] 基于STM32+华为云IOT设计的智能窗帘控制系统
    一、项目背景随着智能家居技术的不断发展,人们对于家居生活的需求也越来越高。智能窗帘作为智能家居领域的重要组成部分,为用户提供了更便捷、舒适的生活体验。本项目基于STM32主控芯片和华为云物联网平台,设计一款智能窗帘控制系统,以满足家庭和商业场所的需求。在本项目中,选择了STM32F103ZET6作为主控芯片具有强大的处理能力和丰富的外设接口,适合用于物联网设备的控制和通信。通过与ESP8266-WIFI模块的连接,可以实现智能窗帘与华为云物联网平台的互联互通,实现远程控制和监测。为了方便用户的操作和控制,使用Qt开发了Android手机APP和Windows上位机软件,用户可以通过这些应用程序进行窗帘的远程控制。同时,本地窗帘也支持手动控制,用户可以通过物理按钮或开关来操作窗帘的开关、升降等功能。在智能化方面,引入了语音识别技术(LD3320模块),用户可以通过语音指令来控制窗帘的运行。这为用户提供了更加便捷、智能的控制方式,使得窗帘的操作更加自然和智能化。除了远程控制和智能化功能,还引入了自动模式。在自动模式下,系统会根据环境条件进行智能判断和控制。例如,当检测到阳光强度超过设定阈值时,系统会自动关闭窗帘,以避免阳光直射室内;在晚上时,系统也会自动拉上窗帘,提供更好的隐私和安全性。本智能窗帘控制系统基于STM32主控芯片和华为云物联网平台,结合语音识别、智能家居控制等功能,为家庭和1商业场所提供便捷、舒适的智能化服务。通过远程控制、自动模式和智能化功能,用户可以实现对窗帘的灵活、智能的控制,提升生活质量和用户体验。二、硬件选型在设计智能窗帘控制系统的硬件方案时,需要考虑主控芯片、通信模块和传感器等关键组件的选型。以下是当前系统的具体硬件选型:【1】主控芯片:采用STM32F103ZET6作为主控芯片。具备强大的处理能力和丰富的外设接口,适合用于物联网设备的控制和通信。可以驱动各种传感器和执行器,并与ESP8266-WIFI模块和LD3320语音识别模块进行通信。【2】通信模块:选择了ESP8266-WIFI模块作为通信模块,用于连接华为云物联网平台。ESP8266-WIFI模块具有低功耗、高集成度和稳定的无线连接能力,能够实现智能窗帘与互联网的互联互通。【3】光照传感器:采用BH1750光照传感器来检测光照强度。BH1750是一种数字式光强度传感器,能够准确测量环境光的强度。通过获取光照强度数据,系统可以根据设定的阈值来判断是否需要自动拉窗帘。【4】语音识别模块:选择了LD3320语音识别模块,用于实现语音控制功能。LD3320是一种高性能语音识别芯片,能够实现对语音指令的识别和解析。通过语音识别模块,用户可以通过语音指令来控制窗帘的开合和模式切换。【5】电机和驱动模块:选择了28BYJ40步进电机作为窗帘控制的电机,并使用ULN2003驱动模块来驱动电机。28BYJ40步进电机具有较高的精度和稳定性,适合用于窗帘的控制。ULN2003是一种高电压、高电流驱动芯片,能够提供足够的电流和电压来驱动步进电机。【6】用户界面设备:采用Qt开发Android手机APP和Windows上位机来实现用户界面。通过这两个界面,用户可以进行远程控制窗帘的操作,包括开关窗帘、调整窗帘的开合程度和切换窗帘的工作模式。三、系统设计智能窗帘控制系统的软件设计主要包括主控程序、通信模块驱动、传感器驱动和用户界面等部分。以下是系统软件设计的思路:【1】主控程序:主控程序是系统的核心,负责控制窗帘的运行、处理传感器数据、与通信模块进行通信等。主控程序需要实现以下功能:初始化各个硬件模块,包括通信模块、传感器和电机驱动等。循环读取传感器数据,根据数据进行窗帘的控制和判断。处理用户的控制指令,包括远程控制指令和本地控制指令。与通信模块进行通信,实现与华为云物联网平台的互联互通。实现自动模式下的智能判断和控制逻辑。【2】通信模块驱动:通信模块驱动负责与华为云物联网平台进行通信,实现远程控制和数据传输。通信模块驱动需要实现以下功能:初始化通信模块,建立与华为云物联网平台的连接。接收来自云平台的控制指令,解析指令内容。将传感器数据和窗帘状态等信息上传到云平台,实现实时监测和数据传输。【3】传感器驱动:传感器驱动负责与光敏传感器、时间传感器等传感器进行交互,获取环境数据。传感器驱动需要实现以下功能:初始化传感器,配置传感器的工作模式和参数。定期读取传感器数据,包括光敏传感器的光强度和时间传感器的时间信息。将传感器数据传递给主控程序,供其进行判断和控制。【4】用户界面:用户界面是用户与系统进行交互的界面,可以通过Android手机APP或Windows上位机软件实现。用户界面需要实现以下功能:显示窗帘的状态和实时数据,如光强度、时间。提供远程控制窗帘的功能,包括开关、升降和自动模式的切换。接收用户的控制指令,将指令传递给主控程序进行处理。三、部署华为云物联网平台华为云官网: cid:link_12打开官网,搜索物联网,就能快速找到 设备接入IoTDA。3.1 物联网平台介绍华为云物联网平台(IoT 设备接入云服务)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助我们快速构筑物联网解决方案。使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi等多种网络接入物联网平台,并使用LWM2M/CoAP、MQTT、HTTPS协议将业务数据上报到平台,平台也可以将控制命令下发给设备。业务应用通过调用物联网平台提供的API,实现设备数据采集、命令下发、设备管理等业务场景。3.2 开通物联网服务地址: cid:link_10进来默认会提示开通标准版,在2023的1月1号年之后没有基础版了。开通之后,点击总览,查看接入信息。 我们当前设备准备采用MQTT协议接入华为云平台,这里可以看到MQTT协议的地址和端口号等信息。总结:端口号: MQTT (1883)| MQTTS (8883) 接入地址: 7445c6bcd3.st1.iotda-app.cn-north-4.myhuaweicloud.com根据域名地址得到IP地址信息:Microsoft Windows [版本 10.0.19044.2728](c) Microsoft Corporation。保留所有权利。​C:\Users\11266>ping 7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com​正在 Ping 7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com [117.78.5.125] 具有 32 字节的数据:来自 117.78.5.125 的回复: 字节=32 时间=42ms TTL=30来自 117.78.5.125 的回复: 字节=32 时间=35ms TTL=30来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=30来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=30​117.78.5.125 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),往返行程的估计时间(以毫秒为单位): 最短 = 35ms,最长 = 42ms,平均 = 37ms​C:\Users\11266>MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口比较合适。 接下来的ESP8266就采用1883端口连接华为云物联网平台。3.3 创建产品(1)创建产品点击产品页,再点击左上角创建产品。(2)填写产品信息根据自己产品名字填写。(3)产品创建成功(4)添加自定义模型产品创建完成之后,点击进入产品详情页面,翻到最下面可以看到模型定义。先点击自定义模型。再创建一个服务ID。接着点击新增属性。3.4 添加设备产品是属于上层的抽象模型,接下来在产品模型下添加实际的设备。添加的设备最终需要与真实的设备关联在一起,完成数据交互。(1)注册设备(2)根据自己的设备填写(3)保存设备信息创建完毕之后,点击保存并关闭,得到创建的设备密匙信息。该信息在后续生成MQTT三元组的时候需要使用。(4) 设备创建完成3.5 MQTT协议主题订阅与发布(1)MQTT协议介绍当前的设备是采用MQTT协议与华为云平台进行通信。MQTT是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。MQTT是专门针对物联网开发的轻量级传输协议。MQTT协议针对低带宽网络,低计算能力的设备,做了特殊的优化,使得其能适应各种物联网应用场景。目前MQTT拥有各种平台和设备上的客户端,已经形成了初步的生态系统。MQTT是一种消息队列协议,使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合,相对于其他协议,开发更简单;MQTT协议是工作在TCP/IP协议上;由TCP/IP协议提供稳定的网络连接;所以,只要具备TCP协议栈的网络设备都可以使用MQTT协议。 本次设备采用的ESP8266就具备TCP协议栈,能够建立TCP连接,所以,配合STM32代码里封装的MQTT协议,就可以与华为云平台完成通信。华为云的MQTT协议接入帮助文档在这里: cid:link_8业务流程:(2)华为云平台MQTT协议使用限制描述限制支持的MQTT协议版本3.1.1与标准MQTT协议的区别支持Qos 0和Qos 1支持Topic自定义不支持QoS2不支持will、retain msgMQTTS支持的安全等级采用TCP通道基础 + TLS协议(最高TLSv1.3版本)单帐号每秒最大MQTT连接请求数无限制单个设备每分钟支持的最大MQTT连接数1单个MQTT连接每秒的吞吐量,即带宽,包含直连设备和网关3KB/sMQTT单个发布消息最大长度,超过此大小的发布请求将被直接拒绝1MBMQTT连接心跳时间建议值心跳时间限定为30至1200秒,推荐设置为120秒产品是否支持自定义Topic支持消息发布与订阅设备只能对自己的Topic进行消息发布与订阅每个订阅请求的最大订阅数无限制(3)主题订阅格式帮助文档地址:cid:link_8对于设备而言,一般会订阅平台下发消息给设备 这个主题。设备想接收平台下发的消息,就需要订阅平台下发消息给设备 的主题,订阅后,平台下发消息给设备,设备就会收到消息。如果设备想要知道平台下发的消息,需要订阅上面图片里标注的主题。以当前设备为例,最终订阅主题的格式如下:$oc/devices/{device_id}/sys/messages/down​最终的格式:$oc/devices/6419627e40773741f9fbdac7_dev1/sys/messages/down(4)主题发布格式对于设备来说,主题发布表示向云平台上传数据,将最新的传感器数据,设备状态上传到云平台。这个操作称为:属性上报。帮助文档地址:cid:link_3根据帮助文档的介绍, 当前设备发布主题,上报属性的格式总结如下:发布的主题格式:$oc/devices/{device_id}/sys/properties/report 最终的格式:$oc/devices/6419627e40773741f9fbdac7_dev1/sys/properties/report发布主题时,需要上传数据,这个数据格式是JSON格式。​上传的JSON数据格式如下:​{ "services": [ { "service_id": <填服务ID>, "properties": { "<填属性名称1>": <填属性值>, "<填属性名称2>": <填属性值>, .......... } } ]}根据JSON格式,一次可以上传多个属性字段。 这个JSON格式里的,服务ID,属性字段名称,属性值类型,在前面创建产品的时候就已经介绍了,不记得可以翻到前面去查看。​根据这个格式,组合一次上传的属性数据:{"services": [{"service_id": "stm32","properties":{"DS18B20":18,"motor_water":1,"motor_oxygen":1,"temp_max":10,"water_hp":130,"motor_food":0,"time_food":0,"oxygen_food":3}}]}3.6 MQTT三元组MQTT协议登录需要填用户ID,设备ID,设备密码等信息,就像我们平时登录QQ,微信一样要输入账号密码才能登录。MQTT协议登录的这3个参数,一般称为MQTT三元组。接下来介绍,华为云平台的MQTT三元组参数如何得到。(1)MQTT服务器地址要登录MQTT服务器,首先记得先知道服务器的地址是多少,端口是多少。帮助文档地址:cid:link_2MQTT协议的端口支持1883和8883,它们的区别是:8883 是加密端口更加安全。但是单片机上使用比较困难,所以当前的设备是采用1883端口进连接的。根据上面的域名和端口号,得到下面的IP地址和端口号信息: 如果设备支持填写域名可以直接填域名,不支持就直接填写IP地址。 (IP地址就是域名解析得到的)华为云的MQTT服务器地址:114.116.232.138域名:7445c6bcd3.st1.iotda-device.cn-north-4.myhuaweicloud.com华为云的MQTT端口号:1883(2)生成MQTT三元组华为云提供了一个在线工具,用来生成MQTT鉴权三元组: cid:link_9打开这个工具,填入设备的信息(也就是刚才创建完设备之后保存的信息),点击生成,就可以得到MQTT的登录信息了。下面是打开的页面:填入设备的信息: (上面两行就是设备创建完成之后保存得到的)直接得到三元组信息。得到三元组之后,设备端通过MQTT协议登录鉴权的时候,填入参数即可。ClientId 6419627e40773741f9fbdac7_dev1_0_0_2023032108Username 6419627e40773741f9fbdac7_dev1Password 861ac9e6a579d36888b2aaf97714be7af6c77017b017162884592bd68b086a6e3.7 模拟设备登录测试经过上面的步骤介绍,已经创建了产品,设备,数据模型,得到MQTT登录信息。 接下来就用MQTT客户端软件模拟真实的设备来登录平台。测试与服务器通信是否正常。(1)填入登录信息打开MQTT客户端软件,对号填入相关信息(就是上面的文本介绍)。然后,点击登录,订阅主题,发布主题。(2)打开网页查看完成上面的操作之后,打开华为云网页后台,可以看到设备已经在线了。点击详情页面,可以看到上传的数据。到此,云平台的部署已经完成,设备已经可以正常上传数据了。四、上位机开发为了方便查看设备上传的数据,对设备进行远程控制,接下来利用Qt开发一款Android和windows系统的上位机。使用华为云平台提供的API接口获取设备上传的数据,也可以给设备下发指令,控制设备。为了方便查看设备上传的数据,对设备进行远程控制,接下来利用Qt开发一款Android和windows系统的上位机。使用华为云平台提供的API接口获取设备上传的数据,也可以给设备下发指令,控制设备。4.1 Qt开发环境安装Qt的中文官网: cid:link_13QT5.12.6的下载地址:cid:link_11打开下载链接后选择下面的版本进行下载:qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details软件安装时断网安装,否则会提示输入账户。安装的时候,第一个复选框里勾选一个mingw 32编译器即可,其他的不管默认就行,直接点击下一步继续安装。说明: 我这里只是介绍PC端的环境搭建(这个比较简单)。 Android的开发环境比较麻烦,可以去我的博客里看详细文章。选择MinGW 32-bit 编译器:4.2 创建IAM账户创建一个IAM账户,因为接下来开发上位机,需要使用云平台的API接口,这些接口都需要token进行鉴权。简单来说,就是身份的认证。 调用接口获取Token时,就需要填写IAM账号信息。所以,接下来演示一下过程。地址: cid:link_4获取Token时,除了AIM账号外,还需要项目凭证:faa0973835ab409ab48182e2590f4ad3鼠标点击自己昵称,点击统一身份认证。点击左上角创建用户。创建成功:4.3 获取影子数据帮助文档:cid:link_5设备影子介绍:设备影子是一个用于存储和检索设备当前状态信息的JSON文档。每个设备有且只有一个设备影子,由设备ID唯一标识设备影子仅保存最近一次设备的上报数据和预期数据无论该设备是否在线,都可以通过该影子获取和设置设备的属性简单来说:设备影子就是保存,设备最新上传的一次数据。我们设计的软件里,如果想要获取设备的最新状态信息,就采用设备影子接口。如果对接口不熟悉,可以先进行在线调试:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=ShowDeviceShadow在线调试接口,可以请求影子接口,了解请求,与返回的数据格式。设备影子接口返回的数据如下:{ "device_id": "6419627e40773741f9fbdac7_dev1", "shadow": [ { "service_id": "stm32", "desired": { "properties": null, "event_time": null }, "reported": { "properties": { "DS18B20": 18, "motor_water": 1, "motor_oxygen": 1, "temp_max": 10, "water_hp": 130, "motor_food": 0, "time_food": 0, "oxygen_food": 3 }, "event_time": "20230321T081126Z" }, "version": 0 } ]}4.4 修改设备属性地址: cid:link_6接口说明设备的产品模型中定义了物联网平台可向设备下发的属性,应用服务器可调用此接口向指定设备下发属性。平台负责将属性以同步方式发送给设备,并将设备执行属性结果同步返回。修改设备属性的接口,可以让服务器给设备下发指令,如果需要控制设备。在线调试地址:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=UpdateProperties修改设备属性是属于同步命令,需要设备在线才可以进行调试,先使用MQTT客户端登录服务器,模拟设备上线。然后进行调试,测试数据远程下发给设备。【1】利用MQTT客户端先登录设备 (这是同步命令,必须在线才能调试)【2】点击调试{"services":{"temp_max":100}}【4】可以看到,MQTT客户端软件上已经收到了服务器下发的消息由于是同步命令,服务器必须要收到设备的响应才能顺利完成一个流程,设备响应了服务器才能确定数据下发成功。MQTT设备端如何响应呢?设备响应格式说明:cid:link_7下面进行实操:当服务器通过在线调试,发送指令下来之后,客户端将请求ID复制下来,添加到发布主题的格式里,再回复回去,服务器收到了响应,一次属性修改就完美完成了。就是成功的状态:下面是请求的总结: (响应服务器的修改设备属性请求)上报主题的格式:$oc/devices/{device_id}/sys/properties/set/response/request_id=$oc/devices/6419627e40773741f9fbdac7_dev1/sys/properties/set/response/request_id=响应的数据:{"result_code": 0,"result_desc": "success"}4.5 设计上位机前面2讲解了需要用的API接口,接下来就使用Qt设计上位机,设计界面,完成整体上位机的逻辑设计。【1】新建Qt工程选择工程路径,放在英文路径下。创建完毕。新建Android的模板:【2】界面设计【4】代码设计:配置参数读取与保存/*功能: 保存数据到文件*/void Widget::SaveDataToFile(QString text){ /*保存数据到文件,方便下次加载*/ QString file; file=QCoreApplication::applicationDirPath()+"/"+ConfigFile; QFile filesrc(file); filesrc.open(QIODevice::WriteOnly); QDataStream out(&filesrc); out << text; //序列化写字符串 filesrc.flush(); filesrc.close();}/*功能: 从文件读取数据*/QString Widget::ReadDataFile(void){ //读取配置文件 QString text,data; text=QCoreApplication::applicationDirPath()+"/"+ConfigFile; //判断文件是否存在 if(QFile::exists(text)) { QFile filenew(text); filenew.open(QIODevice::ReadOnly); QDataStream in(&filenew); // 从文件读取序列化数据 in >> data; //提取写入的数据 filenew.close(); } return data; //返回值读取的值}【3】代码设计:云端数据解析//解析反馈结果void Widget::replyFinished(QNetworkReply *reply){ QString displayInfo; int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); //读取所有数据 QByteArray replyData = reply->readAll(); qDebug()<<"状态码:"<<statusCode; qDebug()<<"反馈的数据:"<<QString(replyData); //更新token if(function_select==3) { displayInfo="token 更新失败."; //读取HTTP响应头的数据 QList<QNetworkReply::RawHeaderPair> RawHeader=reply->rawHeaderPairs(); qDebug()<<"HTTP响应头数量:"<<RawHeader.size(); for(int i=0;i<RawHeader.size();i++) { QString first=RawHeader.at(i).first; QString second=RawHeader.at(i).second; if(first=="X-Subject-Token") { Token=second.toUtf8(); displayInfo="token 更新成功."; //保存到文件 SaveDataToFile(Token); break; } } QMessageBox::information(this,"提示",displayInfo,QMessageBox::Ok,QMessageBox::Ok); return; } //判断状态码 if(200 != statusCode) { //解析数据 QJsonParseError json_error; QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error); if(json_error.error == QJsonParseError::NoError) { //判断是否是对象,然后开始解析数据 if(document.isObject()) { QString error_str=""; QJsonObject obj = document.object(); QString error_code; //解析错误代码 if(obj.contains("error_code")) { error_code=obj.take("error_code").toString(); error_str+="错误代码:"; error_str+=error_code; error_str+="\n"; } if(obj.contains("error_msg")) { error_str+="错误消息:"; error_str+=obj.take("error_msg").toString(); error_str+="\n"; } //显示错误代码 QMessageBox::information(this,"提示",error_str,QMessageBox::Ok,QMessageBox::Ok); } } return; } //设置属性 if(function_select==12 || function_select==13) { //解析数据 QJsonParseError json_error; QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error); if(json_error.error == QJsonParseError::NoError) { //判断是否是对象,然后开始解析数据 if(document.isObject()) { QJsonObject obj = document.object(); if(obj.contains("response")) { QJsonObject obj1=obj.take("response").toObject(); int val=0; QString success; if(obj1.contains("result_code")) { val=obj1.take("result_code").toInt(); } if(obj1.contains("result_desc")) { success=obj1.take("result_desc").toString(); } if(val==0 && success =="success") { //显示状态 QMessageBox::information(this,"提示","远程命令操作完成.",QMessageBox::Ok,QMessageBox::Ok); return; } else { //显示状态 QMessageBox::information(this,"提示","设备未正确回应.请检查设备网络.",QMessageBox::Ok,QMessageBox::Ok); return; } } } } } //查询设备属性 if(function_select==0) { //解析数据 QJsonParseError json_error; QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error); if(json_error.error == QJsonParseError::NoError) { //判断是否是对象,然后开始解析数据 if(document.isObject()) { QJsonObject obj = document.object(); if(obj.contains("shadow")) { QJsonArray array=obj.take("shadow").toArray(); for(int i=0;i<array.size();i++) { QJsonObject obj2=array.at(i).toObject(); if(obj2.contains("reported")) { QJsonObject obj3=obj2.take("reported").toObject(); if(obj3.contains("properties")) { QJsonObject properties=obj3.take("properties").toObject(); qDebug()<<"开始解析数据...."; } } } } } } return; }}五、代码实现5.1 ESP8266连接云平台实现代码以下是使用STM32F103ZET6和ESP8266连接华为云物联网平台,通过MQTT协议实现设备登录、主题订阅和主题发布的实现代码:#include "stm32f10x.h"#include "stdio.h"#include "string.h"// 定义ESP8266的串口USART_TypeDef* ESP_USARTx = USART1;// 定义MQTT服务器的地址和端口const char* MQTT_SERVER = "mqtt.eclipse.org";const int MQTT_PORT = 1883;// 定义设备ID和设备密码const char* DEVICE_ID = "your_device_id";const char* DEVICE_PASSWORD = "your_device_password";// 定义订阅的主题const char* SUBSCRIBE_TOPIC = "your_subscribe_topic";// 定义发布的主题const char* PUBLISH_TOPIC = "your_publish_topic";// 定义接收缓冲区和发送缓冲区的大小#define RX_BUFFER_SIZE 1024#define TX_BUFFER_SIZE 1024// 定义接收缓冲区和发送缓冲区char rxBuffer[RX_BUFFER_SIZE];char txBuffer[TX_BUFFER_SIZE];// 定义接收缓冲区的索引和标志位volatile uint16_t rxIndex = 0;volatile uint8_t rxComplete = 0;// 发送数据到ESP8266void ESP8266_SendData(const char* data) { sprintf(txBuffer, "%s\r\n", data); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n'); USART_SendData(ESP_USARTx, (uint16_t)'\r'); USART_SendData(ESP_USARTx, (uint16_t)'\n');}// 从ESP8266接收数据void ESP8266_ReceiveData(uint16_t size) { while (size--) { rxBuffer[rxIndex++] = USART_ReceiveData(ESP_USARTx); } if (rxIndex >= RX_BUFFER_SIZE) { rxComplete = 1; rxIndex = 0; }}// 处理接收到的数据void ProcessReceivedData() { // TODO: 根据接收到的数据进行处理}// ESP8266串口中断处理函数void USART1_IRQHandler(void) { if (USART_GetITStatus(ESP_USARTx, USART_IT_RXNE) != RESET) { ESP8266_ReceiveData(1); }}// 连接到MQTT服务器void MQTT_Connect() { // 发送连接请求 sprintf(txBuffer, "AT+CIPSTART="TCP","%s",%d\r\n", MQTT_SERVER, MQTT_PORT); ESP8266_SendData(txBuffer); // 等待连接成功 while (!strstr(rxBuffer, "CONNECTED")) { if (rxComplete) { ProcessReceivedData(); rxComplete = 0; } } // 发送MQTT连接请求 sprintf(txBuffer, "AT+MQTTCONNECT="%s","%s"\r\n", DEVICE_ID, DEVICE_PASSWORD); ESP8266_SendData(txBuffer); // 等待连接成功 while (!strstr(rxBuffer, "CONNECTED")) { if (rxComplete) { ProcessReceivedData(); rxComplete = 0; } }}// 订阅主题void MQTT_Subscribe() { sprintf(txBuffer, "AT+MQTTSUBSCRIBE="%s"\r\n", SUBSCRIBE_TOPIC); ESP8266_SendData(txBuffer);}// 发布消息void MQTT_Publish(const char* message) { sprintf(txBuffer, "AT+MQTTPUBLISH="%s","%s"\r\n", PUBLISH_TOPIC, message); ESP8266_SendData(txBuffer);}int main(void) { // 初始化ESP8266的串口 USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(ESP_USARTx, &USART_InitStructure); USART_Cmd(ESP_USARTx, ENABLE); USART_ITConfig(ESP_USARTx, USART_IT_RXNE, ENABLE); NVIC_EnableIRQ(USART1_IRQn); // 连接到MQTT服务器 MQTT_Connect(); // 订阅主题 MQTT_Subscribe(); while (1) { if (rxComplete) { ProcessReceivedData(); rxComplete = 0; } // TODO: 处理其他业务逻辑 // 发布消息 MQTT_Publish("Hello, MQTT!"); // 延时一段时间 delay_ms(1000); }}以上代码用于演示使用STM32F103ZET6和ESP8266连接华为云物联网平台,通过MQTT协议实现设备登录、主题订阅和主题发布的基本功能。5.2 ESP8266的MQTT协议指令ESP8266通过MQTT协议连接到服务器的相关AT指令主要有以下几个:【1】AT+CIPSTART:建立TCP连接功能:使用TCP协议连接到远程服务器用法:AT+CIPSTART="TCP","<服务器地址>",<服务器端口>示例:AT+CIPSTART="TCP","mqtt.eclipse.org",1883【2】AT+MQTTCONNECT:连接到MQTT服务器功能:使用MQTT协议连接到MQTT服务器用法:AT+MQTTCONNECT="<设备ID>","<设备密码>"示例:AT+MQTTCONNECT="your_device_id","your_device_password"【3】AT+MQTTPUBLISH:发布消息功能:向指定主题发布消息用法:AT+MQTTPUBLISH="<主题>","<消息内容>"示例:AT+MQTTPUBLISH="your_publish_topic","Hello, MQTT!"【4】AT+MQTTSUBSCRIBE:订阅主题功能:订阅指定的主题用法:AT+MQTTSUBSCRIBE="<主题>"示例:AT+MQTTSUBSCRIBE="your_subscribe_topic"【5】AT+CIPCLOSE:关闭TCP连接功能:关闭当前的TCP连接用法:AT+CIPCLOSE这些AT指令可以通过串口与ESP8266进行通信,实现与MQTT服务器的连接、消息发布和订阅等功能。通过这些指令,可以在嵌入式设备上实现与云端的通信和数据交换,从而实现物联网应用。5.2 步进电机控制代码以下是使用STM32F103ZET6单片机通过ULN2003驱动芯片控制28BYJ-48步进电机实现角度控制和速度控制的实现代码:#include "stm32f10x.h"#include "delay.h"// 定义步进电机控制引脚#define IN1_PIN GPIO_Pin_0#define IN2_PIN GPIO_Pin_1#define IN3_PIN GPIO_Pin_2#define IN4_PIN GPIO_Pin_3#define IN_PORT GPIOA// 定义步进电机角度和速度参数#define ANGLE_1 512 // 控制步进电机转动一圈的步数#define SPEED_1 5 // 控制步进电机转动的速度// 步进电机转动顺序const uint8_t stepSequence[8] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09};// 步进电机当前角度和速度volatile uint16_t currentAngle = 0;volatile uint8_t currentSpeed = 0;// 初始化步进电机控制引脚void StepperMotor_Init() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = IN1_PIN | IN2_PIN | IN3_PIN | IN4_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(IN_PORT, &GPIO_InitStructure);}// 控制步进电机转动一步void StepperMotor_Step() { static uint8_t stepIndex = 0; GPIO_Write(IN_PORT, stepSequence[stepIndex]); stepIndex = (stepIndex + 1) % 8;}// 控制步进电机转动到指定角度void StepperMotor_MoveToAngle(uint16_t targetAngle) { uint16_t steps = targetAngle - currentAngle; uint16_t absSteps = steps > 0 ? steps : -steps; uint8_t direction = steps > 0 ? 1 : -1; for (uint16_t i = 0; i < absSteps; i++) { StepperMotor_Step(); delay_ms(2); // 控制步进电机转动的速度 } currentAngle = targetAngle;}// 控制步进电机以指定速度连续转动void StepperMotor_MoveWithSpeed(uint8_t speed) { currentSpeed = speed; while (1) { StepperMotor_Step(); delay_ms(20 - currentSpeed); // 控制步进电机转动的速度 }}int main(void) { // 初始化步进电机控制引脚 StepperMotor_Init(); // 控制步进电机转动到指定角度 StepperMotor_MoveToAngle(ANGLE_1); // 控制步进电机以指定速度连续转动 StepperMotor_MoveWithSpeed(SPEED_1); while (1) { // 主循环中可以添加其他逻辑代码 }}5.3 LD3320识别代码以下是使用STM32F103的串口2接收LD3320语音识别结果并进行判断控制的代码:#include "stm32f10x.h"#include <stdio.h>// 定义LD3320串口通信引脚#define LD3320_RX_PIN GPIO_Pin_2#define LD3320_RX_PORT GPIOA#define LD3320_USART USART2// 定义接收缓冲区大小#define BUFFER_SIZE 128// 接收缓冲区volatile char rxBuffer[BUFFER_SIZE];volatile uint8_t rxIndex = 0;volatile uint8_t rxComplete = 0;// 初始化LD3320串口通信引脚void LD3320_UART_Init() { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); GPIO_InitStructure.GPIO_Pin = LD3320_RX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(LD3320_RX_PORT, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx; USART_Init(LD3320_USART, &USART_InitStructure); USART_ITConfig(LD3320_USART, USART_IT_RXNE, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_Cmd(LD3320_USART, ENABLE);}// 串口2中断处理函数void USART2_IRQHandler() { if (USART_GetITStatus(LD3320_USART, USART_IT_RXNE) != RESET) { char data = USART_ReceiveData(LD3320_USART); if (rxIndex < BUFFER_SIZE - 1) { rxBuffer[rxIndex++] = data; } if (data == '\n') { rxComplete = 1; } }}// 处理接收到的LD3320识别结果void ProcessLD3320Result() { // 在这里进行LD3320识别结果的判断和控制逻辑 // 可以根据接收到的字符串进行判断,例如使用strcmp()函数进行比较 // 示例:if (strcmp(rxBuffer, "ON") == 0) { // 执行打开操作 } // 清空接收缓冲区 rxIndex = 0; rxComplete = 0;}int main(void) { // 初始化LD3320串口通信引脚 LD3320_UART_Init(); while (1) { if (rxComplete) { ProcessLD3320Result(); } }}以上代码使用STM32F103的串口2接收LD3320语音识别结果并进行判断控制。代码中使用了串口2的接收中断来接收LD3320的识别结果。在中断处理函数USART2_IRQHandler()中,将接收到的数据存储到接收缓冲区rxBuffer中,并通过检测换行符\n来判断一条完整的识别结果是否接收完成。当识别结果接收完成时,调用ProcessLD3320Result()函数进行识别结果的判断和控制逻辑处理。在ProcessLD3320Result()函数中,可以根据接收到的字符串进行判断和控制逻辑的实现。例如,使用字符串比较函数strcmp()来比较接收到的字符串与预设的控制命令是否匹配,从而执行相应的操作。在这个函数中,可以添加你需要的控制逻辑,例如打开或关闭某个设备,执行特定的动作等。
  • [其他问题] 沙盒实验桌面没有script文件--MindSpore训练手写数字识别模型
    沙盒实验界面没有script文件,我看了桌面只有Xfce、谷歌、data文件夹。导致后面60%的实验都不能进行下去。请问这种情况怎么处理?
  • [训练管理] 云原生AI算法套件实现水表识别 训练报错ImportError: cannot import name 'string_metric' from 'rapidfuzz' (/home/ma-user/anaconda3/envs/PyTor
    如图,按实验手册操作后,报模块导入错误。
  • [获奖公告] 【云声·建议】提产品优化建议,领开发者定制飞盘
    23年【云声·建议】反馈活动第四场来啦~现在万物复苏,是不是已经按捺不住踏青的心情啦?小编贴心的备好出行好礼,有开发者定制飞盘和棒球帽快带上你的小伙伴一起来云声提建议吧!云声建议入口PS:华为云产品相关的有效建议分值更高,积分排名更容易靠前哟~【活动时间】4月1日-4月30日【活动对象】所有华为云用户如果您是老用户功能问题?体验不好?快来云声告诉我们吧!!云声建议入口(点击即可提交建议)如果您是新用户您也可以先去体验我们的免费产品服务~再来吐吐槽~可点击免费试用产品领取直达【奖项设置】有效建议总积分> 4:300元开发者大礼包(定制礼盒+飞盘+棒球帽)4≥ 有效建议总积分≥ 2 : 100元开发者大礼包(飞盘+棒球帽)PS:满足发放条件的前10名用户均可获得奖励哟(飞盘黑白色随机)【活动规则】1.有效建议积分云声关联产品/功能分为云产品建议、解决方案建议、平台建议,三种类型的建议对应的分值不相同,云产品建议(1分)、解决方案建议(0.5分)、平台建议(0.2分),按照当月有效建议类型对应不同分值以及邀请加分项来进行计算总排名,建议类型可在云声提建议页面查看;2.邀请用户加分a.每成功邀请一个用户,邀请者和被邀请者额外加0.2分,邀请加分可叠加,禁止互相推荐,否则双方都取消加分b.被邀请者在云声提交建议后,需要在本条帖子下方评论“被XXX邀请参加云声4月活动”,本此邀请才被认为有效邀请(4月双方都有在云声上提建议)示例:用户A邀请用户B参与云声建议反馈活动,用户B在云声提交优化建议后,在本帖下面评论“被A邀请参加云声4月活动”,则A和B用户各加0.2分c.邀请者和被邀请者双方需要完成华为云官方平台实名认证,否则为无效邀请3.注意事项a.若出现积分相同且排名一致的情况,在每月的已实现和已采纳建议中,会选出价值更高的建议给予奖励,基础评分计算规则,可参考如下表格。若同名次出现同分情况,由内部工作人员评选建议价值度更高的用户获奖以上建议数仅做示例,与实际情况无关,仅做计算参考b.同一用户在同一页面(文档)提出的同一类问题(包括但不限于错别字、语句不通顺、视觉体验等),在通过审核后仅算作一条有效建议数c.若发现代他人提交优化建议,此建议分值只取原分值30%d.如遇商品缺货,将随机换成其他等价值礼品发放
  • [其他] ModelArts使用sklearn例子
    notebook链接:https://developer.huaweicloud.com/develop/aigallery/notebook/detail?id=1589524b-3960-45e8-99e5-ac39b81afac3直接订阅,运行即可
  • [其他] AI产品和服务智能输入一个字便可作一首诗。
    AI产品和服务智能输入一个字便可作一首诗。
  • OK
    OKOKOKOKOK
  • [热门活动] 已完成华为云实践项目。
    已完成华为云实践的项目
  • [其他] 实践
    zhongyunonghaol
总条数:39 到第
上滑加载中