本帖最后由 yjmwxwx 于 2019-6-24 13:13 编辑
去年学了点数字信号处理,我数学一点看不懂,库也不会用,没办法当时写了个FFT的函数,想用ADC采样用FFT计算但是失败了,当时写的那个256点的溢出了,加上第一次接触这东西不会搞,最近一些日子又重新捡起来这阑尾工程,调试了几天终于成功了。
做了简单电路,两个STM32F030F4P6,一个产生正弦波另一个ADC采样256点用FFT计算得到这个正弦波的幅度。
0x20000000-0x20000400是实部 0x20000400-0x20000800是虚部, 取出第22个数据的实部和虚部计算出幅度用数码管显示。 由于是Q15定点数,每次保存右移了1位,结果需要乘64, 数码管显示位数有限没乘64,结果只显示了后4位没显示全。
内存里数据是对的,但是滤波器里面多右移了2位导致数码管显示的不对。。。
电路图
实物图
下图上把单片机数据输入到电脑上软件计算的,用来和单片机计算的比对,第22个实部是-156265.198,虚部是-157711.28
单片机计算的实部,第22个是0XFFFFF675,十进制2443乘64=156352。地址是0X20000058
单片机计算的虚部,第22个是0XFFFFF65F十进制是2465乘64=157760。 地址是0X20000458
结果和电脑上的差不太多,电脑上软件可能是浮点数,我这个是Q15定点数的。
ADC采集的波形,采样率1M 。
示波器波形
SPWM单片机程序
dingshiqispwm.tar.gz
(5.99 KB, 下载次数: 109)
ADC——FFT单片机程序
adcfft1.tar.gz
(28.48 KB, 下载次数: 195)
视频地址
https://v.youku.com/v_show/id_XNDI0MDcyMjcyMA==.html?spm=a2h3j.8428770.3416059.1
程序代码,有点长,查找表和初始化部分删除了,只贴关键部分
- @@单片机stm32f030f4p6
- dmachushihua:
- @+0=LSR,+4=IFCR,
- @+8=CCR1,+c=CNDTR1,+10=CPAR1+14=CMAR1,
- @+1c=CCR2,+20=CNDTR2,+24=CPAR2,+28=CMAR2
- @+30=CCR3,+34=CNDTR3,+38=CPAR2,+3c=CMAR3
- @+44=CCR4,+48=CNDTR4,+4c=CPAR4,+50=CMAR4
- @+58=CCR5,+5c=CNDTR5,+60=CPAR5,+64=CMAR5
- @+6C=CCR6,+70=CNDTR6,+74=CPAR6,+78=CMAR6
- @+80=CCR7,+84=CNDTR7,+88=CPAR7,+8c=CMAR7
- @ tim1DMA
- @ adc dma
- ldr r0, = 0x40020000
- ldr r1, = 0x40012440
- str r1, [r0, # 0x10]
- ldr r1, = dianyabiao
- str r1, [r0, # 0x14]
- ldr r1, = 256
- str r1, [r0, # 0x0c]
- ldr r1, = 0xa81
- str r1, [r0, # 0x08]
-
- _adcchushihua:
- ldr r0, = 0x40012400 @ adc基地址
- ldr r1, = 0x80000000
- str r1, [r0, # 0x08] @ ADC 控制寄存器 (ADC_CR) @adc校准
- _dengadcjiaozhun:
- ldr r1, [r0, # 0x08]
- movs r1, r1
- bmi _dengadcjiaozhun @ 等ADC校准
- _kaiadc:
- ldr r1, [r0, # 0x08]
- movs r2, # 0x01
- orrs r1, r1, r2
- str r1, [r0, # 0x08]
- _dengdaiadcwending:
- ldr r1, [r0]
- lsls r1, r1, # 31
- bpl _dengdaiadcwending @ 等ADC稳定
- _tongdaoxuanze:
- ldr r1, = 0x01
- str r1, [r0, # 0x28] @ 通道选择寄存器 (ADC_CHSELR)
- @ ldr r1, = 0xcC3 @ tim3触发ADC
- ldr r1, = 0x3003
- str r1, [r0, # 0x0c] @ 配置寄存器 1 (ADC_CFGR1)
- movs r1, # 0
- str r1, [r0, # 0x14] @ ADC 采样时间寄存器 (ADC_SMPR)
- ldr r1, [r0, # 0x08]
- ldr r2, = 0x04 @ 开始转换
- orrs r1, r1, r2
- str r1, [r0, # 0x08] @ 控制寄存器 (ADC_CR)
-
- _waishezhongduan: @外设中断
- @0xE000E100 0-31 写1开,写0没效
- @0XE000E180 0-31 写1关,写0没效
- @0XE000E200 0-31 挂起,写0没效
- @0XE000E280 0-31 清除, 写0没效
- ting:
-
- ldr r0, = dianyabiao
- bl _fftjisuan
- ldr r0, = 0x20000058
- movs r1, # 0x01
- lsls r1, r1, # 10
- adds r1, r1, r0
- ldr r0, [r0]
- ldr r1, [r1]
- bl _jisuanfudu
- mov r3, r0
- ldr r0, = lvbohuanchong
- ldr r1, = 256
- ldr r2, = lvbozhizhen
- bl _lvboqi
- ldr r2, = shumaguanma
- movs r1, # 8
- bl _zhuanshumaguanma
- movs r0, # 8
- bl _xieshumaguan
- neicunqingling1:
- ldr r0, = 0x20000000
- movs r1, # 0
- ldr r3, = 0x850
- neicunqinglingxunhuan1:
- subs r3, # 4
- str r1, [r0, r3]
- bne neicunqinglingxunhuan1
- ldr r0, = 0x40020000
- ldr r1, [r0, # 0x0c]
- cmp r1, # 0
- bne ting
- str r1, [r0, # 0x08]
- movs r1, # 0xff
- ldr r2, = 0xa81
- str r1, [r0, # 0x0c]
- str r2, [r0, # 0x08]
- b ting
-
-
-
- _maopaopaixu:
- push {r0-r7,lr}
- @ r0= 表地址, r1= 长度
- mov r7, r1
- _paixu:
- lsls r1, r7, # 2
- _paixuxunhuan:
- ldrh r2, [r0, r1]
- subs r1, r1, # 2
- bmi _paixu1
- ldrh r4, [r0, r1]
- cmp r2, r4
- bls _paixuxunhuan
- strh r2, [r0, r1]
- adds r3, r1, # 2
- strh r4, [r0, r3]
- b _paixuxunhuan
- _paixu1:
- adds r0, r0, # 2
- subs r7, r7, # 1
- bne _paixu
- pop {r0-r7,pc}
- _zhuanshumaguanma:@ 16进制转数码管码
- @ R0要转的数据, R1长度,R2结果表首地址
- push {r0-r7,lr}
- ldr r7, = shumaguanmabiao
- mov r5, r0
- mov r6, r1
- movs r1, # 10
- _xunhuanqiuma:
- bl _chufa
- mov r4, r0
- muls r4, r1
- subs r3, r5, r4
- lsls r3, # 2
- ldr r4, [r7, r3]
- str r4, [r2]
- mov r5, r0
- adds r2, r2, # 4
- subs r6, # 1
- bne _xunhuanqiuma
- pop {r0-r7,pc}
- _xieshumaguan: @ r0=位数 @数码管码
- push {r0-r7,lr}
- lsls r0, r0, # 2
- movs r7, # 0
- mov r6, r0
- ldr r5, = shumaguanma
- ldr r2, = shumaguanshuaxinbiao
- _shumaguanshuaxin:
- ldr r3, [r5, r7]
- ldr r4, [r2, r7]
- orrs r4, r4, r3
- mov r0, r4
- bl _xie595
- adds r7, r7, # 4
- cmp r7, r6
- bls _shumaguanshuaxin
- pop {r0-r7,pc}
-
- _xie595: @ R0=要写的数据
- push {r0-r7,lr}
- mov r5, r0
- movs r0, # 0x40
- movs r7, # 0x80
- movs r6, # 0x20
- movs r3, # 16 @16位
- ldr r2, = 0x48000000 @ gpioa
- movs r1, # 0x01
- _xunhuan595:
- str r7, [r2, # 0x18]
- bl _yanshi
- tst r5, r1
- bne _xie595_0
- str r0, [r2, # 0x28]
- b _suocun595
- _xie595_0:
- str r0, [r2, # 0x18]
- _suocun595:
- bl _yanshi
- lsrs r5, # 1
- str r7, [r2, # 0x28]
- bl _yanshi
- subs r3, r3, # 1
- bne _xunhuan595
- str r6, [r2, # 0x18]
- bl _yanshi
- str r6, [r2, # 0x28]
- bl _yanshi
- pop {r0-r7,pc}
- _yanshi:
- push {r7}
- ldr r7, = 30
- _yanshi11:
- subs r7, # 1
- bne _yanshi11
- pop {r7}
- bx lr
- _chufa: @软件除法
- @ r0 除以 r1 等于 商(r0)余数R1
- push {r1-r4,lr}
- cmp r0, # 0
- beq _chufafanhui
- cmp r1, # 0
- beq _chufafanhui
- mov r2, r0
- movs r3, # 1
- lsls r3, r3, # 31
- movs r0, # 0
- mov r4, r0
- _chufaxunhuan:
- lsls r2, r2, # 1
- adcs r4, r4, r4
- cmp r4, r1
- bcc _chufaweishubudao0
- adds r0, r0, r3
- subs r4, r4, r1
- _chufaweishubudao0:
- lsrs r3, r3, # 1
- bne _chufaxunhuan
- _chufafanhui:
- pop {r1-r4,pc}
- .ltorg
- _jisuanfudu: @ 计算幅度
- @ 入r0= 实部,r1= 虚部
- @ 出r0 = 幅度
- @ Mag ~=Alpha * max(|I|, |Q|) + Beta * min(|I|, |Q|)
- @ Alpha * Max + Beta * Min
- push {r1-r3,lr}
- movs r0, r0
- bpl _shibubushifushu
- mvns r0, r0 @ 是负数转成正数
- adds r0, r0, # 1
- _shibubushifushu: @ 实部不是负数
- movs r1, r1
- bpl _xububushifushu
- mvns r1, r1 @ 是负数转成正数
- adds r1, r1, # 1
- _xububushifushu: @ 虚部不是负数
- cmp r0, # 0
- bne _panduanxubushibushi0
- mov r0, r1
- pop {r1-r3,pc}
- _panduanxubushibushi0:
- cmp r1, # 0
- bne _jisuanfudu1
- pop {r1-r3,pc}
- _jisuanfudu1:
- ldr r2, = 31066 @ Alpha q15 0.948059448969
- ldr r3, = 12867 @ Beta q15 0.392699081699
- cmp r1, r0
- bhi _alpha_min_beta_max
- _alpha_max_beta_min:
- muls r0, r0, r2
- muls r1, r1, r3
- asrs r0, r0, # 15
- asrs r1, r1, # 15
- adds r0, r0, r1
- movs r1, # 1
- pop {r1-r3,pc}
- _alpha_min_beta_max:
- muls r0, r0, r3
- muls r1, r1, r2
- asrs r0, r0, # 15
- asrs r1, r1, # 15
- adds r0, r0, r1
- movs r1, # 0
- pop {r1-r3,pc}
- _lvboqi:
- @滤波器
- @R0=地址,R1=长度,r2=表指针地址,r3=ADC数值
- @出R0=结果
- push {r1-r7,lr}
- ldr r5, [r2] @读出表指针
- lsls r6, r1, # 1
- strh r3, [r0, r5] @数值写到滤波器缓冲区
- adds r5, r5, # 2
- cmp r5, r6
- bne _lvboqimeidaohuanchongquding
- movs r5, # 0
- _lvboqimeidaohuanchongquding:
- str r5, [r2]
- movs r7, # 0
- _lvboqixunhuan:
- cmp r5, r6
- bne _lvbozonghe
- movs r5, # 0
- _lvbozonghe:
- ldrh r4, [r0, r5]
- adds r5, r5, # 2
- adds r7, r7, r4
- subs r1, r1, # 1
- bne _lvboqixunhuan
- asrs r0, r7, # 10 @修改
- pop {r1-r7,pc}
-
- _fftjisuan:
- @ 入口 R0=数据地址
- @ 输出实部=0X20000000-0X20000400
- @ 输出虚部=0X20000400-0X20000800
- @ 结果左移6位(乘64)
- push {r0-r7,lr}
- _fft1:
- ldr r1, = 0x20000000 @ 输出地址
- movs r2, # 128 @ 蝴蝶数量
- ldr r3, = hudieweifanzhuan @ 蝴蝶位反转表
- _fft1xunhuan:
- ldr r6, [r3] @ 取出位反转表里的地一个数据
- ldr r7, [r3, # 0x04] @ 取出第二个
- ldr r6, [r0, r6] @ 根据位反转表找到对应的输入数据
- ldr r7, [r0, r7] @ 第二个
- adds r4, r6, r7 @ 求出蝴蝶上
- subs r5, r6, r7 @ 求出蝴蝶下
- str r4, [r1]
- str r5, [r1, # 0x04] @ 把反过来的顺序排列
- adds r1, r1, # 0x08 @ 输出的地址自增
- adds r3, r3, # 0x08 @ 反转表自增
- subs r2, r2, # 1 @ 蝴蝶数减1
- bne _fft1xunhuan @ 蝴蝶数不到
- _fft2:
- ldr r0, = 0x20000000 @ 实部输出地址0x20000000
- movs r4, # 1
- lsls r4, r4, # 10
- adds r4, r4, r0 @ 虚部输出地址 0x20000400
- mov r8, r4 @ 实部和虚部中间
- _fft2xunhuan:
- ldr r4, [r0] @ 取出数据0
- ldr r5, [r0, # 0x08] @ 取出数据2
- ldr r6, [r0, # 0x04] @ 取出数据1
- ldr r7, [r0, # 0x0c] @ 取出数据3
- adds r1, r4, r5 @ 计算蝴蝶上
- subs r2, r4, r5 @ 计算蝴蝶下
- mov r3, r6 @ 0 r 蝴蝶上实部
- movs r4, # 0
- subs r4, r4, r7 @ 0i 蝴蝶上虚部
- mov r5, r6 @ 3r 蝴蝶下实部
- mov r6, r7 @ 3i 蝴蝶下虚部
- movs r7, # 1
- lsls r7, r7, # 10 @ 内存实部和虚部中间
- adds r7, r7, r0 @ R7等于虚部首地址
- str r1, [r0] @ 蝴蝶上保存实部
- str r2, [r0, # 0x08] @ 蝴蝶下实部
- str r3, [r0, # 0x04] @ 第二组蝴蝶上实部
- str r4, [r7, # 0x04] @ 第二组蝴蝶上虚部
- str r5, [r0, # 0x0c] @ 第二组蝴蝶下实部
- str r6, [r7, # 0x0c] @ 第二组下虚部
- adds r0, r0, # 0x10 @ 蝴蝶组自增
- cmp r0, r8
- bne _fft2xunhuan @ 地址不到循环
- _fft3:
- ldr r6, = xuanzhuanyinzi @ 旋转因子自增变量
- ldr r2, = fft3xuanzhuanyinzi @ 旋转因子第三步的表
- ldr r0, = 0x20000000 @ 实部输出地址
- str r2, [r6] @ 旋转因子表首地址写到变量
- movs r1, # 1
- lsls r1, r1, # 10
- adds r1, r1, r0 @ 虚部输出地址
- mov r8, r1 @ R8虚部地址自增变量
- mov r9, r0 @ R9实部地址自增变量
- mov r10, r2 @ 旋转因子地址写到R10
- movs r5, # 0x10 @ 两组蝴蝶的距离
- mov r11, r5 @ 写到R11
- movs r5, # 4 @ 旋转因子数量
- mov r12, r5 @ 旋转因子数量写到R12
- bl _fftg
- _fft4:
- ldr r6, = xuanzhuanyinzi @ 旋转因子自增变量
- ldr r2, = fft4xuanzhuanyinzi @ 旋转因子第四步表
- ldr r0, = 0x20000000 @ 实部地址
- str r2, [r6] @ 第四步旋转因子表写到自增变量
- movs r1, # 1
- lsls r1, r1, # 10
- adds r1, r1, r0 @ r1 = 虚部地址
- mov r8, r1 @
- mov r9, r0
- mov r10, r2
- movs r5, # 0x20
- mov r11, r5
- movs r5, # 8
- mov r12, r5
- bl _fftg
- _fft5:
- ldr r6, = xuanzhuanyinzi
- ldr r2, = fft5xuanzhuanyinzi
- ldr r0, = 0x20000000
- str r2, [r6]
- movs r1, # 1
- lsls r1, r1, # 10
- adds r1, r1, r0
- mov r8, r1
- mov r9, r0
- mov r10, r2
- movs r5, # 0x40
- mov r11, r5
- movs r5, # 16
- mov r12, r5
- bl _fftg
- _fft6:
- ldr r6, = xuanzhuanyinzi
- ldr r2, = fft6xuanzhuanyinzi
- ldr r0, = 0x20000000
- str r2, [r6]
- movs r1, # 1
- lsls r1, r1, # 10
- adds r1, r1, r0
- mov r8, r1
- mov r9, r0
- mov r10, r2
- movs r5, # 0x80
- mov r11, r5
- movs r5, # 32
- mov r12, r5
- bl _fftg
- _fft7:
- ldr r6, = xuanzhuanyinzi
- ldr r2, = fft7xuanzhuanyinzi
- ldr r0, = 0x20000000
- str r2, [r6]
- movs r1, # 1
- lsls r1, r1, # 10
- adds r1, r1, r0
- mov r8, r1
- mov r9, r0
- mov r10, r2
- movs r5, # 1
- lsls r5, r5, # 8
- mov r11, r5
- movs r5, # 64
- mov r12, r5
- bl _fftg
- _fft8:
- ldr r6, = xuanzhuanyinzi
- ldr r2, = fft8xuanzhuanyinzi
- ldr r0, = 0x20000000
- str r2, [r6]
- movs r1, # 1
- lsls r1, r1, # 10
- adds r1, r1, r0
- mov r8, r1
- mov r9, r0
- mov r10, r2
- movs r5, # 1
- lsls r5, r5, # 9
- mov r11, r5
- movs r5, # 128
- mov r12, r5
- bl _fftg
- pop {r0-r7,pc}
- _fftg:
- push {lr} @ LR保存到堆栈
- movs r4, # 0
- mov lr, r4
- _fftxunhuan:
- mov r0, r9 @ R0实部地址自增变量地址
- mov r1, r8 @ R1虚部地址自增变量地址
- mov r2, r10 @ 旋转因子表地址地址
- mov r3, r11 @ 两组蝴蝶的距离
- ldr r4, [r0] @ r4=蝴蝶上实部
- ldr r5, [r1] @ r5=蝴蝶上虚部
- ldr r6, [r0, r3] @ r6=蝴蝶下实部
- ldr r7, [r1, r3] @ r7=蝴蝶下虚部
- ldr r3, [r2] @ SR
- ldr r2, [r2, # 0x04] @ SI
- push {r4,r5} @ R4 R5保存到堆栈
- @ (a+bi)(c+di)=(ac-bd)+(ad+bc)i
- mov r4, r6 @ r4=蝴蝶下实部
- muls r4, r4, r3 @ 乘旋转因子 ac
- mov r5, r7 @ R5=蝴蝶下虚部
- muls r5, r5, r2 @ 乘旋转因子 bd
- subs r4, r4, r5 @ ac-bd
- asrs r4, r4, # 15 @ 截断Q15
- mov r5, r6
- muls r5, r5, r2 @ ad
- muls r7, r7, r3 @ bc
- adds r7, r7, r5 @ ad+bc
- asrs r7, r7, # 15 @ 截断Q15
- pop {r2,r5} @ R2= 蝴蝶上实部
- @ r5= 蝴蝶上虚部
- adds r3, r2, r4 @ 上实部加下实部=结果上实部
- subs r2, r2, r4 @ 下实部减上实部=结果下实部
- adds r4, r5, r7 @ 上虚部加下虚部=结果上虚部
- subs r5, r5, r7 @ 上虚部减下虚部=结果下虚部
- mov r6, r11 @ r6=蝴蝶距离
- asrs r3, r3, # 1 @ 右移一位防止溢出
- asrs r4, r4, # 1 @ 右移一位防止溢出
- asrs r2, r2, # 1 @ 右移一位防止溢出
- asrs r5, r5, # 1 @ 右移一位防止溢出
- str r3, [r0] @ 保存上实部
- str r4, [r1] @ 保存上虚部
- str r2, [r0, r6] @ 保存下实部
- str r5, [r1, r6] @ 保存下虚部
- adds r0, r0, # 0x04 @ 实部地址加4
- adds r1, r1, # 0x04 @ 虚部地址加4
- mov r9, r0 @ r9=当前实部地址
- mov r8, r1 @ R8=当前虚部地址
- mov r2, r10 @ r2= 当前旋转因子地址
- adds r2, r2, # 0x08 @ R2 = 旋转因子地址加8
- mov r10, r2 @ 保存回去
- mov r4, lr @ 一个蝴蝶旋转因子变量
- adds r4, r4, # 1 @ 自增
- mov lr, r4 @ 保存回去
- mov r7, r12 @ 取出旋转因子总数量
- cmp r4, r7 @ 到没到数量
- bne _fftxunhuan @ 没到继续循环
- movs r4, # 0 @ 到了R4=0
- mov lr, r4 @ 一个蝴蝶旋转因子变量清0
- ldr r6, = xuanzhuanyinzi @ R6=旋转因子自增变量地址
- ldr r5, = 0x20000400 @ R5=虚部地址
- ldr r6, [r6] @ 取出旋转因子自增变量
- mov r7, r11 @ R7= 蝴蝶距离
- mov r10, r6 @ R10 = 旋转因子自增变量
- adds r0, r0, r7 @ 实部地址加蝴蝶距离
- adds r1, r1, r7 @ 虚部地址加蝴蝶距离
- mov r9, r0 @ R9等于当前实部地址
- mov r8, r1 @ R8等于当前虚部地址
- cmp r0, r5 @ 实部到没到虚部边界
- bne _fftxunhuan @ 没到循环计算
- pop {pc} @ 返回
- .ltorg @ 文字池
-
- _nmi_handler:
- bx lr
- _hard_fault:
- bx lr
- _svc_handler:
- bx lr
- _pendsv_handler:
- bx lr
- _systickzhongduan:
- ldr r0, = 0xe000ed04
- movs r1, # 1
- lsls r1, r1, # 25
- str r1, [r0] @ 清除SYSTICK中断
- aaa:
- bx lr
复制代码
|