第十五届单片机模拟考试III

题目

 

 

 

题目看着挺长的,但是很简单常规。

按键功能 

S4界面切换,S5模式切换,S8S9调整参数上下限。上下限有限制和循环。

/*按键函数区域*/
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 4://模式切换按键
			if(++Seg_Mode == 3) Seg_Mode = 0;
			button=0;
		break;
		case 5:
			if(Seg_Mode == 1){//参数界面下,按键旋钮模式切换
				Val_Mode ^= 1;
				button=0; 
			}
			if(Seg_Mode == 2){//在记录界面为清零报警次数
				alarm_count = 0;
			}
		break;
		case 8://下限调整
			if(Seg_Mode == 1){//在参数界面下有效
				if(Val_Mode == 0){//按键模式
					dis_limit_down = dis_limit_down==40?0:dis_limit_down+10;
				}
				else{//旋钮界面
					button=1;//处理下限
				}
			}
		break;
		case 9://上限调整
			if(Seg_Mode == 1){//在参数界面下有效
				if(Val_Mode == 0){//按键模式
					dis_limit_up = dis_limit_up == 90?50:dis_limit_up+10;
				}
				else{//旋钮界面
					button=2;//处理上限~~~~~~~~~~~~~~~~~~~~~按下按键实时控制的定义一个标志位到数码管里面去实时变换
				}
			}	
		break;
	}
	
}

 显示功能

3个界面,界面1测距界面,对超声波模块进行读取获得当前的距离数据显示出来,高位熄灭。

界面2参数界面,分为两个s5控制的模式,通过标志位对模式值来判断,显示上下限,通过按键s89或者旋钮来控制上下限。

界面3记录界面,记录报警次数,大于9次就显示-,每次报警定义的标志位就加一。 

这边注意当距离值持续处于报警的条件的时候,报警次数不变,所以我们定义一个标志位,进入报警界面置1,放入判断里面来避免这个问题。

/*数码管信息函数区域*/
void Seg_Proc(){
	if(Seg_Slow) return;
	Seg_Slow = 1;
	
	dis_disp = ultra_rec();//获取测量的距离
	if(dis_disp>=dis_limit_down && dis_disp<=dis_limit_up){
		error = 0;//正常显示
	}
	else if(error==0 && dis_disp<=dis_limit_up){//原本正常,现在超出上限
		error = 1;
		alarm_count++;
	}
	else if(error==0 && dis_disp>=dis_limit_down){//原本正常现在超出下限
		error = 1;
		alarm_count++;
	}
	else{//一直持续在超出限制的状态
		error = 1;
	}
	if(Val_Mode){//旋钮模式才开始读取电压
		Ad_Val = Ad_Read(0x43);//获取滑动变阻器的值
		Volt = Ad_Val/51;//得到电压值
		if(Volt == 5) Volt = 4;//5v值是另类单独处理
	}
	if(button == 1){//处理下限
		dis_limit_down = Volt*10;
	}
	else if(button == 2){//处理上限
		dis_limit_up = Volt*10 + 50;
	}
	
	switch(Seg_Mode){
		case 0://测距模式
			Seg_Buf[0] = 11;//A
			Seg_Buf[1] = 10;
			Seg_Buf[2] = 10;
			Seg_Buf[3] = 10;
			Seg_Buf[4] = 10;
			Seg_Buf[5] = dis_disp>100?dis_disp/100:10;
			Seg_Buf[6] = dis_disp>10?dis_disp%100/10:10;
			Seg_Buf[7] = dis_disp%10;
		break;
		case 1://参数设置界面
			Seg_Buf[0] = 12;//P
			Seg_Buf[1] = Val_Mode+1;
			Seg_Buf[2] = 10;
			Seg_Buf[3] = dis_limit_down/10;//下限
			Seg_Buf[4] = 0;
			Seg_Buf[5] = 14;//-
			Seg_Buf[6] = dis_limit_up/10;//上限
			Seg_Buf[7] = 0;
		break;
		case 2://记录界面
			Seg_Buf[0] = 13;//E
			Seg_Buf[1] = 10;
			Seg_Buf[2] = 10;
			Seg_Buf[3] = 10;
			Seg_Buf[4] = 10;
			Seg_Buf[5] = 10;
			Seg_Buf[6] = 10;
			Seg_Buf[7] = alarm_count>9?14:alarm_count;//显示报警次数
		break;
	}
	
}

旋钮功能 

 

上限和下限就差了50cm的距离参数,所以我们可以先读取电压值,再判断是上限还是下限,得到对应的值。

if(Val_Mode){//旋钮模式才开始读取电压
		Ad_Val = Ad_Read(0x43);//获取滑动变阻器的值
		Volt = Ad_Val/51;//得到电压值
		if(Volt == 5) Volt = 4;//5v值是另类单独处理
	}
	if(button == 1){//处理下限
		dis_limit_down = Volt*10;
	}
	else if(button == 2){//处理上限
		dis_limit_up = Volt*10 + 50;
	}

 Led功能

 

L123都是常规的界面标志灯

L8额外判断一个标志位即可

/*Led函数区域*/
void Led_Proc(){
	Led_Buf[0] = Seg_Mode == 0?1:0;//测距模式L1点亮
	Led_Buf[1] = Seg_Mode == 1?1:0;//参数模式L2点亮
	Led_Buf[2] = Seg_Mode == 2?1:0;//记录模式L3点亮
	Led_Buf[7] = L8_flash;//L8点亮
}

 完整主函数

/*头文件区域*/
#include <STC15F2K60S2.H>
#include <Init.h>
#include <Led.h>
#include <Seg.h>
#include <Key.h>
#include <ultrasound.h>
#include <iic.h>

/*参数变量区域*/
unsigned char Seg_Slow,Key_Slow;
unsigned char Key_Down,Key_Old,Key_Up,Key_Val;
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 Seg_Mode;//0测距界面,1参数界面,3记录界面
unsigned char Val_Mode;//参数界面有效0按键模式,1旋钮模式
//数据存储
unsigned char alarm_count;//存储报警次数
unsigned char dis_limit_up = 60;//距离参数上限,默认值60
unsigned char dis_limit_down = 10;//距离参数下限,默认值10
unsigned int dis_disp;//测量所得的距离
unsigned char Time_100ms;//0.1s计时
unsigned char Volt;//电压对应的阶梯值,0~5级
unsigned char Ad_Val;//互动变阻器对应的电压值
unsigned char button;//旋钮标志位,0不起作用,1处理下限,2处理上限
bit error;//报警标志位,0默认正常模式
bit L8_flash;//L8闪烁标志位
/*按键函数区域*/
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 4://模式切换按键
			if(++Seg_Mode == 3) Seg_Mode = 0;
			button=0;
		break;
		case 5:
			if(Seg_Mode == 1){//参数界面下,按键旋钮模式切换
				Val_Mode ^= 1;
				button=0; 
			}
			if(Seg_Mode == 2){//在记录界面为清零报警次数
				alarm_count = 0;
			}
		break;
		case 8://下限调整
			if(Seg_Mode == 1){//在参数界面下有效
				if(Val_Mode == 0){//按键模式
					dis_limit_down = dis_limit_down==40?0:dis_limit_down+10;
				}
				else{//旋钮界面
					button=1;//处理下限
				}
			}
		break;
		case 9://上限调整
			if(Seg_Mode == 1){//在参数界面下有效
				if(Val_Mode == 0){//按键模式
					dis_limit_up = dis_limit_up == 90?50:dis_limit_up+10;
				}
				else{//旋钮界面
					button=2;//处理上限~~~~~~~~~~~~~~~~~~~~~按下按键实时控制的定义一个标志位到数码管里面去实时变换
				}
			}	
		break;
	}
	
}
/*数码管信息函数区域*/
void Seg_Proc(){
	if(Seg_Slow) return;
	Seg_Slow = 1;
	
	dis_disp = ultra_rec();//获取测量的距离
	if(dis_disp>=dis_limit_down && dis_disp<=dis_limit_up){
		error = 0;//正常显示
	}
	else if(error==0 && dis_disp<=dis_limit_up){//原本正常,现在超出上限
		error = 1;
		alarm_count++;
	}
	else if(error==0 && dis_disp>=dis_limit_down){//原本正常现在超出下限
		error = 1;
		alarm_count++;
	}
	else{//一直持续在超出限制的状态
		error = 1;
	}
	if(Val_Mode){//旋钮模式才开始读取电压
		Ad_Val = Ad_Read(0x43);//获取滑动变阻器的值
		Volt = Ad_Val/51;//得到电压值
		if(Volt == 5) Volt = 4;//5v值是另类单独处理
	}
	if(button == 1){//处理下限
		dis_limit_down = Volt*10;
	}
	else if(button == 2){//处理上限
		dis_limit_up = Volt*10 + 50;
	}
	
	switch(Seg_Mode){
		case 0://测距模式
			Seg_Buf[0] = 11;//A
			Seg_Buf[1] = 10;
			Seg_Buf[2] = 10;
			Seg_Buf[3] = 10;
			Seg_Buf[4] = 10;
			Seg_Buf[5] = dis_disp>100?dis_disp/100:10;
			Seg_Buf[6] = dis_disp>10?dis_disp%100/10:10;
			Seg_Buf[7] = dis_disp%10;
		break;
		case 1://参数设置界面
			Seg_Buf[0] = 12;//P
			Seg_Buf[1] = Val_Mode+1;
			Seg_Buf[2] = 10;
			Seg_Buf[3] = dis_limit_down/10;//下限
			Seg_Buf[4] = 0;
			Seg_Buf[5] = 14;//-
			Seg_Buf[6] = dis_limit_up/10;//上限
			Seg_Buf[7] = 0;
		break;
		case 2://记录界面
			Seg_Buf[0] = 13;//E
			Seg_Buf[1] = 10;
			Seg_Buf[2] = 10;
			Seg_Buf[3] = 10;
			Seg_Buf[4] = 10;
			Seg_Buf[5] = 10;
			Seg_Buf[6] = 10;
			Seg_Buf[7] = alarm_count>9?14:alarm_count;//显示报警次数
		break;
	}
	
}
/*Led函数区域*/
void Led_Proc(){
	Led_Buf[0] = Seg_Mode == 0?1:0;//测距模式L1点亮
	Led_Buf[1] = Seg_Mode == 1?1:0;//参数模式L2点亮
	Led_Buf[2] = Seg_Mode == 2?1:0;//记录模式L3点亮
	Led_Buf[7] = L8_flash;//L8点亮
}
/*定时器初始化函数区域*/
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;
}

/*定时器中断服务函数区域*/
void Timer0_Service() interrupt 1
{
	if(++Seg_Slow == 10) Seg_Slow = 0;
	if(++Key_Slow == 20) Key_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(error == 0){//正常显示L8点亮
		L8_flash = 1;
	}
	else{
		if(++Time_100ms == 100){
			Time_100ms = 0;
			L8_flash ^= 1;
		}
	}
}
/*主函数区域*/
void main(){
	Sys_Init();
	Timer0_Init();
	while(1){
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值