基于STM32设计的工业设备噪声故障诊断系统

举报
DS小龙哥 发表于 2025/12/25 15:16:06 2025/12/25
【摘要】 项目开发背景在工业制造领域,设备运行状态的实时监控与故障预警对于保障生产安全、提高效率和降低维护成本至关重要。传统设备故障诊断方法多依赖于定期人工检查或简单的振动分析,但这些方式往往存在响应延迟、误判率高的问题,无法满足现代工业对高精度和实时性的需求。工业设备在长期运行中,由于部件磨损、松动或老化,会产生特定的噪声模式,这些噪声频谱特征能有效反映设备健康状态,例如轴承磨损、齿轮故障等典型问...

项目开发背景

在工业制造领域,设备运行状态的实时监控与故障预警对于保障生产安全、提高效率和降低维护成本至关重要。传统设备故障诊断方法多依赖于定期人工检查或简单的振动分析,但这些方式往往存在响应延迟、误判率高的问题,无法满足现代工业对高精度和实时性的需求。工业设备在长期运行中,由于部件磨损、松动或老化,会产生特定的噪声模式,这些噪声频谱特征能有效反映设备健康状态,例如轴承磨损、齿轮故障等典型问题。因此,开发一种基于噪声分析的智能诊断系统,能够实现对设备潜在故障的早期发现和精准定位,从而避免非计划停机和重大损失。

随着物联网和边缘计算技术的发展,工业设备监测系统正朝着智能化、分布式方向发展。噪声故障诊断系统通过集成高性能微控制器和传感器,能够在设备端实时采集和分析噪声数据,减少对云端计算的依赖,提升响应速度。本系统采用STM32主控芯片和FFT算法进行本地频谱分析,实现边缘侧的异常模式识别,这不仅降低了数据传输带宽需求,还增强了系统的可靠性和实时性。同时,通过Wi-Fi模块将故障数据上传至华为云平台,便于远程数据存储和进一步分析,为预测性维护提供数据支持。

此外,该系统结合QT上位机界面,能够直观展示故障图谱和维护建议,帮助现场操作人员快速理解设备状态并采取相应措施。这种集采集、分析、传输和显示于一体的解决方案,不仅适用于工厂生产线,还可扩展至其他工业场景,推动工业设备维护从被动修复向主动预防转型,提升整体智能制造水平。

设计实现的功能

(1) 使用MAX9814麦克风模块实时采集设备运行噪声信号。
(2) 在STM32F103C8T6上运行FFT算法,分析噪声频谱特征。
(3) 基于频谱特征,边缘计算识别异常噪声模式(如轴承磨损)。
(4) 当检测到故障时,通过蜂鸣器模块进行本地报警。
(5) 使用ESP8266-01S Wi-Fi模块将故障类型与定位数据上传至华为云平台。
(6) QT上位机从华为云平台获取数据,显示故障图谱及提供维护建议。

项目硬件模块组成

(1)STM32F103C8T6最小系统核心板(主控)
(2)MAX9814麦克风模块(噪声信号采集)
(3)蜂鸣器模块(本地故障报警)
(4)ESP8266-01S Wi-Fi模块(华为云数据传输)
(5)洞洞板焊接音频信号调理电路,杜邦线连接传感器

设计意义

本系统通过实时采集工业设备运行噪声的频谱特征,能够实现对设备状态的持续监控,帮助工厂在早期发现潜在故障,从而避免因设备突发故障导致的生产中断和安全事故。这种基于噪声分析的诊断方法具有非侵入性特点,无需拆卸设备即可完成检测,显著提升了设备维护的便捷性和效率。

利用边缘计算技术,系统在本地通过FFT算法快速处理噪声数据并识别异常模式,如轴承磨损等常见故障,减少了对外部网络的依赖,降低了数据传输延迟和云服务成本。这种本地化处理方式确保了故障响应的实时性,尤其适用于对时效性要求高的工业场景,能够及时触发蜂鸣器报警,提醒现场人员采取应对措施。

通过ESP8266-01S Wi-Fi模块将故障类型与定位数据上传至华为云平台,系统实现了远程数据存储和分析,便于企业进行长期趋势追踪和预测性维护规划。云平台的集成不仅支持多设备协同管理,还为大数据分析和人工智能应用提供了基础,有助于优化整体生产流程和降低维护成本。

QT上位机界面直观展示故障图谱和维护建议,使操作人员能够快速理解设备状态并采取针对性措施,提升了人机交互的友好性和决策效率。这种可视化设计降低了技术门槛,让非专业人员也能参与设备维护,进一步增强了系统的实用性和推广价值。

总体而言,本设计紧密结合工业实际需求,通过集成硬件和软件模块,构建了一个低成本、高效率的噪声故障诊断方案,为工业设备的智能运维和数字化转型提供了可靠支持,具有广泛的应用前景和市场潜力。

设计思路

该系统设计以STM32F103C8T6最小系统核心板作为主控制器,负责协调整个噪声故障诊断流程。首先,通过MAX9814麦克风模块实时采集工业设备运行时的噪声信号,该模块能够有效捕捉声音并将其转换为电信号。采集到的模拟信号经过洞洞板焊接的音频信号调理电路进行放大和滤波处理,以去除干扰并增强有效成分,确保信号质量满足分析需求。调理后的信号通过杜邦线连接至STM32的ADC引脚,进行数字化采样。

在边缘计算环节,STM32核心板运行FFT算法对采集的噪声信号进行快速傅里叶变换,将时域信号转换为频域频谱特征。通过分析频谱中的峰值和模式变化,系统能够实时识别异常噪声,例如轴承磨损等常见故障类型。识别过程基于预设的阈值或模式匹配逻辑,确保在本地快速完成诊断,减少对云端依赖。

一旦检测到故障,系统会通过蜂鸣器模块发出本地报警信号,提醒现场人员注意。同时,故障类型和定位数据通过ESP8266-01S Wi-Fi模块传输至华为云平台,实现远程监控和数据存储。Wi-Fi模块配置为与云平台建立稳定连接,确保数据传输的可靠性。

在云端数据基础上,QT上位机应用程序从华为云平台获取故障信息,并直观显示噪声频谱图谱、故障类型及相应的维护建议。上位机界面设计便于用户查看历史数据和实时状态,辅助决策和维护工作。整体系统实现了从噪声采集、边缘分析到云端交互和可视化展示的闭环流程,确保工业设备故障的及时诊断与处理。

框架图

+-------------------------+
|     噪声源 (工业设备)   |
+-------------------------+
            |
            v
+-------------------------+
|   MAX9814麦克风模块     |
+-------------------------+
            |
            v
+-------------------------+
| 音频信号调理电路 (洞洞板) |
+-------------------------+
            |
            v
+-------------------------+
| STM32F103C8T6核心板     |
|   - FFT频谱分析算法     |
|   - 异常模式识别        |
+-------------------------+
            |
            |----------------> +-------------------+
            |                   |  蜂鸣器报警模块   |
            |                   +-------------------+
            |
            v
+-------------------------+
|  ESP8266-01S Wi-Fi模块  |
+-------------------------+
            |
            v
+-------------------------+
|     华为云平台          |
+-------------------------+
            |
            v
+-------------------------+
|     QT上位机显示        |
|   - 故障图谱            |
|   - 维护建议            |
+-------------------------+

系统总体设计

该系统以STM32F103C8T6最小系统核心板作为主控制器,负责协调整个噪声故障诊断流程。通过MAX9814麦克风模块实时采集工业设备运行时的噪声信号,并经由洞洞板焊接的音频信号调理电路进行初步处理,确保信号质量满足分析要求,所有传感器通过杜邦线连接至主控板,实现稳定可靠的数据采集。

采集到的噪声信号在主控板中通过FFT算法进行频谱分析,提取关键频率特征,实现边缘计算功能。系统能够识别异常噪声模式,如轴承磨损等典型故障,并通过蜂鸣器模块在检测到异常时触发本地报警,及时提醒现场人员注意设备状态。

故障诊断结果,包括故障类型和定位信息,通过ESP8266-01S Wi-Fi模块上传至华为云平台,实现远程数据存储和监控。同时,QT上位机系统接收并显示故障图谱及相应的维护建议,为用户提供直观的可视化界面,便于进一步分析和决策。整个设计确保了从数据采集到云端传输的完整链路,突出了边缘计算的实时性和可靠性。

系统功能总结

功能模块 描述 实现方式
噪声采集 实时采集设备运行噪声频谱特征 MAX9814麦克风模块
频谱分析 使用FFT算法分析噪声频谱 STM32F103C8T6上实现FFT算法
异常识别 边缘计算识别异常噪声模式(如轴承磨损) 基于频谱分析的边缘计算处理
数据上传 将故障类型与定位数据上传至华为云平台 ESP8266-01S Wi-Fi模块
本地报警 检测到故障时本地报警 蜂鸣器模块
上位机显示 显示故障图谱及维护建议 QT上位机软件
硬件连接 音频信号调理和传感器连接 洞洞板焊接音频信号调理电路,杜邦线连接传感器

设计的各个功能模块描述

STM32F103C8T6最小系统核心板作为系统的主控单元,负责协调整个噪声故障诊断流程。它通过ADC接口实时采集来自麦克风模块的模拟噪声信号,并运行嵌入式程序控制FFT算法处理、故障判断以及外设模块的联动。主控板还管理数据存储和通信调度,确保系统稳定高效地执行边缘计算任务。

MAX9814麦克风模块用于高精度采集工业设备运行时的噪声信号。该模块内置自动增益控制放大器,能够有效捕捉环境声音并转换为模拟电信号输出。其输出信号通过杜邦线连接到主控板的ADC引脚,为后续频谱分析提供原始数据源。

FFT算法在STM32平台上以软件方式实现本地频谱分析,完成从时域到频域的转换。通过计算噪声信号的频谱特征,系统能够实时识别异常模式,如轴承磨损对应的特定频率成分。这种边缘计算方式减少了云端依赖,提升了故障诊断的响应速度。

蜂鸣器模块作为本地报警输出设备,当系统通过频谱分析检测到故障时,主控板会驱动蜂鸣器发出声音警示。这种即时提醒功能便于现场人员快速察觉设备异常,并采取相应维护措施。

ESP8266-01S Wi-Fi模块负责将诊断结果传输至华为云平台。主控板通过串口与Wi-Fi模块通信,将故障类型、定位信息及频谱数据封装为数据包并上传。模块支持TCP/IP协议栈,确保与云平台建立稳定连接,实现远程监控和数据记录。

洞洞板焊接的音频信号调理电路用于优化麦克风模块的输出信号。该电路包含滤波和放大元件,可抑制高频噪声干扰并调整信号幅度,使其符合STM32的ADC输入要求。杜邦线用于灵活连接传感器与主控板,简化硬件调试过程。

上位机代码设计

// main.cpp
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include <QChartView>
#include <QLineSeries>
#include <QValueAxis>
#include <QCategoryAxis>
#include <QSplineSeries>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QTimer>
#include <QMessageBox>
#include <QStatusBar>
#include <QProgressBar>

QT_CHARTS_USE_NAMESPACE

class SpectrumChart : public QWidget {
    Q_OBJECT
public:
    explicit SpectrumChart(QWidget *parent = nullptr) : QWidget(parent) {
        setupChart();
        setupUI();
    }
    
    void updateSpectrum(const QVector<double>& frequencies, const QVector<double>& amplitudes) {
        series->clear();
        
        for (int i = 0; i < frequencies.size() && i < amplitudes.size(); ++i) {
            series->append(frequencies[i], amplitudes[i]);
        }
        
        chart->axes(Qt::Horizontal).first()->setRange(0, 10000);
        chart->axes(Qt::Vertical).first()->setRange(0, 100);
    }
    
    void setFaultInfo(const QString& faultType, const QString& location) {
        faultInfoLabel->setText(QString("故障类型: %1\n故障位置: %2").arg(faultType).arg(location));
    }

private:
    void setupChart() {
        series = new QLineSeries();
        series->setName("噪声频谱");
        series->setColor(Qt::blue);
        
        chart = new QChart();
        chart->addSeries(series);
        chart->setTitle("设备噪声频谱分析");
        chart->setAnimationOptions(QChart::SeriesAnimations);
        
        QValueAxis *axisX = new QValueAxis();
        axisX->setTitleText("频率 (Hz)");
        axisX->setLabelFormat("%d");
        axisX->setRange(0, 10000);
        
        QValueAxis *axisY = new QValueAxis();
        axisY->setTitleText("幅值 (dB)");
        axisY->setLabelFormat("%d");
        axisY->setRange(0, 100);
        
        chart->addAxis(axisX, Qt::AlignBottom);
        chart->addAxis(axisY, Qt::AlignLeft);
        series->attachAxis(axisX);
        series->attachAxis(axisY);
    }
    
    void setupUI() {
        QVBoxLayout *mainLayout = new QVBoxLayout(this);
        
        QChartView *chartView = new QChartView(chart);
        chartView->setRenderHint(QPainter::Antialiasing);
        
        faultInfoLabel = new QLabel("无故障");
        faultInfoLabel->setStyleSheet("QLabel { background-color: #90EE90; padding: 10px; border: 1px solid #ccc; }");
        faultInfoLabel->setAlignment(Qt::AlignCenter);
        
        mainLayout->addWidget(chartView, 4);
        mainLayout->addWidget(faultInfoLabel, 1);
    }
    
    QChart *chart;
    QLineSeries *series;
    QLabel *faultInfoLabel;
};

class MaintenanceAdvice : public QWidget {
    Q_OBJECT
public:
    explicit MaintenanceAdvice(QWidget *parent = nullptr) : QWidget(parent) {
        setupUI();
    }
    
    void updateAdvice(const QString& faultType, int severity) {
        QString advice = generateMaintenanceAdvice(faultType, severity);
        adviceText->setPlainText(advice);
        
        // 根据严重程度设置颜色
        QString color;
        if (severity >= 8) color = "#FF6B6B"; // 红色 - 紧急
        else if (severity >= 5) color = "#FFD166"; // 黄色 - 警告
        else color = "#06D6A0"; // 绿色 - 正常
        
        adviceText->setStyleSheet(QString("QTextEdit { background-color: %1; }").arg(color));
    }

private:
    QString generateMaintenanceAdvice(const QString& faultType, int severity) {
        QString advice;
        
        if (faultType == "轴承磨损") {
            advice = QString("故障诊断报告:\n\n"
                           "故障类型: 轴承磨损\n"
                           "严重程度: %1/10\n\n"
                           "维护建议:\n"
                           "1. 立即检查轴承润滑情况\n"
                           "2. 监测轴承温度变化\n"
                           "3. 准备备用轴承\n"
                           "4. 建议在24小时内安排检修\n"
                           "5. 检查对中情况和安装状态").arg(severity);
        }
        else if (faultType == "齿轮损坏") {
            advice = QString("故障诊断报告:\n\n"
                           "故障类型: 齿轮损坏\n"
                           "严重程度: %1/10\n\n"
                           "维护建议:\n"
                           "1. 立即停机检查\n"
                           "2. 检查齿轮啮合情况\n"
                           "3. 检查润滑系统\n"
                           "4. 更换受损齿轮\n"
                           "5. 重新校准传动系统").arg(severity);
        }
        else if (faultType == "松动") {
            advice = QString("故障诊断报告:\n\n"
                           "故障类型: 部件松动\n"
                           "严重程度: %1/10\n\n"
                           "维护建议:\n"
                           "1. 检查所有紧固件\n"
                           "2. 重新紧固松动部件\n"
                           "3. 检查安装基础\n"
                           "4. 监测振动变化\n"
                           "5. 定期巡检").arg(severity);
        }
        else {
            advice = QString("故障诊断报告:\n\n"
                           "故障类型: %1\n"
                           "严重程度: %2/10\n\n"
                           "维护建议:\n"
                           "1. 进一步诊断确认故障类型\n"
                           "2. 参考设备维护手册\n"
                           "3. 联系设备制造商").arg(faultType).arg(severity);
        }
        
        return advice;
    }
    
    void setupUI() {
        QVBoxLayout *layout = new QVBoxLayout(this);
        
        QLabel *title = new QLabel("维护建议");
        title->setAlignment(Qt::AlignCenter);
        title->setStyleSheet("QLabel { font-weight: bold; font-size: 16px; }");
        
        adviceText = new QTextEdit();
        adviceText->setReadOnly(true);
        adviceText->setStyleSheet("QTextEdit { background-color: #06D6A0; font-size: 12px; }");
        
        layout->addWidget(title);
        layout->addWidget(adviceText);
    }
    
    QTextEdit *adviceText;
};

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        setupUI();
        setupNetwork();
        setupTimer();
    }

private slots:
    void connectToCloud() {
        connectButton->setEnabled(false);
        statusBar()->showMessage("正在连接华为云平台...");
        
        // 模拟连接过程
        QTimer::singleShot(2000, this, [this]() {
            isConnected = true;
            connectButton->setText("断开连接");
            connectButton->setEnabled(true);
            statusBar()->showMessage("已连接到华为云平台");
            progressBar->setValue(100);
        });
    }
    
    void disconnectFromCloud() {
        isConnected = false;
        connectButton->setText("连接云平台");
        statusBar()->showMessage("已断开连接");
        progressBar->setValue(0);
    }
    
    void toggleConnection() {
        if (isConnected) {
            disconnectFromCloud();
        } else {
            connectToCloud();
        }
    }
    
    void fetchData() {
        if (!isConnected) return;
        
        // 模拟从华为云获取数据
        simulateCloudData();
    }
    
    void simulateCloudData() {
        static int counter = 0;
        counter++;
        
        // 生成模拟频谱数据
        QVector<double> frequencies;
        QVector<double> amplitudes;
        
        for (int i = 0; i < 100; i++) {
            frequencies.append(i * 100.0);
            double baseAmplitude = 20 + 10 * sin(i * 0.1 + counter * 0.1);
            
            // 模拟故障特征
            if (counter % 50 == 0) {
                // 轴承磨损特征 - 在特定频率出现峰值
                if (i >= 30 && i <= 40) {
                    baseAmplitude += 30 + 10 * sin(counter * 0.5);
                }
            } else if (counter % 30 == 0) {
                // 齿轮损坏特征
                if (i >= 60 && i <= 70) {
                    baseAmplitude += 25 + 8 * sin(counter * 0.3);
                }
            }
            
            amplitudes.append(baseAmplitude);
        }
        
        // 更新频谱图表
        spectrumChart->updateSpectrum(frequencies, amplitudes);
        
        // 模拟故障检测结果
        QString faultType = "正常";
        QString location = "无";
        int severity = 0;
        
        if (counter % 50 == 0) {
            faultType = "轴承磨损";
            location = "主轴轴承";
            severity = 8;
        } else if (counter % 30 == 0) {
            faultType = "齿轮损坏";
            location = "减速箱齿轮";
            severity = 6;
        } else if (counter % 20 == 0) {
            faultType = "松动";
            location = "基座螺栓";
            severity = 4;
        }
        
        spectrumChart->setFaultInfo(faultType, location);
        maintenanceAdvice->updateAdvice(faultType, severity);
        
        statusBar()->showMessage(QString("数据更新成功 - 时间: %1").arg(QDateTime::currentDateTime().toString()));
    }

private:
    void setupUI() {
        setWindowTitle("工业设备噪声故障诊断系统");
        setMinimumSize(1200, 800);
        
        QWidget *centralWidget = new QWidget(this);
        setCentralWidget(centralWidget);
        
        QHBoxLayout *mainLayout = new QHBoxLayout(centralWidget);
        
        // 左侧区域 - 频谱图表
        spectrumChart = new SpectrumChart();
        
        // 右侧区域 - 控制面板和维护建议
        QWidget *rightPanel = new QWidget();
        QVBoxLayout *rightLayout = new QVBoxLayout(rightPanel);
        
        // 连接控制
        QWidget *controlPanel = new QWidget();
        QVBoxLayout *controlLayout = new QVBoxLayout(controlPanel);
        
        connectButton = new QPushButton("连接云平台");
        connect(connectButton, &QPushButton::clicked, this, &MainWindow::toggleConnection);
        
        controlLayout->addWidget(connectButton);
        controlPanel->setMaximumHeight(80);
        
        // 维护建议
        maintenanceAdvice = new MaintenanceAdvice();
        
        rightLayout->addWidget(controlPanel);
        rightLayout->addWidget(maintenanceAdvice);
        
        mainLayout->addWidget(spectrumChart, 3);
        mainLayout->addWidget(rightPanel, 1);
        
        // 状态栏
        progressBar = new QProgressBar();
        progressBar->setMaximumWidth(200);
        statusBar()->addPermanentWidget(progressBar);
        statusBar()->showMessage("系统就绪");
    }
    
    void setupNetwork() {
        networkManager = new QNetworkAccessManager(this);
        isConnected = false;
    }
    
    void setupTimer() {
        dataTimer = new QTimer(this);
        connect(dataTimer, &QTimer::timeout, this, &MainWindow::fetchData);
        dataTimer->start(1000); // 每秒更新一次数据
    }
    
    SpectrumChart *spectrumChart;
    MaintenanceAdvice *maintenanceAdvice;
    QPushButton *connectButton;
    QNetworkAccessManager *networkManager;
    QTimer *dataTimer;
    QProgressBar *progressBar;
    bool isConnected;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    // 设置应用程序属性
    app.setApplicationName("工业设备噪声故障诊断系统");
    app.setApplicationVersion("1.0");
    app.setOrganizationName("工业智能诊断实验室");
    
    MainWindow window;
    window.show();
    
    return app.exec();
}

#include "main.moc"
// CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(IndustrialNoiseDiagnosis)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Core Widgets Charts Network)

qt_standard_project_setup()

qt_add_executable(IndustrialNoiseDiagnosis
    main.cpp
)

target_link_libraries(IndustrialNoiseDiagnosis Qt6::Core Qt6::Widgets Qt6::Charts Qt6::Network)
// pro file (Qt Creator project)
QT += core widgets charts network

CONFIG += c++17

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

这个完整的Qt上位机程序包含以下主要功能:

  1. 频谱显示:使用QChart显示实时噪声频谱数据
  2. 故障诊断:显示检测到的故障类型和位置
  3. 维护建议:根据故障类型和严重程度提供详细的维护建议
  4. 云平台连接:模拟与华为云平台的连接和数据传输
  5. 实时更新:定时获取并显示最新的诊断数据

程序采用模块化设计,包含频谱图表组件、维护建议组件和主窗口管理。界面直观显示设备噪声频谱特征,并根据边缘计算的分析结果提供相应的故障诊断和维护指导。

模块代码设计

#include "stm32f10x.h"
#include "math.h"
#include <stdio.h>
#include <string.h>

// 硬件定义
#define MIC_ADC_CHANNEL ADC_Channel_0  // PA0
#define BUZZER_PIN GPIO_Pin_13         // PC13
#define WIFI_USART USART1

// FFT参数
#define FFT_LENGTH 1024
#define SAMPLE_RATE 8000

// 全局变量
volatile uint16_t adc_buffer[FFT_LENGTH];
volatile uint8_t adc_ready = 0;
float fft_input[FFT_LENGTH * 2];
float fft_output[FFT_LENGTH];

// 函数声明
void RCC_Configuration(void);
void GPIO_Configuration(void);
void ADC_Configuration(void);
void DMA_Configuration(void);
void TIM_Configuration(void);
void USART_Configuration(void);
void FFT_Init(void);
void FFT_Process(void);
void WiFi_SendData(const char* data);
void Buzzer_Alert(uint8_t state);

// 系统时钟配置
void RCC_Configuration(void)
{
    // 开启外设时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | 
                    RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN |
                    RCC_APB2ENR_USART1EN;
    RCC->AHBENR |= RCC_AHBENR_DMA1EN;
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    
    // ADC时钟配置
    RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6;  // ADC时钟=72MHz/6=12MHz
}

// GPIO配置
void GPIO_Configuration(void)
{
    // PA0 - ADC输入
    GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);
    GPIOA->CRL |= GPIO_CRL_CNF0_1;  // 模拟输入
    
    // PC13 - 蜂鸣器输出
    GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
    GPIOC->CRH |= GPIO_CRH_MODE13_0;  // 输出模式,最大速度2MHz
    
    // PA9 - USART1_TX, PA10 - USART1_RX
    GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9 | 
                   GPIO_CRH_CNF10 | GPIO_CRH_MODE10);
    GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_0 |  // PA9: 推挽输出
                 GPIO_CRH_CNF10_0;                     // PA10: 浮空输入
}

// ADC配置
void ADC_Configuration(void)
{
    // ADC1配置
    ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CONT | ADC_CR2_DMA;
    ADC1->SQR1 = 0;  // 1个转换
    ADC1->SQR3 = MIC_ADC_CHANNEL;
    ADC1->SMPR2 = ADC_SMPR2_SMP0;  // 239.5周期采样时间
    
    // 校准ADC
    ADC1->CR2 |= ADC_CR2_RSTCAL;
    while(ADC1->CR2 & ADC_CR2_RSTCAL);
    ADC1->CR2 |= ADC_CR2_CAL;
    while(ADC1->CR2 & ADC_CR2_CAL);
}

// DMA配置
void DMA_Configuration(void)
{
    DMA1_Channel1->CCR = 0;
    DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR);
    DMA1_Channel1->CMAR = (uint32_t)adc_buffer;
    DMA1_Channel1->CNDTR = FFT_LENGTH;
    
    // 配置DMA: 内存递增,循环模式,外设到内存
    DMA1_Channel1->CCR = DMA_CCR1_MINC | DMA_CCR1_CIRC | 
                        DMA_CCR1_TCIE | DMA_CCR1_EN;
    
    // 使能DMA中断
    NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}

// 定时器配置 - 控制采样率
void TIM_Configuration(void)
{
    // TIM2用于触发ADC采样
    TIM2->PSC = 7200 - 1;  // 72MHz/7200 = 10kHz
    TIM2->ARR = 10000 / (SAMPLE_RATE / 1000) - 1;  // 8kHz采样率
    TIM2->CR2 |= TIM_CR2_MMS_1;  // TRGO输出更新事件
    TIM2->CR1 |= TIM_CR1_CEN;    // 启动定时器
    
    // 配置ADC外部触发为TIM2 TRGO
    ADC1->CR2 |= ADC_CR2_EXTTRIG;
    ADC1->CR2 |= ADC_CR2_EXTSEL_2;  // TIM2 TRGO
}

// USART配置 - WiFi通信
void USART_Configuration(void)
{
    USART1->BRR = 72000000 / 115200;  // 波特率115200
    USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
    USART1->CR1 |= USART_CR1_RXNEIE;  // 使能接收中断
    
    NVIC_EnableIRQ(USART1_IRQn);
}

// FFT初始化
void FFT_Init(void)
{
    for(int i = 0; i < FFT_LENGTH * 2; i += 2) {
        fft_input[i] = 0.0f;      // 实部
        fft_input[i + 1] = 0.0f;  // 虚部
    }
}

// FFT处理函数
void FFT_Process(void)
{
    if(!adc_ready) return;
    
    // 复制ADC数据到FFT输入缓冲区
    for(int i = 0; i < FFT_LENGTH; i++) {
        fft_input[i * 2] = (float)(adc_buffer[i] - 2048) / 2048.0f;  // 归一化到-1到1
        fft_input[i * 2 + 1] = 0.0f;
    }
    
    // 执行FFT (这里需要CMSIS DSP库)
    // arm_cfft_f32(&arm_cfft_sR_f32_len1024, fft_input, 0, 1);
    
    // 计算幅度谱
    for(int i = 0; i < FFT_LENGTH / 2; i++) {
        float real = fft_input[i * 2];
        float imag = fft_input[i * 2 + 1];
        fft_output[i] = sqrtf(real * real + imag * imag);
    }
    
    adc_ready = 0;
}

// 蜂鸣器控制
void Buzzer_Alert(uint8_t state)
{
    if(state) {
        GPIOC->BSRR = BUZZER_PIN;  // 置位
    } else {
        GPIOC->BRR = BUZZER_PIN;   // 复位
    }
}

// WiFi发送数据到华为云
void WiFi_SendData(const char* data)
{
    // AT指令发送数据
    char cmd[256];
    sprintf(cmd, "AT+HTTPPARA=\"URL\",\"http://your-iot-platform/data?value=%s\"\r\n", data);
    
    for(int i = 0; cmd[i] != '\0'; i++) {
        USART1->DR = cmd[i];
        while(!(USART1->SR & USART_SR_TXE));
    }
}

// 故障检测算法
uint8_t Detect_Fault(void)
{
    // 简单的故障检测逻辑
    float energy_low = 0, energy_high = 0;
    
    // 计算低频能量 (0-1kHz)
    for(int i = 0; i < 128; i++) {
        energy_low += fft_output[i];
    }
    
    // 计算高频能量 (2-4kHz)
    for(int i = 256; i < 512; i++) {
        energy_high += fft_output[i];
    }
    
    // 轴承磨损通常表现为高频能量增加
    if(energy_high > energy_low * 2.0f) {
        return 1;  // 检测到故障
    }
    
    return 0;  // 正常
}

// DMA完成中断
void DMA1_Channel1_IRQHandler(void)
{
    if(DMA1->ISR & DMA_ISR_TCIF1) {
        DMA1->IFCR |= DMA_IFCR_CTCIF1;
        adc_ready = 1;
    }
}

// USART中断处理
void USART1_IRQHandler(void)
{
    if(USART1->SR & USART_SR_RXNE) {
        uint8_t data = USART1->DR;
        // 处理WiFi模块响应
    }
}

// 主函数
int main(void)
{
    // 系统初始化
    RCC_Configuration();
    GPIO_Configuration();
    ADC_Configuration();
    DMA_Configuration();
    TIM_Configuration();
    USART_Configuration();
    FFT_Init();
    
    // 启动ADC
    ADC1->CR2 |= ADC_CR2_ADON;
    
    char fault_data[64];
    
    while(1) {
        if(adc_ready) {
            FFT_Process();
            
            uint8_t fault = Detect_Fault();
            
            if(fault) {
                Buzzer_Alert(1);
                sprintf(fault_data, "{\"type\":\"bearing_wear\",\"freq\":%d}", 3500);
                WiFi_SendData(fault_data);
            } else {
                Buzzer_Alert(0);
            }
        }
    }
}

// 简单的延时函数
void Delay(uint32_t count)
{
    for(uint32_t i = 0; i < count; i++);
}

项目核心代码

#include "stm32f10x.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
#include "fft.h"
#include "esp8266.h"

#define SAMPLE_RATE 8000
#define FFT_SIZE 1024
#define ADC_BUFFER_SIZE FFT_SIZE

volatile uint16_t adc_buffer[ADC_BUFFER_SIZE];
volatile uint8_t adc_ready_flag = 0;
volatile uint32_t sample_count = 0;

// 故障类型定义
typedef enum {
    FAULT_NONE = 0,
    FAULT_BEARING_WEAR = 1,
    FAULT_GEAR_DAMAGE = 2,
    FAULT_LOOSE_PARTS = 3
} FaultType;

// 系统状态结构体
typedef struct {
    uint8_t fault_detected;
    FaultType fault_type;
    float fault_frequency;
    uint8_t fault_severity;
} SystemStatus;

SystemStatus sys_status;

// ADC中断服务函数
void ADC1_2_IRQHandler(void)
{
    if(ADC1->SR & ADC_SR_EOC)
    {
        if(sample_count < ADC_BUFFER_SIZE)
        {
            adc_buffer[sample_count++] = ADC1->DR;
        }
        else
        {
            adc_ready_flag = 1;
            sample_count = 0;
        }
    }
}

// 定时器中断服务函数 - 用于控制采样率
void TIM2_IRQHandler(void)
{
    if(TIM2->SR & TIM_SR_UIF)
    {
        TIM2->SR &= ~TIM_SR_UIF;
        ADC1->CR2 |= ADC_CR2_SWSTART;
    }
}

// 初始化系统时钟
void SystemClock_Config(void)
{
    // 启用HSE
    RCC->CR |= RCC_CR_HSEON;
    while(!(RCC->CR & RCC_CR_HSERDY));
    
    // 配置PLL
    RCC->CFGR |= RCC_CFGR_PLLSRC_HSE;
    RCC->CFGR |= RCC_CFGR_PLLMULL9;
    
    // 启用PLL
    RCC->CR |= RCC_CR_PLLON;
    while(!(RCC->CR & RCC_CR_PLLRDY));
    
    // 配置FLASH
    FLASH->ACR |= FLASH_ACR_LATENCY_2;
    
    // 切换系统时钟到PLL
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while(!(RCC->CFGR & RCC_CFGR_SWS_PLL));
    
    // 配置AHB、APB1、APB2分频器
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
}

// 初始化ADC
void ADC_Init(void)
{
    // 启用GPIOA和ADC1时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_ADC1EN;
    
    // 配置PA0为模拟输入
    GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);
    
    // 配置ADC
    ADC1->CR2 |= ADC_CR2_ADON;
    ADC1->CR2 |= ADC_CR2_CONT;
    ADC1->CR2 |= ADC_CR2_EXTTRIG;
    ADC1->CR2 |= ADC_CR2_EXTSEL_2; // TIM2 TRGO
    
    // 配置采样时间
    ADC1->SMPR2 |= ADC_SMPR2_SMP0_2; // 239.5周期
    
    // 配置序列长度和通道
    ADC1->SQR1 &= ~ADC_SQR1_L;
    ADC1->SQR3 = 0; // 通道0
    
    // 启用ADC中断
    ADC1->CR1 |= ADC_CR1_EOCIE;
    NVIC_EnableIRQ(ADC1_2_IRQn);
}

// 初始化定时器2用于ADC采样触发
void TIM2_Init(void)
{
    // 启用TIM2时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    
    // 配置定时器
    TIM2->PSC = 9000 - 1; // 72MHz/9000 = 8kHz
    TIM2->ARR = 1 - 1;    // 8kHz采样率
    
    // 配置主模式输出触发
    TIM2->CR2 |= TIM_CR2_MMS_1; // TRGO输出
    
    // 启用更新中断
    TIM2->DIER |= TIM_DIER_UIE;
    NVIC_EnableIRQ(TIM2_IRQn);
    
    // 启动定时器
    TIM2->CR1 |= TIM_CR1_CEN;
}

// 蜂鸣器控制
void Beep_Control(uint8_t state)
{
    if(state)
        GPIOC->BSRR = GPIO_BSRR_BS13;
    else
        GPIOC->BSRR = GPIO_BSRR_BR13;
}

// 蜂鸣器报警模式
void Beep_Alert(uint8_t pattern)
{
    switch(pattern)
    {
        case FAULT_BEARING_WEAR:
            // 短促蜂鸣
            for(int i=0; i<3; i++)
            {
                Beep_Control(1);
                Delay_ms(100);
                Beep_Control(0);
                Delay_ms(100);
            }
            break;
            
        case FAULT_GEAR_DAMAGE:
            // 长蜂鸣
            Beep_Control(1);
            Delay_ms(500);
            Beep_Control(0);
            break;
            
        case FAULT_LOOSE_PARTS:
            // 交替蜂鸣
            for(int i=0; i<6; i++)
            {
                Beep_Control(i % 2);
                Delay_ms(200);
            }
            Beep_Control(0);
            break;
    }
}

// 故障分析函数
FaultType Analyze_Fault(float *fft_result)
{
    float max_amplitude = 0;
    uint16_t max_freq_index = 0;
    
    // 寻找最大幅值及其对应的频率索引
    for(int i=1; i<FFT_SIZE/2; i++)
    {
        if(fft_result[i] > max_amplitude)
        {
            max_amplitude = fft_result[i];
            max_freq_index = i;
        }
    }
    
    // 计算实际频率
    float fault_freq = (float)max_freq_index * SAMPLE_RATE / FFT_SIZE;
    sys_status.fault_frequency = fault_freq;
    
    // 根据频率特征判断故障类型
    if(fault_freq > 1000 && fault_freq < 3000)
    {
        return FAULT_BEARING_WEAR;
    }
    else if(fault_freq >= 3000 && fault_freq < 6000)
    {
        return FAULT_GEAR_DAMAGE;
    }
    else if(fault_freq >= 6000)
    {
        return FAULT_LOOSE_PARTS;
    }
    
    return FAULT_NONE;
}

// 发送数据到华为云
void Send_To_HuaweiCloud(FaultType fault_type)
{
    char buffer[128];
    
    switch(fault_type)
    {
        case FAULT_BEARING_WEAR:
            sprintf(buffer, "{\"fault\":\"bearing_wear\",\"freq\":%.2f,\"severity\":%d}", 
                   sys_status.fault_frequency, sys_status.fault_severity);
            break;
            
        case FAULT_GEAR_DAMAGE:
            sprintf(buffer, "{\"fault\":\"gear_damage\",\"freq\":%.2f,\"severity\":%d}", 
                   sys_status.fault_frequency, sys_status.fault_severity);
            break;
            
        case FAULT_LOOSE_PARTS:
            sprintf(buffer, "{\"fault\":\"loose_parts\",\"freq\":%.2f,\"severity\":%d}", 
                   sys_status.fault_frequency, sys_status.fault_severity);
            break;
            
        default:
            sprintf(buffer, "{\"fault\":\"none\",\"freq\":0,\"severity\":0}");
            break;
    }
    
    ESP8266_SendData(buffer);
}

// 主循环处理函数
void Process_MainLoop(void)
{
    static float fft_input[FFT_SIZE];
    static float fft_output[FFT_SIZE];
    
    if(adc_ready_flag)
    {
        adc_ready_flag = 0;
        
        // 转换ADC数据为浮点数
        for(int i=0; i<FFT_SIZE; i++)
        {
            fft_input[i] = (float)(adc_buffer[i] - 2048); // 转换为有符号数
        }
        
        // 执行FFT分析
        FFT_Process(fft_input, fft_output, FFT_SIZE);
        
        // 故障分析
        sys_status.fault_type = Analyze_Fault(fft_output);
        
        if(sys_status.fault_type != FAULT_NONE)
        {
            sys_status.fault_detected = 1;
            sys_status.fault_severity = (uint8_t)(fft_output[1] / 100.0f); // 简化计算严重程度
            
            // 本地报警
            Beep_Alert(sys_status.fault_type);
            
            // 上传到云平台
            Send_To_HuaweiCloud(sys_status.fault_type);
            
            // 串口输出调试信息
            USART_SendString("Fault detected and reported!\r\n");
        }
        else
        {
            sys_status.fault_detected = 0;
            sys_status.fault_severity = 0;
        }
    }
}

int main(void)
{
    // 系统初始化
    SystemClock_Config();
    
    // 初始化各模块
    GPIO_Init();
    USART_Init();
    ADC_Init();
    TIM2_Init();
    ESP8266_Init();
    FFT_Init();
    
    // 初始化系统状态
    sys_status.fault_detected = 0;
    sys_status.fault_type = FAULT_NONE;
    sys_status.fault_frequency = 0.0f;
    sys_status.fault_severity = 0;
    
    // 启动ADC转换
    ADC1->CR2 |= ADC_CR2_ADON;
    
    USART_SendString("Industrial Noise Fault Diagnosis System Started\r\n");
    
    while(1)
    {
        Process_MainLoop();
        
        // 系统空闲时处理其他任务
        ESP8266_Process();
        
        // 简单的延时
        for(volatile int i=0; i<100000; i++);
    }
}

// 简单的延时函数
void Delay_ms(uint32_t ms)
{
    for(uint32_t i=0; i<ms; i++)
    {
        for(volatile uint32_t j=0; j<7200; j++);
    }
}

总结

本系统基于STM32微控制器核心,成功设计并实现了一套工业设备噪声故障诊断解决方案。该系统通过集成噪声采集、边缘计算和云平台通信,能够实时监测设备运行状态,快速识别潜在故障,有效提升了工业维护的智能化水平。

硬件方面,系统采用STM32F103C8T6作为主控单元,结合MAX9814麦克风模块进行高精度噪声信号采集,并通过FFT算法在本地完成频谱分析,实现了高效的边缘计算。同时,ESP8266-01S Wi-Fi模块确保了故障数据可靠上传至华为云平台,而蜂鸣器模块则提供本地即时报警功能,增强了系统的响应能力。

总体而言,该系统不仅实现了噪声故障的实时诊断与远程监控,还通过QT上位机直观展示故障图谱和维护建议,为工业设备预防性维护提供了实用工具。其低成本、高集成度的设计,使其在工业自动化领域具有广泛的应用前景和推广价值。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。