第十六届蓝桥杯单片机省赛

一、比赛题目

 

本届蓝桥杯单片机难度相较于第 15 届有所提升,题目在细节方面较多。下面对相关难点及易错细节进行分析。​

二、难点剖析​

(一)超声波模块考察​

超声波以及串口部分,是许多首次参加蓝桥杯的选手常常选择忽略的知识点。这就导致在比赛时,面对超声波模块不知如何使用。​

(二)距离数据采集与运动状态判定​

  1. 赛题要求设备间隔 1 秒采集距离数据,并依据连续两次采集的距离差值(ΔL)来判定运动状态。虽然连续两次采集对于大部分选手而言并非难事,但采集时间间隔的把控以及状态锁定机制成为难点。​

  1. 运动状态更新与保持机制:当运动状态发生变化时,该状态会立即更新并锁定 3 秒。在这锁定的 3 秒期间,正常的距离采集功能依旧保持,但不会对运动状态变化进行判定。需要注意的是,运动状态改变后锁定 3 秒,并非 3 秒后就能立刻改变运动状态。实际上,3 秒后才开始采集距离差值,即在解锁后的第一秒初和末,根据这一秒采集时间内的距离差值来判断运动状态是否变化。所以,状态锁定的实际时间为 3 + 1 = 4 秒。从题目所给的运动状态更新图也能清晰看出,上电后并不立即采集,1 秒后开始采集,第二秒开始时判断距离差值,然后改变状态并锁定三秒,到第五秒结束,第六秒采集这一秒的距离差值并进行判断。由此可知,总共的锁定时间至少是 4 秒。​

(三)光敏电阻获取环境光强数据​

通过光敏电阻获取环境光强数据。需要注意的是,亮度等级越高表示环境越暗,在编写代码时无需进行反向逻辑处理。​

(四)双按键长按考点​

双按键长按这一考点在十四届国赛中曾出现过。对于没有做过国赛题的选手而言,往往难以写出双按键的相关代码。实现方法是在矩阵按键底层,通过行列扫描判断 P33 和 P32 这两个 IO 口是否同时为低电平,若同时为低电平,则表示 S8 和 S9 两个按键同时按下。​

三、其他易错细节​

  1. 超声波数码管显示时,采用高位补 0 的方式,而非高位熄灭。​
  2. 设备间隔 1 秒采集距离数据,刚上电时不采集,1 秒后才开始进行采集操作。​
  3. 当设备触发 “接近” 判定时,L1 - L4 指示灯需按照题目要求显示;在未触发 “接近” 判定的情况下,L1 - L2 - L3 - L4 指示灯全部熄灭。​
  4. 进入参数界面时,LED、继电器状态会被锁定(不可变化),退出参数界面后取消状态锁定,这里的锁定意味着运动状态不改变。​
  5. 数码管显示内容刷新需满足刷新≤0.1 秒的性能要求。​
  6. 每次从运动检测界面切换到参数设置界面时,默认处于温度参数子界面。​
  7. 在统计界面下,当 S8、S9 按键均按下且保持 2 秒以上时,可清零继电器吸合次数数值。需要注意的是,双按键操作仅在统计界面下有效。​

四、赛题源码

以下是博主写的本届赛题的源码,代码仅供参考,不一定全对。

main.c

#include <STC15F2K60S2.H>
#include <smg.h>
#include <init.h>
#include <key.h>
#include <wave.h>
#include <led.h>
#include <onewire.h>
#include <iic.h>
#include <intrins.h>
#include <math.h>
unsigned char key_up,key_down,key_val,key_old,key_slow_down;
unsigned char smg_pos,smg_pont[8] = {0,0,0,0,0,0,0,0},smg_buf[8] = {10,10,10,10,10,10,10,10};
unsigned char smg_Slow_down;
unsigned char ledbuf[8] = {0,0,0,0,0,0,0,0};

unsigned char temperature;//温度变量
unsigned char cs_temperature = 30;//温度参数
unsigned char cs_jl = 30;//距离参数
unsigned char smg_mode;//0环境状态 1运动检测 2参数设置 3统计数据
unsigned char sport_flag = 0;//0静止 1徘徊 2跑动
unsigned char sport_flag_gb = 0;//判断状态是否改变
unsigned char light_level;//光强等级
unsigned char rd_wave;//超声波

unsigned char cj_wave;//采集距离超声波
unsigned char relay_date;//继电器吸合次数
unsigned int time_3s;
unsigned int time_1s;//
unsigned int change_rd_wave;//距离改变值
unsigned int time_2s;
unsigned char time_100ms;

bit relay_flag;
bit led_flag;//led闪烁标志位
bit jiejin;//1接近判断
bit high_temp;//高温判定
bit merue_flag;//采集标志位
bit start_cj_flag;//避免第一次采集
float ani1_Ad;//光敏
bit cs_flag;//0温度 1距离
bit sd_flag;//状态锁定标志位
bit qk_flag;
void Delay750ms(void)	//@12.000MHz
{
	unsigned char data i, j, k;

	_nop_();
	_nop_();
	i = 35;
	j = 51;
	k = 182;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void key_proc()
{
    if(key_slow_down<10) return;
	key_slow_down = 0;
	
	key_val = key_read();
	key_down = key_val & (key_val ^ key_old);
	key_up =   ~key_val& (key_val ^ key_old);
	key_old = key_val;
	
	
	if(smg_mode==3)
	{
	if(key_old == 89)
	{
		qk_flag = 1;
		if(time_2s>=2000)
		{
				relay_date = 0;
		}	
	}
	else
	{
		time_2s = 0;
		qk_flag = 0;
	}
}
	

	switch(key_down)
	{
		case 4://界面切换
			if(++smg_mode==4) smg_mode = 0;
		
		
		cs_flag = 0;
		break;
		case 5://参数界面
			if(smg_mode==2)
				cs_flag ^= 1;
		break;
		case 8://+
			if(smg_mode==2)
			{
			if(cs_flag==0) //温度参数界面
			 {
				cs_temperature++;
			if(cs_temperature==81) cs_temperature = 80;
		 	 }
			else
		   	{
				cs_jl+=5;
			if(cs_jl==85) cs_jl = 80;
			  }
			}
				
		break;
			
					case 9://-
			if(smg_mode==2)
			{
			if(cs_flag==0) //温度参数界面
			 {
				cs_temperature--;
			if(cs_temperature==19) cs_temperature = 20;
		 	 }
			else
		   	{
				cs_jl-=5;
			if(cs_jl==15) cs_jl = 20;
			  }
			}
				
		break;
	
	}

}
void smg_proc()
{
  if(smg_Slow_down<90) return;
	smg_Slow_down = 0;
	
	
	 ani1_Ad = ad_Read(0x01)/51;
	 rd_wave = wave_Read();
	 temperature =read_temperature();
	
	if(ani1_Ad>=3)
		light_level = 0;
	else if(ani1_Ad<3 && ani1_Ad>=2)
		light_level = 1;
	else if(ani1_Ad<2&&ani1_Ad>=0.5)
		light_level = 2;
	else if(ani1_Ad<0.5)
	light_level = 3;
	
	

	if(merue_flag==1)//运动状态采集
	{
		if(start_cj_flag==1)
		change_rd_wave = abs(cj_wave - rd_wave);//变化距离
		
		start_cj_flag = 1;
		cj_wave = rd_wave;
		
	merue_flag = 0;
	}
	
	if(change_rd_wave<cs_jl)//触发接近判定
		jiejin = 1;
	else
		jiejin = 0;
	
	
		if(cs_temperature<temperature)//触发高温判定
		high_temp = 1;
	else
		high_temp = 0;
	
	
	if(sd_flag==0)//可以改变状态
	{
	if(change_rd_wave<5) //静止
	sport_flag = 0;
	else if(change_rd_wave>=5&&change_rd_wave<10) //徘徊
	sport_flag = 1;
	else if(change_rd_wave>=10) //跑动
  sport_flag = 2;
  }
	
	if(sport_flag != sport_flag_gb)
	{
		sd_flag = 1;//状态锁定

		
		
	sport_flag_gb = sport_flag;
	}
	
	switch(smg_mode)
	{
		case 0://环境状态
		smg_buf[0] = 11;//C
		smg_buf[1] = temperature/10%10;
		smg_buf[2] = temperature%10;
   smg_buf[4] = 10;
		smg_buf[5] = 10; 
		smg_buf[6] = 12;//n
		smg_buf[7] = light_level+1;
		break;
	
			case 1://运动检测状态
		smg_buf[0] = 13;//L
		smg_buf[1] =sport_flag+1;
			
		smg_buf[2] =10;

   smg_buf[4] = 10;
		smg_buf[5] = rd_wave/100%10; 
		smg_buf[6] = rd_wave/10%10;//n
		smg_buf[7] = rd_wave%10;
		break;
			
		case 2://参数界面
			 smg_buf[0] = 14;//P
			 smg_buf[5] =	smg_buf[2] = 10;
		   smg_buf[4] = 10;
			if(cs_flag==0)
			{
		smg_buf[1] =11;//C

		smg_buf[6] = cs_temperature/10%10;//
		smg_buf[7] = cs_temperature%10;
	  	}
			else
			{
		smg_buf[1] =13;//L
  
		smg_buf[6] = cs_jl/10%10;//
		smg_buf[7] = cs_jl%10;
			}
		break;
			
						case 3://数据统计界面
		smg_buf[0] = 12;//n
		smg_buf[1] = 11;//c
		smg_buf[2] = 10;
		smg_buf[3] = 10;
		smg_buf[4] =relay_date/1000? relay_date/1000%10:10; 
		smg_buf[5] =relay_date/100? relay_date/100%10:10; 
		smg_buf[6] = relay_date/10?relay_date/10%10:10;//n
		smg_buf[7] = relay_date%10;
		break;
	}


}

void led_proc()
{
	unsigned char i;
	
	if(smg_mode!=2)
	{
	
 if(jiejin==1)//触发接近判定 灯亮
 {
   ledbuf[0] = 1;
	 ledbuf[1] = (light_level==0)?0:1;
	 ledbuf[2] = (light_level>=2)?1:0;
	 ledbuf[3] = (light_level==3)?1:0;
 }	 
 else
 {
    for(i=0;i<5;i++)
    ledbuf[i] = 0;
 
 }
 
 	switch(sport_flag)
	{
		case 0: //静止
			ledbuf[7] = 0;
		break;
		case 1: //徘徊
			ledbuf[7] = 1;
		break;
		
		case 2://跑动
			ledbuf[7] = led_flag;
		break;
		
	}
 
   if(high_temp==1&&jiejin==1)
	 {
	 relay(1);
		 
		 if(relay_flag==0)
			 relay_date++;
		 
		 relay_flag = 1;
	 }
	 else
	 {
		 relay_flag = 0;
		 relay(0);
	 }
 }
 
}

void Timer0_Init(void)		//1??@12.000MHz
{
	AUXR &= 0x7F;			//?????12T??
	TMOD &= 0xF0;			//???????
	TL0 = 0x18;				//???????
	TH0 = 0xFC;				//???????
	TF0 = 0;				//??TF0??
	TR0 = 1;				//???0????
  ET0 = 1;
	EA = 1;
}
void timer0server() interrupt 1
{
  key_slow_down++;
	smg_Slow_down++;
	if(++smg_pos==8) smg_pos = 0;
	smg_disp(smg_pos,smg_buf[smg_pos],smg_pont[smg_pos]);
	disp_led(ledbuf);
 
  if(++time_1s == 1000)
	{
	time_1s = 0;
	merue_flag = 1;//开始采集
	}
  if(sd_flag==1)//锁定  计时
	{
	 if(++time_3s==4000)
	 {
	 sd_flag = 0;//解锁
		time_3s = 0;
	 }
	if(qk_flag==1)
	{
    	time_2s++;
		if(time_2s>2000) time_2s = 2001;
	
	}
	}
	if(sport_flag==2)
	{
	if(++time_100ms==100)
	{
	time_100ms = 0;
		led_flag ^= 1;
	}
   }
}
void main()
{
	read_temperature();
	Delay750ms();


	 Timer0_Init()	;
	system_init();
   while(1)
	 {
	   led_proc();
		 key_proc();
		 smg_proc();
	 }


}

led.c

#include <led.h>

unsigned char temp = 0x00;
unsigned char temp_old = 0xff;

void disp_led(unsigned char *ledbuf)
{
   temp = 0x00;
	temp = (ledbuf[0]<<0) | (ledbuf[1]<<1) |(ledbuf[2]<<2) |(ledbuf[3]<<3) |(ledbuf[4]<<4) |
	(ledbuf[5]<<5) |(ledbuf[6]<<6) |(ledbuf[7]<<7) ;
	
	if(temp != temp_old)
	{
	P0 = ~temp;
	P2 = P2 & 0x1f | 0x80;
	P2 &= 0x1f;
	temp_old = temp;
	}

}


void relay(bit flag)
{
   temp = 0x00;
	
	if(flag)
		temp |= 0x10;
	else
		temp &= 0x10;

	if(temp != temp_old)
	{
	P0 = temp;
	P2 = P2 & 0x1f | 0xa0;
	P2 &= 0x1f;
	temp_old = temp;
	}

}

smg.c

#include <smg.h>

unsigned char code smg_dula [] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xc6,0xc8,0xc7,0x8c};
unsigned char code smg_wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

void smg_disp(unsigned char wela,dula,point)
{
   P0 = 0xff;
	P2 = P2 & 0x1f | 0xe0;
	P2 &= 0x1f;
	
	P0 = smg_wela[wela];
	P2 = P2 & 0x1f | 0xc0;
	P2 &= 0x1f;
	
	P0 = smg_dula[dula];
	if(point)
		P0 &= 0x7f;
	P2 = P2 & 0x1f | 0xe0;
	P2 &= 0x1f;
}

init.c

#include <init.h>


void system_init()
{

  	P0 = 0xff;
	P2 = P2 & 0x1f | 0x80;
	P2 &= 0x1f;

  	P0 = 0x00;
	P2 = P2 & 0x1f | 0xa0;
	P2 &= 0x1f;
}

key.c 

#include <key.h>

unsigned char key_read()
{
	unsigned char temp = 0;
	P44 = 0; P42 = 1; P35 =1; P34 = 1;
	if(P33==0) temp = 4;
	if(P32==0) temp = 5;
	if(P31==0) temp = 6;
	if(P30==0) temp = 7;	
	
		P44 = 1; P42 = 0; P35 =1; P34 = 1;
	if(P33==0) temp = 8;
	if(P32==0) temp = 9;
	if(P33==0&&P32==0) temp = 89;


return temp;
	

}
	

超声波 wave.c

#include <wave.h>
#include <intrins.h>

sbit Tx = P1^0;
sbit Rx = P1^1;

void Delay12us(void)	//@12.000MHz
{
	unsigned char data i;

	_nop_();
	_nop_();
	i = 37;
	while (--i);
}

void wave_init()
{
   unsigned char i;
EA = 0;
	for(i=0;i<8;i++)
	{
	Tx = 1;
	Delay12us();
		Tx = 0;
	Delay12us();
	}
EA = 1;

}

unsigned char wave_Read()
{
    unsigned int temp;
	CMOD = 0x00;
	CH = CL = 0;
   wave_init();
	CR = 1;
	while((Rx==1)&&(CF == 0));
	CR = 0;
	if(CF == 0)
	{
	temp = CH << 8 | CL;
	return temp * 0.017;
	}
	else
	{
	CF = 0;
	return 0;
	}


}

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值