基于STM32的智能鱼缸设计

1. 前言

为了缓解学习、生活、工作带来的压力,提升生活品质,许多人喜欢在家中、办公室等场所养鱼。为节省鱼友时间、劳力、增加养鱼乐趣;为此,本文基于STM32单片机设计了一款智能鱼缸。该鱼缸可以实现水温检测、水质检测、自动或手动换水、氛围灯灯光变换和自动或手动喂食等功能为一体的控制系统,可通过控制键进行一键控制。

从功能上分析,需要用到的硬件如下:

(1)STM32系统板

(2)水温温度检测传感器: 测量水温

(3)水质检测传感器: 测量水中的溶解性固体含量,反应水质。

(4)步进电机: 作为鱼饲料投食器

(5)RGB氛围灯: 采用RGB 3色灯,给鱼缸照明。

(6)抽水电动马达: 用来给鱼缸充氧,换水,加水等。

水产养殖水质常规检测的传感器有哪些?水产养殖水质常规检测的传感器有水质ph传感器、溶解氧传感器和温度传感器。

(1)水质ph传感器:
ph传感器是高智能化在线连续监测仪,由传感器和二次表两部分组成。可配三复合或两复合电极,以满足各种使用场所。配上纯水和超纯水电极,可适用于电导率小于3μs/cm的水质(如化学补给水、饱和蒸气、凝结水等)的pH值测量。

(2)溶解氧传感器:
氧气的消耗量与存在的氧含量成正比,而氧是通过可透膜扩散进来的。传感器与专门设计的监测溶氧的测量电路或电脑数据采集系统相连。 溶解氧传感器能够空气校准,一般校准所需时间较长,在使用后要注意保养。如果在养殖水中工作时间过长,就必须定期地清洗膜,对其进行额外保养。
在很多水产养殖中,每天测几次溶氧就可以了解溶氧情况。对池塘和许多水槽养殖系统。溶氧水平不会变化很快,池塘一般每天检测2~3次。 对于较高密度养殖系统,增氧泵故障发生可能不到1h就会造成鱼虾等大面积死亡。这些密度高的养殖系统要求有足够多的装备或每小时多次自动测量溶氧。

(3)温度传感器:
温度传感器有多种结构,包括热电偶、电阻温度传感器和热敏电阻。热电偶技术成熟,应用领域广,货源充足。选择热电偶必须满足温度范围要求,且其材料与环境相容。 电阻温度传感器(RTDs)的原理为金属的电阻随温度的改变而改变。大多电阻温度传感器(RTDs)由铂、镍或镍合金制成,其线性度比热电偶好,热切更加稳定,但容易破碎。 热敏电阻是电阻与温度具有负相关关系的半导体。热敏电阻比RTD和热电偶更灵敏,也更容易破碎,不能承受大的温差,但这一点在水产养殖中不成问题。

image-20220416182320501

image-20220416182344173

image-20220416182408897

image-20220416182433949

2. 硬件选型

2.1 STM32开发板

主控CPU采用STM32F103RCT6,这颗芯片包括48 KB SRAM、256 KB Flash、2个基本定时器、4个通用定时器、2个高级定时器、51个通用IO口、5个串口、2个DMA控制器、3个SPI、2个I2C、1个USB、1个CAN、3个12位ADC、1个12位DAC、1个SDIO接口,芯片属于大容量类型,配置较高,整体符合硬件选型设计。当前选择的这款开发板自带了一个1.4寸的TFT-LCD彩屏,可以显示当前传感器数据以及一些运行状态信息。

image-20220411152911198

2.2 杜邦线

image-20220411155302747

2.3 PCB板

image-20220411155607391

image-20220411155730898

2.4 步进电机

image-20220411160333214

2.5 抽水马达

image-20220411160727802

image-20220411160743290

2.6 水温检测传感器

测温采用DS18B20,DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。

DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。

主要根据应用场合的不同而改变其外观。封装后的DS18B20可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。

image-20220411163236595

2.7 水质检测传感器

TDS (Total Dissolved Solids)、中文名总溶解固体、又称溶解性固体、又称溶解性固体总量、表明1升水肿容有多少毫克溶解性固体、一般来说、TDS值越高、表示水中含有溶解物越多、水就越不洁净、虽然在特定情况下TDS并不能有效反映水质的情况、但作为一种可快速检测的参数、TDS目前还可以作为有效的在水质情况反映参数来作为参考。常用的TDS检测设备为TDS笔、虽然价格低廉、简单易用、但不能把数据传给控制系统、做长时间的在线监测、并做水质状况分析、使用专门的仪器、虽然能传数据、精度也高、但价格很贵、为此这款TDS传感器模块、即插即用、使用简单方便、测量用的激励源采用交流信号、可有效防止探头极化、延长探头寿命的同时、也增加了输出信号的稳定性、TDS探头为防水探头、可长期侵入水中测量、该产品可以应用于生活用水、水培等领域的水质检测、有了这个传感器、可轻松DIY–套TDS检测仪了、轻松检测水的洁净程度。

image-20220411163406486

image-20220416155149073

image-20220416155202474

温度校正系数T修正计算公式如下:T修正=1+0.02*(T-25>其中T位正为温度校正系数,T为待测溶液测量温度。

注:

(1)TDS 的测量单位有时也用mg/L表示,与ppm 的换算关系为1mgL=1ppm;

(2)TDS 和电导率往往存在一种相通的关系,有时候TDS也可以用来表示电导率,两者的关系: 1ppm =2uS/cm,中 uS/am为电导率的单位。

(3)国家标准GB5749-2006《生活饮用水卫生标准》中规定饮用自来水的TDS 有限量要求:溶解性总固体=1000ppm

校准方法
由于TDS探头的个体差异或者未进行温度补偿等原因,会导致测量值有较大的误差。因此,为获得更精确的TDS 值,在测量之前,必须进行校准。另外,建议连接温度传感器,进行温度补偿,以提高测量精度。具体操作方法介绍如下。

第一步: 连接TDS探针与温度传感器;
第二步: 记录标准TDS 溶液或用TDS笔测量待测溶液的TDS值,记录为TDS标i准值o
第三步: 给TDS传感器模块供电,将TDS 探针和温度传感器放入TDS标准溶液或已知 TDS值的待测溶液中,测试传感器模块AO口输出电压值,记录为V测s。测量当前测试溶液为值记录为T 就t将测量得到电压值V 测出和T测试代入TDS标准曲线公式和温度修正系数计算公式。

3. STM32程序设计

3.1 硬件连线

硬件连接方式:
1. TFT 1.44 寸彩屏接线
GND   电源地
VCC   接5V或3.3v电源
SCL   接PC8(SCL)
SDA   接PC9(SDA)
RST   接PC10
DC    接PB7
CS    接PB8
BL	  接PB11

2. 板载LED灯接线
LED1---PA8
LED2---PD2

3. 板载按键接线
K0---PA0 
K1---PC5 
K2---PA15

4. DS18B20温度传感器接线
DQ->PC6
+ : 3.3V
- : GND

5. 步进电机
ULN2003控制28BYJ-48步进电机接线:
ULN2003接线:
 IN-D: PB15   d
 IN-C: PB14   c
 IN-B: PB13   b
 IN-A: PB12   a
+ : 5V
- : GND

6. 抽水电机
GND---GND
VCC---5V
AO----PA4

7. 水质检测传感器
AO->PA1
+ : 3.3V
- : GND

8. RGB灯
PC13--R
PC14--G
PC15--B

3.2 硬件原理图

image-20220412161337441

3.3 汉字取模

image-20220412161226161

3.3 程序下载

下载软件在资料包里。点击开始编程之后,点击开发板的复位键即可下载程序进去。

image-20220416182137923

3.4 mian.c代码

需要完整代码和资料包的可以去这里下载:https://download.csdn.net/download/xiaolong1126626497/85896081

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include <string.h>
#include "timer.h"
#include "oled.h"
#include <string.h>
#include <stdlib.h>
#include "font.h"
#include "motor.h"
#include "ds18b20.h"
#include "rtc.h"
#include "adc.h"

/*


*/



/*
函数功能: 更新时间框架显示,在RTC中断里调用
*/
char TimeBuff[20];
void Update_FrameShow(void)
{
    
    
	//绘制电子钟时间
    Gui_DrawFont_GBK16(0,0,RED,0,(u8*)"                    "); 
	sprintf(TimeBuff,"%d/%d/%d %d:%d:%d",rtc_clock.year,rtc_clock.mon,rtc_clock.day,rtc_clock.hour,rtc_clock.min,rtc_clock.sec);
    Gui_DrawFont_GBK16(0,0,RED,0,(u8*)TimeBuff);  
}


//JTAG模式设置,用于设置JTAG的模式
//mode:jtag,swd模式设置;00,全使能;01,使能SWD;10,全关闭;	   
#define JTAG_SWD_DISABLE   0X02
#define SWD_ENABLE         0X01
#define JTAG_SWD_ENABLE    0X00		  
void JTAG_Set(u8 mode)
{
    
    
	u32 temp;
	temp=mode;
	temp<<=25;
	RCC->APB2ENR|=1<<0;     //开启辅助时钟	   
	AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]
	AFIO->MAPR|=temp;       //设置jtag模式
}

u16 DS18B20_data=0; //加热芯的温度
u16 DS18B20_temp;
char data_buff[100];
u16 adc_data=0; //水质检测

int main1()
{
    
    
    USART1_Init(115200); //串口1初始化-打印调试信息
    Moto_Init(); //步进电机初始化
    while(1)
    {
    
    
        Motorcw_ring(1,300); //电机正转1圈
        delay_ms(5000);
        printf("电机转动...\r\n");
    }
}

int main()
{
    
    
    u8 key=0;
    u32 time_cnt=0;
    u32 time_rgb=0;
    u32 time1=0; //定时换水
    u32 time2=0; //定时投喂食物
    
    JTAG_Set(JTAG_SWD_DISABLE); //释放PA15
    LED_Init();  //LED灯初始化
    KEY_Init();  //按键初始化
    USART1_Init(115200); //串口1初始化-打印调试信息
    Lcd_Init();    //LCD初始化
    Lcd_Clear(0);  //清屏为黑色
    LCD_LED_SET;   //通过IO控制背光亮		
    DS18B20_Init(); //DA18B20温度传感器
    Moto_Init(); //步进电机初始化
    AdcInit();   //水质传感器
    
    printf("DS18B20检测:%d\r\n",DS18B20_Check());
    
   //实时水温显示
   LCD_ShowChineseFont(0,16*2,16,HZ_FONT_16[0],RED,0);
   LCD_ShowChineseFont(16,16*2,16,HZ_FONT_16[1],RED,0);
   LCD_ShowChineseFont(16*2,16*2,16,HZ_FONT_16[2],RED,0);
   LCD_ShowChineseFont(16*3,16*2,16,HZ_FONT_16[3],RED,0);
   
   //实时水质显示
   LCD_ShowChineseFont(0,16*3,16,HZ_FONT_16[4],RED,0);
   LCD_ShowChineseFont(16,16*3,16,HZ_FONT_16[5],RED,0);
   LCD_ShowChineseFont(16*2,16*3,16,HZ_FONT_16[6],RED,0);
   LCD_ShowChineseFont(16*3,16*3,16,HZ_FONT_16[7],RED,0);

   printf("正在初始化RTC实时时钟.\r\n");
  // RTC_Init();//RTC初始化,一定要初始化成功 
        
   while(1)
   {
    
    
        //按键可以手动控制开启窗帘和LED灯
        key=KEY_Scan();
        if(key)
        {
    
    
            printf("key=%d\r\n",key);
        }
       
        //手动投喂食物
        if(key==2)
        {
    
    
            printf("手动投喂食物.\r\n");
            LED2=0;
            Motorcw_ring(1,300); //电机正转1圈
            LED2=1;
        }    
        
        //手动换水
        if(key==1)
        {
    
    
             printf("手动换水.\r\n");
            //抽水3秒
            MOTOR=1;
            delay_ms(3000);
            MOTOR=0;
        }
        
        //轮询时间到达
        if(time_cnt>200)
        {
    
    
            time_cnt=0;
            LED1=!LED1;
            
            //读取加热芯温度
            DS18B20_temp=DS18B20_Read_Temp();
            printf("水温:%d.%d\r\n",DS18B20_temp>>4,DS18B20_temp&0xF);
            sprintf(data_buff,"%d.%d",DS18B20_temp>>4,DS18B20_temp&0xF);             

            //LCD屏实时显示
            Gui_DrawFont_GBK16(72,16*2,RED,0,(u8*)"       ");
            Gui_DrawFont_GBK16(72,16*2,RED,0,(u8*)data_buff);
            
            //水质检测
            adc_data=GetAdcCHxDATA(1);
            sprintf(data_buff,"%d",adc_data);
            printf("水质质量:%s\r\n",data_buff);
            Gui_DrawFont_GBK16(72,16*3,RED,0,(u8*)"        ");
            Gui_DrawFont_GBK16(72,16*3,RED,0,(u8*)data_buff);  
        }
        
        DelayMs(10);
        time_cnt++;
        time2++;
        time1++;
        time_rgb++;
        
        
        if(time_rgb>=100 && time_rgb<=200)
        {
    
    
            printf("模式1\r\n");
            RGB_R=1;
            RGB_G=0;
            RGB_B=0;
        }
        else if(time_rgb>=200 && time_rgb<=300)
        {
    
    
            printf("模式2\r\n");
            RGB_R=0;
            RGB_G=1;
            RGB_B=0;
        }
        else if(time_rgb>=300 && time_rgb<=400)
        {
    
    
            printf("模式3\r\n");
            RGB_R=0;
            RGB_G=0;
            RGB_B=1;
        }
        else if(time_rgb>=400)
        {
    
    
            time_rgb=0;
        }
        
        
        //定时投喂食物
        //5个小时投喂一次
        if(time2>100*60*60*5)
        {
    
    
             time2=0;
             Motorcw_ring(1,300); //电机正转1圈
        }
        
        //定时换水,2天换一次水
        if(time1>100*60*60*24*2)
        {
    
    
            time1=0;
            MOTOR=1;
            delay_ms(3000);
            MOTOR=0;
        }
	 }
}

猜你喜欢

转载自blog.csdn.net/xiaolong1126626497/article/details/126012501