蓝桥杯单片机第十届决赛

9 篇文章 2 订阅

感受:难,比起第8 ,第9,第11套决赛来说,出题人无所不用其极。它也得到了我的尊重,我特地写篇文章总结总结。

难点在于:

(1)功能要求较多:

代码比其他的赛题要多,细节也更多,刚开始写怀疑按键和串口会冲突,试着用一个锁去调度公用的P30和P31资源,结果根本不需要,因为按键只用到了13,12,16,17,刚好避开了P30和P31,所以按键的动态扫描只针对这四列就行。

(2)资源占用多

(3)对外设的细节把握较多

解题步骤:

数码管动态刷新

按键动态扫描(只扫描按键所需的4行,就屏蔽了P30和P31)

led动态刷新

按键长按短按判断(状态机实现)

外设定时使用(超声波,温度,epprom)

串口消息收发(状态机加串口中断)

全工程如下

main函数如下



#include "sys.h"


u8 s=0;
u8 keytime=0;
u8 smgtime=0;

u16 temp;//温度
u8 ctemp=30;//温度参数
u8 dis=0;//距离
u8 cdis=35;//距离参数
u16 cge=0;//参数变动次数
u8 cmode=1;//参数编号 1 :温度数据 2:距离数据 
            // 3:温度参数 4:距离参数  5:变更次数
u16 tempt=0;//读取温度间隔时间
bit uic=0;
u16 dist=0;//读取距离间隔时间

 
u8 longf=0;
u16 longt=0;
bit cdac=0;  // 0:dac输出 1:dac关闭
u8 ledflush=0;
u16 dact=0;//dac输出时间
u8 savef=0;//参数变更保存到epprom标志
 
 
 
u8 bstate=0;//串口指令状态
u8  xdata sendbuf[18]={'\0'};

//dac电压输出
void DacOut(){

	if(cdac){
		  Pcf_W_Dac(20);
	}
	else{
		if(dis<=cdis) Pcf_W_Dac(102);
		else 
			Pcf_W_Dac(204);
	}
}
//判断LED的状态
void Judgement(){
	
	if(temp<(ctemp*100))LEDDT[0]=0;
	else LEDDT[0]=1;
	if(dis<cdis)LEDDT[1]=2;
	else LEDDT[1]=0;
	if(!cdac)LEDDT[2]=3;
	else LEDDT[2]=0;
	
	
}
//判断按键长按与短按状态
void los(){
	static int keys=0;
	if(key_v==12)keys=12;
	else if(key_v==13)keys=13;
 
	if(!keys)return;
	switch(longf){
		case 0:
			longt=0;
			if(key_v==keys)longf=1;
			break;
		case 1:
			if(key_v==keys){
				if(longt++>1000){//达到长按临界值执行长按的瞬间性操作
				if(keys==12)cge=0;//长按12清0
				else if(keys==13)cdac=~cdac;
				longf=2;
			}
		}
		//按键松开
			else {
			 if(longt<=1000){ //执行短按 
									if(keys==12){
										if(!uic){//数据界面显示
										if(cmode==1)cmode=2;
										else if(cmode==2)cmode=5;
										else cmode=1;
										}
										else {//参数界面切换
										if(cmode==3)cmode=4;
										else cmode=3;
										}
									}								 
								else if(keys==13){
									if(!uic){
										uic=1;
										cmode=3;
									}
									else {
										uic=0;
										cmode=1;
									} 
							}
			 keys=0;
			 longf=0;
		}
	}
		break;
		
		case 2:
			if(key_v==keys){//执行长按的连续性操作
				//没有操作空
			}
			else {
				longf=0;
				keys=0;
			}
			break;
	}
}
 
 


void	UISetting(){
	
	if(cmode==1){//温度数据显示
		DT[0]=21;
		DT[1]=10;
		DT[2]=10;
		DT[3]=10;
		DT[4]=temp/1000%10;
		DT[5]=temp/100%10+11;
		DT[6]=temp/10%10;
		DT[7]=temp%10;
		
	}
	else if(cmode==2){//距离数据显示
		DT[0]=22;
		DT[1]=10;
		DT[2]=10;
		DT[3]=10;
		DT[4]=10;
		DT[5]=10;
		DT[6]=dis/10%10;
		DT[7]=dis%10;
	}
	else if(cmode==3){//温度参数显示
		DT[0]=24;
		DT[1]=10;
		DT[2]=10;
		DT[3]=1;
		DT[4]=10;
		DT[5]=10;
		DT[6]=ctemp/10%10;
		DT[7]=ctemp%10;
	}
	else if(cmode==4){//距离参数显示
		DT[0]=24;
		DT[1]=10;
		DT[2]=10;
		DT[3]=2;
		DT[4]=10;
		DT[5]=10;
		DT[6]=cdis/10%10;
		DT[7]=cdis%10;
	}
	else {//变更次数显示
 
		
		
		DT[0]=23;
		DT[1]=10;
		DT[2]=10;
		DT[3]=cge>=10000?cge/10000:10;
		DT[4]=cge>=1000?cge/1000%10:10;
		DT[5]=cge>=100?cge/100%10:10;
		DT[6]=cge>=10?cge/10%10:10;
		DT[7]=cge%10;
		
	}

}

void KeyConsole(){
	
	if(keytime>8){
			keytime=0;
			 
				key_scan();
		 
				if(rkey){
					switch(rkey){
				 
					case 16:
				 //参数次数变动
						if(cmode==3){
							
							 
									cge++;
							if(ctemp==0)return;
							ctemp-=2;
						}
						else if(cmode==4){
							cge++;
							if(cdis==0)return;
							cdis-=5;
						}
						savef=1;
			 
						break;
					case 17:
					 
						if(cmode==3){
							ctemp+=2;
							cge++;
						}
						else if(cmode==4){
							cdis+=5;
							cge++;
						}
						savef=1;
						break;
					default:
						break;
				}
				}
		
	}
	
	
}
void main(){
	
	UartInit();//定时器2的串口初始化
	Timer1Init();
	sys_init();
 Timer0Init();
	
	
	while(1){
		 //按键扫描
		 KeyConsole();
		//界面显示
		if(smgtime>48){
			smgtime=0;
			
			UISetting();
			Judgement();
				if(savef){
				if(savef==1){//将改变次数保存到epprom ,分两次保存
					EppromW(0,cge/256);
					savef=2;
				}
				else if(savef==2){
					EppromW(1,cge%256);
					savef=0;
				}
			}
		}
		if(dact>479){
			dact=0;
			DacOut();
		}
		//测温
		if(tempt>540){
	//  
			tempt=0;
			 temp=ReadTemp()*100;
			
		}
		//超声波测距
		if(dist>=898){
			dist=0;
			 dis=get_dis();
		 
		}
	 
		
 
	}

}
void TIME1() interrupt 3{//  
	
		smg_play(DT[s],s++);
		if(s>7)s=0;
		smgtime++;
		keytime++;
		dist++;
		tempt++;
		dact++;
		los();
		if(ledflush++==10){
			ledflush=0;
			 LedRunning();
		}
		
		
	}
	
	
	
void UART1() interrupt 4{
		
 
  ReceiveDate();
		
		
		
	}
	
	
	void ReceiveDate(){
				u8 rec;
			 
				if(RI==1){		//每次接受完字符后判断
				RI=0;
				rec=SBUF;
					switch(bstate){
						case 0:
								if(rec=='S')bstate=1;
								else if(rec=='P')bstate=5;
								else bstate=13;
								break;
						case 1:
								if(rec=='T')bstate=2;
								else bstate=13;
								break;
						case 2:
								if(rec=='\r')bstate=3;
								else bstate=13;
								break;
						case 3:
							if(rec=='\n')bstate=4;
							else bstate=13;
								break;	
						case 5:
								if(rec=='A')bstate=6;
								else bstate=13;
								break;
						case 6:
							if(rec=='R')bstate=7;
							else bstate=13;
							break;
						case 7:
							if(rec=='A')bstate=8;
							else bstate=13;
							break;
						case 8:
							if(rec=='\r')bstate=9;
							else bstate=13;
							break;
						case 9:
							if(rec=='\n')bstate=10;
							else bstate=13;
							break;
 
					}
					
			 
					 
						
					if(bstate==4){//查询数据指令
					  sendbuf[0]='$';
						sendbuf[1]=dis/10%10+48;
						sendbuf[2]=dis%10+48;
						sendbuf[3]=',';
						sendbuf[4]=temp/1000%10+48;
						sendbuf[5]=temp/100%10+48;
						sendbuf[6]='.';
						sendbuf[7]=temp/10%10+48;
						sendbuf[8]=temp%10+48;
						sendbuf[9]='\r';
						sendbuf[10]='\n';
						sendbuf[11]='\0';
						SendString(sendbuf);
						bstate=0;	
					 
					}
					//查询参数指令
					//返回当前的距离参数和温度参数
					else if(bstate==10){
						sendbuf[0]='#';
						sendbuf[1]=cdis/10%10+48;
						sendbuf[2]=cdis%10+48;
						sendbuf[3]=',';
						sendbuf[4]=ctemp/10%10+48;
						sendbuf[5]=ctemp%10+48;
						sendbuf[6]='\r';
						sendbuf[7]='\n';
						sendbuf[8]='\0';
						SendString(sendbuf);
						bstate=0;	
						
					}
       if(bstate==13){		 
				bstate=0;
				//发送错误
					SendString("ERROR\r\n");		 
			}	
					
					
			}
	}

sys.c

 
#include "sys.h"
  
 u8 key_state=0;
 u8 rkey=0;
 u8 key_v=0;
 
 u8 DT[]={10,10,10,10,10,10,10,10};
 u8 code SMGINDEX[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,
	 0xc0&0x7f,0xf9&0x7f,0xa4&0x7f,0xb0&0x7f,0x99&0x7f,0x92&0x7f,
	 0x82&0x7f,0xf8&0x7f,0x80&0x7f,0x90&0x7f,
	 0xc6,0xc7,0xc8,0x8c  //C L n p
	 

};

 

u8  code LED[]={0xff,0xfe,0xfd,0xfb};
u8 LEDDT[]={0,0,0};
void LedRunning(){
	
	P0=0xff;
	P0=LED[LEDDT[0]]&LED[LEDDT[1]]&LED[LEDDT[2]];
	lock(4);
	
}

 void sys_init(){
	 
	 P0=0xff;
	 lock(4);
 
	 
		P0=0;
		lock(5);
 

		P0=0;
		lock(6);
 

		P0=0xff;
		lock(7);
 
	 
	 
 }
void smg_play(u8 du,u8 we){
	
	
 
	P0=0xff;
	lock(7);  //消影
	
	P0=0;
	P0=1<<we;   
	lock(6);
 
	P0=0xff;
	P0=SMGINDEX[du]; 
	lock(7);
 
  
}
void key_scan(){
	
	
	switch(key_state){
		case 0:
			key_v=0;
			P32=1;
			P33=1;
			P34=0;
			P35=0;
			
			if(P33!=1||P32!=1)key_state=1;
			break;
		
		
		case 1:
			P32=1;
			P33=1;
			P34=0;
			P35=0;
			if(P32!=1||P33!=1){
			
			if(!P32)key_v=5;
			else if(!P33)key_v=4;
				
			P34=1;
			P35=1;
			P32=0;
			P33=0;
			if(!P34)key_v+=12;
			else if(!P35)key_v+=8;
			rkey=key_v;
			key_state=2;
			
		}
		else 
			key_state=0;
			break;
		
		
		case 2:
			P32=1;
			P33=1;
			P34=0;
			P35=0;
			rkey=0;
			if(P32==1&&P33==1)key_state=0;
			break;
		default:
			break;
	}
}
  
void Timer1Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x18;		//设置定时初始值
	TH1 = 0xFC;		//设置定时初始值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	EA=1;
	ET1=1;
}






 

sys.h

#ifndef __SYS_H_
#define __SYS_H_

#include "mystc.h"
#define lock(x) P2=P2&0x1f|(x<<5); P2=P2&0x1f;
 

typedef unsigned char u8;
typedef unsigned int u16;
void sys_init();
void smg_play(u8 du,u8 we);
void key_scan();

void Timer1Init(void);
float ReadTemp();
u16 get_dis();
void Timer0Init(void);
void LedRunning();
void Pcf_W_Dac(u8 dat);
void EppromW(u8 word,u8 dat);
void SendString(u8 *str);
void Send_char(u8 q);//发送单个字符
void UartInit(void);
u8 DT[];
 void ReceiveDate();
u8 LEDDT[];
extern u8 rkey;
extern u8 key_v;
 

#endif

其他的是外设驱动文件,需要用的函数都在sys.h里进行声明就行

onewire.c

/*
  程序说明: 单总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
  日    期: 2011-8-9
*/
#include "sys.h"

sbit DQ = P1^4;  //单总线接口

//单总线延时函数
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
	
	u8 i=0;
	while(t--){
		for(i=0;i<10;i++);
	}
}

//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//DS18B20设备初始化
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}

float ReadTemp(){
	
	u8 low,high;
	u16 temp=0;
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);

	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	
	low=Read_DS18B20();
	high=Read_DS18B20();
	temp=high<<8|low;
	
	return temp*0.0625;

}





sonnic.c(用定时器1进行定时算超声波距离)

#include "sys.h"
#include "intrins.h"
//用定时器0来计算时间

sbit RX=P1^1;
sbit TX=P1^0;
void Delay12us()		//@12.000MHz
{
	unsigned char i;

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


void Timer0Init(void)		//100微秒@12.000HZ 定时器0做超声波计时器
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x00;		//设置定时初始值
	TH0 = 0x00;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 0;		//定时器0开始计时
	
}

void csb_start(){
	
	u8 i=8;
	EA=0;
	while(i--){
		TX=1;
		Delay12us();
		TX=0;
		Delay12us();
	}
	EA=1;
	
	}
u16 get_dis(){
		u16 dis;
		RX=1;
		csb_start();
		TR0=1;
		while(RX==1&&TF0==0);

		TR0=0;
		if(!TF0){

			dis=TH0<<8|TL0;
			dis=dis*0.017;
			if(dis<=2||dis>=400)dis=999;
		}
		else {
		dis=999;
		}

		TH0=TL0=0;

		
		return dis;
	}
	


	

iic.c

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include "sys.h"
#include "intrins.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

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;  					// 0:应答,1:非应答
    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;
}

//通过I2C总线发送数据
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;  
}

//从I2C总线上接收数据
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;    
}
void EppromW(u8 word,u8 dat){
	
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
 	IIC_SendByte(word);
	IIC_WaitAck();
	
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_SendAck(1);
	IIC_Stop();
	
	
}
void Pcf_W_Dac(u8 dat){
	
 
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
 	IIC_SendByte(0x40);
	IIC_WaitAck();
	
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_SendAck(1);
	IIC_Stop();
	
}

uart.c



#include "sys.h"




void UartInit(void)		//4800bps@12.000MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x01;		//串口1选择定时器2为波特率发生器
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0x8F;		//设置定时初始值
	T2H = 0xFD;		//设置定时初始值
	AUXR |= 0x10;		//定时器2开始计时
	ES=1;
}




void Send_char(u8 q){
	
	ES=0;
	SBUF=q;
	while(!TI);
	TI=0;
	ES=1;

}
void SendString(u8 *str){
	
	while(*str!='\0'){
		Send_char(*str);
		str++;
	}
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第十届蓝桥杯人物相关性题目是一道经典的编程问题,要求我们在给定的人物关系图中,判断两个人物之间是否存在一条关系链,即判断两个人物是否直接或间接地相关。 在这道题目中,我们可以使用图的搜索算法来解决问题。一种常见的算法是深度优先搜索(DFS),另一种是广度优先搜索(BFS)。 大概的思路是:首先,我们需要构建人物关系图,可以通过邻接矩阵、邻接表等数据结构来存储图的信息。然后,我们选择一个起始节点,从该节点开始进行搜索。如果在搜索的过程中找到了目标节点,即两个人物之间存在直接关系,那么我们可以结束搜索并返回结果。如果没有找到目标节点,则需要继续深入搜索,或者在广度搜索中扩展搜索队列。如果最终搜索完整个图都没有找到目标节点,那么可以判定两个人物之间不存在关系链。 具体实现时,可以使用递归或者栈来实现DFS,使用队列来实现BFS。在DFS中,我们可以利用函数的递归调用来实现深度搜索;在BFS中,我们可以通过队列不断地将待搜索节点加入队列,实现广度搜索。 总的来说,第十届蓝桥杯人物相关性题目考察了对图的数据结构和搜索算法的掌握程度。需要我们理解并实现图的构建和搜索过程,进而判断两个人物之间的相关性。这道题目不仅考察了编程基础知识,也锻炼了问题分析和解决能力,是一道非常有挑战性的编程题目。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值