基于单片机的自动浇花器设计
摘 要:随着科技的发展,人们对生活水平的要求逐渐提高,智能家居也慢慢潜入人们的生活,自动化的兴起也是对科技发展的肯定。现在很多人都住上了高层,为了净化室内空气便种植盆栽,一方面是为了净化空气,另一方面是为了陶冶情操。然而很多人想精心照顾他们的花花草草,但是又不懂方法与技巧甚至有的人没时间去照料,所以这就需要设计一款自动浇花器。
1 绪论
1.1 研究背景
1.3主要设计内容
2 系统设计
2.1 方案论证
2.1.1 总体方案设计
2.1.2 土壤湿度测量方案
2.2 硬件的选择
2.3 系统结构
3 系统硬件设计
3.1 AT89C51主要性能参数
3.2 时钟电路
3.3 AT89C51的复位电路
3.4 YL-69土壤湿度传感器
3.5 SRS-05VDC-SL继电器
3.6 按键电路
3.7 DS1302时钟芯片
4 系统软件设计
4.1 系统流程图
4.2 土壤湿度检测程序
4.3 按键程序
4.4 LCD1602显示程序
5 仿真设计与硬件调试
5.1 硬件调试
结论
参考文献
致谢
附录
附录A:主程序
- 完成整体的规划和结构设计
- 围绕着单片机展开相关工作,并对装置原件展开处理,让它们有机的搭配起来。主要的硬件部分涵盖有:土壤湿度检测电路、光亮度检测电路、电源电路、按键设置电路、LCD1602显示电路与继电器控制水泵电路。以及系统的软件设计及编写,使其与硬件模块互相配合。大体涵盖有以下几类程序:主要程序、湿度检测程序、信息汇总程序、按键触碰程序、运行子程序等。
- 完成硬件模块和软件模块的调试。
- 土壤湿度传感器的选择:
图4 按键电路图
3.2YL-69土壤湿度传感器
图5 YL-69与AD转化电路
图7 继电器控制水泵
3.5光敏电阻及其控制电路
图14 程序流程图
5.1 仿真软件简介
proteus仿真软件可以提供对单片机及外围电路进行仿真,它将电路仿真软件、PCB设计软件和虚拟模型仿真软件三者合一,是目前唯一一款三合一平台。它可以实现原理布图、PCB自动或人工布线、SPICE电路仿真,最后达到仿真效果,可以在运行后看到输入输出的效果。此软件提供现成元器件、测试仪器以图形的方式表示,并可以直接从窗口图形中调出,软件中测试仪器的图形与实物相似,而且可以储存实验测试结果的数据、波形、工作状态等,并可以打印输出。
5.2 仿真流程
(1)打开Proteus软件,会弹出如图5-1所示的窗口,我们可以看到右边的大区域是绘图窗口,左面的小窗口是视图小窗口,紧挨着下面分别是元器件列表、控制按钮。
图5-1 Proteus打开界面
(2)在界面视图小窗口的下面有P L按钮,点击P按钮,便可弹出一个搜素栏,在里面输入需要的元器件名称,就会在右边的绘图窗口中弹出,双击需要的元器件,选择好之后关闭对话框,之后就可以在刚才的P L按钮下面点击最终需要的元器件,用鼠标拖动移到绘图窗口即可单击确定位置即可。如图5-2所示:
图5-2搜索添加元器件
(3)将元器件选择好之后,系统自动布线即可完成电路图设计,双击电路图中的单片机会出现一个对话框,然后把.hex文件加载进去,如图5-3所示
图5-3 加载.hex文件
- 最后点击窗口左下角的运行开始键,就可以完成仿真过程,如图5-4所示:
图5-4 运行结果
5.3 仿真结果
在参考电路的运行图之后,依照其样式将实物制出,然后把程序烧录至AT89C51单片机内接通电源,将YL-69土壤湿度传感器探头放入土壤中,按键调至模式一,调至湿度值50%,屏幕显示浇水开始,水泵运行,浇灌到设定湿度值时停止浇水。按键调至模式二,检测到湿度值低于设定湿度,水泵开始浇水,将光敏电阻遮盖住,屏幕显示为夜间模式,停止浇水。将其按键转换到第三种模式,规定时间并运行浇水,在系统检测到需要浇水时,水泵便会自动出水,运行60秒后便停止灌溉。之后,看实物能否稳定操作。如果一切显示都正常的话,就无需开展硬件的相关调整,如果运行的不正常则要分析其原因并开展相关调试工作。
致谢
单片机源程序如下:
- #include<reg52.h>
- #include<LCD1602.h>
- #include<ADC0832.h>
- #include<INTERRUPT.h>
- #include<math.h>
- #include<stdio.h>
- #include<EEPROM.h>
- #include<DS1302.h>
- sbit jidainqi = P1^4;//自动浇花开关
- sbit jidainqi_led = P1^3;//自动浇花开关指示灯
- sbit key_mode = P3^2;//模式切换按键
- sbit key_set = P3^3;//设置
- sbit key_jia = P3^4;//加
- sbit key_jian = P2^0;//减
- sbit guang = P2^2;//光
- uchar temp_ad[6];
- double temp;
- uchar f=0;
- uchar wei;
- uchar mode;
- uchar set_time=0;
- uchar jiaohua_num;//浇花湿度值
- uchar set_shidu=0;//按键设置标志位
- uchar T0_num;
- uchar ad;
- char naozhong1[]={0x00,0x00,0x00};
- /********************************************************
- 函数名称:void delayms(uint ms)
- 函数作用:毫秒延时函数
- 参数说明:
- ********************************************************/
- void Delay_ms(uint ms)
- {
- unsigned char i=100,j;
- for(;ms;ms--)
- {
- while(--i)
- {
- j=10;
- while(--j);
- }
- }
- }
- void display(void)//选择页面
- {
- lcd1602_write_character(0,1,"Watering System "); //初始化显示的文字
- lcd1602_write_character(0,2," Choice mode"); //初始化显示的文字
- }
- void display1(void)//白天自动检测浇花
- {
- ad=ADC0832_read(0);
- Delay_ms(25);
- temp=(1-(double)ad/255)*100;
- if(temp<=jiaohua_num)
- {
- if(f==0)//清屏标志位
- {
- LCD_write_command(0x01);
- delay_n40us(100);
- f=1;
- }
- lcd1602_write_character(0,1,"Flower is Dying!");
- lcd1602_write_character(0,2," Auto Watering!");
- jidainqi=0;jidainqi_led=0;//自动浇花
- }
- else
- {
- // if(temp<1.5)
- // wei=sprintf(temp_ad,"%0.2f",0);
- // else
- wei=sprintf(temp_ad,"%0.2f",temp);
- if(f==1)
- {
- LCD_write_command(0x01);
- delay_n40us(100);
- f=0;
- }
- lcd1602_write_character(0,1," The mode one:"); //初始化显示的文字
- lcd1602_write_character(3,2," ");
- lcd1602_write_character(9-wei,2,temp_ad);
- lcd1602_write_character(9,2,"%RH");
- jidainqi=1;jidainqi_led=1;//停止浇花
- }
- }
- void display4(void)//浇花湿度设置
- {
- T0_num++;
- if(T0_num==254)
- T0_num=0;
- lcd1602_write_character(0,1," Set water num"); //初始化显示的文字
- if(T0_num%2==0) //偶数次显示
- {
- LCD_disp_char(9,2,ASCII[jiaohua_num/10]); //
- LCD_disp_char(10,2,ASCII[jiaohua_num%10]);
- // Delay_ms(1);
- }
- else
- {
- LCD_disp_char(9,2,ASCII[jiaohua_num/10]);
- LCD_disp_char(10,2,ASCII[jiaohua_num%10]);
- }
- }
- void display2(void)//自动浇花加光照
- {
- //lcd1602_write_character(0,1,"mode two:"); //初始化显示的文字
- ad=ADC0832_read(0);
- Delay_ms(25);
- temp=(1-(double)ad/255)*100;
- if(temp<=jiaohua_num&&guang==1)
- {
- if(f==0)//清屏标志位
- {
- LCD_write_command(0x01);
- delay_n40us(100);
- f=1;
- }
- lcd1602_write_character(0,1,"Flower is Dying!");
- lcd1602_write_character(0,2," Auto Watering!");
- jidainqi=0;jidainqi_led=0;//自动浇花
- }
- else
- {
- // if(temp<1.5)
- // wei=sprintf(temp_ad,"%0.2f",0);
- // else
- wei=sprintf(temp_ad,"%0.2f",temp);
- if(f==1)
- {
- LCD_write_command(0x01);
- delay_n40us(100);
- f=0;
- }
- if(guang==0)
- {
- lcd1602_write_character(0,2,"Night");
- }
- else
- {
- lcd1602_write_character(0,2,"Day! ");
- }
- lcd1602_write_character(0,1," The mode two:"); //初始化显示的文字
- lcd1602_write_character(6,2," ");
- lcd1602_write_character(12-wei,2,temp_ad);
- lcd1602_write_character(12,2,"%RH");
- jidainqi=1;jidainqi_led=1;//停止浇花
- }
- }
- void display3(void)//定时模式
- {
- Read_time(); //读取时间
- lcd1602_write_character(0,1,"The mode three:"); //初始化显示的文字
- LCD_disp_char(1,2,ASCII[time[4]/10]);//月
- LCD_disp_char(2,2,ASCII[time[4]%10]);
- LCD_disp_char(3,2,ASCII[11]);
- LCD_disp_char(4,2,ASCII[time[3]/10]);//日
- LCD_disp_char(5,2,ASCII[time[3]%10]);
- LCD_disp_char(7,2,ASCII[time[2]/10]);// 时
- LCD_disp_char(8,2,ASCII[time[2]%10]);
- //LCD_disp_char(9,1,ASCII[11]);
- lcd1602_write_character(9,2,":");
- LCD_disp_char(10,2,ASCII[time[1]/10]);//分
- LCD_disp_char(11,2,ASCII[time[1]%10]);
- //LCD_disp_char(12,1,ASCII[11]);
- lcd1602_write_character(12,2,":");
- LCD_disp_char(13,2,ASCII[time[0]/10]);//秒
- LCD_disp_char(14,2,ASCII[time[0]%10]);
- if(time[2]==naozhong1[2]&&time[1]==naozhong1[1]&&time[0]==naozhong1[0])
- {
- jidainqi=0;jidainqi_led=0;//自动浇花
- }
- if(time[2]==naozhong1[2]&&(time[1]==(naozhong1[1])+1)&&time[0]==naozhong1[0])
- {
- jidainqi=1;jidainqi_led=1;
- }
- }
- void display5(void)
- {
- T0_num++;
- if(T0_num==254)
- T0_num=0;
- LCD_disp_char(3,1,ASCII[11]);
- lcd1602_write_character(9,1,":");
- lcd1602_write_character(12,1,":");
- lcd1602_write_character(7,2,":");
- lcd1602_write_character(10,2,":");
- if(T0_num%2==0) //偶数次显示
- {
- LCD_disp_char(1,1,ASCII[time[4]/10]);//月
- LCD_disp_char(2,1,ASCII[time[4]%10]);
- LCD_disp_char(4,1,ASCII[time[3]/10]);//日
- LCD_disp_char(5,1,ASCII[time[3]%10]);
- LCD_disp_char(7,1,ASCII[time[2]/10]);// 时
- LCD_disp_char(8,1,ASCII[time[2]%10]);
- LCD_disp_char(10,1,ASCII[time[1]/10]);//分
- LCD_disp_char(11,1,ASCII[time[1]%10]);
- LCD_disp_char(13,1,ASCII[time[0]/10]);//秒
- LCD_disp_char(14,1,ASCII[time[0]%10]);
- LCD_disp_char(5,2,ASCII[naozhong1[2]/10]);// 时
- LCD_disp_char(6,2,ASCII[naozhong1[2]%10]);
- LCD_disp_char(8,2,ASCII[naozhong1[1]/10]);//分
- LCD_disp_char(9,2,ASCII[naozhong1[1]%10]);
- LCD_disp_char(11,2,ASCII[naozhong1[0]/10]);//秒
- LCD_disp_char(12,2,ASCII[naozhong1[0]%10]);
- Delay_ms(1);
- }
- else //奇数次时候设置那个量的时候那个量不显示,以达到闪烁的效果
- {
- if(set_time==1)
- {
- LCD_disp_char(1,1,ASCII[13]);
- LCD_disp_char(2,1,ASCII[13]);
- }
- else
- {
- LCD_disp_char(1,1,ASCII[time[4]/10]);
- LCD_disp_char(2,1,ASCII[time[4]%10]);
- }
- if(set_time==2)
- {
- LCD_disp_char(4,1,ASCII[13]);
- LCD_disp_char(5,1,ASCII[13]);
- }
- else
- {
- LCD_disp_char(4,1,ASCII[time[3]/10]);
- LCD_disp_char(5,1,ASCII[time[3]%10]);
- }
- if(set_time==3)
- {
- LCD_disp_char(7,1,ASCII[13]);
- LCD_disp_char(8,1,ASCII[13]);
- }
- else
- {
- LCD_disp_char(7,1,ASCII[time[2]/10]);
- LCD_disp_char(8,1,ASCII[time[2]%10]);
- }
- if(set_time==4)
- {
- LCD_disp_char(10,1,ASCII[13]);
- LCD_disp_char(11,1,ASCII[13]);
- }
- else
- {
- LCD_disp_char(10,1,ASCII[time[1]/10]);
- LCD_disp_char(11,1,ASCII[time[1]%10]);
- }
- if(set_time==5)
- {
- LCD_disp_char(13,1,ASCII[13]);
- LCD_disp_char(14,1,ASCII[13]);
- }
- else
- {
- LCD_disp_char(13,1,ASCII[time[0]/10]);
- LCD_disp_char(14,1,ASCII[time[0]%10]);
- }
- if(set_time==6)
- {
- LCD_disp_char(5,2,ASCII[13]);
- LCD_disp_char(6,2,ASCII[13]);
- }
- else
- {
- LCD_disp_char(5,2,ASCII[naozhong1[2]/10]);
- LCD_disp_char(6,2,ASCII[naozhong1[2]%10]);
- }
- if(set_time==7)
- {
- LCD_disp_char(8,2,ASCII[13]);
- LCD_disp_char(9,2,ASCII[13]);
- }
- else
- {
- LCD_disp_char(8,2,ASCII[naozhong1[1]/10]);
- LCD_disp_char(9,2,ASCII[naozhong1[1]%10]);
- }
- if(set_time==8)
- {
- LCD_disp_char(11,2,ASCII[13]);
- LCD_disp_char(12,2,ASCII[13]);
- }
- else
- {
- LCD_disp_char(11,2,ASCII[naozhong1[0]/10]);
- LCD_disp_char(12,2,ASCII[naozhong1[0]%10]);
- }
- }
- }
- /********************************************************
- 函数名称:void scan(void)
- 函数作用:按键检测函数
- 参数说明:
- ********************************************************/
- void scan(void)
- {
- //模式按键
- if(key_mode==0)
- {
- Delay_ms(7);
- if(key_mode==0)
- {
- jidainqi=1;jidainqi_led=1;//浇花
- LCD_write_command(0x01);//清除屏幕显示
- delay_n40us(100); //实践证明,我的 LCD1602 上,用 for 循环 200 次就能可靠完成清屏指令。
- mode++;set_shidu=0;set_time=0;
- jidainqi=1;jidainqi_led=1;//停止浇花
- if(mode==4)
- {
- mode=0;
- EEPROM_delete(0x2202); //擦除扇区
- EEPROM_write(0x2202,naozhong1[2]);//
- EEPROM_delete(0x2402); //擦除扇区
- EEPROM_write(0x2402,naozhong1[1]);//
- EEPROM_delete(0x2602); //擦除扇区
- EEPROM_write(0x2602,naozhong1[0]);//
- display();
- }
- if(mode==2)
- {
- EEPROM_delete(0x2002); //擦除扇区
- EEPROM_write(0x2002,jiaohua_num);//
- }
- }
- while(!key_mode);//检测按键松开
- }
- //设置键,不支持连按
- if(key_set==0)
- {
- Delay_ms(7);
- if(key_set==0&&mode==1)
- {
- LCD_write_command(0x01);//清除屏幕显示
- delay_n40us(100); //实践证明,我的 LCD1602 上,用 for 循环 200 次就能可靠完成清屏指令。
- set_shidu++;
- jidainqi=1;jidainqi_led=1;//停止浇花
- if(set_shidu==2)
- {
- set_shidu=0;
- EEPROM_delete(0x2002); //擦除扇区
- EEPROM_write(0x2002,jiaohua_num);//
- display1();
- }
- }
- if(key_set==0&&mode==3)
- {
- set_time++;
- if(set_time==1)
- {
- LCD_write_command(0x01);//清除屏幕显示
- delay_n40us(100); //实践证明,我的 LCD1602 上,用 for 循环 200 次就能可靠完成清屏指令?
- }
- if(set_time>8)
- {
- set_time=0;
- EEPROM_delete(0x2202); //擦除扇区
- EEPROM_write(0x2202,naozhong1[2]);//
- EEPROM_delete(0x2402); //擦除扇区
- EEPROM_write(0x2402,naozhong1[1]);//
- EEPROM_delete(0x2602); //擦除扇区
- EEPROM_write(0x2602,naozhong1[0]);//
- LCD_write_command(0x01);//清除屏幕显示
- delay_n40us(100); //实践证明,我的 LCD1602 上,用 for 循环 200 次就能可靠完成清屏指令。
- display3();
- }
- }
- while(!key_set);//检测按键松开
- }
- //加
- if(key_jia==0&&mode==1)
- {
- Delay_ms(5);
- if(key_jia==0&&mode==1&&set_shidu==1)//设置上限值
- {
- jiaohua_num++; //上限自加
- if(jiaohua_num==91)
- jiaohua_num=90;
- display4();//显示
- }
- }
- //减
- if(key_jian==0&&mode==1)
- {
- Delay_ms(5);
- if(key_jian==0&&mode==1&&set_shidu==1)//设置下限
- {
- jiaohua_num--; //
- if(jiaohua_num<6)
- jiaohua_num=5;
- display4();//显示
- }
- }
- //加值键,支持连按
- if(key_jia==0&&mode==3)
- {
- Delay_ms(7);
- if(key_jia==0&&set_time==1)//设置月
- {
- time[4]++;
- if(time[4]>12)
- time[4]=1;
- time1[4]=(time[4]/10)*16+time[4]%10;
- if(time1[4]>0x12)
- time1[4]=0x01;
- Writeds1302 (WRITE_MONTH,time1[4]);
- }
- if(key_jia==0&&set_time==2)//设置日
- {
- time[3]++;
- if(time[4]==1||time[4]==3||time[4]==5||time[4]==7||time[4]==8||time[4]==10||time[4]==12)
- {
- if(time[3]>31)
- time[3]=1;
- }
- else
- {
- if(time[4]==2)
- {
- if(time[6]%4==0)
- {
- if(time[3]>28)
- time[3]=1;
- }
- else
- {
- if(time[3]>29)
- time[3]=1;
- }
- }
- else
- {
- if(time[3]>30)
- time[3]=1;
- }
- }
- time1[3]=(time[3]/10)*16+time[3]%10;
- if(time1[4]==0x01||time1[4]==0x03||time1[4]==0x05||time1[4]==0x07||time1[4]==0x08||time1[4]==0x10||time1[4]==0x12)
- {
- if(time1[3]>0x31)
- time1[3]=0x01;
- }
- else
- {
- if(time1[4]==0x02)
- {
- if(time1[6]%4==0)
- {
- if(time1[3]>0x28)
- time1[3]=0x01;
- }
- else
- {
- if(time1[3]>0x29)
- time1[3]=0x01;
- }
- }
- else
- {
- if(time1[3]>0x30)
- time1[3]=0x01;
- }
- }
- Writeds1302 (WRITE_DAY,time1[3]);
- }
- if(key_jia==0&&set_time==3)//设置时
- {
- time[2]++;
- if(time[2]>23)
- time[2]=0;
- time1[2]=(time[2]/10)*16+time[2]%10;
- if(time1[2]>0x23)
- time1[2]=0x00;
- Writeds1302 (WRITE_HOUR,time1[2]);
- }
- if(key_jia==0&&set_time==4)//设置分
- {
- time[1]++;
- if(time[1]>59)
- time[1]=0;
- time1[1]=(time[1]/10)*16+time[1]%10;
- if(time1[1]>0x59)
- time1[1]=0x00;
- Writeds1302 (WRITE_MINUTE,time1[1]);
- }
- if(key_jia==0&&set_time==5)//设置秒
- {
- time[0]++;
- if(time[0]>59)
- time[0]=0;
- time1[0]=(time[0]/10)*16+time[0]%10;
- if(time1[0]>0x59)
- time1[0]=0x00;
- Writeds1302 (WRITE_SECOND,time1[0]);
- }
- if(key_jia==0&&set_time==6)
- {
- naozhong1[2]++;
- if(naozhong1[2]>23)
- naozhong1[2]=00;
- }
- if(key_jia==0&&set_time==7)
- {
- naozhong1[1]++;
- if(naozhong1[1]>59)
- naozhong1[1]=00;
- }
- if(key_jia==0&&set_time==8)
- {
- naozhong1[0]++;
- if(naozhong1[0]>59)
- naozhong1[0]=00;
- }
- }
- //减值键,支持连按
- if(key_jian==0&&mode==3)
- {
- Delay_ms(7);
- if(key_jian==0&&set_time==1)//设置月
- {
- time[4]--;
- if(time[4]<1)
- time[4]=12;
- time1[4]=(time[4]/10)*16+time[4]%10;
- if(time1[4]<0x01)
- time1[4]=0x12;
- Writeds1302 (WRITE_MONTH,time1[4]);
- }
- if(key_jian==0&&set_time==2)//设置日
- {
- time[3]--;
- if(time[4]==1||time[4]==3||time[4]==5||time[4]==7||time[4]==8||time[4]==10||time[4]==12)
- {
- if(time[3]<1)
- time[3]=31;
- }
- else
- {
- if(time[4]==2)
- {
- if(time[6]%4==0)
- {
- if(time[3]<1)
- time[3]=28;
- }
- else
- {
- if(time[3]<1)
- time[3]=29;
- }
- }
- else
- {
- if(time[3]<1)
- time[3]=30;
- }
- }
- time1[3]=(time[3]/10)*16+time[3]%10;
- if(time1[4]==0x01||time1[4]==0x03||time1[4]==0x05||time1[4]==0x07||time1[4]==0x08||time1[4]==0x10||time1[4]==0x12)
- {
- if(time1[3]<0x01)
- time1[3]=0x31;
- }
- else
- {
- if(time1[4]==0x02)
- {
- if(time1[6]%4==0)
- {
- if(time1[3]<0x01)
- time1[3]=0x28;
- }
- else
- {
- if(time1[3]<0x01)
- time1[3]=0x29;
- }
- }
- else
- {
- if(time1[3]<0x01)
- time1[3]=0x30;
- }
- }
- Writeds1302 (WRITE_DAY,time1[3]);
- }
- if(key_jian==0&&set_time==3)//设置时
- {
- time[2]--;
- if(time[2]<00)
- time[2]=23;
- time1[2]=(time[2]/10)*16+time[2]%10;
- if(time1[2]<0x00)
- time1[2]=0x23;
- Writeds1302 (WRITE_HOUR,time1[2]);
- }
- if(key_jian==0&&set_time==4)//设置分
- {
- time[1]--;
- if(time[1]<00)
- time[1]=59;
- time1[1]=(time[1]/10)*16+time[1]%10;
- if(time1[1]<0x00)
- time1[1]=0x59;
- ……………………