第十一届蓝桥杯单片机省赛题目解析
·
最近也是刚把第十一届的题目写完,我们一起来看看2020年的省赛题目吧。
题目
这次题目照样还是LED、数码管、按键三大模块 ,还有模拟电压输入(ADC)、AT24C02(EEPROM),都是常见的外设,且之前题目出现过的,所以不难,考的都是基本功。
1 数码管显示
数码管主要显示获取的电压、计数和参数设置三个界面,不过要注意上电之后就要显示电压数据界面。
2 LED
当电压小于设置的参数时5s后L1亮,这个还是很好做的。当计数为奇数时L2亮,计数的话,我是先判断电压是比参数大还是小然后过个一段时间在判断电压是比参数大还是小,如果两次比较结果不一样就是电压和参数有过交点。定义一个变量mis,每次错误的按键都mis++,当count>=3时L3亮,正确的按键就让mis=0。
3 按键模块
这次使用的是一个矩阵键盘和之前的有所不一样。s12是电压、计数和参数设置三个界面的切换,s13是可以把计数清零的按键,s16,s17是加减按键不过要注意范围为[0,5]。
4 ADC
就是改写底层驱动代码部分(IIC)。
5 EEPROM
就是改写底层驱动代码部分(IIC),注意在加减后要把参数*10后才保存到EEPROM中,所以在加减完后直接/10.0这样*10也是原来的值,此外还指定的保存的地址为0。
IIC.c
#include"IIC.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);
}
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 AD_input()
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x03);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Stop();
return temp;
}
void write_eeprom(unsigned char add,unsigned char para)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_SendByte(para);
IIC_WaitAck();
IIC_Stop();
}
unsigned char read_eeprom(unsigned char add)
{
unsigned char para;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
para=IIC_RecByte();
IIC_Stop();
return para;
}
IIC.h
#ifndef _IIC_H_
#define _IIC_H_
#include<stc15f2k60s2.h>
#include<intrins.h>
void IIC_Delay(unsigned char i);
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
unsigned char AD_input();
void write_eeprom(unsigned char add,unsigned char para);
unsigned char read_eeprom(unsigned char add);
#endif
init.c
#include"init.h"
#define u8 unsigned char
#define u16 unsigned int
#define key_io P3
#define state_0 0
#define state_1 1
#define state_2 2
u8 tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,0xc1,0x8c,0xc8};
u8 seg[]={11,11,11,11,11,11,11,11};
extern u8 value,mode;
static u8 segaddr=0;
void close() //关闭无关外设
{
P2=(P2&0x1f)|0x80;P0=0xff;P2&=0x1f;
P2=(P2&0x1f)|0xa0;P04=0;P06=0;P2&=0x1f;
P2=(P2&0x1f)|0xc0;P0=0x00;P2&=0x1f;
P2=(P2&0x1f)|0xe0;P0=0xff;P2&=0x1f;
}
void display() //数码管显示函数
{
P2=(P2&0x1f)|0xe0;P0=0xff;P2&=0x1f;
P2=(P2&0x1f)|0xc0;P0=1<<segaddr;P2&=0x1f;
if(mode!=2&&segaddr==5) //判断是否要加小数点
{
P2=(P2&0x1f)|0xe0;P0=tab[seg[segaddr]]&0x7f;P2&=0x1f;
}
else
{
P2=(P2&0x1f)|0xe0;P0=tab[seg[segaddr]];P2&=0x1f;
}
if(++segaddr==8) segaddr=0;
}
u8 read_key() //矩阵键盘
{
static u8 key_state=0,key_num=0;
u8 key_press;
u8 row;
switch(key_state)
{
case state_0:
key_io=0x0f; P42=0; P44=0;
key_press =key_io;
if(key_press != 0x0f)
key_state = state_1;
break;
case state_1:
key_press =key_io;
if(key_press != 0x0f)
{
if((key_io&0x08)==0) row=4;
if((key_io&0x04)==0) row=5;
if((key_io&0x02)==0) row=6;
if((key_io&0x01)==0) row=7;
key_io=0xf0; P42=1;P44=1;
if(P44==0) key_num=row;
if(P42==0) key_num=row+4;
if((key_io&0x20)==0) key_num=row+8;
if((key_io&0x10)==0) key_num=row+12;
key_state = state_2;
}
else
key_state = state_0;
break;
case state_2:
key_io=0x0f; P42=0; P44=0;
key_press =key_io;
if(key_press == 0x0f) key_state = state_0;
break;
}
value=key_num;
key_num=0;
return value;
}
void Timer0Init(void)
{
AUXR |= 0x80;
TMOD &= 0xF0;
TL0 = 0x20;
TH0 = 0xD1;
TF0 = 0;
TR0 = 1;
ET0 = 1;
EA = 1;
}
init.h
#ifndef _INIT_H_
#define _INIT_H_
#include<stc15f2k60s2.h>
void close();
void display();
unsigned char read_key();
void Timer0Init(void);
#endif
jm.c
#include"jm.h"
#define u8 unsigned char
#define u16 unsigned int
extern u8 mode,seg[],N,mis; // extern表示此变量是在别处定义的,要在此处引用
extern u16 RB2;
extern bit p_flag;
extern char D;
void jm12()
{
if(mode==0)
{
seg[0]=12;
seg[1]=11;
seg[2]=11;
seg[3]=11;
seg[4]=11;
seg[5]=RB2/100;
seg[6]=RB2/10%10;
seg[7]=RB2%10;
}
if(mode==1)
{
seg[0]=13;
seg[1]=11;
seg[2]=11;
seg[3]=11;
seg[4]=11;
seg[5]=D/10;
seg[6]=D%10;
seg[7]=0;
}
if(mode==2)
{
seg[0]=14;
seg[1]=11;
seg[2]=11;
seg[3]=11;
seg[4]=11;
seg[5]=11;
seg[6]=N/10;
seg[7]=N%10;
}
}
void jm13()
{
if(mode==2)
N=0;
}
void jm16()
{
if(mode==1)
{
D+=5;
if(D>50)
D=0;
}
}
void jm17()
{
if(mode==1)
{
D-=5;
if(D<0)
D=50;
}
}
void LED() //这个LED显示函数就是if语句嵌套
{
if(p_flag==1)
{
if(N%2!=0)
{
if(mis>=3)
{
P2=(P2&0x1f)|0x80;P0=0xf8;P2&=0x1f;
}
else
{
P2=(P2&0x1f)|0x80;P0=0xfc;P2&=0x1f;
}
}
else
{
if(mis>=3)
{
P2=(P2&0x1f)|0x80;P0=0xfa;P2&=0x1f;
}
else
{
P2=(P2&0x1f)|0x80;P0=0xfe;P2&=0x1f;
}
}
}
else
{
if(N%2!=0)
{
if(mis>=3)
{
P2=(P2&0x1f)|0x80;P0=0xf9;P2&=0x1f;
}
else
{
P2=(P2&0x1f)|0x80;P0=0xfd;P2&=0x1f;
}
}
else
{
if(mis>=3)
{
P2=(P2&0x1f)|0x80;P0=0xfb;P2&=0x1f;
}
else
{
P2=(P2&0x1f)|0x80;P0=0xff;P2&=0x1f;
}
}
}
}
jm.h
#ifndef _JM_H_
#define _JM_H_
#include<stc15f2k60s2.h>
void jm12();
void jm13();
void jm16();
void jm17();
void LED();
#endif
main.c
#include"init.h"
#include"IIC.h"
#include"jm.h"
#define u8 unsigned char
#define u16 unsigned int
u8 mode=0,num=0,N=0,mis=0,value=0;
u8 RB2_count=0,N_count=0;
u16 RB2=0;
u16 p_count=0;
bit p_flag=0,RB2_flag=0,N_flag=0,high=0,low=0;
float p=0;
char D=30; //不能定义为无符号类型的,因为再jm17()中要判断D<0。
void Delay5ms()
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void main()
{
close();
Timer0Init();
D=read_eeprom(0x00);
while(1)
{
if(RB2_flag==1)
{
RB2_flag=0;
RB2=AD_input();
RB2=(RB2*100)/51.0+0.5;
}
if(N_flag==1) //每100ms判断一次RB2是不是小于D
{ //如果判断与上一次不一样
//计数值N+1
N_flag=0;
if(RB2>D*10)
high=1;
else
low=1;
if(high&low)
{
N+=1;
high=0;
low=0;
}
}
num=read_key();
switch(num)
{
case 12:
if(++mode==3) mode=0;
mis=0;
break;
case 13:
if(mode==2)
{
jm13();
mis=0;
}
else mis++;
break;
case 16:
if(mode==1)
{
jm16();
mis=0;
}
else mis++;
p=D/10.0;
write_eeprom(0x00,p*10); //eeprom写入最好延迟个5ms
Delay5ms();
break;
case 17:
if(mode==1)
{
jm17();
mis=0;
}
else mis++;
p=D/10.0;
write_eeprom(0x00,p*10);
Delay5ms();
break;
}
jm12();
LED();
}
}
void Timer0() interrupt 1
{
display();
if(++RB2_count==100)
{
RB2_flag=1;
RB2_count=0;
}
if(++N_count==100)
{
N_flag=1;
N_count=0;
}
if(RB2<D*10)
{
if(++p_count==5000)
{
p_flag=1;
p_count=0;
}
}
else
{
p_count=0;
p_flag=0;
}
}
最后,LED的显示总觉得太繁琐,试过其他方法总是有点问题(多个灯同时亮,亮度不一样),不知道大家有没有什么好的方法。
更多推荐
已为社区贡献9条内容
所有评论(0)