蓝桥杯第五届省赛模拟试题--“模拟智能灌溉系统”

题目要求

功能简述
要求“模拟智能灌溉系统” 能够实现土壤湿度测量、 土壤湿度和时间显示、 湿度阈值设定及存储等基本功能。 通过电位器 Rb2 输出电压信号,模拟湿度传感器输出信号,再通过AD 采集完成湿度测量功能;通过 DS1302 芯片提供时间信息;通过按键完成灌溉系统控制和湿度阈值调整功能,通过 LED 完成系统工作状态指示功能。系统硬件电路主要由单片机控制电路、 显示单元、 ADC 采集单元、 RTC 单元、 EEPROM 存储单元、 继电器控制电路及报警输出电路组成,系统框图如图 1 所示:
在这里插入图片描述MCS-51 单片机资料、 I2C 总线驱动程序和 DS1302 时钟芯片驱动程序、 CT107D 单片机综合训练平台电路原理图以及本题所涉及到的芯片数据手册, 可参考计算机上的电子文档。程序流程图及相关工程文件请以考生准考证号命名,并保存在计算机上的考生文件夹中,文件夹位于 Windows 桌面上。
设计任务及要求
1. 系统工作及初始化状态说明
1.1 自动工作状态,根据湿度数据自动控制打开或关闭灌溉设备, 以 L1 点亮指示;
1.2 手动工作状态,通过按键控制打开或关闭灌溉设备, 以 L2 点亮指示;
1.3 系统上电后处于自动工作状态,系统初始湿度阈值为 50%,此时若湿度低于
50%,灌溉设备自动打开, 达到 50%后,灌溉设备自动关闭;
1.4 灌溉设备打开或关闭通过继电器工作状态模拟。
2. 数码管单元
时间及湿度数据显示格式如图 2 所示:
在这里插入图片描述3. 报警输出单元
系统工作于手动工作状态下时,若当前湿度低于湿度阈值,蜂鸣器发出提示音,并可通过按键 S6 关闭提醒功能。
4. 功能按键
2.1 按键 S7 设定为系统工作状态切换按键;
2.2 手动工作状态下按键 S6、 S5、 S4 功能设定如下:
按下 S6 关闭蜂鸣器提醒功能,再次按下 S6 打开蜂鸣器提醒功能,如此循环;
S5 功能设定为打开灌溉系统;
S4 功能设定为关闭灌溉系统。
2.3 自动工作状态下按键 S6、 S5、 S4 功能设定如下:
S6 功能设定为湿度阈值调整按键,按下 S6 后,进入湿度阈值调整界面(如图 3
所示),此时按下 S5 为湿度阈值加 1,按下 S4 湿度阈值减 1,再次按下 S6 后,系统将新的湿度阈值保存到 EEPROM 中, 并退出湿度阈值设定界面。
在这里插入图片描述5. 实时时钟
“模拟智能灌溉系统”通过读取 DS1302 时钟芯片相关寄存器获得时间, DS1302
芯片时、 分、秒寄存器在程序中设定为系统进行初始化设定,时间为 08 时 30 分。
6. 湿度检测单元
以电位器 Rb2 输出电压信号模拟湿度传感器输出信号, 且假定电压信号与湿度成正比例关系 H 湿度 = KVRb2(K 为常数), Rb2 电压输出为 5V 时对应湿度为 99%。
7. EEPROM 存储单元
系统通过 EEPROM 存储湿度阈值, 自动工作状态下,可通过按键 S6、 S5、 S4 设置和保存阈值信息。
8. 电路设计部分
使用 PTC 热敏电阻、场效应管、继电器及简单阻容元件设计“智能灌溉系统” 中置于电机内部的过热保护电路, 当电机内部温度超过 70℃,断开电机电源,设计电路原理图并简述设计思路与电路工作原理。
PTC 热敏电阻参数说明:
当温度小于 68℃时, 热敏电阻阻值小于 100 欧姆;温度超过 68℃后,电阻值随温度升高呈阶跃性增高, 温度到达 70℃后, 热敏电阻阻值接近 10kΩ。

程序代码

主函数

#include<stc15f2k60s2.h>
#include"ds1302.h"
#include "iic.h"

typedef unsigned char uchar;
typedef unsigned int uint;

uchar code SMG_duan[]={
    
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};	//0~9
uchar code SMG_wei[]={
    
    0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

sbit beep=P0^6;
sbit Relay=P0^4;

void Timer0Init();
void datpross();
void delayms(uint ms);

uchar SMG_count;
uchar Time_display[8];
uchar set_display[8];
uchar shidu;	            //湿度
uchar shidu_limit=50;      //湿度阈值
uchar mode;               //mode=0 自动,mode=1 手动	   S7控制

bit realy_flag;			 //继电器标志位
bit beep_flag;			 //蜂鸣器标志位
bit beep_buzzer;		 //手动模式下,S6控制蜂鸣器
bit set_flag;			//阈值设置标志位

uchar Key_init()
{
    
    
    uchar key=0;									 //不清零会让按键按下后,一直执行
    if(P33==0)
	{
    
    
	   delayms(10);
	   if(P33==0)
	     key=4;
	   while(!P33);
	}
	if(P32==0)
	{
    
    
	   delayms(10);
	   if(P32==0)
	     key=5;
	   while(!P32);
	}
	if(P31==0)
	{
    
    
	   delayms(10);
	   if(P31==0)
	     key=6;
	   while(!P31);
	}
	if(P30==0)
	{
    
    
	   delayms(10);
	   if(P30==0)
	     key=7;
	   while(!P30);
	}
	return key;
}

void main()
{
    
    
   uchar key_val;
   P2=0XA0;P0=0X00;
   P2=0X80;P0=0XFF;

   shidu_limit=Read_2402(0x01);
   Timer0Init();
   Ds1302_init();
   Write_adc(0x03);
   
   set_display[0]=0x40;
   set_display[1]=0x40;
   set_display[2]=0x00;
   set_display[3]=0x00;
   set_display[4]=0x00;
   set_display[5]=0x00;

   while(1)
   {
    
    
	  Ds1302_read();
      key_val=Key_init();
	  Time_display[0]=SMG_duan[TIME[2]/16];
      Time_display[1]=SMG_duan[TIME[2]%16];
      Time_display[2]=0x40;
      Time_display[3]=SMG_duan[TIME[1]/16];
      Time_display[4]=SMG_duan[TIME[1]%16];
      Time_display[5]=0x00;

	  ET0=0;
	  shidu=(Read_adc(0x03)/2.57f); 
	  ET0=1;
      Time_display[6]=SMG_duan[shidu/10];
      Time_display[7]=SMG_duan[shidu%10];

	  set_display[6]=SMG_duan[shidu_limit/10];
	  set_display[7]=SMG_duan[shidu_limit%10];
	  if(mode==1)			   //手动
	  {
    
    
	     P2=0X80;P0=0XFD;
	     if(shidu<shidu_limit)
		 {
    
    
		    if(beep_buzzer==0)
		    beep_flag=1;
			else
			beep_flag=0;
		 }
		 else
		 {
    
     
		    beep_flag=0;			
		 }
	  }
	  else 					 //自动
	  {
    
    
		 P2=0X80;P0=0XFE;
		 if(shidu<shidu_limit)
			{
    
    
			   realy_flag=1;
			}
			else
			{
    
    
			   realy_flag=0;
			}
	  }
	  switch(key_val)
	  {
    
    
	     case 4: 
		 		if(mode)
				{
    
    
				  realy_flag=0;
				  beep_flag=0;
				}
				else
				{
    
    
				  if(set_flag)
				  shidu_limit--;
				}
		        break;
		 case 5:
		       	if(mode)
				{
    
    
				  realy_flag=1;
				  beep_flag=0;
				}
				else
				{
    
    
				  if(set_flag)
				  shidu_limit++;
				}
			    break;
		 case 6: 
		 		if(mode)
				{
    
    
				  beep_buzzer=~beep_buzzer;
				}
				else
				{
    
    
				  set_flag=~set_flag;
				  if(set_flag==0)
				  {
    
    
				  Write_2402(0x01,shidu_limit);
				  }				   
				}
		        break;
		 case 7:
		 		mode++;
				if(mode==2)
				mode=0;
		        break;
	  }
	  if(realy_flag==0&beep_flag==0)
      {
    
     P2=0XA0;beep=0;Relay=0; }

      if(realy_flag==0&beep_flag==1)
      {
    
     P2=0XA0;beep=1;Relay=0; }

      if(realy_flag==1&beep_flag==0)
      {
    
     P2=0XA0;beep=0;Relay=1; }

      if(realy_flag==1&beep_flag==1)
      {
    
     P2=0XA0;beep=1;Relay=1; }
   }
   
        
}


void Timer0Init()		//1毫秒@11.0592MHz
{
    
    
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA=1;
	ET0=1;
}

void Timer0() interrupt 1
{
    
    
   uchar i;
   SMG_count++;
   if(SMG_count==3)
   {
    
    	      						  
	  SMG_count=0;
	  P2=0Xc0;P0=0X00;P2=0X00;
	  P2=0XC0;P0=SMG_wei[i];
	  if(set_flag)
	  {
    
    
	   P2=0XE0;P0=~set_display[i];
	  }
	  else
	  {
    
    
	   P2=0XE0;P0=~Time_display[i];
	  }
	  i++;
	  if(i==8)
	  i=0;
   }
}

void delayms(uint ms)
{
    
    
   int i,j;
   for(i=0;i<ms;i++)
    for(j=845;j>0;j--);
}

DS1302时钟模块

#include "ds1302.h"

unsigned char Write_add[]={
    
    0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char READ_add[]={
    
    0x81,0x83,0x85,0x87,0x89,0x8B,0x8D};

unsigned char TIME[]={
    
    0X50,0X30,0X08,0X14,0X02,0X20,0X19};

void Write_Ds1302_Byte(unsigned char dat) 
{
    
    
	unsigned char i;
	SCK = 0;
	_nop_();
	for (i=0;i<8;i++) 
	{
    
     
		if (dat & 0x01) 	// 等价于if((addr & 0x01) ==1) 
		{
    
    
			SDA_SET;		//#define SDA_SET SDA=1 /*电平置高*/
		}
		else 
		{
    
    
			SDA_CLR;		//#define SDA_CLR SDA=0 /*电平置低*/
		}		 
		SCK_SET;
		_nop_();
		SCK_CLR;
		_nop_();		
		dat = dat >> 1; 
	} 
}
/********************************************************************/ 
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void) 
{
    
    
	unsigned char i, dat=0;	
	for (i=0;i<8;i++)
	{
    
    	
		dat = dat >> 1;
		if (SDA_R) 	  //等价于if(SDA_R==1)    #define SDA_R SDA /*电平读取*/	
		{
    
    
			dat |= 0x80;
		}
		else 
		{
    
    
			dat &= 0x7F;
		}
		SCK_SET;
		_nop_();
		SCK_CLR;
		_nop_();
	}
	return dat;
}

/********************************************************************/ 
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{
    
     

	RST_CLR;			
	_nop_();
	SCK_CLR;		
	_nop_();

	RST_SET;		
	_nop_();
	addr = addr & 0xFE;	 
	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/	
	Write_Ds1302_Byte(dat);	 /*写入数据:dat*/
	RST_CLR;				 
	_nop_();
}

/********************************************************************/ 
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr) 
{
    
     
	unsigned char temp;
	RST_CLR;			
	_nop_();
	SCK_CLR;		
	_nop_();

	RST_SET;
	_nop_();	
	addr = addr | 0x01;	 
	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
	temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/		
	RST_CLR;	/*停止DS1302总线*/
	_nop_();

	SD=0;
	_nop_();
	SD=1;
	_nop_();
	return temp;
}

void Ds1302_init()
{
    
    
    unsigned char i;
	Ds1302_Single_Byte_Write(0x8e,0x00);
	for(i=0;i<7;i++)
	{
    
    
	   	Ds1302_Single_Byte_Write(Write_add[i],TIME[i]);
	}
	Ds1302_Single_Byte_Write(0x8e,0x81);

}

void Ds1302_read()
{
    
    
   unsigned char i;
   for(i=0;i<7;i++)
   {
    
    
	  TIME[i]=Ds1302_Single_Byte_Read(READ_add[i]);
   }
}

EEPROM模块

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(12MHz)
  日    期: 2011-8-9
*/

#include "iic.h"

void IIC_delay(unsigned char i)
{
    
    
   do
   {
    
    
	  _nop_();

   }while(i--);
}
//总线启动条件
void IIC_Start(void)
{
    
    
	SDA = 1;
	SCL = 1;
	IIC_delay(5);
	SDA = 0;
	IIC_delay(5);
	SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    
    
	SDA = 0;
	SCL = 1;
	IIC_delay(5);
	SDA = 1;
}


//等待应答
bit IIC_WaitAck(void)
{
    
    
	SDA = 1;
	IIC_delay(5);
	SCL = 1;
	IIC_delay(5);
	if(SDA)    
	{
    
       
		SCL = 0;
		IIC_Stop();
		return 0;
	}
	else  
	{
    
     
		SCL = 0;
		return 1;
	}
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    
    
	unsigned char i;
	for(i=0;i<8;i++)
	{
    
       
		if(byt&0x80) 
		{
    
    	
			SDA = 1;
		}
		else 
		{
    
    
			SDA = 0;
		}
		IIC_delay(5);
		SCL = 1;
		byt <<= 1;
		IIC_delay(5);
		SCL = 0;
	}
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    
    
	unsigned char da;
	unsigned char i;
	
	for(i=0;i<8;i++)
	{
    
       
		SCL = 1;
		IIC_delay(5);
		da <<= 1;
		if(SDA) 
		da |= 0x01;
		SCL = 0;
		IIC_delay(5);
	}
	return da;
}

void Write_adc(unsigned char dat)
{
    
    
   IIC_Start();
   IIC_SendByte(0x90);			//从设备地址
   IIC_WaitAck();
   IIC_SendByte(dat);		   //控制字
   IIC_WaitAck();
   IIC_Stop();
}

unsigned char Read_adc(unsigned char dat)
{
    
    
   unsigned char temp;
   IIC_Start();
   IIC_SendByte(0x90);
   IIC_WaitAck();
   IIC_SendByte(dat);
   IIC_WaitAck();

   IIC_Start();
   IIC_SendByte(0x91);
   IIC_WaitAck();
   temp=IIC_RecByte();
   
   IIC_Stop();

   return temp;
}

void Write_2402(unsigned char addr,unsigned char dat)
{
    
    
   IIC_Start();
   IIC_SendByte(0xa0);
   IIC_WaitAck();
   IIC_SendByte(addr);
   IIC_WaitAck();
   IIC_SendByte(dat);
   IIC_WaitAck();
   IIC_Stop();
}

unsigned char Read_2402(unsigned char dat)
{
    
    
   unsigned char temp;
   IIC_Start();
   IIC_SendByte(0xa0);
   IIC_WaitAck();
   IIC_SendByte(dat);
   IIC_WaitAck();

   IIC_Start();
   IIC_SendByte(0xa1);
   IIC_WaitAck();		 //一定要跟应答
   temp=IIC_RecByte();
   //IIC_WaitAck();
   IIC_Stop();

   return temp;
}

以上就是代码的全部内容,欢迎交流,共同学习~
附上工程包下载——蓝桥杯第五届省赛模拟试题

猜你喜欢

转载自blog.csdn.net/qq_43280087/article/details/104629858