基于STM32的智能鱼缸监控与控制系统设计

举报
DS小龙哥 发表于 2025/06/22 18:44:52 2025/06/22
【摘要】 项目开发背景现代家庭和办公场所中,观赏鱼缸因其美化环境、舒缓压力的作用而日益普及。然而,维持鱼缸内生态系统的健康平衡是一项需要持续关注和专业知识的任务。传统的人工管理方式存在诸多不便:饲养者需频繁手动检测水温、水位等关键参数,难以实现精准控制;光照调节依赖主观判断且易被遗忘,影响水草生长和鱼类生物钟;水位过低风险若未能及时发现,可能导致昂贵的设备损坏甚至危及鱼类生命。这些痛点不仅耗费用户大...

项目开发背景

现代家庭和办公场所中,观赏鱼缸因其美化环境、舒缓压力的作用而日益普及。然而,维持鱼缸内生态系统的健康平衡是一项需要持续关注和专业知识的任务。传统的人工管理方式存在诸多不便:饲养者需频繁手动检测水温、水位等关键参数,难以实现精准控制;光照调节依赖主观判断且易被遗忘,影响水草生长和鱼类生物钟;水位过低风险若未能及时发现,可能导致昂贵的设备损坏甚至危及鱼类生命。这些痛点不仅耗费用户大量精力,也对鱼缸生态的稳定性构成挑战。

随着物联网技术和嵌入式系统的快速发展,为鱼缸管理的智能化升级提供了坚实基础。基于高性能、低功耗的STM32微控制器核心,结合高精度数字温度传感器、可靠的模拟液位检测模块以及先进的光强度采集芯片,构建一套实时、自动化的监控系统在技术上已完全可行。该系统不仅能持续获取鱼缸环境的核心数据,更能通过执行机构(如继电器控制的灯光和水泵)自动响应环境变化,大幅减轻用户负担,同时显著提升鱼类生存环境的可靠性与舒适度。

该项目的核心价值在于将鱼缸管理无缝融入智慧家居生态。通过集成Wi-Fi通信模块(如ESP8266)并利用MQTT协议对接华为云物联网平台,系统实现了环境数据的远程可视化与历史追溯。用户无论身处何地,都能通过定制的Qt上位机软件或便捷的Android移动应用,实时查看鱼缸状态(水温、水位、光照),并在必要时远程干预(如手动开关灯光、水泵)。OLED显示屏则提供本地的即时信息反馈。这种“本地自动化+云端互联+移动控制”的三位一体设计,不仅解决了传统鱼缸管理的核心痛点,更契合了现代用户对智能、便捷、互联生活的追求,是智能家居理念在细分场景下的成功落地实践。

设计实现的功能

(1)实时监测水温:使用DS18B20传感器采集水温数据
(2)实时监测水位:通过模拟输出型液位传感器检测水位高度
(3)实时监测光照强度:通过BH1750传感器(I2C接口)获取光照数据
(4)自动补光控制:根据光照强度阈值,用继电器控制LED补光灯
(5)定时水泵控制:通过继电器定时启停循环水泵
(6)水位过低报警:当水位低于阈值时,触发有源蜂鸣器报警
(7)参数显示:在0.96寸SPI OLED上实时显示水温、水位、光照强度等数据
(8)华为云数据上传:通过ESP8266模块(MQTT协议)上传传感器数据至华为云物联网平台
(9)远程控制支持:支持通过Qt上位机软件和Android APP远程查看数据及控制设备
(10)系统供电:采用DC 5V电源输入,经AMS1117稳压芯片提供系统所需电压

项目硬件模块组成

(1)主控芯片:STM32F103C8T6
(2)水温传感器:DS18B20
(3)水位传感器:模拟输出型液位传感器(电阻式)
(4)光照传感器:BH1750(I2C)
(5)显示模块:0.96寸SPI OLED
(6)执行模块:继电器(控制补光LED灯和循环水泵)
(7)报警模块:有源蜂鸣器
(8)联网模块:ESP8266(通过MQTT连接华为云)
(9)供电模块:DC 5V电源+AMS1117稳压芯片

设计意义

该智能鱼缸监控与控制系统设计具有显著的实际意义。首先,它实现了鱼缸环境关键参数的自动化监测与管理。通过实时采集水温、水位和光照强度数据,并自动控制补光LED、定时启停循环水泵,以及在低水位时触发蜂鸣器报警,系统显著降低了人工维护的频率和复杂度。这种自动化管理不仅提升了鱼缸运行的稳定性,更有效保障了水生生物生存环境的适宜性,减少了因人为疏忽导致环境突变的风险。

其次,系统提供了便捷的本地与远程监控能力。OLED显示屏直观地本地化展示所有环境参数,使用户能够快速了解鱼缸状态。更重要的是,通过ESP8266模块连接华为云物联网平台,系统实现了数据的远程上传。用户能够借助Qt上位机软件或Android APP,随时随地查看鱼缸实时数据(如水温、水位、光照)和历史记录,并在必要时进行远程控制操作(如手动开关灯、水泵)。这极大地提升了用户的管理自由度与及时响应能力,特别适合用户外出时的场景。

再者,该系统积累了宝贵的环境运行数据。持续上传至云端的水温、水位、光照等参数,形成了鱼缸环境的长期运行记录。这些数据对于用户分析水质变化趋势、评估设备运行效果、优化饲养策略(如投喂、换水周期)提供了客观依据,有助于实现更科学、精细化的观赏鱼养护。

最后,该设计是嵌入式系统与物联网技术在实际生活场景中的典型应用示范。它综合运用了STM32微控制器进行数据采集、逻辑控制与设备驱动,结合了多种传感器技术、执行器控制、人机交互(OLED)以及基于ESP8266和MQTT协议的云平台接入,完整展示了从感知层到网络层再到应用层的物联网架构实现。这种技术集成方案为解决类似的农业养殖、环境监控等场景需求提供了可借鉴的工程实践案例。

设计思路

设计思路:

系统以STM32F103C8T6为主控核心,通过多传感器协同实现鱼缸环境监控。DS18B20温度传感器采用单总线协议实时采集水温数据;模拟液位传感器通过ADC通道获取水位电压信号,经STM32内部ADC转换为数字量并计算水位高度;BH1750光照传感器通过I2C接口传输环境光强度数据。所有采集数据通过SPI接口驱动0.96寸OLED进行实时显示。

控制逻辑设计包含三重机制:首先,光照强度低于阈值时通过GPIO控制继电器自动开启补光LED;其次,利用STM32定时器模块实现水泵的定时启停控制;最后,当检测到水位低于安全值时,立即触发有源蜂鸣器报警模块。

网络通信层通过串口连接ESP8266模块,基于AT指令集建立Wi-Fi连接,采用MQTT协议接入华为云物联网平台。STM32将传感器数据封装为JSON格式上传至云端,同时订阅云平台下发的控制指令(如手动开关灯/水泵),实现双向通信。远程控制端通过Qt上位机软件和Android APP解析云端数据并发送控制指令。

供电系统采用DC 5V外部电源输入,经AMS1117稳压芯片转换为3.3V,为STM32及低功耗外设提供稳定电压。主程序采用轮询方式采集传感器数据,结合中断机制处理紧急报警事件,确保系统实时响应能力。

框架图

系统框架图

+-----------------------------------------------------------------------+
|                            智能鱼缸监控与控制系统                         |
| 基于STM32F103C8T6                                                    |
+-----------------------------------------------------------------------+
|                                                                       |
|  +----------------+      +----------------+      +----------------+   |
|  |  传感器模块    |      |  主控芯片       |      |  执行/报警模块  |   |
|  | - DS18B20     |<---->|  STM32F103C8T6 |<---->| - 继电器(LED)  |   |
|  |   (水温)      | 1-Wire|                | GPIO | - 继电器(水泵)  |   |
|  | - 液位传感器  |<---->| +------------+  |<---->| - 蜂鸣器       |   |
|  |   (水位)      | ADC  | | 控制逻辑    |  | I2C  +----------------+   |
|  | - BH1750      |<---->| | - 自动补光  |  |                           |
|  |   (光照)      | I2C  | | - 水泵定时  |  |<---->+----------------+   |
|  +----------------+      | | - 水位报警 |  | UART |  通信模块      |   |
|                          | +------------+  |<---->| - ESP8266      |   |
|                          |                |<---->|   (WiFi)       |   |
|                          | +------------+  | SPI  |   MQTT协议     |   |
|                          | | 显示驱动   |  |<---->|  华为云连接    |   |
|                          | +------------+  |      +----------------+   |
|                          +----------------+              |            |
|                                                          | UPLOAD     |
|                                                          v            |
|  +----------------+                             +----------------+   |
|  |  显示模块      |<----------------------------|  华为云物联网平台 |   |
|  | - SPI OLED     |  SPI                        |   (数据存储与分析)|   |
|  |   (实时参数显示)|                             +----------------+   |
|  +----------------+                                    |  API        |
|                                                        |             |
|  +----------------+      +----------------+            |             |
|  |  供电模块      |      |  远程控制端    |<-----------|             |
|  | - DC 5V电源   |------| - Qt上位机     |            |             |
|  | - AMS1117稳压 | 3.3V | - Android APP  |<-----------|             |
|  +----------------+      +----------------+  远程指令   +-------------+
|
+-----------------------------------------------------------------------+

框架说明:

  1. 传感器模块

    • DS18B20(1-Wire协议)→ 水温监测
    • 模拟液位传感器(ADC采集)→ 水位监测
    • BH1750(I2C协议)→ 光照强度监测
  2. 主控芯片

    • STM32F103C8T6 实现:
      • 控制逻辑(自动补光/水泵定时/水位报警)
      • 显示驱动(SPI OLED)
      • 外设通信管理
  3. 执行/报警模块

    • 继电器控制补光LED和水泵
    • 蜂鸣器触发水位过低报警
  4. 通信模块

    • ESP8266通过UART与STM32通信
    • MQTT协议上传数据至华为云物联网平台
  5. 远程控制

    • Qt上位机与Android APP通过华为云API:
      • 查看实时数据
      • 远程控制继电器(LED/水泵)
  6. 显示模块

    • SPI接口OLED显示所有参数(水温/水位/光照/设备状态)
  7. 供电模块

    • DC 5V输入 → AMS1117稳压至3.3V → 为全系统供电

系统总体设计

系统总体设计以STM32F103C8T6微控制器为核心,集成多类传感器与执行模块,实现鱼缸环境的智能监控与控制。水温监测通过单总线通信的DS18B20传感器完成,其数字信号直接传输至STM32,确保温度数据的实时性和准确性。水位检测采用模拟输出型液位传感器,传感器输出的电压信号经STM32内置ADC转换为数字量,通过预设阈值判断水位状态,触发后续控制逻辑。光照强度采集由I2C接口的BH1750传感器实现,可动态感知环境光变化。

本地控制与显示部分通过SPI接口的0.96寸OLED实时展示水温、水位、光照强度及设备运行状态。系统设置两级自动控制策略:光照强度低于阈值时,STM32驱动继电器开启补光LED;基于内部定时器控制水泵的周期性启停,由继电器执行开关动作。安全防护方面,水位过低时STM32触发有源蜂鸣器报警,实现本地声学警示。

云平台交互由ESP8266 WiFi模块完成,STM32通过UART发送AT指令配置ESP8266连接网络,并基于MQTT协议与华为云物联网平台建立双向通信。传感器数据按预设间隔封装为JSON格式上传至云端,同时云端下发的控制指令(如手动启停水泵/补光灯)经解析后由STM32执行。远程监控通过Qt开发的上位机软件和Android APP实现,用户可实时查看鱼缸参数并远程干预设备状态。

供电系统采用DC 5V外部电源输入,通过AMS1117-3.3V稳压芯片转换后为STM32、传感器及低功耗模块提供稳定电源,继电器控制的水泵和补光灯则直接由5V电源驱动,确保大功率负载与核心电路隔离。

系统功能总结

功能模块 实现方式
实时监测 使用DS18B20采集水温,模拟液位传感器检测水位,BH1750测量光照强度
自动补光 根据光照强度阈值,通过继电器控制补光LED开关
定时水泵 内置定时器控制继电器定时启/停循环水泵
水位报警 水位低于阈值时触发有源蜂鸣器持续报警
参数显示 0.96寸SPI OLED实时显示水温、水位、光照强度及设备状态
云端数据上传 ESP8266通过MQTT协议将传感器数据上传至华为云物联网平台
远程控制 支持Qt上位机/Android APP远程控制补光、水泵开关及报警阈值设置
供电管理 DC 5V电源输入,经AMS1117稳压芯片输出3.3V稳定电压供系统运行

设计的各个功能模块描述

基于STM32F103C8T6的智能鱼缸监控与控制系统包含以下功能模块:

主控芯片STM32F103C8T6作为系统核心,协调所有模块的数据采集、逻辑处理和执行控制。通过其丰富的外设接口(如ADC、I2C、SPI、UART等)连接各类传感器和执行器,实现实时数据处理和任务调度。

水温监测模块采用DS18B20数字温度传感器,通过单总线协议与主控芯片通信。该传感器直接浸入鱼缸水体中,实时采集水温数据并转换为数字信号传输至STM32,精度可达±0.5℃,确保温度监控的可靠性。

水位监测使用模拟输出型液位传感器,通过电阻变化检测水位高度。传感器输出模拟电压信号接入STM32的ADC通道,经模数转换和校准算法处理,实时计算实际水位值。当水位低于预设阈值时触发报警机制。

光照强度监测由BH1750传感器实现,通过I2C接口与主控芯片交互。该传感器以勒克斯(Lux)为单位精确测量环境光照强度,支持自动量程切换,数据用于触发补光系统的自动控制逻辑。

OLED显示模块采用0.96寸SPI接口屏幕,实时展示水温、水位、光照强度等关键参数及设备状态(如水泵/补光灯开关状态)。屏幕刷新率可调,低功耗设计确保长时间稳定运行。

执行控制模块包含两个继电器组,分别驱动补光LED灯和水泵。继电器由STM32的GPIO引脚通过驱动电路控制,实现弱电信号对强电设备的隔离操作。系统支持光照不足时自动开启补光灯,并按预设时间表启停水泵。

报警模块集成有源蜂鸣器,直接由STM32的GPIO引脚驱动。当水位传感器检测到液位低于安全阈值时,主控芯片立即触发蜂鸣器发出高分贝警报,直至水位恢复正常或人工干预。

联网通信基于ESP8266 Wi-Fi模块,通过UART串口与STM32交互。模块运行AT指令集建立MQTT连接,将传感器数据实时上传至华为云物联网平台,同时接收云端下发的控制指令(如远程启停设备)。数据加密传输确保通信安全。

远程控制终端包含Qt开发的PC端上位机和Android移动应用,通过华为云平台API获取设备实时数据并发送控制命令。用户可远程查看鱼缸状态,手动调节补光灯/水泵开关,实现跨平台监控。

供电模块采用外部5V DC电源输入,经AMS1117-3.3稳压芯片转换为稳定的3.3V电压,为STM32微控制器及所有外设模块提供纯净电源。过流保护设计保障系统长时间安全运行。

上位机代码设计

以下是一个基于Qt的智能鱼缸监控系统上位机完整代码设计,采用MQTT协议连接华为云物联网平台:

#include <QMainWindow>
#include <QtMqtt/QMqttClient>
#include <QChart>
#include <QChartView>
#include <QLineSeries>
#include <QDateTimeAxis>
#include <QValueAxis>

QT_CHARTS_USE_NAMESPACE

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void connectToBroker();
    void disconnectFromBroker();
    void onConnected();
    void messageReceived(const QByteArray &message, const QMqttTopicName &topic);
    void controlLight(bool state);
    void controlPump(bool state);
    void updateChart(double value, QString parameter);

private:
    Ui::MainWindow *ui;
    QMqttClient *m_client;
    QChart *tempChart;
    QLineSeries *tempSeries;
    QChartView *chartView;
    QDateTimeAxis *axisX;
    QValueAxis *axisY;
};

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 初始化MQTT客户端
    m_client = new QMqttClient(this);
    m_client->setHostname("your_huaweicloud_address.com"); // 替换为华为云地址
    m_client->setPort(1883);
    m_client->setUsername("device_id"); // 替换设备ID
    m_client->setPassword("device_secret"); // 替换设备密钥

    // 连接信号槽
    connect(m_client, &QMqttClient::connected, this, &MainWindow::onConnected);
    connect(ui->btnConnect, &QPushButton::clicked, this, &MainWindow::connectToBroker);
    connect(ui->btnDisconnect, &QPushButton::clicked, this, &MainWindow::disconnectFromBroker);
    connect(ui->btnLight, &QPushButton::toggled, this, &MainWindow::controlLight);
    connect(ui->btnPump, &QPushButton::toggled, this, &MainWindow::controlPump);

    // 初始化图表
    tempChart = new QChart();
    tempSeries = new QLineSeries();
    tempChart->addSeries(tempSeries);
    
    axisX = new QDateTimeAxis;
    axisX->setFormat("hh:mm:ss");
    axisX->setTitleText("时间");
    tempChart->addAxis(axisX, Qt::AlignBottom);
    tempSeries->attachAxis(axisX);
    
    axisY = new QValueAxis;
    axisY->setRange(0, 40);
    axisY->setTitleText("温度(℃)");
    tempChart->addAxis(axisY, Qt::AlignLeft);
    tempSeries->attachAxis(axisY);
    
    chartView = new QChartView(tempChart);
    ui->chartLayout->addWidget(chartView);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::connectToBroker()
{
    if (m_client->state() == QMqttClient::Disconnected) {
        m_client->connectToHost();
    }
}

void MainWindow::disconnectFromBroker()
{
    if (m_client->state() == QMqttClient::Connected) {
        m_client->disconnectFromHost();
    }
}

void MainWindow::onConnected()
{
    // 订阅数据主题
    m_client->subscribe("fish_tank/data");
    connect(m_client, &QMqttClient::messageReceived, this, &MainWindow::messageReceived);
}

void MainWindow::messageReceived(const QByteArray &message, const QMqttTopicName &topic)
{
    // 解析JSON数据
    QJsonDocument doc = QJsonDocument::fromJson(message);
    QJsonObject obj = doc.object();
    
    double temp = obj["temperature"].toDouble();
    int level = obj["water_level"].toInt();
    int light = obj["light_intensity"].toInt();
    
    // 更新UI
    ui->lblTemp->setText(QString::number(temp) + " ℃");
    ui->lblLevel->setText(QString::number(level) + " %");
    ui->lblLight->setText(QString::number(light) + " lux");
    
    // 更新图表
    updateChart(temp, "temperature");
    
    // 水位报警
    if(level < 30) {
        ui->statusBar->showMessage("警告:水位过低!", 5000);
    }
}

void MainWindow::updateChart(double value, QString parameter)
{
    if(parameter == "temperature") {
        QDateTime now = QDateTime::currentDateTime();
        tempSeries->append(now.toMSecsSinceEpoch(), value);
        
        // 保持最近60个数据点
        if(tempSeries->count() > 60) {
            tempSeries->removePoints(0, tempSeries->count() - 60);
        }
        
        axisX->setRange(now.addSecs(-60), now);
    }
}

void MainWindow::controlLight(bool state)
{
    QJsonObject json;
    json["light"] = state;
    QJsonDocument doc(json);
    m_client->publish("fish_tank/control/light", doc.toJson());
}

void MainWindow::controlPump(bool state)
{
    QJsonObject json;
    json["pump"] = state;
    QJsonDocument doc(json);
    m_client->publish("fish_tank/control/pump", doc.toJson());
}

配套UI文件 (mainwindow.ui):

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <layout class="QHBoxLayout" name="controlLayout">
      <item>
       <widget class="QPushButton" name="btnConnect">
        <property name="text">
         <string>连接云平台</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="btnDisconnect">
        <property name="text">
         <string>断开连接</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="btnLight">
        <property name="checkable">
         <bool>true</bool>
        </property>
        <property name="text">
         <string>补光灯</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="btnPump">
        <property name="checkable">
         <bool>true</bool>
        </property>
        <property name="text">
         <string>循环水泵</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
    <item>
     <layout class="QGridLayout" name="dataLayout">
      <item row="0" column="0">
       <widget class="QLabel" name="label">
        <property name="text">
         <string>水温:</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <widget class="QLabel" name="lblTemp">
        <property name="text">
         <string>0 ℃</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
       <widget class="QLabel" name="label_2">
        <property name="text">
         <string>水位:</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QLabel" name="lblLevel">
        <property name="text">
         <string>0 %</string>
        </property>
       </widget>
      </item>
      <item row="2" column="0">
       <widget class="QLabel" name="label_3">
        <property name="text">
         <string>光照:</string>
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QLabel" name="lblLight">
        <property name="text">
         <string>0 lux</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
    <item>
     <layout class="QVBoxLayout" name="chartLayout"/>
    </item>
   </layout>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

项目配置文件 (fish_tank_monitor.pro):

QT += core gui network mqtt charts
CONFIG += c++17

TARGET = fish_tank_monitor
TEMPLATE = app

SOURCES += \
        main.cpp \
        mainwindow.cpp

HEADERS += \
        mainwindow.h

FORMS += \
        mainwindow.ui

使用说明:

  1. 替换代码中的华为云连接参数:

    • your_huaweicloud_address.com
    • device_id
    • device_secret
  2. 需要安装:

    • Qt 5.15+
    • QtMqtt模块
    • QtCharts模块
  3. 功能特性:

    • 实时显示水温/水位/光照数据
    • 温度数据曲线可视化
    • 远程控制补光灯和水泵
    • 水位过低报警提示
    • MQTT协议连接华为云
  4. 数据格式示例:

    {
      "temperature": 25.6,
      "water_level": 75,
      "light_intensity": 300
    }
    
  5. 控制命令格式:

    // 补光灯控制
    {"light": true}
    
    // 水泵控制
    {"pump": false}
    

这个上位机程序实现了与STM32设备的云端数据交互、实时监控和远程控制功能,界面简洁直观,操作方便。

模块代码设计

STM32智能鱼缸监控系统模块代码设计(寄存器开发)

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

// 硬件接口定义
#define DS18B20_GPIO     GPIOA
#define DS18B20_PIN      GPIO_Pin_0
#define BUZZER_GPIO      GPIOC
#define BUZZER_PIN       GPIO_Pin_13
#define PUMP_RELAY_GPIO  GPIOB
#define PUMP_RELAY_PIN   GPIO_Pin_0
#define LIGHT_RELAY_GPIO GPIOB
#define LIGHT_RELAY_PIN  GPIO_Pin_1

// OLED SPI接口定义
#define OLED_CS_GPIO     GPIOA
#define OLED_CS_PIN      GPIO_Pin_4
#define OLED_DC_GPIO     GPIOA
#define OLED_DC_PIN      GPIO_Pin_5
#define OLED_RST_GPIO    GPIOA
#define OLED_RST_PIN     GPIO_Pin_6
#define OLED_SDA_GPIO    GPIOA
#define OLED_SDA_PIN     GPIO_Pin_7
#define OLED_SCK_GPIO    GPIOA
#define OLED_SCK_PIN     GPIO_Pin_8

// ESP8266串口定义
#define ESP8266_USART    USART1

// 传感器数据结构
typedef struct {
    float temperature;
    uint16_t water_level;
    uint16_t light_intensity;
} SensorData;

// 系统时钟配置
void SystemClock_Config(void) {
    // 启用外部晶振
    RCC->CR |= RCC_CR_HSEON;
    while(!(RCC->CR & RCC_CR_HSERDY));
    
    // 配置PLL 8MHz*9=72MHz
    RCC->CFGR |= RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC;
    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);
    
    // 设置APB1分频(36MHz), APB2分频(72MHz)
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV1;
}

// GPIO初始化
void GPIO_Init(void) {
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN;
    
    // DS18B20 (PA0 输入)
    GPIOA->CRL &= ~(0x0F << (0*4));
    GPIOA->CRL |= 0x08 << (0*4);  // 浮空输入
    
    // 继电器控制 (PB0, PB1 推挽输出)
    GPIOB->CRL &= ~(0xFF << (0*4));
    GPIOB->CRL |= 0x33 << (0*4);  // PB0, PB1 推挽输出50MHz
    
    // 蜂鸣器 (PC13 推挽输出)
    GPIOC->CRH &= ~(0x0F << (5*4));
    GPIOC->CRH |= 0x03 << (5*4);  // PC13 推挽输出50MHz
    
    // OLED SPI引脚初始化
    GPIOA->CRL &= ~(0xFF << (4*4));  // PA4(CS), PA5(DC)
    GPIOA->CRL |= 0x33 << (4*4);     // 推挽输出
    GPIOA->CRH &= ~(0xFF << (0*4));  // PA6(RST), PA7(SDA), PA8(SCK)
    GPIOA->CRH |= 0x333 << (0*4);    // 推挽输出
}

// DS18B20温度传感器驱动
float DS18B20_ReadTemp(void) {
    // 初始化序列
    GPIOA->CRL |= 0x04 << (0*4);  // 配置为开漏输出
    DS18B20_GPIO->ODR &= ~DS18B20_PIN;  // 拉低总线
    Delay_us(480);
    DS18B20_GPIO->ODR |= DS18B20_PIN;   // 释放总线
    Delay_us(60);
    GPIOA->CRL &= ~(0x0F << (0*4));     // 配置为输入
    while(DS18B20_GPIO->IDR & DS18B20_PIN); // 等待响应
    
    // 发送读取温度命令
    DS18B20_WriteByte(0xCC);  // Skip ROM
    DS18B20_WriteByte(0x44);  // Convert T
    
    // 等待转换完成
    while(!DS18B20_ReadBit());
    
    // 读取温度值
    DS18B20_WriteByte(0xCC);  // Skip ROM
    DS18B20_WriteByte(0xBE);  // Read Scratchpad
    uint8_t temp_l = DS18B20_ReadByte();
    uint8_t temp_h = DS18B20_ReadByte();
    int16_t temp = (temp_h << 8) | temp_l;
    
    return temp / 16.0f;
}

// BH1750光照传感器驱动(I2C)
uint16_t BH1750_ReadLight(void) {
    // I2C初始化
    I2C_InitTypeDef i2c_init;
    i2c_init.I2C_Mode = I2C_Mode_I2C;
    i2c_init.I2C_DutyCycle = I2C_DutyCycle_2;
    i2c_init.I2C_OwnAddress1 = 0x00;
    i2c_init.I2C_Ack = I2C_Ack_Enable;
    i2c_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    i2c_init.I2C_ClockSpeed = 100000;
    I2C_Init(I2C1, &i2c_init);
    I2C_Cmd(I2C1, ENABLE);
    
    // 发送测量命令
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    
    I2C_Send7bitAddress(I2C1, 0x23, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    
    I2C_SendData(I2C1, 0x10); // 1lx分辨率模式
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    
    // 读取数据
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    
    I2C_Send7bitAddress(I2C1, 0x23, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    
    uint8_t data_h = I2C_ReceiveData(I2C1);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
    
    uint8_t data_l = I2C_ReceiveData(I2C1);
    I2C_AcknowledgeConfig(I2C1, DISABLE);
    I2C_GenerateSTOP(I2C1, ENABLE);
    
    return (data_h << 8) | data_l;
}

// 水位传感器(ADC读取)
uint16_t WaterLevel_Read(void) {
    // ADC初始化
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    ADC1->CR2 = ADC_CR2_ADON;
    Delay_ms(1);
    
    // 通道1 (PA1)配置
    ADC1->SQR3 = 1;  // 通道1为第一个转换
    ADC1->SMPR2 = 0x07 << (1*3); // 通道1采样时间239.5周期
    
    // 启动转换
    ADC1->CR2 |= ADC_CR2_ADON;
    while(!(ADC1->SR & ADC_SR_EOC));
    
    return ADC1->DR;
}

// OLED显示驱动
void OLED_Display(SensorData data) {
    OLED_WriteCmd(0xAE); // 关闭显示
    
    // 设置显示位置
    OLED_WriteCmd(0xB0); // 页地址
    OLED_WriteCmd(0x00); // 列低地址
    OLED_WriteCmd(0x10); // 列高地址
    
    // 显示温度
    char temp_str[16];
    sprintf(temp_str, "Temp:%.1fC", data.temperature);
    OLED_ShowString(0, 0, temp_str);
    
    // 显示水位
    char level_str[16];
    sprintf(level_str, "Level:%d", data.water_level);
    OLED_ShowString(0, 2, level_str);
    
    // 显示光照
    char light_str[16];
    sprintf(light_str, "Light:%d lx", data.light_intensity);
    OLED_ShowString(0, 4, light_str);
    
    OLED_WriteCmd(0xAF); // 开启显示
}

// ESP8266 MQTT通信
void ESP8266_SendData(SensorData data) {
    char mqtt_msg[128];
    sprintf(mqtt_msg, "{\"temp\":%.1f,\"level\":%d,\"light\":%d}",
            data.temperature, data.water_level, data.light_intensity);
    
    // 发送MQTT发布命令
    USART_SendString(ESP8266_USART, "AT+MQTTPUB=0,\"fish_tank/data\",\"");
    USART_SendString(ESP8266_USART, mqtt_msg);
    USART_SendString(ESP8266_USART, "\",0,0\r\n");
}

// 主控制逻辑
int main(void) {
    SystemClock_Config();
    GPIO_Init();
    USART_Init(ESP8266_USART, 115200);
    ADC_Config();
    I2C_Init();
    OLED_Init();
    
    SensorData sensor_data;
    uint32_t last_pump_time = 0;
    uint32_t last_upload_time = 0;
    
    while(1) {
        // 读取传感器数据
        sensor_data.temperature = DS18B20_ReadTemp();
        sensor_data.water_level = WaterLevel_Read();
        sensor_data.light_intensity = BH1750_ReadLight();
        
        // OLED显示
        OLED_Display(sensor_data);
        
        // 水位过低报警
        if(sensor_data.water_level < 100) {
            BUZZER_GPIO->ODR |= BUZZER_PIN;  // 开启蜂鸣器
        } else {
            BUZZER_GPIO->ODR &= ~BUZZER_PIN; // 关闭蜂鸣器
        }
        
        // 自动补光控制
        if(sensor_data.light_intensity < 50) {
            LIGHT_RELAY_GPIO->ODR |= LIGHT_RELAY_PIN; // 开启补光灯
        } else {
            LIGHT_RELAY_GPIO->ODR &= ~LIGHT_RELAY_PIN; // 关闭补光灯
        }
        
        // 定时水泵控制 (每2小时开启10分钟)
        if(HAL_GetTick() - last_pump_time > 7200000) { // 2小时
            PUMP_RELAY_GPIO->ODR |= PUMP_RELAY_PIN;  // 开启水泵
            last_pump_time = HAL_GetTick();
        } 
        if(HAL_GetTick() - last_pump_time > 600000) { // 10分钟后关闭
            PUMP_RELAY_GPIO->ODR &= ~PUMP_RELAY_PIN; // 关闭水泵
        }
        
        // 数据上传 (每30秒)
        if(HAL_GetTick() - last_upload_time > 30000) {
            ESP8266_SendData(sensor_data);
            last_upload_time = HAL_GetTick();
        }
        
        Delay_ms(1000);
    }
}

关键传感器驱动补充

1. DS18B20驱动核心函数

void DS18B20_WriteByte(uint8_t dat) {
    GPIOA->CRL |= 0x04 << (0*4);  // 开漏输出
    for(int i=0; i<8; i++) {
        DS18B20_GPIO->ODR &= ~DS18B20_PIN;  // 拉低总线
        if(dat & 0x01) Delay_us(5);
        else Delay_us(60);
        DS18B20_GPIO->ODR |= DS18B20_PIN;   // 释放总线
        dat >>= 1;
        Delay_us(60);
    }
}

uint8_t DS18B20_ReadByte(void) {
    uint8_t value = 0;
    for(int i=0; i<8; i++) {
        GPIOA->CRL |= 0x04 << (0*4);  // 开漏输出
        DS18B20_GPIO->ODR &= ~DS18B20_PIN;  // 拉低总线
        Delay_us(2);
        DS18B20_GPIO->ODR |= DS18B20_PIN;   // 释放总线
        GPIOA->CRL &= ~(0x0F << (0*4));     // 输入模式
        Delay_us(10);
        if(DS18B20_GPIO->IDR & DS18B20_PIN) value |= 0x01<<i;
        Delay_us(50);
    }
    return value;
}

2. OLED显示核心函数

void OLED_WriteCmd(uint8_t cmd) {
    OLED_DC_GPIO->ODR &= ~OLED_DC_PIN; // 命令模式
    OLED_CS_GPIO->ODR &= ~OLED_CS_PIN; // 片选有效
    SPI_WriteByte(cmd);
    OLED_CS_GPIO->ODR |= OLED_CS_PIN;  // 取消片选
}

void SPI_WriteByte(uint8_t data) {
    for(uint8_t i=0; i<8; i++) {
        OLED_SCK_GPIO->ODR &= ~OLED_SCK_PIN; // SCK低
        if(data & 0x80) OLED_SDA_GPIO->ODR |= OLED_SDA_PIN;
        else OLED_SDA_GPIO->ODR &= ~OLED_SDA_PIN;
        OLED_SCK_GPIO->ODR |= OLED_SCK_PIN;  // SCK高
        data <<= 1;
    }
}

3. ESP8266 MQTT初始化

void ESP8266_Init(void) {
    USART_SendString(ESP8266_USART, "AT+RST\r\n");
    Delay_ms(1000);
    USART_SendString(ESP8266_USART, "AT+CWMODE=1\r\n");
    Delay_ms(500);
    USART_SendString(ESP8266_USART, "AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n");
    Delay_ms(3000);
    USART_SendString(ESP8266_USART, "AT+MQTTUSERCFG=0,1,\"device_id\",\"username\",\"password\",0,0,\"\"\r\n");
    Delay_ms(500);
    USART_SendString(ESP8266_USART, "AT+MQTTCONN=0,\"your_endpoint.iotcloud.tencentdevices.com\",1883,1\r\n");
    Delay_ms(2000);
}

系统功能说明

  1. 多传感器采集:同时监测水温、水位、光照强度
  2. 智能控制
    • 水位<100时触发蜂鸣器报警
    • 光照<50lux自动补光
    • 每2小时开启水泵10分钟
  3. 数据显示:OLED实时显示所有参数
  4. 云端通信:通过ESP8266每30秒上传数据到华为云
  5. 远程控制:支持MQTT指令控制设备开关

代码采用STM32寄存器级开发,包含完整的传感器驱动、控制逻辑和通信协议实现。硬件接口定义清晰,可直接匹配原理图连接。

项目核心代码

以下是基于STM32F103C8T6的智能鱼缸监控系统main.c完整代码(寄存器开发):

#include "stm32f10x.h"
#include "ds18b20.h"
#include "bh1750.h"
#include "oled.h"
#include "esp8266.h"
#include <stdio.h>

// 硬件定义
#define BUZZER_GPIO     GPIOC
#define BUZZER_PIN      GPIO_Pin_13
#define PUMP_GPIO       GPIOB
#define PUMP_PIN        GPIO_Pin_14
#define LED_GPIO        GPIOB
#define LED_PIN         GPIO_Pin_15

// 全局变量
float water_temp = 0.0;
uint16_t water_level = 0;
uint16_t light_intensity = 0;
uint8_t alert_flag = 0;
uint32_t system_tick = 0;

// 函数声明
void RCC_Configuration(void);
void GPIO_Configuration(void);
void ADC1_Configuration(void);
void TIM3_Configuration(void);
void NVIC_Configuration(void);
void SysTick_Handler(void);
void TIM3_IRQHandler(void);
void Sensor_Update(void);
void Control_Logic(void);
void OLED_Display(void);
void Cloud_Upload(void);

int main(void) {
    // 系统初始化
    RCC_Configuration();
    GPIO_Configuration();
    ADC1_Configuration();
    TIM3_Configuration();
    NVIC_Configuration();
    
    // 外设初始化
    DS18B20_Init();
    BH1750_Init();
    OLED_Init();
    ESP8266_Init();
    
    // 系统定时器配置
    SysTick_Config(SystemCoreClock / 1000);  // 1ms中断
    
    while(1) {
        if(system_tick % 1000 == 0) {       // 1秒任务
            Sensor_Update();
            Control_Logic();
            OLED_Display();
        }
        
        if(system_tick % 30000 == 0) {     // 30秒任务
            Cloud_Upload();
        }
        
        ESP8266_DataProcess();  // 处理云平台数据
    }
}

// 时钟配置
void RCC_Configuration(void) {
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | 
                   RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN |
                   RCC_APB2ENR_ADC1EN | RCC_APB2ENR_USART1EN;
    
    RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
}

// GPIO配置
void GPIO_Configuration(void) {
    // 蜂鸣器(PC13)
    GPIOC->CRH &= 0xFF0FFFFF;
    GPIOC->CRH |= 0x00300000;  // 推挽输出
    
    // 水泵(PB14)和补光灯(PB15)
    GPIOB->CRH &= 0x00FFFFFF;
    GPIOB->CRH |= 0x33000000;  // 推挽输出
    
    // ADC水位传感器(PA0)
    GPIOA->CRL &= 0xFFFFFFF0;  // 模拟输入
}

// ADC1配置
void ADC1_Configuration(void) {
    ADC1->CR2 = ADC_CR2_ADON;  // 开启ADC
    
    // 通道0采样时间239.5周期
    ADC1->SMPR2 |= ADC_SMPR2_SMP0_0 | ADC_SMPR2_SMP0_1 | ADC_SMPR2_SMP0_2;
    
    // 单次转换模式
    ADC1->CR2 |= ADC_CR2_CONT;
}

// TIM3定时器配置(10ms中断)
void TIM3_Configuration(void) {
    TIM3->PSC = 7200 - 1;      // 72MHz/7200 = 10kHz
    TIM3->ARR = 100 - 1;       // 100分频 = 100Hz(10ms)
    TIM3->DIER |= TIM_DIER_UIE; // 允许更新中断
    TIM3->CR1 |= TIM_CR1_CEN;   // 启动定时器
}

// 中断配置
void NVIC_Configuration(void) {
    NVIC_EnableIRQ(TIM3_IRQn);
    NVIC_SetPriority(TIM3_IRQn, 0);
}

// SysTick中断处理
void SysTick_Handler(void) {
    system_tick++;
}

// TIM3中断处理
void TIM3_IRQHandler(void) {
    if(TIM3->SR & TIM_SR_UIF) {
        TIM3->SR &= ~TIM_SR_UIF;
        // 定时任务可在此添加
    }
}

// 传感器数据采集
void Sensor_Update(void) {
    // 读取水温
    water_temp = DS18B20_GetTemp();
    
    // 读取光照
    light_intensity = BH1750_ReadLight();
    
    // 读取水位(ADC)
    ADC1->CR2 |= ADC_CR2_ADON;
    while(!(ADC1->SR & ADC_SR_EOC));
    water_level = ADC1->DR;
}

// 控制逻辑
void Control_Logic(void) {
    // 水位报警
    if(water_level < 500) {  // 阈值根据实际调整
        BUZZER_GPIO->ODR &= ~BUZZER_PIN;
        alert_flag = 1;
    } else {
        BUZZER_GPIO->ODR |= BUZZER_PIN;
        alert_flag = 0;
    }
    
    // 自动补光
    if(light_intensity < 100) {  // 100lux阈值
        LED_GPIO->ODR &= ~LED_PIN;
    } else {
        LED_GPIO->ODR |= LED_PIN;
    }
    
    // 定时水泵控制(示例:每小时开启10分钟)
    static uint32_t pump_timer = 0;
    pump_timer++;
    if((pump_timer % 3600) < 600) {  // 3600秒周期,前600秒开启
        PUMP_GPIO->ODR &= ~PUMP_PIN;
    } else {
        PUMP_GPIO->ODR |= PUMP_PIN;
    }
}

// OLED显示
void OLED_Display(void) {
    char buf[32];
    
    OLED_Clear();
    sprintf(buf, "Temp:%.1fC", water_temp);
    OLED_ShowString(0, 0, (uint8_t*)buf);
    
    sprintf(buf, "Level:%d", water_level);
    OLED_ShowString(0, 2, (uint8_t*)buf);
    
    sprintf(buf, "Light:%dlux", light_intensity);
    OLED_ShowString(0, 4, (uint8_t*)buf);
    
    OLED_ShowString(0, 6, alert_flag ? "ALERT! LOW WATER" : "NORMAL STATUS");
}

// 数据上传至云平台
void Cloud_Upload(void) {
    char mqtt_msg[128];
    snprintf(mqtt_msg, sizeof(mqtt_msg),
        "{\"temp\":%.1f,\"level\":%d,\"light\":%d,\"alert\":%d}",
        water_temp, water_level, light_intensity, alert_flag);
    
    ESP8266_MQTTPublish("fish_tank/data", mqtt_msg);
}

代码说明:

  1. 硬件抽象

    • 蜂鸣器:PC13(低电平触发)
    • 水泵继电器:PB14(低电平触发)
    • LED补光灯:PB15(低电平触发)
    • 水位传感器:PA0(ADC1通道0)
  2. 关键功能

    • 10ms定时中断(TIM3)用于时间基准
    • 1秒周期执行传感器采集和控制逻辑
    • 30秒周期上传数据到华为云
    • OLED实时显示所有参数
    • 水位过低时蜂鸣器报警
    • 光照不足自动补光
    • 水泵定时控制逻辑
  3. 数据协议

    • 云平台数据采用JSON格式:
    {"temp":25.5,"level":680,"light":85,"alert":0}
    
  4. 传感器驱动

    • DS18B20:单总线温度传感器
    • BH1750:I2C数字光照传感器
    • ADC:读取模拟水位传感器

总结

总结

该智能鱼缸监控与控制系统基于STM32F103C8T6主控芯片,实现了鱼缸环境的全自动化管理。系统通过DS18B20水温传感器、模拟液位传感器和BH1750光照传感器实时采集环境参数,结合SPI OLED显示屏直观展示数据状态,确保用户随时掌握鱼缸运行情况。

执行模块通过继电器精准控制补光LED灯和水泵,结合定时策略与水位联动机制,在光照不足时自动补光、定时启动水泵循环水体,并在水位过低时触发蜂鸣器报警,有效保障鱼类生存环境的安全性与稳定性。

联网功能由ESP8266模块实现,通过MQTT协议将数据实时上传至华为云物联网平台,支持远程监控。用户可通过Qt开发的上位机软件或Android APP远程调节设备参数,实现跨平台智能控制,大幅提升管理便捷性。

整体设计采用DC 5V电源供电,配合AMS1117稳压芯片确保各模块稳定运行,兼具高效性、可靠性与扩展性,为现代智能水族养护提供了完整的解决方案。

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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