撼山岳—第三届之自动售水机

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

第三届是我写的最后一届省赛题了,从第九届到第三届其实感触还是有很多的,从第三届一直往上到第九届,难度也在逐渐的增加,而且考察的方面一直在一个圈子里面,从来没有超出过。

第三届考察的是AD模块、按键模块和数码管处模块。下面看一下这届的题目:

题目中有几位数码管的数字是要求第八位也显示的,这也就要求我们要知道数码怎样显示一个数字,我们要知道这个数码管是一个共阳数码管,知道了共阳数码管一切就好办了。还有一点要注意的就是在数字不断加一的过程中,进位这里不要弄错。AD转换方面主要注意的就是AD的驱动函数要写好,要按照手册上去写,不要随便的加一些延时函数,这样很可能导致你的AD采集不准确或者说采集不成功。

这个题目我也说一下自己的思路吧:

第一步:实现按下S7之后的出水量的计算(我用的是定时器实现一秒钟加数码管数值改变一次)以及继电器的打开

第二步:实现按下S6之后实现水费的显示以及继电器的关闭

第三步:实现AD采集以及L1灯的亮灭(将采集的数据与64相比较,题目要求我们是1.25V也就是说在0到5区间的1.25,那也就是0到256的64)

下面看一下我写的代码:

第一:按键代码(这个题目比较简单只用了两个独立按键)

#include "key.h"

uchar KeyS7_open;
uchar KeyS6_close;
//独立按键扫描函数
void D_keyscan()
{
	if(P30==0)
	{
		Delay5ms();
		if(P30==0)					//按键S7
		{
			KeyS7_open = 1;
		}
		while(!P30);
	}
	else if(P31==0)				//按键S6
	{
		Delay5ms();
		if(P31==0)
		{
			KeyS6_close = 1;
		}
		while(!P31);
	}
	else if(P32==0)				//按键S5
	{
		Delay5ms();
		if(P32==0)
		{

		}
		while(!P32);
	}
	else if(P33==0)				//按键S4
	{
		Delay5ms();
		if(P33==0)
		{
			
		}		
		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,0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10};//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 Display3_4(uchar san,uchar si)
{
		P2=0XC0;//打开位选573   U8
		P0=0X04;//选择第一个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[san];
		Delay1ms();Delay1ms();
		
		P2=0XC0;//打开位选573   U8
		P0=0X08;//选择第一个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[si];
		Delay1ms();Delay1ms();
}
//第五和第六个数码管
void Display5_6(uchar wu,uchar liu)
{
		P2=0XC0;//打开位选573   U8
		P0=0X10;//选择第三个数码管
		P2=0XFF;//打开段选573   U7
		P0=shu_tab[wu];
		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();
		P2=0XFF;//打开段选573   U7
		P0=0XFF;
}


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

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



第三:AD程序

#include "ad.h"
/*
IICAD_read(0x03);//读取滑动变阻器的值
IICAD_read(0x01);//读取光敏电阻的值
*/
//AD开始函数
void IICAD_statrt(void)
{	
	SDA = 1;
	_nop_();
	SCL = 1;
	_nop_();
	SDA = 0;
	_nop_();
	SCL = 0;
	_nop_();
}
//AD停止函数
void IICAD_stop(void)
{
	SDA = 0;
	_nop_();
	SCL = 1;
	_nop_();
	SDA = 1;
	_nop_();
}
//向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;
		IICAD_stop();
		Delay100us();
		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_stop();
	
	IICAD_statrt();
	AD_writebyte(0x91);
	ACK_AD();
	temp = IICAD_readbyte();
	ACK_AD();
	//现在显示的是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);
}

第四:初始化函数(.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 char u8;
typedef unsigned int u16;
void Init(void);

#endif

最后一部分:主函数程序

#include "system.h"
#include "ad.h"
#include "key.h"
#include "shuma.h"
void Timer0Init(void);
extern uchar yi,er,san,si,wu,liu,qi,ba;
extern uchar KeyS7_open;								//按键S7按下之后显示出水量
extern uchar KeyS6_close;								//按键S6按下之后关闭出水,显示价格
float Price;														//存储价格的变量
uchar Price_int;												//存储价格的整数部分
uchar Price_float;											//存储价格的小数部分
uint AD_num;														//存储AD读取的数据
uint Dis_timer;													//控制出水为1秒中出水0.1L时间位
uchar Dis_flag;													//控制出水为1秒中出水0.1L标志位
uchar Dis_price;												//控制出水量为99.9L时显示价格
uchar Init_flag;												//控制进入函数初始化一次变量
uchar ADD_flag1;												//用在出水量进位的变量
uchar ADD_flag2;												//用在出水量进位的变量
uchar AD_read_flag;											//AD每100ms读取一次的标志位
uchar AD_read_timer;										//AD每100ms读取一次的时间控制位
uchar num_1;														//为实现计费与出水模式的循环设定的储存数值的变量
uchar num_2;														//为实现计费与出水模式的循环设定的储存数值的变量
uchar num_3;														//为实现计费与出水模式的循环设定的储存数值的变量
void main(void)
{
	Init();
	Timer0Init();
	yi = 12;er = 13;san = 5;si = 0;
	wu = 12; liu = 12;qi = 12;ba = 12;	
	while(1)
	{
		D_keyscan();
		if(AD_read_flag == 1)
		{
			AD_num = IICAD_read(0x01);			//采集AD数据
			AD_read_flag = 0;
			if(AD_num < 64)									//AD数据小于1.25时L1灯亮
			{
				P2 = 0X80;
				P0 = 0XFE;
			}
			else 														//AD数据大于1.25时L1灯灭
			{
				P2 = 0X80;
				P0 = 0XFF;			
			}
		}	
		if(KeyS7_open == 1)								//按键S7按下
		{			
			if(Init_flag == 0)								//控制进入函数初始化一次变量
			{
				Init_flag = 1;
				wu = 0;liu = 0;
				qi = 0;ba = 0;	
				KeyS6_close = 0;				
			}
			if((qi == 9) && (liu == 22) && (wu == 9))//控制出水量为99.9L时显示价格
			{
				Dis_price = 1;
				qi = 9;liu = 23;wu = 9;
				P2=0XA0;P0=0X00;												//关闭继电器
			}
			else 																			//出水量小于99.9L
			{
				P2=0XA0;P0=0X10;												//开启继电器
				if(Dis_flag == 1)												//控制出水为1秒中出水0.1L标志位
				{	
					Dis_flag = 0;
					num_1 = num_1 + 1;
					if(num_1 == 10)
					{
						ADD_flag1 +=1;
						num_2 = 13 + ADD_flag1;
						num_1 = num_1 - 10;					
					}
					else if(num_1 < 10)
					{
						num_2 = 13 + ADD_flag1;
					}	
					if(num_2 == 23)
					{
						ADD_flag2 +=1;
						num_3 = 0 + ADD_flag2;
						num_2 = num_2 - 10;	
						ADD_flag1 = 0;
					}
					ba = 0;
					qi = num_1;
					liu = num_2;
					wu = num_3;	
				} 				
			}
			if((KeyS6_close == 1) || (Dis_price == 1))//按键S6按下或者出水量达到99.9
			{
				P2=0XA0;P0=0X00;												//关闭继电器
				Dis_price = 0;
				KeyS7_open = 0;
				KeyS6_close = 0;
				Price = (qi + (liu - 13)*10 + wu*100)*0.5*0.1;//计算价格
				Price_int = (int)Price;
				Price_float = (Price - Price_int)*100;
				wu = Price_int/10;													//将价格显示在数码管上
				liu = (Price_int%10 + 13);
				qi = Price_float/10;
				ba = Price_float%10;
			}			
			Display1_2(yi,er);
			Display3_4(san,si);
			Display5_6(wu,liu);
			Display7_8(qi,ba);
		}
		Display1_2(yi,er);
		Display3_4(san,si);
		Display5_6(wu,liu);
		Display7_8(qi,ba);
	}
}

void Timer0Init(void)		//2毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x9A;		//设置定时初值
	TH0 = 0xA9;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
}
void Timer0(void) interrupt 1
{
	
	TL0 = 0x9A;		//设置定时初值
	TH0 = 0xA9;		//设置定时初值
	AD_read_timer++;
	if(AD_read_timer == 50)//AD每100ms读取一次
	{
		AD_read_timer = 0;
		AD_read_flag = 1;
	}
	if(KeyS7_open == 1)
	{
		Dis_timer++;
		if(Dis_timer == 500)	//控制出水为1秒中出水0.1L时间位
		{
			Dis_timer = 0;
			Dis_flag = 1;				//控制出水为1秒中出水0.1L标志位
		}
	}
}

在文章的最后我也把我的完整工程上传一下,供大家参考https://download.csdn.net/my

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值