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

举报
梦笔生花 发表于 2024/05/15 23:10:19 2024/05/15
【摘要】 一、系统概述 自动浇水灌溉系统设计方案,以AT89C51单片机为控制核心,采用模块化的设计方法。 组成部分为:5V供电模块、土壤湿度传感器模块、ADC0832模数转换模块、水泵控制模块、按键输入模块、LCD显示模块和声光报警模块,结构如下。 工作原理为:土壤湿度传感器测出土壤湿度模拟信号,经AD转换器将模拟信号转换成数字信号后传输到51单片机,单片机将土壤湿度数据与设定的上下限值进行比较。

一、系统概述

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

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

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

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

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

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

二、土壤湿度传感器

Proteus仿真电路

三、原理图

仿真结果分析

打开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

}

}


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。