基于STM32的智能鱼塘监控系统

举报
DS小龙哥 发表于 2025/12/25 11:58:09 2025/12/25
【摘要】 项目开发背景随着水产养殖业的快速发展,鱼塘养殖作为重要的农业生产方式,在保障食品供应和促进农村经济中扮演着关键角色。然而,传统鱼塘管理主要依赖人工经验,养殖户需要频繁现场检测水质参数,如温度、pH值和溶解氧含量,这不仅效率低下,还容易因人为疏忽导致监测不及时,引发鱼类疾病或死亡,造成经济损失。在当前农业现代化趋势下,智能化和自动化技术正逐步应用于水产养殖领域,以提升管理效率和精准度。通过引...

项目开发背景

随着水产养殖业的快速发展,鱼塘养殖作为重要的农业生产方式,在保障食品供应和促进农村经济中扮演着关键角色。然而,传统鱼塘管理主要依赖人工经验,养殖户需要频繁现场检测水质参数,如温度、pH值和溶解氧含量,这不仅效率低下,还容易因人为疏忽导致监测不及时,引发鱼类疾病或死亡,造成经济损失。

在当前农业现代化趋势下,智能化和自动化技术正逐步应用于水产养殖领域,以提升管理效率和精准度。通过引入物联网和嵌入式系统,可以实现对鱼塘环境的实时监控与远程控制,帮助养殖户及时响应水质变化,降低运营成本,并促进可持续养殖模式的推广。

基于此,本项目开发了一套基于STM32的智能鱼塘监控系统,旨在通过集成传感器、通信模块和执行设备,构建一个高效、可靠的解决方案。该系统能够自动采集和分析水质数据,支持用户远程监控和操作,从而有效解决传统养殖中的管理难题,推动鱼塘养殖向智能化、精细化方向发展。

设计实现的功能

(1) 实时监测鱼塘水体温度、pH值、溶解氧等关键水质参数。
(2) 用户可通过手机APP远程查看水质数据,并手动控制增氧机、喂食机。
(3) 系统可设置自动模式,根据水质参数阈值自动控制增氧机的启停。
(4) 所有设备状态和水质历史数据可在APP端查询。

项目硬件模块组成

(1)主控芯片:STM32F103系列单片机
(2)传感模块:DS18B20水温传感器、pH传感器、溶解氧传感器
(3)通信模块:ESP8266 Wi-Fi模块
(4)执行模块:继电器模块(控制增氧机、喂食机)
(5)显示模块:LCD1602液晶显示屏(可选,用于本地显示)

设计意义

该系统通过集成传感器和无线通信技术,实现了对鱼塘水质的实时监测与设备远程控制,有效提升了水产养殖管理的自动化水平。用户无需频繁现场检查,即可通过手机APP获取关键数据并操作设备,显著减少了人力投入和操作时间。

通过持续监控温度、pH值和溶解氧等参数,系统能够及时调整增氧机和喂食机的工作状态,确保鱼类生长环境稳定。这有助于预防水质恶化导致的疾病或死亡,从而提高养殖成功率和鱼类健康水平。

系统的自动模式功能根据预设阈值智能控制设备运行,避免了人为疏忽可能引发的风险。同时,历史数据查询功能为用户提供了长期趋势分析的基础,支持更科学的养殖决策,优化资源利用。

该设计推动了传统水产养殖向智能化转型,降低了能源和人力成本,提升了生产效益。它以实际应用为导向,为中小型养殖户提供了一种可靠、经济的解决方案,具有广泛的市场推广价值。

设计思路

该系统设计以STM32F103系列单片机为核心控制器,负责协调整个鱼塘监控系统的运行。系统通过集成多种传感器模块实时采集鱼塘水体的关键参数,包括DS18B20数字温度传感器测量水温、pH传感器检测酸碱度、溶解氧传感器监测水中氧气含量。这些传感器数据经过STM32的ADC或数字接口进行读取和处理,确保数据的准确性和实时性。

数据处理后,STM32根据预设的阈值判断水质状态,并通过继电器模块控制增氧机和喂食机的启停。在自动模式下,系统会持续比较采集值与阈值,例如当溶解氧低于设定值时自动启动增氧机,实现智能化管理,减少人工干预。同时,继电器模块的设计允许安全驱动大功率设备,保障鱼塘设备的稳定运行。

通信部分采用ESP8266 Wi-Fi模块,将STM32处理的数据上传到云端服务器或直接与手机APP交互。用户可以通过APP远程查看实时水质数据、手动控制设备开关,并查询历史记录,方便随时掌握鱼塘状况。Wi-Fi模块的配置确保数据传输的可靠性和低延迟,支持多种网络环境。

用户交互方面,手机APP提供直观的界面显示水质参数和设备状态,并允许设置自动模式的阈值。此外,可选配的LCD1602液晶显示屏可用于本地实时显示关键数据,作为辅助监控手段,增强系统的实用性。整个设计注重稳定性和易用性,满足鱼塘日常管理的实际需求。

框架图

+----------------+       +-----------------+       +-------------------+
|  传感器模块     |------>|   主控芯片      |<----->|   通信模块        |
| - DS18B20     |       |   STM32F103    |       |   ESP8266 Wi-Fi  |
| - pH传感器     |       |                |       |                   |
| - 溶解氧传感器 |       +-----------------+       +-------------------+
+----------------+               |                         |
                                 |                         |
                                 v                         v
                         +-----------------+       +-------------------+
                         |   执行模块      |       |   手机APP        |
                         | - 继电器模块   |       |   (远程控制/查看) |
                         | - 增氧机       |       +-------------------+
                         | - 喂食机       |
                         +-----------------+
                                 |
                         +-----------------+
                         |   显示模块      |
                         | - LCD1602      |
                         |   (可选)       |
                         +-----------------+

系统总体设计

本系统基于STM32F103系列单片机作为核心控制器,旨在实现对鱼塘水质的智能化监控和管理。系统通过集成多种传感器模块,实时采集水体温度、pH值和溶解氧等关键参数,确保对鱼塘环境的全面监测。这些数据经过主控芯片处理和分析后,为后续的自动控制和远程交互提供基础。

在数据采集方面,系统使用DS18B20水温传感器、pH传感器和溶解氧传感器分别获取相应的水质指标。STM32主控芯片定期读取传感器数据,并进行必要的校准和转换,以保证数据的准确性和可靠性。处理后的数据可用于本地显示或通过通信模块传输。

远程通信和控制功能通过ESP8266 Wi-Fi模块实现,该模块将系统连接到互联网,使得用户能够通过手机APP实时查看水质参数。用户还可以通过APP手动发送指令,控制增氧机和喂食机的开关状态,实现远程操作。同时,系统支持自动模式,用户可在APP端设置水质参数的阈值,当监测数据超出范围时,系统自动通过继电器模块控制增氧机的启停,无需人工干预。

对于本地显示,系统可选配LCD1602液晶显示屏,用于实时展示当前水质数据和设备运行状态,方便现场查看。所有设备状态和水质历史数据均被记录和存储,用户可通过手机APP查询历史记录,以便分析趋势和优化管理策略。整体设计注重实用性和稳定性,确保系统在鱼塘环境中高效运行。

系统功能总结

功能项 功能描述
实时监测 实时监测鱼塘水体温度、pH值、溶解氧等关键水质参数。
远程查看与控制 用户可通过手机APP远程查看水质数据,并手动控制增氧机、喂食机。
自动控制 系统可设置自动模式,根据水质参数阈值自动控制增氧机的启停。
数据查询 所有设备状态和水质历史数据可在APP端查询。

设计的各个功能模块描述

主控模块基于STM32F103系列单片机,作为系统的核心处理单元,负责协调和控制所有其他模块的运行。它实时采集传感模块的数据,处理水质参数信息,并根据预设逻辑或用户指令控制执行模块的动作,同时管理通信模块的数据传输和显示模块的更新,确保系统稳定高效地工作。

传感模块由DS18B20水温传感器、pH传感器和溶解氧传感器组成,用于持续监测鱼塘水体的关键水质指标。这些传感器将采集到的温度、pH值和溶解氧数据转换为电信号,传送给主控芯片进行分析和处理,以实现对鱼塘环境的实时监控。

通信模块采用ESP8266 Wi-Fi模块,实现系统与互联网的无缝连接。通过该模块,主控芯片可以将水质数据和设备状态发送到云端服务器,用户即可通过手机APP远程查看实时信息、手动控制增氧机和喂食机,并查询历史记录,确保远程管理的便捷性和实时性。

执行模块通过继电器模块控制增氧机和喂食机的操作,主控芯片根据用户通过APP发送的指令或自动模式下设定的水质参数阈值(如溶解氧水平)来驱动继电器,从而自动或手动启停这些设备,以维持鱼塘水质的稳定和鱼类的健康生长。

显示模块可选配LCD1602液晶显示屏,用于在本地直观展示当前水质参数(如温度、pH值和溶解氧)以及设备运行状态。该模块为用户提供现场监控的便利,无需依赖远程设备即可快速获取系统信息,增强了系统的实用性和灵活性。

上位机代码设计

#include <iostream>
#include <vector>
#include <string>
#include <thread>
#include <chrono>
#include <random>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <map>
#include <mutex>

// 水质数据结构体
struct WaterQualityData {
    double temperature;    // 温度 ℃
    double pH;            // pH值
    double dissolvedOxygen; // 溶解氧 mg/L
    std::string timestamp; // 时间戳
    bool aeratorStatus;    // 增氧机状态
    bool feederStatus;     // 喂食机状态
};

// 设备控制命令
enum class DeviceCommand {
    AERATOR_ON,
    AERATOR_OFF,
    FEEDER_ON,
    FEEDER_OFF,
    GET_DATA
};

// 智能鱼塘监控系统上位机类
class FishPondMonitor {
private:
    std::vector<WaterQualityData> historyData;
    std::mutex dataMutex;
    bool isRunning;
    bool autoMode;
    double tempThreshold;
    double pHThreshold;
    double oxygenThreshold;
    
    // 模拟传感器数据生成
    WaterQualityData generateSensorData() {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_real_distribution<> tempDist(15.0, 30.0);
        std::uniform_real_distribution<> pHDist(6.5, 8.5);
        std::uniform_real_distribution<> oxygenDist(5.0, 12.0);
        
        WaterQualityData data;
        data.temperature = tempDist(gen);
        data.pH = pHDist(gen);
        data.dissolvedOxygen = oxygenDist(gen);
        
        // 生成时间戳
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        std::stringstream ss;
        ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
        data.timestamp = ss.str();
        
        return data;
    }
    
    // 模拟与STM32通信
    bool sendCommandToSTM32(DeviceCommand command) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        return true;
    }
    
    WaterQualityData receiveDataFromSTM32() {
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        return generateSensorData();
    }

public:
    FishPondMonitor() : isRunning(false), autoMode(true), 
                       tempThreshold(25.0), pHThreshold(7.0), 
                       oxygenThreshold(6.0) {}
    
    // 启动监控系统
    void startMonitoring() {
        isRunning = true;
        std::cout << "智能鱼塘监控系统启动..." << std::endl;
        
        // 数据采集线程
        std::thread dataThread([this]() {
            while (isRunning) {
                WaterQualityData newData = receiveDataFromSTM32();
                
                std::lock_guard<std::mutex> lock(dataMutex);
                historyData.push_back(newData);
                
                // 保持历史数据在100条以内
                if (historyData.size() > 100) {
                    historyData.erase(historyData.begin());
                }
                
                // 自动模式控制
                if (autoMode) {
                    if (newData.dissolvedOxygen < oxygenThreshold) {
                        sendCommandToSTM32(DeviceCommand::AERATOR_ON);
                        std::cout << "溶解氧过低,自动开启增氧机" << std::endl;
                    } else if (newData.dissolvedOxygen > oxygenThreshold + 2.0) {
                        sendCommandToSTM32(DeviceCommand::AERATOR_OFF);
                        std::cout << "溶解氧正常,自动关闭增氧机" << std::endl;
                    }
                }
                
                std::this_thread::sleep_for(std::chrono::seconds(5));
            }
        });
        
        dataThread.detach();
    }
    
    // 停止监控系统
    void stopMonitoring() {
        isRunning = false;
        std::cout << "监控系统停止" << std::endl;
    }
    
    // 获取当前水质数据
    WaterQualityData getCurrentData() {
        std::lock_guard<std::mutex> lock(dataMutex);
        if (historyData.empty()) {
            return generateSensorData();
        }
        return historyData.back();
    }
    
    // 获取历史数据
    std::vector<WaterQualityData> getHistoryData(int count = 10) {
        std::lock_guard<std::mutex> lock(dataMutex);
        if (historyData.size() <= count) {
            return historyData;
        }
        return std::vector<WaterQualityData>(
            historyData.end() - count, historyData.end());
    }
    
    // 手动控制增氧机
    bool controlAerator(bool turnOn) {
        DeviceCommand cmd = turnOn ? DeviceCommand::AERATOR_ON : DeviceCommand::AERATOR_OFF;
        bool success = sendCommandToSTM32(cmd);
        if (success) {
            std::cout << "增氧机" << (turnOn ? "开启" : "关闭") << std::endl;
        }
        return success;
    }
    
    // 手动控制喂食机
    bool controlFeeder(bool turnOn) {
        DeviceCommand cmd = turnOn ? DeviceCommand::FEEDER_ON : DeviceCommand::FEEDER_OFF;
        bool success = sendCommandToSTM32(cmd);
        if (success) {
            std::cout << "喂食机" << (turnOn ? "开启" : "关闭") << std::endl;
        }
        return success;
    }
    
    // 设置自动模式
    void setAutoMode(bool enabled) {
        autoMode = enabled;
        std::cout << "自动模式" << (enabled ? "开启" : "关闭") << std::endl;
    }
    
    // 设置阈值
    void setThresholds(double temp, double pH, double oxygen) {
        tempThreshold = temp;
        pHThreshold = pH;
        oxygenThreshold = oxygen;
        std::cout << "阈值设置成功: 温度=" << temp << "℃, pH=" << pH << ", 溶解氧=" << oxygen << "mg/L" << std::endl;
    }
    
    // 显示当前状态
    void displayCurrentStatus() {
        WaterQualityData current = getCurrentData();
        std::cout << "\n=== 当前鱼塘状态 ===" << std::endl;
        std::cout << "时间: " << current.timestamp << std::endl;
        std::cout << "水温: " << current.temperature << " ℃" << std::endl;
        std::cout << "pH值: " << current.pH << std::endl;
        std::cout << "溶解氧: " << current.dissolvedOxygen << " mg/L" << std::endl;
        std::cout << "增氧机: " << (current.aeratorStatus ? "运行中" : "停止") << std::endl;
        std::cout << "喂食机: " << (current.feederStatus ? "运行中" : "停止") << std::endl;
        std::cout << "自动模式: " << (autoMode ? "开启" : "关闭") << std::endl;
        std::cout << "===================" << std::endl;
    }
    
    // 显示历史数据
    void displayHistoryData(int count = 10) {
        std::vector<WaterQualityData> history = getHistoryData(count);
        std::cout << "\n=== 最近" << count << "条历史数据 ===" << std::endl;
        for (const auto& data : history) {
            std::cout << data.timestamp << " - "
                      << "温度:" << data.temperature << "℃ "
                      << "pH:" << data.pH << " "
                      << "溶解氧:" << data.dissolvedOxygen << "mg/L" << std::endl;
        }
        std::cout << "===================" << std::endl;
    }
};

// 手机APP模拟界面类
class MobileApp {
private:
    FishPondMonitor& monitor;

public:
    MobileApp(FishPondMonitor& mon) : monitor(mon) {}
    
    void showMainMenu() {
        int choice;
        do {
            std::cout << "\n===== 智能鱼塘监控APP =====" << std::endl;
            std::cout << "1. 查看当前状态" << std::endl;
            std::cout << "2. 查看历史数据" << std::endl;
            std::cout << "3. 手动控制增氧机" << std::endl;
            std::cout << "4. 手动控制喂食机" << std::endl;
            std::cout << "5. 设置自动模式" << std::endl;
            std::cout << "6. 设置报警阈值" << std::endl;
            std::cout << "0. 退出" << std::endl;
            std::cout << "请选择操作: ";
            std::cin >> choice;
            
            switch (choice) {
                case 1:
                    monitor.displayCurrentStatus();
                    break;
                case 2:
                    monitor.displayHistoryData();
                    break;
                case 3:
                    controlAeratorMenu();
                    break;
                case 4:
                    controlFeederMenu();
                    break;
                case 5:
                    setAutoModeMenu();
                    break;
                case 6:
                    setThresholdMenu();
                    break;
                case 0:
                    std::cout << "退出APP" << std::endl;
                    break;
                default:
                    std::cout << "无效选择" << std::endl;
            }
        } while (choice != 0);
    }
    
private:
    void controlAeratorMenu() {
        int choice;
        std::cout << "\n--- 增氧机控制 ---" << std::endl;
        std::cout << "1. 开启增氧机" << std::endl;
        std::cout << "2. 关闭增氧机" << std::endl;
        std::cout << "0. 返回" << std::endl;
        std::cout << "请选择: ";
        std::cin >> choice;
        
        if (choice == 1) {
            monitor.controlAerator(true);
        } else if (choice == 2) {
            monitor.controlAerator(false);
        }
    }
    
    void controlFeederMenu() {
        int choice;
        std::cout << "\n--- 喂食机控制 ---" << std::endl;
        std::cout << "1. 开启喂食机" << std::endl;
        std::cout << "2. 关闭喂食机" << std::endl;
        std::cout << "0. 返回" << std::endl;
        std::cout << "请选择: ";
        std::cin >> choice;
        
        if (choice == 1) {
            monitor.controlFeeder(true);
        } else if (choice == 2) {
            monitor.controlFeeder(false);
        }
    }
    
    void setAutoModeMenu() {
        int choice;
        std::cout << "\n--- 自动模式设置 ---" << std::endl;
        std::cout << "1. 开启自动模式" << std::endl;
        std::cout << "2. 关闭自动模式" << std::endl;
        std::cout << "0. 返回" << std::endl;
        std::cout << "请选择: ";
        std::cin >> choice;
        
        if (choice == 1) {
            monitor.setAutoMode(true);
        } else if (choice == 2) {
            monitor.setAutoMode(false);
        }
    }
    
    void setThresholdMenu() {
        double temp, pH, oxygen;
        std::cout << "\n--- 报警阈值设置 ---" << std::endl;
        std::cout << "请输入温度阈值(℃): ";
        std::cin >> temp;
        std::cout << "请输入pH阈值: ";
        std::cin >> pH;
        std::cout << "请输入溶解氧阈值(mg/L): ";
        std::cin >> oxygen;
        
        monitor.setThresholds(temp, pH, oxygen);
    }
};

// 主函数
int main() {
    std::cout << "STM32智能鱼塘监控系统 - 上位机程序" << std::endl;
    
    // 创建监控系统实例
    FishPondMonitor monitor;
    
    // 启动监控
    monitor.startMonitoring();
    
    // 创建手机APP界面
    MobileApp app(monitor);
    
    // 显示主菜单
    app.showMainMenu();
    
    // 停止监控
    monitor.stopMonitoring();
    
    return 0;
}

模块代码设计

#include "stm32f10x.h"

// 引脚定义
#define DS18B20_GPIO_PORT    GPIOA
#define DS18B20_GPIO_PIN     GPIO_Pin_0
#define DS18B20_RCC          RCC_APB2Periph_GPIOA

#define RELAY_OXYGEN_GPIO    GPIOB
#define RELAY_OXYGEN_PIN     GPIO_Pin_0
#define RELAY_FEED_GPIO      GPIOB
#define RELAY_FEED_PIN       GPIO_Pin_1

#define pH_SENSOR_ADC_CH     ADC_Channel_1
#define DO_SENSOR_ADC_CH     ADC_Channel_2

// DS18B20函数声明
void DS18B20_Init(void);
void DS18B20_WriteByte(uint8_t data);
uint8_t DS18B20_ReadByte(void);
void DS18B20_Start(void);
float DS18B20_GetTemp(void);
static void DS18B20_DelayUs(uint16_t us);

// ADC函数声明
void ADC1_Init(void);
uint16_t ADC_GetValue(uint8_t channel);
float Get_pH_Value(void);
float Get_DO_Value(void);

// 继电器控制函数
void Relay_Init(void);
void OxygenPump_Ctrl(uint8_t state);
void FeedMachine_Ctrl(uint8_t state);

// 系统初始化
void System_Init(void) {
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
    
    DS18B20_Init();
    ADC1_Init();
    Relay_Init();
    
    // 初始化USART1用于ESP8266通信
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_CNF10);
    GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_CNF10_0;
    GPIOA->CRH |= GPIO_CRH_MODE9 | GPIO_CRH_MODE10;
    
    USART1->BRR = 0x1D4C; // 9600波特率
    USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}

// DS18B20温度传感器代码
void DS18B20_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(DS18B20_RCC, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure);
    
    DS18B20_GPIO_PORT->BSRR = DS18B20_GPIO_PIN;
}

static void DS18B20_DelayUs(uint16_t us) {
    us *= 8;
    while(us--);
}

void DS18B20_WriteByte(uint8_t data) {
    uint8_t i;
    for(i = 0; i < 8; i++) {
        if(data & 0x01) {
            // 写1
            DS18B20_GPIO_PORT->BRR = DS18B20_GPIO_PIN;
            DS18B20_DelayUs(2);
            DS18B20_GPIO_PORT->BSRR = DS18B20_GPIO_PIN;
            DS18B20_DelayUs(60);
        } else {
            // 写0
            DS18B20_GPIO_PORT->BRR = DS18B20_GPIO_PIN;
            DS18B20_DelayUs(60);
            DS18B20_GPIO_PORT->BSRR = DS18B20_GPIO_PIN;
            DS18B20_DelayUs(2);
        }
        data >>= 1;
    }
}

uint8_t DS18B20_ReadByte(void) {
    uint8_t i, data = 0;
    for(i = 0; i < 8; i++) {
        data >>= 1;
        DS18B20_GPIO_PORT->BRR = DS18B20_GPIO_PIN;
        DS18B20_DelayUs(2);
        DS18B20_GPIO_PORT->BSRR = DS18B20_GPIO_PIN;
        DS18B20_DelayUs(8);
        
        if(DS18B20_GPIO_PORT->IDR & DS18B20_GPIO_PIN) {
            data |= 0x80;
        }
        DS18B20_DelayUs(50);
    }
    return data;
}

void DS18B20_Start(void) {
    DS18B20_Init();
    
    // 复位
    DS18B20_GPIO_PORT->BRR = DS18B20_GPIO_PIN;
    DS18B20_DelayUs(480);
    DS18B20_GPIO_PORT->BSRR = DS18B20_GPIO_PIN;
    DS18B20_DelayUs(60);
    
    // 等待应答
    while(DS18B20_GPIO_PORT->IDR & DS18B20_GPIO_PIN);
    DS18B20_DelayUs(480);
    
    // 发送跳过ROM命令
    DS18B20_WriteByte(0xCC);
    // 发送温度转换命令
    DS18B20_WriteByte(0x44);
}

float DS18B20_GetTemp(void) {
    uint8_t tempL, tempH;
    int16_t temp;
    float temperature;
    
    DS18B20_Start();
    DS18B20_DelayUs(100000); // 等待转换完成
    
    DS18B20_Init();
    
    // 复位
    DS18B20_GPIO_PORT->BRR = DS18B20_GPIO_PIN;
    DS18B20_DelayUs(480);
    DS18B20_GPIO_PORT->BSRR = DS18B20_GPIO_PIN;
    DS18B20_DelayUs(60);
    
    while(DS18B20_GPIO_PORT->IDR & DS18B20_GPIO_PIN);
    DS18B20_DelayUs(480);
    
    // 发送跳过ROM命令
    DS18B20_WriteByte(0xCC);
    // 发送读温度命令
    DS18B20_WriteByte(0xBE);
    
    tempL = DS18B20_ReadByte();
    tempH = DS18B20_ReadByte();
    
    temp = (tempH << 8) | tempL;
    temperature = temp * 0.0625;
    
    return temperature;
}

// ADC初始化
void ADC1_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    
    // 使能GPIOA和ADC1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
    
    // 配置PA1(pH), PA2(DO)为模拟输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // ADC配置
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);
    
    // 使能ADC1
    ADC_Cmd(ADC1, ENABLE);
    
    // ADC校准
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
}

uint16_t ADC_GetValue(uint8_t channel) {
    ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_239Cycles5);
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    return ADC_GetConversionValue(ADC1);
}

float Get_pH_Value(void) {
    uint16_t adc_value = ADC_GetValue(pH_SENSOR_ADC_CH);
    float voltage = (adc_value * 3.3) / 4096.0;
    // pH值转换公式,根据实际传感器校准
    float pH_value = 7.0 + (voltage - 1.5) * 2.0;
    return pH_value;
}

float Get_DO_Value(void) {
    uint16_t adc_value = ADC_GetValue(DO_SENSOR_ADC_CH);
    float voltage = (adc_value * 3.3) / 4096.0;
    // 溶解氧转换公式,根据实际传感器校准
    float do_value = voltage * 5.0; // mg/L
    return do_value;
}

// 继电器控制
void Relay_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = RELAY_OXYGEN_PIN | RELAY_FEED_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 初始状态关闭
    GPIOB->BSRR = RELAY_OXYGEN_PIN | RELAY_FEED_PIN;
}

void OxygenPump_Ctrl(uint8_t state) {
    if(state) {
        RELAY_OXYGEN_GPIO->BRR = RELAY_OXYGEN_PIN; // 打开
    } else {
        RELAY_OXYGEN_GPIO->BSRR = RELAY_OXYGEN_PIN; // 关闭
    }
}

void FeedMachine_Ctrl(uint8_t state) {
    if(state) {
        RELAY_FEED_GPIO->BRR = RELAY_FEED_PIN; // 打开
    } else {
        RELAY_FEED_GPIO->BSRR = RELAY_FEED_PIN; // 关闭
    }
}

// 自动控制逻辑
void AutoControl(void) {
    float temperature = DS18B20_GetTemp();
    float pH_value = Get_pH_Value();
    float do_value = Get_DO_Value();
    
    // 自动控制增氧机
    if(do_value < 5.0) { // 溶解氧低于5mg/L时开启增氧机
        OxygenPump_Ctrl(1);
    } else if(do_value > 8.0) { // 溶解氧高于8mg/L时关闭增氧机
        OxygenPump_Ctrl(0);
    }
    
    // 可以根据需要添加其他自动控制逻辑
}

// 主循环
int main(void) {
    System_Init();
    
    while(1) {
        // 执行自动控制
        AutoControl();
        
        // 延时
        for(int i = 0; i < 1000000; i++);
    }
}

项目核心代码

#include "stm32f10x.h"

// 硬件模块定义
#define DS18B20_GPIO     GPIOA
#define DS18B20_PIN      GPIO_Pin_0

#define PH_SENSOR_GPIO   GPIOA
#define PH_SENSOR_PIN    GPIO_Pin_1

#define DO_SENSOR_GPIO   GPIOA  
#define DO_SENSOR_PIN    GPIO_Pin_2

#define RELAY_OXYGEN_GPIO    GPIOB
#define RELAY_OXYGEN_PIN     GPIO_Pin_0

#define RELAY_FEED_GPIO      GPIOB
#define RELAY_FEED_PIN       GPIO_Pin_1

#define ESP8266_USART        USART1
#define ESP8266_GPIO         GPIOA
#define ESP8266_TX_PIN       GPIO_Pin_9
#define ESP8266_RX_PIN       GPIO_Pin_10

// 全局变量
float water_temperature = 0.0;
float ph_value = 0.0;
float dissolved_oxygen = 0.0;
uint8_t auto_mode = 1;  // 1-自动模式, 0-手动模式
uint8_t oxygen_status = 0;  // 增氧机状态
uint8_t feed_status = 0;    // 喂食机状态

// 阈值设置
float TEMP_THRESHOLD_LOW = 18.0;
float TEMP_THRESHOLD_HIGH = 28.0;
float PH_THRESHOLD_LOW = 6.5;
float PH_THRESHOLD_HIGH = 8.5;
float DO_THRESHOLD_LOW = 5.0;

// 函数声明
void RCC_Configuration(void);
void GPIO_Configuration(void);
void USART_Configuration(void);
void ADC_Configuration(void);
void TIM_Configuration(void);
void NVIC_Configuration(void);

void DS18B20_ReadTemperature(void);
void PH_Sensor_Read(void);
void DO_Sensor_Read(void);
void ESP8266_SendData(void);
void ESP8266_ReceiveHandler(void);
void Control_Oxygen_Machine(void);
void Control_Feed_Machine(void);
void Process_APP_Command(uint8_t* command);

// 系统时钟配置
void RCC_Configuration(void)
{
    // 开启HSE
    RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    while(!(RCC->CR & RCC_CR_HSERDY));
    
    // FLASH预取指缓冲使能
    FLASH->ACR |= FLASH_ACR_PRFTBE;
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
    
    // HCLK = SYSCLK
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    // PCLK2 = HCLK
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    // PCLK1 = HCLK/2
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
    
    // PLL配置: PLLCLK = HSE * 9 = 72 MHz
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
    
    // 使能PLL
    RCC->CR |= RCC_CR_PLLON;
    while((RCC->CR & RCC_CR_PLLRDY) == 0);
    
    // 选择PLL作为系统时钟
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08);
    
    // 开启GPIO时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
    
    // 开启USART1时钟
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    
    // 开启ADC1时钟
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    
    // 开启TIM2时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
}

// GPIO配置
void GPIO_Configuration(void)
{
    // DS18B20 - PA0 输入
    GPIOA->CRL &= 0xFFFFFFF0;
    GPIOA->CRL |= 0x00000004;
    
    // pH传感器 - PA1 模拟输入
    GPIOA->CRL &= 0xFFFFFF0F;
    GPIOA->CRL |= 0x00000000;
    
    // 溶解氧传感器 - PA2 模拟输入  
    GPIOA->CRL &= 0xFFFFF0FF;
    GPIOA->CRL |= 0x00000000;
    
    // 继电器控制 - PB0, PB1 推挽输出
    GPIOB->CRL &= 0xFFFFFF00;
    GPIOB->CRL |= 0x00000011;
    
    // ESP8266 USART1 - PA9(TX) 复用推挽输出, PA10(RX) 浮空输入
    GPIOA->CRH &= 0xFFFFF00F;
    GPIOA->CRH |= 0x000004B0;
}

// USART配置
void USART_Configuration(void)
{
    // 波特率设置 115200
    USART1->BRR = 0x0271;
    
    // 使能USART, 发送使能, 接收使能, 接收中断使能
    USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
}

// ADC配置
void ADC_Configuration(void)
{
    // ADC1配置
    ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CONT;  // 开启ADC, 连续转换模式
    ADC1->CR1 = 0x00;
    
    // 采样时间设置
    ADC1->SMPR2 = 0x00000000;  // 通道1,2采样时间1.5周期
    
    // 规则序列配置
    ADC1->SQR1 = 0x00000000;   // 1个转换
    ADC1->SQR3 = 0x00000001;   // 通道1(pH)在序列1
}

// 定时器配置 - 用于定时采集数据
void TIM_Configuration(void)
{
    // TIM2配置 - 1秒定时
    TIM2->PSC = 7200 - 1;      // 72MHz/7200 = 10kHz
    TIM2->ARR = 10000 - 1;     // 10kHz/10000 = 1Hz
    
    // 使能更新中断
    TIM2->DIER |= TIM_DIER_UIE;
    
    // 启动定时器
    TIM2->CR1 |= TIM_CR1_CEN;
}

// NVIC配置
void NVIC_Configuration(void)
{
    // 设置中断优先级分组
    NVIC_SetPriorityGrouping(3);
    
    // 使能USART1中断
    NVIC_EnableIRQ(USART1_IRQn);
    NVIC_SetPriority(USART1_IRQn, 0);
    
    // 使能TIM2中断
    NVIC_EnableIRQ(TIM2_IRQn);
    NVIC_SetPriority(TIM2_IRQn, 1);
}

// 读取温度传感器
void DS18B20_ReadTemperature(void)
{
    // DS18B20读取温度实现
    // 这里简化实现,实际需要按照DS18B20协议编写
    water_temperature = 25.5;  // 示例温度值
}

// 读取pH值
void PH_Sensor_Read(void)
{
    // 启动ADC转换
    ADC1->SQR3 = 0x00000001;  // 选择通道1(pH传感器)
    ADC1->CR2 |= ADC_CR2_SWSTART;
    
    // 等待转换完成
    while(!(ADC1->SR & ADC_SR_EOC));
    
    // 读取ADC值并转换为pH值
    uint16_t adc_value = ADC1->DR;
    ph_value = (float)adc_value * 3.3 / 4096 * 2.0 + 6.0;  // 转换为pH值
}

// 读取溶解氧
void DO_Sensor_Read(void)
{
    // 启动ADC转换
    ADC1->SQR3 = 0x00000002;  // 选择通道2(溶解氧传感器)
    ADC1->CR2 |= ADC_CR2_SWSTART;
    
    // 等待转换完成
    while(!(ADC1->SR & ADC_SR_EOC));
    
    // 读取ADC值并转换为溶解氧值
    uint16_t adc_value = ADC1->DR;
    dissolved_oxygen = (float)adc_value * 3.3 / 4096 * 10.0;  // 转换为溶解氧值
}

// 控制增氧机
void Control_Oxygen_Machine(void)
{
    if(auto_mode)
    {
        // 自动模式:根据溶解氧阈值控制
        if(dissolved_oxygen < DO_THRESHOLD_LOW)
        {
            RELAY_OXYGEN_GPIO->BSRR = RELAY_OXYGEN_PIN;  // 开启增氧机
            oxygen_status = 1;
        }
        else
        {
            RELAY_OXYGEN_GPIO->BRR = RELAY_OXYGEN_PIN;   // 关闭增氧机
            oxygen_status = 0;
        }
    }
}

// 控制喂食机
void Control_Feed_Machine(void)
{
    // 喂食机主要在手动模式下控制
    // 自动喂食逻辑可以在这里扩展
}

// 通过ESP8266发送数据到服务器
void ESP8266_SendData(void)
{
    char buffer[128];
    
    // 格式化数据为JSON格式
    sprintf(buffer, "{\"temp\":%.1f,\"ph\":%.1f,\"do\":%.1f,\"oxygen\":%d,\"feed\":%d,\"auto\":%d}",
            water_temperature, ph_value, dissolved_oxygen, 
            oxygen_status, feed_status, auto_mode);
    
    // 发送数据
    for(int i = 0; buffer[i] != '\0'; i++)
    {
        USART1->DR = buffer[i];
        while(!(USART1->SR & USART_SR_TXE));
    }
}

// 处理APP命令
void Process_APP_Command(uint8_t* command)
{
    // 解析APP发送的命令
    if(strstr((char*)command, "OXYGEN_ON"))
    {
        RELAY_OXYGEN_GPIO->BSRR = RELAY_OXYGEN_PIN;
        oxygen_status = 1;
    }
    else if(strstr((char*)command, "OXYGEN_OFF"))
    {
        RELAY_OXYGEN_GPIO->BRR = RELAY_OXYGEN_PIN;
        oxygen_status = 0;
    }
    else if(strstr((char*)command, "FEED_ON"))
    {
        RELAY_FEED_GPIO->BSRR = RELAY_FEED_PIN;
        feed_status = 1;
    }
    else if(strstr((char*)command, "FEED_OFF"))
    {
        RELAY_FEED_GPIO->BRR = RELAY_FEED_PIN;
        feed_status = 0;
    }
    else if(strstr((char*)command, "AUTO_ON"))
    {
        auto_mode = 1;
    }
    else if(strstr((char*)command, "AUTO_OFF"))
    {
        auto_mode = 0;
    }
}

// USART1中断服务函数
void USART1_IRQHandler(void)
{
    if(USART1->SR & USART_SR_RXNE)
    {
        static uint8_t rx_buffer[64];
        static uint8_t rx_index = 0;
        
        uint8_t data = USART1->DR;
        
        if(data == '\n' || rx_index >= 63)
        {
            rx_buffer[rx_index] = '\0';
            Process_APP_Command(rx_buffer);
            rx_index = 0;
        }
        else
        {
            rx_buffer[rx_index++] = data;
        }
    }
}

// TIM2中断服务函数 - 定时采集数据
void TIM2_IRQHandler(void)
{
    if(TIM2->SR & TIM_SR_UIF)
    {
        TIM2->SR &= ~TIM_SR_UIF;
        
        // 读取所有传感器数据
        DS18B20_ReadTemperature();
        PH_Sensor_Read();
        DO_Sensor_Read();
        
        // 自动控制增氧机
        Control_Oxygen_Machine();
        
        // 发送数据到服务器
        ESP8266_SendData();
    }
}

int main(void)
{
    // 系统初始化
    RCC_Configuration();
    GPIO_Configuration();
    USART_Configuration();
    ADC_Configuration();
    TIM_Configuration();
    NVIC_Configuration();
    
    // 初始化继电器状态 - 全部关闭
    RELAY_OXYGEN_GPIO->BRR = RELAY_OXYGEN_PIN;
    RELAY_FEED_GPIO->BRR = RELAY_FEED_PIN;
    
    while(1)
    {
        // 主循环 - 中断驱动模式,主循环可以处理其他任务
        // 例如:本地显示、按键检测等
        
        // 延时
        for(int i = 0; i < 1000000; i++);
    }
}

总结

基于STM32的智能鱼塘监控系统,成功实现了对鱼塘水质的智能化管理。该系统通过集成多种传感器,实时监测水体温度、pH值和溶解氧等关键参数,确保鱼塘环境处于最佳状态。用户可通过手机APP远程查看数据并手动控制增氧机和喂食机,同时系统支持自动模式,根据预设阈值自动调节设备运行,大大提升了养殖效率与便捷性。

在硬件方面,系统以STM32F103系列单片机为核心,结合DS18B20水温传感器、pH传感器和溶解氧传感器采集数据,并通过ESP8266 Wi-Fi模块实现无线通信。继电器模块负责控制增氧机和喂食机的启停,而可选用的LCD1602液晶显示屏则为本地显示提供了便利。整体设计紧凑可靠,为现代水产养殖提供了高效、低成本的解决方案。

该系统不仅实现了水质数据的实时监控与远程管理,还通过自动控制功能减少了人工干预,保障了鱼塘的稳定运行。历史数据查询和设备状态跟踪功能进一步增强了系统的实用性,使其成为提升养殖效益的重要工具。

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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