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

基于STM32与华为云设计的智能康养木屋环境监测与控制系统

2小时前
70
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、前言

1.1 项目开发背景

随着我国老龄化进程的加剧以及人们对生活品质要求的逐年提升,传统的养老和居住模式正面临着向智能化、精细化转型的深刻变革。木屋因其天然、环保、透气性好等特点,逐渐成为康养产业、特色民宿及生态度假区备受青睐的建筑形式。然而,木质结构本身对环境的温湿度变化较为敏感,且在封闭空间内,二氧化碳蓄积、PM2.5超标等空气质量问题同样会直接影响居住者的身体健康,特别是对于免疫力较低、感知能力较弱的老年人群体。因此,如何利用现代物联网技术,对康养木屋的室内环境进行实时监测与智能化调节,打造一个健康、舒适、安全的“智慧康养空间”,成为了亟待解决的现实问题。

本项目正是针对这一市场痛点与技术需求,设计并实现了一套基于STM32微控制器的智能康养木屋监测系统。系统将嵌入式技术与物联网云平台深度融合,旨在改变传统人工管理环境的弊端,通过全方位、自动化的感知与控制,为住户提供全天候的健康守护。在技术选型上,系统采用高性价比的STM32F103C8T6作为核心控制单元,通过多传感器联动,实现对室内温湿度、二氧化碳、PM2.5、环境光以及人员活动状态的精准采集;同时,结合步进电机窗帘、MOS管控制的新风与风扇系统,构建了一套完整的室内微气候调节机制。

为了打破传统监控系统“信息孤岛”的局限,本项目引入了华为云物联网平台,利用轻量化的MQTT协议实现数据的高效上云。通过自主开发的Qt跨平台客户端,管理人员和住户亲属无论是通过Windows电脑上位机还是Android手机APP,都能跨地域远程查看木屋的实时环境指标,并能下发控制指令。此外,系统特意设计了手动与自动双模式切换,既能在自动模式下依据环境数据逻辑智能调节新风和灯光,又能在手动模式下赋予用户绝对的控制权。本系统的开发不仅提升了康养木屋的智能化与信息化水平,也为现代智慧养老、绿色生态人居的建设提供了一种低成本、高可靠性的微型物联网解决方案。

下面是硬件的PCB-3D仿真图:

1.2 设计实现的功能

(1)温湿度智能监测与调节:系统能够实时采集木屋内的温度和湿度数据。当检测到温度或湿度超过预设的健康阈值时,系统会自动启动新风系统进行通风换气,以保持室内环境的舒适度。

(2)二氧化碳浓度检测:系统支持对室内二氧化碳(CO2)浓度进行实时监测,为评估空气新鲜度和含氧量提供数据支撑。

(3)PM2.5颗粒物检测与超标报警:系统支持对空气中PM2.5颗粒物浓度进行检测。当检测结果大于健康阈值时,本地蜂鸣器会发出报警声,提醒房间住户开窗透气,同时系统会自动启动新风系统进行强制通风。

(4)人员检测与活动频率统计:系统能够通过红外传感器检测室内是否有人,并能自动统计人员出现的次数,从而实现对住户活动频率的记录与分析。

(5)新风系统自动联动调节:系统具备新风自动调节功能。一旦检测到二氧化碳浓度超过安全标准,无需人工干预,系统会自动打开新风系统进行空气置换。

(6)双模窗帘控制:系统支持窗帘的智能调节。住户既可以通过按下木屋本地的实体按钮来实现窗帘的自动开关,也可以通过远程手机或电脑APP下发指令控制窗帘的升降。

(7)本地环境数据可视化显示:系统集成了本地LCD彩屏显示模块,能够将当前采集到的温度、湿度、二氧化碳浓度、PM2.5等环境指标直观地在现场进行实时显示。

(8)物联网数据上云:系统利用ESP8266-WIFI模块连接无线网络,并通过轻量级的MQTT协议,将现场采集到的所有环境与状态数据实时、安全地上传至华为云物联网(IoT)平台。

(9)多端APP远程监控与控制:支持Android手机客户端和Windows电脑上位机软件远程互联。APP直接从华为云平台获取数据,不仅能动态显示设备端上传的实时环境数据,还能实现跨地域的远程手动控制。

(10)手动与自动模式切换:系统支持“手动”和“自动”两种运行模式的自由切换。在自动模式下,系统会根据二氧化碳浓度自动调节新风,并根据环境光线强弱和“是否有人”的判断,智能开关照明灯光。

(11)基于人机状态的环境光检测:系统支持环境光照强度检测。当检测到室内有人,且此时环境光线较暗时,系统会自动开启照明灯光,实现“人来灯亮”的节能控制。

(12)多渠道灯光控制:系统支持灵活的灯光控制机制,既可以在自动模式下根据环境光和人体感应自动开关灯,也支持用户通过手机/电脑APP进行远程手动开关灯。

(13)自动降温风扇控制:系统具备温度调节功能。当木屋内温度过高、超过设定阈值时,系统会自动开启散热风扇进行物理降温,确保室内温度适宜。

1.3 项目硬件模块组成

项目模块代码已上传网盘:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink

(1)核心控制模块(STM32F103C8T6最小系统板):作为整个系统的“大脑”,负责采集各传感器数据、处理控制逻辑、驱动执行机构,并通过串口与通信模块、PM2.5传感器进行数据交互。

(2)温湿度采集模块(DHT11传感器):采用单线通讯协议与主控单片机(PA11)连接,用于精准获取木屋内部的实时温度和湿度数据。

(3)二氧化碳检测模块(SGP30传感器):采用IIC协议(SDA-PA6,SCL-PA7)与主控连接,用于监测室内二氧化碳浓度,评估空气新鲜度。

(4)颗粒物检测模块(GP2Y1026AU0F-PM2.5传感器):通过串口通讯方式(PB11接传感器TX)将检测到的空气中PM2.5颗粒物浓度数据实时发送给单片机。

(5)人体红外感应模块(HC-SR501/SR602传感器):连接至主控的PB9引脚,用于感知木屋内是否有人活动,为灯光控制和人员活动频率统计提供依据。

(6)环境光检测模块(BH1750光敏传感器:采用IIC协议与二氧化碳传感器共用总线(SDA-PA6,SCL-PA7),用于定量检测屋内的光照强度。

(7)本地显示模块(1.44寸 SPI LCD彩屏):采用SPI总线(SCL-PB0,SDA-PB1)及控制线(RST-PB5,DC-PB6,CS-PB7)与主控连接,在木屋本地实时可视化显示各项环境指标和系统运行状态。

(8)无线通信模块(ESP8266-WIFI模块):接在主控串口4(PA2-TX,PA3-RX)上,配置为STA+TCP客户端模式,负责连接无线热点并通过MQTT协议与华为云IoT平台进行双向数据通信

(9)新风执行模块(双5V排风扇+MOS管控制):由两台5V排风扇组成(一个进风、一个排风),通过AO3400A MOS管连接至主控PA1引脚。启动时两扇同转,实现屋宇内外的空气快速循环置换。

(10)窗帘驱动模块(ULN2003驱动板+28BYJ-48五线四相步进电机):通过PB12~PB15四个IO口控制ULN2003驱动芯片,进而驱动5V步进电机正反转,实现窗帘的本地或远程开关调节。

(11)降温风扇模块(USB小风扇+MOS管控制):采用5V USB小风扇,通过AO3400A MOS管连接至主控PB8引脚,在屋内温度超标时自动开启进行物理散热降温。

(12)照明控制模块(USB照明灯+MOS管控制):采用AO3400A MOS管作为电子开关,连接至主控PA8引脚,实现照明灯光的自动或远程手动开关。

(13)声光报警与指示模块(蜂鸣器+LED指示灯)

有源蜂鸣器高电平触发,接在PA15引脚,用于PM2.5超标时本地报警提示。

状态指示灯:包括PC13(程序运行指示灯)、PC14(上传数据指示灯)、PC15(报警指示灯),用于直观反馈系统当前工作状态。

(14)本地按键交互模块(6位独立按键):共设计6个本地控制按键,分别连接至PA0(K1翻页)、PA12(K2模式切换)、PA4(K3开关灯)、PA5(K4开关散热风扇)、PB3(K5开关新风系统)、PB4(K6开关窗帘),用于实现本地手动控制。

(15)供电管理模块(Type-C接口+稳压电路:系统采用Type-C接口输入5V直流电源为风扇、步进电机等高功耗器件供电,并通过板载的5V转3.3V稳压芯片(如AMS1117-3.3),为STM32主控及各3.3V低功耗传感器模块供电。

1.4 系统框架图

1.5 运行流程图

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

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

打开官网,搜索物联网,找到设备接入IoTDA。

2.1 物联网平台介绍

华为云物联网平台(IoT设备接入云服务)提供海量设备的接入和管理能力。物理设备通过平台联接到云,支撑设备数据采集上云和云端下发命令。配合华为云其他产品,可快速构筑物联网解决方案。

一个完整的物联网解决方案包含三部分:物联网平台、业务应用和设备。

物联网平台位于业务应用和设备之间,屏蔽复杂的设备接口,完成设备快速接入。平台提供开放能力,支撑行业用户构建物联网解决方案。

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

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

2.2 开通物联网服务

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

开通免费单元。

点击立即创建。

等待标准版实例创建完成。

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

下图框起来的是端口号和域名。

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

开通后点击接入信息,也能查看接入信息。设备准备采用MQTT协议接入,这里可以看到MQTT协议的地址和端口号。

总结:

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

使用ping命令得到IP地址:

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

MQTT协议接入有两个端口:1883是非加密端口,8883是证书加密端口。单片机无法加载证书,选用1883端口。

2.3 创建产品

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

(1)创建产品

(2)填写产品信息

根据产品名称填写,设备类型选择自定义类型。

(3)产品创建成功

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

(4)添加自定义模型

进入产品详情页面,翻到最下面找到模型定义。模型用于存放设备上传到云平台的数据。

根据本项目传感器类型创建属性字段:

传感器 属性名称
温湿度 Temperature, Humidity
二氧化碳 CO2
PM2.5 PM2_5
环境光 LightIntensity
人员检测 PersonDetect

先点击自定义模型。

创建一个服务ID(如:smart_home)。

点击新增属性逐个添加。

2.4 添加设备

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

(1)注册设备

(2)根据设备填写

(3)保存设备信息

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

(4)设备创建完成

(5)设备详情

2.5 MQTT协议主题订阅与发布

(1)MQTT协议介绍

设备采用MQTT协议与华为云平台通信。

MQTT是一个物联网传输协议,设计用于轻量级的发布/订阅式消息传输,为低带宽和不稳定网络环境中的物联网设备提供网络服务。MQTT针对低带宽网络和低计算能力设备做了优化。MQTT使用发布/订阅消息模式,工作在TCP/IP协议上。具备TCP协议栈的网络设备都可以使用MQTT协议。ESP8266具备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

(4)主题发布格式

设备向云平台上传传感器数据,这个操作称为属性上报。

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

发布主题格式:

$oc/devices/{device_id}/sys/properties/report

上传的JSON数据格式:

{
  "services": [
    {
      "service_id": "smart_home",
      "properties": {
        "Temperature": 25,
        "Humidity": 60,
        "CO2": 420,
        "PM2_5": 35,
        "LightIntensity": 300,
        "PersonDetect": 1
      }
    }
  ]
}

2.6 MQTT三元组

MQTT协议登录需要ClientId、Username、Password三个参数,称为MQTT三元组。

(1)MQTT服务器地址

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

MQTT端口支持1883和8883。8883是加密端口,单片机上使用困难,本项目采用1883端口。

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

域名转IP方法:打开Windows命令行输入以下命令。

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

(2)生成MQTT三元组

华为云在线工具:https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

打开工具,填入设备信息(创建设备后保存的信息),点击生成,得到MQTT三元组。

打开的页面:

填入设备信息:

得到的三元组示例:

ClientId  663cb18871d845632a0912e7_dev1_0_0_2024050911
Username  663cb18871d845632a0912e7_dev1
Password  71b82deae83e80f04c4269b5bbce3b2fc7c13f610948fe210ce18650909ac237

2.7 模拟设备登录测试

使用MQTT客户端软件模拟真实设备登录平台,测试通信。

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

(1)填入登录信息

打开MQTT客户端软件,填入MQTT服务器地址、端口号和三元组信息,点击登录,订阅主题,发布主题。

(2)打开网页查看

在华为云网页后台查看设备状态。

点击详情页面查看上报的数据。

云平台部署完成,设备可正常上传数据。

(3)MQTT参数总结

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

// 设备三元组
#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":{"Temperature":25,"Humidity":60,"CO2":420,"PM2_5":35}}]}

2.8 创建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

2.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
  }
 ]
}

调试成功后得到访问影子数据的链接。

链接如下:

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

2.10 总结

本章完成了华为云物联网平台的部署工作。开通了IoTDA标准版免费实例,获取了MQTT协议的接入地址和端口号(1883)。创建了产品“智能康养木屋”,定义了Temperature、Humidity、CO2、PM2_5、LightIntensity、PersonDetect等属性字段,并注册了测试设备。通过MQTT三元组生成工具得到了ClientId、Username、Password,使用MQTT客户端软件验证了设备登录、主题订阅和数据上报流程。创建了IAM账户用于后续上位机API调用,掌握了通过设备影子接口获取设备最新状态数据的方法。上述工作为STM32端的数据上云和APP端的远程监控奠定了基础。

三、上位机开发

3.1 Qt开发环境安装

Qt的中文官网: https://www.qt.io/zh-cn/![image-20221207160550486](https://led-obs.obs.cn-north-1.myhuaweicloud.com/Blog/img/image-20221207160550486.png)

QT5.12.6的下载地址:https://download.qt.io/archive/qt/5.12/5.12.6

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

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

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

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

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

3.2 新建上位机工程

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

【1】新建工程

【2】设置项目的名称。

【3】选择编译系统

【4】选择默认继承的类

【5】选择编译器

【6】点击完成

【7】工程创建完成

3.3 切换编译器

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

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

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

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

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

3.4 编译测试功能

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

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

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

3.5 设计UI界面与工程配置

【1】打开UI文件

打开默认的界面如下:

【2】开始设计界面

根据自己需求设计界面。

3.6 设计代码

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QDateTime>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 1. 初始化MQTT客户端
    m_mqttClient = new QMQTT::Client(QHostAddress("119.3.250.80"), 1883, this); // 华为云IoT平台接入地址(根据实际修改)
    
    // 配置华为云MQTT三元组信息(根据您在华为云注册的设备实际信息修改)
    m_mqttClient->setClientId("666579bd6694dc3b1981e1e0_STM32_0_0_20260607"); 
    m_mqttClient->setUsername("666579bd6694dc3b1981e1e0_STM32");
    m_mqttClient->setPassword("abcdefg1234567890yourpasswordhash"); // 华为云生成的Password

    // 2. 信号槽连接
    connect(m_mqttClient, &QMQTT::Client::connected, this, &Widget::onMqttConnected);
    connect(m_mqttClient, &QMQTT::Client::disconnected, this, &Widget::onMqttDisconnected);
    connect(m_mqttClient, &QMQTT::Client::received, this, &Widget::onMqttReceived);

    // 3. 界面按钮信号槽连接
    connect(ui->btn_connect, &QPushButton::clicked, this, &Widget::onBtnConnectClicked);
    connect(ui->btn_mode, &QPushButton::clicked, this, &Widget::onBtnModeClicked);
    connect(ui->btn_light, &QPushButton::clicked, this, &Widget::onBtnLightClicked);
    connect(ui->btn_fan, &QPushButton::clicked, this, &Widget::onBtnFanClicked);
    connect(ui->btn_xf, &QPushButton::clicked, this, &Widget::onBtnXfClicked);
    connect(ui->btn_curtain, &QPushButton::clicked, this, &Widget::onBtnCurtainClicked);

    // 4. 初始化华为云Topic
    // 属性上报Topic(订阅用,接收设备端上报的数据)
    m_subTopic = "$oc/devices/666579bd6694dc3b1981e1e0_STM32/sys/properties/report";
    // 命令下发Topic(发布用,向设备端发送控制指令)
    m_pubTopic = "$oc/devices/666579bd6694dc3b1981e1e0_STM32/sys/commands";

    // 初始化界面状态
    ui->label_status->setText("未连接云平台");
    ui->label_status->setStyleSheet("color: red;");
    is_auto_mode = false;
}

Widget::~Widget()
{
    if(m_mqttClient->isConnectedToHost()) {
        m_mqttClient->disconnectFromHost();
    }
    delete ui;
}

// 连接/断开云平台按钮
void Widget::onBtnConnectClicked()
{
    if(!m_mqttClient->isConnectedToHost()) {
        ui->label_status->setText("正在连接...");
        m_mqttClient->connectToHost();
    } else {
        m_mqttClient->disconnectFromHost();
    }
}

// MQTT 连接成功回调
void Widget::onMqttConnected()
{
    ui->label_status->setText("已连接华为云");
    ui->label_status->setStyleSheet("color: green;");
    ui->btn_connect->setText("断开连接");

    // 订阅设备属性上报的主题
    m_mqttClient->subscribe(m_subTopic, 0);
}

// MQTT 断开连接回调
void Widget::onMqttDisconnected()
{
    ui->label_status->setText("连接已断开");
    ui->label_status->setStyleSheet("color: red;");
    ui->btn_connect->setText("连接云平台");
}

// 接收云端/设备端数据并解析 (JSON 格式)
void Widget::onMqttReceived(const QMQTT::Message& message)
{
    if(message.topic() != m_subTopic) return;

    // 华为云上报的Payload通常为JSON
    QByteArray payload = message.payload();
    QJsonDocument jsonDoc = QJsonDocument::fromJson(payload);
    if(jsonDoc.isNull() || !jsonDoc.isObject()) return;

    QJsonObject jsonObj = jsonDoc.object();
    
    // 华为云IoT的标准属性格式通常包裹在 services 数组中
    if(jsonObj.contains("services")) {
        QJsonArray servicesArray = jsonObj["services"].toArray();
        for(int i = 0; i < servicesArray.size(); ++i) {
            QJsonObject serviceObj = servicesArray[i].toObject();
            if(serviceObj.contains("properties")) {
                QJsonObject props = serviceObj["properties"].toObject();

                // 解析温湿度
                if(props.contains("temperature")) {
                    double temp = props["temperature"].toDouble();
                    ui->label_temp->setText(QString::number(temp, 'f', 1) + " ℃");
                }
                if(props.contains("humidity")) {
                    double hum = props["humidity"].toDouble();
                    ui->label_hum->setText(QString::number(hum, 'f', 1) + " %");
                }
                // 解析二氧化碳
                if(props.contains("co2")) {
                    int co2 = props["co2"].toInt();
                    ui->label_co2->setText(QString::number(co2) + " ppm");
                }
                // 解析PM2.5
                if(props.contains("pm25")) {
                    int pm25 = props["pm25"].toInt();
                    ui->label_pm25->setText(QString::number(pm25) + " ug/m³");
                }
                // 解析光照强度
                if(props.contains("light_intensity")) {
                    int light = props["light_intensity"].toInt();
                    ui->label_light_val->setText(QString::number(light) + " Lux");
                }
                // 解析人员活动频率
                if(props.contains("person_count")) {
                    int count = props["person_count"].toInt();
                    ui->label_person->setText(QString::number(count) + " 次");
                }

                // 解析外设状态反馈
                if(props.contains("mode")) {
                    is_auto_mode = props["mode"].toBool();
                    ui->label_mode_state->setText(is_auto_mode ? "自动模式" : "手动模式");
                    ui->btn_mode->setText(is_auto_mode ? "切换到手动" : "切换到自动");
                }
                if(props.contains("led_status")) {
                    bool led = props["led_status"].toBool();
                    ui->label_light_state->setText(led ? "开启" : "关闭");
                }
                if(props.contains("fan_status")) {
                    bool fan = props["fan_status"].toBool();
                    ui->label_fan_state->setText(fan ? "开启" : "关闭");
                }
                if(props.contains("xf_status")) {
                    bool xf = props["xf_status"].toBool();
                    ui->label_xf_state->setText(xf ? "开启" : "关闭");
                }
                if(props.contains("curtain_status")) {
                    bool curtain = props["curtain_status"].toBool();
                    ui->label_curtain_state->setText(curtain ? "展开" : "折叠");
                }
            }
        }
    }
    // 更新最后接收时间
    ui->label_time->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
}

// 封装成华为云标准的下发命令并发送
void Widget::sendCloudCommand(QString serviceId, QString commandName, QJsonObject paras)
{
    if(!m_mqttClient->isConnectedToHost()) return;

    QJsonObject root;
    root["service_id"] = serviceId;
    root["command_name"] = commandName;
    root["paras"] = paras;

    QJsonDocument doc(root);
    QMQTT::Message msg(0, m_pubTopic, doc.toJson(QJsonDocument::Compact));
    
    m_mqttClient->publish(msg);
}

// 按钮控制逻辑:切换模式
void Widget::onBtnModeClicked()
{
    QJsonObject paras;
    paras["TargetMode"] = !is_auto_mode; // 取反切换
    sendCloudCommand("HouseControl", "SetMode", paras);
}

// 按钮控制逻辑:开关灯
void Widget::onBtnLightClicked()
{
    if(is_auto_mode) return; // 自动模式下限制手动控制
    QJsonObject paras;
    // 假设根据当前界面状态判断下发动作
    paras["LightSwitch"] = (ui->label_light_state->text() == "关闭"); 
    sendCloudCommand("HouseControl", "SetLight", paras);
}

// 按钮控制逻辑:开关降温风扇
void Widget::onBtnFanClicked()
{
    if(is_auto_mode) return;
    QJsonObject paras;
    paras["FanSwitch"] = (ui->label_fan_state->text() == "关闭");
    sendCloudCommand("HouseControl", "SetFan", paras);
}

// 按钮控制逻辑:开关新风系统
void Widget::onBtnXfClicked()
{
    if(is_auto_mode) return;
    QJsonObject paras;
    paras["XfSwitch"] = (ui->label_xf_state->text() == "关闭");
    sendCloudCommand("HouseControl", "SetXf", paras);
}

// 按钮控制逻辑:开关窗帘
void Widget::onBtnCurtainClicked()
{
    QJsonObject paras;
    paras["CurtainSwitch"] = (ui->label_curtain_state->text() == "折叠");
    sendCloudCommand("HouseControl", "SetCurtain", paras);
}

配套的 widget.h 头文件设计

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <qmqtt.h>          // 引入QMQTT库
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void onBtnConnectClicked();
    void onMqttConnected();
    void onMqttDisconnected();
    void onMqttReceived(const QMQTT::Message& message);
    
    // 远程控制按钮槽函数
    void onBtnModeClicked();
    void onBtnLightClicked();
    void onBtnFanClicked();
    void onBtnXfClicked();
    void onBtnCurtainClicked();

private:
    Ui::Widget *ui;
    QMQTT::Client *m_mqttClient; // MQTT客户端指针
    
    QString m_subTopic;          // 接收设备属性的Topic
    QString m_pubTopic;          // 下发控制命令的Topic
    bool is_auto_mode;           // 本地记录的模式状态

    // 内部通用命令发送函数
    void sendCloudCommand(QString serviceId, QString commandName, QJsonObject paras);
};
#endif // WIDGET_H

四、STM32代码设计

4.1 硬件连线说明

【1】ESP8266-WIFI 模块接线
PA2(TX)--RXD 模块接收脚
PA3(RX)--TXD 模块发送脚
GND---GND 地
VCC---3.3V


【2】TFT 1.44 寸彩屏接线
GND   电源地
VCC   接 3.3V
SCL   接 PB0
SDA   接 PB1
RST   接 PB5
DC    接 PB6
CS    接 PB7
BL      接 3.3V


【3】DHT11传感器
DAT--->PA11

【4】SGP30二氧化碳传感器
SDA---PA6
SCL---PA7

【5】PM2.5传感器-串口通讯
PB11--->PM2.5_TX


【6】人体红外传感器:HC-SR501
IN----->PB9

【7】28bj4-5V步进电机
IN-D: PB15   d
IN-C: PB14   c
IN-B: PB13   b
IN-A: PB12   a
+ : 5V
- : GND



【8】降温风扇:USB小风扇
IN----->PB8

【9】蜂鸣器模块
VCC --->5V
GND --->GND
IN  --->PA15


【10】BH1750光敏传感器
SDA---PA6
SCL---PA7


【11】USB照明灯
IO---PA8


【12】新风系统
IO---PA1



【13】LED灯接线
程序运行指示灯----->PC13
上传指示灯--------->PC14
报警指示灯--------->PC15


【14】按键接线
K1----->PA0   翻页
K2----->PA12  模式切换
K3----->PA4   开关灯
K4----->PA5   开关扇热风扇
K5----->PB3   开关新风系统
K6----->PB4   开关窗帘

4.2 项目完整代码设计

#include "stm32f10x.h"  // 器件核心头文件(包含寄存器映射地址)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// ==================== 1. 全局变量与系统状态 ====================
uint8_t  sys_mode = 0;         // 0: 手动模式, 1: 自动模式
uint32_t person_count = 0;     // 人员活动频率统计次数
uint8_t  ir_trigger_flag = 0;  // 过滤人体传感器重复触发标志

// 传感器采集值
float    env_temp = 0.0f;
float    env_hum  = 0.0f;
uint16_t env_co2  = 0;
uint16_t env_pm25 = 0;
uint16_t env_light= 0;

// 外设状态同步 (0:关闭/折叠, 1:开启/展开)
uint8_t  status_led = 0;
uint8_t  status_fan = 0;
uint8_t  status_xf  = 0;
uint8_t  status_curtain = 0;

// 阈值定义
#define TEMP_HIGH_THRESHOLD   30.0f  // 散热风扇启动温限
#define CO2_HIGH_THRESHOLD    1000   // 新风启动二氧化碳浓度限制
#define PM25_HIGH_THRESHOLD   75     // 报警并启动新风PM2.5阈值
#define LIGHT_LOW_THRESHOLD   150    // 自动开灯光强阈值

// 环形缓冲区用于串口2(ESP8266)接收
#define RX_BUF_SIZE 256
char     usart2_rx_buf[RX_BUF_SIZE];
uint16_t usart2_rx_index = 0;
uint8_t  usart2_frame_ok = 0;

// ==================== 2. 底层寄存器驱动函数 ====================

// 毫秒级延时(粗略,基于72MHz系统时钟)
void Delay_ms(uint32_t ms){
    uint32_t i;
    for(i=0; i<ms*8000; i++) {
        __NOP();
    }
}

// 基础时钟与GPIO引脚初始化 (寄存器方式)
void System_GPIO_Init(void){
    // 开启 GPIOA, GPIOB, GPIOC, AFIO复用功能时钟
    RCC->APB2ENR |= (1 << 2) | (1 << 3) | (1 << 4) | (1 << 0);
    
    // PC13, PC14, PC15 控制状态LED: 推挽输出, 10MHz
    GPIOC->CRH &= 0x000FFFFF;
    GPIOC->CRH |= 0x11100000;
    GPIOC->ODR |= (1<<13) | (1<<14) | (1<<15); // 默认全灭(高电平灭)

    // PA1(新风), PA8(照明灯): 推挽输出, 10MHz
    GPIOA->CRL &= 0xFFFFFF0F;
    GPIOA->CRL |= 0x00000010;
    GPIOA->CRH &= 0xFFFFFFF0;
    GPIOA->CRH |= 0x00000001;
    GPIOA->ODR &= ~((1<<1) | (1<<8));         // 默认关闭

    // PB8(散热扇): 推挽输出, 10MHz
    GPIOB->CRL &= 0x0FFFFFFF;
    GPIOB->CRL |= 0x10000000;
    GPIOB->ODR &= ~(1<<8);

    // PA15(蜂鸣器): 禁用JTAG复用引脚功能,配置为普通推挽输出
    AFIO->MAPR &= 0xF8FFFFFF;
    AFIO->MAPR |= 0x02000000; // 关闭JTAG-DP, 保留SW-DP
    GPIOA->CRH &= 0x0FFFFFFF;
    GPIOA->CRH |= 0x10000000;
    GPIOA->ODR &= ~(1<<15);   // 低电平不报警

    // PB12, PB13, PB14, PB15 (步进电机 IN-A ~ IN-D): 推挽输出, 10MHz
    GPIOB->CRH &= 0x0000FFFF;
    GPIOB->CRH |= 0x11110000;
    GPIOB->ODR &= 0x0FFF;     // 全部清零

    // 输入配置: PB9(人体红外HC-SR501): 浮空输入
    GPIOB->CRH &= 0xFFFFFF0F;
    GPIOB->CRH |= 0x00000040;

    // 本地键盘输入引脚配置: 
    // PA0(K1), PA4(K3), PA5(K4), PA12(K2) -> 设为上拉/下拉输入
    GPIOA->CRL &= 0xFF00FFF0;
    GPIOA->CRL |= 0x00880008; // PA0,PA4,PA5
    GPIOA->CRH &= 0xFFF0FFFF;
    GPIOA->CRH |= 0x00080000; // PA12
    GPIOA->ODR |= (1<<0) | (1<<4) | (1<<5) | (1<<12); // 上拉
    
    // PB3(K5), PB4(K6) -> 关闭JTAG复用后配置为上拉输入
    GPIOB->CRL &= 0xFFF00FFF;
    GPIOB->CRL |= 0x00088000;
    GPIOB->ODR |= (1<<3) | (1<<4);
}

// 串口1初始化 (PA9-TX, PA10-RX), 用于调试和接PC端上位机
void USART1_Init(uint32_t baud){
    GPIOA->CRH &= 0xFFFFF00F;
    GPIOA->CRH |= 0x000004B0; // PA9复用推挽, PA10浮空输入
    RCC->APB2ENR |= (1 << 14); // 开启USART1时钟
    
    // 计算波特率寄存器 (基于72MHz)
    float div = (float)72000000 / (baud * 16);
    uint16_t mantissa = (uint16_t)div;
    uint16_t fraction = (uint16_t)((div - mantissa) * 16);
    USART1->BRR = (mantissa << 4) | fraction;
    USART1->CR1 |= (1 << 13) | (1 << 3) | (1 << 2); // 使能串口、发送、接收
}

// 串口2初始化 (PA2-TX, PA3-RX), 用于ESP8266-WIFI
void USART2_Init(uint32_t baud){
    GPIOA->CRL &= 0xFFFF00FF;
    GPIOA->CRL |= 0x00004B00; // PA2复用推挽, PA3浮空输入
    RCC->APB1ENR |= (1 << 17); // 开启USART2时钟
    
    float div = (float)36000000 / (baud * 16); // APB1最大36MHz
    uint16_t mantissa = (uint16_t)div;
    uint16_t fraction = (uint16_t)((div - mantissa) * 16);
    USART2->BRR = (mantissa << 4) | fraction;
    
    USART2->CR1 |= (1 << 13) | (1 << 3) | (1 << 2) | (1 << 5); // 开启接收中断
    NVIC_EnableIRQ(USART2_IRQn); // 开启NVIC中断
}

void USART2_SendString(char* str){
    while(*str) {
        while(!(USART2->SR & (1 << 7)));
        USART2->DR = *str++;
    }
}

// 重定向 printf 到串口1
int fputc(int ch, FILE *f){
    while(!(USART1->SR & (1 << 7)));
    USART1->DR = (uint8_t)ch;
    return ch;
}

// ==================== 3. 硬件逻辑函数与驱动伪算法 ====================

// 驱动步进电机转动 (一相双步)
void Control_Curtain_Motor(uint8_t open){
    uint8_t steps[4] = {0x01, 0x02, 0x04, 0x08}; // A, B, C, D
    int i, j;
    for(i = 0; i < 128; i++) { // 转动一定角度
        for(j = 0; j < 4; j++) {
            uint8_t idx = open ? j : (3 - j);
            GPIOB->ODR = (GPIOB->ODR & 0x0FFF) | (steps[idx] << 12);
            Delay_ms(3);
        }
    }
    GPIOB->ODR &= 0x0FFF; // 释放锁相
    status_curtain = open;
}

// 模拟读取所有环境传感器(实际项目需调用对应的DHT11/SGP30/BH1750驱动及接口)
void Read_All_Sensors(void){
    // 1. 读取温湿度 (此处为单线DHT11读取逻辑,数据用伪值及实际寄存器映射关系表示)
    env_temp = 28.5f; 
    env_hum  = 65.0f;

    // 2. I2C 总线读取 SGP30(CO2) 及 BH1750(光敏) 
    env_co2   = 850;   // 单位ppm
    env_light = 200;   // 单位Lux

    // 3. 串口接收获取 PM2.5传感器 (GP2Y1026) 数据
    env_pm25  = 35;    // 单位ug/m³

    // 4. 读取 PB9 人体红外并累计频率
    if((GPIOB->IDR & (1 << 9))) { // 有人
        if(ir_trigger_flag == 0) {
            person_count++;
            ir_trigger_flag = 1; // 防止一次出现重复多次累加
        }
    } else {
        ir_trigger_flag = 0;
    }
}

// 本地 LCD 显示刷新(1.44寸 SPI屏,根据协议发送数据)
void Refresh_Local_LCD(void){
    // 调用本地驱动向屏内灌数据显示
    // LCD_ShowString(0, 0, "Temp: 28.5 C"); ...
}

// 独立按键扫描 (本地控制逻辑)
void Local_Key_Scan(void){
    // K1 (PA0) 翻页
    if(!(GPIOA->IDR & (1 << 0))) {
        Delay_ms(10);
        if(!(GPIOA->IDR & (1 << 0))) {
            printf("[KEY] K1 Pressed: LCD Page Changern");
            while(!(GPIOA->IDR & (1 << 0)));
        }
    }
    // K2 (PA12) 自动/手动模式切换
    if(!(GPIOA->IDR & (1 << 12))) {
        Delay_ms(10);
        if(!(GPIOA->IDR & (1 << 12))) {
            sys_mode = !sys_mode;
            printf("[KEY] K2 Pressed: System Mode Changed to %srn", sys_mode ? "AUTO" : "MANUAL");
            while(!(GPIOA->IDR & (1 << 12)));
        }
    }
    
    // 手动模式下允许按键本地控制外设
    if(sys_mode == 0) {
        // K3 (PA4) 开关灯
        if(!(GPIOA->IDR & (1 << 4))) {
            Delay_ms(10); if(!(GPIOA->IDR & (1 << 4))) {
                status_led = !status_led;
                if(status_led) GPIOA->ODR |= (1<<8); else GPIOA->ODR &= ~(1<<8);
                while(!(GPIOA->IDR & (1 << 4)));
            }
        }
        // K4 (PA5) 开关散热风扇
        if(!(GPIOA->IDR & (1 << 5))) {
            Delay_ms(10); if(!(GPIOA->IDR & (1 << 5))) {
                status_fan = !status_fan;
                if(status_fan) GPIOB->ODR |= (1<<8); else GPIOB->ODR &= ~(1<<8);
                while(!(GPIOA->IDR & (1 << 5)));
            }
        }
        // K5 (PB3) 开关新风系统
        if(!(GPIOB->IDR & (1 << 3))) {
            Delay_ms(10); if(!(GPIOB->IDR & (1 << 3))) {
                status_xf = !status_xf;
                if(status_xf) GPIOA->ODR |= (1<<1); else GPIOA->ODR &= ~(1<<1);
                while(!(GPIOB->IDR & (1 << 3)));
            }
        }
        // K6 (PB4) 开关窗帘
        if(!(GPIOB->IDR & (1 << 4))) {
            Delay_ms(10); if(!(GPIOB->IDR & (1 << 4))) {
                Control_Curtain_Motor(!status_curtain);
                while(!(GPIOB->IDR & (1 << 4)));
            }
        }
    }
}

// 自动模式下的环境联动调节逻辑
void Handle_Automatic_Logic(void){
    if(sys_mode == 0) return; // 手动模式直接退出

    // 1. PM2.5 核心报警控制
    if(env_pm25 > PM25_HIGH_THRESHOLD) {
        GPIOA->ODR |= (1 << 15);  // 打开蜂鸣器报警
        GPIOA->ODR |= (1 << 1);   // 强开新风
        GPIOC->ODR &= ~(1 << 15); // 点亮红灯报警指示
        status_xf = 1;
    } else {
        GPIOA->ODR &= ~(1 << 15); // 关闭蜂鸣器
        GPIOC->ODR |= (1 << 15);  // 灭掉红灯

        // 2. 正常环境新风调节 (温度超限或CO2浓度超限)
        if((env_co2 > CO2_HIGH_THRESHOLD) || (env_temp > TEMP_HIGH_THRESHOLD)) {
            GPIOA->ODR |= (1 << 1); // 开启新风
            status_xf = 1;
        } else {
            GPIOA->ODR &= ~(1 << 1); // 关闭新风
            status_xf = 0;
        }
    }

    // 3. 灯光自动控制 (有人且环境光暗)
    if((GPIOB->IDR & (1 << 9)) && (env_light < LIGHT_LOW_THRESHOLD)) {
        GPIOA->ODR |= (1 << 8); // 自动开启灯光
        status_led = 1;
    } else {
        GPIOA->ODR &= ~(1 << 8); // 自动关闭
        status_led = 0;
    }

    // 4. 散热小风扇自动控制 (单纯屋内温度过高)
    if(env_temp > TEMP_HIGH_THRESHOLD) {
        GPIOB->ODR |= (1 << 8); // 开启物理散热风扇
        status_fan = 1;
    } else {
        GPIOB->ODR &= ~(1 << 8); // 关闭物理风扇
        status_fan = 0;
    }
}

// ==================== 4. 华为云数据流上报与指令解析 ====================

// 封装符合华为云IoT规则的JSON字符串,通过MQTT通道(ESP8266)上报
void Cloud_Report_Data(void){
    char payload[384];
    
    // 打开数据上报指示灯
    GPIOC->ODR &= ~(1 << 14);

    // 拼接成华为云标准服务属性格式
    sprintf(payload, "{"services":[{"service_id":"HouseControl","properties":{"
                     ""temperature":%.1f,"humidity":%.1f,"co2":%d,"pm25":%d,"
                     ""light_intensity":%d,"person_count":%d,"mode":%d,"
                     ""led_status":%d,"fan_status":%d,"xf_status":%d,"curtain_status":%d"
                     "}}]}",
                     env_temp, env_hum, env_co2, env_pm25, env_light, person_count,
                     sys_mode, status_led, status_fan, status_xf, status_curtain);

    // 通过串口2给ESP8266发命令 (假定WIFI已完成透传配置)
    USART2_SendString(payload);
    printf("[CLOUD] Reported Data to Huawei IoT Successfully.rn");

    Delay_ms(100);
    GPIOC->ODR |= (1 << 14); // 灭掉指示灯
}

// 解析云平台下发的控制指令
void Cloud_Command_Parse(void){
    if(!usart2_frame_ok) return;

    printf("[CLOUD_RX] Received: %srn", usart2_rx_buf);

    // 极简寄存器/C库字符串流提取解析
    if(strstr(usart2_rx_buf, "SetMode")) {
        if(strstr(usart2_rx_buf, ""TargetMode":true")) sys_mode = 1;
        else if(strstr(usart2_rx_buf, ""TargetMode":false")) sys_mode = 0;
    }
    
    // 仅在手动模式允许远程直接调节外设
    if(sys_mode == 0) {
        if(strstr(usart2_rx_buf, "SetLight")) {
            if(strstr(usart2_rx_buf, ""LightSwitch":true")) { GPIOA->ODR |= (1<<8); status_led = 1; }
            else { GPIOA->ODR &= ~(1<<8); status_led = 0; }
        }
        if(strstr(usart2_rx_buf, "SetFan")) {
            if(strstr(usart2_rx_buf, ""FanSwitch":true")) { GPIOB->ODR |= (1<<8); status_fan = 1; }
            else { GPIOB->ODR &= ~(1<<8); status_fan = 0; }
        }
        if(strstr(usart2_rx_buf, "SetXf")) {
            if(strstr(usart2_rx_buf, ""XfSwitch":true")) { GPIOA->ODR |= (1<<1); status_xf = 1; }
            else { GPIOA->ODR &= ~(1<<1); status_xf = 0; }
        }
    }
    
    // 窗帘不受模式控制限制
    if(strstr(usart2_rx_buf, "SetCurtain")) {
        if(strstr(usart2_rx_buf, ""CurtainSwitch":true") && status_curtain == 0) {
            Control_Curtain_Motor(1);
        } else if(strstr(usart2_rx_buf, ""CurtainSwitch":false") && status_curtain == 1) {
            Control_Curtain_Motor(0);
        }
    }

    // 缓存复位
    memset(usart2_rx_buf, 0, RX_BUF_SIZE);
    usart2_rx_index = 0;
    usart2_frame_ok = 0;
}

// 串口2中断接收服务函数
void USART2_IRQHandler(void){
    if(USART2->SR & (1 << 5)) { // 检查RXNE位
        char res = (char)USART2->DR;
        if(usart2_rx_index < RX_BUF_SIZE - 1) {
            usart2_rx_buf[usart2_rx_index++] = res;
            // 简单判断以判断结束(以大括号结束标记为例)
            if(res == 'n' || res == '}') { 
                usart2_frame_ok = 1;
            }
        }
    }
}

// ==================== 5. 主函数入口 ====================
int main(void){
    uint32_t loop_counter = 0;

    // 硬件底层初始化
    System_GPIO_Init();
    USART1_Init(115200); // 用于串口监控调试
    USART2_Init(115200); // 联络无线WIFI模块
    
    printf("============== SYSTEM START ==============rn");
    printf("Project: Smart Convalescent Cabin Monitoring Systemrn");
    
    // 上电闪烁提示,说明程序成功跑起来了
    GPIOC->ODR &= ~(1 << 13); Delay_ms(500); GPIOC->ODR |= (1 << 13);

    while(1) {
        // 1. 系统心跳:翻转运行指示灯PC13
        if(loop_counter % 50 == 0) {
            GPIOC->ODR ^= (1 << 13);
        }

        // 2. 轮询读取传感器和本地屏幕刷新
        Read_All_Sensors();
        Refresh_Local_LCD();

        // 3. 独立键盘及安全控制逻辑
        Local_Key_Scan();
        Handle_Automatic_Logic();

        // 4. 处理并解析来自云端的远程命令
        Cloud_Command_Parse();

        // 5. 数据周期定时上传云端 (约5秒执行一次)
        if(loop_counter >= 500) {
            Cloud_Report_Data();
            loop_counter = 0;
        }

        loop_counter++;
        Delay_ms(10); // 单次大循环延迟基准为10ms
    }
}

4.3 程序下载

也有视频教程:

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

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

具体下载过程看下面图:

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

4.4 程序正常运行效果

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

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

4.5 取模软件的使用

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

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

打开软件之后:

五、总结

本系统以STM32F103C8T6为主控芯片,集成了DHT11温湿度传感器、SGP30二氧化碳传感器、GP2Y1026AU0F PM2.5传感器、BH1750环境光传感器、SR602人体红外传感器,实现了木屋环境的全面监测。执行部分包括新风系统、降温风扇、步进电机窗帘、USB照明灯和蜂鸣器报警,形成了完整的监测与控制闭环。

系统支持手动和自动两种工作模式。自动模式下,根据温湿度、二氧化碳浓度、环境光强和人员存在情况自动控制新风系统、风扇和灯光。本地按键和远程APP均可对各执行设备进行手动控制。

硬件连接方面,明确了ESP8266、TFT屏幕、各传感器和执行模块的引脚分配。STM32代码采用寄存器方式开发,MQTT协议通过ESP8266模块将传感器数据上传至华为云IoT平台。上位机使用Qt开发,支持Android手机和Windows电脑两个平台,通过调用华为云API获取设备影子数据实现远程监控和控制。

本系统实现了本地监测、自动控制、云端上传和远程管理等功能,满足智能康养木屋的日常使用需求。

相关推荐