MSP430F5529 FFT(ADC+DMA)

前言:

电赛期间因题目需要,需要FFT算法,但430的资料太少,加上数据与信号处理未学,相关资料仅有stm32、DSP、FPGA等,虽然最后结果并不理想,但有所学。

代码资料如下,有需自取:

涉及FFT变换,相位差计算:

双通道ADC:P6.0,P6.1

#include <msp430.h>

#include <stdint.h>

#include <stdlib.h>

#include <math.h>

int data_buf0[128];

int data_buf1[128];

#include<math.h>

#define PI 3.14159265   //定义圆周率值

struct compx {float real,imag;};                        //定义一个复数结构struct compx s[128];

struct compx s1[128];

struct compx s[128];                                  //FFT输入和输出:从S[1]开始存放,根据大小自己定义

float result[128],result1[128];

int phase=0,phase1=0;

float phase_dif[20],phase_dif_aver,phase_plus;

unsigned char flag_phase=0;

unsigned int j=0;

float d;

struct compx EE(struct compx a,struct compx b)

{

    struct compx c;

    c.real=a.real*b.real-a.imag*b.imag;

    c.imag=a.real*b.imag+a.imag*b.real;

return(c);

}

void FFT(struct compx *xin)

{

    int f,m,nv2,nm1,i,k,l,j=0;

    struct compx u,w,t;

    nv2=128/2;

    //变址运算,即把自然顺序变成倒位序,采用雷德算法

    nm1=128-1;

    for(i=0;i<nm1;i++)

    {

        if(i<j) //如果i<j,即进行变址

        {

            t=xin[j];

            xin[j]=xin[i];

            xin[i]=t;

        }

        k=nv2;

        //求j的下一个倒位序

        while(k<=j) //如果k<=j,表示j的最高位为1

        {

            j=j-k; //把最高位变成0

            k=k/2; //k/2,比较次高位,依次类推,逐个比较,直到某个位为0

        }

        j=j+k; //把0改为1

    }

    {

        int le,lei,ip;//FFT运算核,使用蝶形运算完成FFT运算

        f=128;

        for(l=1;(f=f/2)!=1;l++) ;//计算l的值,即计算蝶形级数

            for(m=1;m<=l;m++) // 控制蝶形结级数

            {

                                    //m表示第m级蝶形,l为蝶形级总数l=log(2)N

                le=2<<(m-1);         //le蝶形结距离,即第m级蝶形的蝶形结相距le点

                lei=le/2; //同一蝶形结中参加运算的两点的距离

                u.real=1.0; //u为蝶形结运算系数,初始值为1

                u.imag=0.0;

                w.real=cos(PI/lei); //w为系数商,即当前系数与前一个系数的商

                w.imag=-sin(PI/lei);

                for(j=0;j<=lei-1;j++) //控制计算不同种蝶形结,即计算系数不同的蝶形结

                {

                    for(i=j;i<=128-1;i=i+le) //控制同一蝶形结运算,即计算系数相同蝶形结

                    {

                        ip=i+lei; //i,ip分别表示参加蝶形运算的两个节点

                        t=EE(xin[ip],u); //蝶形运算,详见公式

                        xin[ip].real=xin[i].real-t.real;

                        xin[ip].imag=xin[i].imag-t.imag;

                        xin[i].real=xin[i].real+t.real;

                        xin[i].imag=xin[i].imag+t.imag;

                    }

                    u=EE(u,w); //改变系数,进行下一个蝶形运算

                }

            }

    }

}

void upVcc(void)//核心电压上升

{

    PMMCTL0_H = 0xA5;

    SVSMLCTL |= SVSMLRRL_1 + SVMLE;

    PMMCTL0 = PMMPW +PMMCOREV_3;

    while((PMMIFG & SVSMLDLYIFG)==0);

    PMMIFG &=~ (SVMLVLRIFG + SVMLIFG + SVSMLDLYIFG);

    if((PMMIFG & SVMLIFG)==1)

        while((PMMIFG & SVMLVLRIFG)==0);

    SVSMLCTL &=~ SVMLE;

    PMMCTL0_H = 0x00;

}

void timerup(void)//配置时钟25MHZ

{

UCSCTL3 = SELREF_2;

UCSCTL4 |= SELA_2;

__bis_SR_register(SCG0);

UCSCTL0 = 0x0000;

UCSCTL1 = DCORSEL_7;//50Mhz范围

UCSCTL2 = FLLD_0 + 762;    //(762+1)*32768==25MHZ

__bic_SR_register(SCG0);

__delay_cycles(782000);

while(SFRIFG1 & OFIFG)

{

    UCSCTL7 &=~ (XT2OFFG + XT1LFOFFG + DCOFFG);

    SFRIFG1 &=~ OFIFG;

}

//UCSCTL4 = UCSCTL4&(~(SELS_7|SELM_7))|SELS_3|SELM_3;

}

void clock_init()

{

    P5SEL |= BIT2|BIT3; //将IO配置为XT2功能

    UCSCTL6 &= ~XT2OFF; //使能XT2

    UCSCTL4 = UCSCTL4&(~(SELA_7))|SELA_1; //先将ACLK配置为VLOCLK

    UCSCTL3 |= SELREF_2;                  //将REFCLK配置为REFCLK

    while (SFRIFG1 & OFIFG){

      UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);         // 清除三类时钟标志位

                                // 这里需要清除三种标志位,因为任何一种

                                // 标志位都会将OFIFG置位

      SFRIFG1 &= ~OFIFG;                                  // 清除时钟错误标志位

    }

    UCSCTL4 = UCSCTL4&(~(SELS_7))|SELS_5;     //将SMCLK时钟源配置为XT2

}

// 冒泡法排序函数

void BubbleSort(float pt[], int Cnt)

{

    int     k      = 0;

        float temp = 0;

    while (Cnt > 0)

    {

        for (k=0; k<Cnt-1; k++)

        {

            if (pt[k] < pt[k+1])

            {

                temp    = pt[k];

                pt[k]   = pt[k+1];

                pt[k+1] = temp;

            }

        }

        Cnt--;

    }

}

/**

 * main.c

 */

int main(void)

{

    unsigned int i;

    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer

    upVcc();

    timerup();

    clock_init();

    P5SEL |= BIT7;              // P5.7/TB1 option select

    P5DIR |= BIT7;              // Output direction

    P6SEL |= 0x03;              // Enable A/D channel A0 A1

    //Setup Timer B0

    TBCCR0 = 128;

    TBCCR1 = 64;

    TBCCTL1 = OUTMOD_3;                       // CCR1 set/reset mode

    TBEX0 = TBIDEX_0;                         //CLK/1 divide

    TBCTL = TBSSEL_1+MC_1+TBCLR + ID_0;       // SMCLK, Up-Mode

    // Setup ADC12

    ADC12CTL0 = ADC12ON+ADC12MSC+ADC12SHT0_8;   // Turn on ADC12, extend sampling time

                                                // to avoid overflow of results

    ADC12CTL1 = ADC12SHS_3+ADC12CONSEQ_3;       // Use sampling timer, repeated sequence

    ADC12MCTL0 = ADC12INCH_0;                  // ref+=AVcc, channel = A0

    ADC12MCTL1 = ADC12INCH_1 + ADC12EOS;       // ref+=AVcc, channel = A1

    ADC12CTL0 |= ADC12ENC;                    // Enable conversions

    // Setup DMA COMMON

    DMACTL0 = DMA0TSEL_24 + DMA1TSEL_24;      // ADC12IFGx triggered

    DMACTL4 = DMARMWDIS;                      // Read-modify-write disable

    // Setup DMA0

    DMA0CTL &= ~DMAIFG;

    DMA0CTL = DMADT_4+DMAEN+DMADSTINCR_3;     // Rpt single tranfer, Destination address is incremented.

    DMA0SZ = 128;        // DMA0 size = 100

    __data20_write_long((uintptr_t) &DMA0SA,(uintptr_t) &ADC12MEM0); // Source block address

    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &data_buf0[0]);

    // Setup DMA1

    DMA1CTL &= ~DMAIFG;

    DMA1CTL = DMADT_4+DMAEN+DMADSTINCR_3; // Rpt single tranfer, Destination address is incremented.

    DMA1SZ = 128;       // DMA0 size = 100

    __data20_write_long((uintptr_t) &DMA1SA,(uintptr_t) &ADC12MEM1); // Source block address

    __data20_write_long((uintptr_t) &DMA1DA,(uintptr_t) &data_buf1[0]);

    while(data_buf0[127]==0 | data_buf1[127]==0);

    //float acosx=acos((s[1].real*s1[1].real+s[1].imag*s1[1].imag)/(s[1].real*s[1].real));

    while (1) {

        for(i=0;i<128;i++)

        {

            s[i].real=data_buf0[i];

            s[i].imag=0;

        }

        FFT(s);  //进行快速福利叶变换

        for(i=0;i<128;i++) //求变换后结果的模值,存入复数的实部部分

            if(i==0)

            result[0]=sqrt(s[i].real*s[i].real+s[i].imag*s[i].imag)/128;//幅值

            else

                result[i]=sqrt(s[i].real*s[i].real+s[i].imag*s[i].imag)*2/128;

        for(i=0;i<128;i++)

        {

            s1[i].real=data_buf0[i];

            s1[i].imag=0;

        }

        FFT(s1);  //进行快速福利叶变换

        for(i=0;i<128;i++) //求变换后结果的模值,存入复数的实部部分

            if(i==0)

            result1[0]=sqrt(s1[i].real*s1[i].real+s1[i].imag*s1[i].imag)/128;//幅值

            else

                result1[i]=sqrt(s1[i].real*s1[i].real+s1[i].imag*s1[i].imag)*2/128;

    /**************以下是相位差部分*************/

        for(i=0;i<128;i++)

        {

            if(data_buf0[i]>1638-100 && data_buf0[i]<1638+100) {

                    phase=i;

                    flag_phase=1;

            }

            if(data_buf1[i]>1638-100 && data_buf1[i]<1638+100) {

                phase1=i;

                if(abs(phase1-phase)<=64) {

                    //phase_dif[j]=(90-(abs(phase1-phase))/128.0*360);

                    phase_plus+=((abs(phase1-phase))/128.0*360-34.475);//10->44.29,40->15.6--默认0--->55°,40--->15.6°

                    j++;

                    if(j==20){ phase_dif_aver=phase_plus/j;j=0;phase_plus=0;d=tan(phase_dif_aver);}//相位差平均值

                }

            }

        }

    }

}


 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值