第十一届蓝桥杯单片机江苏省省赛编程题案例(2020年7月,附源码和简单分析)

第十一届蓝桥杯单片机江苏省省赛编程题案例(2020年7月,附源码和简单分析)

昨天刚比完,今天我简要回忆了一下自己写的东西,复刻一遍,肯定有一些小问题,但基本实现了所有要求,供大家参考。
今年只考了iic通信(adc和eeprom),ds1302和ds18b20都没有用到。除此之外还有数码管显示、led显示和矩阵键盘。
整体的题目是测量电位器上的电压,当它的值穿过某一阈值(Vp)时候就会把计数值加一,然后其余的东西都是依此展开。
具体的也不大记得了,不过我猜来看的大多是参加过这次大赛或者马上要参赛的,大家可以下载程序看看效果啥的。
说下按键:
S12:模式切换,共三个模式
S13:计数清零,仅在数码管第一位显示n的时候有效
S17:Vp减少,仅在数码管第一位显示P的时候有效
S16:Vp增加,仅在数码管第一位显示P的时候有效

这四个都是矩阵键盘上的,可能往年独立按键考多了,今年换换口味。
整个工程的源码在文章最后!!!
有问题欢迎讨论区讨论
这是我的整个工程文件:
第十一届蓝桥杯单片机江苏省省赛编程题案例(2020年7月,附源码和简单分析)_第1张图片
下面是mian.c代码

#include "stc15f2k60s2.h"
#include "function.h"
#include "iic.h"

//数据显示模式,数码管第一位显示U
#define U 0
//Vp设置模式,数码管第一位显示P
#define P 1
//计数显示模式,数码管第一位显示N
#define N 2

//8位数码管显示,10为熄灭,0-9显示数字0-9,11显示U,12显示P,13显示N
u8 dis_buf[]={
     10,10,10,10,10,10,10,10};
//读出的8位adc的数值,已经乘以了一百,数据范围0-500
unsigned long adc;
//为1进行adc读取flag,100ms读取一次
bit adc_flag=0;
//数码管刷新flag
bit dis_flag=0;
//芯片上电时计数值N可能会加1,可以用这个屏蔽掉,上电1秒后清零
bit startup_flag=1;
//Vp改变是置位,eeprom存入后归零
bit Vp_change_flag=0;
//N值,波形穿越阈值的次数
u16 n=0;
//当前模式
u8 mode=U;
//默认的阈值Vp
u8 Vp=25;
//上一次读到的adc,用于判断是否穿越阈值
u16 adc_old;
//用于给adc的值小于Vp时计数
u16 second=0;
//错误按键计数
u8 error_count;
//LED显示本地寄存器,用于防止数码管干扰
u8 my_p0=0xff;
void main()
{
     
	//初始化两个定时器,定时器1用于给adc的值小于Vp时计数
	Timer0Init();
	Timer1Init();
	//读取eeprom里面的Vp数值
	Vp=read_eeprom(0x00);
	
	while(1)
	{
     
		//读取adc时刻
 		if(adc_flag==1)
		{
     
			adc_flag=0;
			adc_old=adc;
			//adc数据转换
			adc=read_adc(0x03);
			adc=adc*500/256;
			//判断是否穿越阈值
			if((adc<Vp*10&&adc_old>Vp*10)||(adc>Vp*10&&adc_old<Vp*10))
			{
     
				//屏蔽第一次上电产生的N增加
				if(startup_flag==1)
				{
     
					startup_flag=0;
				}
					else
					{
     
						//Vp设置模式暂时屏蔽n的增加,防止因为改变Vp造成误判
						if(mode!=P)
						{
     
							n++;
						}
				  }
			}
			//当前adc小于Vp,开始计数
			if(adc<Vp*10)
			{
     
				TR1=1;
			}
			else
			//否则停止计数,计数清零
			{
     
				TR1=0;
				second=0;
			}
		}
		//数码管显示
		if(dis_flag==1)
		{
     
			dis_flag=0;
			//分模式显示
			if(mode==U)
			{
     
				dis_buf[0]=11;
				dis_buf[5]=adc/100;
				dis_buf[6]=adc/10%10;
				dis_buf[7]=adc%10;
			}
			if(mode==P)
			{
     
				dis_buf[0]=12;
				dis_buf[5]=Vp/10;
				dis_buf[6]=Vp%10;
				dis_buf[7]=0;
			}
			if(mode==N)
			{
     
				dis_buf[0]=13;
				dis_buf[5]=10;
				dis_buf[6]=n/10;
				dis_buf[7]=n%10;
			}
			
		}
		//Vp改变时写入eeprom
		if(Vp_change_flag==1)
		{
     
			Vp_change_flag=0;
			write_eeprom(0x00,Vp);
		}
	}

}



void Timer0() interrupt 1
{
     
	//定时器计数
	u16 count;
	//按键返回值
	u8 val;
	//数码管显示函数
	display(dis_buf,mode);
	//按键扫描
  val=key_scan(mode);
	//S12,模式切换,按键正确,错误计数清零
	if(val==12)
	{
     
		mode=(mode+1)%3;
	  error_count=0;
	}
	//S13,计数清零,按键正确,错误计数清零
	if(val==13)
	{
     
		error_count=0;
		n=0;
	}
	//S17,Vp加,按键正确,错误计数清零
	if(val==17)
	{
     
		error_count=0;
		if(Vp>=5)
		{
     Vp=Vp-5;}
		else{
     Vp=50;}
		Vp_change_flag=1;
	}
	//S16,Vp减,按键正确,错误计数清零
	if(val==16)
	{
     
		error_count=0;
		if(Vp<=45)
		{
     Vp=Vp+5;}
		else{
     Vp=0;}
		Vp_change_flag=1;
	}
	//按键错误,错误计数增加
	if(val==99)
	{
     
		error_count++;
	}
	
	//错误计数超过3,led3亮,否则灭
	if(error_count>=3)
	{
     
		P2=P2&0x1f|0x80;
		my_p0=my_p0&0xfb;
		P0=my_p0;
		P2=P2&0x1f;
	}
	else
	{
     
		P2=P2&0x1f|0x80;
		my_p0=my_p0|0x04;
		P0=my_p0;
		P2=P2&0x1f;
	
	}
	//计数为奇数LED2亮,否则灭
	if(n%2==0)
	{
     
		P2=P2&0x1f|0x80;
		my_p0=my_p0|0x02;
		P0=my_p0;
		P2=P2&0x1f;
	}
	else
	{
     
		P2=P2&0x1f|0x80;
		my_p0=my_p0&0xfd;
		P0=my_p0;
		P2=P2&0x1f;
	}
  //adc小于Vp超过五秒,LED1亮,否则灭
	if(second>=5)
	{
     
		P2=P2&0x1f|0x80;
		my_p0=my_p0&0xfe;
		P0=my_p0;
		P2=P2&0x1f;
	}
	else
	{
     
	  P2=P2&0x1f|0x80;
		my_p0=my_p0|0x01;
		P0=my_p0;
		P2=P2&0x1f;
	
	}

	count++;
	//100ms到,进行adc采样
	if(count%50==0)
	{
     
		adc_flag=1;
	}
	//200ms到,进行数码管刷新
	if(count%100==0)
	{
     
		dis_flag=1;
	}
	//1s到,count重新计数
	if(count==500)
	{
     
		count=0;
	}
}


void Timer1() interrupt 3
{
     
	u16 count;
	//启动时每秒计数加一
	if(++count==500)
	{
     
		count=0;
		second++;
	}
}

下面是function.c代码

#include "function.h"
#include "stc15f2k60s2.h"
#include "intrins.h"
u8 code Table[]={
     0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xc1,0x8c,0xc8};

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

	_nop_();
	_nop_();
	i = 57;
	while (--i);
}
void display(u8 *dis_buf,mode)
{
     
	u8 i;
	P2=P2&0X1F|0XC0;
	P0=0X01<<i;
	P2=P2&0X1F|0XE0;
	if(mode!=2&&i==5)
	{
     P0=Table[dis_buf[i]]&0x7f;}
		else
	{
     P0=Table[dis_buf[i]];}

	P2=P2&0X1F;
	if(++i==8)
	{
     
		i=0;
	}
}


void Timer0Init(void)		//2毫秒@12.000MHz
{
     
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x40;		//设置定时初值
	TH0 = 0xA2;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
}

void Timer1Init(void)		//2毫秒@12.000MHz
{
     
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x40;		//设置定时初值
	TH1 = 0xA2;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 0;		//定时器1开始计时
	ET1=1;
	
}

u8 key_scan(u8 mode)
{
     
	u8 var;
	P34=0;P35=1;P42=1;P44=1;
	if(P30==0)
	{
     
		Delay20us();
		if(P30==0)
		{
     
			var=99;
		}
		while(!P30);
	}
		if(P31==0)
	{
     
		Delay20us();
		if(P31==0)
		{
     
			var=99;
		}
		while(!P31);
	}
		if(P32==0)
	{
     
		Delay20us();
		if(P32==0)
		{
     
			if(mode==1)
			{
     
			var=17;
			}
			else
			{
     
			var=99;
			}
		}
		while(!P32);
	}
		if(P33==0)
	{
     
		Delay20us();
		if(P33==0)
		{
     
			if(mode==1)
			{
     
			var=16;
			}
			else
			{
     
			var=99;
			}
		}
		while(!P33);
	}
	P34=1;P35=0;P42=1;P44=1;
	if(P30==0)
	{
     
		Delay20us();
		if(P30==0)
		{
     
			var=99;
		}
		while(!P30);
	}
		if(P31==0)
	{
     
		Delay20us();
		if(P31==0)
		{
     
			var=99;
		}
		while(!P31);
	}
		if(P32==0)
	{
     
		Delay20us();
		if(P32==0)
		{
     
			if(mode==2)
			{
     
			var=13;
			}
			else
			{
     
			var=99;
			}
		}
		while(!P32);
	}
		if(P33==0)
	{
     
		Delay20us();
		if(P33==0)
		{
     
			var=12;
		}
		while(!P33);
	}
	P34=1;P35=1;P42=0;P44=1;
	if(P30==0)
	{
     
		Delay20us();
		if(P30==0)
		{
     
			var=99;
		}
		while(!P30);
	}
		if(P31==0)
	{
     
		Delay20us();
		if(P31==0)
		{
     
			var=99;
		}
		while(!P31);
	}
		if(P32==0)
	{
     
		Delay20us();
		if(P32==0)
		{
     
			var=99;
		}
		while(!P32);
	}
		if(P33==0)
	{
     
		Delay20us();
		if(P33==0)
		{
     
			var=99;
		}
		while(!P33);
	}
	P34=1;P35=1;P42=1;P44=0;
	if(P30==0)
	{
     
		Delay20us();
		if(P30==0)
		{
     
			var=99;
		}
		while(!P30);
	}
		if(P31==0)
	{
     
		Delay20us();
		if(P31==0)
		{
     
			var=99;
		}
		while(!P31);
	}
		if(P32==0)
	{
     
		Delay20us();
		if(P32==0)
		{
     
			var=99;
		}
		while(!P32);
	}
		if(P33==0)
	{
     
		Delay20us();
		if(P33==0)
		{
     
			var=99;
		}
		while(!P33);
	}
	P34=1;P35=1;P42=1;P44=1;
	return var;
}

下面是function.h代码

#define u8 unsigned char
#define u16 unsigned int
	
void display(u8 *dis_buf,mode);
void Timer0Init(void);	
void Timer1Init(void)	;
u8 key_scan(u8 mode);

下面是我的整个工程的下载链接:
https://download.csdn.net/download/weixin_44584198/12582790

你可能感兴趣的:(单片机,单片机,Keil,C51编译器,蓝桥杯)