在第十二届国赛和刚刚过去的第十四届省赛中,遇到了一个新问题:多数暂存、平均值、最大值、最小值问题。
其实这个要求并不难,就是平均值显示那个地方容易想不出来。其他的认真想想就可以。
第十二届国赛具体要求如下:
、
首先,这一部分数据的存储肯定要用数组去做,我们定义一个可以存放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--);
}