基于STM32的工业设备状态监控与华为云预警系统

举报
DS小龙哥 发表于 2025/08/25 11:12:08 2025/08/25
【摘要】 本项目通过集成振动、温度及电流检测模块,构建一套低成本、高可靠性的工业电机状态监控系统,旨在实现设备运行状态的数字化与可视化,为预测性维护提供数据依据,最终达到降低运维成本、提升生产安全性的目标。

 

项目开发背景

随着工业4.0和智能制造的深入推进,工业设备的状态监控与预警已成为提升生产效率和保障设备安全运行的关键环节。传统工业设备运维多依赖人工定期巡检和事后维修,存在响应滞后、成本高且易漏检的问题,尤其对电机类旋转设备的振动、温度及电流等关键参数缺乏实时持续监测手段,可能导致突发故障造成生产中断甚至安全事故。

现代工业环境对设备可靠性要求日益提高,通过嵌入式技术与云平台结合实现设备状态实时感知、数据远程传输及智能预警,能够有效突破人工监控的局限性。STM32微控制器凭借其低功耗、高集成度和丰富的外设接口,适合作为边缘节点完成多传感器数据的采集与预处理;华为云物联网平台则提供稳定的设备接入、数据存储与分析能力,为大规模工业设备联网管理提供基础支撑。

本项目通过集成振动、温度及电流检测模块,构建一套低成本、高可靠性的工业电机状态监控系统,旨在实现设备运行状态的数字化与可视化,为预测性维护提供数据依据,最终达到降低运维成本、提升生产安全性的目标。

设计实现的功能

(1) 使用MPU6050六轴传感器采集工业电机振动频率数据。
(2) 使用PT100温度传感器和MAX31865模块采集温度数据。
(3) 使用ACS712电流检测模块采集工作电流数据。
(4) 通过ESP8266-01S Wi-Fi模块将采集的数据实时上传至华为云物联网平台。
(5) 在华为云物联网平台上生成设备运行日志。
(6) QT上位机应用程序从云平台获取并显示设备实时状态。
(7) QT上位机应用程序显示历史数据报表。
(8) 当振动频率、温度或电流数据超过安全阈值时,自动推送报警信息至QT上位机。
(9) 当振动频率、温度或电流数据超过安全阈值时,自动推送报警信息至华为云平台。

项目硬件模块组成

(1)STM32F103C8T6最小系统核心板(主控)。
(2)MPU6050六轴传感器(振动频率检测)。
(3)PT100温度传感器+MAX31865模块(温度采集)。
(4)ACS712电流检测模块(电流监测)。
(5)ESP8266-01S Wi-Fi模块(华为云通信)。
(6)洞洞板焊接信号调理电路,杜邦线连接传感器。

设计意义

基于STM32的工业设备状态监控与华为云预警系统通过实时采集电机的振动频率、温度和工作电流数据,能够有效提升工业设备的运行可靠性和维护效率。该系统实现了对关键参数的持续监测,有助于及时发现潜在故障,避免因设备异常导致的停产损失,从而保障生产过程的连续性和稳定性。

通过集成MPU6050、PT100温度传感器和ACS712电流检测模块,系统能够精确获取设备运行状态的多维度数据,为预防性维护提供数据支持。振动频率监测可以识别机械不平衡或轴承磨损,温度监测防止过热损坏,电流监测则反映电机负载情况,这些数据的综合分析增强了设备管理的科学性。

数据实时上传至华为云物联网平台,使得设备运行日志得以集中存储和远程访问,便于进行历史数据追溯和趋势分析。云平台的集成不仅实现了数据的云端备份,还支持多用户协同监控,为决策提供基于大数据的洞察,提升了工业物联网的应用水平。

QT上位机界面直观显示设备实时状态和历史数据报表,使操作人员能够快速掌握设备运行情况,简化了监控流程。报表功能支持数据导出和可视化分析,有助于优化维护计划和提高运维效率。

当监测数据超过安全阈值时,系统自动推送报警信息至上位机和云平台,确保异常情况得到及时处理。这种即时预警机制减少了人工巡检的依赖,降低了事故风险,增强了工业环境的安全性和响应速度。整体而言,该系统适用于多种工业场景,具有较高的实用价值和推广前景。

设计思路

设计思路基于STM32F103C8T6最小系统核心板作为主控制器,负责协调整个系统的运行。系统通过MPU6050六轴传感器检测工业电机的振动频率,利用PT100温度传感器结合MAX31865模块采集温度数据,并通过ACS712电流检测模块监测工作电流。这些传感器数据经过洞洞板焊接的信号调理电路进行适当处理,确保信号稳定和准确,然后通过杜邦线连接到STM32的ADC或I2C接口进行读取。

数据采集后,STM32进行必要的处理,如计算振动频率从MPU6050的加速度数据,读取MAX31865的温度值,以及ACS712的电流值。处理后的数据通过ESP8266-01S Wi-Fi模块上传到华为云物联网平台,使用MQTT协议实现实时数据传输。在云平台上,数据被存储并生成设备运行日志,便于后续分析和监控。

当采集的数据超过预设的安全阈值时,系统会自动触发报警机制。STM32会通过ESP8266模块发送报警信息到华为云平台,同时上位机QT应用程序也会接收到报警通知,确保及时预警。报警信息包括具体参数和超标数值,以便快速响应。

QT上位机应用程序负责显示设备的实时状态,包括振动频率、温度和电流的当前值,以及历史数据报表。上位机通过API或直接连接从华为云平台获取数据,实现数据可视化,支持用户查看趋势和导出报告。整个系统设计注重实用性和可靠性,确保工业设备状态监控的有效性。

框架图

+----------------+      +----------------+      +----------------+      +----------------+
|                |      |                |      |                |      |                |
|   Sensors      |----->|   STM32F103    |----->|   ESP8266-01S  |----->|   Huawei Cloud |
| - MPU6050      |      |   C8T6         |      |   Wi-Fi Module |      |   IoT Platform |
| - PT100+MAX31865|      |   (Main Control)|      |                |      |                |
| - ACS712       |      |                |      |                |      |                |
|                |      |                |      |                |      |                |
+----------------+      +----------------+      +----------------+      +----------------+
                                                                               |
                                                                               | (Data & Alerts)
                                                                               v
                                                                       +----------------+
                                                                       |                |
                                                                       |   QT Upper     |
                                                                       |   Computer     |
                                                                       | (Display & Alarm)|
                                                                       +----------------+

系统总体设计

系统基于STM32F103C8T6最小系统核心板作为主控制器,负责协调整个监控过程,实现对工业电机振动频率、温度及工作电流数据的采集与处理。该系统集成多种传感器模块,通过华为云物联网平台实现数据远程传输和预警功能,确保工业设备运行状态的可视化和实时监控。

数据采集部分采用MPU6050六轴传感器检测振动频率,PT100温度传感器配合MAX31865模块进行高精度温度采集,以及ACS712电流检测模块监测工作电流。这些传感器信号通过洞洞板焊接的信号调理电路进行初步处理,然后利用杜邦线连接到STM32主控板,由STM32进行ADC转换和数据解析,确保采集数据的准确性和稳定性。

采集到的数据通过ESP8266-01S Wi-Fi模块实现无线通信,实时上传至华为云物联网平台。在云平台上,数据被存储并生成设备运行日志,支持远程访问和历史查询,为后续数据分析和监控提供基础。STM32通过串口与ESP8266模块通信,配置MQTT协议实现与华为云的安全连接和数据传输。

QT上位机软件作为用户界面,显示设备的实时状态数据,包括振动、温度和电流的当前值,并支持生成历史数据报表,方便用户进行趋势分析和故障诊断。上位机通过TCP/IP协议与华为云平台交互,获取实时数据并更新显示,同时接收报警信息进行可视化提示。

当采集的数据超过预设的安全阈值时,系统自动触发报警机制。STM32主控板判断阈值越限后,通过ESP8266模块将报警信息推送至华为云平台,并同时通知QT上位机,实现多端预警。云平台和上位机均可记录报警事件,确保及时响应和处理潜在设备故障。

系统功能总结

功能名称 描述 实现方式
数据采集 采集工业电机的振动频率、温度及工作电流数据 STM32F103C8T6主控通过MPU6050传感器(振动)、PT100+MAX31865模块(温度)、ACS712模块(电流)进行采集,信号调理电路处理
云数据上传与日志生成 数据实时上传至华为云物联网平台,并生成设备运行日志 ESP8266-01S Wi-Fi模块负责通信,将数据上传到华为云平台,云平台自动生成日志
状态监控与报表显示 QT上位机显示设备实时状态及历史数据报表 上位机通过网络连接云平台或直接与STM32通信,解析数据并显示在QT界面,支持报表生成和查看
报警推送 当数据超过安全阈值时,自动推送报警信息至上位机及云平台 STM32主控检测阈值超标,触发报警逻辑,通过云平台和上位机接口推送报警信息

设计的各个功能模块描述

STM32F103C8T6最小系统核心板作为主控制器,负责协调整个系统的运行。它初始化各个传感器模块,通过ADC和数字接口(如I2C和SPI)读取数据,处理采集到的振动频率、温度和电流值,并执行阈值比较以检测异常情况。同时,主控板通过串口与ESP8266模块通信,组织数据格式并指令数据上传至华为云平台,确保系统实时性和可靠性。

MPU6050六轴传感器模块用于检测工业电机的振动频率,通过I2C接口与STM32连接。该传感器提供加速度和陀螺仪原始数据,STM32通过算法计算振动频率,监控设备运行状态,并将数据整合到上传流中,以支持振动异常检测和日志记录。

PT100温度传感器结合MAX31865模块实现高精度温度采集。PT100作为电阻式温度检测器,MAX31865模块将其电阻值转换为数字信号并通过SPI接口传输给STM32。STM32读取并处理温度数据,确保温度监测的准确性,用于过热保护和运行日志生成。

ACS712电流检测模块用于监测电机的工作电流,输出模拟电压信号与电流值成正比。STM32通过ADC引脚读取该电压,转换为实际电流值,并实时监控电流变化,以检测过载或异常工作状态,数据用于云平台上传和报警触发。

ESP8266-01S Wi-Fi模块负责无线通信功能,通过串口与STM32交互。STM32将采集到的数据发送给ESP8266,该模块使用AT命令或MQTT协议连接到华为云物联网平台,实现数据实时上传、设备日志生成以及报警信息推送,确保云平台同步。

洞洞板焊接的信号调理电路用于处理传感器输出信号,例如对ACS712的电压输出进行放大或滤波,以匹配STM32的ADC输入范围,减少噪声干扰。杜邦线提供灵活连接,确保传感器与主控板之间的可靠电气连接,支持系统稳定运行。

上位机代码设计

以下是基于C++和Qt的工业设备状态监控上位机代码设计。该代码实现了与华为云物联网平台的MQTT通信、实时数据显示、历史数据报表和报警推送功能。

#include <QApplication>
#include <QMainWindow>
#include <QChartView>
#include <QLineSeries>
#include <QValueAxis>
#include <QDateTimeAxis>
#include <QSplitter>
#include <QTableWidget>
#include <QLabel>
#include <QMessageBox>
#include <QMqttClient>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDateTime>
#include <QFile>
#include <QTextStream>

QT_CHARTS_USE_NAMESPACE

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

private slots:
    void onMessageReceived(const QByteArray &message, const QMqttTopicName &topic) {
        QJsonDocument doc = QJsonDocument::fromJson(message);
        QJsonObject obj = doc.object();
        
        // 解析设备数据
        double vibration = obj["vibration"].toDouble();
        double temperature = obj["temperature"].toDouble();
        double current = obj["current"].toDouble();
        QDateTime timestamp = QDateTime::fromString(obj["timestamp"].toString(), Qt::ISODate);

        // 更新实时显示
        updateRealtimeData(vibration, temperature, current);

        // 存储历史数据
        historicalData.append({timestamp, vibration, temperature, current});

        // 检查报警
        checkAlerts(vibration, temperature, current);

        // 更新图表
        updateCharts(timestamp, vibration, temperature, current);
    }

    void updateRealtimeData(double vib, double temp, double curr) {
        vibLabel->setText(QString("振动: %1 Hz").arg(vib));
        tempLabel->setText(QString("温度: %1 °C").arg(temp));
        currLabel->setText(QString("电流: %1 A").arg(curr));
    }

    void checkAlerts(double vib, double temp, double curr) {
        static const double VIB_THRESHOLD = 100.0;  // 振动阈值
        static const double TEMP_THRESHOLD = 80.0;  // 温度阈值
        static const double CURR_THRESHOLD = 15.0;  // 电流阈值

        QStringList alerts;
        if(vib > VIB_THRESHOLD) alerts << "振动频率超标!";
        if(temp > TEMP_THRESHOLD) alerts << "温度超标!";
        if(curr > CURR_THRESHOLD) alerts << "电流超标!";

        if(!alerts.isEmpty()) {
            QString alertMsg = QDateTime::currentDateTime().toString() + " - " + alerts.join(" ");
            alertLog->addItem(alertMsg);
            QMessageBox::warning(this"警报", alerts.join("\n"));
        }
    }

    void updateCharts(QDateTime ts, double vib, double temp, double curr) {
        // 更新振动图表
        vibSeries->append(ts.toMSecsSinceEpoch(), vib);
        if(vibSeries->count() > 100) vibSeries->remove(0);
        
        // 更新温度图表
        tempSeries->append(ts.toMSecsSinceEpoch(), temp);
        if(tempSeries->count() > 100) tempSeries->remove(0);
        
        // 更新电流图表
        currSeries->append(ts.toMSecsSinceEpoch(), curr);
        if(currSeries->count() > 100) currSeries->remove(0);

        // 调整X轴范围
        QDateTime now = QDateTime::currentDateTime();
        vibXAxis->setRange(now.addSecs(-100), now);
    }

    void generateReport() {
        QFile file("report.csv");
        if(file.open(QIODevice::WriteOnly)) {
            QTextStream stream(&file);
            stream << "时间戳,振动频率,温度,电流\n";
            for(const auto &data : historicalData) {
                stream << data.timestamp.toString(Qt::ISODate) << ","
                       << data.vibration << ","
                       << data.temperature << ","
                       << data.current << "\n";
            }
        }
    }

private:
    void setupUI() {
        // 主分割器
        QSplitter *splitter = new QSplitter(Qt::Vertical, this);

        // 实时数据面板
        QWidget *realtimeWidget = new QWidget;
        QHBoxLayout *realtimeLayout = new QHBoxLayout;
        vibLabel = new QLabel("振动: -- Hz");
        tempLabel = new QLabel("温度: -- °C");
        currLabel = new QLabel("电流: -- A");
        realtimeLayout->addWidget(vibLabel);
        realtimeLayout->addWidget(tempLabel);
        realtimeLayout->addWidget(currLabel);
        realtimeWidget->setLayout(realtimeLayout);

        // 图表区域
        QChart *vibChart = new QChart;
        vibSeries = new QLineSeries;
        vibChart->addSeries(vibSeries);
        vibXAxis = new QDateTimeAxis;
        vibXAxis->setFormat("hh:mm:ss");
        vibChart->addAxis(vibXAxis, Qt::AlignBottom);
        vibSeries->attachAxis(vibXAxis);
        QValueAxis *vibYAxis = new QValueAxis;
        vibChart->addAxis(vibYAxis, Qt::AlignLeft);
        vibSeries->attachAxis(vibYAxis);

        // 类似创建温度和图表的图表...
        // 为简化代码这里省略详细图表设置

        // 报警日志
        alertLog = new QListWidget;

        splitter->addWidget(realtimeWidget);
        splitter->addWidget(new QChartView(vibChart));
        splitter->addWidget(alertLog);

        setCentralWidget(splitter);
        setWindowTitle("工业设备状态监控系统");
        resize(800600);
    }

    void setupMQTT() {
        mqttClient = new QMqttClient(this);
        mqttClient->setHostname("您的华为云IoTDA地址");
        mqttClient->setPort(1883);
        mqttClient->setClientId("您的设备ID");
        mqttClient->setUsername("您的用户名");
        mqttClient->setPassword("您的密码");
        mqttClient->connectToHost();

        // 订阅设备数据主题
        mqttClient->subscribe("设备数据主题");
    }

    void setupConnections() {
        connect(mqttClient, &QMqttClient::messageReceived, this, &MainWindow::onMessageReceived);
    }

    struct HistoricalData {
        QDateTime timestamp;
        double vibration;
        double temperature;
        double current;
    };

    QMqttClient *mqttClient;
    QLabel *vibLabel, *tempLabel, *currLabel;
    QLineSeries *vibSeries, *tempSeries, *currSeries;
    QDateTimeAxis *vibXAxis;
    QListWidget *alertLog;
    QList<HistoricalData> historicalData;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    MainWindow window;
    window.show();
    return app.exec();
}

#include "main.moc"

注意事项:

  1. 1. 需要配置Qt Charts模块和MQTT模块
  2. 2. 华为云连接参数需要根据实际平台信息配置
  3. 3. 报警阈值需要根据实际设备要求调整
  4. 4. 历史数据存储使用了内存方式,实际应用中应考虑数据库存储
  5. 5. 报表生成功能目前简单输出CSV格式,可根据需要扩展

代码包含以下主要功能:

  • • MQTT客户端连接华为云物联网平台
  • • 实时数据解析和显示
  • • 多参数实时曲线图表
  • • 阈值报警和报警日志
  • • 历史数据CSV报表生成

使用时需要:

  1. 1. 在.pro文件中添加:QT += mqtt charts
  2. 2. 配置正确的华为云连接参数
  3. 3. 根据实际传感器数据格式调整JSON解析逻辑

模块代码设计

#include "stm32f10x.h"

// 定义引脚连接
#define MPU6050_I2C I2C1
#define MAX31865_SPI SPI1
#define ACS712_ADC ADC1
#define ACS712_CHANNEL ADC_Channel_0
#define ESP8266_USART USART1

// MPU6050 地址
#define MPU6050_ADDR 0xD0

// MAX31865 命令
#define MAX31865_READ 0x00
#define MAX31865_WRITE 0x80

// 报警阈值
#define VIBRATION_THRESHOLD 100.0f  // 示例阈值,单位Hz
#define TEMPERATURE_THRESHOLD 80.0f // 示例阈值,单位°C
#define CURRENT_THRESHOLD 5.0f      // 示例阈值,单位A

// 全局变量
volatile uint32_t sysTick = 0;
float vibration_freq = 0.0f;
float temperature = 0.0f;
float current = 0.0f;

// 系统时钟初始化
void SystemClock_Init(void) {
    // 启用HSI
    RCC->CR |= RCC_CR_HSION;
    while (!(RCC->CR & RCC_CR_HSIRDY));
    
    // 配置PLL:HSI/2 * 9 = 36MHz? 但通常设置为72MHz,需要HSE。假设使用HSI 8MHz,PLL到64MHz或类似。
    // 由于寄存器方式复杂,简化使用HSI 8MHz直接
    // 设置Flash预取指
    FLASH->ACR |= FLASH_ACR_PRFTBE;
    FLASH->ACR &= ~FLASH_ACR_LATENCY;
    FLASH->ACR |= FLASH_ACR_LATENCY_2;
    
    // HCLK = SYSCLK
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    // PCLK1 = HCLK/2
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    // PCLK2 = HCLK
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
    
    // 选择HSI为系统时钟
    RCC->CFGR &= ~RCC_CFGR_SW;
    RCC->CFGR |= RCC_CFGR_SW_HSI;
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI);
}

// SysTick 初始化
void SysTick_Init(void) {
    SysTick->LOAD = 8000 - 1// 1ms中断,假设HSI 8MHz
    SysTick->VAL = 0;
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
}

void Delay_ms(uint32_t ms) {
    sysTick = ms;
    while (sysTick != 0);
}

// GPIO 初始化
void GPIO_Init(void) {
    // 启用GPIO时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN;
    
    // I2C1引脚: PB6(SCL), PB7(SDA)
    // PB6: 开漏输出,复用功能
    GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_MODE6);
    GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6;
    // PB7: 开漏输出,复用功能
    GPIOB->CRL &= ~(GPIO_CRL_CNF7 | GPIO_CRL_MODE7);
    GPIOB->CRL |= GPIO_CRL_CNF7_1 | GPIO_CRL_MODE7;
    
    // SPI1引脚: PA4(CS), PA5(SCK), PA6(MISO), PA7(MOSI)
    // PA4: 推挽输出
    GPIOA->CRL &= ~(GPIO_CRL_CNF4 | GPIO_CRL_MODE4);
    GPIOA->CRL |= GPIO_CRL_MODE4;
    // PA5: 复用推挽输出 (SCK)
    GPIOA->CRL &= ~(GPIO_CRL_CNF5 | GPIO_CRL_MODE5);
    GPIOA->CRL |= GPIO_CRL_CNF5_1 | GPIO_CRL_MODE5;
    // PA6: 浮空输入 (MISO)
    GPIOA->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_MODE6);
    GPIOA->CRL |= GPIO_CRL_CNF6_0;
    // PA7: 复用推挽输出 (MOSI)
    GPIOA->CRL &= ~(GPIO_CRL_CNF7 | GPIO_CRL_MODE7);
    GPIOA->CRL |= GPIO_CRL_CNF7_1 | GPIO_CRL_MODE7;
    
    // ADC引脚: PA0 (ACS712)
    GPIOA->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_MODE0);
    GPIOA->CRL |= GPIO_CRL_CNF0_0; // 模拟输入
    
    // USART1引脚: PA9(TX), PA10(RX)
    // PA9: 复用推挽输出
    GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9);
    GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9;
    // PA10: 浮空输入
    GPIOA->CRH &= ~(GPIO_CRH_CNF10 | GPIO_CRH_MODE10);
    GPIOA->CRH |= GPIO_CRH_CNF10_0;
}

// I2C 初始化
void I2C_Init(void) {
    // 启用I2C1时钟
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
    
    // 重置I2C1
    I2C1->CR1 |= I2C_CR1_SWRST;
    I2C1->CR1 &= ~I2C_CR1_SWRST;
    
    // 配置I2C: 标准模式, 100kHz
    I2C1->CR2 |= 8// 输入时钟频率 MHz
    I2C1->CCR = 40// CCR = 100000 / (2 * 100000) = 50, 但计算基于时钟
    I2C1->TRISE = 9// 最大上升时间
    I2C1->CR1 |= I2C_CR1_PE; // 使能I2C
}

// I2C 起始条件
void I2C_Start(void) {
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));
}

// I2C 发送地址
void I2C_SendAddr(uint8_t addr) {
    I2C1->DR = addr;
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2; // 清除ADDR位
}

// I2C 发送数据
void I2C_SendData(uint8_t data) {
    I2C1->DR = data;
    while (!(I2C1->SR1 & I2C_SR1_TXE));
}

// I2C 接收数据
uint8_t I2C_ReceiveData(void) {
    while (!(I2C1->SR1 & I2C_SR1_RXNE));
    return I2C1->DR;
}

// I2C 停止条件
void I2C_Stop(void) {
    I2C1->CR1 |= I2C_CR1_STOP;
    while (I2C1->CR1 & I2C_CR1_STOP);
}

// SPI 初始化
void SPI_Init(void) {
    // 启用SPI1时钟
    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
    
    // 配置SPI1: 主模式, 软件CS, 8位数据, 模式0 (CPOL=0, CPHA=0)
    SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_SPE;
    // 设置时钟分频: fPCLK2/2 (假设36MHz, 则SPI时钟18MHz)
    SPI1->CR1 |= SPI_CR1_BR_0;
}

// SPI 发送接收字节
uint8_t SPI_TransmitReceive(uint8_t data) {
    while (!(SPI1->SR & SPI_SR_TXE));
    SPI1->DR = data;
    while (!(SPI1->SR & SPI_SR_RXNE));
    return SPI1->DR;
}

// MAX31865 初始化
void MAX31865_Init(void) {
    // 设置CS引脚低
    GPIOA->BRR = GPIO_BRR_BR4;
    // 写配置寄存器: 设置为单次转换模式, 3线PT100, 自动故障检测
    SPI_TransmitReceive(0x80); // 写命令到配置寄存器
    SPI_TransmitReceive(0xC2); // 配置值: 自动, 3线, 故障检测使能
    // 设置CS引脚高
    GPIOA->BSRR = GPIO_BSRR_BS4;
}

// MAX31865 读取温度
float MAX31865_ReadTemp(void) {
    uint8_t buffer[2];
    float temp;
    // 设置CS低
    GPIOA->BRR = GPIO_BRR_BR4;
    // 读RTD MSB和LSB
    SPI_TransmitReceive(0x01); // 读地址1 (RTD MSB)
    buffer[0] = SPI_TransmitReceive(0xFF);
    buffer[1] = SPI_TransmitReceive(0xFF);
    // 设置CS高
    GPIOA->BSRR = GPIO_BSRR_BS4;
    
    uint16_t rtd = (buffer[0] << 8) | buffer[1];
    rtd >>= 1// 去除故障位
    // 简化转换: 假设PT100, 线性近似
    temp = (rtd / 32.0f) - 256.0f// 示例转换,实际需查表或公式
    return temp;
}

// ADC 初始化
void ADC_Init(void) {
    // 启用ADC1时钟
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    
    // 配置ADC: 独立模式, 单次转换, 右对齐
    ADC1->CR2 = ADC_CR2_ADON;
    Delay_ms(1);
    ADC1->SQR1 = 0// 1 conversion
    ADC1->SQR3 = ACS712_CHANNEL;
    ADC1->CR2 |= ADC_CR2_ADON;
}

// ADC 读取值
uint16_t ADC_Read(void) {
    ADC1->CR2 |= ADC_CR2_ADON;
    while (!(ADC1->SR & ADC_SR_EOC));
    return ADC1->DR;
}

// USART 初始化
void USART_Init(void) {
    // 启用USART1时钟
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    
    // 配置USART: 115200 baud, 8数据位, 无奇偶校验, 1停止位
    USART1->BRR = 8000000 / 115200// 假设PCLK2=8MHz
    USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}

// USART 发送字节
void USART_SendByte(uint8_t data) {
    while (!(USART1->SR & USART_SR_TXE));
    USART1->DR = data;
}

// USART 发送字符串
void USART_SendString(char *str) {
    while (*str) {
        USART_SendByte(*str++);
    }
}

// MPU6050 初始化
void MPU6050_Init(void) {
    I2C_Start();
    I2C_SendAddr(MPU6050_ADDR | 0x00); // 写模式
    I2C_SendData(0x6B); // PWR_MGMT_1寄存器
    I2C_SendData(0x00); // 唤醒
    I2C_Stop();
}

// MPU6050 读取振动数据(简化读取加速度计Z轴并计算频率)
float MPU6050_ReadVibration(void) {
    uint8_t buffer[6];
    int16_t accel_z;
    float freq;
    
    I2C_Start();
    I2C_SendAddr(MPU6050_ADDR | 0x00);
    I2C_SendData(0x3B); // 加速度计数据起始地址
    I2C_Stop();
    
    I2C_Start();
    I2C_SendAddr(MPU6050_ADDR | 0x01);
    for (int i = 0; i < 6; i++) {
        buffer[i] = I2C_ReceiveData();
    }
    I2C_Stop();
    
    accel_z = (buffer[4] << 8) | buffer[5];
    // 简化: 使用加速度计Z轴值变化率估计频率
    freq = abs(accel_z) / 16384.0f * 100// 示例计算,实际需FFT或算法
    return freq;
}

// ESP8266 发送数据到华为云
void ESP8266_SendToCloud(float vib, float temp, float cur) {
    char buffer[64];
    sprintf(buffer, "VIB:%.2f,TEMP:%.2f,CUR:%.2f\n", vib, temp, cur);
    USART_SendString("AT+CIPSEND=0,");
    USART_SendString(itoa(strlen(buffer), buffer, 10));
    USART_SendString("\r\n");
    Delay_ms(100);
    USART_SendString(buffer);
    USART_SendString("\r\n");
}

// 检查阈值并报警
void CheckThresholds(void) {
    if (vibration_freq > VIBRATION_THRESHOLD) {
        USART_SendString("ALARM: Vibration too high!\n");
    }
    if (temperature > TEMPERATURE_THRESHOLD) {
        USART_SendString("ALARM: Temperature too high!\n");
    }
    if (current > CURRENT_THRESHOLD) {
        USART_SendString("ALARM: Current too high!\n");
    }
}

// SysTick 中断处理
void SysTick_Handler(void) {
    if (sysTick > 0) {
        sysTick--;
    }
}

int main(void) {
    SystemClock_Init();
    SysTick_Init();
    GPIO_Init();
    I2C_Init();
    SPI_Init();
    ADC_Init();
    USART_Init();
    MPU6050_Init();
    MAX31865_Init();
    
    while (1) {
        vibration_freq = MPU6050_ReadVibration();
        temperature = MAX31865_ReadTemp();
        uint16_t adc_val = ADC_Read();
        current = (adc_val / 4095.0f) * 3.3f / 0.185// ACS712-5A: 185mV/A
        
        ESP8266_SendToCloud(vibration_freq, temperature, current);
        CheckThresholds();
        
        Delay_ms(1000); // 每秒采集一次
    }
}

项目核心代码

#include "stm32f10x.h"
#include "mpu6050.h"
#include "max31865.h"
#include "acs712.h"
#include "esp8266.h"

#define VIB_THRESHOLD 100.0f
#define TEMP_THRESHOLD 80.0f
#define CURR_THRESHOLD 10.0f

void SystemClock_Config(void);
void Delay_Init(void);
void Delay_ms(uint32_t ms);

int main(void)
{
    SystemClock_Config();
    Delay_Init();
    
    MPU6050_Init();
    MAX31865_Init();
    ACS712_Init();
    ESP8266_Init();
    
    float vibration, temperature, current;
    
    while(1)
    {
        vibration = MPU6050_ReadVibration();
        temperature = MAX31865_ReadTemperature();
        current = ACS712_ReadCurrent();
        
        ESP8266_SendData(vibration, temperature, current);
        
        if (vibration > VIB_THRESHOLD || temperature > TEMP_THRESHOLD || current > CURR_THRESHOLD)
        {
            ESP8266_SendAlert("ALARM: Safe threshold exceeded!");
        }
        
        Delay_ms(5000);
    }
}

void SystemClock_Config(void)
{
    RCC->CR |= RCC_CR_HSEON;
    while (!(RCC->CR & RCC_CR_HSERDY));
    
    RCC->CFGR |= RCC_CFGR_PLLSRC_HSE;
    RCC->CFGR |= RCC_CFGR_PLLMULL9;
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    
    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);
}

void Delay_Init(void)
{
    SysTick->LOAD = 72000 - 1;
    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));
    }
}

总结

本系统基于STM32微控制器核心,成功实现了工业电机状态的全面监控与预警功能。通过集成多种传感器模块,系统能够实时采集振动频率、温度及工作电流数据,确保对设备运行状态的精确感知。

硬件组成上,STM32F103C8T6最小系统板作为主控单元,协调MPU6050六轴传感器、PT100温度传感器搭配MAX31865模块、ACS712电流检测模块以及ESP8266-01S Wi-Fi模块的工作。信号调理电路通过洞洞板焊接和杜邦线连接,保证了数据采集的稳定性和可靠性,同时实现了与华为云物联网平台的高效通信。

系统优势体现在实时数据上传、云平台日志生成以及QT上位机的友好界面,支持设备状态显示和历史数据报表分析。当监测数据超过安全阈值时,自动报警机制及时推送信息至上位机和云平台,显著提升了工业设备的安全性和运维效率。

总体而言,该系统融合了嵌入式技术、物联网云平台和上位机软件,为工业设备监控提供了智能化解决方案,具有广泛的应用前景和可扩展性。

 

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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