蓝桥杯——13届第二批试题解析

蓝桥杯第13届第二批结束了,很多人在考前没有准备超声波的部分,所以看起来总体比较难。

话不多说先看框图:

 一共由五个部分组成,除去必考的按键、LED、数码管。考到的其实就是超声波PCF8591

按键部分的功能:

 可能是因为考了超声波吧,所以这次题的按键部分考的就是简单的的独立按键,和第一批试题的小矩阵按键不同,可以说把总体的难度平衡了一下。

按键、数码管 这两个部分作为我们工程的最小框架:

看链接: 链接

S8作为界面的切换,S7作为设置参数的选择,S6是加上、下限的值,S5是减上、下限的值。

         为了方便显示我们将上、下限的值扩大十倍,既从 5-50,每次加减 5.

在参数设置的说明里还有两个特殊的说明。

        第一个特殊说明我们可以通过设置两个不同的参数,一个是在设置参数界面时被加减的参数,另一个是退出参数界面被赋值的参数。

        第二个特殊的就是默认修改的参数是上线参数,上线参数相对应的是 set 的值。       

因为需要显示3个界面,所以我们还需要添加两个界面的代码。

我们将后面两个界面先显示提示符,所以只需要修改dis[0]的内容。

连续按下按键按键8我们可以看到数码管界面的切换。

PCF8591部分:

我选择先做PCF8591,因为超声波需要涉及到DAC部分,所以先完成ADC和DAC。这部分需要用到IIC,将官方提供的IIC的代码添加到工程中。

为了不使ADC和DAC发生冲突,所以控制字直接写0x43.PCF8591解析链接

这里RB2电压的adc的频率不宜太高,如果是放在主函数中连续的读取,会有以下几个弊端,第一影响按键的检测,第二影响dac的输出。所以在这里我推荐300ms读一次。或者是其他的时间,只要不太短就行。(换成一定频率读取后也可以放到主函数,也可以放中断)。

 超声波部分:

 这部分我是在比赛的前一天准备的。哈哈哈哈哈,怕什么来什么。还好是准备了。

位定义放到开头/
sbit TX=P1^0;
sbit RX=P1^1;
放到定时器初始化函数中///
CMOD = 0x08;
CCON = 0x00;
函数///
void Delay13us()		//@12.000MHz
{
	unsigned char i;
	_nop_();
	_nop_();
	i = 39;
	while (--i);
}

void send_wave()
{
	unsigned char i=8;
	do
	{
		TX=1;
		Delay13us();
		TX=0;
		Delay13us();
	}
	while(i--);
}
void SonicDrive()
{
	uint time;
    send_wave();
    CH = 0;
    CL = 0;
    CR = 1;
    while((RX) && (CF==0));
    CR= 0;
    if(CF == 1) 
    {
        CF = 0; 
    }
    else 
    {
        time = (CH * 256) + CL;
        distance = (uint)((time * 0.017) / 12 );
  	}
}

LED闪烁:

        LED的闪烁,其实具体的实现是靠闪烁的标志位的    0-1的变换 每100ms状态颠倒一次。

设计题:

 

 

 

 

 main:

#include "stc15.h"
#include "iic.h"
#define FOSC 12000000L
#define uchar unsigned char 
#define uint  unsigned int
sbit TX=P1^0;
sbit RX=P1^1;
///
void Init();
void BTN();
void Timer();
void Delay100us();
void display_u();
void display_p();
void display_t();
void SonicDrive();
///
unsigned char Trg,Cont,flag,menu=1,set=1,add,sub;
void write_dac(uchar dat);
uchar code LedChar[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
uint dac_v,distance;
uchar L1,L2,L3,L8;
bit L8_b;
uint volt_v;
uchar volt;
uchar dac_value,read_flag;
uchar set_max=45,set_min=5,set_max_1=45,set_min_1=5;
/
void main()
{
	Init();
	Timer();
	while(1)
	{
		
		if(flag) //按键检测的标志10ms进一次
		{
			flag=0; //进入后清空
			BTN();  //按键检测函数
			if(Trg&0x08) // 判断是不是按键S8被按下
			{
				menu++;  //按键S8被按下则进入下一个界面
				if(menu==4) menu =1; //界面循环
			}
			else if(Trg&0x04) // 判断是不是按键S7被按下
			{
				set++;
				if(set==3) set =1;  //设置位循环
			}
			else if(Trg&0x02) // 判断是不是按键S5被按下
			{
				if(menu ==3) add++; //加的标志位,使用后会清空
			}
			else if(Trg&0x01) // 判断是不是按键S4被按下
			{
				if(menu ==3) sub++; //减的标志位,使用后会清空
			}
		}
//参数设置
		if(menu ==3)  //进入参数设置界面
		{
			if(set==1) //设置上限值
			{
				if(add) //执行加操作
				{
					add=0;
					set_max_1=set_max_1+5;
				}
				if(sub) //执行减操作
				{
					sub=0;
					set_max_1=set_max_1-5;
				}
			}
			if(set==2)//设置下限值
			{
				if(add) //执行加操作
				{
					add=0;
					set_min_1=set_min_1+5;
				}
				if(sub) //执行减操作
				{
					sub=0;
					set_min_1 = set_min_1-5;
				}
			}
            //循环 (5-50)
			if(set_min_1<5)   set_min_1=50; 
			if(set_max_1<5)   set_max_1=50;
			if(set_min_1>50)  set_min_1=5;
			if(set_max_1>50)  set_max_1=5;
		}
		
	if(menu==1) //从设置界面出来后将设置的值赋给上下限,达到题目中的要求 ”退出设置界面生效“
	{
		set_max=set_max_1;
		set_min=set_min_1;
	}
adc dac
	if(read_flag) //读取RB2电压值的标志位
	{
		read_flag =0; //清空标志位
		dac_value = read_adc(0X43); //adc读取电压的同时,允许模拟输出
	    dac_v = dac_value*1.96;     //电压转换,并扩大一百倍
	}
/LED
	if((set_min*10<dac_v) && (dac_v<set_max*10))  //因为ADC的值扩大了一百倍,而上下限在这设置的时候只扩大了10倍,所以这里还需要扩大十倍才能比较。
	{
		L8=1;        //如果ADC的值在上下限之间则L8开始闪烁,同时是超声波开启连续测距的标志位
	}
	else //如果ADC的值在上下限之外则L8熄灭。
	{
		L8_b=0;    
		L8=0;
	}
	if(menu==1) //界面1 => L1 亮 L2、L3熄灭
	{
		L1=1;
		L2=0;
		L3=0;
	}
	else if(menu==2) //界面2 => L2 亮 L1、L3熄灭
	{
		L1=0;
		L2=1;
		L3=0;
	}
	else if(menu==3) //界面3 => L3 亮 L1、L2熄灭
	{
		L1=0;
		L2=0;
		L3=1;
	}
			
	if(L1&&L8_b)
	{
		P2=0x80;
		P0=0X7E;
	}
	else if(L2&&L8_b)
	{
		P2=0x80;
		P0=0X7d;
	}
	else if(L3&&L8_b)
	{
		P2=0x80;
		P0=0X7b;
	}
	else if(L1)
	{
		P2=0x80;
		P0=0XFE;
	}
	else if(L2)
	{
		P2=0x80;
		P0=0XFD;
	}
	else if(L3)
	{
		P2=0x80;
		P0=0XFb;
	}

	}
}

void Init()
{
	P2=0X80;
	P0=0XFF;
	P2=0XA0;
	P0=0X00;
}

void Timer()
{

	AUXR |= 0x80;
	TL0 = 0xCD;
	TH0 = 0xD4;
	EA  = 1;
	TR0 = 1;		
	ET0 = 1;
	
	CMOD = 0x08; //超声波专用的定时器
	CCON = 0x00;
}
void Timer0() interrupt 1
{
	static uchar flag_cnt=0,dis_cnt=0,re_adc_cnt=0,L8_blink_cnt=0;
	static uint re_dis_cnt=0;
	flag_cnt++; //按键标志位的计数
	if(flag_cnt==10) //周期10ms
	{
			flag_cnt=0;
			flag=1;
	}
	dis_cnt++; //数码管显示的计数
	if(dis_cnt==5) //周期5ms
	{
		dis_cnt=0;
		if(menu==1) display_u();
		else if(menu==2) display_p();
		else if(menu==3) display_t();
	}
	re_adc_cnt++; //读取RB2电压的计数
	if(re_adc_cnt==300); //周期300ms
	{
		re_adc_cnt=0;
		read_flag =1;
	}
	if(L8==1)  //L8点亮的标志位
	{
		L8_blink_cnt++;
		if(L8_blink_cnt==100) //闪烁周期100ms
		{
			L8_blink_cnt=0;
			L8_b=~L8_b;
		}
	}

	if(L8==1) //超声波开启连续测距
	{
		re_dis_cnt++;  //测距的计数
		if(re_dis_cnt==300) //测距周期300ms
		{
			re_dis_cnt=0;
			SonicDrive();
			//distance=81;
			if(distance>=20&&distance<=80) //对应函数
			{
				volt_v = 6.7*distance-34;
				if(volt_v<=0) volt_v=0;
				volt = (51* volt_v)/100;
				write_dac(volt);
			}
			else if(distance<20)
			{
				write_dac(51);
			}
			else if(distance>80)
			{
				write_dac(255);
			}
		}
	}
	else if(L8 ==0) //如果不测距,则DAC输出0V
	{
		re_dis_cnt++;
		if(re_dis_cnt>=300)
		{
			write_dac(10);
			re_dis_cnt=0;
		}
	}
	
}
void Delay13us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	_nop_();
	i = 39;
	while (--i);
}
void send_wave()
{
	unsigned char i=8;
	do
	{
		TX=1;
		Delay13us();
		TX=0;
		Delay13us();
	}
	while(i--);
}
void SonicDrive()
{
		uint time;
    send_wave();
    CH = 0;
    CL = 0;
    CR = 1;
    while((RX) && (CF==0));
    CR= 0;
    if(CF == 1) 
    {
        CF = 0; 
    }
    else 
    {
        time = (CH * 256) + CL;
        distance = (uint)((time * 0.017) / 12 );
  	}
}
void BTN()
{
	unsigned char dat=P3^0xff;
	Trg = dat & (dat^Cont);
	Cont = dat;
}

void display_u() 
{
	uchar dis[8],i;
	dis[0]=0Xc1;//0Xc1  0X88
	dis[1]=0XFF ;
	dis[2]=0XFF;
	dis[3]=0XFF;
	dis[4]=0XFF;
	dis[5]=LedChar[dac_v/100%10]^0x80;
	dis[6]=LedChar[dac_v/10%10] ;
	dis[7]=LedChar[dac_v%10] ;
	for(i=1;i<8;i++)
	{
		if(dis[i]==LedChar[0])
		{
			dis[i]=0xff;
		}
		else break;
	}
	for(i=0;i<8;i++){
		P2&=0x1f;
		P0=1<<i;
		P2|=0xc0;
		P2&=0x1f;
		P0=dis[i];
		P2|=0xe0;
		Delay100us(); 
		P0=0xff;
	}
	P2&=0x1f;
}
void display_p() 
{
	uchar dis[8],i;
	dis[0]=0Xc3;
	if(L8)
	{
		dis[1]=0xff;
		dis[2]=0xff;
		dis[3]=0xff;
		dis[4]=0xff;
		dis[5]=LedChar[distance/100%10];
		dis[6]=LedChar[distance/10%10];
		dis[7]=LedChar[distance%10];
	}
	else if(L8==0)
	{
		dis[1]=0xff;
		dis[2]=0xff;
		dis[3]=0xff;
		dis[4]=0xff;
		dis[5]=0X88;
		dis[6]=0X88;
		dis[7]=0X88;
	}

	for(i=5;i<8;i++)
	{
		if(dis[i]==LedChar[0])
		{
			dis[i]=0xff;
		}
		else break;
	}
	for(i=0;i<8;i++){
		P2&=0x1f;
		P0=1<<i;
		P2|=0xc0;
		P2&=0x1f;
		P0=dis[i];
		P2|=0xe0;
		Delay100us(); 
		P0=0xff;
	}
	P2&=0x1f;
}


void display_t()
{
	uchar dis[8],i; 
	dis[0]=0X8c;  //0X88
	dis[1]=0XFF ;
	dis[2]=0XFF;
	dis[3]=LedChar[set_max_1/10%10]^0x80;
	dis[4]=LedChar[set_max_1%10];
	dis[5]=0XFF;
	dis[6]=LedChar[set_min_1/10%10]^0x80;
	dis[7]=LedChar[set_min_1%10] ;
	for(i=1;i<8;i++)
	{
		if(dis[i]==LedChar[0])
		{
			dis[i]=0xff;
		}
		else break;
	}
	for(i=0;i<8;i++){
		P2&=0x1f;
		P0=1<<i;
		P2|=0xc0;
		P2&=0x1f;
		P0=dis[i];
		P2|=0xe0;
		Delay100us(); 
		P0=0xff;
	}
	P2&=0x1f;
}
void Delay100us()		//@12.000MHz
{
	unsigned char i, j;

	i = 2;
	j = 39;
	do
	{
		while (--j);
	} while (--i);
}

IIC.C

#include "iic.h"
#define DELAY_TIME 5
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;  					
    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;
}
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;  
}
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;    
}
unsigned char read_adc(unsigned char dat)
{
	unsigned char date;
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	date= IIC_RecByte();
	IIC_Stop();
	return date ;
}
void write_dac(unsigned char dat)
{
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(0x43);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Stop();
}

IIC.H

#ifndef _IIC_H
#define _IIC_H
#include "stc15.h"
#include "intrins.h"
sbit SDA = P2^1;
sbit SCL = P2^0;
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 write_dac(unsigned char dat);
unsigned char read_adc(unsigned char dat);
#endif

PS:省赛结束了,要开始备战国赛了,希望取得一个满意的成绩。hhhhhhh。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值