当前位置: 首页 > news >正文

【STM32项目开源】基于STM32的智能鱼缸养殖系统

目录

一、设计背景和意义

1.1设计背景

1.2设计意义

二、实物效果展示

2.1实物图片

2.2实物演示视频

三、硬件功能简介

3.1项目功能详解

3.2元器件清单

四、主框图与软件流程图

五、硬件PCB展示

六、软件程序设计

七、项目资料包内容

         资料获取:查看主页介绍“充哥单片机设计”


一、设计背景和意义

1.1设计背景

        随着智能化、信息化技术的快速发展,物联网(IoT)、嵌入式系统和云计算等技术正不断渗透到人们的日常生活中,推动传统行业向智能化方向转型。鱼缸养殖作为家庭休闲娱乐和小型生态系统管理的一种形式,越来越受到城市居民的青睐。然而,传统鱼缸管理仍高度依赖人工,诸如水质变化监测、水温控制、定时投喂、充氧以及换水等环节均需要人为干预。这不仅大大增加了操作的复杂性和人力成本,同时也对养殖者的经验和时间管理能力提出较高要求,若未能及时维护,极易引发水质恶化、鱼类应激反应或死亡等问题。

1.2设计意义

        本课题所研究的“智能鱼缸养殖系统”,旨在通过现代嵌入式技术、传感器技术、无线通信与云平台服务相结合,实现鱼缸环境的智能监测与自动化管理。这种系统化、模块化的智能养殖解决方案,不仅可以降低用户管理难度、提高养殖成功率,还可以实现远程控制、历史数据分析和精准干预等功能,提升整个系统的可用性、可控性和用户体验。该课题是嵌入式系统设计、传感器数据处理、无线通信协议实现和物联网平台应用等多个技术领域的交叉点,具有较强的工程综合性和创新实践价值。通过该系统的构建与实现,能够深入探索STM32单片机在智能设备中的应用能力,研究如何实现高效的多传感器数据融合与控制策略制定,同时探索轻量级WiFi模块(如ESP8266)与云平台之间的数据交互方式,具有较强的研究推广意义。本课题涵盖嵌入式编程、电路设计、云平台对接、前后台联调、系统联动测试等多个技能模块,能够有效锻炼学生的软硬件协同开发能力、问题分析与解决能力、系统集成与调试能力,是高校实践教学的重要补充内容。同时,该项目的研究成果还可为智能农业、智能水产、远程生态监测等更广泛的智能控制应用场景提供参考与借鉴,具有较强的教学与科研拓展潜力。

二、实物效果展示

2.1实物图片

2.2实物演示视频

【开源】基于STM32的智能鱼缸养殖系统

三、硬件功能简介

3.1项目功能详解

  1. 传感器检测:检测水温、超声波水位、TDS水质、光照强度数据。
  2. 数据显示:0.96OLED屏幕显示全部的传感器数据以及传感器的阈值等数据。
  3. 执行机构:控制LED灯、步进电机(喂食)、加水、放水、加热、充氧等开关。
  4. 接入云平台:系统通过ESP8266 WIFI联网后,接入机智云平台。
  5. App远程查看:通过App远程监控全部传感器数据;App远程控制LED和步进电机。
  6. App远程控制:App控制LED灯、步进电机(喂食)、加水、放水、加热、充氧等开关。
  7. 阈值数据设定:系统通过按键设定阈值,也可以通过手机App远程设定。
  8. 定时投喂:可以谁设定时间,实现周期开启投喂开关。
  9. 定时充氧:设定充氧开关,实现周期性开启关闭充氧,
  10. 模式切换:可以通过按键或者手机App实现自动/手动模式的切换。
  11. 手动模式:通过手机App或按键控制LED灯、步进电机(喂食)、加水、放水、加热、充氧等开关。
  12. 自动模式:检测到的水位低于阈值,自动开启加水水泵;检测到的水质低于水质阈值自动开启排水和加水的水泵。检测到的水温低于水温阈值自动开启加片加热。根据设定的时间周期性开启投喂和充氧开关。
  13. 声光报警:当前的水温高于水温阈值会自动开启声光报警。

3.2元器件清单

  1. 主控STM32F103C8T6最小系统板
  2. 0.96OLED显示屏幕
  3. JDY31-SPP蓝牙模块
  4. 超声波水位传感器
  5. TDS电导率水质传感器
  6. DS18B20水温传感器
  7. 继电器
  8. 加热片
  9. 加水水泵
  10. 排水水泵
  11. 充氧泵

四、主框图与软件流程图

主框图

流程图

五、硬件PCB展示

六、软件程序设计

#include "stm32f10x.h"
#include "sys.h"
#include "led.h"
#include "bmp.h"
#include "oled.h"
#include "adc.h"
#include "ds18b20.h"
#include "timer.h"
#include "delay.h"
#include "usart.h"
#include "usart2.h"
#include "cJSON.h"
#include "sr04.h"int LED_STATUS = 0;
int FAN_STATUS = 0;char WIFIName[] = "ESP8266-WIFI";
char WIFIpwd[] = "12345678";int temp_up = 35,temp_down = 15;     // 温度上下限
int tds_up = 90,tds_down = 0;      // 水质上下限
int level_up = 5,level_down = 60;  // 水位上下限int maxHighLevel = 5;                // 换水最高水位int feedTime = 30;               // 喂食时间
int cacheFeedTime = 30;          // 缓存喂食时间     
int sendDataTime = 3;            // 数据发送时间
int cacheSendTime = 3;           // 缓存数据发送时间#define LED   PAout(2)     // LED
#define BUZZ  PAout(4)     // 蜂鸣器#define JD1		PAout(8)     	// 继电器1-抽水
#define JD2   PAout(5)			// 继电器2-放水
#define JD3   PAout(6)			// 继电器3-加热
#define JD4   PAout(7)     	// 继电器4-降温#define KEY_EDIT PBin(13)   // 设置按钮
#define KEY_NEXT PBin(14)  // 切换按钮
#define KEY_SWIT PBin(15)  // 下一页按钮
#define KEY_ADD  PAin(11)  // 加一按钮
#define KEY_DEC  PBin(12)  // 减一按钮#define TEST PCout(13)#define SG90_CLOSE  175    // 舵机关闭
#define SG90_OPEN   185    // 舵机打开// 上位机数据处理
int connectFlag = 0;       // 连接成功标志位
int handleFlag = 0;        // 判断上位机发送的数据需要处理哪一个
int sendFlag = 0;          // 定时器时间到了该位置一表示发送数据
int initFlag = 0;          // ESP8266初始化成功标志位
int paramFlag = 1;         // 是否开启参数检查
int changeWaterFlag = 0;   // 换水标志位int feedFlag = 0;          // 是否喂食
int feedEndFlag = 0;       // 喂食结束unsigned char temp = 0,level = 0; // 温度,湿度void paramCheck( void );             // 检查参数是否超过
void handleData( void );             // 上位机数据处理
void co2Process(void);               // CO2数据处理
void DisplayUI( void );              // 固定页面UI渲染
void paramEdit( void );              // 阈值参数设置
void editUiDisplay( int pageIndex ); // 设置页面UI初始化
void runAlter(int cursor,int count); // 执行参数修改extern char *USARTx_RX_BUF;         // 串口数据缓存
extern float TDS_value;	int main(void)
{int time;delay_init();LED_Init();OLED_Init();Adc_Init();DS18B20_Init();	                  // 温度初始化HC_SR04Config();                  // 超声波初始化uart_init(115200);timeInit(4999,7199);              // 72M 0.1ms 500ms 串口数据初始化、timeSendInit(9999,7199);          // 72m 0.1ms 1s    发送数据定时timePwmInit(199,7199);            // PWM-> CH3->PA2  CH4->PA3  (调脉宽)TIM_SetCompare4(TIM2,100);TIM_SetCompare4(TIM2,SG90_CLOSE); // 关闭喂食OLED_ShowChLength(38,16,47,3);    // 显示启动中	ESP8266Init(WIFIName,WIFIpwd);OLED_Clear();while(1){DisplayUI();if( time++ > 5 ){time = 0;temp  =  getTemperture();           // 获取温度delay_ms(1000);delay_ms(1000);temp  =  getTemperture();           // 获取温度TDS_Value_Conversion();             // 获取TDS水质值}level =  Getlength();         // 获取水位OLED_ShowNum(45,0,temp,2,16,1);OLED_ShowNum(45,16,level,3,16,1);OLED_ShowNum(45,32,TDS_value,3,16,1);OLED_ShowNum(76,48,cacheFeedTime,3,16,1);OLED_Refresh();// 开始喂食if( feedFlag ){TIM_SetCompare4(TIM2,SG90_OPEN);// 等待喂食结束if( feedEndFlag ){feedFlag = 0;feedEndFlag = 0;feedTime = cacheFeedTime;TIM_SetCompare4(TIM2,SG90_CLOSE);}}// 进入设置页面if( !KEY_EDIT ){      while( !KEY_EDIT ); // 防抖paramEdit();        // 进入参数设置// 刷新参数提示按钮(每次进入设置以后出来这个按钮没有,需要更新一下)if( !paramFlag ) OLED_ShowChLength(105,2,62,1);else OLED_ShowString(105,2,"  ",16,1);}// 切换参数提醒设置if( !KEY_NEXT ){      while( !KEY_NEXT );paramFlag = !paramFlag;  if( !paramFlag ){   // 关闭提示JD2 = 0;JD3 = 0;JD4 = 0;JD1 = 0;BUZZ = 0;OLED_ShowChLength(105,2,62,1);}else{OLED_ShowString(105,2,"  ",16,1);}OLED_Refresh();			}// 上位机更改数据if( handleFlag ) handleData();// 3s上传一次数据if( sendFlag && 1){      ESP8266Pub(temp,level,TDS_value);sendFlag = 0;                 // 重置标志位sendDataTime = cacheSendTime; // 刷新发送时间}// 检查参数是否超出范围(开启了参数检查)if( paramFlag ) paramCheck();   delay_ms(100);}
}// 绘制固定不变的UI画面
void DisplayUI( void ){// 显示汉字OLED_ShowChLength(0,0,11,2);OLED_ShowChLength(0,16,87,2);OLED_ShowChLength(0,32,67,2);OLED_ShowChLength(0,48,75,4);// 汉字冒号OLED_ShowString(33,0,":",16,1);OLED_ShowString(33,16,":",16,1);OLED_ShowString(33,32,":",16,1);OLED_ShowString(65,48,":",16,1);// 单位OLED_ShowChLength(65,1,21,1);OLED_ShowString(74,16,"CM",16,1);OLED_ShowString(74,32,"PPM",16,1);OLED_ShowString(105,48,"S",16,1);}// 处理阈值参数
void handleData( void ){cJSON *data = NULL;cJSON *upData = NULL;cJSON *downData = NULL;data = cJSON_Parse( (const char *)USARTx_RX_BUF );switch( handleFlag ){case 1:LED = 1;break;case 2:LED = 0;break;case 3:break;case 4:break;case 5:	upData = cJSON_GetObjectItem(data,"temp_up");downData = cJSON_GetObjectItem(data,"temp_down");temp_up = upData->valueint;temp_down = downData->valueint;break;case 6:upData = cJSON_GetObjectItem(data,"level_up");downData = cJSON_GetObjectItem(data,"level_down");level_up = upData->valueint;level_down = downData->valueint;break;case 7:upData = cJSON_GetObjectItem(data,"tds_up");downData = cJSON_GetObjectItem(data,"tds_down");tds_up = upData->valueint;tds_down = downData->valueint;break;}// USART_SendString(USART2,(char *)USARTx_RX_BUF);clearCache();cJSON_Delete(data);handleFlag = 0;USART_RX_STA = 0;
}void paramEdit( void ){int pageIndex = 0,cursor = 0,alterTip = 0,beforeCursor = 0;// 初始化UIOLED_Clear();OLED_ShowString(112,0,"<",16,1);while( 1 ){editUiDisplay(pageIndex); // UI显示if( !KEY_NEXT ){while( !KEY_NEXT );beforeCursor = (cursor % 4) * 16;            // 拿到之前的修改显示位置cursor++;		                                  cursor = (cursor % 4) + 4 * pageIndex;   		 // 得到第几个数据alterTip = (cursor % 4) * 16;            		 // 提示按钮的显示行OLED_ShowString(112,beforeCursor," ",16,1);  // 显示提示<OLED_ShowString(112,alterTip,"<",16,1);      // 显示提示< }if( !KEY_SWIT ){                  // 按下页面切换按钮while(!KEY_SWIT);pageIndex = (++pageIndex)%2;    // 切换页面// pageIndex = !pageIndex;      // 切换页面cursor = 4 * pageIndex;         // 拿到参数的游标 OLED_Clear();OLED_ShowString(112,0,"<",16,1);// 重新显示提示按钮OLED_Refresh();			}if( !KEY_ADD ){while(!KEY_ADD);runAlter(cursor,1);}if( !KEY_DEC ){while(!KEY_DEC);runAlter(cursor,-1);}if( !KEY_EDIT ){                  // 按下设置按钮推出当前页面while( !KEY_EDIT );OLED_Clear();break;}if( handleFlag ) handleData();OLED_Refresh(); }
}// 执行修改param1执行类型 游标
void runAlter(int cursor,int count){int countResult;switch( cursor ){case 0:countResult = temp_up + count;temp_up = countResult>0?countResult:0;break;case 1:countResult = temp_down + count;temp_down = countResult>0 ? countResult : 0;break;case 2:countResult = level_up + count;level_up = countResult>0 ? countResult : 0;break;case 3:countResult = level_down + (count * 5);level_down = countResult>0 ? countResult : 0;break;case 4:countResult = tds_up + (count * 10);tds_up = countResult>0 ? countResult : 0;break;case 5:countResult = tds_down + (count * 10);tds_down = countResult>0 ? countResult : 0;break;case 6:countResult = cacheFeedTime + (count * 5);cacheFeedTime = countResult>0 ? countResult : 0;break;	case 7:break;}
}// 设置初始化UI
void editUiDisplay( int pageIndex ){// 如果是第一页显示第一页if( pageIndex == 0){// 显示汉字OLED_ShowChLength(0,0,23,4);OLED_ShowChLength(0,16,27,4);OLED_ShowChLength(0,32,83,4);OLED_ShowChLength(0,48,87,4);// 显示冒号OLED_ShowString(65,0,":",16,1);OLED_ShowString(65,16,":",16,1);OLED_ShowString(65,32,":",16,1);OLED_ShowString(65,48,":",16,1);// 显示测量值OLED_ShowNum(76,0,temp_up,2,16,1);OLED_ShowNum(76,16,temp_down,2,16,1);OLED_ShowNum(76,32,level_up,2,16,1);OLED_ShowNum(76,48,level_down,2,16,1);return;}if( pageIndex == 1 ){// 显示第二页OLED_ShowChLength(0,0,67,4);OLED_ShowChLength(0,16,71,4);OLED_ShowChLength(0,32,75,4);OLED_ShowChLength(0,48,79,4);// 显示冒号OLED_ShowString(65,0,":",16,1);OLED_ShowString(65,16,":",16,1);OLED_ShowString(65,32,":",16,1);OLED_ShowString(65,48,":",16,1);// 显示测量值OLED_ShowNum(76,0,tds_up,4,16,1);OLED_ShowNum(76,16,tds_down,4,16,1);OLED_ShowNum(76,32,cacheFeedTime,4,16,1);OLED_ShowNum(76,48,00,4,16,1);}OLED_Refresh();}// 检查个参数是否超出范围
void paramCheck( void ){int buzzFlag; // 保存蜂鸣器的状态buzzFlag = 0;if( !changeWaterFlag ){// 1.检查水位是否超过范围if( level && level <= level_up ){JD2 = 1;  // 继电器1工作(放水)JD1 = 0;  // 继电器1停止(停止抽水)// buzzFlag = 1;}else if( level && level >= level_down ){JD2 = 0;  // 继电器1停止(停止放水)JD1 = 1;  // 继电器1工作(抽水)// buzzFlag = 1;}else{JD2 = 0;  // 继电器1停止(停止放水)JD1 = 0;  // 继电器1停止(停止抽水)}}// 2.检查温度是否超过范围if( temp && temp >= temp_up){JD4 = 1;  // 继电器3工作(散热)buzzFlag = 1;}else if( temp && temp <= temp_down ){JD3 = 1;  // 继电器1工作(加热)buzzFlag = 1;}else{JD3 = 0;  // 继电器2停止(停止加热)JD4 = 0;  // 继电器3停止(停止散热)}// 3.检查水质是否超过范围if( TDS_value && TDS_value >= tds_up ){if( changeWaterFlag == 0) {changeWaterFlag = 1;	JD2 = 0;JD1 = 0;}}// 水质超过阈值开始放水if( changeWaterFlag == 1 ){JD2 = 1;    //开始放水if( level >= level_down ){changeWaterFlag = 2;}}else if( changeWaterFlag == 2 ){JD2 = 0;  // 停止放水JD1 = 1;  // 开始抽水if( level && (level <= maxHighLevel) ){JD1 = 0;  // 停止抽水changeWaterFlag = 0;}}// 控制蜂鸣器if( buzzFlag ){BUZZ = 1;}else{BUZZ = 0;}
}

七、项目资料包内容

         资料获取:查看主页介绍“充哥单片机设计”

http://www.dtcms.com/a/414407.html

相关文章:

  • 【小迪安全v2023】学习笔记集合 --- 持续更新
  • Django - DRF
  • Python全方位处理XML指南:解析、修改与重写实战
  • LabVIEW实现B样条曲线拟合
  • 门户网站系统建设招标文件中国建设教育协会网站培训中心
  • 常熟网站网站建设在线教育自助网站建设平台
  • 【Linux】深入探索多线程编程:从互斥锁到高性能线程池实战
  • 广州手机网站建设报价沧州市政务服务大厅
  • .net网站开发程序员深圳专业网站建设公司
  • DedeCMS命令执行复现研究 | CVE-2025-6335
  • BJDCTF2020
  • LeetCode:239. 滑动窗口最大值
  • 文件上传漏洞(二)iis6.0 CGI漏洞
  • PHP的json_encode()函数了解
  • LeetCode:76.数据流的中位数
  • 瑞达恒建筑网站网站设计技术大全
  • 32.Linux NFS 服务
  • ubuntu?centos?还是 redhat?Linux 系统选哪个?
  • Rich库演示教程
  • 买网站西安关键词优化平台
  • 构建质量的堡垒:一文读懂单元测试、集成测试、系统测试与回归测试
  • 深入MySQL、JVM与Maven核心原理​
  • MySQL中的数据去重,该用DISTINCT还是GROUP BY?
  • 低空物流自动驾驶机器人
  • 自动驾驶中的传感器技术54——USS(0)
  • 使用虚幻引擎(UE5)打造黑夜场景氛围
  • 嵌入式学习笔记3.基于寄存器方式控制GPIO
  • 自动驾驶中的传感器技术53——Radar(14)
  • 杭州网站推广技巧十大跨境电商公司
  • Boost电路项目实战:从原理到实战全解析(含电流环电压环)