当前位置:网站首页>蓝桥杯——13届第二批试题解析
蓝桥杯——13届第二批试题解析
2022-06-29 06:39:00 【2020级机器人实验班】
蓝桥杯第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);
#endifPS:省赛结束了,要开始备战国赛了,希望取得一个满意的成绩。hhhhhhh。
边栏推荐
- 利用IPv6實現公網訪問遠程桌面
- [qnx hypervisor 2.2 user manual]6.2.1 communication between guests
- Chinese garbled code on idea console [valid through personal test]
- 数字ic设计——UART
- Unexpected exception ... code: Badrequest when downloading Xilinx 2018.2
- Genicam gentl standard ver1.5 (3) Chapter 4
- 【FreeRTOS】中断机制
- Redis of NoSQL database (II): introduction to redis configuration file
- 部署Prometheus-server服务 system管理
- 解题-->在线OJ(十三)
猜你喜欢

并发幂等性防抖

Markdown 技能树(5):图片

Mmclassification installation and debugging

In vscade, how to use eslint to lint and format

九州云助力内蒙古“东数西算”工程,驱动测绘行业智慧新生态

【软件测试】接口——基本测试流程
如何看待软件测试培训?你需要培训吗?

Explain canfd message and format in AUTOSAR arxml in detail

Uniapp obtains the date implementation of the beginning and end of the previous month and the next month

Tree drop-down selection box El select combined with El tree effect demo (sorting)
随机推荐
Redis of NoSQL database (II): introduction to redis configuration file
Idea integrated code cloud
Ci tools Jenkins installation configuration tutorial
Markdown skill tree (6): List
Ci tool Jenkins II: build a simple CI project
Markdown skill tree (5): picture
ShapeShifter: Robust Physical Adversarial Attack on Faster R-CNN Object Detector
项目中 if else 的代替写法
Markdown skill tree (2): paragraph and emphasis
Livedata source code appreciation - basic use
微信小程序学习笔记(暑假)
LeetCode_ Dynamic programming_ Medium_ 91. decoding method
Introduction to NoSQL database
Markdown skill tree (1): introduction to markdown
systemd 管理node-exporter
National Security Agency and CISA kubernetes reinforcement guidelines - new content in version 1.1
uva10891
利用IPv6实现公网访问远程桌面
关联性——相关性分析
jmeter 用beanshell导入自己jar包老是查找不到