蓝桥杯第十五届省赛单片机组真题及相关代码(基于西风代码解析)

题目分析

1.各模块分析

        本次蓝桥杯程序设计题难度相比去年有了明显的下降,大部分功能比较常规(如按键模块没有出现要求长按,多击等形式),主要考的模块包括:数码管,按键,led, DAC输出电压 ,频率测量,ds1302时钟芯片模块。

2.重难点分析

        其中重点在于频率的测量与显示,所以按键模块不能对P34引脚做手脚(因为是用P34来进行频率测量的会导致误差)。

        本次比赛存在设置校准值(有负有正)对实际频率进行矫正(第十四届国赛考点),我是选择设置一个标志位变量来判断频率校准值为正还是负,就可以把测量的频率变量定义为unsigned int 类型来实现频率上限的增加(如果定义成int类型在加上校准值的话可能会存在溢出的问题),还有比较基本的,所有参数真正意义上的修改只有在退出参数界面才能实现(西风哥的视频有讲)。

        然后再扣一点细节的话,就是数码管的减速变量的值应当选择100以下(题目要求,响应时间<0.1s),但具体会不会影响很大也是不到嘞。

if(++Key_Slow_Down==10){Key_Slow_Down=0;} //每10ms检测按键
if(++Seg_Slow_Down==100){Seg_Slow_Down=0;} //每100ms检测数码管

小白代码参考

(由于是比赛时写的,加上作者还是小白,也许仍然存在一些缺陷,欢迎指正批评!)

1. main.c

#include <STC15F2K60S2.H>
#include "Seg.h"
#include "Key.h"
#include "Led.h"
#include "iic.h"
#include "ds1302.h"
#include "intrins.h"
unsigned char Key_Val,Key_Down,Key_Up,Key_Old;   //按键相关变量
unsigned char Key_Slow_Down;                    //按键减速变量

unsigned char Seg_Buf[8]={16,16,16,16,16,16,16,16};   //数码管各位置数据
unsigned char Seg_Point[8]={0,0,0,0,0,0,0,0};        //数码管各位置小数点亮灭情况
unsigned int Seg_Slow_Down;                         //数码管减速变量
unsigned char Seg_Pos;                             //数码管位置

unsigned char Led_Buf[8]={0,0,0,0,0,0,0,0};       //led显示情况

bit Dat_Mode=0;                      			 //参数界面切换 0是参数 1是校准值
bit Dat_Flag=0;                       	 		//判断参数是正还是负 0是正 1是负
bit Final_Flag=0;                              //回显模式的变换 0是最大频率 1记录时间
bit Error_Flag=0;                             //判断是否错误中间变量
bit Error_Real=0;                            //判断是否错误变量
unsigned char Mode_Show=0;         	  		//总模式切换

unsigned int Freq_Set=2000;                 //设置的频率参数
unsigned int Freq_Set_Temp=2000;           //设置的频率参数中间变量
unsigned int Freq_Fix=0;                  //设置的频率校准值
unsigned int Freq_Fix_Temp=0;            //设置的频率校准值中间变量
unsigned int Freq;                      //测量得到的频率
unsigned int Freq_Max=0;               //频率最大值

unsigned char Time[3]={0x05,0x02,0x13};       //存放时间变量
unsigned char Max_Time[3]={0,0,0};           //存放频率最大值的时间数组

unsigned int Time_1s=0;               //用于每1秒读取频率
unsigned char Time_200ms=0;          //用于灯闪烁
unsigned char Time_200ms_L1=0;      //用于灯闪烁
void Key_Proc()
{
	if(Key_Slow_Down)
	{
		return;
	}
	Key_Slow_Down=1;
	
	Key_Val=Key_Choose();
	Key_Down=Key_Val & (Key_Old ^ Key_Val);
	Key_Up=~Key_Val & (Key_Old ^ Key_Val);
	Key_Old=Key_Val;
	
	
	switch(Key_Down)
	{
		case 4:
		if(++Mode_Show==4)
		{
			Mode_Show=0;
		}
		break;
		
		case 5:
		if(Mode_Show==1)
		{
			Dat_Mode^=1;
		}
		else if(Mode_Show==3)
		{
			Final_Flag^=1;
		}
		break;
		
		case 8:
		if(Mode_Show==1)
		{
			if(Dat_Mode==0)
			{
				Freq_Set_Temp+=1000;
				if(Freq_Set_Temp>9000)
				{
					Freq_Set_Temp=9000;
				}
			}
			else if(Dat_Mode==1)
			{
				if(Dat_Flag==0)
				{
					Freq_Fix_Temp+=100;
				}
				if(Dat_Flag==1&&Freq_Fix_Temp<=100)
				{
					Freq_Fix_Temp-=100;
					Dat_Flag=0;	
				}
				if(Dat_Flag==1&&Freq_Fix_Temp>100)
				{
					Freq_Fix_Temp-=100;
				}
				if(Freq_Fix_Temp>900)
				{
					Freq_Fix_Temp=900;
				}
			}
		}
		break;
		
		case 9:
		if(Mode_Show==1)
		{
			if(Dat_Mode==0)
			{
				Freq_Set_Temp-=1000;
				if(Freq_Set_Temp<1000)
				{
					Freq_Set_Temp=1000;
				}
			}
			else if(Dat_Mode==1)
			{
				if(Dat_Flag==1&&Freq_Fix_Temp>=100)
				{
					Freq_Fix_Temp+=100;
				}
				if(Dat_Flag==0&&Freq_Fix_Temp<100)
				{
					Dat_Flag=1;
					Freq_Fix_Temp+=100;
				}
				if(Dat_Flag==0&&Freq_Fix_Temp>=100)
				{
					Freq_Fix_Temp-=100;
				}
				if(Freq_Fix_Temp>900)
				{
					Freq_Fix_Temp=900;
				}
			}
		}
		break;
			
	}
}

void Seg_Proc()
{
	if(Seg_Slow_Down)
	{
		return;
	}
	Seg_Slow_Down=1;
	
	Ds1302_Read(Time);
	
	switch(Mode_Show)
	{
		case 0:
		if(Error_Flag==0)
		{
			Seg_Buf[0]=15;
			Seg_Buf[1]=16;
			Seg_Buf[2]=16;
			if(Freq/10000==0)
			{
				Seg_Buf[3]=16;
			}
			else
			{
				Seg_Buf[3]=Freq/10000;
			}
			if(Freq/10000==0&&Freq/1000%10==0)
			{
				Seg_Buf[4]=16;
			}
			else
			{
				Seg_Buf[4]=Freq/1000%10;
			}
			if(Freq/100%10==0&&Freq/10000==0&&Freq/1000%10==0)
			{
				Seg_Buf[5]=16;
			}
			else
			{
				Seg_Buf[5]=Freq/100%10;
			}
			if(Freq/10%10==0&&Freq/100%10==0&&Freq/10000==0&&Freq/1000%10==0)
			{
				Seg_Buf[6]=16;
			}
			else
			{
				Seg_Buf[6]=Freq/10%10;
			}
			Seg_Buf[7]=Freq%10;
		}
		else if(Error_Flag==1)
		{
			Seg_Buf[0]=15;
			Seg_Buf[1]=16;
			Seg_Buf[2]=16;
			Seg_Buf[3]=16;
			Seg_Buf[4]=16;
			Seg_Buf[5]=16;
			Seg_Buf[6]=20;
			Seg_Buf[7]=20;
		}
		break;
		
		case 1:
		if(Dat_Mode==0)
		{
			Seg_Buf[0]=19;
			Seg_Buf[1]=1;
			Seg_Buf[2]=16;
			Seg_Buf[3]=16;
			Seg_Buf[4]=Freq_Set_Temp/1000;
			Seg_Buf[5]=Freq_Set_Temp/100%10;
			Seg_Buf[6]=Freq_Set_Temp/10%10;
			Seg_Buf[7]=Freq_Set_Temp%10;
		}
		else if(Dat_Mode==1)
		{
			Seg_Buf[0]=19;
			Seg_Buf[1]=2;
			Seg_Buf[2]=16;
			Seg_Buf[3]=16;
			if(Dat_Flag==0)
			{
				Seg_Buf[4]=16;
			}
			if(Dat_Flag==1)
			{
				Seg_Buf[4]=17;
			}
			if(Freq_Fix_Temp/100%10==0)
			{
				Seg_Buf[5]=16;
			}
			else
			{
			  Seg_Buf[5]=Freq_Fix_Temp/100%10;
			}
			if(Freq_Set_Temp/10%10==0&&Freq_Fix_Temp/100%10==0)
			{
				Seg_Buf[6]=16;
			}
			else
			{
				Seg_Buf[6]=Freq_Set_Temp/10%10;
			}
			Seg_Buf[7]=Freq_Set_Temp%10;
		}
		break;
		
		case 2:
			Seg_Buf[0]=Time[2]/16;
			Seg_Buf[1]=Time[2]%16;
			Seg_Buf[2]=17;
			Seg_Buf[3]=Time[1]/16;
			Seg_Buf[4]=Time[1]%16;
			Seg_Buf[5]=17;
			Seg_Buf[6]=Time[0]/16;
			Seg_Buf[7]=Time[0]%16;
		break;
		
		case 3:
		if(Final_Flag==0)
		{
			Seg_Buf[0]=18;
			Seg_Buf[1]=15;
			Seg_Buf[2]=16;
			if(Freq_Max/10000==0)
			{
				Seg_Buf[3]=16;
			}
			else
			{
				Seg_Buf[3]=Freq_Max/10000;
			}
			if(Freq_Max/10000==0&&Freq_Max/1000%10==0)
			{
				Seg_Buf[4]=16;
			}
			else
			{
				Seg_Buf[4]=Freq_Max/1000%10;
			}
			if(Freq_Max/100%10==0&&Freq_Max/10000==0&&Freq_Max/1000%10==0)
			{
				Seg_Buf[5]=16;
			}
			else
			{
				Seg_Buf[5]=Freq_Max/100%10;
			}
			if(Freq_Max/10%10==0&&Freq_Max/100%10==0&&Freq_Max/10000==0&&Freq_Max/1000%10==0)
			{
				Seg_Buf[6]=16;
			}
			else
			{
				Seg_Buf[6]=Freq_Max/10%10;
			}
			Seg_Buf[7]=Freq_Max%10;
		}
		else if(Final_Flag==1)
		{
			Seg_Buf[0]=18;
			Seg_Buf[1]=10;
			Seg_Buf[2]=Max_Time[2]/16;
			Seg_Buf[3]=Max_Time[2]%16;
			Seg_Buf[4]=Max_Time[1]/16;
			Seg_Buf[5]=Max_Time[1]%16;
			Seg_Buf[6]=Max_Time[0]/16;
			Seg_Buf[7]=Max_Time[0]%16;
		}
		break;
			
		
	}
			
	
	
}

void Led_Proc()
{

	if(Freq<=500&&Error_Flag==0)
	{
		DA_Write(51);
	}
	else if(Freq>500&&Freq<=Freq_Set&&Error_Flag==0)
	{
		DA_Write(((4*(Freq-500.0))/(Freq_Set-500)+1.0)*51);
	}
	else if(Freq>500&&Error_Flag==0)
	{
		DA_Write(255);
	}
	else if(Error_Flag==1) 
	{
		DA_Write(0);
	}
	
	if(Freq<=Freq_Set)
	{
		Led_Buf[1]=0;
	}
	
	if(Error_Flag)
	{
		Led_Buf[1]=1;
	}
	
	if(Freq<=Freq_Set&&Error_Real==0)
	{
		Led_Buf[1]=0;
	}
}
//
void Timer1Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器1时钟12T模式
	AUXR &= 0xBF;		//定时器0时钟12T模式
	
	TMOD |= 0x05;		//设置定时器模式
	
	TL1 = 0x18;		//设置定时初值
	TH1 = 0xFC;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1=1;
	EA=1;
	
	TL0 = 0;		//设置定时初值
	TH0 = 0;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

void Timer1_Rountine(void) interrupt 3
{
	TL1 = 0x18;		//设置定时初值
	TH1 = 0xFC;		//设置定时初值
	
	if(++Key_Slow_Down==10){Key_Slow_Down=0;}
	if(++Seg_Slow_Down==100){Seg_Slow_Down=0;}
	if(++Seg_Pos==8){Seg_Pos=0;}
	
	if(Mode_Show==0)
	{
		Freq_Set_Temp=Freq_Set;
		Freq_Fix_Temp=Freq_Fix;
		Dat_Mode=0;
		Error_Flag=Error_Real;
	}
	if(Mode_Show==2)
	{
		Freq_Set=Freq_Set_Temp;
		Freq_Fix=Freq_Fix_Temp;
		Final_Flag=0;
		Error_Real=Error_Flag;
	}


	if(++Time_1s>1000)
	{
		Time_1s=0;
		Freq=(TH0<<8)|TL0;
		if(Dat_Flag==0)
		{
			Error_Flag=0;
			Freq=(TH0<<8)|TL0+Freq_Fix;
		}
		else if(Dat_Flag==1&&Freq>=Freq_Fix)
		{
			Error_Flag=0;
			Freq=(TH0<<8)|TL0-Freq_Fix;
		}
		else if(Dat_Flag==1&&Freq<Freq_Fix)
		{
			Error_Flag=1;
		}
		if(Freq>Freq_Max)
		{
			Freq_Max=Freq;
			Max_Time[0]=Time[0];
			Max_Time[1]=Time[1];
			Max_Time[2]=Time[2];
		}
		TL0=0;
		TH0=0;
	}
	
		
	if(Mode_Show==0)
	{
		Time_200ms++;
		if(Time_200ms<=200)
		{
			Led_Buf[0]=1;
		}
		if(Time_200ms>200&&Time_200ms<400)
		{
			Led_Buf[0]=0;
		}
		if(Time_200ms>=400)
		{
			Time_200ms=0;
		}
	}
	else
	{
		Led_Buf[0]=0;
	}
	
	if(Freq>Freq_Set&&Error_Flag==0)
	{
		Time_200ms_L1++;
		if(Time_200ms_L1<=200)
		{
			Led_Buf[1]=1;
		}
		if(Time_200ms_L1>200&&Time_200ms_L1<400)
		{
			Led_Buf[1]=0;
		}
		if(Time_200ms_L1>=400)
		{
			Time_200ms_L1=0;
		}
	}
	else if(Freq<=Freq_Set&&Error_Real==0)
	{
		Led_Buf[1]=0;
	}
	else if(Error_Real==1)
	{
		Led_Buf[1]=1;
	}

	
	Seg_Choose(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
	Led_Choose(Seg_Pos,Led_Buf[Seg_Pos]);
	
}

void main()
{
	P0=0xff;
	P2=P2&0x1f|0x9f;
	P2&=0x1f;

	P0=0x00;
	P2=P2&0x1f|0xa0;
	P2&=0x1f;
	
	Freq=0;
	Timer1Init();
	Ds1302_Set(Time);
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}
	

 2.数码管

#include <STC15F2K60S2.H>

unsigned char Seg_Table[]={
//   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black  -     H    P    L
    0x00,0x40,0x76,0x73,0x38};

unsigned char Seg_Location[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

void Seg_Choose(unsigned char Location,Dat,Point)
{
    //实现数码管清零
	P0=0x00;
	P2=P2&0x1f|0xe0;
	P2&=0x1f;
	
    //实现数码管选择位置
	P0=Seg_Location[Location];
	P2=P2&0x1f|0xc0;
	P2&=0x1f;
	
    //实现数码管选择数据
	P0=~Seg_Table[Dat];
	if(Point)
	{
		P0&=0x7f;
	}
	P2=P2&0x1f|0xe0;
	P2&=0x1f;
}

 3.按键

#include <STC15F2K60S2.H>

unsigned char Key_Choose()
{
	unsigned char Temp;
    EA=0;
	P44=0;P42=1;P35=1;
	if(P30==0){Temp=7;}
	if(P31==0){Temp=6;}
	if(P32==0){Temp=5;}
	if(P33==0){Temp=4;}
	
	P44=1;P42=0;P35=1;
	if(P30==0){Temp=11;}
	if(P31==0){Temp=10;}
	if(P32==0){Temp=9;}
	if(P33==0){Temp=8;}
	
	P44=1;P42=1;P35=0;
	if(P30==0){Temp=15;}
	if(P31==0){Temp=14;}
	if(P32==0){Temp=13;}
	if(P33==0){Temp=12;}
	
//	P44=1;P42=1;P35=1;P34=0;
//	if(P30==0){Temp=19;}
//	if(P31==0){Temp=18;}
//	if(P32==0){Temp=17;}
//	if(P33==0){Temp=16;}
	
    EA=1;
	P3=0xff;
	return Temp;
}

4.Led灯显示

#include <STC15F2K60S2.H>

void Led_Choose(unsigned char Location,Enable)
{
	static unsigned char Temp=0x00;
	static unsigned char Temp_Old=0xff;
	if(Enable)
	{
		Temp|=0x01<<Location;
	}
	else
	{
		Temp&=~(0x01<<Location);
	}
	if(Temp!=Temp_Old)
	{
		P0=~Temp;
		P2=P2&0x1f|0x80;
		P2&=0x1f;
		Temp_Old=Temp;
	}
}

5.iic

/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <STC15F2K60S2.H>
#include "intrins.h"

sbit scl=P2^0;
sbit sda=P2^1;

#define DELAY_TIME	10

//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}
//
void DA_Write(unsigned char Dat)
{
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x41);
	I2CWaitAck();
	I2CSendByte(Dat);
	I2CWaitAck();
	I2CStop();
}

 6.ds1302

#include <STC15F2K60S2.H>
#include "intrins.h"

sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST=P1^3;

//
void Write_Ds1302(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK = 0;
		SDA = temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);	
 	Write_Ds1302(dat);		
 	RST=0; 
}

//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	return (temp);			
}
//
void Ds1302_Set(unsigned char *Time)
{
	Write_Ds1302_Byte( 0x8e,0x00 );
	Write_Ds1302_Byte( 0x80,Time[0] );
	Write_Ds1302_Byte( 0x82,Time[1] );
	Write_Ds1302_Byte( 0x84,Time[2] );
	Write_Ds1302_Byte( 0x8e,0x80 );
}
//
void Ds1302_Read(unsigned char *Time)
{
	Time[0]=Read_Ds1302_Byte ( 0x81 );
	Time[1]=Read_Ds1302_Byte ( 0x83 );
	Time[2]=Read_Ds1302_Byte ( 0x85 );
}

作者:多睡午觉

物联沃分享整理
物联沃-IOTWORD物联网 » 蓝桥杯第十五届省赛单片机组真题及相关代码(基于西风代码解析)

发表评论