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

一、系统概述

自动浇水灌溉系统设计方案,以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
            }
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

51单片机超声波测距_液位检测_温度检测原理图PCB仿真代码

目录 实物图&#xff1a; PCB ​原理图​ 仿真图 ​编辑 程序 资料下载地址&#xff1a;51单片机超声波测距-液位检测-温度检测原理图PCB仿真代码 主控为stc89c52,通过ds18b20进行温度采集&#xff0c;超声波测距&#xff0c;距离不可以超过1m&#xff0c;通过按键可以设…

做简单易用的GIS资源管理软件

在室外资源管理领域&#xff0c;采用基于GIS的解决方案已成为主流趋势&#xff0c;旨在实现资源的高效利用和管理。GIS技术结合资源对象的规划、定位和监控&#xff0c;为企业提供全面的管理方案&#xff0c;从而优化资源使用、提高运营效率和降低成本。 然而&#xff0c;许多资…

shell脚本实现linux系统自动化配置免密互信

目录 背景脚本功能脚本内容及使用方法 1.背景 进行linux自动化运维时需要先配置免密&#xff0c;但某些特定场景下&#xff0c;做了互信的节点需要取消免密&#xff0c;若集群庞大节点数量多时&#xff0c;节点两两之间做互信操作非常麻烦&#xff0c;比如有五个节点&#x…

计网面试干货---带你梳理常考的面试题

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、HTTP和HTTPS的区别 1.安全性&#xff1a;HTTPS通过SSL/TLS协议对数据进行加密处理&#xff0c;有效防止数据在传输过…

人工智能项目,如何解决大模型的数据私有化

这个问题是最近走访百家企业&#xff0c;客户问的最多的问题。人工智能是对数据集中后&#xff0c;再利用的智能化手段&#xff0c;ChatGPT还在持续的投入&#xff0c;汇集数据、训练模型&#xff0c;微软也不过是做了一个办公客户端的智能工具&#xff0c;那么行业应运之时&am…

写后端项目时上传文件接口使用阿里云oss-规范写法

文章目录 开通对象存储服务密钥管理点击头像点击密钥管理创建新密钥AccessKey 写在yml配置文件中相关配置1.pom依赖2.全局配置类3.AliOssUtil 工具类3.AliOssProperties类&#xff0c;用于读取yml文件中写入的密钥4.controller层&#xff0c;用于写传输文件的接口 开通对象存储…

《Python编程从入门到实践》day29

# 昨日知识点回顾 修改折线图文字和线条粗细 矫正图形 使用内置格式 # 今日知识点学习 15.2.4 使用scatter()绘制散点图并设置样式 import matplotlib.pyplot as plt import matplotlib matplotlib.use(TkAgg)plt.style.use(seaborn-v0_8) # 使用内置格式 fig, ax plt.subpl…

荣耀MagicBook X 14 Pro锐龙版 2023 集显(FRI-H76)笔记本电脑原装出厂Windows11系统工厂模式安装包下载,带F10智能还原

恢复开箱状态预装OEM系统&#xff0c;适用型号&#xff1a;HONOR荣耀FRI-H76、FRI-H56 链接&#xff1a;https://pan.baidu.com/s/1Lcg45byotu5kDDSBs3FStA?pwdl30r 提取码&#xff1a;l30r 华为荣耀原装WIN11系统工厂安装包&#xff0c;含F10一键恢复功能、系统自带所有驱…

蓝桥杯-外卖店优先级(简单写法)

“饱了么”外卖系统中维护着 N 家外卖店&#xff0c;编号 1∼N。 每家外卖店都有一个优先级&#xff0c;初始时 (0 时刻) 优先级都为 0。 每经过 1 个时间单位&#xff0c;如果外卖店没有订单&#xff0c;则优先级会减少 1&#xff0c;最低减到 0&#xff1b;而如果外卖店有订…

四、基于Stage模型的应用架构设计

前面我们了解了如何构建鸿蒙应用以及开发了第一个页面&#xff0c;这只是简单的demo&#xff1b;那么如何去设计&#xff0c;从0到1搭建一个真正的应用呢 一、基本概念 1、Stage模型基本概念 Stage模型概念图 AbilityStage&#xff1a;是一个Module级别的组件容器&#xff0…

「AIGC」Python实现tokens算法

本文主要介绍通过python实现tokens统计,避免重复调用openai等官方api,开源节流。 一、设计思路 初始化tokenizer使用tokenizer将文本转换为tokens计算token的数量二、业务场景 2.1 首次加载依赖 2.2 执行业务逻辑 三、核心代码 from transformers import AutoTokenizer imp…

基于网络爬虫技术的网络新闻分析(二)

目录 2 系统需求分析 2.1 系统需求概述 2.2 系统需求分析 2.2.1 系统功能要求 2.2.2 系统IPO图 2.2 系统非功能性需求分析 3 系统概要设计 3.1 设计约束 3.1.1 需求约束 3.1.2 设计策略 3.1.3 技术实现 3.3 模块结构 3.3.1 模块结构图 3.3.2 系统层次图 3.3.3…

与禹老师学前端vue3学习汇总

24.5.15&#xff1a; 创建Vue3工程 1.确定自己电脑有没有nodejs环境&#xff0c;在cmd中输入node&#xff0c;如果出现Node.js的版本号说明已经有这个环境了&#xff0c;否则搜索Node.js安装 2.先在D盘创建一个文件夹Vue3_Study&#xff0c;然后在这个空文件夹中右键选择终端…

汇聚荣:拼多多长期没有流量如何提高?

在电商的海洋中&#xff0c;拼多多以其独特的团购模式吸引了众多消费者的目光。然而&#xff0c;随着市场竞争的加剧和消费者需求的多样化&#xff0c;一些商家发现自家店铺的流量持续低迷&#xff0c;销售业绩难以突破。面对这样的挑战&#xff0c;如何有效提升拼多多店铺的客…

Linux进程控制——Linux进程程序替换

前言&#xff1a;Linux进程控制包含了进程终止&#xff0c;进程等待&#xff0c;进程程序替换。走到现在我们也只剩下进程程序替换没介绍了&#xff0c;那么让我们来看看进程程序替换到底是什么&#xff01; 本篇主要内容&#xff1a; 替换原理 替换函数 实现简易shell 我们所创…

不用投稿邮箱,怎样向各大新闻媒体投稿?

身为单位的信息宣传员,我深知肩上责任重大。每个月,完成单位在媒体上投稿发表文章的考核任务,就如同一场无声的赛跑,既要保证速度,更要注重质量。起初,我遵循“前辈们”的老路,一头扎进了邮箱投稿的海洋。但很快,现实给了我一记重拳——邮箱投稿的竞争犹如千军万马过独木桥,稿件…

C++ 中的 lambda 表达式

1.概念 lambda表达式实际上是一个匿名类的成员函数&#xff0c;该类由编译器为lambda创建&#xff0c;该函数被隐式地定义为内联。因此&#xff0c;调用lambda表达式相当于直接调用匿名类的operator()函数&#xff0c;这个函数可以被编译器内联优化&#xff08;建议&#xff0…

20240511每日运维----聊聊nignx改配置所有的nginx改完unknow

1、改配置所有的nginx改完unknow src/core/nginx.h src/http/ngx_http_header_filter_module.c src/http/ngx_http_special_response.c src/http/v2/ngx_http_v2_filter_module.c 2、make 3、去objs里面把nginx文件替换过去sbin/nginx

Android系统不同版本存储权限

一、Android存储简介 Android系统分为内部存储和外部存储 从Android6.0开始不断在更新存储&#xff08;读写&#xff09;权限&#xff0c;除了在AndroidManifest.xml文件里声明&#xff0c;app运行时也要动态申请使用对应的权限 提醒&#xff1a;应用私有存储不需要动态申请权…

在linux里登录远程服务器

在linux里登录远程服务器。在虚拟终端里输入命令&#xff1a; ssh 远程服务器ip -l username 然后输入登录密码&#xff0c;就可以登录到远程服务器的命令行界面。登录方便&#xff0c;字体也可以在本地机的虚拟终端里设置得大一点。 下面是一张截屏图片。