蓝桥杯第十五届省赛单片机组真题及相关代码(基于西风代码)
题目分析
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 );
}
作者:多睡午觉