蓝桥杯CT107D真题:“自动售水机”之找错误

目录

功能简述

设计任务及要求

程序实现


功能简述

        通过竞赛硬件平台模拟小区自动售水机的工作流程:通过按键控制售水机水流出和停止;
通过数码管显示费率、出水量及总费用;通过光敏电阻检测环境亮度,在亮度过低的情况下,
自动开灯。系统硬件电路主要由单片机控制电路、数码管显示电路、 A/D 转换电路及功能按
键组成。系统图如图:

 设计任务及要求

1. 按键控制单元
        设定按键 S7 为出水控制按键,当 S7 按下后,售水机持续出水(继电器接通,指示灯 L10 点亮)。设定按键 S6 为停水控制按键,当 S6 按下后,停止出水(继电器断开,指示灯 L10 灭)。
2. 数码管显示单元
        通过 4 位数码管 DS1 显示费率,单位为元/升,保留 2 位有效数字;通过 4 位数码管 DS2 显示当前出水总量(出水时,单位为升)和总价(停止时,单位为元):按下出水按键 S7 后,清除数码管 DS2 显示数据,数码管 DS2 实时显示出水量(保留两位有效数字),在出水状态下,再次按下 S7,不会影响出水状态,直到按下停止按键 S6 为止;按下停止出水按键 S6 后,数码管 DS2 显示总价(保留两位有效数字)

 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 "Timer.h"
#include "Close.h"
#include "HC138.h"
#include "iic.h"
#include "intrins.h"
#include "PCF8591.h"

code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xBF,0x7F};
unsigned char dspbuf[8]={0,0,5,0,0,0,0,0};
unsigned char dspcom=0;	//数码管显示变量

unsigned char intr;		//定时器0计数
unsigned char ad_value;//ad值,取64
unsigned int v_value; //电压值,1.25v
unsigned int cnt,cnt1;//出水量(多少个100ms),水费
unsigned char  n1,key_value=0;//50ms次数,n2没有用到,key_value是按键值

bit flag_10;
bit flag_s6;
bit key_flag;

void display()
{
	HC138(7);
	P0=0xff;
	
	HC138(6);
	P0=(1<<dspcom);
	
	HC138(7);
	P0=tab[dspbuf[dspcom]];
	
	if((dspcom==1)||(dspcom==5))
	{
		P0=tab[dspbuf[dspcom]]&0x7f;
	}
	P2&=0x1f;
	
	if(++dspcom==8)
	{
		dspcom=1;
	}
}	

void Timer0_Rountine()	interrupt 1
{
	TL0 = 0x30;
	TH0 = 0xF8;
	display();
	if(++intr==20)
	{
		flag_10=1;
		key_flag=1;
		intr=0;
	}
}
void scan_key()
{
	static unsigned char key_st=0;
	switch(key_st)
	{
		case 0:
			if((P3&0x0f)!=0x0f)
			{
				key_st=1;
			}
			break;
		case 1:	
			if((P3&0x0F)!= 0x0F)
			{
				key_st = 2;
				if((P3&0x0F) == 0x0E) key_value = 1;      //S7
				else if((P3&0x0F) == 0x0D) key_value = 2; //S6
				else if((P3&0x0F) == 0x0B) key_value = 3; //S5
				else if((P3&0x0F) == 0x07) key_value = 4; //S4
			}
			else
			{
				key_st = 0;	//按键抖动
			}
			break;
		case 2:	
			if((P3&0x0F) == 0x0F)
			{
				key_st = 0;
			}
			break;
	}
}


void main()
{
	Close_Init();
	Timer0Init();
	Timer1Init();
	
	while(1)
	{
		if(key_flag)
		{
			key_flag=0;
			scan_key();
		}
		
		if((key_value==1) && (flag_s6==0))	//s7按下,s6松开
		{
			TR1=1;	//开始计时
			if(TF1)
			{
				n1++;
				TF1=0;
			}
			if(n1==2)
			{
				n1=0;
				cnt++;
				if(cnt>9999)
				{
					cnt=0;
					TR1=0;
					HC138(5);
					P0=0x0f;
					P2=P2&0x1f;
					P0=0xff;
				}
				dspbuf[4]=cnt/1000;
				dspbuf[5]=cnt%1000/100;
				dspbuf[6]=cnt%100/10;
				dspbuf[7]=cnt%10; 	
			}
						
				HC138(5);
				P0|=0x10;
				P2=P2&0x1f;
				P0=0xff;
		}
		if(key_value==2)
		{
			TR1=0;	//停止出水,然后显示水费,不再计时
			flag_s6=1;
			cnt1=cnt/2;	//水费cnt1等于用水量除以2
			
			dspbuf[4] = cnt1/1000;
			dspbuf[5] = cnt1%1000/100;
			dspbuf[6] = cnt1%100/10;
			dspbuf[7] = cnt1%10;
			
			HC138(5);
			P0=0x0f;
			P2&=0x1f;
			P0=0xff;
		}
		
		if((key_value==1)&&(flag_s6==1))
		{
			cnt=0;
			flag_s6=0;
		}
		
		if(flag_10)
		{
			flag_10=0;
			init_pcf8591(0x01);
			ad_value=read_pcf8591();
			v_value=ad_value*100/51;
		}
		
		if(v_value<125)
		{
			HC138(4);
			P2=0xfe;
			P2=0x1f;
			P0=0x00;
		}
		else
		{
			HC138(4);
			P0=0xff;
			P2=0x1f;
			P0=0x00;
		}
	
	}
}

下面为各驱动代码

#include "STC15F2K60S2.h"
#incldue "intrins.h"

void HC138(unsigned char n)
{
	switch(n)
	{
		case 4:P2=((P2&0x1f)|0x80);break;
		case 5:P2=((P2&0x1f)|0xa0);break;
		case 6:P2=((P2&0x1f)|0xc0);break;
		case 7:P2=((P2&0x1f)|0xe0);break;
	}
}


#include "STC15F2K60S2.H"
#include "intrins.h"

void Timer0Init(void)		//2毫秒@12.000MH,用于didplay的显示
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x30;		//设置定时初始值
	TH0 = 0xF8;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA=1;			//中断总开关
	ET0=1;			//允许定时器0申请中断
}

void Timer1Init(void)		//50毫秒@12.000MHz,用于计算出水量
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xB0;		//设置定时初始值
	TH1 = 0x3C;		//设置定时初始值
	TF1 = 0;		//清除TF1标志
	TR1 = 0;		//定时器1开始计时
}


#include "STC15F2K60S2.H"
#include "intrins.h"
#include "HC138.h"

void Close_Init()
{
	HC138(5);
	P06=0;
	P04=0;
	P2&=0x1f;
	
	HC138(4);
	P0=0xff;
	P2&=0x1f;
}


#include "iic.H"
#include "STC15F2K60S2.H"
#include "intrins.h"
void Delay10us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	_nop_();
	i = 27;
	while (--i);
}
void init_pcf8591(unsigned char channel)
{
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	
	IIC_SendByte(channel);  //ADC通道3
	IIC_WaitAck();
	
	IIC_Stop();
	Delay10us();
}
unsigned char read_pcf8591(void)
{
	unsigned char temp;

	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	temp = IIC_RecByte();
	IIC_Ack(0);     //发送非应答信号 
	IIC_Stop();
	
	return temp;
}

         上列代码中,我在光敏电阻区域稍微改动了一点,使在遮挡光敏电阻后,数码管、LED状态为闪动。若是同学们发现改动的地方,可以在评论区留言评论。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值