一、项目开发背景
面粉厂作为食品加工行业的重要组成部分,其生产车间环境复杂,涉及大量机械设备运行和粉尘产生,存在较高的安全风险。面粉粉尘具有可燃性,当浓度达到一定阈值时,遇火源可能引发爆炸事故,同时车间温湿度变化和设备异常震动也会影响生产稳定性和人员安全。传统监控方式主要依赖人工巡检和简单仪表,存在响应延迟、数据不全面等问题,难以实现实时预警和高效管理。
随着工业自动化与物联网技术的发展,智能监控系统成为提升安全生产水平的关键手段。通过集成传感器、微控制器和无线通信技术,可以实时采集环境参数,及时识别异常状态,并自动触发报警机制,从而有效预防事故的发生。本项目基于STM32单片机设计的面粉厂车间安全生产系统,正是为了应对这些挑战,结合温湿度、粉尘浓度和震动监测等功能,构建一个全面、可靠的监控网络。
该系统的开发弥补传统方法的不足,通过高精度传感器和WiFi通信模块,实现数据远程传输与终端APP实时显示,使管理人员能够随时随地掌握车间状况。此外,系统支持阈值远程设置和本地指示,增强了灵活性和智能化程度,有助于降低人为失误,提高应急响应效率。通过这一创新应用,不仅能够保障生产安全,还能推动面粉厂向数字化、智能化转型,为行业可持续发展提供支持。
框架图
应用展示层网络通信层核心控制层感知执行层状态指示单元报警执行单元数据采集单元
开关量(GPIO/EXTI)
GPIO(高电平触发)
GPIO(高电平触发)
GPIO
GPIO
TCP/IP协议
无线数据透传
阈值设置指令
UART串口
DHT11温湿度传感器GP2Y1051AU0F粉尘浓度传感器SW-420震动传感器有源蜂鸣器红色报警LED灯运行状态LEDWiFi状态LEDSTM32F103RCT6主控制器ESP8266 WiFi模块(ESP-12F)WiFi无线网络Qt开发终端APP数据实时显示报警信息推送阈值远程设置
框架图层次与流程说明:
1. 感知执行层 (最底层)
• 数据采集单元:负责物理世界信号的感知。
DHT11:通过单总线数字协议将温湿度数据发送给STM32。•
GP2Y1051AU0F:输出模拟电压信号,由STM32的ADC模块转换为粉尘浓度数字值。•
SW-420:输出开关量信号,可通过STM32的GPIO或外部中断(EXTI)检测震动状态。
• 报警执行单元:接收STM32的控制指令,进行声光报警。
2. 核心控制层
STM32F103RCT6:作为系统的“大脑”。
功能:轮询采集所有传感器数据,进行数据处理、阈值比较和逻辑判断。根据结果控制执行单元,并通过UART与WiFi模块进行通信调度。
3. 网络通信层
ESP8266模块:作为通信网关,通过UART串口与STM32连接,使用AT指令集进行数据传输。•
WiFi网络:提供无线传输媒介,承载设备与APP之间的TCP/IP通信。
4. 应用展示层 (最顶层)
Qt终端APP:为用户提供图形化界面。
功能:实时显示车间所有环境参数与设备状态;接收并推送报警信息;提供界面供用户远程修改阈值参数,并下发至STM32。
二、设计实现的功能
(1)温湿度检测功能:采用DHT11温湿度传感器,实时采集车间温湿度数据并显示。
(2)粉尘浓度检测功能:采用GP2Y1051AU0F粉尘传感器,检测车间空气中粉尘浓度,超过阈值自动报警。
(3)震动检测功能:采用SW-420震动传感器,监测设备运行状态,当震动异常时触发警报。
(4)声光报警功能:采用高亮红色LED报警灯与高电平触发有源蜂鸣器组成声光报警单元,实现故障警示。
(5)WiFi通信功能:采用ESP8266-WIFI模块(ESP-12F版本),通过UART串口与STM32通信,实现数据上传与远程监控。
(6)数据采集与处理功能:由STM32F103RCT6单片机作为主控核心,负责各传感器数据的采集、分析与判断。
(7)远程监控与显示功能:终端APP基于Qt(C++)开发,可实时显示车间温湿度、粉尘浓度、震动状态及报警信息。
(8)阈值设定与修改功能:APP端支持阈值参数设置,并通过WiFi下发至STM32端实现实时调整。
(9)本地运行指示功能:通过LED指示灯显示系统运行与联网状态,便于现场维护与监控。
三、项目硬件模块组成
(1)主控芯片:STM32F103RCT6,负责系统核心控制、数据处理与逻辑判断。
(2)温湿度传感器模块:DHT11,用于检测车间温度与湿度。
(3)粉尘传感器模块:GP2Y1051AU0F,用于检测空气中粉尘浓度。
(4)震动传感器模块:SW-420,用于监测机械震动状态。
(5)WiFi通信模块:ESP8266(ESP-12F),用于无线数据传输与APP通信。
(6)报警模块:包含高电平触发有源蜂鸣器与红色LED报警灯,用于声光报警提示。
(7)显示与指示模块:LED指示灯,用于显示系统运行与报警状态。
(8)电源模块:DC 5V稳压电源模块,为主控及传感器提供稳定电源。
(9)数据通信接口:UART串口通信接口,用于STM32与ESP8266之间的数据交互。
模块的模块源码已经上传到网盘:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink
四、设计意义
本系统的设计旨在提升面粉厂车间的安全生产水平,通过实时监测关键环境参数和设备状态,有效预防因温湿度异常、粉尘浓度超标或机械故障引发的安全事故。面粉厂车间环境中的粉尘具有易燃易爆特性,系统通过粉尘浓度检测与报警功能,能够及时警示工作人员采取措施,降低爆炸风险,保障人员与设备安全。同时,震动监测功能可识别设备异常运行,避免机械故障扩大化,减少生产中断和设备损坏。
系统的远程监控与数据上传功能通过WiFi模块实现,使管理人员能够通过终端APP实时查看车间数据,并在异常时接收警报,大大提升了监控的便捷性和响应速度。这种智能化设计减少了人工巡检的依赖,提高了生产管理的效率,并支持阈值参数的灵活调整,使系统能够适应不同工况需求,增强整体运营的适应性。
此外,本地声光报警和状态指示功能确保了现场工作人员能够快速识别问题,及时处理异常,进一步强化了车间的应急响应能力。整体上,该系统通过集成传感器、主控芯片和通信模块,实现了对车间环境的全面智能化管理,不仅提升了安全防护水平,还为面粉厂的可持续生产提供了可靠的技术支持。
五、设计思路
该系统设计以STM32F103RCT6单片机为核心控制器,负责协调各传感器模块的数据采集与处理,实现对面粉厂车间环境的全面监控。通过集成DHT11温湿度传感器、GP2Y1051AU0F粉尘传感器和SW-420震动传感器,系统能够实时获取车间温度、湿度、粉尘浓度及设备震动状态等关键参数。所有采集的数据由STM32进行解析和判断,确保高效可靠的环境监测。
数据采集后,系统会与预设阈值进行比对,若温湿度、粉尘浓度或震动频率超出安全范围,STM32将立即触发声光报警单元,包括高电平触发有源蜂鸣器和红色LED报警灯,以警示现场工作人员采取应对措施。报警逻辑基于实时数据分析,确保及时响应异常情况,避免安全生产事故。
通信方面,系统采用ESP8266 WiFi模块通过UART串口与STM32连接,实现数据的无线传输。终端APP基于Qt开发,可实时接收并显示车间监测数据,同时在异常时推送警报信息。APP还支持远程修改阈值参数,并通过WiFi下发至STM32,增强系统的灵活性和智能化程度,方便用户根据实际需求调整监控标准。
本地运行状态通过LED指示灯实时显示,包括系统正常运行、联网状态及报警触发情况,便于现场维护人员直观掌握系统工作状态。电源模块提供稳定的5V供电,确保各硬件组件可靠运行。整体设计注重实用性与可靠性,通过模块化集成实现了数据采集、处理、报警和远程监控的一体化功能。
六、框架图
+---------------------------------------------+
| 终端APP (Qt) |
| - 实时显示监测数据 |
| - 接收警报信息 |
| - 设置阈值参数 |
+---------------------------------------------+
^
| WiFi通信
v
+---------------------------------------------+
| WiFi模块 (ESP8266) |
| (ESP-12F) |
+---------------------------------------------+
^
| UART串口通信
v
+---------------------------------------------+
| STM32F103RCT6 |
| - 数据采集与处理 |
| - 阈值判断与报警控制 |
| - 与WiFi模块通信 |
+---------------------------------------------+
| | |
v v v
+----------+ +----------+ +----------+
| 温湿度传感器 | | 粉尘传感器 | | 震动传感器 |
| (DHT11) | | (GP2Y1051) | | (SW-420) |
+----------+ +----------+ +----------+
|
v
+---------------------------------------------+
| 报警模块 |
| - 声光报警 (蜂鸣器+红色LED) |
+---------------------------------------------+
^
|
+---------------------------------------------+
| 电源模块 |
| (DC 5V稳压) |
+---------------------------------------------+
七、系统总体设计
系统总体设计基于STM32F103RCT6主控芯片为核心,构建一个面粉厂车间安全生产监控系统。系统通过集成多种传感器实时采集车间环境参数,包括温湿度、粉尘浓度和设备震动状态,确保生产环境安全可靠。主控芯片负责数据采集、分析和逻辑判断,当检测到参数超过预设阈值时,自动触发声光报警单元,提醒工作人员及时处理异常情况。
硬件架构包括温湿度传感器DHT11、粉尘传感器GP2Y1051AU0F和震动传感器SW-420,这些传感器分别负责监测车间温度、湿度、粉尘浓度和机械震动频率。WiFi通信模块ESP8266通过UART串口与STM32主控连接,实现数据无线传输至终端APP,支持远程监控和数据交互。报警模块由高电平触发有源蜂鸣器和红色LED报警灯组成,用于在异常时发出声光警示。
数据采集与处理功能由STM32主控统一管理,实时读取传感器数据并进行阈值比较,判断是否触发报警。系统支持本地和远程阈值参数设置,通过WiFi模块接收APP下发的配置信息,增强系统灵活性和智能化水平。终端APP基于Qt开发,可实时显示车间监测数据、报警状态,并允许用户调整阈值参数。
通信机制通过WiFi模块实现STM32与APP之间的稳定数据传输,确保车间环境数据实时上传和远程监控。系统运行状态和报警信息通过本地LED指示灯直观显示,便于现场维护人员快速识别系统状况。电源模块采用DC 5V稳压电源,为整个系统提供稳定电力支持,保证各硬件模块正常运行。
八、系统功能总结
| 功能模块 | 功能描述 |
|---|---|
| 温湿度检测功能 | 采用DHT11传感器实时采集车间温度与湿度数据,并进行分析与显示。 |
| 粉尘浓度检测功能 | 使用GP2Y1051AU0F传感器检测空气中粉尘浓度,超阈值时自动触发报警机制。 |
| 震动检测功能 | 通过SW-420震动传感器监测设备运行状态,异常震动时判断机械故障并报警。 |
| 声光报警功能 | 集成高亮红色LED报警灯和有源蜂鸣器,实现超限或故障时的声光警示。 |
| WiFi通信功能 | 采用ESP8266模块通过UART串口与STM32通信,支持数据远程上传和APP交互。 |
| 数据采集与处理功能 | STM32F103RCT6主控负责多传感器数据采集、分析与逻辑判断,确保系统稳定运行。 |
| 远程监控与显示功能 | 基于Qt开发的终端APP实时显示温湿度、粉尘浓度、震动状态及报警信息。 |
| 阈值设定与修改功能 | 支持APP端远程或本地修改温湿度、粉尘浓度等阈值参数,增强系统灵活性。 |
| 本地运行指示功能 | 通过LED指示灯实时显示系统运行状态、联网状态及报警情况,便于现场维护。 |
九、设计的各个功能模块描述
温湿度检测功能采用DHT11传感器实时采集面粉厂车间的温度和湿度数据,传感器将采集到的参数传输至STM32主控芯片进行处理和显示,确保环境条件处于安全监控范围内。
粉尘浓度检测功能通过GP2Y1051AU0F粉尘传感器监测车间空气中的粉尘浓度,当检测值超过预设阈值时,系统会自动触发报警机制,提醒工作人员及时处理潜在安全隐患。
震动检测功能使用SW-420震动传感器监测设备运行状态,当检测到异常震动频率或持续高震动时,系统判断可能存在机械故障,并立即启动报警流程以预防设备损坏。
声光报警功能由高亮红色LED报警灯和高电平触发有源蜂鸣器组成,当系统检测到温湿度、粉尘浓度或震动参数异常时,自动激活声光警示,为现场人员提供直观的故障提醒。
WiFi通信功能集成ESP8266-WIFI模块(ESP-12F版本),通过UART串口与STM32主控芯片进行数据交互,实现车间监测数据的无线上传和终端APP的远程通信,支持实时监控和指令接收。
数据采集与处理功能以STM32F103RCT6单片机为核心,负责从各传感器采集温湿度、粉尘浓度和震动数据,并进行实时分析、判断与逻辑控制,确保系统响应准确及时。
远程监控与显示功能基于Qt(C++)开发的终端APP,可实时显示车间温湿度、粉尘浓度、震动状态及报警信息,用户可通过APP远程查看数据并在异常时接收警报通知。
阈值设定与修改功能允许用户在APP端设置和调整温湿度、粉尘浓度等参数的阈值,这些设置通过WiFi模块下发至STM32端,实现远程参数配置,提升系统的灵活性和适应性。
本地运行指示功能通过LED指示灯实时显示系统运行状态和联网情况,例如正常运行时亮绿灯,报警时亮红灯,便于现场维护人员快速识别系统状况并进行处理。
十、上位机代码设计
11.1 Qt开发入门与环境搭建
【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 以其强大的跨平台能力和全面的功能集合成为许多企业和个人开发者选择用来开发高性能、高稳定性的应用程序的重要工具之一,被广泛应用于各类桌面软件、嵌入式设备、移动应用以及服务器端组件等领域。
【2】Qt版本介绍
在Qt发行版本中将要涉及两个版本:Qt商业授权和Qt开源授权。
(1)Qt商业授权是设计商业软件的开发环境,这些商业软件使用了传统的商业来发布,它包含了一些更新的功能、技术上的支持和大量的解决方案,开发了使用于行业的一些特定的组件,有一些特殊的功能只在商业用户中使用。
(2)Qt开源授权是用来开发开源的软件,它提供了一些免费的支持,并遵循QPL协议。
开放源代码是免费的软件,不牵涉用户的某些权益。任何人都有使用开源软件和参与它的修改的机会,这就意味着其他的人同样可获得你开发的代码。目前 Qt 的开源授权有两种,一种是 GPL 授权,另一种是 LGPL 授权。
【3】Qt开发环境安装
Qt的中文官网: https://www.qt.io/zh-cn/
QT5.12.6的下载地址:https://download.qt.io/archive/qt/5.12/5.12.6
打开下载链接后选择下面的版本进行下载:
qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details
软件安装时断网安装,否则会提示输入账户。
如果下载不了,可以在网盘里找到安装包下载: 飞书文档记录的网盘地址:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink
安装的时候,第一个复选框里勾选一个mingw 32编译器即可,其他的不管默认就行,直接点击下一步继续安装。
选择MinGW 32-bit 编译器:
【4】开发第一个QT程序
在QT开发过程中,可以手动编写代码也可以使用UI设计师直接拖拽控件的方式编写界面和布局,在实际的开发过程中一般是两种方式结合使用,提高开发效率。
本小节用一个简单的 "Hello QT" 程序介绍一下使用QtCreator新建工程的步骤。
(1)打开QtCreator软件,选择New Project,新建一个工程。
(2)项目模板选择QT Widgets Application
(3)设置项目名称和存放路径
注意:QT项目路径和名称不能出现中文字符。
(4)编译工具套件选择
编译工具套件可以后面自己增加,比如增加Android的。套件是指 Qt 程序从编译链接到运行环境的全部工具和 Qt 类库的集合。
(5)设置生成的类信息
在类信息设置界面选择基类,目前有三种基类:QMainWindow,QWidget,QDialog。在基类里选择QMainWindow,类名和文件名会根据基类自动修改,一般不需要修改,默认即可。
(6)项目管理
在项目管理界面可以设置作为子项目,以及加入版本控制系统。这两个功能暂时用不到,都用默认的 ,然后点击 “完成”。
(7)创建完成
(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,让程序进入消息循环。等待可能的菜单,工具条,鼠标等的输入,进行响应。
(9)行程序
运行程序可以点击左下角的三角形符号或者按下快捷键Ctrl+R。
【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();
}
运行程序,观察输出的调试信息:
【6】QT Creator常用的快捷键
掌握一些适用的快捷键,可以提高程序开发的效率。
(1)F1 键,快速切换光标选中的函数或者类的帮助信息,按一次半屏显示,按下两次全屏显示。
(2)F2 键,快速切换到光标选中的函数或者类的源码定义处。
(3)F4键,快速在源文件和头文件之间切换。
(4)Ctrl(按住)+ Tab,快速切换已打开的文件
(5)Ctrl+ I ,缩进光标选中行代码(自动与上层代码对齐)。
(6)Ctrl + / ,快速注释或者取消注释光标选中行。
(7)快速修改全局变量名
鼠标光标选中变量名,按下Ctrl+Shift+R,当变量名称出现红色框表示已经激活全局修改功能。修改一处,整个工程对应变量名称全部会修改。修改完毕之后,光标移开,再按下Ctrl+Shift+R保存修改。
(8)快速修改全局函数名
快捷方式与变量修改一样按下Ctrl+Shift+R,一处修改整个工程对应的函数名称也会跟着改。选中函数后,按下Ctrl+Shift+R后整个工程的对应的函数名会高亮,并且在软件下方弹出修改框。
【7】QT帮助文档
Qt 帮助文档太多,难以全部翻译成中文,即使翻译了一部分,翻译花的时间太多,翻译更新的时效性也难以保证,最终还是得看英文帮助,QtCreator 集成了帮助系统,查找非常方便。
打开QtCreator,选择菜单栏的最左边的帮助选项,界面如下:
(1)查看Qlabel控件的帮助信息:
【8】UI设计师使用
上节的Hello QT程序使用纯C++代码编写,这一节使用QT界面设计模式实现与上一节Hello QT程序一样的功能。仿照着上节新创建一个工程。双击打开mainwindow.ui文件,进入到UI设计界面。
(1)拖一个Label控件到编辑区,双击Label控件可以修改文本内容。
(2)运行程序可以点击左下角的三角形符号或者按下快捷键Ctrl+R。
(3)UI设计师界面功能介绍
【9】按钮控件组
QT Creator UI设计师界面的按钮组截图如下:
以下是对按钮组控件的一些功能介绍:
(1)Push Button按压按钮:最普通的按钮,按(点击)按钮命令计算机执行一些动作,或者回答问题,比如windows开始菜单里的重启,注销,关机等按钮。
(2)Tool Button工具按钮:工具按钮通常是一个集合,一般集成在工具栏里。比如打开,保存,复制,粘贴,剪切等常用的操作。
(3)Radio Button单选按钮:单选按钮通常是两个以上的形式出现在一块,按钮之间有互斥关系,每次只能选中一个。比如:一个人的性别只能选择一个,不能同时是男性又是女性。
(4)Check Box复选框:复选框与单选按钮概念相反,复选框通常表示多个可以同时存在的选项,比如一个人可以同时拥有多个爱好,比如读书、看电影、爬山、游泳等。
(5)Command Link Button命令链接按钮:一般用来打开的窗口或者网页链接。
(6)Dialog Button Box标准按钮盒:标准按钮盒通常用于对话框程序;比如:常见的确认对话框有 “确定”“取消”等标准按钮,Qt 将这些典型的按钮做成标准按钮盒,并将相应的信号加以封装,方便程序员使用。
【10】布局控件组
开发一个图形界面应用程序,界面的布局影响到界面的美观。前面的程序中都是使用UI界面拖控件,如果有多个按钮,会出现大小难调整、位置难对齐等问题。Qt 提供的“布局管理“就很好的解决了控件摆放的问题。
以下是UI设计师界面的布局相关控件组:
功能介绍:
(1)Vertical Layout:垂直布局
(2)Horizontal Layout:水平布局
(3)Grid Layout:网格布局
(4)Form Layout:窗体中布局
(5)Horizontal Spacers:水平空格,在布局中用来占位。
(6)Vertical Spacer:垂直空格,在布局中用来占位。
【11】基本布局控件
在UI设计界面添加一个布局控件,然后将需要布局的其他控件放入布局控件中即可完成布局,布局控件可以互相嵌套使用。(本节只介绍基本布局控件的使用)
以下是4种布局控件的效果:
【12】UI设计师的布局功能
在UI设计界面的左上角有一排快捷的布局选项,使用时选中两个以上的控件,点击其中一种布局方式就可以切换布局。
以下为布局的简单示例图:
(1)为布局的选项。
(2)控件层次图,可以看到控件的布局摆放层次。
如果想要控制某个控件的固定大小,不随着布局改变大小,可以限定最大最小尺寸。选中控件鼠标右键-->大小限定->设置大小。
水平布局与垂直布局:
水平布局将控件按照水平方式摆放,垂直布局将控件按照垂直方式摆放。鼠标拖动红色布局框上的黑色方点,可以调整布局框的大小。随着布局框的尺寸变化,包含的控件高度不会变化,宽度会随着布局框变化。选中其中一个控件然后鼠标右键>点击大小限定,可以限定控件的最大和最小尺寸。
分裂器水平布局与垂直布局:
分裂器方式布局,包含控件的高度和宽度都会随着布局框的拉伸而改变。选中其中一个控件然后鼠标右键>点击大小限定,可以限定控件的最大和最小尺寸。
窗体中布局与栅格布局:
栅格(网格)布局器的基本单元是单元格,而窗体中布局(表单)的基本单元是行。随着布局框的尺寸变化,包含的控件高度不会变化,宽度会随着布局框变化。
设置主窗体布局方式:
设置主窗体的布局方式后,包含在主窗体内的控件会随着窗体的拉伸自动调整大小。
11.2 上位机开发
【1】Qt开发环境安装
QT5.12.6的下载地址:https://download.qt.io/archive/qt/5.12/5.12.6
打开下载链接后选择下面的版本进行下载:
如果下载不了,可以在网盘里找到安装包下载: 飞书文档记录的网盘地址:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink
软件安装时断网安装,否则会提示输入账户。
安装的时候,第一个复选框里的编译器可以全选,直接点击下一步继续安装。
选择编译器: (一定要看清楚了)
【2】新建上位机工程
前面2讲解了需要用的API接口,接下来就使用Qt设计上位机,设计界面,完成整体上位机的逻辑设计。
【1】新建工程
【2】设置项目的名称。
【3】选择编译系统
【4】选择默认继承的类
【5】选择编译器
【6】点击完成
【7】工程创建完成
【3】切换编译器
在左下角是可以切换编译器的。 可以选择用什么样的编译器编译程序。
目前新建工程的时候选择了2种编译器。 一种是mingw32这个编译Windows下运行的程序。 一种是Android编译器,可以生成Android手机APP。
不过要注意:Android的编译器需要配置一些环境才可以正常使用,这个大家可以网上找找教程配置一下就行了。
windows的编译器就没有这么麻烦,安装好Qt就可以编译使用。
下面我这里就选择的 mingw32这个编译器,编译Windows下运行的程序。
【4】编译测试功能
创建完毕之后,编译测试一下功能是否OK。
点击左下角的绿色三角形按钮。
正常运行就可以看到弹出一个白色的框框。这就表示工程环境没有问题了。 接下来就可以放心的设计界面了。
【5】设计UI界面与工程配置
【1】打开UI文件
打开默认的界面如下:
【2】开始设计界面
根据自己需求设计界面。
【7】编译Windows上位机
点击软件左下角的绿色三角形按钮进行编译运行。
【8】配置Android环境
如果想编译Android手机APP,必须要先自己配置好自己的Android环境。(搭建环境的过程可以自行百度搜索学习)
然后才可以进行下面的步骤。
【1】选择Android编译器
选择编译器。
切换编译器。
【2】创建Android配置文件
创建完成。
11.3 上位机代码
#include <QtWidgets>
#include <QTcpSocket>
#include <QTimer>
class SafetyMonitor : public QWidget
{
Q_OBJECT
public:
SafetyMonitor(QWidget *parent = nullptr) : QWidget(parent)
{
setupUI();
setupConnections();
setupNetwork();
}
private slots:
void connectToDevice();
void disconnectFromDevice();
void sendThresholds();
void readData();
void connectionError();
void updateDisplay();
private:
void setupUI();
void setupConnections();
void setupNetwork();
void parseSensorData(const QString &data);
// UI组件
QLabel *tempLabel, *humiLabel, *dustLabel, *vibLabel;
QLCDNumber *tempLCD, *humiLCD, *dustLCD;
QLabel *vibStatus, *alarmStatus;
QDoubleSpinBox *tempThreshold, *humiThreshold, *dustThreshold;
QPushButton *connectBtn, *disconnectBtn, *setThresholdBtn;
QLineEdit *ipEdit, *portEdit;
QTextEdit *logText;
QTimer *updateTimer;
// 网络组件
QTcpSocket *tcpSocket;
// 数据存储
double currentTemp, currentHumi, currentDust;
bool currentVib, currentAlarm;
};
void SafetyMonitor::setupUI()
{
// 主布局
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// 连接设置区域
QGroupBox *connGroup = new QGroupBox("设备连接");
QHBoxLayout *connLayout = new QHBoxLayout(connGroup);
ipEdit = new QLineEdit("192.168.1.100");
portEdit = new QLineEdit("8080");
connectBtn = new QPushButton("连接");
disconnectBtn = new QPushButton("断开");
disconnectBtn->setEnabled(false);
connLayout->addWidget(new QLabel("IP:"));
connLayout->addWidget(ipEdit);
connLayout->addWidget(new QLabel("端口:"));
connLayout->addWidget(portEdit);
connLayout->addWidget(connectBtn);
connLayout->addWidget(disconnectBtn);
// 数据显示区域
QGroupBox *dataGroup = new QGroupBox("实时监测数据");
QGridLayout *dataLayout = new QGridLayout(dataGroup);
tempLabel = new QLabel("温度(°C):");
humiLabel = new QLabel("湿度(%):");
dustLabel = new QLabel("粉尘(mg/m3):");
vibLabel = new QLabel("震动状态:");
tempLCD = new QLCDNumber();
humiLCD = new QLCDNumber();
dustLCD = new QLCDNumber();
tempLCD->setSegmentStyle(QLCDNumber::Filled);
humiLCD->setSegmentStyle(QLCDNumber::Filled);
dustLCD->setSegmentStyle(QLCDNumber::Filled);
vibStatus = new QLabel("正常");
alarmStatus = new QLabel("无报警");
alarmStatus->setStyleSheet("QLabel { background-color: green; color: white; padding: 5px; }");
dataLayout->addWidget(tempLabel, 0, 0);
dataLayout->addWidget(tempLCD, 0, 1);
dataLayout->addWidget(humiLabel, 1, 0);
dataLayout->addWidget(humiLCD, 1, 1);
dataLayout->addWidget(dustLabel, 2, 0);
dataLayout->addWidget(dustLCD, 2, 1);
dataLayout->addWidget(vibLabel, 3, 0);
dataLayout->addWidget(vibStatus, 3, 1);
dataLayout->addWidget(new QLabel("报警状态:"), 4, 0);
dataLayout->addWidget(alarmStatus, 4, 1);
// 阈值设置区域
QGroupBox *thresholdGroup = new QGroupBox("报警阈值设置");
QGridLayout *thresholdLayout = new QGridLayout(thresholdGroup);
tempThreshold = new QDoubleSpinBox();
humiThreshold = new QDoubleSpinBox();
dustThreshold = new QDoubleSpinBox();
tempThreshold->setRange(0, 100);
humiThreshold->setRange(0, 100);
dustThreshold->setRange(0, 1.0);
tempThreshold->setValue(35.0);
humiThreshold->setValue(80.0);
dustThreshold->setValue(0.08);
setThresholdBtn = new QPushButton("设置阈值");
thresholdLayout->addWidget(new QLabel("温度阈值:"), 0, 0);
thresholdLayout->addWidget(tempThreshold, 0, 1);
thresholdLayout->addWidget(new QLabel("湿度阈值:"), 1, 0);
thresholdLayout->addWidget(humiThreshold, 1, 1);
thresholdLayout->addWidget(new QLabel("粉尘阈值:"), 2, 0);
thresholdLayout->addWidget(dustThreshold, 2, 1);
thresholdLayout->addWidget(setThresholdBtn, 3, 0, 1, 2);
// 日志区域
QGroupBox *logGroup = new QGroupBox("系统日志");
QVBoxLayout *logLayout = new QVBoxLayout(logGroup);
logText = new QTextEdit();
logText->setReadOnly(true);
logLayout->addWidget(logText);
// 组合所有区域
mainLayout->addWidget(connGroup);
mainLayout->addWidget(dataGroup);
mainLayout->addWidget(thresholdGroup);
mainLayout->addWidget(logGroup);
setWindowTitle("面粉厂安全生产监控系统");
resize(600, 800);
}
void SafetyMonitor::setupConnections()
{
connect(connectBtn, &QPushButton::clicked, this, &SafetyMonitor::connectToDevice);
connect(disconnectBtn, &QPushButton::clicked, this, &SafetyMonitor::disconnectFromDevice);
connect(setThresholdBtn, &QPushButton::clicked, this, &SafetyMonitor::sendThresholds);
}
void SafetyMonitor::setupNetwork()
{
tcpSocket = new QTcpSocket(this);
connect(tcpSocket, &QTcpSocket::readyRead, this, &SafetyMonitor::readData);
connect(tcpSocket, &QTcpSocket::errorOccurred, this, &SafetyMonitor::connectionError);
updateTimer = new QTimer(this);
connect(updateTimer, &QTimer::timeout, this, &SafetyMonitor::updateDisplay);
}
void SafetyMonitor::connectToDevice()
{
tcpSocket->connectToHost(ipEdit->text(), portEdit->text().toInt());
if(tcpSocket->waitForConnected(3000)) {
logText->append("连接设备成功");
connectBtn->setEnabled(false);
disconnectBtn->setEnabled(true);
setThresholdBtn->setEnabled(true);
updateTimer->start(1000);
} else {
logText->append("连接设备失败");
}
}
void SafetyMonitor::disconnectFromDevice()
{
tcpSocket->disconnectFromHost();
connectBtn->setEnabled(true);
disconnectBtn->setEnabled(false);
setThresholdBtn->setEnabled(false);
updateTimer->stop();
logText->append("断开设备连接");
}
void SafetyMonitor::sendThresholds()
{
if(tcpSocket->state() == QAbstractSocket::ConnectedState) {
QString command = QString("SET_THRESHOLD:TEMP:%1,HUMI:%2,DUST:%3")
.arg(tempThreshold->value())
.arg(humiThreshold->value())
.arg(dustThreshold->value());
tcpSocket->write(command.toUtf8());
logText->append("发送阈值设置: " + command);
}
}
void SafetyMonitor::readData()
{
QByteArray data = tcpSocket->readAll();
QString sensorData = QString::fromUtf8(data);
parseSensorData(sensorData);
logText->append("接收数据: " + sensorData);
}
void SafetyMonitor::parseSensorData(const QString &data)
{
QStringList parts = data.split(',');
for(const QString &part : parts) {
if(part.startsWith("TEMP:")) {
currentTemp = part.mid(5).toDouble();
} else if(part.startsWith("HUMI:")) {
currentHumi = part.mid(5).toDouble();
} else if(part.startsWith("DUST:")) {
currentDust = part.mid(5).toDouble();
} else if(part.startsWith("VIB:")) {
currentVib = (part.mid(4).toInt() == 1);
} else if(part.startsWith("ALARM:")) {
currentAlarm = (part.mid(6).toInt() == 1);
}
}
}
void SafetyMonitor::updateDisplay()
{
tempLCD->display(currentTemp);
humiLCD->display(currentHumi);
dustLCD->display(currentDust);
vibStatus->setText(currentVib ? "异常" : "正常");
vibStatus->setStyleSheet(currentVib ?
"QLabel { color: red; font-weight: bold; }" :
"QLabel { color: green; }");
if(currentAlarm) {
alarmStatus->setText("报警中");
alarmStatus->setStyleSheet("QLabel { background-color: red; color: white; padding: 5px; }");
QApplication::beep();
} else {
alarmStatus->setText("正常");
alarmStatus->setStyleSheet("QLabel { background-color: green; color: white; padding: 5px; }");
}
}
void SafetyMonitor::connectionError()
{
logText->append("连接错误: " + tcpSocket->errorString());
disconnectFromDevice();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
SafetyMonitor monitor;
monitor.show();
return app.exec();
}
#include "main.moc"
十一、STM32模块代码设计
当前项目使用的相关软件工具、模块源码已经上传到网盘:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink
#include "stm32f10x.h"
// 引脚定义
#define DHT11_PIN GPIO_Pin_0
#define DHT11_PORT GPIOC
#define DUST_ADC ADC1
#define DUST_PIN GPIO_Pin_1
#define DUST_PORT GPIOA
#define DUST_ADC_CH ADC_Channel_1
#define VIBRATION_PIN GPIO_Pin_1
#define VIBRATION_PORT GPIOC
#define BUZZER_PIN GPIO_Pin_2
#define BUZZER_PORT GPIOC
#define ALARM_LED_PIN GPIO_Pin_3
#define ALARM_LED_PORT GPIOC
#define STATUS_LED_PIN GPIO_Pin_4
#define STATUS_LED_PORT GPIOC
// WiFi模块串口
#define WIFI_USART USART1
#define WIFI_USART_IRQ USART1_IRQn
// 阈值定义
volatile float temp_threshold = 35.0;
volatile float humi_threshold = 80.0;
volatile float dust_threshold = 100.0;
// 传感器数据结构
typedef struct {
float temperature;
float humidity;
float dust_density;
uint8_t vibration_state;
} SensorData;
SensorData sensor_data;
// 系统状态
volatile uint8_t system_alarm = 0;
volatile uint8_t wifi_connected = 0;
// 延时函数
void delay_ms(uint32_t ms) {
volatile uint32_t i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 7200; j++);
}
void delay_us(uint32_t us) {
volatile uint32_t i;
for(i = 0; i < us * 8; i++);
}
// GPIO初始化
void GPIO_Init_Config(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN;
// DHT11 - 推挽输出/浮空输入
GPIOC->CRL &= ~(0xF << 0);
GPIOC->CRL |= (0x3 << 0);
// 粉尘传感器ADC引脚 - 模拟输入
GPIOA->CRL &= ~(0xF << 4);
GPIOA->CRL |= (0x0 << 4);
// 震动传感器 - 浮空输入
GPIOC->CRL &= ~(0xF << 4);
GPIOC->CRL |= (0x4 << 4);
// 蜂鸣器 - 推挽输出
GPIOC->CRL &= ~(0xF << 8);
GPIOC->CRL |= (0x3 << 8);
// 报警LED - 推挽输出
GPIOC->CRL &= ~(0xF << 12);
GPIOC->CRL |= (0x3 << 12);
// 状态LED - 推挽输出
GPIOC->CRL &= ~(0xF << 16);
GPIOC->CRL |= (0x3 << 16);
}
// USART1初始化 - WiFi通信
void USART1_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
// PA9-TX 推挽复用输出, PA10-RX 浮空输入
GPIOA->CRH &= ~(0xFF << 4);
GPIOA->CRH |= (0xB << 4) | (0x4 << 8);
USART1->BRR = 72000000 / 115200;
USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
USART1->CR1 |= USART_CR1_RXNEIE;
NVIC_EnableIRQ(WIFI_USART_IRQ);
NVIC_SetPriority(WIFI_USART_IRQ, 0);
}
// ADC初始化 - 粉尘传感器
void ADC1_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
ADC1->SQR1 = 0;
ADC1->SQR2 = 0;
ADC1->SQR3 = DUST_ADC_CH;
ADC1->SMPR2 = 0;
ADC1->SMPR2 |= (0x7 << (DUST_ADC_CH * 3));
ADC1->CR1 = 0;
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CONT;
// ADC校准
ADC1->CR2 |= ADC_CR2_RSTCAL;
while(ADC1->CR2 & ADC_CR2_RSTCAL);
ADC1->CR2 |= ADC_CR2_CAL;
while(ADC1->CR2 & ADC_CR2_CAL);
delay_ms(1);
ADC1->CR2 |= ADC_CR2_ADON;
}
// DHT11温湿度传感器驱动
uint8_t DHT11_Read_Data(float *temperature, float *humidity) {
uint8_t data[5] = {0};
uint8_t i, j;
// 主机发送开始信号
DHT11_PORT->BRR = DHT11_PIN; // 拉低
delay_ms(18);
DHT11_PORT->BSRR = DHT11_PIN; // 释放
delay_us(40);
// 配置为输入模式
GPIOC->CRL &= ~(0xF << 0);
GPIOC->CRL |= (0x4 << 0);
// 等待DHT11响应
if((DHT11_PORT->IDR & DHT11_PIN)) return 0;
delay_us(80);
if(!(DHT11_PORT->IDR & DHT11_PIN)) return 0;
delay_us(80);
// 读取40位数据
for(i = 0; i < 5; i++) {
for(j = 0; j < 8; j++) {
while(!(DHT11_PORT->IDR & DHT11_PIN));
delay_us(30);
if(DHT11_PORT->IDR & DHT11_PIN) {
data[i] |= (1 << (7 - j));
while(DHT11_PORT->IDR & DHT11_PIN);
}
}
}
// 校验数据
if(data[4] == (data[0] + data[1] + data[2] + data[3])) {
*humidity = data[0] + data[1] * 0.1;
*temperature = data[2] + data[3] * 0.1;
// 恢复输出模式
GPIOC->CRL &= ~(0xF << 0);
GPIOC->CRL |= (0x3 << 0);
return 1;
}
// 恢复输出模式
GPIOC->CRL &= ~(0xF << 0);
GPIOC->CRL |= (0x3 << 0);
return 0;
}
// 粉尘浓度读取
float Dust_Sensor_Read(void) {
uint32_t adc_value = 0;
float voltage, density;
ADC1->CR2 |= ADC_CR2_ADON;
delay_ms(10);
// 读取ADC值
for(uint8_t i = 0; i < 10; i++) {
ADC1->CR2 |= ADC_CR2_SWSTART;
while(!(ADC1->SR & ADC_SR_EOC));
adc_value += ADC1->DR;
delay_ms(5);
}
adc_value /= 10;
voltage = (adc_value * 3.3) / 4096.0;
// 转换为粉尘浓度 (ug/m3)
// 需要根据传感器特性曲线校准
density = (voltage - 0.6) * 200.0;
if(density < 0) density = 0;
return density;
}
// 震动传感器读取
uint8_t Vibration_Sensor_Read(void) {
return (VIBRATION_PORT->IDR & VIBRATION_PIN) ? 1 : 0;
}
// 蜂鸣器控制
void Buzzer_Control(uint8_t state) {
if(state) {
BUZZER_PORT->BSRR = BUZZER_PIN;
} else {
BUZZER_PORT->BRR = BUZZER_PIN;
}
}
// LED控制
void LED_Control(uint8_t led, uint8_t state) {
if(led == 0) { // 报警LED
if(state) {
ALARM_LED_PORT->BSRR = ALARM_LED_PIN;
} else {
ALARM_LED_PORT->BRR = ALARM_LED_PIN;
}
} else { // 状态LED
if(state) {
STATUS_LED_PORT->BSRR = STATUS_LED_PIN;
} else {
STATUS_LED_PORT->BRR = STATUS_LED_PIN;
}
}
}
// 数据打包发送
void Send_Sensor_Data(void) {
char buffer[128];
sprintf(buffer, "TEMP:%.1f,HUMI:%.1f,DUST:%.1f,VIB:%d,ALARM:%drn",
sensor_data.temperature, sensor_data.humidity,
sensor_data.dust_density, sensor_data.vibration_state,
system_alarm);
for(uint8_t i = 0; buffer[i] != ''; i++) {
USART1->DR = buffer[i];
while(!(USART1->SR & USART_SR_TXE));
}
}
// 报警检测
void Alarm_Check(void) {
uint8_t alarm = 0;
if(sensor_data.temperature > temp_threshold) alarm = 1;
if(sensor_data.humidity > humi_threshold) alarm = 1;
if(sensor_data.dust_density > dust_threshold) alarm = 1;
if(sensor_data.vibration_state) alarm = 1;
if(alarm && !system_alarm) {
system_alarm = 1;
LED_Control(0, 1); // 打开报警LED
Buzzer_Control(1); // 打开蜂鸣器
} else if(!alarm && system_alarm) {
system_alarm = 0;
LED_Control(0, 0); // 关闭报警LED
Buzzer_Control(0); // 关闭蜂鸣器
}
}
// WiFi数据接收处理
void USART1_IRQHandler(void) {
if(USART1->SR & USART_SR_RXNE) {
uint8_t data = USART1->DR;
static char cmd_buffer[32];
static uint8_t cmd_index = 0;
if(data == 'r' || data == 'n') {
cmd_buffer[cmd_index] = '';
// 解析阈值设置命令
if(strncmp(cmd_buffer, "TEMP:", 5) == 0) {
temp_threshold = atof(cmd_buffer + 5);
} else if(strncmp(cmd_buffer, "HUMI:", 5) == 0) {
humi_threshold = atof(cmd_buffer + 5);
} else if(strncmp(cmd_buffer, "DUST:", 5) == 0) {
dust_threshold = atof(cmd_buffer + 5);
} else if(strcmp(cmd_buffer, "CONNECTED") == 0) {
wifi_connected = 1;
LED_Control(1, 1);
} else if(strcmp(cmd_buffer, "DISCONNECTED") == 0) {
wifi_connected = 0;
LED_Control(1, 0);
}
cmd_index = 0;
} else if(cmd_index < 31) {
cmd_buffer[cmd_index++] = data;
}
}
}
// 系统初始化
void System_Init(void) {
// 时钟配置
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
FLASH->ACR |= FLASH_ACR_LATENCY_2;
RCC->CR |= RCC_CR_HSEON;
while(!(RCC->CR & RCC_CR_HSERDY));
RCC->CFGR |= RCC_CFGR_PLLSRC;
RCC->CFGR |= RCC_CFGR_PLLMULL9;
RCC->CR |= RCC_CR_PLLON;
while(!(RCC->CR & RCC_CR_PLLRDY));
RCC->CFGR |= RCC_CFGR_SW_PLL;
while(!(RCC->CFGR & RCC_CFGR_SWS_PLL));
SystemCoreClock = 72000000;
GPIO_Init_Config();
USART1_Init();
ADC1_Init();
// 初始化状态
LED_Control(0, 0);
LED_Control(1, 0);
Buzzer_Control(0);
}
// 主函数
int main(void) {
System_Init();
uint32_t last_send_time = 0;
uint32_t last_dht11_time = 0;
uint32_t last_vibration_time = 0;
uint8_t vibration_count = 0;
while(1) {
uint32_t current_time = SysTick->VAL;
// DHT11数据采集 (每2秒)
if(current_time - last_dht11_time > 2000) {
if(DHT11_Read_Data(&sensor_data.temperature, &sensor_data.humidity)) {
// 数据读取成功
}
last_dht11_time = current_time;
}
// 粉尘浓度采集 (持续)
sensor_data.dust_density = Dust_Sensor_Read();
// 震动检测 (防抖处理)
if(Vibration_Sensor_Read()) {
vibration_count++;
if(vibration_count > 5) {
sensor_data.vibration_state = 1;
last_vibration_time = current_time;
}
} else {
vibration_count = 0;
if(current_time - last_vibration_time > 5000) {
sensor_data.vibration_state = 0;
}
}
// 报警检测
Alarm_Check();
// 数据发送 (每1秒)
if(current_time - last_send_time > 1000) {
if(wifi_connected) {
Send_Sensor_Data();
}
last_send_time = current_time;
// 状态LED闪烁
static uint8_t led_state = 0;
LED_Control(1, led_state);
led_state = !led_state;
}
delay_ms(100);
}
}
十二、STM32项目核心代码
当前项目使用的相关软件工具、模块源码已经上传到网盘:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink
#include "stm32f10x.h"
// 传感器数据结构
typedef struct {
float temperature;
float humidity;
float dust_concentration;
uint8_t vibration_state;
} SensorData;
// 报警阈值结构
typedef struct {
float temp_threshold;
float hum_threshold;
float dust_threshold;
} ThresholdData;
// 全局变量
SensorData sensor_data = {0};
ThresholdData thresholds = {35.0, 80.0, 50.0}; // 默认阈值
uint8_t alarm_flag = 0;
uint8_t wifi_connected = 0;
// 函数声明
void System_Init(void);
void GPIO_Init(void);
void UART_Init(void);
void TIM_Init(void);
void ADC_Init(void);
void Read_Sensors(void);
void Check_Alarm(void);
void Send_Data_To_WIFI(void);
void Process_WIFI_Command(void);
void LED_Display_Status(void);
int main(void)
{
// 系统初始化
System_Init();
GPIO_Init();
UART_Init();
TIM_Init();
ADC_Init();
// 主循环
while(1)
{
// 读取传感器数据
Read_Sensors();
// 检查报警条件
Check_Alarm();
// 发送数据到WiFi模块
Send_Data_To_WIFI();
// 处理WiFi命令
Process_WIFI_Command();
// LED状态显示
LED_Display_Status();
// 延时
for(volatile int i = 0; i < 1000000; i++);
}
}
// 系统初始化
void System_Init(void)
{
// 开启时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN |
RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN |
RCC_APB2ENR_USART1EN | RCC_APB2ENR_ADC1EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
// 系统时钟配置
SystemInit();
}
// GPIO初始化
void GPIO_Init(void)
{
// PA2, PA3 - USART2 TX, RX (连接ESP8266)
GPIOA->CRL &= ~(GPIO_CRL_CNF2 | GPIO_CRL_CNF3 |
GPIO_CRL_MODE2 | GPIO_CRL_MODE3);
GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2_0 | // PA2: 复用推挽输出
GPIO_CRL_CNF3_0 | GPIO_CRL_MODE3_0; // PA3: 浮空输入
// PC13 - 系统运行指示灯
GPIOC->CRH &= ~(GPIO_CRH_CNF13 | GPIO_CRH_MODE13);
GPIOC->CRH |= GPIO_CRH_MODE13_0; // 推挽输出, 2MHz
// PC14 - 报警指示灯
GPIOC->CRH &= ~(GPIO_CRH_CNF14 | GPIO_CRH_MODE14);
GPIOC->CRH |= GPIO_CRH_MODE14_0; // 推挽输出, 2MHz
// PB8 - 蜂鸣器控制
GPIOB->CRH &= ~(GPIO_CRH_CNF8 | GPIO_CRH_MODE8);
GPIOB->CRH |= GPIO_CRH_MODE8_0; // 推挽输出, 2MHz
// PA0 - 震动传感器输入
GPIOA->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_MODE0);
GPIOA->CRL |= GPIO_CRL_CNF0_0; // 浮空输入
// PA1 - 粉尘传感器ADC输入
GPIOA->CRL &= ~(GPIO_CRL_CNF1 | GPIO_CRL_MODE1);
GPIOA->CRL |= GPIO_CRL_CNF1_1; // 模拟输入
}
// UART初始化
void UART_Init(void)
{
// USART2初始化 - 连接ESP8266
USART2->BRR = 0x1D4C; // 9600波特率 @72MHz
USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
USART2->CR1 |= USART_CR1_RXNEIE; // 使能接收中断
// 配置NVIC
NVIC_EnableIRQ(USART2_IRQn);
NVIC_SetPriority(USART2_IRQn, 0);
}
// 定时器初始化
void TIM_Init(void)
{
// TIM2用于定时读取传感器
TIM2->PSC = 7200 - 1; // 10kHz
TIM2->ARR = 10000 - 1; // 1秒
TIM2->DIER = TIM_DIER_UIE; // 使能更新中断
TIM2->CR1 = TIM_CR1_CEN; // 启动定时器
// 配置NVIC
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, 1);
}
// ADC初始化
void ADC_Init(void)
{
// ADC1初始化
ADC1->SQR1 = 0; // 1个转换
ADC1->SQR3 = 1; // 通道1 (PA1)
ADC1->SMPR2 = ADC_SMPR2_SMP1_2 | ADC_SMPR2_SMP1_1 | ADC_SMPR2_SMP1_0; // 239.5周期
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CONT; // 开启ADC, 连续转换
}
// 读取传感器数据
void Read_Sensors(void)
{
// 读取温湿度 (DHT11)
// 这里调用DHT11读取函数
// sensor_data.temperature = DHT11_Read_Temperature();
// sensor_data.humidity = DHT11_Read_Humidity();
// 读取粉尘浓度 (GP2Y1051AU0F)
ADC1->CR2 |= ADC_CR2_SWSTART;
while(!(ADC1->SR & ADC_SR_EOC));
uint16_t adc_value = ADC1->DR;
sensor_data.dust_concentration = (adc_value * 3.3 / 4096) * 100; // 转换为浓度值
// 读取震动状态 (SW-420)
sensor_data.vibration_state = (GPIOA->IDR & GPIO_IDR_IDR0) ? 1 : 0;
}
// 检查报警条件
void Check_Alarm(void)
{
alarm_flag = 0;
// 温度报警
if(sensor_data.temperature > thresholds.temp_threshold)
alarm_flag |= 0x01;
// 湿度报警
if(sensor_data.humidity > thresholds.hum_threshold)
alarm_flag |= 0x02;
// 粉尘浓度报警
if(sensor_data.dust_concentration > thresholds.dust_threshold)
alarm_flag |= 0x04;
// 震动报警
if(sensor_data.vibration_state)
alarm_flag |= 0x08;
// 控制报警设备
if(alarm_flag)
{
GPIOC->BSRR = GPIO_BSRR_BR14; // 报警灯亮
GPIOB->BSRR = GPIO_BSRR_BS8; // 蜂鸣器响
}
else
{
GPIOC->BSRR = GPIO_BSRR_BS14; // 报警灯灭
GPIOB->BSRR = GPIO_BSRR_BR8; // 蜂鸣器关
}
}
// 发送数据到WiFi模块
void Send_Data_To_WIFI(void)
{
if(wifi_connected)
{
// 构造JSON格式数据
char buffer[128];
sprintf(buffer, "{"temp":%.1f,"hum":%.1f,"dust":%.1f,"vib":%d,"alarm":%d}",
sensor_data.temperature, sensor_data.humidity,
sensor_data.dust_concentration, sensor_data.vibration_state,
alarm_flag);
// 发送数据
for(int i = 0; buffer[i] != ''; i++)
{
USART2->DR = buffer[i];
while(!(USART2->SR & USART_SR_TXE));
}
USART2->DR = 'n';
while(!(USART2->SR & USART_SR_TXE));
}
}
// 处理WiFi命令
void Process_WIFI_Command(void)
{
// 处理来自APP的阈值设置命令
// 实际实现中需要解析JSON命令
}
// LED状态显示
void LED_Display_Status(void)
{
static uint32_t blink_counter = 0;
blink_counter++;
// 系统运行指示灯闪烁
if(blink_counter % 2 == 0)
GPIOC->BSRR = GPIO_BSRR_BS13; // 亮
else
GPIOC->BSRR = GPIO_BSRR_BR13; // 灭
}
// USART2中断服务函数
void USART2_IRQHandler(void)
{
if(USART2->SR & USART_SR_RXNE)
{
uint8_t data = USART2->DR;
// 处理WiFi模块响应
if(data == 'O' || data == 'K') // 简化处理
{
wifi_connected = 1;
}
// 这里可以添加更多命令解析逻辑
}
}
// TIM2中断服务函数 - 定时读取传感器
void TIM2_IRQHandler(void)
{
if(TIM2->SR & TIM_SR_UIF)
{
TIM2->SR &= ~TIM_SR_UIF;
// 设置标志触发主循环读取传感器
// 实际实现中可以使用标志位或直接调用Read_Sensors()
}
}
十三、总结
本项目成功设计并实现了一个基于STM32的面粉厂车间安全生产系统,在通过智能化手段保障车间环境的安全运行。系统集成了温湿度、粉尘浓度和震动监测等多种传感器,能够实时采集关键参数,并在异常时自动触发声光报警,有效预防潜在风险。
系统以STM32F103RCT6为主控核心,结合DHT11、GP2Y1051AU0F和SW-420等传感器模块,实现了数据的准确采集与处理。通过ESP8266 WiFi模块,系统支持远程通信,使终端APP能够实时显示数据并接收警报,同时允许用户灵活设置阈值参数,增强了系统的适应性和智能化程度。
整体设计注重实用性与可靠性,通过本地LED指示灯和声光报警单元提供直观的状态反馈,确保了现场维护的便捷性。该系统不仅提升了面粉厂车间的安全管理水平,还为类似工业环境提供了可扩展的解决方案,具有广泛的应用前景。
2531