1.下载完毕后进行安装,这里我甩出一个下载链接。
2.接收协议。
3.安装路径,我这里喜欢选择D盘。
4.安装完毕后,有一些需要的库和参考Demo文件。
5. STM32F1移植ST 的DSP官方库
在STMF1上移植ST 的FFT官方库运行一下看一下效果,然而STM32F103毕竟不是STM32F4系列的处理器,对于一般的FFT运算程序还是比较缓慢的。官方提供了针对FFT的官方库,下载移植体验一下,下载完毕后,主要有四个文件:
cr4_fft_256_stm32.s: Cortex-M3的256点基4复FFT优化。 cr4_fft_1024_stm32.s:Cortex-M3的1024点基4复FFT优化。 stm32_dsp.h: 头文件包含DSP函数的原型。 table_fft.h: 包含FFT计算所需的系数 |
在正点原子的基础工程上进行移植DSP库,一共就4个文件,不难办吧。移植后的效果如下:
添加头文件路径如下:
在主函数main.c中直接调用stm32_dsp.h 会报错,提示不能打开stm32f1xx_hal.h,看来dsp库使用的是HAL库,这里我们把它改为标准库就不会报错啦!
注释 #include "stm32f1xx_hal.h" 引用#include "stm32f10x.h",再次编译就没有错误啦!
1.提供STM32 单片机调用的FFT变换的64点、256点、2048点的函数如下:
/* Radix-4 complex FFT for STM32, in assembly */ /* 64 points*/ void cr4_fft_64_stm32(void *pssOUT, void *pssIN, u16 Nbin); /* 256 points */ void cr4_fft_256_stm32(void *pssOUT, void *pssIN, u16 Nbin); /* 1024 points */ void cr4_fft_1024_stm32(void *pssOUT, void *pssIN, u16 Nbin); |
pssIN:是输入采样的样本。
pssOUT:调用官方函数后,输出的傅里叶序列。
Nbin:样本的数量(采了多少个点)。
为什么是64、256、1024这个3个值?因为官方使用的是基4蝶形算法,简单理解要使用官方fft库函数,必须遵循采样点数Nbin,是4的n次方。
2.提供了16位的IIR滤波器和FIR滤波器函数,具体如下:
/* FIR 16-bit filter in assembly */ void fir_16by16_stm32(void *y, void *x, COEFS *c, u32 N); /* IIR filter in assembly */ void iirarma_stm32(void *y, void *x, u16 *h2, u16 *h1, u32 ny ); /* IIR filter in C */ void iir_biquad_stm32(u16 *y, u16 *x, s16 *IIRCoeff, u16 ny); |
3.此外还提供了一些PID相关的,这里暂且不深究
/* PID controller in C, error computed outside the function */ u16 DoPID(u16 Error, u16 *Coeff); /* Full PID in C, error computed inside the function */ u16 DoFullPID(u16 In, u16 Ref, u16 *Coeff); /* PID controller in assembly, error computed outside the function */ u16 PID_stm32(u16 Error, u16 *Coeff); |
4.傅里叶变换后,输出了个啥,咋用?我们需要有个基础知识,傅里叶变换的目的:求取幅频特性/相频特性,fft变换后,输出的是一个傅里叶序列(怎么用?)。傅里叶序列本身,不是我们能够肉眼分析的东西,我们还需要对傅里叶序列进行计算,求取幅频特性/相频特性序列。通过串口打印输出的方式先测试一下64点、256点、2048点的FFT函数。
3.1添加串口驱动,对于正点原子的工程,在system文件夹中已经加入串口1的驱动,直接就可以使用串口1。
3.2对串口进行初始化,保证串口可用。
int main(void) { delay_init(); //延时函数初始化 LED_Init(); //初始化与LED连接的硬件接口 uart_init(9600); //初始化串口 9600波特率 printf("这是一个FFT 测试实验\r\n"); while(1) { LED0=0; LED1=1; delay_ms(300); //延时300ms LED0=1; LED1=0; delay_ms(300); //延时300ms } } |
3.3添加测试数据集,验证256点的FFT函数,填充输入数组
//填入数组 void InitBufInArray() { unsigned short i; float fx; for(i=0; i { fx = 1500 * sin(PI2 * i * 350.0 / Fs) + 2700 * sin(PI2 * i * 8400.0 / Fs) + 4000 * sin(PI2 * i * 18725.0 / Fs); FFT_256PointIn[i] = ((signed short)fx) << 16; } } |
3.4计算各次谐波幅值,先将lBufOutArray分解成实部(X)和虚部(Y),然后计算幅值(sqrt(X*X+Y*Y)。
void GetPowerMag() { signed short lX,lY; float X,Y,Mag; unsigned short i; for(i=0; i { lX = (FFT_256PointOut[i] << 16) >> 16; lY = (FFT_256PointOut[i] >> 16); X = N * ((float)lX) / 32768; Y = N * ((float)lY) / 32768; Mag = sqrt(X * X + Y * Y) / N; if(i == 0) lBufMagArray[i] = (unsigned long)(Mag * 32768); else lBufMagArray[i] = (unsigned long)(Mag * 65536); printf("%d ",i); printf("%d ",F*i); printf("%d ",lBufMagArray[i]); printf("%d ",lX); printf("%d \r\n",lY); } } |
3.5主函数测试,先填充输入数组再做fft256点运算,最后求出赋值,打印测试。
int main(void) { delay_init(); //延时函数初始化 LED_Init(); //初始化与LED连接的硬件接口 uart_init(9600); //初始化串口 9600波特率 printf("这是一个FFT 测试实验\r\n"); InitBufInArray(); cr4_fft_256_stm32(FFT_256PointOut, FFT_256PointIn,N); printf("点数 频率 幅值 实部 虚部\n"); GetPowerMag();
while(1) { LED0=0; LED1=1; delay_ms(300); //延时300ms LED0=1; LED1=0; delay_ms(300); //延时300ms } } |
3.6串口测试界面如下:
点数 频率 幅值 实部 虚部 0 0 4 0 -4 1 175 14 -6 -4 2 350 1500 -380 647 3 525 11 -5 -3 4 700 10 -4 -3 5 875 8 -4 -2 6 1050 8 -4 -1 7 1225 6 -3 0 8 1400 8 -3 -3 9 1575 8 -4 -1 10 1750 8 -4 -1 11 1925 8 -4 0 12 2100 5 -2 -2 13 2275 6 -3 -1 14 2450 8 -3 -3 15 2625 7 -3 -2 16 2800 5 -2 -2 17 2975 6 -3 -1 18 3150 6 -3 0 19 3325 6 -3 0 20 3500 6 -3 -1 21 3675 6 -3 0 22 3850 6 -3 0 23 4025 2 -1 0 24 4200 6 -3 -1 25 4375 6 -3 0 26 4550 4 -2 0 27 4725 4 -2 0 28 4900 2 -1 -1 29 5075 4 -2 0 30 5250 2 -1 0 31 5425 4 -2 0 32 5600 2 -1 0 33 5775 6 -3 -1 34 5950 6 -3 0 35 6125 6 -3 -1 36 6300 4 -2 -1 37 6475 6 -3 0 38 6650 4 -2 0 39 6825 6 -3 0 40 7000 5 -2 -2 41 7175 6 -3 0 42 7350 2 0 -1 43 7525 6 -3 0 44 7700 2 -1 -1 45 7875 4 -2 0 46 8050 6 -3 -1 47 8225 2 -1 0 48 8400 2704 -676 -1171 49 8575 4 -2 0 50 8750 2 -1 0 51 8925 4 -2 -1 52 9100 2 -1 -1 53 9275 4 -2 0 54 9450 2 -1 0 55 9625 2 -1 -1 56 9800 2 -1 -1 57 9975 4 -2 0 58 10150 2 0 -1 59 10325 4 -2 0 60 10500 2 -1 -1 61 10675 2 -1 -1 62 10850 4 -2 -1 63 11025 2 -1 -1 64 11200 0 0 0 65 11375 2 -1 0 66 11550 4 -2 0 67 11725 2 0 -1 68 11900 2 -1 -1 69 12075 2 -1 1 70 12250 2 -1 1 71 12425 4 -2 1 72 12600 4 -2 -1 73 12775 2 -1 1 74 12950 2 -1 -1 75 13125 4 -2 1 76 13300 2 -1 -1 77 13475 4 -2 1 78 13650 2 -1 -1 79 13825 4 -2 0 80 14000 2 -1 0 81 14175 4 -2 0 82 14350 4 -2 1 83 14525 4 -2 1 84 14700 2 -1 0 85 14875 2 -1 1 86 15050 4 -2 0 87 15225 4 -2 0 88 15400 2 -1 -1 89 15575 4 -2 1 90 15750 2 -1 1 91 15925 2 -1 1 92 16100 0 0 0 93 16275 4 -2 1 94 16450 2 -1 1 95 16625 4 -2 1 96 16800 2 -1 0 97 16975 4 -2 0 98 17150 4 -2 1 99 17325 4 -2 0 100 17500 2 -1 0 101 17675 4 -2 0 102 17850 2 -1 0 103 18025 4 -2 0 104 18200 4 -2 -1 105 18375 4 -2 1 106 18550 2 -1 -1 107 18725 3996 1998 1 108 18900 2 -1 0 109 19075 2 -1 1 110 19250 4 -2 0 111 19425 4 -2 1 112 19600 2 -1 0 113 19775 2 -1 1 114 19950 2 -1 1 115 20125 4 -2 1 116 20300 0 0 0 117 20475 4 -2 1 118 20650 2 -1 1 119 20825 2 0 1 120 21000 2 -1 0 121 21175 2 -1 1 122 21350 2 -1 0 123 21525 4 -1 2 124 21700 2 -1 0 125 21875 2 0 1 126 22050 2 -1 0 127 22225 2 0 1 |
由以上的实验数据,我们可以看出,在频率为350Hz,8400Hz和18725Hz时,幅值出现峰值,分别为1500、2696和3996,这与我们所预期的结果正好相符,从而验证了实验结果的正确性。