撼山岳—第四届之模拟智能灌溉系统

声明:代码确实写的不好,用的都是最笨的方法实现功能,不喜勿喷

第四届的题目明显和之前我写的那几届不同,难度也算有吧,但是不是很大。主要是这次的题目用到了AD转换和EEPROM,对于之前没有用过的东西,有一点困难就是要熟悉使用。这次我也是写了五个半小时,虽然也是写出来了,但是遗憾的是我没有缩短时间。

下面来看一下题目要求:
 

撼山岳—第四届之模拟智能灌溉系统_第1张图片

撼山岳—第四届之模拟智能灌溉系统_第2张图片

撼山岳—第四届之模拟智能灌溉系统_第3张图片

撼山岳—第四届之模拟智能灌溉系统_第4张图片

第一眼看这个题目把我下一跳,一下七条要求,平常的都是五条,没想到这个一下搞出了七条。其实仔细一看你就那个样子吧,没什么特别的地方。

下面说一下我自己的思路:

第一步:实现自动模式下的数码管显示和阈值比较以及L1的亮灭、继电器的开关

第二步:实现在手动模式下的数码管显示和阈值比较

第三步:实现在手动模式下各个按键的功能

第四步:实现自动模式下,阈值的设定以及保存至EEPROM

下面看一下代码:

第一:按键程序

#include "key.h"
uchar KeyS7_mode;		//模式切换标志位
uchar KeyS6_buzzer;//蜂鸣器控制位
uchar KeyS5_relayo;//开继电器控制位
uchar KeyS4_relayc;//关继电器控制位
uchar KeyS6_set;		//在自动模式下设置阈值标志位
uchar KeyS5_add;		//在自动模式下阈值加一标志位
uchar KeyS4_duc;		//在自动模式下阈值减一标志位
//独立按键扫描函数
void D_keyscan()
{
	if(P30==0)
	{
		Delay5ms();
		if(P30==0)					//按键S7
		{
			KeyS7_mode += 1;
			if(KeyS7_mode == 2)
				KeyS7_mode = 0;
		}
		while(!P30);
	}
	else if(P31==0)				//按键S6
	{
		Delay5ms();
		if(P31==0)
		{
			KeyS6_set += 1;
			KeyS6_buzzer += 1;
			if(KeyS6_buzzer == 2)
				KeyS6_buzzer = 0;
		}
		while(!P31);
	}
	else if(P32==0)				//按键S5
	{
		Delay5ms();
		if(P32==0)
		{
			KeyS5_add = 1;
			KeyS5_relayo = 1;
		}
		while(!P32);
	}
	else if(P33==0)				//按键S4
	{
		Delay5ms();
		if(P33==0)
		{
			KeyS4_duc = 1;
			KeyS4_relayc = 1;
		}		
		while(!P33);
	}
}

void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

第二:数码管程序

#include "shuma.h"
u8 shu_tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XC6,0XFF};//0XC6是英文C
uchar yi,er,san,si,wu,liu,qi,ba;

//第一和第二个数码管
void Display1_2(uchar yi,uchar er)
{
		P2=0XC0;//打开位选573   U8
		P0=0X01;//选择第一个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[yi];
		Delay1ms();Delay1ms();
		
		P2=0XC0;//打开位选573   U8
		P0=0X02;//选择第二个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[er];
		Delay1ms();Delay1ms();
}	
//第四和第五个数码管
void Display4_5(uchar si,uchar wu)
{
		P2=0XC0;//打开位选573   U8
		P0=0X08;//选择第一个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[si];
		Delay1ms();Delay1ms();
		
		P2=0XC0;//打开位选573   U8
		P0=0X10;//选择第一个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[wu];
		Delay1ms();Delay1ms();
}
//第三和第六个数码管
void Display3_6(uchar san,uchar liu)
{
		P2=0XC0;//打开位选573   U8
		P0=0X04;//选择第三个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[san];
		Delay1ms();Delay1ms();
		
		P2=0XC0;//打开位选573   U8
		P0=0X20;//选择第四个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[liu];
		Delay1ms();Delay1ms();
}

//第七和第八个数码管
void Display7_8(uchar qi,uchar ba)
{
		P2=0XC0;//打开位选573   U8
		P0=0X40;//选择第一个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[qi];
		Delay1ms();Delay1ms();
		
		P2=0XC0;//打开位选573   U8
		P0=0X80;//选择第一个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[ba];
		Delay1ms();Delay1ms();
}


void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}



第三:AD程序(AD转换是我第一次在省赛中遇到,也是自己写好的封装函数)

#include "ad.h"
#include "eeprom.h"
//AD开始函数
void IICAD_statrt(void)
{	
	SDA = 1;
	_nop_();
	SCL = 1;
	_nop_();
	SDA = 0;
	_nop_();
	SCL = 0;
}
//AD停止函数
void IICAD_stop(void)
{
	SDA = 0;
	_nop_();
	SCL = 1;
	_nop_();
	SDA = 1;

}
//向AD写一个字节
void AD_writebyte(uchar dat)
{
	uchar i;
	for(i=0;i<8;i++)
	{
		SCL = 0;
		_nop_();
		SDA = dat&0x80;
		_nop_();
		SCL = 1;
		dat<<=1;
	}
	SCL = 0;
	_nop_();
}	

//应答函数
uchar ACK_AD(void)
{
	SCL = 1;
	IICAD_delay(5);
	if(SDA == 1)
	{
		SCL = 0;
		Delay100us();
		IICAD_stop();
		return 0;
	}
	else
	{
		SCL = 0;
		Delay100us();
		return 1;
	}
}
//从AD中读取数据
uchar IICAD_read(uchar add)
{
	uchar temp;
	IICAD_statrt();
	AD_writebyte(0x90);
	ACK_AD();
	AD_writebyte(add);
	ACK_AD();
	
	IICAD_statrt();
	AD_writebyte(0x91);
	ACK_AD();
	temp = IICAD_readbyte();
	IICAD_stop();
	//现在显示的是0-255,如果需要显示0-100可以加代码(temp = 0.39*temp;)
	return temp;
}
//从AD中读取一个字节
uchar IICAD_readbyte()
{
	uchar dat;
	uchar i;
	SCL = 0;
	_nop_();
	SCL = 1;
	_nop_();
	for(i=0;i<8;i++)
	{
		SCL = 1;
		dat<<=1;
		if(SDA)
		{
			dat |= 0x01;
		}
		SCL = 0;
	}
	return dat;
}

void IICAD_delay(uchar a)
{
	do
	{
		_nop_();
	}
	while(a--);
}
void Delay100us()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 2;
	j = 15;
	do
	{
		while (--j);
	} while (--i);
}

第四:EEPROM程序(EEPROM转换是我第一次在省赛中遇到,也是自己写好的封装函数)

#include "eeprom.h"
//IIC开始函数
void IICEE_statrt(void)
{	
	SDA = 1;
	_nop_();
	SCL = 1;
	_nop_();
	SDA = 0;
	_nop_();
	SCL = 0;
}
//IIC停止函数
void IICEE_stop(void)
{
	SDA = 0;
	_nop_();
	SCL = 1;
	_nop_();
	SDA = 1;

}
//将地址和数据写进IIC
void IICEE_write(uchar add ,uchar dat)
{
	IICEE_statrt();
	EE_writebyte(0xa0);
	ACK_EE();
	EE_writebyte(add);
	ACK_EE();
	EE_writebyte(dat);
	ACK_EE();	
	IICEE_stop();
	Delay10ms();Delay10ms();//一定要加
}
//向IIC写一个字节
void EE_writebyte(uchar dat)
{
	uchar i;
	for(i=0;i<8;i++)
	{
		SCL = 0;
		_nop_();
		SDA = dat&0x80;
		_nop_();
		SCL = 1;
		dat<<=1;
	}
	SCL = 0;
	_nop_();
}	
void IICEE_delay(uchar a)
{
	do
	{
		_nop_();
	}
	while(a--);
}
//应答函数
uchar ACK_EE(void)
{
	SCL = 1;
	IICEE_delay(5);
	if(SDA == 1)
	{
		SCL = 0;
		IICEE_stop();
		return 0;
	}
	else
	{
		SCL = 0;
		return 1;
	}
}
//从IIC中读取数据
uchar IICEE_read(uchar add)
{
	uchar temp;
	IICEE_statrt();
	EE_writebyte(0xa0);
	ACK_EE();
	EE_writebyte(add);
	ACK_EE();
	
	IICEE_statrt();
	EE_writebyte(0xa1);
	ACK_EE();
	temp = IICEE_readbyte();
	IICEE_stop();
	Delay10ms();
	return temp;
}
//从IIC中读取一个字节
uchar IICEE_readbyte()
{
	uchar dat;
	uchar i;
	SCL = 0;
	_nop_();
	SCL = 1;
	_nop_();
	for(i=0;i<8;i++)
	{
		SCL = 1;
		dat<<=1;
		if(SDA)
		{
			dat |= 0x01;
		}
		SCL = 0;
	}
	return dat;
}

void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 108;
	j = 145;
	do
	{
		while (--j);
	} while (--i);
}

AD的程序和EEPROM的程序非常相似,只是有两个地址不同而已。

第五:初始化程序(.c)

#include "system.h"

void Init(void)
{
	P2=0XA0;//打开蜂鸣器,继电器控制端
	P0=0X00;//关闭蜂鸣器,继电器
	
	P2=0X80;//打开LED灯控制端
	P0=0XFF;//关闭LED灯
	
	P2=0XC0;//打开数码管片选控制端
	P0=0XFF;//选择所有数码管
	
	P2=0XFF;//打开数码管段选控制端
	P0=0XFF;//关闭所有数码管段选
}

初始化程序(.h)

#ifndef __SYSTEM_H
#define __SYSTEM_H
#include "STC15F2K60S2.H"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
typedef unsigned int u16;
typedef unsigned char u8;
void Init(void);


#endif

最后:主函数程序

#include "system.h"
#include "shuma.h"
#include "key.h"
#include "eeprom.h"
#include "ds1302.h"
#include "ad.h"
extern uchar yi,er,san,si,wu,liu,qi,ba;
extern uchar shijian[7];
extern uchar KeyS7_mode;		//模式切换标志位
extern uchar KeyS6_buzzer;//蜂鸣器控制位
extern uchar KeyS5_relayo;//开继电器控制位
extern uchar KeyS4_relayc;//关继电器控制位
extern uchar KeyS6_set;		//自动模式下湿度阈值调整控制位
extern uchar KeyS5_add;		//自动模式下湿度阈值加标志位
extern uchar KeyS4_duc;		//自动模式下湿度阈值减标志位
uchar AD_num;							//读取AD数据
uchar Set_z1_flag;				//完成两种模式按键的清零功能
uchar Set_z0_flag;				//完成两种模式按键的清零功能
uchar ba_flag1;						//实现在自动模式下按下S5加一
uchar qi_flag1;						//实现在自动模式下按下S5当个位满十进一
uchar ba_flag2;						//实现在自动模式下按下S4减一
uchar qi_flag2;						//实现在自动模式下按下S4当个位不够减的时候向高位借位
uchar ba_num =1;						
uchar qi_num;
uchar duc_flag;						
uchar IIC_num;						//读取EEPROM中的数据
uchar Set_qi;							//将设定好的阈值保存
uchar Set_ba;							//将设定好的阈值保存
void main(void)
{
	Init();
	DS13Init();
	while(1)
	{
		Read_Time();//读取时间
		D_keyscan();
		if(KeyS7_mode == 0)									//如果S7没有按下进入自动模式
		{
				if(Set_z0_flag == 0)					//完成两种模式按键的清零功能	
				{
					KeyS6_buzzer = 0;
					KeyS5_relayo = 0;
					KeyS4_relayc = 0;
					Set_z0_flag = 1;
				}
				AD_num = IICAD_read(0x03);//读取滑动变阻器的值
				if(AD_num <= 128)					//模拟湿度,最大值255,小于等于百分之五十,继电器开,L1亮
				{
					P2=0XA0;P0=0X10;
					P2=0X80;P0=0XFE;
				}
				else 											//模拟湿度,最大值255,大于百分之五十,继电器关,L1灭
				{
					P2=0XA0;P0=0X00;
					P2=0X80;P0=0XFF;
				}					

				if(KeyS6_set == 1)					//在自动模式下按下S6进入湿度阈值设置界面
				{
					yi = 10;er = 10;san = 12;
					si = 12;wu = 12;liu = 12;
					if(KeyS5_add == 1)						//如果S5按下实现阈值加一的功能
					{
						if((qi == 9) && (ba == 9))		//如果到达最大值就不再加一
						{
							KeyS5_add = 0;
						}
						else
						{
								ba_flag1++;									//记录按键按下的次数
								ba_num = (AD_num*100/256)%10 + ba_flag1;
								if((ba_num >= 10) && (ba_num < 20))		//判断加上按键按下次数之后数值的范围
								{
									ba = ba_num - 10;
								}
								else if((ba_num >= 20) && (ba_num < 30))
								{
									ba = ba_num - 20;
								}
								else if((ba_num >= 30) && (ba_num < 40))
								{
									ba = ba_num - 30;
								}
								else if((ba_num >= 40) && (ba_num < 50))
								{
									ba = ba_num - 40;
								}
								else if((ba_num >= 50) && (ba_num < 60))
								{
									ba = ba_num - 50;
								}
								else if((ba_num >= 60) && (ba_num < 70))
								{
									ba = ba_num - 60;
								}
								else if((ba_num >= 70) && (ba_num < 80))
								{
									ba = ba_num - 70;
								}
								else if((ba_num >= 80) && (ba_num < 90))
								{
									ba = ba_num - 80;
								}
								else 
								{
									ba = (AD_num*100/256)%10 + ba_flag1;
								}
								if(ba_num == 10)		//实现满十进一
									qi_flag1 = 1;
								if(ba_num == 20)
									qi_flag1 = 2;
								if(ba_num == 30)
									qi_flag1 = 3;
								if(ba_num == 40)
									qi_flag1 = 4;
								if(ba_num == 50)
									qi_flag1 = 5;
								if(ba_num == 60)
									qi_flag1 = 6;
								if(ba_num == 70)
									qi_flag1 = 7;
								if(ba_num == 80)
									qi_flag1 = 8;
								if(ba_num == 90)
									qi_flag1 = 9;
								qi = (AD_num*100/256)/10 + qi_flag1;								
						}
						KeyS5_add = 0;
					}
					if(KeyS4_duc == 1)								//如果S4按下实现阈值减一的功能
					{
						if((qi == 0) && (ba == 0))			//如果减到最小值不再减一
						{
							KeyS4_duc = 0;
						}
						else 
						{
							ba_flag2++;										//记录按键S4按下的次数
							if(ba_num != 0)								
							{
								if(duc_flag == 1)					//向十位借位之后的个位数值
								{
									ba_num = 9 - ba_flag2;
									ba = ba_num;
								}
								else 
								{
									ba_num = (AD_num*100/256)%10 - ba_flag2;	//如果不需要借位就一直减一
									ba = (AD_num*100/256)%10 - ba_flag2;
									qi = (AD_num*100/256)/10 ;									
								}
							}
							else if(ba_num == 0)			//个位已经减到零
							{
								qi_flag2 += 1;
								ba_flag2 = 0;							//将按键按下的次数清零,便于个位数字的计算
								ba_num = 1;
								duc_flag = 1;
								qi = (AD_num*100/256)/10 - qi_flag2;		//控制十位减被借位减一
								ba = 9;
								
							}							
						}
						KeyS4_duc = 0;
					}
					Set_qi = qi;				//保存设定好的湿度阈值,用于写进EEPROM
					Set_ba = ba;				//保存设定好的湿度阈值,用于写进EEPROM
				}
				else if(KeyS6_set == 2)	//按键S6第二次按下,退出阈值设置模式
				{
					IICEE_write(0x00,0);//初始化
					IICEE_write(0x00,(Set_qi*10+Set_ba));		//将保存的阈值写入EEPORM
					IIC_num = IICEE_read(0x00);		
					KeyS6_set = 0;
				}
				else 
				{
					yi = shijian[2]/10;er = shijian[2]%10;		//显示时间
					san = 10;si = shijian[1]/10;
					wu = shijian[1]%10;liu = 12;					
					qi = (AD_num*100/256)/10;ba = (AD_num*100/256)%10;		//显示模拟湿度					
				}
				Display1_2(yi,er);
				Display4_5(si,wu);
				Display3_6(san,liu);
				Display7_8(qi,ba);
		}
		else if(KeyS7_mode == 1)						//进入手动模式
		{
				AD_num = IICAD_read(0x03);//读取滑动变阻器的值
				if(AD_num <= 128)					//模拟湿度,最大值255,小于等于百分之五十,继电器开,L1亮
				{
					if(Set_z1_flag == 0)			//完成两种模式按键的清零功能
					{
						KeyS6_buzzer = 0;
						KeyS5_relayo = 0;
						KeyS4_relayc = 0;
						Set_z1_flag = 1;
					}
					if(KeyS6_buzzer == 0)					
					{
						P2=0XA0;P0=0X40;											
					}
					else if(KeyS6_buzzer == 1)				//在手动模式下,按下第一次S6蜂鸣器关闭,再次按下蜂鸣器开,依次循环
					{
						P2=0XA0;P0=0X00;		
					}
					if(KeyS5_relayo == 1)						//在手动模式下,按下S5继电器开,L2灯亮
					{
						P2=0XA0;P0=0X10; 
						P2=0X80;P0=0XFD;	
						if(KeyS4_relayc == 1)					//在手动模式下,按下S4继电器关,L2灯灭
						{
							P2=0XA0;P0=0X00; 
							P2=0X80;P0=0XFF;
							KeyS5_relayo = 0;
							KeyS4_relayc = 0;
						}
					}

				}
				else 											//模拟湿度,最大值255,大于百分之五十,继电器关,L1灭
				{
					P2=0XA0;P0=0X00;
					P2=0X80;P0=0XFF;
				}
			
				yi = shijian[2]/10;er = shijian[2]%10;		//显示时间
				san = 10;si = shijian[1]/10;
				wu = shijian[1]%10;liu = 12;
				qi = (AD_num*100/256)/10;ba = (AD_num*100/256)%10;		//显示模拟湿度
				Display1_2(yi,er);
				Display4_5(si,wu);
				Display3_6(san,liu);
				Display7_8(qi,ba);				
		}
	}

}

写这个题目只有一个点是比较值得注意的,就是在阈值设定的时候数的加减问题,要注意数字的边界值。

还是老样子我会把我的整个工程上传https://download.csdn.net/my

你可能感兴趣的:(蓝桥杯)