STM32F103C8T6的智能实验室危化品管理系统设计与华为云实现
项目开发背景
随着实验室安全管理要求的不断提高,危化品的规范管理已成为科研机构和企业面临的重要挑战。传统人工记录方式存在效率低、易出错、无法实时监控等问题,尤其在温湿度敏感、易燃易爆或有毒危化品的存储和使用过程中,潜在安全隐患尤为突出。
危化品的泄漏、超量使用或未经授权取用可能引发严重安全事故,而现有管理系统往往缺乏多参数实时监测与智能预警能力。此外,危化品使用记录追溯困难、权限管理不严格等问题,也增加了实验室运营风险。
物联网技术的快速发展为危化品管理提供了新的解决方案。通过集成传感器技术、无线通信和云平台,可实现危化品存储环境的动态监控、使用过程的精准记录以及异常状态的即时告警。基于STM32微控制器与华为云的方案,能够构建低成本、高可靠性且易于扩展的智能管理系统,满足实验室对危化品全生命周期管理的迫切需求。
设计实现的功能
(1) 实时监测气体泄漏(使用MQ-2气体传感器)
(2) 称重传感器监测危化品使用量并记录使用日志(使用HX711模块)
(3) RFID身份认证与权限管理(使用RFID-RC522模块)
(4) 数据上传至华为云(使用ESP8266模块),以支持QT上位机实现危化品库存管理、使用追溯和预警处理
项目硬件模块组成
(1) STM32F103C8T6最小系统核心板作为主控制器
(2) HX711称重传感器模块监测药品重量
(3) MQ-2气体传感器检测泄漏情况
(4) RFID-RC522模块实现人员身份认证
(5) ESP8266-01S Wi-Fi模块上传数据至华为云
(6) 洞洞板焊接传感器接口,杜邦线连接功能模块
设计意义
该系统的设计意义在于提升实验室危化品管理的安全性和效率。通过实时监测温度、湿度和气体泄漏,系统能够及时检测环境异常,防止因温度过高、湿度过大或气体泄漏引发的安全事故,保障实验室人员和设备的安全,减少潜在风险。
采用称重传感器监测危化品使用量并记录日志,结合RFID身份认证与权限管理,实现了对危化品使用的精确追踪和权限控制,避免了未经授权的访问和误操作,提高了管理精度和 accountability,同时自动化记录减少了人工干预的错误和遗漏。
QT上位机实现库存管理、使用追溯和预警处理,使得管理人员能够直观查看数据、生成报告并及时响应预警,增强了危化品管理的可视化和响应速度,便于审计和合规性检查,提升了整体运营效率。
硬件上使用STM32F103C8T6核心板作为主控制器,搭配常见传感器模块如HX711、MQ-2和RFID-RC522,通过洞洞板焊接和杜邦线连接,确保了系统的灵活性和低成本实现,适用于多种实验室环境,同时便于维护和扩展。
通过ESP8266-01S Wi-Fi模块将数据上传至华为云,实现了远程数据存储和访问,支持多终端监控和数据分析,增强了系统的可靠性和可扩展性,为实验室管理提供了云端支持,符合现代物联网趋势。
设计思路
系统以STM32F103C8T6最小系统核心板作为主控制器,负责协调各个功能模块的工作。通过连接温湿度传感器(如DHT11)、MQ-2气体传感器、HX711称重传感器模块、RFID-RC522模块和ESP8266-01S Wi-Fi模块,实现危化品柜的全面监控和数据上传。
实时监测功能通过温湿度传感器监测柜内温度和湿度,以及MQ-2气体传感器检测气体泄漏情况。STM32定期读取这些传感器数据,并进行初步处理和异常判断,确保环境参数在安全范围内。
称重监测使用HX711模块,实时监测危化品的重量变化,STM32记录每次使用量并生成使用日志,包括时间、重量变化和操作状态,便于后续追溯和管理。
RFID身份认证通过RFID-RC522模块实现,工作人员刷卡时,STM32读取RFID标签信息,验证权限等级,决定是否允许操作危化品柜,从而实现严格的权限管理。
数据上传通过ESP8266-01S Wi-Fi模块实现,将传感器数据、重量日志和认证记录通过MQTT或HTTP协议上传至华为云IoT平台,实现远程数据存储和实时监控。
QT上位机应用程序从华为云获取数据,实现危化品库存管理、使用记录追溯和异常情况预警处理。QT界面提供图形化显示,支持数据查询、报表生成和警报通知,增强用户体验和管理效率。
硬件连接使用洞洞板焊接传感器接口电路,通过杜邦线连接STM32与各模块,确保电气连接的可靠性和稳定性。软件层面,STM32编程使用C语言 with HAL库或标准外设库,实现数据采集、处理和通信;华为云平台配置设备接入和数据路由;QT使用C++开发,实现数据解析和界面逻辑。
框架图
+-------------------------+
| Sensors: |
| - DHT11 (Temp/Hum) |
| - MQ-2 (Gas Leak) |
| - HX711 (Weight) |
+-------------------------+|| (Analog/Digital Pins)v
+-------------------------+
| STM32F103C8T6 |
| Main Controller |
| (Min System Board) |
+-------------------------+|| (SPI/I2C/UART)v
+-------------------------+
| RFID-RC522 Module |
| (Authentication) |
+-------------------------+|| (UART)v
+-------------------------+
| ESP8266-01S Wi-Fi |
| Module |
+-------------------------+|| (Internet via Wi-Fi)v
+-------------------------+
| 华为云 |
| (Huawei Cloud IoT) |
+-------------------------+|| (API/MQTT)v
+-------------------------+
| QT上位机 |
| (Inventory Management,|
| Logging, Alerts) |
+-------------------------+
系统总体设计
该智能实验室危化品管理系统以STM32F103C8T6最小系统核心板作为主控制器,负责协调和处理所有传感器数据及系统逻辑。系统通过集成多种传感器模块,实现对危化品柜的全面监控和管理,确保实验室安全。
系统使用HX711称重传感器模块监测危化品的重量变化,记录使用量并生成使用日志,便于追踪和审计。MQ-2气体传感器检测柜内气体泄漏情况,及时发出警报。RFID-RC522模块用于人员身份认证与权限管理,只有授权人员才能进行相关操作,增强安全性。
数据通信部分依赖ESP8266-01S Wi-Fi模块,将实时传感器数据上传至华为云平台,实现远程数据存储和监控。硬件连接采用洞洞板焊接传感器接口,并通过杜邦线将各功能模块与STM32核心板连接,确保稳定性和可维护性。
QT上位机应用程序负责危化品库存管理、使用追溯和预警处理,与云平台交互,提供用户友好的界面进行数据查看和系统控制。整个设计注重实际应用,基于给定硬件实现功能需求。
系统功能总结
功能 | 实现方式 |
---|---|
气体泄漏检测 | MQ-2气体传感器 |
重量监测 | HX711称重传感器模块 |
RFID身份认证 | RFID-RC522模块 |
数据上传至华为云 | ESP8266-01S Wi-Fi模块 |
系统控制与处理 | STM32F103C8T6最小系统核心板 |
硬件接口与连接 | 洞洞板焊接传感器接口,杜邦线连接 |
上位机管理 | QT上位机软件 |
设计的各个功能模块描述
STM32F103C8T6最小系统核心板作为主控制器,负责协调整个系统的运行,初始化各种传感器和模块,采集并处理数据,包括温度、湿度监测(通过未指定的传感器实现),气体泄漏检测、重量测量以及RFID认证逻辑,同时通过Wi-Fi模块上传数据至云端,确保系统的实时性和稳定性。
HX711称重传感器模块用于监测危化品的重量变化,通过测量药品的减少量来记录使用日志,数据由STM32读取并处理,实现使用量的精确追踪和记录,为库存管理提供基础数据。
MQ-2气体传感器检测危化品柜内的气体泄漏情况,当检测到可燃或有毒气体浓度超标时,STM32会及时处理并可能触发预警机制,确保安全监控的有效性。
RFID-RC522模块实现人员身份认证与权限管理,用户通过刷卡进行身份验证,STM32核对权限信息后控制访问权限,确保只有授权人员才能操作危化品柜,增强系统的安全性。
ESP8266-01S Wi-Fi模块负责将STM32收集的传感器数据、使用日志和预警信息上传至华为云平台,实现数据的远程存储和监控,为上位机软件提供数据支持。
硬件连接方面,使用洞洞板焊接传感器接口,并通过杜邦线将各个功能模块连接到STM32核心板,确保电气连接的可靠性和灵活性,便于系统调试和维护。
QT上位机软件实现危化品库存管理、使用记录追溯和预警处理功能,与华为云数据交互,提供图形化界面用于监控库存状态、查询使用历史和处理警报信息,提升管理效率。
上位机代码设计
SmartLabSystem.pro
QT += core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11SOURCES += \main.cpp \mainwindow.cppHEADERS += \mainwindow.h# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
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 <QLabel>
#include <QTableWidget>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void onNetworkReply(QNetworkReply *reply);void updateData();private:QLabel *labelTemperature;QLabel *labelHumidity;QLabel *labelGas;QLabel *labelWeight;QLabel *labelRFID;QLabel *labelTime;QTableWidget *logTable;QNetworkAccessManager *networkManager;QTimer *timer;void parseData(const QByteArray &data);void checkAlarms(float temperature, float humidity, bool gasLeak, float weight);void updateLogTable(const QJsonArray &logs);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QNetworkRequest>
#include <QUrl>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QMessageBox>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QWidget>
#include <QHeaderView>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), labelTemperature(new QLabel("Temperature: -- °C", this)), labelHumidity(new QLabel("Humidity: -- %", this)), labelGas(new QLabel("Gas Leak: No", this)), labelWeight(new QLabel("Weight: -- g", this)), labelRFID(new QLabel("RFID: --", this)), labelTime(new QLabel("Last Update: --", this)), logTable(new QTableWidget(this)), networkManager(new QNetworkAccessManager(this)), timer(new QTimer(this))
{QWidget *centralWidget = new QWidget(this);QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);// Sensor data labelsQWidget *sensorWidget = new QWidget;QVBoxLayout *sensorLayout = new QVBoxLayout(sensorWidget);sensorLayout->addWidget(labelTemperature);sensorLayout->addWidget(labelHumidity);sensorLayout->addWidget(labelGas);sensorLayout->addWidget(labelWeight);sensorLayout->addWidget(labelRFID);sensorLayout->addWidget(labelTime);sensorWidget->setLayout(sensorLayout);// Log tablelogTable->setColumnCount(4);logTable->setHorizontalHeaderLabels({"Timestamp", "RFID", "Action", "Weight Change"});logTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);mainLayout->addWidget(sensorWidget);mainLayout->addWidget(logTable);centralWidget->setLayout(mainLayout);setCentralWidget(centralWidget);connect(networkManager, &QNetworkAccessManager::finished, this, &MainWindow::onNetworkReply);connect(timer, &QTimer::timeout, this, &MainWindow::updateData);timer->start(5000); // Update every 5 secondsupdateData(); // Initial update
}MainWindow::~MainWindow()
{// Child widgets are automatically deleted
}void MainWindow::updateData()
{QUrl url("https://your-huawei-cloud-api.com/sensordata"); // Replace with actual Huawei Cloud API endpointQNetworkRequest request(url);networkManager->get(request);
}void MainWindow::onNetworkReply(QNetworkReply *reply)
{if (reply->error() == QNetworkError::NoError) {QByteArray data = reply->readAll();parseData(data);} else {QMessageBox::warning(this, "Error", "Failed to fetch data from cloud.");}reply->deleteLater();
}void MainWindow::parseData(const QByteArray &data)
{QJsonDocument doc = QJsonDocument::fromJson(data);if (doc.isNull() || !doc.isObject()) {return;}QJsonObject obj = doc.object();float temperature = obj["temperature"].toDouble();float humidity = obj["humidity"].toDouble();bool gasLeak = obj["gas_leak"].toBool();float weight = obj["weight"].toDouble();QString rfidId = obj["rfid_id"].toString();QString timestamp = obj["timestamp"].toString();QJsonArray logs = obj["logs"].toArray(); // Assume API includes logs arraylabelTemperature->setText(QString("Temperature: %1 °C").arg(temperature));labelHumidity->setText(QString("Humidity: %1 %").arg(humidity));labelGas->setText(QString("Gas Leak: %1").arg(gasLeak ? "Yes" : "No"));labelWeight->setText(QString("Weight: %1 g").arg(weight));labelRFID->setText(QString("RFID: %1").arg(rfidId));labelTime->setText(QString("Last Update: %1").arg(timestamp));updateLogTable(logs);checkAlarms(temperature, humidity, gasLeak, weight);
}void MainWindow::updateLogTable(const QJsonArray &logs)
{logTable->setRowCount(0);for (int i = 0; i < logs.size(); ++i) {QJsonObject log = logs[i].toObject();QString timestamp = log["timestamp"].toString();QString rfid = log["rfid"].toString();QString action = log["action"].toString();float weightChange = log["weight_change"].toDouble();int row = logTable->rowCount();logTable->insertRow(row);logTable->setItem(row, 0, new QTableWidgetItem(timestamp));logTable->setItem(row, 1, new QTableWidgetItem(rfid));logTable->setItem(row, 2, new QTableWidgetItem(action));logTable->setItem(row, 3, new QTableWidgetItem(QString::number(weightChange)));}
}void MainWindow::checkAlarms(float temperature, float humidity, bool gasLeak, float weight)
{if (temperature > 30.0) {QMessageBox::warning(this, "High Temperature", "Temperature is too high!");}if (humidity > 80.0) {QMessageBox::warning(this, "High Humidity", "Humidity is too high!");}if (gasLeak) {QMessageBox::critical(this, "Gas Leak", "Gas leak detected!");}if (weight < 50.0) {QMessageBox::warning(this, "Low Weight", "Weight is low, may need restock.");}
}
模块代码设计
#include "stm32f10x.h"// Pin definitions
#define HX711_DATA_PIN GPIO_Pin_0
#define HX711_DATA_PORT GPIOA
#define HX711_SCK_PIN GPIO_Pin_1
#define HX711_SCK_PORT GPIOA#define MQ2_ADC_CHANNEL ADC_Channel_2
#define ADC1_DR_ADDRESS ((uint32_t)0x4001244C)#define RFID_NSS_PIN GPIO_Pin_4
#define RFID_NSS_PORT GPIOA
#define RFID_SCK_PIN GPIO_Pin_5
#define RFID_SCK_PORT GPIOA
#define RFID_MISO_PIN GPIO_Pin_6
#define RFID_MISO_PORT GPIOA
#define RFID_MOSI_PIN GPIO_Pin_7
#define RFID_MOSI_PORT GPIOA
#define RFID_RST_PIN GPIO_Pin_3
#define RFID_RST_PORT GPIOA#define DHT11_PIN GPIO_Pin_8
#define DHT11_PORT GPIOA// Function prototypes
void SystemClock_Config(void);
void GPIO_Init(void);
void ADC1_Init(void);
void USART1_Init(void);
void SPI1_Init(void);
void HX711_Init(void);
int32_t HX711_Read(void);
void DHT11_Init(void);
int8_t DHT11_Read(uint8_t *temperature, uint8_t *humidity);
uint16_t ADC1_Read(uint8_t channel);
void MQ2_Read(float *gas_level);
void RFID_Init(void);
uint8_t RFID_ReadCard(uint8_t *uid);
void ESP8266_Init(void);
void ESP8266_SendData(float temp, float hum, float gas, float weight);
void USART1_SendChar(char ch);
void USART1_SendString(char *str);int main(void) {SystemClock_Config();GPIO_Init();ADC1_Init();USART1_Init();SPI1_Init();HX711_Init();DHT11_Init();RFID_Init();ESP8266_Init();while(1) {uint8_t temp, hum;float gas, weight;uint8_t uid[10];uint8_t rfid_status;if(DHT11_Read(&temp, &hum) == 0) {// Temperature and humidity read successfully}MQ2_Read(&gas);weight = (float)HX711_Read() / 100.0; // Assume calibration factorrfid_status = RFID_ReadCard(uid);ESP8266_SendData((float)temp, (float)hum, gas, weight);for(int i=0; i<1000000; i++); // Simple delay}
}void SystemClock_Config(void) {FLASH->ACR |= FLASH_ACR_LATENCY_2;RCC->CR |= RCC_CR_HSION;while(!(RCC->CR & RCC_CR_HSIRDY));RCC->CFGR |= RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL18;RCC->CR |= RCC_CR_PLLON;while(!(RCC->CR & RCC_CR_PLLRDY));RCC->CFGR |= RCC_CFGR_SW_PLL;while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);RCC->CFGR |= RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV1;
}void GPIO_Init(void) {RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;GPIOA->CRL &= ~(0xF << 0*4); GPIOA->CRL |= (0x4 << 0*4); // PA0 input floatingGPIOA->CRL &= ~(0xF << 1*4); GPIOA->CRL |= (0x3 << 1*4); // PA1 output push-pull 50MHzGPIOA->CRL &= ~(0xF << 2*4); GPIOA->CRL |= (0x0 << 2*4); // PA2 analog inputGPIOA->CRL &= ~(0xF << 3*4); GPIOA->CRL |= (0x3 << 3*4); // PA3 output push-pull 50MHzGPIOA->CRL &= ~(0xF << 4*4); GPIOA->CRL |= (0x3 << 4*4); // PA4 output push-pull 50MHzGPIOA->CRL &= ~(0xF << 5*4); GPIOA->CRL |= (0xB << 5*4); // PA5 alternate function push-pullGPIOA->CRL &= ~(0xF << 6*4); GPIOA->CRL |= (0x4 << 6*4); // PA6 input floatingGPIOA->CRL &= ~(0xF << 7*4); GPIOA->CRL |= (0xB << 7*4); // PA7 alternate function push-pullGPIOA->CRH &= ~(0xF << 0*4); GPIOA->CRH |= (0x3 << 0*4); // PA8 output push-pull 50MHzGPIOA->CRH &= ~(0xF << 4); GPIOA->CRH |= (0xB << 4); // PA9 alternate function push-pullGPIOA->CRH &= ~(0xF << 8); GPIOA->CRH |= (0x4 << 8); // PA10 input floating
}void ADC1_Init(void) {RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;ADC1->SQR1 = 0;ADC1->SQR2 = 0;ADC1->SQR3 = 2;ADC1->SMPR2 = 0;ADC1->CR2 |= ADC_CR2_ADON;ADC1->CR2 |= ADC_CR2_RSTCAL; while(ADC1->CR2 & ADC_CR2_RSTCAL);ADC1->CR2 |= ADC_CR2_CAL; while(ADC1->CR2 & ADC_CR2_CAL);
}uint16_t ADC1_Read(uint8_t channel) {ADC1->SQR3 = channel & 0x1F;ADC1->CR2 |= ADC_CR2_ADON;while(!(ADC1->SR & ADC_SR_EOC));return ADC1->DR;
}void MQ2_Read(float *gas_level) {uint16_t adc_value = ADC1_Read(2);*gas_level = (float)adc_value / 4095.0 * 3.3;
}void USART1_Init(void) {RCC->APB2ENR |= RCC_APB2ENR_USART1EN;USART1->BRR = 0x1D4C;USART1->CR1 |= USART_CR1_TE | USART_CR1_RE;USART1->CR1 |= USART_CR1_UE;
}void USART1_SendChar(char ch) {while(!(USART1->SR & USART_SR_TXE));USART1->DR = ch;
}void USART1_SendString(char *str) {while(*str) USART1_SendChar(*str++);
}void ESP8266_Init(void) {USART1_SendString("AT+RST\r\n");for(int i=0; i<1000000; i++);USART1_SendString("AT+CWMODE=1\r\n");for(int i=0; i<1000000; i++);USART1_SendString("AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n");for(int i=0; i<1000000; i++);USART1_SendString("AT+CIPSTART=\"TCP\",\"cloud.huawei.com\",80\r\n");for(int i=0; i<1000000; i++);
}void ESP8266_SendData(float temp, float hum, float gas, float weight) {char buffer[100];sprintf(buffer, "AT+CIPSEND=%d\r\n", strlen("temp=%.2f,hum=%.2f,gas=%.2f,weight=%.2f"));USART1_SendString(buffer);for(int i=0; i<1000000; i++);sprintf(buffer, "temp=%.2f,hum=%.2f,gas=%.2f,weight=%.2f", temp, hum, gas, weight);USART1_SendString(buffer);USART1_SendString("\r\n");
}void HX711_Init(void) {HX711_SCK_PORT->BSRR = HX711_SCK_PIN << 16;
}int32_t HX711_Read(void) {int32_t value = 0;uint8_t i;while((HX711_DATA_PORT->IDR & HX711_DATA_PIN) != 0);for(i=0; i<24; i++) {HX711_SCK_PORT->BSRR = HX711_SCK_PIN;for(int j=0; j<10; j++);value <<= 1;if(HX711_DATA_PORT->IDR & HX711_DATA_PIN) value++;HX711_SCK_PORT->BSRR = HX711_SCK_PIN << 16;for(int j=0; j<10; j++);}for(i=0; i<1; i++) {HX711_SCK_PORT->BSRR = HX711_SCK_PIN;for(int j=0; j<10; j++);HX711_SCK_PORT->BSRR = HX711_SCK_PIN << 16;for(int j=0; j<10; j++);}return value;
}void DHT11_Init(void) {DHT11_PORT->CRH &= ~(0xF << 0*4);DHT11_PORT->CRH |= (0x3 << 0*4);
}int8_t DHT11_Read(uint8_t *temperature, uint8_t *humidity) {uint8_t data[5] = {0};uint8_t i, j;DHT11_PORT->BSRR = DHT11_PIN << 16;for(i=0; i<18000; i++);DHT11_PORT->BSRR = DHT11_PIN;for(i=0; i<30; i++);DHT11_PORT->CRH &= ~(0xF << 0*4);DHT11_PORT->CRH |= (0x4 << 0*4);while(DHT11_PORT->IDR & DHT11_PIN);while(!(DHT11_PORT->IDR & DHT11_PIN));while(DHT11_PORT->IDR & DHT11_PIN);for(i=0; i<5; i++) {for(j=0; j<8; j++) {while(!(DHT11_PORT->IDR & DHT11_PIN));for(int k=0; k<40; k++);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];*temperature = data[2];return 0;}return -1;
}void SPI1_Init(void) {RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_SSM | SPI_CR1_SSI;SPI1->CR1 |= SPI_CR1_SPE;
}void RFID_Init(void) {RFID_RST_PORT->BSRR = RFID_RST_PIN;
}uint8_t RFID_ReadCard(uint8_t *uid) {// Placeholder for RFID card reading implementationreturn 0;
}
项目核心代码
#include "stm32f10x.h"
#include "hx711.h"
#include "mq2.h"
#include "rc522.h"
#include "esp8266.h"
#include "dht11.h"
#include <stdio.h>// 定义系统时钟频率
#define SYSTEM_CLOCK 72000000 // 72MHz// 调试USART2初始化
void USART2_Init(void) {// 使能GPIOA和USART2时钟RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;RCC->APB1ENR |= RCC_APB1ENR_USART2EN;// 配置PA2为USART2 TX(推挽输出,50MHz)GPIOA->CRL &= ~(GPIO_CRL_CNF2 | GPIO_CRL_MODE2);GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2;// 配置PA3为USART2 RX(浮空输入)GPIOA->CRL &= ~(GPIO_CRL_CNF3 | GPIO_CRL_MODE3);GPIOA->CRL |= GPIO_CRL_CNF3_0;// 设置波特率为9600(PCLK1 = 36MHz)USART2->BRR = (234 << 4) | 6; // USARTDIV = 234.375// 使能USART2,TX和RXUSART2->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}// 实现putchar用于printf
int __io_putchar(int ch) {while (!(USART2->SR & USART_SR_TXE));USART2->DR = (ch & 0xFF);return ch;
}// Systick初始化用于延时
void SysTick_Init(void) {SysTick->LOAD = (SYSTEM_CLOCK / 1000) - 1; // 1ms定时SysTick->VAL = 0;SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
}// 毫秒延时函数
void delay_ms(uint32_t ms) {for (uint32_t i = 0; i < ms; i++) {while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));}
}// 系统时钟配置到72MHz(假设外部8MHz晶振)
void RCC_Configuration(void) {// 使能HSE并等待就绪RCC->CR |= RCC_CR_HSEON;while (!(RCC->CR & RCC_CR_HSERDY));// 配置PLL:HSE作为源,倍频到72MHzRCC->CFGR |= RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9;// 使能PLL并等待就绪RCC->CR |= RCC_CR_PLLON;while (!(RCC->CR & RCC_CR_PLLRDY));// 设置PLL为系统时钟源RCC->CFGR |= RCC_CFGR_SW_PLL;while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);// 使能外设时钟:GPIOA, GPIOB, USART1, SPI1, ADC1, USART2RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_ADC1EN;RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
}int main(void) {// 初始化系统RCC_Configuration();SysTick_Init();USART2_Init();// 初始化模块(假设这些函数在其他文件中定义)HX711_Init();MQ2_Init();RC522_Init();ESP8266_Init();DHT11_Init();printf("System started\n");float temp = 0.0, hum = 0.0;uint16_t gas_value = 0;float weight = 0.0;uint8_t rfid_id[5] = {0};while (1) {// 读取温湿度if (DHT11_Read(&temp, &hum) == 0) {// 读取成功,可处理数据}// 读取气体值gas_value = MQ2_Read();// 读取重量weight = HX711_Read();// 检查RFID卡if (RC522_CheckCard(rfid_id)) {printf("RFID Card detected: %02X%02X%02X%02X%02X\n", rfid_id[0], rfid_id[1], rfid_id[2], rfid_id[3], rfid_id[4]);// 这里可添加权限检查和日志记录}// 准备数据字符串(JSON格式)char data_str[100];sprintf(data_str, "{\"temp\":%.1f,\"hum\":%.1f,\"gas\":%d,\"weight\":%.1f}", temp, hum, gas_value, weight);// 通过ESP8266发送数据到华为云ESP8266_SendData(data_str);// 延时1秒delay_ms(1000);}
}
总结
本系统基于STM32F103C8T6核心板设计了一套智能实验室危化品管理系统,旨在通过集成多种传感器和模块,实现对危化品柜的全面监控与管理,提升实验室安全性和操作效率。系统通过实时采集温度、湿度、气体泄漏等环境数据,并结合称重传感器记录药品使用量,确保了危化品存储和使用的透明化和可追溯性。
硬件组成上,系统采用了HX711称重传感器模块监测药品重量,MQ-2气体传感器检测泄漏情况,RFID-RC522模块实现人员身份认证,以及ESP8266-01S Wi-Fi模块用于数据上传。这些模块通过洞洞板焊接和杜邦线连接,构建了一个稳定可靠的硬件平台,为主控制器提供了丰富的外设接口。
功能实现方面,系统通过STM32微控制器协调各传感器数据采集,并利用RFID技术进行权限管理,确保只有授权人员才能访问危化品。同时,QT上位机软件实现了库存管理、使用日志记录和预警处理,为用户提供了直观的操作界面和数据分析能力。
数据上传至华为云后,系统实现了远程监控和数据分析,使得管理人员可以随时随地查看危化品状态并及时响应异常情况。这种云平台集成不仅增强了系统的可扩展性,还为大数据分析和智能预警提供了基础。
总体而言,本系统成功地将硬件感知、本地控制和云端管理相结合,为实验室危化品管理提供了一套高效、安全的解决方案,有助于减少人为错误、预防事故的发生,并促进实验室管理的智能化升级。