目录
功能简述
设计任务及要求
程序实现
功能简述
????????通过竞赛硬件平台模拟小区自动售水机的工作流程:通过按键控制售水机水流出和停止; 通过数码管显示费率、出水量及总费用;通过光敏电阻检测环境亮度,在亮度过低的情况下, 自动开灯。系统硬件电路主要由单片机控制电路、数码管显示电路、 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状态为闪动。若是同学们发现改动的地方,可以在评论区留言评论。
|