蓝桥杯单片机11届省赛

题目

 

 

 

题目很短,但是对上了EEprom模块,让这道题目有了一点乐趣

敲好大模板,导入题目需要的IIC底层,写好相关函数,再着手题目的分析。

按键功能

 

用到的是矩阵键盘,S12切换三种界面,S13清零,注意下面的设计要求,S13只有在计数界面有效 ,S16S17在参数界面有效,是是否普通的参数加减运算,注意上下限的判定就行。

/*按键函数区域*/
void Key_Proc(){
	
	if(Key_Slow) return;
	Key_Slow = 1;
	
	Key_Val = Key_Read();
	Key_Down = Key_Val & (Key_Val ^ Key_Old);
	Key_Up = ~Key_Val & (Key_Val ^ Key_Old);
	Key_Old = Key_Val;
	
	switch(Key_Down){
		case 12://界面切换
			if(++Seg_Mode == 3) Seg_Mode = 0;
			EEprom[0] = Volt_Val;
			EE_Write(EEprom,1,0);//参数界面切换完后参数写入EEprom里面
		break;
		case 13://清除计数值,仅在计数模式有效
			if(Seg_Mode == 2){
				Count = 0;
			}
		break;
		case 16://参数界面有效,电压加0.5v,加到5v再次按下变成0v
			if(Seg_Mode == 1){
				Volt_Val = Volt_Val == 50?0:Volt_Val+5;
			}
		break;
		case 17://减去0.5v
			if(Seg_Mode == 1){
				Volt_Val = Volt_Val == 0?50:Volt_Val-5;
			}
		break;
	}
}

显示功能 

 

 很普通正常的显示功能,三个不一样的提示符,显示的内容也是很简单的,没有多余的累赘

    Seg_Buf[1] = 10;
	Seg_Buf[2] = 10;
	Seg_Buf[3] = 10;
	Seg_Buf[4] = 10;
	switch(Seg_Mode){
		case 0://数据界面
			Seg_Buf[0] = 11;//U
			Point[5] = 1;
			Seg_Buf[5] = (unsigned char)Volt;
			Seg_Buf[6] = (unsigned char)(Volt*10)%10;
			Seg_Buf[7] = (unsigned int)(Volt*100)%10;
		break;
		case 1:
			Seg_Buf[0] = 12;//P
			Seg_Buf[5] = Volt_Val/10%10;
			Point[5] = 1;
			Seg_Buf[6] = Volt_Val%10;
			Seg_Buf[7] = 0;
		break;
		case 2:
			Point[5] = 0;
			Seg_Buf[0] = 13;//N
			Seg_Buf[5] = 10;
		Seg_Buf[6] = Count>10?Count/10:10;
			Seg_Buf[7] = Count%10;
		break;
	}

数据分析 

对于我们显示功能需要的数据,我们在数码管函数里面进行分析

首先来看计数值加一的触发条件,只有按照图的显示,只有我们获取到的滑动变阻器电压在之前先大于电压参数,再小于电压参数 ,我们才完成一次计数。

我们就可以定义一个标志位,在当前电压大于电压参数的时候置1,低于电压参数的时候置0,只有当前电压低于电压参数且标志位为1,也就是之前电压大于电压参数,这个时候我们才计数

	hd = Ad_Read(0x43);//获取滑动电阻电压值
	
	Volt = hd/51.0;
//计数计算
	if(Volt*100>Volt_Val*10){//当前电压高于参数电压
		Volt_Up = 1;
	}
	if((Volt*100<Volt_Val*10)&&(Volt_Up)){//电压低于参数电压,且之前电压值大于参数电压
		Volt_Up = 0;
		Count++;
	}

我喜欢用数据的10倍100倍来把小数变成整数来继续计算和显示 

Led指示灯功能

if(Volt*100>Volt_Val*10){//当前电压高于参数电压
		Volt_trap = 0;
		Timer_5s = 0;
		L1_Flag = 0;
	}
	else Volt_trap = 1;//当前电压小于电压参数

 条件符合用一个标志位来定时器0里面计时,超过5sL1标志位置1

Led_Buf[0] = L1_Flag;//L1和当前电压与电压参数的关系有关
	if(Count%2==1){//Count计数值为奇数时点亮L2
		Led_Buf[1] = 1;
	}
	else Led_Buf[1] = 0;
	if(error_flag>=3){//连续三次或以上的无效按键触发点亮L3
		 Led_Buf[2] = 1;
	}
	else Led_Buf[2] = 0;

 L3是连续三次或以上无效按键触发,什么是无效按键触发呢,现在我们只用到了四个按键,S12任何界面都有效,S13,S16,S17三个按键都是在一定条件下按下才有效,比如说S13只在参数界面有效,而在别的界面按下S13就是无效按键触发,对于这些无效触发,我们定义一个变量来记录,,只要有一次有效触发,就把这个无效触发值清零,在Led函数里面进行判断,点亮L3

switch(Key_Down){
		case 12://界面切换
			if(++Seg_Mode == 3) Seg_Mode = 0;
			error_flag = 0;
			EEprom[0] = Volt_Val;
			EE_Write(EEprom,1,0);//参数界面切换完后参数写入EEprom里面
		break;
		case 13://清除计数值,仅在计数模式有效
			if(Seg_Mode == 2){
				Count = 0;
				error_flag = 0;
			}
			else error_flag++;
		break;
		case 16://参数界面有效,电压加0.5v,加到5v再次按下变成0v
			if(Seg_Mode == 1){
				Volt_Val = Volt_Val == 50?0:Volt_Val+5;
				error_flag = 0;
			}
			else error_flag++;
		break;
		case 17://减去0.5v
			if(Seg_Mode == 1){
				error_flag = 0;
				Volt_Val = Volt_Val == 0?50:Volt_Val-5;
			}
			else error_flag++;
		break;
	}

完整主函数 

 

/*头文件区域*/
#include <STC15F2K60S2.H>
#include <Key.h>
#include <Seg.h>
#include <Init.h>
#include <Led.h>
#include <iic.h>
/*参数变量区域*/
unsigned char Key_Down,Key_Up,Key_Old,Key_Val;
unsigned char Key_Slow,Seg_Slow;
unsigned char Seg_Pos;
//数组
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};
unsigned char Led_Buf[8] = {0,0,0,0,0,0,0,0};
unsigned char Point[8] = {0,0,0,0,0,0,0,0};
unsigned char EEprom[1] = {30};
//标志位
unsigned int Timer_5s;
bit Volt_trap;//当前电压小于电压参数
bit L1_Flag;
bit Volt_Up;//电压高于参数电压标志位
unsigned char Seg_Mode;//0数据,1参数,2计数
unsigned char Volt_Val;//电压参数值的十倍
//数据
float Volt;
unsigned char Count;//计数值
unsigned char error_flag;//记录错误的按键
/*按键函数区域*/
void Key_Proc(){
	
	if(Key_Slow) return;
	Key_Slow = 1;
	
	Key_Val = Key_Read();
	Key_Down = Key_Val & (Key_Val ^ Key_Old);
	Key_Up = ~Key_Val & (Key_Val ^ Key_Old);
	Key_Old = Key_Val;
	
	switch(Key_Down){
		case 12://界面切换
			if(++Seg_Mode == 3) Seg_Mode = 0;
			error_flag = 0;
			EEprom[0] = Volt_Val;
			EE_Write(EEprom,1,0);//参数界面切换完后参数写入EEprom里面
		break;
		case 13://清除计数值,仅在计数模式有效
			if(Seg_Mode == 2){
				Count = 0;
				error_flag = 0;
			}
			else error_flag++;
		break;
		case 16://参数界面有效,电压加0.5v,加到5v再次按下变成0v
			if(Seg_Mode == 1){
				Volt_Val = Volt_Val == 50?0:Volt_Val+5;
				error_flag = 0;
			}
			else error_flag++;
		break;
		case 17://减去0.5v
			if(Seg_Mode == 1){
				error_flag = 0;
				Volt_Val = Volt_Val == 0?50:Volt_Val-5;
			}
			else error_flag++;
		break;
	}
}

/*数码管函数区域*/
void Seg_Proc(){
	unsigned char hd;
	
	if(Seg_Slow) return;
	Seg_Slow = 1;
	
	hd = Ad_Read(0x43);//获取滑动电阻电压值
	
	Volt = hd/51.0;
	
	//计数计算
	if(Volt*100>Volt_Val*10){//当前电压高于参数电压
		Volt_Up = 1;
	}
	if((Volt*100<Volt_Val*10)&&(Volt_Up)){//电压低于参数电压,且之前电压值大于参数电压
		Volt_Up = 0;
		Count++;
	}
	
	if(Volt*100>Volt_Val*10){//当前电压高于参数电压
		Volt_trap = 0;
		Timer_5s = 0;
		L1_Flag = 0;
	}
	else Volt_trap = 1;//当前电压小于电压参数
	
	Seg_Buf[1] = 10;
	Seg_Buf[2] = 10;
	Seg_Buf[3] = 10;
	Seg_Buf[4] = 10;
	switch(Seg_Mode){
		case 0://数据界面
			Seg_Buf[0] = 11;//U
			Point[5] = 1;
			Seg_Buf[5] = (unsigned char)Volt;
			Seg_Buf[6] = (unsigned char)(Volt*10)%10;
			Seg_Buf[7] = (unsigned int)(Volt*100)%10;
		break;
		case 1:
			Seg_Buf[0] = 12;//P
			Seg_Buf[5] = Volt_Val/10%10;
			Point[5] = 1;
			Seg_Buf[6] = Volt_Val%10;
			Seg_Buf[7] = 0;
		break;
		case 2:
			Point[5] = 0;
			Seg_Buf[0] = 13;//N
			Seg_Buf[5] = 10;
		Seg_Buf[6] = Count>10?Count/10:10;
			Seg_Buf[7] = Count%10;
		break;
	}
}

/*Led函数区域*/
void Led_Proc(){
	Led_Buf[0] = L1_Flag;//L1和当前电压与电压参数的关系有关
	if(Count%2==1){//Count计数值为奇数时点亮L2
		Led_Buf[1] = 1;
	}
	else Led_Buf[1] = 0;
	if(error_flag>=3){//连续三次或以上的无效按键触发点亮L3
		 Led_Buf[2] = 1;
	}
	else Led_Buf[2] = 0;
	
}

/*定时器0初始化函数区域*/
void Timer0_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0x18;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;
	EA = 1;
}


/*定时器0中断服务函数区域*/
void Timer0_Service() interrupt 1
{
	if(++Key_Slow == 50) Key_Slow = 0;
	if(++Seg_Slow == 100) Seg_Slow = 0;
	
	if(++Seg_Pos == 8) Seg_Pos = 0;
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Point[Seg_Pos]);
	Led_Disp(Seg_Pos,Led_Buf[Seg_Pos]);
	
	if(Volt_trap){
		if(++Timer_5s >= 5000){
			Timer_5s = 5050;
			L1_Flag = 1;
		}
	}
	
}

/*主函数区域*/
void main(){
	Init_Sys();
	Timer0_Init();
	//EE_Write(EEprom,1,0);//先写入一次EEprom
	EE_Read(EEprom,1,0);//上电读取EEprom
	Volt_Val = EEprom[0];
	while(1){
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值