蓝桥杯第三届初赛“自动售水机”设计任务书
Author:Luis
Time:2022-04-06
Version:v1.0
说明
蓝桥杯系列的代码都是本人亲手写和调试,可能有时会有点错误,请见谅。此外,代码仅供大家学习,祝福各位在蓝桥杯比赛中能获得比较满意的成绩。
功能简述
通过竞赛硬件平台模拟小区自动售水机的工作流程:通过按键控制售水机水流出和停止;
通过数码管显示费率、出水量及总费用;通过光敏电阻检测环境亮度,在亮度过低的情况下,
自动开灯。系统硬件电路主要由单片机控制电路、数码管显示电路、A/D 转换电路及功能按
键组成。
具体代码
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;
}
// addd
// PCF8591
void init_pcf8591()
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0X01); // 第一通道
IIC_WaitAck();
IIC_Stop();
}
// 通过I2C总线读取ADC结果
unsigned char adc_pcf8591()
{
unsigned char da;
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
da = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return da;
}
iic.h
#ifndef __IIC_H
#define __IIC_H
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendAck(bit ackbit);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
void init_pcf8591(); // 初始化pcf8591
unsigned char adc_pcf8591(); // 通过I2C总线读取ADC结果
#endif
main.c
// 注意:J3跳线配置为IO方式,J5配置为BTN、J2配置为1-3和2-4
#include <STC15F2K60S2.h>
#include "intrins.h"
#include "iic.h"
// 小数点是第8位为0 原本数字-0x80
unsigned char data_pros[] = {
0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xff, 0xbf};
unsigned char dspbuf[8] = {10, 10, 10, 10, 10, 10, 10, 10}; //显示缓冲区
unsigned char key_flag = 0;
unsigned char water_flag = 0; // 是否开始计数
int water = 0; // 水量
int water_value = 0; // 水价
unsigned int adc_dat = 0;
unsigned char adc_flag = 0; // 200ms一次
// 初始化值
void close_init()
{
P2 = 0xA0;
P0 = 0x00;
P2 = 0x80;
P0 = 0xff;
P2 = 0x00;
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j)
;
} while (--i);
}
// 读取独立键值 J5为BTN模式
unsigned char read_key()
{
unsigned char key_temp;
static unsigned char key_press = 0; // 按下次数
static unsigned char key_right = 0; // 是否按下
static unsigned char key_value = 0; // 按下值
key_temp = (P3 & 0x0f);
if (key_temp != 0x0f)
key_press++;
else
key_press = 0;
if (key_press == 5) // 按下五次算按下
{
key_press = 0;
key_right = 1;
switch (key_temp) // 检验值
{
case 0x0e:
key_value = 1; // S7
break;
case 0x0d:
key_value = 2; // S6
break;
}
}
if ((key_right == 1) && (key_temp == 0x0f)) // 松开手
{
key_right = 0;
return key_value;
}
return 0xff;
}
void Timer0Init(void) // 1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
// add
ET0 = 1;
EA = 1;
}
// 显示函数 dspbuf为数码管的缓冲区
void display()
{
static unsigned char dspnum = 0; // 数码管的位置
P2 = 0xE0;
P2 = 0xff; // 消影
P2 = 0xc0;
P0 = (1 << dspnum);
P2 = 0xe0;
if (dspnum == 1 || dspnum == 5)
P0 = data_pros[dspbuf[dspnum]] - 0x80;
else
P0 = data_pros[dspbuf[dspnum]];
P2 = 0x00;
if (++dspnum == 8)
dspnum = 0;
}
void main()
{
unsigned char key_value = 0;
unsigned char i = 0;
close_init();
Timer0Init();
init_pcf8591();
Delay5ms();
dspbuf[1] = 0; // 初始化值
dspbuf[2] = 5;
for (i = 3; i < 8; i++)
dspbuf[i] = 0;
while (1)
{
if (key_flag)
{
key_flag = 0;
key_value = read_key();
if (key_value != 0xff)
{
switch (key_value)
{
case 1:
{
P2 = 0xA0;
P0 = 0x10;
P2 = 0x00;
water_flag = 1;
}
break;
case 2:
P2 = 0xA0;
P0 = 0x00;
P2 = 0x00;
water_flag = 2;
}
}
}
if (water_flag == 1) // 1 是出水
{
dspbuf[4] = water / 1000;
dspbuf[5] = water / 100 % 10;
dspbuf[6] = water / 10 % 10;
dspbuf[7] = water % 10;
}
if (water == 9999)
water_flag = 2; // 强制转化
if (water_flag == 2) // 2 是总价格
{
water_value = water * 0.5;
dspbuf[4] = water_value / 1000;
dspbuf[5] = water_value / 100 % 10;
dspbuf[6] = water_value / 10 % 10;
dspbuf[7] = water_value % 10;
water = 0; // 清0
water_flag = 0; // 状态改变
}
// 光敏电阻--->电压
if (adc_flag == 1)
{
adc_flag = 0;
adc_dat = adc_pcf8591();
// 8位 255;1.25/5v=1/4 255*1/4=64;
if (adc_dat < 64)
{
P2 = 0x80;
P0 = 0xfe;
P2 = 0x00;
}
else
{
P2 = 0x80;
P0 = 0xff;
P2 = 0x00;
}
}
}
}
void isr_time_0() interrupt 1
{
static unsigned char key_time = 0; // 键盘刷新次数
static unsigned char water_time = 0;
static unsigned char adc_time = 0;
if (++key_time == 10)
{
key_flag = 1;
key_time = 0;
}
display();
if (water_flag == 1) // 1 是出水
{
// 100ml/s 100ms 数字加1
if (++water_time == 100)
{
water_time = 0;
water++;
}
}
if (++adc_time == 200) // 200ms测一次
{
adc_time = 0;
adc_flag = 1;
}
}