基于STM32的智能快递柜控制系统设计

450 阅读1小时+

一、前言

1.1 项目介绍

【1】项目开发背景

随着电子商务的迅猛发展,快递包裹数量持续激增,传统的快递派送方式在“最后一公里”环节面临效率低、成本高、用户体验差等诸多问题。智能快递柜作为一种新型的物流终端设备,凭借其便捷、高效、安全的特点,逐渐在小区、校园、写字楼等场所得到广泛应用。它不仅解决了收件人不在家时快递投递难的问题,还降低了快递员多次派送的劳动强度和时间成本,成为现代智慧物流体系中的重要一环。

在智能快递柜的实际使用中,用户认证、存取流程、数据管理以及系统安全性是设计与实现中的关键环节。当前市场上的智能快递柜多采用商用一体化解决方案,成本较高,维护复杂,不利于教学与小型场景的灵活部署。因此,基于嵌入式技术开发一套简洁、高效、可控的智能快递柜控制系统,对于高校教学、嵌入式项目实践以及中小型智能柜需求具有重要意义。

本项目基于STM32F103C8T6单片机作为核心控制器,结合RFID刷卡模块实现用户身份识别,配合电磁锁和继电器完成柜门控制;通过1.44寸LCD显示屏提供操作提示与状态反馈;利用ESP8266模块接入WiFi网络,将柜门状态和操作记录通过MQTT协议上传至华为云物联网平台,实现远程监控;系统还通过干簧管检测门的开关状态,确保信息的真实性与安全性。同时,Qt上位机软件可用于管理员远程查看设备状态和开门记录,形成完整的“云-端-人”交互闭环。

image.png

graph TD
    A[STM32F103C8T6 主控芯片]
    
    A --> B[MFRC522 RFID模块]
    A --> C[1.44寸TFT LCD显示屏]
    A --> D[继电器控制电磁锁]
    A --> E[干簧管门磁状态检测]
    A --> F[蜂鸣器提示模块]
    A --> G[ESP8266 WiFi模块]
    
    G --> H[华为云物联网平台 (MQTT协议)]
    H --> I[Qt上位机管理软件]
mindmap
  root((智能快递柜控制系统))
    硬件模块
      STM32F103C8T6
      MFRC522 RFID模块
      1.44寸TFT LCD
      电磁锁继电器
      干簧管门磁传感器
      蜂鸣器
      ESP8266 WiFi模块
    软件功能
      用户刷卡识别
      柜门开关控制
      门状态检测
      状态显示与提示
      数据联网上传
      云平台远程监控
      上位机管理软件
    通信协议
      MQTT协议
      华为云物联网平台
    系统特性
      实时性
      安全性
      远程管理
      数据可视化

【2】设计实现的功能

(1)通过RFID模块MFRC522识别用户IC卡,实现刷卡开锁功能,控制对应储物格的电磁锁打开。

(2)使用1.44寸TFT LCD显示屏,实时显示系统运行状态、用户操作提示及刷卡结果。

(3)通过干簧管+磁铁模块检测柜门的开关状态,实现柜门状态变化的实时反馈。

(4)利用ESP8266 WiFi模块连接无线网络,通过MQTT协议与华为云物联网平台通信,上传开门状态和操作记录数据。

(5)系统集成蜂鸣器模块,在刷卡成功、柜门关闭或异常操作等情况下提供声音提示。

(6)上位机使用Qt5开发,支持管理员查看各储物柜的当前状态、历史开门记录和用户操作日志。

(7)主控芯片STM32F103C8T6负责整体系统的逻辑控制、数据处理与各模块间的协调通信。

【3】项目硬件模块组成

(1)主控芯片模块:采用STM32F103C8T6单片机,作为系统的核心控制单元,负责各功能模块的协调控制与逻辑处理。

(2)RFID刷卡识别模块:使用MFRC522模块(SPI接口),用于识别用户IC卡,实现身份验证与开锁控制。

(3)LCD显示模块:采用1.44寸TFT LCD,用于实时显示系统状态、用户操作提示、刷卡反馈等信息。

(4)电磁锁控制模块:通过继电器驱动电磁锁,实现对储物柜门的开闭控制。

(5)联网通信模块:使用ESP8266 WiFi模块,接入局域网,通过MQTT协议连接华为云物联网平台,实现数据上传与远程监控。

(6)蜂鸣器提示模块:用于操作反馈音效提示,如刷卡成功、门未关、非法卡提示等。

(7)柜门状态检测模块:由干簧管与磁铁构成,用于检测柜门是否关闭,实现门状态监测与异常提醒。

(8)上位机模块:基于Qt5开发的Windows端管理软件,用于查看快递柜运行状态、开锁记录及用户信息管理。

【4】设计意义

随着快递业务的快速发展,传统的人工派送方式已无法满足日益增长的物流需求,尤其是在“最后一公里”环节,频繁的上门派送不仅增加了快递员的工作负担,也常常因为用户不在家而导致派送效率低下。智能快递柜作为现代物流体系的重要补充,凭借其便捷、安全、高效的特点,成为解决快递投递难题的重要手段,广泛应用于小区、校园、办公楼等场所。

本项目基于STM32F103C8T6单片机设计智能快递柜控制系统,具有良好的实用性与工程价值。通过集成RFID刷卡识别、电磁锁控制、柜门状态检测、LCD信息交互及ESP8266网络通信等功能,构建了一个完整的智能控制系统,满足快递柜核心功能的基本需求。系统可实现刷卡开锁、状态反馈、数据上传与本地提示,有效提高了快递投递与领取的效率。

此外,项目通过MQTT协议与华为云物联网平台对接,实现数据远程上传与监控管理,配合Qt开发的上位机软件,可方便管理员实时查看柜门状态与历史开锁记录,进一步提升系统的智能化与可视化水平。该设计不仅展示了嵌入式开发与物联网技术的综合应用,也具有较强的教学示范和项目实践价值,对于高校嵌入式课程设计及相关工程训练具有积极意义。

【5】市面上同类产品研究现状

目前,智能快递柜已广泛应用于各类社区、校园、企业和公共服务场所,成为物流行业中“最后一公里”配送的重要解决方案。市面上的主流产品主要由京东、菜鸟驿站、中邮速递易、丰巢等企业提供,它们在功能、技术架构、用户体验和数据管理方面不断优化和升级,形成了较为成熟的应用体系。

丰巢智能快递柜为例,其系统基于4G通信模块接入云平台,支持用户通过手机App扫码取件,快递员则通过专属终端或刷身份证完成投递。该系统配有高清摄像头、电子标签、电控锁和触摸屏界面,支持语音提示和远程管理,具有良好的用户交互体验。丰巢系统的云平台支持大数据分析,可进行用户行为跟踪、设备故障检测与远程维护,技术较为先进。

再如菜鸟驿站智能柜,其产品重点在于与阿里巴巴生态系统的深度融合,依托淘宝、支付宝等平台,实现快递自动入柜、短信通知、扫码取件等功能,后台系统支持海量用户并发操作,具备较强的系统稳定性和扩展性。此外,菜鸟驿站智能柜采用模块化设计,可根据场景扩展箱体数量,灵活部署。

与上述商用产品相比,本项目以STM32为核心的智能快递柜系统虽功能相对简化,但其结构清晰、模块独立、成本较低,适用于教学实验、小规模场景或定制化需求场所。同时,本设计也兼顾了联网通信、数据上传、状态反馈等关键功能,为探索低成本、可控性强的物联网终端设备提供了有益的技术参考。

【6】摘要

随着快递业务量的持续增长,传统派送方式在“最后一公里”环节面临效率低、管理难等问题。智能快递柜作为现代物流的重要组成部分,能够有效提升快递投递与领取的效率,改善用户体验。本项目设计并实现了一套基于STM32的智能快递柜控制系统。系统以STM32F103C8T6单片机为核心,集成MFRC522 RFID模块用于刷卡识别用户身份,控制电磁锁实现柜门开闭;通过1.44寸TFT LCD显示当前操作状态和提示信息;利用ESP8266 WiFi模块实现设备联网,并通过MQTT协议将柜门状态和开锁记录上传至华为云物联网平台。同时,采用干簧管检测柜门状态,配合蜂鸣器进行声音反馈。上位机软件由Qt5开发,实现对柜门状态和历史操作记录的可视化管理。该系统具备结构清晰、功能完善、运行稳定等特点,具有一定的实用性和推广价值。

关键字:

STM32;智能快递柜;RFID;ESP8266;MQTT协议;华为云;Qt上位机

1.2 设计思路

本项目的设计思路围绕“智能快递柜”的核心功能展开,采用模块化设计方式,以实现系统的可维护性、可扩展性和功能完整性。系统以STM32F103C8T6单片机为主控核心,结合各功能模块完成用户识别、柜门控制、状态显示、联网上传和数据管理等任务。整体设计思路遵循“用户→控制→反馈→管理”的流程,确保各环节协调一致,运行稳定。

在用户识别方面,采用MFRC522射频识别模块读取IC卡信息,通过SPI接口与STM32通信,主控芯片根据接收到的卡号进行身份验证和开锁控制。为提升用户体验,系统配备1.44寸TFT LCD屏幕,用于实时显示刷卡提示、开锁状态等操作信息,实现人机交互。

柜门的开关状态通过干簧管与磁铁实现检测,STM32定时读取该状态,当检测到柜门已打开或未关严时,可及时发出蜂鸣器提示,同时将状态信息发送到云端。电磁锁通过继电器进行驱动,由STM32控制其通断,实现柜门的物理开关控制。蜂鸣器用于操作结果的提示反馈,增强系统的互动性和安全性。

联网部分使用ESP8266模块连接WiFi,实现与华为云物联网平台的数据通信。系统通过MQTT协议将刷卡记录、柜门状态等信息上传至云端,便于远程查看与管理。为进一步提升系统的管理效率,开发了基于Qt5的上位机软件,支持管理员查看各柜子的当前状态、历史开锁记录和用户刷卡日志,增强系统的可控性与可视化能力。

整体上,本系统设计强调功能实用、结构清晰和通信可靠,硬件电路与软件逻辑相互配合,能够较好地满足智能快递柜在小型场景中的应用需求。

1.3 系统功能总结

功能模块实现功能描述
用户身份识别使用MFRC522 RFID模块识别IC卡,完成用户刷卡认证与柜门选择
储物格控制通过继电器控制电磁锁,实现指定储物柜的开锁与关锁操作
状态显示利用1.44寸TFT LCD显示屏,实时显示系统状态、操作提示、刷卡反馈等信息
柜门状态检测使用干簧管+磁铁检测柜门开关状态,判断是否开门或未关门
声音提示通过蜂鸣器在刷卡成功、操作错误、柜门未关等情况下发出提示音
网络通信采用ESP8266 WiFi模块连接互联网,通过MQTT协议将数据上传至华为云物联网平台
数据上传与云端管理上传柜门状态、刷卡时间、开锁记录等信息至云端,实现远程监控与数据留存
上位机管理基于Qt5开发的PC端软件,支持查看柜子状态、用户信息和开锁历史记录
系统控制核心STM32F103C8T6作为主控芯片,负责各模块间的数据处理、逻辑控制和状态管理

1.4 开发工具的选择

【1】设备端开发

硬件设备端的开发主要依赖于C语言,利用该语言直接操作硬件寄存器,确保系统运行的高效性和低延迟。C语言在嵌入式开发中具有广泛的应用,它能够直接访问硬件,满足对资源消耗和响应速度的严格要求。为了编写高效、稳定的代码,开发工具选择了Keil uVision 5作为主要的开发环境。Keil是一个专业的嵌入式开发工具,广泛应用于基于ARM架构的微控制器(如STM32)开发。Keil提供了完善的调试、编译和仿真支持,能够帮助在软件开发过程中高效地进行调试、单步执行以及断点设置,确保开发的稳定性和高效性。 STM32F103RCT6是项目中使用的主控芯片,它基于ARM Cortex-M3架构,拥有强大的计算能力和丰富的外设接口。在硬件编程中,寄存器级编程是常用的方式,这要求开发者对芯片的硬件寄存器有深入的理解。在Keil环境中,通过STM32的寄存器直接控制GPIO、ADC、I2C、SPI等硬件接口,以满足各个硬件模块(如传感器、执行器、显示屏等)与主控芯片的交互。使用寄存器编程能够提供更高效、精确的控制,避免了外部库的开销,同时也能深入调控硬件特性,提升系统性能。

【2】上位机开发

本项目的上位机开发基于Qt 5框架,使用**C++**作为主要编程语言。Qt是一个跨平台的应用开发框架,广泛用于开发GUI应用程序。Qt提供了丰富的GUI组件和工具,能够高效地实现图形界面的设计与开发。C++则作为Qt的底层语言,具有高效的性能和良好的控制力,非常适合用于处理设备与系统之间的数据交互、通信协议的实现和复杂的计算任务。在项目中,Qt被用于开发Windows平台的桌面应用程序以及Android平台的手机APP。Qt框架的跨平台特性使得开发者能够使用同一套代码在不同操作系统上进行构建和部署,大大提高了开发效率。

为了方便开发和调试,上位机的开发采用了Qt Creator作为主要的集成开发环境(IDE)。Qt Creator是一款由Qt官方提供的开发工具,专为Qt应用程序开发设计,支持C++、QML和JavaScript等语言。Qt Creator提供了丰富的功能,如代码编辑、调试、构建、版本控制集成等,能够显著提升开发者的生产力。在本项目中,Qt Creator为开发者提供了自动化构建、界面设计工具(如Qt Designer)和调试工具(如QDebug和QML调试工具),使得开发过程更加高效和流畅。 上位机与硬件设备端的通信采用了基于TCP/IP协议的数据传输方式。为了实现这一功能,Qt提供了丰富的网络编程支持,尤其是QTcpSocketQTcpServer类,使得上位机能够轻松地与硬件设备建立TCP连接,进行数据收发。上位机通过WIFI连接ESP8266-WIFI模块,ESP8266模块创建TCP服务器,上位机应用则作为客户端连接到服务器,进行实时的数据传输与控制命令的下发。 为了满足不同用户的需求,本项目需要支持Windows平台的桌面应用和Android平台的移动APP。Qt的跨平台特性使得开发人员能够在一个代码库下完成多平台应用的开发和移植。开发者仅需要编写一次应用逻辑和用户界面,就可以通过Qt的跨平台构建工具生成Windows和Android两个平台的可执行文件。此外,Qt提供了丰富的文档和社区支持,帮助开发者解决平台差异和兼容性问题,确保应用在不同平台上都能稳定运行。

总体而言,上位机开发环境采用了Qt 5框架和C++语言,结合Qt Creator集成开发环境,提供了一个高效、稳定、跨平台的开发工具链。通过Qt强大的GUI设计、网络通信、多线程支持以及数据库管理功能,开发者能够轻松实现与硬件设备的交互、控制设备、处理传感器数据,并为用户提供直观、流畅的操作体验。

1.5 华为云上传的属性字段

本项目中,基于STM32的智能快递柜控制系统通过 ESP8266 模块 连接至 华为云 IoT 平台,使用 MQTT 协议上传快递柜的运行数据。以下为上传至华为云平台的主要属性字段设计:

属性字段名数据类型描述说明示例值
cabinet_idString快递柜编号,唯一标识每个设备"CABINET_01"
card_idString用户刷卡的IC卡编号"0xA12B34C5"
locker_idInt被打开的储物格编号3
open_timeString开门操作发生的时间戳(上传时格式化)"2025-06-29 13:45:12"
door_statusBool当前柜门状态(true为打开,false为关闭)false
lock_statusBool电磁锁状态(true为通电打开,false为上锁)false
operation_resultString本次操作结果(如 "success""invalid_card" 等)"success"
buzzerBool蜂鸣器是否触发(提示音)true
signal_strengthIntWiFi信号强度(单位 dBm,便于远程诊断)-65
upload_timeString数据上传时间(服务器端记录或设备端时间)"2025-06-29 13:45:13"

数据上传格式建议(JSON 示例):

{
  "cabinet_id": "CABINET_01",
  "card_id": "0xA12B34C5",
  "locker_id": 3,
  "open_time": "2025-06-29 13:45:12",
  "door_status": false,
  "lock_status": false,
  "operation_result": "success",
  "buzzer": true,
  "signal_strength": -65,
  "upload_time": "2025-06-29 13:45:13"
}

二、部署华为云物联网平台

华为云官网: www.huaweicloud.com/

打开官网,搜索物联网,就能快速找到 设备接入IoTDA

image-20221204193824815

2.1 物联网平台介绍

华为云物联网平台(IoT 设备接入云服务)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助我们快速构筑物联网解决方案。

使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。

物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。

设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi等多种网络接入物联网平台,并使用LWM2M/CoAP、MQTT、HTTPS协议将业务数据上报到平台,平台也可以将控制命令下发给设备。

业务应用通过调用物联网平台提供的API,实现设备数据采集、命令下发、设备管理等业务场景。

img

2.2 开通物联网服务

地址: www.huaweicloud.com/product/iot…

image-20241028135834377

开通免费单元。

image-20241028135935457

点击立即创建

image-20240117134653452

正在创建标准版实例,需要等待片刻。

image-20241028140048811

创建完成之后,点击详情。 可以看到标准版实例的设备接入端口和地址。

image-20241028140129102

下面框起来的就是端口号域名

image-20241028140229696

点击实例名称,可以查看当前免费单元的配置情况。

image-20241028140331523

image-20241028140428663

开通之后,点击接入信息,也能查看接入信息。 我们当前设备准备采用MQTT协议接入华为云平台,这里可以看到MQTT协议的地址和端口号等信息。

image-20241028140511105

总结:

端口号:   MQTT (1883)| MQTTS (8883)    
接入地址: dab1a1f2c6.st1.iotda-device.cn-north-4.myhuaweicloud.com

根据域名地址得到IP地址信息:

打开Windows电脑的命令行控制台终端,使用ping 命令。ping一下即可。

Microsoft Windows [版本 10.0.19045.5011]
(c) Microsoft Corporation。保留所有权利。

C:\Users\Lenovo>ping dab1a1f2c6.st1.iotda-device.cn-north-4.myhuaweicloud.com

正在 Ping dab1a1f2c6.st1.iotda-device.cn-north-4.myhuaweicloud.com [117.78.5.125] 具有 32 字节的数据:
来自 117.78.5.125 的回复: 字节=32 时间=37ms TTL=44
来自 117.78.5.125 的回复: 字节=32 时间=37ms TTL=44
来自 117.78.5.125 的回复: 字节=32 时间=37ms TTL=44
来自 117.78.5.125 的回复: 字节=32 时间=37ms TTL=44

117.78.5.125 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 37ms,最长 = 37ms,平均 = 37ms

C:\Users\Lenovo>

MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口合适

2.3 创建产品

链接:console.huaweicloud.com/iotdm/?regi…

(1)创建产品

image-20241028141601305

(2)填写产品信息

根据自己产品名字填写,下面的设备类型选择自定义类型。

image-20240612094809689

(3)产品创建成功

image-20240612095148945

创建完成之后点击查看详情。

image-20240612095134263

(4)添加自定义模型

产品创建完成之后,点击进入产品详情页面,翻到最下面可以看到模型定义。

模型简单来说: 就是存放设备上传到云平台的数据。

你可以根据自己的产品进行创建。

比如:

烟雾可以叫  MQ2
温度可以叫  Temperature
湿度可以叫  humidity
火焰可以叫  flame
其他的传感器自己用单词简写命名即可。 这就是你的单片机设备端上传到服务器的数据名字。

先点击自定义模型。

image-20240612095517900

再创建一个服务ID。

image-20240612095542749

接着点击新增属性。

image-20240612095648815

image-20240612095711898

2.4 添加设备

产品是属于上层的抽象模型,接下来在产品模型下添加实际的设备。添加的设备最终需要与真实的设备关联在一起,完成数据交互。

(1)注册设备

image-20240425181935561

(2)根据自己的设备填写

image-20240612100115167

(3)保存设备信息

创建完毕之后,点击保存并关闭,得到创建的设备密匙信息。该信息在后续生成MQTT三元组的时候需要使用。

image-20240612100128061

(4)设备创建完成

image-20240612100147232

(5)设备详情

image-20240612100202960

image-20240612100217236

2.5 MQTT协议主题订阅与发布

(1)MQTT协议介绍

当前的设备是采用MQTT协议与华为云平台进行通信。

MQTT是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。MQTT是专门针对物联网开发的轻量级传输协议。MQTT协议针对低带宽网络,低计算能力的设备,做了特殊的优化,使得其能适应各种物联网应用场景。目前MQTT拥有各种平台和设备上的客户端,已经形成了初步的生态系统。

MQTT是一种消息队列协议,使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合,相对于其他协议,开发更简单;MQTT协议是工作在TCP/IP协议上;由TCP/IP协议提供稳定的网络连接;所以,只要具备TCP协议栈的网络设备都可以使用MQTT协议。 本次设备采用的ESP8266就具备TCP协议栈,能够建立TCP连接,所以,配合STM32代码里封装的MQTT协议,就可以与华为云平台完成通信。

华为云的MQTT协议接入帮助文档在这里: support.huaweicloud.com/devg-iothub…

img

业务流程:

img

(2)华为云平台MQTT协议使用限制

描述限制
支持的MQTT协议版本3.1.1
与标准MQTT协议的区别支持Qos 0和Qos 1支持Topic自定义不支持QoS2不支持will、retain msg
MQTTS支持的安全等级采用TCP通道基础 + TLS协议(最高TLSv1.3版本)
单帐号每秒最大MQTT连接请求数无限制
单个设备每分钟支持的最大MQTT连接数1
单个MQTT连接每秒的吞吐量,即带宽,包含直连设备和网关3KB/s
MQTT单个发布消息最大长度,超过此大小的发布请求将被直接拒绝1MB
MQTT连接心跳时间建议值心跳时间限定为30至1200秒,推荐设置为120秒
产品是否支持自定义Topic支持
消息发布与订阅设备只能对自己的Topic进行消息发布与订阅
每个订阅请求的最大订阅数无限制

(3)主题订阅格式

帮助文档地址:support.huaweicloud.com/devg-iothub…

image-20221207153310037

对于设备而言,一般会订阅平台下发消息给设备 这个主题。

设备想接收平台下发的消息,就需要订阅平台下发消息给设备 的主题,订阅后,平台下发消息给设备,设备就会收到消息。

如果设备想要知道平台下发的消息,需要订阅上面图片里标注的主题。

以当前设备为例,最终订阅主题的格式如下:
$oc/devices/{device_id}/sys/messages/down
    
最终的格式:
$oc/devices/663cb18871d845632a0912e7_dev1/sys/messages/down

(4)主题发布格式

对于设备来说,主题发布表示向云平台上传数据,将最新的传感器数据,设备状态上传到云平台。

这个操作称为:属性上报。

帮助文档地址:support.huaweicloud.com/usermanual-…

image-20221207153637391

根据帮助文档的介绍, 当前设备发布主题,上报属性的格式总结如下:

发布的主题格式:
$oc/devices/{device_id}/sys/properties/report
 
最终的格式:
$oc/devices/663cb18871d845632a0912e7_dev1/sys/properties/report
发布主题时,需要上传数据,这个数据格式是JSON格式。

上传的JSON数据格式如下:

{
  "services": [
    {
      "service_id": <填服务ID>,
      "properties": {
        "<填属性名称1>": <填属性值>,
        "<填属性名称2>": <填属性值>,
        ..........
      }
    }
  ]
}
根据JSON格式,一次可以上传多个属性字段。 这个JSON格式里的,服务ID,属性字段名称,属性值类型,在前面创建产品的时候就已经介绍了,不记得可以翻到前面去查看。

根据这个格式,组合一次上传的属性数据:
{"services": [{"service_id": "stm32","properties":{"你的字段名字1":30,"你的字段名字2":10,"你的字段名字3":1,"你的字段名字4":0}}]}

2.6 MQTT三元组

MQTT协议登录需要填用户ID,设备ID,设备密码等信息,就像我们平时登录QQ,微信一样要输入账号密码才能登录。MQTT协议登录的这3个参数,一般称为MQTT三元组。

接下来介绍,华为云平台的MQTT三元组参数如何得到。

(1)MQTT服务器地址

要登录MQTT服务器,首先记得先知道服务器的地址是多少,端口是多少。

帮助文档地址:console.huaweicloud.com/iotdm/?regi…

image-20240509193207359

MQTT协议的端口支持1883和8883,它们的区别是:8883 是加密端口更加安全。但是单片机上使用比较困难,所以当前的设备是采用1883端口进连接的。

根据上面的域名和端口号,得到下面的IP地址和端口号信息: 如果设备支持填写域名可以直接填域名,不支持就直接填写IP地址。 (IP地址就是域名解析得到的)

华为云的MQTT服务器地址:117.78.5.125
华为云的MQTT端口号:1883

如何得到IP地址?如何域名转IP? 打开Windows的命令行输入以下命令。

ping  ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com

image-20240425182610048

(2)生成MQTT三元组

华为云提供了一个在线工具,用来生成MQTT鉴权三元组: iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

打开这个工具,填入设备的信息(也就是刚才创建完设备之后保存的信息),点击生成,就可以得到MQTT的登录信息了。

下面是打开的页面:

image-20240425183025893

填入设备的信息: (上面两行就是设备创建完成之后保存得到的)

直接得到三元组信息。

image-20240509193310020

得到三元组之后,设备端通过MQTT协议登录鉴权的时候,填入参数即可。

ClientId  663cb18871d845632a0912e7_dev1_0_0_2024050911
Username  663cb18871d845632a0912e7_dev1
Password  71b82deae83e80f04c4269b5bbce3b2fc7c13f610948fe210ce18650909ac237

2.7 模拟设备登录测试

经过上面的步骤介绍,已经创建了产品,设备,数据模型,得到MQTT登录信息。 接下来就用MQTT客户端软件模拟真实的设备来登录平台。测试与服务器通信是否正常。

MQTT软件下载地址【免费】: download.csdn.net/download/xi…

(1)填入登录信息

打开MQTT客户端软件,对号填入相关信息(就是上面的文本介绍)。然后,点击登录,订阅主题,发布主题。

image-20240509193457358

(2)打开网页查看

完成上面的操作之后,打开华为云网页后台,可以看到设备已经在线了。

image-20240612100508790

点击详情页面,可以看到上传的数据:

image-20240612100529581

到此,云平台的部署已经完成,设备已经可以正常上传数据了。

(3)MQTT登录测试参数总结

MQTT服务器:  117.78.5.125
MQTT端口号:  183

//物联网服务器的设备信息
#define MQTT_ClientID "663cb18871d845632a0912e7_dev1_0_0_2024050911"
#define MQTT_UserName "663cb18871d845632a0912e7_dev1"
#define MQTT_PassWord "71b82deae83e80f04c4269b5bbce3b2fc7c13f610948fe210ce18650909ac237"

//订阅与发布的主题
#define SET_TOPIC  "$oc/devices/663cb18871d845632a0912e7_dev1/sys/messages/down"  //订阅
#define POST_TOPIC "$oc/devices/663cb18871d845632a0912e7_dev1/sys/properties/report"  //发布


发布的数据:
{"services": [{"service_id": "stm32","properties":{"你的字段名字1":30,"你的字段名字2":10,"你的字段名字3":1,"你的字段名字4":0}}]}

2.8 创建IAM账户

创建一个IAM账户,因为接下来开发上位机,需要使用云平台的API接口,这些接口都需要token进行鉴权。简单来说,就是身份的认证。 调用接口获取Token时,就需要填写IAM账号信息。所以,接下来演示一下过程。

地址: console.huaweicloud.com/iam/?region…

**【1】获取项目凭证 ** 点击左上角用户名,选择下拉菜单里的我的凭证

image-20240509193646253

image-20240509193701262

项目凭证:

28add376c01e4a61ac8b621c714bf459

【2】创建IAM用户

鼠标放在左上角头像上,在下拉菜单里选择统一身份认证

image-20240509193729078

点击左上角创建用户

image-20240509193744287

image-20240314153208692

image-20240314153228359

image-20240314153258229

创建成功:

image-20240314153315444

【3】创建完成

image-20240509193828289

用户信息如下:

主用户名  l19504562721
IAM用户  ds_abc
密码     DS12345678

2.9 获取影子数据

帮助文档:support.huaweicloud.com/api-iothub/…

设备影子介绍:

设备影子是一个用于存储和检索设备当前状态信息的JSON文档。
每个设备有且只有一个设备影子,由设备ID唯一标识
设备影子仅保存最近一次设备的上报数据和预期数据
无论该设备是否在线,都可以通过该影子获取和设置设备的属性

简单来说:设备影子就是保存,设备最新上传的一次数据。

我们设计的软件里,如果想要获取设备的最新状态信息,就采用设备影子接口。

如果对接口不熟悉,可以先进行在线调试:apiexplorer.developer.huaweicloud.com/apiexplorer…

在线调试接口,可以请求影子接口,了解请求,与返回的数据格式。

调试完成看右下角的响应体,就是返回的影子数据。

image-20240509194152229

设备影子接口返回的数据如下:

{
 "device_id": "663cb18871d845632a0912e7_dev1",
 "shadow": [
  {
   "service_id": "stm32",
   "desired": {
    "properties": null,
    "event_time": null
   },
   "reported": {
    "properties": {
     "DHT11_T": 18,
     "DHT11_H": 90,
     "BH1750": 38,
     "MQ135": 70
    },
    "event_time": "20240509T113448Z"
   },
   "version": 3
  }
 ]
}

调试成功之后,可以得到访问影子数据的真实链接,接下来的代码开发中,就采用Qt写代码访问此链接,获取影子数据,完成上位机开发。

image-20240509194214716

链接如下:

https://ad635970a1.st1.iotda-app.cn-north-4.myhuaweicloud.com:443/v5/iot/28add376c01e4a61ac8b621c714bf459/devices/663cb18871d845632a0912e7_dev1/shadow

三、Qt开发入门与环境搭建

当前项目的上位机是采用Qt开发的,这一章节主要是介绍Qt开发环境的安装,以及Qt开发环境入门的使用。如果你Qt没有任何基础,建议仔细看一遍。

3.1 Qt是什么?

Qt 是一个功能强大、跨平台的应用程序开发框架,主要用于创建图形用户界面(GUI)应用程序,但它不仅仅局限于GUI编程。它由挪威的奇趣科技(TrollTech)最初于1991年开发,并在后续的发展历程中经历了多次所有权变更,包括诺基亚和Digia等公司接手,现在Qt属于The Qt Company所有。

Qt 主要特点和优势包括:

(1)跨平台:Qt 支持多种操作系统,开发者可以使用同一份源代码在不同平台上编译运行,如Windows、Linux、macOS、Android以及各种嵌入式系统(如RTOS),实现“一次编写,到处编译”。

(2)C++ 开发:Qt 的核心是基于C++编程语言构建,提供了一套丰富的类库,通过面向对象的设计方式简化了开发过程。

(3)图形用户界面:Qt 提供了完整的GUI组件集,包含窗口、按钮、标签、文本框等各种标准控件,以及布局管理器、样式表等功能,使得开发者能够高效地创建美观且功能完善的桌面应用或移动应用界面。

(4)工具链完整:Qt 包含一系列集成开发环境(IDE)和辅助工具,例如Qt Creator是一个全能的跨平台IDE,Qt Designer用于可视化拖拽设计UI界面,Qt Linguist支持国际化资源文件的翻译,还有Qt Assistant和大量文档资源方便开发者的使用。

(5)非GUI功能丰富:除了GUI功能外,Qt 还提供了众多非图形化功能模块,如网络通信、数据库访问、XML处理、多媒体处理(音频视频)、文件I/O、线程与并发处理、OpenGL和3D图形渲染等。

(6)元对象系统:Qt 使用元对象系统(Meta-Object System, MOC)实现了信号与槽机制(Signals and Slots),这是一种高级事件处理机制,允许在不同对象之间安全地进行异步通信。

(7)可扩展性与灵活性:Qt 架构高度灵活,支持插件体系结构,开发者可以根据需要自定义组件并轻松地集成到Qt应用中。

Qt 以其强大的跨平台能力和全面的功能集合成为许多企业和个人开发者选择用来开发高性能、高稳定性的应用程序的重要工具之一,被广泛应用于各类桌面软件、嵌入式设备、移动应用以及服务器端组件等领域。

3.2 Qt版本介绍

在Qt发行版本中将要涉及两个版本:Qt商业授权和Qt开源授权。

(1)Qt商业授权是设计商业软件的开发环境,这些商业软件使用了传统的商业来发布,它包含了一些更新的功能、技术上的支持和大量的解决方案,开发了使用于行业的一些特定的组件,有一些特殊的功能只在商业用户中使用。

(2)Qt开源授权是用来开发开源的软件,它提供了一些免费的支持,并遵循QPL协议。

开放源代码是免费的软件,不牵涉用户的某些权益。任何人都有使用开源软件和参与它的修改的机会,这就意味着其他的人同样可获得你开发的代码。目前 Qt 的开源授权有两种,一种是 GPL 授权,另一种是 LGPL 授权。

3.3 Qt开发环境安装

Qt的中文官网: www.qt.io/zh-cn/![ima…

image-20221207160606892

QT5.12.6的下载地址:download.qt.io/archive/qt/…

打开下载链接后选择下面的版本进行下载:

qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details

软件安装时断网安装,否则会提示输入账户。

如果下载不了,可以在网盘里找到安装包下载: 飞书文档记录的网盘地址:ccnr8sukk85n.feishu.cn/wiki/QjY8we…

安装的时候,第一个复选框里勾选一个mingw 32编译器即可,其他的不管默认就行,直接点击下一步继续安装。

image-20221203151742653

选择MinGW 32-bit 编译器:

image-20221203151750344

3.4 开发第一个QT程序

在QT开发过程中,可以手动编写代码也可以使用UI设计师直接拖拽控件的方式编写界面和布局,在实际的开发过程中一般是两种方式结合使用,提高开发效率。

本小节用一个简单的 "Hello QT" 程序介绍一下使用QtCreator新建工程的步骤

(1)打开QtCreator软件,选择New Project,新建一个工程。

image-20240304134953164

(2)项目模板选择QT Widgets Application

image-20240304135416497

(3)设置项目名称和存放路径

注意:QT项目路径和名称不能出现中文字符。

image-20240304135504345

(4)编译工具套件选择

编译工具套件可以后面自己增加,比如增加Android的。套件是指 Qt 程序从编译链接到运行环境的全部工具和 Qt 类库的集合。

image-20240304135535341

(5)设置生成的类信息

在类信息设置界面选择基类,目前有三种基类:QMainWindow,QWidget,QDialog。在基类里选择QMainWindow,类名和文件名会根据基类自动修改,一般不需要修改,默认即可。

image-20240304135630942

(6)项目管理

在项目管理界面可以设置作为子项目,以及加入版本控制系统。这两个功能暂时用不到,都用默认的 ,然后点击 “完成”。

image-20240304135652922

(7)创建完成

image-20240304135728165

(8) 编辑代码

展开main.cpp文件,添加内容如下:

#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QLabel>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //MainWindow w;
    //w.show();
    QLabel *label =new QLabel("Hello Qt!");
    label->setGeometry(400,100,100,20);
    label->show();
    return a.exec();
}

代码解析:

1)	#include <QApplication>和 #include <QLabel>是QT的类声明头文件,对于每个QT类都有一个与该类同名的头文件,在这个头文件包含了对该类的定义。
2)	main(int argc, char *argv[]) :main函数的标准写法。
3)	QApplication a(argc, argv):创建一个QApplication对象,用于管理应用程序的资源,QApplication类的构造函数需要两个参数。
4)	QLabel *label =new QLabel("Hello Qt!") :创建QLabel窗口部件,QLabel是一个Qt提供的窗口部件,可以用来显示一行文本。
5)	label->setGeometry(400,100,100,20) : 设置控件显示的位置。
6)	label->show():使Qlabel创建的窗口可见,就是显示设置的文本。
7)	return a.exec():应用程序将控制权传递给QT,让程序进入消息循环。等待可能的菜单,工具条,鼠标等的输入,进行响应。

image-20240304135908750

(9)行程序

运行程序可以点击左下角的三角形符号或者按下快捷键Ctrl+R。

image-20240304135938848

3.5 调试输出

QT中使用QDebug类输出调试信息。主要用于调试代码,类似于std::cout的替代品,支持QT的数据类型。使用前需要包含头文件。

调试输出的分类

qDebug调试信息提示
qWarning一般的警告提示
qCritical严重错误提示
qFatal致命错误提示

示例代码:

qDebug("调试信息输出");
qWarning("一般警告信息输出");
qCritical("严重错误输出");
qFatal("致命错误输出");

qDebug输出的信息会打印到QT软件下边的输出面板。

在上节的HelloQt工程上加上调试输出代码,增加的main.cpp代码如下:

#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //MainWindow w;
    //w.show();
    qDebug()<<"QT调试信息输出";
    int data_int=8888;
    qDebug()<<data_int;
    float data_float=123.888;
    qDebug()<<data_float;
    return a.exec();
}

运行程序,观察输出的调试信息:

image-20240304140142790

3.6 QT Creator常用的快捷键

掌握一些适用的快捷键,可以提高程序开发的效率。

(1)F1 键,快速切换光标选中的函数或者类的帮助信息,按一次半屏显示,按下两次全屏显示。

(2)F2 键,快速切换到光标选中的函数或者类的源码定义处。

(3)F4键,快速在源文件和头文件之间切换。

(4)Ctrl(按住)+ Tab,快速切换已打开的文件

(5)Ctrl+ I ,缩进光标选中行代码(自动与上层代码对齐)。

(6)Ctrl + / ,快速注释或者取消注释光标选中行。

(7)快速修改全局变量名

鼠标光标选中变量名,按下Ctrl+Shift+R,当变量名称出现红色框表示已经激活全局修改功能。修改一处,整个工程对应变量名称全部会修改。修改完毕之后,光标移开,再按下Ctrl+Shift+R保存修改。

image-20240304140242113

(8)快速修改全局函数名

快捷方式与变量修改一样按下Ctrl+Shift+R,一处修改整个工程对应的函数名称也会跟着改。选中函数后,按下Ctrl+Shift+R后整个工程的对应的函数名会高亮,并且在软件下方弹出修改框。

image-20240304140311742

3.7 QT帮助文档

Qt 帮助文档太多,难以全部翻译成中文,即使翻译了一部分,翻译花的时间太多,翻译更新的时效性也难以保证,最终还是得看英文帮助,QtCreator 集成了帮助系统,查找非常方便。

打开QtCreator,选择菜单栏的最左边的帮助选项,界面如下:

image-20240304140337833

(1)查看Qlabel控件的帮助信息:

image-20240304140357011

3.8 UI设计师使用

上节的Hello QT程序使用纯C++代码编写,这一节使用QT界面设计模式实现与上一节Hello QT程序一样的功能。仿照着上节新创建一个工程。双击打开mainwindow.ui文件,进入到UI设计界面。

(1)拖一个Label控件到编辑区,双击Label控件可以修改文本内容。

image-20240304140517858

(2)运行程序可以点击左下角的三角形符号或者按下快捷键Ctrl+R。

image-20240304140600717

(3)UI设计师界面功能介绍

image-20240304140615717

3.9 按钮控件组

QT Creator UI设计师界面的按钮组截图如下:

image-20240304140809093

以下是对按钮组控件的一些功能介绍:

(1)Push Button按压按钮:最普通的按钮,按(点击)按钮命令计算机执行一些动作,或者回答问题,比如windows开始菜单里的重启,注销,关机等按钮。

(2)Tool Button工具按钮:工具按钮通常是一个集合,一般集成在工具栏里。比如打开,保存,复制,粘贴,剪切等常用的操作。

(3)Radio Button单选按钮:单选按钮通常是两个以上的形式出现在一块,按钮之间有互斥关系,每次只能选中一个。比如:一个人的性别只能选择一个,不能同时是男性又是女性。

(4)Check Box复选框:复选框与单选按钮概念相反,复选框通常表示多个可以同时存在的选项,比如一个人可以同时拥有多个爱好,比如读书、看电影、爬山、游泳等。

(5)Command Link Button命令链接按钮:一般用来打开的窗口或者网页链接。

(6)Dialog Button Box标准按钮盒:标准按钮盒通常用于对话框程序;比如:常见的确认对话框有 “确定”“取消”等标准按钮,Qt 将这些典型的按钮做成标准按钮盒,并将相应的信号加以封装,方便程序员使用。

3.10 布局控件组

开发一个图形界面应用程序,界面的布局影响到界面的美观。前面的程序中都是使用UI界面拖控件,如果有多个按钮,会出现大小难调整、位置难对齐等问题。Qt 提供的“布局管理“就很好的解决了控件摆放的问题。

以下是UI设计师界面的布局相关控件组:

image-20240304140914361

功能介绍:

(1)Vertical Layout:垂直布局

(2)Horizontal Layout:水平布局

(3)Grid Layout:网格布局

(4)Form Layout:窗体中布局

(5)Horizontal Spacers:水平空格,在布局中用来占位。

(6)Vertical Spacer:垂直空格,在布局中用来占位。

image-20240304140956243

3.11 基本布局控件

在UI设计界面添加一个布局控件,然后将需要布局的其他控件放入布局控件中即可完成布局,布局控件可以互相嵌套使用。(本节只介绍基本布局控件的使用)

以下是4种布局控件的效果:

image-20240304141035428

3.12 UI设计师的布局功能

在UI设计界面的左上角有一排快捷的布局选项,使用时选中两个以上的控件,点击其中一种布局方式就可以切换布局。

以下为布局的简单示例图:

image-20240304141115657

(1)为布局的选项。

(2)控件层次图,可以看到控件的布局摆放层次。

如果想要控制某个控件的固定大小,不随着布局改变大小,可以限定最大最小尺寸。选中控件鼠标右键-->大小限定->设置大小。

image-20240304141311256

水平布局与垂直布局:

image-20240304141335977

image-20240304141347209

水平布局将控件按照水平方式摆放,垂直布局将控件按照垂直方式摆放。鼠标拖动红色布局框上的黑色方点,可以调整布局框的大小。随着布局框的尺寸变化,包含的控件高度不会变化,宽度会随着布局框变化。选中其中一个控件然后鼠标右键>点击大小限定,可以限定控件的最大和最小尺寸。

分裂器水平布局与垂直布局:

image-20240304141412287

image-20240304141426088

分裂器方式布局,包含控件的高度和宽度都会随着布局框的拉伸而改变。选中其中一个控件然后鼠标右键>点击大小限定,可以限定控件的最大和最小尺寸。

窗体中布局与栅格布局:

image-20240304141449390

栅格(网格)布局器的基本单元是单元格,而窗体中布局(表单)的基本单元是行。随着布局框的尺寸变化,包含的控件高度不会变化,宽度会随着布局框变化。

设置主窗体布局方式:

设置主窗体的布局方式后,包含在主窗体内的控件会随着窗体的拉伸自动调整大小。

image-20240304141518067

image-20240304141529003

四、上位机开发

4.1 Qt开发环境安装

Qt的中文官网: www.qt.io/zh-cn/![ima…

image-20221207160606892

QT5.12.6的下载地址:download.qt.io/archive/qt/…

打开下载链接后选择下面的版本进行下载:

如果下载不了,可以在网盘里找到安装包下载: 飞书文档记录的网盘地址:ccnr8sukk85n.feishu.cn/wiki/QjY8we…

软件安装时断网安装,否则会提示输入账户。

安装的时候,第一个复选框里的编译器可以全选,直接点击下一步继续安装。

image-20221203151742653

选择编译器: (一定要看清楚了)

image-20241028152725134

4.2 新建上位机工程

前面2讲解了需要用的API接口,接下来就使用Qt设计上位机,设计界面,完成整体上位机的逻辑设计。

【1】新建工程

image-20240117144052547

【2】设置项目的名称。

image-20250420200347498

【3】选择编译系统

image-20240117144239681

【4】选择默认继承的类

image-20240117144302275

【5】选择编译器

image-20241028153603487

【6】点击完成

image-20240117144354252

【7】工程创建完成

image-20250420200411303

4.3 切换编译器

在左下角是可以切换编译器的。 可以选择用什么样的编译器编译程序。

目前新建工程的时候选择了2种编译器。 一种是mingw32这个编译Windows下运行的程序。 一种是Android编译器,可以生成Android手机APP。

不过要注意:Android的编译器需要配置一些环境才可以正常使用,这个大家可以网上找找教程配置一下就行了。

windows的编译器就没有这么麻烦,安装好Qt就可以编译使用。

下面我这里就选择的 mingw32这个编译器,编译Windows下运行的程序。

image-20250420200424965

4.4 编译测试功能

创建完毕之后,编译测试一下功能是否OK。

点击左下角的绿色三角形按钮

image-20250420200442769

正常运行就可以看到弹出一个白色的框框。这就表示工程环境没有问题了。 接下来就可以放心的设计界面了。

image-20250420200457319

4.5 设计UI界面与工程配置

【1】打开UI文件

image-20250420200514220

打开默认的界面如下:

image-20250420200526194

【2】开始设计界面

根据自己需求设计界面。

4.6 设计代码

【1】获取token

调用华为云的API都需要填token参数,先看帮助文章,了解如何获取token。

帮助文档:support.huaweicloud.com/api-iam/iam…

image-20221207175635181

根据帮助文档,写完成下面代码编写:

image-20250402143229329

这段代码的功能是通过华为云IAM服务获取Token,以便后续调用华为云API时使用。以下是代码的详细功能解释:


1. 设置功能标识
function_select = 3;
  • function_select是一个标识变量,用于区分当前请求的功能类型。这里设置为3,表示当前请求是获取Token。

2. 构造请求URL
QString requestUrl;
QNetworkRequest request;

// 设置请求地址
QUrl url;

// 获取token请求地址
requestUrl = QString("https://iam.%1.myhuaweicloud.com/v3/auth/tokens")
             .arg(SERVER_ID);
  • 构造获取Token的请求URL,URL格式为:https://iam.{SERVER_ID}.myhuaweicloud.com/v3/auth/tokens
  • SERVER_ID是华为云服务器的区域ID(如cn-north-1),通过QStringarg方法动态替换到URL中。

3. 设置请求头
// 设置数据提交格式
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));
  • 设置HTTP请求头,指定请求体的数据格式为application/json;charset=UTF-8,表示发送的数据是JSON格式。

4. 设置请求URL
// 构造请求
url.setUrl(requestUrl);
request.setUrl(url);
  • 将构造好的URL设置到QUrl对象中,并将其绑定到QNetworkRequest对象。

5. 构造请求体
QString text = QString("{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":"
"{\"user\":{\"domain\": {"
"\"name\":\"%1\"},\"name\": \"%2\",\"password\": \"%3\"}}},"
"\"scope\":{\"project\":{\"name\":\"%4\"}}}}")
        .arg(MAIN_USER)
        .arg(IAM_USER)
        .arg(IAM_PASSWORD)
        .arg(SERVER_ID);
  • 构造JSON格式的请求体,用于向华为云IAM服务请求Token。请求体包含以下字段:
    • auth:认证信息。
      • identity:身份信息。
        • methods:认证方法,这里使用密码认证(password)。
        • password:密码认证的具体信息。
          • user:用户信息。
            • domain:用户所属的域名。
              • name:域名名称(MAIN_USER)。
            • name:用户名(IAM_USER)。
            • password:用户密码(IAM_PASSWORD)。
      • scope:请求的范围。
        • project:项目信息。
          • name:项目名称(SERVER_ID)。
  • 使用QStringarg方法动态替换请求体中的变量(如MAIN_USERIAM_USER等)。

6. 发送HTTP POST请求
// 发送请求
manager->post(request, text.toUtf8());
  • 使用QNetworkAccessManagerpost方法发送HTTP POST请求。
  • request是构造好的请求对象,text.toUtf8()是将请求体转换为UTF-8编码的字节数组。

7. 总结

这段代码的核心功能是:

  1. 构造获取Token的HTTP请求:包括请求URL、请求头和请求体。
  2. 发送请求:通过QNetworkAccessManager发送POST请求,向华为云IAM服务请求Token。
  3. Token的作用:获取到的Token将用于后续调用华为云API时的身份验证。

通过这段代码,QT上位机能够获取华为云的Token,为后续的设备数据查询、控制等操作提供身份验证支持。

【2】获取影子数据

前面章节介绍了影子数据获取接口。下面是对应编写的代码:

image-20250402143256287

这段代码的功能是向华为云IoT平台查询设备的属性信息(设备状态)。以下是对代码的详细功能含义解释:

代码功能含义解释:

(1)function_select = 0;

  • 这行代码设置function_select为0,表示当前操作是查询设备属性。这个变量用于标识不同的操作,可以帮助后续根据不同的操作类型执行不同的处理逻辑。

(2)QString requestUrl; QNetworkRequest request;

  • requestUrl:用于存储请求的URL地址,后续将构造一个用于查询设备属性的URL。
  • request:用来封装HTTP请求的对象,包含请求的所有信息,包括请求头、URL等。

(3)QUrl url;

  • url:用于存储并处理请求的URL对象,确保请求使用正确的地址。

(4)构造请求URL:

requestUrl = QString("https://%1:443/v5/iot/%2/devices/%3/shadow")
             .arg(IP_ADDR)
             .arg(PROJECT_ID)
             .arg(device_id);

这行代码构建了一个URL,用于查询设备的状态(属性)。URL包括了:

IP_ADDR:华为云IoT平台的IP地址或域名。

PROJECT_ID:项目的ID,用于区分不同的项目。

device_id:设备的唯一标识符,用于查询指定设备的属性。

:443指定使用HTTPS协议(端口443)进行安全通信。

最终构造出的URL形如:https://<IP_ADDR>:443/v5/iot/<PROJECT_ID>/devices/<device_id>/shadow,这是查询设备状态的API接口。

(1)request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

  • 设置请求头的内容类型为application/json,表明请求体中的数据格式是JSON。

(2)request.setRawHeader("X-Auth-Token", Token);

  • 设置请求头中的X-Auth-Token字段,传递身份验证令牌(Token)。这个令牌用于验证请求的合法性,确保只有授权的用户可以查询设备的状态。

(3)url.setUrl(requestUrl);

  • 将前面构建好的请求URL赋值给url对象,确保后续的请求使用正确的URL。

(4)request.setUrl(url);

  • url对象设置到request对象中,准备发送请求。

(5)manager->get(request);

  • 使用QNetworkAccessManagerget方法发送GET请求,查询设备的属性。request中包含了URL、请求头以及Token等信息,服务器接收到请求后将返回设备的属性信息(如设备状态、属性值等)。

代码整体功能:

该代码实现了通过华为云IoT平台的API查询设备的属性信息。具体步骤包括:

  1. 构造查询设备属性的API请求URL。
  2. 设置请求头,指定数据格式为JSON,并传递Token进行身份验证。
  3. 使用QNetworkAccessManager发送GET请求,向服务器请求设备的状态数据。
  4. 服务器将返回设备的属性数据,供后续处理。

总结:

这段代码的功能是向华为云IoT平台查询指定设备的属性信息,并通过GET请求将设备的状态返回给客户端。通过Token进行身份验证,确保请求的合法性。

【3】解析数据更新界面

根据接口返回的数据更新界面。

【4】判断设备是否离线

这段代码用于判断设备是否离线。通过获取设备上传到服务器数据的时间与本地的系统时间差进行对比。

image-20250402143349492

这段代码的核心功能是通过比较设备上传数据的时间和本地系统时间来判断设备是否处于离线状态,以下是其详细解释:


(1)功能分析

显示最新更新时间

ui->label_update_time->setText("最新时间:" + update_time);

将设备上传的最新时间 update_time 显示在界面上的 label_update_time 控件中,格式为 最新时间:yyyy-MM-dd HH:mm:ss

方便用户了解设备数据的最近更新时间。

获取本地当前时间

QDateTime currentDateTime = QDateTime::currentDateTime();

使用 QDateTime::currentDateTime() 获取系统当前时间,作为对比基准。

计算时间差

qint64 secondsDiff = currentDateTime.secsTo(dateTime);

secsTo: 计算 currentDateTime 和设备上传时间 dateTime 之间的时间差(单位:秒)。

dateTime 是通过解析 JSON 数据提取到的设备数据上传时间,并已转换为本地时间格式。

判断设备状态

if (qAbs(secondsDiff) >= 5 * 60)

使用 qAbs 获取时间差的绝对值。

如果时间差超过 5 分钟(300秒),表示设备长时间未上传数据,判定为“离线”。


(2)离线处理

更新状态显示

ui->label_dev_state->setText("设备状态:离线");

在界面 label_dev_state 控件中显示设备当前状态为“离线”。


(3)在线处理

状态更新ui->label_dev_state->setText("设备状态:在线");如果时间差小于 5 分钟,显示“设备状态:在线”。

【5】获取设备最新数据上传时间

这是解析华为云API接口返回的数据,解析出来里面设备数据的时间,进行显示。

image-20250402143424863

这段代码的主要作用是解析华为云 API 返回的 JSON 数据中的设备数据时间字段,转换为本地时间格式,并最终以用户友好的标准格式输出到界面。


(1)详细代码解析

(1)提取时间字段

QString event_time = obj3.take("event_time").toString();
qDebug() << "event_time:" << event_time;

obj3.take("event_time"):从 JSON 数据中的 reported 对象提取 event_time 字段,值为一个字符串,表示设备上传数据的时间。

toString():将提取的字段值转换为 QString 类型,便于后续操作。

调试输出:使用 qDebug() 输出提取的时间值,例如:20231121T120530Z

2. 转换为 QDateTime 对象

QDateTime dateTime = QDateTime::fromString(event_time, "yyyyMMddTHHmmssZ");

QDateTime::fromString:

使用指定格式解析 event_time 字符串为 QDateTime 对象。

格式说明:

  • yyyyMMdd: 年、月、日(如 20231121)。

  • T: 时间部分的分隔符(固定为 T)。

  • HHmmss: 时、分、秒(如 120530)。

  • Z: 表示时间是 UTC 时间。

  • 如果时间字符串格式不匹配,会返回一个无效的 QDateTime 对象。

3. 转换时区到本地时间

dateTime.setTimeSpec(Qt::UTC);
dateTime = dateTime.toLocalTime();

setTimeSpec(Qt::UTC):

  • 明确告知 dateTime 对象,当前时间是 UTC 时间。
  • 确保时间转换准确,避免因为默认时区不明确导致的误差。

toLocalTime():

  • 将时间从 UTC 转换为本地时区时间,例如中国标准时间(CST, UTC+8)。

4. 格式化输出为标准时间字符串

QString update_time = dateTime.toString("yyyy-MM-dd HH:mm:ss");

toString():将 QDateTime 转换为指定格式的字符串。

格式说明:

  • yyyy-MM-dd: 年-月-日。
  • HH:mm:ss: 小时:分钟:秒。

示例结果:2023-11-21 20:05:30

用户显示友好性:转换后的格式易读,符合国际通用的日期时间表示规范。


(2)代码运行效果

假设 API 返回的时间字段值为 20231121T120530Z

转换流程:

  1. 解析为 QDateTime 对象:2023-11-21 12:05:30 (UTC);
  2. 转换为本地时间:2023-11-21 20:05:30 (CST)
  3. 格式化输出:"2023-11-21 20:05:30"

输出到界面时,显示为:

最新时间: 2023-11-21 20:05:30

4.5 编译Windows上位机

点击软件左下角的绿色三角形按钮进行编译运行。

image-20250402144112519

4.6 配置Android环境

如果想编译Android手机APP,必须要先自己配置好自己的Android环境。(搭建环境的过程可以自行百度搜索学习)

然后才可以进行下面的步骤。

【1】选择Android编译器

选择编译器。

image-20240425232651515

切换编译器。

image-20250402144840442

【2】创建Android配置文件

image-20240117144604025

image-20240117144635052

image-20240117144652014

创建完成。

image-20250402144902155

【3】配置Android图标与名称

根据自己的需求配置 Android图标与名称。

image-20250613111054529

【3】编译Android上位机

Qt本身是跨平台的,直接选择Android的编译器,就可以将程序编译到Android平台。

然后点击构建。

image-20250613111041456

成功之后,在目录下可以看到生成的apk文件,也就是Android手机的安装包,电脑端使用QQ发送给手机QQ,手机登录QQ接收,就能直接安装。

生成的apk的目录在哪里呢? 编译完成之后,在控制台会输出APK文件的路径。

知道目录在哪里之后,在Windows的文件资源管理器里,找到路径,具体看下图,找到生成的apk文件。

image-20250402145406894

File: D:/QtProject/build-333_QtProject-Android_for_arm64_v8a_Clang_Qt_5_12_6_for_Android_ARM64_v8a-Release/android-build//build/outputs/apk/debug/android-build-debug.apk

4.7 设备仿真调试

通过MQTT客户端模拟设备登录华为云服务器。进行设备联调,实现数据上传和下发测试。

五、STM32代码设计

5.1 硬件连线说明

  1. STM32F103C8T6主控芯片
    • 作为系统核心,负责控制和协调各模块的工作。
  2. MFRC522 RFID模块(SPI接口)
    • 连接接口:
      • SDA(SS) — PA4(SPI片选)
      • SCK — PA5(SPI时钟)
      • MOSI — PA7(SPI主出从入)
      • MISO — PA6(SPI主入从出)
      • RST — PB0(复位引脚)
      • IRQ — 未使用或连接至中断口(可选)
    • 说明:SPI总线连接至STM32对应的SPI1接口,PA4作为片选信号。
  3. 1.44寸TFT LCD显示模块
    • 连接接口(SPI通讯):
      • CS — PB12(片选)
      • RESET — PB13(复位)
      • DC(数据/命令) — PB14
      • SCK — PA5(SPI时钟,复用同RFID)
      • MOSI — PA7(SPI主出从入,复用同RFID)
      • LED — 3.3V电源(背光控制可接PWM或高电平)
      • GND — 地
    • 说明:LCD与MFRC522共用SPI总线,片选和控制信号独立。
  4. 继电器控制电磁锁模块
    • 控制线连接:
      • 控制信号 — PB1(GPIO输出,驱动继电器)
      • 继电器供电和电磁锁电源根据继电器模块规格连接
    • 说明:通过GPIO口控制继电器开关,进而控制电磁锁通断。
  5. ESP8266 WiFi模块
    • 连接接口(串口通信):
      • TX — PA10(STM32 USART1 RX)
      • RX — PA9(STM32 USART1 TX)
      • CH_PD(使能) — 3.3V
      • VCC — 3.3V
      • GND — 地
    • 说明:使用串口1进行AT命令通信,实现联网功能。
  6. 蜂鸣器提示模块
    • 连接接口:
      • 控制端 — PB2(GPIO输出)
      • 电源和地根据蜂鸣器模块规格连接
    • 说明:通过GPIO口控制蜂鸣器鸣响。
  7. 柜门状态检测(干簧管+磁铁)
    • 连接接口:
      • 一端接3.3V或5V电源
      • 另一端接PA0(GPIO输入,带上拉或下拉)
    • 说明:门关闭时磁铁吸合干簧管,改变GPIO电平,实现开关状态检测。

5.2 传感器代码

当前项目使用的相关软件工具、模块源码已经上传到网盘:ccnr8sukk85n.feishu.cn/wiki/QjY8we…

本项目智能快递柜传感器模块代码

  • MFRC522 RFID模块读卡代码
  • 干簧管门磁检测代码
  • 蜂鸣器控制代码

1. MFRC522 RFID模块代码(SPI)

mfrc522.h
#ifndef __MFRC522_H
#define __MFRC522_H

#include "stm32f1xx_hal.h"

// MFRC522 SPI接口相关定义
#define MFRC522_SPI_HANDLE    hspi1  // 你需要在main.c中定义或extern声明SPI句柄

// MFRC522寄存器地址(示例,实际可参考MFRC522手册补充)
#define CommandReg           0x01
#define ComIEnReg            0x02
#define DivIEnReg            0x03
#define ComIrqReg            0x04
#define DivIrqReg            0x05
#define FIFODataReg          0x09
#define FIFOLevelReg         0x0A
#define ControlReg           0x0C
#define BitFramingReg        0x0D
#define ModeReg              0x11
#define TxControlReg         0x14

// 初始化
void MFRC522_Init(void);

// 读取一张卡,返回是否成功读取卡号
uint8_t MFRC522_Request(uint8_t req_mode, uint8_t *tag_type);

// 防冲突检测,返回卡号长度
uint8_t MFRC522_Anticoll(uint8_t *serNum);

// 清除FIFO缓冲
void MFRC522_ClearFIFO(void);

#endif
mfrc522.c
#include "mfrc522.h"

extern SPI_HandleTypeDef MFRC522_SPI_HANDLE;

// MFRC522片选IO,自己定义
#define MFRC522_CS_GPIO_Port GPIOA
#define MFRC522_CS_Pin       GPIO_PIN_4

static void MFRC522_Select(void)
{
    HAL_GPIO_WritePin(MFRC522_CS_GPIO_Port, MFRC522_CS_Pin, GPIO_PIN_RESET);
}

static void MFRC522_Unselect(void)
{
    HAL_GPIO_WritePin(MFRC522_CS_GPIO_Port, MFRC522_CS_Pin, GPIO_PIN_SET);
}

static void MFRC522_WriteRegister(uint8_t addr, uint8_t val)
{
    uint8_t buff[2];
    buff[0] = (addr << 1) & 0x7E;  // 写地址
    buff[1] = val;

    MFRC522_Select();
    HAL_SPI_Transmit(&MFRC522_SPI_HANDLE, buff, 2, 100);
    MFRC522_Unselect();
}

static uint8_t MFRC522_ReadRegister(uint8_t addr)
{
    uint8_t val;
    uint8_t addr_byte = ((addr << 1) & 0x7E) | 0x80;

    MFRC522_Select();
    HAL_SPI_Transmit(&MFRC522_SPI_HANDLE, &addr_byte, 1, 100);
    HAL_SPI_Receive(&MFRC522_SPI_HANDLE, &val, 1, 100);
    MFRC522_Unselect();

    return val;
}

void MFRC522_Init(void)
{
    // 这里写初始化流程,复位等
    HAL_GPIO_WritePin(MFRC522_CS_GPIO_Port, MFRC522_CS_Pin, GPIO_PIN_SET);

    MFRC522_WriteRegister(CommandReg, 0x0F); // 软复位
    HAL_Delay(50);
    // 初始化寄存器,开启天线等
    MFRC522_WriteRegister(TxControlReg, 0x83);
}

// 简化示范函数,完整的MFRC522操作较复杂,建议用库
uint8_t MFRC522_Request(uint8_t req_mode, uint8_t *tag_type)
{
    // 省略,实际可以使用开源库或实现卡片请求命令
    return 0;
}

uint8_t MFRC522_Anticoll(uint8_t *serNum)
{
    // 省略,完成防冲突读取卡号
    return 0;
}

void MFRC522_ClearFIFO(void)
{
    MFRC522_WriteRegister(FIFOLevelReg, 0x80);
}

2. 干簧管门磁检测代码

door_sensor.h
#ifndef __DOOR_SENSOR_H
#define __DOOR_SENSOR_H

#include "stm32f1xx_hal.h"

#define DOOR_GPIO_Port GPIOA
#define DOOR_Pin       GPIO_PIN_0

// 初始化门磁输入口
void DoorSensor_Init(void);

// 获取门状态,返回1门开,0门关
uint8_t DoorSensor_GetStatus(void);

#endif
door_sensor.c
#include "door_sensor.h"

void DoorSensor_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitStruct.Pin = DOOR_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP; // 取决于硬件设计
    HAL_GPIO_Init(DOOR_GPIO_Port, &GPIO_InitStruct);
}

uint8_t DoorSensor_GetStatus(void)
{
    return HAL_GPIO_ReadPin(DOOR_GPIO_Port, DOOR_Pin) == GPIO_PIN_RESET ? 1 : 0;
}

3. 蜂鸣器控制代码

buzzer.h
#ifndef __BUZZER_H
#define __BUZZER_H

#include "stm32f1xx_hal.h"

#define BUZZER_GPIO_Port GPIOB
#define BUZZER_Pin       GPIO_PIN_2

// 蜂鸣器初始化
void Buzzer_Init(void);

// 蜂鸣器开
void Buzzer_On(void);

// 蜂鸣器关
void Buzzer_Off(void);

// 蜂鸣器短鸣
void Buzzer_Beep(uint16_t delay_ms);

#endif
buzzer.c
#include "buzzer.h"

void Buzzer_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStruct.Pin = BUZZER_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(BUZZER_GPIO_Port, &GPIO_InitStruct);

    Buzzer_Off();
}

void Buzzer_On(void)
{
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
}

void Buzzer_Off(void)
{
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
}

void Buzzer_Beep(uint16_t delay_ms)
{
    Buzzer_On();
    HAL_Delay(delay_ms);
    Buzzer_Off();
}

5.3 项目核心代码

以下是STM32主函数完整示范代码(基于HAL库)。该代码集成了RFID模块、门磁检测、蜂鸣器控制、LCD显示及ESP8266联网上传的基本调用框架


main.c

#include "main.h"
#include "mfrc522.h"
#include "door_sensor.h"
#include "buzzer.h"
#include "lcd.h"
#include "esp8266.h"

// SPI句柄,注意与你实际工程匹配
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart1; // ESP8266使用的串口

int main(void)
{
    HAL_Init();
    SystemClock_Config();

    // 初始化GPIO、SPI、UART
    MX_GPIO_Init();
    MX_SPI1_Init();
    MX_USART1_UART_Init();

    // 模块初始化
    MFRC522_Init();      // RFID
    DoorSensor_Init();   // 门磁
    Buzzer_Init();       // 蜂鸣器
    LCD_Init();          // LCD初始化,需你自己完善
    ESP8266_Init();      // ESP8266初始化,需你自己完善

    LCD_Clear(BACKGROUND_COLOR);
    LCD_ShowString(10, 10, "智能快递柜系统启动");

    uint8_t cardID[5];
    uint8_t doorStatus = 0;
    uint8_t lastDoorStatus = 0;

    while (1)
    {
        // 1. 读取门状态
        doorStatus = DoorSensor_GetStatus();
        if (doorStatus != lastDoorStatus)
        {
            lastDoorStatus = doorStatus;

            if (doorStatus == 1)
            {
                LCD_ShowString(10, 50, "柜门已打开   ");
                Buzzer_Beep(200);
            }
            else
            {
                LCD_ShowString(10, 50, "柜门已关闭   ");
            }

            // 上传门状态到云端
            ESP8266_UploadDoorStatus(doorStatus);
        }

        // 2. 读取IC卡
        if (MFRC522_Request(0x26, cardID)) // 0x26 = ISO14443A请求命令
        {
            if (MFRC522_Anticoll(cardID))
            {
                char buf[64];
                sprintf(buf, "卡号: %02X%02X%02X%02X%02X", cardID[0], cardID[1], cardID[2], cardID[3], cardID[4]);
                LCD_ShowString(10, 90, buf);

                // TODO: 验证卡号是否有权限(可通过云端或本地比对)

                // 开锁逻辑:控制继电器打开对应柜门
                Lock_OpenLocker();

                // 声音提示
                Buzzer_Beep(300);

                // 上传开锁记录
                ESP8266_UploadOpenRecord(cardID);

                Lock_CloseLocker();
            }
        }
    }
}

5.4 程序下载

也有视频教程:

讲解如何编译代码,下载STM32程序: www.bilibili.com/video/BV1Cw…

打STM32的keil工程,编译代码、然后,使用USB线将开发板的左边的USB口(串口1)与电脑的USB连接,打开程序下载软件下载程序。

具体下载过程看下面图:

image-20240319223247836

打开程序下载软件:[软件就在资料包里的软件工具目录下]

image-20240120160735942

5.5 程序正常运行效果

设备运行过程中会通过串口打印调试信息,我们可以通过串口打印了解程序是否正常。

程序下载之后,可以打开串口调试助手查看程序运行的状态信息。[软件就在资料包里的软件工具目录下]

image-20240327212042050

5.6 取模软件的使用

显示屏上会显示中文,字母,数字等数据,可以使用下面的取模软件进行取模设置。

[软件就在资料包里的软件工具目录下]

image-20241024142522970

打开软件之后:

image-20241127212320020

六、总结

本项目基于STM32单片机设计并实现了一套功能完善的智能快递柜控制系统,涵盖了用户身份识别、柜门控制、状态显示、联网通信及远程管理等关键功能。通过集成RFID刷卡模块、电磁锁控制、干簧管门状态检测和ESP8266无线通信,实现了柜门的安全可靠控制和实时状态反馈。结合华为云物联网平台的MQTT协议,系统能够实现数据的远程上传与监控管理,配合Qt上位机软件,实现了柜门状态和开锁记录的可视化管理。整个系统结构合理、运行稳定,具备良好的实用性和扩展性。项目不仅提升了快递柜智能化管理水平,也为嵌入式系统与物联网技术的应用提供了有力的实践支持,具有较高的推广价值和应用前景。