声明:代码确实写的不好,用的都是最笨的方法实现功能,不喜勿喷
第三届是我写的最后一届省赛题了,从第九届到第三届其实感触还是有很多的,从第三届一直往上到第九届,难度也在逐渐的增加,而且考察的方面一直在一个圈子里面,从来没有超出过。
第三届考察的是AD模块、按键模块和数码管处模块。下面看一下这届的题目:
题目中有几位数码管的数字是要求第八位也显示的,这也就要求我们要知道数码怎样显示一个数字,我们要知道这个数码管是一个共阳数码管,知道了共阳数码管一切就好办了。还有一点要注意的就是在数字不断加一的过程中,进位这里不要弄错。AD转换方面主要注意的就是AD的驱动函数要写好,要按照手册上去写,不要随便的加一些延时函数,这样很可能导致你的AD采集不准确或者说采集不成功。
这个题目我也说一下自己的思路吧:
第一步:实现按下S7之后的出水量的计算(我用的是定时器实现一秒钟加数码管数值改变一次)以及继电器的打开
第二步:实现按下S6之后实现水费的显示以及继电器的关闭
第三步:实现AD采集以及L1灯的亮灭(将采集的数据与64相比较,题目要求我们是1.25V也就是说在0到5区间的1.25,那也就是0到256的64)
下面看一下我写的代码:
第一:按键代码(这个题目比较简单只用了两个独立按键)
#include "key.h"
uchar KeyS7_open;
uchar KeyS6_close;
//独立按键扫描函数
void D_keyscan()
{
if(P30==0)
{
Delay5ms();
if(P30==0) //按键S7
{
KeyS7_open = 1;
}
while(!P30);
}
else if(P31==0) //按键S6
{
Delay5ms();
if(P31==0)
{
KeyS6_close = 1;
}
while(!P31);
}
else if(P32==0) //按键S5
{
Delay5ms();
if(P32==0)
{
}
while(!P32);
}
else if(P33==0) //按键S4
{
Delay5ms();
if(P33==0)
{
}
while(!P33);
}
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
第二:数码管程序
#include "shuma.h"
u8 shu_tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XC6,0XFF,0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10};//0XC6是英文C
uchar yi,er,san,si,wu,liu,qi,ba;
//第一和第二个数码管
void Display1_2(uchar yi,uchar er)
{
P2=0XC0;//打开位选573 U8
P0=0X01;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[yi];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X02;//选择第二个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[er];
Delay1ms();Delay1ms();
}
//第三和第四个数码管
void Display3_4(uchar san,uchar si)
{
P2=0XC0;//打开位选573 U8
P0=0X04;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[san];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X08;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[si];
Delay1ms();Delay1ms();
}
//第五和第六个数码管
void Display5_6(uchar wu,uchar liu)
{
P2=0XC0;//打开位选573 U8
P0=0X10;//选择第三个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[wu];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X20;//选择第四个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[liu];
Delay1ms();Delay1ms();
}
//第七和第八个数码管
void Display7_8(uchar qi,uchar ba)
{
P2=0XC0;//打开位选573 U8
P0=0X40;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[qi];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X80;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[ba];
Delay1ms();Delay1ms();
P2=0XFF;//打开段选573 U7
P0=0XFF;
}
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
第三:AD程序
#include "ad.h"
/*
IICAD_read(0x03);//读取滑动变阻器的值
IICAD_read(0x01);//读取光敏电阻的值
*/
//AD开始函数
void IICAD_statrt(void)
{
SDA = 1;
_nop_();
SCL = 1;
_nop_();
SDA = 0;
_nop_();
SCL = 0;
_nop_();
}
//AD停止函数
void IICAD_stop(void)
{
SDA = 0;
_nop_();
SCL = 1;
_nop_();
SDA = 1;
_nop_();
}
//向AD写一个字节
void AD_writebyte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
SCL = 0;
_nop_();
SDA = dat&0x80;
_nop_();
SCL = 1;
dat<<=1;
}
SCL = 0;
_nop_();
}
//应答函数
uchar ACK_AD(void)
{
SCL = 1;
IICAD_delay(5);
if(SDA == 1)
{
SCL = 0;
IICAD_stop();
Delay100us();
return 0;
}
else
{
SCL = 0;
Delay100us();
return 1;
}
}
//从AD中读取数据
uchar IICAD_read(uchar add)
{
uchar temp;
IICAD_statrt();
AD_writebyte(0x90);
ACK_AD();
AD_writebyte(add);
ACK_AD();
IICAD_stop();
IICAD_statrt();
AD_writebyte(0x91);
ACK_AD();
temp = IICAD_readbyte();
ACK_AD();
//现在显示的是0-255,如果需要显示0-100可以加代码(temp = 0.39*temp;)
return temp;
}
//从AD中读取一个字节
uchar IICAD_readbyte()
{
uchar dat;
uchar i;
SCL = 0;
_nop_();
SCL = 1;
_nop_();
for(i=0;i<8;i++)
{
SCL = 1;
dat<<=1;
if(SDA)
{
dat |= 0x01;
}
SCL = 0;
}
return dat;
}
void IICAD_delay(uchar a)
{
do
{
_nop_();
}
while(a--);
}
void Delay100us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
}
第四:初始化函数(.c)
#include "system.h"
void Init(void)
{
P2=0XA0;//打开蜂鸣器,继电器控制端
P0=0X00;//关闭蜂鸣器,继电器
P2=0X80;//打开LED灯控制端
P0=0XFF;//关闭LED灯
P2=0XC0;//打开数码管片选控制端
P0=0XFF;//选择所有数码管
P2=0XFF;//打开数码管段选控制端
P0=0XFF;//关闭所有数码管段选
}
初始化函数(.h)
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include "STC15F2K60S2.H"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
typedef unsigned char u8;
typedef unsigned int u16;
void Init(void);
#endif
最后一部分:主函数程序
#include "system.h"
#include "ad.h"
#include "key.h"
#include "shuma.h"
void Timer0Init(void);
extern uchar yi,er,san,si,wu,liu,qi,ba;
extern uchar KeyS7_open; //按键S7按下之后显示出水量
extern uchar KeyS6_close; //按键S6按下之后关闭出水,显示价格
float Price; //存储价格的变量
uchar Price_int; //存储价格的整数部分
uchar Price_float; //存储价格的小数部分
uint AD_num; //存储AD读取的数据
uint Dis_timer; //控制出水为1秒中出水0.1L时间位
uchar Dis_flag; //控制出水为1秒中出水0.1L标志位
uchar Dis_price; //控制出水量为99.9L时显示价格
uchar Init_flag; //控制进入函数初始化一次变量
uchar ADD_flag1; //用在出水量进位的变量
uchar ADD_flag2; //用在出水量进位的变量
uchar AD_read_flag; //AD每100ms读取一次的标志位
uchar AD_read_timer; //AD每100ms读取一次的时间控制位
uchar num_1; //为实现计费与出水模式的循环设定的储存数值的变量
uchar num_2; //为实现计费与出水模式的循环设定的储存数值的变量
uchar num_3; //为实现计费与出水模式的循环设定的储存数值的变量
void main(void)
{
Init();
Timer0Init();
yi = 12;er = 13;san = 5;si = 0;
wu = 12; liu = 12;qi = 12;ba = 12;
while(1)
{
D_keyscan();
if(AD_read_flag == 1)
{
AD_num = IICAD_read(0x01); //采集AD数据
AD_read_flag = 0;
if(AD_num < 64) //AD数据小于1.25时L1灯亮
{
P2 = 0X80;
P0 = 0XFE;
}
else //AD数据大于1.25时L1灯灭
{
P2 = 0X80;
P0 = 0XFF;
}
}
if(KeyS7_open == 1) //按键S7按下
{
if(Init_flag == 0) //控制进入函数初始化一次变量
{
Init_flag = 1;
wu = 0;liu = 0;
qi = 0;ba = 0;
KeyS6_close = 0;
}
if((qi == 9) && (liu == 22) && (wu == 9))//控制出水量为99.9L时显示价格
{
Dis_price = 1;
qi = 9;liu = 23;wu = 9;
P2=0XA0;P0=0X00; //关闭继电器
}
else //出水量小于99.9L
{
P2=0XA0;P0=0X10; //开启继电器
if(Dis_flag == 1) //控制出水为1秒中出水0.1L标志位
{
Dis_flag = 0;
num_1 = num_1 + 1;
if(num_1 == 10)
{
ADD_flag1 +=1;
num_2 = 13 + ADD_flag1;
num_1 = num_1 - 10;
}
else if(num_1 < 10)
{
num_2 = 13 + ADD_flag1;
}
if(num_2 == 23)
{
ADD_flag2 +=1;
num_3 = 0 + ADD_flag2;
num_2 = num_2 - 10;
ADD_flag1 = 0;
}
ba = 0;
qi = num_1;
liu = num_2;
wu = num_3;
}
}
if((KeyS6_close == 1) || (Dis_price == 1))//按键S6按下或者出水量达到99.9
{
P2=0XA0;P0=0X00; //关闭继电器
Dis_price = 0;
KeyS7_open = 0;
KeyS6_close = 0;
Price = (qi + (liu - 13)*10 + wu*100)*0.5*0.1;//计算价格
Price_int = (int)Price;
Price_float = (Price - Price_int)*100;
wu = Price_int/10; //将价格显示在数码管上
liu = (Price_int%10 + 13);
qi = Price_float/10;
ba = Price_float%10;
}
Display1_2(yi,er);
Display3_4(san,si);
Display5_6(wu,liu);
Display7_8(qi,ba);
}
Display1_2(yi,er);
Display3_4(san,si);
Display5_6(wu,liu);
Display7_8(qi,ba);
}
}
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
void Timer0(void) interrupt 1
{
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
AD_read_timer++;
if(AD_read_timer == 50)//AD每100ms读取一次
{
AD_read_timer = 0;
AD_read_flag = 1;
}
if(KeyS7_open == 1)
{
Dis_timer++;
if(Dis_timer == 500) //控制出水为1秒中出水0.1L时间位
{
Dis_timer = 0;
Dis_flag = 1; //控制出水为1秒中出水0.1L标志位
}
}
}
在文章的最后我也把我的完整工程上传一下,供大家参考https://download.csdn.net/my