真题内容取自:
无语凝烟
功能简述:
- 通过竞赛硬件平台
模拟小区自动售水机
的工作流程,具体的:通过按键控制售水机水流出和停止;通过数码管显示费率、出水量及总费用;通过光敏电阻检测环境亮度,在亮度过低的情况下,自动开灯。系统硬件电路主要由单片机控制电路、数码管显示电路、A/D 转换电路及功能按 键组成。系统框图如图 1 所示:
设计任务及要求
-
按键控制单元
设定按键 S7 为出水控制按键,当 S7 按下后,售水机持续出水(继电器接通,指示 灯 L10 点亮)。设定按键 S6 为停水控制按键,当 S6 按下后,停止出水(继电器断开, 指示灯 L10 熄灭)。 -
数码管显示单元
通过 4 位数码管 DS1 显示费率,单位为元/升,保留 2 位有效数字;通过 4 位数码管 DS2 显示当前出水总量(出水时,单位为升)和总价(停止时,单 位为元):按下出水按键 S7 后,清除数码管 DS2 显示数据,数码管 DS2 实时显示出水 量(保留两位有效数字),在出水状态下,再次按下 S7,不会影响出水状态,直到按下停 止按键 S6 为止;按下停止出水按键 S6 后,数码管 DS2 显示总价(保留两位有效数字)。
例:当 S7 按下后,数码管示意图如图 2 所示:
售水机出水状态数码管显示 当按键 S6 按下后,数码管示意图如图 3 所示:
-
AD 转换单元
通过光敏电阻 RD1 和 AD 转换芯片 PCF8591 组成的亮度检测电路(亮度值转换为 PCF8591 光敏电阻通道的电压)检测环境亮度;当 PCF8591 光敏电阻通道输入电压小 于 1.25 V 时,L1 点亮,大于 1.25V 时,L1 熄灭。 -
系统说明
(1)假定水价为 0.5 元/升,出水速度为 100 毫升/秒;
(2)一次出水总量达到 99.99L 时,继电器自动断开,数码管显示 DS2 显示价格。
实现代码
注意点:记得添加资源数据包中的两个iic的底层代码到考生文件夹中,同时需查看发送非应答中的实参是0还是1(即结束读pcf8591,最后要给数据总线SDA一个高电平,下图给了大概的位置,自己实现代码时,要留意一下!)
//config.h--用于声明头文件,声明函数,声明一些经常使用的变量或难书写的语句
#ifndef _CONFIG_H
#define _CONFIG_H
#include <STC15F2K60S2.H>//对应芯片函数头文件,定义了一些特殊功能寄存器
#include<intrins.h>
#include "iic.h"
//typedef unsigned char uchar;
#define uchar unsigned char
#define uint unsigned int
void Delay10us(); //@12.000MHz
#endif
#include "config.h"
uchar n1 = 0, ad_val = 0;
uint cnt = 0, cnt1 = 0, v_val = 0;
uchar key_val = 0, key_cnt = 0;
bit key_flag = 0, flag_s6 = 0, flag_20ms = 0;
uchar dspcom = 0;
uchar dspbuf[8] = { 16, 0, 5, 0, 0, 0, 0, 0};
//共阴数码管段选表
uchar tab[] = { //标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
void close_peripheral()
{
//初始化led为全灭
P2 = (P2 & 0x1f) | 0x80;
P0 = 0xff;
//初始化继电器,蜂鸣器不吸附,不发声
P2 = (P2 & 0x1f) | 0xa0;
P0 = 0xaf;
P2 &= 0x1f;
}
void Timer0Init(void) //2毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x30; //设置定时初值
TH0 = 0xF8; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
void Timer1Init(void) //50毫秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xB0; //设置定时初值
TH1 = 0x3C; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 0; //定时器1根据S7是否按下来判断是否计时
//这边注释就对了??具体为啥还不知道
// ET1 = 1;
// EA = 1;
}
void display()
{
//消隐
P2 = (P2 & 0x1f) | 0xe0;
P0 = 0xff;
//位选
P2 = (P2 & 0x1f) | 0xc0;
P0 = 1 << dspcom;
//段选
P2 = (P2 & 0x1f) | 0xe0;
P0 = ~tab[dspbuf[dspcom]];
if (dspcom == 1 || dspcom == 5)
P0 = (~tab[dspbuf[dspcom]]) & 0x7f;//小数点
P2 &= 0x1f;
if (++dspcom == 8)
{
dspcom = 0;
}
}
void key_scanf()
{
static char key_st = 0;
switch(key_st)
{
case 0:
{
P3 = 0x0f;
if (P3 != 0x0f)
key_st++;
break;
}
case 1://由case0到case1需要20ms其实相当于消抖
{
P3 = 0x0f;
if (P3 != 0x0f)
{
key_st = 2;
if (P30 == 0) key_val = 1;//s7
if (P31 == 0) key_val = 2;//s6
if (P32 == 0) key_val = 3;//s5
if (P33 == 0) key_val = 4;//s4
}
else //按键抖动
key_st = 0;
break;
}
case 2:
{
P3 = 0x0f;
if (P3 == 0x0f)
{
key_st = 0;
}
break;
}
}
}
void init_pcf8591(unsigned char channel)
{
IIC_Start();
IIC_SendByte(0x90);//写
IIC_WaitAck();
IIC_SendByte(channel); //ADC通道1
IIC_WaitAck();
IIC_Stop();
Delay10us();
}
unsigned char read_pcf8591(void)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp = IIC_RecByte();
IIC_SendAck(1);//发送非应答信号 !!!注意这个地方的改变,要跟资源数据包中的内容对照一下
IIC_Stop();
return temp;
}
void main()
{
close_peripheral();
Timer0Init();//按键扫描和数码管显示
Timer1Init();//用于出水总量和出水费用计算
while(1)
{
if (key_flag)//20ms一次按键扫描
{
key_scanf();
key_flag = 0;
}
if (key_val == 1 && !flag_s6)//出水键S7按下并且停水控制按键S6未按下,此时即将持续出水
{
TR1 = 1;//S7按下开始计时
if (TF1)//50ms自动溢出标志
{
TF1 = 0;
n1++;
}
if (n1 == 2)//100ms增加0.01升总出水量
{
n1 = 0;
cnt++;//100ms增加0.01升总出水量
if (cnt > 9999)//一次出水总量达到 99.99L 时,继电器自动断开,停止出水
{
TR1 = 0;
cnt = 0;
P2 = (P2 & 0x1f) | 0xa0;
P0 = 0xaf;
P2 &= 0x1f;
}
dspbuf[4] = cnt / 1000;
dspbuf[5] = cnt / 100 % 10;
dspbuf[6] = cnt / 10 % 10;
dspbuf[7] = cnt % 10;
}
//按下S7键时,继电器吸附,蜂鸣器发声
P2 = (P2 & 0x1f) | 0xa0;
P0 |= 0x10;
P2 &= 0x1f;
P0=0xff;
}
//按下S6键
if (key_val == 2)
{
TR1 = 0;
flag_s6 = 1;
cnt1 = cnt / 2;
dspbuf[4] = cnt1 / 1000;
dspbuf[5] = cnt1 / 100 % 10;
dspbuf[6] = cnt1 / 10 % 10;
dspbuf[7] = cnt1 % 10;
//S6 按下后,停止出水(继电器断开,蜂鸣器不发声 指示灯 L10 熄灭)。
P2 = (P2 & 0x1f) | 0xa0;
P0 &= 0xaf;
P2 &= 0x1f;
P0=0xff;
}
//按下S6后我们就,清除数码管 DS2 显示数据,使得数码管 DS2 实时显示出水量
if (key_val == 1 && flag_s6)
{
cnt = 0;
flag_s6 = 0;
}
//AD 转换单元每20ms采集数据
if (flag_20ms)
{
flag_20ms = 0;
init_pcf8591(0x01);
ad_val = read_pcf8591();//ad_value:0--255
v_val = ad_val * 100 / 51;// v_value:0--500
}
//PCF8591 结合光敏电阻通道输入电压小于 1.25 V 时,L1 点亮,大于 1.25V 时,L1 熄灭。
if (v_val < 125)
{
P2 = (P2 & 0x1f) | 0x80;
P0 = 0xfe;
P2 &= 0x1f;
}
else
{
P2 = (P2 & 0x1f) | 0x80;
P0 = 0xff;
P2 &= 0x1f;
}
}
}
void timer0() interrupt 1
{
TL0 = 0x30; //设置定时初值,2ms
TH0 = 0xF8; //设置定时初值
display();
if (++key_cnt == 10)
{
flag_20ms = 1;
key_cnt = 0;
key_flag = 1;//扫描按键的标志
}
}
void Delay10us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 27;
while (--i);
}
版权声明:本文为CSDN博主「是七喜呀!」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/MerryMaking7946/article/details/122800850
暂无评论