基于STM32设计的智能实验室离心机监控系统
项目开发背景
在工业和实验室环境中,离心机作为一种关键设备,广泛应用于生物医学、化学分析和材料分离等领域,其运行稳定性与安全性直接关系到实验结果的准确性和设备的使用寿命。离心机在高速旋转过程中,转速、温度和振动等参数的变化可能引发设备故障或样品损坏,传统的人工监测方式难以实现实时响应和精确控制,存在一定的安全隐患。
随着物联网和嵌入式技术的发展,智能监控系统已成为提升设备自动化水平的重要手段。本项目旨在设计一套基于STM32微控制器的离心机智能监控系统,通过集成多种传感器和无线通信模块,实现对运行参数的实时采集、分析和远程传输。该系统能够及时检测异常情况并触发自动保护机制,有效预防事故的发生,同时为实验数据管理和状态分析提供可靠支持。
通过结合华为云平台和QT上位机界面,本项目不仅实现了数据的可视化展示和预警功能,还推动了离心机监控的数字化与智能化转型,为工业自动化和实验室管理提供了高效、安全的解决方案。
设计实现的功能
(1) 实时监测离心机转速、温度和振动参数
(2) 超限报警和自动安全保护控制
(3) 实验数据记录和运行状态分析
(4) QT上位机显示运行参数曲线和安全预警信息
项目硬件模块组成
(1)STM32F103C8T6最小系统核心板作为主控制器
(2)霍尔传感器检测离心机转速
(3)DS18B20温度传感器监测运行温度
(4)SW-420振动传感器检测异常振动
(5)ESP8266-01S Wi-Fi模块上传数据至华为云
(6)洞洞板焊接信号调理电路,杜邦线连接传感器
设计意义
该设计通过实时监测离心机的转速、温度和振动参数,有效提升了设备运行的安全性和可靠性,能够及时识别异常状态,防止因参数超限导致的设备损坏或实验失败,从而保障实验过程的稳定进行。
采用STM32F103C8T6作为主控制器,结合霍尔传感器、DS18B20温度传感器和SW-420振动传感器,实现了高效的数据采集与处理,确保了监测系统的精确性和响应速度,同时通过信号调理电路和杜邦线连接,简化了硬件部署,降低了系统复杂度。
通过ESP8266-01S Wi-Fi模块将数据上传至华为云,实现了实验数据的远程记录和存储,便于后续对运行状态进行历史分析和趋势评估,为设备维护和优化提供数据支持,增强了系统的可扩展性和实用性。
QT上位机显示运行参数曲线和安全预警信息,为用户提供了直观的图形界面,方便实时监控和快速响应异常情况,进一步强化了人机交互体验,确保了操作人员能够高效管理离心机运行状态。
设计思路
本设计以STM32F103C8T6最小系统核心板作为主控制器,负责协调整个系统的数据采集、处理和通信。系统通过霍尔传感器实时检测离心机转速,利用DS18B20数字温度传感器监测运行温度,并采用SW-420振动传感器捕捉异常振动信号。这些传感器通过洞洞板焊接的信号调理电路进行信号适配,再使用杜邦线连接到STM32的相应引脚,确保数据采集的稳定性和准确性。
在数据处理方面,STM32控制器对采集的转速、温度和振动参数进行实时分析,通过预设阈值判断是否超限。一旦检测到参数异常,系统会立即触发声光报警并执行自动安全保护控制,例如停止离心机运行或降低转速,以防止设备损坏或安全事故。同时,控制器将运行状态和报警信息记录在内部存储器中,便于后续实验数据分析和故障诊断。
数据通信通过ESP8266-01S Wi-Fi模块实现,将实时监测数据和安全预警信息上传至华为云平台。华为云作为数据中转站,存储历史记录并支持远程访问,为运行状态分析提供数据基础。上传的数据包括传感器读数、时间戳和报警状态,确保信息的完整性和可追溯性。
QT上位机软件作为用户界面,从华为云获取数据并动态显示运行参数曲线,如转速、温度和振动随时间的变化趋势。同时,上位机会实时展示安全预警信息,包括报警类型和发生时间,帮助操作人员快速响应异常情况。整个系统设计注重实用性和可靠性,确保离心机运行过程的监控和保护高效进行。
框架图
系统框架图:
+---------------------+ +-----------------------+ +-----------------------+
| | | | | |
| 传感器模块 |------>| 信号调理电路 |------>| STM32F103C8T6 |
| | | (洞洞板) | | 主控制器 |
| - 霍尔传感器 (转速) | | | | - 数据采集与处理 |
| - DS18B20 (温度) | | | | - 超限报警逻辑 |
| - SW-420 (振动) | | | | - 安全保护控制 |
+---------------------+ +-----------------------+ +-----------------------+
|
+-----------------------+
| 离心机执行器 |
| (安全保护控制输出) |
+-----------------------+
|
| (数据通信)
v
+-----------------------+
| ESP8266-01S |
| Wi-Fi模块 |
+-----------------------+
|
| (上传数据至云)
v
+-----------------------+
| 华为云 |
| - 数据存储 |
| - 运行状态分析 |
+-----------------------+
|
| (数据接口)
v
+-----------------------+
| QT上位机 |
| - 参数曲线显示 |
| - 安全预警信息 |
+-----------------------+
系统总体设计
系统总体设计基于STM32F103C8T6最小系统核心板作为主控制器,负责协调整个监测与控制流程。该系统通过集成多种传感器实时采集离心机的运行参数,包括使用霍尔传感器检测转速、DS18B20温度传感器监测温度以及SW-420振动传感器检测异常振动,所有传感器信号通过洞洞板焊接的信号调理电路进行初步处理,并使用杜邦线连接至主控制器,确保数据采集的稳定性和准确性。
在主控制器端,STM32F103C8T6实时处理传感器数据,执行超限判断逻辑,当转速、温度或振动参数超过预设阈值时,系统会触发声光报警并启动自动安全保护措施,例如停止离心机运行以防止设备损坏。同时,控制器将实验数据记录到内部存储器中,支持后续运行状态分析,包括参数趋势计算和异常事件统计。
数据通过ESP8266-01S Wi-Fi模块上传至华为云平台,实现远程监控和数据存储。上传的数据包括实时参数和报警信息,确保用户能够随时访问历史记录和当前状态。此外,系统通过QT开发的上位机软件显示运行参数曲线,如转速、温度和振动随时间变化的图表,并提供安全预警信息界面,方便用户直观查看和分析离心机运行状况。
整个系统设计注重实用性和可靠性,硬件连接简洁,软件功能聚焦于实时监测与保护,无需额外功能扩展即可满足离心机安全运行的需求。
系统功能总结
| 功能类别 | 具体功能描述 | 硬件支持 |
|---|---|---|
| 实时监测 | 监测离心机转速、温度、振动参数 | STM32F103C8T6, 霍尔传感器, DS18B20, SW-420, 洞洞板信号调理电路, 杜邦线 |
| 超限报警 | 当参数超过设定阈值时,发出报警并执行自动安全保护控制 | STM32F103C8T6 |
| 数据记录与分析 | 记录实验数据,通过Wi-Fi上传至华为云,进行运行状态分析 | STM32F103C8T6, ESP8266-01S |
| 图形显示与预警 | QT上位机实时显示运行参数曲线和安全预警信息 | ESP8266-01S (数据传输), QT软件 |
设计的各个功能模块描述
主控制器模块基于STM32F103C8T6最小系统核心板,负责实时采集和处理来自各种传感器的数据,包括转速、温度和振动参数。它执行超限报警逻辑和自动安全保护控制,当监测参数超过预设阈值时,会触发声光报警或自动停止离心机运行,确保设备安全。同时,该模块记录实验数据并分析运行状态,为后续优化提供支持。
转速监测模块使用霍尔传感器检测离心机的旋转运动,通过计数脉冲信号来计算实时转速。传感器输出信号经过调理后送入主控制器,实现高精度的转速测量,并在超限时及时报警。
温度监测模块采用DS18B20数字温度传感器,直接输出数字温度值,简化了与主控制器的接口设计。该传感器实时监测离心机运行温度,确保在安全范围内运行,避免过热风险。
振动监测模块依靠SW-420振动传感器检测离心机的异常振动情况。当振动幅度超过设定阈值时,传感器输出信号变化,主控制器据此判断并触发安全保护措施,防止设备损坏。
通信模块通过ESP8266-01S Wi-Fi模块将采集的转速、温度和振动数据上传至华为云平台,实现远程数据存储和监控。该模块支持无线传输,便于实时数据共享和后续分析。
信号调理电路在洞洞板上焊接,用于处理传感器输出的原始信号,例如对霍尔传感器的脉冲进行滤波和整形,确保主控制器能准确读取数据。杜邦线连接各传感器,简化了硬件布局和维护。
上位机显示模块基于QT开发,从华为云或直接接收数据,实时显示转速、温度和振动的参数曲线,并在检测到安全预警时弹出警报信息。该界面提供直观的运行状态分析和历史数据查询功能,辅助用户进行决策。
上位机代码设计
// main.cpp
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QTextEdit>
#include <QChartView>
#include <QLineSeries>
#include <QValueAxis>
#include <QDateTimeAxis>
#include <QTimer>
#include <QDateTime>
#include <QMessageBox>
#include <QMqttClient>
#include <QJsonDocument>
#include <QJsonObject>
QT_CHARTS_USE_NAMESPACE
class CentrifugeMonitor : public QMainWindow
{
Q_OBJECT
public:
CentrifugeMonitor(QWidget *parent = nullptr) : QMainWindow(parent)
{
setupUI();
setupMQTT();
setupCharts();
setupTimer();
}
private slots:
void connectToBroker()
{
m_client->setHostname(hostEdit->text());
m_client->setPort(portEdit->text().toInt());
m_client->connectToHost();
}
void onConnected()
{
statusLabel->setText("已连接到华为云");
m_client->subscribe("centrifuge/data", 0);
}
void onMessageReceived(const QByteArray &message)
{
QJsonDocument doc = QJsonDocument::fromJson(message);
QJsonObject obj = doc.object();
double rpm = obj["rpm"].toDouble();
double temp = obj["temp"].toDouble();
double vibration = obj["vibration"].toDouble();
updateCharts(rpm, temp, vibration);
checkAlarms(rpm, temp, vibration);
logData(rpm, temp, vibration);
}
void updateRealTimeData()
{
QDateTime currentTime = QDateTime::currentDateTime();
// 模拟数据更新
static double rpm = 0;
static double temp = 25;
static double vibration = 0.1;
rpm += (qrand() % 100 - 50);
temp += (qrand() % 10 - 5) * 0.1;
vibration += (qrand() % 10 - 5) * 0.01;
// 限制数值范围
rpm = qMax(0.0, qMin(5000.0, rpm));
temp = qMax(0.0, qMin(100.0, temp));
vibration = qMax(0.0, qMin(5.0, vibration));
rpmValue->setText(QString::number(rpm, 'f', 0) + " RPM");
tempValue->setText(QString::number(temp, 'f', 1) + " °C");
vibrationValue->setText(QString::number(vibration, 'f', 3) + " g");
}
private:
void setupUI()
{
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
// 连接设置区域
QHBoxLayout *connLayout = new QHBoxLayout();
hostEdit = new QLineEdit("iot-mqtts.cn-north-4.myhuaweicloud.com");
portEdit = new QLineEdit("1883");
QPushButton *connectBtn = new QPushButton("连接");
statusLabel = new QLabel("未连接");
connLayout->addWidget(new QLabel("服务器:"));
connLayout->addWidget(hostEdit);
connLayout->addWidget(new QLabel("端口:"));
connLayout->addWidget(portEdit);
connLayout->addWidget(connectBtn);
connLayout->addWidget(statusLabel);
// 实时数据显示区域
QHBoxLayout *dataLayout = new QHBoxLayout();
rpmValue = new QLabel("0 RPM");
tempValue = new QLabel("25.0 °C");
vibrationValue = new QLabel("0.100 g");
dataLayout->addWidget(new QLabel("转速:"));
dataLayout->addWidget(rpmValue);
dataLayout->addWidget(new QLabel("温度:"));
dataLayout->addWidget(tempValue);
dataLayout->addWidget(new QLabel("振动:"));
dataLayout->addWidget(vibrationValue);
// 图表区域
QHBoxLayout *chartLayout = new QHBoxLayout();
rpmChartView = new QChartView();
tempChartView = new QChartView();
vibrationChartView = new QChartView();
chartLayout->addWidget(rpmChartView);
chartLayout->addWidget(tempChartView);
chartLayout->addWidget(vibrationChartView);
// 预警信息区域
QVBoxLayout *alarmLayout = new QVBoxLayout();
alarmText = new QTextEdit();
alarmText->setMaximumHeight(150);
alarmLayout->addWidget(new QLabel("安全预警信息:"));
alarmLayout->addWidget(alarmText);
mainLayout->addLayout(connLayout);
mainLayout->addLayout(dataLayout);
mainLayout->addLayout(chartLayout);
mainLayout->addLayout(alarmLayout);
connect(connectBtn, &QPushButton::clicked, this, &CentrifugeMonitor::connectToBroker);
setWindowTitle("离心机监控系统");
resize(1200, 800);
}
void setupMQTT()
{
m_client = new QMqttClient(this);
connect(m_client, &QMqttClient::connected, this, &CentrifugeMonitor::onConnected);
connect(m_client, &QMqttClient::messageReceived, this, &CentrifugeMonitor::onMessageReceived);
}
void setupCharts()
{
// 转速图表
rpmSeries = new QLineSeries();
QChart *rpmChart = new QChart();
rpmChart->addSeries(rpmSeries);
rpmChart->createDefaultAxes();
rpmChart->setTitle("转速监测");
rpmChart->axisX()->setTitleText("时间");
rpmChart->axisY()->setTitleText("转速 (RPM)");
rpmChartView->setChart(rpmChart);
// 温度图表
tempSeries = new QLineSeries();
QChart *tempChart = new QChart();
tempChart->addSeries(tempSeries);
tempChart->createDefaultAxes();
tempChart->setTitle("温度监测");
tempChart->axisX()->setTitleText("时间");
tempChart->axisY()->setTitleText("温度 (°C)");
tempChartView->setChart(tempChart);
// 振动图表
vibrationSeries = new QLineSeries();
QChart *vibrationChart = new QChart();
vibrationChart->addSeries(vibrationSeries);
vibrationChart->createDefaultAxes();
vibrationChart->setTitle("振动监测");
vibrationChart->axisX()->setTitleText("时间");
vibrationChart->axisY()->setTitleText("振动 (g)");
vibrationChartView->setChart(vibrationChart);
}
void setupTimer()
{
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &CentrifugeMonitor::updateRealTimeData);
timer->start(1000); // 1秒更新一次
}
void updateCharts(double rpm, double temp, double vibration)
{
QDateTime currentTime = QDateTime::currentDateTime();
// 更新转速图表
rpmSeries->append(currentTime.toMSecsSinceEpoch(), rpm);
if(rpmSeries->count() > 100) {
rpmSeries->remove(0);
}
// 更新温度图表
tempSeries->append(currentTime.toMSecsSinceEpoch(), temp);
if(tempSeries->count() > 100) {
tempSeries->remove(0);
}
// 更新振动图表
vibrationSeries->append(currentTime.toMSecsSinceEpoch(), vibration);
if(vibrationSeries->count() > 100) {
vibrationSeries->remove(0);
}
// 更新图表显示范围
updateChartAxes();
}
void updateChartAxes()
{
// 更新X轴时间范围
QDateTime currentTime = QDateTime::currentDateTime();
QDateTime minTime = currentTime.addSecs(-100);
QValueAxis *axisX = qobject_cast<QValueAxis*>(rpmChartView->chart()->axisX());
if(axisX) {
axisX->setRange(minTime.toMSecsSinceEpoch(), currentTime.toMSecsSinceEpoch());
}
}
void checkAlarms(double rpm, double temp, double vibration)
{
QString alarmMessage;
QDateTime currentTime = QDateTime::currentDateTime();
if(rpm > 4500) {
alarmMessage = currentTime.toString("hh:mm:ss") + " - 警告: 转速超限! 当前值: " + QString::number(rpm) + " RPM\n";
}
if(temp > 80) {
alarmMessage += currentTime.toString("hh:mm:ss") + " - 警告: 温度超限! 当前值: " + QString::number(temp) + " °C\n";
}
if(vibration > 2.0) {
alarmMessage += currentTime.toString("hh:mm:ss") + " - 警告: 振动超限! 当前值: " + QString::number(vibration) + " g\n";
}
if(!alarmMessage.isEmpty()) {
alarmText->append(alarmMessage);
QMessageBox::warning(this, "安全预警", alarmMessage);
}
}
void logData(double rpm, double temp, double vibration)
{
QDateTime currentTime = QDateTime::currentDateTime();
QString logEntry = currentTime.toString("yyyy-MM-dd hh:mm:ss") +
" - 转速: " + QString::number(rpm) + " RPM, " +
"温度: " + QString::number(temp) + " °C, " +
"振动: " + QString::number(vibration) + " g";
// 这里可以添加数据保存到文件的逻辑
qDebug() << logEntry;
}
private:
QMqttClient *m_client;
// UI组件
QLineEdit *hostEdit;
QLineEdit *portEdit;
QLabel *statusLabel;
QLabel *rpmValue;
QLabel *tempValue;
QLabel *vibrationValue;
QTextEdit *alarmText;
// 图表组件
QChartView *rpmChartView;
QChartView *tempChartView;
QChartView *vibrationChartView;
QLineSeries *rpmSeries;
QLineSeries *tempSeries;
QLineSeries *vibrationSeries;
};
// pro文件内容
/*
QT += core gui charts mqtt network
CONFIG += c++11
SOURCES += \
main.cpp
HEADERS +=
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
*/
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
CentrifugeMonitor monitor;
monitor.show();
return app.exec();
}
#include "main.moc"
// CentrifugeData.h (数据模型类)
#ifndef CENTRIFUGEDATA_H
#define CENTRIFUGEDATA_H
#include <QObject>
#include <QDateTime>
class CentrifugeData : public QObject
{
Q_OBJECT
public:
explicit CentrifugeData(QObject *parent = nullptr);
double rpm() const { return m_rpm; }
double temperature() const { return m_temperature; }
double vibration() const { return m_vibration; }
QDateTime timestamp() const { return m_timestamp; }
void setData(double rpm, double temp, double vibration);
signals:
void dataChanged();
private:
double m_rpm;
double m_temperature;
double m_vibration;
QDateTime m_timestamp;
};
#endif // CENTRIFUGEDATA_H
// CentrifugeData.cpp
#include "CentrifugeData.h"
CentrifugeData::CentrifugeData(QObject *parent)
: QObject(parent)
, m_rpm(0)
, m_temperature(25.0)
, m_vibration(0.1)
{
}
void CentrifugeData::setData(double rpm, double temp, double vibration)
{
m_rpm = rpm;
m_temperature = temp;
m_vibration = vibration;
m_timestamp = QDateTime::currentDateTime();
emit dataChanged();
}
// DataLogger.h (数据记录器)
#ifndef DATALOGGER_H
#define DATALOGGER_H
#include <QObject>
#include <QFile>
#include <QTextStream>
#include "CentrifugeData.h"
class DataLogger : public QObject
{
Q_OBJECT
public:
explicit DataLogger(QObject *parent = nullptr);
~DataLogger();
void startLogging();
void stopLogging();
public slots:
void logData(const CentrifugeData &data);
private:
QFile m_logFile;
QTextStream m_stream;
bool m_isLogging;
};
#endif // DATALOGGER_H
// DataLogger.cpp
#include "DataLogger.h"
#include <QDateTime>
#include <QDir>
DataLogger::DataLogger(QObject *parent)
: QObject(parent)
, m_isLogging(false)
{
}
DataLogger::~DataLogger()
{
stopLogging();
}
void DataLogger::startLogging()
{
QString fileName = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss") + "_centrifuge_log.csv";
m_logFile.setFileName(fileName);
if(m_logFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
m_stream.setDevice(&m_logFile);
m_stream << "时间,转速(RPM),温度(°C),振动(g)\n";
m_isLogging = true;
}
}
void DataLogger::stopLogging()
{
if(m_isLogging) {
m_logFile.close();
m_isLogging = false;
}
}
void DataLogger::logData(const CentrifugeData &data)
{
if(m_isLogging) {
m_stream << data.timestamp().toString("yyyy-MM-dd hh:mm:ss") << ","
<< data.rpm() << ","
<< data.temperature() << ","
<< data.vibration() << "\n";
m_stream.flush();
}
}
这个完整的Qt上位机程序包含以下功能:
- 实时数据显示:显示转速、温度、振动参数的实时数值
- 曲线图表:使用Qt Charts绘制三个参数的实时变化曲线
- MQTT通信:连接华为云IoT平台接收数据
- 安全预警:当参数超限时显示警告信息
- 数据记录:可选的数据记录功能
主要特性:
- 使用QMqttClient进行MQTT通信
- 使用QChartView显示实时曲线
- 支持数据超限报警
- 模块化设计,易于扩展
- 支持数据日志记录到CSV文件
使用时需要配置正确的华为云MQTT服务器地址和端口,并根据实际需求调整报警阈值。
模块代码设计
#include "stm32f10x.h"
// 引脚定义
#define HALL_SENSOR_PIN GPIO_Pin_0 // PA0 霍尔传感器
#define TEMP_SENSOR_PIN GPIO_Pin_1 // PA1 DS18B20
#define VIBRATION_PIN GPIO_Pin_2 // PA2 振动传感器
#define ESP8266_TX_PIN GPIO_Pin_9 // PA9 USART1_TX
#define ESP8266_RX_PIN GPIO_Pin_10 // PA10 USART1_RX
// 变量定义
volatile uint32_t hall_pulse_count = 0;
volatile uint32_t rpm = 0;
volatile int16_t temperature = 0;
volatile uint8_t vibration_state = 0;
volatile uint32_t system_time = 0;
// DS18B20延时函数
void DS18B20_Delay_us(uint16_t time)
{
TIM2->CNT = 0;
while(TIM2->CNT < time);
}
// DS18B20初始化
uint8_t DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = TEMP_SENSOR_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 复位脉冲
GPIOA->BSRR = TEMP_SENSOR_PIN << 16; // 拉低
DS18B20_Delay_us(480);
GPIOA->BSRR = TEMP_SENSOR_PIN; // 释放总线
DS18B20_Delay_us(60);
// 检测存在脉冲
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
if(GPIOA->IDR & TEMP_SENSOR_PIN) return 0; // 无设备
DS18B20_Delay_us(480);
if(!(GPIOA->IDR & TEMP_SENSOR_PIN)) return 0; // 存在脉冲未结束
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
return 1;
}
// DS18B20写一位
void DS18B20_WriteBit(uint8_t bit)
{
GPIOA->BSRR = TEMP_SENSOR_PIN << 16; // 拉低
if(bit) {
DS18B20_Delay_us(1);
GPIOA->BSRR = TEMP_SENSOR_PIN; // 释放总线
DS18B20_Delay_us(60);
} else {
DS18B20_Delay_us(60);
GPIOA->BSRR = TEMP_SENSOR_PIN; // 释放总线
DS18B20_Delay_us(1);
}
}
// DS18B20写一个字节
void DS18B20_WriteByte(uint8_t data)
{
uint8_t i;
for(i = 0; i < 8; i++) {
DS18B20_WriteBit(data & 0x01);
data >>= 1;
}
}
// DS18B20读一位
uint8_t DS18B20_ReadBit(void)
{
uint8_t bit = 0;
GPIOA->BSRR = TEMP_SENSOR_PIN << 16; // 拉低
DS18B20_Delay_us(1);
GPIOA->BSRR = TEMP_SENSOR_PIN; // 释放总线
DS18B20_Delay_us(14);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = TEMP_SENSOR_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
if(GPIOA->IDR & TEMP_SENSOR_PIN) bit = 1;
DS18B20_Delay_us(45);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
return bit;
}
// DS18B20读一个字节
uint8_t DS18B20_ReadByte(void)
{
uint8_t i, data = 0;
for(i = 0; i < 8; i++) {
data >>= 1;
if(DS18B20_ReadBit()) data |= 0x80;
}
return data;
}
// 读取温度
int16_t DS18B20_ReadTemp(void)
{
uint8_t temp_l, temp_h;
int16_t temp;
if(!DS18B20_Init()) return 0;
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0x44); // 开始转换
DS18B20_Delay_us(100000); // 等待转换完成
if(!DS18B20_Init()) return 0;
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0xBE); // 读暂存器
temp_l = DS18B20_ReadByte();
temp_h = DS18B20_ReadByte();
temp = (temp_h << 8) | temp_l;
return temp;
}
// 霍尔传感器中断服务函数
void EXTI0_IRQHandler(void)
{
if(EXTI->IMR & EXTI_Line0) {
if(EXTI->PR & EXTI_Line0) {
hall_pulse_count++;
EXTI->PR = EXTI_Line0; // 清除中断标志
}
}
}
// 振动传感器读取
uint8_t Vibration_Read(void)
{
return (GPIOA->IDR & VIBRATION_PIN) ? 1 : 0;
}
// USART1初始化 - ESP8266通信
void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
// TX引脚配置
GPIO_InitStructure.GPIO_Pin = ESP8266_TX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// RX引脚配置
GPIO_InitStructure.GPIO_Pin = ESP8266_RX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART配置
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
// USART1发送字符
void USART1_SendChar(uint8_t ch)
{
USART1->DR = ch;
while(!(USART1->SR & USART_SR_TC));
}
// USART1发送字符串
void USART1_SendString(char *str)
{
while(*str) {
USART1_SendChar(*str++);
}
}
// 定时器2初始化 - 用于DS18B20延时和RPM计算
void TIM2_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 1MHz计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_Cmd(TIM2, ENABLE);
}
// 定时器3初始化 - 系统定时和RPM计算
void TIM3_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 9999; // 10ms中断
TIM_TimeBaseStructure.TIM_Prescaler = 719;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3, ENABLE);
}
// 外部中断初始化 - 霍尔传感器
void EXTI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
// 霍尔传感器引脚配置
GPIO_InitStructure.GPIO_Pin = HALL_SENSOR_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 振动传感器引脚配置
GPIO_InitStructure.GPIO_Pin = VIBRATION_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 外部中断配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
// 计算RPM
void Calculate_RPM(void)
{
static uint32_t last_pulse_count = 0;
uint32_t pulses;
pulses = hall_pulse_count - last_pulse_count;
rpm = (pulses * 60) / 2; // 假设每转2个脉冲
last_pulse_count = hall_pulse_count;
}
// 数据上传到云平台
void Upload_Data_To_Cloud(void)
{
char buffer[100];
sprintf(buffer, "AT+CIPSEND=0,50\r\n");
USART1_SendString(buffer);
Delay_ms(100);
sprintf(buffer, "{\"rpm\":%lu,\"temp\":%d,\"vib\":%d}\r\n",
rpm, temperature, vibration_state);
USART1_SendString(buffer);
}
// 安全保护控制
void Safety_Protection(void)
{
// 转速超限保护
if(rpm > 5000) { // 假设最大转速5000RPM
// 执行停机操作
// 发送报警信息
USART1_SendString("AT+CIPSEND=0,30\r\n");
Delay_ms(100);
USART1_SendString("{\"alarm\":\"RPM_OVER_LIMIT\"}\r\n");
}
// 温度超限保护
if(temperature > 800) { // 假设80.0°C
USART1_SendString("AT+CIPSEND=0,30\r\n");
Delay_ms(100);
USART1_SendString("{\"alarm\":\"TEMP_OVER_LIMIT\"}\r\n");
}
// 振动异常保护
if(vibration_state) {
USART1_SendString("AT+CIPSEND=0,30\r\n");
Delay_ms(100);
USART1_SendString("{\"alarm\":\"VIBRATION_ALARM\"}\r\n");
}
}
// 定时器3中断服务函数
void TIM3_IRQHandler(void)
{
if(TIM3->SR & TIM_SR_UIF) {
TIM3->SR = ~TIM_SR_UIF;
system_time++;
// 每100ms计算一次RPM
if(system_time % 10 == 0) {
Calculate_RPM();
}
// 每1秒读取一次温度
if(system_time % 100 == 0) {
temperature = DS18B20_ReadTemp();
}
// 每100ms读取振动状态
if(system_time % 10 == 0) {
vibration_state = Vibration_Read();
}
// 每5秒上传数据
if(system_time % 500 == 0) {
Upload_Data_To_Cloud();
Safety_Protection();
}
}
}
// 简单延时函数
void Delay_ms(uint32_t nTime)
{
uint32_t i, j;
for(i = 0; i < nTime; i++)
for(j = 0; j < 7200; j++);
}
// ESP8266初始化
void ESP8266_Init(void)
{
Delay_ms(2000);
USART1_SendString("AT+RST\r\n");
Delay_ms(2000);
USART1_SendString("AT+CWMODE=1\r\n");
Delay_ms(1000);
USART1_SendString("AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n"); // 替换实际WiFi信息
Delay_ms(5000);
USART1_SendString("AT+CIPSTART=\"TCP\",\"cloud_server_ip\",1883\r\n"); // 替换云服务器信息
Delay_ms(3000);
}
int main(void)
{
// 系统时钟初始化
SystemInit();
// 外设初始化
TIM2_Init();
TIM3_Init();
EXTI_Init();
USART1_Init();
// 传感器初始化
DS18B20_Init();
// ESP8266初始化
ESP8266_Init();
while(1) {
// 主循环处理其他任务
// 数据采集和上传在定时器中断中处理
}
}
项目核心代码
#include "stm32f10x.h"
// 传感器引脚定义
#define HALL_SENSOR_PIN GPIO_Pin_0 // PA0 - 霍尔传感器
#define TEMP_SENSOR_PIN GPIO_Pin_1 // PA1 - DS18B20
#define VIBRATION_PIN GPIO_Pin_2 // PA2 - SW-420振动传感器
#define LED_ALARM_PIN GPIO_Pin_3 // PA3 - 报警LED
#define RELAY_PIN GPIO_Pin_4 // PA4 - 继电器控制
// 云平台通信定义
#define ESP8266_USART USART1
#define CLOUD_UPDATE_INTERVAL 1000 // 数据上传间隔(ms)
// 报警阈值
#define SPEED_LIMIT 5000 // 转速上限(rpm)
#define TEMP_LIMIT 80 // 温度上限(℃)
#define VIBRATION_LIMIT 1000 // 振动上限
// 全局变量
volatile uint32_t systemTick = 0;
volatile uint16_t centrifugeSpeed = 0;
volatile int16_t temperature = 0;
volatile uint16_t vibration = 0;
volatile uint8_t alarmFlag = 0;
volatile uint32_t lastCloudUpdate = 0;
// 函数声明
void System_Init(void);
void GPIO_Config(void);
void USART_Config(void);
void TIM_Config(void);
void NVIC_Config(void);
void Read_Sensors(void);
void Safety_Control(void);
void Cloud_Communication(void);
void Delay_ms(uint32_t ms);
// 中断服务函数
void TIM2_IRQHandler(void);
void USART1_IRQHandler(void);
int main(void)
{
System_Init();
while(1)
{
Read_Sensors();
Safety_Control();
// 定时上传数据到云平台
if(systemTick - lastCloudUpdate >= CLOUD_UPDATE_INTERVAL)
{
Cloud_Communication();
lastCloudUpdate = systemTick;
}
Delay_ms(100);
}
}
void System_Init(void)
{
// 开启外设时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_USART1EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
GPIO_Config();
USART_Config();
TIM_Config();
NVIC_Config();
// 系统启动时关闭继电器
GPIOA->BSRR = RELAY_PIN << 16;
}
void GPIO_Config(void)
{
// PA0, PA1, PA2 - 输入模式
GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0 |
GPIO_CRL_MODE1 | GPIO_CRL_CNF1 |
GPIO_CRL_MODE2 | GPIO_CRL_CNF2);
GPIOA->CRL |= GPIO_CRL_CNF0_1 | GPIO_CRL_CNF1_1 | GPIO_CRL_CNF2_1; // 浮空输入
// PA3, PA4 - 推挽输出
GPIOA->CRL &= ~(GPIO_CRL_MODE3 | GPIO_CRL_CNF3 |
GPIO_CRL_MODE4 | GPIO_CRL_CNF4);
GPIOA->CRL |= GPIO_CRL_MODE3_0 | GPIO_CRL_MODE4_0; // 输出模式,最大速度10MHz
// PA9(TX), PA10(RX) - 复用推挽输出,浮空输入
GPIOA->CRH &= ~(GPIO_CRH_MODE9 | GPIO_CRH_CNF9 |
GPIO_CRH_MODE10 | GPIO_CRH_CNF10);
GPIOA->CRH |= GPIO_CRH_MODE9_1 | GPIO_CRH_CNF9_1; // PA9 复用推挽输出
GPIOA->CRH |= GPIO_CRH_CNF10_0; // PA10 浮空输入
}
void USART_Config(void)
{
// 波特率115200
ESP8266_USART->BRR = 72000000 / 115200;
// 使能发送、接收、接收中断
ESP8266_USART->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE | USART_CR1_UE;
}
void TIM_Config(void)
{
// TIM2用于系统定时和转速测量
// 72MHz / (7199 + 1) = 10kHz, 100us
TIM2->PSC = 7199;
TIM2->ARR = 999; // 100ms
// 使能更新中断
TIM2->DIER |= TIM_DIER_UIE;
// 启动定时器
TIM2->CR1 |= TIM_CR1_CEN;
}
void NVIC_Config(void)
{
// 设置中断优先级
NVIC->IP[28] = 0x10; // TIM2中断优先级
NVIC->IP[37] = 0x20; // USART1中断优先级
// 使能中断
NVIC->ISER[0] |= (1 << 28); // TIM2
NVIC->ISER[1] |= (1 << 5); // USART1
}
void Read_Sensors(void)
{
static uint32_t hallCount = 0;
static uint32_t lastHallTime = 0;
// 霍尔传感器计数 (简化处理)
if(GPIOA->IDR & HALL_SENSOR_PIN)
{
uint32_t currentTime = systemTick;
if(currentTime - lastHallTime > 10) // 消抖
{
hallCount++;
lastHallTime = currentTime;
// 计算转速 (假设每转产生2个脉冲)
if(systemTick % 1000 == 0) // 每秒计算一次
{
centrifugeSpeed = (hallCount * 60) / 2; // 转换为RPM
hallCount = 0;
}
}
}
// 温度传感器读取 (简化处理)
static uint32_t lastTempRead = 0;
if(systemTick - lastTempRead > 2000) // 2秒读取一次
{
// 这里应该实现DS18B20的读取协议
// temperature = DS18B20_ReadTemp();
temperature = 25; // 模拟温度值
lastTempRead = systemTick;
}
// 振动传感器读取
vibration = (GPIOA->IDR & VIBRATION_PIN) ? 500 : 0; // 简化处理
}
void Safety_Control(void)
{
uint8_t currentAlarm = 0;
// 检查是否超限
if(centrifugeSpeed > SPEED_LIMIT)
{
currentAlarm |= 0x01; // 转速超限
}
if(temperature > TEMP_LIMIT)
{
currentAlarm |= 0x02; // 温度超限
}
if(vibration > VIBRATION_LIMIT)
{
currentAlarm |= 0x04; // 振动超限
}
// 报警处理
if(currentAlarm)
{
alarmFlag = currentAlarm;
// 点亮报警LED
GPIOA->BSRR = LED_ALARM_PIN;
// 紧急停机 - 断开继电器
GPIOA->BSRR = RELAY_PIN << 16;
}
else
{
// 正常状态
alarmFlag = 0;
GPIOA->BSRR = LED_ALARM_PIN << 16; // 关闭报警LED
GPIOA->BSRR = RELAY_PIN; // 闭合继电器
}
}
void Cloud_Communication(void)
{
// 发送数据到云平台
char buffer[64];
sprintf(buffer, "{\"speed\":%d,\"temp\":%d,\"vib\":%d,\"alarm\":%d}",
centrifugeSpeed, temperature, vibration, alarmFlag);
// 发送数据
char *p = buffer;
while(*p)
{
while(!(ESP8266_USART->SR & USART_SR_TXE));
ESP8266_USART->DR = *p++;
}
}
void Delay_ms(uint32_t ms)
{
uint32_t startTick = systemTick;
while(systemTick - startTick < ms);
}
// 中断服务函数
void TIM2_IRQHandler(void)
{
if(TIM2->SR & TIM_SR_UIF)
{
TIM2->SR &= ~TIM_SR_UIF;
systemTick++;
}
}
void USART1_IRQHandler(void)
{
if(ESP8266_USART->SR & USART_SR_RXNE)
{
uint8_t data = ESP8266_USART->DR;
// 处理接收到的数据 (可扩展云平台下发指令)
}
}
总结
该系统成功实现了对离心机运行状态的全面监控,通过STM32F103C8T6主控制器实时采集转速、温度和振动参数,确保实验过程的安全性与稳定性。硬件集成霍尔传感器、DS18B20温度传感器和SW-420振动传感器,结合信号调理电路,有效检测关键指标,并在超限时触发报警与自动保护机制。
数据通过ESP8266-01S Wi-Fi模块上传至华为云平台,支持实验记录的存储与运行状态分析,同时QT上位机直观显示参数曲线与预警信息,便于用户远程监控与决策。整体设计兼顾实用性与可靠性,为离心机操作提供了高效的安全保障和数据分析支持。
- 点赞
- 收藏
- 关注作者
评论(0)