• 正文
  • 相关推荐
申请入驻 产业图谱

基于STM32设计的智能防盗单车锁

04/09 10:07
1925
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、前言

1.1 项目开发背景

在现代城市交通日益便捷的背景下,单车以其绿色环保、便于停放的优点成为了人们短途出行的重要工具。然而,随之而来的单车被盗问题也日益严重,尤其是在城市的公共区域或偏僻地带,传统的机械锁缺乏智能化手段,一旦遭遇非法移动或破坏,用户很难第一时间获知,从而造成财产损失。因此,设计一款具备智能化、联网化、远程监控能力的单车防盗锁成为了当前智能出行领域的一项实际需求。

随着物联网技术的快速发展,嵌入式系统移动通信技术的融合愈发紧密,为智能防盗系统的设计提供了可靠的技术支撑。STM32系列单片机具备处理能力强、资源丰富、低功耗等特点,适合部署在需要实时响应和长期稳定运行的应用场景中。而4G通信模块则提供了在无WiFi环境下的高速网络连接,尤其适用于户外场景的单车设备,实现数据的远程上传与控制。同时,借助GPS模块实现对车辆位置的精准定位,使得车辆被盗后能快速追踪,为用户提供更强的安全保障。

为了提升用户体验,本项目还引入了OLED显示屏用于本地状态提示,蜂鸣器实现现场声响报警,结合APP弹窗提醒与短信告警的多重通知方式,增强系统的实时性和可靠性。APP与上位机均采用MQTT协议接入华为云物联网平台,实现多终端、跨平台的数据共享与控制,提升系统智能化和可扩展性。

因此,本项目“基于STM32设计的智能防盗单车锁”不仅聚焦于实际生活中的防盗需求,也融合了当下先进的嵌入式控制、移动通信和物联网技术,具有较强的应用前景和推广价值,能够为智能交通领域提供一种可行的、低成本的智能安全解决方案。

1.2 设计实现的功能

(1)智能防盗报警功能
当单车处于锁车状态时,如果被非法移动,系统通过加速度传感器检测到位移后,立即触发本地蜂鸣器发出声响进行报警。同时通过4G模块向预设的手机号码发送报警短信,并通过MQTT协议上传报警信息至华为云物联网平台,Android APP和Windows上位机将弹出提醒窗口,提示用户单车被移动,增强安全性与及时性。

(2)远程监控与控制功能
通过华为云IOT物联网平台,用户可以通过Android APP或Windows上位机查看设备当前状态,包括锁的开关状态、报警状态、GPS定位信息等。同时,用户还可以通过远程操作实现对锁的开关控制,真正实现智能化的单车锁管理。

(3)数据上云功能
系统通过Air724UG 4G模块接入互联网,采用MQTT协议将锁的开关状态、GPS定位信息、报警状态等数据实时上传至华为云IOT平台,支持多终端访问和实时数据监控,提升系统的可靠性与管理便捷性。

(4)短信告警功能
设备具备短信发送能力,借助Air724UG模块内置的短信功能,一旦发生非法移动事件,除上传云端外,还会同步发送短信至预设用户手机,确保即使在无网络状态下也能接收警报信息。

(5)GPS实时定位功能
采用ATGM336H-5N GPS模块,实时获取当前设备地理位置,并通过4G模块上传至云平台,用户可在APP或上位机地图界面上查看车辆位置,为车辆防盗追踪提供支持。

(6)本地OLED信息显示功能
设备配备0.96寸SPI OLED显示屏,可实时显示锁的当前状态(如“已锁定”“已解锁”)、GPS信号状态等关键信息,方便用户通过屏幕快速掌握设备运行状态。

(7)蜂鸣器本地声响报警功能
当系统判断存在异常移动时,立即驱动高电平触发的有源蜂鸣器发出声响,具备现场即时报警功能,威慑潜在盗窃行为。

(8)低功耗与可扩展供电功能
设备主供电采用14500锂电池,满足低功耗便携应用需求,同时预留太阳能供电扩展接口,支持在户外环境下的长时间无人值守运行。

(9)跨平台APP与上位机控制界面
Android手机APP和Windows上位机软件均采用QT5(C++)开发,界面统一、美观,支持多平台查看设备状态、接收报警提醒和控制操作,提高用户使用体验与系统通用性。

1.3 项目硬件模块组成

(1)STM32F103RCT6主控模块
作为系统核心控制单元,负责处理各类传感器数据、控制执行模块、通信管理、数据上传及本地信息显示等任务,所有逻辑控制与功能实现均基于该芯片完成。

(2)Air724UG 4G通信模块
用于实现设备与华为云物联网平台的远程通信,支持MQTT协议进行数据上云,同时集成短信功能,能在单车被移动时向用户发送短信报警信息。

(3)ATGM336H-5N GPS定位模块
用于实时获取设备的地理位置信息,采集经纬度数据,通过STM32上传至云平台,实现远程地图定位及轨迹追踪功能。

(4)ADXL345三轴加速度传感器模块
用于监测车辆在锁车状态下是否发生移动,通过检测姿态变化判断是否触发防盗报警逻辑,是实现智能防盗的关键传感器模块。

(5)0.96寸SPI OLED显示模块
用于显示锁的当前状态、GPS模块状态、网络连接情况等信息,为用户提供直观的本地交互界面,提升使用便捷性与信息透明度。

(6)高电平触发有源蜂鸣器模块
在检测到非法移动时由STM32驱动发出高分贝声响,起到警示与威慑作用,是本地声响报警的执行装置。

(7)锂电池供电模块(14500锂电池)
为整套系统提供便携式供电,支持长时间户外运行,同时预留接口,可外接太阳能板,实现绿色能源补充与连续运行保障。

(8)硬件连接模块(洞洞板+杜邦线/焊接)
整套硬件系统搭建于洞洞板(万能板)上,模块之间通过杜邦线或焊接方式连接,方便原型搭建、系统调试与后期维护,是硬件搭建的基础平台。

(9)调试与串口通信模块
包含用于程序烧录的串口接口、电源控制接口及串口调试接口,用于开发过程中进行程序下载、数据监测及调试信息输出,保障开发效率与系统稳定性。

1.4 设计思路

本项目设计并实现一款基于STM32的智能防盗单车锁系统,结合物联网技术实现远程监控、报警提醒和状态管理。设计思路以“本地智能识别+远程数据联动”为核心,融合硬件控制、无线通信和云平台服务,实现一套既具备本地防护能力又支持远程操作的智能防盗方案。

系统整体架构分为三个层级:感知层、控制层和应用层。感知层由GPS定位模块、加速度传感器和蜂鸣器组成,负责实时监测车辆位置信息和状态变化(如是否被非法移动),并在异常情况发生时立即触发报警机制。控制层以STM32F103RCT6为核心主控,通过寄存器方式开发,负责数据采集、逻辑判断、指令执行和与通信模块的数据交互。应用层通过4G通信模块(Air724UG)连接华为云IOT平台,采用MQTT协议进行消息通信,支持将锁的状态、位置等数据上传至云端,并接收远程下发的开锁/关锁等控制指令。

在用户交互方面,系统配备一块0.96寸SPI OLED显示屏,显示当前锁状态和GPS工作状态,方便用户在现场了解设备运行情况。同时,为满足用户远程监控需求,设计了基于QT5的Android手机APP和Windows上位机应用,实现远程查看锁状态、地图定位、历史记录查询、短信提醒等功能,并支持一键远程开关锁。

为了适应单车户外运行环境,系统采用14500锂电池供电,并预留太阳能供电接口,实现绿色续航与长时间运行能力。硬件集成部分基于洞洞板搭建,采用模块化设计思想,便于后期调试与硬件维护。整体设计在满足安全性和实用性的基础上,兼顾了低功耗、可扩展性与用户操作便利性,体现出物联网在个人交通工具智能化保护方面的应用前景。

1.5 系统功能总结

功能类别 功能描述
防盗报警功能 当车辆在锁车状态下发生移动时,系统通过加速度传感器检测异常,触发蜂鸣器发出声响,同时通过4G模块发送短信提醒并在APP上弹窗报警。
远程控制功能 用户可通过Android手机APP或Windows上位机,远程实现对单车锁的开锁、关锁控制,提升用户操作的便捷性与灵活性。
数据上云功能 设备通过Air724UG 4G模块接入华为云IOT平台,使用MQTT协议将锁状态、定位信息等实时数据上传至云端,实现远程监控与数据记录。
GPS定位功能 内置GPS模块可实时获取设备位置信息,并上传至云端用于地图显示、轨迹跟踪、远程查询等,增强车辆追踪能力。
本地显示功能 OLED显示屏可本地显示锁状态、GPS模块状态、网络连接情况等运行信息,方便用户在现场查看设备当前状态。
本地报警功能 内置蜂鸣器在车辆被非法移动时自动发出高分贝报警音,对潜在盗窃行为进行震慑和提醒。
电源管理功能 系统采用14500锂电池供电,支持便携式低功耗运行,并预留太阳能供电接口,适应户外环境下长时间运行的需求。
姿态检测功能 通过ADXL345加速度传感器监测车辆姿态变化,用于判断是否处于被移动状态,为防盗报警功能提供关键判断依据。
用户交互功能 用户通过APP或上位机可视化界面与系统交互,查看锁状态、定位信息、报警记录,接收通知并进行控制,提升用户体验与系统智能化程度。

1.6 模块的技术详情介绍

【1】Air724UG-4G模块

Air724UG 是一款功能强大的 4G 全网通通信模块,广泛应用于物联网设备中,特别适用于对数据通信、短信发送和远程控制有较高要求的嵌入式系统。该模块支持中国移动、中国联通和中国电信的 LTE 网络,具备良好的网络兼容性和覆盖能力,特别适合部署在户外、流动性强或无WiFi覆盖的场景中,如智能车锁、共享设备、远程监控等。

Air724UG 模块内部集成了高性能的处理器,支持 AT 指令集,具备串口通信接口UART),可方便地与 STM32 等主控芯片进行通信。模块支持 MQTT、TCP、HTTP等多种协议,特别是在本项目中,Air724UG 可用于将设备状态、GPS位置信息等通过 MQTT 协议上传至华为云物联网平台,实现数据上云与远程管理。

除了数据通信功能外,Air724UG 还支持 SMS(短消息服务)功能,可通过 AT 指令实现短信的发送与接收。在智能防盗单车锁项目中,当检测到车辆被非法移动时,模块能够快速向预设联系人发送报警短信,提高用户的安全响应效率。

在供电与功耗方面,Air724UG 支持低功耗待机模式,适合依赖锂电池供电的应用场景。同时,其体积小巧、接口标准化,方便集成到各类嵌入式设备中。此外,模块还具备掉线自动重连、网络状态检测等功能,提高通信的稳定性和可靠性。

Air724UG 作为核心通信部件,在本项目中起到了“云-端”之间桥梁的关键作用,是实现智能控制、远程监控和移动报警的重要技术基础。

【2】MQTT协议

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种轻量级、发布/订阅模式的消息传输协议,专为低带宽、不可靠网络环境设计。它最早由IBM提出,现已成为物联网(IoT)通信的重要协议之一。由于其高效、低功耗和实时性等特点,MQTT在智能家居工业自动化、远程监控和车联网等领域得到了广泛应用。

MQTT的工作原理基于发布/订阅模型。这种模型有别于传统的客户端-服务器模型,通信方不需要直接建立连接。MQTT由三个核心组件构成:客户端、代理(Broker)和主题(Topic)。客户端可以作为消息的发布者或订阅者,消息通过代理进行路由。代理是一个中间服务端,用于接收和分发来自不同客户端的消息。发布者发送消息到一个特定的主题上,代理负责将这些消息分发给所有订阅了该主题的客户端。通过这种解耦的架构设计,客户端之间可以实现松耦合的通信,降低了复杂性和依赖性。

在MQTT协议中,消息被分为不同的主题(Topic),例如“home/sensor/temperature”可以用来代表温度传感器数据。客户端可以订阅这个主题,当发布者发送新的数据到该主题时,所有订阅该主题的客户端都会收到更新信息。这种灵活的主题结构和层次化的命名规则,使得MQTT在复杂场景下也能快速组织和管理消息流。

MQTT协议支持三种服务质量(QoS)等级,分别为“至多一次”(QoS 0)、“至少一次”(QoS 1)和“仅一次”(QoS 2)。QoS 0表示消息传输尽力而为,可能会丢失或重复;QoS 1确保消息至少送达一次,但可能会有重复;QoS 2则确保消息恰好传输一次,保证消息的严格可靠性。这种设计使MQTT能够适应不同的应用场景,用户可以根据应用需求选择合适的QoS级别。

为了保证通信的安全性,MQTT支持用户名和密码验证,代理可以对连接进行身份认证。此外,许多实现中还支持TLS/SSL加密通信,确保数据在传输过程中不会被窃取或篡改。用户也可以使用不同的认证方式来增强系统的安全性,适应物联网应用中对安全性的高需求。

MQTT非常注重轻量化和低功耗。它的报文头非常小,通信开销很低,这使其特别适合在资源受限的设备或不稳定的网络环境中使用。MQTT支持“保持连接”和“遗嘱消息”功能,客户端可以在连接断开时自动向代理发送遗嘱消息,通知其他客户端连接状态的变化。这种特性有助于提高网络的健壮性和系统的可用性。

MQTT的典型使用场景包括物联网设备数据采集、实时监控、消息推送和控制命令的发布。比如在智能家居中,传感器可以发布环境数据,如温湿度、烟雾浓度等,控制设备根据收到的消息作出响应,实现自动化操作。在工业场景中,MQTT可以帮助收集和管理大规模设备的运行状态,实现集中化和高效的设备监控。

总的来说,MQTT协议凭借其低功耗、高效能、实时性强等优势,已成为物联网通信的主要协议之一。它的发布/订阅模式简化了设备之间的通信,使其特别适合多对多、低延迟、高可靠性的数据传输场景。MQTT易于使用、拓展性强,为开发者提供了灵活的解决方案来构建各种物联网应用。

【3】中科微ATGM336H-GPS模块

中科微ATGM336H-GPS模块是一款高性能、低功耗的全球定位模块,专为卫星定位导航应用设计。该模块集成了GNSS基带处理器和RF接收器,支持GPS、GLONASS、BDS(北斗)等多种卫星系统的定位信号,能够实现快速精准的定位,并提供稳定可靠的位置、速度和时间数据。ATGM336H模块广泛应用于车辆定位、物流跟踪、无人机导航、智能穿戴设备、户外运动设备和物联网等领域。

ATGM336H模块采用小巧的LCC封装,尺寸为16mm x 12.2mm x 2.3mm,便于集成到各种紧凑型设备中。模块内置高灵敏度接收芯片,具有-165dBm的高灵敏度,即使在复杂环境下也能快速捕获和跟踪卫星信号。其冷启动时间在开阔地带一般小于30秒,热启动时间约为1秒,重捕获时间小于1秒,使其在车辆移动和各种快速切换的场景下表现出色,定位精度可达2.5米。

该模块支持多种工作模式,以满足不同应用的功耗要求。它不仅可以在普通模式下连续定位,还支持周期性模式和节电模式,通过关闭部分功能或降低数据输出频率来减少功耗,适合电池供电的便携式设备。其最低功耗在微安级别,能够显著延长电池续航时间,使其成为移动设备的理想选择。

ATGM336H-GPS模块的接口丰富,支持UART、I2C、SPI等多种通信接口,方便与主控MCU进行数据交换。模块提供的标准NMEA协议输出和二进制格式数据能够直接对接多种导航应用程序。此外,模块还具有内置的天线检测功能和动态干扰抑制技术,有助于在有较强电磁干扰的环境中保持定位精度,并能实时检测和报告天线状态,进一步提高定位可靠性。

为了提高用户体验和简化开发过程,中科微为ATGM336H模块提供了完善的开发手册和技术支持,便于开发者快速上手并将其应用到多种设备中。此外,模块还支持多卫星系统协同定位的功能,通过融合GPS、BDS、GLONASS等卫星数据,提高在市区、高山、森林等卫星信号受限环境下的定位精度和稳定性,使其适用于复杂环境的高精度定位需求。

二、硬件选型(搭建模型参考)

2.1 STM32开发板

2.2 USB下载线

2.3 Air724UG 4G模块

2.4 继电器

2.5 蜂鸣器模块

2.6 ADXL345 三轴加速度计模块

2.7 OLED显示屏

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

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

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

3.1 物联网平台介绍

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

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

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

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

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

3.2 开通物联网服务

地址: https://www.huaweicloud.com/product/iothub.html

开通免费单元。

点击立即创建

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

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

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

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

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

总结:

端口号:   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:UsersLenovo>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:UsersLenovo>

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

3.3 创建产品

链接:https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-dev/all-product?instanceId=03c5c68c-e588-458c-90c3-9e4c640be7af

(1)创建产品

(2)填写产品信息

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

(3)产品创建成功

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

(4)添加自定义模型

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

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

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

比如:

锁可以叫    LOCK      (整数)
定位可以叫  GPS         (字符串)
报警可以叫  BEEP         (整数)
其他的传感器自己用单词简写命名即可。 这就是你的单片机设备端上传到服务器的数据名字。

先点击自定义模型。

再创建一个服务ID。

接着点击新增属性。

3.4 添加设备

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

(1)注册设备

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

(3)保存设备信息

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

(4)设备创建完成

(5)设备详情

3.5 MQTT协议主题订阅与发布

(1)MQTT协议介绍

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

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

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

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

业务流程:

(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)主题订阅格式

帮助文档地址:https://support.huaweicloud.com/devg-iothub/iot_02_2200.html

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

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

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

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

(4)主题发布格式

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

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

帮助文档地址:https://support.huaweicloud.com/usermanual-iothub/iot_06_v5_3010.html

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

发布的主题格式:
$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}}]}

3.6 MQTT三元组

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

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

(1)MQTT服务器地址

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

帮助文档地址:https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-portal/home

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

(2)生成MQTT三元组

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

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

下面是打开的页面:

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

直接得到三元组信息。

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

ClientId  663cb18871d845632a0912e7_dev1_0_0_2024050911
Username  663cb18871d845632a0912e7_dev1
Password  71b82deae83e80f04c4269b5bbce3b2fc7c13f610948fe210ce18650909ac237

3.7 模拟设备登录测试

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

MQTT软件下载地址【免费】: https://download.csdn.net/download/xiaolong1126626497/89928772

(1)填入登录信息

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

(2)打开网页查看

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

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

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

(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}}]}

3.8 创建IAM账户

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

地址: https://console.huaweicloud.com/iam/?region=cn-north-4#/iam/users

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

项目凭证:

28add376c01e4a61ac8b621c714bf459

【2】创建IAM用户

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

点击左上角创建用户

创建成功:

【3】创建完成

用户信息如下:

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

3.9 获取影子数据

帮助文档:https://support.huaweicloud.com/api-iothub/iot_06_v5_0079.html

设备影子介绍:

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

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

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

如果对接口不熟悉,可以先进行在线调试:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=ShowDeviceShadow

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

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

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

{
 "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写代码访问此链接,获取影子数据,完成上位机开发。

链接如下:

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

3.10 访问接口的代码实现

(1)配置 Qt 项目

在 Qt 项目的 .pro 文件中,加入对 libcurl 的支持:

QT += core
CONFIG += console
CONFIG -= app_bundle

INCLUDEPATH += /usr/include/curl  # 根据你的系统设置 libcurl 的路径
LIBS += -lcurl  # 链接 libcurl 库

SOURCES += main.cpp

(2)代码实现

main.cpp 文件中实现代码如下:

#include <QCoreApplication>
#include <curl/curl.h>
#include <QDebug>
#include <QString>
#include <QByteArray>

// 回调函数,处理libcurl下载数据
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t totalSize = size * nmemb;
    QByteArray *response = static_cast<QByteArray *>(userp);
    response->append(static_cast<char *>(contents), totalSize);
    return totalSize;
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 初始化libcurl
    CURL *curl;
    CURLcode res;
    QByteArray responseData;  // 用于存储响应数据

    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if (curl) {
        // 设置访问URL
        const QString url = "https://ad635970a1.st1.iotda-app.cn-north-4.myhuaweicloud.com:443/v5/iot/28add376c01e4a61ac8b621c714bf459/devices/663cb18871d845632a0912e7_dev1/shadow";

        // 设置HTTP请求头
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "Authorization: Bearer <Your_Access_Token>"); // 这里需要替换为你的实际 token

        curl_easy_setopt(curl, CURLOPT_URL, url.toStdString().c_str());
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);

        // 发起GET请求
        res = curl_easy_perform(curl);

        if (res != CURLE_OK) {
            qDebug() << "Curl request failed:" << curl_easy_strerror(res);
        } else {
            qDebug() << "Response data:" << responseData;
        }

        // 清理
        curl_easy_cleanup(curl);
        curl_slist_free_all(headers);
    }

    curl_global_cleanup();

    return a.exec();
}

3.11 数据解析代码

在 Qt 中使用 CJSON (一个用于解析 JSON 数据的轻量级 C 库) 来解析返回的 JSON 数据。

(1)配置 Qt 项目

在 Qt 项目的 .pro 文件中,确保包括了 CJSON 的头文件,并链接 CJSON 的源代码

QT += core
CONFIG += console
CONFIG -= app_bundle

SOURCES += main.cpp 
           cJSON.c  # 将 cJSON.c 文件添加到你的项目中

INCLUDEPATH += path/to/cjson/  # 添加 CJSON 头文件的路径

LIBS += -lcurl  # 链接 libcurl 库

(2)解析 JSON 数据的完整代码

在 main.cpp 中,以下代码展示了如何解析你提供的 JSON 数据。

#include <QCoreApplication>
#include <curl/curl.h>
#include <QDebug>
#include <QString>
#include <QByteArray>
#include "cJSON.h"

// 回调函数,处理libcurl下载数据
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t totalSize = size * nmemb;
    QByteArray *response = static_cast<QByteArray *>(userp);
    response->append(static_cast<char *>(contents), totalSize);
    return totalSize;
}

// 解析 JSON 数据
void parseJson(const QByteArray &data) {
    // 将 QByteArray 转换为 char*
    const char* jsonData = data.constData();

    // 解析 JSON
    cJSON *root = cJSON_Parse(jsonData);
    if (root == NULL) {
        qDebug() << "Error parsing JSON.";
        return;
    }

    // 解析 "device_id"
    cJSON *deviceId = cJSON_GetObjectItemCaseSensitive(root, "device_id");
    if (cJSON_IsString(deviceId) && (deviceId->valuestring != NULL)) {
        qDebug() << "Device ID:" << deviceId->valuestring;
    }

    // 解析 "shadow" 数组
    cJSON *shadow = cJSON_GetObjectItemCaseSensitive(root, "shadow");
    if (cJSON_IsArray(shadow)) {
        cJSON *shadowItem = NULL;
        cJSON_ArrayForEach(shadowItem, shadow) {
            // 解析每个 shadow 项目
            cJSON *serviceId = cJSON_GetObjectItemCaseSensitive(shadowItem, "service_id");
            if (cJSON_IsString(serviceId) && (serviceId->valuestring != NULL)) {
                qDebug() << "Service ID:" << serviceId->valuestring;
            }

            // 解析 "reported" 对象
            cJSON *reported = cJSON_GetObjectItemCaseSensitive(shadowItem, "reported");
            if (cJSON_IsObject(reported)) {
                // 解析 "properties" 对象
                cJSON *properties = cJSON_GetObjectItemCaseSensitive(reported, "properties");
                if (cJSON_IsObject(properties)) {
                    cJSON *data1 = cJSON_GetObjectItemCaseSensitive(properties, "data1");
                    if (cJSON_IsNumber(data1)) {
                        qDebug() << "data1:" << data1->valueint;
                    }
                    cJSON *data2 = cJSON_GetObjectItemCaseSensitive(properties, "data2");
                    if (cJSON_IsNumber(data2)) {
                        qDebug() << "data2:" << data2->valueint;
                    }
                    cJSON *data3 = cJSON_GetObjectItemCaseSensitive(properties, "data3");
                    if (cJSON_IsNumber(data3)) {
                        qDebug() << "data3:" << data3->valueint;
                    }
                    cJSON *data4 = cJSON_GetObjectItemCaseSensitive(properties, "data4");
                    if (cJSON_IsNumber(data4)) {
                        qDebug() << "data4:" << data4->valueint;
                    }
                }

                // 解析 "event_time"
                cJSON *eventTime = cJSON_GetObjectItemCaseSensitive(reported, "event_time");
                if (cJSON_IsString(eventTime) && (eventTime->valuestring != NULL)) {
                    qDebug() << "Event Time:" << eventTime->valuestring;
                }
            }

            // 解析 version
            cJSON *version = cJSON_GetObjectItemCaseSensitive(shadowItem, "version");
            if (cJSON_IsNumber(version)) {
                qDebug() << "Version:" << version->valueint;
            }
        }
    }

    // 释放 JSON 对象
    cJSON_Delete(root);
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 模拟获取到的 JSON 数据
    QByteArray jsonData = R"(
    {
        "device_id": "663cb18871d845632a0912e7_dev1",
        "shadow": [
            {
                "service_id": "stm32",
                "desired": {
                    "properties": null,
                    "event_time": null
                },
                "reported": {
                    "properties": {
                        "data1": 18,
                        "data2": 90,
                        "data3": 38,
                        "data4": 70
                    },
                    "event_time": "20240509T113448Z"
                },
                "version": 3
            }
        ]
    })";

    // 调用解析函数
    parseJson(jsonData);

    return a.exec();
}

四、STM32设备端代码设计

以下是该项目的 main.c 完整代码以及整体代码的设计思路。涵盖了4G通信、短信报警、GPS定位、蜂鸣器报警、姿态检测、OLED显示等功能。

4.1 整体代码设计思路

系统的主控芯片为 STM32F103RCT6,采用寄存器方式进行编程。整体设计分为以下几个模块,代码通过主函数进行初始化和任务调度:

    1. 1.

系统初始化阶段

      • • 时钟系统初始化(使用 HSE)• 串口初始化(用于与 Air724UG 4G 模块、GPS 模块通信)• OLED 显示初始化• 加速度传感器 ADXL345 初始化(通过 I2C)• 蜂鸣器 GPIO 初始化• 相关中断使能(如串口接收中断)

2. 主循环任务调度阶段

      • • 循环读取 ADXL345 判断是否发生车辆移动• 如果发生移动,触发本地蜂鸣器报警,并调用4G模块发送短信• 获取 GPS 位置信息并通过 MQTT 上传至云平台• 实时更新锁状态和GPS信息到 OLED 屏幕• 接收上位机或APP发来的远程开锁/关锁指令并控制锁状态

3. 中断服务程序

    • • 串口接收中断,处理4G模块和GPS模块返回的数据• 定时器或轮询机制定时上传状态信息至云端

4.2 main.c 完整示例代码

#include "stm32f10x.h"
#include "oled.h"
#include "usart.h"
#include "adxl345.h"
#include "gps.h"
#include "delay.h"
#include "buzzer.h"
#include "mqtt.h"
#include "lock.h"
#include "string.h"

// 全局状态变量
uint8_t bike_locked = 1;
uint8_t movement_detected = 0;
char gps_data[100];
char lock_status[10];

// 主函数
int main(void)
{
    // 基础外设初始化
    SystemInit();
    delay_init();
    USART1_Init(9600);   // 用于GPS
    USART2_Init(115200); // 用于Air724UG模块
    OLED_Init();
    ADXL345_Init();
    BUZZER_Init();
    LOCK_Init();

    OLED_ShowString(0, 0, "Smart Bike Lock");
    delay_ms(1000);
    OLED_Clear();

    // MQTT初始化
    MQTT_Init();

    while (1)
    {
        // 姿态检测模块读取
        if (ADXL345_DetectMovement())
        {
            movement_detected = 1;
        }

        // 如果处于锁车状态并且检测到移动
        if (bike_locked && movement_detected)
        {
            BUZZER_On();
            OLED_ShowString(0, 0, "ALARM: Movement!");
            Send_SMS("警告:单车被非法移动!");
            MQTT_Publish_Alert("bike/move", "Bike Moved!");
            movement_detected = 0;
            delay_ms(5000);
            BUZZER_Off();
            OLED_Clear();
        }

        // 获取GPS信息并上传
        GPS_GetLocation(gps_data);
        MQTT_Publish("bike/gps", gps_data);
        OLED_ShowString(0, 2, "GPS:");
        OLED_ShowString(0, 3, gps_data);

        // 更新锁状态显示
        strcpy(lock_status, bike_locked ? "Locked" : "Unlocked");
        OLED_ShowString(0, 5, "Lock:");
        OLED_ShowString(36, 5, lock_status);
        MQTT_Publish("bike/status", lock_status);

        // 处理远程开锁指令(模拟)
        if (MQTT_Received_Unlock())
        {
            bike_locked = 0;
            LOCK_Unlock();
            OLED_ShowString(0, 6, "Unlock by remote");
        }

        // 处理远程关锁指令
        if (MQTT_Received_Lock())
        {
            bike_locked = 1;
            LOCK_Lock();
            OLED_ShowString(0, 6, "Lock by remote");
        }
    }
}

说明

USART1

    • :用于与GPS模块通信•

USART2

    • :用于与Air724UG模块通信(发送MQTT/短信)•

ADXL345_DetectMovement()

    • :检测车辆是否移动(阈值判断)•

Send_SMS()

    • :通过AT指令调用Air724UG发送短信•

MQTT_Publish()

    • :上传数据到华为云•

MQTT_Received_Unlock()

    •  /

Lock()

    • :接收远程指令•

OLED_ShowString()

    • :显示实时信息•

LOCK_Unlock()

    •  /

LOCK_Lock()

4.3 ADXL345模块

ADXL345.h

#ifndef __ADXL345_H
#define __ADXL345_H

#include "stm32f10x.h"

// I2C引脚定义(使用软件模拟)
#define ADXL_SCL_GPIO    GPIOB
#define ADXL_SCL_PIN     GPIO_Pin_6
#define ADXL_SDA_GPIO    GPIOB
#define ADXL_SDA_PIN     GPIO_Pin_7

// 宏函数控制SCL/SDA
#define ADXL_SCL_HIGH()  GPIO_SetBits(ADXL_SCL_GPIO, ADXL_SCL_PIN)
#define ADXL_SCL_LOW()   GPIO_ResetBits(ADXL_SCL_GPIO, ADXL_SCL_PIN)
#define ADXL_SDA_HIGH()  GPIO_SetBits(ADXL_SDA_GPIO, ADXL_SDA_PIN)
#define ADXL_SDA_LOW()   GPIO_ResetBits(ADXL_SDA_GPIO, ADXL_SDA_PIN)
#define ADXL_SDA_READ()  GPIO_ReadInputDataBit(ADXL_SDA_GPIO, ADXL_SDA_PIN)

void ADXL345_Init(void);
uint8_t ADXL345_Read_Byte(uint8_t reg);
void ADXL345_Write_Byte(uint8_t reg, uint8_t data);
void ADXL345_ReadXYZ(int16_t *x, int16_t *y, int16_t *z);
uint8_t ADXL345_DetectMovement(void);

#endif

ADXL345.c

#include "ADXL345.h"
#include "delay.h"

#define ADXL345_ADDRESS  0xA6  // 7位地址为0x53,左移1位即为0xA6

// 模拟I2C初始化
static void I2C_GPIO_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = ADXL_SCL_PIN | ADXL_SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(ADXL_SCL_GPIO, &GPIO_InitStructure);
    ADXL_SCL_HIGH();
    ADXL_SDA_HIGH();
}

static void I2C_Start(void)
{
    ADXL_SDA_HIGH();
    ADXL_SCL_HIGH();
    delay_us(5);
    ADXL_SDA_LOW();
    delay_us(5);
    ADXL_SCL_LOW();
}

static void I2C_Stop(void)
{
    ADXL_SDA_LOW();
    ADXL_SCL_HIGH();
    delay_us(5);
    ADXL_SDA_HIGH();
    delay_us(5);
}

static void I2C_SendAck(uint8_t ack)
{
    if (ack)
        ADXL_SDA_LOW();
    else
        ADXL_SDA_HIGH();
    ADXL_SCL_HIGH();
    delay_us(5);
    ADXL_SCL_LOW();
    delay_us(5);
}

static uint8_t I2C_WaitAck(void)
{
    uint8_t ack;
    ADXL_SDA_HIGH();
    ADXL_SCL_HIGH();
    delay_us(5);
    ack = ADXL_SDA_READ();
    ADXL_SCL_LOW();
    return ack;
}

static void I2C_WriteByte(uint8_t byte)
{
    for (int i = 0; i < 8; i++)
    {
        if (byte & 0x80)
            ADXL_SDA_HIGH();
        else
            ADXL_SDA_LOW();
        byte <<= 1;
        ADXL_SCL_HIGH();
        delay_us(5);
        ADXL_SCL_LOW();
        delay_us(5);
    }
}

static uint8_t I2C_ReadByte(uint8_t ack)
{
    uint8_t byte = 0;
    ADXL_SDA_HIGH();
    for (int i = 0; i < 8; i++)
    {
        ADXL_SCL_HIGH();
        delay_us(5);
        byte <<= 1;
        if (ADXL_SDA_READ())
            byte |= 0x01;
        ADXL_SCL_LOW();
        delay_us(5);
    }
    I2C_SendAck(ack);
    return byte;
}

void ADXL345_Write_Byte(uint8_t reg, uint8_t data)
{
    I2C_Start();
    I2C_WriteByte(ADXL345_ADDRESS);
    I2C_WaitAck();
    I2C_WriteByte(reg);
    I2C_WaitAck();
    I2C_WriteByte(data);
    I2C_WaitAck();
    I2C_Stop();
}

uint8_t ADXL345_Read_Byte(uint8_t reg)
{
    uint8_t value;
    I2C_Start();
    I2C_WriteByte(ADXL345_ADDRESS);
    I2C_WaitAck();
    I2C_WriteByte(reg);
    I2C_WaitAck();
    I2C_Start();
    I2C_WriteByte(ADXL345_ADDRESS | 0x01);
    I2C_WaitAck();
    value = I2C_ReadByte(0);
    I2C_Stop();
    return value;
}

void ADXL345_ReadXYZ(int16_t *x, int16_t *y, int16_t *z)
{
    uint8_t x0 = ADXL345_Read_Byte(0x32);
    uint8_t x1 = ADXL345_Read_Byte(0x33);
    uint8_t y0 = ADXL345_Read_Byte(0x34);
    uint8_t y1 = ADXL345_Read_Byte(0x35);
    uint8_t z0 = ADXL345_Read_Byte(0x36);
    uint8_t z1 = ADXL345_Read_Byte(0x37);

    *x = ((int16_t)(x1 << 8) | x0);
    *y = ((int16_t)(y1 << 8) | y0);
    *z = ((int16_t)(z1 << 8) | z0);
}

void ADXL345_Init(void)
{
    I2C_GPIO_Init();
    ADXL345_Write_Byte(0x2D, 0x08); // POWER_CTL - 测量模式
    ADXL345_Write_Byte(0x31, 0x0B); // 数据格式 - 全分辨率 ±16g
    ADXL345_Write_Byte(0x2C, 0x0A); // BW_RATE - 100Hz
}

// 检测是否发生移动(简单阈值判断)
uint8_t ADXL345_DetectMovement(void)
{
    int16_t x, y, z;
    ADXL345_ReadXYZ(&x, &y, &z);
    if (x > 200 || x < -200 || y > 200 || y < -200 || z > 200 || z < -200)
        return 1;
    return 0;
}

五、上位机开发

为了方便查看设备上传的数据,接下来利用Qt开发一款Android手机APP 和 Windows上位机。

使用华为云平台提供的API接口获取设备上传的数据,进行可视化显示,以及远程控制设备。

5.1 Qt开发环境安装

可以在网盘里找到安装包下载: https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink

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

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

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

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

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

【1】新建工程

【2】设置项目的名称。

【3】选择编译系统

【4】选择默认继承的类

【5】选择编译器

【6】点击完成

【7】工程创建完成

5.3 切换编译器

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

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

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

Android环境搭建的博客链接: https://blog.csdn.net/xiaolong1126626497/article/details/117254453

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

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

5.4 编译测试功能

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

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

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

5.5 设计UI界面与工程配置

【1】打开UI文件

打开默认的界面如下:

【2】开始设计界面

根据自己需求设计界面。

5.5 编译Windows上位机

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

5.6 配置Android环境

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

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

【1】选择Android编译器

选择编译器。

切换编译器。

【2】创建Android配置文件

创建完成。

【3】配置Android图标与名称

【3】编译Android上位机

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

然后点击构建。

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

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

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

  -- File: D:/QtProject/build-265_AgritechIoTManager-Android_for_arm64_v8a_Clang_Qt_5_12_6_for_Android_ARM64_v8a-Release/android-build//build/outputs/apk/debug/android-build-debug.apk

六、总结

本项目基于STM32F103RCT6单片机设计了一套功能完整、运行稳定的智能防盗单车锁系统,融合了物联网通信技术、传感检测技术与移动端控制手段,实现了本地与远程相结合的智能防护与管理。系统通过多模块协作,能够有效对单车的使用状态进行监控,对非法移动行为做出及时报警,并通过短信与APP进行多端同步提醒,大幅提升单车的安全保障能力。

项目充分考虑了单车运行环境的特殊性,在硬件设计上选择了低功耗、高集成度的器件,采用锂电池供电并预留太阳能扩展接口,增强了系统的户外适应能力与续航性能。通信方面,选用Air724UG 4G模块确保了在无WiFi环境下依然能够稳定联网,并借助华为云物联网平台实现数据的实时上传与远程管理,体现出云端协同与边缘智能的结合。

在软件设计方面,采用了嵌入式寄存器级编程实现了主控芯片的高效控制,同时借助QT5平台开发了跨平台的APP和上位机软件,提升了用户交互体验。系统整体架构清晰、功能完整、可扩展性强,为后续功能升级与规模化应用提供了良好基础。

综上所述,本系统不仅具有较高的实用价值和技术含量,同时也展现了物联网在智能交通工具防护中的广阔应用前景,具备良好的推广与开发潜力。

相关推荐