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;
}