基于华为云的STM32智能仓储防火防盗监控系统
项目开发背景
随着现代物流行业的快速发展,仓储管理面临着日益严峻的安全挑战,尤其是防火和防盗问题。仓库内通常存放大量贵重物品,一旦发生火灾或非法入侵,不仅会造成巨大的经济损失,还可能危及人员安全。因此,实现高效、实时的监控系统至关重要,以预防和及时响应潜在风险。
传统的仓储监控系统往往依赖人工巡检或简单的传感器报警,存在响应延迟、集成度低和覆盖范围有限等问题。这些系统通常无法实现多参数综合监测,如同时处理烟雾、温度和人体信号,且缺乏云端数据备份和远程访问功能,导致管理效率低下和应急处理能力不足。
近年来,物联网技术和云平台的兴起为智能监控提供了新的解决方案。通过将嵌入式系统与云服务结合,可以实现数据的实时采集、传输和分析,提升监控的自动化和智能化水平。华为云作为可靠的云服务提供商,能够支持大规模数据存储和处理,为仓储监控系统提供稳定、高效的后端支持。
本项目基于STM32微控制器和多种传感器,旨在开发一个集防火防盗功能于一体的智能监控系统。通过集成烟雾、温度和人体红外传感器,系统能够实时监测仓库环境,并在检测到异常时触发本地报警和图像抓拍。同时,利用ESP8266 Wi-Fi模块将报警信息和图像数据上传至华为云平台,实现远程监控和数据管理。配合QT开发的上位机软件,用户可以直观查看多仓库的实时画面、历史记录和报警数据,从而提高整体安全性和管理效率。
这一系统的开发不仅满足了现代仓储对高效安全监控的需求,还体现了物联网技术在传统行业中的应用潜力,为未来智能仓储的推广和实施提供了可行参考。
设计实现的功能
(1)实时监测仓库内烟雾浓度、温度及人体红外信号。
(2)发现异常时触发本地声光报警并抓拍图像。
(3)报警信息及图像数据上传至华为云平台。
(4)QT上位机显示多仓库监控画面、报警记录及实时数据。
项目硬件模块组成
(1)STM32F103C8T6最小系统核心板(主控)。
(2)MQ-2烟雾传感器。
(3)DHT11温度传感器。
(4)HC-SR501人体红外传感器。
(5)OV2640摄像头模块(图像抓拍)。
(6)ESP8266-01S Wi-Fi模块(华为云通信)。
(7)洞洞板焊接传感器接口电路,杜邦线连接模块。
设计意义
该系统设计旨在实现仓库环境的智能监控,通过集成多种传感器和云平台技术,提升仓储管理的安全性和效率。系统能够实时监测烟雾浓度、温度和人体红外信号,及时发现火灾隐患和非法入侵行为,从而有效保护仓库内货物安全,防止因意外事件导致的财产损失。
当检测到异常情况时,系统立即触发本地声光报警并抓拍图像,这种快速响应机制有助于在紧急情况下迅速采取行动,减少潜在风险,并为事后分析提供视觉证据。报警信息和图像数据通过Wi-Fi模块上传至华为云平台,实现了远程监控和数据存储,使得管理人员能够随时随地通过网络访问系统状态,及时处理报警事件,提高了管理的灵活性和响应速度。
QT上位机软件提供多仓库监控画面、报警记录及实时数据显示功能,便于用户集中管理多个仓库点,历史数据回溯和分析有助于识别 patterns 或优化安防策略,从而提升整体仓储运营的智能化水平。该系统采用成本效益高的硬件组件,如STM32主控和常见传感器,易于部署和维护,适用于中小型仓库的 practical 应用,体现了物联网技术在传统行业中的创新集成。
设计思路
该系统以STM32F103C8T6最小系统核心板作为主控制器,负责协调整个监控系统的运行。通过洞洞板焊接传感器接口电路,使用杜邦线连接各模块,确保硬件连接稳定可靠。主控板实时采集来自MQ-2烟雾传感器、DHT11温度传感器和HC-SR501人体红外传感器的数据,实现仓库内环境参数的持续监控。
传感器数据采集通过STM32的ADC和GPIO接口完成,烟雾浓度和温度值由模拟或数字信号读取,人体红外信号则通过中断方式检测。主控程序循环扫描这些数据,并与预设阈值进行比较,以判断是否出现异常情况,如烟雾浓度超标、温度过高或检测到非法入侵。
当发现异常时,系统立即触发本地声光报警装置,例如通过蜂鸣器和LED灯进行警示,同时启动OV2640摄像头模块抓拍现场图像。图像数据被暂存到缓冲区,主控板协调处理报警信息和图像,确保数据完整性。
报警信息和抓拍的图像通过ESP8266-01S Wi-Fi模块上传至华为云平台。STM32通过串口与Wi-Fi模块通信,使用AT指令配置网络连接,并按照华为云API协议封装数据包,实现可靠的上传功能,确保云端及时接收和处理报警事件。
QT上位机软件负责显示多仓库的监控画面、报警记录及实时数据。上位机通过网络接口从华为云平台获取数据,解析并展示传感器读数、报警历史和实时图像,提供用户友好的界面用于远程监控和管理,增强系统的可视化和响应能力。
框架图
+-------------------------+
| 传感器模块 |
| - MQ-2烟雾传感器 |
| - DHT11温度传感器 |
| - HC-SR501人体红外传感器|
| - OV2640摄像头模块 |
+-------------------------+
|
v
+-------------------------+
| STM32F103C8T6 |
| 主控核心板 |
| - 数据处理 |
| - 控制逻辑 |
+-------------------------+
|\
| \-> [声光报警模块] (本地)
|
v
+-------------------------+
| ESP8266-01S |
| Wi-Fi模块 |
+-------------------------+
|
v
+-------------------------+
| 华为云平台 |
| - 数据存储 |
| - 消息推送 |
+-------------------------+
|
v
+-------------------------+
| QT上位机软件 |
| - 多仓库监控画面 |
| - 报警记录 |
| - 实时数据 |
+-------------------------+
系统总体设计
系统以STM32F103C8T6最小系统核心板作为主控制器,负责协调整个监控系统的运行。该系统通过集成多种传感器实时采集仓库环境数据,包括MQ-2烟雾传感器检测烟雾浓度、DHT11温度传感器测量环境温度、以及HC-SR501人体红外传感器感知人体活动信号。这些传感器数据由STM32主控进行周期性读取和处理,确保实时监测仓库状态。
当系统检测到异常情况,如烟雾浓度超标、温度过高或人体红外信号触发时,STM32主控会立即启动本地声光报警装置,并通过OV2640摄像头模块抓拍现场图像。报警信息和图像数据被暂存于主控内存中,为后续上传做准备。
系统利用ESP8266-01S Wi-Fi模块建立与华为云平台的连接,通过MQTT或HTTP协议将报警信息及抓拍的图像数据上传至云端。这一过程确保了数据的远程存储和可访问性,同时STM32主控会处理网络通信的稳定性,包括重连机制和数据校验。
QT上位机软件作为监控界面,从华为云平台获取多仓库的实时数据、报警记录和图像信息,并以图形化方式显示监控画面、历史报警和传感器读数。上位机还支持用户交互,如查看详细报警日志和实时数据趋势,从而实现对仓库环境的远程监控和管理。
整个系统的硬件连接通过洞洞板焊接传感器接口电路,并使用杜邦线连接各模块,确保了结构的灵活性和可维护性。STM32主控程序采用嵌入式C语言开发,实现数据采集、处理、报警触发和通信功能,而华为云平台和QT上位机则共同完成数据的云端存储和可视化展示。
系统功能总结
功能描述 | 实现方式 |
---|---|
实时监测烟雾浓度 | MQ-2烟雾传感器 |
实时监测温度 | DHT11温度传感器 |
实时监测人体红外信号 | HC-SR501人体红外传感器 |
异常时触发本地声光报警 | STM32主控控制声光报警器件 |
异常时抓拍图像 | OV2640摄像头模块 |
上传报警信息及图像数据至华为云 | ESP8266-01S Wi-Fi模块 |
QT上位机显示多仓库监控画面、报警记录及实时数据 | 通过Wi-Fi传输数据,QT软件处理 |
设计的各个功能模块描述
STM32F103C8T6最小系统核心板作为主控模块,负责协调整个系统的运行,通过ADC和GPIO接口读取传感器数据,处理逻辑判断,并在检测到异常时控制声光报警和图像抓拍,同时通过串口与Wi-Fi模块通信实现数据上传。
MQ-2烟雾传感器模块用于实时监测仓库内的烟雾浓度,其模拟输出连接到STM32的ADC引脚,STM32定期采样并转换为烟雾浓度值,当浓度超过预设阈值时触发报警。
DHT11温度传感器模块监测仓库环境温度,通过单总线协议与STM32通信,提供数字温度数据,系统实时显示并判断是否异常超温。
HC-SR501人体红外传感器模块检测人体红外信号,用于防盗监控,其数字输出连接到STM32的GPIO引脚,当检测到移动人体时输出高电平,STM32据此判断入侵事件。
OV2640摄像头模块用于图像抓拍,在系统检测到异常(如烟雾、温度或人体信号)时,STM32通过I2C接口控制摄像头启动,捕获JPEG图像并暂存,准备上传。
ESP8266-01S Wi-Fi模块作为云通信模块,通过AT指令与STM32串口交互,将报警信息(如传感器数据)和图像数据通过HTTP或MQTT协议上传至华为云平台,实现远程监控。
洞洞板焊接的传感器接口电路提供稳定的电源和信号连接,使用杜邦线灵活连接各模块到STM32,确保传感器和模块的可靠电气接口,减少噪声干扰。
本地声光报警模块由LED和蜂鸣器组成,直接由STM32的GPIO引脚控制,当系统检测到异常时,STM输出驱动信号,触发声光报警以提醒现场人员。
QT上位机软件模块运行于PC端,通过网络连接华为云平台,实时显示多仓库的监控画面、报警记录和传感器数据,提供图形化界面用于远程监控和管理。
上位机代码设计
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QLabel>
#include <QTableWidget>
#include <QListWidget>
#include <QTimer>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGroupBox>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void fetchRealTimeData();
void fetchAlarmRecords();
void fetchImages();
void onRealTimeDataReceived(QNetworkReply *reply);
void onAlarmRecordsReceived(QNetworkReply *reply);
void onImagesReceived(QNetworkReply *reply);
void updateDisplay();
private:
QNetworkAccessManager *networkManager;
QTimer *dataTimer;
QLabel *temperatureLabel;
QLabel *smokeLabel;
QLabel *pirLabel;
QTableWidget *alarmTable;
QListWidget *imageList;
QList<QLabel*> warehouseImageLabels;
QList<QString> warehouseIds; // Assume multiple warehouse IDs
void setupUI();
void parseRealTimeData(const QJsonObject &json);
void parseAlarmRecords(const QJsonArray &jsonArray);
void parseImages(const QJsonArray &jsonArray);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QHeaderView>
#include <QImage>
#include <QPixmap>
#include <QBuffer>
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), networkManager(new QNetworkAccessManager(this))
{
setupUI();
dataTimer = new QTimer(this);
connect(dataTimer, &QTimer::timeout, this, &MainWindow::fetchRealTimeData);
dataTimer->start(5000); // Update every 5 seconds
// Fetch initial data
fetchRealTimeData();
fetchAlarmRecords();
fetchImages();
// Connect network signals
connect(networkManager, &QNetworkAccessManager::finished, this, [this](QNetworkReply *reply) {
if (reply->error() == QNetworkReply::NoError) {
QString url = reply->url().toString();
if (url.contains("realtime-data")) {
onRealTimeDataReceived(reply);
} else if (url.contains("alarms")) {
onAlarmRecordsReceived(reply);
} else if (url.contains("images")) {
onImagesReceived(reply);
}
} else {
QMessageBox::warning(this, "Network Error", reply->errorString());
}
reply->deleteLater();
});
// Initialize warehouse IDs (example IDs, replace with actual)
warehouseIds << "warehouse1" << "warehouse2" << "warehouse3";
}
MainWindow::~MainWindow()
{
}
void MainWindow::setupUI()
{
QWidget *centralWidget = new QWidget(this);
QHBoxLayout *mainLayout = new QHBoxLayout(centralWidget);
// Left side: real-time data and alarm records
QVBoxLayout *leftLayout = new QVBoxLayout();
// Real-time data group
QGroupBox *realTimeGroup = new QGroupBox("Real-time Data");
QVBoxLayout *realTimeLayout = new QVBoxLayout();
temperatureLabel = new QLabel("Temperature: -- °C");
smokeLabel = new QLabel("Smoke Concentration: -- ppm");
pirLabel = new QLabel("PIR Signal: --");
realTimeLayout->addWidget(temperatureLabel);
realTimeLayout->addWidget(smokeLabel);
realTimeLayout->addWidget(pirLabel);
realTimeGroup->setLayout(realTimeLayout);
leftLayout->addWidget(realTimeGroup);
// Alarm records group
QGroupBox *alarmGroup = new QGroupBox("Alarm Records");
QVBoxLayout *alarmLayout = new QVBoxLayout();
alarmTable = new QTableWidget(0, 4);
alarmTable->setHorizontalHeaderLabels({"Time", "Warehouse", "Type", "Value"});
alarmTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
alarmLayout->addWidget(alarmTable);
alarmGroup->setLayout(alarmLayout);
leftLayout->addWidget(alarmGroup);
mainLayout->addLayout(leftLayout, 1);
// Right side: warehouse images
QGroupBox *imageGroup = new QGroupBox("Warehouse Monitoring");
QVBoxLayout *imageLayout = new QVBoxLayout();
// Create image labels for each warehouse
for (int i = 0; i < warehouseIds.size(); ++i) {
QLabel *imageLabel = new QLabel();
imageLabel->setFixedSize(320, 240);
imageLabel->setStyleSheet("border: 1px solid black;");
imageLabel->setAlignment(Qt::AlignCenter);
imageLabel->setText("No image");
warehouseImageLabels.append(imageLabel);
imageLayout->addWidget(new QLabel("Warehouse " + QString::number(i+1)));
imageLayout->addWidget(imageLabel);
}
imageGroup->setLayout(imageLayout);
mainLayout->addWidget(imageGroup, 2);
centralWidget->setLayout(mainLayout);
setCentralWidget(centralWidget);
setWindowTitle("Smart Warehouse Monitoring System");
resize(1200, 800);
}
void MainWindow::fetchRealTimeData()
{
// Example API endpoint: replace with actual Huawei Cloud URL
QUrl url("https://your-huawei-cloud-api.com/api/realtime-data");
networkManager->get(QNetworkRequest(url));
}
void MainWindow::fetchAlarmRecords()
{
QUrl url("https://your-huawei-cloud-api.com/api/alarms");
networkManager->get(QNetworkRequest(url));
}
void MainWindow::fetchImages()
{
for (const QString &warehouseId : warehouseIds) {
QUrl url("https://your-huawei-cloud-api.com/api/images/" + warehouseId);
networkManager->get(QNetworkRequest(url));
}
}
void MainWindow::onRealTimeDataReceived(QNetworkReply *reply)
{
QByteArray data = reply->readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
if (jsonDoc.isObject()) {
parseRealTimeData(jsonDoc.object());
}
}
void MainWindow::onAlarmRecordsReceived(QNetworkReply *reply)
{
QByteArray data = reply->readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
if (jsonDoc.isArray()) {
parseAlarmRecords(jsonDoc.array());
}
}
void MainWindow::onImagesReceived(QNetworkReply *reply)
{
QByteArray data = reply->readAll();
// Assume the reply contains image data or JSON with image URL
// For simplicity, assume direct image data in response
QImage image;
if (image.loadFromData(data)) {
// Extract warehouse ID from URL to determine which label to update
QString urlStr = reply->url().toString();
for (int i = 0; i < warehouseIds.size(); ++i) {
if (urlStr.contains(warehouseIds[i])) {
QPixmap pixmap = QPixmap::fromImage(image);
warehouseImageLabels[i]->setPixmap(pixmap.scaled(320, 240, Qt::KeepAspectRatio));
break;
}
}
} else {
// Try parsing as JSON if image data is not direct
QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
if (jsonDoc.isObject()) {
QJsonObject obj = jsonDoc.object();
if (obj.contains("imageUrl")) {
QString imageUrl = obj["imageUrl"].toString();
// Download image from imageUrl - for simplicity, we skip here
}
}
}
}
void MainWindow::parseRealTimeData(const QJsonObject &json)
{
if (json.contains("temperature")) {
temperatureLabel->setText("Temperature: " + QString::number(json["temperature"].toDouble()) + " °C");
}
if (json.contains("smoke")) {
smokeLabel->setText("Smoke Concentration: " + QString::number(json["smoke"].toDouble()) + " ppm");
}
if (json.contains("pir")) {
pirLabel->setText("PIR Signal: " + QString::number(json["pir"].toInt()));
}
}
void MainWindow::parseAlarmRecords(const QJsonArray &jsonArray)
{
alarmTable->setRowCount(0);
for (const QJsonValue &value : jsonArray) {
QJsonObject obj = value.toObject();
int row = alarmTable->rowCount();
alarmTable->insertRow(row);
alarmTable->setItem(row, 0, new QTableWidgetItem(obj["time"].toString()));
alarmTable->setItem(row, 1, new QTableWidgetItem(obj["warehouse"].toString()));
alarmTable->setItem(row, 2, new QTableWidgetItem(obj["type"].toString()));
alarmTable->setItem(row, 3, new QTableWidgetItem(QString::number(obj["value"].toDouble())));
}
}
void MainWindow::parseImages(const QJsonArray &jsonArray)
{
// If images are returned as JSON array, but we handle in onImagesReceived
}
项目文件说明
- • main.cpp: 应用程序入口点,创建主窗口并启动事件循环。
- • mainwindow.h: 主窗口类的声明,包括槽函数和私有成员。
- • mainwindow.cpp: 主窗口类的实现,包括UI设置、网络请求和数据解析。
使用说明
- 1. 确保已安装QT和C++编译器。
- 2. 创建一个新的QT Widgets应用程序项目。
- 3. 将上述代码复制到相应的文件中。
- 4. 替换API端点URL为实际的华为云API地址。
- 5. 根据需要调整仓库ID和UI布局。
- 6. 编译并运行项目。
此代码提供了一个基本框架,用于从华为云获取数据并显示。实际部署时,需完善错误处理、认证(如API密钥)和图像处理逻辑。
模块代码设计
#include "stm32f10x.h" // 假设有基本类型定义,但寄存器方式下,我们直接定义寄存器
// 寄存器地址定义
#define RCC_BASE 0x40021000
#define GPIOA_BASE 0x40010800
#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define ADC1_BASE 0x40012400
#define USART1_BASE 0x40013800
#define RCC_APB2ENR *(volatile unsigned long *)(RCC_BASE + 0x18)
#define GPIOA_CRL *(volatile unsigned long *)(GPIOA_BASE + 0x00)
#define GPIOA_CRH *(volatile unsigned long *)(GPIOA_BASE + 0x04)
#define GPIOA_IDR *(volatile unsigned long *)(GPIOA_BASE + 0x08)
#define GPIOA_ODR *(volatile unsigned long *)(GPIOA_BASE + 0x0C)
#define GPIOB_CRL *(volatile unsigned long *)(GPIOB_BASE + 0x00)
#define GPIOB_CRH *(volatile unsigned long *)(GPIOB_BASE + 0x04)
#define GPIOB_IDR *(volatile unsigned long *)(GPIOB_BASE + 0x08)
#define GPIOB_ODR *(volatile unsigned long *)(GPIOB_BASE + 0x0C)
#define GPIOC_CRH *(volatile unsigned long *)(GPIOC_BASE + 0x04)
#define GPIOC_ODR *(volatile unsigned long *)(GPIOC_BASE + 0x0C)
#define ADC1_SR *(volatile unsigned long *)(ADC1_BASE + 0x00)
#define ADC1_CR2 *(volatile unsigned long *)(ADC1_BASE + 0x08)
#define ADC1_SQR3 *(volatile unsigned long *)(ADC1_BASE + 0x34)
#define ADC1_DR *(volatile unsigned long *)(ADC1_BASE + 0x4C)
#define USART1_SR *(volatile unsigned long *)(USART1_BASE + 0x00)
#define USART1_DR *(volatile unsigned long *)(USART1_BASE + 0x04)
#define USART1_BRR *(volatile unsigned long *)(USART1_BASE + 0x08)
#define USART1_CR1 *(volatile unsigned long *)(USART1_BASE + 0x0C)
// 引脚定义
#define MQ2_PIN 0 // PA0 for ADC
#define DHT11_PIN 1 // PA1 for DHT11 data
#define PIR_PIN 2 // PA2 for HC-SR501 output
#define BUZZER_PIN 3 // PA3 for buzzer
#define LED_PIN 13 // PC13 for LED
#define OV2640_SIOC_PIN 6 // PB6 for I2C SCL
#define OV2640_SIOD_PIN 7 // PB7 for I2C SDA
// OV2640 data pins assumed on PB8-PB15 for simplicity, but not fully implemented
#define WIFI_TX_PIN 9 // PA9 for USART1 TX
#define WIFI_RX_PIN 10 // PA10 for USART1 RX
// 阈值定义
#define SMOKE_THRESHOLD 500 // ADC value for smoke detection
#define TEMP_THRESHOLD 50 // Temperature in Celsius
#define PIR_DETECT 1 // High means detection
// 全局变量
volatile unsigned int smoke_value = 0;
volatile int temperature = 0;
volatile int humidity = 0;
volatile unsigned char pir_status = 0;
volatile unsigned char image_buffer[320*240]; //假设图像缓冲区,实际OV2640输出JPEG
// 函数声明
void SystemInit(void);
void GPIO_Init(void);
void ADC_Init(void);
void USART_Init(void);
void Delay_us(unsigned int us);
void Delay_ms(unsigned int ms);
unsigned int DHT11_Read(void);
unsigned int ADC_Read(unsigned char channel);
void Read_Sensors(void);
void Trigger_Alarm(void);
void OV2640_Init(void);
void OV2640_Capture(void);
void ESP8266_SendCommand(char *cmd);
void ESP8266_UploadData(void);
void USART_SendChar(char ch);
void USART_SendString(char *str);
// 系统初始化
void SystemInit(void) {
// Enable clocks
RCC_APB2ENR |= (1<<2) | (1<<3) | (1<<4) | (1<<14); // Enable GPIOA, GPIOB, GPIOC, ADC1 clocks
RCC_APB2ENR |= (1<<0); // Enable AFIO clock if needed, but not used here
RCC_APB2ENR |= (1<<14); // Enable USART1 clock
}
// GPIO初始化
void GPIO_Init(void) {
// PA0: analog input for MQ2
GPIOA_CRL &= ~(0xF << (MQ2_PIN * 4));
GPIOA_CRL |= (0x0 << (MQ2_PIN * 4)); // Analog mode
// PA1: output for DHT11 (open drain)
GPIOA_CRL &= ~(0xF << (DHT11_PIN * 4));
GPIOA_CRL |= (0x4 << (DHT11_PIN * 4)); // Output open drain
// PA2: input for PIR
GPIOA_CRL &= ~(0xF << (PIR_PIN * 4));
GPIOA_CRL |= (0x8 << (PIR_PIN * 4)); // Input with pull-up/pull-down? Assume floating
// PA3: output for buzzer
GPIOA_CRL &= ~(0xF << (BUZZER_PIN * 4));
GPIOA_CRL |= (0x3 << (BUZZER_PIN * 4)); // Output push-pull
// PC13: output for LED
GPIOC_CRH &= ~(0xF << ((LED_PIN-8) * 4));
GPIOC_CRH |= (0x3 << ((LED_PIN-8) * 4)); // Output push-pull
// PB6 and PB7 for I2C (OV2640), but simplified here
GPIOB_CRL &= ~(0xF << (OV2640_SIOC_PIN * 4));
GPIOB_CRL |= (0x4 << (OV2640_SIOC_PIN * 4)); // Output open drain
GPIOB_CRL &= ~(0xF << (OV2640_SIOD_PIN * 4));
GPIOB_CRL |= (0x4 << (OV2640_SIOD_PIN * 4)); // Output open drain
// PA9 and PA10 for USART1
GPIOA_CRH &= ~(0xFF << ((WIFI_TX_PIN-8) * 4));
GPIOA_CRH |= (0x0B << ((WIFI_TX_PIN-8) * 4)); // PA9: Alternate function push-pull
GPIOA_CRH |= (0x04 << ((WIFI_RX_PIN-8) * 4)); // PA10: Input floating
}
// ADC初始化
void ADC_Init(void) {
ADC1_CR2 = 0;
ADC1_CR2 |= (1<<0); // ADON: enable ADC
Delay_ms(1);
ADC1_CR2 |= (1<<3); // RSTCAL: reset calibration
while (ADC1_CR2 & (1<<3)); // Wait for reset
ADC1_CR2 |= (1<<2); // CAL: start calibration
while (ADC1_CR2 & (1<<2)); // Wait for calibration
ADC1_SQR3 = 0; // Channel 0 as first conversion
}
// USART初始化
void USART_Init(void) {
USART1_BRR = 0x1D4C; // 9600 baud at 72MHz
USART1_CR1 |= (1<<13) | (1<<3) | (1<<2); // UE, TE, RE
}
// 微秒延时
void Delay_us(unsigned int us) {
us *= 72; // Assuming 72MHz clock, adjust as needed
while (us--) {
__asm__("nop");
}
}
// 毫秒延时
void Delay_ms(unsigned int ms) {
while (ms--) {
Delay_us(1000);
}
}
// 读取DHT11
unsigned int DHT11_Read(void) {
unsigned char data[5] = {0};
unsigned int i, j;
// Start signal
GPIOA_ODR &= ~(1<<DHT11_PIN); // Set PA1 low
Delay_ms(18);
GPIOA_ODR |= (1<<DHT11_PIN); // Set PA1 high
Delay_us(30);
// Wait for response
while (GPIOA_IDR & (1<<DHT11_PIN)); // Wait for low
while (!(GPIOA_IDR & (1<<DHT11_PIN))); // Wait for high
// Read data
for (i=0; i<5; i++) {
for (j=0; j<8; j++) {
while (!(GPIOA_IDR & (1<<DHT11_PIN))); // Wait for high
Delay_us(40);
if (GPIOA_IDR & (1<<DHT11_PIN)) {
data[i] |= (1<<(7-j));
while (GPIOA_IDR & (1<<DHT11_PIN)); // Wait for low
}
}
}
if ((data[0] + data[1] + data[2] + data[3]) == data[4]) {
humidity = data[0];
temperature = data[2];
return 1;
}
return 0;
}
// ADC读取
unsigned int ADC_Read(unsigned char channel) {
ADC1_SQR3 = channel;
ADC1_CR2 |= (1<<0); // ADON
while (!(ADC1_SR & (1<<1))); // Wait for EOC
return ADC1_DR;
}
// 读取所有传感器
void Read_Sensors(void) {
smoke_value = ADC_Read(MQ2_PIN);
DHT11_Read();
pir_status = (GPIOA_IDR & (1<<PIR_PIN)) ? 1 : 0;
}
// 触发报警
void Trigger_Alarm(void) {
GPIOA_ODR |= (1<<BUZZER_PIN); // Buzzer on
GPIOC_ODR |= (1<<LED_PIN); // LED on
Delay_ms(500);
GPIOA_ODR &= ~(1<<BUZZER_PIN); // Buzzer off
GPIOC_ODR &= ~(1<<LED_PIN); // LED off
}
// OV2640初始化(简化)
void OV2640_Init(void) {
// 通过I2C配置OV2640,但这里简化
// 实际需要发送多个寄存器配置
Delay_ms(100);
}
// OV2640抓拍(简化)
void OV2640_Capture(void) {
// 实际需要触发抓拍并读取图像数据到buffer
// 这里模拟为填充缓冲区
for (int i=0; i<320*240; i++) {
image_buffer[i] = 0x55; // 模拟数据
}
}
// USART发送字符
void USART_SendChar(char ch) {
while (!(USART1_SR & (1<<7))); // Wait for TXE
USART1_DR = ch;
}
// USART发送字符串
void USART_SendString(char *str) {
while (*str) {
USART_SendChar(*str++);
}
}
// ESP8266发送AT命令
void ESP8266_SendCommand(char *cmd) {
USART_SendString(cmd);
USART_SendChar('\r');
USART_SendChar('\n');
Delay_ms(1000);
}
// ESP8266上传数据到华为云
void ESP8266_UploadData(void) {
// 假设华为云AT命令接口
ESP8266_SendCommand("AT+CIPSTART=\"TCP\",\"cloud.huawei.com\",80");
Delay_ms(2000);
ESP8266_SendCommand("AT+CIPSEND=100");
Delay_ms(1000);
// 构建HTTP POST请求或MQTT消息,这里简化
char buffer[100];
sprintf(buffer, "Smoke:%d,Temp:%d,PIR:%d", smoke_value, temperature, pir_status);
USART_SendString(buffer);
USART_SendChar(0x1A); // Ctrl+Z to send
Delay_ms(2000);
}
// 主函数
int main(void) {
SystemInit();
GPIO_Init();
ADC_Init();
USART_Init();
OV2640_Init();
while (1) {
Read_Sensors();
if (smoke_value > SMOKE_THRESHOLD || temperature > TEMP_THRESHOLD || pir_status == PIR_DETECT) {
Trigger_Alarm();
OV2640_Capture();
ESP8266_UploadData();
}
Delay_ms(1000); // 每1秒检查一次
}
}
// 中断服务例程等省略,根据需要添加
项目核心代码
#include "stm32f10x.h"
// 引脚定义
#define MQ2_PIN 0 // PA0 for ADC
#define DHT11_PIN 1 // PA1
#define PIR_PIN 2 // PA2
#define LED_PIN 13 // PC13
#define BUZZER_PIN 14 // PC14
// 函数声明
void SystemInit_Config(void);
void GPIO_Init(void);
void ADC1_Init(void);
void USART1_Init(void);
void TIM2_Init(void); // 用于延时和DHT11时序
void Delay_ms(uint32_t ms);
void DHT11_Start(void);
uint8_t DHT11_Read_Byte(void);
uint8_t DHT11_Read_Data(float *temperature, float *humidity);
uint16_t ADC_Read(uint8_t channel);
void ESP8266_SendCmd(char *cmd);
void ESP8266_SendData(char *data);
void OV2640_Init(void);
void OV2640_Capture(void);
void Alarm_On(void);
void Alarm_Off(void);
// 全局变量
volatile uint32_t msTicks = 0;
// SysTick中断处理函数
void SysTick_Handler(void) {
msTicks++;
}
// 毫秒延时函数
void Delay_ms(uint32_t ms) {
uint32_t startTicks = msTicks;
while ((msTicks - startTicks) < ms);
}
int main(void) {
SystemInit_Config();
GPIO_Init();
ADC1_Init();
USART1_Init();
TIM2_Init();
OV2640_Init();
float temp, humidity;
uint16_t smoke_value;
uint8_t pir_status;
uint8_t dht11_status;
while (1) {
// 读取烟雾传感器(MQ-2)
smoke_value = ADC_Read(MQ2_PIN);
// 读取温度湿度(DHT11)
dht11_status = DHT11_Read_Data(&temp, &humidity);
// 读取人体红外传感器(HC-SR501)
pir_status = GPIOA->IDR & (1 << PIR_PIN); // 假设高电平有效
// 检查异常:烟雾浓度高、温度高或检测到人
if (smoke_value > 2000 || temp > 50.0 || pir_status) {
Alarm_On(); // 触发声光报警
OV2640_Capture(); // 抓拍图像
// 上传报警信息和图像到华为云(通过ESP8266)
char alertMsg[100];
sprintf(alertMsg, "Alert: Smoke=%u, Temp=%.1f, PIR=%u", smoke_value, temp, pir_status);
ESP8266_SendData(alertMsg);
// 假设图像上传函数已处理
Delay_ms(5000); // 报警持续5秒
Alarm_Off();
}
Delay_ms(1000); // 每秒检测一次
}
}
void SystemInit_Config(void) {
// 设置系统时钟为72MHz(使用外部8MHz晶振)
RCC->CR |= 0x00010000; // HSEON
while (!(RCC->CR & 0x00020000)); // 等待HSE就绪
RCC->CFGR = 0x001D0400; // PLL乘法9倍,APB1分频2,APB2不分频
RCC->CR |= 0x01000000; // PLLON
while (!(RCC->CR & 0x02000000)); // 等待PLL就绪
RCC->CFGR |= 0x00000002; // 切换至PLL
while ((RCC->CFGR & 0x00000008) != 0x00000008); // 等待切换完成
// 配置SysTick用于延时
SysTick_Config(SystemCoreClock / 1000); // 每毫秒中断一次
}
void GPIO_Init(void) {
// 使能GPIOA、GPIOC时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN;
// 配置PA0为模拟输入(ADC)
GPIOA->CRL &= ~(0x0F << (0 * 4));
GPIOA->CRL |= (0x00 << (0 * 4));
// 配置PA1为推挽输出(DHT11)
GPIOA->CRL &= ~(0x0F << (1 * 4));
GPIOA->CRL |= (0x03 << (1 * 4));
// 配置PA2为输入下拉(HC-SR501)
GPIOA->CRL &= ~(0x0F << (2 * 4));
GPIOA->CRL |= (0x08 << (2 * 4)); // 输入下拉
// 配置PC13和PC14为推挽输出(LED和蜂鸣器)
GPIOC->CRH &= ~(0x0F << ((13-8) * 4) | (0x0F << ((14-8) * 4));
GPIOC->CRH |= (0x03 << ((13-8) * 4)) | (0x03 << ((14-8) * 4));
}
void ADC1_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
ADC1->CR2 = 0x00000000; // 先关闭ADC
ADC1->CR1 = 0x00000000;
ADC1->CR2 |= 0x00000001; // 开启ADC并启动校准
while (ADC1->CR2 & 0x00000001); // 等待校准完成
ADC1->CR2 |= 0x00000001; // 再次开启ADC
ADC1->SQR3 = 0x00000000; // 通道0
ADC1->SQR1 = 0x00000000; // 1 conversion
ADC1->CR2 |= 0x00000001; // ADON
}
uint16_t ADC_Read(uint8_t channel) {
ADC1->SQR3 = channel;
ADC1->CR2 |= 0x00000001; // 开始转换
while (!(ADC1->SR & 0x00000002)); // 等待转换完成
return ADC1->DR;
}
void USART1_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
// 配置PA9为推挽复用输出(TX),PA10为浮空输入(RX)
GPIOA->CRH &= ~(0x0F << ((9-8) * 4) | (0x0F << ((10-8) * 4));
GPIOA->CRH |= (0x0B << ((9-8) * 4)) | (0x04 << ((10-8) * 4));
USART1->BRR = 0x00000506; // 72MHz / 9600 baud
USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; // 使能USART,发送和接收
}
void ESP8266_SendCmd(char *cmd) {
while (*cmd) {
while (!(USART1->SR & USART_SR_TXE));
USART1->DR = *cmd++;
}
}
void ESP8266_SendData(char *data) {
// 简化发送,实际需处理华为云协议
ESP8266_SendCmd("AT+CIPSEND=0,100\r\n");
Delay_ms(100);
ESP8266_SendCmd(data);
ESP8266_SendCmd("\r\n");
}
void TIM2_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->PSC = 7200 - 1; // 10kHz频率
TIM2->ARR = 10000 - 1; // 1秒中断
TIM2->DIER |= TIM_DIER_UIE;
NVIC_EnableIRQ(TIM2_IRQn);
TIM2->CR1 |= TIM_CR1_CEN;
}
void DHT11_Start(void) {
GPIOA->BSRR = (1 << DHT11_PIN) << 16; // 设置PA1低
Delay_ms(18);
GPIOA->BSRR = (1 << DHT11_PIN); // 设置PA1高
__nop(); __nop(); // 短暂延时
}
uint8_t DHT11_Read_Byte(void) {
uint8_t data = 0;
for (int i = 0; i < 8; i++) {
while (!(GPIOA->IDR & (1 << DHT11_PIN))); // 等待高电平
Delay_ms(0.05); // 50us延时
if (GPIOA->IDR & (1 << DHT11_PIN)) {
data |= (1 << (7 - i));
while (GPIOA->IDR & (1 << DHT11_PIN)); // 等待低电平
}
}
return data;
}
uint8_t DHT11_Read_Data(float *temperature, float *humidity) {
uint8_t data[5];
DHT11_Start();
if (!(GPIOA->IDR & (1 << DHT11_PIN))) {
while (!(GPIOA->IDR & (1 << DHT11_PIN))); // 等待响应
while (GPIOA->IDR & (1 << DHT11_PIN)); // 等待响应结束
for (int i = 0; i < 5; i++) {
data[i] = DHT11_Read_Byte();
}
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;
return 1;
}
}
return 0;
}
void Alarm_On(void) {
GPIOC->BSRR = (1 << LED_PIN); // LED on
GPIOC->BSRR = (1 << BUZZER_PIN); // Buzzer on
}
void Alarm_Off(void) {
GPIOC->BSRR = (1 << LED_PIN) << 16; // LED off
GPIOC->BSRR = (1 << BUZZER_PIN) << 16; // Buzzer off
}
// 假设其他模块函数已实现
void OV2640_Init(void) {
// 初始化OV2640摄像头
}
void OV2640_Capture(void) {
// 抓拍图像并存储
}
总结
本系统基于STM32F103C8T6核心板设计,实现了对仓库环境的智能监控,包括实时监测烟雾浓度、温度和人体红外信号,确保及时发现火灾和入侵风险。通过集成多种传感器和模块,系统在异常情况下自动触发本地声光报警并抓拍图像,提升了仓库的安全性和响应速度。
硬件组成涵盖了MQ-2烟雾传感器、DHT11温度传感器、HC-SR501人体红外传感器、OV2640摄像头模块以及ESP8266-01S Wi-Fi模块,这些组件通过洞洞板焊接和杜邦线连接,构成了一个稳定可靠的监控网络。主控单元协调各传感器数据,并通过Wi-Fi模块将报警信息和图像数据高效上传至华为云平台。
此外,系统通过QT上位机实现了多仓库监控画面的集中显示、报警记录查询和实时数据可视化,为用户提供了友好的交互界面和远程管理能力。整体设计体现了物联网技术在仓储安全中的实际应用,具有较高的实用性和扩展性。
- 点赞
- 收藏
- 关注作者
评论(0)