基于51单片机的自动浇花器电路

news2024/9/21 12:25:02

一、系统概述

自动浇水灌溉系统设计方案,以AT89C51单片机为控制核心,采用模块化的设计方法。

组成部分为:5V供电模块、土壤湿度传感器模块、ADC0832模数转换模块、水泵控制模块、按键输入模块、LCD显示模块和声光报警模块,结构如下。

工作原理为:土壤湿度传感器测出土壤湿度模拟信号,经AD转换器将模拟信号转换成数字信号后传输到51单片机,单片机将土壤湿度数据与设定的上下限值进行比较。

当土壤湿度低于下限时,驱动水泵工作进行灌溉浇水,并提供声光报警。设计获取,蒋宇智QQ(2327603104)。

当土壤湿度增加至超过下限时,声光报警关闭,但水泵会继续工作,直到土壤湿度继续增加并超过设定的上限值为止。

用户可通过按键设定湿度上下限值,土壤湿度数据和上下限值数据均通过LCD显示屏实时显示。

二、土壤湿度传感器

Proteus仿真电路

三、原理图

原理图.jpg

仿真结果分析

打开Proteus仿真文件,其后缀名为.DSN。双击单片机,加载AutoWater.hex文件(位于Keil C程序文件夹内),运行仿真,结果如下。

由图可知,LCD显示当前测量的土壤湿度(Humidity)为53%,系统预设的湿度上限(H:High的缩写)为60%,下限(L:Low的缩写)为30%,土壤湿度正常,在上下限范围之内。资源获取,蒋宇智QQ(2327603104)。

此时,湿度低报警灯和蜂鸣器处于关闭状态,继电器RL1开关打至下方,水泵处于断电状态。

通过调节滑动变阻器RV2(鼠标点击上下两个红色箭头),改变输入到ADC0832采样通道0的电压大小来模拟土壤湿度的变化。

点击RV2向下的红色箭头,模拟土壤湿度的降低。例如,当土壤湿度从53%降低至23%,低于下限值30%时,红色LED报警灯点亮,蜂鸣器发声,继电器RL1开关打至上方,水泵通电,开始自动浇水,绿色的水泵工作指示灯也被点亮。

点击RV2向上的红色箭头,模拟土壤湿度的增加。

当土壤湿度从23%增加至37%,超过下限时,声光报警停止工作,但水泵会继续工作,直到土壤湿度继续增加到高于上限值为止,过程如下所示。

需要说明的是,水泵停止工作(即:土壤湿度超过上限)后,调节RV2模拟土壤湿度的下降,在下降到上下限范围内时,水泵不会启动,只有土壤湿度继续下降至低于下限时才会启动。

通过按键可以预设湿度的上下限值。

点击“设定”键,进入上下限设置模式,首先是H上限值光标闪烁,此时可以点击加/减键,改变上限值大小。

上限值设置完成后,点击“设定”键,L下限值光标闪烁,同理,点击加/减键,改变下限值大小。

上下限值都设置完成后,再次点击“设定”键,退出上下限设置模式。例如,我们设置湿度上限值H为75%,下限值L为25%,结果如下图所示。

综上所述,仿真运行效果满足设计要求。

四、C代码

void main()//主函数
{
	Init1602();//初始化液晶函数
	init(); //初始化定时器
	init_eeprom(); //开始初始化保存的数据
	while(1)//进入循环
	{
		for(m=0;m<50;m++)//读50次AD值
			sum = adc0832(0)+sum;	//读到的AD值,将读到的数据累加到sum
		temp=sum/50;//跳出上面的for循环后,将累加的总数除以50得到平均值temp
		sum=0; //平均值计算完成后,将总数清零
		temp = temp*0.390625;	//ADC0832存储数据为1个字节,湿度显示范围为0~100,因此1单位湿度=100/256=0.390625				
//		if(temp<=full_range)
//		temp=(temp*100)/full_range;
//		else
//		temp=100;
		if(set==0)//set为0,说明现在不是设置状态
		Display_1602(temp,MH,ML);//显示AD数值和报警值
		if(temp<ML&&set==0)//湿度值小于报警值
		{//资源获取,蒋宇智QQ(2327603104)
			flag=1;//打开报警
			Relay=0;//继电器触点闭合,水泵工作
			LED_R=0;	//红灯点亮
		}
		else if(temp>MH&&set==0) //湿度值大于报警值
		{
			flag=0;//关闭报警
			Relay=1;//继电器触点打开,水泵停止
			LED_R=1;	//红灯熄灭
		}
		else
		{
			flag=0;
			LED_R=1;	//红灯熄灭
		}
		Key(); //调用按键函数
	}
}

    #include <reg51.H>
    #include "intrins.h"
    #define uint unsigned int
    #define uchar unsigned char
    #define ulong unsigned long
    #define     LCDIO      P0         //液晶屏数据口
    //ADC0832的引脚
    sbit ADCLK =P1^1;  //ADC0832 clock signal
    sbit ADDIO =P1^3;  //ADC0832 k in
    sbit ADCS =P1^4;  //ADC0832 chip seclect

    sbit rs=P1^0;  //定义1602 RS
    sbit lcden=P1^2; //定义1602 EN
    sbit key1=P3^0;    //设定
    sbit key2=P3^1;    //加
    sbit key3=P3^2;    //减
    sbit motor=P3^7;   //继电器接口
    sbit speak=P1^5;        //蜂鸣器接口
    uchar key;         //设定指针
    uint RH=400,RL=200;//水位上下限
    float temp_f;
    ulong temp;
    uchar v;
    uchar count,s1num;
    uchar code table[]= " moisture:          ";
    uchar code table1[]="RH:  %              ";
    uchar getdata; //获取ADC转换回来的值
    /*********************************************/
    void delay(uint z)                  //延时
    {
            uint x,y;
            for(x=z;x>0;x--)
                    for(y=110;y>0;y--);
    }
    /**********************************************/
    void write_com(uchar com)
    {
            rs=0;
    //        rd=0;
            lcden=0;
            P0=com;
            delay(5);
            lcden=1;
            delay(5);
            lcden=0;       
    }
    /*********************************************/
    void write_date(uchar date)
    {
            rs=1;
    //        rd=0;
            lcden=0;
            P0=date;
            delay(5);
            lcden=1;
            delay(5);
            lcden=0;       
    }

    void lcdinit()
    {
            lcden=0;
            write_com(0x38);
            write_com(0x0c);
            write_com(0x06);
            write_com(0x01);
    }
    /***********************************************/
    void init()
    {
            uchar num;
           
            for(num=0;num<15;num++)
                    {
                            write_date(table[num]);
                            delay(5);
                    }
            write_com(0x80+0x40);
            for(num=0;num<15;num++)
                    {
                            write_date(table1[num]);
                            delay(5);
                    }
            }
    //****************************************************************************/
    /************
    读ADC0832函数
    ************/
    //采集并返回
    /****************************************************************************
    函数功能:AD转换子程序
    入口参数:CH(如果读取CH0,channel的值为0x01,如果读取CH1则channel的值为0x03)
    出口参数:adval
    ****************************************************************************/
    uchar Adc0832()     //AD转换,返回结果
    {
        uchar i;
        uchar dat=0;

        ADCLK=0;
        ADDIO=1;
        ADCS=0;                  //拉低CS端
        ADCLK=1;                 
        ADCLK=0;                 //拉低CLK端,形成下降沿1

        ADDIO=1;//指定转换通道是CH1还是CH2,指定值位与0x1,取最后一位的值
        ADCLK=1;   
        ADCLK=0;                 //拉低CLK端,形成下降沿2

        ADDIO=0;//指定值右移一位,再取最后一位的值
        ADCLK=1;
        ADCLK=0;                //拉低CLK端,形成下降沿3


        ADDIO=1;               
            for(i=0;i<8;i++)
        {
            ADCLK=1;
            ADCLK=0;           //形成一次时钟脉冲
            if(ADDIO)
                       dat|= 0x80>>i;  //收数据
        }


        ADCS=1;                //拉低CS端
        ADCLK=1;
        ADDIO=1;               //拉高数据端,回到初始状态
        return(dat);           //return dat
    }
    /***************************************************************************/


    /********************************************************/
    void displayRH()                        //下限显示
    {write_com(0xc0+3);
    write_date(RH/100%10+0x30);//上限百位
    write_date(RH/10%10+0x30);//上限十位
    //write_date('.');
    //write_date(RH%10+0x30);
    }
    void displayRL()          //下限显示
    {write_com(0xca);
      write_date('R');
      write_date('L');
      write_date(':');
    write_date(RL/100%10+0x30);//下限百位
    write_date(RL/10%10+0x30);//下限十位
    write_date('%');
    }
    /**************************************************/
    /********************************************************/
    void keyscan()                 //按键处理
    {bit kk1=0,kk2=0;
    if(key1==0)
    {delay(30);
      while(key1==0);
       if(key>=2)
       {key=0;
       }
       else
       {key++;
       }
       switch(key)
       {speak=1;kk2=motor;motor=1;
        case 1:{write_com(0x0f);write_com(0xce); //光标闪烁
            while(key1!=0)         //等待按键松开
            {
        if(key2==0)                //key2按键下
       {delay(30);                //按键延时消抖
       if(key2==0)                //确定key2按下
       {
        while(key2==0); //等待松开
            if(RL>=998)
            {RL=999;                //RL下限最大设置为99
            }
            else
            {RL+=10;                //RL加1
            }       
       }
       displayRL();                //调用RL下限显示函数
       write_com(0xce);
      }   
       if(key3==0)                //key3按下
       {delay(30);                //按键延时消抖
       if(key3==0)                //确定key3按下
       {
        while(key3==0);         //等待key3按键松开
            if(RL<=1)                 //RL最小设置为1
            {RL=0;
            }
            else
            {RL-=10;                 //RL下限减1
            }
       }
       displayRL();                //调用RL下限显示函数
       write_com(0xce);
      }

       
       }while(key1==0);       
            }
            case 2:{write_com(0x0f);write_com(0xc4);  //RH设置数据,光标闪烁
       while(key1==1)
       {
        if(key2==0)           //key2按下
       {delay(30);           //按键延时消抖
       if(key2==0)           //确定key2按下
       {
        while(key2==0);        //等待松开
            if(RH>=998)                //RH最大设置为99
            {RH=999;
            }
            else
            {RH+=10;                //RH加1
            }
           
       }
       displayRH();                //RH上限显示函数
        write_com(0xc4);
      }

       
       
       if(key3==0)          //key3按下
       {delay(30);          //按键延时消抖
       if(key3==0)          //确定按下
       {
        while(key3==0);//等待松开
            if(RH<=1)           //RH最小设置为1
            {RH=0;
            }
            else
            {RH-=10;                //RH减1
            }

       }
       displayRH();                //调用RH显示函数
        write_com(0xc4);
      }


       }
       while(key1==0);
       }
            case 0:{write_com(0x0c);
                            motor=kk2;

                break;}
       }
       }
    }
    /**************************************************/
    void Conut(void)          //土壤检测数据转换
    {          
          v=Adc0832();
              temp=v;
          temp_f=temp*9.90/2.55;
          temp=temp_f;
              temp=1000-temp;         
              write_com(0x80+10);
              write_date(temp/100%10+0x30);//千位
              write_date(temp/10%10+0x30);//百位
              write_date('.');
              write_date(temp%10+0x30);
              write_date('%');//显示符号位
           
             }
    /********************************************************/
    void main(void)
    {
            lcdinit();
            init();
            displayRH();   //显示上限
            displayRL();   //显示下限
            delay(50);         //启动等待,等LCD讲入工作状态
            delay(50);         //延时片刻(可不要)
            delay(50);                         //延时
            delay(50);
            Conut();           //显示函数
            delay(150);        
            while(1)
            {        
                 Conut();        //显示当前湿度
                     keyscan();
                     if(temp>RH)  //如果湿度大于上限停止浇水
                     {motor=1;          //关闭继电器
                     }
                     else if(temp<RL) //如果湿度小于RL下限启动浇水
                     {motor=0;                 //启动继电器
                     }
                     if(temp<RL)           //小于下限启动报警并浇水
                     {speak=0;                                //启动报警
                      delay(150);                         //延时
                      speak=1;
                     }
                     keyscan();                 //按键检测
                     delay(150);                         //延时50MS
            }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1680207.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Gradio 案例——将 dicom 文件转为 nii文件

文章目录 Gradio 案例——将 dicom 文件转为 nii文件界面截图依赖安装项目目录结构代码 Gradio 案例——将 dicom 文件转为 nii文件 利用 SimpleITK 库&#xff0c;将 dicom 文件转为 nii文件更完整、丰富的示例项目见 GitHub - AlionSSS/dcm2niix-webui: The web UI for dcm2…

利用MMDetection进行模型微调和权重初始化

目录 模型微调修改第一处&#xff1a;更少的训练回合Epoch修改第二处&#xff1a;更小的学习率Learning Rate修改第三处&#xff1a;使用预训练模型 权重初始化实际使用案例init_cfg 的具体使用规则初始化器配置汇总 本文基于 MMDetection官方文档&#xff0c;对模型微调和权重…

eMMC和SD模式速率介绍

概述 在实际项目开发中我们常见的问题是有人会问,“当前项目eMMC、SD所使用模式是什么? 速率是多少?”。这些和eMMC、SD的协议中要求的,要符合协议。接下来整理几张图来介绍。 eMMC 模式介绍 一般情况下我们项目中都是会支持到HS400 8bit 1.8V,最大时钟频率为200MHZ,通…

ESP8266-01模块继电器制作手机APP远程遥控智能开关

资料下载地址&#xff1a; ESP8266-01模块继电器制作手机APP远程遥控智能开关 这是一款使用ESP8266-01模块继电器制作手机APP远程遥控智能开关&#xff0c;它能实现远程遥控、定时、倒计时控制。电路简单&#xff0c;适合新手入门制作&#xff0c;下图是用这个智能开关制作的小…

springboot项目打包部署

springboot打包的前提条件jdk必须17以后不然本地运行不来&#xff08;我用的jdk是22&#xff09; 查看自己电脑jdk版本可以参考&#xff08;完美解决Windows10下-更换JDK环境变量后&#xff0c;在cmd下执行仍java -version然出现原来版本的JDK的问题-CSDN博客&#xff09; 1、…

treejs 3D+echart实现三维旋转炫酷导航网页

treejs 3Dechart实现三维旋转炫酷导航网页https://www.bilibili.com/video/BV1SM4m1C7ki/

吴恩达深度学习笔记:优化算法 (Optimization algorithms)2.1-2.2

目录 第二门课: 改善深层神经网络&#xff1a;超参数调试、正 则 化 以 及 优 化 (Improving Deep Neural Networks:Hyperparameter tuning, Regularization and Optimization)第二周&#xff1a;优化算法 (Optimization algorithms)2.1 Mini-batch 梯度下降&#xff08;Mini-b…

07-Fortran基础--Fortran指针(Pointer)的使用

07-Fortran基础--Fortran指针Pointer的使用 0 引言1 指针&#xff08;Poionter&#xff09;的有关内容1.1 一般类型指针1.2 数组指针1.3 派生类(type)指针1.4 函数指针 2 可运行code 0 引言 Fortran是一种广泛使用的编程语言&#xff0c;特别适合科学计算和数值分析。Fortran 9…

【设计模式】JAVA Design Patterns——Abstract-document(抽象文档模式)

&#x1f50d; 目的 使用动态属性&#xff0c;并在保持类型安全的同时实现非类型化语言的灵活性。 &#x1f50d; 解释 抽象文档模式使您能够处理其他非静态属性。 此模式使用特征的概念来实现类型安全&#xff0c;并将不同类的属性分离为一组接口 真实世界例子 考虑由多个部…

指针在函数的应用(C++)

一、传递地址 实参传递进函数体内后&#xff0c;生成的是实参的副本&#xff0c;在函数内改变副本的值并不影响实参。指针传递参数时&#xff0c;指针变量产生了副本&#xff0c;但副本与原变量指向的内存区域是同一个。改变指针副本指向的变量&#xff0c;就是改变原指针变量指…

Java 插入数据到Elasticsearch中进行各种类型文档的内容检索

源码下载&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1D3yszkTzjwQz0vFRozQl2g?pwdz6kb 提取码&#xff1a;z6kb 实现思路 1.搭建一个新的springboot项目&#xff0c;不会的请看我这篇博客&#xff1a;springboot项目搭建 2.添加maven依赖 <dependency><…

项目管理-案例重点知识(成本管理)

项目管理&#xff1a;每天进步一点点~ 活到老&#xff0c;学到老 ヾ(◍∇◍)&#xff89;&#xff9e; 何时学习都不晚&#xff0c;加油 三、成本管理 案例重点 成本管理 案例重点内容&#xff1a; &#xff08;1&#xff09;成本管理计划内容 &#xff08;2&#xff09;估算…

汇聚荣科技:拼多多上架商品后需要做页面推广吗?

在电商平台上&#xff0c;商品的曝光率和销量往往成正比。那么&#xff0c;当您在拼多多上架了新品&#xff0c;是不是就意味着坐等订单呢?答案显然是否定的。商品一旦上架&#xff0c;接下来需要做的就是通过有效的页面推广来增加商品的可见度&#xff0c;吸引潜在买家的注意…

23.HashMap的put方法流程

一、put方法的流程图 二、put方法的执行步骤 首先&#xff0c;根据key值计算哈希值。然后判断table数组是否为空或者数组长度是否为0&#xff0c;是的话则要扩容&#xff0c;resize&#xff08;&#xff09;。接着&#xff0c;根据哈希值计算数组下标。如果这个下标位置为空&a…

fastadmin对登录token的处理

fastadmin对token的操作 最近开发遇到一个场景&#xff0c;需要绕过验证获取登录&#xff0c;所以恶补了一下这个知识点&#xff0c;这个主要就是控制fastadmin的token的问题 代码分步实现 class Xcxuser extends Api {//关于鉴权protected $noNeedLogin [login,getopenid,…

踩坑小结:Linux安装python环境 、安装OpenSSL

一、查看python版本 查看发现&#xff0c;linux上自带了python&#xff0c;不过是2.x版本的。 二、下载python3 2.1 下载 www.python.org/downloads/s… 可在当前目录下找到相对应的版本或者最新版本下载 也可以直接下载 Python 3.10.4 下载完在服务器上选择一个目录存放…

ffmpeg使用xfade的转场特效

ffmpeg使用xfade的转场特效 1. 介绍2. ffmpeg里面的xfade3. 使用 1. 介绍 参考文档 ffmpeg是一个音视频编辑工具&#xff0c;具体的。。。。我才搞接触&#xff0c;所以不懂。 xfade是一种视频转场滤镜&#xff0c;用于在两个视频片段之间创建平滑的过渡效果。xfade的转场效果…

扭亏为盈的赛力斯,真正进入稳态了吗?

“72小时内大定破1万台”。5月15日&#xff0c;问界新M5开启全国大规模交付&#xff0c;从当前取得的成绩来看&#xff0c;赛力斯的“富贵”似乎还将延续。 其实&#xff0c;此前基于问界新M7等车型的爆火&#xff0c;赛力斯已经找到了创收轨道。财报显示&#xff0c;2024年一…

戒烟网站|基于SSM+vue的戒烟网站系统的设计与实现(源码+数据库+文档)

戒烟网站 目录 基于SSM&#xff0b;vue的戒烟网站系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1网站功能模块 2管理员功能模块 3用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主…

每日5题Day3 - LeetCode 11 - 15

每一步向前都是向自己的梦想更近一步&#xff0c;坚持不懈&#xff0c;勇往直前&#xff01; 第一题&#xff1a;11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09; class Solution {public int maxArea(int[] height) {//这道题比较特殊&#xff0c;因为两边是任意…