蓝桥杯15单片机--专项问题:多数暂存、平均值、最大值、最小值问题

在第十二届国赛和刚刚过去的第十四届省赛中,遇到了一个新问题:多数暂存、平均值、最大值、最小值问题。

其实这个要求并不难,就是平均值显示那个地方容易想不出来。其他的认真想想就可以。

第十二届国赛具体要求如下:

首先,这一部分数据的存储肯定要用数组去做,我们定义一个可以存放50个数据的数组,distance[n]

 值得注意的是:我们前面要用xdata来存储。如果不加的话,默认使用data型,那么数据内存就会超标,产生错误。

unsigned int xdata distance[50]=0;

最大值和最小值很简单,把第一个数当作最大值和最小值,然后每进去一个数进行比较,如果大于最大值或者小于最小值就把新数值化为最大值或最小值。

if(n==0) {LCM_min=distance[0];LCM_max=distance[0];}

if(distance[n]>LCM_max) {LCM_max=distance[n];}

else if(distance[n]<LCM_min) {LCM_min=distance[n];}

平均值的话,由于牵扯到小数显示,所以要定义两个变量:一个小数平均值(进行计算)和整数平均值(进行显示)。计算出小数平均值,然后乘10转换成整数形式,再进行小数显示。

LCM_all=LCM_all+distance[n];

LCM_pingjun_xiaoshu=LCM_all/(n+1);

LCM_pingjun=(int)(LCM_pingjun_xiaoshu*10);

最后一步就是数组数据的更新:如果读取的数据超过 50个,将数据依次前移,去掉最前面那一个数据。

if(n==50)
{
    for(i=1;i<=49;i++)
	{
		distance[i-1]=distance[i];
	}
	n=49;
}

最后放上程序源码

程序要求:读取超声波测量到的50个距离数据,并且满50个之后进行更新。按键S4切换显示平均值、最大值、最小值。

#include <STC15F2K60S2.H>
#include <intrins.H>

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

#define uchar unsigned char
#define uint unsigned int
	
uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,//0-9
									0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10,//0.-9.
                  0XBF,0XFF,0X8E,0XC1};//- 关 F U
uchar Smg_num=0;
uchar Smg[]={0,7,10,5,3,10,1,0};

unsigned int LCM_tt = 0 ;//超声波采集时间的计数 间隔多长时间进行一次超声波测量
bit LCM_Ref = 0 ;//超声波开始测量的标志位
unsigned int LCM = 0 ;//超声波测量的距离  单位:cm
unsigned int LCM_Time = 0 ;//超声波从发送到接收返回信号的时间

uint xdata distance[50]=0;
float LCM_pingjun_xiaoshu=0.0f;
uint LCM_pingjun=0,LCM_min=0,LCM_max=0,caiji_tt=0;
bit caiji_flag=0;
uchar mode=0,n=0,i=0;
long LCM_all=0;

void Allinit();
void Delayms(uint ms);
void Keyscan();
void Timer2Init(void);		//1毫秒@12.000MHz
void Smg_work();
void Send_wave();
void Csb_work();
void Delay16us();
void Timer1Init(void);

void main()
{
	Allinit();
	Timer1Init();
	Timer2Init();
	while(1)
	{
		if(caiji_flag==1)//每1秒采集一次
		{
			Csb_work();
			distance[n]=LCM;//存储数据进数组
			
			// 最小值 最大值 平均值 的确定
			if(n==0) {LCM_min=distance[0];LCM_max=distance[0];}
			if(distance[n]>LCM_max) {LCM_max=distance[n];}
			else if(distance[n]<LCM_min) {LCM_min=distance[n];}
			LCM_all=LCM_all+distance[n];
			LCM_pingjun_xiaoshu=LCM_all/(n+1);
			LCM_pingjun=(int)(LCM_pingjun_xiaoshu*10); 
			if(LCM_pingjun>=9999) LCM_pingjun=9999;
			n=n+1;
			
			// 读取的数据超过 50个,将数据依次前移,去掉最前面那一个数据
			if(n==50)
			{
				for(i=1;i<=49;i++)
				{
					distance[i-1]=distance[i];
				}
				n=49;
			}
			caiji_flag=0;
		}
		
		Smg_work();
		Keyscan();
		//Keyscan16();
		//Delayms(5);
	}
}

void Smg_work()
{
	if(mode==0)
	{
		Smg[0]=22;Smg[1]=1;Smg[2]=21;Smg[3]=21;
		Smg[4]=LCM_max/1000;Smg[5]=LCM_max%1000/100;
		Smg[6]=LCM_max%100/10;Smg[7]=LCM_max%10;
	}
	else if(mode==1)
	{
		Smg[0]=22;Smg[1]=2;Smg[2]=21;Smg[3]=21;
		Smg[4]=LCM_pingjun/1000;Smg[5]=LCM_pingjun%1000/100;
		Smg[6]=LCM_pingjun%100/10;Smg[7]=LCM_pingjun%10;
	}
	else if(mode==2)
	{
		Smg[0]=22;Smg[1]=3;Smg[2]=21;Smg[3]=21;
		Smg[4]=LCM_min/1000;Smg[5]=LCM_min%1000/100;
		Smg[6]=LCM_min%100/10;Smg[7]=LCM_min%10;
	}
	else if(mode==3)
	{
		Smg[0]=distance[n-2]/1000;Smg[1]=distance[n-2]%1000/100;
		Smg[2]=distance[n-2]%100/10;Smg[3]=distance[n-2]%10;
		Smg[4]=distance[n-1]/1000;Smg[5]=distance[n-1]%1000/100;
		Smg[6]=distance[n-1]%100/10;Smg[7]=distance[n-1]%10;
	}
}

void Send_wave()//发送超声波信号
{
	uchar i=8;
	
	do
	{
		TX=1;  Delay16us();
		TX=0;  Delay16us();
	}
	while(i--);
}

void Csb_work()//这个放在 while 循环里面
{
	if(LCM_Ref==1)
	{
		LCM_Ref=0;
		Send_wave();
		TR1=1;
		while((RX==1)&&(TF1==0));//如果RX没有接收到低电平(返回信号),就一直等待;或者检测中断标志位,没有溢出中断
		//当检测到返回信号,或者一直没有接收到返回信号但是中断溢出了,程序就继续往下进行。
		TR1=0;
		if(TF1==1)//这种情况是 一直没有接收到返回信号但是溢出中断了
		{
			TF1=0; LCM=9999;//表示没有检测到返回信号了,数据超出范围
		}
		else
		{
			LCM_Time = TH1;
			LCM_Time <<= 8;
			LCM_Time |= TL1;//读出超声波从发送到接收信号所用的时间,但这读出来的是定时器计数的值,所以下面我们要对其进行换算
			LCM=(uint)(LCM_Time*17/1000);
			//定时器计数一次需要 1/1000000秒(1/12000000/12)(12M晶振),总共计数了 LCM_Time次
			//LCM_Time * 1/1000000 * 17000(34000/2) 距离单位是厘米
		}
		TL1=0X00;
		TH1=0X00;//清零方便下次计数	
	}
}

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

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

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

void timer2() interrupt 12
{
	P0=0XFF;
	P2|=0XC0;//打开位选573   U8
	P2&=0XDF;
	P2&=0X1F;
	
	P0=0XFF;
	P2|=0XE0;
	P2&=0XFF;//打开段选573   U7
	P2&=0X1F;

	P0=(1<<Smg_num);
	P2|=0XC0;//打开位选573   U8
	P2&=0XDF;
	P2&=0X1F;
	
	P0=tab[Smg[Smg_num]];
	P2|=0XE0;
	P2&=0XFF;//打开段选573   U7
	P2&=0X1F;
	if(++Smg_num==8) Smg_num=0;
	
	if(++LCM_tt==300)//每三百毫秒进行一次超声波检测
	{
		LCM_tt=0;LCM_Ref=1;
	}
	
	if(caiji_flag==0)
	{
		caiji_tt++;
		if(caiji_tt==1000)
		{
			caiji_flag=1;caiji_tt=0;
		}
	}
}

void Timer2Init(void)		//1毫秒@12.000MHz
{
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0x20;		//设置定时初始值
	T2H = 0xD1;		//设置定时初始值
	AUXR |= 0x10;		//定时器2开始计时

	IE2|=0X04;EA=1;
}

void Keyscan()
{
	if(P30==0)
	{
		Delayms(5);
		if(P30==0)
		{
			Smg[0]=1;
		}
		while(!P30);
	}
	
	else if(P31==0)
	{
		Delayms(5);
		if(P31==0)
		{
			Smg[1]=2;
		}
		while(!P31);
	}
	
	else if(P32==0)
	{
		Delayms(5);
		if(P32==0)
		{
			Smg[2]=3;
		}
		while(!P32);
	}
	
	else if(P33==0)
	{
		Delayms(5);
		if(P33==0)
		{
			if(mode==0) mode=1;
			else if(mode==1) mode=2;
			else if(mode==2) mode=3;
			else if(mode==3) mode=0;
		}
		while(!P33);
	}
}

void Allinit()
{
	P2|=0XA0;P2&=0XBF;P0=0X00;
	
	P2|=0X80;P2&=0X9F;P0=0XFF;
	
	P2|=0XC0;P2&=0XDF;P0=0XFF;
	P2|=0XE0;P2&=0XFF;P0=0XFF;
}

void Delayms(uint ms)
{
	uint i,j;
	for(i=ms;i>0;i--)
	for(j=845;j>0;j--);
}

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值