搜索
bottom↓
楼主: elefan

看看日本人做的音频FFT分析器,有LCD显示[包含原代码]

  [复制链接]

出0入0汤圆

发表于 2010-5-18 21:24:27 | 显示全部楼层
我编写了一个,程序框架和http://elm-chan.org/works/akilcd/report_e.html 提供一样,实现部分也是用汇编语言编写。不过我的FFT只转换128或者64点。原因是我是这样认为的,如果是256个点或者以上,对应M8,M16来说,RAM不够了,如果点数是64以下,好像又没有什么实用。
   原作者是频域抽取的,我是时域抽取的,我的FFT执行速度在128个点时候比他的快0.5MS左右,64个点时候快0.1MS。迟一段时间发些作品SHOW一下。
   我为了实现这个FFT,我已经花费很长时间了,很辛苦,当实现之后,内心很愉快,因为我终于认识什么叫FFT了!本来我想单独开贴的,但是感觉意义不大,原因是:我的程序很大程度是参考http://elm-chan.org/works/akilcd/report_e.html,只不过实现方式不同(不像有某些人,将人家的程序只改一点点,然后就拿去卖钱),当然我提供的程序注释肯定比他的详细。
程序如下:
头文件:
#ifndef FFT_N
#define FFT_N  128

#ifndef FFT_ASM
#include <avr/pgmspace.h>
//tbl_window:        tbl_window[] = ... (This is a Hamming window汉明窗数据)
unsigned int tbl_window[] PROGMEM=
{
#if FFT_N == 128
  2621, 2639, 2693, 2784, 2910, 3073, 3270, 3502, 3768, 4068, 4401, 4765, 5161, 5587, 6042, 6525,
  7036, 7571, 8132, 8715, 9320, 9945, 10588, 11249, 11926, 12616, 13318, 14031, 14753, 15482, 16216, 16954,
  17694, 18433, 19171, 19905, 20634, 21356, 22069, 22772, 23462, 24138, 24799, 25443, 26068, 26673, 27256, 27816,
  28352, 28862, 29345, 29800, 30226, 30622, 30987, 31319, 31619, 31885, 32117, 32315, 32477, 32603, 32694, 32748,
  32766, 32748, 32694, 32603, 32477, 32315, 32117, 31885, 31619, 31319, 30987, 30622, 30226, 29800, 29345, 28862,
  28352, 27816, 27256, 26673, 26068, 25443, 24799, 24138, 23462, 22772, 22069, 21356, 20634, 19905, 19171, 18433,
  17694, 16954, 16216, 15482, 14753, 14031, 13318, 12616, 11926, 11249, 10588, 9945, 9320, 8715, 8132, 7571,
  7036, 6526, 6042, 5587, 5161, 4765, 4401, 4068, 3768, 3502, 3270, 3073, 2910, 2784, 2693, 2639
#elif FFT_N==64
  2621, 2693, 2910, 3270, 3768, 4401, 5161, 6042, 7036, 8132, 9320, 10588, 11926, 13318, 14753, 16216,
  17694, 19171, 20634, 22069, 23462, 24799, 26068, 27256, 28352, 29345, 30226, 30987, 31619, 32117, 32477, 32694,
  32766, 32694, 32477, 32117, 31619, 30987, 30226, 29345, 28352, 27256, 26068, 24799, 23462, 22069, 20634, 19171,
  17694, 16216, 14753, 13318, 11926, 10588, 9320, 8132, 7036, 6042, 5161, 4401, 3768, 3270, 2910, 2693
#endif
};

//COS,SIN表格数据,注意他们是int型,每一个点需要4个字节
//tbl_cos_sin:         Table of {cos(x),sin(x)}, (0 <= x < pi, in FFT_N/2 steps)
signed int tbl_cos_sin[] PROGMEM=
{
#if FFT_N == 128
  32767, 0, 32727, 1607, 32609, 3211, 32412, 4807, 32137, 6392, 31785, 7961, 31356, 9511, 30851, 11038,
  30272, 12539, 29621, 14009, 28897, 15446, 28105, 16845, 27244, 18204, 26318, 19519, 25329, 20787, 24278, 22004,
  23169, 23169, 22004, 24278, 20787, 25329, 19519, 26318, 18204, 27244, 16845, 28105, 15446, 28897, 14009, 29621,
  12539, 30272, 11038, 30851, 9511, 31356, 7961, 31785, 6392, 32137, 4807, 32412, 3211, 32609, 1607, 32727,
  0, 32766, -1607, 32727, -3211, 32609, -4807, 32412, -6392, 32137, -7961, 31785, -9511, 31356, -11038, 30851,
  -12539, 30272, -14009, 29621, -15446, 28897, -16845, 28105, -18204, 27244, -19519, 26318, -20787, 25329, -22004, 24278,
  -23169, 23169, -24278, 22005, -25329, 20787, -26318, 19519, -27244, 18204, -28105, 16845, -28897, 15446, -29620, 14009,
  -30272, 12539, -30851, 11038, -31356, 9511, -31784, 7961, -32137, 6392, -32412, 4807, -32609, 3211, -32727, 1607
#elif FFT_N==64
  32767, 0, 32609, 3211, 32137, 6392, 31356, 9511, 30272, 12539, 28897, 15446, 27244, 18204, 25329, 20787,
  23169, 23169, 20787, 25329, 18204, 27244, 15446, 28897, 12539, 30272, 9511, 31356, 6392, 32137, 3211, 32609,
  0, 32766, -3211, 32609, -6392, 32137, -9511, 31356, -12539, 30272, -15446, 28897, -18204, 27244, -20787, 25329,
  -23169, 23169, -25329, 20787, -27244, 18204, -28897, 15446, -30272, 12539, -31356, 9511, -32137, 6392, -32609, 3211
#endif
};
//反序表,为什么要*4?因为复数数组每一个元素地址间隔是4个字节(实部和虚部都是int型)
unsigned int tbl_bitrev[] PROGMEM=
{
#if FFT_N == 128
  0*4,64*4,32*4,96*4,16*4,80*4,48*4,112*4,8*4,72*4,40*4,104*4,24*4,88*4,56*4,120*4,
  4*4,68*4,36*4,100*4,20*4,84*4,52*4,116*4,12*4,76*4,44*4,108*4,28*4,92*4,60*4,124*4,
  2*4,66*4,34*4,98*4,18*4,82*4,50*4,114*4,10*4,74*4,42*4,106*4,26*4,90*4,58*4,122*4,
  6*4,70*4,38*4,102*4,22*4,86*4,54*4,118*4,14*4,78*4,46*4,110*4,30*4,94*4,62*4,126*4,
  1*4,65*4,33*4,97*4,17*4,81*4,49*4,113*4,9*4,73*4,41*4,105*4,25*4,89*4,57*4,121*4,
  5*4,69*4,37*4,101*4,21*4,85*4,53*4,117*4,13*4,77*4,45*4,109*4,29*4,93*4,61*4,125*4,
  3*4,67*4,35*4,99*4,19*4,83*4,51*4,115*4,11*4,75*4,43*4,107*4,27*4,91*4,59*4,123*4,
  7*4,71*4,39*4,103*4,23*4,87*4,55*4,119*4,15*4,79*4,47*4,111*4,31*4,95*4,63*4,127*4
#elif FFT_N==64
  0*4,32*4,16*4,48*4,8*4,40*4,24*4,56*4,4*4,36*4,20*4,52*4,12*4,44*4,28*4,60*4,
  2*4,34*4,18*4,50*4,10*4,42*4,26*4,58*4,6*4,38*4,22*4,54*4,14*4,46*4,30*4,62*4,
  1*4,33*4,17*4,49*4,9*4,41*4,25*4,57*4,5*4,37*4,21*4,53*4,13*4,45*4,29*4,61*4,
  3*4,35*4,19*4,51*4,11*4,43*4,27*4,59*4,7*4,39*4,23*4,55*4,15*4,47*4,31*4,63*4       
#endif
};

typedef struct complex{
                        signed int real;
                                                signed int imaginary;         
                      } complex_t;
//输入是int型数组(只有实部,没有虚部),将输入乘以窗函数(如果flag=1乘以汉明窗,flag=0乘以矩形窗(乘以1))然后倒序,
//然后输出到复数数组的实部,复数数组的虚部是任意的.
extern void fft_input(signed int *source,complex_t *object,signed char flag);
extern void fft_execute(complex_t *source);
//如果是复数数组,输出是复数的(实部^2+虚部^2)的开方并且向右移动16位,结果存放在复数数组的实部里面,这样做为了省RAM
extern void fft_output(complex_t *source);

#else
.extern tbl_window,tbl_cos_sin,tbl_bitrev

;加载abs这个立即数到dh,dl
.macro        ldiw        dh,dl, abs
        ldi        \dl, lo8(\abs)
        ldi        \dh, hi8(\abs)
.endm

;dh,dl减去abs这个立即数
.macro        subiw        dh,dl, abs
        subi        \dl, lo8(\abs)
        sbci        \dh, hi8(\abs)
.endm

;将dh,dl清0
.macro        clrw        dh, dl
        clr        \dh
        clr        \dl
.endm

;两个两字节数据相加
;dh,dl是第一个两字节数据也是相加之后存放结果的寄存器
;sh,sl是第二个两字节被加数据
.macro        addw        dh,dl, sh,sl
        add        \dl, \sl
        adc        \dh, \sh
.endm

;两个四个字节数据相加
;d3,d2,d1,d0是第一个被加的4字节数据,也是返回结果的存放存储器
;s3,s2,s1,s0是第二个被加的4字节数据
.macro        addd        d3,d2,d1,d0, s3,s2,s1,s0
        add        \d0, \s0
        adc        \d1, \s1
        adc        \d2, \s2
        adc        \d3, \s3
.endm

;两个两字节数据相减
;dh,dl是第一个两字节数据也是相减之后存放结果的寄存器
;sh,sl是第二个两字节被减数据
.macro        subw        dh,dl, sh,sl
        sub        \dl, \sl
        sbc        \dh, \sh
.endm

;两个四个字节数据相减
;d3,d2,d1,d0是第一个被减的4字节数据,也是返回结果的存放存储器
;s3,s2,s1,s0是第二个被减的4字节数据
.macro        subd        d3,d2,d1,d0, s3,s2,s1,s0
        sub        \d0, \s0
        sbc        \d1, \s1
        sbc        \d2, \s2
        sbc        \d3, \s3
.endm

;从RAM中读取两个字节数据
;dh,dl存放读取RAM返回的数据
;src是要被读取数据的低字节RAM地址,但是 要求地址是:Z+0形式,则Z不会自动增加
.macro        lddw        dh,dl, src
        ldd        \dl, \src
        ldd        \dh, \src+1
.endm

;从RAM中读取两个字节数据
;dh,dl存放读取RAM返回的数据
;src是要被读取数据的低字节RAM地址,但是要求地址是Z+(或者Z+1)形式,则Z会自动增加,并且指向下一个字RAM
.macro        ldw        dh,dl, src
        ld        \dl, \src
        ld        \dh, \src
.endm

;存储两字节数据sh,sl到RAM中,要求传入RAM地址形式:dst+
.macro        stw        dst, sh,sl
        st        \dst, \sl
        st        \dst, \sh
.endm

;存储两字节数据sh,sl到RAM中,要求传入RAM地址形式:dst+0或者就是dst形式(dst数值不变,dsts只能使用Z,Y寄存器)
.macro        stdw        dst, sh,sl
        std        \dst, \sl
        std        \dst+1, \sh
.endm

;将dh,dl往右边移动一位,高位用0补充,低位移出去到CY
.macro        lsrw        dh, dl
        lsr        \dh
        ror        \dl
.endm

;将dh,dl往左边移动一位,低位用0补充,高位移出去到CY
.macro        lslw        dh, dl
        lsl        \dl
        rol        \dh
.endm

;将dh,dl往右边移动一位,但是符号位不变(即:如果是正数,用0补充最高位,最低位移出去到CY;如果是负数,最高位用1补充,最低位移出去到CY)
.macro        asrw        dh, dl
        asr        \dh
        ror        \dl
.endm

;将两个字节dh,dl压进堆栈
.macro        pushw        dh, dl
        push        \dh
        push        \dl
.endm

;将堆栈里面两字节数据弹到dh,dl
.macro        popw        dh, dl
        pop        \dl
        pop        \dh
.endm

;从flash中读取量字节数据到dl,dh中,要求传入flash地址形式是:src+
.macro        lpmw        dh,dl, src
        lpm        \dl, \src
        lpm        \dh, \src
.endm


;16位乘以8位并获取16结果,无符号相乘
;d1,d0是输出结果
;a1,a0是被乘数的高8位和低8位
;b0是一个8为的乘数

.macro MUL16to16  d1,d0,a1,a0,b0
    mul \a0,\b0      ;d1:d0=a0*b0
        movw \d0,R0     ;
        mul \a1,\b0      ;
        add \d1,R0      ;d1=lo8(a1*b0)
.endm  

;16位乘以16位并获取32结果,有符号相乘,使用该宏时候需要zero=0
;d3,d2,d1,d0是输出结果
;s1h,s1l是被乘数,其中s1h是高8位,s1l是低8位,要求:s1h,s1l必须是R16~R23的寄存器
;s2h,s2l是乘数,其中s2h是高8位,s2l是低8位,要求:s2h,s2l必须是R16~R23的寄存器

;=======================================================
.macro FMULS16to32 D3,D2,D1,D0,AH,AL,BH,BL,ZERO
    FMULS  \AH,\BH  ;两个高字节相乘
        MOVW   \D2,R0   ;将结果存放到d3,d2中

        FMUL   \AL,\BL  ;两个数的低字节相乘
        MOVW   \D0,R0   ;将结果存放到d1,d0中
        ADC    \D2,\ZERO

        FMULSU \AH,\BL    ;一个数的高字节和另外一个数的低字节相乘
        SBC    \D3,\ZERO  ;我这个不理解了
        ADD    \D1,R0
        ADC    \D2,R1
        ADC    \D3,\ZERO

        FMULSU \BH,\AL   ;一个数的高字节和另外一个数的低字节相乘
        SBC    \D3,\ZERO
        ADD    \D1,R0
        ADC    \D2,R1
        ADC    \D3,\ZERO
.endm
;=======================================================

;32位无符号数开方,得到16无符号数
;root2,root1,root0是开方后的的结果:根,其中root2对结果来说是无用的,这里是用于移位
;rem2,rem1,rem0是用于开方过程保留余数的
;rem2,rem1,rem0,s3,s2,s1,s0是被开方数据
;zero 用于加法减法过程的0常量
;one  用于加法减法过程中的1常量,要求:one 必须是R16以上的寄存器,因为用到ldi指令,如果输出参数时候one=1了,那么没有这个限制
;counter  用于开方循环次数变量,要求:counter 必须是R16以上的寄存器,因为用到ldi指令
.macro        SQRT32 root2,root1,root0,rem2,rem1,rem0,s3,s2,s1,s0,zero,one,counter
       ldi \counter,16
clear:
       sbrc \s3,7   ;如果被开方数的最高2位是00,则被开方数据左移动2位,循环变量counter减1
       rjmp done
           sbrc \s3,6
           rjmp done
           lsl \s0
           rol \s1
           rol \s2
           rol \s3
   

           lsl \s0
           rol \s1
           rol \s2
           rol \s3
           dec \counter
           brne clear
           clr \root0
           clr \root1
           rjmp quit
done:
       clr \root0
           clr \root1
           clr \root2
           clr \rem0
           clr \rem1
           clr \rem2
       clr \zero  ;0常量
       ldi \one,1   ;1常量
loop:  
       lsl \s0    ;被开方数据向左移动2位,并且移近余数最低2位内部
           rol \s1
           rol \s2
           rol \s3
          
           rol \rem0  ;余数原来数据向左移动2位,用被开方数据向左移动出来的数据补充最低2位
           rol \rem1
           rol \rem2   
                        
       lsl \s0
           rol \s1
           rol \s2
           rol \s3
          
           rol \rem0
           rol \rem1
           rol \rem2                
      
           lsl \root0  ;根向左移动1位,并且加1
           rol \root1
           rol \root2
           add \root0,\one   ;root +=1假设余数大于等于除数
           adc \root1,\zero
           adc \root2,\zero   
      
           cp  \rem0,\root0  ;比较根与余数之间的大小关系
           cpc \rem1,\root1
       cpc \rem2,\root2  ;如果rem>=root则进位标志C=0,否则为1

           brcs next         ;如果rem<root,则跳到NEXT实现root -=1
           sub \rem0,\root0  ;rem>root的情况 rem=rem-root,并且root +=1
           sbc \rem1,\root1
           sbc \rem2,\root2

           add \root0,\one
           adc \root1,\zero
           adc \root2,\zero
           rjmp next1
next:                   ;rem<root的情况 rem不变,root -=1(假设不成立情况)
       sub \root0,\one
           sbc \root1,\zero
           sbc \root2,\zero
next1:
       dec \counter
           brne loop   ;循环次数减1,如果counter!=0则循环
          
           lsr \root2  ;将平方根返回,root需要往右边移动1位
           ror \root1
           ror \root0
quit:              ;被开方数据=0情况
.endm

#endif        /* FFT_ASM */
#endif        /* FFT_N */
//====================================================================================================
实现部分:
#define FFT_ASM
#include "fft_h.h"

#if FFT_N == 128
#define FFT_B 7
#elif FFT_N == 64
#define FFT_B 6
#else
#error Wrong setting of FFT_N.
#endif
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;16位定点FFT在CPU=M8,F=16MHz情况下需要的时间表:
;
;点数                fft_input                fft_execute                        fft_output                总共花费时间
;
;64                        216.56us                1943.06us                        1058.19us                3217.81us(3.3ms)
;128                428.56us                4463.81us                        1967.31us                6859.69us(6.9ms)
;
;注:如果输出数据绝对值越大,则fft_out需要时间会增加,增加量大概是100~200us之间
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.section .text
;=================================================================================================
;注意:R2~R17,R28~R29不是任意使用的,使用前需要保存,退出程序之前需要恢复
;任意使用寄存器:R0,R18~R27和R30~R31
;R1:在程序退出前,必须要清0

;输入参数:R25 R24 R23 R22 R20
;其中:
;R25 R24是int *source的source指针值,也是数组的首地址
;R23 R22是Complex_t *object的object指针值,也是数组的首地址
;R20 是char flag的flag的值
;输出参数:无

;寄存器使用说明
;R31,R30(Z寄存器)指向tbl_bitrev表
;R29,R28(Y寄存器)指向输出复数数组首地址
;R27,R26(X寄存器)指向输入数组首地址(注意:使用前需要保存该寄存器,退出程序后需要恢复)
;R1,R0用于乘法,存放单字节乘法结果(注意:退出程序后需要将R1清0)
;R25,R24,R23,R22用于使用宏MULS16to32的输出结果
;R21,R20用于使用宏MULS16to32的第一个乘数,就是从RAM读取出来的数据
;R19,R18用于使用宏MULS16to32的第二个乘数,就是窗函数数据

;R17用于存放循环变量(注意:使用前需要保存该寄存器,退出程序后需要恢复)
;R16用于乘法宏的0寄存器(注意:使用前需要保存该寄存器,退出程序后需要恢复)

;R15用于存放从反序表读取出来的数据(注意:使用前需要保存该寄存器,退出程序后需要恢复)
;R14用于存放从反序表读取出来的数据(注意:使用前需要保存该寄存器,退出程序后需要恢复)

;R13,R12用于存放输出复数数组首地址(注意:使用前需要保存该寄存器,退出程序后需要恢复),固定不变
;R11:R10保存反序表的第n个数据地址(注意:使用前需要保存该寄存器,退出程序后需要恢复)
;R9:R8保存汉明窗表的第n个数据地址(注意:使用前需要保存该寄存器,退出程序后需要恢复)

.global fft_input
fft_input:
    PUSHW R29,R28
        PUSHW R17,16
        PUSHW R15,R14
        PUSHW R13,R12
        PUSHW R11,R10
        PUSHW R9,R8
       
        LDI R17,FFT_N
        CLR R16

    MOVW R12,R22 ;MOVW R13:R12,R23:R22      ;R13,R12用于保存输出复数数组首地址,固定不变
        MOVW R26,R24 ;MOVW R27:R26,R25:R24      ;X指针指向输入数组
    ldiw R31,R30,tbl_bitrev   ;Z指针指向反序表

    CP R20,R16
        BRNE HANMING   ;如果flag!=0表示需要乘以汉明窗,同时释放R20
;矩形窗情况
IN_LOOP1:
    ldw R21,R20,X+  ;从RAM中读取2字节数据到R21:R20,X指向下一个数据(X++,X++,因为是int型数据)
    lpmw R15,R14,Z+      ;从反序表中读取一个数据到R15:R14,Z++
    MOVW R28,R12    ;Y指向输出复数数组首地址
    addw R29,R28,R15,R14           ;Y等于输出数组首地址+反序表查找出来的数据
    stw Y+,R21,R20  ;将从RAM读取出来的数据,根据反序表存放到输出复数数组里面的实部
        ;stw Y+,R16,R16  ;虚部=0
        stw Y+,R21,R20
    DEC R17
        BRNE IN_LOOP1   
        RJMP IN_EXIT

;汉明窗情况
HANMING:
    ;MOVW R11:R10,R31:R30
        MOVW R10,R30              ;R11:R10保存反序表的第n个数据地址,n=0开始
    ldiw R31,R30,tbl_window
    ;MOVW R9:R8,R31:R30
        MOVW R8,R30               ;R9:R8保存汉明窗表的第n个数据地址,n=0开始

IN_LOOP2:
    ldw R21,R20,X+     ;从RAM中读取2字节数据到R21:R20,X指向下一个数据(X++,X++,因为是int型数据)

        MOVW R30,R8        ;MOVW R31:R30,R9:R8 ;从汉明窗数据表中读取两个字节数据到R19,R18中
    lpmw R19,R18,Z+   
        MOVW R8,R30        ;MOVW R9:R8,R31:R30 ;将Z保存到R9:R8中

    FMULS16to32 R25,R24,R23,R22,R21,R20,R19,R18,R16  ;R25:R25是输入数据*窗数据的高16位,R16=0

    MOVW R30,R10 ;MOVW R31:R30,R11:R10  ;从反序表中读取一个字数据到R15:R14,Z++
    lpmw R15,R14,Z+   
        MOVW R10,R30 ;MOVW R11:R10,R31:R30  ;将Z保存到R11:R10中

    MOVW R28,R12    ;Y指向输出复数数组首地址   
    addw R29,R28,R15,R14           ;Y等于输出数组首地址+反序表查找出来的数据
    stw Y+,R25,R24  ;将从RAM读取出来的数据乘以窗数据(只取最高16位相当于结果右移16位),根据反序表存放到输出复数数组里面的实部
        ;stw Y+,R16,R16  ;虚部=0
    stw Y+,R25,R24

    DEC R17
    BRNE IN_LOOP2
             
IN_EXIT:
    POPW R9,R8
        POPW R11,R10
    POPW R13,R12
    POPW R15,R14
        POPW R17,R16
        POPW R29,R28   
        CLR R1
        RET

;=================================================================================================
;注意:R2~R17,R28~R29不是任意使用的,使用前需要保存,退出程序之前需要恢复
;任意使用寄存器:R0,R18~R27和R30~R31
;R1:在程序退出前,必须要清0

;输入参数:R25 R24
;R25 R24是Complex_t *source的source指针值,也是数组的首地址
;输出参数:无

;寄存器使用说明
;R31 R30(Z)指向tbl_cos_sin[],和指向蝶形左上角的数据
;R29 R28(Y)指向蝶形左下角的数据
;R27 R26(X)临时变量(主要存放复数相乘的实部,以及调整Z,Y所需要)

;R25 R24存放输入复数数组首地址(固定不变)

;R23 R22存放COS(在第三层循环体内固定不变)
;R21 R20存放SIN(在第三层循环体内固定不变)
;R19 R18存放蝶形左上,下角数据的实部Yr
;R17 R16存放蝶形左上,下角数据的虚部Yi

;R15 R14 R13 R12存放蝶形左下角数据实部*COS   或者,存放蝶形左下角数据实部*SIN,还用于临时变量,如R15:R14存放复数相乘的虚部
;R11 R10 R9 R8  存放蝶形做左下角数据虚部*SIN 或者,存放蝶形左下角数据实部*COS,还用于临时变量(备份蝶形左上角的实部和虚部)
;R7 记录蝶形阶数(还用于乘法运算宏的零寄存器)
;R6 记录每阶蝶形的蝶形组数
;R5 记录每组蝶形的蝶形个数
;R4 记录旋转因子WnK的系数K
;R3 用于第二层循环,记录循环次数
;R2 用于第三层循环,记录循环次数
;
;时域抽取基2快速FFT
.global fft_execute
fft_execute:
    PUSHW R3,R2
        PUSHW R5,R4
        PUSHW R7,R6
        PUSHW R9,R8
        PUSHW R11,R10
        PUSHW R13,R12
        PUSHW R15,R14
        PUSHW R17,R16
        PUSHW R29,R28

    LDI   R31,FFT_N
        MOV   R6,R31     ;R6记录每阶蝶形的蝶形组数

        CLR   R5
        INC   R5         ;R5记录每组蝶形的蝶形个数,第一阶蝶形运算,每组蝶形的蝶形个数是1,然后是2,4,8,16....(在第二层循环结束后更新)

        LDI   R31,FFT_B
        MOV   R7,R31     ;R7记录蝶形运算的阶数,从FFT_B开始
EXE_LOOP1:           ;第一层循环,循环次数是蝶形运算的阶数(FFT_B)
    PUSH  R7         ;R7还用于乘法宏的0寄存器,所以将它压进堆栈保存,需要使用时候再弹出来使用
        CLR   R7         ;用于乘法宏的0寄存器
    LSR   R6         ;每阶蝶形运算的蝶形组数,从FFT_N/2开始,然后是FFT_N/4,FFT_N/8,FFT_N/16.....
    CLR   R4         ;蝶形运算的旋转因子系数K,每阶开始的K总是从0开始,在同组蝶形里面,下一个蝶形K和本蝶形K差别是本阶蝶形运算的蝶形组数

        CLR   R3         ;第二层循环的循环次数,从0开始,每循环一次就加1,等于每组蝶形的蝶形个数(R5)时候结束
EXE_LOOP2:
;第二层循环开始任务是:
;1.根据旋转因子系数K在tbl_cos_sin表里面找出对应的COS,SIN加载到R23:R22和R21:R20,并调整K(K=K+蝶形组数R6)
;2.使得X指向蝶形左上角的数据,Y指向蝶形左下角数据
    MOV   R12,R4
        CLR   R13
    lslw  R13,R12
        lslw  R13,R12   ;R13:R12=K*4

        ldiw  R31,R30,tbl_cos_sin
    addw  R31,R30,R13,R12   ;Z指向tbl_cos_sin[k]元素的地址
   
        lpmw  R23,R22,Z+ ;R23:R22=COS
        lpmw  R21,R20,Z+ ;R21:R20=SIN

    ADD R4,R6        ;调整旋转因子系数K,K=K+每阶蝶形的组数

        MOV R12,R3       ;R3 用于第二层循环,记录循环次数,也表示第0蝶形组里面的第R3个蝶形左上角所对应的复数数据
        CLR R13
        lslw R13,R12
        lslw R13,R12
        MOVW R30,R24     ;Z=source首地址+R3*4,(因为每个source元素占用4字节RAM)
        addw R31,R30,R13,R12  ;Z指向输入复数数组source[R3]元素的地址

        MOV  R12,R5           ;R5 记录每组蝶形的蝶形个数
        CLR R13
        lslw R13,R12
        lslw R13,R12          ;R13:R12=R5*4,因为复数数值每个元素占用4字节RAM
        MOVW R28,R30          ;Y=Z+R5*4
        addw R29,R28,R13,R12  ;Y指向输入复数数组source[R3+每组蝶形的蝶形个数]元素的地址

        CLR R2           ;第三层循环的循环次数,从0开始,每循环一次就加1,等于当前阶蝶形运算的蝶形组数(R6)时候结束
EXE_LOOP3:           ;游历每组蝶形具有相同旋转因子系数K的蝶形
;本循环体作用是:
;读取出Y(即:source[R3+每组蝶形的蝶形个数]),实部暂存放R19:R18;虚部暂存放R17,R16(Y大小不变),实部和虚部都除以2,防止后面乘法和加减法溢出

;根据复数乘法:(A+jB)*(COS+[-jSIN])=(A*B+jB*[-jSIN])+(jB*COS+A*[-jSIN])=(A*B+B*SIN)+j(B*COS-A*SIN)
;求出 source[R3+每组蝶形的蝶形个数].real*COS + source[R3+每组蝶形的蝶形个数].imaginary*SIN,存放R19:R18(取最高16位),并且算术右移1位(相当于除以2)
;求出 source[R3+每组蝶形的蝶形个数].imaginary*COS - source[R3+每组蝶形的蝶形个数].real*SIN,存放R17:R16(取最高16位),并且算术右移1位(相当于除以2)

;读取Z(即source[R3]),并且实部和虚部都算术右移动1位,相当与除以2,但是符号不变(Z大小不变)

;求出source[R3].real+R19:R18,并存放到source[R3]实部;source[R3].imaginary+R17:R16,并存放到source[R3]虚部.(Z大小不变)
;求出source[R3].real-R19:R18,并存放到Y指向的元素实部;source[R3].imaginary-R17:R16,并存放到Y指向元素的虚部.(Y大小不变)

;调整Z,Z=Z+2*每组蝶形的蝶形个数(R5)
;调整Y,Y=Y+2*每组蝶形的蝶形个数(R5)

;读取蝶形左下角复数数据
    lddw R19,R18,Y+0   ;Y数值不会变化,R19:R18=Y指向复数元素的实部
        lddw R17,R16,Y+2   ;Y数值不会变化,R17:R16=Y指向复数元素的虚部
        asrw R19,R18       ;Y指向复数元素的实部向右边算术移动一位,相当于除以2,因为后面要进行复数乘法加减法,防止溢出
        asrw R17,R16       ;Y指向复数元素的虚部向右边算术移动一位,相当于除以2,因为后面要进行复数乘法加减法,防止溢出       

;左下角复数×旋转因子,R27:R26=左下角复数实部×旋转因子实部+左下角复数虚部×旋转因子虚部
;X(R27,R26)=Y实*COS+Y虚*SIN ,只取高16位,相当与所得结果向右边移动了16位  
    FMULS16to32 R27,R26,R13,R12,R19,R18,R23,R22,R7    ;R27 R26 R13 R12=R19 R18*R23 R22=Y实*COS ,R7是用来记录蝶形阶数的,由于压进堆栈并清0了,这里用于乘法宏的0寄存器
        FMULS16to32 R11,R10,R9,R8,R17,R16,R21,R20,R7      ;R11 R10 R9  R8= R17 R16*R21 R20=Y虚*SIN
    addd R27,R26,R13,R12,R11,R10,R9,R8               ;R27 R26 R13 R12=Y实*COS+Y虚*SIN  (结果暂存放X)只取高16位,相当与所得结果向右边移动了16位
  

;左下角复数×旋转因子,R15:R14=左下角复数虚部×旋转因子实部-左下角复数实部×旋转因子虚部
;R15 R14=Y虚*COS-Y实*SIN,只取高16位,相当与所得结果向右边移动了16位  
    FMULS16to32 R15,R14,R13,R12,R17,R16,R23,R22,R7    ;R15 R14 R13 R12=R17 R16*R23 R22=Y虚*COS
        FMULS16to32 R11,R10,R9,R8,R19,R18,R21,R20,R7      ;R11 R10 R9  R8= R19 R18*R21 R20=Y实*SIN
    subd  R15,R14,R13,R12,R11,R10,R9,R8              ;R15 R14 R13 R12=Y虚*COS-Y实*SIN
;R19:R18和R17,R16已经释放了,R27:R26,R15:R14保留着复数相乘的实部和虚部

;读取蝶形左上角复数的实部和虚部
;实部在R19,R18中
        lddw R19,R18,Z+0   ;R19 :R18 =Z指向复数元素的实部,Z数值不变  
;虚部在R17,R16中
        lddw R17,R16,Z+2   ;R17:R16=Z指向复数元素的虚部,Z数值不变  

        asrw R19,R18       ;R9 :R8=Z指向复数元素的实部/2,因为后面要进行复数加减法,防止溢出
        asrw R17,R16       ;R11:R10=Z指向复数元素的虚部/2,因为后面要进行复数加减法,防止溢出

;R8,R9,R10,R11,R12,R13现在可以任意使用
;R19:R18备份到R11:R10
;R17:R16备份到R9:R8
    MOVW R10,R18
        MOVW R8, R16

;求蝶形左上角复数+蝶形左下角复数×WnK的实部和虚部

;实部和=R19:R18+R27:R26 (R19:R18已经备份到R11:R10,为实部差做好准备)
;虚部和=R17:R16+R15:R14
    addw R19,R18,R27,R26
        addw R17,R16,R15,R14
    stdw  Z+0,R19,R18     ;保存两复数实部和到Z指向复数元素的实部中,Z不变
        stdw  Z+2,R17,R16     ;保存两复数虚部和到Z指向复数元素的虚部中,Z不变

;实部差=R11:R10-R27:R26 (在上面,R19:R18已经备份到R11:R10,为实部差做好准备)
;虚部差=R9:R8-R15:R14
    subw R11,R10,R27,R26
        subw R9,R8,R15,R14
        stdw Y+0,R11,R10    ;保存两复数实部之差到Y指向复数元素的实部中(Y数值不变)
        stdw Y+2,R9,R8      ;保存两复数虚部之差到Y指向复数元素的虚部中(Y数值不变)

;R27:R26,R15:R14,R13,R12,R11,R10,R9,R8释放了,可以任意使用

;调整Z,Z=Z+2*每组蝶形的蝶形个数(R5)
;调整Y,Y=Y+2*每组蝶形的蝶形个数(R5)
;调整Z,Y,使得他们指向下一组蝶形并且具有相同旋转因子(WnK)系数的蝶形,即:Z=Z+2*每组蝶形的蝶形个数,Y=Y+2*每组蝶形的蝶形个数
;但是每个复数元素需要占用4字节RAM,所以Z=Z+(2*每组蝶形的蝶形个数)*4,Y=Y+(2*每组蝶形的蝶形个数)*4,
;R5 记录每组蝶形的蝶形个数
        
        LDI R26,8            ;每组蝶形的蝶形个数*8,R1:R0=R5*8
        MUL R26,R5
        addw R31,R30,R1,R0   ;Z=Z+(2*每组蝶形的蝶形个数)*4=Z+每组蝶形的蝶形个数*8
    addw R29,R28,R1,R0   ;Y=Y+(2*每组蝶形的蝶形个数)*4=Y+每组蝶形的蝶形个数*8

;判断第三层循环是否结束,也是判断R2+1之后是否等于蝶形组数(R6)   
    INC R2
        CP R2,R6
    BREQ EXE_NEXT1        ;如果R2=R6则退出第三层循环体
        RJMP EXE_LOOP3
;第二层循环体后面部分,判断第二层循环体是否结束,也是判断R3+1之后是否等于当前阶蝶形任何一组蝶形的蝶形个数(R5)
EXE_NEXT1:
    INC R3
        CP R3,R5
        BREQ EXE_NEXT2
        RJMP EXE_LOOP2
;第一层循环体后面部分,判断第一层循环体是否结束,也是判断蝶形阶数R7+1之后是否等于FFT_B,由于R7已经保存到堆栈里面,所以需要
;从堆栈里面恢复.如果第一层循环没有结束,需要调整每组蝶形的蝶形个数(R5),也就是R5=R5*2
EXE_NEXT2:
    LSL R5     ;调整下一阶蝶形每组蝶形的蝶形个数
        POP R7     ;从堆栈里面恢复R7
    DEC R7
        BREQ EXE_NEXT3  ;如果R7==0则退出循环
        RJMP EXE_LOOP1  ;如果R7!=0则继续循环
EXE_NEXT3:
;-------------------------------------------------------------------------------------------------
    POPW  R29,R28
        POPW  R17,R16
        POPW  R15,R14
        POPW  R13,R12
        POPW  R11,R10
        POPW  R9,R8
        POPW  R7,R6
        POPW  R5,R4
        POPW  R3,R2
        CLR R1
    RET

;==================================================================================================
;输入输出都时同一个复数数组,运算过程是:复数数组某个元素的SQRT32(实部^2+虚部^2)->该元素的实部
;由于运算结果是中间对称的,所以只需要运算前面的FFT_N/2个元素就可以,后面的可以不理会,或者将前面的复制到后面去
;注意:R2~R17,R28~R29不是任意使用的,使用前需要保存,退出程序之前需要恢复
;任意使用寄存器:R0,R18~R27和R30~R31
;R1:在程序退出前,必须要清0

;输入参数:R25 R24
;R25 R24是Complex_t *source的source指针值,也是数组的首地址
;输出参数:无

;寄存器使用说明
;X(R27:R26)指向输入复数数组首地址,用于读取数据
;Y(R29:R28)也指向输入复数数组首地址,用于存储结果

;R23:R22存放读取复数的实部和虚部
;R21 R20 R19 R18存放实部的平方,也存放实部和虚部的平方和(也就是s3 s2 s1 s0)
;R17 R16 R15 R14存放虚部的平方
;R31存放循环次数
;R30用于开方宏总的counter

;在获得平方和之后,R17 R16 R15用于开方宏中的root2 root1 root0
;在获得平方数据之后,R24 R23 R22用于开方宏中的rem2 rem1 rem0
;R14 R25用于开方宏中的zero one所以R14=0,R25=1
;R13 用于MULS16to32宏的zero寄存器

;注意:需要保护R17 R16 R15 R14,R13在退出程序后要恢复R17 R16 R15 R14 R13以及将R1清0
.global fft_output
fft_output:
    PUSHW R29,R28
        PUSHW R17,R16
        PUSHW R15,R14
        PUSH  R13
    MOVW R26,R24  ;X指向输入复数数组首地址,用于读取数据,同时释放R25,R24
        MOVW R28,R24  ;Y指向输入复数数组首地址,用于存放数据,同时释放R25,R24
    LDI R31,FFT_N/2 ;只求数组前面一半的数据模,R31用于循环
        CLR R13
OUT_LOOP:

        ldw R23,R22,X+ ;从输入复数数组中读取实部到R23 R22中
        FMULS16to32 R17,R16,R15,R14,R23,R22,R23,R22,R13  ;求实部的平方,结果存放到R17,R16,R15,R14中

    ldw R23,R22,X+ ;从输入复数数组中读取虚部到R25 R24中,X指向下一个复数结构体的数据
    FMULS16to32 R21,R20,R19,R18,R23,R22,R23,R22,R13  ;求虚部的平方,结果存放到R21 R20 R19 R18中,R13=0

    addd  R21,R20,R19,R18,R17,R16,R15,R14  ;求实部和虚部平方之和,将结果存放在R21 R20 R19 R18

;.macro        SQRT32 root2,root1,root0,rem2,rem1,rem0,s3,s2,s1,s0,zero,one,counter
    SQRT32 R17,R16,R15,   R24,R23,R22,   R21,R20,R19,R18,   R14,R25,R30 ;实部和虚部平方之和开方,结果存放在R16 R15中
    stw Y+,R16,R15  ;将开方结果存放在输出复数数组的实部里面
    ;stw Y+,R13,R13  ;将0存放在输出复数数组的虚部里面,Y指向下一个复数结构体数据
        stw Y+,R16,R15
        DEC R31
        BREQ OUT_EXIT   ;循环FFT_N/2次,由于BREQ只能调整上下63条指令,由于AQRT32已经超出了,只能间接方法循环
        RJMP OUT_LOOP
          
OUT_EXIT:
    POP   R13
        POPW  R15,R14
        POPW  R17,R16
        POPW  R29,R28
        CLR R1
    RET
;==================================================================================================
测试:
#include <avr/io.h>
#include "fft_h.h"
typedef unsigned char uchar;
typedef unsigned int  uint;
signed int inp[]=
{
32052,
29935,
26510,
21926,
16384,
10126,
3425,
-3425,
-10126,
-16384,
-21926,
-26510,
-29935,
-32052,
-32768,
-32052,
-29935,
-26510,
-21926,
-16384,
-10126,
-3425,
3425,
10126,
16384,
21926,
26510,
29935,
32052,
32768,
32052,
29935,
26510,
21926,
16384,
10126,
3425,
-3425,
-10126,
-16384,
-21926,
-26510,
-29935,
-32052,
-32768,
-32052,
-29935,
-26510,
-21926,
-16384,
-10126,
-3425,
3425,
10126,
16384,
21926,
26510,
29935,
32052,
32768,
32052,
29935,
26510,
21926,
16384,
10126,
3425,
-3425,
-10126,
-16384,
-21926,
-26510,
-29935,
-32052,
-32768,
-32052,
-29935,
-26510,
-21926,
-16384,
-10126,
-3425,
3425,
10126,
16384,
21926,
26510,
29935,
32052,
32768,
32052,
29935,
26510,
21926,
16384,
10126,
3425,
-3425,
-10126,
-16384,
-21926,
-26510,
-29935,
-32052,
-32768,
-32052,
-29935,
-26510,
-21926,
-16384,
-10126,
-3425,
3425,
10126,
16384,
21926,
26510,
29935,
32052,
32768,
32052,
29935,
26510,
21926,
16384,
10126,
3425,
-3425
};
complex_t outp[FFT_N];
int main(void)
{
  fft_input(inp,outp,1);
  fft_execute(outp);
  fft_output(outp);

  while(1);
  return 0;
}

//==========================================================================================

我一直搞不明白FMUL MUL,我在调试过程中只是发现FMUL实现将两个数相乘之后,然后将结果往左边移动1位。但是怎样实现小数乘法呢?
我也一直搞不明白AVR201文档提供的多字节有符号乘法程序,如果谁能将AVR201文档翻译为中文就好了!

出0入0汤圆

发表于 2010-5-18 22:55:43 | 显示全部楼层
MARK FFT

出0入0汤圆

发表于 2010-5-18 23:47:29 | 显示全部楼层
回复【101楼】lzf713
-----------------------------------------------------------------------

顶,很好很强大~~~

出0入0汤圆

发表于 2010-5-19 03:29:52 | 显示全部楼层
记号~~

出0入0汤圆

发表于 2010-5-19 08:21:20 | 显示全部楼层
FFT,记号,上次见到还没有复习一下,又来了一个,答辩完抓紧时间复习看看,呵呵,谢谢

出0入0汤圆

发表于 2010-5-19 11:37:40 | 显示全部楼层
双面板市场上有卖, 那个叫贵啊..
这个线也有卖的, 我现在就在用啊, 一般在卖维修手机用品的店里有卖

出0入0汤圆

发表于 2010-5-19 22:55:38 | 显示全部楼层
顶【101楼】 lzf713

出0入264汤圆

发表于 2010-5-20 21:50:18 | 显示全部楼层
学习。

出0入0汤圆

发表于 2010-5-21 19:48:08 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-21 22:47:39 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-22 12:07:38 | 显示全部楼层
看不懂的留记号。

出0入0汤圆

发表于 2010-5-25 01:53:02 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-25 09:15:00 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-27 14:50:33 | 显示全部楼层
看我们国产的!
(原文件名:Music-Bar.jpg)

出0入0汤圆

发表于 2010-6-3 23:34:36 | 显示全部楼层
对FFT还是满有兴趣的

出0入0汤圆

发表于 2010-6-11 11:08:59 | 显示全部楼层
回复【102楼】eduhf_123 经历
-----------------------------------------------------------------------

唉,我还没有理解怎么做FFT,指点一下小弟呀,把取得的AD数据,比如说有32字节,怎么把这32个字节分成复数形式呢?也就是如何取得实部和虚部

出0入0汤圆

发表于 2010-6-11 11:22:03 | 显示全部楼层
原理图好的很漂亮。不知是什么软件?

出0入0汤圆

发表于 2010-6-12 07:53:33 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-6-12 09:43:56 | 显示全部楼层
回复【楼主位】elefan
-----------------------------------------------------------------------

实在太牛X了

出0入0汤圆

发表于 2010-6-12 19:03:26 | 显示全部楼层
实在太牛X了

出0入0汤圆

发表于 2010-6-14 11:01:52 | 显示全部楼层
学习了

出0入0汤圆

发表于 2010-6-17 11:56:39 | 显示全部楼层
他的网站是挺有意思的

出0入0汤圆

发表于 2010-6-17 12:35:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-6-17 12:37:43 | 显示全部楼层
回复【楼主位】elefan
-----------------------------------------------------------------------

dddddddddd

出0入0汤圆

发表于 2010-6-18 21:34:19 | 显示全部楼层
实在太牛x了,为什么老贴子有这么多牛贴呢。。。

出0入0汤圆

发表于 2010-6-18 22:00:45 | 显示全部楼层
再记号

出0入0汤圆

发表于 2010-6-30 14:39:17 | 显示全部楼层
MARK FFT

出0入0汤圆

发表于 2010-6-30 19:22:42 | 显示全部楼层
这个牛

出0入0汤圆

发表于 2010-10-18 21:14:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-18 23:41:03 | 显示全部楼层
只能记号了

出0入4汤圆

发表于 2010-10-19 19:43:56 | 显示全部楼层
留个爪印

出0入0汤圆

发表于 2010-10-23 18:49:05 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-10-23 23:30:48 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-10 11:05:51 | 显示全部楼层
顶!

出0入0汤圆

发表于 2010-11-10 21:27:38 | 显示全部楼层
回复【8楼】fsclub 绿林好汉
那天对mlf的cp2102飞8条线,花了超过半个小时,眼睛被松香弄得快睁不开了.
对了,我现在焊板子时,都佩戴3m的防毒面具,你们有什么防护措施吗?
-----------------------------------------------------------------------

用嘴狂吹着焊 ⊙﹏⊙b汗

出0入0汤圆

发表于 2010-11-11 09:04:27 | 显示全部楼层
nb

出0入0汤圆

发表于 2010-11-11 20:25:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-11 22:09:03 | 显示全部楼层
每次来坛子都有收获,我得花些时间来消化啊。。。。
我那个急啊。
我那个感谢啊。

出0入0汤圆

发表于 2010-11-11 22:25:45 | 显示全部楼层
网址打不开,文件下不了。

不过 lzf713 的程序我拿去学习学习

出0入0汤圆

发表于 2010-11-18 15:29:49 | 显示全部楼层
M

出0入0汤圆

发表于 2010-11-18 16:25:02 | 显示全部楼层
FFT程序,mark

出0入0汤圆

发表于 2010-11-18 16:53:32 | 显示全部楼层
还不是很理解FFT,标记回看!

出0入0汤圆

发表于 2010-11-18 19:52:44 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-8 20:25:35 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-9 09:20:22 | 显示全部楼层
牛X

出0入0汤圆

发表于 2010-12-9 10:19:09 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-9 11:54:42 | 显示全部楼层
mark  fft
最近在找如何在洞洞板上焊贴片IC,看来没有偷懒的方法,怪自己不够耐心。

出0入0汤圆

发表于 2010-12-9 11:56:57 | 显示全部楼层
回复【136楼】qilujie 福大狗
回复【8楼】fsclub 绿林好汉
那天对mlf的cp2102飞8条线,花了超过半个小时,眼睛被松香弄得快睁不开了.  
对了,我现在焊板子时,都佩戴3m的防毒面具,你们有什么防护措施吗?
-----------------------------------------------------------------------
用嘴狂吹着焊 ⊙﹏⊙b汗
-----------------------------------------------------------------------

我用电脑机箱风扇做了个排烟机,还带上口罩和防护眼镜。
最近焊多了,感觉还是要保护一下自己。

出0入0汤圆

发表于 2010-12-28 23:36:19 | 显示全部楼层
mark~~

出0入0汤圆

发表于 2010-12-29 17:22:15 | 显示全部楼层
学习

出0入0汤圆

发表于 2010-12-29 17:28:18 | 显示全部楼层
支持你,狂顶!很好 可以让我学习了

出0入0汤圆

发表于 2010-12-29 18:18:04 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-30 23:26:39 | 显示全部楼层
FFT研究很长时间了,自己用430做了个,效果还行,谢谢论坛无私奉献的大侠们!!

出0入0汤圆

发表于 2010-12-31 00:55:17 | 显示全部楼层
芯片焊得不错

出0入0汤圆

发表于 2011-3-1 16:16:00 | 显示全部楼层
佩服到五体投地...

出0入0汤圆

发表于 2011-3-3 23:12:17 | 显示全部楼层
fft日本人diy

出0入0汤圆

发表于 2011-3-4 14:40:03 | 显示全部楼层
学习一下

出0入8汤圆

发表于 2011-3-5 14:19:25 | 显示全部楼层
收藏级别资料,mark
谢谢楼主分享

出0入0汤圆

发表于 2011-3-14 14:12:17 | 显示全部楼层
这个网站貌似关闭了,非常遗憾啊

出0入0汤圆

发表于 2011-3-14 14:22:21 | 显示全部楼层
回复【161楼】hackerboygn 湘大臭要饭的
这个网站貌似关闭了,非常遗憾啊
-----------------------------------------------------------------------

你是不是这几天看的,因为震的缘故吧
我上个月还看过,好好的

出0入0汤圆

发表于 2011-3-14 14:56:35 | 显示全部楼层
mark very good~~~~~~~

出0入0汤圆

发表于 2011-3-14 15:02:59 | 显示全部楼层
学习

出0入0汤圆

发表于 2011-3-14 16:10:44 | 显示全部楼层
回复【162楼】Jigsaw
回复【161楼】hackerboygn 湘大臭要饭的
这个网站貌似关闭了,非常遗憾啊
-----------------------------------------------------------------------
你是不是这几天看的,因为震的缘故吧
我上个月还看过,好好的
-----------------------------------------------------------------------

我前个星期就上不去了,直接跳转到yahoo

出0入0汤圆

发表于 2011-3-14 17:17:57 | 显示全部楼层
感叹焊接工艺!!!
话说这个实时FFT的具体应用是什么?
之前做过基于FPGA的FFT,实时没问题,但是就是不知道有啥用。。。
知道的说一下,我看能不能把那个东东真真用起来~~

出0入0汤圆

发表于 2011-3-18 16:00:47 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-18 16:47:02 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-25 23:39:41 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-28 22:09:29 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-4 16:45:37 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-5-13 17:29:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-16 17:14:02 | 显示全部楼层
顶下更健康!!

出0入0汤圆

发表于 2011-6-16 17:28:48 | 显示全部楼层
这个很有意思,发点时间好好研究研究,

mark

出0入0汤圆

发表于 2011-6-16 19:21:36 | 显示全部楼层
学术无国界,顶一个

出0入0汤圆

发表于 2011-6-16 20:40:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-17 19:41:48 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-17 21:16:58 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-18 12:26:45 | 显示全部楼层
这个好玩,有时间玩一下,MARK

出0入0汤圆

发表于 2011-6-18 12:50:03 | 显示全部楼层
mark

出100入143汤圆

发表于 2011-6-18 12:54:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-18 13:19:15 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-24 11:01:28 | 显示全部楼层
有没有做成功啊?SG12232C好像淘宝上买不到,哪位有这个模块啊。QQ:9658570

出0入0汤圆

发表于 2011-6-27 15:11:30 | 显示全部楼层
标记一下

出0入0汤圆

发表于 2011-7-16 00:47:44 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-16 10:01:42 | 显示全部楼层
膜拜之。。。

出0入0汤圆

发表于 2011-7-16 10:03:19 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-1 23:25:44 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-16 18:02:03 | 显示全部楼层
有人做好了吗

出0入0汤圆

发表于 2011-8-16 18:52:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-17 11:25:41 | 显示全部楼层
又见飞线帝.....

出0入0汤圆

发表于 2011-8-17 13:39:26 | 显示全部楼层
学一下

出0入0汤圆

发表于 2011-8-22 11:25:59 | 显示全部楼层
现在市场上也有该散件买吗?

出0入0汤圆

发表于 2011-8-27 23:05:25 | 显示全部楼层
MARk

出0入0汤圆

发表于 2011-8-27 23:42:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-28 00:29:01 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-28 07:52:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-28 10:02:47 | 显示全部楼层
回复【1楼】fsclub  绿林好汉
-----------------------------------------------------------------------
我们需要做个开关电源,不知能能够提供个方案吗?

出0入0汤圆

发表于 2011-8-28 10:08:15 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-28 10:18:06 | 显示全部楼层
多谢楼主分享!

出0入0汤圆

发表于 2011-8-28 10:50:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-9-6 22:57:38 | 显示全部楼层
mark
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-28 18:04

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表