蓝桥杯第四届省赛模拟试题--自动售水机

题目要求

功能简述
通过竞赛硬件平台模拟小区自动售水机的工作流程:通过按键控制售水机水流出和停止;通过数码管显示费率、出水量及总费用;通过光敏电阻检测环境亮度,在亮度过低的情况下,自动开灯。系统硬件电路主要由单片机控制电路、数码管显示电路、 A/D 转换电路及功能按键组成。系统框图如图 1 所示:
蓝桥杯第四届省赛模拟试题--自动售水机_第1张图片I2C 总线驱动程序、 CT107D 考试平台电路原理图以及本题所涉及到的芯片数据手册,可参考计算机上的电子文档。程序流程图及相关工程文件请以考生号命名,并保存在计算机上的考生文件夹中(文件夹名为考生准考证号,文件夹位于 Windows 桌面上)
设计任务及要求
1. 按键控制单元
设定按键 S7 为出水控制按键,当 S7 按下后,售水机持续出水(继电器接通,指示灯 L10 点亮)。设定按键 S6 为停水控制按键,当 S6 按下后,停止出水(继电器断开,
指示灯 L10 熄灭)。
2. 数码管显示单元
通过 4 位数码管 DS1 显示费率,单位为元/升,保留 2 位有效数字;
通过 4 位数码管 DS2 显示当前出水总量(出水时,单位为升)和总价(停止时,单位为元):按下出水按键 S7 后,清除数码管 DS2 显示数据,数码管DS2 实时显示出水量(保留两位有效数字),在出水状态下,再次按下 S7,不会影响出水状态,直到按下停止按键 S6 为止;按下停止出水按键 S6 后,数码管 DS2 显示总价(保留两位有效数字)。
例:当 S7 按下后,数码管示意图如图 2 所示:
蓝桥杯第四届省赛模拟试题--自动售水机_第2张图片当按键 S6 按下后,数码管示意图如图 3 所示:
蓝桥杯第四届省赛模拟试题--自动售水机_第3张图片3. AD 转换单元
通过光敏电阻 RD1 和 AD 转换芯片 PCF8591 组成的亮度检测电路(亮度值转换为PCF8591 光敏电阻通道的电压)检测环境亮度;当 PCF8591 光敏电阻通道输入电压小于 1.25 V 时, L1 点亮,大于 1.25V 时, L1 熄灭。
4. 系统说明

  1. 假定水价为 0.5 元/升,出水速度为 100 毫升/秒;
  2. 一次出水总量达到 99.99L 时,继电器自动断开,数码管显示 DS2 显示价格。

5. 设计部分
假定自动售水机中存在一出水量检测传感器,输出信号为 4mA 到 20mA 直流信号,使用运算放大器设计接口电路,使得输入 4mA,输出 0V;输入 20mA,输出 5V。输入与输出满足线性关系。

程序代码

主函数

#include"stc15f2k60s2.h"
#include"iic.h"

sbit beep=P0^6;				//蜂鸣器
sbit Relay=P0^4;			//继电器

uchar code SMG_tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};    //共阴  0~9
uchar code SMG_duan[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uchar smg1,smg2,smg3,smg4,smg5,smg6,smg7,smg8;
uchar key;							//键值
uchar water_on;						//是否出水
uchar SMG_delete;
uchar on_display[10];
uchar off_display[10];

uint price;							//水的价格
uint water_v;						//水的体积
uint count;							//定时器计数,大于256一定不能再是uchar型!!!!

void delayms(uchar ms);
void display();
uchar Key_init();
void Timer0Init();
char read_key();

void main()
{
   uchar key_val;  
   Timer0Init();			 //1ms定时器
   Write(0x01,0);
   P2=0XA0;P0=0X00;
   P2=0X80;P0=0XFF;

   on_display[0]=SMG_tab[10];on_display[1]=SMG_tab[0]|0x80;
   on_display[2]=SMG_tab[5];on_display[3]=SMG_tab[0];

   off_display[0]=SMG_tab[10];off_display[1]=SMG_tab[0]|0x80;
   off_display[2]=SMG_tab[5];off_display[3]=SMG_tab[0];

   off_display[4]=SMG_tab[0];off_display[5]=SMG_tab[0]|0x80;
   off_display[6]=SMG_tab[0];off_display[7]=SMG_tab[0];
   while(1)
   {
       on_display[4]=SMG_tab[water_v/1000];
	   on_display[5]=SMG_tab[water_v/100%10]|0x80;
	   on_display[6]=SMG_tab[water_v/10%10];
	   on_display[7]=SMG_tab[water_v%10];
       key_val=read_key();
	 ET0=0;							  //定时器会影响iic的时序,所以先关闭
	 if(Read(0x01)<64)
	 {
	 	P2=0X80;P0=0XFF;
		P0=0XFE;
	 }
	 else
	 {
	 	P2=0X80;P0=0XFF;
		P0=0XFF;
	 }
	 ET0=1;
	 	
	 if(water_v==10000)
	  {
	    water_on=0;
		P2=0XA0;
	   Relay=0;beep=0;
	   price=water_v/2;
       off_display[4]=SMG_tab[price/1000];
	   off_display[5]=SMG_tab[price/100%10]|0x80;
	   off_display[6]=SMG_tab[price/10%10];
	   off_display[7]=SMG_tab[price%10];
	 }
	   switch(key_val)
	   {
		  case 4:break;
		  case 5:break;
		  case 6:
				 water_on=0;
		         price=water_v/2;
			    off_display[4]=SMG_tab[price/1000];
			    off_display[5]=SMG_tab[price/100%10]|0x80;
			    off_display[6]=SMG_tab[price/10%10];
			    off_display[7]=SMG_tab[price%10];
			  	P2=0XA0;
				Relay=0;beep=0;
				break;
		 case 7:
			   if(water_on==0)
				 water_v=0;						//清除上次数据
			     water_on=1;
			  	 P2=0XA0;
				 Relay=1;beep=0;
				 break;
	   }
   }
   
}

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;
   count++;
   SMG_delete++;
   if(SMG_delete==1)
   {
	 SMG_delete=0;
	 P2=0XC0;P0=0X00;P2=0X00;
	 if(water_on)
	 {
	  P2=0XE0;P0=~on_display[i];P2=0; 
	 } 
	 if(water_on==0)
	 {
	  P2=0XE0;P0=~off_display[i];P2=0;	  
	 }
	 P2=0XC0;P0=SMG_duan[i];P2=0;
	 i++;
	 if(i==8)
	 i=0;
   }
   if(count==10)
   {
	  count=0;
	  if(water_on)
	  water_v=water_v+10;
	  
   }
      
}
void delayms(uchar ms)
{
   int i,j;
   for(i=0;i<ms;i++)
    for(j=845;j>0;j--);
}


/*    按键状态机   */
#define key_input P3
#define key_state_0  0  		//判断是否按下
#define key_state_1  1 			//判断是否为抖动
#define key_state_2  2 			//判断是否弹起
   
char read_key() 
{ 
    static char key_state = 0; 
    char key_press, key_return = 0;
	uchar key_mask=0x0f; 
    key_press = key_input&key_mask; 
    switch (key_state) 
     { 	
       case key_state_0:     
             if (key_press!=key_mask)
             key_state = key_state_1; 
             break; 	 
       case key_state_1:    
             if (key_press!=key_mask) 
               { 
			  	 if(key_press==0x0e) key_return = 7;  //S7
				 if(key_press==0x0d) key_return = 6;  //S6
				 if(key_press==0x0b) key_return = 5;  //S5
				 if(key_press==0x07) key_return = 4;  //S4
  	             key_state = key_state_2;  
               }  
            else 
   	          key_state = key_state_0;  
            break;  
       case key_state_2: 
            if (key_press==0x0f) 
			key_state = key_state_0; 
            break; 
     } 
     return key_return; 
} 

EEPROM模块

#include"IIC.h"

void IIC_delay(uchar m);


void IIC_start()		  //起始
{
   SDA=1;
   _nop_();
   SCL=1;
   _nop_();
   SDA=0;
   _nop_();
   SCL=0;
   _nop_();
}

void IIC_stop()			//终止
{
   SDA=0;
   _nop_();
   SCL=1;
   _nop_();
   SDA=1;
   _nop_();
}

void Writebyte(uchar dat)				  //写一个字节
{
	uchar i;
	for(i=0;i<8;i++)
	{
		SCL=0;
		IIC_delay(5);
		SDA=dat&0x80;				  //从高位开始传输
		SCL=1;
		IIC_delay(5);
		dat<<=1;
	}
	SCL=0;
	IIC_delay(5);
}

uchar Readbyte()			   //读一个字节
{
	uchar dat;
	uchar i;
	for(i=0;i<8;i++)
	{
		SCL=1;
		IIC_delay(5);
		dat<<=1;
		if(SDA)
		{
			dat|=0x01;
		}
		SCL=0;
		IIC_delay(5);
	}
	
	return dat;
}

uchar answer()
{
    SCL=1;
	IIC_delay(5);
	if(SDA==1)			   //SDA=1表示非应答
	{
		SCL=0;
		IIC_stop();
		return 0;
	}
	else 
	{
		SCL=0;
		return 1;
	}
}

void Write(uchar addr,uchar dat)
{
   IIC_start();
   Writebyte(0x90);				   //器件地址	  A/D
   answer();					  //每收到一个8位数据,EEPROM都会在第9个时钟周期返回应答信号
   Writebyte(addr);				  //数据首地址
   answer();
   Writebyte(dat);
   answer();
   IIC_stop();
}

uchar Read(uchar addr)
{
    uchar num;
    IIC_start();
	Writebyte(0x90);				//器件地址		最后一位为0,写入
    answer();					  
    Writebyte(addr);				   //读出首地址
    answer();
	   
	IIC_start();				  //在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好反相。
	Writebyte(0x91);				 //器件地址+1  最后一位为1,读取
    answer();             
	num=Readbyte();
	IIC_stop();

	return num;
}

void IIC_delay(uchar m)
{
	do
	{
		_nop_();
	}
	while(m--);
}

以上就是代码的全部内容,欢迎交流,共同学习~

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