【STM32项目】智能鱼缸(版本3)
基于STM32的智能鱼缸设计 本设计实现了鱼缸水质智能监测与控制系统,采用STM32F103C8T6作为主控芯片,配备多种传感器(pH、浊度、水位、温度)和WiFi模块(ESP8266)。系统具有三种工作模式:远程模式(通过手机APP控制)、手动模式(按键操作)和自动模式(根据预设阈值自动调节)。主要功能包括:实时监测水质参数、自动控制水泵/加热器、异常报警等。通过OLED显示屏直观显示各项参数,

✌️✌️大家好,这里是5132单片机毕设设计项目分享,今天给大家分享的是基于《基于STM32的智能鱼缸设计》。
目录
一、系统功能
2.1、硬件清单
STM32F103C8T6 最小核心控制板 + OLED 显示屏 + ESP8266-01s + 继电器(3 个)+pH 传感器 + 浊度传感器 + 水位传感器 + DS18B20 温度传感器 + 声光报警模块(绿色 LED 灯 + 蜂鸣器)+ 后备电池 + 舵机 + 按键(4 个)
2.2、功能介绍
(1)STM32F103C8T6 最小核心控制板:作为系统的核心控制单元,负责协调和控制整个智能鱼缸水质净化系统的运行。
(2)OLED 显示屏:用于显示时间、控制模式、水位、pH 值、浊度以及温度等参数,让用户能够直观地了解鱼缸的各项数据。
(3)ESP8266-01s:连接云平台,实现手机 APP 对鱼缸设备的远程控制,使用户可以在远程对鱼缸进行操作和监控。
(4)继电器(3 个):分别控制排水泵、补水泵以及加热器,通过继电器的通断来实现对这三个设备的开关控制。
(5)pH 传感器:用于测量鱼缸水质的 pH 值,实时监测水质的酸碱度变化。
(6)浊度传感器:测量水的浊度,反映水质的浑浊程度,以便及时了解水质情况。
(7)水位传感器:检测鱼缸的水位高度,为水位控制提供数据支持。
(8)DS18B20 温度传感器:测量水的温度,确保鱼缸内水温在适宜的范围内。
(9)声光报警模块(绿色 LED 灯 + 蜂鸣器):当检测到的参数(如 pH 值、浊度、温度等)超出设定阈值时,发出声光报警信号,提醒用户注意。
(10)后备电池:在主电源断电时,为系统提供备用电源,保证系统的部分功能能够继续运行。
(11)舵机:模拟净化系统的运行,可能用于控制某些净化装置的动作。
(12)按键(4 个):第一个按键为模式切换按键,用于在远程模式、手动模式和自动模式之间进行切换;后面三个按键在不同的模式下具有不同的功能,如手动模式下控制舵机、补水泵、排水泵、加热器等设备,以及在阈值设置时进行加减操作。
2.3、控制模式
(1)远程模式:上电后可能默认进入该模式(或需通过按键切换),通过 ESP8266-01s 连接云平台,用户可以通过手机 APP 远程控制排水泵、补水泵、声光报警、加热器等设备的开关,同时实时获取温度、水位、浊度、pH 值等数据,并在 OLED 显示屏上显示时间、控制模式及各项参数。
(2)手动模式:通过第一个按键切换到手动模式,此时通过后面三个按键来控制设备。第一个按键控制舵机,第二个按键按一下打开补水泵,再按一下打开排水泵,再按一下全部关闭,第三个按键控制加热器的开关。
(3)自动模式:通过第一个按键切换到自动模式,系统根据各传感器的检测值与设定阈值的对比自动执行相应动作:
- 水位控制:当水位小于水位下限阈值时,打开补水泵;当水位大于水位上限阈值时,关闭补水泵,打开排水泵;当水位在上下限阈值之间时,两个水泵都关闭。
- pH 值报警:当 pH 值小于 pH 阈值时,声光报警模块发出报警信号。
- 浊度报警:当浊度大于浊度阈值时,声光报警模块发出报警信号。
- 温度控制:当采集的温度小于温度阈值时,打开加热器;当温度大于等于温度阈值时,关闭加热器。
此外,系统支持通过按键进入阈值设置界面,对各参数的阈值进行设置,第一个按键用于切换阈值,第二个按键用于加,第三个按键用于减。
二、演示视频和实物
基于STM32的鱼缸水质净化系统

三、系统设计框图

四、软件设计流程图

五、原理图



六、主程序
#include "sys.h" //头文件
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "usart3.h"
#include "gizwits_product.h"
#include "Key.h"
#include "Buzzer.h"
#include "OLED.h"
#include "AD.h"
#include "MyRTC.h"
#include "Servo.h"
#include "ds18b20.h"
uint8_t KeyNum; //存储按键值
uint32_t bufe[10]; //存储传感器采集的数据
uint16_t AD0, AD1, AD2, AD3; //存储5路ADC值
uint32_t TempYu = 25;
uint32_t ShuiWeiYu_Xia = 10;
uint32_t ShuiWeiYu_Shang = 70;
uint32_t ZhuoYu = 70;
uint32_t PHYu = 5;
short temperature; //存放温湿度
u8 state, state2 = 2, state2_1, state2_2, state3; //按键状态标志
u8 t = 0; //传感器读取时间间隔
u8 flag; //远程控制标志
u8 flag2 = 0, flag1, flag3;
uint16_t RTC_Time[] = {0, 0, 0};
uint16_t RTC_Time1[] = {7, 0, 0}; //定时时间---开
uint16_t RTC_Time2[] = {19, 0, 0}; //定时时间---关
u8 T_state, T_state1, qingping = 1, state_dingshi_yu_guan, state_dingshi_yu_kai, state_dingshi_yu_switch, state3_1;
float PH;
extern void TimeSet(void);
extern void TimeRead(void);
extern void DingShiMoShi(void);
extern void YuZhiSet(void);
extern void ChuangGan(void);
void MY_Gizwits_Init(void) //机智云初始化函数
{
TIM3_Int_Init(9, 7199); //1MS系统定时
usart3_init(9600);//WIFI初始化
memset((uint8_t *)¤tDataPoint, 0, sizeof(dataPoint_t)); //设备状态结构体初始化
gizwitsInit();//环形缓冲区初始化
gizwitsSetMode(2); //设置模式
userInit();
}
u16 Get_Adc_Average(u8 ADC_CHx, u8 times)
{
u32 temp_val = 0;
u8 t;
for (t = 0; t < times; t++)
{
temp_val += AD_GetValue(ADC_CHx);
//SYSTICK_DelayMs(5);
}
return temp_val / times;
}
void shoudong()
{
TimeRead();
if (KeyNum == 2) //按键
{
delay_ms(20);
if (KeyNum == 2)
{
state2++;
if (state2 > 1)
{
state2 = 0;
}
}
}
if (state2 == 0)
{
Servo_SetAngle(90);//外设操作
}
if (state2 == 1)
{
Servo_SetAngle(0);//外设操作
}
if (KeyNum == 3) //按键
{
delay_ms(20);
if (KeyNum == 3)
{
state2_1++;
if (state2_1 > 2)
{
state2_1 = 0;
}
}
}
if (state2_1 == 1)
{
BuShuiBen_ON();//外设操作
PaiShuiBen_OFF();
}
if (state2_1 == 0)
{
BuShuiBen_OFF();//外设操作
PaiShuiBen_OFF();
}
if (state2_1 == 2)
{
BuShuiBen_OFF();//外设操作
PaiShuiBen_ON();
}
if (KeyNum == 4) //按键
{
delay_ms(20);
if (KeyNum == 4)
{
state2_2++;
if (state2_2 > 1)
{
state2_2 = 0;
}
}
}
if (state2_2 == 1)
{
JiaRe_ON();//外设操作
}
if (state2_2 == 0)
{
JiaRe_OFF();//外设操作
}
}
void zhidong()
{
if (bufe[0] < ShuiWeiYu_Xia)
{
BuShuiBen_ON();
PaiShuiBen_OFF();
}else if (bufe[0] > ShuiWeiYu_Shang)
{
PaiShuiBen_ON();
BuShuiBen_OFF();
}else
{
PaiShuiBen_OFF();
BuShuiBen_OFF();
}
if (bufe[3]/10 < TempYu)
{
JiaRe_ON();
}
else
{
JiaRe_OFF();
}
if ((bufe[1]/10 < PHYu) || (bufe[2] > ZhuoYu))
{
Buzzer_Turn();
}
else
{
Buzzer_OFF();
}
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(9600); //串口初始化为9600
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
Buzzer_Init(); //下面为外设初始化
OLED_Init();
Key_Init();
AD_Init();
MyRTC_Init();
Servo_Init(); //舵机初始化,并设置舵机初始角度
while (DS18B20_Init()) //DS18B20初始化
{
printf("ds18b20 success!");
delay_ms(200);
}
MY_Gizwits_Init(); //机智云初始化
while (1)
{
userHandle(); //数据上传
gizwitsHandle((dataPoint_t *)¤tDataPoint); //后台处理,必须放在while里
if (t % 10 == 0)
{
AD0 = AD_GetValue(ADC_Channel_0); //水位传感器 PA0
if (AD0 > 4000)AD0 = 4000;
bufe[0] = (u8)(AD0 / 40);
AD2 = Get_Adc_Average(ADC_Channel_2, 10);
PH = (float)AD2 * (3.3 / 4096); //读取ADC通道4的值
PH = -5.7541 * PH + 16.654; //输出电压范围0~3V3 因为STM32的ADC参考电压是3.3V
//将ADC的原始值(adcx)转换为电压值。这里假设ADC的参考电压是3.3V,并且ADC的位数是12位(即最大值为4096)。
bufe[1] = PH * 10;
AD3 = AD_GetValue(ADC_Channel_3); //浊度传感器 PA3
if (AD3 > 4000)AD3 = 4000;
bufe[2] = (u8)(100 - (AD3 / 40));
temperature = DS18B20_Get_Temp();
bufe[3] = temperature;
}
t++;
KeyNum = Key_GetNum();
if (KeyNum == 1)
{
qingping = 0;
state2 = 2,
delay_ms(20);
if (KeyNum == 1)
{
state++;
if (state > 3)
{
state = 0;
}
}
}
if (state == 0) //远程模式
{
if (qingping == 0)
{
OLED_Clear();
qingping = 1;
}
TimeRead();
ChuangGan();
OLED_ShowChinese(1, 7, 49);
OLED_ShowChinese(1, 8, 50);
}
if (state == 2) //自动模式
{
OLED_ShowChinese(1, 7, 51);
OLED_ShowChinese(1, 8, 52);
TimeRead();
zhidong();
ChuangGan();
}
if (state == 1) //手动模式
{
OLED_ShowChinese(1, 7, 18);
OLED_ShowChinese(1, 8, 52);
ChuangGan();
shoudong();
}
if (state == 3) //阈值设置
{
if (qingping == 0)
{
OLED_Clear();
qingping = 1;
}
YuZhiSet();
}
}
}
void TimeSet() //设置时间
{
if (KeyNum == 2) //PB10
{
delay_ms(20);
if (KeyNum == 2)
{
T_state++;
if (T_state > 2)
{
T_state = 0;
}
}
}
if (T_state == 0) //时间显示模式
{
MyRTC_ReadTime();
OLED_ShowNum(1, 5, MyRTC_Time[3], 2); //时
OLED_ShowString(1, 7, ":");
OLED_ShowNum(1, 8, MyRTC_Time[4], 2); //分
OLED_ShowString(1, 10, ":");
OLED_ShowNum(1, 11, MyRTC_Time[5], 2); //秒
RTC_Time[0] = MyRTC_Time[3];
RTC_Time[1] = MyRTC_Time[4];
RTC_Time[2] = MyRTC_Time[5];
}
if (T_state == 1) //修改时间
{
if (KeyNum == 5)
{
delay_ms(20);
if (KeyNum == 5)
{
T_state1++;
if (T_state1 > 2)
{
T_state1 = 0;
}
}
}
if (T_state1 == 0) //修改时
{
if (KeyNum == 4)RTC_Time[0]++;
if (KeyNum == 3)RTC_Time[0]--;
if (RTC_Time[0] > 23 & RTC_Time[0] < 100)RTC_Time[0] = 0;
if (RTC_Time[0] > 100)RTC_Time[0] = 23;
OLED_ShowNum(1, 5, RTC_Time[0], 2); //时
}
if (T_state1 == 1) //修改分
{
if (KeyNum == 4)RTC_Time[1]++;
if (KeyNum == 3)RTC_Time[1]--;
if (RTC_Time[1] > 59 & RTC_Time[1] < 100)RTC_Time[1] = 0;
if (RTC_Time[1] > 100)RTC_Time[1] = 59;
OLED_ShowNum(1, 8, RTC_Time[1], 2); //时
}
if (T_state1 == 2) //修改秒
{
if (KeyNum == 4)RTC_Time[2]++;
if (KeyNum == 3)RTC_Time[2]--;
if (RTC_Time[2] > 59)RTC_Time[2] = 0;
if (RTC_Time[2] > 59 & RTC_Time[2] < 100)RTC_Time[2] = 0;
if (RTC_Time[2] > 100)RTC_Time[2] = 59;
OLED_ShowNum(1, 11, RTC_Time[2], 2); //时
}
}
if (T_state == 2)
{
MyRTC_Time[3] = RTC_Time[0];
MyRTC_Time[4] = RTC_Time[1];
MyRTC_Time[5] = RTC_Time[2];
MyRTC_SetTime();
T_state = 0;
}
}
void TimeRead()
{
MyRTC_ReadTime();
OLED_ShowNum(1, 5, MyRTC_Time[3], 2); //时
OLED_ShowString(1, 7, ":");
OLED_ShowNum(1, 8, MyRTC_Time[4], 2); //分
OLED_ShowString(1, 10, ":");
OLED_ShowNum(1, 11, MyRTC_Time[5], 2); //秒
}
void DingShiMoShi()
{
TimeRead();
//...............................定时模式..................................../
if ((MyRTC_Time[3] == RTC_Time1[0]) && (MyRTC_Time[4] == RTC_Time1[1]) && (MyRTC_Time[5] == RTC_Time1[2]))
{
//外设操作
}
if ((MyRTC_Time[3] == RTC_Time2[0]) && (MyRTC_Time[4] == RTC_Time2[1]) && (MyRTC_Time[5] == RTC_Time2[2]))
{
//外设操作
}
//...............................修改定时时间..................................../
OLED_ShowChinese(3, 1, 31);
OLED_ShowString(3, 3, ":");
OLED_ShowNum(3, 5, RTC_Time1[0], 2);
OLED_ShowString(3, 7, ":");
OLED_ShowNum(3, 8, RTC_Time1[1], 2);
OLED_ShowString(3, 10, ":");
OLED_ShowNum(3, 11, RTC_Time1[2], 2);
OLED_ShowChinese(4, 1, 32);
OLED_ShowString(4, 3, ":");
OLED_ShowNum(4, 5, RTC_Time2[0], 2);
OLED_ShowString(4, 7, ":");
OLED_ShowNum(4, 8, RTC_Time2[1], 2);
OLED_ShowString(4, 10, ":");
OLED_ShowNum(4, 11, RTC_Time2[2], 2);
if (KeyNum == 5)
{
delay_ms(20);
if (KeyNum == 5)
{
state_dingshi_yu_switch++;
if (state_dingshi_yu_switch > 2)
{
state_dingshi_yu_switch = 0;
}
}
}
if (state_dingshi_yu_switch == 1) //设置阈值开的时间
{
if (KeyNum == 2)
{
delay_ms(20);
if (KeyNum == 2)
{
state_dingshi_yu_kai++;
if (state_dingshi_yu_kai > 2)
{
state_dingshi_yu_kai = 0;
}
}
}
if (state_dingshi_yu_kai == 0) //时
{
if (KeyNum == 3) RTC_Time2[0]++;
if (KeyNum == 4) RTC_Time2[0]--;
}
if (state_dingshi_yu_kai == 1)//分
{
if (KeyNum == 3) RTC_Time2[1]++;
if (KeyNum == 4) RTC_Time2[1]--;
}
if (state_dingshi_yu_kai == 2)//秒
{
if (KeyNum == 3) RTC_Time2[2]++;
if (KeyNum == 4) RTC_Time2[2]--;
}
}
else
{
if (KeyNum == 2)
{
delay_ms(20);
if (KeyNum == 2)
{
state_dingshi_yu_guan++;
if (state_dingshi_yu_guan > 2)
{
state_dingshi_yu_guan = 0;
}
}
}
if (state_dingshi_yu_guan == 0) //时
{
if (KeyNum == 3) RTC_Time1[0]++;
if (KeyNum == 4) RTC_Time1[0]--;
}
if (state_dingshi_yu_guan == 1)//分
{
if (KeyNum == 3) RTC_Time1[1]++;
if (KeyNum == 4) RTC_Time1[1]--;
}
if (state_dingshi_yu_guan == 2)//秒
{
if (KeyNum == 3) RTC_Time1[2]++;
if (KeyNum == 4) RTC_Time1[2]--;
}
}
if (state3_1 == 0) //时
{
if (KeyNum == 5) RTC_Time1[0]++;
if (KeyNum == 6) RTC_Time1[0]--;
}
if (state3_1 == 1)//分
{
if (KeyNum == 5) RTC_Time1[1]++;
if (KeyNum == 6) RTC_Time1[1]--;
}
if (state3_1 == 2)//秒
{
if (KeyNum == 5) RTC_Time1[2]++;
if (KeyNum == 6) RTC_Time1[2]--;
}
}
void YuZhiSet()
{
zhidong();
OLED_ShowChinese(1, 3, 72); //显示“阈值设置”
OLED_ShowChinese(1, 4, 73);
OLED_ShowChinese(1, 5, 74);
OLED_ShowChinese(1, 6, 75);
OLED_ShowString(2, 1, "S_W_X:");
OLED_ShowNum(2, 7, ShuiWeiYu_Xia, 2);
OLED_ShowString(3, 1, "S_W_S:");
OLED_ShowNum(3, 7, ShuiWeiYu_Shang, 2);
OLED_ShowString(4, 10, "PH:");
OLED_ShowNum(4, 13, PHYu, 2);
OLED_ShowString(2, 10, "Temp:");
OLED_ShowNum(2, 15, TempYu, 2);
OLED_ShowString(3, 10, "Z_D:");
OLED_ShowNum(3, 14, ZhuoYu, 2);
if (KeyNum == 2) //自动模式下PB0按键控制阈值切换
{
delay_ms(20);
if (KeyNum == 2)
{
state3++;
if (state3 > 4)
{
state3 = 0;
}
}
}
if (state3 == 0)
{
if (KeyNum == 3)ShuiWeiYu_Xia++;
if (KeyNum == 4)ShuiWeiYu_Xia--;
}
if (state3 == 1)
{
if (KeyNum == 3)ShuiWeiYu_Shang++;
if (KeyNum == 4)ShuiWeiYu_Shang--;
}
if (state3 == 4)
{
if (KeyNum == 3)PHYu++;
if (KeyNum == 4)PHYu--;
}
if (state3 == 2)
{
if (KeyNum == 3)TempYu ++;
if (KeyNum == 4)TempYu --;
}
if (state3 == 3)
{
if (KeyNum == 3)ZhuoYu ++;
if (KeyNum == 4)ZhuoYu --;
}
}
void ChuangGan()
{
OLED_ShowChinese(2, 1, 39);
OLED_ShowChinese(2, 2, 40);
OLED_ShowString(2, 5, ":");
OLED_ShowNum(2, 6, bufe[0], 2);
OLED_ShowString(2, 8, "%");
OLED_ShowString(4, 8, "%");
OLED_ShowString(2, 11, "PH:");
OLED_ShowNum(2, 14, bufe[1] / 10, 1);
OLED_ShowString(2, 15, ".");
OLED_ShowNum(2, 16, bufe[1] % 10, 1);
OLED_ShowChinese(3, 1, 26);
OLED_ShowChinese(3, 2, 28);
OLED_ShowString(3, 5, ":");
if (temperature < 0)
{
OLED_ShowString(3, 6, "-"); //显示负号
temperature = -temperature; //转为正数
}
else OLED_ShowString(3, 6, "+"); //去掉负号
OLED_ShowNum(3, 7, temperature / 10, 2);
OLED_ShowString(3, 9, ".");
OLED_ShowNum(3, 10, temperature % 10, 1);
OLED_ShowChinese(4, 1, 78);
OLED_ShowChinese(4, 2, 79);
OLED_ShowString(4, 5, ":");
OLED_ShowNum(4, 6, bufe[2], 2);
}
七、总结
基于STM32的智能鱼缸设计 本设计实现了鱼缸水质智能监测与控制系统,采用STM32F103C8T6作为主控芯片,配备多种传感器(pH、浊度、水位、温度)和WiFi模块(ESP8266)。系统具有三种工作模式:远程模式(通过手机APP控制)、手动模式(按键操作)和自动模式(根据预设阈值自动调节)。主要功能包括:实时监测水质参数、自动控制水泵/加热器、异常报警等。通过OLED显示屏直观显示各项参数,并支持阈值设置。该系统有效解决了传统鱼缸管理不便的问题,实现了智能化、远程化的鱼缸管理。
八、资料内容

更多推荐



所有评论(0)