基于STM32的智能鱼塘监控系统
项目开发背景
随着水产养殖业的快速发展,鱼塘养殖作为重要的农业生产方式,在保障食品供应和促进农村经济中扮演着关键角色。然而,传统鱼塘管理主要依赖人工经验,养殖户需要频繁现场检测水质参数,如温度、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液晶显示屏则为本地显示提供了便利。整体设计紧凑可靠,为现代水产养殖提供了高效、低成本的解决方案。
该系统不仅实现了水质数据的实时监控与远程管理,还通过自动控制功能减少了人工干预,保障了鱼塘的稳定运行。历史数据查询和设备状态跟踪功能进一步增强了系统的实用性,使其成为提升养殖效益的重要工具。
- 点赞
- 收藏
- 关注作者
评论(0)