缘由
做了十三届的国赛题后想要继续巩固,于是随便选了一套题,以为挺简单,做起来发现还是有点难度。做完自我评价还是不错,又是决定分享出来给需要的同学。
题目
工程链接
链接: [link](程序压缩包https://pan.baidu.com/s/1jVvLsp-Hguih3ejICQpNow
提取码:T02z)
我的理解
第八届的题目粗看下来好像非常简单,感觉是省赛题一样,果细读题目的话就会发现其中的逻辑需要仔细梳理,因为使用到E2PROM,而且需要保存的测量数据有10次,超过了才循环,所以如果初次测量了5次,那么掉电后再上电测量应从第六次保存数据,而不是又从第一次保存数据,所以测量次数也应该保存进E2PROM,而不是简单的设置个全局变量
代码
#include<STC15F2K60S2.H>
#include<intrins.h>
#include <iic.h>
#define uchar unsigned char
#define uint unsigned int
//11:F 12:C
uchar code Tab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff,0x8e,0xc6};
uchar dis_dat[9];//数码管每一位显示值
sbit TX = P1^0;
sbit RX = P1^1;
uint distance_new = 0;//当次测量显示值
uint distance_last = 0;//上次测量显示值
uint distance = 0;//超声波测量值
uint distance_add = 0;//计算结果
uint L1_time = 0;//L1闪烁间隔
uchar mode = 1;//界面选择
uchar key_state = 0;//按键值
uchar distance_adjust = 20;//测量盲区
uchar distance_count = 0x00;//测量次数
uchar mode2_page = 0x01;//数据回显界面页数
uchar SMG_count = 0;//数码管刷新间隔
uchar smg_bit = 0;//数码管位置
uchar led_state = 0xFF;//LED状态
uchar L1_count = 0;//L1亮灭次数
bit operate = 0;//操作位
bit wave_flag = 0;//超声波启动标志
bit L1_flag = 0;//L1标志
bit L7_flag = 0;//L7标志
bit L8_flag = 0;//L8标志
bit L1_complate = 0;//测量完成指示灯
//*************************************延迟5毫秒***********************************
void Delay5ms() //@12.000MHz
{
unsigned char i, j;
i = 59;
j = 90;
do
{
while (--j);
} while (--i);
}
//*************************************初始化*************************************
void Init_System()
{
P2&=0x1f;
P0=0xff;
P2|=0x80;
P2&=0x1f;
P0=0x00;
P2|=0xa0;
P2&=0x1f;
P0=0xFF;
P2|=0xc0;
P2&=0x1f;
P0=0xff;
P2|=0xe0;
P2&=0x1f;
}
//*********************************定时器2中断***********************************
void Timer2Init(void) //100微秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0x50; //设置定时初值
T2H = 0xFB; //设置定时初值
AUXR |= 0x10; //定时器2开始计时
IE2|=0x04;
EA = 1;
}
void Timer2() interrupt 12//每一百微秒进入一次中断
{
P2&=0x1F;
if(++SMG_count==20)//每2毫秒刷新一次数码管
{
SMG_count=0;
P0=0xFF;
P2|=0xE0;
P2&=0x1F;
P0=1<<smg_bit;//位选,数码管依次移动一位
P2|=0xC0;
P2&=0x1F;
P0=Tab[dis_dat[smg_bit+1]];
P2|=0xE0;
P2&=0x1F;
if(++smg_bit>=8)
smg_bit=0;
}
if(L1_complate)//判断测量是否完成
{
if((++L1_time>=2000)&&(++L1_count<=20))
{
L1_flag=!L1_flag;
L1_time=0;
}
else if(L1_count>20)
{
L1_count=0;
L1_complate=0;
}
}
}
//*****************************************超声波程序*************************************
void Timer1Init(void) //10微秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xF6; //设置定时初值
TH1 = 0xFF; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 0; //定时器1开始计时
}
void wave_distance()//超声波测距
{
uchar num = 10;
TX=0;
TH1=0xF6;
TL1=0xFF;
TR1=1;
while(num--)//发送方波
{
while(!TF1);
TF1=0;
TX^=1;
}
TR1=0;
TH1=0;
TL1=0;
TR1=1;
while(RX&&!TF1);//等待接收
TR1=0;
if(TF1)
distance=255;
else
distance=((TH1<<8)+TL1)*0.017;
}
//**********************************数码管程序***********************************
void show_SMG_C()//测距显示界面,单位为cm
{
dis_dat[1]=operate;
dis_dat[2]=10;
if(!operate)//无操作
{
//上次测量结果
if(distance_last>=100)
dis_dat[3]=distance_last/100%10;
else
dis_dat[3]=10;
if(distance_last>=10)
dis_dat[4]=distance_last/10%10;
else
dis_dat[4]=10;
dis_dat[5]=distance_last%10;
//本次测量结果
if(distance_new>=100)
dis_dat[6]=distance_new/100%10;
else
dis_dat[6]=10;
if(distance_new>=10)
dis_dat[7]=distance_new/10%10;\
else
dis_dat[7]=10;
dis_dat[8]=distance_new%10;
}
else//加操作
{
//上次及本次测量和
if(distance_add>=100)
dis_dat[3]=distance_add/100%10;
else
dis_dat[3]=10;
if(distance_add>=10)
dis_dat[4]=distance_add/10%10;
else
dis_dat[4]=10;
dis_dat[5]=distance_add%10;
//本次测量结果
if(distance_new>=100)
dis_dat[6]=distance_new/100%10;
else
dis_dat[6]=10;
if(distance_new>=10)
dis_dat[7]=distance_new/10%10;\
else
dis_dat[7]=10;
dis_dat[8]=distance_new%10;
}
}
void show_SMG_data()//数据回显界面
{
if(mode2_page>=10)
dis_dat[1]=mode2_page/10%10;
else
dis_dat[1]=0;
dis_dat[2]=mode2_page%10;
dis_dat[3]=10;
dis_dat[4]=10;
dis_dat[5]=10;
if(Read_AT24C02(mode2_page)>=100)
dis_dat[6]=Read_AT24C02(mode2_page)/100%10;
else
dis_dat[6]=10;
if(Read_AT24C02(mode2_page)>=10)
dis_dat[7]=Read_AT24C02(mode2_page)/10%10;
else
dis_dat[7]=10;
dis_dat[8]=Read_AT24C02(mode2_page)%10;
}
void show_SMG_F()//参数设置界面
{
dis_dat[1]=11;
dis_dat[2]=10;
dis_dat[3]=10;
dis_dat[4]=10;
dis_dat[5]=10;
dis_dat[6]=10;
dis_dat[7]=distance_adjust/10%10;
dis_dat[8]=0;
}
//******************************************按键程序**************************************
void Key_scan()
{
uchar key_value = 0;
key_value=P3&0x0F;
if(key_value!=0x0F&&!key_state)//判断是否按下
{
Delay5ms();//消抖
key_value=P3&0x0F;
if(key_value!=0x0F&&!key_state)
{
key_state=key_value;
}
}
else if(key_value==0x0F&&key_state)//松手检测
{
Delay5ms();
key_value=P3&0x0F;
if(key_value==0x0F&&key_state)
{
switch(key_state)
{
//S4
case 0x07:
if(mode==1)
{
wave_flag=1;//启动超声波
++distance_count;
Write_AT24C02(0x0C,distance_count);
Delay5ms();
if(wave_flag)
{
wave_flag=0;
wave_distance();
}
L1_complate=1;
distance_new=distance;
if(distance_count<=10)
{
Write_AT24C02(distance_count,distance);
Delay5ms();
distance_last=Read_AT24C02(distance_count-1);
}
else
{
distance_last=Read_AT24C02(distance_count-1);
distance_count=0x01;
Write_AT24C02(distance_count,distance);
Delay5ms();
}
}
break;
//S5,切换数据回显界面
case 0x0B:
if(mode==1)//进入
{
mode=2;
L8_flag=1;
}
else if(mode==2)//退出
{
mode=1;
L8_flag=0;
}
break;
//S6,切换参数设置界面
case 0x0D:
if(mode==1)
{
mode=3;
distance_adjust=Read_AT24C02(0x0B);
L7_flag=1;
}
else if(mode==3)
{
Write_AT24C02(0x0B,distance_adjust);
Delay5ms();
L7_flag=0;
mode=1;
}
break;
//S7翻页及更改参数
case 0x0E:
if(mode==1)//选择操作位
{
operate=!operate;
}
if(mode==2)//翻页
{
if(++mode2_page>10)
mode2_page=1;
}
else if(mode==3)//更改盲区参数
{
distance_adjust+=10;
if(distance_adjust>90)
distance_adjust=0;
}
break;
}
key_state=0;
}
}
}
//*****************************************主函数程序***********************************
void main(void)
{
Init_System();
Timer1Init();
Timer2Init();
distance_count=Read_AT24C02(0x0C);//读取测量次数
while(1)
{
//按键检测
Key_scan();
//DAC输出电压
if(distance_new<=distance_adjust)
Write_PCF8591(0);
else if(distance_new<=270)
Write_PCF8591((5/(270-20)*(distance_new-270)+5)/5*255);
else
Write_PCF8591(255);
//界面显示
distance_add=distance_new+distance_last;
switch(mode)
{
case 1:
show_SMG_C();
break;
case 2:
show_SMG_data();
break;
case 3:
show_SMG_F();
break;
}
//LED灯状态判断
led_state=0xFF;
if(L1_flag)
led_state&=0xFE;
if(L7_flag)
led_state&=0xBF;
if(L8_flag)
led_state&=0x7F;
P0=led_state;P2|=0x80;P0=led_state;P2&=0x1F;
}
}