单片机毕业设计|农家菜园自动灌溉控制系统设计

 作者主页:编程指南针

作者简介:Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师

主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互助

收藏点赞不迷路  关注作者有好处

文末获取源码 

项目编号:BS-DPJ-006

一,环境介绍

语言环境:C

开发技术:51单片机

二,项目简介

随着时代的发展,电子控制技术在人们的生活中得到了广泛的应用。如何运用现代的电子技术,对农家菜园温度、湿度进行自动监测,并依据相关的数据进行相应的灌溉作业。这对于促进温室作物的增产、节省劳动力都是十分必要的。该系统包括单片机STC89C52,湿度传感器,温度传感器,按键,光照传感器,液晶显示屏,水泵,蓝牙和电源。该系统以STC89C52单片机为核心,以 AltiumDesigner 10为主要硬件,以 Keil为主要开发工具,以 C语言编写。论文首先对系统方案进行了整体的描述,并提出了硬件方面的设计,其中包括控制器的选择,温湿度检测模块的硬件选择,光照强度检测模块的选择,显示模块的选择,水泵灌溉模块的选择,蓝牙模块的设计。软件模块主要包括整个软件流程图、温湿度检测、光强检测等部分流程图,并采用单片机实现对电动机的控制,最后使用 C语言编写了相应的程序。

本系统是基于单片机的农家菜园自动灌溉控制系统设计,以51单片机作为控制核心,实现菜园自动灌溉及智能控制系统的设计,能够实现对土壤温湿度以及光照强度的检测,并且根据设置的阈值及时间进行自动检测与灌溉。具体来说,本文的研究内容如下:

(1)本论文的研究内容为:自动灌溉系统的设计,包括土壤湿度检测、土壤温度检测、光照强度检测、水泵灌溉、定时自动灌溉。LCD显示屏和蓝牙无线接入。本课题的研究内容包括:灌区自动控制系统总体方案设计、硬件电路设计、软件流程设计等。本论文是一项细致而有效的自动化控制工作。其终极目的是实现自动灌溉和智能化控制,可通过设定的温度、湿度和光照强度来自动监测和灌溉。

(2)首先,本文对农户菜园自动灌溉控制系统的整体结构进行了阐述,并提出了硬件方面的设计,其中包括控制器的选择,温湿度检测模块的硬件选择,光照强度检测模块的选择,显示模块的选择,水泵灌溉模块的选择,蓝牙模块的设计。软件模块主要包括整个软件流程图、温湿度检测、光强检测等部分流程图,并采用单片机实现对电动机的控制,最后使用 C语言编写了相应的程序。

(3)根据硬件设计方案,实现了农户菜园自动灌溉控制系统的实际生产,并按“先局部后整体”的原则,对控制器模块、温湿度检测模块、光照强度检测模块、显示模块、水泵灌溉模块和蓝牙模块进行模块测试,并对整个系统进行全面测试,并将有关数据进行记录。通过试验,实现了菜园的自动灌溉和智能控制,可以检测土壤的温度、湿度和光照,并根据设定的阈值和时间,自动检测和灌溉,保证了测量精度和精度。

三,系统展示

四,核心代码展示

#include <reg52.h>
#include <intrins.h>

#define uchar unsigned char		// 以后unsigned char就可以用uchar代替
#define uint  unsigned int		// 以后unsigned int 就可以用uint 代替


sbit ADC_CS     = P1^6; 			// ADC0832的CS引脚
sbit ADC_CLK    = P1^7; 			// ADC0832的CLK引脚
sbit ADC_DAT    = P3^2; 			// ADC0832的DI/DO引脚
sbit SCK_P      = P1^0;				// 时钟芯片DS1302的SCK管脚
sbit SDA_P      = P1^1;				// 时钟芯片DS1302的SDA管脚
sbit RST_P      = P1^2;				// 时钟芯片DS1302的RST管脚
sbit LcdRs_P    = P1^3;       // 1602液晶的RS管脚       
sbit LcdRw_P    = P1^4;       // 1602液晶的RW管脚 
sbit LcdEn_P    = P1^5;       // 1602液晶的EN管脚

sbit KeyMode_P  = P3^3;				// 模式切换
sbit KeySet_P   = P3^4;				// 设置时间按键
sbit KeySet2_P  = P3^5;				// 设置时间模式的开关时间和光照控制强度
sbit KeyDown_P  = P3^6;				// 减按键
sbit KeyUp_P    = P3^7;				// 加按键
sbit Led_P      = P2^0;				// 指示灯
sbit led2=P2^1;
sbit fm=P2^2;
bit bjflag;

sbit ds=P3^1;
bit closeflag,openflag;
uchar gMode=1;								// 
uchar OpenHour    = 12;				// 开启水泵的小时
uchar OpenMinute  = 00;				// 开启水泵的分钟
uchar CloseHour   = 12;				// 关闭水泵的小时
uchar CloseMinute = 30;				// 关闭水泵的分钟
uchar gLight      = 30;				// 水泵开关的阈值

uchar wDu=20;
uchar X_sd=40;

uint wd=13,t;
uchar xsflag;

uchar bjcount;

uchar TimeBuff[7]={17,9,1,6,18,30,40};					// 时间数组,默认2017年9月1日,星期五,18:30:40
// TimeBuff[0] 代表年份,范围00-99
// TimeBuff[1] 代表月份,范围1-12
// TimeBuff[2] 代表日期,范围1-31
// TimeBuff[3] 代表星期,范围1-7
// TimeBuff[4] 代表小时,范围00-23
// TimeBuff[5] 代表分钟,范围00-59
// TimeBuff[6] 代表秒钟,范围00-59



/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
	uint i,j;
	for(i=0;i<time;i++)
		for(j=0;j<112;j++);
}
void delay(uint z)						  //延时函数
{
	uint x,y;
	for(x=z;x>0;x--)
		for(y=110;y>0;y--);
}

/*********************************************************/
// 1602液晶写命令函数,cmd就是要写入的命令
/*********************************************************/
void LcdWriteCmd(uchar cmd)
{ 
	LcdRs_P = 0;
	LcdRw_P = 0;
	LcdEn_P = 0;
	P0=cmd;
	DelayMs(2);
	LcdEn_P = 1;    
	DelayMs(2);
	LcdEn_P = 0;	
}


/*********************************************************/
// 1602液晶写数据函数,dat就是要写入的数据
/*********************************************************/
void LcdWriteData(uchar dat)
{
	LcdRs_P = 1; 
	LcdRw_P = 0;
	LcdEn_P = 0;
	P0=dat;
	DelayMs(2);
	LcdEn_P = 1;    
	DelayMs(2);
	LcdEn_P = 0;
}


/*********************************************************/
// 1602液晶初始化函数
/*********************************************************/
void LcdInit()
{
	LcdWriteCmd(0x38);        // 16*2显示,5*7点阵,8位数据口
	LcdWriteCmd(0x0C);        // 开显示,不显示光标
	LcdWriteCmd(0x06);        // 地址加1,当写入数据后光标右移
	LcdWriteCmd(0x01);        // 清屏
}


/*********************************************************/
// 液晶光标定位函数
/*********************************************************/
void LcdGotoXY(uchar line,uchar column)
{
	// 第一行
	if(line==0)        
		LcdWriteCmd(0x80+column); 
	// 第二行
	if(line==1)        
		LcdWriteCmd(0x80+0x40+column); 
}


/*********************************************************/
// 液晶输出字符串函数
/*********************************************************/
void LcdPrintStr(uchar *str)
{
	while(*str!='\0')
			LcdWriteData(*str++);
}


/*********************************************************/
// 液晶输出数字(0-99)
/*********************************************************/
void LcdPrintNum(uchar num)
{
	LcdWriteData(num/10+48);		// 十位
	LcdWriteData(num%10+48); 		// 个位
}


/*********************************************************/
// 显示模式
/*********************************************************/
void LcdPrintMode(uchar num)
{
	switch(num)			
	{
		case 1: LcdPrintStr("sdms");	break;
		case 2: LcdPrintStr("dsms");	break;
		default:												break;
	}
}


/*********************************************************/
// 液晶显示内容的初始化
/*********************************************************/
void LcdShowInit()
{
	LcdGotoXY(0,0);
	LcdPrintStr("20du   -     :  ");
	LcdGotoXY(1,0);
	LcdPrintStr("      sd:  gz:  ");
	LcdGotoXY(1,0);
	LcdPrintMode(gMode);
}



/*********************************************************/
// 刷新时间显示
/*********************************************************/
void FlashTime()
{
	LcdGotoXY(0,0);										// 年份
	LcdPrintNum(wd);
	LcdGotoXY(0,5);										// 月份
	LcdPrintNum(TimeBuff[1]);
	LcdGotoXY(0,8);										// 日期
	LcdPrintNum(TimeBuff[2]);
	LcdGotoXY(0,11);									// 小时
	LcdPrintNum(TimeBuff[4]);
	LcdGotoXY(0,14);									// 分钟
	LcdPrintNum(TimeBuff[5]);
	LcdGotoXY(0,13);									// 秒钟
	if(TimeBuff[6]%2==0)							// 秒钟是偶数显示冒号
		LcdWriteData(':');
	else															// 秒钟是奇数显示空格
		LcdWriteData(' ');
}


/*********************************************************/
// 初始化DS1302
/*********************************************************/
void DS1302_Init(void)
{
	RST_P=0;			// RST脚置低
	SCK_P=0;			// SCK脚置低
	SDA_P=0;			// SDA脚置低				
}


/*********************************************************/
// 从DS1302读出一字节数据
/*********************************************************/
uchar DS1302_Read_Byte(uchar addr) 
{
	uchar i;
	uchar temp;
	
	RST_P=1;								
	
	/* 写入目标地址:addr*/
	for(i=0;i<8;i++) 
	{     
		if(addr&0x01) 
			SDA_P=1;
		else 
			SDA_P=0;
		
		SCK_P=1;
		_nop_();
		SCK_P=0;
		_nop_();
		
		addr=addr>> 1;
	}
	
	/* 读出该地址的数据 */
	for(i=0;i<8;i++) 
	{
		temp=temp>>1;
		
		if(SDA_P) 
			temp|= 0x80;
		else 
			temp&=0x7F;
		
		SCK_P=1;
		_nop_();
		SCK_P=0;
		_nop_();
	}
	
	RST_P=0;
	
	return temp;
}


/*********************************************************/
// 向DS1302写入一字节数据
/*********************************************************/
void DS1302_Write_Byte(uchar addr, uchar dat)
{
	uchar i;
	
	RST_P = 1;
	
	/* 写入目标地址:addr*/
	for(i=0;i<8;i++) 
	{ 
		if(addr&0x01) 
			SDA_P=1;
		else 
			SDA_P=0;

		SCK_P=1;
		_nop_();
		SCK_P=0;
		_nop_();
		
		addr=addr>>1;
	}
	
	/* 写入数据:dat*/
	for(i=0;i<8;i++) 
	{
		if(dat&0x01) 
			SDA_P=1;
		else 
			SDA_P=0;
	
		SCK_P=1;
		_nop_();
		SCK_P=0;
		_nop_();
		
		dat=dat>>1;
	}
	
	RST_P=0;					
}


/*********************************************************/
// 向DS1302写入时间数据
/*********************************************************/
void DS1302_Write_Time() 
{
  uchar i;
	uchar temp1;
	uchar temp2;
	
	for(i=0;i<7;i++)			// 十进制转BCD码
	{
		temp1=(TimeBuff[i]/10)<<4;
		temp2=TimeBuff[i]%10;
		TimeBuff[i]=temp1+temp2;
	}
	
	DS1302_Write_Byte(0x8E,0x00);								// 关闭写保护 
	DS1302_Write_Byte(0x80,0x80);								// 暂停时钟 
	DS1302_Write_Byte(0x8C,TimeBuff[0]);				// 年 
	DS1302_Write_Byte(0x88,TimeBuff[1]);				// 月 
	DS1302_Write_Byte(0x86,TimeBuff[2]);				// 日 
	DS1302_Write_Byte(0x8A,TimeBuff[3]);				// 星期
	DS1302_Write_Byte(0x84,TimeBuff[4]);				// 时 
	DS1302_Write_Byte(0x82,TimeBuff[5]);				// 分
	DS1302_Write_Byte(0x80,TimeBuff[6]);				// 秒
	DS1302_Write_Byte(0x80,TimeBuff[6]&0x7F);		// 运行时钟
	DS1302_Write_Byte(0x8E,0x80);								// 打开写保护  
}



/*********************************************************/
// 从DS1302读出时间数据
/*********************************************************/
void DS1302_Read_Time()  
{ 
	uchar i;

	TimeBuff[0]=DS1302_Read_Byte(0x8D);						// 年 
	TimeBuff[1]=DS1302_Read_Byte(0x89);						// 月 
	TimeBuff[2]=DS1302_Read_Byte(0x87);						// 日 
	TimeBuff[3]=DS1302_Read_Byte(0x8B);						// 星期
	TimeBuff[4]=DS1302_Read_Byte(0x85);						// 时 
	TimeBuff[5]=DS1302_Read_Byte(0x83);						// 分 
	TimeBuff[6]=(DS1302_Read_Byte(0x81))&0x7F;		// 秒 

	for(i=0;i<7;i++)		// BCD转十进制
	{           
		TimeBuff[i]=(TimeBuff[i]/16)*10+TimeBuff[i]%16;
	}
}


/*********************************************************/
// ADC0832的时钟脉冲
/*********************************************************/
void WavePlus()
{
	_nop_();
	ADC_CLK = 1;
	_nop_();
	ADC_CLK = 0;
}


/*********************************************************/
// 获取指定通道的A/D转换结果
/*********************************************************/
uchar Get_ADC0832()
{ 
	uchar i;
	uchar dat1=0;
	uchar dat2=0;
	
	ADC_CLK = 0;				// 电平初始化
	ADC_DAT = 1;
	_nop_();
	ADC_CS = 0;
	WavePlus();					// 起始信号 
	ADC_DAT = 1;
	WavePlus();					// 通道选择的第一位
	ADC_DAT = 0;      
	WavePlus();					// 通道选择的第二位
	ADC_DAT = 1;
	
	for(i=0;i<8;i++)		// 第一次读取
	{
		dat1<<=1;
		WavePlus();
		if(ADC_DAT)
			dat1=dat1|0x01;
		else
			dat1=dat1|0x00;
	}
	
	for(i=0;i<8;i++)		// 第二次读取
	{
		dat2>>= 1;
		if(ADC_DAT)
			dat2=dat2|0x80;
		else
			dat2=dat2|0x00;
		WavePlus();
	}
	
	_nop_();						// 结束此次传输
	ADC_DAT = 1;
	ADC_CLK = 1;
	ADC_CS  = 1;   

	if(dat1==dat2)			// 返回采集结果
		return dat1;
	else
		return 0;
} 

uchar Get_ADC08322()
{ 
	uchar i;
	uchar dat1=0;
	uchar dat2=0;
	
	ADC_CLK = 0;				// 电平初始化
	ADC_DAT = 1;
	_nop_();
	ADC_CS = 0;
	WavePlus();					// 起始信号 
	ADC_DAT = 1;
	WavePlus();					// 通道选择的第一位
	ADC_DAT = 1;      
	WavePlus();					// 通道选择的第二位
	ADC_DAT = 1;
	
	for(i=0;i<8;i++)		// 第一次读取
	{
		dat1<<=1;
		WavePlus();
		if(ADC_DAT)
			dat1=dat1|0x01;
		else
			dat1=dat1|0x00;
	}
	
	for(i=0;i<8;i++)		// 第二次读取
	{
		dat2>>= 1;
		if(ADC_DAT)
			dat2=dat2|0x80;
		else
			dat2=dat2|0x00;
		WavePlus();
	}
	
	_nop_();						// 结束此次传输
	ADC_DAT = 1;
	ADC_CLK = 1;
	ADC_CS  = 1;   

	if(dat1==dat2)			// 返回采集结果
		return dat1;
	else
		return 0;
} 
/*********************************************************/
unsigned char UART_data; //定义串口接收数据变量
/*********************************************************/
// 按键扫描(设置当前时间)
/*********************************************************/
void KeyScanf1()
{
	if(KeySet_P==0 || UART_data == 'b')
	{
		UART_data = 'z';
		LcdGotoXY(0,13);				// 显示秒钟的冒号
		LcdWriteData(':');
		
		
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		

		
		LcdGotoXY(0,6);					// 定位光标到月份闪烁
		LcdWriteCmd(0x0f);			// 启动光标闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
			
		/* 调整月份 */
		while(1)
		{
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按键被下去
			{
				UART_data = 'z';
				if(TimeBuff[1]>1)						// 判断月份是否大于1		
					TimeBuff[1]--;						// 是的话就减去1
				LcdGotoXY(0,5);							// 光标定位到月份的位置
				LcdPrintNum(TimeBuff[1]);		// 刷新显示改变后的月份
				LcdGotoXY(0,6);							// 定位光标到月份闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按键被下去
			{
				UART_data = 'z';
				if(TimeBuff[1]<12)					// 判断月份是否小于12
					TimeBuff[1]++;						// 是的话就加上1
				LcdGotoXY(0,5);							// 光标定位到月份的位置
				LcdPrintNum(TimeBuff[1]);		// 刷新显示改变后的月份
				LcdGotoXY(0,6);							// 定位光标到月份闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0 || UART_data =='b')
			{
				UART_data = 'z';
				break;
			}
		}
		
		LcdGotoXY(0,9);					// 定位光标到日期闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 调整日期 */
		while(1)
		{
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按键被下去
			{
				UART_data = 'z';
				if(TimeBuff[2]>1)						// 判断日期是否大于1		
					TimeBuff[2]--;						// 是的话就减去1
				LcdGotoXY(0,8);							// 光标定位到日期的位置
				LcdPrintNum(TimeBuff[2]);		// 刷新显示改变后的日期
				LcdGotoXY(0,9);							// 定位光标到日期闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按键被下去
			{
				UART_data = 'z';
				if(TimeBuff[2]<31)					// 判断日期是否小于31
					TimeBuff[2]++;						// 是的话就加上1
				LcdGotoXY(0,8);							// 光标定位到日期的位置
				LcdPrintNum(TimeBuff[2]);		// 刷新显示改变后的日期
				LcdGotoXY(0,9);							// 定位光标到日期闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0 || UART_data == 'b')
			{
				UART_data = 'z';
				break;
			}
		}
		
		LcdGotoXY(0,12);				// 定位光标到小时闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		
		/* 调整小时 */
		while(1)
		{
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按键被下去
			{
				UART_data = 'z';
				if(TimeBuff[4]>0)						// 判断小时是否大于0
					TimeBuff[4]--;						// 是的话就减去1
				LcdGotoXY(0,11);						// 光标定位到小时的位置
				LcdPrintNum(TimeBuff[4]);		// 刷新显示改变后的小时
				LcdGotoXY(0,12);						// 定位光标到小时闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按键被下去
			{
				UART_data = 'z';
				if(TimeBuff[4]<23)					// 判断小时是否小于23
					TimeBuff[4]++;						// 是的话就加上1
				LcdGotoXY(0,11);						// 光标定位到小时的位置
				LcdPrintNum(TimeBuff[4]);		// 刷新显示改变后的小时
				LcdGotoXY(0,12);						// 定位光标到小时闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0 || UART_data == 'b')
			{
				UART_data = 'z';
				break;
			}
		}
		
		LcdGotoXY(0,15);				// 定位光标到分钟闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 调整分钟 */
		while(1)
		{
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按键被下去
			{
				UART_data = 'z';
				if(TimeBuff[5]>0)						// 判断分钟是否大于0
					TimeBuff[5]--;						// 是的话就减去1
				LcdGotoXY(0,14);						// 光标定位到分钟的位置
				LcdPrintNum(TimeBuff[5]);		// 刷新显示改变后的分钟
				LcdGotoXY(0,15);						// 定位光标到分钟闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按键被下去
			{
				UART_data = 'z';
				if(TimeBuff[5]<59)					// 判断分钟是否小于59
					TimeBuff[5]++;						// 是的话就加上1
				LcdGotoXY(0,14);						// 光标定位到分钟的位置
				LcdPrintNum(TimeBuff[5]);		// 刷新显示改变后的分钟
				LcdGotoXY(0,15);						// 定位光标到分钟闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0 || UART_data == 'b')
			{
				UART_data = 'z';
				break;
			}
		}
		
		/* 退出前的设置 */
		LcdWriteCmd(0x0C);			// 关闭光标闪烁
		DS1302_Write_Time();		// 把新设置的时间值存入DS1302芯片
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
	}
}
uint temp,mm;uchar i;float f_temp;
/*******************************************************
温度函数
*******************************************************/
void dsreset(void)					   //下边是温度获取子程衼E
{
	uint i;
	ds=0;
	i=103;
	while(i>0)i--;
	ds=1;
	i=4;
	while(i>0)i--;
}
bit tempreadbit(void)				   //读一位
{
	uint i;
	bit dat;
	ds=0;i++;
	ds=1;i++;i++;
	dat=ds;
	i=8;while(i>0)i--;
	return(dat);
}
uchar tempread(void)					 //获取温度
{
	uchar i,j,dat;
	dat=0;
	for(i=1;i<=8;i++)
	{
		j=tempreadbit();
		dat=(j<<7)|(dat>>1);
	}
	return(dat);
}
void tempwritebyte(uchar dat)			   //写一个字节
{
	uint i;
	uchar j;
	bit testb;
	for(j=1;j<=8;j++)
	{
		testb=dat&0x01;
		dat=dat>>1;
		if(testb)
		{
			ds=0;
			ds=1;
			i=8;while(i>0)i--;
		}
		else
		{
			ds=0;
			i=8;while(i>0)i--;
			ds=1;
			i++;i++;
		}
	}
}
void tempchange(void)					   //温度转换
{
	dsreset();
	delay(1);
	tempwritebyte(0x44);
}
uint get_temp()							//获取温度
{
	uchar a,b;
	dsreset();
	delay(1);
	tempwritebyte(0xcc);
	tempwritebyte(0xbe);
	a=tempread();
	b=tempread();
	temp=b;
	temp<<=8;
	temp=temp|a;
	f_temp=temp*0.0625;
	temp=f_temp*10+0.5;
	f_temp=f_temp+0.05;
	return temp;
}
/***********************************/

/*********************************************************/
// 按键扫描(设置水泵的动作)
/*********************************************************/
void KeyScanf2()
{
	if(KeySet2_P==0 || UART_data == 'c')
	{
		UART_data = 'z';
		LcdGotoXY(0,0);										// 光标定位
		LcdPrintStr(" OpenTime   :   ");	// 显示第1行内容
		LcdGotoXY(1,0);										// 光标定位
		LcdPrintStr("CloseTime   :   ");	// 显示第2行内容
		LcdGotoXY(0,10);									// 光标定位
		LcdPrintNum(OpenHour);						// 显示开启水泵的小时
		LcdGotoXY(0,13);									// 光标定位
		LcdPrintNum(OpenMinute);					// 显示开启水泵的分钟
		LcdGotoXY(1,10);									// 光标定位
		LcdPrintNum(CloseHour);						// 显示关闭水泵的小时
		LcdGotoXY(1,13);									// 光标定位
		LcdPrintNum(CloseMinute);					// 显示关闭水泵的分钟		
		
		LcdWriteCmd(0x0f);							// 启动光标闪烁
		LcdGotoXY(0,11);								// 定位光标
		DelayMs(10);										// 延时等待,消除按键按下的抖动
		while(!KeySet2_P);							// 等待按键释放
		DelayMs(10);										// 延时等待,消除按键松开的抖动
		
		/* 调整开启的小时 */
		while(1)
		{
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按键被下去
			{
				UART_data ='z';
				if(OpenHour>0)							// 判断小时是否大于0		
					OpenHour--;								// 是的话就减去1
				LcdGotoXY(0,10);						// 光标定位
				LcdPrintNum(OpenHour);			// 刷新显示改变后的小时
				LcdGotoXY(0,11);						// 定位光标
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按键被下去
			{
				UART_data = 'z';
				if(OpenHour<23)							// 判断小时是否小于23
					OpenHour++;								// 是的话就加上1
				LcdGotoXY(0,10);						// 光标定位
				LcdPrintNum(OpenHour);			// 刷新显示改变后的小时
				LcdGotoXY(0,11);						// 定位光标
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet2_P==0 || UART_data == 'c')
			{
				UART_data = 'z';
				break;
			}
		}
		
		LcdGotoXY(0,14);								// 定位光标
		DelayMs(10);										// 延时等待,消除按键按下的抖动
		while(!KeySet2_P);							// 等待按键释放
		DelayMs(10);										// 延时等待,消除按键松开的抖动
		
		/* 调整开启的分钟 */
		while(1)
		{
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按键被下去
			{
				UART_data = 'z';
				if(OpenMinute>0)						// 判断分钟是否大于0
					OpenMinute--;							// 是的话就减去1
				LcdGotoXY(0,13);						// 光标定位
				LcdPrintNum(OpenMinute);		// 刷新显示改变后的分钟
				LcdGotoXY(0,14);						// 定位光标
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按键被下去
			{
				UART_data = 'z';
				if(OpenMinute<59)						// 判断分钟是否小于59
					OpenMinute++;							// 是的话就加上1
				LcdGotoXY(0,13);						// 光标定位
				LcdPrintNum(OpenMinute);		// 刷新显示改变后的分钟
				LcdGotoXY(0,14);						// 定位光标
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet2_P==0 || UART_data == 'c')
			{
				UART_data = 'z';
				break;
			}
		}
		
		LcdGotoXY(1,11);								// 定位光标
		DelayMs(10);										// 延时等待,消除按键按下的抖动
		while(!KeySet2_P);							// 等待按键释放
		DelayMs(10);										// 延时等待,消除按键松开的抖动
		
		/* 调整关闭的小时 */
		while(1)
		{
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按键被下去
			{
				UART_data = 'z';
				if(CloseHour>0)							// 判断小时是否大于0		
					CloseHour--;							// 是的话就减去1
				LcdGotoXY(1,10);						// 光标定位
				LcdPrintNum(CloseHour);			// 刷新显示改变后的小时
				LcdGotoXY(1,11);						// 定位光标
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按键被下去
			{
				UART_data = 'z';
				if(CloseHour<23)						// 判断小时是否小于23
					CloseHour++;							// 是的话就加上1
				LcdGotoXY(1,10);						// 光标定位
				LcdPrintNum(CloseHour);			// 刷新显示改变后的小时
				LcdGotoXY(1,11);						// 定位光标
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet2_P==0 || UART_data == 'c')
			{
				UART_data = 'z';
				break;
			}
		}
		
		LcdGotoXY(1,14);								// 定位光标
		DelayMs(10);										// 延时等待,消除按键按下的抖动
		while(!KeySet2_P);							// 等待按键释放
		DelayMs(10);										// 延时等待,消除按键松开的抖动
		
		/* 调整关闭的分钟 */
		while(1)
		{
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按键被下去
			{
				UART_data = 'z';
				if(CloseMinute>0)						// 判断分钟是否大于0
					CloseMinute--;						// 是的话就减去1
				LcdGotoXY(1,13);						// 光标定位
				LcdPrintNum(CloseMinute);		// 刷新显示改变后的分钟
				LcdGotoXY(1,14);						// 定位光标
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按键被下去
			{
				UART_data = 'z';
				if(CloseMinute<59)					// 判断分钟是否小于59
					CloseMinute++;						// 是的话就加上1
				LcdGotoXY(1,13);						// 光标定位
				LcdPrintNum(CloseMinute);		// 刷新显示改变后的分钟
				LcdGotoXY(1,14);						// 定位光标
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet2_P==0 || UART_data == 'c')
			{
				UART_data = 'z';
				break;
			}
		}
		
		DelayMs(10);										// 延时等待,消除按键按下的抖动
		while(!KeySet2_P);							// 等待按键释放
		DelayMs(10);										// 延时等待,消除按键松开的抖动
		
		/* 光照强度的设置 */
		LcdWriteCmd(0x0C);								// 关闭光标闪烁
		LcdGotoXY(0,0);										// 光标定位
		LcdPrintStr("   Light Set    ");	// 显示第1行内容
		LcdGotoXY(1,0);										// 光标定位
		LcdPrintStr("                ");	// 显示第2行内容
		LcdGotoXY(1,7);										// 光标定位
		LcdPrintNum(gLight);							// 显示水泵的光线控制强度阈值
		
		while(1)
		{
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按键被下去
			{
				UART_data = 'z';
				if(gLight>0)								// 判断光线阈值是否大于0
					gLight--;									// 是的话就减去1
				LcdGotoXY(1,7);							// 光标定位
				LcdPrintNum(gLight);				// 刷新显示改变后的光线阈值
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按键被下去
			{
				UART_data = 'z';
				if(gLight<99)								// 判断光线阈值是否小于59
					gLight++;									// 是的话就加上1
				LcdGotoXY(1,7);							// 光标定位
				LcdPrintNum(gLight);				// 刷新显示改变后的光线阈值
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet2_P==0 || UART_data == 'c')
			{
				UART_data = 'z';
				break;
			}
		}

		DelayMs(10);										// 延时等待,消除按键按下的抖动
		while(!KeySet2_P);							// 等待按键释放
		DelayMs(10);										// 延时等待,消除按键松开的抖动

	// 		设置温度
		LcdWriteCmd(0x0C);								// 关闭光眮E了?
		LcdGotoXY(0,0);										// 光眮Eㄎ?
		LcdPrintStr("   Wendu Set    ");	// 显示第1行内容
		LcdGotoXY(1,0);										// 光眮Eㄎ?
		LcdPrintStr("                ");	// 显示第2行内容
		LcdGotoXY(1,7);										// 光眮Eㄎ?
		LcdPrintNum(wDu);							// 显示水泵的光线控制强度阈值	
		while(1){
		 	LcdGotoXY(1,7);										// 光眮Eㄎ?
			LcdPrintNum(wDu);							// 显示水泵的光线控制强度阈值
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按紒E幌氯?
			{
				UART_data = 'z';
				if(wDu>0)								// 判断光线阈值是否大于0
					wDu--;									// 是的话就减去1
				DelayMs(300);								// 延时0.3脕E笥?
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按紒E幌氯?
			{
				UART_data = 'z';
				if(wDu<99)								// 判断光线阈值是否小于59
					wDu++;									// 是的话就加上1
				DelayMs(300);								// 延时0.3脕E笥?
			}
			if(KeySet2_P==0 || UART_data == 'c')
			{
				UART_data = 'z';
				break;
			}
		}

			DelayMs(10);										// 延时等待,消除按键按下的抖动
		while(!KeySet2_P);							// 等待按键释放
		DelayMs(10);										// 延时等待,消除按键松开的抖动

	// 		设置湿度
		LcdWriteCmd(0x0C);								// 关闭光眮E了?
		LcdGotoXY(0,0);										// 光眮Eㄎ?
		LcdPrintStr("   Shidu Set    ");	// 显示第1行内容
		LcdGotoXY(1,0);										// 光眮Eㄎ?
		LcdPrintStr("                ");	// 显示第2行内容
		LcdGotoXY(1,7);										// 光眮Eㄎ?
		LcdPrintNum(X_sd);							// 显示水泵的光线控制强度阈值	
		while(1){
		 	LcdGotoXY(1,7);										// 光眮Eㄎ?
			LcdPrintNum(X_sd);							// 显示水泵的光线控制强度阈值
			if(KeyDown_P==0 || UART_data == 'd')							// 如果减按紒E幌氯?
			{
				UART_data = 'z';
				if(X_sd>0)								// 判断光线阈值是否大于0
					X_sd--;									// 是的话就减去1
				DelayMs(300);								// 延时0.3脕E笥?
			}
			
			if(KeyUp_P==0 || UART_data == 'e')								// 如果加按紒E幌氯?
			{
				UART_data = 'z';
				if(X_sd<99)								// 判断光线阈值是否小于59
					X_sd++;									// 是的话就加上1
				DelayMs(300);								// 延时0.3脕E笥?
			}
			if(KeySet2_P==0 || UART_data == 'c')
			{
				UART_data = 'z';
				break;
			}
		}
		
		/* 退出前的设置 */
		LcdShowInit();					// 液晶显示内容初始化
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet2_P);			// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
	}
}


/*********************************************************/
// 按键扫描(模式切换)
/*********************************************************/
void KeyScanf3()
{
	if(KeyMode_P==0 || UART_data == 'a')
	{
		UART_data = 'z';
		gMode++;							// 切换到下一模式
		if(gMode==3)				// 如果到尽头了
			gMode=1;						// 回到第一种模式
		LcdGotoXY(1,0);				// 光标定位
		LcdPrintMode(gMode);	// 显示模式
		DelayMs(10);					// 去除按键按下的抖动
		while(!KeyMode_P);		// 等待按键是否
		DelayMs(10);					// 去除按键松开的抖动
	Led_P=1;
	bjflag=0;
	}
}


/*********************************************************/
// 开窗
/*********************************************************/
void Open()
{

	Led_P=0;
	bjflag=1;
}



/*********************************************************/
// 关窗
/*********************************************************/
void Close()
{

	Led_P=1;
	bjflag=0;
}



/*********************************************************/
// 主函数
/*********************************************************/
void main()
{
	uchar light;
	uchar sd;
	
	LcdInit();			// 执行液晶初始化	
	DS1302_Init();	// 时钟芯片的初始化
	LcdShowInit();	// 液晶显示内容的初始化
	
	TMOD=0x21;//定时器0  模式1  16位定时模式
	EA=1;			   //开启总中断	
	ES = 1; //允许UART串口的中断
	PCON = 0x80;	//波特率倍频(屏蔽本句波特率为2400)
	SCON = 0x50;	//串口工作方式1,允许串口接收(SCON = 0x40 时禁止串口接收)
	TH1 = 0xFa;	//定时器初值高8位设置   //12MHZ晶振,波特率为4800 0xf3
	TL1 = 0xFa;	//定时器初值低8位设置   //11.0592MHZ晶振,波特率为4800 0xf4   9600  0xfa   19200  0xfd
	TR1=1;
	
	if(DS1302_Read_Byte(0x81)>=128)			// 判断时钟芯片是否正在运行
	{
		DS1302_Write_Time();							// 如果没有,则初始化一个时间
	}
	
	while(1)
	{
		tempchange();
		t=get_temp();
		if(t>=0&&t<=1250)  //温度合法范围,不在这个范围就是没有获取到合适的值
		{
			wd=t/10;
		}
			


		DS1302_Read_Time();				// 获取当前时钟芯片的时间,存在数组time_buf中
		FlashTime();							// 刷新时间显示

		light=Get_ADC08322();			// 读取光照强度
		sd=Get_ADC0832();
		sd=sd/2.5;
		light=light/2.5;					// 缩小光照检测结果(在0-99)
		if(light>99)							// 如果大于99
			light=99;								// 则依然保持99
		LcdGotoXY(1,14);					// 光标定位
		LcdPrintNum(light);				// 显示光照强度
		LcdGotoXY(1,9);					// 光标定位
		LcdPrintNum(sd);				// 显示湿度
		
		KeyScanf1();							// 按键扫描(时间的设置)
		KeyScanf2();							// 按键扫描(阈值的设置)
		KeyScanf3();							// 按键扫描(模式切换)
	
		/*土壤湿度控制模式*/
		if(gMode==1)
		{
			if(sd<X_sd)  //湿度小于阈值开启
				Open();
			else
				Close();	
		}
		
		/*时间控制模式*/
		if(gMode==2)
		{
			if((TimeBuff[4]==CloseHour)&&(TimeBuff[5]==CloseMinute)&&(TimeBuff[6]==0))	// 如果到了关的时间	
			{
				Close();
			}
			if((TimeBuff[4]==OpenHour)&&(TimeBuff[5]==OpenMinute)&&(TimeBuff[6]==0))		// 如果到了开的时间	
			{
				Open();
			}	
		}
		
		if(light<gLight)		// 当前光线小于设置的阈值
		{
			led2=0;//开灯
		}else{
			led2=1;
		}
		if(wd<wDu || light<gLight)		// 当前温度小于设置的阈值
		{
			bjflag=1;
		}else{
			bjflag=0;
		}
		
		if(bjflag==1){
			bjcount++;
			if(bjcount>5){
				bjcount=0;
				fm=0;DelayMs(100);DelayMs(100);fm=1;
			}
		}else{
			fm=1;
		}
		
		DelayMs(100);							// 延时0.1秒
	}
}
void UART_R ( ) interrupt 4  using 1  //切换寄存器组到1
{ 
	
	RI = 0;			//令接收中断标志位为0(软件清零)
		UART_data = SBUF;	//将接收到的数据送入变量 UART_data
}

五,相关作品展示

基于Java开发、Python开发、PHP开发、C#开发等相关语言开发的实战项目

基于Nodejs、Vue等前端技术开发的前端实战项目

基于微信小程序和安卓APP应用开发的相关作品

基于51单片机等嵌入式物联网开发应用

基于各类算法实现的AI智能应用

基于大数据实现的各类数据管理和推荐系统

 

 

猜你喜欢

转载自blog.csdn.net/whirlwind526/article/details/133432489
今日推荐