基本信息
源码名称:电子设计大赛中MSP430写的FFT变换程序(总共128个点)
源码大小:0.16M
文件格式:.zip
开发语言:C/C++
更新时间:2019-07-12
   友情提示:(无需注册或充值,赞助后即可获取资源下载链接)

     嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):813200300

本次赞助数额为: 2 元 
   源码介绍

#include "MSP430X14X.h"
#include "math.h"
#include "OCMJ4X8C.h"
#include"MSP430KEY.h"
#include"df_timera.h"

#define num_point 128	//取样点数
#define num_grade 7	//蝶形运算阶数
const float tab_sin[256]={
      0, 0.0245, 0.0491, 0.0736, 0.0980, 0.1224, 0.1467, 0.1710, 0.1951,
 0.2191, 0.2430, 0.2667, 0.2903, 0.3137, 0.3369, 0.3599, 0.3827, 0.4052,
 0.4276, 0.4496, 0.4714, 0.4929, 0.5141, 0.5350, 0.5556, 0.5758, 0.5957,
 0.6152, 0.6344, 0.6532, 0.6716, 0.6895, 0.7071, 0.7242, 0.7410, 0.7572,
 0.7730, 0.7883, 0.8032, 0.8176, 0.8315, 0.8449, 0.8577, 0.8701, 0.8819,
 0.8932, 0.9040, 0.9142, 0.9239, 0.9330, 0.9415, 0.9495, 0.9569, 0.9638,
 0.9700, 0.9757, 0.9808, 0.9853, 0.9892, 0.9925, 0.9952, 0.9973, 0.9988,
 0.9997, 1.0000, 0.9997, 0.9988, 0.9973, 0.9952, 0.9925, 0.9892, 0.9853,
 0.9808, 0.9757, 0.9700, 0.9638, 0.9569, 0.9495, 0.9415, 0.9330, 0.9239,
 0.9142, 0.9040, 0.8932, 0.8819, 0.8701, 0.8577, 0.8449, 0.8315, 0.8176,
 0.8032, 0.7883, 0.7730, 0.7572, 0.7410, 0.7242, 0.7071, 0.6895, 0.6716,
 0.6532, 0.6344, 0.6152, 0.5957, 0.5758, 0.5556, 0.5350, 0.5141, 0.4929,
 0.4714, 0.4496, 0.4276, 0.4052, 0.3827, 0.3599, 0.3369, 0.3137, 0.2903,
 0.2667, 0.2430, 0.2191, 0.1951, 0.1710, 0.1467, 0.1224, 0.0980, 0.0736,
 0.0491, 0.0245, 0.0000,-0.0245,-0.0491,-0.0736,-0.0980,-0.1224,-0.1467,
-0.1710,-0.1951,-0.2191,-0.2430,-0.2667,-0.2903,-0.3137,-0.3369,-0.3599,
-0.3827,-0.4052,-0.4276,-0.4496,-0.4714,-0.4929,-0.5141,-0.5350,-0.5556,
-0.5758,-0.5957,-0.6152,-0.6344,-0.6532,-0.6716,-0.6895,-0.7071,-0.7242,
-0.7410,-0.7572,-0.7730,-0.7883,-0.8032,-0.8176,-0.8315,-0.8449,-0.8577,
-0.8701,-0.8819,-0.8932,-0.9040,-0.9142,-0.9239,-0.9330,-0.9415,-0.9495,
-0.9569,-0.9638,-0.9700,-0.9757,-0.9808,-0.9853,-0.9892,-0.9925,-0.9952,
-0.9973,-0.9988,-0.9997,-1.0000,-0.9997,-0.9988,-0.9973,-0.9952,-0.9925,
-0.9892,-0.9853,-0.9808,-0.9757,-0.9700,-0.9638,-0.9569,-0.9495,-0.9415,
-0.9330,-0.9239,-0.9142,-0.9040,-0.8932,-0.8819,-0.8701,-0.8577,-0.8449,
-0.8315,-0.8176,-0.8032,-0.7883,-0.7730,-0.7572,-0.7410,-0.7242,-0.7071,
-0.6895,-0.6716,-0.6532,-0.6344,-0.6152,-0.5957,-0.5758,-0.5556,-0.5350,
-0.5141,-0.4929,-0.4714,-0.4496,-0.4276,-0.4052,-0.3827,-0.3599,-0.3369,
-0.3137,-0.2903,-0.2667,-0.2430,-0.2191,-0.1951,-0.1710,-0.1467,-0.1224,
-0.0980,-0.0736,-0.0491,-0.0245};
//float tab_dftR[num_point];         //输入的波形数据,兼作输出数据的实部
float tab_dftI[num_point];           //输出数据的虚部
//float tab_power[num_point];          //模,频率对应的功率谱
float result[num_point];             //AD转换结果
float power_t=0;                     //时域总功率
float power_f=0;                     //频域总功率
unsigned int data1;
unsigned int data2;
unsigned char disp1[16];
unsigned char disp2[16];

unsigned int num_B=0;
unsigned int mem[num_point];

//以下为液晶显示信息
unsigned char Text[]=
{
  "宜宾学院        "  
  "请按E 键开始    "
  "音频信号分析仪  "
  "按R 键返回      "
};

unsigned char Start[]=
{
  "按E 键采集信号  "
  "按R 键返回      "    
  "进行FFT 分析    "
  "系统会在5S后返回"
};

unsigned char Sure[]=
{
  "请按确定键把FFT "
  "每按一次显示    "
  "的功率谱分布显示"
  "一个功率值      "
};
unsigned char spectrum[]=
{
  "    频谱分析    "
  "                "
  "                "
  "                "
};
void InitSys();//系统初始化 
void fft(float dataR[num_point],float dataI[num_point]);   //FFT变换
void get_power_t(float result[num_point]);//计算时域功率,一定要放于void FFT前,否则result数据被覆盖
void get_power(float result[num_point],float dataI[num_point]);	           //求模	
void AD_timeB();
void AdcConvert(unsigned char *Numeral,unsigned int result);
void sort(float* mod,unsigned int* count_in);//大到小的排序
void display(float result[num_point]);
//static unsigned int length;

void main( void )
{
  unsigned char key[2],LCD_data[16];
  unsigned int count,freq_count;
  unsigned long data1,data2;
  float data3; 
  signed long Chan_data;
  unsigned int count_index[num_point/2];
  
  WDTCTL = WDTPW   WDTHOLD;          //关闭看门狗
  for(unsigned int p0=0;p0<num_point/2;p0  )
    count_index[p0]=p0;//0-127无符号数序列 频率的参考倍数
 InitSys();
start:
        count=0;
        chn_disp (Text);//输出实验人信息

    while(1)
      {
        key[0]=GetKeyZhi(&key[1]);
         if(key[0]==0x84)
          break;
        LPM3;
       }       
        clrram();
        chn_disp(Start); 
        
        while(1)
        {
          key[0]=GetKeyZhi(&key[1]);
          if(key[0]==0x88)   //返回
            goto start;
          if(key[0]==0x84)
            break;
          LPM3;
        }         
       clrram();
       AD_timeB(); //定时器控件AD转换
       while(1)
        { 
            if(num_B==num_point)
            {
              ADC12CTL0&=~ENC;
              TBCTL&=~(BIT5 BIT4);
               break;
            }
        } 
       
       for(unsigned int q4=0;q4<num_point;q4  )
       {
         Chan_data=mem[q4];  //signed long mem为最初12位无符号采样结果
         Chan_data -=0x7FF;
         Chan_data *=5;
         result[q4] =((float)Chan_data)/4095;//AD转换结果 result=(mem-0x7FF)*5/4095
       }
       get_power_t(result);
       fft(result,tab_dftI);
       get_power(result,tab_dftI);    
        clrram();
        
        chn_disp(Sure);        
        
        while(1)
         {
            key[0]=GetKeyZhi(&key[1]);
           if(key[0]==0x88)
             goto start;
            if(key[0]==0x84)
              clrram();
            delay(500);
              break;
         }          
         clrram();
        Clear_GDRAM();
         chn_disp(spectrum);
         display(result);// 显示频谱      
       sort(result,count_index);  //排序     
       while(count!=101)      //频率为10k
        {
          key[0]=GetKeyZhi(&key[1]);
          if(key[0]==0x88)
            goto start;
          if(key[0]==0x84)
          {            
            clrram(); 
            Clear_GDRAM();
         freq_count =count_index[count]*100;   //频率=0
        data3=result[count];
        data1=(unsigned int)data3; //模,频率对应的整数功率谱
        data3=data3-data1;        //误差
        data2=(unsigned int)(data3*10000);  //误差的10000倍(精度小数点后4位有效数字)
        Convert(LCD_data,data1,data2,freq_count);          
        line_disp(LCD_data,0x80);
        count  ;
 
        freq_count =count_index[count]*100; //频率=
        data3=result[count];
        data1=(unsigned int)data3;
        data3=data3-data1;
        data2=(unsigned int)(data3*10000);
        Convert(LCD_data,data1,data2,freq_count);         
        line_disp(LCD_data,0x90);
        count  ;
          
        freq_count =count_index[count]*100;  //200
        data3=result[count];
        data1=(unsigned int)data3;
        data3=data3-data1;
        data2=(unsigned int)(data3*10000);
        Convert(LCD_data,data1,data2,freq_count);         
        line_disp(LCD_data,0x88);
        count  ;
                  
        freq_count =count_index[count]*100;   //=300
        data3=result[count];
        data1=(unsigned int)data3;
        data3=data3-data1;
        data2=(unsigned int)(data3*10000);
        Convert(LCD_data,data1,data2,freq_count);         
        line_disp(LCD_data,0x98);
        count  ;
          }
        }       
}

void get_power_t(float result[num_point])
{
  unsigned int i;
  for(i=0;i<num_point;i  )
    power_t=power_t result[i]*result[i]/num_point;
}

/*********************************************************
FFT转换
*********************************************************/
void fft(float dataR[num_point],float dataI[num_point])
{   
  int i,L,j,k,b,p,q,xx,pow1,pow2;
  float TR,TI,temp;
  /***********following code invert sequence********/
  for(i=0;i<num_point;i  )
  {
    pow1=1;pow2=num_grade-1;
    while(pow2>0)
    {pow1=pow1*2;pow2--;}                 // pow1= 2^(pow2)
    xx=(i&0x01)*pow1;
    for(j=1;j<num_grade;j  )
    {
      pow1=1;pow2=num_grade-1-j;
      while(pow2>0)
      {pow1=pow1*2;pow2--;}
      xx=xx ((i>>j)&0x01)*pow1;
    }
    dataI[xx]=dataR[i];
  }
  for(i=0;i<num_point;i  )
  {
    dataR[i]=dataI[i];
    dataI[i]=0;
  }
  /********** following code invert sequence ************
  //按照书上写的位反转算法
  int pp=1,qq;
  int bit_rev[num_point];

  bit_rev[0]=0;
  while(pp<num_point)          
  {
    for(qq=0;qq<pp;qq  )
    {
      bit_rev[qq]=bit_rev[qq]*2;
      bit_rev[qq pp]=bit_rev[qq] 1;
    }
    pp=pp*2;
  }
  for(i=0;i<num_point;i  )
  {dataI[i]=dataR[bit_rev[i]];}

  for(i=0;i<num_point;i  )
  {dataR[i]=dataI[i]; dataI[i]=0;}*/
  /************** following code FFT *******************/
  for(L=1;L<=num_grade;L  )
  { //for(1)第一层 8个级数次循环
    b=1; i=L-1;
    while(i>0)
    {b=b*2;i--;}               //b= 2^(L-1) 
    for(j=0;j<=b-1;j  )        //for (2)第二层 蝶形因子次循环
    {
      p=1; i=num_grade-L;
      while(i>0)               //p=pow(2,7-L)*j
      {p=p*2;i--;}
      p=p*j;

      if(p<3*256/4)
        q=p 256/4;
      else
        q=p-3*256/4;

      for(k=j;k<num_point;k=k 2*b) //for (3)第三层
      {
        TR=dataR[k]; TI=dataI[k]; temp=dataR[k b];
        dataR[k]=TR dataR[k b]*tab_sin[q] dataI[k b]*tab_sin[p];
        dataI[k]=TI-dataR[k b]*tab_sin[p] dataI[k b]*tab_sin[q];
        dataR[k b]=TR-dataR[k b]*tab_sin[q]-dataI[k b]*tab_sin[p];
        dataI[k b]=TI temp*tab_sin[p]-dataI[k b]*tab_sin[q];
      } //END for (3)
    }//END for (2)
  }//END for (1)
}//END FFT

void get_power(float result[num_point],float dataI[num_point])
{
  int i;
  for(i=0;i<num_point;i  )
  {
    result[i]=(result[i]*result[i] tab_dftI[i]*tab_dftI[i])/num_point;    //取模值,频率对应的功率谱
   result[i]=result[i]/num_point;
    power_f=power_f result[i];      //频域总功率
  }
}

/**************************************************************
系统初始化
**************************************************************/
void InitSys()
{
  unsigned int iq0;

  //使用XT2振荡器
  BCSCTL1 &=~XT2OFF;           //打开XT2振荡器
  do
  {
    IFG1 &=~OFIFG;          //清除振荡器失效标志
    for(iq0=0xFF;iq0>0;iq0--);//延时,等待XT2起振
  }
  while((IFG1&OFIFG)!=0);      //判断能力XT2是否起振

  BCSCTL2=SELM_2 SELS;         //选择MCLK,SMCLK为XT2
  InitKey();                   //初始化按键端口
  TimerAInit();                //初始化定时器A
  init_lcd();
  _EINT();                     //打开全局中断控制,若不需要打开,则可以屏蔽本句
}

/**************************************************************
定时器B中断向量
**************************************************************/
#pragma vector=TIMERB0_VECTOR
__interrupt void Timer_B (void)
{
    ADC12CTL0|=ADC12SC;   /* ADC12 Start Conversion */
    while((ADC12IFG&BIT0)==0);
    mem[num_B]=ADC12MEM0;  //采样结果赋值给mem
    num_B  ;
    ADC12CTL0&=~ENC;
    ADC12CTL0|=ENC;
    TBCTL&=~BIT0;   
}

/*************************************************************************
 定时器控件AD转换
*************************************************************************/
void AD_timeB()
{
       ADC12CTL0&=~ENC;
       P6SEL |= 0x04;        // 使能ADC通道
       ADC12CTL0|=REFON REF2_5V SHT0_1 ADC12ON;//SHT0_1 REFON ADC12ON;//多次,2.5vref 使能 SHT0_1设置采样时钟
       //for(unsigned iq6=0;iq6<255;iq6  );SHT0_2
       ADC12CTL1|=SHP ADC12SSEL_2;//单道1次,clk=mclk=dco  SHP要置位 SAMPCON signal is sourced from the sampling timer
       ADC12MCTL0 |=INCH_2 SREF_1;
       ADC12CTL0|=ENC;//ENC=0才可以改变ADC12CTL1 ADC12CTL2
       
       TBCTL = TBSSEL1   MC0;              // MCLK=8MHZ, MC0upmode
       TBCCTL0 = CCIE;                         //允许定时器中断
       TBCCR0 = 745;                       //定时时间
}
       
/**********************************************************************************
把ADC的读数转换为液晶能够显示形式
**********************************************************************************/
void AdcConvert(unsigned char *Numeral,unsigned int result)
{
  unsigned int Figure[4],Figure1[4],result1;
  unsigned long long value;
  result1=result;
  value=result;
  value=value*25000;   //result=result*25000/4095
  value=value/4095;
  result=value;
  for(unsigned char m=0;m<4;m  )  //Figure=[0,0,0,0]
  {
    Figure[m]=0;
  }
  for(unsigned char n=0;n<4;n  )  //Figure1=[0,0,0,0]
  {
    Figure1[n]=0;
  }
  for(unsigned char i=5;i>0;i--)
  {
    Figure[i-1] =result%10;
    result=result/10;
  }
   for(unsigned char j=4;j>0;j--)
  {
    Figure1[j-1] =result1%10;
    result1=result1/10;
  }
  *Numeral=Figure[0] 48;
  Numeral  ;
  *Numeral='.';
  Numeral  ;
  for(unsigned char k=1;k<5;k  )
  {
    *Numeral =Figure[k];
    *Numeral  ='0';
    Numeral  ;
  } 
  *Numeral='(';
  Numeral  ;
  *Numeral='V';
  Numeral  ;
  *Numeral=')';
  Numeral  =2;
  for(unsigned char l=0;l<4;l  )
  {
    *Numeral =Figure1[l];
    *Numeral  ='0';
    Numeral  ;
  } 
}


/****************************************************
排序算法,对tab_mod[](频谱功率)中的数据进行从大到小的排序
***************************************************/
void sort(float* mod,unsigned int* count_in)
{
	float temp;
	for(unsigned int i=0;i<num_point/2;i  )
		for(unsigned int j=i;j<num_point/2;j  )
		{
			if(mod[i]<mod[j])
			{
				temp=mod[i];
				mod[i]=mod[j];
				mod[j]=temp;
                                temp=count_in[i];
                                count_in[i]=count_in[j];
                                count_in[j]=(unsigned int)temp;
			}
		}
}

/////////////////////////////////////////////////////////////
void display(float result[num_point])
{
  float result_max=0;
  unsigned char count_y;
  for(unsigned char m=1;m<61;m  )   //绘坐标 y轴
  {
    GUI_Point(18,m); 
  if(m%5==0)
    GUI_Point(19,m);
  }
  for(unsigned char n=18;n<num_point-6;n  )  //X轴
  { GUI_Point(n,60); 
  if((n-18)%10==0)
    GUI_Point(n,61);}
  GUI_Point(17,2);
  GUI_Point(19,2);
  GUI_Point(120,59);
  GUI_Point(120,61);
 for(unsigned char k=1;k<num_point;k  ) //绘频谱
    if(result_max<result[k])
      result_max=result[k];
  for(unsigned char i=1;i<num_point/2 10;i  )
  {
    count_y=(unsigned char)((result[i]*50)/result_max);
             for(unsigned char j=59;j>59-count_y;j--)
              GUI_Point(i 18,j); 
  } 
  

 

}