蓝桥杯单片机复习-------第二届省赛题:自动售水机

CT107D:自动售水机

阅读前的声明:希望我的文章对你能有所帮助(源码有不明白的,可联系我:qq:2530318393,或者留言,另外:写作不易,转载请声明所属~~~~~~~~)

首先来看看题目:在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这个题目相对而言较为简单,就是考察了对按键、数码管、继电器、led、AD的光敏部分的一个结合性实验。
我觉得值得注意的地方是:出水速度是:100ml/s,而显示的格式是:??.??L,所以最小单位的变度是10ml,而换算下来就是100ms。

下面先奉上源码的下载地址:链接:https://pan.baidu.com/s/1L-deSSSsiZjj7ByePIbbmw 
							 提取码:lcvo 

不想下载的朋友也可以看看(这里也贴上):

main.c

/**
*第三届省赛题:自动售水机
*现象:s7开始出水,s6停止出水,计算出价格显示,继电器的开合模拟出水机的工作
**/

#include <stc15f2k60s2.h>
#include "smg.h"
#include "key.h"
#include "iic.h"

void CT107D_Init();   //开发板初始化
void Timer0Init(void);   //定时器初始化

sbit RELAY = P0^4;     //继电器引脚

unsigned char keyVal = 0;    //读取到的按键值
unsigned long time = 0;     //定时用,通过定时时间不同可改变出水速度
bit timeGo = 0;     //开始出水后计时的标志变量
code unsigned char smgduan[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};   //数码管段选数组

void main()
{
	unsigned long ml = 0;    //已出水总量
	Timer0Init();
	pcf8591Init();
	CT107D_Init();    //初始化
	while(1)
	{
		if(keyVal == 7)    //按下出水按键
		{
			timeGo = 1;    //开始计时
			P2 = (P2 & 0x1f) | 0xa0;
			P0 = 0x00;
			RELAY = 1;     //继电器打开
			P2 = P2 & 0x1f;
			keyVal = 0;    //按键值清零
			while(1)     //进入等待停止出水按键按下或者自动停止出水
			{
				if ((time % 100) == 0)    //出水速度100ml/s
				{
					ml++;
				}
				smgBuf[4] = smgduan[ml / 1000];   //数码管同步更新
				smgBuf[5] = smgduan[ml % 1000 / 100] & 0x7f;
				smgBuf[6] = smgduan[ml % 100 / 10];
				smgBuf[7] = smgduan[ml % 10];
				if(ml >= 9999)      //如果到达99.99ml水的时候就自动停止放水,并把相关变量清零,继电器关闭
				{
					P2 = (P2 & 0x1f) | 0xa0;
					P0 = 0x00;
					P2 = P2 & 0x1f;
					
					timeGo = 0;
					keyVal = 0;
					ml = 0;
					time = 0;
					smgBuf[4] = smgduan[5];   //数码管值同步
					smgBuf[5] = smgduan[0] & 0x7f;
					smgBuf[6] = smgduan[0];
					smgBuf[7] = smgduan[0];
					break;   //退出内部的嵌套死循环
				}    
				if(keyVal == 6)  //或者提前按下s6停止出水按键
				{
					P2 = (P2 & 0x1f) | 0xa0;    //关闭继电器
					P0 = 0;
					P2 = P2 & 0x1f;
					timeGo = 0;
					keyVal = 0;
					ml = ml/2;   //计算价格
					time = 0;
					smgBuf[4] = smgduan[ml / 1000];     //显示价格
					smgBuf[5] = smgduan[ml % 1000 / 100] & 0x7f;
					smgBuf[6] = smgduan[ml % 100 / 10];
					smgBuf[7] = smgduan[ml % 10];
					ml = 0;
					break;			//退出内部的嵌套死循环
				}
			}
		}
	}
}

void CT107D_Init()
{
	P2 = (P2 & 0x1f) | 0x80;
	P0 = 0xff;
	
	P2 = (P2 & 0x1f) | 0xa0;
	P0 = 0x00;
	
	smgBuf[1] &= 0x7f;
	smgBuf[5] &= 0x7f;
}
	

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

void breakOfTimer0()  interrupt 1
{
	if(timeGo)
		time++;
	display();
	keyVal = keyread();
	if(adReadPcf8591()>66)
	{
		P2 = (P2 & 0x1f) | 0x80;
		P0 = 0xff;
		P2 = P2 & 0x1f;
	}
	else
	{
		P2 = (P2 & 0x1f) | 0x80;
		P0 = 0xfe;
		P2 = P2 & 0x1f;
	}
}

key.h

#ifndef _KEY_H
#define _KEY_H

unsigned char keyread();

#endif

key.c

#include <stc15f2k60s2.h>

unsigned char keyread()   //通过定时器辅助对按键进行状态机方式的扫描
{
	static keyYes = 1;
	static unsigned char keyValTmp = 0,keyCnt = 0;
	unsigned char tmp;
	
	if(P30 & P31 & P32 & P33)
	{
		if(keyYes)
		{
			keyYes = 0;
			tmp = keyValTmp;
			keyValTmp = 0;
			keyCnt = 0;
			return tmp;
		}
		else
		{
			keyValTmp = 0;
			keyCnt = 0;
		}
	}
	else
	{
		keyCnt++;
		if(keyYes == 0)
		{
			if(keyCnt == 20)
			{
				if(P30 == 0)
					keyValTmp = 7;	
				else if(P31 == 0)
					keyValTmp = 6;
				else if(P32 == 0)
					keyValTmp = 5;	
				else if(P33 == 0)
					keyValTmp = 4;
				
				keyYes = 1;
			}
		}
	}
	return 0;
}

smg.h

#ifndef _SMG_H
#define _SMG_H

void display();
extern unsigned char smgBuf[8];

#endif

smg.c

#include <stc15f2k60s2.h>
#include <intrins.h>

unsigned char smgBuf[8] = {0xc0,0xc0,0x92,0xc0,0xc0,0xc0,0xc0,0xc0};   //数码管显示数组

void display()    //数码管显示函数
{
	static unsigned char i = 0; 
	
	P2 = (P2 & 0x1f) | 0xe0;
	P0 = 0xff;
	
	P2 = (P2 & 0x1f) | 0xc0;
	P0 = _crol_(0x01,i);
	
	P2 = 0xff;
	P0 = smgBuf[i];
	
	i++;
	i %= 8;
}

IIC.H

#ifndef _IIC_H
#define _IIC_H

unsigned char adReadPcf8591();
void pcf8591Init();

#endif

iic.c

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

#include "reg52.h"
#include "intrins.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

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

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

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

void pcf8591Init()
{
	IIC_Start(); 
	IIC_SendByte(0x90);  
	IIC_WaitAck(); 
	IIC_SendByte(0x01);
	IIC_WaitAck();
	IIC_Stop();	
}

//读取pcf8591芯片通道1的ad转换值,
unsigned char adReadPcf8591()
{
	unsigned char date;
	
	IIC_Start(); 
	IIC_SendByte(0x91);  
	IIC_WaitAck(); 
	
	date = IIC_RecByte();
	IIC_SendAck(1); 
	
	IIC_Stop();	
	
	return date;
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值