蓝桥杯单片机第十五届模拟题三

本文详细描述了如何使用IAP15F2K61S2单片机和提供的竞赛实训平台,实现一个包含超声波测距、模拟输入、状态指示、数据显示等功能的系统,涉及硬件配置、界面设计、按键和旋钮操作,以及上电初始状态的设定。
摘要由CSDN通过智能技术生成

一、题目

一、基本要求


使用大赛组委会提供的四梯/国信长天单片机竞赛实训平台,完成本试题的程序设计与调试。程序编写、调试完成后,选手需通过考试系统提交以准考证号命名的hex文件。不符合以上文件提交要求的作品将被评为零分或者被酌情扣分。

硬件设置:

将IAP15F2K61S2单片机内部振荡器频率设定为12MHz

键盘工作模式跳线J5配置为KBD矩阵按键模式。

扩展方式跳线J13配置为IO模式。

请注意:选手需严格按照以上要求配置竞赛板,编写和调试程序,不符合以上配置要求的作品将被评为零分或者被酌情扣分。

二、硬件框图


图1 系统硬件框图

三、功能描述


3.1 基本功能描述

1、通过超声波传感器完成距离测量功能;

2、通过 PCF8591完成试题要求的模拟功能;

3、通过LED指示灯完成试题要求的状态指示功能;

4、通过数码管、按键完成试题要求的数据显示、界面切换和参数设置等功能。

3.2 显示功能

1、测距界面

测距界面如图2所示,显示内容包括标识符(A)和距离值组成。距离值固定使用3位数码管显示,数码管显示不足3位时,高位(左侧)数码管熄灭。

距离值单位为:cm。

图2 测距界面

2、参数界面

参数界面如图3所示,由标识符(P)、模式值(按键模式:1;旋钮模式:2),参数下限、间隔符和参数上限组成。固定使用2位数码管显示参数下限/上限。

参数上限、参数下限单位为:cm。

图3 参数界面

3、记录界面

记录界面如图4所示,由标识符(E)和报警次数组成。

图4.1 记录界面(报警次数0-9)

图4.2 记录界面(报警次数>9)

测量的距离值由“参数下限≤测量的距离值≤参数上限”变为“测量的距离值>参数上限”或“测量的距离值<参数下限”时,报警次数加1;

注意:持续处于测量的距离值>参数上限或测量的距离值<参数下限时,报警次数不改变,

4、显示要求

(1)按照题目要求的界面格式和切换方式进行设计。

(2)数码管显示无重影、闪烁、过暗、亮度不均匀等严重影响显示效果的缺陷。

3.3 按键功能

1、功能说明

(1)S4:定义为“切换”,按下S4按键,切换“测距界面”、“参数界面”和“记录界面”。

图5 界面切换顺序

(2)S5:

在“参数界面”下,定义为“模式”,按下按键S5,切换参数调整模式。切换顺序如图6所示。

图6 模式切换

在“记录界面下”,定义为“清零”,按下按键S5,清零当前的报警次数。

(3)S9:在“参数界面”下

“按键模式”下,定义为“上限调整”,按下按键S9,参数上限加10。参数上限调整顺序:

50 60 70 80 90 50 …

“旋钮模式”下,定义为“上限”,按下按键S9,可使用旋钮调整当前参数上限。调整顺序详见3.4(1)。

(4)S8:在“参数界面”下,

“按键模式”下,定义为“下限调整”,按下按键S8,参数下限加10。参数下限调整顺序:

0 10 20 30 40 0 10 …

“旋钮模式”下,定义为“下限”,按下按键S8,可使用旋钮调整当前参数上限。调整顺序详见3.4(2)。

(5)按键要求

① 按键应做好消抖处理,避免出现一次按键动作导致功能多次触发。

② 按键动作不影响数码管显示等其他功能。

③ 当前界面或模式下无功能的按键按下,不触发其它界面的功能。

④ 参数上限调整范围“50-90”;

⑤ 参数下限调整范围“0-50”。

3.4 旋钮模式

使用PCF8591的ADC功能采集RB2的模拟信号,模拟旋钮功能调整参数上限或参数下限:

(1)“上限”调整过程如图7所示:

图7 “上限”调整过程

(2)“下限”调整过程如图8所示:

图8 “下限”调整过程

3.5 LED指示灯功能

(1)测距界面下,指示灯 L1 点亮,否则指示灯 L1 熄灭。

(2)参数界面下,指示灯 L2 点亮,否则指示灯 L2 熄灭。

(3)记录界面下,指示灯 L3 点亮,否则指示灯 L3 熄灭。

(4)参数下限≤测量的距离值≤参数上限,指示灯L8点亮,否则L8以0.1s为间隔切换亮灭状态。

(5)除L1、L2、L3和L8指示灯外,其余指示灯均处于熄灭状态。

3.6 初始状态

请严格按照以下要求设计作品的上电初始状态。

1、处于测距界面

2、按键模式

3、参数上限60;参数下限10。

二、代码

1.mian.c

main.c
#include <STC15F2K60S2.H>
#include <iic.h>
#include <Seg.h>
#include <Key.h>
#include <Led.h>
#include <Ultra.h>
#include <Init.h>

//变量定义区
//键盘专用
unsigned char Key_Slow_Down;//10ms
unsigned char Key_Val,Key_Down,Key_Up,Key_Old;

//数码管专用
unsigned int Seg_Slow_Down;//500ms
unsigned char Seg_Pos;
unsigned char Seg_Buf[8]={10,10,10,10,10,10,10,10};
unsigned char Seg_Point[8]={0,0,0,0,0,0,0,0};

//Led灯专用
unsigned char ucLed[8]={0,0,0,0,0,0,0,0};

//超声波测距
unsigned int Distance;//实时距离

//PCF8592
float Voltage;//实时电压

unsigned char Seg_Disp_Mode;//界面切换标志 0-测距界面,1-参数界面,2-记录界面
/*测距界面*/
//超声波测距
unsigned int Distance;//实时距离
/*参数界面*/
unsigned char Seg_Mode;//1-按键模式 2-旋钮模式
unsigned char Seg_Max=60;//参数上限 初始值:60
unsigned char Seg_Min=10;//参数下限 初始值:10
bit Seg_Voltage_Flag1;//参数上限:1-旋钮调整 0-按键调整
bit Seg_Voltage_Flag2;//参数下限:1-旋钮调整 0-按键调整


/*记录界面*/
unsigned char Index;//报警次数 
unsigned char Distance_Old;
bit flag;//判断上一次的Index的值处于什么地方
bit Led_Star_Flag;//闪烁标志位
unsigned char Timer_100ms;//100毫秒

//关于参数上限的读取函数
void Read_Seg_Max()
{

	Voltage=AD_Read(0x43)/51.0;
	if(Voltage>=0&&Voltage<1) Seg_Max=50;
	else if(Voltage>=1&&Voltage<2) Seg_Max=60;
	else if(Voltage>=2&&Voltage<3) Seg_Max=70;
	else if(Voltage>=3&&Voltage<4) Seg_Max=80;
	else Seg_Max=90;
}

//关于参数下限的读取函数
void Read_Seg_Min()
{

	Voltage=AD_Read(0x43)/51.0;
	if(Voltage>=0&&Voltage<1) Seg_Min=0;
	else if(Voltage>=1&&Voltage<2) Seg_Min=10;
	else if(Voltage>=2&&Voltage<3) Seg_Min=20;
	else if(Voltage>=3&&Voltage<4) Seg_Min=30;
	else Seg_Min=40;
}

//按键处理函数
void Key_Proc()
{
	if(Key_Slow_Down) return;
	Key_Slow_Down=1;
	
	Key_Val = Key_Read();
	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(++Seg_Disp_Mode==3) Seg_Disp_Mode=0;
		break;
		
		case 5:
			if(Seg_Disp_Mode==1)
				Seg_Mode=!Seg_Mode;
			else if(Seg_Disp_Mode==2)
				Index=0;
		break;
			
		case 9:
			if(Seg_Disp_Mode==1)
			{
				if(Seg_Mode==0)
				{
					Seg_Voltage_Flag1=0;
					Seg_Max+=10;
					if(Seg_Max==100)
						Seg_Max=50;
				}
				else if(Seg_Mode==1)
				{
					Seg_Voltage_Flag1=1;
					Seg_Voltage_Flag2=0;
				}
			}
		break;
			
		case 8:
		if(Seg_Disp_Mode==1)
		{
			if(Seg_Mode==0)
			{
				Seg_Voltage_Flag2=0;
				Seg_Min+=10;
				if(Seg_Min==50)
					Seg_Min=0;
			}
			else if(Seg_Mode==1)
			{
				Seg_Voltage_Flag2=1;
				Seg_Voltage_Flag1=0;
			}
		}
		break;
			
			
			
	}
	
}

//数码管清除函数
void Clear_Seg()
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		Seg_Buf[i]=10;
		Seg_Point[i]=0;
	}
}

void Index_Judge()
{
	if((Distance_Old>=Seg_Min)&&(Distance_Old<=Seg_Max))
		flag=1;
	else 
		flag=0;
	if(flag==1)
	{
		if((Distance>Seg_Max)||(Distance<Seg_Min))
			Index++;
	}
	
	Distance_Old=Distance;
}

//数码管处理函数
void Seg_Proc()
{
	if(Seg_Slow_Down) return;
	Seg_Slow_Down=1;
	
	Distance=Ultra_Data();
	Index_Judge();
	
	if(Seg_Voltage_Flag1==1)
		Read_Seg_Max();
	if(Seg_Voltage_Flag2==1)
		Read_Seg_Min();
	switch(Seg_Disp_Mode)
	{
		//测距界面
		case 0:
			Clear_Seg();
			Seg_Buf[0]=12;//A
			Seg_Buf[5]=(Distance/100%10>0)?(Distance/100%10):10;
			Seg_Buf[6]=((Distance/10%10==0)&(Distance/100%10==0))?10:(Distance/10%10);
			Seg_Buf[7]=Distance%10;
		break;
		
		//参数界面
		case 1:
			Clear_Seg();
			Seg_Buf[0]=13;//P
			Seg_Buf[1]=Seg_Mode+1;
			Seg_Buf[3]=Seg_Min/10;
			Seg_Buf[4]=Seg_Min%10;
			Seg_Buf[5]=11;//-
			Seg_Buf[6]=Seg_Max/10;
			Seg_Buf[7]=Seg_Max%10;	
		break;
		
		//记录界面
		case 2:
			Clear_Seg();
			Seg_Buf[0]=14;//E
			if(Index>9)
				Seg_Buf[7]=11;//-
			else
				Seg_Buf[7]=Index;
		break;
	}
	
}

//其他处理函数
void Led_Proc()
{
	unsigned char i;
	for(i=0;i<3;i++)
		ucLed[i]=(i==Seg_Disp_Mode);
	if(flag==1) ucLed[7]=1;
	else ucLed[7]=Led_Star_Flag;
	
}
	
	
//定时器0初始化
void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	EA=1;
	ET0=1;
}

void Timer0Sever() interrupt 1
{
	if(++Key_Slow_Down==10) Key_Slow_Down=0;
	if(++Seg_Slow_Down==500) Seg_Slow_Down=0;
	
	if(++Seg_Pos==8) Seg_Pos=0;
	
	if(flag==0)
	{
		if(++Timer_100ms==100) 
		{
			Timer_100ms=0;
			Led_Star_Flag=!Led_Star_Flag;
		}
	}
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
	Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
}

//main()函数
void main()
{
	System_Init();
	Timer0Init();
	Ultra_Data();
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
	
}
	

2.ultra.c

超声波测距

ultra.c
#include <Ultra.h>
#include <intrins.h>

sbit TX=P1^0;
sbit RX=P1^1;

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

	_nop_();
	_nop_();
	i = 36;
	while (--i);
}

void Ultra_Init()
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		TX=1;
		Delay12us();
		TX=0;
		Delay12us();
	}
}

unsigned char Ultra_Data()
{
	unsigned int time;
	CMOD=0x00;
	CH=CL=0;

    ET0=0;
	Ultra_Init();//8个方波
    ET0=1;

	CR=1;//开始计时
	while((RX==1)&&(CF==0));
	CR=0;//停止计时
	
	if(CF==0)
	{
		time=(CH<<8)|CL;
		return (time*0.017);//单位:cm
	}
	
	else
	{
		//超过测量范围
		CF=0;
		return 999;
	}
}

3.Led.c

Led.c
#include <Led.h>

void Led_Disp(unsigned char addr,unsigned char flag)
{
	static unsigned char temp=0x00;
	static unsigned char temp_old=0xff;
	
	if(flag)
		temp|=0x01<<addr;
	else
		temp&=~(0x01<<addr);
	
	if(temp_old!=temp)
	{
		P0=~temp;
		P2=P2&0x1f|0x80;
		P2&=0x1f;
		temp_old=temp;
	}
}

 4.Key.c

Key.c
#include <Key.h>

unsigned char Key_Read()
{
	unsigned char temp=0;
	P44=0;P42=1;P35=1;P34=1;
	if(P33==0) temp=4;
	if(P32==0) temp=5;
	if(P31==0) temp=6;
	if(P30==0) temp=7;
	P44=1;P42=0;P35=1;P34=1;
	if(P33==0) temp=8;
	if(P32==0) temp=9;
	if(P31==0) temp=10;
	if(P30==0) temp=11;
	P44=1;P42=1;P35=0;P34=1;
	if(P33==0) temp=12;
	if(P32==0) temp=13;
	if(P31==0) temp=14;
	if(P30==0) temp=15;
	P44=1;P42=1;P35=1;P34=0;
	if(P33==0) temp=16;
	if(P32==0) temp=17;
	if(P31==0) temp=18;
	if(P30==0) temp=19;
	
	return temp;
}

 5.Seg.c

Seg.c
#include <Seg.h>


unsigned char Wulu[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned char Dulu[15]={
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0xff, //熄灭
0xbf, //-
0x88, //A
0x8c, //P
0x86 //E	
};

void Seg_Disp(unsigned char addr,unsigned char dat,unsigned char point)
{
	//段选消隐
	P0=0xff;
	P2=P2&0x1f|0xe0;
	P2&=0x1f;
	
	//位选
	P0=Wulu[addr];
	P2=P2&0x1f|0xc0;
	P2&=0x1f;
	
	//段选
	P0=Dulu[dat];
	if(point)
		P0&=0x7f;
	P2=P2&0x1f|0xe0;
	P2&=0x1f;
}

6.Init.c

Init.c
#include <Init.h>

void System_Init(void)
{
	//关闭Led
	P0=0xff;
	P2=P2&0x1f|0x80;
	P2&=0x1f;
	
	//关闭蜂鸣器、继电器
	P0=0x00;
	P2=P2&0x1f|0xa0;
	P2&=0x1f;
}

  • 47
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值